From 7cb2519e2a8b1d4020128660cc8a22c6e2f60e86 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Fri, 12 Jun 2009 21:15:46 +0000 Subject: [PATCH 01/95] (Dev) "trunk" is now labelled "2.1 wip". Makefile: "make ziprelease" now automatically names archives according to the version label from pversion.c git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@862 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 13 +++++++++---- pversion.c | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 93e734a2..5c0afe2b 100644 --- a/Makefile +++ b/Makefile @@ -237,10 +237,15 @@ release : version $(BIN) # Create a zip archive ready for upload to the website, including binaries and sourcecode ziprelease: version $(BIN) release - tar cvzf src-svn`svnversion | sed 's/:/-/'`.tgz --transform 's,^,src/,g' *.c *.h Makefile Makefile.dep gfx2.ico - $(ZIP) $(ZIPOPT) grafx2-svn`svnversion | sed 's/:/-/'`$(TTFLABEL)-$(PLATFORM).$(ZIP) $(BIN) gfx2def.ini skins/base.gif gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt fonts/Tuffy.ttf src-svn`svnversion | sed 's/:/-/'`.tgz $(PLATFORMFILES) - $(DELCOMMAND) src-svn`svnversion | sed 's/:/-/'`.tgz - tar cvzf grafx2-svn`svnversion | sed 's/:/-/'`$(TTFLABEL)-src.tgz --transform 's,^,grafx2/,g' *.c *.h Makefile Makefile.dep gfx2def.ini skins/base.gif gfx2.ico gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt misc/grafx2.1 misc/grafx2.xpm misc/grafx2.desktop fonts/8pxfont.png fonts/Tuffy.ttf + echo `sed "s/.*=\"\(.*\)\";/\1/" pversion.c`-svn`svnversion` | tr " :" "_-" > $(OBJDIR)/versiontag + + tar cvzf "src-`cat $(OBJDIR)/versiontag`.tgz" --transform 's,^,src/,g' *.c *.h Makefile Makefile.dep gfx2.ico + $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN) gfx2def.ini skins/base.gif gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt fonts/Tuffy.ttf src-`cat $(OBJDIR)/versiontag`.tgz $(PLATFORMFILES) + $(DELCOMMAND) "src-`cat $(OBJDIR)/versiontag`.tgz" + tar cvzf "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --transform 's,^,grafx2/,g' *.c *.h Makefile Makefile.dep gfx2def.ini skins/base.gif gfx2.ico gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt misc/grafx2.1 misc/grafx2.xpm misc/grafx2.desktop fonts/8pxfont.png fonts/Tuffy.ttf + $(DELCOMMAND) "$(OBJDIR)/versiontag" + +testsed : $(BIN) : $(OBJ) $(OBJRES) $(CC) $(OBJ) $(OBJRES) -o $(BIN) $(LOPT) diff --git a/pversion.c b/pversion.c index 94351ab0..f4205dfc 100644 --- a/pversion.c +++ b/pversion.c @@ -1 +1 @@ -char Program_version[]="2.0"; +char Program_version[]="2.1 wip"; From fb05f785bd9fcc3b66e02e4ab2fe227aaee42bef Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 14 Jun 2009 18:22:29 +0000 Subject: [PATCH 02/95] (Dev) Makefile: File names from 'make ziprelease' are now grafx2-2.1wip862-win32.zip if label is '2.1wip', and grafx2-2.1.862-win32.zip if label is '2.1' git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@863 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 2 +- pversion.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5c0afe2b..8a806aa9 100644 --- a/Makefile +++ b/Makefile @@ -237,7 +237,7 @@ release : version $(BIN) # Create a zip archive ready for upload to the website, including binaries and sourcecode ziprelease: version $(BIN) release - echo `sed "s/.*=\"\(.*\)\";/\1/" pversion.c`-svn`svnversion` | tr " :" "_-" > $(OBJDIR)/versiontag + echo `sed "s/.*=\"\(.*\)\";/\1/" pversion.c`.`svnversion` | tr " :" "_-" | sed -e s/\\(wip\\)\\\\./\\1/I > $(OBJDIR)/versiontag tar cvzf "src-`cat $(OBJDIR)/versiontag`.tgz" --transform 's,^,src/,g' *.c *.h Makefile Makefile.dep gfx2.ico $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN) gfx2def.ini skins/base.gif gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt fonts/Tuffy.ttf src-`cat $(OBJDIR)/versiontag`.tgz $(PLATFORMFILES) diff --git a/pversion.c b/pversion.c index f4205dfc..f7ca5bb4 100644 --- a/pversion.c +++ b/pversion.c @@ -1 +1 @@ -char Program_version[]="2.1 wip"; +char Program_version[]="2.1wip"; From 8478d293730e1aba0c3cbb39e9b331d86bf8ed34 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 14 Jun 2009 19:48:03 +0000 Subject: [PATCH 03/95] Quick shortcuts for numeric transparency levels (Issue 154) (defaults 1-9 and 0). Shortcut for all effects off (default shift-E) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@864 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 83 +++++++++++++++++++++++---- buttons.h | 11 ++++ const.h | 13 ++++- engine.c | 44 ++++++++++++++ help.c | 4 +- helpfile.h | 11 ++++ hotkeys.c | 165 ++++++++++++++++++++++++++++++++++++++++++----------- 7 files changed, 283 insertions(+), 48 deletions(-) diff --git a/buttons.c b/buttons.c index 1b58324a..1483c785 100644 --- a/buttons.c +++ b/buttons.c @@ -3544,7 +3544,6 @@ void Button_Smear_mode(void) Smear_mode=!Smear_mode; } - // -- Mode Colorize --------------------------------------------------------- void Compute_colorize_table(void) { @@ -3792,6 +3791,76 @@ void Button_Tiling_menu(void) Display_cursor(); } +// -- All modes off --------------------------------------------------------- +void Effects_off(void) +{ + Effect_function=No_effect; + Shade_mode=0; + Quick_shade_mode=0; + Colorize_mode=0; + Smooth_mode=0; + Tiling_mode=0; + Smear_mode=0; + Stencil_mode=0; + Mask_mode=0; + Sieve_mode=0; + Snap_mode=0; + + if (! Windows_open) + { + + } +} + +void Transparency_set(byte amount) +{ + const int doubleclick_delay = 500; + static long time_click = 0; + long time_previous; + + if (!Colorize_mode) + { + // Activate mode + switch(Colorize_current_mode) + { + case 0 : + Effect_function=Effect_interpolated_colorize; + break; + case 1 : + Effect_function=Effect_additive_colorize; + break; + case 2 : + Effect_function=Effect_substractive_colorize; + } + Shade_mode=0; + Quick_shade_mode=0; + Smooth_mode=0; + Tiling_mode=0; + + Colorize_mode=1; + } + + time_previous = time_click; + time_click = SDL_GetTicks(); + + // Check if it's a quick re-press + if (time_click - time_previous < doubleclick_delay) + { + // Use the typed amount as units, keep the tens. + Colorize_opacity = ((Colorize_opacity%100) /10 *10) + amount; + if (Colorize_opacity == 0) + Colorize_opacity = 100; + } + else + { + // Use 10% units: "1"=10%, ... "0"=100% + if (amount == 0) + Colorize_opacity = 100; + else + Colorize_opacity = amount*10; + } + Compute_colorize_table(); +} //---------------------------- Courbes de Bézier ---------------------------- @@ -4970,17 +5039,7 @@ void Button_Effects(void) exit_by_close_button=1; break; case 12 : // All off - Effect_function=No_effect; - Shade_mode=0; - Quick_shade_mode=0; - Colorize_mode=0; - Smooth_mode=0; - Tiling_mode=0; - Smear_mode=0; - Stencil_mode=0; - Mask_mode=0; - Sieve_mode=0; - Snap_mode=0; + Effects_off(); Hide_cursor(); Display_effect_states(); Display_cursor(); diff --git a/buttons.h b/buttons.h index 68542809..8b87fc9b 100644 --- a/buttons.h +++ b/buttons.h @@ -425,6 +425,17 @@ void Button_Tiling_mode(void); Displays the tiling setup menu. */ void Button_Tiling_menu(void); + +/*! + Callback for the command that turns off all drawaing effects. +*/ +void Effects_off(void); + +/*! + Command that sets the transparency level. +*/ +void Transparency_set(byte amount); + // Menu des effets /*! diff --git a/const.h b/const.h index b3716712..64c7dc6b 100644 --- a/const.h +++ b/const.h @@ -33,7 +33,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 134 ///< Number of actions that can have a key combination associated to it. +#define NB_SHORTCUTS 145 ///< Number of actions that can have a key combination associated to it. #define NB_ZOOM_FACTORS 12 ///< 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. @@ -374,7 +374,18 @@ enum SPECIAL_ACTIONS SPECIAL_SMOOTH_MODE, SPECIAL_SMOOTH_MENU, SPECIAL_SMEAR_MODE, + SPECIAL_EFFECTS_OFF, SPECIAL_TILING_MODE, + SPECIAL_TRANSPARENCY_1, + SPECIAL_TRANSPARENCY_2, + SPECIAL_TRANSPARENCY_3, + SPECIAL_TRANSPARENCY_4, + SPECIAL_TRANSPARENCY_5, + SPECIAL_TRANSPARENCY_6, + SPECIAL_TRANSPARENCY_7, + SPECIAL_TRANSPARENCY_8, + SPECIAL_TRANSPARENCY_9, + SPECIAL_TRANSPARENCY_0, SPECIAL_TILING_MENU, ///< This must be the last of the "effects" family NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; diff --git a/engine.c b/engine.c index 24c71e0e..70e31fa3 100644 --- a/engine.c +++ b/engine.c @@ -857,6 +857,50 @@ void Main_handler(void) Button_Tiling_menu(); Key=0; break; + case SPECIAL_EFFECTS_OFF : + Effects_off(); + Key=0; + break; + case SPECIAL_TRANSPARENCY_1 : + Transparency_set(1); + Key=0; + break; + case SPECIAL_TRANSPARENCY_2 : + Transparency_set(2); + Key=0; + break; + case SPECIAL_TRANSPARENCY_3 : + Transparency_set(3); + Key=0; + break; + case SPECIAL_TRANSPARENCY_4 : + Transparency_set(4); + Key=0; + break; + case SPECIAL_TRANSPARENCY_5 : + Transparency_set(5); + Key=0; + break; + case SPECIAL_TRANSPARENCY_6 : + Transparency_set(6); + Key=0; + break; + case SPECIAL_TRANSPARENCY_7 : + Transparency_set(7); + Key=0; + break; + case SPECIAL_TRANSPARENCY_8 : + Transparency_set(8); + Key=0; + break; + case SPECIAL_TRANSPARENCY_9 : + Transparency_set(9); + Key=0; + break; + case SPECIAL_TRANSPARENCY_0 : + Transparency_set(0); + Key=0; + break; default : // Gestion des touches de raccourci de bouton: // Pour chaque bouton shortcut_button=-1; diff --git a/help.c b/help.c index 817e1cf0..456f4619 100644 --- a/help.c +++ b/help.c @@ -119,7 +119,7 @@ void Window_set_shortcut(int action_id) while (Ordering[order_index]!=action_id) { order_index++; - if (order_index>=134) + if (order_index>=NB_SHORTCUTS) { Error(0); return; @@ -130,7 +130,7 @@ void Window_set_shortcut(int action_id) while (ConfigKey[config_index].Number!=order_index) { config_index++; - if (config_index>=134) + if (config_index>=NB_SHORTCUTS) { Error(0); return; diff --git a/helpfile.h b/helpfile.h index 4b7c4539..354cf234 100644 --- a/helpfile.h +++ b/helpfile.h @@ -159,6 +159,7 @@ static const T_Help_table helptable_help[] = HELP_LINK ("Adjust picture: %s", 0x100+BUTTON_ADJUST) HELP_LINK ("Flip picture menu: %s", 0x200+BUTTON_ADJUST) HELP_LINK ("Effects menu: %s", 0x100+BUTTON_EFFECTS) + HELP_LINK ("Effects all off %s", SPECIAL_EFFECTS_OFF) HELP_LINK ("Shade mode: %s", SPECIAL_SHADE_MODE) HELP_LINK ("Shade menu: %s", SPECIAL_SHADE_MENU) HELP_LINK ("Quick-shade mode: %s", SPECIAL_QUICK_SHADE_MODE) @@ -173,6 +174,16 @@ static const T_Help_table helptable_help[] = HELP_LINK ("Sieve menu: %s", SPECIAL_SIEVE_MENU) HELP_LINK ("Invert Sieve: %s", SPECIAL_INVERT_SIEVE) HELP_LINK ("Colorize mode: %s", SPECIAL_COLORIZE_MODE) + HELP_LINK (" At opacity 10%%: %s", SPECIAL_TRANSPARENCY_1) + HELP_LINK (" At opacity 20%%: %s", SPECIAL_TRANSPARENCY_2) + HELP_LINK (" At opacity 30%%: %s", SPECIAL_TRANSPARENCY_3) + HELP_LINK (" At opacity 40%%: %s", SPECIAL_TRANSPARENCY_4) + HELP_LINK (" At opacity 50%%: %s", SPECIAL_TRANSPARENCY_5) + HELP_LINK (" At opacity 60%%: %s", SPECIAL_TRANSPARENCY_6) + HELP_LINK (" At opacity 70%%: %s", SPECIAL_TRANSPARENCY_7) + HELP_LINK (" At opacity 80%%: %s", SPECIAL_TRANSPARENCY_8) + HELP_LINK (" At opacity 90%%: %s", SPECIAL_TRANSPARENCY_9) + HELP_LINK (" At opacity 100%%: %s", SPECIAL_TRANSPARENCY_0) HELP_LINK ("Colorize menu: %s", SPECIAL_COLORIZE_MENU) HELP_LINK ("Smooth mode: %s", SPECIAL_SMOOTH_MODE) HELP_LINK ("Smooth menu: %s", SPECIAL_SMOOTH_MENU) diff --git a/hotkeys.c b/hotkeys.c index 8d29852c..c6a12d5e 100644 --- a/hotkeys.c +++ b/hotkeys.c @@ -1094,6 +1094,94 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { true, SDLK_PERIOD, // .> (:/ en AZERTY) 0}, + {134, + "Effects off", + "Turns off all drawing effects. This", + "is the same as the 'All off' button", + "in the Effects screen", + true, + SDLK_e|MOD_SHIFT, // Shift-E + 0}, + {135, + "Transparency 10%", + "Turns transparency on and sets its", + "opacity at 10%.", + "", + true, + SDLK_1, // 1 + 0}, + {136, + "Transparency 20%", + "Turns transparency on and sets its", + "opacity at 20%.", + "", + true, + SDLK_1, // 1 + 0}, + {137, + "Transparency 30%", + "Turns transparency on and sets its", + "opacity at 30%.", + "", + true, + SDLK_1, // 1 + 0}, + {138, + "Transparency 40%", + "Turns transparency on and sets its", + "opacity at 40%.", + "", + true, + SDLK_1, // 1 + 0}, + {139, + "Transparency 50%", + "Turns transparency on and sets its", + "opacity at 50%.", + "", + true, + SDLK_1, // 1 + 0}, + {140, + "Transparency 60%", + "Turns transparency on and sets its", + "opacity at 60%.", + "", + true, + SDLK_1, // 1 + 0}, + {141, + "Transparency 70%", + "Turns transparency on and sets its", + "opacity at 70%.", + "", + true, + SDLK_1, // 1 + 0}, + {142, + "Transparency 80%", + "Turns transparency on and sets its", + "opacity at 80%.", + "", + true, + SDLK_1, // 1 + 0}, + {143, + "Transparency 90%", + "Turns transparency on and sets its", + "opacity at 90%.", + "", + true, + SDLK_1, // 1 + 0}, + {144, + "Transparency 0%", + "Turns transparency on and sets its", + "opacity at 0%.", + "", + true, + SDLK_1, // 1 + 0}, }; word Ordering[NB_SHORTCUTS]= @@ -1116,39 +1204,39 @@ word Ordering[NB_SHORTCUTS]= SPECIAL_MOUSE_RIGHT, // Emulate mouse right SPECIAL_CLICK_LEFT, // Emulate mouse click left SPECIAL_CLICK_RIGHT, // Emulate mouse click right - 0x100+BUTTON_HIDE, // Show / Hide menu + 0x100+BUTTON_HIDE, // Show / Hide menu SPECIAL_SHOW_HIDE_CURSOR, // Show / Hide cursor - SPECIAL_DOT_PAINTBRUSH, // Paintbrush = "." - 0x100+BUTTON_PAINTBRUSHES, // Paintbrush choice - 0x200+BUTTON_PAINTBRUSHES, // Monochrome brush - 0x100+BUTTON_DRAW, // Freehand drawing - 0x200+BUTTON_DRAW, // Switch freehand drawing mode - SPECIAL_CONTINUOUS_DRAW, // Continuous freehand drawing - 0x100+BUTTON_LINES, // Line - 0x200+BUTTON_LINES, // Knotted lines - 0x100+BUTTON_AIRBRUSH, // Spray - 0x200+BUTTON_AIRBRUSH, // Spray menu + SPECIAL_DOT_PAINTBRUSH, // Paintbrush = "." + 0x100+BUTTON_PAINTBRUSHES, // Paintbrush choice + 0x200+BUTTON_PAINTBRUSHES, // Monochrome brush + 0x100+BUTTON_DRAW, // Freehand drawing + 0x200+BUTTON_DRAW, // Switch freehand drawing mode + SPECIAL_CONTINUOUS_DRAW, // Continuous freehand drawing + 0x100+BUTTON_LINES, // Line + 0x200+BUTTON_LINES, // Knotted lines + 0x100+BUTTON_AIRBRUSH, // Spray + 0x200+BUTTON_AIRBRUSH, // Spray menu 0x100+BUTTON_FLOODFILL, // Floodfill 0x200+BUTTON_FLOODFILL, // Replace color - 0x100+BUTTON_CURVES, // Bézier's curves - 0x200+BUTTON_CURVES, // Bézier's curve with 3 or 4 points + 0x100+BUTTON_CURVES, // Bézier's curves + 0x200+BUTTON_CURVES, // Bézier's curve with 3 or 4 points 0x100+BUTTON_RECTANGLES, // Empty rectangle 0x100+BUTTON_FILLRECT, // Filled rectangle 0x100+BUTTON_CIRCLES, // Empty circle 0x200+BUTTON_CIRCLES, // Empty ellipse 0x100+BUTTON_FILLCIRC, // Filled circle 0x200+BUTTON_FILLCIRC, // Filled ellipse - 0x100+BUTTON_POLYGONS, // Empty polygon - 0x200+BUTTON_POLYGONS, // Empty polyform + 0x100+BUTTON_POLYGONS, // Empty polygon + 0x200+BUTTON_POLYGONS, // Empty polyform 0x100+BUTTON_POLYFILL, // Polyfill 0x200+BUTTON_POLYFILL, // Filled polyform 0x100+BUTTON_GRADRECT, // Gradient rectangle 0x100+BUTTON_GRADMENU, // Gradation menu 0x100+BUTTON_SPHERES, // Spheres 0x200+BUTTON_SPHERES, // Gradient ellipses - 0x100+BUTTON_ADJUST, // Adjust picture - 0x200+BUTTON_ADJUST, // Flip picture menu - 0x100+BUTTON_EFFECTS, // Menu des effets + 0x100+BUTTON_ADJUST, // Adjust picture + 0x200+BUTTON_ADJUST, // Flip picture menu + 0x100+BUTTON_EFFECTS, // Menu des effets SPECIAL_SHADE_MODE, // Shade mode SPECIAL_SHADE_MENU, // Shade menu SPECIAL_QUICK_SHADE_MODE, // Quick-shade mode @@ -1169,9 +1257,9 @@ word Ordering[NB_SHORTCUTS]= SPECIAL_SMEAR_MODE, // Smear mode SPECIAL_TILING_MODE, // Tiling mode SPECIAL_TILING_MENU, // Tiling menu - 0x100+BUTTON_BRUSH, // Pick brush - 0x100+BUTTON_POLYBRUSH, // Pick polyform brush - 0x200+BUTTON_BRUSH, // Restore brush + 0x100+BUTTON_BRUSH, // Pick brush + 0x100+BUTTON_POLYBRUSH, // Pick polyform brush + 0x200+BUTTON_BRUSH, // Restore brush SPECIAL_FLIP_X, // Flip X SPECIAL_FLIP_Y, // Flip Y SPECIAL_ROTATE_90, // 90° brush rotation @@ -1183,27 +1271,27 @@ word Ordering[NB_SHORTCUTS]= SPECIAL_GET_BRUSH_COLORS, // Get colors from brush SPECIAL_RECOLORIZE_BRUSH, // Recolorize brush SPECIAL_ROTATE_ANY_ANGLE, // Rotate brush by any angle - 0x100+BUTTON_COLORPICKER, // Pipette - 0x200+BUTTON_COLORPICKER, // Swap fore/back color - 0x100+BUTTON_MAGNIFIER, // Magnifier mode - 0x200+BUTTON_MAGNIFIER, // Zoom factor menu + 0x100+BUTTON_COLORPICKER, // Pipette + 0x200+BUTTON_COLORPICKER, // Swap fore/back color + 0x100+BUTTON_MAGNIFIER, // Magnifier mode + 0x200+BUTTON_MAGNIFIER, // Zoom factor menu SPECIAL_ZOOM_IN, // Zoom in SPECIAL_ZOOM_OUT, // Zoom out 0x100+BUTTON_BRUSH_EFFECTS, // Brush effects menu - 0x100+BUTTON_TEXT, // Text + 0x100+BUTTON_TEXT, // Text 0x100+BUTTON_RESOL, // Resolution menu 0x200+BUTTON_RESOL, // Safety resolution 0x100+BUTTON_HELP, // Help & credits 0x200+BUTTON_HELP, // Statistics 0x100+BUTTON_PAGE, // Go to spare page 0x200+BUTTON_PAGE, // Copy to spare page - 0x100+BUTTON_SAVE, // Save as - 0x200+BUTTON_SAVE, // Save - 0x100+BUTTON_LOAD, // Load - 0x200+BUTTON_LOAD, // Re-load + 0x100+BUTTON_SAVE, // Save as + 0x200+BUTTON_SAVE, // Save + 0x100+BUTTON_LOAD, // Load + 0x200+BUTTON_LOAD, // Re-load SPECIAL_SAVE_BRUSH, // Save brush SPECIAL_LOAD_BRUSH, // Load brush - 0x100+BUTTON_SETTINGS, // Settings + 0x100+BUTTON_SETTINGS, // Settings 0x100+BUTTON_UNDO, // Undo 0x200+BUTTON_UNDO, // Redo 0x100+BUTTON_KILL, // Kill @@ -1230,6 +1318,17 @@ word Ordering[NB_SHORTCUTS]= SPECIAL_PREVIOUS_USER_FORECOLOR, // Previous user-defined foreground color SPECIAL_NEXT_USER_BACKCOLOR, // Next user-defined background color SPECIAL_PREVIOUS_USER_BACKCOLOR, // Previous user-defined background color - SPECIAL_SMALLER_PAINTBRUSH, // Rétrécir le pinceau - SPECIAL_BIGGER_PAINTBRUSH // Grossir le pinceau + SPECIAL_SMALLER_PAINTBRUSH, // Sets paintbrush size: smaller + SPECIAL_BIGGER_PAINTBRUSH, // Sets paintbrush size: bigger + SPECIAL_EFFECTS_OFF, // Turns off all effects + SPECIAL_TRANSPARENCY_1, // Sets transparency level 10% + SPECIAL_TRANSPARENCY_2, // Sets transparency level 20% + SPECIAL_TRANSPARENCY_3, // Sets transparency level 30% + SPECIAL_TRANSPARENCY_4, // Sets transparency level 40% + SPECIAL_TRANSPARENCY_5, // Sets transparency level 50% + SPECIAL_TRANSPARENCY_6, // Sets transparency level 60% + SPECIAL_TRANSPARENCY_7, // Sets transparency level 70% + SPECIAL_TRANSPARENCY_8, // Sets transparency level 80% + SPECIAL_TRANSPARENCY_9, // Sets transparency level 90% + SPECIAL_TRANSPARENCY_0, // Sets transparency level 00% }; From 69dbed8d04d1c9661d92c7759f9287bf16cbafa3 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 14 Jun 2009 20:15:20 +0000 Subject: [PATCH 04/95] Fix default shortcuts from previous commit (in code). Implemented user-definable mouse-click speed and double-keypress speed. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@865 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 4 ++-- gfx2.cfg | Bin 10067 -> 10133 bytes gfx2def.ini | 11 +++++++++++ hotkeys.c | 18 +++++++++--------- readini.c | 18 +++++++++++++++++- saveini.c | 7 +++++++ struct.h | 2 ++ 7 files changed, 48 insertions(+), 12 deletions(-) diff --git a/buttons.c b/buttons.c index 1483c785..a06bb8a1 100644 --- a/buttons.c +++ b/buttons.c @@ -287,7 +287,7 @@ void Button_Select_forecolor(void) if (color == Fore_color) { // Check if it's a double-click - if (time_click - time_previous < 500) + if (time_click - time_previous < Config.Double_click_speed) { // Open palette window Button_Palette(); @@ -3814,7 +3814,7 @@ void Effects_off(void) void Transparency_set(byte amount) { - const int doubleclick_delay = 500; + const int doubleclick_delay = Config.Double_key_speed; static long time_click = 0; long time_previous; diff --git a/gfx2.cfg b/gfx2.cfg index 43f249a8294ebad62302340874bb0683f974f7e7..20ab6b6713f6e84640b9ae5bc2c16528704bffbb 100644 GIT binary patch delta 87 zcmccYH`Slh+0C7aA&G$@Z6l{Dvwa&wssIB+JA)wu149Rc5s>U;Fb0xc3?@Lbo52)F f_Ar<%27}Go%o-{H#Sad0 delta 23 ecmbR0f7y@I+0C7aA&G%OWh195^X39(RTThD?gh92 diff --git a/gfx2def.ini b/gfx2def.ini index 757c4c38..d03c6c53 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -312,4 +312,15 @@ ; OS isn't able to do it by itself. (ie: Windows) Window_position = 9999,9999; (Default 9999,9999 which means: NA) + ; This is the time (in milliseconds) between two clicks for Grafx2 to + ; recognize a double-click. Double-click is used mostly in the palette + ; area of the menu: double-click a color to open the palette. + Double_click_speed = 500; (Default 500) + + ; When you press two digit keys in rapid succession (ex: 3 8), Grafx2 + ; sets transparency to 38% (instead of 30% then 80%). This setting + ; allows you to set the maximum delay between two keypresses for + ; GrafX2 to recognize them as a combo. + Double_key_speed = 500; (Default 500) + ; end of configuration diff --git a/hotkeys.c b/hotkeys.c index c6a12d5e..2d232019 100644 --- a/hotkeys.c +++ b/hotkeys.c @@ -1116,7 +1116,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 20%.", "", true, - SDLK_1, // 1 + SDLK_2, // 2 0}, {137, "Transparency 30%", @@ -1124,7 +1124,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 30%.", "", true, - SDLK_1, // 1 + SDLK_3, // 3 0}, {138, "Transparency 40%", @@ -1132,7 +1132,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 40%.", "", true, - SDLK_1, // 1 + SDLK_4, // 4 0}, {139, "Transparency 50%", @@ -1140,7 +1140,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 50%.", "", true, - SDLK_1, // 1 + SDLK_5, // 5 0}, {140, "Transparency 60%", @@ -1148,7 +1148,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 60%.", "", true, - SDLK_1, // 1 + SDLK_6, // 6 0}, {141, "Transparency 70%", @@ -1156,7 +1156,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 70%.", "", true, - SDLK_1, // 1 + SDLK_7, // 7 0}, {142, "Transparency 80%", @@ -1164,7 +1164,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 80%.", "", true, - SDLK_1, // 1 + SDLK_8, // 8 0}, {143, "Transparency 90%", @@ -1172,7 +1172,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 90%.", "", true, - SDLK_1, // 1 + SDLK_9, // 9 0}, {144, "Transparency 0%", @@ -1180,7 +1180,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "opacity at 0%.", "", true, - SDLK_1, // 1 + SDLK_0, // 0 0}, }; diff --git a/readini.c b/readini.c index 7c3b7cb6..26c5fdb2 100644 --- a/readini.c +++ b/readini.c @@ -788,7 +788,7 @@ int Load_INI(T_Config * conf) break; } conf->Palette_vertical=0; - // Optionnel, vertical palette option (>98.0%) + // Optional, vertical palette option (>98.0%) if (!Load_INI_get_values (file,buffer,"Palette_vertical",1,values)) { if ((values[0]<0) || (values[0]>1)) @@ -804,6 +804,22 @@ int Load_INI(T_Config * conf) conf->Window_pos_x = values[0]; conf->Window_pos_y = values[1]; } + + conf->Double_click_speed=500; + // Optional, speed of double-click (>98.0%) + if (!Load_INI_get_values (file,buffer,"Double_click_speed",1,values)) + { + if ((values[0]>0) || (values[0]<=2000)) + conf->Double_click_speed=values[0]; + } + + conf->Double_key_speed=500; + // Optional, speed of double-keypress (>98.0%) + if (!Load_INI_get_values (file,buffer,"Double_key_speed",1,values)) + { + if ((values[0]>0) || (values[0]<=2000)) + conf->Double_key_speed=values[0]; + } fclose(file); diff --git a/saveini.c b/saveini.c index ac8e53d3..975c9807 100644 --- a/saveini.c +++ b/saveini.c @@ -635,6 +635,13 @@ int Save_INI(T_Config * conf) if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,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))) + 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))) + goto Erreur_Retour; Save_INI_flush(Ancien_fichier,Nouveau_fichier,buffer); diff --git a/struct.h b/struct.h index 81f26b0d..ee1cf40d 100644 --- a/struct.h +++ b/struct.h @@ -269,6 +269,8 @@ typedef struct char Bookmark_label[NB_BOOKMARKS][8+1];///< Bookmarked directories in fileselectors: This is the displayed name. int Window_pos_x; ///< Last window x position (9999 if unsupportd/irrelevant for the platform) int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) + word Double_click_speed; ///< Maximum delay for double-click, in ms. + word Double_key_speed; ///< Maximum delay for double-keypress, in ms. } T_Config; // Structures utilisées pour les descriptions de pages et de liste de pages. From dad7e3d363701a0e159c593777191f2d026bec90 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 15 Jun 2009 18:41:36 +0000 Subject: [PATCH 05/95] Help for the quick translucency shortcuts. Fix a bug in Help where a hotkey highlight was on wrong position if an escaped character preceded it (The case never occured in 2.0) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@866 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- help.c | 14 ++++++++++++++ helpfile.h | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/help.c b/help.c index 456f4619..6070f98c 100644 --- a/help.c +++ b/help.c @@ -278,7 +278,21 @@ void Display_help(void) else if (line_type == 'K') { const char *hyperlink; + const char * escaped_percent_pos; + // Determine link position: link_position = strstr(line,"%s") - line; + // Adjust for any escaped %% that would precede it. + escaped_percent_pos = line; + do + { + escaped_percent_pos = strstr(escaped_percent_pos,"%%"); + if (escaped_percent_pos && escaped_percent_pos - line < link_position) + { + link_position--; + escaped_percent_pos+=2; + } + } while (escaped_percent_pos); + // hyperlink=Keyboard_shortcut_value(Help_section[Current_help_section].Help_table[start_line + line_index].Line_parameter); link_size=strlen(hyperlink); snprintf(buffer, 44, line, hyperlink); diff --git a/helpfile.h b/helpfile.h index 354cf234..51dba160 100644 --- a/helpfile.h +++ b/helpfile.h @@ -1535,6 +1535,24 @@ static const T_Help_table helptable_effects[] = HELP_TEXT ("paintbrush with the colors of the picture.") HELP_TEXT ("It's used to make transparency effects like") HELP_TEXT ("with watercolors.") + HELP_TEXT ("") + HELP_TEXT ("You can also use the following shortcuts to") + HELP_TEXT ("activate transparency mode and assign an") + HELP_TEXT ("amount of opacity:") + HELP_LINK (" 10%% : %s", SPECIAL_TRANSPARENCY_1) + HELP_LINK (" 20%% : %s", SPECIAL_TRANSPARENCY_2) + HELP_LINK (" 30%% : %s", SPECIAL_TRANSPARENCY_3) + HELP_LINK (" 40%% : %s", SPECIAL_TRANSPARENCY_4) + HELP_LINK (" 50%% : %s", SPECIAL_TRANSPARENCY_5) + HELP_LINK (" 60%% : %s", SPECIAL_TRANSPARENCY_6) + HELP_LINK (" 70%% : %s", SPECIAL_TRANSPARENCY_7) + HELP_LINK (" 80%% : %s", SPECIAL_TRANSPARENCY_8) + HELP_LINK (" 90%% : %s", SPECIAL_TRANSPARENCY_9) + HELP_LINK (" 100%% : %s", SPECIAL_TRANSPARENCY_0) + HELP_TEXT ("If you use two of these shortcuts quickly,") + HELP_TEXT ("the second will set the units for finer") + HELP_TEXT ("control. Ie: 4 6 makes 45%, 0 9 makes 9%.") + HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MODE) HELP_TEXT ("") From 04ff11c4d9663c3bc7c7fbb6ee4f82ada38a9b7e Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 15 Jun 2009 18:46:23 +0000 Subject: [PATCH 06/95] Fixed typo in previous commit git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@867 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- helpfile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpfile.h b/helpfile.h index 51dba160..405c5998 100644 --- a/helpfile.h +++ b/helpfile.h @@ -1551,7 +1551,7 @@ static const T_Help_table helptable_effects[] = HELP_LINK (" 100%% : %s", SPECIAL_TRANSPARENCY_0) HELP_TEXT ("If you use two of these shortcuts quickly,") HELP_TEXT ("the second will set the units for finer") - HELP_TEXT ("control. Ie: 4 6 makes 45%, 0 9 makes 9%.") + HELP_TEXT ("control. Ie: 4 5 makes 45%, 0 9 makes 9%.") HELP_TEXT ("") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MODE) From 2189d00ec4e82230a387ccba6390b5c8441541ff Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 15 Jun 2009 19:53:12 +0000 Subject: [PATCH 07/95] Merged buttons 'Grad rectangle' and 'Gradient menu' (issue 107) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@868 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 14 ++++++-------- const.h | 1 - engine.c | 6 ++++-- helpfile.h | 12 +++++------- hotkeys.c | 2 +- init.c | 14 +++----------- skins/base.gif | Bin 21880 -> 21862 bytes skins/ilkke.png | Bin 21172 -> 21169 bytes 8 files changed, 19 insertions(+), 30 deletions(-) diff --git a/buttons.c b/buttons.c index a06bb8a1..e21f464a 100644 --- a/buttons.c +++ b/buttons.c @@ -2073,7 +2073,7 @@ void Button_Gradients(void) default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { - Window_help(BUTTON_GRADMENU, NULL); + Window_help(BUTTON_GRADRECT, NULL); Key=0; break; } @@ -2082,7 +2082,10 @@ void Button_Gradients(void) while (clicked_button<6); Close_window(); - Unselect_button(BUTTON_GRADMENU); + // The Grad rect operation uses the same button as Grad menu. + if (Current_operation != OPERATION_GRAD_RECTANGLE) + Unselect_button(BUTTON_GRADRECT); + Display_cursor(); Gradient_pixel=Display_pixel; @@ -3804,12 +3807,7 @@ void Effects_off(void) Stencil_mode=0; Mask_mode=0; Sieve_mode=0; - Snap_mode=0; - - if (! Windows_open) - { - - } + Snap_mode=0; } void Transparency_set(byte amount) diff --git a/const.h b/const.h index 64c7dc6b..052efa6b 100644 --- a/const.h +++ b/const.h @@ -271,7 +271,6 @@ enum BUTTON_NUMBERS BUTTON_CIRCLES, BUTTON_FILLCIRC, BUTTON_GRADRECT, - BUTTON_GRADMENU, BUTTON_SPHERES, BUTTON_BRUSH, BUTTON_POLYBRUSH, diff --git a/engine.c b/engine.c index 70e31fa3..80262a69 100644 --- a/engine.c +++ b/engine.c @@ -75,8 +75,7 @@ char * Menu_tooltip[NB_BUTTONS]= "Filled rectangles ", "Empty circles / ellipses", "Filled circles / ellips.", - "Grad. rectangles ", - "Gradation menu ", + "Grad. rect / Grad. menu ", "Grad. spheres / ellipses", "Brush grab. / Restore ", "Lasso / Restore brush ", @@ -372,6 +371,9 @@ void Select_button(int btn_number,byte click) // the unselection of all "Tool" buttons. if (btn_number==BUTTON_ADJUST && click==RIGHT_SIDE) break; + // Same case with the Grad. Rectangle button. + if (btn_number==BUTTON_GRADRECT && click==RIGHT_SIDE) + break; // Pour chaque bouton: for (b=0; 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�-v;QAW(E!x|g)BpF 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 delta 20993 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 AH~;_u diff --git a/skins/ilkke.png b/skins/ilkke.png index 9de1b6f2a495dafe213a4c3d2a8061f8c8a54ac7..d0f72fa09c4eb03e51d857d1ab75a1ca9348a783 100644 GIT binary patch delta 19749 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 E0pkO)$N&HU delta 19749 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 Date: Mon, 15 Jun 2009 20:09:57 +0000 Subject: [PATCH 08/95] -Renomed skins. "base" becomes "classic", "ilkke" becomes "modern" (as I heard Ilkke is working on yet another skin...). -Converted them to png (base was a .gif but this is a bad format :)) -Changed dates in the splash screen to say coyright 2007-2009. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@869 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 10 ++++++---- buttons.c | 4 ++-- gfx2.cfg | Bin 10133 -> 10133 bytes main.c | 2 +- skins/base.gif | Bin 21862 -> 0 bytes skins/classic.png | Bin 0 -> 18907 bytes skins/{ilkke.png => modern.png} | Bin 7 files changed, 9 insertions(+), 7 deletions(-) delete mode 100644 skins/base.gif create mode 100644 skins/classic.png rename skins/{ilkke.png => modern.png} (100%) diff --git a/Makefile b/Makefile index 8a806aa9..5ff25b5f 100644 --- a/Makefile +++ b/Makefile @@ -240,9 +240,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" --transform 's,^,src/,g' *.c *.h Makefile Makefile.dep gfx2.ico - $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN) gfx2def.ini skins/base.gif gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt fonts/Tuffy.ttf src-`cat $(OBJDIR)/versiontag`.tgz $(PLATFORMFILES) + $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN) gfx2def.ini skins/modern.png skins/classic.png gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt fonts/Tuffy.ttf src-`cat $(OBJDIR)/versiontag`.tgz $(PLATFORMFILES) $(DELCOMMAND) "src-`cat $(OBJDIR)/versiontag`.tgz" - tar cvzf "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --transform 's,^,grafx2/,g' *.c *.h Makefile Makefile.dep gfx2def.ini skins/base.gif gfx2.ico gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt misc/grafx2.1 misc/grafx2.xpm misc/grafx2.desktop fonts/8pxfont.png fonts/Tuffy.ttf + tar cvzf "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --transform 's,^,grafx2/,g' *.c *.h Makefile Makefile.dep gfx2def.ini skins/modern.png skins/classic.png gfx2.ico gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt misc/grafx2.1 misc/grafx2.xpm misc/grafx2.desktop fonts/8pxfont.png fonts/Tuffy.ttf $(DELCOMMAND) "$(OBJDIR)/versiontag" testsed : @@ -303,7 +303,8 @@ install : $(BIN) $(CP) gfx2def.ini $(DESTDIR)$(datadir)/grafx2/ $(CP) gfx2.gif $(DESTDIR)$(datadir)/grafx2/ $(CP) fonts/* $(DESTDIR)$(datadir)/grafx2/fonts/ - $(CP) skins/base.gif $(DESTDIR)$(datadir)/grafx2/skins/ + $(CP) skins/modern.png $(DESTDIR)$(datadir)/grafx2/skins/ + $(CP) skins/classic.png $(DESTDIR)$(datadir)/grafx2/skins/ # Icon and desktop file for debian $(CP) misc/grafx2.desktop $(DESTDIR)$(datadir)/applications/ $(CP) misc/grafx2.xpm $(DESTDIR)$(datadir)/icons/ @@ -317,7 +318,8 @@ uninstall : $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/gfx2.gif $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/fonts/* $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/fonts),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/fonts) - $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/skins/base.gif + $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/skins/modern.png + $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/skins/classic.png $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/skins),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/skins) # Icon and desktop file for debian $(DELCOMMAND) $(DESTDIR)$(datadir)/applications/grafx2.desktop diff --git a/buttons.c b/buttons.c index e21f464a..3bdde17e 100644 --- a/buttons.c +++ b/buttons.c @@ -126,9 +126,9 @@ void Button_Message_initial(void) for (x=14,x_pos=0; x_pos<231; x_pos++,x++) Pixel_in_window(x,y,GFX_logo_grafx2[offs_y+x_pos]); - Print_in_window(130-4*21,88,"Copyright (c) 2007 by",MC_Dark,MC_Light); + Print_in_window(130-4*26,88,"Copyright (c) 2007-2009 by",MC_Dark,MC_Light); Print_in_window(130-4*23,96,"the Grafx2 project team",MC_Black,MC_Light); - Print_in_window(130-4*26,112,"Copyright (c) 1996-1999 by",MC_Dark,MC_Light); + Print_in_window(130-4*26,112,"Copyright (c) 1996-2001 by",MC_Dark,MC_Light); Print_in_window(130-4*13,120,"Sunset Design",MC_Black,MC_Light); //Print_in_window( 120-4*13,128,"(placeholder)",MC_Dark,MC_Light); Print_in_window(130-4*28,136,"http://grafx2.googlecode.com",MC_Dark,MC_Light); diff --git a/gfx2.cfg b/gfx2.cfg index 20ab6b6713f6e84640b9ae5bc2c16528704bffbb..6fdab707d525fcae06308336302177857354d994 100644 GIT binary patch delta 28 hcmbR0Kh=N35>;*?2?ijT1jI~}Cn_J`T&5<^2mo_|2Z#Uw delta 28 hcmbR0Kh=N35>;*ic?KYu1jI~}Cn_J`T&5<^2mo{52aNy# diff --git a/main.c b/main.c index 65ae2dea..3e27e223 100644 --- a/main.c +++ b/main.c @@ -76,7 +76,7 @@ #endif // filename for the current GUI skin file. -static char Gui_skin_file[MAX_PATH_CHARACTERS]= "skins" PATH_SEPARATOR "base.gif"; +static char Gui_skin_file[MAX_PATH_CHARACTERS]= "skins" PATH_SEPARATOR "modern.png"; //--- Affichage de la syntaxe, et de la liste des modes vidéos disponibles --- void Display_syntax(void) diff --git a/skins/base.gif b/skins/base.gif deleted file mode 100644 index ea993ea5a0a3d68b5a6a8e57a93982a3501cd5ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21862 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 diff --git a/skins/classic.png b/skins/classic.png new file mode 100644 index 0000000000000000000000000000000000000000..8de524a29ab04044a66ccd5df160210d7c4158ed GIT binary patch literal 18907 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 SevVpzG#!XIw68JzM8SU*=CLyX literal 0 HcmV?d00001 diff --git a/skins/ilkke.png b/skins/modern.png similarity index 100% rename from skins/ilkke.png rename to skins/modern.png From 62738a1526be3b2c85cb37d679c90aee40bcc0cb Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Mon, 15 Jun 2009 21:43:21 +0000 Subject: [PATCH 09/95] Begin of work on the file selector. Quite ugly, i tried to reuse code from the other fileselectors, but I failed. Basically, it works, but we can improve it a lot. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@870 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ buttons.h | 5 + engine.c | 2 +- init.c | 2 +- 4 files changed, 311 insertions(+), 2 deletions(-) diff --git a/buttons.c b/buttons.c index 3bdde17e..7484447c 100644 --- a/buttons.c +++ b/buttons.c @@ -51,6 +51,19 @@ #include "brush.h" #include "input.h" +#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) + #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 extern short Old_MX; @@ -963,6 +976,297 @@ void Button_Settings(void) } +void Display_skins_list(short offset_first, short selector_offset) +// +// offset_first = Décalage entre le premier fichier visible dans le +// sélecteur et le premier fichier de la liste +// +// selector_offset = Décalage entre le premier fichier visible dans le +// sélecteur et le fichier sélectionné dans la liste +// +{ + T_Fileselector_item * current_item; + byte index; // index du fichier qu'on affiche (0 -> 9) + byte text_color; + byte background_color; + + + // On vérifie s'il y a au moins 1 fichier dans la liste: + if (Filelist_nb_elements>0) + { + // On commence par chercher à pointer sur le premier fichier visible: + current_item=Filelist; + for (;offset_first>0;offset_first--) + current_item=current_item->Next; + + // Pour chacun des 10 éléments inscriptibles à l'écran + for (index=0;index<10;index++) + { + // S'il est sélectionné: + if (!selector_offset) + { + text_color=MC_White; + background_color=MC_Light; + } + else + { + text_color=MC_Light; + background_color=MC_Black; + } + + // On affiche l'élément + Print_in_window(8,17+index*8,current_item->Short_name,text_color,background_color); + + // On passe à la ligne suivante + selector_offset--; + current_item=current_item->Next; + if (!current_item) + break; + } // End de la boucle d'affichage + + } // End du test d'existence de fichiers +} + + + +/// Skin selector window +void Button_Skins(void) +{ + short clicked_button; + short temp; + char quicksearch_filename[MAX_PATH_CHARACTERS]=""; + char * most_matching_filename; + char skinsdir[MAX_PATH_CHARACTERS]; + DIR* Repertoire_Courant; //Répertoire courant + struct dirent* entry; // Structure de lecture des éléments + struct stat Infos_enreg; + char * current_path; + + T_Scroller_button * file_scroller; + + Open_window(178,120,"Skins"); + + // Ok button + Window_set_normal_button(6,102, 51,14,"OK" ,0,1,SDLK_RETURN); // 1 + + // Frame autour du fileselector + Window_display_frame_in(6,15,148,84); + + // Fileselector + Window_set_special_button(9,17,144,80); // 2 + + // Scroller du fileselector + file_scroller = Window_set_scroller_button(160,16,82,1,10,0); // 3 + + strcpy(skinsdir,Data_directory); + strcat(skinsdir,"skins"); + chdir(skinsdir); + getcwd(skinsdir,256); + + // Affichage des premiers fichiers visibles: + // Ensuite, on vide la liste actuelle: + Free_fileselector_list(); + // Après effacement, il ne reste ni fichier ni répertoire dans la liste + Filelist_nb_elements=0; + + // On lit tous les répertoires: + current_path=getcwd(NULL,0); + Repertoire_Courant=opendir(current_path); + while ((entry=readdir(Repertoire_Courant))) + { + stat(entry->d_name,&Infos_enreg); + if (S_ISREG(Infos_enreg.st_mode) && //Il s'agit d'un fichier + (Config.Show_hidden_files || //Il n'est pas caché + !isHidden(entry))) + { + // On rajoute le fichier à la liste + Add_element_to_list(entry->d_name, 0); + Filelist_nb_elements++; + } + } + + closedir(Repertoire_Courant); + free(current_path); + + Sort_list_of_files(); + + file_scroller->Nb_elements=Filelist_nb_elements; + file_scroller->Position=Main_fileselector_position; + Compute_slider_cursor_height(file_scroller); + Window_draw_slider(file_scroller); + // On efface les anciens noms de fichier: + Window_rectangle(8-1,15-1,144+2,80+2,MC_Black); + // On affiche les nouveaux: + Display_skins_list(Main_fileselector_position,Main_fileselector_offset); + + Update_window_area(0,0,Window_width, Window_height); + + Display_cursor(); + + do + { + clicked_button=Window_clicked_button(); + + switch(clicked_button) + { + case 2 : // Zone d'affichage de la liste de fichiers + Hide_cursor(); + + temp=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-95)>>3; + if (temp>=Filelist_nb_elements) + temp=Filelist_nb_elements-1; + if (temp>=0) + { + // On met à jour le décalage + Main_fileselector_offset=temp; + + // On affiche à nouveau la liste + Display_skins_list(Main_fileselector_position,Main_fileselector_offset); + + // On vient de changer de nom de fichier, donc on doit s'appreter + // a rafficher une preview + *quicksearch_filename=0; + } + Display_cursor(); + Wait_end_of_click(); + break; + + case 3 : // Scroller de fichiers + Hide_cursor(); + Main_fileselector_position=Window_attribute2; + // On affiche à nouveau la liste + Display_skins_list(Main_fileselector_position,Main_fileselector_offset); + Display_cursor(); + *quicksearch_filename=0; + break; + } + + switch (Key) + { + case SDLK_UNKNOWN : break; + /* + case SDLK_DOWN : // Bas + *quicksearch_filename=0; + Hide_cursor(); + Selector_scroll_down(&Main_fileselector_position,&Main_fileselector_offset); + if (file_scroller->Position!=Main_fileselector_position) + { + // Si c'est le cas, il faut mettre à jour la jauge + file_scroller->Position=Main_fileselector_position; + Window_draw_slider(file_scroller); + } + Key=0; + break; + case SDLK_UP : // Haut + *quicksearch_filename=0; + Hide_cursor(); + Selector_scroll_up(&Main_fileselector_position,&Main_fileselector_offset); + if (file_scroller->Position!=Main_fileselector_position) + { + // Si c'est le cas, il faut mettre à jour la jauge + file_scroller->Position=Main_fileselector_position; + Window_draw_slider(file_scroller); + } + Key=0; + break; + case SDLK_PAGEDOWN : // PageDown + case KEY_MOUSEWHEELDOWN : + *quicksearch_filename=0; + Hide_cursor(); + Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,9); + if (file_scroller->Position!=Main_fileselector_position) + { + // Si c'est le cas, il faut mettre à jour la jauge + file_scroller->Position=Main_fileselector_position; + Window_draw_slider(file_scroller); + } + Key=0; + break; + case SDLK_PAGEUP : // PageUp + case KEY_MOUSEWHEELUP : + *quicksearch_filename=0; + Hide_cursor(); + Selector_page_up(&Main_fileselector_position,&Main_fileselector_offset,9); + if (file_scroller->Position!=Main_fileselector_position) + { + // Si c'est le cas, il faut mettre à jour la jauge + file_scroller->Position=Main_fileselector_position; + Window_draw_slider(file_scroller); + } + Key=0; + break; + case SDLK_END : // End + *quicksearch_filename=0; + Hide_cursor(); + Selector_end(&Main_fileselector_position,&Main_fileselector_offset); + if (file_scroller->Position!=Main_fileselector_position) + { + // Si c'est le cas, il faut mettre à jour la jauge + file_scroller->Position=Main_fileselector_position; + Window_draw_slider(file_scroller); + } + Key=0; + break; + case SDLK_HOME : // Home + *quicksearch_filename=0; + Hide_cursor(); + Selector_home(&Main_fileselector_position,&Main_fileselector_offset); + if (file_scroller->Position!=Main_fileselector_position) + { + // Si c'est le cas, il faut mettre à jour la jauge + file_scroller->Position=Main_fileselector_position; + Window_draw_slider(file_scroller); + } + Key=0; + break; + */ + default: // Autre => On se place sur le nom de fichier qui correspond + if (clicked_button<=0) + { + if (Is_shortcut(Key,0x100+BUTTON_HELP)) + { + Window_help(BUTTON_SETTINGS, NULL); + break; + } + temp=strlen(quicksearch_filename); + if (Key_ANSI>= ' ' && Key_ANSI < 255 && temp<50) + { + quicksearch_filename[temp]=Key_ANSI; + quicksearch_filename[temp+1]='\0'; + most_matching_filename=Find_filename_match(quicksearch_filename); + if ( (most_matching_filename) ) + { + temp=Main_fileselector_position+Main_fileselector_offset; + Hide_cursor(); + Highlight_file(most_matching_filename); + 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; + } + } + else + *quicksearch_filename=0; + } + } + while ( (clicked_button!=1) && (Key!=SDLK_RETURN) ); + + strcpy(skinsdir,"skins/"); + Get_selected_item(Main_fileselector_position,Main_fileselector_offset,skinsdir+6,NULL); + Load_graphics(skinsdir); + + Close_window(); + Unselect_button(BUTTON_SETTINGS); + // Raffichage du menu pour que les inscriptions qui y figurent soient retracées avec la nouvelle fonte + Display_menu(); + Display_cursor(); +} + + //---------------------------- Changement de page ---------------------------- void Button_Page(void) { diff --git a/buttons.h b/buttons.h index 8b87fc9b..4e109c83 100644 --- a/buttons.h +++ b/buttons.h @@ -579,6 +579,11 @@ void Button_Autosave(void); */ void Button_Settings(void); +/*! + Display the skin selector window. +*/ +void Button_Skins(void); + // Annulation de la dernière modification /*! diff --git a/engine.c b/engine.c index 80262a69..76635d36 100644 --- a/engine.c +++ b/engine.c @@ -88,7 +88,7 @@ char * Menu_tooltip[NB_BUTTONS]= "Go / Copy to other page ", "Save as / Save ", "Load / Re-load ", - "Settings ", + "Settings / Skins ", "Clear / with backcolor ", "Help / Statistics ", "Undo / Redo ", diff --git a/init.c b/init.c index ddb06ecb..8d7f1ccb 100644 --- a/init.c +++ b/init.c @@ -1026,7 +1026,7 @@ void Init_buttons(void) 178,18, 16,16, BUTTON_SHAPE_RECTANGLE, - Button_Settings,Button_Settings, + Button_Settings,Button_Skins, Do_nothing, FAMILY_INSTANT); From 1b2fa69f6a6dde06e3d5c705c1ebd5e35c486855 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 16 Jun 2009 19:43:37 +0000 Subject: [PATCH 10/95] GUi skin elements are allocated on the heap git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@871 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 29 ++--- const.h | 6 +- engine.c | 32 ++--- global.h | 59 +--------- help.c | 18 +-- init.c | 347 +++++++++++++++++++++++++++--------------------------- init.h | 2 +- main.c | 25 ++-- palette.c | 6 +- struct.h | 71 +++++++++++ windows.c | 82 ++++++------- 11 files changed, 350 insertions(+), 327 deletions(-) diff --git a/buttons.c b/buttons.c index 7484447c..b328c41e 100644 --- a/buttons.c +++ b/buttons.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "const.h" @@ -137,7 +138,7 @@ void Button_Message_initial(void) Menu_factor_X*237,Menu_factor_Y*60,MC_Black); for (y=23,offs_y=0; y<79; offs_y+=231,y++) for (x=14,x_pos=0; x_pos<231; x_pos++,x++) - Pixel_in_window(x,y,GFX_logo_grafx2[offs_y+x_pos]); + Pixel_in_window(x,y,Gfx->Logo_grafx2[offs_y+x_pos]); Print_in_window(130-4*26,88,"Copyright (c) 2007-2009 by",MC_Dark,MC_Light); Print_in_window(130-4*23,96,"the Grafx2 project team",MC_Black,MC_Light); @@ -958,9 +959,9 @@ void Button_Settings(void) // Font selection if (Config.Font) - Menu_font=GFX_fun_font; + Menu_font=Gfx->Fun_font; else - Menu_font=GFX_system_font; + Menu_font=Gfx->System_font; if (config_is_reloaded) Compute_optimal_menu_colors(Main_palette); @@ -1257,7 +1258,7 @@ void Button_Skins(void) strcpy(skinsdir,"skins/"); Get_selected_item(Main_fileselector_position,Main_fileselector_offset,skinsdir+6,NULL); - Load_graphics(skinsdir); + Load_graphics(Gfx, skinsdir); Close_window(); Unselect_button(BUTTON_SETTINGS); @@ -2519,15 +2520,15 @@ void Button_Paintbrush_menu(void) if (clicked_button!=1) // pas Cancel { index=clicked_button-2; - Paintbrush_shape=Paintbrush_type[index]; - Paintbrush_width=Preset_paintbrush_width[index]; - Paintbrush_height=Preset_paintbrush_height[index]; - Paintbrush_offset_X=Preset_paintbrush_offset_X[index]; - Paintbrush_offset_Y=Preset_paintbrush_offset_Y[index]; + 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]); } Unselect_button(BUTTON_PAINTBRUSHES); @@ -4617,7 +4618,7 @@ void Draw_preset_sieve_patterns(void) for (i=0; i<16*Menu_factor_X/Zoom; i++) Block(((index*23+10)*Menu_factor_X)+i*Zoom+Window_pos_X, (22*Menu_factor_Y)+j*Zoom+Window_pos_Y,Zoom,Zoom, - ((GFX_sieve_pattern[index][j&0xF]>>(15-(i&0xF)))&1)?MC_White:MC_Black); + ((Gfx->Sieve_pattern[index][j&0xF]>>(15-(i&0xF)))&1)?MC_White:MC_Black); Update_rect(ToWinX(10),ToWinY(22),ToWinL(12*23+16),ToWinH(16)); } @@ -4629,7 +4630,7 @@ void Copy_preset_sieve(byte index) for (j=0; j<16; j++) for (i=0; i<16; i++) - Sieve[i][j]=(GFX_sieve_pattern[index][j]>>(15-i))&1; + Sieve[i][j]=(Gfx->Sieve_pattern[index][j]>>(15-i))&1; Sieve_width=16; Sieve_height=16; } @@ -5057,7 +5058,7 @@ void Display_effect_sprite(short sprite_number, short start_x, short start_y) 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); } diff --git a/const.h b/const.h index 052efa6b..6c604d5c 100644 --- a/const.h +++ b/const.h @@ -58,9 +58,9 @@ #define DEFAULT_ZOOM_FACTOR 4 ///< Initial zoom factor for the magnifier. #define MAX_PATH_CHARACTERS 260 ///< Number of characters for a file+complete path. Adapt to your OS... #define NB_BOOKMARKS 4 ///< Number of bookmark buttons in Save/Load screen. -// Character to show a right arrow, used when editing long strings. It's present in ::GFX_system_font +// Character to show a right arrow, used when editing long strings. It's present in ::Gfx->System_font #define RIGHT_TRIANGLE_CHARACTER 16 -// Character to show a left arrow, used when editing long strings. It's present in ::GFX_system_font +// Character to show a left arrow, used when editing long strings. It's present in ::Gfx->System_font #define LEFT_TRIANGLE_CHARACTER 17 /// Character to display in menus for an ellipsis. #define ELLIPSIS_CHARACTER '…' @@ -241,7 +241,7 @@ enum CHUNKS_CFG CHUNK_MAX }; -/// Identifiers for the 8x8 icons of ::GFX_icon_sprite (these are unused now) +/// Identifiers for the 8x8 icons of ::Gfx->Icon_sprite (most are unused now) enum ICON_TYPES { ICON_FLOPPY_3_5=0, ///< 3½" Floppy disk diff --git a/engine.c b/engine.c index 76635d36..2a7f3546 100644 --- a/engine.c +++ b/engine.c @@ -210,74 +210,74 @@ void Draw_menu_button_frame(byte btn_number,byte pressed) case BUTTON_SHAPE_RECTANGLE : // On colorie le point haut droit Pixel_in_menu(end_x,start_y,color_diagonal); - GFX_menu_block[start_y][end_x]=color_diagonal; + Gfx->Menu_block[start_y][end_x]=color_diagonal; // On colorie le point bas gauche Pixel_in_menu(start_x,end_y,color_diagonal); - GFX_menu_block[end_y][start_x]=color_diagonal; + Gfx->Menu_block[end_y][start_x]=color_diagonal; // On colorie la partie haute for (x_pos=start_x;x_pos<=end_x-1;x_pos++) { Pixel_in_menu(x_pos,start_y,color_top_left); - GFX_menu_block[start_y][x_pos]=color_top_left; + Gfx->Menu_block[start_y][x_pos]=color_top_left; } for (y_pos=start_y+1;y_pos<=end_y-1;y_pos++) { // On colorie la partie gauche Pixel_in_menu(start_x,y_pos,color_top_left); - GFX_menu_block[y_pos][start_x]=color_top_left; + Gfx->Menu_block[y_pos][start_x]=color_top_left; // On colorie la partie droite Pixel_in_menu(end_x,y_pos,color_bottom_right); - GFX_menu_block[y_pos][end_x]=color_bottom_right; + Gfx->Menu_block[y_pos][end_x]=color_bottom_right; } // On colorie la partie basse for (x_pos=start_x+1;x_pos<=end_x;x_pos++) { Pixel_in_menu(x_pos,end_y,color_bottom_right); - GFX_menu_block[end_y][x_pos]=color_bottom_right; + Gfx->Menu_block[end_y][x_pos]=color_bottom_right; } break; case BUTTON_SHAPE_TRIANGLE_TOP_LEFT: // On colorie le point haut droit Pixel_in_menu(end_x,start_y,color_diagonal); - GFX_menu_block[start_y][end_x]=color_diagonal; + Gfx->Menu_block[start_y][end_x]=color_diagonal; // On colorie le point bas gauche Pixel_in_menu(start_x,end_y,color_diagonal); - GFX_menu_block[end_y][start_x]=color_diagonal; + Gfx->Menu_block[end_y][start_x]=color_diagonal; // On colorie le coin haut gauche for (x_pos=0;x_posMenu_block[start_y][start_x+x_pos]=color_top_left; Pixel_in_menu(start_x,start_y+x_pos,color_top_left); - GFX_menu_block[start_y+x_pos][start_x]=color_top_left; + Gfx->Menu_block[start_y+x_pos][start_x]=color_top_left; } // On colorie la diagonale for (x_pos=1;x_posMenu_block[end_y-x_pos][start_x+x_pos]=color_bottom_right; } break; case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT: // On colorie le point haut droit Pixel_in_menu(end_x,start_y,color_diagonal); - GFX_menu_block[start_y][end_x]=color_diagonal; + Gfx->Menu_block[start_y][end_x]=color_diagonal; // On colorie le point bas gauche Pixel_in_menu(start_x,end_y,color_diagonal); - GFX_menu_block[end_y][start_x]=color_diagonal; + Gfx->Menu_block[end_y][start_x]=color_diagonal; // On colorie la diagonale for (x_pos=1;x_posMenu_block[end_y-x_pos][start_x+x_pos]=color_top_left; } // On colorie le coin bas droite for (x_pos=0;x_posMenu_block[end_y][end_x-x_pos]=color_bottom_right; Pixel_in_menu(end_x,end_y-x_pos,color_bottom_right); - GFX_menu_block[end_y-x_pos][end_x]=color_bottom_right; + Gfx->Menu_block[end_y-x_pos][end_x]=color_bottom_right; } } if (Menu_is_visible) diff --git a/global.h b/global.h index 89b3eb00..1e4b6150 100644 --- a/global.h +++ b/global.h @@ -63,9 +63,6 @@ GFX2_GLOBAL T_Video_mode Video_mode[MAX_VIDEO_MODES]; /// Actual number of video modes in ::Video_mode. GFX2_GLOBAL int Nb_video_modes; -/// A default 256-color palette. -GFX2_GLOBAL T_Palette Default_palette; - // -- Menu colors GFX2_GLOBAL byte MC_Black; ///< Index of color to use as "black" in the GUI menus. @@ -139,12 +136,6 @@ GFX2_GLOBAL byte Cursor_hidden; GFX2_GLOBAL byte Cursor_in_menu; /// Boolean, means the cursor was hovering over a menu GUI element. GFX2_GLOBAL byte Cursor_in_menu_previous; -/// X coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_WIDTH -GFX2_GLOBAL word Cursor_offset_X[NB_CURSOR_SPRITES]; -/// Y coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_HEIGHT -GFX2_GLOBAL word Cursor_offset_Y[NB_CURSOR_SPRITES]; -/// Graphic resources for the mouse cursor. -GFX2_GLOBAL byte GFX_cursor_sprite[NB_CURSOR_SPRITES][CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; /// Storage for the graphics under the mouse cursor. Used by ::Hide_cursor and ::Display_cursor GFX2_GLOBAL byte CURSOR_BACKGROUND[CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; @@ -164,18 +155,6 @@ GFX2_GLOBAL byte Paintbrush_hidden; GFX2_GLOBAL short Paintbrush_X; /// Cordinate of the preview paintbrush in image space. GFX2_GLOBAL short Paintbrush_Y; -/// Graphic resources for the preset paintbrushes. -GFX2_GLOBAL byte GFX_paintbrush_sprite [NB_PAINTBRUSH_SPRITES][PAINTBRUSH_HEIGHT][PAINTBRUSH_WIDTH]; -/// Width of the preset paintbrushes. -GFX2_GLOBAL word Preset_paintbrush_width[NB_PAINTBRUSH_SPRITES]; -/// Height of the preset paintbrushes. -GFX2_GLOBAL word Preset_paintbrush_height[NB_PAINTBRUSH_SPRITES]; -/// Type of the preset paintbrush: index in enum PAINTBRUSH_SHAPES -GFX2_GLOBAL byte Paintbrush_type[NB_PAINTBRUSH_SPRITES]; -/// Brush handle for the preset brushes. Generally ::Preset_paintbrush_width[]/2 -GFX2_GLOBAL word Preset_paintbrush_offset_X[NB_PAINTBRUSH_SPRITES]; -/// Brush handle for the preset brushes. Generally ::Preset_paintbrush_height[]/2 -GFX2_GLOBAL word Preset_paintbrush_offset_Y[NB_PAINTBRUSH_SPRITES]; /// Pixel data of the current brush GFX2_GLOBAL byte * Paintbrush_sprite; /// Current paintbrush's width @@ -675,8 +654,6 @@ GFX2_GLOBAL word Snap_offset_Y; GFX2_GLOBAL byte Sieve_mode; /// Sprite of the sieve pattern. It's actually an array of booleans. GFX2_GLOBAL byte Sieve[16][16]; -/// Preset sieve patterns, stored as binary (one word per line) -GFX2_GLOBAL word GFX_sieve_pattern[12][16]; /// Width of the sieve pattern, in Sieve mode. GFX2_GLOBAL short Sieve_width; /// Height of the sieve pattern, in Sieve mode. @@ -810,40 +787,14 @@ GFX2_GLOBAL byte File_in_command_line; /// Boolean, true if Grafx2 was run with a command-line argument to set a resolution on startup (overrides config) GFX2_GLOBAL byte Resolution_in_command_line; -// - Graphic skin data +// - Graphic -/// Bitmap data for the menu, a single rectangle. -GFX2_GLOBAL byte GFX_menu_block[MENU_HEIGHT][MENU_WIDTH]; -/// Bitmap data for the icons that are displayed over the menu. -GFX2_GLOBAL byte GFX_menu_sprite[NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; -/// Bitmap data for the different "effects" icons. -GFX2_GLOBAL byte GFX_effect_sprite[NB_EFFECTS_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; -/// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. -GFX2_GLOBAL byte * GFX_logo_grafx2; -/// Bitmap data for the classic 8x8 font used in menus etc. -GFX2_GLOBAL byte GFX_system_font[256*8*8]; -/// Bitmap data for the "fun" 8x8 font used in menus etc. -GFX2_GLOBAL byte GFX_fun_font [256*8*8]; -/// Bitmap data for the 6x8 font used in help screens. -GFX2_GLOBAL byte GFX_help_font_norm [256][6][8]; -/// Bitmap data for the 6x8 font used in help screens ("bold" verstion). -GFX2_GLOBAL byte GFX_bold_font [256][6][8]; -// 12 -// 34 -/// Bitmap data for the title font used in help screens. Top-left quarter. -GFX2_GLOBAL byte GFX_help_font_t1 [64][6][8]; -/// Bitmap data for the title font used in help screens. Top-right quarter. -GFX2_GLOBAL byte GFX_help_font_t2 [64][6][8]; -/// Bitmap data for the title font used in help screens. Bottom-left quarter. -GFX2_GLOBAL byte GFX_help_font_t3 [64][6][8]; -/// Bitmap data for the title font used in help screens. Bottom-right quarter. -GFX2_GLOBAL byte GFX_help_font_t4 [64][6][8]; -/// Bitmap data for the small 8x8 icons. -GFX2_GLOBAL byte GFX_icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; - -/// Pointer to the font selected for menus. It's either ::GFX_system_font or ::GFX_fun_font +/// Pointer to the font selected for menus. It's either ::Gfx->System_font or ::Gfx->Fun_font GFX2_GLOBAL byte * Menu_font; +/// Pointer to the current active skin. +GFX2_GLOBAL T_Gui_skin * Gfx; + // -- Help data /// Index of the ::Help_section shown by the Help screen. diff --git a/help.c b/help.c index 6070f98c..c8291ea7 100644 --- a/help.c +++ b/help.c @@ -323,27 +323,27 @@ void Display_help(void) if (line_type=='T') { if (line[char_index/2]>'_' || line[char_index/2]<' ') - char_pixel=&(GFX_help_font_norm['!'][0][0]); // Caractère pas géré + 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]); + 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]); + 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é + 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]); + 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]); + 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]); + 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]); + 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 + 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_factorCursor_offset_X[cursor_number]=14-start_x; + gfx->Cursor_offset_Y[cursor_number]=14-start_y; for (y=0;yCursor_sprite[cursor_number][y][x]=cursor_buffer[(start_y+y)*29+start_x+x]; } -void Load_graphics(const char * skin_file) +void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { int index; char filename[MAX_PATH_CHARACTERS]; @@ -275,9 +272,9 @@ void Load_graphics(const char * skin_file) // Lecture de la palette par défaut for (i=0; i<256; i++) { - Default_palette[i].R=SDLPal->colors[i].r; - Default_palette[i].G=SDLPal->colors[i].g; - Default_palette[i].B=SDLPal->colors[i].b; + gfx->Default_palette[i].R=SDLPal->colors[i].r; + gfx->Default_palette[i].G=SDLPal->colors[i].g; + gfx->Default_palette[i].B=SDLPal->colors[i].b; } // Carré "noir" @@ -353,7 +350,7 @@ void Load_graphics(const char * skin_file) // Menu GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu"); - Read_GUI_block(gui, cursor_x, cursor_y, GFX_menu_block, MENU_WIDTH, MENU_HEIGHT,"menu",0); + Read_GUI_block(gui, cursor_x, cursor_y, gfx->Menu_block, MENU_WIDTH, MENU_HEIGHT,"menu",0); cursor_y+=MENU_HEIGHT; // Effets @@ -363,7 +360,7 @@ void Load_graphics(const char * skin_file) GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "effect sprite"); else GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "effect sprite"); - Read_GUI_block(gui, cursor_x, cursor_y, GFX_effect_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "effect sprite",0); + Read_GUI_block(gui, cursor_x, cursor_y, gfx->Effect_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "effect sprite",0); cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; @@ -376,7 +373,7 @@ void Load_graphics(const char * skin_file) else GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "mouse cursor"); Read_GUI_block(gui, cursor_x, cursor_y, mouse_cursor_area, 29, 29, "mouse cursor",1); - Center_GUI_cursor((byte *)mouse_cursor_area,i); + Center_GUI_cursor(gfx, (byte *)mouse_cursor_area,i); cursor_x+=29; } cursor_y+=29; @@ -388,7 +385,7 @@ void Load_graphics(const char * skin_file) GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu sprite"); else GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "menu sprite"); - Read_GUI_block(gui, cursor_x, cursor_y, GFX_menu_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1); + Read_GUI_block(gui, cursor_x, cursor_y, gfx->Menu_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1); cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; @@ -407,7 +404,7 @@ void Load_graphics(const char * skin_file) { GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "brush icon"); } - Read_GUI_block(gui, cursor_x, cursor_y, GFX_paintbrush_sprite[i], PAINTBRUSH_WIDTH, PAINTBRUSH_HEIGHT, "brush icon",2); + Read_GUI_block(gui, cursor_x, cursor_y, gfx->Paintbrush_sprite[i], PAINTBRUSH_WIDTH, PAINTBRUSH_HEIGHT, "brush icon",2); cursor_x+=PAINTBRUSH_WIDTH; } cursor_y+=PAINTBRUSH_HEIGHT; @@ -419,17 +416,17 @@ void Load_graphics(const char * skin_file) GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "sprite drive"); else GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "sprite drive"); - Read_GUI_block(gui, cursor_x, cursor_y, GFX_icon_sprite[i], ICON_SPRITE_WIDTH, ICON_SPRITE_HEIGHT, "sprite drive",1); + Read_GUI_block(gui, cursor_x, cursor_y, gfx->Icon_sprite[i], ICON_SPRITE_WIDTH, ICON_SPRITE_HEIGHT, "sprite drive",1); cursor_x+=ICON_SPRITE_WIDTH; } cursor_y+=ICON_SPRITE_HEIGHT; // Logo splash screen - if (!(GFX_logo_grafx2=(byte *)malloc(231*56))) + if (!(gfx->Logo_grafx2=(byte *)malloc(231*56))) Error(ERROR_MEMORY); GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "logo menu"); - Read_GUI_block(gui, cursor_x, cursor_y, GFX_logo_grafx2, 231, 56, "logo menu",3); + Read_GUI_block(gui, cursor_x, cursor_y, gfx->Logo_grafx2, 231, 56, "logo menu",3); cursor_y+=56; // Trames @@ -439,7 +436,7 @@ void Load_graphics(const char * skin_file) GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "sieve pattern"); else GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "sieve pattern"); - Read_GUI_pattern(gui, cursor_x, cursor_y, GFX_sieve_pattern[i],"sieve pattern"); + Read_GUI_pattern(gui, cursor_x, cursor_y, gfx->Sieve_pattern[i],"sieve pattern"); cursor_x+=16; } cursor_y+=16; @@ -458,11 +455,11 @@ void Load_graphics(const char * skin_file) { GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "system font"); } - Read_GUI_block(gui, cursor_x, cursor_y, &GFX_system_font[i*64], 8, 8, "system font",2); + Read_GUI_block(gui, cursor_x, cursor_y, &gfx->System_font[i*64], 8, 8, "system font",2); cursor_x+=8; } cursor_y+=8; - Menu_font=GFX_system_font; + Menu_font=gfx->System_font; // Font Fun for (i=0; i<256; i++) @@ -478,7 +475,7 @@ void Load_graphics(const char * skin_file) { GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "fun font"); } - Read_GUI_block(gui, cursor_x, cursor_y, &GFX_fun_font[i*64], 8, 8, "fun font",2); + Read_GUI_block(gui, cursor_x, cursor_y, &gfx->Fun_font[i*64], 8, 8, "fun font",2); cursor_x+=8; } cursor_y+=8; @@ -497,7 +494,7 @@ void Load_graphics(const char * skin_file) { GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (norm)"); } - Read_GUI_block(gui, cursor_x, cursor_y, &(GFX_help_font_norm[i][0][0]), 6, 8, "help font (norm)",0); + Read_GUI_block(gui, cursor_x, cursor_y, &(gfx->Help_font_norm[i][0][0]), 6, 8, "help font (norm)",0); cursor_x+=6; } cursor_y+=8; @@ -516,7 +513,7 @@ void Load_graphics(const char * skin_file) { GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (bold)"); } - Read_GUI_block(gui, cursor_x, cursor_y, &(GFX_bold_font[i][0][0]), 6, 8, "help font (bold)",0); + Read_GUI_block(gui, cursor_x, cursor_y, &(gfx->Bold_font[i][0][0]), 6, 8, "help font (bold)",0); cursor_x+=6; } cursor_y+=8; @@ -539,14 +536,14 @@ void Load_graphics(const char * skin_file) if (i&1) if (i&64) - dest=&(GFX_help_font_t4[char_4++][0][0]); + dest=&(gfx->Help_font_t4[char_4++][0][0]); else - dest=&(GFX_help_font_t2[char_2++][0][0]); + dest=&(gfx->Help_font_t2[char_2++][0][0]); else if (i&64) - dest=&(GFX_help_font_t3[char_3++][0][0]); + dest=&(gfx->Help_font_t3[char_3++][0][0]); else - dest=&(GFX_help_font_t1[char_1++][0][0]); + dest=&(gfx->Help_font_t1[char_1++][0][0]); Read_GUI_block(gui, cursor_x, cursor_y, dest, 6, 8, "help font (title)",0); cursor_x+=6; @@ -559,202 +556,202 @@ void Load_graphics(const char * skin_file) Current_help_section=0; Help_position=0; - Preset_paintbrush_width[ 0]= 1; - Preset_paintbrush_height[ 0]= 1; - Paintbrush_type [ 0]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 0]= 1; + gfx->Preset_paintbrush_height[ 0]= 1; + gfx->Paintbrush_type [ 0]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 1]= 2; - Preset_paintbrush_height[ 1]= 2; - Paintbrush_type [ 1]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 1]= 2; + gfx->Preset_paintbrush_height[ 1]= 2; + gfx->Paintbrush_type [ 1]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 2]= 3; - Preset_paintbrush_height[ 2]= 3; - Paintbrush_type [ 2]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 2]= 3; + gfx->Preset_paintbrush_height[ 2]= 3; + gfx->Paintbrush_type [ 2]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 3]= 4; - Preset_paintbrush_height[ 3]= 4; - Paintbrush_type [ 3]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 3]= 4; + gfx->Preset_paintbrush_height[ 3]= 4; + gfx->Paintbrush_type [ 3]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 4]= 5; - Preset_paintbrush_height[ 4]= 5; - Paintbrush_type [ 4]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 4]= 5; + gfx->Preset_paintbrush_height[ 4]= 5; + gfx->Paintbrush_type [ 4]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 5]= 7; - Preset_paintbrush_height[ 5]= 7; - Paintbrush_type [ 5]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 5]= 7; + gfx->Preset_paintbrush_height[ 5]= 7; + gfx->Paintbrush_type [ 5]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 6]= 8; - Preset_paintbrush_height[ 6]= 8; - Paintbrush_type [ 6]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 6]= 8; + gfx->Preset_paintbrush_height[ 6]= 8; + gfx->Paintbrush_type [ 6]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 7]=12; - Preset_paintbrush_height[ 7]=12; - Paintbrush_type [ 7]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 7]=12; + gfx->Preset_paintbrush_height[ 7]=12; + gfx->Paintbrush_type [ 7]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 8]=16; - Preset_paintbrush_height[ 8]=16; - Paintbrush_type [ 8]=PAINTBRUSH_SHAPE_SQUARE; + gfx->Preset_paintbrush_width [ 8]=16; + gfx->Preset_paintbrush_height[ 8]=16; + gfx->Paintbrush_type [ 8]=PAINTBRUSH_SHAPE_SQUARE; - Preset_paintbrush_width[ 9]=16; - Preset_paintbrush_height[ 9]=16; - Paintbrush_type [ 9]=PAINTBRUSH_SHAPE_SIEVE_SQUARE; + gfx->Preset_paintbrush_width [ 9]=16; + gfx->Preset_paintbrush_height[ 9]=16; + gfx->Paintbrush_type [ 9]=PAINTBRUSH_SHAPE_SIEVE_SQUARE; - Preset_paintbrush_width[10]=15; - Preset_paintbrush_height[10]=15; - Paintbrush_type [10]=PAINTBRUSH_SHAPE_DIAMOND; + gfx->Preset_paintbrush_width [10]=15; + gfx->Preset_paintbrush_height[10]=15; + gfx->Paintbrush_type [10]=PAINTBRUSH_SHAPE_DIAMOND; - Preset_paintbrush_width[11]= 5; - Preset_paintbrush_height[11]= 5; - Paintbrush_type [11]=PAINTBRUSH_SHAPE_DIAMOND; + gfx->Preset_paintbrush_width [11]= 5; + gfx->Preset_paintbrush_height[11]= 5; + gfx->Paintbrush_type [11]=PAINTBRUSH_SHAPE_DIAMOND; - Preset_paintbrush_width[12]= 3; - Preset_paintbrush_height[12]= 3; - Paintbrush_type [12]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [12]= 3; + gfx->Preset_paintbrush_height[12]= 3; + gfx->Paintbrush_type [12]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[13]= 4; - Preset_paintbrush_height[13]= 4; - Paintbrush_type [13]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [13]= 4; + gfx->Preset_paintbrush_height[13]= 4; + gfx->Paintbrush_type [13]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[14]= 5; - Preset_paintbrush_height[14]= 5; - Paintbrush_type [14]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [14]= 5; + gfx->Preset_paintbrush_height[14]= 5; + gfx->Paintbrush_type [14]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[15]= 6; - Preset_paintbrush_height[15]= 6; - Paintbrush_type [15]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [15]= 6; + gfx->Preset_paintbrush_height[15]= 6; + gfx->Paintbrush_type [15]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[16]= 8; - Preset_paintbrush_height[16]= 8; - Paintbrush_type [16]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [16]= 8; + gfx->Preset_paintbrush_height[16]= 8; + gfx->Paintbrush_type [16]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[17]=10; - Preset_paintbrush_height[17]=10; - Paintbrush_type [17]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [17]=10; + gfx->Preset_paintbrush_height[17]=10; + gfx->Paintbrush_type [17]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[18]=12; - Preset_paintbrush_height[18]=12; - Paintbrush_type [18]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [18]=12; + gfx->Preset_paintbrush_height[18]=12; + gfx->Paintbrush_type [18]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[19]=14; - Preset_paintbrush_height[19]=14; - Paintbrush_type [19]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [19]=14; + gfx->Preset_paintbrush_height[19]=14; + gfx->Paintbrush_type [19]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[20]=16; - Preset_paintbrush_height[20]=16; - Paintbrush_type [20]=PAINTBRUSH_SHAPE_ROUND; + gfx->Preset_paintbrush_width [20]=16; + gfx->Preset_paintbrush_height[20]=16; + gfx->Paintbrush_type [20]=PAINTBRUSH_SHAPE_ROUND; - Preset_paintbrush_width[21]=15; - Preset_paintbrush_height[21]=15; - Paintbrush_type [21]=PAINTBRUSH_SHAPE_SIEVE_ROUND; + gfx->Preset_paintbrush_width [21]=15; + gfx->Preset_paintbrush_height[21]=15; + gfx->Paintbrush_type [21]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - Preset_paintbrush_width[22]=11; - Preset_paintbrush_height[22]=11; - Paintbrush_type [22]=PAINTBRUSH_SHAPE_SIEVE_ROUND; + gfx->Preset_paintbrush_width [22]=11; + gfx->Preset_paintbrush_height[22]=11; + gfx->Paintbrush_type [22]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - Preset_paintbrush_width[23]= 5; - Preset_paintbrush_height[23]= 5; - Paintbrush_type [23]=PAINTBRUSH_SHAPE_SIEVE_ROUND; + gfx->Preset_paintbrush_width [23]= 5; + gfx->Preset_paintbrush_height[23]= 5; + gfx->Paintbrush_type [23]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - Preset_paintbrush_width[24]= 2; - Preset_paintbrush_height[24]= 1; - Paintbrush_type [24]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; + gfx->Preset_paintbrush_width [24]= 2; + gfx->Preset_paintbrush_height[24]= 1; + gfx->Paintbrush_type [24]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - Preset_paintbrush_width[25]= 3; - Preset_paintbrush_height[25]= 1; - Paintbrush_type [25]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; + gfx->Preset_paintbrush_width [25]= 3; + gfx->Preset_paintbrush_height[25]= 1; + gfx->Paintbrush_type [25]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - Preset_paintbrush_width[26]= 4; - Preset_paintbrush_height[26]= 1; - Paintbrush_type [26]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; + gfx->Preset_paintbrush_width [26]= 4; + gfx->Preset_paintbrush_height[26]= 1; + gfx->Paintbrush_type [26]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - Preset_paintbrush_width[27]= 8; - Preset_paintbrush_height[27]= 1; - Paintbrush_type [27]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; + gfx->Preset_paintbrush_width [27]= 8; + gfx->Preset_paintbrush_height[27]= 1; + gfx->Paintbrush_type [27]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - Preset_paintbrush_width[28]= 1; - Preset_paintbrush_height[28]= 2; - Paintbrush_type [28]=PAINTBRUSH_SHAPE_VERTICAL_BAR; + gfx->Preset_paintbrush_width [28]= 1; + gfx->Preset_paintbrush_height[28]= 2; + gfx->Paintbrush_type [28]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - Preset_paintbrush_width[29]= 1; - Preset_paintbrush_height[29]= 3; - Paintbrush_type [29]=PAINTBRUSH_SHAPE_VERTICAL_BAR; + gfx->Preset_paintbrush_width [29]= 1; + gfx->Preset_paintbrush_height[29]= 3; + gfx->Paintbrush_type [29]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - Preset_paintbrush_width[30]= 1; - Preset_paintbrush_height[30]= 4; - Paintbrush_type [30]=PAINTBRUSH_SHAPE_VERTICAL_BAR; + gfx->Preset_paintbrush_width [30]= 1; + gfx->Preset_paintbrush_height[30]= 4; + gfx->Paintbrush_type [30]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - Preset_paintbrush_width[31]= 1; - Preset_paintbrush_height[31]= 8; - Paintbrush_type [31]=PAINTBRUSH_SHAPE_VERTICAL_BAR; + gfx->Preset_paintbrush_width [31]= 1; + gfx->Preset_paintbrush_height[31]= 8; + gfx->Paintbrush_type [31]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - Preset_paintbrush_width[32]= 3; - Preset_paintbrush_height[32]= 3; - Paintbrush_type [32]=PAINTBRUSH_SHAPE_CROSS; + gfx->Preset_paintbrush_width [32]= 3; + gfx->Preset_paintbrush_height[32]= 3; + gfx->Paintbrush_type [32]=PAINTBRUSH_SHAPE_CROSS; - Preset_paintbrush_width[33]= 5; - Preset_paintbrush_height[33]= 5; - Paintbrush_type [33]=PAINTBRUSH_SHAPE_CROSS; + gfx->Preset_paintbrush_width [33]= 5; + gfx->Preset_paintbrush_height[33]= 5; + gfx->Paintbrush_type [33]=PAINTBRUSH_SHAPE_CROSS; - Preset_paintbrush_width[34]= 5; - Preset_paintbrush_height[34]= 5; - Paintbrush_type [34]=PAINTBRUSH_SHAPE_PLUS; + gfx->Preset_paintbrush_width [34]= 5; + gfx->Preset_paintbrush_height[34]= 5; + gfx->Paintbrush_type [34]=PAINTBRUSH_SHAPE_PLUS; - Preset_paintbrush_width[35]=15; - Preset_paintbrush_height[35]=15; - Paintbrush_type [35]=PAINTBRUSH_SHAPE_PLUS; + gfx->Preset_paintbrush_width [35]=15; + gfx->Preset_paintbrush_height[35]=15; + gfx->Paintbrush_type [35]=PAINTBRUSH_SHAPE_PLUS; - Preset_paintbrush_width[36]= 2; - Preset_paintbrush_height[36]= 2; - Paintbrush_type [36]=PAINTBRUSH_SHAPE_SLASH; + gfx->Preset_paintbrush_width [36]= 2; + gfx->Preset_paintbrush_height[36]= 2; + gfx->Paintbrush_type [36]=PAINTBRUSH_SHAPE_SLASH; - Preset_paintbrush_width[37]= 4; - Preset_paintbrush_height[37]= 4; - Paintbrush_type [37]=PAINTBRUSH_SHAPE_SLASH; + gfx->Preset_paintbrush_width [37]= 4; + gfx->Preset_paintbrush_height[37]= 4; + gfx->Paintbrush_type [37]=PAINTBRUSH_SHAPE_SLASH; - Preset_paintbrush_width[38]= 8; - Preset_paintbrush_height[38]= 8; - Paintbrush_type [38]=PAINTBRUSH_SHAPE_SLASH; + gfx->Preset_paintbrush_width [38]= 8; + gfx->Preset_paintbrush_height[38]= 8; + gfx->Paintbrush_type [38]=PAINTBRUSH_SHAPE_SLASH; - Preset_paintbrush_width[39]= 2; - Preset_paintbrush_height[39]= 2; - Paintbrush_type [39]=PAINTBRUSH_SHAPE_ANTISLASH; + gfx->Preset_paintbrush_width [39]= 2; + gfx->Preset_paintbrush_height[39]= 2; + gfx->Paintbrush_type [39]=PAINTBRUSH_SHAPE_ANTISLASH; - Preset_paintbrush_width[40]= 4; - Preset_paintbrush_height[40]= 4; - Paintbrush_type [40]=PAINTBRUSH_SHAPE_ANTISLASH; + gfx->Preset_paintbrush_width [40]= 4; + gfx->Preset_paintbrush_height[40]= 4; + gfx->Paintbrush_type [40]=PAINTBRUSH_SHAPE_ANTISLASH; - Preset_paintbrush_width[41]= 8; - Preset_paintbrush_height[41]= 8; - Paintbrush_type [41]=PAINTBRUSH_SHAPE_ANTISLASH; + gfx->Preset_paintbrush_width [41]= 8; + gfx->Preset_paintbrush_height[41]= 8; + gfx->Paintbrush_type [41]=PAINTBRUSH_SHAPE_ANTISLASH; - Preset_paintbrush_width[42]= 4; - Preset_paintbrush_height[42]= 4; - Paintbrush_type [42]=PAINTBRUSH_SHAPE_RANDOM; + gfx->Preset_paintbrush_width [42]= 4; + gfx->Preset_paintbrush_height[42]= 4; + gfx->Paintbrush_type [42]=PAINTBRUSH_SHAPE_RANDOM; - Preset_paintbrush_width[43]= 8; - Preset_paintbrush_height[43]= 8; - Paintbrush_type [43]=PAINTBRUSH_SHAPE_RANDOM; + gfx->Preset_paintbrush_width [43]= 8; + gfx->Preset_paintbrush_height[43]= 8; + gfx->Paintbrush_type [43]=PAINTBRUSH_SHAPE_RANDOM; - Preset_paintbrush_width[44]=13; - Preset_paintbrush_height[44]=13; - Paintbrush_type [44]=PAINTBRUSH_SHAPE_RANDOM; + gfx->Preset_paintbrush_width [44]=13; + gfx->Preset_paintbrush_height[44]=13; + gfx->Paintbrush_type [44]=PAINTBRUSH_SHAPE_RANDOM; - Preset_paintbrush_width[45]= 3; - Preset_paintbrush_height[45]= 3; - Paintbrush_type [45]=PAINTBRUSH_SHAPE_MISC; + gfx->Preset_paintbrush_width [45]= 3; + gfx->Preset_paintbrush_height[45]= 3; + gfx->Paintbrush_type [45]=PAINTBRUSH_SHAPE_MISC; - Preset_paintbrush_width[46]= 3; - Preset_paintbrush_height[46]= 3; - Paintbrush_type [46]=PAINTBRUSH_SHAPE_MISC; + gfx->Preset_paintbrush_width [46]= 3; + gfx->Preset_paintbrush_height[46]= 3; + gfx->Paintbrush_type [46]=PAINTBRUSH_SHAPE_MISC; - Preset_paintbrush_width[47]= 7; - Preset_paintbrush_height[47]= 7; - Paintbrush_type [47]=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;index>1); - Preset_paintbrush_offset_Y[index]=(Preset_paintbrush_height[index]>>1); + gfx->Preset_paintbrush_offset_X[index]=(gfx->Preset_paintbrush_width [index]>>1); + gfx->Preset_paintbrush_offset_Y[index]=(gfx->Preset_paintbrush_height[index]>>1); } } diff --git a/init.h b/init.h index e0913bb0..7b5d5cc1 100644 --- a/init.h +++ b/init.h @@ -22,7 +22,7 @@ /// Initialization (and some de-initialization) functions. ////////////////////////////////////////////////////////////////////////////// -void Load_graphics(const char * skin_file); +void Load_graphics(T_Gui_skin *gfx, const char * skin_file); void Init_buttons(void); void Init_operations(void); int Load_CFG(int reload_all); diff --git a/main.c b/main.c index 3e27e223..dca2d1a1 100644 --- a/main.c +++ b/main.c @@ -532,8 +532,11 @@ int Init_program(int argc,char * argv[]) Analyze_command_line(argc,argv); - // Charger les sprites et la palette - Load_graphics(Gui_skin_file); + // Load sprites, palette etc. + Gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); + if (Gfx == NULL) + Error(ERROR_MEMORY); + Load_graphics(Gfx, Gui_skin_file); // Infos sur les trames (Sieve) Sieve_mode=0; @@ -541,21 +544,21 @@ int Init_program(int argc,char * argv[]) // Transfert des valeurs du .INI qui ne changent pas dans des variables // plus accessibles: - Default_palette[MC_Black]=Fav_menu_colors[0]=Config.Fav_menu_colors[0]; - Default_palette[MC_Dark] =Fav_menu_colors[1]=Config.Fav_menu_colors[1]; - Default_palette[MC_Light]=Fav_menu_colors[2]=Config.Fav_menu_colors[2]; - Default_palette[MC_White]=Fav_menu_colors[3]=Config.Fav_menu_colors[3]; - Compute_optimal_menu_colors(Default_palette); + Gfx->Default_palette[MC_Black]=Fav_menu_colors[0]=Config.Fav_menu_colors[0]; + Gfx->Default_palette[MC_Dark] =Fav_menu_colors[1]=Config.Fav_menu_colors[1]; + Gfx->Default_palette[MC_Light]=Fav_menu_colors[2]=Config.Fav_menu_colors[2]; + Gfx->Default_palette[MC_White]=Fav_menu_colors[3]=Config.Fav_menu_colors[3]; + Compute_optimal_menu_colors(Gfx->Default_palette); Fore_color=MC_White; Back_color=MC_Black; // Prise en compte de la fonte if (Config.Font) - Menu_font=GFX_fun_font; + Menu_font=Gfx->Fun_font; else - Menu_font=GFX_system_font; + Menu_font=Gfx->System_font; - memcpy(Main_palette,Default_palette,sizeof(T_Palette)); + memcpy(Main_palette, Gfx->Default_palette, sizeof(T_Palette)); // Allocation de mémoire pour la brosse if (!(Brush =(byte *)malloc( 1* 1))) Error(ERROR_MEMORY); @@ -755,7 +758,7 @@ int main(int argc,char * argv[]) { if (Config.Opening_message && (!File_in_command_line)) Button_Message_initial(); - free(GFX_logo_grafx2); // Pas encore utilisé dans le About + free(Gfx->Logo_grafx2); // Not yet used in the About screen if (File_in_command_line) { diff --git a/palette.c b/palette.c index 85591592..4b083c66 100644 --- a/palette.c +++ b/palette.c @@ -1227,9 +1227,9 @@ void Button_Palette(void) case 5 : // Default memcpy(backup_palette,working_palette,sizeof(T_Palette)); - memcpy(working_palette,Default_palette,sizeof(T_Palette)); - memcpy(temp_palette,Default_palette,sizeof(T_Palette)); - Set_palette(Default_palette); + memcpy(working_palette,Gfx->Default_palette,sizeof(T_Palette)); + memcpy(temp_palette,Gfx->Default_palette,sizeof(T_Palette)); + Set_palette(Gfx->Default_palette); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prépare la "modifiabilité" des nouvelles couleurs memcpy(temp_palette,working_palette,sizeof(T_Palette)); diff --git a/struct.h b/struct.h index ee1cf40d..9aaf0eb4 100644 --- a/struct.h +++ b/struct.h @@ -305,5 +305,76 @@ typedef struct } T_List_of_pages; +/// GUI skin data +typedef struct +{ + // Mouse + + /// X coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_WIDTH + word Cursor_offset_X[NB_CURSOR_SPRITES]; + /// Y coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_HEIGHT + word Cursor_offset_Y[NB_CURSOR_SPRITES]; + /// 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) + word Sieve_pattern[12][16]; + + // Menu and other graphics + + /// Bitmap data for the menu, a single rectangle. + byte Menu_block[MENU_HEIGHT][MENU_WIDTH]; + /// Bitmap data for the icons that are displayed over the menu. + byte Menu_sprite[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]; + /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. + byte * Logo_grafx2; + /// Bitmap data for the 6x8 font used in help screens. + byte Help_font_norm [256][6][8]; + /// Bitmap data for the 6x8 font used in help screens ("bold" verstion). + byte Bold_font [256][6][8]; + // 12 + // 34 + /// Bitmap data for the title font used in help screens. Top-left quarter. + byte Help_font_t1 [64][6][8]; + /// Bitmap data for the title font used in help screens. Top-right quarter. + byte Help_font_t2 [64][6][8]; + /// Bitmap data for the title font used in help screens. Bottom-left quarter. + byte Help_font_t3 [64][6][8]; + /// Bitmap data for the title font used in help screens. Bottom-right quarter. + byte Help_font_t4 [64][6][8]; + /// Bitmap data for the small 8x8 icons. + byte Icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; + + // 8x8 fonts + + /// Bitmap data for the classic 8x8 font used in menus etc. + byte System_font[256*8*8]; + /// Bitmap data for the "fun" 8x8 font used in menus etc. + byte Fun_font [256*8*8]; + + /// A default 256-color palette. + T_Palette Default_palette; + + +} T_Gui_skin; #endif diff --git a/windows.c b/windows.c index 8e36219c..24191a72 100644 --- a/windows.c +++ b/windows.c @@ -423,7 +423,7 @@ void Display_menu(void) // Affichage du sprite du menu for (y_pos=0;y_posMenu_block[y_pos][x_pos]); // Affichage de la bande grise sous la palette Block(MENU_WIDTH*Menu_factor_X,Menu_status_Y-Menu_factor_Y,Screen_width-(MENU_WIDTH*Menu_factor_X),9*Menu_factor_Y,MC_Light); @@ -883,9 +883,9 @@ void Display_sprite_in_menu(int btn_number,int sprite_number) for (y_pos=0;y_posMenu_sprite[sprite_number][y_pos][x_pos]; Pixel_in_menu(menu_x_pos+x_pos,menu_y_pos+y_pos,color); - GFX_menu_block[menu_y_pos+y_pos][menu_x_pos+x_pos]=color; + Gfx->Menu_block[menu_y_pos+y_pos][menu_x_pos+x_pos]=color; } Update_rect(Menu_factor_X*(Buttons_Pool[btn_number].X_offset+1), (Buttons_Pool[btn_number].Y_offset+1)*Menu_factor_Y+Menu_Y, @@ -909,9 +909,9 @@ void Display_paintbrush_in_menu(void) for (menu_y_pos=2,y_pos=0;y_posMenu_sprite[4][y_pos][x_pos]; Pixel_in_menu(menu_x_pos,menu_y_pos,color); - GFX_menu_block[menu_y_pos][menu_x_pos]=color; + Gfx->Menu_block[menu_y_pos][menu_x_pos]=color; } break; default : // Pinceau @@ -920,7 +920,7 @@ void Display_paintbrush_in_menu(void) for (menu_x_pos=1,x_pos=0;x_posMenu_block[menu_y_pos][menu_x_pos]=MC_Light; } // On affiche le nouveau menu_start_x=8-Paintbrush_offset_X; @@ -946,7 +946,7 @@ void Display_paintbrush_in_menu(void) { color=(Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos])?MC_Black:MC_Light; Pixel_in_menu(menu_x_pos,menu_y_pos,color); - GFX_menu_block[menu_y_pos][menu_x_pos]=color; + Gfx->Menu_block[menu_y_pos][menu_x_pos]=color; } } Update_rect(0,Menu_Y,MENU_SPRITE_WIDTH*Menu_factor_X+3,MENU_SPRITE_HEIGHT*Menu_factor_Y+3); @@ -973,18 +973,18 @@ void Display_paintbrush_in_window(word x,word y,int number) if (y_size<1) y_size=1; - origin_x = (x + 8)*Menu_factor_X - (Preset_paintbrush_offset_X[number])*x_size+Window_pos_X; - origin_y = (y + 8)*Menu_factor_Y - (Preset_paintbrush_offset_Y[number])*y_size+Window_pos_Y; + origin_x = (x + 8)*Menu_factor_X - (Gfx->Preset_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; - 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); // On n'utilise pas Pixel_in_window() car on ne dessine pas // forcément avec la même taille de pixel. Update_rect( ToWinX(origin_x), ToWinY(origin_y), - ToWinL(Preset_paintbrush_width[number]), - ToWinH(Preset_paintbrush_height[number]) + ToWinL(Gfx->Preset_paintbrush_width[number]), + ToWinH(Gfx->Preset_paintbrush_height[number]) ); } @@ -1041,7 +1041,7 @@ void Window_display_icon_sprite(word x_pos,word y_pos,byte type) for (j=0; jIcon_sprite[type][j][i]); Update_rect(ToWinX(x_pos),ToWinY(y_pos),ToWinL(ICON_SPRITE_WIDTH),ToWinH(ICON_SPRITE_HEIGHT)); } @@ -1567,8 +1567,8 @@ void Display_cursor(void) else { temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; - start_x=Mouse_X-Cursor_offset_X[temp]; - start_y=Mouse_Y-Cursor_offset_Y[temp]; + start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; + start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (x_pos=start_x,counter_x=0;counter_x<15 && x_pos < Screen_width;x_pos++,counter_x++) { @@ -1576,7 +1576,7 @@ void Display_cursor(void) for (y_pos=start_y,counter_y=0;counter_y<15 && y_pos < Screen_height;y_pos++,counter_y++) { if( y_pos < 0 || y_pos >= Screen_height) continue; - color=GFX_cursor_sprite[temp][counter_y][counter_x]; + color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); @@ -1636,8 +1636,8 @@ void Display_cursor(void) { DEBUG("B",0); temp=(Config.Cursor)?CURSOR_SHAPE_THIN_COLORPICKER:CURSOR_SHAPE_COLORPICKER; - start_x=Mouse_X-Cursor_offset_X[temp]; - start_y=Mouse_Y-Cursor_offset_Y[temp]; + start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; + start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { @@ -1647,7 +1647,7 @@ void Display_cursor(void) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; - color=GFX_cursor_sprite[temp][counter_y][counter_x]; + color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) @@ -1666,8 +1666,8 @@ void Display_cursor(void) case CURSOR_SHAPE_ARROW : case CURSOR_SHAPE_HOURGLASS : - start_x=Mouse_X-Cursor_offset_X[shape]; - start_y=Mouse_Y-Cursor_offset_Y[shape]; + start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; + start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { if(x_pos<0) continue; @@ -1676,7 +1676,7 @@ void Display_cursor(void) { if(y_pos<0) continue; if(y_pos>=Screen_height) break; - color=GFX_cursor_sprite[shape][counter_y][counter_x]; + color=Gfx->Cursor_sprite[shape][counter_y][counter_x]; // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) @@ -1873,8 +1873,8 @@ void Hide_cursor(void) else { temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; - start_x=Mouse_X-Cursor_offset_X[temp]; - start_y=Mouse_Y-Cursor_offset_Y[temp]; + start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; + start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { @@ -1941,8 +1941,8 @@ void Hide_cursor(void) else { temp=(Config.Cursor)?CURSOR_SHAPE_THIN_COLORPICKER:CURSOR_SHAPE_COLORPICKER; - start_x=Mouse_X-Cursor_offset_X[temp]; - start_y=Mouse_Y-Cursor_offset_Y[temp]; + start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; + start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { @@ -1969,8 +1969,8 @@ void Hide_cursor(void) case CURSOR_SHAPE_ARROW : case CURSOR_SHAPE_HOURGLASS : - start_x=Mouse_X-Cursor_offset_X[shape]; - start_y=Mouse_Y-Cursor_offset_Y[shape]; + start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; + start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { @@ -2492,52 +2492,52 @@ void Compute_optimal_menu_colors(T_Components * palette) for (k=0; kCursor_sprite[k][j][i]); // Le menu for (j=0; jMenu_block[j][i]); // Sprites du menu for (k=0; kMenu_sprite[k][j][i]); // Sprites d'effets for (k=0; kEffect_sprite[k][j][i]); // Fontes de l'aide for (k=0; k<256; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) - Remap_pixel(&GFX_help_font_norm[k][i][j]); + Remap_pixel(&Gfx->Help_font_norm[k][i][j]); for (k=0; k<256; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) - Remap_pixel(&GFX_bold_font[k][i][j]); + Remap_pixel(&Gfx->Bold_font[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) - Remap_pixel(&GFX_help_font_t1[k][i][j]); + Remap_pixel(&Gfx->Help_font_t1[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) - Remap_pixel(&GFX_help_font_t2[k][i][j]); + Remap_pixel(&Gfx->Help_font_t2[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) - Remap_pixel(&GFX_help_font_t3[k][i][j]); + Remap_pixel(&Gfx->Help_font_t3[k][i][j]); for (k=0; k<64; k++) for (j=0; j<8; j++) for (i=0; i<6; i++) - Remap_pixel(&GFX_help_font_t4[k][i][j]); + Remap_pixel(&Gfx->Help_font_t4[k][i][j]); // Sprites de lecteurs (drives) for (k=0; kIcon_sprite[k][j][i]); } Clear_border(MC_Black); } From 51bcccce47f01a19505c8e6d5c55d301cfd0efd7 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 17 Jun 2009 15:11:32 +0000 Subject: [PATCH 11/95] Yay ! A 10 hours trip in the train is good for my opensource productivity :) - Moved font and cursor choice to the skin window instead of settings - Changed them to use dropdown instead of buttons - Save the config includintg the chosen skin (i had to wildly hack the save routine to allow '.' as a character in a string in the inifile... check if it's ok please) - Renamed 00.rgb.studios to "the Peach", as they seem to be the same person :) in the help/bugfinders - Wrote a little help for the skins window - Some other random tweakings i already forgot. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@872 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 188 +++++++++++++++++++++++++++++++--------------------- engine.h | 2 + gfx2def.ini | 5 +- helpfile.h | 52 ++++++++++----- main.c | 3 +- readini.c | 4 ++ saveini.c | 6 ++ struct.h | 1 + 8 files changed, 164 insertions(+), 97 deletions(-) diff --git a/buttons.c b/buttons.c index b328c41e..2aa7efb2 100644 --- a/buttons.c +++ b/buttons.c @@ -711,13 +711,16 @@ void Settings_display_config(T_Config * conf) Print_in_window( 91, 99,(conf->Clear_palette)?YES:NO,MC_Black,MC_Light); Print_in_window( 91,114,(conf->Maximize_preview)?YES:NO,MC_Black,MC_Light); Print_in_window( 91,129,(conf->Backup)?YES:NO,MC_Black,MC_Light); + /* switch (conf->Cursor) { case 0 : Print_in_window(67,144," Solid",MC_Black,MC_Light); break; case 1 : Print_in_window(67,144,"Transp",MC_Black,MC_Light); break; default: Print_in_window(67,144," Thin",MC_Black,MC_Light); } + */ + /* if (conf->Font) { // Fun Print_in_window( 8,31," ",MC_Black,MC_Light); @@ -732,6 +735,7 @@ void Settings_display_config(T_Config * conf) Print_in_window( 8,31,"\020",MC_Black,MC_Light); Print_in_window( 78,31,"\021",MC_Black,MC_Light); } + */ Print_in_window(155,166,(conf->Auto_save)?YES:NO,MC_Black,MC_Light); @@ -771,7 +775,6 @@ void Button_Settings(void) Open_window(307,182,"Settings"); // On commence par dessiner tous les Cadres - Window_display_frame( 5, 16,157,30); // Font Window_display_frame( 5, 47,157,17); // Nb UNDO Window_display_frame(163, 16,139,48); // Show in filelist Window_display_frame(253, 77, 49,82); // Mouse sens. @@ -786,7 +789,6 @@ void Button_Settings(void) Pixel_in_window(160,77,MC_Dark); */ // On affiche maintenant tout le blabla - Print_in_window( 69, 19,"Font" ,MC_Dark,MC_Light); Print_in_window(169, 19,"Show in filelist",MC_Dark,MC_Light); Print_in_window( 9, 52,"Nb of UNDO pages",MC_Dark,MC_Light); Print_in_window( 80, 70,"Miscellaneous" ,MC_Dark,MC_Light); @@ -795,52 +797,47 @@ void Button_Settings(void) Print_in_window(256,123,"X" ,MC_Dark,MC_Light); Print_in_window(292,123,"Y" ,MC_Dark,MC_Light); - // Boutons de fontes - Window_set_normal_button(17,28,59,14,"Classic",0,1,SDLK_LAST); // 1 - Window_set_normal_button(91,28,59,14,"Fun" ,0,1,SDLK_LAST); // 2 // Button Show/Hide dans le fileselect - Window_set_normal_button(167, 28,131,14,"Hidden files: ",0,1,SDLK_LAST); // 3 - Window_set_normal_button(167, 43,131,14,"Hidden dir. : ",0,1,SDLK_LAST); // 4 -// Window_set_normal_button(167, 58,131,14,"System dir. : ",0,1,SDLK_LAST); // 5 + Window_set_normal_button(167, 28,131,14,"Hidden files: ",0,1,SDLK_LAST); // 1 + Window_set_normal_button(167, 43,131,14,"Hidden dir. : ",0,1,SDLK_LAST); // 2 +// Window_set_normal_button(167, 58,131,14,"System dir. : ",0,1,SDLK_LAST); // 3 // Button Show/Hide Picture limits - Window_set_normal_button( 9, 81,107,14,"Limits : ",0,1,SDLK_LAST); // 6 + Window_set_normal_button( 9, 81,107,14,"Limits : ",0,1,SDLK_LAST); // 3 // Button Show/Hide Picture limits - Window_set_normal_button( 9, 96,107,14,"Clear pal: ",0,1,SDLK_LAST); // 7 + Window_set_normal_button( 9, 96,107,14,"Clear pal: ",0,1,SDLK_LAST); // 4 // Button Show/Hide Picture limits - Window_set_normal_button( 9,111,107,14,"Max prev.: ",0,1,SDLK_LAST); // 8 + Window_set_normal_button( 9,111,107,14,"Max prev.: ",0,1,SDLK_LAST); // 5 // Button Effectuer des backups à chaque sauvegarde - Window_set_normal_button( 9,126,107,14,"Backup : ",0,1,SDLK_LAST); // 9 - // Button item du curseur - Window_set_normal_button( 9,141,107,14,"Cursor: ",0,1,SDLK_LAST); // 10 + Window_set_normal_button( 9,126,107,14,"Backup : ",0,1,SDLK_LAST); // 6 // Button Safety colors - Window_set_normal_button(117, 81,131,14,"Safe. colors: ",0,1,SDLK_LAST); // 11 + Window_set_normal_button(117, 81,131,14,"Safe. colors: ",0,1,SDLK_LAST); // 8 // Button Adjust Brush Pick - Window_set_normal_button(117, 96,131,14,"AdjBrushPick: ",0,1,SDLK_LAST); // 12 + Window_set_normal_button(117, 96,131,14,"AdjBrushPick: ",0,1,SDLK_LAST); // 9 // Button Separate colors - Window_set_normal_button(117,111,131,14,"Separate col: ",0,1,SDLK_LAST); // 13 + Window_set_normal_button(117,111,131,14,"Separate col: ",0,1,SDLK_LAST); // 10 // Button Passer dans la résolution appropriée après un chargement - Window_set_normal_button(117,126,131,14,"Auto-set res: ",0,1,SDLK_LAST); // 14 + Window_set_normal_button(117,126,131,14,"Auto-set res: ",0,1,SDLK_LAST); // 11 // Button Adapter la palette après un chargement (<=> Shift+BkSpc) - Window_set_normal_button(117,141,131,14,"Coords: ",0,1,SDLK_LAST); // 15 + Window_set_normal_button(117,141,131,14,"Coords: ",0,1,SDLK_LAST); // 12 // Button Reload - Window_set_normal_button( 6,163, 51,14,"Reload" ,0,1,SDLK_LAST); // 16 + Window_set_normal_button( 6,163, 51,14,"Reload" ,0,1,SDLK_LAST); // 13 // Button Auto-save - Window_set_normal_button( 73,163,107,14,"Auto-save: ",0,1,SDLK_LAST); // 17 + Window_set_normal_button( 73,163,107,14,"Auto-save: ",0,1,SDLK_LAST); // 14 // Button Save - Window_set_normal_button(183,163, 51,14,"Save" ,0,1,SDLK_LAST); // 18 + Window_set_normal_button(183,163, 51,14,"Save" ,0,1,SDLK_LAST); // 15 // Button Close - Window_set_normal_button(250,163, 51,14,"Close" ,0,1,KEY_ESC); // 19 + Window_set_normal_button(250,163, 51,14,"Close" ,0,1,KEY_ESC); // 16 // Jauges de sensibilité de la souris (X puis Y) - Window_set_scroller_button(265,99,56,4,1,0); // 20 - Window_set_scroller_button(279,99,56,4,1,0); // 21 + Window_set_scroller_button(265,99,56,4,1,0); // 17 + Window_set_scroller_button(279,99,56,4,1,0); // 18 // Zone de saisie du nb de pages de Undo - Window_set_input_button(140,50,2); // 22 + Window_set_input_button(140,50,2); // 19 Update_window_area(0,0,Window_width, Window_height); @@ -855,69 +852,60 @@ void Button_Settings(void) switch(clicked_button) { - case 1 : // Classic - Config_choisie.Font=0; - break; - case 2 : // Fun - Config_choisie.Font=1; - break; - case 3 : // Hidden files + case 1 : // Hidden files Config_choisie.Show_hidden_files=(Config_choisie.Show_hidden_files)?0:-1; break; - case 4 : // Hidden dir. + case 2 : // Hidden dir. Config_choisie.Show_hidden_directories=(Config_choisie.Show_hidden_directories)?0:-1; break; // case 5 : // System dir. // Config_choisie.Show_system_directories=(Config_choisie.Show_system_directories)?0:-1; // break; - case 5 : // Draw limits + case 3 : // Draw limits Config_choisie.Display_image_limits=!Config_choisie.Display_image_limits; break; - case 6 : // Clear palette + case 4 : // Clear palette Config_choisie.Clear_palette=!Config_choisie.Clear_palette; break; - case 7 : // Maximize preview + case 5 : // Maximize preview Config_choisie.Maximize_preview=!Config_choisie.Maximize_preview; break; - case 8 : // Backup + case 6 : // Backup Config_choisie.Backup=!Config_choisie.Backup; break; - case 9 : // Cursor - Config_choisie.Cursor=(Config_choisie.Cursor+1)%3; - break; - case 10 : // Safety colors + case 7 : // Safety colors Config_choisie.Safety_colors=!Config_choisie.Safety_colors; break; - case 11 : // Adjust brush pick + case 8 : // Adjust brush pick Config_choisie.Adjust_brush_pick=!Config_choisie.Adjust_brush_pick; break; - case 12 : // Separate colors + case 9 : // Separate colors Config_choisie.Separate_colors=!Config_choisie.Separate_colors; break; - case 13 : // Auto-set resolution + case 10 : // Auto-set resolution Config_choisie.Auto_set_res=!Config_choisie.Auto_set_res; break; - case 14 : // Coordonnées + case 11 : // Coordonnées Config_choisie.Coords_rel=!Config_choisie.Coords_rel; break; - case 15 : // Reload + case 12 : // Reload Settings_load_config(&Config_choisie); config_is_reloaded=1; break; - case 16 : // Auto-save + case 13 : // Auto-save Config_choisie.Auto_save=!Config_choisie.Auto_save; break; - case 17 : // Save + case 14 : // Save Settings_save_config(&Config_choisie); break; - // 18 : OK - case 19 : // X Sensib. + // 15 : OK + case 16 : // X Sensib. Config_choisie.Mouse_sensitivity_index_x=Window_attribute2+1; break; - case 20 : // Y Sensib. + case 17 : // Y Sensib. Config_choisie.Mouse_sensitivity_index_y=Window_attribute2+1; break; - case 21 : // Nb pages Undo + case 18 : // Nb pages Undo Num2str(Config_choisie.Max_undo_pages,str,2); Readline(142,52,str,2,1); Config_choisie.Max_undo_pages=atoi(str); @@ -947,22 +935,16 @@ void Button_Settings(void) Spare_fileselector_offset=0; } - if ((clicked_button>=1) && (clicked_button<=18)) + if ((clicked_button>=1) && (clicked_button<15)) Settings_display_config(&Config_choisie); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_SETTINGS, NULL); } - while ( (clicked_button!=18) && (Key!=SDLK_RETURN) ); + while ( (clicked_button!=15) && (Key!=SDLK_RETURN) ); Config=Config_choisie; - // Font selection - if (Config.Font) - Menu_font=Gfx->Fun_font; - else - Menu_font=Gfx->System_font; - if (config_is_reloaded) Compute_optimal_menu_colors(Main_palette); @@ -977,6 +959,7 @@ void Button_Settings(void) } +#define FILESEL_Y 52 void Display_skins_list(short offset_first, short selector_offset) // // offset_first = Décalage entre le premier fichier visible dans le @@ -1016,7 +999,7 @@ void Display_skins_list(short offset_first, short selector_offset) } // On affiche l'élément - Print_in_window(8,17+index*8,current_item->Short_name,text_color,background_color); + Print_in_window(8,FILESEL_Y+2+index*8,current_item->Short_name,text_color,background_color); // On passe à la ligne suivante selector_offset--; @@ -1042,22 +1025,48 @@ void Button_Skins(void) struct dirent* entry; // Structure de lecture des éléments struct stat Infos_enreg; char * current_path; + T_Config Config_choisie = Config; + T_Dropdown_button* font_dropdown; + T_Dropdown_button* cursor_dropdown; T_Scroller_button * file_scroller; - Open_window(178,120,"Skins"); + Open_window(178,155,"Skins"); + + // Frames + Window_display_frame_in(6,FILESEL_Y-2,148,84); // File selector + + // Texts + Print_in_window( 6, 21,"Font" ,MC_Black,MC_Light); + Print_in_window( 6, 36,"Cursor" ,MC_Black,MC_Light); // Ok button - Window_set_normal_button(6,102, 51,14,"OK" ,0,1,SDLK_RETURN); // 1 - - // Frame autour du fileselector - Window_display_frame_in(6,15,148,84); + Window_set_normal_button(6,136, 51,14,"OK" ,0,1,SDLK_RETURN); // 1 // Fileselector - Window_set_special_button(9,17,144,80); // 2 + Window_set_special_button(9,FILESEL_Y+2,144,80); // 2 // Scroller du fileselector - file_scroller = Window_set_scroller_button(160,16,82,1,10,0); // 3 + file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82,1,10,0); // 3 + + // Boutons de fontes + font_dropdown = Window_set_dropdown_button(60,19,70,11,0,(Config_choisie.Font==0)?"Classic":"Fun ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 4 + Window_dropdown_add_item(font_dropdown,0,"Classic"); + Window_dropdown_add_item(font_dropdown,1,"Fun "); + + // Cancel + Window_set_normal_button(62,136, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 5 + + // Button item du curseur + if(Config_choisie.Cursor==0) + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Solid ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 6 + else if(Config_choisie.Cursor==1) + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Transparent",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 6 + else + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Thin ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 6 + Window_dropdown_add_item(cursor_dropdown,0,"Solid "); + Window_dropdown_add_item(cursor_dropdown,1,"Transparent"); + Window_dropdown_add_item(cursor_dropdown,2,"Thin "); strcpy(skinsdir,Data_directory); strcat(skinsdir,"skins"); @@ -1095,8 +1104,12 @@ void Button_Skins(void) file_scroller->Position=Main_fileselector_position; Compute_slider_cursor_height(file_scroller); Window_draw_slider(file_scroller); + + // Select the current skin (we know it does exist, so no need to do a + // nearest match search) + Highlight_file(Config_choisie.SkinFile); // On efface les anciens noms de fichier: - Window_rectangle(8-1,15-1,144+2,80+2,MC_Black); + Window_rectangle(8-1,FILESEL_Y-1,144+2,80+2,MC_Black); // On affiche les nouveaux: Display_skins_list(Main_fileselector_position,Main_fileselector_offset); @@ -1110,10 +1123,11 @@ void Button_Skins(void) switch(clicked_button) { + // 1: OK case 2 : // Zone d'affichage de la liste de fichiers Hide_cursor(); - temp=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-95)>>3; + temp=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-FILESEL_Y)>>3; if (temp>=Filelist_nb_elements) temp=Filelist_nb_elements-1; if (temp>=0) @@ -1140,6 +1154,13 @@ void Button_Skins(void) Display_cursor(); *quicksearch_filename=0; break; + case 4 : // Font dropdown + Config_choisie.Font=Window_attribute2; // récupère le numéro de l'item selectionné + break; + // 5: Cancel + case 6 : // Cursor + Config_choisie.Cursor=Window_attribute2; + break; } switch (Key) @@ -1254,11 +1275,24 @@ void Button_Skins(void) *quicksearch_filename=0; } } - while ( (clicked_button!=1) && (Key!=SDLK_RETURN) ); + while ( (clicked_button!=1) && (Key!=SDLK_RETURN) && (clicked_button !=5) && (Key != SDLK_ESCAPE)); - strcpy(skinsdir,"skins/"); - Get_selected_item(Main_fileselector_position,Main_fileselector_offset,skinsdir+6,NULL); - Load_graphics(Gfx, skinsdir); + if(clicked_button == 1 || Key == SDLK_RETURN) + { + strcpy(skinsdir,"skins/"); + Get_selected_item(Main_fileselector_position,Main_fileselector_offset,skinsdir+6,NULL); + Load_graphics(Gfx, skinsdir); + + strcpy(Config_choisie.SkinFile,skinsdir+6); + + // Font selection + if (Config_choisie.Font) + Menu_font=Gfx->Fun_font; + else + Menu_font=Gfx->System_font; + + Config = Config_choisie ; + } Close_window(); Unselect_button(BUTTON_SETTINGS); @@ -1271,8 +1305,8 @@ void Button_Skins(void) //---------------------------- Changement de page ---------------------------- void Button_Page(void) { - byte temp_byte; - word temp_word; + byte temp_byte; + word temp_word; short temp_short; float temp_float; char Temp_buffer[256]; diff --git a/engine.h b/engine.h index 855c361a..43c639c9 100644 --- a/engine.h +++ b/engine.h @@ -50,6 +50,8 @@ T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, word width, word height, char * title,byte undersc_letter, byte clickable, word shortcut); +#define GGUI_set_normal_button(x_pos,y_pos,width,height,title,undersc_letter,clickable,shortcut,NAME) \ + const short NAME = Window_set_normal_button((x_pos),(y_pos),(width),(height),(title),(undersc_letter),(clickable),(shortcut))->Number; T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, word width, word height, char * title,byte undersc_letter, diff --git a/gfx2def.ini b/gfx2def.ini index d03c6c53..8b6090dd 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -81,7 +81,10 @@ ; 2: Fun | 2: Fun Font = 1 ; (default 1) - + ; Name of the skinfile you want to | Nom du fichier skin que vous voulez + ; use. | utiliser. + ; default 'modern.png' + Skin_file = modern.png [FILE_SELECTOR] # [SELECTEUR_DE_FICHIERS] diff --git a/helpfile.h b/helpfile.h index 8881d638..e989fb17 100644 --- a/helpfile.h +++ b/helpfile.h @@ -336,22 +336,22 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (begasus\100skynet.be)") HELP_TEXT ("") - HELP_TEXT (" Made it work on your favourite toaster") + HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" BUGFINDERS") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT (" BDCIron Ced El Topo ") - HELP_TEXT (" fallenblood Frost Grimmy ") - HELP_TEXT (" Gürkan Sengün HoraK-FDF iLKke ") - HELP_TEXT (" keito kusma Lord Graga ") - HELP_TEXT (" MagerValp mind MooZ ") - HELP_TEXT (" richienyhus TeeEmCee tempest ") - HELP_TEXT (" Timo Kurrpa titus^Rab Tobé ") - HELP_TEXT (" 00ai99 00.rgb.studios") + HELP_TEXT (" BDCIron Ced El Topo ") + HELP_TEXT (" fallenblood Frost Grimmy ") + HELP_TEXT (" Gürkan Sengün HoraK-FDF iLKke ") + HELP_TEXT (" keito kusma Lord Graga ") + HELP_TEXT (" MagerValp mind MooZ ") + HELP_TEXT (" the Peach richienyhus TeeEmCee ") + HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") + HELP_TEXT (" Tobé 00ai99 ") HELP_TEXT ("") - HELP_TEXT (" Posted the annoying bug reports.") + HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" FILE FORMATS CREDITS") @@ -1959,10 +1959,6 @@ static const T_Help_table helptable_settings[] = HELP_TEXT ("pages. To flick through these pages, use the") HELP_TEXT ("\"Oops\" button (Undo/Redo).") HELP_TEXT ("") - HELP_TEXT ("- Font: determines whether you want to use") - HELP_TEXT ("GrafX2 with a classical font, or another one") - HELP_TEXT ("a bit funnier.") - HELP_TEXT ("") HELP_TEXT ("- Mouse sensibility: Modifies the speed of") HELP_TEXT ("the mouse when you're in fullscreen. With") HELP_TEXT ("the normal setting (slider on top), you may") @@ -2006,10 +2002,6 @@ static const T_Help_table helptable_settings[] = HELP_TEXT ("the name of the backup file, no backup file") HELP_TEXT ("will be created (of course!) ;).") HELP_TEXT ("") - HELP_TEXT ("- Cursor: allows you to choose whether you") - HELP_TEXT ("prefer a solid cursor or a transparent") - HELP_TEXT ("cursor.") - HELP_TEXT ("") HELP_TEXT ("- Safety colors: Brings back the 4 default") HELP_TEXT ("colors of the menus if you run an operation") HELP_TEXT ("that passes the image in less than four") @@ -2059,6 +2051,30 @@ static const T_Help_table helptable_settings[] = HELP_TEXT ("- Save: saves the configuration at once.") HELP_TEXT (" All modifications will be effective just") HELP_TEXT ("after closing the menu.") + HELP_TEXT ("") + HELP_TITLE("SKINS") + HELP_TEXT ("") + HELP_TEXT ("This window allow you to change the look and") + HELP_TEXT ("feel of the program.") + HELP_TEXT ("") + HELP_TEXT ("- Font: determines whether you want to use") + HELP_TEXT ("GrafX2 with a classical font, or another one") + HELP_TEXT ("a bit funnier.") + HELP_TEXT ("") + HELP_TEXT ("- Cursor: allows you to choose whether you") + HELP_TEXT ("prefer a solid cursor or a transparent") + HELP_TEXT ("cursor.") + HELP_TEXT ("") + HELP_TEXT ("- Graphic file: you can change the whole") + HELP_TEXT ("interface by selecting where the sprites for") + HELP_TEXT ("all buttons are. Look at the files in the") + HELP_TEXT ("\"skin\" directory if you want to create your") + HELP_TEXT ("own. There are two skins available, the") + HELP_TEXT ("default for 2.1 is called modern. Classic is") + HELP_TEXT ("for nostalgics who wush to remember the old") + HELP_TEXT ("days of Sunset Design. If you create a good") + HELP_TEXT ("skin, feel free to share it with us! We may") + HELP_TEXT ("include it in a future release...") }; static const T_Help_table helptable_clear[] = { diff --git a/main.c b/main.c index dca2d1a1..77bec990 100644 --- a/main.c +++ b/main.c @@ -76,7 +76,7 @@ #endif // filename for the current GUI skin file. -static char Gui_skin_file[MAX_PATH_CHARACTERS]= "skins" PATH_SEPARATOR "modern.png"; +static char Gui_skin_file[MAX_PATH_CHARACTERS]= "skins" PATH_SEPARATOR ; //--- Affichage de la syntaxe, et de la liste des modes vidéos disponibles --- void Display_syntax(void) @@ -536,6 +536,7 @@ int Init_program(int argc,char * argv[]) Gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); if (Gfx == NULL) Error(ERROR_MEMORY); + strcpy(Gui_skin_file+6,Config.SkinFile); Load_graphics(Gfx, Gui_skin_file); // Infos sur les trames (Sieve) diff --git a/readini.c b/readini.c index 26c5fdb2..4fc2e54a 100644 --- a/readini.c +++ b/readini.c @@ -529,6 +529,10 @@ int Load_INI(T_Config * conf) goto Erreur_ERREUR_INI_CORROMPU; conf->Font=values[0]-1; + if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) + strcpy(conf->SkinFile,value_label); + else + strcpy(conf->SkinFile,"modern.png"); if ((return_code=Load_INI_reach_group(file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; diff --git a/saveini.c b/saveini.c index 975c9807..e30ccd11 100644 --- a/saveini.c +++ b/saveini.c @@ -93,6 +93,7 @@ int Save_INI_char_in_value_alphabet(char c) (c<='z') ) || (c == '$') // Symbole d'hexadécimal + || (c== '.') // Point (dans les noms de fichiers) ) return 1; else @@ -479,6 +480,11 @@ int Save_INI(T_Config * conf) if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Font",1,values,0))) goto Erreur_Retour; + if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Skin_file",conf->SkinFile))) + goto Erreur_Retour; + +puts(conf->SkinFile); + if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; diff --git a/struct.h b/struct.h index 9aaf0eb4..1f98599c 100644 --- a/struct.h +++ b/struct.h @@ -226,6 +226,7 @@ typedef struct typedef struct { byte Font; ///< Boolean, true to use the "fun" font in menus, false to use the classic one. + char SkinFile[64]; ///< String, name of the file where all the graphic data is stored int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. // int Show_system_directories; ///< (removed when converted from DOS) From a219287e23c9eb9bcaa3cb595a2329feb3272aa8 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 17 Jun 2009 16:09:24 +0000 Subject: [PATCH 12/95] Typo. Sorry ! git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@873 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- gfx2.cfg | Bin 10133 -> 10133 bytes helpfile.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx2.cfg b/gfx2.cfg index 6fdab707d525fcae06308336302177857354d994..00f063575534f2fe1325217f0fc194bb9d34460b 100644 GIT binary patch delta 115 zcmbR0Kh=Lj4YM{Q11AFmBNGD`kYr}y29hicJV26_ffq=!G4KIN1_llWb_V{=c zH#hL}h-_})X5rY}qs-0-k_G~h8W1&kg38CqlT?McMZ_3@U=k2BO`fQHd~=zaJR<;T C-Vwq8 delta 297 zcmWN{M@|A^06^h4VxkEq$OwuRbp|ZhEB1z1-oKH!Mz)qa03ru@?XH6x8V%_ zFL}E!Wu%Osm?fTz9hE#BILW5~7ljm2ObMlw;RdCg3M$di@!+M3YHFy(M;-Mv&?rR{ z&9u-;8|`$^iJvaI>7kcC`WcX7kRgT{VUz%4j1y#nNv4>NFvBc{By-FYVu3}LSZ0M) z)>vnQO}5x(M~Yqc*yn&ljyUFoQ_eUiOoR(Axsu|V8*aJdo(G~l^29SQyb|M$cjDs1 r=Cp`}Eyp1e*34}2sbwkVx1KhCb-S7Ls8-d5EGf@0zqCIQ^}3aR5*soV diff --git a/helpfile.h b/helpfile.h index e989fb17..47e7c14e 100644 --- a/helpfile.h +++ b/helpfile.h @@ -2071,7 +2071,7 @@ static const T_Help_table helptable_settings[] = HELP_TEXT ("\"skin\" directory if you want to create your") HELP_TEXT ("own. There are two skins available, the") HELP_TEXT ("default for 2.1 is called modern. Classic is") - HELP_TEXT ("for nostalgics who wush to remember the old") + HELP_TEXT ("for nostalgics who wish to remember the old") HELP_TEXT ("days of Sunset Design. If you create a good") HELP_TEXT ("skin, feel free to share it with us! We may") HELP_TEXT ("include it in a future release...") From 1c53b5dd7f7ad7c51061b2dce78a176c074ba848 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 17 Jun 2009 19:23:41 +0000 Subject: [PATCH 13/95] GUI skins: fixes INI ascending compatibility git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@876 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- gfx2def.ini | 10 +++++----- readini.c | 15 ++++++++------- saveini.c | 9 +++------ 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/gfx2def.ini b/gfx2def.ini index 8b6090dd..752096b8 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -81,11 +81,6 @@ ; 2: Fun | 2: Fun Font = 1 ; (default 1) - ; Name of the skinfile you want to | Nom du fichier skin que vous voulez - ; use. | utiliser. - ; default 'modern.png' - Skin_file = modern.png - [FILE_SELECTOR] # [SELECTEUR_DE_FICHIERS] ; Show hidden files and | Afficher les fichiers et répertoires @@ -326,4 +321,9 @@ ; GrafX2 to recognize them as a combo. Double_key_speed = 500; (Default 500) + ; Name of the skinfile you want to | Nom du fichier skin que vous voulez + ; use. | utiliser. + ; default 'modern.png' + Skin_file = modern.png + ; end of configuration diff --git a/readini.c b/readini.c index 4fc2e54a..f1594c1d 100644 --- a/readini.c +++ b/readini.c @@ -529,11 +529,6 @@ int Load_INI(T_Config * conf) goto Erreur_ERREUR_INI_CORROMPU; conf->Font=values[0]-1; - if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) - strcpy(conf->SkinFile,value_label); - else - strcpy(conf->SkinFile,"modern.png"); - if ((return_code=Load_INI_reach_group(file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; @@ -810,7 +805,7 @@ int Load_INI(T_Config * conf) } conf->Double_click_speed=500; - // Optional, speed of double-click (>98.0%) + // Optional, speed of double-click (>2.0) if (!Load_INI_get_values (file,buffer,"Double_click_speed",1,values)) { if ((values[0]>0) || (values[0]<=2000)) @@ -818,13 +813,19 @@ int Load_INI(T_Config * conf) } conf->Double_key_speed=500; - // Optional, speed of double-keypress (>98.0%) + // Optional, speed of double-keypress (>2.0) if (!Load_INI_get_values (file,buffer,"Double_key_speed",1,values)) { if ((values[0]>0) || (values[0]<=2000)) conf->Double_key_speed=values[0]; } + // Optional, name of skin file. (>2.0) + if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) + strcpy(conf->SkinFile,value_label); + else + strcpy(conf->SkinFile,"modern.png"); + fclose(file); diff --git a/saveini.c b/saveini.c index e30ccd11..4130624a 100644 --- a/saveini.c +++ b/saveini.c @@ -480,12 +480,6 @@ int Save_INI(T_Config * conf) if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Font",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Skin_file",conf->SkinFile))) - goto Erreur_Retour; - -puts(conf->SkinFile); - - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; @@ -648,6 +642,9 @@ puts(conf->SkinFile); values[0]=(conf->Double_key_speed); if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,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->SkinFile))) + goto Erreur_Retour; Save_INI_flush(Ancien_fichier,Nouveau_fichier,buffer); From 1910a39fd42ec80243cce8f12ead2b1ac06a6c41 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 17 Jun 2009 19:38:55 +0000 Subject: [PATCH 14/95] Gui skins: Added memory checks and correctness git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@877 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 27 +++++++++++++++++++++------ main.c | 7 +++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/buttons.c b/buttons.c index 2aa7efb2..1493153c 100644 --- a/buttons.c +++ b/buttons.c @@ -1279,12 +1279,27 @@ void Button_Skins(void) if(clicked_button == 1 || Key == SDLK_RETURN) { - strcpy(skinsdir,"skins/"); - Get_selected_item(Main_fileselector_position,Main_fileselector_offset,skinsdir+6,NULL); - Load_graphics(Gfx, skinsdir); - - strcpy(Config_choisie.SkinFile,skinsdir+6); - + T_Gui_skin * gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); + if (gfx == NULL) + { + Error(0); + } + else + { + strcpy(skinsdir,"skins/"); + Get_selected_item(Main_fileselector_position,Main_fileselector_offset,skinsdir+6,NULL); + Load_graphics(gfx, skinsdir); + if (0) // Error + { + free(gfx); + } + else + { + free(Gfx); + Gfx = gfx; + strcpy(Config_choisie.SkinFile,skinsdir+6); + } + } // Font selection if (Config_choisie.Font) Menu_font=Gfx->Fun_font; diff --git a/main.c b/main.c index b3e60e9e..e15c054e 100644 --- a/main.c +++ b/main.c @@ -687,6 +687,13 @@ void Program_shutdown(void) free(Spare_screen); free(Main_screen); + // Free the skin (Gui graphics) data + if (Gfx) + { + free(Gfx); + Gfx=NULL; + } + // On prend bien soin de passer dans le répertoire initial: if (chdir(Initial_directory)!=-1) { From 7f3fd42f770e6c1aa65bdf070c6365b2708f2813 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 17 Jun 2009 23:49:56 +0000 Subject: [PATCH 15/95] Started implementing generic 'List' controls. Currently in Text window, it's WIP, misses the initial display, no kb shortcuts, and untested with lists smaller than display area. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@878 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 69 ++++++++++++++-------------- engine.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++--- engine.h | 1 + global.h | 5 ++ struct.h | 15 ++++++ 5 files changed, 184 insertions(+), 39 deletions(-) diff --git a/buttons.c b/buttons.c index 1493153c..b16f8687 100644 --- a/buttons.c +++ b/buttons.c @@ -5420,14 +5420,10 @@ void Button_Effects(void) Display_cursor(); } -// Affiche tout le selecteur de fontes -void Draw_font_selector(short x, short y, short list_start, short cursor_position, short nb_visibles) +// Callback to display a font name in the list +void Draw_one_font_name(word x, word y, word index, byte highlighted) { - int index; - for (index=0; index < nb_visibles; index++) - { - Print_in_window(x,y+index*8,Font_label(index+list_start), MC_Black, (cursor_position==index)?MC_Dark:MC_Light); - } + Print_in_window(x,y,Font_label(index), MC_Black, (highlighted)?MC_Dark:MC_Light); } void Button_Text() @@ -5437,6 +5433,7 @@ void Button_Text() static int antialias=1; static short list_start=0; // index de le premiere fonte dans le selector static short cursor_position=0; // index de la ligne active dans le selector + static short selected_font_index=0; static short is_bold=0; static short is_italic=0; @@ -5449,10 +5446,12 @@ void Button_Text() T_Special_button * input_size_button; T_Special_button * input_text_button; T_Special_button * preview_button; + T_Special_button * font_list_button; T_Scroller_button * font_scroller; + T_List_button * font_list; + byte redraw_is_needed=1; byte preview_is_needed=1; - short temp; Open_window(288,180,"Text"); @@ -5476,7 +5475,7 @@ void Button_Text() // Scroller des fontes font_scroller = Window_set_scroller_button(165,35,NB_FONTS*8,Nb_fonts,NB_FONTS,list_start); // 5 // Liste des fontes disponibles - Window_set_special_button(8,35,152,NB_FONTS*8); // 6 + font_list_button = Window_set_special_button(8,35,152,NB_FONTS*8); // 6 Window_display_frame_in(7, 33, 154, NB_FONTS*8+4); // Taille texte @@ -5490,6 +5489,13 @@ void Button_Text() Window_set_normal_button(8,160,40,14,"OK",0,1,SDLK_RETURN); // 11 Window_set_normal_button(54,160,60,14,"Cancel",0,1,KEY_ESC); // 12 + + // List of fonts + font_list = Window_set_list_button(font_list_button, font_scroller, Draw_one_font_name); // 13 + // Restore its settings from last passage in screen + font_list->List_start = list_start; + font_list->Cursor_position = cursor_position; + Update_window_area(0,0,Window_width, Window_height); // str texte @@ -5505,8 +5511,6 @@ void Button_Text() // Taille Num2str(font_size,size_buffer,3); Window_input_content(input_size_button,size_buffer); - // Selecteur de fonte - Draw_font_selector(8, 35, list_start, cursor_position, NB_FONTS); } if (preview_is_needed) { @@ -5518,7 +5522,7 @@ void Button_Text() free(new_brush); } Window_rectangle(8, 106, 273, 50,Back_color); - new_brush = Render_text(preview_string, cursor_position+list_start, 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); if (new_brush) { Display_brush( @@ -5547,7 +5551,7 @@ void Button_Text() clicked_button=Window_clicked_button(); if (clicked_button==0) - { + {/* if (Key==SDLK_UP && (cursor_position+list_start)>0) { Key=0; @@ -5687,6 +5691,7 @@ void Button_Text() font_scroller->Position=list_start; Window_draw_slider(font_scroller); } + */ if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_TEXT, NULL); } @@ -5719,29 +5724,19 @@ void Button_Text() break; case 5: // Scroller des fontes - if (list_start!=Window_attribute2) - { - cursor_position+=list_start; - list_start=Window_attribute2; - cursor_position-=list_start; - // On affiche à nouveau la liste - Hide_cursor(); - redraw_is_needed=1; - } + /* Cannot happen, event is catched by the list control */ break; case 6: // Selecteur de fonte - temp=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-35)>>3; - if (temp!=cursor_position && temp < Nb_fonts) - { - cursor_position=temp; - // On affiche à nouveau la liste - Hide_cursor(); - redraw_is_needed=1; - preview_is_needed=1; - } + /* Cannot happen, event is catched by the list control */ break; - + + case 13: // Font selection + selected_font_index = Window_attribute2; + Hide_cursor(); + preview_is_needed=1; + break; + case 7: // Taille du texte (nombre) Readline(222,45,size_buffer,3,1); font_size=atoi(size_buffer); @@ -5780,6 +5775,10 @@ void Button_Text() case 11: // OK + // Save the selector settings + list_start = font_list->List_start; + cursor_position = font_list->Cursor_position; + if (!new_brush) { // Si echec de rendu @@ -5803,7 +5802,7 @@ void Button_Text() // On passe en brosse: Display_cursor(); - if (antialias || !TrueType_font(cursor_position+list_start)) + if (antialias || !TrueType_font(selected_font_index)) Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); else Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); @@ -5819,6 +5818,10 @@ void Button_Text() return; case 12: // Cancel + // Save the selector settings + list_start = font_list->List_start; + cursor_position = font_list->Cursor_position; + if (new_brush) free(new_brush); Close_window(); diff --git a/engine.c b/engine.c index 2a7f3546..240501b6 100644 --- a/engine.c +++ b/engine.c @@ -1178,6 +1178,7 @@ void Close_window(void) T_Scroller_button * temp3; T_Special_button * temp4; T_Dropdown_button * temp5; + T_List_button * temp6; Hide_cursor(); @@ -1212,6 +1213,12 @@ void Close_window(void) free(Window_dropdown_button_list); Window_dropdown_button_list=temp5; } + while (Window_list_button_list) + { + temp6=Window_list_button_list->Next; + free(Window_list_button_list); + Window_list_button_list=temp6; + } if (Windows_open != 1) { @@ -1659,6 +1666,29 @@ void Window_dropdown_clear_items(T_Dropdown_button * dropdown) } } +//----------------------- Create a List control ----------------------- +// These controls are special. They work over two controls previously created: +// - entry_button is the textual area where the list values will be printed. +// - scroller is a scroller button attached to it + +T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item) +{ + T_List_button *temp; + + temp=(T_List_button *)malloc(sizeof(T_List_button)); + temp->Number =++Window_nb_buttons; + temp->List_start = 0; + temp->Cursor_position = 0; + temp->Entry_button = entry_button; + temp->Scroller = scroller; + temp->Draw_list_item = draw_list_item; + + temp->Next=Window_list_button_list; + Window_list_button_list=temp; + return temp; +} + + //----------------------- Ouverture d'un pop-up ----------------------- void Open_popup(word x_pos, word y_pos, word width,word height) @@ -1722,7 +1752,8 @@ void Close_popup(void) T_Palette_button * temp2; T_Scroller_button * temp3; T_Special_button * temp4; - T_Dropdown_button * temp5; + T_Dropdown_button * temp5; + T_List_button * temp6; Hide_cursor(); @@ -1757,7 +1788,13 @@ void Close_popup(void) free(Window_dropdown_button_list); Window_dropdown_button_list=temp5; } - + while (Window_list_button_list) + { + temp6=Window_list_button_list->Next; + free(Window_list_button_list); + Window_list_button_list=temp6; + } + if (Windows_open != 1) { // Restore de ce que la fenêtre cachait @@ -2500,7 +2537,25 @@ short Window_get_button_shortcut(void) temp=temp->Next; } } - + + // Handle arrow keys, end/home, and mouse wheel that have + // a certain behavior if a list control is present. + if (Window_list_button_list) + { + T_List_button *list = Window_list_button_list; + // If there's more than one of such control, only capture + // events if the mouse cursor is over it. + if (list->Next) + { + // to do + } + + + + + + + } return 0; } @@ -2510,7 +2565,7 @@ short Window_clicked_button(void) if(!Get_input())SDL_Delay(20); - // Gestion des clicks + // Handle clicks if (Mouse_K) { if ((Mouse_XNext) + { + if (list->Entry_button->Number == clicked_button) + { + // Click in the textual part of a list. + short clicked_line; + clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; + if (clicked_line == list->Cursor_position || // Same as before + clicked_line >= list->Scroller->Nb_elements) // Below last line + return 0; + + Hide_cursor(); + // Redraw one item as disabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 0); + list->Cursor_position = clicked_line; + // Redraw one item as enabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 1); + 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; + } + else if (list->Scroller->Number == clicked_button) + { + short i; + + // Click in the scroller part of a list + if (list->List_start == list->Scroller->Position) + return 0; // Didn't actually move + // Update scroller indices + list->Cursor_position += list->List_start; + list->List_start = list->Scroller->Position; + list->Cursor_position -= list->List_start; + // Need to redraw all + Hide_cursor(); + for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--) + { + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + i * 8, + list->List_start + i, + i == list->Cursor_position); + } + Display_cursor(); + } + } + return clicked_button; + } } } - // Gestion des touches + // Intercept keys if (Key) { Button=Window_get_button_shortcut(); diff --git a/engine.h b/engine.h index 43c639c9..d47b8675 100644 --- a/engine.h +++ b/engine.h @@ -71,6 +71,7 @@ T_Special_button * Window_set_input_button(word x_pos,word y_pos,word width_in_c T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width,word height,word dropdown_width,const char *label,byte display_choice,byte display_centered,byte display_arrow,byte active_button); void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label); void Window_dropdown_clear_items(T_Dropdown_button * dropdown); +T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item); byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y); short Wait_click_in_palette(T_Palette_button * button); void Get_color_behind_window(byte * color, byte * click); diff --git a/global.h b/global.h index 1e4b6150..3980a64b 100644 --- a/global.h +++ b/global.h @@ -527,6 +527,11 @@ 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] +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] + + GFX2_GLOBAL int Window_stack_attribute1[8]; /// diff --git a/struct.h b/struct.h index 1f98599c..879bf44d 100644 --- a/struct.h +++ b/struct.h @@ -61,6 +61,7 @@ typedef void (* Func_display_zoom) (word,word,word,byte *); typedef void (* Func_display_brush_color_zoom) (word,word,word,word,word,word,byte,word,byte *); typedef void (* Func_display_brush_mono_zoom) (word,word,word,word,word,word,byte,byte,word,byte *); typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word); +typedef void (* Func_draw_list_item) (word,word,word,byte); /// A set of RGB values. typedef struct @@ -157,6 +158,20 @@ typedef struct T_Fileselector_item struct T_Fileselector_item * Previous;///< Pointer to previous item of the current fileselector. } T_Fileselector_item; +typedef struct T_List_button +{ + short Number; ///< Unique identifier for all controls + short List_start; ///< Index of the font to appear as first line + short Cursor_position; ///< Index of the selected line (0=top) + + T_Special_button * Entry_button; ///< Pointer to the associated selection control. + T_Scroller_button * Scroller; ///< Pointer to the associated scroller + + Func_draw_list_item Draw_list_item; ///< + + struct T_List_button * Next; ///< Pointer to the next list button of current window. +} T_List_button; + /// 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. From 0d54a9524f6cc63e33e697aa53a664afbaeddc77 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 18 Jun 2009 19:43:40 +0000 Subject: [PATCH 16/95] More work on List controls. Used in GUI Skin selector now git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@879 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 228 ++++++++++++++++++++++-------------------------------- engine.c | 24 +++--- engine.h | 1 + filesel.c | 8 +- io.c | 10 +-- 5 files changed, 116 insertions(+), 155 deletions(-) diff --git a/buttons.c b/buttons.c index b16f8687..b933417f 100644 --- a/buttons.c +++ b/buttons.c @@ -958,60 +958,50 @@ void Button_Settings(void) Set_number_of_backups(Config.Max_undo_pages); } +// Add a skin to the list +void Add_skin(const char *name) +{ + char * fname; -#define FILESEL_Y 52 -void Display_skins_list(short offset_first, short selector_offset) -// -// offset_first = Décalage entre le premier fichier visible dans le -// sélecteur et le premier fichier de la liste -// -// selector_offset = Décalage entre le premier fichier visible dans le -// sélecteur et le fichier sélectionné dans la liste -// + Add_element_to_list(name, 0); + Filelist_nb_elements++; + + // Cut the long name to keep only filename (no directory) + fname = Find_last_slash(Filelist->Full_name); + if (fname[0]=='\0') + return; + + strcpy(Filelist->Full_name, fname+1); + + // Reformat the short name + strcpy(Filelist->Short_name,Format_filename(Filelist->Full_name, 0)); + +} + +T_Fileselector_item * Get_selected_skin(word index) { T_Fileselector_item * current_item; - byte index; // index du fichier qu'on affiche (0 -> 9) - byte text_color; - byte background_color; + // Fast-forward to the requested item. + current_item=Filelist; + for (;index>0;index--) + current_item=current_item->Next; + // I know it's highly inefficient (O(n²)) but there shouldn't be dozens + // of skins in the directory... + + return current_item; +} +// Callback to display a skin name in the list +void Draw_one_skin_name(word x, word y, word index, byte highlighted) +{ + T_Fileselector_item * current_item; - // On vérifie s'il y a au moins 1 fichier dans la liste: if (Filelist_nb_elements>0) { - // On commence par chercher à pointer sur le premier fichier visible: - current_item=Filelist; - for (;offset_first>0;offset_first--) - current_item=current_item->Next; - - // Pour chacun des 10 éléments inscriptibles à l'écran - for (index=0;index<10;index++) - { - // S'il est sélectionné: - if (!selector_offset) - { - text_color=MC_White; - background_color=MC_Light; - } - else - { - text_color=MC_Light; - background_color=MC_Black; - } - - // On affiche l'élément - Print_in_window(8,FILESEL_Y+2+index*8,current_item->Short_name,text_color,background_color); - - // On passe à la ligne suivante - selector_offset--; - current_item=current_item->Next; - if (!current_item) - break; - } // End de la boucle d'affichage - - } // End du test d'existence de fichiers + current_item = Get_selected_skin(index); + Print_in_window(x,y,current_item->Short_name, MC_Black, (highlighted)?MC_Dark:MC_Light); + } } - - /// Skin selector window void Button_Skins(void) @@ -1021,16 +1011,35 @@ void Button_Skins(void) char quicksearch_filename[MAX_PATH_CHARACTERS]=""; char * most_matching_filename; char skinsdir[MAX_PATH_CHARACTERS]; - DIR* Repertoire_Courant; //Répertoire courant + DIR* current_directory; //Répertoire courant struct dirent* entry; // Structure de lecture des éléments struct stat Infos_enreg; char * current_path; + static int selector_position=0; T_Config Config_choisie = Config; - T_Dropdown_button* font_dropdown; - T_Dropdown_button* cursor_dropdown; - + T_Dropdown_button * font_dropdown; + T_Dropdown_button * cursor_dropdown; + T_List_button * skin_list; T_Scroller_button * file_scroller; + #define FILESEL_Y 52 + + // --- Read the contents of skins/ directory ------------------ + + // Here we use the same data container as the fileselectors. + // Reinitialize the list + Free_fileselector_list(); + Filelist_nb_elements=0; + // Browse the "skins" directory + strcpy(skinsdir,Data_directory); + strcat(skinsdir,"skins"); + // Add each found file to the list + For_each_file(skinsdir, Add_skin); + // Sort it + Sort_list_of_files(); + + // -------------------------------------------------------------- + Open_window(178,155,"Skins"); // Frames @@ -1043,75 +1052,41 @@ void Button_Skins(void) // Ok button Window_set_normal_button(6,136, 51,14,"OK" ,0,1,SDLK_RETURN); // 1 - // Fileselector - Window_set_special_button(9,FILESEL_Y+2,144,80); // 2 - - // Scroller du fileselector - file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82,1,10,0); // 3 + // List of skins + skin_list = Window_set_list_button( + // Fileselector + Window_set_special_button(9,FILESEL_Y+2,144,80), // 2 + // Scroller du fileselector + (file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82,Filelist_nb_elements,10,selector_position)), // 3 + Draw_one_skin_name); // 4 // Boutons de fontes - font_dropdown = Window_set_dropdown_button(60,19,70,11,0,(Config_choisie.Font==0)?"Classic":"Fun ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 4 + font_dropdown = Window_set_dropdown_button(60,19,70,11,0,(Config_choisie.Font==0)?"Classic":"Fun ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 Window_dropdown_add_item(font_dropdown,0,"Classic"); Window_dropdown_add_item(font_dropdown,1,"Fun "); // Cancel - Window_set_normal_button(62,136, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 5 + Window_set_normal_button(62,136, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 6 // Button item du curseur if(Config_choisie.Cursor==0) - cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Solid ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 6 + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Solid ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 else if(Config_choisie.Cursor==1) - cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Transparent",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 6 + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Transparent",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 else - cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Thin ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 6 + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Thin ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 Window_dropdown_add_item(cursor_dropdown,0,"Solid "); Window_dropdown_add_item(cursor_dropdown,1,"Transparent"); Window_dropdown_add_item(cursor_dropdown,2,"Thin "); - strcpy(skinsdir,Data_directory); - strcat(skinsdir,"skins"); - chdir(skinsdir); - getcwd(skinsdir,256); - - // Affichage des premiers fichiers visibles: - // Ensuite, on vide la liste actuelle: - Free_fileselector_list(); - // Après effacement, il ne reste ni fichier ni répertoire dans la liste - Filelist_nb_elements=0; - - // On lit tous les répertoires: - current_path=getcwd(NULL,0); - Repertoire_Courant=opendir(current_path); - while ((entry=readdir(Repertoire_Courant))) - { - stat(entry->d_name,&Infos_enreg); - if (S_ISREG(Infos_enreg.st_mode) && //Il s'agit d'un fichier - (Config.Show_hidden_files || //Il n'est pas caché - !isHidden(entry))) - { - // On rajoute le fichier à la liste - Add_element_to_list(entry->d_name, 0); - Filelist_nb_elements++; - } - } - - closedir(Repertoire_Courant); - free(current_path); - - Sort_list_of_files(); - - file_scroller->Nb_elements=Filelist_nb_elements; - file_scroller->Position=Main_fileselector_position; - Compute_slider_cursor_height(file_scroller); - Window_draw_slider(file_scroller); - // Select the current skin (we know it does exist, so no need to do a // nearest match search) - Highlight_file(Config_choisie.SkinFile); + //Highlight_file(Config_choisie.SkinFile); // On efface les anciens noms de fichier: - Window_rectangle(8-1,FILESEL_Y-1,144+2,80+2,MC_Black); + //Window_rectangle(8-1,FILESEL_Y-1,144+2,80+2,MC_Black); // On affiche les nouveaux: - Display_skins_list(Main_fileselector_position,Main_fileselector_offset); + //Display_skins_list(Main_fileselector_position,Main_fileselector_offset); + Window_redraw_list(skin_list); Update_window_area(0,0,Window_width, Window_height); @@ -1123,42 +1098,19 @@ void Button_Skins(void) switch(clicked_button) { - // 1: OK - case 2 : // Zone d'affichage de la liste de fichiers - Hide_cursor(); - - temp=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-FILESEL_Y)>>3; - if (temp>=Filelist_nb_elements) - temp=Filelist_nb_elements-1; - if (temp>=0) - { - // On met à jour le décalage - Main_fileselector_offset=temp; - - // On affiche à nouveau la liste - Display_skins_list(Main_fileselector_position,Main_fileselector_offset); - - // On vient de changer de nom de fichier, donc on doit s'appreter - // a rafficher une preview - *quicksearch_filename=0; - } - Display_cursor(); - Wait_end_of_click(); + case 1 : // OK + break; + case 2 : // doesn't happen break; - - case 3 : // Scroller de fichiers - Hide_cursor(); - Main_fileselector_position=Window_attribute2; - // On affiche à nouveau la liste - Display_skins_list(Main_fileselector_position,Main_fileselector_offset); - Display_cursor(); - *quicksearch_filename=0; + case 3 : // doesn't happen break; - case 4 : // Font dropdown + case 4 : // a file is selected + break; + case 5 : // Font dropdown Config_choisie.Font=Window_attribute2; // récupère le numéro de l'item selectionné break; // 5: Cancel - case 6 : // Cursor + case 7 : // Cursor Config_choisie.Cursor=Window_attribute2; break; } @@ -1241,7 +1193,6 @@ void Button_Skins(void) } Key=0; break; - */ default: // Autre => On se place sur le nom de fichier qui correspond if (clicked_button<=0) { @@ -1273,11 +1224,12 @@ void Button_Skins(void) } else *quicksearch_filename=0; + */ } } - while ( (clicked_button!=1) && (Key!=SDLK_RETURN) && (clicked_button !=5) && (Key != SDLK_ESCAPE)); + while ( (clicked_button!=1) && (clicked_button !=6) && (Key != SDLK_ESCAPE)); - if(clicked_button == 1 || Key == SDLK_RETURN) + if(clicked_button == 1) { T_Gui_skin * gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); if (gfx == NULL) @@ -1286,8 +1238,10 @@ void Button_Skins(void) } else { - strcpy(skinsdir,"skins/"); - Get_selected_item(Main_fileselector_position,Main_fileselector_offset,skinsdir+6,NULL); + strcpy(skinsdir,"skins/"); + strcat( + skinsdir, + Get_selected_skin(skin_list->List_start+skin_list->Cursor_position)->Full_name); Load_graphics(gfx, skinsdir); if (0) // Error { @@ -5496,6 +5450,8 @@ void Button_Text() font_list->List_start = list_start; font_list->Cursor_position = cursor_position; + Window_redraw_list(font_list); + Update_window_area(0,0,Window_width, Window_height); // str texte diff --git a/engine.c b/engine.c index 240501b6..600fd077 100644 --- a/engine.c +++ b/engine.c @@ -1688,6 +1688,19 @@ T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroll return temp; } +void Window_redraw_list(T_List_button * list) +{ + int i; + + for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--) + { + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + i * 8, + list->List_start + i, + i == list->Cursor_position); + } +} //----------------------- Ouverture d'un pop-up ----------------------- @@ -2620,8 +2633,6 @@ short Window_clicked_button(void) } else if (list->Scroller->Number == clicked_button) { - short i; - // Click in the scroller part of a list if (list->List_start == list->Scroller->Position) return 0; // Didn't actually move @@ -2631,14 +2642,7 @@ short Window_clicked_button(void) list->Cursor_position -= list->List_start; // Need to redraw all Hide_cursor(); - for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--) - { - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + i * 8, - list->List_start + i, - i == list->Cursor_position); - } + Window_redraw_list(list); Display_cursor(); } } diff --git a/engine.h b/engine.h index d47b8675..b3547cc3 100644 --- a/engine.h +++ b/engine.h @@ -72,6 +72,7 @@ T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width, void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label); void Window_dropdown_clear_items(T_Dropdown_button * dropdown); T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item); +void Window_redraw_list(T_List_button * list); byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y); short Wait_click_in_palette(T_Palette_button * button); void Get_color_behind_window(byte * color, byte * click); diff --git a/filesel.c b/filesel.c index 19334d89..f48babe4 100644 --- a/filesel.c +++ b/filesel.c @@ -207,7 +207,7 @@ void Read_list_of_files(byte selected_format) // Cette procédure charge dans la liste chainée les fichiers dont l'extension // correspond au format demandé. { - DIR* Repertoire_Courant; //Répertoire courant + DIR* current_directory; //Répertoire courant struct dirent* entry; // Structure de lecture des éléments char * filter = "*"; // Extension demandée struct stat Infos_enreg; @@ -225,8 +225,8 @@ void Read_list_of_files(byte selected_format) // On lit tous les répertoires: current_path=getcwd(NULL,0); - Repertoire_Courant=opendir(current_path); - while ((entry=readdir(Repertoire_Courant))) + current_directory=opendir(current_path); + while ((entry=readdir(current_directory))) { // On ignore le répertoire courant if ( !strcmp(entry->d_name, ".")) @@ -264,7 +264,7 @@ void Read_list_of_files(byte selected_format) Filelist_nb_directories ++; #endif - closedir(Repertoire_Courant); + closedir(current_directory); free(current_path); Filelist_nb_elements=Filelist_nb_directories+Filelist_nb_files; diff --git a/io.c b/io.c index fe210fb6..507700be 100644 --- a/io.c +++ b/io.c @@ -243,16 +243,16 @@ int File_length_file(FILE * file) void For_each_file(const char * directory_name, void Callback(const char *)) { // Pour scan de répertoire - DIR* Repertoire_Courant; //Répertoire courant + 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); - Repertoire_Courant=opendir(directory_name); - if(Repertoire_Courant == NULL) return; // Répertoire invalide ... + current_directory=opendir(directory_name); + if(current_directory == NULL) return; // Répertoire invalide ... strcat(full_filename, PATH_SEPARATOR); filename_position = strlen(full_filename); - while ((entry=readdir(Repertoire_Courant))) + while ((entry=readdir(current_directory))) { struct stat Infos_enreg; strcpy(&full_filename[filename_position], entry->d_name); @@ -262,6 +262,6 @@ void For_each_file(const char * directory_name, void Callback(const char *)) Callback(full_filename); } } - closedir(Repertoire_Courant); + closedir(current_directory); } From f683d9ff2e8db2620eaa584834e64e25710c89f6 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 21 Jun 2009 18:34:57 +0000 Subject: [PATCH 17/95] GUI skins: The loader now recovers cleanly from errors and displays a message that says what's the problem in the image. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@881 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 46 +++++----- init.c | 265 +++++++++++++++++++++++++++++++++++------------------- init.h | 4 +- main.c | 11 +-- struct.h | 2 +- windows.c | 41 +++++++++ windows.h | 1 + 7 files changed, 244 insertions(+), 126 deletions(-) diff --git a/buttons.c b/buttons.c index b933417f..87dce6de 100644 --- a/buttons.c +++ b/buttons.c @@ -1231,34 +1231,28 @@ void Button_Skins(void) if(clicked_button == 1) { - T_Gui_skin * gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); - if (gfx == NULL) + T_Gui_skin * gfx; + strcpy(skinsdir,"skins/"); + strcat( + skinsdir, + Get_selected_skin(skin_list->List_start+skin_list->Cursor_position)->Full_name); + gfx=Load_graphics(skinsdir); + if (gfx == NULL) // Error { - Error(0); - } - else - { - strcpy(skinsdir,"skins/"); - strcat( - skinsdir, - Get_selected_skin(skin_list->List_start+skin_list->Cursor_position)->Full_name); - Load_graphics(gfx, skinsdir); - if (0) // Error - { - free(gfx); - } - else - { - free(Gfx); - Gfx = gfx; - strcpy(Config_choisie.SkinFile,skinsdir+6); - } - } - // Font selection - if (Config_choisie.Font) - Menu_font=Gfx->Fun_font; + Verbose_error_message(Gui_loading_error_message); + } else - Menu_font=Gfx->System_font; + { + free(Gfx); + Gfx = gfx; + // Font selection + if (Config_choisie.Font) + Menu_font=Gfx->Fun_font; + else + Menu_font=Gfx->System_font; + + strcpy(Config_choisie.SkinFile,skinsdir+6); + } Config = Config_choisie ; } diff --git a/init.c b/init.c index f9554564..9f3470c4 100644 --- a/init.c +++ b/init.c @@ -66,6 +66,7 @@ #include "init.h" #include "transform.h" +char Gui_loading_error_message[512]; // Rechercher la liste et le type des lecteurs de la machine @@ -74,7 +75,7 @@ void bstrtostr( BSTR in, STRPTR out, TEXT max ); #endif // Fonctions de lecture dans la skin de l'interface graphique -void GUI_seek_down(SDL_Surface *gui, int *start_x, int *start_y, byte neutral_color,char * section) +byte GUI_seek_down(SDL_Surface *gui, int *start_x, int *start_y, byte neutral_color,char * section) { byte color; int y; @@ -86,17 +87,17 @@ void GUI_seek_down(SDL_Surface *gui, int *start_x, int *start_y, byte neutral_co if (color!=neutral_color) { *start_y=y; - return; + return 0; } y++; } while (yh); - printf("Error in skin file: Was looking down from %d,%d for a '%s', and reached the end of the image\n", + sprintf(Gui_loading_error_message, "Error in skin file: Was looking down from %d,%d for a '%s', and reached the end of the image\n", *start_x, *start_y, section); - Error(ERROR_GUI_CORRUPTED); + return 1; } -void GUI_seek_right(SDL_Surface *gui, int *start_x, int start_y, byte neutral_color, char * section) +byte GUI_seek_right(SDL_Surface *gui, int *start_x, int start_y, byte neutral_color, char * section) { byte color; int x; @@ -108,17 +109,17 @@ void GUI_seek_right(SDL_Surface *gui, int *start_x, int start_y, byte neutral_co if (color!=neutral_color) { *start_x=x; - return; + return 0; } x++; } while (xw); - printf("Error in skin file: Was looking right from %d,%d for a '%s', and reached the edege of the image\n", + sprintf(Gui_loading_error_message, "Error in skin file: Was looking right from %d,%d for a '%s', and reached the edege of the image\n", *start_x, start_y, section); - Error(ERROR_GUI_CORRUPTED); + return 1; } -void Read_GUI_block(SDL_Surface *gui, int start_x, int start_y, void *dest, int width, int height, char * section, int type) +byte Read_GUI_block(SDL_Surface *gui, int start_x, int start_y, void *dest, int width, int height, char * section, int type) { // type: 0 = normal GUI element, only 4 colors allowed // type: 1 = mouse cursor, 4 colors allowed + transparent @@ -132,9 +133,9 @@ void Read_GUI_block(SDL_Surface *gui, int start_x, int start_y, void *dest, int // Verification taille if (start_y+height>=gui->h || start_x+width>=gui->w) { - printf("Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but it doesn't fit the image.\n", + sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but it doesn't fit the image.\n", start_x, start_y, height, width, section); - Error(ERROR_GUI_CORRUPTED); + return 1; } for (y=start_y; yCursor_sprite[cursor_number][y][x]=cursor_buffer[(start_y+y)*29+start_x+x]; } -void Load_graphics(T_Gui_skin *gfx, const char * skin_file) +byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) { int index; - char filename[MAX_PATH_CHARACTERS]; - SDL_Surface * gui; - SDL_Palette * SDLPal; int i; int cursor_x=0,cursor_y=0; byte color; @@ -248,43 +249,36 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) int char_3=0; // l'une des fontes dans l'ordre : 1 2 int char_4=0; // 3 4 byte mouse_cursor_area[29][29]; + SDL_Palette * SDLPal; - // Lecture du fichier "skin" - strcpy(filename,Data_directory); - strcat(filename,skin_file); - - gui=IMG_Load(filename); - if (!gui) - { - Error(ERROR_GUI_MISSING); - } + // Default palette if (!gui->format || gui->format->BitsPerPixel != 8) { - printf("Not a 8-bit image"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Not a 8-bit image"); + return 1; } SDLPal=gui->format->palette; if (!SDLPal || SDLPal->ncolors!=256) { - printf("Not a 256-color palette"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Not a 256-color palette"); + return 1; } - // Lecture de la palette par défaut + // Read the default palette for (i=0; i<256; i++) { gfx->Default_palette[i].R=SDLPal->colors[i].r; gfx->Default_palette[i].G=SDLPal->colors[i].g; gfx->Default_palette[i].B=SDLPal->colors[i].b; } - + // Carré "noir" MC_Black = Get_SDL_pixel_8(gui,cursor_x,cursor_y); do { if (++cursor_x>=gui->w) { - printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); + return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Black); @@ -294,8 +288,8 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (++cursor_x>=gui->w) { - printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); + return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Dark); @@ -305,8 +299,8 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (++cursor_x>gui->w) { - printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); + return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Light); @@ -316,8 +310,8 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (++cursor_x>=gui->w) { - printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); + return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_White); @@ -327,8 +321,8 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (++cursor_x>=gui->w) { - printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); + return 1; } color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); } while(color==MC_Trans); @@ -343,24 +337,33 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) cursor_y++; if (cursor_y>=gui->h) { - printf("Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - Error(ERROR_GUI_CORRUPTED); + sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); + return 1; } } // Menu - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu"); - Read_GUI_block(gui, cursor_x, cursor_y, gfx->Menu_block, MENU_WIDTH, MENU_HEIGHT,"menu",0); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu")) + return 1; + if (Read_GUI_block(gui, cursor_x, cursor_y, gfx->Menu_block, MENU_WIDTH, MENU_HEIGHT,"menu",0)) + return 1; cursor_y+=MENU_HEIGHT; // Effets for (i=0; iEffect_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "effect sprite",0); + { + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "effect sprite")) + return 1; + } + if (Read_GUI_block(gui, cursor_x, cursor_y, gfx->Effect_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "effect sprite",0)) + return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; @@ -369,10 +372,17 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) for (i=0; iMenu_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1); + { + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "menu sprite")) + return 1; + } + if (Read_GUI_block(gui, cursor_x, cursor_y, gfx->Menu_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1)) + return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; @@ -398,13 +415,16 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (i!=0) cursor_y+=PAINTBRUSH_HEIGHT; - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "brush icon"); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "brush icon")) + return 1; } else { - GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "brush icon"); + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "brush icon")) + return 1; } - Read_GUI_block(gui, cursor_x, cursor_y, gfx->Paintbrush_sprite[i], PAINTBRUSH_WIDTH, PAINTBRUSH_HEIGHT, "brush icon",2); + if (Read_GUI_block(gui, cursor_x, cursor_y, gfx->Paintbrush_sprite[i], PAINTBRUSH_WIDTH, PAINTBRUSH_HEIGHT, "brush icon",2)) + return 1; cursor_x+=PAINTBRUSH_WIDTH; } cursor_y+=PAINTBRUSH_HEIGHT; @@ -413,30 +433,44 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) for (i=0; iIcon_sprite[i], ICON_SPRITE_WIDTH, ICON_SPRITE_HEIGHT, "sprite drive",1); + { + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "sprite drive")) + return 1; + } + if (Read_GUI_block(gui, cursor_x, cursor_y, gfx->Icon_sprite[i], ICON_SPRITE_WIDTH, ICON_SPRITE_HEIGHT, "sprite drive",1)) + return 1; cursor_x+=ICON_SPRITE_WIDTH; } cursor_y+=ICON_SPRITE_HEIGHT; // Logo splash screen - if (!(gfx->Logo_grafx2=(byte *)malloc(231*56))) - Error(ERROR_MEMORY); - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "logo menu"); - Read_GUI_block(gui, cursor_x, cursor_y, gfx->Logo_grafx2, 231, 56, "logo menu",3); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "logo menu")) + return 1; + if (Read_GUI_block(gui, cursor_x, cursor_y, gfx->Logo_grafx2, 231, 56, "logo menu",3)) + return 1; cursor_y+=56; // Trames for (i=0; iSieve_pattern[i],"sieve pattern"); + { + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "sieve pattern")) + return 1; + } + if (Read_GUI_pattern(gui, cursor_x, cursor_y, gfx->Sieve_pattern[i],"sieve pattern")) + return 1; cursor_x+=16; } cursor_y+=16; @@ -449,17 +483,19 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (i!=0) cursor_y+=8; - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "system font"); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "system font")) + return 1; } else { - GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "system font"); + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "system font")) + return 1; } - Read_GUI_block(gui, cursor_x, cursor_y, &gfx->System_font[i*64], 8, 8, "system font",2); + if (Read_GUI_block(gui, cursor_x, cursor_y, &gfx->System_font[i*64], 8, 8, "system font",2)) + return 1; cursor_x+=8; } cursor_y+=8; - Menu_font=gfx->System_font; // Font Fun for (i=0; i<256; i++) @@ -469,13 +505,16 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (i!=0) cursor_y+=8; - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "fun font"); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "fun font")) + return 1; } else { - GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "fun font"); + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "fun font")) + return 1; } - Read_GUI_block(gui, cursor_x, cursor_y, &gfx->Fun_font[i*64], 8, 8, "fun font",2); + if (Read_GUI_block(gui, cursor_x, cursor_y, &gfx->Fun_font[i*64], 8, 8, "fun font",2)) + return 1; cursor_x+=8; } cursor_y+=8; @@ -488,13 +527,16 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (i!=0) cursor_y+=8; - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (norm)"); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (norm)")) + return 1; } else { - GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (norm)"); + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (norm)")) + return 1; } - Read_GUI_block(gui, cursor_x, cursor_y, &(gfx->Help_font_norm[i][0][0]), 6, 8, "help font (norm)",0); + if (Read_GUI_block(gui, cursor_x, cursor_y, &(gfx->Help_font_norm[i][0][0]), 6, 8, "help font (norm)",0)) + return 1; cursor_x+=6; } cursor_y+=8; @@ -507,13 +549,16 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (i!=0) cursor_y+=8; - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (bold)"); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (bold)")) + return 1; } else { - GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (bold)"); + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (bold)")) + return 1; } - Read_GUI_block(gui, cursor_x, cursor_y, &(gfx->Bold_font[i][0][0]), 6, 8, "help font (bold)",0); + if (Read_GUI_block(gui, cursor_x, cursor_y, &(gfx->Bold_font[i][0][0]), 6, 8, "help font (bold)",0)) + return 1; cursor_x+=6; } cursor_y+=8; @@ -527,11 +572,13 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) { if (i!=0) cursor_y+=8; - GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (title)"); + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (title)")) + return 1; } else { - GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (title)"); + if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (title)")) + return 1; } if (i&1) @@ -545,14 +592,12 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) else dest=&(gfx->Help_font_t1[char_1++][0][0]); - Read_GUI_block(gui, cursor_x, cursor_y, dest, 6, 8, "help font (title)",0); + if (Read_GUI_block(gui, cursor_x, cursor_y, dest, 6, 8, "help font (title)",0)) + return 1; cursor_x+=6; } cursor_y+=8; - // Terminé: libération de l'image skin - SDL_FreeSurface(gui); - Current_help_section=0; Help_position=0; @@ -753,7 +798,41 @@ void Load_graphics(T_Gui_skin *gfx, const char * skin_file) gfx->Preset_paintbrush_offset_X[index]=(gfx->Preset_paintbrush_width [index]>>1); gfx->Preset_paintbrush_offset_Y[index]=(gfx->Preset_paintbrush_height[index]>>1); } + return 0; +} +T_Gui_skin * Load_graphics(const char * skin_file) +{ + T_Gui_skin * gfx; + char filename[MAX_PATH_CHARACTERS]; + SDL_Surface * gui; + + gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); + if (gfx == NULL) + { + sprintf(Gui_loading_error_message, "Not enough memory to read skin file\n"); + return NULL; + } + + // Read the "skin" file + strcpy(filename,Data_directory); + strcat(filename,skin_file); + + gui=IMG_Load(filename); + if (!gui) + { + sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); + free(gfx); + return NULL; + } + if (Parse_skin(gui, gfx)) + { + SDL_FreeSurface(gui); + free(gfx); + return NULL; + } + SDL_FreeSurface(gui); + return gfx; } diff --git a/init.h b/init.h index 7b5d5cc1..6a28c728 100644 --- a/init.h +++ b/init.h @@ -22,7 +22,7 @@ /// Initialization (and some de-initialization) functions. ////////////////////////////////////////////////////////////////////////////// -void Load_graphics(T_Gui_skin *gfx, const char * skin_file); +T_Gui_skin *Load_graphics(const char * skin_file); void Init_buttons(void); void Init_operations(void); int Load_CFG(int reload_all); @@ -30,3 +30,5 @@ int Save_CFG(void); void Set_all_video_modes(void); void Set_config_defaults(void); void Init_sighandler(void); + +extern char Gui_loading_error_message[512]; diff --git a/main.c b/main.c index e15c054e..956d09c7 100644 --- a/main.c +++ b/main.c @@ -534,12 +534,13 @@ int Init_program(int argc,char * argv[]) Analyze_command_line(argc,argv); // Load sprites, palette etc. - Gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); - if (Gfx == NULL) - Error(ERROR_MEMORY); strcpy(Gui_skin_file+6,Config.SkinFile); - Load_graphics(Gfx, Gui_skin_file); - + Gfx = Load_graphics(Gui_skin_file); + if (Gfx == NULL) + { + printf("%s", Gui_loading_error_message); + Error(ERROR_GUI_MISSING); + } // Infos sur les trames (Sieve) Sieve_mode=0; Copy_preset_sieve(0); diff --git a/struct.h b/struct.h index 879bf44d..ad0a107d 100644 --- a/struct.h +++ b/struct.h @@ -362,7 +362,7 @@ typedef struct /// Bitmap data for the different "effects" icons. byte Effect_sprite[NB_EFFECTS_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. - byte * Logo_grafx2; + byte Logo_grafx2[231*56]; /// Bitmap data for the 6x8 font used in help screens. byte Help_font_norm [256][6][8]; /// Bitmap data for the 6x8 font used in help screens ("bold" verstion). diff --git a/windows.c b/windows.c index 24191a72..b7b29291 100644 --- a/windows.c +++ b/windows.c @@ -860,6 +860,47 @@ void Warning_message(char * message) Display_cursor(); } +//---- Window that shows a big message, and waits for a click on OK ----- +void Verbose_error_message(char * message) +{ + short clicked_button; + int line; + int i; + char buffer[36]; // 35 characters + \0 + + Open_window(300,160,"Error!"); + + // Word-wrap the message + for (line=0; line < 10; line++) + { + for (i=0;i<35 && *message!='\0';i++) + { + if (*message == '\n') + { + message++; + break; + } + buffer[i]=*message; + message++; + } + buffer[i]='\0'; + Print_in_window(10,20+line*8,buffer,MC_Black,MC_Light); + if (*message=='\0') + break; + } + + Window_set_normal_button(300/2-20,160-23,40,14,"OK",1,1,SDLK_RETURN); // 1 + Update_window_area(0,0,Window_width,Window_height); + Display_cursor(); + + do + clicked_button=Window_clicked_button(); + while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); + Key=0; + + Close_window(); + Display_cursor(); +} // -- Redessiner le sprite d'un bouton dans le menu -- diff --git a/windows.h b/windows.h index 219ba3da..7feff36f 100644 --- a/windows.h +++ b/windows.h @@ -70,6 +70,7 @@ void Print_counter(short x,short y,const char * str,byte text_color,byte backgro byte Confirmation_box(char * message); void Warning_message(char * message); +void Verbose_error_message(char * message); void Display_image_limits(void); void Display_all_screen(void); From 5a01415960b947e225bf2bd7298c56578ced03e9 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 22 Jun 2009 17:35:52 +0000 Subject: [PATCH 18/95] GUI Generic list control: now takes cursors and mousewheel shortcuts. Still some mouse cursor problems, but almost done. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@882 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 142 +-------------------------------------------- engine.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 141 deletions(-) diff --git a/buttons.c b/buttons.c index 87dce6de..ff7253cf 100644 --- a/buttons.c +++ b/buttons.c @@ -5501,147 +5501,7 @@ void Button_Text() clicked_button=Window_clicked_button(); if (clicked_button==0) - {/* - if (Key==SDLK_UP && (cursor_position+list_start)>0) - { - Key=0; - Hide_cursor(); - cursor_position--; - if (cursor_position<0) - { - list_start=list_start+cursor_position; - cursor_position=0; - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - } - redraw_is_needed=1; - preview_is_needed=1; - } - if (Key==SDLK_DOWN && (cursor_position+list_start)<(Nb_fonts-1)) - { - Key=0; - Hide_cursor(); - cursor_position++; - if (cursor_position>(NB_FONTS-1)) - { - list_start=list_start+cursor_position-(NB_FONTS-1); - cursor_position=(NB_FONTS-1); - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - } - redraw_is_needed=1; - preview_is_needed=1; - } - if (Key==SDLK_HOME && (cursor_position!=0 || list_start!=0)) - { - Key=0; - Hide_cursor(); - cursor_position=0; - list_start=0; - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - redraw_is_needed=1; - preview_is_needed=1; - } - if (Key==SDLK_END && (cursor_position+list_start)<(Nb_fonts-1)) - { - Key=0; - Hide_cursor(); - cursor_position=(Nb_fonts-1)-list_start; - if (cursor_position>(NB_FONTS-1)) - { - list_start=list_start+cursor_position-(NB_FONTS-1); - cursor_position=(NB_FONTS-1); - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - } - redraw_is_needed=1; - preview_is_needed=1; - } - if (Key==SDLK_PAGEDOWN && (cursor_position+list_start)<(Nb_fonts-1)) - { - Key=0; - Hide_cursor(); - if (Nb_fontsNb_fonts) - { - list_start=Nb_fonts-NB_FONTS; - } - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - } - redraw_is_needed=1; - preview_is_needed=1; - } - if (Key==SDLK_PAGEUP && (cursor_position+list_start)>0) - { - Key=0; - Hide_cursor(); - if(cursor_position!=0) - { - cursor_position=0; - } - else - { - list_start-=NB_FONTS; - if (list_start<0) - { - list_start=0; - } - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - } - redraw_is_needed=1; - preview_is_needed=1; - } - if (Key == KEY_MOUSEWHEELUP && list_start>0) - { - cursor_position+=list_start; - if (list_start>=3) - list_start-=3; - else - list_start=0; - cursor_position-=list_start; - // On affiche à nouveau la liste - Hide_cursor(); - redraw_is_needed=1; - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - } - if (Key==KEY_MOUSEWHEELDOWN && list_startNb_fonts) - { - list_start=Nb_fonts-NB_FONTS; - } - cursor_position-=list_start; - // On affiche à nouveau la liste - Hide_cursor(); - redraw_is_needed=1; - // Mise à jour du scroller - font_scroller->Position=list_start; - Window_draw_slider(font_scroller); - } - */ + { if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_TEXT, NULL); } diff --git a/engine.c b/engine.c index 600fd077..99bd3510 100644 --- a/engine.c +++ b/engine.c @@ -2654,12 +2654,180 @@ short Window_clicked_button(void) // Intercept keys if (Key) { + T_List_button * list; + Button=Window_get_button_shortcut(); if (Button) { Key=0; return Button; } + // Check if there's a list control and the keys can control it + for (list=Window_list_button_list; list!=NULL; list=list->Next) + { + // FIXME: Make only one list have the keyboard focus. + if (1) + { + if (Key==SDLK_UP && (list->Cursor_position+list->List_start)>0) + { + Key=0; + Hide_cursor(); + list->Cursor_position--; + if (list->Cursor_position<0) + { + list->List_start=list->List_start+list->Cursor_position; + list->Cursor_position=0; + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + } + Window_redraw_list(list);// reduce redraw? + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + if (Key==SDLK_DOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) + { + Key=0; + Hide_cursor(); + list->Cursor_position++; + if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) + { + list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); + list->Cursor_position=(list->Scroller->Nb_visibles-1); + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + } + Window_redraw_list(list);// reduce redraw? + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + if (Key==SDLK_HOME && (list->Cursor_position!=0 || list->List_start!=0)) + { + Key=0; + Hide_cursor(); + list->Cursor_position=0; + list->List_start=0; + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + Window_redraw_list(list);// reduce redraw? + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + if (Key==SDLK_END && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) + { + Key=0; + Hide_cursor(); + list->Cursor_position=(list->Scroller->Nb_elements-1)-list->List_start; + if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) + { + list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); + list->Cursor_position=(list->Scroller->Nb_visibles-1); + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + } + Window_redraw_list(list);// reduce redraw? + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + if (Key==SDLK_PAGEDOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) + { + Key=0; + Hide_cursor(); + if (list->Scroller->Nb_elementsScroller->Nb_visibles) + { + list->Cursor_position=list->Scroller->Nb_elements-1; + } + else if(list->Cursor_position!=list->Scroller->Nb_visibles-1) + { + list->Cursor_position=list->Scroller->Nb_visibles-1; + } + else + { + list->List_start+=list->Scroller->Nb_visibles; + if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) + { + list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; + } + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + } + Window_redraw_list(list);// reduce redraw? + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + if (Key==SDLK_PAGEUP && (list->Cursor_position+list->List_start)>0) + { + Key=0; + Hide_cursor(); + if(list->Cursor_position!=0) + { + list->Cursor_position=0; + } + else + { + list->List_start-=list->Scroller->Nb_visibles; + if (list->List_start<0) + { + list->List_start=0; + } + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + } + Window_redraw_list(list);// reduce redraw? + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + if (Key == KEY_MOUSEWHEELUP && list->List_start>0) + { + list->Cursor_position+=list->List_start; + if (list->List_start>=3) + list->List_start-=3; + else + list->List_start=0; + list->Cursor_position-=list->List_start; + // On affiche à nouveau la liste + Hide_cursor(); + Window_redraw_list(list);// reduce redraw? + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + } + if (Key==KEY_MOUSEWHEELDOWN && list->List_startScroller->Nb_elements-list->Scroller->Nb_visibles) + { + list->Cursor_position+=list->List_start; + list->List_start+=3; + if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) + { + list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; + } + list->Cursor_position-=list->List_start; + // On affiche à nouveau la liste + Hide_cursor(); + Window_redraw_list(list);// reduce redraw? + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + } + + } + } } return 0; From 230baa77e7c1eb7a9c8419fb30f839216ebb32b7 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 22 Jun 2009 21:30:54 +0000 Subject: [PATCH 19/95] GUI Listboxes: fixed mouse cursor display while using keyboard; Skin selector: tweaked position and made it ignore files that don't end in .PNG .GIF, or those that start with '_'; Added 2 old fonts and 2 new ones (thanks Ilkke) as files skins/_fontname.png git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@883 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 31 ++++++++++++++++++++----------- engine.c | 24 ++++++++++++++++-------- skins/_classic.png | Bin 0 -> 2634 bytes skins/_fairlight.png | Bin 0 -> 2681 bytes skins/_fun.png | Bin 0 -> 2728 bytes skins/_melon.png | Bin 0 -> 2715 bytes 6 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 skins/_classic.png create mode 100644 skins/_fairlight.png create mode 100644 skins/_fun.png create mode 100644 skins/_melon.png diff --git a/buttons.c b/buttons.c index ff7253cf..ec5eecd0 100644 --- a/buttons.c +++ b/buttons.c @@ -962,19 +962,28 @@ void Button_Settings(void) void Add_skin(const char *name) { char * fname; - - Add_element_to_list(name, 0); - Filelist_nb_elements++; + int namelength; // Cut the long name to keep only filename (no directory) - fname = Find_last_slash(Filelist->Full_name); - if (fname[0]=='\0') - return; - - strcpy(Filelist->Full_name, fname+1); + fname = Find_last_slash(name); + if (fname) + fname++; + else + fname=name; + namelength = strlen(fname); + if (namelength>=5 && fname[0]!='_' && (!stricmp(fname+namelength-4,".png") || !stricmp(fname+namelength-4,".gif"))) + { + Add_element_to_list(name, 0); + Filelist_nb_elements++; + + if (fname[0]=='\0') + return; - // Reformat the short name - strcpy(Filelist->Short_name,Format_filename(Filelist->Full_name, 0)); + strcpy(Filelist->Full_name, fname); + + // Reformat the short name + strcpy(Filelist->Short_name,Format_filename(Filelist->Full_name, 0)); + } } @@ -1055,7 +1064,7 @@ void Button_Skins(void) // List of skins skin_list = Window_set_list_button( // Fileselector - Window_set_special_button(9,FILESEL_Y+2,144,80), // 2 + Window_set_special_button(8,FILESEL_Y+1,144,80), // 2 // Scroller du fileselector (file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82,Filelist_nb_elements,10,selector_position)), // 3 Draw_one_skin_name); // 4 diff --git a/engine.c b/engine.c index 99bd3510..e133065c 100644 --- a/engine.c +++ b/engine.c @@ -2681,7 +2681,8 @@ short Window_clicked_button(void) list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } - Window_redraw_list(list);// reduce redraw? + 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. @@ -2700,7 +2701,8 @@ short Window_clicked_button(void) list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } - Window_redraw_list(list);// reduce redraw? + 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. @@ -2715,7 +2717,8 @@ short Window_clicked_button(void) // Mise à jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); - Window_redraw_list(list);// reduce redraw? + 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. @@ -2734,7 +2737,8 @@ short Window_clicked_button(void) list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } - Window_redraw_list(list);// reduce redraw? + 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. @@ -2763,7 +2767,8 @@ short Window_clicked_button(void) list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } - Window_redraw_list(list);// reduce redraw? + 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. @@ -2788,7 +2793,8 @@ short Window_clicked_button(void) list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); } - Window_redraw_list(list);// reduce redraw? + 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. @@ -2804,10 +2810,11 @@ short Window_clicked_button(void) list->Cursor_position-=list->List_start; // On affiche à nouveau la liste Hide_cursor(); - Window_redraw_list(list);// reduce redraw? + Window_redraw_list(list); // Mise à jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); + Display_cursor(); } if (Key==KEY_MOUSEWHEELDOWN && list->List_startScroller->Nb_elements-list->Scroller->Nb_visibles) { @@ -2820,10 +2827,11 @@ short Window_clicked_button(void) list->Cursor_position-=list->List_start; // On affiche à nouveau la liste Hide_cursor(); - Window_redraw_list(list);// reduce redraw? + Window_redraw_list(list); // Mise à jour du scroller list->Scroller->Position=list->List_start; Window_draw_slider(list->Scroller); + Display_cursor(); } } diff --git a/skins/_classic.png b/skins/_classic.png new file mode 100644 index 0000000000000000000000000000000000000000..8db8d5fcef4096bf8aaf63fdfa56f602ddb2e463 GIT binary patch literal 2634 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 literal 0 HcmV?d00001 diff --git a/skins/_fun.png b/skins/_fun.png new file mode 100644 index 0000000000000000000000000000000000000000..a1e36addebfe482da2491d8d1ebcfc775cc254ca GIT binary patch literal 2728 zcmeH}`#%%<1I9lyY_4OuE0#p4Hb!*8Ft+5DIpuz9$clxzl*>kP$t5HbCqp6!QEkRi zmdGU$tw_X4qU2VHjD0(Q$M-xxJg?{VdVYG|KRxMA4g@K26>$K7)Nvx-834%d2yk%d zZ*RZsmI(k9IN7;a15hmx2>$K<(|-j1{|JzgP4mB3BWTvHG!iwC7VQ@v00`lJfiVWm zauNjq81XpX!X>6;+ASkb^)OscAb4GP6*e1+%X?gGU+JLZp(gcl(C}>F!&8#jXB)#! z=%x6!>_0M&hHu@9^nrVvOgZ7F&a2ZM>#LG=&oaD4_ny;1areK|3g1}mtB>A$TlVJJ z3V9eeL2&M)-gYvWIdD3-^0|Qj18t>ws`lA)_%qb2;WvAllo;~4dnY>-c|HJGx?;~% z=O=sOCsl!(dMVd2qK5+*>4nIc3$!X1>H$a)!{kE&Zm>|~80Ltw%<;Q+^lpYQ(*!;p z^%Rh$g_t;;O_LL7~v^FjWOjIlva}e0%W$RAY$(H0@f|cUrN&X3W;kP$!Ll5 z;`f~M&*>2VZVJV7ikd3&M}3s`<_+XymL~K+t>?~wN#g?d{?eE!Bf{FlKxV-`-g(*A z!~{vZgDU(>K+S3db=aS|rl)1bW-ogrjFLLF^p@Y-t$v$wG%h|`&68!rVc`~+-muzp zGS)kHoiElQ`BrX;;Rfu^89oABd(%T2PYOtueszPk&BrjjurvnI_YPa9NR*)^6=HlE zRC}aoBMxdDo;AgQq0IX4xk(9_>Bb9e1#Qt1xNYU+@-xzyFm4_aA~kdeawABcnZYV{ z@}6H?+sx4eFE+2xZy-%HMvcpovsyS8SrH#AA9dIE7ILHIH=$EqlJS(nTpQFJt5q^! z

ZQ^DywZ#0vgF1e3jskn@APg|&bUJ!{Yl(Z>LQ=7XMRbllKYCj&7Rl#EKJ{9Kh zNeBqYX|5W{Mw$v!bl!$${9W>p{~l{SR^bSs_f71K@K$k6LOLOUlGv?4SFGqZN@zPZ zhh{@=$Eb#PEOS=kE+%y%u+*>)gO;KwRGBc%peKiuM91o_V$G^8df=$Llp)3YhN7H9 zbFffig7D5en3_CG^pdsv;K2{!RVbXOiTK?B35MQD;HnL{KT#9#nsgF84V@F0{(!Fn zTt_o+&e3{M%Q~;};m#J2eZNrEiIy%%*ZOv+BO(U0FY(H=f&`4@fqf6sx+Bf^KJ@9_ zc)jH;Z*4!Z6Aff^=j*8W(5}?YRIM~4&U#Azj(jA`Bj?(}<8?D5B7ZLIMpbC2)=vwd z@|{xO94#Xv1}+=7^om6+Dk?M68ty6I4n8lN=;zX$yM_Q;)Z#$bU=2=WG^b5&?;pj`_>CQP@4{}qNr%*K`KqJ#P_)MIH04AGF{}XUW(SzzeyAfBP*iL%(La9 z=R2FKwqkUtrHUpqyP%)ryZ=cQ@dAY^f}Y)3tOI5IB9`O$PF-BhAM6N($^yaoxpr5D z8T9d&$W6Epe~F9h|E27%tauSM6}ZpxDa>?iJlb?JNLyV@XR|i+>^%OTDxqGkAvAv= z;jrh@&Dfc}FgSkK!XyHtrH=vRduH3X^01JS^jmBc&UV;j!0xi8^Ch3YPvco}qN=E{ z%=cM(pIZ=cnau7D_(|c=(}~QmzU{g=zuV4iCyvvxCB)}Hl`g<=z84f_;tZODp6`!a z=DZu}%Xb&85&Ftl3?!yF1!Ir477bo+m0_&5nm^%eQ4t-l)?xYLZ-!`9Wh&K z4?oo4(ug*{Q^X+x?)&t&wlJeS(V8wj-p@__xh9*fuEdsy-2?g!vjY&6WD9((J+>|&maYJMeo-o-8Bd_D vn1um(cAu9tJTzs3ir5@lC{-6K@e#nBW98H*^dcMoJsHQX9q{#*zDfTB$NYdq literal 0 HcmV?d00001 diff --git a/skins/_melon.png b/skins/_melon.png new file mode 100644 index 0000000000000000000000000000000000000000..efa4d4f0131f5c7ce1e791e6465f7e6a45c08b13 GIT binary patch literal 2715 zcmeH}`9Bl>1IORnG@GMQDrRXCa^=b=M`4*enIlJi9Q&?_oJ06JwjspaNBHzXIieLB zLJBoWA!igSM_J^aBVqgc{2kxV>xb9l^?1B~dcA&n-X>f$6&64X004x|&G5DWK=vXq zM8Nj^Rje}|02m-#ur~&vg2&@UH*Eh?|Eqr=_&=bP0?-3kIBwquj zWTHoyM)7?+Zvgo9%<(w;u)80elgTnVh&Uc^w)q+2hhMtM^qXCP~ezu5hlndP%(66XHb++4Dre4=;EiCHs9V#F(t-j6q_S_p0 z=oPw9*KYwPc)P+YS`=F<$AM8dFzrTJnMsWMuItmShJo%ryG-r?P9_f2gKh*03?L?1 z^n11kyhUlpfRlbzThUBzAOsv#m8}U7dSLIbN^_@b>*pE{I_`T;3|7ZxUC8IAL-rX4 ziM(5gfplW{3~5xllmtQB(mF#bph6w)$4cy=-bExup$vQL?wYoG7j=|^|78$jC6wuei}s)*P@KRz+ih5h@oHs3N6r!>PDk&MT9SeyhyTme$>Rs z7)U}cETQJuaVQ+qAWKLg-~lyJ7ccG5OmcTsugA7z*mbN9U=rr-BY&5|s1Sr<)M3Yn zsio_o&t!>{TcXZ2d=b?I38rL@!KBRs8;%YuaP)Uun@%FZM4f*nv#FFE+-|!^`4~5=`&fwEmf2M5!1ZD7Dp(^K`vdJ#Wq};ggRutn-$O_X@%@>^&LbM0>6!r{ zC@SrKx4qLzclrB*Dw?tH7c)zYX6%mU8o>-T=nwg*t9c^nUmVM}gGdbCTQ#sI7)w^u zmA9PA&&?BAY$iswP^Jl=m&p2KgK}B5O)juyj2UcLejQzyH-FClw3#aL(qb@9YpD6~ zA8FF)MdN*rde-4D*Bh^5OP2`jc85Ax+oYt6=S}f$gkoQ1xEFw)wt>LjUa(T7!-u9+ zNE9)j+eH}!I}w91zZ&6uYJ_lLPaI1IrlS^Pt>CaS%eWMAU*7ZdMmNI{H4ue=l;V8^?r7a0yVnnjR4JUlD7(A+=#SE!3 zPi+N}>Q3BUZpy$Ghd)VwUH-44%J>u$whl;j-0oQ$(7gA^lGU7eyk*pFvbZess{nsm zuu{)U!Y|(=3T!wpGwAF4BA7_dm3Vnx^SKPP_kXe|kIeZF@GO4<G|PQj9{abj_CVBTU=l9bEihlw)ChdA^$^{O~F(^1GU+9ej#>5gZ{MB=*HLoBz8V ztoV~77Sq8jF6NgqwAAF~~QapY^^#+cpKujg$#MdCGI6ELpIdCgeXxxFmt|9%C~EsH@uTOK5JL?1%fja1PDw`dSgfrh4}A4$kfZ~`6* zc_~=C)h<3LwTy&e#9Y^?@}MGj`gh>|VByQJoTZR8puwN+@5dX2sRwgGS__`5qk={x#p^{SqPbHyZJPs$@AMI)%7ZE sssM_6$}m7PGWy)km1YVB5fHeGN Date: Mon, 22 Jun 2009 21:42:28 +0000 Subject: [PATCH 20/95] Linux build fix. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@884 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/buttons.c b/buttons.c index ec5eecd0..a68c76af 100644 --- a/buttons.c +++ b/buttons.c @@ -958,6 +958,11 @@ void Button_Settings(void) Set_number_of_backups(Config.Max_undo_pages); } +// POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. +#ifdef __linux__ + #define stricmp strcasecmp +#endif + // Add a skin to the list void Add_skin(const char *name) { From ab9671b2865e126886329a331c7fd19df1f69cb4 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 23 Jun 2009 21:04:58 +0000 Subject: [PATCH 21/95] Separated font graphics from skin graphics. WIP, a lot is still hard-coded (font list) or not coded at all (save/load in ini, and match in skin selection screen). git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@885 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 38 ++++-- gfx2def.ini | 5 - global.h | 2 +- init.c | 120 ++++++++++++------- init.h | 8 ++ main.c | 13 +- readini.c | 6 - saveini.c | 4 - skins/classic.png | Bin 18907 -> 14352 bytes skins/{_classic.png => font_Classic.png} | Bin skins/{_fairlight.png => font_Fairlight.png} | Bin skins/{_fun.png => font_Fun.png} | Bin skins/{_melon.png => font_Melon.png} | Bin skins/modern.png | Bin 21169 -> 16553 bytes struct.h | 11 +- 15 files changed, 124 insertions(+), 83 deletions(-) rename skins/{_classic.png => font_Classic.png} (100%) rename skins/{_fairlight.png => font_Fairlight.png} (100%) rename skins/{_fun.png => font_Fun.png} (100%) rename skins/{_melon.png => font_Melon.png} (100%) diff --git a/buttons.c b/buttons.c index a68c76af..f530a3a2 100644 --- a/buttons.c +++ b/buttons.c @@ -1035,6 +1035,10 @@ void Button_Skins(void) T_Dropdown_button * cursor_dropdown; T_List_button * skin_list; T_Scroller_button * file_scroller; + int selected_font=0; + + char * fonts[] = {"Classic", "Fun", "Melon", "Fairlight"}; + int nb_fonts = 4; #define FILESEL_Y 52 @@ -1075,9 +1079,11 @@ void Button_Skins(void) Draw_one_skin_name); // 4 // Boutons de fontes - font_dropdown = Window_set_dropdown_button(60,19,70,11,0,(Config_choisie.Font==0)?"Classic":"Fun ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 - Window_dropdown_add_item(font_dropdown,0,"Classic"); - Window_dropdown_add_item(font_dropdown,1,"Fun "); + font_dropdown = Window_set_dropdown_button(60,19,70,11,0, fonts[selected_font],1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 + for (temp=0; tempFun_font; - else - Menu_font=Gfx->System_font; + new_font = Load_font(fonts[selected_font]); + if (new_font) + { + free(Menu_font); + Menu_font = new_font; + if (Config_choisie.Font_name) + { + free (Config_choisie.Font_name); + Config_choisie.Font_name = NULL; + } + Config_choisie.Font_name = (char *)malloc(strlen(fonts[selected_font])+1); + if (Config_choisie.Font_name) + { + strcpy(Config_choisie.Font_name,fonts[selected_font]); + } + } strcpy(Config_choisie.SkinFile,skinsdir+6); } diff --git a/gfx2def.ini b/gfx2def.ini index 752096b8..4f5382ef 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -76,11 +76,6 @@ ; the menus and tool-bar | des menus et de la barre d'outils Menu_ratio = 1 ; (default 1) - ; Font: | Police de caractères (fonte): - ; 1: Classic | 1: Classique - ; 2: Fun | 2: Fun - Font = 1 ; (default 1) - [FILE_SELECTOR] # [SELECTEUR_DE_FICHIERS] ; Show hidden files and | Afficher les fichiers et répertoires diff --git a/global.h b/global.h index 3980a64b..0542ea6b 100644 --- a/global.h +++ b/global.h @@ -794,7 +794,7 @@ GFX2_GLOBAL byte Resolution_in_command_line; // - Graphic -/// Pointer to the font selected for menus. It's either ::Gfx->System_font or ::Gfx->Fun_font +/// Pointer to the font selected for menus. GFX2_GLOBAL byte * Menu_font; /// Pointer to the current active skin. diff --git a/init.c b/init.c index 9f3470c4..c917b99e 100644 --- a/init.c +++ b/init.c @@ -474,50 +474,6 @@ byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) cursor_x+=16; } cursor_y+=16; - - // Font Système - for (i=0; i<256; i++) - { - // Rangés par ligne de 32 - if ((i%32)==0) - { - if (i!=0) - cursor_y+=8; - if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "system font")) - return 1; - } - else - { - if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "system font")) - return 1; - } - if (Read_GUI_block(gui, cursor_x, cursor_y, &gfx->System_font[i*64], 8, 8, "system font",2)) - return 1; - cursor_x+=8; - } - cursor_y+=8; - - // Font Fun - for (i=0; i<256; i++) - { - // Rangés par ligne de 32 - if ((i%32)==0) - { - if (i!=0) - cursor_y+=8; - if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "fun font")) - return 1; - } - else - { - if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "fun font")) - return 1; - } - if (Read_GUI_block(gui, cursor_x, cursor_y, &gfx->Fun_font[i*64], 8, 8, "fun font",2)) - return 1; - cursor_x+=8; - } - cursor_y+=8; // Font help normale for (i=0; i<256; i++) @@ -835,6 +791,82 @@ T_Gui_skin * Load_graphics(const char * skin_file) return gfx; } +// ---- font loading ----- + +byte Parse_font(SDL_Surface * image, byte * font) +{ + int character; + byte color; + int x, y; + int chars_per_line; + + // Check image size + if (image->w % 8) + { + sprintf(Gui_loading_error_message, "Error in font file: Image width is not a multiple of 8.\n"); + return 1; + } + if (image->w * image->h < 8*8*256) + { + sprintf(Gui_loading_error_message, "Error in font file: Image is too small to be a 256-character 8x8 font.\n"); + return 1; + } + chars_per_line = image->w/8; + + for (character=0; character < 256; character++) + { + for (y=0; y<8; y++) + { + for (x=0;x<8; x++) + { + // Pick pixel + color = Get_SDL_pixel_8(image, (character % chars_per_line)*8+x, (character / chars_per_line)*8+y); + if (color > 1) + { + sprintf(Gui_loading_error_message, "Error in font file: Only colors 0 and 1 can be used for the font.\n"); + return 1; + } + // Put it in font. 0 = BG, 1 = FG. + font[character*64 + y*8 + x]=color; + } + } + } + return 0; +} + +byte * Load_font(const char * font_name) +{ + byte * font; + char filename[MAX_PATH_CHARACTERS]; + SDL_Surface * image; + + font = (byte *)malloc(8*8*256); + if (font == NULL) + { + sprintf(Gui_loading_error_message, "Not enough memory to read font file\n"); + return NULL; + } + + // Read the file containing the image + sprintf(filename,"%sskins%sfont_%s.png", Data_directory, PATH_SEPARATOR, font_name); + + image=IMG_Load(filename); + if (!image) + { + sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); + free(font); + return NULL; + } + if (Parse_font(image, font)) + { + SDL_FreeSurface(image); + free(font); + return NULL; + } + SDL_FreeSurface(image); + return font; +} + // Initialisation des boutons: diff --git a/init.h b/init.h index 6a28c728..86053986 100644 --- a/init.h +++ b/init.h @@ -32,3 +32,11 @@ void Set_config_defaults(void); void Init_sighandler(void); extern char Gui_loading_error_message[512]; + +/// +/// Loads a 8x8 monochrome font, the kind used in all menus and screens. +/// This function allocates the memory, and returns a pointer to it when +/// successful. +/// If an error is encountered, it frees what needs it, prints an error message +/// in ::Gui_loading_error_message, and returns NULL. +byte * Load_font(const char * font_name); diff --git a/main.c b/main.c index 956d09c7..c76df867 100644 --- a/main.c +++ b/main.c @@ -555,11 +555,14 @@ int Init_program(int argc,char * argv[]) Fore_color=MC_White; Back_color=MC_Black; - // Prise en compte de la fonte - if (Config.Font) - Menu_font=Gfx->Fun_font; - else - Menu_font=Gfx->System_font; + // Font + { + byte *font; + font = Load_font("Classic"); + if (font) + Menu_font=font; + } + memcpy(Main_palette, Gfx->Default_palette, sizeof(T_Palette)); diff --git a/readini.c b/readini.c index f1594c1d..bef5316f 100644 --- a/readini.c +++ b/readini.c @@ -523,12 +523,6 @@ int Load_INI(T_Config * conf) goto Erreur_ERREUR_INI_CORROMPU; conf->Ratio=values[0]; - if ((return_code=Load_INI_get_values (file,buffer,"Font",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>2)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Font=values[0]-1; - if ((return_code=Load_INI_reach_group(file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; diff --git a/saveini.c b/saveini.c index 4130624a..2bf95c04 100644 --- a/saveini.c +++ b/saveini.c @@ -476,10 +476,6 @@ int Save_INI(T_Config * conf) if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Menu_ratio",1,values,0))) goto Erreur_Retour; - values[0]=(conf->Font)+1; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Font",1,values,0))) - goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; diff --git a/skins/classic.png b/skins/classic.png index 8de524a29ab04044a66ccd5df160210d7c4158ed..6ce4c0242df329b00125dbb4f38ba73843b89352 100644 GIT binary patch delta 13630 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 literal 18907 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 SevVpzG#!XIw68JzM8SU*=CLyX diff --git a/skins/_classic.png b/skins/font_Classic.png similarity index 100% rename from skins/_classic.png rename to skins/font_Classic.png diff --git a/skins/_fairlight.png b/skins/font_Fairlight.png similarity index 100% rename from skins/_fairlight.png rename to skins/font_Fairlight.png diff --git a/skins/_fun.png b/skins/font_Fun.png similarity index 100% rename from skins/_fun.png rename to skins/font_Fun.png diff --git a/skins/_melon.png b/skins/font_Melon.png similarity index 100% rename from skins/_melon.png rename to skins/font_Melon.png diff --git a/skins/modern.png b/skins/modern.png index d0f72fa09c4eb03e51d857d1ab75a1ca9348a783..4247fc1465046c339403cac0cf5c9a288974e065 100644 GIT binary patch delta 15846 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 literal 21169 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 diff --git a/struct.h b/struct.h index ad0a107d..38f9ab6d 100644 --- a/struct.h +++ b/struct.h @@ -240,8 +240,8 @@ typedef struct /// This structure holds all the settings which are saved and loaded as gfx2.ini. typedef struct { - byte Font; ///< Boolean, true to use the "fun" font in menus, false to use the classic one. - char SkinFile[64]; ///< String, name of the file where all the graphic data is stored + char *Font_name; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) + char SkinFile[64]; ///< String, name of the file where all the graphic data is stored int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. // int Show_system_directories; ///< (removed when converted from DOS) @@ -380,13 +380,6 @@ typedef struct /// Bitmap data for the small 8x8 icons. byte Icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; - // 8x8 fonts - - /// Bitmap data for the classic 8x8 font used in menus etc. - byte System_font[256*8*8]; - /// Bitmap data for the "fun" 8x8 font used in menus etc. - byte Fun_font [256*8*8]; - /// A default 256-color palette. T_Palette Default_palette; From 67dbb218a2e4a527e115ed9be6ab12136faa2ee7 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 28 Jun 2009 18:19:21 +0000 Subject: [PATCH 22/95] GUI skins and fileselectors: cleaned up a little git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@886 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 52 +++------ filesel.c | 309 +++++++++++++++++++++++++++++++----------------------- filesel.h | 15 +++ global.h | 11 -- main.c | 2 +- struct.h | 21 ++++ 6 files changed, 233 insertions(+), 177 deletions(-) diff --git a/buttons.c b/buttons.c index f530a3a2..218eaf69 100644 --- a/buttons.c +++ b/buttons.c @@ -958,15 +958,13 @@ void Button_Settings(void) Set_number_of_backups(Config.Max_undo_pages); } -// POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. -#ifdef __linux__ - #define stricmp strcasecmp -#endif +// Data for skin selector +T_Fileselector Skin_files_list; // Add a skin to the list void Add_skin(const char *name) { - char * fname; + const char * fname; int namelength; // Cut the long name to keep only filename (no directory) @@ -976,33 +974,18 @@ void Add_skin(const char *name) else fname=name; namelength = strlen(fname); - if (namelength>=5 && fname[0]!='_' && (!stricmp(fname+namelength-4,".png") || !stricmp(fname+namelength-4,".gif"))) + if (namelength>=5 && fname[0]!='_' && (!strcasecmp(fname+namelength-4,".png") || !strcasecmp(fname+namelength-4,".gif"))) { - Add_element_to_list(name, 0); - Filelist_nb_elements++; + Add_element_to_list(&Skin_files_list, name, 0); if (fname[0]=='\0') return; - - strcpy(Filelist->Full_name, fname); - - // Reformat the short name - strcpy(Filelist->Short_name,Format_filename(Filelist->Full_name, 0)); - } - -} -T_Fileselector_item * Get_selected_skin(word index) -{ - T_Fileselector_item * current_item; - // Fast-forward to the requested item. - current_item=Filelist; - for (;index>0;index--) - current_item=current_item->Next; - // I know it's highly inefficient (O(n²)) but there shouldn't be dozens - // of skins in the directory... - - return current_item; + 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)); + } + } // Callback to display a skin name in the list @@ -1010,9 +993,9 @@ void Draw_one_skin_name(word x, word y, word index, byte highlighted) { T_Fileselector_item * current_item; - if (Filelist_nb_elements>0) + if (Skin_files_list.Nb_elements) { - current_item = Get_selected_skin(index); + current_item = Get_item_by_index(&Skin_files_list, index); Print_in_window(x,y,current_item->Short_name, MC_Black, (highlighted)?MC_Dark:MC_Light); } } @@ -1046,15 +1029,14 @@ void Button_Skins(void) // Here we use the same data container as the fileselectors. // Reinitialize the list - Free_fileselector_list(); - Filelist_nb_elements=0; + Free_fileselector_list(&Skin_files_list); // Browse the "skins" directory strcpy(skinsdir,Data_directory); strcat(skinsdir,"skins"); // Add each found file to the list For_each_file(skinsdir, Add_skin); // Sort it - Sort_list_of_files(); + Sort_list_of_files(&Skin_files_list); // -------------------------------------------------------------- @@ -1075,7 +1057,7 @@ void Button_Skins(void) // Fileselector Window_set_special_button(8,FILESEL_Y+1,144,80), // 2 // Scroller du fileselector - (file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82,Filelist_nb_elements,10,selector_position)), // 3 + (file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82,Skin_files_list.Nb_elements,10,selector_position)), // 3 Draw_one_skin_name); // 4 // Boutons de fontes @@ -1226,7 +1208,7 @@ void Button_Skins(void) { quicksearch_filename[temp]=Key_ANSI; quicksearch_filename[temp+1]='\0'; - most_matching_filename=Find_filename_match(quicksearch_filename); + most_matching_filename=Find_filename_match(Skin_files_list, quicksearch_filename); if ( (most_matching_filename) ) { temp=Main_fileselector_position+Main_fileselector_offset; @@ -1255,7 +1237,7 @@ void Button_Skins(void) strcpy(skinsdir,"skins/"); strcat( skinsdir, - Get_selected_skin(skin_list->List_start+skin_list->Cursor_position)->Full_name); + 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 { diff --git a/filesel.c b/filesel.c index f48babe4..16e6c3f0 100644 --- a/filesel.c +++ b/filesel.c @@ -64,14 +64,58 @@ #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 +// -- Fileselector data + +T_Fileselector Filelist; + // Conventions: // // * Le fileselect modifie le répertoire courant. Ceci permet de n'avoir // qu'un findfirst dans le répertoire courant à faire: +void Recount_files(T_Fileselector *list) +{ + T_Fileselector_item *item; + + list->Nb_files=0; + list->Nb_directories=0; + list->Nb_elements=0; + + for (item = list->First; item != NULL; item = item->Next) + { + if (item->Type == 0) + list->Nb_files ++; + else + list->Nb_directories ++; + list->Nb_elements ++; + } + + if (list->Index) + { + free(list->Index); + list->Index = NULL; + } + + if (list->Nb_elements>0) + { + int i; + + list->Index = (T_Fileselector_item **) malloc(list->Nb_elements * sizeof(T_Fileselector_item **)); + if (list->Index) + { + // Fill the index + for (item = list->First, i=0; item != NULL; item = item->Next, i++) + { + list->Index[i] = item; + } + } + // If the malloc failed, we're probably in trouble, but I don't know + // how to recover from that..I'll just make the index bulletproof. + } +} -// -- Déstruction de la liste chaînée --------------------------------------- -void Free_fileselector_list(void) +// -- Destruction de la liste chaînée --------------------------------------- +void Free_fileselector_list(T_Fileselector *list) // Cette procédure détruit la chaine des fichiers. Elle doit être appelée // avant de rappeler la fonction Read_list_of_files, ainsi qu'en fin de // programme. @@ -79,23 +123,19 @@ void Free_fileselector_list(void) // Pointeur temporaire de destruction T_Fileselector_item * temp_item; - while (Filelist!=NULL) + while (list->First!=NULL) { // On mémorise l'adresse du premier élément de la liste - temp_item =Filelist; + temp_item =list->First; // On fait avancer la tête de la liste - Filelist=Filelist->Next; + list->First=list->First->Next; // Et on efface l'ancien premier élément de la liste free(temp_item); } + Recount_files(list); } - -/// -/// 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 -/// including the '\0'. -char * Format_filename(char * fname, int type) +char * Format_filename(const char * fname, int type) { static char result[19]; int c; @@ -148,7 +188,7 @@ char * Format_filename(char * fname, int type) // -- Rajouter a la liste des elements de la liste un element --------------- -void Add_element_to_list(char * fname, int type) +void Add_element_to_list(T_Fileselector *list, const char * fname, int type) // Cette procedure ajoute a la liste chainee un fichier passé en argument. { // Pointeur temporaire d'insertion @@ -162,12 +202,12 @@ void Add_element_to_list(char * fname, int type) strcpy(temp_item->Full_name,fname); temp_item->Type = type; - temp_item->Next =Filelist; + temp_item->Next =list->First; temp_item->Previous=NULL; - if (Filelist!=NULL) - Filelist->Previous=temp_item; - Filelist=temp_item; + if (list->First!=NULL) + list->First->Previous=temp_item; + list->First=temp_item; } // -- Vérification si un fichier a l'extension demandée. @@ -203,7 +243,7 @@ int Check_extension(const char *filename, char * filter) // -- Lecture d'une liste de fichiers --------------------------------------- -void Read_list_of_files(byte selected_format) +void Read_list_of_files(T_Fileselector *list, byte selected_format) // Cette procédure charge dans la liste chainée les fichiers dont l'extension // correspond au format demandé. { @@ -218,10 +258,8 @@ void Read_list_of_files(byte selected_format) filter = File_formats[selected_format-1].Extension; // Ensuite, on vide la liste actuelle: - Free_fileselector_list(); + Free_fileselector_list(list); // Après effacement, il ne reste ni fichier ni répertoire dans la liste - Filelist_nb_files=0; - Filelist_nb_directories=0; // On lit tous les répertoires: current_path=getcwd(NULL,0); @@ -243,8 +281,8 @@ void Read_list_of_files(byte selected_format) !isHidden(entry))) { // On rajoute le répertoire à la liste - Add_element_to_list(entry->d_name, 1); - Filelist_nb_directories++; + Add_element_to_list(list, entry->d_name, 1); + list->Nb_directories++; } else if (S_ISREG(Infos_enreg.st_mode) && //Il s'agit d'un fichier (Config.Show_hidden_files || //Il n'est pas caché @@ -253,21 +291,21 @@ void Read_list_of_files(byte selected_format) if (Check_extension(entry->d_name, filter)) { // On rajoute le fichier à la liste - Add_element_to_list(entry->d_name, 0); - Filelist_nb_files++; + Add_element_to_list(list, entry->d_name, 0); + list->Nb_files++; } } } #if defined(__MORPHOS__) || defined(__AROS__) || defined (__amigaos4__) || defined(__amigaos__) - Add_element_to_list("/",1); // on amiga systems, / means parent. And there is no .. - Filelist_nb_directories ++; + Add_element_to_list(list, "/",1); // on amiga systems, / means parent. And there is no .. + list->Nb_directories ++; #endif closedir(current_directory); free(current_path); - Filelist_nb_elements=Filelist_nb_directories+Filelist_nb_files; + Recount_files(list); } #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) @@ -290,14 +328,14 @@ void bstrtostr( BSTR in, STRPTR out, TEXT max ) #endif // -- Lecture d'une liste de lecteurs / volumes ----------------------------- -void Read_list_of_drives(void) +void Read_list_of_drives(T_Fileselector *list) { // Empty the current content of fileselector: - Free_fileselector_list(); + Free_fileselector_list(list); // Reset number of items - Filelist_nb_files=0; - Filelist_nb_directories=0; + list->Nb_files=0; + list->Nb_directories=0; #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) { @@ -311,8 +349,8 @@ void Read_list_of_drives(void) { bstrtostr( dl->dol_Name, tmp, 254 ); strcat( tmp, ":" ); - Add_element_to_list( tmp, 2 ); - Filelist_nb_directories++; + Add_element_to_list(list, tmp, 2 ); + list->Nb_directories++; } UnLockDosList( LDF_VOLUMES | LDF_READ ); } @@ -354,8 +392,8 @@ void Read_list_of_drives(void) break; } drive_name[0]='A'+bit_index; - Add_element_to_list(drive_name,2); - Filelist_nb_directories++; + Add_element_to_list(list, drive_name,2); + list->Nb_directories++; drive_index++; } } @@ -368,7 +406,7 @@ void Read_list_of_drives(void) // Ensuite on utilise read_file_system_list pour compléter - struct mount_entry* Liste_points_montage; + struct mount_entry* mount_points_list; struct mount_entry* next; #if defined(__BEOS__) || defined(__HAIKU__) @@ -376,42 +414,42 @@ void Read_list_of_drives(void) #else char * home_dir = getenv("HOME"); #endif - Add_element_to_list("/", 2); - Filelist_nb_directories++; + Add_element_to_list(list, "/", 2); + list->Nb_directories++; if(home_dir) { - Add_element_to_list(home_dir, 2); - Filelist_nb_directories++; + Add_element_to_list(list, home_dir, 2); + list->Nb_directories++; } - Liste_points_montage = read_file_system_list(0); + mount_points_list = read_file_system_list(0); - while(Liste_points_montage != NULL) + while(mount_points_list != NULL) { - if(Liste_points_montage->me_dummy == 0 && strcmp(Liste_points_montage->me_mountdir,"/") && strcmp(Liste_points_montage->me_mountdir,"/home")) + if(mount_points_list->me_dummy == 0 && strcmp(mount_points_list->me_mountdir,"/") && strcmp(mount_points_list->me_mountdir,"/home")) { - Add_element_to_list(Liste_points_montage->me_mountdir,2); - Filelist_nb_directories++; + Add_element_to_list(list, mount_points_list->me_mountdir,2); + list->Nb_directories++; } - next = Liste_points_montage -> me_next; + next = mount_points_list -> me_next; #if !(defined(__macosx__) || defined(__FreeBSD__)) - free(Liste_points_montage -> me_type); + free(mount_points_list -> me_type); #endif - free(Liste_points_montage -> me_devname); - free(Liste_points_montage -> me_mountdir); - free(Liste_points_montage); - Liste_points_montage = next; + free(mount_points_list -> me_devname); + free(mount_points_list -> me_mountdir); + free(mount_points_list); + mount_points_list = next; } } #endif - Filelist_nb_elements=Filelist_nb_directories+Filelist_nb_files; + Recount_files(list); } // -- Tri de la liste des fichiers et répertoires --------------------------- -void Sort_list_of_files(void) +void Sort_list_of_files(T_Fileselector *list) // Tri la liste chainée existante dans l'ordre suivant: // // * Les répertoires d'abord, dans l'ordre alphabétique de leur nom @@ -426,14 +464,14 @@ void Sort_list_of_files(void) // Avant de trier quoi que ce soit, on vérifie qu'il y ait suffisamment // d'éléments pour qu'il soit possibles qu'ils soient en désordre: - if (Filelist_nb_elements>1) + if (list->Nb_elements>1) { do { // Par défaut, on considère que la liste est triée list_is_sorted=1; - current_item=Filelist; + current_item=list->First; next_item=current_item->Next; while ( (current_item!=NULL) && (next_item!=NULL) ) @@ -478,8 +516,8 @@ void Sort_list_of_files(void) next_to_next_item->Previous=current_item; // On fait bien attention à modifier la tête de liste en cas de besoin - if (current_item==Filelist) - Filelist=next_item; + if (current_item==list->First) + list->First=next_item; // Ensuite, on se prépare à étudier les éléments précédents: current_item=prev_item; @@ -499,11 +537,34 @@ void Sort_list_of_files(void) } while (!list_is_sorted); } + // Force a recount / re-index + Recount_files(list); +} + +T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index) +{ + if (list->Index) + { + return list->Index[index]; + } + else + { + // Index not available. + // Can only happen in case of malloc error. + // Fall back anyway on iterative search + + T_Fileselector_item * item = list->First; + for (;index>0;index--) + item = item->Next; + + return item; + } + } // -- Affichage des éléments de la liste de fichier / répertoire ------------ -void Display_file_list(short offset_first,short selector_offset) +void Display_file_list(T_Fileselector *list, short offset_first,short selector_offset) // // offset_first = Décalage entre le premier fichier visible dans le // sélecteur et le premier fichier de la liste @@ -519,12 +580,10 @@ void Display_file_list(short offset_first,short selector_offset) // On vérifie s'il y a au moins 1 fichier dans la liste: - if (Filelist_nb_elements>0) + if (list->Nb_elements>0) { // On commence par chercher à pointer sur le premier fichier visible: - current_item=Filelist; - for (;offset_first>0;offset_first--) - current_item=current_item->Next; + current_item = Get_item_by_index(list, offset_first); // Pour chacun des 10 éléments inscriptibles à l'écran for (index=0;index<10;index++) @@ -566,7 +625,7 @@ void Display_file_list(short offset_first,short selector_offset) // -- Récupérer le libellé d'un élément de la liste ------------------------- -void Get_selected_item(short offset_first,short selector_offset,char * label,int *type) +void Get_selected_item(T_Fileselector *list, short offset_first,short selector_offset,char * label,int *type) // // offset_first = Décalage entre le premier fichier visible dans le // sélecteur et le premier fichier de la liste @@ -582,16 +641,11 @@ void Get_selected_item(short offset_first,short selector_offset,char * label,int T_Fileselector_item * current_item; // On vérifie s'il y a au moins 1 fichier dans la liste: - if (Filelist_nb_elements>0) + if (list->Nb_elements>0) { // On commence par chercher à pointer sur le premier fichier visible: - current_item=Filelist; - for (;offset_first>0;offset_first--) - current_item=current_item->Next; - // Ensuite, on saute autant d'éléments que le décalage demandé: - for (;selector_offset>0;selector_offset--) - current_item=current_item->Next; + current_item = Get_item_by_index(list, offset_first + selector_offset); // On recopie la chaîne strcpy(label, current_item->Full_name); @@ -608,12 +662,12 @@ void Selector_scroll_down(short * offset_first,short * selector_offset) // Fait scroller vers le bas le sélecteur de fichier... (si possible) { if ( ((*selector_offset)<9) - && ( (*selector_offset)+1 < Filelist_nb_elements ) ) + && ( (*selector_offset)+1 < Filelist.Nb_elements ) ) // Si la sélection peut descendre - Display_file_list(*offset_first,++(*selector_offset)); + Display_file_list(&Filelist, *offset_first,++(*selector_offset)); else // Sinon, descendre la fenêtre (si possible) - if ((*offset_first)+100) // Si la sélection peut monter - Display_file_list(*offset_first,--(*selector_offset)); + Display_file_list(&Filelist, *offset_first,--(*selector_offset)); else // Sinon, monter la fenêtre (si possible) if ((*offset_first)>0) - Display_file_list(--(*offset_first),*selector_offset); + Display_file_list(&Filelist, --(*offset_first),*selector_offset); } void Selector_page_down(short * offset_first,short * selector_offset, short lines) { - if (Filelist_nb_elements-1>*offset_first+*selector_offset) + if (Filelist.Nb_elements-1>*offset_first+*selector_offset) { if (*selector_offset<9) { - if (Filelist_nb_elements<10) + if (Filelist.Nb_elements<10) { *offset_first=0; - *selector_offset=Filelist_nb_elements-1; + *selector_offset=Filelist.Nb_elements-1; } else *selector_offset=9; } else { - if (Filelist_nb_elements>*offset_first+18) + if (Filelist.Nb_elements>*offset_first+18) *offset_first+=lines; else { - *offset_first=Filelist_nb_elements-10; + *offset_first=Filelist.Nb_elements-10; *selector_offset=9; } } } - Display_file_list(*offset_first,*selector_offset); + Display_file_list(&Filelist, *offset_first,*selector_offset); } @@ -671,29 +725,29 @@ void Selector_page_up(short * offset_first,short * selector_offset, short lines) *offset_first=0; } } - Display_file_list(*offset_first,*selector_offset); + Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_end(short * offset_first,short * selector_offset) { - if (Filelist_nb_elements<10) + if (Filelist.Nb_elements<10) { *offset_first=0; - *selector_offset=Filelist_nb_elements-1; + *selector_offset=Filelist.Nb_elements-1; } else { - *offset_first=Filelist_nb_elements-10; + *offset_first=Filelist.Nb_elements-10; *selector_offset=9; } - Display_file_list(*offset_first,*selector_offset); + Display_file_list(&Filelist, *offset_first,*selector_offset); } void Selector_home(short * offset_first,short * selector_offset) { - Display_file_list((*offset_first)=0,(*selector_offset)=0); + Display_file_list(&Filelist, (*offset_first)=0,(*selector_offset)=0); } @@ -708,8 +762,8 @@ short Compute_click_offset_in_fileselector(void) short computed_offset; computed_offset=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-95)>>3; - if (computed_offset>=Filelist_nb_elements) - computed_offset=Filelist_nb_elements-1; + if (computed_offset>=Filelist.Nb_elements) + computed_offset=Filelist.Nb_elements-1; return computed_offset; } @@ -803,22 +857,21 @@ void Print_filename_in_fileselector(void) int Selected_type; // Utilisé pour mémoriser le type d'entrée choisi // dans le selecteur de fichier. -void Prepare_and_display_filelist(short Position, short offset, - T_Scroller_button * button) +void Prepare_and_display_filelist(short Position, short offset, T_Scroller_button * button) { - button->Nb_elements=Filelist_nb_elements; + button->Nb_elements=Filelist.Nb_elements; button->Position=Position; Compute_slider_cursor_height(button); Window_draw_slider(button); // On efface les anciens noms de fichier: Window_rectangle(8-1,95-1,144+2,80+2,MC_Black); // On affiche les nouveaux: - Display_file_list(Position,offset); + Display_file_list(&Filelist, Position,offset); Update_window_area(8-1,95-1,144+2,80+2); // On récupère le nom du schmilblick à "accéder" - Get_selected_item(Position,offset,Main_filename,&Selected_type); + Get_selected_item(&Filelist, Position,offset,Main_filename,&Selected_type); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); // On affiche le nom du répertoire courant @@ -826,11 +879,10 @@ void Prepare_and_display_filelist(short Position, short offset, } -void Reload_list_of_files(byte filter, short Position, short offset, - T_Scroller_button * button) +void Reload_list_of_files(byte filter, short Position, short offset, T_Scroller_button * button) { - Read_list_of_files(filter); - Sort_list_of_files(); + Read_list_of_files(&Filelist, filter); + Sort_list_of_files(&Filelist); Prepare_and_display_filelist(Position,offset,button); } @@ -848,7 +900,7 @@ void Scroll_fileselector(T_Scroller_button * file_scroller) Window_draw_slider(file_scroller); } // On récupére le nom du schmilblick à "accéder" - Get_selected_item(Main_fileselector_position,Main_fileselector_offset,Main_filename,&Selected_type); + Get_selected_item(&Filelist, Main_fileselector_position,Main_fileselector_offset,Main_filename,&Selected_type); if (strcmp(old_filename,Main_filename)) New_preview_is_needed=1; @@ -858,12 +910,12 @@ void Scroll_fileselector(T_Scroller_button * file_scroller) } -short Find_file_in_fileselector(char * fname) +short Find_file_in_fileselector(T_Fileselector *list, char * fname) { T_Fileselector_item * current_item; short index; - for (index=0, current_item=Filelist; + for (index=0, current_item=list->First; ((current_item!=NULL) && (strcmp(current_item->Full_name,fname))); index++,current_item=current_item->Next); @@ -875,18 +927,18 @@ void Highlight_file(char * fname) { short index; - index=Find_file_in_fileselector(fname); + index=Find_file_in_fileselector(&Filelist, fname); - if ((Filelist_nb_elements<=10) || (index<5)) + if ((Filelist.Nb_elements<=10) || (index<5)) { Main_fileselector_position=0; Main_fileselector_offset=index; } else { - if (index>=Filelist_nb_elements-5) + if (index>=Filelist.Nb_elements-5) { - Main_fileselector_position=Filelist_nb_elements-10; + Main_fileselector_position=Filelist.Nb_elements-10; Main_fileselector_offset=index-Main_fileselector_position; } else @@ -898,18 +950,16 @@ void Highlight_file(char * fname) } -char FFF_best_name[MAX_PATH_CHARACTERS]; -char * Find_filename_match(char * fname) +char * Find_filename_match(T_Fileselector *list, char * fname) { char * best_name_ptr; T_Fileselector_item * current_item; byte matching_letters=0; byte counter; - strcpy(FFF_best_name,Main_filename); best_name_ptr=NULL; - for (current_item=Filelist; current_item!=NULL; current_item=current_item->Next) + for (current_item=list->First; current_item!=NULL; current_item=current_item->Next) { if ( (!Config.Find_file_fast) || (Config.Find_file_fast==(current_item->Type+1)) ) @@ -919,7 +969,6 @@ char * Find_filename_match(char * fname) if (counter>matching_letters) { matching_letters=counter; - strcpy(FFF_best_name,current_item->Full_name); best_name_ptr=current_item->Full_name; } } @@ -1118,12 +1167,12 @@ byte Button_Load_or_Save(byte load, byte image) break; case 3 : // Delete - if (Filelist_nb_elements && (*Main_filename!='.') && Selected_type!=2) + if (Filelist.Nb_elements && (*Main_filename!='.') && Selected_type!=2) { char * message; Hide_cursor(); // On affiche une demande de confirmation - if (Main_fileselector_position+Main_fileselector_offset>=Filelist_nb_directories) + if (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) { message="Delete file ?"; } @@ -1134,7 +1183,7 @@ byte Button_Load_or_Save(byte load, byte image) if (Confirmation_box(message)) { // Si c'est un fichier - if (Main_fileselector_position+Main_fileselector_offset>=Filelist_nb_directories) + if (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) // On efface le fichier (si on peut) temp=(!remove(Main_filename)); else // Si c'est un repertoire @@ -1144,7 +1193,7 @@ byte Button_Load_or_Save(byte load, byte image) if (temp) // temp indique si l'effacement s'est bien passé { // On remonte si c'était le dernier élément de la liste - if (Main_fileselector_position+Main_fileselector_offset==Filelist_nb_elements-1) + if (Main_fileselector_position+Main_fileselector_offset==Filelist.Nb_elements-1) { if (Main_fileselector_position) Main_fileselector_position--; @@ -1155,7 +1204,7 @@ byte Button_Load_or_Save(byte load, byte image) else // Si ce n'était pas le dernier, il faut faire gaffe à ce { // que ses copains d'en dessous ne remontent pas trop. if ( (Main_fileselector_position) - && (Main_fileselector_position+10==Filelist_nb_elements) ) + && (Main_fileselector_position+10==Filelist.Nb_elements) ) { Main_fileselector_position--; Main_fileselector_offset++; @@ -1192,11 +1241,11 @@ byte Button_Load_or_Save(byte load, byte image) Main_fileselector_offset=temp; // On récupére le nom du schmilblick à "accéder" - Get_selected_item(Main_fileselector_position,Main_fileselector_offset,Main_filename,&Selected_type); + Get_selected_item(&Filelist, Main_fileselector_position,Main_fileselector_offset,Main_filename,&Selected_type); // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); // On affiche à nouveau la liste - Display_file_list(Main_fileselector_position,Main_fileselector_offset); + Display_file_list(&Filelist, Main_fileselector_position,Main_fileselector_offset); // On vient de changer de nom de fichier, donc on doit s'appreter // a rafficher une preview @@ -1209,8 +1258,8 @@ byte Button_Load_or_Save(byte load, byte image) // faut mettre le nom de fichier au nom du répertoire. Sinon, dans // certains cas, on risque de sauvegarder avec le nom du fichier // actuel au lieu de changer de répertoire. - if (Main_fileselector_position+Main_fileselector_offsetFull_name,PARENT_DIR)) + if (!strcmp(Filelist.First->Full_name,PARENT_DIR)) { // On va dans le répertoire parent. strcpy(Main_filename,PARENT_DIR); @@ -1485,7 +1534,7 @@ byte Button_Load_or_Save(byte load, byte image) { quicksearch_filename[temp]=Key_ANSI; quicksearch_filename[temp+1]='\0'; - most_matching_filename=Find_filename_match(quicksearch_filename); + most_matching_filename=Find_filename_match(&Filelist, quicksearch_filename); if ( (most_matching_filename) ) { temp=Main_fileselector_position+Main_fileselector_offset; @@ -1530,8 +1579,8 @@ byte Button_Load_or_Save(byte load, byte image) getcwd(Main_current_directory,256); // On lit le nouveau répertoire - Read_list_of_files(Main_format); - Sort_list_of_files(); + 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); } @@ -1592,7 +1641,7 @@ byte Button_Load_or_Save(byte load, byte image) if (Timer_state==1) // Il faut afficher la preview { - if ( (Main_fileselector_position+Main_fileselector_offset>=Filelist_nb_directories) && (Filelist_nb_elements) ) + if ( (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) && (Filelist.Nb_elements) ) { strcpy(Main_file_directory,Main_current_directory); @@ -1639,7 +1688,7 @@ byte Button_Load_or_Save(byte load, byte image) Unselect_button((load)?BUTTON_LOAD:BUTTON_SAVE); Display_cursor(); - Free_fileselector_list(); + Free_fileselector_list(&Filelist); Pixel_load_function=Pixel_load_in_current_screen; diff --git a/filesel.h b/filesel.h index 783554f9..ed722a4a 100644 --- a/filesel.h +++ b/filesel.h @@ -23,3 +23,18 @@ ////////////////////////////////////////////////////////////////////////////// byte Button_Load_or_Save(byte load, byte image); + +void Add_element_to_list(T_Fileselector *list, const char * fname, int type); +/// +/// 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 +/// including the '\0'. +char * Format_filename(const char * fname, int type); + +void Free_fileselector_list(T_Fileselector *list); + +void Sort_list_of_files(T_Fileselector *list); + +void Recount_files(T_Fileselector *list); + +T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); diff --git a/global.h b/global.h index 0542ea6b..5b1632ba 100644 --- a/global.h +++ b/global.h @@ -881,17 +881,6 @@ GFX2_GLOBAL struct Func_action Action; ///< Function to call } Operation[NB_OPERATIONS][3][OPERATION_STACK_SIZE]; -// -- Fileselector data - -/// Number of elements in the current fileselector's ::Filelist -GFX2_GLOBAL short Filelist_nb_elements; -/// Number of files in the current fileselector's ::Filelist -GFX2_GLOBAL short Filelist_nb_files; -/// Number of directories in the current fileselector's ::Filelist -GFX2_GLOBAL short Filelist_nb_directories; -/// Head of the linked list for the fileselector. -GFX2_GLOBAL T_Fileselector_item * Filelist; - // -- misc /// diff --git a/main.c b/main.c index c76df867..964b9673 100644 --- a/main.c +++ b/main.c @@ -355,7 +355,7 @@ int Init_program(int argc,char * argv[]) Brush_fileformat =Main_fileformat; // On initialise ce qu'il faut pour que les fileselects ne plantent pas: - Filelist=NULL; // Au début, il n'y a pas de fichiers dans la liste + Main_fileselector_position=0; // Au début, le fileselect est en haut de la liste des fichiers Main_fileselector_offset=0; // Au début, le fileselect est en haut de la liste des fichiers Main_format=0; diff --git a/struct.h b/struct.h index 38f9ab6d..cbe9544c 100644 --- a/struct.h +++ b/struct.h @@ -33,6 +33,12 @@ #include "const.h" + +// POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. +#ifdef WIN32 + #define strcasecmp stricmp +#endif + // Definition of the base data types /// 8bit unsigned integer #define byte uint8_t @@ -158,6 +164,21 @@ typedef struct T_Fileselector_item struct T_Fileselector_item * Previous;///< Pointer to previous item of the current fileselector. } T_Fileselector_item; +/// Data for a fileselector +typedef struct T_Fileselector +{ + /// Number of elements in the current fileselector's ::Filelist + short Nb_elements; + /// Number of files in the current fileselector's ::Filelist + short Nb_files; + /// Number of directories in the current fileselector's ::Filelist + short Nb_directories; + /// Head of the linked list for the fileselector. + T_Fileselector_item * First; + /// Index for direct access to element number N + T_Fileselector_item ** Index; +} T_Fileselector; + typedef struct T_List_button { short Number; ///< Unique identifier for all controls From a61989786203a475dd366459661e2b1a05494d6e Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 28 Jun 2009 19:18:30 +0000 Subject: [PATCH 23/95] Don't free the GrafX2 logo when exiting the splash screen, it's now part of a struct and we free the struct at exit. This made the linux version crash. If you find it's memory waste, then make the logo a pointer instead of an array of bytes in the struct. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@887 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/main.c b/main.c index 964b9673..ff8b3d06 100644 --- a/main.c +++ b/main.c @@ -771,7 +771,6 @@ int main(int argc,char * argv[]) { if (Config.Opening_message && (!File_in_command_line)) Button_Message_initial(); - free(Gfx->Logo_grafx2); // Not yet used in the About screen if (File_in_command_line) { From cc64de7e1ffea4c95dd49489a92fbea04a5c8f12 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 28 Jun 2009 19:27:20 +0000 Subject: [PATCH 24/95] -Pad font names with spaces, as we need that to clear the dropdown button from previus selection -Made the font dropdown a little larger to hold 'fairlight' (quite a big group ;)) -Don't list fonts in the skin fileselector git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@888 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/buttons.c b/buttons.c index 218eaf69..9004e6a3 100644 --- a/buttons.c +++ b/buttons.c @@ -950,7 +950,8 @@ void Button_Settings(void) Close_window(); Unselect_button(BUTTON_SETTINGS); - // Raffichage du menu pour que les inscriptions qui y figurent soient retracées avec la nouvelle fonte + // Raffichage du menu pour que les inscriptions qui y figurent soient + // retracées avec la nouvelle fonte Display_menu(); Display_cursor(); @@ -961,6 +962,14 @@ void Button_Settings(void) // Data for skin selector T_Fileselector Skin_files_list; +/// Checks if the filename is a skin or a font. We avoid adding fonts to the +/// skin selector, and vice versa +char is_font(const char* name) +{ + return name[0]=='f' && name[1]=='o' && name[2]=='n' && name[3]=='t' + && name[4]=='_'; +} + // Add a skin to the list void Add_skin(const char *name) { @@ -974,7 +983,9 @@ void Add_skin(const char *name) else fname=name; namelength = strlen(fname); - if (namelength>=5 && fname[0]!='_' && (!strcasecmp(fname+namelength-4,".png") || !strcasecmp(fname+namelength-4,".gif"))) + if (namelength>=5 && fname[0]!='_' && !is_font(fname) + && (!strcasecmp(fname+namelength-4,".png") + || !strcasecmp(fname+namelength-4,".gif"))) { Add_element_to_list(&Skin_files_list, name, 0); @@ -983,7 +994,9 @@ void Add_skin(const char *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)); + strcpy(Skin_files_list.First->Short_name, + Format_filename(Skin_files_list.First->Full_name, 0) + ); } } @@ -1020,7 +1033,7 @@ void Button_Skins(void) T_Scroller_button * file_scroller; int selected_font=0; - char * fonts[] = {"Classic", "Fun", "Melon", "Fairlight"}; + char * fonts[] = {"Classic ", "Fun ", "Melon ", "Fairlight"}; int nb_fonts = 4; #define FILESEL_Y 52 @@ -1057,11 +1070,13 @@ void Button_Skins(void) // Fileselector Window_set_special_button(8,FILESEL_Y+1,144,80), // 2 // Scroller du fileselector - (file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82,Skin_files_list.Nb_elements,10,selector_position)), // 3 + (file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82, + Skin_files_list.Nb_elements,10,selector_position)), // 3 Draw_one_skin_name); // 4 - // Boutons de fontes - font_dropdown = Window_set_dropdown_button(60,19,70,11,0, fonts[selected_font],1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 + // Font dropdown + font_dropdown = Window_set_dropdown_button(60,19,86,11,0, + fonts[selected_font],1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 for (temp=0; temp Date: Sun, 28 Jun 2009 19:36:06 +0000 Subject: [PATCH 25/95] -Remove the spaces I just added when looking for the fonts, -No need to check if a pointer is NULL before freeing it, free() takes care of that, -Removed useless variables after Yves cleanup git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@889 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/buttons.c b/buttons.c index 9004e6a3..c447dab5 100644 --- a/buttons.c +++ b/buttons.c @@ -1018,13 +1018,7 @@ void Button_Skins(void) { short clicked_button; short temp; - char quicksearch_filename[MAX_PATH_CHARACTERS]=""; - char * most_matching_filename; char skinsdir[MAX_PATH_CHARACTERS]; - DIR* current_directory; //Répertoire courant - struct dirent* entry; // Structure de lecture des éléments - struct stat Infos_enreg; - char * current_path; static int selector_position=0; T_Config Config_choisie = Config; T_Dropdown_button * font_dropdown; @@ -1248,6 +1242,8 @@ void Button_Skins(void) if(clicked_button == 1) { + char* tmp_font; + char* tmp_ptr; T_Gui_skin * gfx; strcpy(skinsdir,"skins/"); strcat( @@ -1265,16 +1261,18 @@ void Button_Skins(void) free(Gfx); Gfx = gfx; // Font selection - new_font = Load_font(fonts[selected_font]); + tmp_font = strdup(fonts[selected_font]); + tmp_ptr=tmp_font; + while(*tmp_ptr!=' ' && *tmp_ptr!='\0') + tmp_ptr++; + *tmp_ptr='\0'; + new_font = Load_font(tmp_font); + free(tmp_font); if (new_font) { free(Menu_font); Menu_font = new_font; - if (Config_choisie.Font_name) - { - free (Config_choisie.Font_name); - Config_choisie.Font_name = NULL; - } + free (Config_choisie.Font_name); Config_choisie.Font_name = (char *)malloc(strlen(fonts[selected_font])+1); if (Config_choisie.Font_name) { From d4dcba62a639a117a4cf6b71e79cdd4e028194e9 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 28 Jun 2009 21:50:01 +0000 Subject: [PATCH 26/95] More work on fonts/skins git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@890 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 14 +-- buttons.c | 111 ++++++++++++------------ engine.c | 7 +- filesel.c | 5 +- filesel.h | 2 + gfx2def.ini | 4 +- init.c | 3 +- main.c | 14 +-- readini.c | 2 +- skins/{classic.png => skin_classic.png} | Bin skins/{modern.png => skin_modern.png} | Bin 11 files changed, 88 insertions(+), 74 deletions(-) rename skins/{classic.png => skin_classic.png} (100%) rename skins/{modern.png => skin_modern.png} (100%) diff --git a/Makefile b/Makefile index 5ff25b5f..8929ec6a 100644 --- a/Makefile +++ b/Makefile @@ -227,6 +227,8 @@ 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 +SKIN_FILES = skins/skin_classic.png skins/skin_modern.png skins/font_Classic.png skins/font_Fun.png + all : $(BIN) debug : $(BIN) @@ -240,9 +242,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" --transform 's,^,src/,g' *.c *.h Makefile Makefile.dep gfx2.ico - $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN) gfx2def.ini skins/modern.png skins/classic.png gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt fonts/Tuffy.ttf src-`cat $(OBJDIR)/versiontag`.tgz $(PLATFORMFILES) + $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN) gfx2def.ini $(SKIN_FILES) gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt fonts/Tuffy.ttf src-`cat $(OBJDIR)/versiontag`.tgz $(PLATFORMFILES) $(DELCOMMAND) "src-`cat $(OBJDIR)/versiontag`.tgz" - tar cvzf "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --transform 's,^,grafx2/,g' *.c *.h Makefile Makefile.dep gfx2def.ini skins/modern.png skins/classic.png gfx2.ico gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt misc/grafx2.1 misc/grafx2.xpm misc/grafx2.desktop fonts/8pxfont.png fonts/Tuffy.ttf + tar cvzf "grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --transform 's,^,grafx2/,g' *.c *.h Makefile Makefile.dep gfx2def.ini $(SKIN_FILES) gfx2.ico gfx2.gif doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt misc/grafx2.1 misc/grafx2.xpm misc/grafx2.desktop fonts/8pxfont.png fonts/Tuffy.ttf $(DELCOMMAND) "$(OBJDIR)/versiontag" testsed : @@ -303,8 +305,7 @@ install : $(BIN) $(CP) gfx2def.ini $(DESTDIR)$(datadir)/grafx2/ $(CP) gfx2.gif $(DESTDIR)$(datadir)/grafx2/ $(CP) fonts/* $(DESTDIR)$(datadir)/grafx2/fonts/ - $(CP) skins/modern.png $(DESTDIR)$(datadir)/grafx2/skins/ - $(CP) skins/classic.png $(DESTDIR)$(datadir)/grafx2/skins/ + $(CP) $(SKIN_FILES) $(DESTDIR)$(datadir)/grafx2/skins/ # Icon and desktop file for debian $(CP) misc/grafx2.desktop $(DESTDIR)$(datadir)/applications/ $(CP) misc/grafx2.xpm $(DESTDIR)$(datadir)/icons/ @@ -318,8 +319,9 @@ uninstall : $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/gfx2.gif $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/fonts/* $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/fonts),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/fonts) - $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/skins/modern.png - $(DELCOMMAND) $(DESTDIR)$(datadir)/grafx2/skins/classic.png + cd $(DESTDIR)$(datadir)/grafx2 + $(DELCOMMAND) $(SKIN_FILES) + cd .. $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/skins),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/skins) # Icon and desktop file for debian $(DELCOMMAND) $(DESTDIR)$(datadir)/applications/grafx2.desktop diff --git a/buttons.c b/buttons.c index c447dab5..2641de9d 100644 --- a/buttons.c +++ b/buttons.c @@ -962,16 +962,33 @@ void Button_Settings(void) // Data for skin selector T_Fileselector Skin_files_list; -/// Checks if the filename is a skin or a font. We avoid adding fonts to the -/// skin selector, and vice versa -char is_font(const char* name) + +// Data for font selector +T_Fileselector Font_files_list; + +// +char * Format_font_filename(const char * fname) { - return name[0]=='f' && name[1]=='o' && name[2]=='n' && name[3]=='t' - && name[4]=='_'; + static char result[12]; + int c; + int length; + + fname+=5; // Assume "font_" prefix + length=strlen(fname) - 4; // assume .png extension + + for (c=0;c<11 && c11) + result[10] = ELLIPSIS_CHARACTER; + + return result; } // Add a skin to the list -void Add_skin(const char *name) +void Add_font_or_skin(const char *name) { const char * fname; int namelength; @@ -983,7 +1000,7 @@ void Add_skin(const char *name) else fname=name; namelength = strlen(fname); - if (namelength>=5 && fname[0]!='_' && !is_font(fname) + if (namelength>=10 && fname[0]!='_' && !strncmp(fname, "skin_", 5) && (!strcasecmp(fname+namelength-4,".png") || !strcasecmp(fname+namelength-4,".gif"))) { @@ -992,12 +1009,25 @@ void Add_skin(const char *name) 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 && !strncmp(fname, "font_", 5) && (!strcasecmp(fname+namelength-4,".png"))) + { + Add_element_to_list(&Font_files_list, name, 0); + + 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)); + } } @@ -1027,8 +1057,7 @@ void Button_Skins(void) T_Scroller_button * file_scroller; int selected_font=0; - char * fonts[] = {"Classic ", "Fun ", "Melon ", "Fairlight"}; - int nb_fonts = 4; + char * cursors[] = { "Solid", "Transparent", "Thin" }; #define FILESEL_Y 52 @@ -1037,13 +1066,17 @@ void Button_Skins(void) // Here we use the same data container as the fileselectors. // Reinitialize the list Free_fileselector_list(&Skin_files_list); + Free_fileselector_list(&Font_files_list); // Browse the "skins" directory strcpy(skinsdir,Data_directory); strcat(skinsdir,"skins"); // Add each found file to the list - For_each_file(skinsdir, Add_skin); + For_each_file(skinsdir, Add_font_or_skin); // Sort it Sort_list_of_files(&Skin_files_list); + Sort_list_of_files(&Font_files_list); + + //selected_font = Find_file_in_fileselector(&Font_files_list, Config_choisie.Font_name); // -------------------------------------------------------------- @@ -1068,35 +1101,19 @@ void Button_Skins(void) Skin_files_list.Nb_elements,10,selector_position)), // 3 Draw_one_skin_name); // 4 - // Font dropdown - font_dropdown = Window_set_dropdown_button(60,19,86,11,0, - fonts[selected_font],1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 - for (temp=0; tempShort_name,1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 + for (temp=0; tempShort_name); // Cancel Window_set_normal_button(62,136, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 6 - // Button item du curseur - if(Config_choisie.Cursor==0) - cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Solid ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 - else if(Config_choisie.Cursor==1) - cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Transparent",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 - else - cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,"Thin ",1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 - Window_dropdown_add_item(cursor_dropdown,0,"Solid "); - Window_dropdown_add_item(cursor_dropdown,1,"Transparent"); - Window_dropdown_add_item(cursor_dropdown,2,"Thin "); + // Dropdown list to choose cursor type + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,cursors[Config_choisie.Cursor],1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 + for (temp=0; temp<3; temp++) + Window_dropdown_add_item(cursor_dropdown,temp,cursors[temp]); - // Select the current skin (we know it does exist, so no need to do a - // nearest match search) - //Highlight_file(Config_choisie.SkinFile); - // On efface les anciens noms de fichier: - //Window_rectangle(8-1,FILESEL_Y-1,144+2,80+2,MC_Black); - // On affiche les nouveaux: - //Display_skins_list(Main_fileselector_position,Main_fileselector_offset); Window_redraw_list(skin_list); Update_window_area(0,0,Window_width, Window_height); @@ -1242,13 +1259,8 @@ void Button_Skins(void) if(clicked_button == 1) { - char* tmp_font; - char* tmp_ptr; T_Gui_skin * gfx; - strcpy(skinsdir,"skins/"); - strcat( - skinsdir, - Get_item_by_index(&Skin_files_list, skin_list->List_start+skin_list->Cursor_position)->Full_name); + 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 { @@ -1257,30 +1269,21 @@ void Button_Skins(void) else { byte * new_font; - free(Gfx); Gfx = gfx; // Font selection - tmp_font = strdup(fonts[selected_font]); - tmp_ptr=tmp_font; - while(*tmp_ptr!=' ' && *tmp_ptr!='\0') - tmp_ptr++; - *tmp_ptr='\0'; - new_font = Load_font(tmp_font); - free(tmp_font); + new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name); if (new_font) { + const char * fname; free(Menu_font); Menu_font = new_font; free (Config_choisie.Font_name); - Config_choisie.Font_name = (char *)malloc(strlen(fonts[selected_font])+1); - if (Config_choisie.Font_name) - { - strcpy(Config_choisie.Font_name,fonts[selected_font]); - } + fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name; + Config_choisie.Font_name = strdup(fname); } - strcpy(Config_choisie.SkinFile,skinsdir+6); + strcpy(Config_choisie.SkinFile,skinsdir); } Config = Config_choisie ; diff --git a/engine.c b/engine.c index e133065c..605cf0a3 100644 --- a/engine.c +++ b/engine.c @@ -2289,8 +2289,11 @@ short Window_dropdown_on_click(T_Dropdown_button *Button) Window_attribute2=item->Number; if (Button->Display_choice) { - // Mettre à jour automatiquement le libellé de la dropdown - Print_in_window(Button->Pos_X+2,Button->Pos_Y+(Button->Height-7)/2,item->Label,MC_Black,MC_Light); + // Automatically update the label of the dropdown list. + int text_length = (Button->Width-4-(Button->Display_arrow?8:0))/8; + // Clear original label area + Window_rectangle(Button->Pos_X+2,Button->Pos_Y+(Button->Height-7)/2,text_length*8,8,MC_Light); + Print_in_window_limited(Button->Pos_X+2,Button->Pos_Y+(Button->Height-7)/2,item->Label,text_length ,MC_Black,MC_Light); } return Button->Number; } diff --git a/filesel.c b/filesel.c index 16e6c3f0..4a449f2f 100644 --- a/filesel.c +++ b/filesel.c @@ -462,9 +462,8 @@ void Sort_list_of_files(T_Fileselector *list) T_Fileselector_item * next_item; T_Fileselector_item * next_to_next_item; - // Avant de trier quoi que ce soit, on vérifie qu'il y ait suffisamment - // d'éléments pour qu'il soit possibles qu'ils soient en désordre: - if (list->Nb_elements>1) + // Check there are at least two elements before sorting + if (list->First && list->First->Next) { do { diff --git a/filesel.h b/filesel.h index ed722a4a..1cbd2432 100644 --- a/filesel.h +++ b/filesel.h @@ -38,3 +38,5 @@ void Sort_list_of_files(T_Fileselector *list); void Recount_files(T_Fileselector *list); T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); + +short Find_file_in_fileselector(T_Fileselector *list, char * fname); diff --git a/gfx2def.ini b/gfx2def.ini index 4f5382ef..7d42e54a 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -318,7 +318,7 @@ ; Name of the skinfile you want to | Nom du fichier skin que vous voulez ; use. | utiliser. - ; default 'modern.png' - Skin_file = modern.png + ; default 'skin_modern.png' + Skin_file = skin_modern.png ; end of configuration diff --git a/init.c b/init.c index c917b99e..16b993f1 100644 --- a/init.c +++ b/init.c @@ -772,6 +772,7 @@ T_Gui_skin * Load_graphics(const char * skin_file) // Read the "skin" file strcpy(filename,Data_directory); + strcat(filename,"skins" PATH_SEPARATOR); strcat(filename,skin_file); gui=IMG_Load(filename); @@ -848,7 +849,7 @@ byte * Load_font(const char * font_name) } // Read the file containing the image - sprintf(filename,"%sskins%sfont_%s.png", Data_directory, PATH_SEPARATOR, font_name); + sprintf(filename,"%sskins%s%s", Data_directory, PATH_SEPARATOR, font_name); image=IMG_Load(filename); if (!image) diff --git a/main.c b/main.c index ff8b3d06..dea075bd 100644 --- a/main.c +++ b/main.c @@ -76,7 +76,7 @@ #endif // filename for the current GUI skin file. -static char Gui_skin_file[MAX_PATH_CHARACTERS]= "skins" PATH_SEPARATOR ; +static char Gui_skin_file[MAX_PATH_CHARACTERS]; //--- Affichage de la syntaxe, et de la liste des modes vidéos disponibles --- void Display_syntax(void) @@ -534,12 +534,16 @@ int Init_program(int argc,char * argv[]) Analyze_command_line(argc,argv); // Load sprites, palette etc. - strcpy(Gui_skin_file+6,Config.SkinFile); + strcpy(Gui_skin_file,Config.SkinFile); Gfx = Load_graphics(Gui_skin_file); if (Gfx == NULL) { - printf("%s", Gui_loading_error_message); - Error(ERROR_GUI_MISSING); + Gfx = Load_graphics("skin_modern.png"); + if (Gfx == NULL) + { + printf("%s", Gui_loading_error_message); + Error(ERROR_GUI_MISSING); + } } // Infos sur les trames (Sieve) Sieve_mode=0; @@ -558,7 +562,7 @@ int Init_program(int argc,char * argv[]) // Font { byte *font; - font = Load_font("Classic"); + font = Load_font("font_Classic.png"); if (font) Menu_font=font; } diff --git a/readini.c b/readini.c index bef5316f..ccad626a 100644 --- a/readini.c +++ b/readini.c @@ -818,7 +818,7 @@ int Load_INI(T_Config * conf) if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) strcpy(conf->SkinFile,value_label); else - strcpy(conf->SkinFile,"modern.png"); + strcpy(conf->SkinFile,"skin_modern.png"); fclose(file); diff --git a/skins/classic.png b/skins/skin_classic.png similarity index 100% rename from skins/classic.png rename to skins/skin_classic.png diff --git a/skins/modern.png b/skins/skin_modern.png similarity index 100% rename from skins/modern.png rename to skins/skin_modern.png From 8b4533f105e188f44790ba7b0c1f54edee1cecd1 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 29 Jun 2009 00:28:58 +0000 Subject: [PATCH 27/95] Skin graphics and font are now recorded & reloaded. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@891 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 49 +++++++++++++++++++++++++++---------------------- gfx2def.ini | 9 +++++++-- main.c | 15 +++++++-------- readini.c | 9 +++++++-- saveini.c | 5 ++++- struct.h | 4 ++-- 6 files changed, 54 insertions(+), 37 deletions(-) diff --git a/buttons.c b/buttons.c index 2641de9d..8dbceb40 100644 --- a/buttons.c +++ b/buttons.c @@ -1049,13 +1049,12 @@ void Button_Skins(void) short clicked_button; short temp; char skinsdir[MAX_PATH_CHARACTERS]; - static int selector_position=0; - T_Config Config_choisie = Config; T_Dropdown_button * font_dropdown; T_Dropdown_button * cursor_dropdown; T_List_button * skin_list; T_Scroller_button * file_scroller; int selected_font=0; + int selected_cursor=Config.Cursor; char * cursors[] = { "Solid", "Transparent", "Thin" }; @@ -1076,7 +1075,7 @@ void Button_Skins(void) Sort_list_of_files(&Skin_files_list); Sort_list_of_files(&Font_files_list); - //selected_font = Find_file_in_fileselector(&Font_files_list, Config_choisie.Font_name); + selected_font = Find_file_in_fileselector(&Font_files_list, Config.Font_file); // -------------------------------------------------------------- @@ -1096,10 +1095,12 @@ void Button_Skins(void) skin_list = Window_set_list_button( // Fileselector Window_set_special_button(8,FILESEL_Y+1,144,80), // 2 - // Scroller du fileselector + // Scroller for the fileselector (file_scroller = Window_set_scroller_button(160,FILESEL_Y+1,82, - Skin_files_list.Nb_elements,10,selector_position)), // 3 + Skin_files_list.Nb_elements,10,0)), // 3 Draw_one_skin_name); // 4 + + skin_list->Cursor_position = Find_file_in_fileselector(&Skin_files_list, Config.Skin_file); // Buttons to choose a font font_dropdown = Window_set_dropdown_button(60,19,104,11,0, Get_item_by_index(&Font_files_list,selected_font)->Short_name,1,0,1,RIGHT_SIDE|LEFT_SIDE); // 5 @@ -1110,7 +1111,7 @@ void Button_Skins(void) Window_set_normal_button(62,136, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 6 // Dropdown list to choose cursor type - cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,cursors[Config_choisie.Cursor],1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 + cursor_dropdown = Window_set_dropdown_button(60,34,104,11,0,cursors[selected_cursor],1,0,1,RIGHT_SIDE|LEFT_SIDE); // 7 for (temp=0; temp<3; temp++) Window_dropdown_add_item(cursor_dropdown,temp,cursors[temp]); @@ -1139,7 +1140,7 @@ void Button_Skins(void) break; // 5: Cancel case 7 : // Cursor - Config_choisie.Cursor=Window_attribute2; + selected_cursor = Window_attribute2; break; } @@ -1260,6 +1261,9 @@ void Button_Skins(void) if(clicked_button == 1) { T_Gui_skin * gfx; + byte * new_font; + + // (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 @@ -1268,25 +1272,26 @@ void Button_Skins(void) } else { - byte * new_font; free(Gfx); Gfx = gfx; - // Font selection - new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name); - if (new_font) - { - const char * fname; - free(Menu_font); - Menu_font = new_font; - free (Config_choisie.Font_name); - fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name; - Config_choisie.Font_name = strdup(fname); - } - strcpy(Config_choisie.SkinFile,skinsdir); + free(Config.Skin_file); + Config.Skin_file = strdup(skinsdir); + } + // (Re-)load the selected font + new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name); + if (new_font) + { + const char * fname; + + free(Menu_font); + 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 = Config_choisie ; + // Confirm the change of cursor shape + Config.Cursor = selected_cursor; } Close_window(); diff --git a/gfx2def.ini b/gfx2def.ini index 7d42e54a..fe166e40 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -318,7 +318,12 @@ ; Name of the skinfile you want to | Nom du fichier skin que vous voulez ; use. | utiliser. - ; default 'skin_modern.png' - Skin_file = skin_modern.png + ; Default : (empty to let the program choose) + Skin_file = + ; Name of the font file (8x8) you | Nom du fichier police de caractère + ; want to use. | 8x8 utilisée dans les menus. + ; Default : (empty to let the program choose) + Font_file = + ; end of configuration diff --git a/main.c b/main.c index dea075bd..b2d4754a 100644 --- a/main.c +++ b/main.c @@ -534,7 +534,7 @@ int Init_program(int argc,char * argv[]) Analyze_command_line(argc,argv); // Load sprites, palette etc. - strcpy(Gui_skin_file,Config.SkinFile); + strcpy(Gui_skin_file,Config.Skin_file); Gfx = Load_graphics(Gui_skin_file); if (Gfx == NULL) { @@ -560,13 +560,12 @@ int Init_program(int argc,char * argv[]) Back_color=MC_Black; // Font - { - byte *font; - font = Load_font("font_Classic.png"); - if (font) - Menu_font=font; - } - + if (!(Menu_font=Load_font(Config.Font_file))) + if (!(Menu_font=Load_font("font_Classic.png"))) + { + printf("Unable to open the default font file: %s\n", "font_Classic.png"); + Error(ERROR_GUI_MISSING); + } memcpy(Main_palette, Gfx->Default_palette, sizeof(T_Palette)); diff --git a/readini.c b/readini.c index ccad626a..ddbd8f80 100644 --- a/readini.c +++ b/readini.c @@ -816,10 +816,15 @@ int Load_INI(T_Config * conf) // Optional, name of skin file. (>2.0) if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) - strcpy(conf->SkinFile,value_label); + conf->Skin_file = strdup(value_label); else - strcpy(conf->SkinFile,"skin_modern.png"); + conf->Skin_file = strdup("skin_modern.png"); + // Optional, name of font file. (>2.0) + if(!Load_INI_get_string(file,buffer,"Font_file",value_label,1)) + conf->Font_file = strdup(value_label); + else + conf->Font_file = strdup("font_Classic.png"); fclose(file); diff --git a/saveini.c b/saveini.c index 2bf95c04..3305e2e0 100644 --- a/saveini.c +++ b/saveini.c @@ -639,7 +639,10 @@ int Save_INI(T_Config * conf) if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,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->SkinFile))) + if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,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))) goto Erreur_Retour; Save_INI_flush(Ancien_fichier,Nouveau_fichier,buffer); diff --git a/struct.h b/struct.h index cbe9544c..ed890449 100644 --- a/struct.h +++ b/struct.h @@ -261,8 +261,8 @@ typedef struct /// This structure holds all the settings which are saved and loaded as gfx2.ini. typedef struct { - char *Font_name; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) - char SkinFile[64]; ///< String, name of the file where all the graphic data is stored + char *Font_file; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) + char *Skin_file; ///< String, name of the file where all the graphic data is stored int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. // int Show_system_directories; ///< (removed when converted from DOS) From 19a2892e88da0d47badcc4af03efdede241a8c0d Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 1 Jul 2009 19:21:58 +0000 Subject: [PATCH 28/95] I extended the line clamping to do iso pixelart. However I only managed to find the equation for the 3 others. Maybe someone is better at geometry. I let the unequationed lines move free when you press shift. The limit between each spot can also be adjusted. Is someone better than me at math around here ? git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@894 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- graph.c | 53 ++++++++++++++++++++++++++++++++++++++--------------- operatio.c | 6 ++++-- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/graph.c b/graph.c index 9a9d8fac..6d0a424c 100644 --- a/graph.c +++ b/graph.c @@ -1356,42 +1356,65 @@ void Draw_filled_ellipse(short center_x,short center_y,short horizontal_radius,s * TRACÉ DE LIGNES * ******************/ +/// Alters bx and by so the (AX,AY)-(BX,BY) segment becomes either horizontal, +/// vertical, 45degrees, or isometrical for pixelart (ie 2:1 ratio) void Clamp_coordinates_45_degrees(short ax, short ay, short* bx, short* by) -// Modifie bx et by pour que la ligne AXAY - BXBY soit -// - une droite horizontale -// - une droite verticale -// - une droite avec une pente de 45 degrés { int dx, dy; float tan; dx = (*bx)-ax; - dy = ay- *by; // On prend l'opposée car à l'écran les Y sont positifs en bas, et en maths, positifs en haut + dy = ay- *by; + // On prend l'opposée car à l'écran les Y sont positifs en bas, et en + // maths, positifs en haut - if (dx==0) return; // On est en lockx et de toutes façons le X n'a pas bougé, on sort tout de suite pour éviter une méchante division par 0 + if (dx==0) return; + // On est en lockx et de toutes façons le X n'a pas bougé, on sort tout + // de suite pour éviter une méchante division par 0 tan = (float)dy/(float)dx; - if (tan <= 0.4142 && tan >= -0.4142) + // These equation look a bit more complex than they should, but that's + // because we have to balance the line length to make it end near the + // cursor + if (tan <= 0.25 && tan >= -0.25) { - // Cas 1 : Lock Y + // horizontal (OK) *by = ay; } - else if ( tan > 0.4142 && tan < 2.4142) + else if ( tan > 0.25 && tan < 0.75) { - // Cas 2 : dy=dx + // dx=2dy, iso (ok) + *bx = (2* *bx + ax + 2*dy)/3; + *by = ay - (*bx-ax)/2; + } + else if ( tan >=0.75 && tan <= 1.5 ) + { + // dy=-dx, diagonal upright (ok) *by = (*by + ay - dx)/2; *bx = ax + ay - *by; - } - else if (tan < -0.4142 && tan >= -2.4142) + } + else if ( tan > 1.5 && tan <= 3 ) + { + // "vertical iso" + } + else if (tan < -0.25 && tan >= -0.75) { - // Cas 8 : dy = -dx + // iso to bottom + } + else if ( tan <-0.75 && tan > -1.5 ) + { + // dy=dx, downright diagonal (ok) *by = (*by + ay + dx)/2; *bx = ax - ay + *by; - } + } + else if ( tan < -1.5 && tan >= -3 ) + { + // vertical iso to bottom + } else { - // Cas 3 : Lock X + // vertical (ok) *bx = ax; } diff --git a/operatio.c b/operatio.c index a1454ef4..863d58c0 100644 --- a/operatio.c +++ b/operatio.c @@ -39,7 +39,8 @@ #define M_PI 3.14159265358979323846 #endif -/// Time (in SDL ticks) when the next airbrush drawing should be done. Also used for discontinuous freehand drawing. +/// Time (in SDL ticks) when the next airbrush drawing should be done. Also used +/// for discontinuous freehand drawing. Uint32 Airbrush_next_time; void Start_operation_stack(word new_operation) @@ -482,7 +483,8 @@ void Line_12_5(void) // // Souris effacée: Non -// Poursuite du tracé d'une ligne (déplacement de la souris en gardant le curseur appuyé) +// Poursuite du tracé d'une ligne (déplacement de la souris en gardant le +// curseur appuyé) { short start_x; short start_y; From 9e9fd506b6768c68cc65898c9fd53a73a9160a95 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 2 Jul 2009 21:38:11 +0000 Subject: [PATCH 29/95] Continued the line clamping. Seems to work perfectly for all 16 directions, but I discovered an older problem in the input handler when you release a key that participates in cursor emulation. Not completely fixed. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@895 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- graph.c | 96 +++++++++++++++++++++++++----------------------------- graph.h | 2 +- input.c | 24 +++++++------- operatio.c | 38 ++++++++++++--------- 4 files changed, 79 insertions(+), 81 deletions(-) diff --git a/graph.c b/graph.c index 6d0a424c..6c09776f 100644 --- a/graph.c +++ b/graph.c @@ -1358,66 +1358,58 @@ void Draw_filled_ellipse(short center_x,short center_y,short horizontal_radius,s /// Alters bx and by so the (AX,AY)-(BX,BY) segment becomes either horizontal, /// vertical, 45degrees, or isometrical for pixelart (ie 2:1 ratio) -void Clamp_coordinates_45_degrees(short ax, short ay, short* bx, short* by) +void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by) { int dx, dy; - float tan; + float angle; + float length; - dx = (*bx)-ax; - dy = ay- *by; - // On prend l'opposée car à l'écran les Y sont positifs en bas, et en - // maths, positifs en haut + dx = *bx-ax; + dy = *by-ay; - if (dx==0) return; + if (dx==0 || dy == 0) return; // On est en lockx et de toutes façons le X n'a pas bougé, on sort tout // de suite pour éviter une méchante division par 0 - tan = (float)dy/(float)dx; - - // These equation look a bit more complex than they should, but that's - // because we have to balance the line length to make it end near the - // cursor - if (tan <= 0.25 && tan >= -0.25) - { - // horizontal (OK) - *by = ay; - } - else if ( tan > 0.25 && tan < 0.75) - { - // dx=2dy, iso (ok) - *bx = (2* *bx + ax + 2*dy)/3; - *by = ay - (*bx-ax)/2; - } - else if ( tan >=0.75 && tan <= 1.5 ) - { - // dy=-dx, diagonal upright (ok) - *by = (*by + ay - dx)/2; - *bx = ax + ay - *by; - } - else if ( tan > 1.5 && tan <= 3 ) - { - // "vertical iso" - } - else if (tan < -0.25 && tan >= -0.75) - { - // iso to bottom - } - else if ( tan <-0.75 && tan > -1.5 ) - { - // dy=dx, downright diagonal (ok) - *by = (*by + ay + dx)/2; - *bx = ax - ay + *by; - } - else if ( tan < -1.5 && tan >= -3 ) - { - // vertical iso to bottom - } - else - { - // vertical (ok) - *bx = ax; - } + angle = atan2(dx, dy); + + if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0)) + angle = M_PI*(16.0/16.0); + else if (angle < M_PI*(-13.0/16.0)) + angle = -2.677945045; + else if (angle < M_PI*(-11.0/16.0)) + angle = M_PI*(-12.0/16.0); + else if (angle < M_PI*(-9.0/16.0)) + angle = -2.034443936; + else if (angle < M_PI*(-7.0/16.0)) + angle = M_PI*(-8.0/16.0); + else if (angle < M_PI*(-5.0/16.0)) + angle = -1.107148718; + else if (angle < M_PI*(-3.0/16.0)) + angle = M_PI*(-4.0/16.0); + else if (angle < M_PI*(-1.0/16.0)) + angle = -0.463647609; + else if (angle < M_PI*(1.0/16.0)) + angle = M_PI*(0.0/16.0); + else if (angle < M_PI*(3.0/16.0)) + angle = 0.463647609; + else if (angle < M_PI*(5.0/16.0)) + angle = M_PI*(4.0/16.0); + else if (angle < M_PI*(7.0/16.0)) + angle = 1.107148718; + else if (angle < M_PI*(9.0/16.0)) + angle = M_PI*(8.0/16.0); + else if (angle < M_PI*(11.0/16.0)) + angle = 2.034443936; + else if (angle < M_PI*(13.0/16.0)) + angle = M_PI*(12.0/16.0); + else //if (angle < M_PI*(15.0/16.0)) + angle = 2.677945045; + length = sqrt((float)(dx)*(float)(dx)+(float)(dy)*(float)(dy)); + *bx=ax + lrintf(sin(angle)*length); + *by=ay + lrintf(cos(angle)*length); + return; } diff --git a/graph.h b/graph.h index 83739a84..aded3bd4 100644 --- a/graph.h +++ b/graph.h @@ -66,7 +66,7 @@ void Draw_empty_ellipse_preview (short center_x,short center_y,short horizontal void Hide_empty_ellipse_preview (short center_x,short center_y,short horizontal_radius,short vertical_radius); void Draw_filled_ellipse (short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); -void Clamp_coordinates_45_degrees(short ax, short ay, short* bx, short* by); +void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by); void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color); void Draw_line_permanet (short start_x,short start_y,short end_x,short end_y,byte color); void Draw_line_preview (short start_x,short start_y,short end_x,short end_y,byte color); diff --git a/input.c b/input.c index 77a1bc3d..8fcf8a4d 100644 --- a/input.c +++ b/input.c @@ -345,34 +345,34 @@ int Handle_key_press(SDL_KeyboardEvent event) int Release_control(int key_code, int modifier) { - if(key_code == (Config_Key[SPECIAL_MOUSE_UP][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_UP][0]&modifier) || - key_code == (Config_Key[SPECIAL_MOUSE_UP][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_UP][1]&modifier)) + 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; } - if(key_code == (Config_Key[SPECIAL_MOUSE_DOWN][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_DOWN][0]&modifier) || - key_code == (Config_Key[SPECIAL_MOUSE_DOWN][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_DOWN][1]&modifier)) + 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; } - if(key_code == (Config_Key[SPECIAL_MOUSE_LEFT][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_LEFT][0]&modifier) || - key_code == (Config_Key[SPECIAL_MOUSE_LEFT][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_LEFT][1]&modifier)) + 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; } - if(key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][0]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_RIGHT][0]&modifier) || - key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][1]&0x0FFF) || (Config_Key[SPECIAL_MOUSE_RIGHT][1]&modifier)) + 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; } - if(key_code == (Config_Key[SPECIAL_CLICK_LEFT][0]&0x0FFF) || (Config_Key[SPECIAL_CLICK_LEFT][0]&modifier) || - key_code == (Config_Key[SPECIAL_CLICK_LEFT][1]&0x0FFF) || (Config_Key[SPECIAL_CLICK_LEFT][1]&modifier)) + 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)) { Input_new_mouse_K &= ~1; return Move_cursor_with_constraints(); } - if(key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) || - key_code == (Config_Key[SPECIAL_CLICK_RIGHT][1]&0x0FFF) || (Config_Key[SPECIAL_CLICK_RIGHT][1]&modifier)) + if((key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) || + (key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][1]&modifier)) { Input_new_mouse_K &= ~2; return Move_cursor_with_constraints(); diff --git a/operatio.c b/operatio.c index 863d58c0..4cc6b202 100644 --- a/operatio.c +++ b/operatio.c @@ -490,20 +490,26 @@ void Line_12_5(void) short start_y; short end_x; short end_y; + + short cursor_x; + short cursor_y; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); + cursor_x = Paintbrush_X; + cursor_y = Paintbrush_Y; + // On corrige les coordonnées de la ligne si la touche shift est appuyée... if(SDL_GetModState() & KMOD_SHIFT) { - Clamp_coordinates_45_degrees(start_x,start_y,&Paintbrush_X,&Paintbrush_Y); + Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); } // On vient de bouger - if ((Paintbrush_X!=end_x) || (Paintbrush_Y!=end_y)) + if ((cursor_x!=end_x) || (cursor_y!=end_y)) { Hide_cursor(); @@ -513,18 +519,18 @@ void Line_12_5(void) if (Mouse_K==LEFT_SIDE) { Pixel_figure_preview (start_x,start_y,Fore_color); - Draw_line_preview (start_x,start_y,Paintbrush_X,Paintbrush_Y,Fore_color); + Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Fore_color); } else { Pixel_figure_preview (start_x,start_y,Back_color); - Draw_line_preview (start_x,start_y,Paintbrush_X,Paintbrush_Y,Back_color); + Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Back_color); } Operation_push(start_x); Operation_push(start_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); + Operation_push(cursor_x); + Operation_push(cursor_y); Display_cursor(); } @@ -559,10 +565,6 @@ void Line_0_5(void) Operation_pop(&start_x); Operation_pop(&color); - // On corrige les coordonnées de la ligne si la touche shift est appuyée... - if(SDL_GetModState() & KMOD_SHIFT) - Clamp_coordinates_45_degrees(start_x,start_y,&end_x,&end_y); - Paintbrush_shape=Paintbrush_shape_before_operation; Pixel_figure_preview_auto (start_x,start_y); @@ -4760,22 +4762,26 @@ void Grad_rectangle_12_9(void) short start_y; short end_x; short end_y; + short cursor_x; + short cursor_y; Operation_pop(&end_y); Operation_pop(&end_x); Operation_pop(&start_y); Operation_pop(&start_x); - if ((Paintbrush_X!=end_x) || (Paintbrush_Y!=end_y)) + cursor_x = Paintbrush_X; + cursor_y = Paintbrush_Y; + // 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); + + if ((cursor_x!=end_x) || (cursor_y!=end_y)) { - // On corrige les coordonnées de la ligne si la touche shift est appuyée... - if(SDL_GetModState() & KMOD_SHIFT) - Clamp_coordinates_45_degrees(start_x,start_y,&Paintbrush_X,&Paintbrush_Y); - Display_coords_rel_or_abs(start_x,start_y); Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); - Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0); + Draw_line_preview_xor(start_x,start_y,cursor_x,cursor_y,0); } From 158cd7ff45442fb9cb58e916cdadd5a1a8fc368e Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 2 Jul 2009 22:09:57 +0000 Subject: [PATCH 30/95] Fixed an old (pre v2.0) control bug where releasing shift key had the extra effect of releasing the left mouse button. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@896 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- input.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/input.c b/input.c index 8fcf8a4d..f3130336 100644 --- a/input.c +++ b/input.c @@ -39,6 +39,8 @@ byte Directional_down; byte Directional_down_left; byte Directional_left; byte Directional_up_left; +byte Directional_click; + long Directional_delay; long Directional_last_move; long Directional_step; @@ -330,11 +332,13 @@ int Handle_key_press(SDL_KeyboardEvent event) else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT)) { Input_new_mouse_K=1; + Directional_click=1; return Move_cursor_with_constraints(); } else if(Is_shortcut(Key,SPECIAL_CLICK_RIGHT)) { Input_new_mouse_K=2; + Directional_click=2; return Move_cursor_with_constraints(); } @@ -368,14 +372,22 @@ int Release_control(int key_code, int modifier) 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)) { - Input_new_mouse_K &= ~1; - return Move_cursor_with_constraints(); + if (Directional_click & 1) + { + Directional_click &= ~1; + Input_new_mouse_K &= ~1; + return Move_cursor_with_constraints(); + } } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][1]&modifier)) { - Input_new_mouse_K &= ~2; - return Move_cursor_with_constraints(); + if (Directional_click & 2) + { + Directional_click &= ~2; + Input_new_mouse_K &= ~2; + return Move_cursor_with_constraints(); + } } // Other keys don't need to be released : they are handled as "events" and procesed only once. From 392d17c56c8746ecc7b0f4a21eeeec7e6a74d1f6 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 2 Jul 2009 22:12:24 +0000 Subject: [PATCH 31/95] Fixed the clamping of Grad rectangle (I hadn't tested at all :-/ ) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@897 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- operatio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operatio.c b/operatio.c index 4cc6b202..d19a583c 100644 --- a/operatio.c +++ b/operatio.c @@ -4788,8 +4788,8 @@ void Grad_rectangle_12_9(void) Operation_push(start_x); Operation_push(start_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); + Operation_push(cursor_x); + Operation_push(cursor_y); } void Grad_rectangle_0_9(void) From 243b645383fbb8679133d188f1bce4a7ce1deffb Mon Sep 17 00:00:00 2001 From: Pete Gordon Date: Fri, 3 Jul 2009 11:49:09 +0000 Subject: [PATCH 32/95] Fixes to make it build on OS4 and the latest SDK git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@898 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 8929ec6a..b23c31af 100644 --- a/Makefile +++ b/Makefile @@ -62,7 +62,7 @@ else RMDIR = rmdir CP = cp BIN = grafx2 - COPT = -Wall -c -gstabs -mcrt=newlib `sdl-config --cflags` -D__USE_INLINE__ $(TTFCOPT) + COPT = -Wall -c -gstabs -mcrt=newlib `sdl-config --cflags` -I/SDK/Local/common/include/SDL -D__USE_INLINE__ $(TTFCOPT) LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lft2 CC = gcc OBJDIR = obj/amiga @@ -254,7 +254,7 @@ $(BIN) : $(OBJ) $(OBJRES) # SVN revision number version.c : - echo "char SVN_revision[]=\"`svnversion`\";" > version.c + echo "char SVN_revision[]=\"`svnversion .`\";" > version.c ifeq ($(LABEL),) else echo "char Program_version[]=\"$(LABEL)\";" > pversion.c From 15a8c67db714313a1a60cc848319a4f8e87c3b24 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 7 Jul 2009 13:58:37 +0000 Subject: [PATCH 33/95] Patch by MagerValp to allow building on mac with make. Thanks ! git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@902 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Info.plist | 8 ++++---- Makefile | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- graph.c | 8 ++++++-- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/Info.plist b/Info.plist index e2b73ab1..b5d2a5aa 100644 --- a/Info.plist +++ b/Info.plist @@ -1,19 +1,19 @@ - + CFBundleDevelopmentRegion English CFBundleExecutable - ${EXECUTABLE_NAME} + Grafx2 CFBundleIconFile CFBundleIdentifier - http://grafx2.googlecode.com/ + com.googlecode.grafx2 CFBundleInfoDictionaryVersion 6.0 CFBundleName - ${PRODUCT_NAME} + Grafx2 CFBundlePackageType APPL CFBundleSignature diff --git a/Makefile b/Makefile index b23c31af..0001edf3 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ ### PLATFORM DETECTION AND CONFIGURATION ### +PLATFORMOBJ = + # There is no uname under windows, but we can guess we are there with the COMSPEC env.var # Windows specific ifdef COMSPEC @@ -69,6 +71,25 @@ else ZIP = lha ZIPOPT = a + else ifeq ($(PLATFORM),Darwin) + #Mac OS X specific + DELCOMMAND = rm -rf + MKDIR = mkdir -p + RMDIR = rmdir + CP = cp + ZIP = zip + PLATFORMFILES = gfx2.png + BIN = grafx2 + COPT = -D__macosx__ -D__linux__-W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) -I/usr/X11/include + LOPT = `sdl-config --libs` -framework SDL_image -framework SDL_ttf -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 + #CC = nccgen -ncgcc -ncld -ncfabs + OBJDIR = obj/macosx + PLATFORMOBJ = $(OBJDIR)/SDLMain.o + X11LOPT = + MACAPPEXE = Grafx2.app/Contents/MacOS/Grafx2 + else ifeq ($(PLATFORM),AROS) #AROS specific DELCOMMAND = rm -rf @@ -185,7 +206,7 @@ else # Compiles a regular linux exectutable for the native platform BIN = grafx2 - COPT = -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) + COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc @@ -225,11 +246,30 @@ 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 +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 $(PLATFORMOBJ) SKIN_FILES = skins/skin_classic.png skins/skin_modern.png skins/font_Classic.png skins/font_Fun.png +ifeq ($(PLATFORM),Darwin) +all : $(MACAPPEXE) +$(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 -r English.lproj Grafx2.app/Contents/Resources + cp -r fonts Grafx2.app/Contents/Resources + cp -r skins Grafx2.app/Contents/Resources + cp -r gfx2.cfg Grafx2.app/Contents/Resources + cp -r gfx2def.ini Grafx2.app/Contents/Resources + cp -Rp /Library/Frameworks/SDL.framework Grafx2.app/Contents/Frameworks + cp -Rp /Library/Frameworks/SDL_image.framework Grafx2.app/Contents/Frameworks + cp -Rp /Library/Frameworks/SDL_ttf.framework Grafx2.app/Contents/Frameworks + cp $(BIN) $(MACAPPEXE) +else all : $(BIN) +endif + debug : $(BIN) @@ -272,10 +312,14 @@ else $(DELCOMMAND) pversion.c endif -$(OBJDIR)/%.o : +$(OBJDIR)/%.o : %.c $(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR)) $(CC) $(COPT) -c $*.c -o $(OBJDIR)/$*.o +$(OBJDIR)/%.o : %.m + $(if $(wildcard $(OBJDIR)),,$(MKDIR) $(OBJDIR)) + $(CC) $(COPT) -c $*.m -o $(OBJDIR)/$*.o + depend : $(CC) -MM *.c | sed 's:^[^ ]:$$(OBJDIR)/&:' > Makefile.dep diff --git a/graph.c b/graph.c index 6c09776f..28200734 100644 --- a/graph.c +++ b/graph.c @@ -1367,20 +1367,24 @@ void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by) dx = *bx-ax; dy = *by-ay; + // No mouse move: no need to clamp anything if (dx==0 || dy == 0) return; - // On est en lockx et de toutes façons le X n'a pas bougé, on sort tout - // de suite pour éviter une méchante division par 0 angle = atan2(dx, dy); + // Horizontal < 15/16 if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0)) angle = M_PI*(16.0/16.0); + // 15/16 < Iso < 13/16 else if (angle < M_PI*(-13.0/16.0)) angle = -2.677945045; + // 13/16 < 45deg (3pi/4) < 11/16 else if (angle < M_PI*(-11.0/16.0)) angle = M_PI*(-12.0/16.0); + // 11/16 < "vertical iso" < 9/19 else if (angle < M_PI*(-9.0/16.0)) angle = -2.034443936; + // 9/16 < vertical < 7/16 else if (angle < M_PI*(-7.0/16.0)) angle = M_PI*(-8.0/16.0); else if (angle < M_PI*(-5.0/16.0)) From cadb762640de794545ee23bbf71ef22af6941760 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Tue, 7 Jul 2009 14:03:21 +0000 Subject: [PATCH 34/95] Fixed issue 190: buffer overflow in splash screen. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@903 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/buttons.c b/buttons.c index 8dbceb40..59671543 100644 --- a/buttons.c +++ b/buttons.c @@ -126,10 +126,11 @@ void Message_out_of_memory(void) void Button_Message_initial(void) { - char str[21]; + char str[30]; int x_pos,offs_y,x,y; - sprintf(str,"GrafX2 version %s",Program_version); + strcpy(str,"GrafX2 version "); + strcat(str,Program_version); Open_window(260,172,str); Window_display_frame_in(10,20,239,62); From 72e6452d5b3c51f44fbe60a799a4123bd80697f1 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 7 Jul 2009 19:26:37 +0000 Subject: [PATCH 35/95] Integrated Makefile changes from MagerValp (Issue 188 comment 4) for MacOSX; adapted Windows build slightly; Updated Help screens for list of bug finders. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@904 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 23 +++++++++++++---------- helpfile.h | 17 +++++++++-------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 0001edf3..a96d4780 100644 --- a/Makefile +++ b/Makefile @@ -47,8 +47,7 @@ ifdef COMSPEC OBJDIR = obj/win32 # Resources (icon) WINDRES = windres.exe - OBJRES = $(OBJDIR)/winres.o - CFGOBJRES = $(OBJDIR)/wincfgres.o + PLATFORMOBJ = $(OBJDIR)/winres.o PLATFORM = win32 PLATFORMFILES = SDL.dll SDL_image.dll libpng13.dll zlib1.dll gfx2.ico $(TTFLIBS) #some misc files we have to add to the release archive under windows. ZIP = zip @@ -80,8 +79,12 @@ else ZIP = zip PLATFORMFILES = gfx2.png BIN = grafx2 - COPT = -D__macosx__ -D__linux__-W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) -I/usr/X11/include - LOPT = `sdl-config --libs` -framework SDL_image -framework SDL_ttf -L/usr/X11/lib -R/usr/X11/lib -lpng + # Where the SDL frameworks are located + 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 + 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 #CC = nccgen -ncgcc -ncld -ncfabs @@ -262,9 +265,9 @@ $(MACAPPEXE) : $(BIN) cp -r skins Grafx2.app/Contents/Resources cp -r gfx2.cfg Grafx2.app/Contents/Resources cp -r gfx2def.ini Grafx2.app/Contents/Resources - cp -Rp /Library/Frameworks/SDL.framework Grafx2.app/Contents/Frameworks - cp -Rp /Library/Frameworks/SDL_image.framework Grafx2.app/Contents/Frameworks - cp -Rp /Library/Frameworks/SDL_ttf.framework Grafx2.app/Contents/Frameworks + 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 cp $(BIN) $(MACAPPEXE) else all : $(BIN) @@ -289,8 +292,8 @@ ziprelease: version $(BIN) release testsed : -$(BIN) : $(OBJ) $(OBJRES) - $(CC) $(OBJ) $(OBJRES) -o $(BIN) $(LOPT) +$(BIN) : $(OBJ) + $(CC) $(OBJ) -o $(BIN) $(LOPT) # SVN revision number version.c : @@ -328,7 +331,7 @@ $(OBJDIR)/winres.o : gfx2.ico echo "1 ICON \"gfx2.ico\"" | $(WINDRES) -o $(OBJDIR)/winres.o clean : - $(DELCOMMAND) $(OBJ) $(OBJDIR)/version.o $(OBJRES) + $(DELCOMMAND) $(OBJ) $(DELCOMMAND) $(BIN) # Linux installation of the program diff --git a/helpfile.h b/helpfile.h index 47e7c14e..2ad00968 100644 --- a/helpfile.h +++ b/helpfile.h @@ -342,14 +342,15 @@ static const T_Help_table helptable_credits[] = HELP_TITLE(" BUGFINDERS") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT (" BDCIron Ced El Topo ") - HELP_TEXT (" fallenblood Frost Grimmy ") - HELP_TEXT (" Gürkan Sengün HoraK-FDF iLKke ") - HELP_TEXT (" keito kusma Lord Graga ") - HELP_TEXT (" MagerValp mind MooZ ") - HELP_TEXT (" the Peach richienyhus TeeEmCee ") - HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") - HELP_TEXT (" Tobé 00ai99 ") + HELP_TEXT (" blumunkee BDCIron Ced ") + HELP_TEXT (" El Topo fallenblood Frost ") + HELP_TEXT (" Grimmy Gürkan Sengün HoraK-FDF ") + HELP_TEXT (" iLKke Jamon keito ") + HELP_TEXT (" kusma Lord Graga MagerValp ") + HELP_TEXT (" mind MooZ the Peach ") + HELP_TEXT (" richienyhus tape.wyrm TeeEmCee ") + HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") + HELP_TEXT (" Tobé 00ai99 ") HELP_TEXT ("") HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") From c425d3e20de4496c5e543664b67f7ea158d5978b Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 8 Jul 2009 00:27:05 +0000 Subject: [PATCH 36/95] OSX: Config files now in a subdirectory of ~/Library/Preferences. This will keep your settings when you install new versions. Patch by MagerValp, issue 192 git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@907 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- setup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.c b/setup.c index 054b97af..ba0245bd 100644 --- a/setup.c +++ b/setup.c @@ -110,12 +110,8 @@ void Set_data_directory(const char * program_dir, char * data_dir) // OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir) { - // MacOSX - #if defined(__macosx__) - strcpy(config_dir,program_dir); - strcat(config_dir,"Contents/Resources/"); // AmigaOS4 - #elif defined(__amigaos4__) || defined(__AROS__) + #if defined(__amigaos4__) || defined(__AROS__) strcpy(config_dir,"PROGDIR:"); // GP2X #elif defined(__GP2X__) @@ -141,6 +137,10 @@ void Set_config_directory(const char * program_dir, char * config_dir) // "~/.grafx2", the BeOS way const char* Config_SubDir = ".grafx2"; config_parent_dir = getenv("$HOME"); + #elif defined(__macosx__) + // "~/Library/Preferences/com.googlecode.grafx2" + const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; + config_parent_dir = getenv("HOME"); #else // "~/.grafx2" const char* Config_SubDir = ".grafx2"; From 260347ac219a8a47202c157bfdd8fec0e4ec0df3 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Thu, 9 Jul 2009 01:08:02 +0000 Subject: [PATCH 37/95] Updated credits git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@909 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 1 + helpfile.h | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index a96d4780..e950d744 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ # Grafx2 - The Ultimate 256-color bitmap paint program # +# Copyright 2009 Per Olofsson # Copyright 2008 Peter Gordon # Copyright 2008 Yves Rizoud # Copyright 2007 Adrien Destugues diff --git a/helpfile.h b/helpfile.h index 2ad00968..612b2011 100644 --- a/helpfile.h +++ b/helpfile.h @@ -24,7 +24,7 @@ /// /// Note: The source code is kept on a public website, so keep this in mind /// if you're thinking of putting an e-mail address in there. At least, use -/// "\100" instead of @, to help against the most basic email address harversters. +/// "\100" instead of @, to help against the most basic email address harvesters. ////////////////////////////////////////////////////////////////////////////// #include "const.h" // Uses enumerations BUTTON_NUMBERS and SPECIAL_ACTIONS @@ -280,14 +280,13 @@ static const T_Help_table helptable_credits[] = HELP_TEXT (" Guillaume Dorme alias \"Robinson\" (code)") HELP_TEXT (" Karl Maritaud alias \"X-Man\" (code&gfx)") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT (" (k.maritaud\100laposte.net)") // there is an \100 so the line is shorter than it looks HELP_TEXT ("") HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") HELP_TEXT ("") HELP_BOLD (" THE GRAFX2 PROJECT TEAM") HELP_TEXT ("") - HELP_TEXT (" Adrien Destugues (pulkomandy\100gmail.com)") - HELP_TEXT (" Yves Rizoud (yrizoud\100gmail.com)") + HELP_TEXT (" Adrien Destugues (pulkomandy)") + HELP_TEXT (" Yves Rizoud (yrizoud)") HELP_TEXT ("") HELP_TEXT (" Got the source back to life in 2006") HELP_TEXT ("") @@ -295,7 +294,8 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TEXT (" GrafX2 logo by Made (www.m4de.com)") HELP_TEXT (" Icons and fonts by X-Man ") - HELP_TEXT (" Additional graphics by iLKke") + HELP_TEXT (" Additional graphics and logo by iLKke") + HELP_TEXT (" (ilkke.blogspot.com)") HELP_TEXT ("") HELP_TEXT (" Pixelled all the graphics") HELP_TEXT ("") @@ -304,37 +304,37 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_BOLD (" AMIGA OS 3 PORT") HELP_TEXT ("") - HELP_TEXT (" Artur Jarosik (arturjarosik\100gmail.com)") + HELP_TEXT (" Artur Jarosik") HELP_TEXT ("") HELP_BOLD (" AMIGA OS 4 PORT") HELP_TEXT ("") - HELP_TEXT (" Peter Gordon (pete\100petergordon.org.uk)") + HELP_TEXT (" Peter Gordon (www.petergordon.org.uk)") HELP_TEXT ("") HELP_BOLD (" AROS PORT") HELP_TEXT ("") - HELP_TEXT (" Fernando Mastandrea (masta.uy\100gmail.com)") - HELP_TEXT (" Markus Weiss (mweiss\100id-architekten.de)") + HELP_TEXT (" Fernando Mastandrea (masta.uy)") + HELP_TEXT (" Markus Weiss") HELP_TEXT ("") HELP_BOLD (" FREEBSD PORT") HELP_TEXT ("") - HELP_TEXT (" Jean-Baptiste Berlioz") - HELP_TEXT (" (tobe\100freemind-tobe.com)") + HELP_TEXT (" Jean-Baptiste Berlioz (Tobe)") HELP_TEXT ("") HELP_BOLD (" HAIKU OS AND BEOS PORT") HELP_TEXT ("") - HELP_TEXT (" Luc Schrijvers (begasus\100skynet.be)") + HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") HELP_BOLD (" MAC OS X PORT") HELP_TEXT ("") - HELP_TEXT (" Franck Charlet (hitchhikr\100australia.edu)") + HELP_TEXT (" Franck Charlet (hitchhikr)") + HELP_TEXT (" Per Olofsson (MagerValp)") HELP_TEXT ("") HELP_BOLD (" MORPHOS PORT") HELP_TEXT ("") - HELP_TEXT (" Rusback (rusback\100wanadoo.fr)") + HELP_TEXT (" Rusback") HELP_TEXT ("") HELP_BOLD (" SKYOS PORT") HELP_TEXT ("") - HELP_TEXT (" Luc Schrijvers (begasus\100skynet.be)") + HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") From 7bde7d90ce25d28e9774e1d611a389a0ba427474 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Mon, 13 Jul 2009 08:09:40 +0000 Subject: [PATCH 38/95] Quick-made support for Neochrome files. Loading works, saving leaves parts of the header uninitialized. Neochrome may or may not like it. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@911 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- const.h | 11 ++-- gfx2.cfg | Bin 10133 -> 10133 bytes loadsave.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 5 deletions(-) diff --git a/const.h b/const.h index 6c604d5c..c0fcc269 100644 --- a/const.h +++ b/const.h @@ -90,14 +90,14 @@ // -- File formats #ifndef __no_pnglib__ +#define NB_KNOWN_FORMATS 14 ///< Total number of known file formats. +#define NB_FORMATS_LOAD 14 ///< Number of file formats that grafx2 can load. +#define NB_FORMATS_SAVE 14 ///< Number of file formats that grafx2 can save. +#else +// Without pnglib #define NB_KNOWN_FORMATS 13 ///< Total number of known file formats. #define NB_FORMATS_LOAD 13 ///< Number of file formats that grafx2 can load. #define NB_FORMATS_SAVE 13 ///< Number of file formats that grafx2 can save. -#else -// Without pnglib -#define NB_KNOWN_FORMATS 12 ///< Total number of known file formats. -#define NB_FORMATS_LOAD 12 ///< Number of file formats that grafx2 can load. -#define NB_FORMATS_SAVE 12 ///< Number of file formats that grafx2 can save. #endif /// List of file formats recognized by grafx2 @@ -114,6 +114,7 @@ enum FILE_FORMATS FORMAT_PI1, FORMAT_PC1, FORMAT_CEL, + FORMAT_NEO, FORMAT_KCF, FORMAT_PAL, FORMAT_PNG diff --git a/gfx2.cfg b/gfx2.cfg index 00f063575534f2fe1325217f0fc194bb9d34460b..a02e005c348bed9e79b9b9e14dc8e34e45e0c912 100644 GIT binary patch delta 156 zcmY+2I}(C000lP$1q~WR{EI0-Z(_}DtSqp%kqo^@a3-Y(@E)GTSh6#3X7_bQDN-vWh4sG ZhaUD>eQkTpRBHZz>lfHZ`Ei$%5kK&E6H@>H delta 118 zcmbR0Kh=Lj4YM{Q11AFmBNGD`kYr}y29hicJV26_ffq=!G4KIN1_llWb_V{=c zH#hL}h-_})X5rY}qs-0-QUnAbH9%_e29-yXFQ^Dio}?>4);x_pos++) + { + PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); + ptr+=8; + } + for (x_pos=0;x_pos<320;x_pos++) + Pixel_load_function(x_pos,y_pos,pixels[x_pos]); + } + } + } + else + File_error=1; + free(buffer); + } + else + File_error=1; + fclose(file); + } + else + File_error=1; +} + +void Save_NEO(void) +{ + char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier + FILE *file; + short x_pos,y_pos; + byte * buffer; + byte * ptr; + byte pixels[320]; + + Get_full_filename(filename,0); + + File_error=0; + // Ouverture du fichier + if ((file=fopen(filename,"wb"))) + { + // allocation d'un buffer mémoire + buffer=(byte *)malloc(32128); + // Codage de la résolution + buffer[0]=0x00; + buffer[1]=0x00; + buffer[2]=0x00; + buffer[3]=0x00; + // Codage de la palette + PI1_code_palette((byte *)Main_palette,buffer+4); + // Codage de l'image + ptr=buffer+128; + for (y_pos=0;y_pos<200;y_pos++) + { + // Codage de la ligne + memset(pixels,0,320); + if (y_pos>4);x_pos++) + { + PI1_16p_to_8b(pixels+(x_pos<<4),ptr); + ptr+=8; + } + } + + if (Write_bytes(file,buffer,32128)) + { + fclose(file); + } + else // Error d'écriture (disque plein ou protégé) + { + fclose(file); + remove(filename); + File_error=1; + } + // Libération du buffer mémoire + free(buffer); + } + else + { + fclose(file); + remove(filename); + File_error=1; + } +} + ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// PNG //////////////////////////////////// From 77728125fbdf8993f74659af5f98f888548857e4 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 13 Jul 2009 19:10:48 +0000 Subject: [PATCH 39/95] GUI: All controls are now 'sticky', ie. when you're dragging a slider/scroller and you move the mouse too far, it no longer activate other buttons. (Issue 191) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@918 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- engine.c | 194 ++++++++++++++++++++++++++++++++++++++----------------- input.c | 12 +++- input.h | 7 ++ 3 files changed, 151 insertions(+), 62 deletions(-) diff --git a/engine.c b/engine.c index 605cf0a3..7a13df61 100644 --- a/engine.c +++ b/engine.c @@ -2334,6 +2334,59 @@ short Window_normal_button_onclick(word x_pos, word y_pos, word width, word heig } } +// Returns true if the mouse cursor sits inside the boundary of control. +short Window_click_in_control(short control) +{ + T_Normal_button * temp1; + T_Palette_button * temp2; + T_Scroller_button * temp3; + T_Special_button * temp4; + T_Dropdown_button * temp5; + + for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next) + { + if (temp1->Number == control) + return Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1); + } + + for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next) + { + if (temp2->Number == control) + return Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82); + } + + for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) + { + if (temp3->Number == (control & 1023)) + { + // top scroller arrow + if (control & 1024) + return Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10); + // bottom scroller arrow + if (control & 2048) + return Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1); + // middle slider + return Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-13); + } + } + + // Test du click sur une zone spéciale + for (temp4=Window_special_button_list; temp4; temp4=temp4->Next) + { + if (temp4->Number == control) + return Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1); + } + + // Test du click sur une dropdown + for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next) + { + if (temp5->Number == control) + return Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1); + } + + return 0; +} + // --- Renvoie le numéro du bouton clicke (-1:hors de la fenêtre, 0:aucun) --- short Window_get_clicked_button(void) { @@ -2352,6 +2405,7 @@ short Window_get_clicked_button(void) { if (Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1)) { + Input_sticky_control = temp1->Number; if (temp1->Repeatable) { Hide_cursor(); @@ -2372,6 +2426,7 @@ short Window_get_clicked_button(void) { if (Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82)) { + Input_sticky_control = temp2->Number; // On stocke dans Attribut2 le numero de couleur cliqué Window_attribute2 = (((Mouse_X-Window_pos_X)/Menu_factor_X)-(temp2->Pos_X+2)) / 10 * 16 + (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(temp2->Pos_Y+3)) / 5; @@ -2387,6 +2442,7 @@ short Window_get_clicked_button(void) // Button flèche Haut if (Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10)) { + Input_sticky_control = temp3->Number | 1024; Hide_cursor(); Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); @@ -2412,6 +2468,7 @@ short Window_get_clicked_button(void) // Button flèche Bas if (Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1)) { + Input_sticky_control = temp3->Number | 2048; Hide_cursor(); Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,11,11); @@ -2437,6 +2494,7 @@ short Window_get_clicked_button(void) // Jauge if (Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-13)) { + Input_sticky_control = temp3->Number; if (temp3->Nb_elements>temp3->Nb_visibles) { // S'il y a la place de faire scroller le curseur: @@ -2488,7 +2546,10 @@ short Window_get_clicked_button(void) for (temp4=Window_special_button_list; temp4; temp4=temp4->Next) { if (Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1)) - return temp4->Number; + { + Input_sticky_control = temp4->Number; + return temp4->Number; + } } // Test du click sur une dropdown @@ -2496,6 +2557,7 @@ short Window_get_clicked_button(void) { if (Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1)) { + Input_sticky_control = temp5->Number; if (Mouse_K & temp5->Active_button) return Window_dropdown_on_click(temp5); else @@ -2587,71 +2649,81 @@ short Window_clicked_button(void) if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y))) - return -1; - else { - if (Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) - Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); + if (Input_sticky_control == 0 || Input_sticky_control == -1) + { + Input_sticky_control = -1; + return -1; + } else { - short clicked_button; - T_List_button * list; - // Check which controls was clicked (by rectangular area) - clicked_button = Window_get_clicked_button(); - - // Check if it's part of a list control - for (list=Window_list_button_list; list!=NULL; list=list->Next) - { - if (list->Entry_button->Number == clicked_button) - { - // Click in the textual part of a list. - short clicked_line; - clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; - if (clicked_line == list->Cursor_position || // Same as before - clicked_line >= list->Scroller->Nb_elements) // Below last line - return 0; - - Hide_cursor(); - // Redraw one item as disabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 0); - list->Cursor_position = clicked_line; - // Redraw one item as enabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 1); - 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; - } - else if (list->Scroller->Number == clicked_button) - { - // Click in the scroller part of a list - if (list->List_start == list->Scroller->Position) - return 0; // Didn't actually move - // Update scroller indices - list->Cursor_position += list->List_start; - list->List_start = list->Scroller->Position; - list->Cursor_position -= list->List_start; - // Need to redraw all - Hide_cursor(); - Window_redraw_list(list); - Display_cursor(); - } - } - return clicked_button; + return 0; } } + + if (Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) + { + Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); + } + else + { + short clicked_button; + T_List_button * list; + // Check which controls was clicked (by rectangular area) + clicked_button = Window_get_clicked_button(); + + // Check if it's part of a list control + for (list=Window_list_button_list; list!=NULL; list=list->Next) + { + if (list->Entry_button->Number == clicked_button) + { + // Click in the textual part of a list. + short clicked_line; + clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; + if (clicked_line == list->Cursor_position || // Same as before + clicked_line >= list->Scroller->Nb_elements) // Below last line + return 0; + + Hide_cursor(); + // Redraw one item as disabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 0); + list->Cursor_position = clicked_line; + // Redraw one item as enabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 1); + Display_cursor(); + + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return ((Input_sticky_control = list->Number)); + } + else if (list->Scroller->Number == clicked_button) + { + // Click in the scroller part of a list + if (list->List_start == list->Scroller->Position) + return 0; // Didn't actually move + // Update scroller indices + list->Cursor_position += list->List_start; + list->List_start = list->Scroller->Position; + list->Cursor_position -= list->List_start; + // Need to redraw all + Hide_cursor(); + Window_redraw_list(list); + Display_cursor(); + } + } + return clicked_button; + } } // Intercept keys diff --git a/input.c b/input.c index f3130336..1f91d1be 100644 --- a/input.c +++ b/input.c @@ -31,6 +31,8 @@ void Handle_window_resize(SDL_ResizeEvent event); void Handle_window_exit(SDL_QuitEvent event); +int Input_sticky_control = 0; + byte Directional_up; byte Directional_up_right; byte Directional_right; @@ -155,8 +157,14 @@ int Move_cursor_with_constraints() (Input_new_mouse_Y != Mouse_Y) || (Input_new_mouse_K != Mouse_K)) { + // On every change of mouse state if ((Input_new_mouse_K != Mouse_K)) - feedback=1; + { + feedback=1; + + if (Input_new_mouse_K == 0) + Input_sticky_control = 0; + } Hide_cursor(); // On efface le curseur AVANT de le déplacer... if (Input_new_mouse_X != Mouse_X || Input_new_mouse_Y != Mouse_Y) { @@ -298,6 +306,8 @@ int Handle_mouse_release(SDL_MouseButtonEvent event) Input_new_mouse_K &= ~2; break; } + Input_sticky_control = -1; + return Move_cursor_with_constraints(); } diff --git a/input.h b/input.h index 7a878c95..8a70ca8f 100644 --- a/input.h +++ b/input.h @@ -40,3 +40,10 @@ int Is_shortcut(word Key, word function); void Adjust_mouse_sensitivity(word fullscreen); void Set_mouse_position(void); + +/// +/// This holds the ID of the GUI control that the mouse +/// is manipulating. The input system will reset it to zero +/// when mouse button is released, but it's the engine +/// that will record and retrieve a real control ID. +extern int Input_sticky_control; \ No newline at end of file From 3a5b4601847292347cf8eaa020d9e7c01a338605 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Mon, 13 Jul 2009 21:36:53 +0000 Subject: [PATCH 40/95] Finished the sticky buttons (didn't have any visible effect) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@919 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- engine.c | 121 ++++++++++++++++++++++++++++++------------------------- input.c | 1 - 2 files changed, 65 insertions(+), 57 deletions(-) diff --git a/engine.c b/engine.c index 7a13df61..59296c4b 100644 --- a/engine.c +++ b/engine.c @@ -2661,68 +2661,77 @@ short Window_clicked_button(void) } } - if (Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) + if (Input_sticky_control != 0 && !Window_click_in_control(Input_sticky_control)) { - Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); + // do nothing } else { - short clicked_button; - T_List_button * list; - // Check which controls was clicked (by rectangular area) - clicked_button = Window_get_clicked_button(); - - // Check if it's part of a list control - for (list=Window_list_button_list; list!=NULL; list=list->Next) + + if (Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) { - if (list->Entry_button->Number == clicked_button) - { - // Click in the textual part of a list. - short clicked_line; - clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; - if (clicked_line == list->Cursor_position || // Same as before - clicked_line >= list->Scroller->Nb_elements) // Below last line - return 0; - - Hide_cursor(); - // Redraw one item as disabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 0); - list->Cursor_position = clicked_line; - // Redraw one item as enabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 1); - Display_cursor(); - - // Store the selected value as attribute2 - Window_attribute2=list->List_start + list->Cursor_position; - // Return the control ID of the list. - return ((Input_sticky_control = list->Number)); - } - else if (list->Scroller->Number == clicked_button) - { - // Click in the scroller part of a list - if (list->List_start == list->Scroller->Position) - return 0; // Didn't actually move - // Update scroller indices - list->Cursor_position += list->List_start; - list->List_start = list->Scroller->Position; - list->Cursor_position -= list->List_start; - // Need to redraw all - Hide_cursor(); - Window_redraw_list(list); - Display_cursor(); - } + Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); + } + else + { + short clicked_button; + T_List_button * list; + + // Check which controls was clicked (by rectangular area) + clicked_button = Window_get_clicked_button(); + + // Check if it's part of a list control + for (list=Window_list_button_list; list!=NULL; list=list->Next) + { + if (list->Entry_button->Number == clicked_button) + { + // Click in the textual part of a list. + short clicked_line; + clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; + if (clicked_line == list->Cursor_position || // Same as before + clicked_line >= list->Scroller->Nb_elements) // Below last line + return 0; + + Hide_cursor(); + // Redraw one item as disabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 0); + list->Cursor_position = clicked_line; + // Redraw one item as enabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 1); + Display_cursor(); + + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return ((Input_sticky_control = list->Number)); + } + else if (list->Scroller->Number == clicked_button) + { + // Click in the scroller part of a list + if (list->List_start == list->Scroller->Position) + return 0; // Didn't actually move + // Update scroller indices + list->Cursor_position += list->List_start; + list->List_start = list->Scroller->Position; + list->Cursor_position -= list->List_start; + // Need to redraw all + Hide_cursor(); + Window_redraw_list(list); + Display_cursor(); + } + } + return clicked_button; } - return clicked_button; } } diff --git a/input.c b/input.c index 1f91d1be..6ffc6f07 100644 --- a/input.c +++ b/input.c @@ -306,7 +306,6 @@ int Handle_mouse_release(SDL_MouseButtonEvent event) Input_new_mouse_K &= ~2; break; } - Input_sticky_control = -1; return Move_cursor_with_constraints(); } From c596b80b8d00bc99fdc7e9daabfa233815e0384a Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 14 Jul 2009 20:43:51 +0000 Subject: [PATCH 41/95] GUI: Made slider controls movable even if you bring mouse cursor far from them. Makes it much easier to maximize or minimize a value. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@920 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- engine.c | 382 +++++++++++++++++++++++-------------------------------- 1 file changed, 162 insertions(+), 220 deletions(-) diff --git a/engine.c b/engine.c index 59296c4b..bef06ad1 100644 --- a/engine.c +++ b/engine.c @@ -2334,60 +2334,7 @@ short Window_normal_button_onclick(word x_pos, word y_pos, word width, word heig } } -// Returns true if the mouse cursor sits inside the boundary of control. -short Window_click_in_control(short control) -{ - T_Normal_button * temp1; - T_Palette_button * temp2; - T_Scroller_button * temp3; - T_Special_button * temp4; - T_Dropdown_button * temp5; - - for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next) - { - if (temp1->Number == control) - return Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1); - } - - for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next) - { - if (temp2->Number == control) - return Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82); - } - - for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) - { - if (temp3->Number == (control & 1023)) - { - // top scroller arrow - if (control & 1024) - return Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10); - // bottom scroller arrow - if (control & 2048) - return Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1); - // middle slider - return Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-13); - } - } - - // Test du click sur une zone spéciale - for (temp4=Window_special_button_list; temp4; temp4=temp4->Next) - { - if (temp4->Number == control) - return Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1); - } - - // Test du click sur une dropdown - for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next) - { - if (temp5->Number == control) - return Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1); - } - - return 0; -} - -// --- Renvoie le numéro du bouton clicke (-1:hors de la fenêtre, 0:aucun) --- +// --- Returns the number of the clicked button (-1:out of the window, 0:none) --- short Window_get_clicked_button(void) { T_Normal_button * temp1; @@ -2400,10 +2347,11 @@ short Window_get_clicked_button(void) Window_attribute1=Mouse_K; - // Test du click sur les boutons normaux + // Test click on normal buttons for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next) { - if (Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1)) + if ((Input_sticky_control == 0 || Input_sticky_control == temp1->Number) + && Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1)) { Input_sticky_control = temp1->Number; if (temp1->Repeatable) @@ -2421,141 +2369,143 @@ short Window_get_clicked_button(void) } } - // Test du click sur les zones "palette" + // Test click on "Palette" buttons for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next) { - if (Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82)) + if ((Input_sticky_control == 0 || Input_sticky_control == temp2->Number) + && Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82)) { Input_sticky_control = temp2->Number; - // On stocke dans Attribut2 le numero de couleur cliqué + // We store the clicked color in Attribute2 Window_attribute2 = (((Mouse_X-Window_pos_X)/Menu_factor_X)-(temp2->Pos_X+2)) / 10 * 16 + (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(temp2->Pos_Y+3)) / 5; return temp2->Number; } } - // Test du click sur les barres de défilement + // Test click oin slider/scroller bars for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) { - if (Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1)) + // Button Up arrow + if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|1024)) + && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10)) { - // Button flèche Haut - if (Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10)) + Input_sticky_control = temp3->Number | 1024; + Hide_cursor(); + Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); + + if (temp3->Position) { - Input_sticky_control = temp3->Number | 1024; - Hide_cursor(); - Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); - - if (temp3->Position) - { - temp3->Position--; - Window_attribute1=1; - Window_attribute2=temp3->Position; - Window_draw_slider(temp3); - } - else - Window_attribute1=0; - - Display_cursor(); - - Slider_timer((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); - Display_cursor(); + temp3->Position--; + Window_attribute1=1; + Window_attribute2=temp3->Position; + Window_draw_slider(temp3); } else - // Button flèche Bas - if (Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1)) + Window_attribute1=0; + + Display_cursor(); + + Slider_timer((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); + Display_cursor(); + + return (Window_attribute1)? temp3->Number : 0; + } + + // 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)) + { + 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->Position+temp3->Nb_visiblesNb_elements) { - 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->Position+temp3->Nb_visiblesNb_elements) - { - temp3->Position++; - Window_attribute1=2; - Window_attribute2=temp3->Position; - Window_draw_slider(temp3); - } - else - Window_attribute1=0; - - Display_cursor(); - - Slider_timer((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); - Display_cursor(); + temp3->Position++; + Window_attribute1=2; + Window_attribute2=temp3->Position; + Window_draw_slider(temp3); } else - // Jauge - if (Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-13)) - { - Input_sticky_control = temp3->Number; - if (temp3->Nb_elements>temp3->Nb_visibles) - { - // S'il y a la place de faire scroller le curseur: - - max_slider_height=(temp3->Height-24); - - // Window_attribute2 reçoit la position dans la jauge correspondant au click - 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 (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; - } - - // Si le curseur de la jauge bouge: - - if (temp3->Position!=Window_attribute2) - { - temp3->Position=Window_attribute2; - Window_attribute1=3; - Hide_cursor(); - Window_draw_slider(temp3); - Display_cursor(); - } - else - // Si le curseur de la jauge ne bouge pas: - Window_attribute1=0; - } - else - // S'il n'y a pas la place de bouger le curseur de la jauge: - Window_attribute1=0; - } - else - // Le click se situe dans la zone de la jauge mais n'est sur aucune - // des 3 parties importantes de la jauge Window_attribute1=0; + Display_cursor(); + + Slider_timer((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); + 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))) + { + 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); + + // 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 (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; + } + + // If the cursor moved + + if (temp3->Position!=Window_attribute2) + { + temp3->Position=Window_attribute2; + Window_attribute1=3; + Hide_cursor(); + Window_draw_slider(temp3); + Display_cursor(); + } + else + // If the cursor moved + Window_attribute1=0; + } + else + // If there's not enough room to make the cursor move: + Window_attribute1=0; + + return (Window_attribute1)? temp3->Number : 0; + } } - // Test du click sur une zone spéciale + // Test click on a special button for (temp4=Window_special_button_list; temp4; temp4=temp4->Next) { - if (Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1)) + if ((Input_sticky_control == 0 || Input_sticky_control == temp4->Number) + && Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1)) { Input_sticky_control = temp4->Number; return temp4->Number; } } - // Test du click sur une dropdown + // Test click on a dropdown box for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next) { - if (Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1)) + if ((Input_sticky_control == 0 || Input_sticky_control == temp5->Number) + && Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1)) { Input_sticky_control = temp5->Number; if (Mouse_K & temp5->Active_button) @@ -2660,78 +2610,70 @@ short Window_clicked_button(void) return 0; } } - - if (Input_sticky_control != 0 && !Window_click_in_control(Input_sticky_control)) + + if (!Input_sticky_control && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) { - // do nothing + Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); } else { - - if (Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) + short clicked_button; + T_List_button * list; + + // Check which controls was clicked (by rectangular area) + clicked_button = Window_get_clicked_button(); + + // Check if it's part of a list control + for (list=Window_list_button_list; list!=NULL; list=list->Next) { - Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); - } - else - { - short clicked_button; - T_List_button * list; - - // Check which controls was clicked (by rectangular area) - clicked_button = Window_get_clicked_button(); - - // Check if it's part of a list control - for (list=Window_list_button_list; list!=NULL; list=list->Next) + if (list->Entry_button->Number == clicked_button) { - if (list->Entry_button->Number == clicked_button) - { - // Click in the textual part of a list. - short clicked_line; - clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; - if (clicked_line == list->Cursor_position || // Same as before - clicked_line >= list->Scroller->Nb_elements) // Below last line - return 0; - - Hide_cursor(); - // Redraw one item as disabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 0); - list->Cursor_position = clicked_line; - // Redraw one item as enabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 1); - Display_cursor(); - - // Store the selected value as attribute2 - Window_attribute2=list->List_start + list->Cursor_position; - // Return the control ID of the list. - return ((Input_sticky_control = list->Number)); - } - else if (list->Scroller->Number == clicked_button) - { - // Click in the scroller part of a list - if (list->List_start == list->Scroller->Position) - return 0; // Didn't actually move - // Update scroller indices - list->Cursor_position += list->List_start; - list->List_start = list->Scroller->Position; - list->Cursor_position -= list->List_start; - // Need to redraw all - Hide_cursor(); - Window_redraw_list(list); - Display_cursor(); - } + // Click in the textual part of a list. + short clicked_line; + clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; + if (clicked_line == list->Cursor_position || // Same as before + clicked_line >= list->Scroller->Nb_elements) // Below last line + return 0; + + Hide_cursor(); + // Redraw one item as disabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 0); + list->Cursor_position = clicked_line; + // Redraw one item as enabled + if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) + list->Draw_list_item( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y + list->Cursor_position * 8, + list->List_start + list->Cursor_position, + 1); + 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; + } + else if (list->Scroller->Number == clicked_button) + { + // Click in the scroller part of a list + if (list->List_start == list->Scroller->Position) + return 0; // Didn't actually move + // Update scroller indices + list->Cursor_position += list->List_start; + list->List_start = list->Scroller->Position; + list->Cursor_position -= list->List_start; + // Need to redraw all + Hide_cursor(); + Window_redraw_list(list); + Display_cursor(); } - return clicked_button; } + return clicked_button; } } From 7fc318a856a8c6148ab2a68cdbf989b7e6ae7117 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 15 Jul 2009 18:50:25 +0000 Subject: [PATCH 42/95] Experimental work on mouse locking with shift (issue 193). Consider unstable. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@921 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- input.c | 21 ++++++++++++++++++--- input.h | 9 ++++++++- windows.c | 41 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/input.c b/input.c index 6ffc6f07..34148178 100644 --- a/input.c +++ b/input.c @@ -31,7 +31,14 @@ void Handle_window_resize(SDL_ResizeEvent event); void Handle_window_exit(SDL_QuitEvent event); +// public Globals (available as extern) + int Input_sticky_control = 0; +int Snap_axis = 0; +int Snap_axis_origin_X; +int Snap_axis_origin_Y; + +// -- byte Directional_up; byte Directional_up_right; @@ -357,6 +364,14 @@ int Handle_key_press(SDL_KeyboardEvent event) int Release_control(int key_code, int modifier) { + int need_feedback = 0; + + if (modifier == MOD_SHIFT) + { + // Disable "snap axis" mode + Snap_axis = 0; + need_feedback = 1; + } 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)) @@ -385,7 +400,7 @@ int Release_control(int key_code, int modifier) { Directional_click &= ~1; Input_new_mouse_K &= ~1; - return Move_cursor_with_constraints(); + return Move_cursor_with_constraints() || need_feedback; } } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) || @@ -395,14 +410,14 @@ int Release_control(int key_code, int modifier) { Directional_click &= ~2; Input_new_mouse_K &= ~2; - return Move_cursor_with_constraints(); + return Move_cursor_with_constraints() || need_feedback; } } // Other keys don't need to be released : they are handled as "events" and procesed only once. // These clicks are apart because they need to be continuous (ie move while key pressed) // We are relying on "hardware" keyrepeat to achieve that. - return 0; + return need_feedback; } diff --git a/input.h b/input.h index 8a70ca8f..c6f68f23 100644 --- a/input.h +++ b/input.h @@ -46,4 +46,11 @@ void Set_mouse_position(void); /// is manipulating. The input system will reset it to zero /// when mouse button is released, but it's the engine /// that will record and retrieve a real control ID. -extern int Input_sticky_control; \ No newline at end of file +extern int Input_sticky_control; + +/// Allows locking movement to X or Y axis: 0=normal, 1=lock on next move, 2=locked horizontally, 3=locked vertically. +extern int Snap_axis; +/// For the :Snap_axis mode, sets the origin's point (in image coordinates) +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; diff --git a/windows.c b/windows.c index b7b29291..c91cc862 100644 --- a/windows.c +++ b/windows.c @@ -32,6 +32,7 @@ #include "misc.h" #include "sdlscreen.h" #include "errors.h" +#include "input.h" // L'encapsulation tente une percée...ou un dernier combat. @@ -1275,6 +1276,46 @@ void Compute_paintbrush_coordinates(void) Paintbrush_X=(((Paintbrush_X+(Snap_width>>1)-Snap_offset_X)/Snap_width)*Snap_width)+Snap_offset_X; Paintbrush_Y=(((Paintbrush_Y+(Snap_height>>1)-Snap_offset_Y)/Snap_height)*Snap_height)+Snap_offset_Y; } + + // Handling the snap axis mode, when shift is pressed. + switch (Current_operation) + { + // Operations that don't implement it + case OPERATION_LINE: + Snap_axis=0; + break; + // Operations that implement it + default: + if (Snap_axis==0 && (SDL_GetModState() & KMOD_SHIFT)) + { + // Start "Snap axis" mode + Snap_axis=1; + Snap_axis_origin_X=Paintbrush_X; + Snap_axis_origin_Y=Paintbrush_Y; + } + } + + if (Snap_axis==1) + { + // Cursor moved + if (Paintbrush_X != Snap_axis_origin_X || Paintbrush_Y != Snap_axis_origin_Y) + { + if ((Paintbrush_X-Snap_axis_origin_X)*(Paintbrush_X-Snap_axis_origin_X) > + (Paintbrush_Y-Snap_axis_origin_Y)*(Paintbrush_Y-Snap_axis_origin_Y)) + // Displacement was bigger on X axis: lock Y + Snap_axis=2; + else + Snap_axis=3; + } + } + if (Snap_axis==2) + { + Paintbrush_Y = Snap_axis_origin_Y; + } + else if (Snap_axis==3) + { + Paintbrush_X = Snap_axis_origin_X; + } } From 9d0c73b5bee2e4b029e14c4f8e7c1c23f166ae8c Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 15 Jul 2009 20:11:07 +0000 Subject: [PATCH 43/95] =?UTF-8?q?Tweaked=20the=20line=20clamping=20algorit?= =?UTF-8?q?hm=20(Issue=20186):=20Multiples=20of=2045=C2=B0=20use=20orthogo?= =?UTF-8?q?nal=20projection=20(again),=20ISO=20lines=20are=20now=20constra?= =?UTF-8?q?ined=20to=20exact=202:1=20lines=20and=20their=20length=20is=20p?= =?UTF-8?q?rojected=20on=20most=20significant=20axis,=20horizontal=20or=20?= =?UTF-8?q?vertical?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@922 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- gfx2.cfg | Bin 10133 -> 10133 bytes graph.c | 165 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 116 insertions(+), 49 deletions(-) diff --git a/gfx2.cfg b/gfx2.cfg index a02e005c348bed9e79b9b9e14dc8e34e45e0c912..eeea8c6a91e496bbeb2557ae8d8c8446d4daa94a 100644 GIT binary patch delta 16 VcmbR0Kh=LjuR4bVg98Hy001q=1GNAE delta 16 VcmbR0Kh=LjuQ~?@0|x^L001ht14RG; diff --git a/graph.c b/graph.c index 28200734..b01133ad 100644 --- a/graph.c +++ b/graph.c @@ -1360,61 +1360,128 @@ void Draw_filled_ellipse(short center_x,short center_y,short horizontal_radius,s /// vertical, 45degrees, or isometrical for pixelart (ie 2:1 ratio) void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by) { - int dx, dy; - float angle; - float length; + int dx, dy; + float angle; - dx = *bx-ax; - dy = *by-ay; + dx = *bx-ax; + dy = *by-ay; // No mouse move: no need to clamp anything - if (dx==0 || dy == 0) return; + if (dx==0 || dy == 0) return; - angle = atan2(dx, dy); + // Determine angle (heading) + angle = atan2(dx, dy); - // Horizontal < 15/16 - if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0)) - angle = M_PI*(16.0/16.0); - // 15/16 < Iso < 13/16 - else if (angle < M_PI*(-13.0/16.0)) - angle = -2.677945045; - // 13/16 < 45deg (3pi/4) < 11/16 - else if (angle < M_PI*(-11.0/16.0)) - angle = M_PI*(-12.0/16.0); - // 11/16 < "vertical iso" < 9/19 - else if (angle < M_PI*(-9.0/16.0)) - angle = -2.034443936; - // 9/16 < vertical < 7/16 - else if (angle < M_PI*(-7.0/16.0)) - angle = M_PI*(-8.0/16.0); - else if (angle < M_PI*(-5.0/16.0)) - angle = -1.107148718; - else if (angle < M_PI*(-3.0/16.0)) - angle = M_PI*(-4.0/16.0); - else if (angle < M_PI*(-1.0/16.0)) - angle = -0.463647609; - else if (angle < M_PI*(1.0/16.0)) - angle = M_PI*(0.0/16.0); - else if (angle < M_PI*(3.0/16.0)) - angle = 0.463647609; - else if (angle < M_PI*(5.0/16.0)) - angle = M_PI*(4.0/16.0); - else if (angle < M_PI*(7.0/16.0)) - angle = 1.107148718; - else if (angle < M_PI*(9.0/16.0)) - angle = M_PI*(8.0/16.0); - else if (angle < M_PI*(11.0/16.0)) - angle = 2.034443936; - else if (angle < M_PI*(13.0/16.0)) - angle = M_PI*(12.0/16.0); - else //if (angle < M_PI*(15.0/16.0)) - angle = 2.677945045; + // Get absolute values, useful from now on: + //dx=abs(dx); + //dy=abs(dy); + + // Negative Y + if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0)) + { + *bx=ax; + *by=ay + dy; + } + // Iso close to negative Y + else if (angle < M_PI*(-13.0/16.0)) + { + dy=dy | 1; // Round up to next odd number + *bx=ax + dy/2; + *by=ay + dy; + } + // 45deg + else if (angle < M_PI*(-11.0/16.0)) + { + *by = (*by + ay + dx)/2; + *bx = ax - ay + *by; + } + // Iso close to negative X + else if (angle < M_PI*(-9.0/16.0)) + { + dx=dx | 1; // Round up to next odd number + *bx=ax + dx; + *by=ay + dx/2; + } + // Negative X + else if (angle < M_PI*(-7.0/16.0)) + { + *bx=ax + dx; + *by=ay; + } + // Iso close to negative X + else if (angle < M_PI*(-5.0/16.0)) + { + dx=dx | 1; // Round up to next odd number + *bx=ax + dx; + *by=ay - dx/2; + } + // 45 degrees + else if (angle < M_PI*(-3.0/16.0)) + { + *by = (*by + ay - dx)/2; + *bx = ax + ay - *by; + } + // Iso close to positive Y + else if (angle < M_PI*(-1.0/16.0)) + { + dy=dy | 1; // Round up to next odd number + *bx=ax - dy/2; + *by=ay + dy; + } + // Positive Y + else if (angle < M_PI*(1.0/16.0)) + { + *bx=ax; + *by=ay + dy; + } + // Iso close to positive Y + else if (angle < M_PI*(3.0/16.0)) + { + dy=dy | 1; // Round up to next odd number + *bx=ax + dy/2; + *by=ay + dy; + } + // 45 degrees + else if (angle < M_PI*(5.0/16.0)) + { + *by = (*by + ay + dx)/2; + *bx = ax - ay + *by; + } + // Iso close to positive X + else if (angle < M_PI*(7.0/16.0)) + { + dx=dx | 1; // Round up to next odd number + *bx=ax + dx; + *by=ay + dx/2; + } + // Positive X + else if (angle < M_PI*(9.0/16.0)) + { + *bx=ax + dx; + *by=ay; + } + // Iso close to positive X + else if (angle < M_PI*(11.0/16.0)) + { + dx=dx | 1; // Round up to next odd number + *bx=ax + dx; + *by=ay - dx/2; + } + // 45 degrees + else if (angle < M_PI*(13.0/16.0)) + { + *by = (*by + ay - dx)/2; + *bx = ax + ay - *by; + } + // Iso close to negative Y + else //if (angle < M_PI*(15.0/16.0)) + { + dy=dy | 1; // Round up to next odd number + *bx=ax - dy/2; + *by=ay + dy; + } - length = sqrt((float)(dx)*(float)(dx)+(float)(dy)*(float)(dy)); - *bx=ax + lrintf(sin(angle)*length); - *by=ay + lrintf(cos(angle)*length); - - return; + return; } // -- Tracer général d'une ligne ------------------------------------------ From 8b5681eccbbdea83f09bb301f3c41352aa0e69c7 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 16 Jul 2009 07:04:39 +0000 Subject: [PATCH 44/95] -"fixed" warning about vars being used uninitialized (may happen if mouse cursor is totally offscreen or screen resolution is 0 pixel height, that is, never). -Put some cursor drawing loops in the right order (loop on y, then on x) to make them a little more cache-friendly (and easier to read). I wrote them the wrong way, sorry! -Some code formatting to 80 columns (not really important, don't worry about it) -Added a sample neochrome picture to the pic-samples folder. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@923 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pic-samples/BALLOONS.NEO | Bin 0 -> 32128 bytes windows.c | 108 +++++++++++++++++++-------------------- 2 files changed, 54 insertions(+), 54 deletions(-) create mode 100644 pic-samples/BALLOONS.NEO diff --git a/pic-samples/BALLOONS.NEO b/pic-samples/BALLOONS.NEO new file mode 100644 index 0000000000000000000000000000000000000000..d4fb7497ff91f344792ee8e04bb3749f4cf6baf1 GIT binary patch literal 32128 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 cNB%xo=uWZRbf@Y!Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; - for (x_pos=start_x,counter_x=0;counter_x<15 && x_pos < Screen_width;x_pos++,counter_x++) - { - if( x_pos < 0 ) continue; - for (y_pos=start_y,counter_y=0;counter_y<15 && y_pos < Screen_height;y_pos++,counter_y++) - { - if( y_pos < 0 || y_pos >= Screen_height) continue; - color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; - CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); - if (color!=MC_Trans) - Pixel(x_pos,y_pos,color); + for (y_pos=start_y,counter_y=0; counter_y<15 && y_pos < Screen_height; + y_pos++,counter_y++) + { + if( y_pos < 0 ) continue; + for (x_pos=start_x,counter_x=0; + counter_x<15 && x_pos < Screen_width; x_pos++,counter_x++) + { + if( x_pos < 0 ) continue; + color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; + CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); + if (color!=MC_Trans) + Pixel(x_pos,y_pos,color); } - } + } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } @@ -1721,20 +1723,20 @@ void Display_cursor(void) start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { + if(y_pos<0) continue; + if(y_pos>=Screen_height) break; + for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + { if(x_pos<0) continue; if(x_pos>=Screen_width) break; - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; - color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; - // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard - CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); - if (color!=MC_Trans) - Pixel(x_pos,y_pos,color); - } + color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; + // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard + CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); + if (color!=MC_Trans) + Pixel(x_pos,y_pos,color); + } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } @@ -1750,18 +1752,18 @@ void Display_cursor(void) case CURSOR_SHAPE_HOURGLASS : start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { - if(x_pos<0) continue; - if(x_pos>=Screen_width) break; - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; - color=Gfx->Cursor_sprite[shape][counter_y][counter_x]; - // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard - CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); - if (color!=MC_Trans) + if(y_pos<0) continue; + if(y_pos>=Screen_height) break; + for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + { + if(x_pos<0) continue; + if(x_pos>=Screen_width) break; + color=Gfx->Cursor_sprite[shape][counter_y][counter_x]; + // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard + CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); + if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } } @@ -1908,14 +1910,11 @@ void Hide_cursor(void) int start_y; short end_x; short end_y; - int x_pos; + int x_pos = 0; int y_pos; - short counter_x; + short counter_x = 0; short counter_y; - //short end_counter_x; // Position X ou s'arrête l'affichage de la brosse/pinceau - //short end_counter_y; // Position Y ou s'arrête l'affichage de la brosse/pinceau int temp; - //byte color; float cos_a,sin_a; short x1,y1,x2,y2,x3,y3,x4,y4; @@ -1960,10 +1959,11 @@ void Hide_cursor(void) for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { + if(y_pos < 0) continue; if(y_pos>=Screen_height) break; for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) { - if ( (x_pos<0) || (y_pos < 0)) continue; + if(x_pos < 0) continue; else if (x_pos>=Screen_width) break; Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]); } @@ -2026,18 +2026,18 @@ void Hide_cursor(void) start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { + if(y_pos<0) continue; + if(y_pos>=Screen_height) break; + for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + { if(x_pos<0) continue; if(x_pos>=Screen_width) break; - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]); - } } - Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); + } + Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); } } if (!Paintbrush_hidden) @@ -2054,14 +2054,14 @@ void Hide_cursor(void) start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) { - if(x_pos<0) continue; - if(x_pos>=Screen_width) break; - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; + if(y_pos<0) continue; + if(y_pos>=Screen_height) break; + for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) + { + if(x_pos<0) continue; + if(x_pos>=Screen_width) break; Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]); } } From 07bfc119b8fe3f39b1da03f316791f15ec7bad1e Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 16 Jul 2009 07:33:14 +0000 Subject: [PATCH 45/95] -No need to check if a pointer is null before freeing it. -However if the pointer is still living (for example a global) you should assign NULL to it to avoid bad ram access and random bugs. Accessing a NULL pointer always gives a segfault, accessing a freed pointer may or may not crash. -Also fixed a memory leak git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@924 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 25 +++++++++++-------------- graph.c | 3 +-- loadsave.c | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/buttons.c b/buttons.c index 59671543..36ea052d 100644 --- a/buttons.c +++ b/buttons.c @@ -2735,6 +2735,8 @@ void Load_picture(byte image) use_brush_palette=Confirmation_box("Use the palette of the brush?"); } + // do_not_restore is modified inside the first if, that's why we check it + // again here if (do_not_restore) { old_cursor_shape=Cursor_shape; @@ -2764,13 +2766,13 @@ void Load_picture(byte image) if (File_error==3) // On ne peut pas allouer la brosse { - if (Brush) free(Brush); + free(Brush); Brush=(byte *)malloc(1*1); Brush_height=1; Brush_width=1; *Brush=Fore_color; - if (Smear_brush) free(Smear_brush); + 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; @@ -2828,7 +2830,7 @@ void Load_picture(byte image) } new_mode=Best_video_mode(); - // TODO : Utiliser içi Ratio_of_loaded_image pour passer dans la + // TODO : Utiliser ici Ratio_of_loaded_image pour passer dans la // bonne taille de pixels. if ((Config.Auto_set_res) && (new_mode!=Current_resolution)) { @@ -2858,8 +2860,7 @@ void Load_picture(byte image) Display_cursor(); } - if (!image) - free(initial_palette); + free(initial_palette); if (!do_not_restore) { @@ -4863,10 +4864,9 @@ void Button_Sieve_menu(void) break; case 7 : // Transfer to brush - if (Brush) - free(Brush); Brush_width=Sieve_width; Brush_height=Sieve_height; + free(Brush); Brush=(byte *)malloc(((long)Brush_height)*Brush_width); for (y_pos=0; y_posList_start; cursor_position = font_list->Cursor_position; - if (new_brush) - free(new_brush); + free(new_brush); + new_brush = NULL; Close_window(); Unselect_button(BUTTON_TEXT); Display_cursor(); diff --git a/graph.c b/graph.c index b01133ad..e97cb30a 100644 --- a/graph.c +++ b/graph.c @@ -495,8 +495,7 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) else if (Pixel_width>Pixel_height && Screen_height>=Menu_factor_Y*2*200) Menu_factor_Y*=2; - if (Horizontal_line_buffer) - free(Horizontal_line_buffer); + free(Horizontal_line_buffer); Horizontal_line_buffer=(byte *)malloc(Pixel_width*((Screen_width>Main_image_width)?Screen_width:Main_image_width)); Set_palette(Main_palette); diff --git a/loadsave.c b/loadsave.c index 9a894320..5aeecbbc 100644 --- a/loadsave.c +++ b/loadsave.c @@ -5483,8 +5483,8 @@ void Load_PC1(void) else { File_error=1; - if (bufferdecomp) free(bufferdecomp); - if (buffercomp) free(buffercomp); + free(bufferdecomp); + free(buffercomp); } fclose(file); } From b5e806eda320f3717c8bfc54c231ce624a3a7d97 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 16 Jul 2009 08:49:27 +0000 Subject: [PATCH 46/95] -Style fixes (check for (i != 0) instead of just i for int -Error on some extreme cases (can't even allocate 1 byte) (the exit here are to make splint happy) -Header protection with #ifdef git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@925 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- brush.c | 125 +++++++++++++++++++++----------------- engine.h | 178 ++++++++++++++++++++++++++++-------------------------- filesel.h | 6 ++ gfx2.cfg | Bin 10133 -> 10133 bytes 4 files changed, 168 insertions(+), 141 deletions(-) diff --git a/brush.c b/brush.c index a9d7ce16..54d0f323 100644 --- a/brush.c +++ b/brush.c @@ -123,7 +123,8 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) int position; byte * temp; - if (!(is_preview && Mouse_K)) // Si bouton enfoncé & preview > pas de dessin + if (is_preview==0 || Mouse_K==0) // pas de curseur si on est en preview et + // en train de cliquer switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!! @@ -151,7 +152,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) end_counter_x=start_x_counter+width; end_counter_y=start_y_counter+height; - if (is_preview) + if (is_preview != 0) { if ( (width>0) && (height>0) ) Display_brush_color( @@ -165,7 +166,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) Brush_width ); - if (Main_magnifier_mode) + if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width, &height @@ -196,9 +197,9 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) } else { - if ((Smear_mode) && (Shade_table==Shade_table_left)) + if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) { - if (Smear_start) + if (Smear_start != 0) { if ((width>0) && (height>0)) { @@ -275,7 +276,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) start_y_counter=start_y-(y-Brush_offset_Y); end_counter_x=start_x_counter+width; end_counter_y=start_y_counter+height; - if (is_preview) + if (is_preview != 0) { if ( (width>0) && (height>0) ) Display_brush_mono(start_x-Main_offset_X, @@ -285,7 +286,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) Back_color,Fore_color, Brush_width); - if (Main_magnifier_mode) + if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Brush_offset_X); @@ -314,9 +315,9 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) } else { - if ((Smear_mode) && (Shade_table==Shade_table_left)) + if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) { - if (Smear_start) + if (Smear_start != 0) { if ((width>0) && (height>0)) { @@ -377,7 +378,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) start_y_counter=start_y-(y-Paintbrush_offset_Y); end_counter_x=start_x_counter+width; end_counter_y=start_y_counter+height; - if (is_preview) + if (is_preview != 0) { temp=Brush; Brush=Paintbrush_sprite; @@ -390,7 +391,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) 0,Fore_color, MAX_PAINTBRUSH_SIZE); - if (Main_magnifier_mode) + if (Main_magnifier_mode != 0) { Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); start_x_counter=start_x-(x-Paintbrush_offset_X); @@ -419,9 +420,9 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) } else { - if ((Smear_mode) && (Shade_table==Shade_table_left)) + if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) { - if (Smear_start) + if (Smear_start != 0) { if ((width>0) && (height>0)) { @@ -444,10 +445,13 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) { temp_color=Read_pixel_from_current_screen(x_pos,y_pos); position=(counter_y*Smear_brush_width)+counter_x; - if ( (Paintbrush_sprite[(MAX_PAINTBRUSH_SIZE*counter_y)+counter_x]) // Le pinceau sert de masque pour dire quels pixels on doit traiter dans le rectangle - && (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) ) - Display_pixel(x_pos,y_pos,Smear_brush[position]); + if ( (Paintbrush_sprite[(MAX_PAINTBRUSH_SIZE*counter_y)+counter_x] != 0) + // Le pinceau sert de masque pour dire quels pixels on doit traiter dans le rectangle + && (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) + // On clippe l'effet smear entre Smear_Min et Smear_Max + ) + Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } Update_part_of_screen(start_x, start_y, width, height); @@ -464,7 +468,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) for (y_pos=start_y,counter_y=start_y_counter;counter_yMAX_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 (Smear_brush == NULL) // On ne peut même pas allouer la brosse du smear! { Error(0); 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; } @@ -690,7 +709,7 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width); // On regarde s'il faut effacer quelque chose: - if (clear) + if (clear != 0) { for (y_pos=start_y;y_pos0) Pixel_in_brush(x_pos-1,y_pos,Back_color); @@ -955,7 +964,7 @@ void Nibble_brush(void) } else { - if (!state) + if (state == 0) { Pixel_in_brush(x_pos,y_pos,Back_color); state=1; @@ -984,7 +993,7 @@ void Nibble_brush(void) } else { - if (!state) + if (state == 0) { Pixel_in_brush(x_pos,y_pos,Back_color); state=1; @@ -1021,7 +1030,7 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) short start_y=Limit_bottom+1; short end_x=Limit_left-1; short end_y=Limit_top-1; - short temp; + unsigned short temp; short x_pos; short y_pos; word new_brush_width; @@ -1029,10 +1038,10 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) // On recherche les bornes de la brosse: - for (temp=0; tempend_x) @@ -1079,6 +1088,7 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) Error(0); Brush=(byte *)malloc(1*1); + if(Brush==NULL) Error(ERROR_MEMORY); new_brush_height=new_brush_width=1; *Brush=Fore_color; } @@ -1097,6 +1107,7 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) free(Brush); Brush=(byte *)malloc(1*1); + if(Brush==NULL) Error(ERROR_MEMORY); Brush_height=1; Brush_width=1; diff --git a/engine.h b/engine.h index b3547cc3..e3de8d0f 100644 --- a/engine.h +++ b/engine.h @@ -1,84 +1,94 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file engine.h -/// Utility functions for the menu and all windows. -////////////////////////////////////////////////////////////////////////////// - -void Main_handler (void); -void Draw_menu_button_frame(byte btn_number,byte pressed); -void Unselect_button (int btn_number); -void Select_button (int btn_number,byte click); -void Open_window (word width,word height, char * title); -void Close_window (void); - -void Open_popup (word x_pos, word y_pos, word width, word height); -void Close_popup (void); - -void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, - char * title,byte undersc_letter,byte clickable); -void Window_select_normal_button(word x_pos,word y_pos,word width,word height); -void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height); -void Window_draw_palette_bouton(word x_pos,word y_pos); - -void Compute_slider_cursor_height(T_Scroller_button * button); -void Window_draw_slider(T_Scroller_button * button); -void Window_draw_scroller_bouton(T_Scroller_button * button); - -void Window_input_content(T_Special_button * button, char * content); -void Window_clear_input_button(T_Special_button * button); -void Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters); - -T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, - word width, word height, - char * title,byte undersc_letter, - byte clickable, word shortcut); -#define GGUI_set_normal_button(x_pos,y_pos,width,height,title,undersc_letter,clickable,shortcut,NAME) \ - const short NAME = Window_set_normal_button((x_pos),(y_pos),(width),(height),(title),(undersc_letter),(clickable),(shortcut))->Number; -T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, - word width, word height, - char * title,byte undersc_letter, - byte clickable, word shortcut); - -T_Palette_button * Window_set_palette_button(word x_pos, word y_pos); -void Window_clear_tags(void); -void Tag_color_range(byte start,byte end); - -T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, - word height, - word nb_elements, - word nb_elements_visible, - word initial_position); -T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width,word height); -T_Special_button * Window_set_input_button(word x_pos,word y_pos,word width_in_characters); -T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width,word height,word dropdown_width,const char *label,byte display_choice,byte display_centered,byte display_arrow,byte active_button); -void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label); -void Window_dropdown_clear_items(T_Dropdown_button * dropdown); -T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item); -void Window_redraw_list(T_List_button * list); -byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y); -short Wait_click_in_palette(T_Palette_button * button); -void Get_color_behind_window(byte * color, byte * click); - -short Window_clicked_button(void); -int Button_under_mouse(void); -short Window_get_clicked_button(void); -void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y); -void Pixel_background(int x_pos, int y_pos, byte color); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file engine.h +/// Utility functions for the menu and all windows. +////////////////////////////////////////////////////////////////////////////// + +#ifndef __ENGINE_H__ +#define __ENGINE_H__ + +#include "struct.h" + +void Main_handler (void); +void Draw_menu_button_frame(byte btn_number,byte pressed); +void Unselect_button (int btn_number); +void Select_button (int btn_number,byte click); +void Open_window (word width,word height, char * title); +void Close_window (void); + +void Open_popup (word x_pos, word y_pos, word width, word height); +void Close_popup (void); + +void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, + char * title,byte undersc_letter,byte clickable); +void Window_select_normal_button(word x_pos,word y_pos,word width,word height); +void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height); +void Window_draw_palette_bouton(word x_pos,word y_pos); + +void Compute_slider_cursor_height(T_Scroller_button * button); +void Window_draw_slider(T_Scroller_button * button); +void Window_draw_scroller_bouton(T_Scroller_button * button); + +void Window_input_content(T_Special_button * button, char * content); +void Window_clear_input_button(T_Special_button * button); +void Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters); + +T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, + word width, word height, + char * title,byte undersc_letter, + byte clickable, word shortcut); +T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, + word width, word height, + char * title,byte undersc_letter, + byte clickable, word shortcut); + +T_Palette_button * Window_set_palette_button(word x_pos, word y_pos); +void Window_clear_tags(void); +void Tag_color_range(byte start,byte end); + +T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, + word height, word nb_elements, word nb_elements_visible, + word initial_position); +T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width, + word height); +T_Special_button * Window_set_input_button(word x_pos,word y_pos, + word width_in_characters); +T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width, + word height,word dropdown_width,const char *label,byte display_choice, + byte display_centered,byte display_arrow,byte active_button); +void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, + const char *label); +void Window_dropdown_clear_items(T_Dropdown_button * dropdown); +T_List_button * Window_set_list_button(T_Special_button * entry_button, + T_Scroller_button * scroller, Func_draw_list_item draw_list_item); +void Window_redraw_list(T_List_button * list); +byte Window_click_in_rectangle(short start_x,short start_y,short end_x, + short end_y); +short Wait_click_in_palette(T_Palette_button * button); +void Get_color_behind_window(byte * color, byte * click); + +short Window_clicked_button(void); +int Button_under_mouse(void); +short Window_get_clicked_button(void); +void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y); +void Pixel_background(int x_pos, int y_pos, byte color); + +#endif diff --git a/filesel.h b/filesel.h index 1cbd2432..febe5e36 100644 --- a/filesel.h +++ b/filesel.h @@ -21,6 +21,10 @@ ///@file filesel.h /// Fileselector window, used for loading and saving images and brushes. ////////////////////////////////////////////////////////////////////////////// +#ifndef __FILESEL_H__ +#define __FILESEL_H__ + +#include "struct.h" byte Button_Load_or_Save(byte load, byte image); @@ -40,3 +44,5 @@ void Recount_files(T_Fileselector *list); T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); short Find_file_in_fileselector(T_Fileselector *list, char * fname); + +#endif diff --git a/gfx2.cfg b/gfx2.cfg index eeea8c6a91e496bbeb2557ae8d8c8446d4daa94a..5154c5a924dcc4ee0ddb84bc4bb15f421e66d70a 100644 GIT binary patch delta 19 bcmbR0Kh=N35>+OK|C1*wU)WrxCeH`}R7?lS delta 28 hcmbR0Kh=N35>;*ic?KYu1jI~}Cn_J`T&5<^2mo{52aNy# From 3a7edb8323f0b54ada4e7c0b218dc36f20ddc61d Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 16 Jul 2009 08:49:56 +0000 Subject: [PATCH 47/95] Some files are still using msdos encoding, which is bad :) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@926 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- filesel.h | 96 +++++++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/filesel.h b/filesel.h index febe5e36..0ad4520a 100644 --- a/filesel.h +++ b/filesel.h @@ -1,48 +1,48 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file filesel.h -/// Fileselector window, used for loading and saving images and brushes. -////////////////////////////////////////////////////////////////////////////// -#ifndef __FILESEL_H__ -#define __FILESEL_H__ - -#include "struct.h" - -byte Button_Load_or_Save(byte load, byte image); - -void Add_element_to_list(T_Fileselector *list, const char * fname, int type); -/// -/// 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 -/// including the '\0'. -char * Format_filename(const char * fname, int type); - -void Free_fileselector_list(T_Fileselector *list); - -void Sort_list_of_files(T_Fileselector *list); - -void Recount_files(T_Fileselector *list); - -T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); - -short Find_file_in_fileselector(T_Fileselector *list, char * fname); - -#endif +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file filesel.h +/// Fileselector window, used for loading and saving images and brushes. +////////////////////////////////////////////////////////////////////////////// +#ifndef __FILESEL_H__ +#define __FILESEL_H__ + +#include "struct.h" + +byte Button_Load_or_Save(byte load, byte image); + +void Add_element_to_list(T_Fileselector *list, const char * fname, int type); +/// +/// 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 +/// including the '\0'. +char * Format_filename(const char * fname, int type); + +void Free_fileselector_list(T_Fileselector *list); + +void Sort_list_of_files(T_Fileselector *list); + +void Recount_files(T_Fileselector *list); + +T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); + +short Find_file_in_fileselector(T_Fileselector *list, char * fname); + +#endif From e877292ca2931ac8fe35aa238917906c8c3825b6 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 16 Jul 2009 12:57:11 +0000 Subject: [PATCH 48/95] The cluster system for color reduction when loading a truecolor image now uses a linked list instead of a table. This fix a potential problem because there was an overlapping memcpy. It also avoids copying the big cluster table around and just moves pointer around. It should be faster but I did not really noticed any change on my computer :(. Maybe it's too fast... The same can probably be done for the gradient sets. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@927 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- Makefile | 2 +- op_c.c | 327 ++++++++++++++++++++++++++++--------------------------- op_c.h | 4 +- setup.c | 9 +- 4 files changed, 176 insertions(+), 166 deletions(-) diff --git a/Makefile b/Makefile index e950d744..21af96b7 100644 --- a/Makefile +++ b/Makefile @@ -210,7 +210,7 @@ else # Compiles a regular linux exectutable for the native platform BIN = grafx2 - COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) + COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc diff --git a/op_c.c b/op_c.c index 687dc260..418ba8a6 100644 --- a/op_c.c +++ b/op_c.c @@ -657,37 +657,40 @@ void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) //////////////////////////// M‚thodes de gestion des ensembles de clusters // ///////////////////////////////////////////////////////////////////////////// +/// Setup the first cluster before we start the operations void CS_Init(T_Cluster_set * cs,T_Occurrence_table * to) { - cs->clusters[0].Rmin=cs->clusters[0].rmin=0; - cs->clusters[0].Gmin=cs->clusters[0].vmin=0; - cs->clusters[0].Bmin=cs->clusters[0].bmin=0; - cs->clusters[0].Rmax=cs->clusters[0].rmax=to->rng_r-1; - cs->clusters[0].Vmax=cs->clusters[0].vmax=to->rng_g-1; - cs->clusters[0].Bmax=cs->clusters[0].bmax=to->rng_b-1; - Cluster_analyser(cs->clusters+0,to); - // Et hop : le 1er ensemble de couleurs est initialis‚ + cs->clusters->Rmin = cs->clusters->rmin = 0; + cs->clusters->Gmin = cs->clusters->vmin = 0; + cs->clusters->Bmin = cs->clusters->bmin = 0; + cs->clusters->Rmax = cs->clusters->rmax = to->rng_r-1; + cs->clusters->Vmax = cs->clusters->vmax = to->rng_g-1; + cs->clusters->Bmax = cs->clusters->bmax = to->rng_b-1; + cs->clusters->next = NULL; + Cluster_analyser(cs->clusters,to); cs->nb=1; } +/// Allocate a new cluster set T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to) { T_Cluster_set * n; n=(T_Cluster_set *)malloc(sizeof(T_Cluster_set)); - if (n!=0) + if (n != NULL) { // On recopie les paramŠtres demand‚s n->nb_max=OT_count_colors(to); - // On vient de compter le nombre de couleurs existantes, s'il est plus grand que 256 on limit à 256 (nombre de couleurs voulu au final) + // On vient de compter le nombre de couleurs existantes, s'il est plus grand que 256 on limite à 256 + // (nombre de couleurs voulu au final) if (n->nb_max>nbmax) { n->nb_max=nbmax; } - // On tente d'allouer la table - n->clusters=(T_Cluster *)malloc(nbmax*sizeof(T_Cluster)); + // On tente d'allouer le premier cluster + n->clusters=(T_Cluster *)malloc(sizeof(T_Cluster)); if (n->clusters!=NULL) // C'est bon! On initialise CS_Init(n,to); @@ -702,68 +705,74 @@ T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to) return n; } +/// Free a cluster set void CS_Delete(T_Cluster_set * cs) { - free(cs->clusters); - free(cs); + T_Cluster* nxt; + while(cs->clusters != NULL) + { + nxt = cs->clusters->next; + free(cs->clusters); + cs->clusters = nxt; + } + free(cs); } void CS_Get(T_Cluster_set * cs,T_Cluster * c) { - int index; + T_Cluster* current = cs->clusters; + T_Cluster* prev = NULL; - // On cherche un cluster que l'on peut couper en deux, donc avec au moins deux valeurs - // différentes sur l'une des composantes - for (index=0;indexnb;index++) - if ( (cs->clusters[index].rminclusters[index].rmax) || - (cs->clusters[index].vminclusters[index].vmax) || - (cs->clusters[index].bminclusters[index].bmax) ) + // Search a cluster with at least 2 distinct colors so we can split it + do + { + if ( (current->rmin < current->rmax) || + (current->vmin < current->vmax) || + (current->bmin < current->bmax) ) break; - // On le recopie dans c - *c=cs->clusters[index]; + prev = current; + + } while((current = current -> next)); - // On décrémente le nombre et on décale tous les clusters suivants - // Sachant qu'on va réinsérer juste après, il me semble que ça serait une bonne idée de gérer les clusters - // comme une liste chainée... on n'a aucun accès direct dedans, que des parcours ... + // copy it to c + *c = *current; + + // remove it from the list cs->nb--; - memcpy((cs->clusters+index),(cs->clusters+index+1),(cs->nb-index)*sizeof(T_Cluster)); + + if(prev) + prev->next = current->next; + else + cs->clusters = current->next; + free(current); + current = NULL; } void CS_Set(T_Cluster_set * cs,T_Cluster * c) { - int index; - // int decalage; + T_Cluster* current = cs->clusters; + T_Cluster* prev = NULL; - // Le tableau des clusters est trié par nombre d'occurences. Donc on cherche la position du premier cluster - // qui est plus grand que le notre - for (index=0;indexnb;index++) - if (cs->clusters[index].occurencesoccurences) -/* - if (((OPTPAL_Cluster[index].rmax-OPTPAL_Cluster[index].rmin+1)* - (OPTPAL_Cluster[index].gmax-OPTPAL_Cluster[index].gmin+1)* - (OPTPAL_Cluster[index].bmax-OPTPAL_Cluster[index].bmin+1)) - < - ((Set->rmax-Set->rmin+1)* - (Set->gmax-Set->gmin+1)* - (Set->bmax-Set->bmin+1)) - ) -*/ - break; - - if (indexnb) + // Search the first cluster that is smaller than ours + if(current != NULL) // don't search if the list is empty + do { - // On distingue ici une insertion plutot qu'un placement en fin de liste. - // On doit donc décaler les ensembles suivants vers la fin pour se faire - // une place dans la liste. + if (current->occurences < c->occurences) + break; + prev = current; + } while((current = current -> next)); - //for (decalage=cs->nb;decalage>index;decalage--) - // memcpy((cs->clusters+decalage),(cs->clusters+decalage-1),sizeof(T_Cluster)); - memmove(cs->clusters+index+1,cs->clusters+index,(cs->nb-index)*sizeof(T_Cluster)); - } + // Now insert our cluster just before the one we found + c -> next = current; - cs->clusters[index]=*c; - cs->nb++; + current = malloc(sizeof(T_Cluster)); + *current = *c ; + + if(prev) prev -> next = current; + else cs->clusters = current; + + cs -> nb++; } // Détermination de la meilleure palette en utilisant l'algo Median Cut : @@ -802,96 +811,91 @@ void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to) void CS_Compute_colors(T_Cluster_set * cs,T_Occurrence_table * to) { - int index; T_Cluster * c; - for (index=0,c=cs->clusters;indexnb;index++,c++) + for (c=cs->clusters;c!=NULL;c=c->next) Cluster_compute_hue(c,to); } void CS_Sort_by_chrominance(T_Cluster_set * cs) { - int byte_used[256]; - int decalages[256]; - int index; - T_Cluster * nc; + T_Cluster* nc; + T_Cluster* prev = NULL; + T_Cluster* place; + T_Cluster* newlist = NULL; - nc=(T_Cluster *)malloc(cs->nb_max*sizeof(T_Cluster)); + while((nc = cs->clusters)) + { + // Remove the first cluster from the original list + nc = cs->clusters; + cs->clusters = cs->clusters->next; - // Initialisation de la table d'occurence de chaque octet - for (index=0;index<256;index++) - byte_used[index]=0; + // Find his position in the new list + for(place = newlist;place != NULL; place = place->next) + { + if(place->h > nc->h) break; + prev = place; + } - // Comptage du nombre d'occurences de chaque octet - for (index=0;indexnb;index++) - byte_used[cs->clusters[index].h]++; + // Chain it there + nc->next = place; + if(prev) prev->next = nc; + else newlist = nc; - // Calcul de la table des d‚calages - decalages[0]=0; - for (index=1;index<256;index++) - decalages[index]=decalages[index-1]+byte_used[index-1]; + } - // Copie r‚ordonn‚e dans la nouvelle liste - for (index=0;indexnb;index++) - { - nc[decalages[cs->clusters[index].h]]=cs->clusters[index]; - decalages[cs->clusters[index].h]++; - } - - // Remplacement de la liste d‚sordonn‚e par celle tri‚e - free(cs->clusters); - cs->clusters=nc; + // Put the new list bavk in place + cs->clusters = newlist; } void CS_Sort_by_luminance(T_Cluster_set * cs) { - int byte_used[256]; - int decalages[256]; - int index; - T_Cluster * nc; + T_Cluster* nc; + T_Cluster* prev = NULL; + T_Cluster* place; + T_Cluster* newlist = NULL; - nc=(T_Cluster *)malloc(cs->nb_max*sizeof(T_Cluster)); + while((nc = cs->clusters)) + { + // Remove the first cluster from the original list + nc = cs->clusters; + cs->clusters = cs->clusters->next; - // Initialisation de la table d'occurence de chaque octet - for (index=0;index<256;index++) - byte_used[index]=0; + // Find his position in the new list + for(place = newlist;place != NULL; place = place->next) + { + if(place->l > nc->l) break; + prev = place; + } - // Comptage du nombre d'occurences de chaque octet - for (index=0;indexnb;index++) - byte_used[cs->clusters[index].l]++; + // Chain it there + nc->next = place; + if(prev) prev->next = nc; + else newlist = nc; - // Calcul de la table des d‚calages - decalages[0]=0; - for (index=1;index<256;index++) - decalages[index]=decalages[index-1]+byte_used[index-1]; + } - // Copie r‚ordonn‚e dans la nouvelle liste - for (index=0;indexnb;index++) - { - nc[decalages[cs->clusters[index].l]]=cs->clusters[index]; - decalages[cs->clusters[index].l]++; - } - - // Remplacement de la liste d‚sordonn‚e par celle tri‚e - free(cs->clusters); - cs->clusters=nc; + // Put the new list bavk in place + cs->clusters = newlist; } void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * tc,T_Components * palette) { int index; int r,g,b; + T_Cluster* current = cs->clusters; for (index=0;indexnb;index++) { - palette[index].R=cs->clusters[index].r; - palette[index].G=cs->clusters[index].g; - palette[index].B=cs->clusters[index].b; + palette[index].R=current->r; + palette[index].G=current->g; + palette[index].B=current->b; - for (r=cs->clusters[index].Rmin;r<=cs->clusters[index].Rmax;r++) - for (g=cs->clusters[index].Gmin;g<=cs->clusters[index].Vmax;g++) - for (b=cs->clusters[index].Bmin;b<=cs->clusters[index].Bmax;b++) + for (r=current->Rmin; r<=current->Rmax; r++) + for (g=current->Gmin;g<=current->Vmax;g++) + for (b=current->Bmin;b<=current->Bmax;b++) CT_set(tc,r,g,b,index); + current = current->next; } } @@ -902,9 +906,9 @@ void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * void GS_Init(T_Gradient_set * ds,T_Cluster_set * cs) { ds->gradients[0].nb_colors=1; - ds->gradients[0].min=cs->clusters[0].h; - ds->gradients[0].max=cs->clusters[0].h; - ds->gradients[0].hue=cs->clusters[0].h; + ds->gradients[0].min=cs->clusters->h; + ds->gradients[0].max=cs->clusters->h; + ds->gradients[0].hue=cs->clusters->h; // Et hop : le 1er ensemble de d‚grad‚s est initialis‚ ds->nb=1; } @@ -943,57 +947,60 @@ void GS_Delete(T_Gradient_set * ds) void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) { - int ic,id; // Les indexs de parcours des ensembles + int id; // Les indexs de parcours des ensembles int best_gradient; // Meilleur d‚grad‚ int best_diff; // Meilleure diff‚rence de chrominance int diff; // difference de chrominance courante + T_Cluster * current = cs->clusters; // Pour chacun des clusters … traiter - for (ic=0;icnb;ic++) - { - // On recherche le d‚grad‚ le plus proche de la chrominance du cluster - best_gradient=-1; - best_diff=99999999; - for (id=0;idnb;id++) - { - diff=abs(cs->clusters[ic].h - ds->gradients[id].hue); - if ((best_diff>diff) && (diff<16)) - { - best_gradient=id; - best_diff=diff; - } - } + do + { + // On recherche le d‚grad‚ le plus proche de la chrominance du cluster + best_gradient=-1; + best_diff=99999999; + for (id=0;idnb;id++) + { + diff=abs(current->h - ds->gradients[id].hue); + if ((best_diff>diff) && (diff<16)) + { + best_gradient=id; + best_diff=diff; + } + } - // Si on a trouv‚ un d‚grad‚ dans lequel inclure le cluster - if (best_gradient!=-1) - { - // On met … jour le d‚grad‚ - if (cs->clusters[ic].h < ds->gradients[best_gradient].min) - ds->gradients[best_gradient].min=cs->clusters[ic].h; - if (cs->clusters[ic].h > ds->gradients[best_gradient].max) - ds->gradients[best_gradient].max=cs->clusters[ic].h; - ds->gradients[best_gradient].hue=((ds->gradients[best_gradient].hue* - ds->gradients[best_gradient].nb_colors) - +cs->clusters[ic].h) - /(ds->gradients[best_gradient].nb_colors+1); - ds->gradients[best_gradient].nb_colors++; - } - else - { - // On cr‚e un nouveau d‚grad‚ - best_gradient=ds->nb; - ds->gradients[best_gradient].nb_colors=1; - ds->gradients[best_gradient].min=cs->clusters[ic].h; - ds->gradients[best_gradient].max=cs->clusters[ic].h; - ds->gradients[best_gradient].hue=cs->clusters[ic].h; - ds->nb++; - } - cs->clusters[ic].h=best_gradient; - } + // Si on a trouv‚ un d‚grad‚ dans lequel inclure le cluster + if (best_gradient!=-1) + { + // On met … jour le d‚grad‚ + if (current->h < ds->gradients[best_gradient].min) + ds->gradients[best_gradient].min=current->h; + if (current->h > ds->gradients[best_gradient].max) + ds->gradients[best_gradient].max=current->h; + ds->gradients[best_gradient].hue=((ds->gradients[best_gradient].hue* + ds->gradients[best_gradient].nb_colors) + +current->h) + /(ds->gradients[best_gradient].nb_colors+1); + ds->gradients[best_gradient].nb_colors++; + } + else + { + // On cr‚e un nouveau d‚grad‚ + best_gradient=ds->nb; + ds->gradients[best_gradient].nb_colors=1; + ds->gradients[best_gradient].min=current->h; + ds->gradients[best_gradient].max=current->h; + ds->gradients[best_gradient].hue=current->h; + ds->nb++; + } + current->h=best_gradient; + } while((current = current->next)); - // On redistribue les valeurs dans les clusters - for (ic=0;icnb;ic++) - cs->clusters[ic].h=ds->gradients[cs->clusters[ic].h].hue; + // On redistribue les valeurs dans les clusters + current = cs -> clusters; + do + current->h=ds->gradients[current->h].hue; + while((current = current ->next)); } diff --git a/op_c.h b/op_c.h index ebd943fe..4fd6739f 100644 --- a/op_c.h +++ b/op_c.h @@ -88,7 +88,7 @@ typedef struct ///////////////////////////////////////// Définition d'un ensemble de couleur -typedef struct +typedef struct S_Cluster { int occurences; // Nb total d'occurences des couleurs de l'ensemble @@ -106,6 +106,8 @@ typedef struct byte r,g,b; // color synthétisant l'ensemble byte h; // Chrominance byte l; // Luminosité + + struct S_Cluster* next; } T_Cluster; diff --git a/setup.c b/setup.c index ba0245bd..5b54ce09 100644 --- a/setup.c +++ b/setup.c @@ -57,7 +57,8 @@ int Create_ConfigDirectory(char * config_dir) // Determine which directory contains the executable. // IN: Main's argv[0], some platforms need it, some don't. // OUT: Write into program_dir. Trailing / or \ is kept. -// Note : in fact this is only used to check for the datafiles and fonts in this same directory. +// Note : in fact this is only used to check for the datafiles and fonts in +// this same directory. void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) { #undef ARG_UNUSED @@ -76,9 +77,9 @@ void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) // Others: The part of argv[0] before the executable name. // Keep the last \ or /. - // Note that on Unix, once installed, the executable is called from a shell script - // sitting in /usr/local/bin/, this allows argv[0] to contain the full path. - // On Windows, Mingw32 already provides the full path in all cases. + // Note that on Unix, once installed, the executable is called from a shell + // script sitting in /usr/local/bin/, this allows argv[0] to contain the full + // path. On Windows, Mingw32 already provides the full path in all cases. #else Extract_path(program_dir, argv0); #endif From 97c8453dcd65e9d06c86e2e5fc1cffcdd1815e23 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 16 Jul 2009 12:58:36 +0000 Subject: [PATCH 49/95] Converted all files to unix end of lines. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@928 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- help.h | 96 +- helpfile.h | 4866 ++++++++++++------------ hotkeys.c | 2668 ++++++------- init.h | 84 +- keyboard.c | 1300 +++---- keyboard.h | 150 +- loadsave.h | 114 +- misc.h | 300 +- mountlist.c | 1828 ++++----- mountlist.h | 94 +- op_c.c | 2452 ++++++------ op_c.h | 430 +-- operatio.c | 10226 +++++++++++++++++++++++++------------------------- operatio.h | 438 +-- pages.h | 186 +- palette.c | 4604 +++++++++++------------ palette.h | 84 +- pxdouble.c | 994 ++--- pxdouble.h | 96 +- pxquad.c | 1064 +++--- pxquad.h | 96 +- pxsimple.c | 940 ++--- pxsimple.h | 102 +- pxtall.c | 906 ++--- pxtall.h | 92 +- pxtall2.c | 1048 +++--- pxtall2.h | 96 +- pxtriple.c | 1040 ++--- pxtriple.h | 96 +- pxwide.c | 1012 ++--- pxwide.h | 98 +- pxwide2.c | 1028 ++--- pxwide2.h | 96 +- readini.h | 54 +- readline.c | 700 ++-- readline.h | 88 +- saveini.h | 50 +- setup.c | 364 +- setup.h | 108 +- shade.h | 64 +- special.c | 728 ++-- special.h | 86 +- struct.h | 820 ++-- text.h | 108 +- transform.c | 818 ++-- transform.h | 54 +- 46 files changed, 21383 insertions(+), 21383 deletions(-) diff --git a/help.h b/help.h index 30ac2c97..883df678 100644 --- a/help.h +++ b/help.h @@ -1,48 +1,48 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file help.h -/// Functions related to the help browser. The help data is in helpfile.h -////////////////////////////////////////////////////////////////////////////// - -#ifndef __HELP_H_ -#define __HELP_H_ - -/*! - Called to open the help window with the keyboard shortcut. - If the mouse is over a button, its contextual help will be displayed. - Else, the default helpscreen will be shown. -*/ -void Button_Help(void); - -/*! - Displays and runs the "Statistics" window -*/ -void Button_Stats(void); - -/*! - Displays and runs the "Help / About..." window - @param section Number of the help section page to display (equals the button number the mouse was hovering for the contextual help), -1 for the main help page. - @param sub_section Help sub-section title (the page will be scrolled so this title is at the top). -*/ -void Window_help(int section, const char * sub_section); - -#endif - +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file help.h +/// Functions related to the help browser. The help data is in helpfile.h +////////////////////////////////////////////////////////////////////////////// + +#ifndef __HELP_H_ +#define __HELP_H_ + +/*! + Called to open the help window with the keyboard shortcut. + If the mouse is over a button, its contextual help will be displayed. + Else, the default helpscreen will be shown. +*/ +void Button_Help(void); + +/*! + Displays and runs the "Statistics" window +*/ +void Button_Stats(void); + +/*! + Displays and runs the "Help / About..." window + @param section Number of the help section page to display (equals the button number the mouse was hovering for the contextual help), -1 for the main help page. + @param sub_section Help sub-section title (the page will be scrolled so this title is at the top). +*/ +void Window_help(int section, const char * sub_section); + +#endif + diff --git a/helpfile.h b/helpfile.h index 612b2011..81a26cb2 100644 --- a/helpfile.h +++ b/helpfile.h @@ -1,2433 +1,2433 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2009 Franck Charlet - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file helpfile.h -/// This is all the text that appears in contextual help and credits. -/// -/// Note: The source code is kept on a public website, so keep this in mind -/// if you're thinking of putting an e-mail address in there. At least, use -/// "\100" instead of @, to help against the most basic email address harvesters. -////////////////////////////////////////////////////////////////////////////// - -#include "const.h" // Uses enumerations BUTTON_NUMBERS and SPECIAL_ACTIONS - -// Some magic formulas: - -#define HELP_TEXT(x) {'N', x, 0}, -// Generates a 'N' line (Normal) - -#define HELP_LINK(x,y) {'K', x, y}, -// Generates a 'K' line (Key) - -#define HELP_BOLD(x) {'S', x, 0}, -// Generates a 'S' line (BOLD) - -#define HELP_TITLE(x) {'T', x, 0}, {'-', x, 0}, -// Generates a 'T' line (Title, upper half) -// and a second '-' line (Title, lower half), with the same text. - -static const T_Help_table helptable_about[] = -/* - Do not exceed 44 characters for normal lines: - HELP_TEXT ("--------------------------------------------") - Do not exceed 22 characters for title lines: - HELP_TITLE("======================") -*/ -{ - HELP_TEXT ("") // Leave enough room for a hard-coded logo, eventually. - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" GRAFX 2 ") - HELP_BOLD (" \"Summer Sunset\" Edition") - HELP_BOLD (" THE ULTIMATE MULTI-RESOLUTION GFX EDITOR") - HELP_TEXT (" http://grafx2.googlecode.com") - HELP_TEXT ("") - HELP_TEXT (" Copyright 2007 by the Grafx2 project team") - HELP_TEXT (" Copyright 1996-2001 by SUNSET DESIGN") -}; -static const T_Help_table helptable_licence[] = -{ - HELP_TITLE(" LICENSE") - HELP_TEXT ("") - HELP_TEXT ("Grafx2 is FREE SOFTWARE, you can") - HELP_TEXT ("redistribute it and/or modify it under the") - HELP_TEXT ("terms of the GNU General Public License as") - HELP_TEXT ("published by the Free Software Foundation;") - HELP_TEXT ("version 2 of the License.") - HELP_TEXT ("") - HELP_TEXT ("Grafx2 is distributed in the hope that it") - HELP_TEXT ("will be useful, but WITHOUT ANY WARRANTY;") - HELP_TEXT ("without even the implied warranty of") - HELP_TEXT ("MERCHANTABILITY or FITNESS FOR A PARTICULAR") - HELP_TEXT ("PURPOSE. See the GNU General Public License") - HELP_TEXT ("for more details.") - HELP_TEXT ("") - HELP_TEXT ("You should have received a copy of the GNU") - HELP_TEXT ("General Public License along with Grafx2;") - HELP_TEXT ("if not, see http://www.gnu.org/licenses/ or") - HELP_TEXT ("write to the Free Software Foundation, Inc.") - HELP_TEXT (" 59 Temple Place - Suite 330, Boston,") - HELP_TEXT (" MA 02111-1307, USA.") - -}; -static const T_Help_table helptable_help[] = -{ - HELP_TITLE(" HELP") - HELP_TEXT ("") - HELP_TEXT (" Contextual help is available by pressing") - HELP_LINK (" the %s key",0x100+BUTTON_HELP) - HELP_TEXT (" You can do it while hovering a menu icon,") - HELP_TEXT (" or while a window is open.") - HELP_TEXT (" When a keyboard shortcut is displayed it's") - HELP_TEXT (" your current configuration and you can") - HELP_TEXT (" change it by clicking it.") - HELP_TEXT ("") - HELP_TITLE(" KEYBOARD SHORTCUTS") - HELP_TEXT ("") - HELP_TEXT ("Scroll visible area") - HELP_LINK (" up: %s", SPECIAL_SCROLL_UP) - HELP_LINK (" down: %s", SPECIAL_SCROLL_DOWN) - HELP_LINK (" left: %s", SPECIAL_SCROLL_LEFT) - HELP_LINK (" right: %s", SPECIAL_SCROLL_RIGHT) - HELP_LINK (" up faster: %s", SPECIAL_SCROLL_UP_FAST) - HELP_LINK (" down faster: %s", SPECIAL_SCROLL_DOWN_FAST) - HELP_LINK (" left faster: %s", SPECIAL_SCROLL_LEFT_FAST) - HELP_LINK (" right faster: %s", SPECIAL_SCROLL_RIGHT_FAST) - HELP_LINK (" up slower: %s", SPECIAL_SCROLL_UP_SLOW) - HELP_LINK (" down slower: %s", SPECIAL_SCROLL_DOWN_SLOW) - HELP_LINK (" left slower: %s", SPECIAL_SCROLL_LEFT_SLOW) - HELP_LINK (" right slower: %s", SPECIAL_SCROLL_RIGHT_SLOW) - HELP_TEXT ("Emulate mouse") - HELP_LINK (" Up: %s", SPECIAL_MOUSE_UP) - HELP_LINK (" Down: %s", SPECIAL_MOUSE_DOWN) - HELP_LINK (" Left: %s", SPECIAL_MOUSE_LEFT) - HELP_LINK (" Right: %s", SPECIAL_MOUSE_RIGHT) - HELP_LINK (" Left click: %s", SPECIAL_CLICK_LEFT) - HELP_LINK (" Right click: %s", SPECIAL_CLICK_RIGHT) - HELP_LINK ("Show / Hide menu: %s", 0x100+BUTTON_HIDE) - HELP_LINK ("Show / Hide cursor: %s", SPECIAL_SHOW_HIDE_CURSOR) - HELP_LINK ("Paintbrush = \".\": %s", SPECIAL_DOT_PAINTBRUSH) - HELP_LINK ("Paintbrush choice: %s", 0x100+BUTTON_PAINTBRUSHES) - HELP_LINK ("Monochrome brush: %s", 0x200+BUTTON_PAINTBRUSHES) - HELP_LINK ("Freehand drawing: %s", 0x100+BUTTON_DRAW) - HELP_TEXT ("Switch freehand") - HELP_LINK (" drawing mode: %s", 0x200+BUTTON_DRAW) - HELP_TEXT ("Continuous freehand") - HELP_LINK (" drawing: %s", SPECIAL_CONTINUOUS_DRAW) - HELP_LINK ("Line: %s", 0x100+BUTTON_LINES) - HELP_LINK ("Knotted lines: %s", 0x200+BUTTON_LINES) - HELP_LINK ("Spray: %s", 0x100+BUTTON_AIRBRUSH) - HELP_LINK ("Spray menu: %s", 0x200+BUTTON_AIRBRUSH) - HELP_LINK ("Floodfill: %s", 0x100+BUTTON_FLOODFILL) - HELP_LINK ("Replace color: %s", 0x200+BUTTON_FLOODFILL) - HELP_LINK ("Bezier's curves: %s", 0x100+BUTTON_CURVES) - HELP_TEXT ("Bezier's curve with") - HELP_LINK (" 3 or 4 points %s", 0x200+BUTTON_CURVES) - HELP_LINK ("Empty rectangle: %s", 0x100+BUTTON_RECTANGLES) - HELP_LINK ("Filled rectangle: %s", 0x100+BUTTON_FILLRECT) - HELP_LINK ("Empty circle: %s", 0x100+BUTTON_CIRCLES) - HELP_LINK ("Empty ellipse: %s", 0x200+BUTTON_CIRCLES) - HELP_LINK ("Filled circle: %s", 0x100+BUTTON_FILLCIRC) - HELP_LINK ("Filled ellipse: %s", 0x200+BUTTON_FILLCIRC) - HELP_LINK ("Empty polygon: %s", 0x100+BUTTON_POLYGONS) - HELP_LINK ("Empty polyform: %s", 0x200+BUTTON_POLYGONS) - HELP_LINK ("Polyfill: %s", 0x100+BUTTON_POLYFILL) - 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 ("Spheres: %s", 0x100+BUTTON_SPHERES) - HELP_LINK ("Gradient ellipses: %s", 0x200+BUTTON_SPHERES) - HELP_LINK ("Adjust picture: %s", 0x100+BUTTON_ADJUST) - HELP_LINK ("Flip picture menu: %s", 0x200+BUTTON_ADJUST) - HELP_LINK ("Effects menu: %s", 0x100+BUTTON_EFFECTS) - HELP_LINK ("Effects all off %s", SPECIAL_EFFECTS_OFF) - HELP_LINK ("Shade mode: %s", SPECIAL_SHADE_MODE) - HELP_LINK ("Shade menu: %s", SPECIAL_SHADE_MENU) - HELP_LINK ("Quick-shade mode: %s", SPECIAL_QUICK_SHADE_MODE) - HELP_LINK ("Quick-shade menu: %s", SPECIAL_QUICK_SHADE_MENU) - HELP_LINK ("Stencil mode: %s", SPECIAL_STENCIL_MODE) - HELP_LINK ("Stencil menu: %s", SPECIAL_STENCIL_MENU) - HELP_LINK ("Mask mode: %s", SPECIAL_MASK_MODE) - HELP_LINK ("Mask menu: %s", SPECIAL_MASK_MENU) - HELP_LINK ("Grid mode: %s", SPECIAL_GRID_MODE) - HELP_LINK ("Grid menu: %s", SPECIAL_GRID_MENU) - HELP_LINK ("Sieve mode: %s", SPECIAL_SIEVE_MODE) - HELP_LINK ("Sieve menu: %s", SPECIAL_SIEVE_MENU) - HELP_LINK ("Invert Sieve: %s", SPECIAL_INVERT_SIEVE) - HELP_LINK ("Colorize mode: %s", SPECIAL_COLORIZE_MODE) - HELP_LINK (" At opacity 10%%: %s", SPECIAL_TRANSPARENCY_1) - HELP_LINK (" At opacity 20%%: %s", SPECIAL_TRANSPARENCY_2) - HELP_LINK (" At opacity 30%%: %s", SPECIAL_TRANSPARENCY_3) - HELP_LINK (" At opacity 40%%: %s", SPECIAL_TRANSPARENCY_4) - HELP_LINK (" At opacity 50%%: %s", SPECIAL_TRANSPARENCY_5) - HELP_LINK (" At opacity 60%%: %s", SPECIAL_TRANSPARENCY_6) - HELP_LINK (" At opacity 70%%: %s", SPECIAL_TRANSPARENCY_7) - HELP_LINK (" At opacity 80%%: %s", SPECIAL_TRANSPARENCY_8) - HELP_LINK (" At opacity 90%%: %s", SPECIAL_TRANSPARENCY_9) - HELP_LINK (" At opacity 100%%: %s", SPECIAL_TRANSPARENCY_0) - HELP_LINK ("Colorize menu: %s", SPECIAL_COLORIZE_MENU) - HELP_LINK ("Smooth mode: %s", SPECIAL_SMOOTH_MODE) - HELP_LINK ("Smooth menu: %s", SPECIAL_SMOOTH_MENU) - HELP_LINK ("Smear mode: %s", SPECIAL_SMEAR_MODE) - HELP_LINK ("Tiling mode: %s", SPECIAL_TILING_MODE) - HELP_LINK ("Tiling menu: %s", SPECIAL_TILING_MENU) - HELP_LINK ("Pick brush: %s", 0x100+BUTTON_BRUSH) - HELP_LINK ("Pick polyform brush: %s", 0x100+BUTTON_POLYBRUSH) - HELP_LINK ("Restore brush: %s", 0x200+BUTTON_BRUSH) - HELP_LINK ("Flip brush X: %s", SPECIAL_FLIP_X) - HELP_LINK ("Flip brush Y: %s", SPECIAL_FLIP_Y) - HELP_LINK ("90° brush rotation: %s", SPECIAL_ROTATE_90) - HELP_LINK ("180° brush rotation: %s", SPECIAL_ROTATE_180) - HELP_LINK ("Stretch brush: %s", SPECIAL_STRETCH) - HELP_LINK ("Distort brush: %s", SPECIAL_DISTORT) - HELP_LINK ("Outline brush: %s", SPECIAL_OUTLINE) - HELP_LINK ("Nibble brush: %s", SPECIAL_NIBBLE) - 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) - HELP_LINK ("Pipette: %s", 0x100+BUTTON_COLORPICKER) - HELP_LINK ("Swap fore/back color:%s", 0x200+BUTTON_COLORPICKER) - HELP_LINK ("Magnifier mode: %s", 0x100+BUTTON_MAGNIFIER) - HELP_LINK ("Zoom factor menu: %s", 0x200+BUTTON_MAGNIFIER) - HELP_LINK ("Zoom in: %s", SPECIAL_ZOOM_IN) - HELP_LINK ("Zoom out: %s", SPECIAL_ZOOM_OUT) - HELP_LINK ("Brush effects menu: %s", 0x100+BUTTON_BRUSH_EFFECTS) - HELP_LINK ("Text: %s", 0x100+BUTTON_TEXT) - HELP_LINK ("Resolution menu: %s", 0x100+BUTTON_RESOL) - HELP_LINK ("Safety resolution: %s", 0x200+BUTTON_RESOL) - HELP_LINK ("Help: %s", 0x100+BUTTON_HELP) - HELP_LINK ("Statistics: %s", 0x200+BUTTON_HELP) - HELP_LINK ("Go to spare page: %s", 0x100+BUTTON_PAGE) - HELP_LINK ("Copy to spare page: %s", 0x200+BUTTON_PAGE) - HELP_LINK ("Save as: %s", 0x100+BUTTON_SAVE) - HELP_LINK ("Save: %s", 0x200+BUTTON_SAVE) - HELP_LINK ("Load: %s", 0x100+BUTTON_LOAD) - HELP_LINK ("Re-load: %s", 0x200+BUTTON_LOAD) - HELP_LINK ("Save brush: %s", SPECIAL_SAVE_BRUSH) - HELP_LINK ("Load brush: %s", SPECIAL_LOAD_BRUSH) - HELP_LINK ("Larger brush size: %s", SPECIAL_BIGGER_PAINTBRUSH) - HELP_LINK ("Smaller brush size: %s", SPECIAL_SMALLER_PAINTBRUSH) - HELP_LINK ("Settings: %s", 0x100+BUTTON_SETTINGS) - HELP_LINK ("Undo: %s", 0x100+BUTTON_UNDO) - HELP_LINK ("Redo: %s", 0x200+BUTTON_UNDO) - HELP_LINK ("Kill page: %s", 0x100+BUTTON_KILL) - HELP_LINK ("Clear: %s", 0x100+BUTTON_CLEAR) - HELP_LINK ("Clear with BG color: %s", 0x200+BUTTON_CLEAR) - HELP_LINK ("Quit: %s", 0x100+BUTTON_QUIT) - HELP_LINK ("Palette menu: %s", 0x100+BUTTON_PALETTE) - HELP_LINK ("2nd Palette menu: %s", 0x200+BUTTON_PALETTE) - HELP_LINK ("Exclude colors menu: %s", SPECIAL_EXCLUDE_COLORS_MENU) - HELP_TEXT ("") - HELP_TEXT ("Scroll palette") - HELP_LINK (" Back: %s", 0x100+BUTTON_PAL_LEFT) - HELP_LINK (" Forward: %s", 0x100+BUTTON_PAL_RIGHT) - HELP_LINK (" Back faster: %s", 0x200+BUTTON_PAL_LEFT) - HELP_LINK (" Forward faster: %s", 0x200+BUTTON_PAL_RIGHT) - HELP_TEXT ("") - HELP_TEXT ("Change brush attachement") - HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) - HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) - HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) - HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) - HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) - HELP_TEXT ("") - HELP_TEXT ("Select foreground color") - HELP_TEXT ("") - HELP_LINK (" Next : %s", SPECIAL_NEXT_FORECOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_FORECOLOR) - HELP_TEXT ("") - HELP_TEXT ("Select background color") - HELP_LINK (" Next : %s", SPECIAL_NEXT_BACKCOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_BACKCOLOR) - HELP_TEXT ("") - HELP_TEXT ("Select user-defined foreground color") - HELP_TEXT ("") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) - HELP_TEXT ("") - HELP_TEXT ("Select user-defined background color") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) - HELP_TEXT ("") -}; -static const T_Help_table helptable_credits[] = -{ -//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TITLE(" GRAFX2 IS CREATED BY") - HELP_TEXT ("") - HELP_BOLD (" SUNSET DESIGN") - HELP_BOLD (" AUTHORS OF GRAFX2.0 BETA 96.5%") - HELP_TEXT ("") - HELP_TEXT (" Guillaume Dorme alias \"Robinson\" (code)") - HELP_TEXT (" Karl Maritaud alias \"X-Man\" (code&gfx)") -//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT ("") - HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") - HELP_TEXT ("") - HELP_BOLD (" THE GRAFX2 PROJECT TEAM") - HELP_TEXT ("") - HELP_TEXT (" Adrien Destugues (pulkomandy)") - HELP_TEXT (" Yves Rizoud (yrizoud)") - HELP_TEXT ("") - HELP_TEXT (" Got the source back to life in 2006") - HELP_TEXT ("") - HELP_BOLD (" ART") - HELP_TEXT ("") - HELP_TEXT (" GrafX2 logo by Made (www.m4de.com)") - HELP_TEXT (" Icons and fonts by X-Man ") - HELP_TEXT (" Additional graphics and logo by iLKke") - HELP_TEXT (" (ilkke.blogspot.com)") - HELP_TEXT ("") - HELP_TEXT (" Pixelled all the graphics") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" OTHER MACHINES PORTS") - HELP_TEXT ("") - HELP_BOLD (" AMIGA OS 3 PORT") - HELP_TEXT ("") - HELP_TEXT (" Artur Jarosik") - HELP_TEXT ("") - HELP_BOLD (" AMIGA OS 4 PORT") - HELP_TEXT ("") - HELP_TEXT (" Peter Gordon (www.petergordon.org.uk)") - HELP_TEXT ("") - HELP_BOLD (" AROS PORT") - HELP_TEXT ("") - HELP_TEXT (" Fernando Mastandrea (masta.uy)") - HELP_TEXT (" Markus Weiss") - HELP_TEXT ("") - HELP_BOLD (" FREEBSD PORT") - HELP_TEXT ("") - HELP_TEXT (" Jean-Baptiste Berlioz (Tobe)") - HELP_TEXT ("") - HELP_BOLD (" HAIKU OS AND BEOS PORT") - HELP_TEXT ("") - HELP_TEXT (" Luc Schrijvers (Begasus)") - HELP_TEXT ("") - HELP_BOLD (" MAC OS X PORT") - HELP_TEXT ("") - HELP_TEXT (" Franck Charlet (hitchhikr)") - HELP_TEXT (" Per Olofsson (MagerValp)") - HELP_TEXT ("") - HELP_BOLD (" MORPHOS PORT") - HELP_TEXT ("") - HELP_TEXT (" Rusback") - HELP_TEXT ("") - HELP_BOLD (" SKYOS PORT") - HELP_TEXT ("") - HELP_TEXT (" Luc Schrijvers (Begasus)") - HELP_TEXT ("") - HELP_TEXT (" ... made it work on your favourite toaster") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" BUGFINDERS") - HELP_TEXT ("") -//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT (" blumunkee BDCIron Ced ") - HELP_TEXT (" El Topo fallenblood Frost ") - HELP_TEXT (" Grimmy Gürkan Sengün HoraK-FDF ") - HELP_TEXT (" iLKke Jamon keito ") - HELP_TEXT (" kusma Lord Graga MagerValp ") - HELP_TEXT (" mind MooZ the Peach ") - HELP_TEXT (" richienyhus tape.wyrm TeeEmCee ") - HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") - HELP_TEXT (" Tobé 00ai99 ") - HELP_TEXT ("") - HELP_TEXT (" ... posted the annoying bug reports.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" FILE FORMATS CREDITS") - HELP_TEXT ("") - HELP_TEXT (" BMP : Microsoft") - HELP_TEXT (" CEL,KCF : K.O.S. (KISekae Set system)") - HELP_TEXT (" GIF : Compuserve") - HELP_TEXT (" IMG : Bivas (W. Wiedmann?)") - HELP_TEXT (" LBM : Electronic Arts") - HELP_TEXT (" PAL : ermmh... nobody (?)") - HELP_TEXT (" PCX : Z-Soft") - HELP_TEXT (" PI1,PC1 : Degas Elite") - HELP_TEXT (" PKM : Sunset Design") - HELP_TEXT (" PNG : W3C") - HELP_TEXT (" SCx : Colorix (?)") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE (" OUR HOMEPAGE") - HELP_TEXT ("") - HELP_BOLD (" http://grafx2.codegoogle.com") - HELP_TEXT ("") - HELP_TEXT (" Please report any bug you may find there") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE (" GREETINGS") - HELP_TEXT ("") - HELP_TEXT (" To the Pouet.net BBS posters, the #CPC") - HELP_TEXT (" trolls and the bitfellas") - HELP_TEXT (" To every people who makes the scene alive!") - HELP_TEXT (" To all guys making nice pixelled pictures") - HELP_TEXT (" (with or without GrafX2)") - HELP_TEXT ("") - HELP_BOLD (" We send our best regards to...") - HELP_TEXT ("") - HELP_TEXT (" Access Filter Pink") - HELP_TEXT (" Ace Fiver Pixel") - HELP_TEXT (" AcidJam Flan Profil") - HELP_TEXT (" Acryl Fred Prowler") - HELP_TEXT (" Alexel FreddyV Puznik") - HELP_TEXT (" Alias Frost Quick") - HELP_TEXT (" Amiral Gaël(GDC) Ra") - HELP_TEXT (" Arrakis GainX Raster") - HELP_TEXT (" Avocado Gandalf Ravian") - HELP_TEXT (" Baloo Goblin RedBug") - HELP_TEXT (" Barti Greenpix7 Rem") - HELP_TEXT (" Bat Grid Rez") - HELP_TEXT (" Biro GrosQuick Roudoudou") - HELP_TEXT (" Bisounours HackerCroll Sacrilege") - HELP_TEXT (" BlackAxe Haplo Sam") - HELP_TEXT (" Bonnie Hof SandMan") - HELP_TEXT (" Boo Hornet Scape") - HELP_TEXT (" Boz Hulud Sébastien") - HELP_TEXT (" Carine Java Shodan") - HELP_TEXT (" Chandra JBT Skal") - HELP_TEXT (" Cheetah Jérôme Skyfire") - HELP_TEXT (" Chill Julien(JCA) Sphair") - HELP_TEXT (" Cougar KalMinDo Sprocket") - HELP_TEXT (" Cremax KaneWood Stef") - HELP_TEXT (" Cyclone Karma Stony") - HELP_TEXT (" Dake Keith303 Sumaleth") - HELP_TEXT (" Danny Lazur Sunday") - HELP_TEXT (" Danube LightShow Suny") - HELP_TEXT (" Darjul Lluvia Sybaris") - HELP_TEXT (" Darwin Louie TBF") - HELP_TEXT (" DarkAngel Luk Tempest") - HELP_TEXT (" Das Made Thor") - HELP_TEXT (" Decker Mamos TMK") - HELP_TEXT (" DerPiipo Mandrixx TwoFace") - HELP_TEXT (" Destop Mangue Underking") - HELP_TEXT (" Diabolo Mars Unreal") - HELP_TEXT (" DineS Mephisto VaeVictis") - HELP_TEXT (" Drac Mercure Vastator") - HELP_TEXT (" DrYes Mirec Vatin") - HELP_TEXT (" Edyx Moa Veckman") - HELP_TEXT (" Eller Moxica Wain") - HELP_TEXT (" Ellyn MRK Wally") - HELP_TEXT (" EOF Nitch WillBe") - HELP_TEXT (" Fall Noal Xoomie") - HELP_TEXT (" Fame Nytrik Xtrm") - HELP_TEXT (" Fantom Optic YannSulu") - HELP_TEXT (" Fear Orome Z") - HELP_TEXT (" Feather Pahladin Zeb") - HELP_TEXT (" Fennec Phar Zebig") - HELP_TEXT ("") - HELP_TEXT (" and all #pixel, #demofr and #coders.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE (" SNAIL MAIL") - HELP_TEXT ("") - HELP_TEXT (" (From 2001, current status: unknown)") - HELP_TEXT ("") - HELP_TEXT (" GUILLAUME DORME (Robinson)") - HELP_TEXT (" 15, rue de l'observatoire") - HELP_TEXT (" 87000 LIMOGES (FRANCE)") - HELP_TEXT ("") - HELP_TEXT (" KARL MARITAUD (X-Man)") - HELP_TEXT (" 10, rue de la Brasserie") - HELP_TEXT (" 87000 LIMOGES (FRANCE)") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" THANKS") - HELP_TEXT ("") - HELP_TEXT (" Some information taken from several docs") - HELP_TEXT (" (PCGPE, Intervue, PC Interdit...)") - HELP_TEXT (" gave us an invaluable help.") - HELP_TEXT ("") - HELP_TEXT (" Thanks to Shawn Hargreaves for his filled") - HELP_TEXT (" polygon routine from Allegro v2.2.") - HELP_TEXT ("") - HELP_TEXT (" Thanks to Carlos \"Made\" Pardo for his") - HELP_TEXT (" great GrafX2 logo.") - HELP_TEXT ("") - HELP_TEXT (" This is our very first program compiled") - HELP_TEXT (" with the Gnu C Compiler.") - HELP_TEXT (" A thousand thanks to the authors of") - HELP_TEXT (" this compiler.") - HELP_TEXT ("") - HELP_TEXT (" We also would like to thank all the") - HELP_TEXT (" people who gave us ideas to improve") - HELP_TEXT (" GrafX2.") - HELP_TITLE("") -}; -static const T_Help_table helptable_paintbrush[] = -{ - HELP_TITLE("PAINTBRUSHES") - HELP_TEXT ("") - HELP_BOLD (" LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_PAINTBRUSHES) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can choose the") - HELP_TEXT ("shape of your paintbrush.") - HELP_TEXT ("") - HELP_TEXT ("Paintbrushes are sorted by family. You can") - HELP_TEXT ("see some paintbrushes of the same family but") - HELP_TEXT ("with different sizes. There is at least one") - HELP_TEXT ("paint-brush from each family displayed in") - HELP_TEXT ("this menu.") - HELP_TEXT ("Here is the list of all the different") - HELP_TEXT ("paintbrush families:") - HELP_TEXT ("") - HELP_TEXT ("******* *** * * * * * * ") - HELP_TEXT ("******* ***** * * * * * * ") - HELP_TEXT ("******* ******* * * * * * * * * ") - HELP_TEXT ("******* ******* * * * * * * ") - HELP_TEXT ("******* ******* * * * * * * * * ") - HELP_TEXT ("******* ***** * * * * * * ") - HELP_TEXT ("******* *** * * * * * * ") - HELP_TEXT ("") - HELP_TEXT ("Square Disc Sieve Sieve ") - HELP_TEXT (" square disc ") - HELP_TEXT (" ") - HELP_TEXT (" * * * ") - HELP_TEXT (" *** * * * ") - HELP_TEXT (" ***** * * ") - HELP_TEXT ("******* ******* * ") - HELP_TEXT (" ***** * * * * ") - HELP_TEXT (" *** * ") - HELP_TEXT (" * * * * ") - HELP_TEXT (" ") - HELP_TEXT ("Diamond Random Horiz. Vertical") - HELP_TEXT (" bar bar ") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * *******") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * * *") - HELP_TEXT ("* * * * *") - HELP_TEXT ("") - HELP_TEXT (" Slash Back- Cross X Cross +") - HELP_TEXT (" slash") - HELP_TEXT ("") - HELP_TEXT ("When using one of these, you can change the") - 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_BOLD (" RIGHT CLICK ") - HELP_LINK ("(Key:%s)",0x200+BUTTON_PAINTBRUSHES) - HELP_TEXT ("") - HELP_TEXT ("Transforms your current user-defined brush") - HELP_TEXT ("into a paintbrush. This is actually a") - HELP_TEXT ("\"monochromisation\" of your user-defined") - HELP_TEXT ("brush. This means that every color of the") - HELP_TEXT ("brush that aren't the Back-color will be") - HELP_TEXT ("set to the Fore-color. But this option") - HELP_TEXT ("doesn't alter the brush: you'll just have") - HELP_TEXT ("to right-click on the \"Get brush\" buttons") - HELP_TEXT ("to get your brush back.") - HELP_TEXT ("") - HELP_TEXT ("Note: When you press (not in the menu) the") - HELP_LINK ("key %s, the current",SPECIAL_DOT_PAINTBRUSH) - HELP_TEXT ("paintbrush becomes the smallest member of") - HELP_TEXT ("the \"Disc\" family: i.e one pixel.") - -}; -static const T_Help_table helptable_adjust[] = -{ - HELP_TITLE("ADJUST OR TRANSFORM") - HELP_TITLE(" PICTURE") - HELP_TEXT ("") - HELP_BOLD (" LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_ADJUST) - HELP_TEXT ("") - HELP_TEXT ("Allows you to scroll the picture to") - HELP_TEXT ("re-center your graph for example.") - HELP_TEXT ("") - HELP_TEXT ("Any part of the picture that goes out of") - HELP_TEXT ("the image by a side comes back by the") - HELP_TEXT ("opposite one.") - HELP_TEXT ("") - HELP_TEXT ("It is assimilated to the drawing tools") - HELP_TEXT ("family.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_BOLD (" RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_ADJUST) - HELP_TEXT ("") - HELP_TEXT ("Opens the Picture Transform menu.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("PICTURE TRANSFORM") - HELP_TEXT ("") - HELP_BOLD ("RESCALE") - HELP_TEXT ("") - HELP_TEXT ("Allows you to change the image's size,") - HELP_TEXT ("rescaling it accordingly. Enter new size") - HELP_TEXT ("and press RESIZE to confirm.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("When 'Lock proportions' is checked and you") - HELP_TEXT ("change one dimension, the other one is") - HELP_TEXT ("automatically adjusted to preserve the") - HELP_TEXT ("proportions of the original image.") - HELP_TEXT ("") - HELP_TEXT ("You can use the dropdown button to choose") - HELP_TEXT ("between three ways to enter the dimensions:") - HELP_TEXT ("") - HELP_TEXT ("In 'Pixels' mode, the column 'old' shows") - HELP_TEXT ("the original dimensions, and you can set") - HELP_TEXT ("the new size in pixels.") - HELP_TEXT ("") - HELP_TEXT ("In 'Percent' mode, you set a percentage") - HELP_TEXT ("compared to the original image.") - HELP_TEXT ("") - HELP_TEXT ("In 'Ratio' mode, you can set 2 numbers for") - HELP_TEXT ("each dimension, and the resizing factor will") - HELP_TEXT ("be of 'new'÷'old'. For example you can use") - HELP_TEXT ("1:3 to divide the image by three, 2:1 to") - HELP_TEXT ("double it, and any fraction like 15:16.") - HELP_TEXT ("") - HELP_TEXT ("Be careful that moving from one mode to the") - HELP_TEXT ("next can lose precision, if the selected") - HELP_TEXT ("dimensions cannot be represented exactly in") - HELP_TEXT ("the new mode.") - HELP_TEXT ("") - HELP_BOLD ("MIRROR") - HELP_TEXT ("") - HELP_TEXT ("- X: Flip the picture horizontally.") - HELP_TEXT ("") - HELP_TEXT ("- Y: Flip the picture vertically.") - HELP_TEXT ("") - HELP_BOLD ("ROTATE") - HELP_TEXT ("") - HELP_TEXT ("-90°: Rotates the image by 90°") - HELP_TEXT (" clockwise.") - HELP_TEXT ("") - HELP_TEXT ("+90°: Rotates the image by 90°") - HELP_TEXT (" counter-clockwise.") - HELP_TEXT ("180°: Rotates the image by 180°") - HELP_TEXT ("") - HELP_TEXT ("") -}; -static const T_Help_table helptable_draw[] = -{ - HELP_TITLE("HAND-DRAWING") - HELP_TEXT ("") - HELP_BOLD (" LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_DRAW) - HELP_TEXT ("") - HELP_TEXT ("Selects the current hand-drawing mode as the") - HELP_TEXT ("active drawing tool. There are 4") - HELP_TEXT ("hand-drawing modes:") - HELP_TEXT ("") - HELP_TEXT ("Continuous hand-drawing: as you move the") - HELP_TEXT ("mouse, the paintbrush is regularily pasted") - HELP_TEXT ("on the picture. This drawing tool allows to") - HELP_TEXT ("change the fore and back colors when being") - HELP_TEXT ("in use.") - HELP_TEXT ("") - HELP_TEXT ("Discontinuous hand-drawing: as you move the") - HELP_TEXT ("mouse, the paintbrush is pasted on the") - HELP_TEXT ("picture every time a delay is passed") - HELP_TEXT ("(actually, the delay is 1 VBL") - HELP_TEXT ("(vertical blanking)). This drawing tool") - HELP_TEXT ("allows to change the fore and back colors") - HELP_TEXT ("when being in use.") - HELP_TEXT ("") - HELP_TEXT ("Dot by dot hand-drawing: the paintbrush is") - HELP_TEXT ("only pasted at the position where you first") - HELP_TEXT ("clicked.") - HELP_TEXT ("") - HELP_TEXT ("Contour fill: Draws pixels like continuous") - HELP_TEXT ("mode, but when you release the button Grafx2") - HELP_TEXT ("draws a line back to your starting position,") - HELP_TEXT ("and fills the area. This tool doesn't use the") - HELP_TEXT ("current brush, but single pixels.") - HELP_TEXT ("") - HELP_BOLD (" RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_DRAW) - HELP_TEXT ("") - HELP_TEXT ("Toggles the different hand-drawing modes") - HELP_TEXT ("and activates, at the same time, the") - HELP_TEXT ("hand-drawing tool.") -}; -static const T_Help_table helptable_curves[] = -{ - HELP_TITLE("SPLINES") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_CURVES) - HELP_TEXT ("") - HELP_TEXT ("Selects the current curve-drawing mode as") - HELP_TEXT ("the active drawing tool. There are 2") - HELP_TEXT ("different curve-drawing modes:") - HELP_TEXT ("") - HELP_TEXT ("* 4 control points curves: define the basic") - HELP_TEXT ("line like a classical line, then move, with") - HELP_TEXT ("the left mouse button, the inner control") - HELP_TEXT ("points to choose the shape of your curve.") - HELP_TEXT ("When the curve has the shape you want, click") - HELP_TEXT ("with the right mouse button to draw it") - HELP_TEXT ("definitively.") - HELP_TEXT ("") - HELP_TEXT ("* 3 control points curves: the same as") - HELP_TEXT ("above, but you'll have only one inner") - HELP_TEXT ("control point to place. Moreover, the spline") - HELP_TEXT ("will be traced just after placing this") - HELP_TEXT ("point.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_CURVES) - HELP_TEXT ("") - HELP_TEXT ("Toggles the different curve-drawing modes") - HELP_TEXT ("and activates, at the same time, the") - HELP_TEXT ("curve-drawing tool.") -}; -static const T_Help_table helptable_lines[] = -{ - HELP_TITLE("LINES") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LINES) - HELP_TEXT ("") - HELP_TEXT ("Selects the current line-drawing mode as the") - HELP_TEXT ("active drawing tool. There are 3") - HELP_TEXT ("line-drawing modes:") - HELP_TEXT ("") - HELP_TEXT ("* Classical lines: when first clicking on") - HELP_TEXT ("the picture, you'll define the start of the") - HELP_TEXT ("line. Maintain your click to choose the end") - HELP_TEXT ("of the line and release the mouse button to") - HELP_TEXT ("set it.") - HELP_TEXT ("If you hold SHIFT when drawing, the line") - HELP_TEXT ("will be constrained to horizonal, vertical") - HELP_TEXT ("or diagonal.") - HELP_TEXT ("") - HELP_TEXT ("* Knotted lines: works like classical lines,") - HELP_TEXT ("but the end of your line will automatically") - HELP_TEXT ("become the start of the next one. When you") - HELP_TEXT ("want to stop chaining lines, use the") - HELP_TEXT ("opposite mouse button. \"The opposite button\"") - HELP_TEXT ("means that if you started to draw lignes") - HELP_TEXT ("with the left button (Fore-color), you'll") - HELP_TEXT ("have to stop the procedure with the right") - HELP_TEXT ("button; and conversely.") - HELP_TEXT ("") - HELP_TEXT ("* Concentric lines: when first clicking on") - HELP_TEXT ("the picture, you'll define center of the") - HELP_TEXT ("lines. In fact, the center is defined by the") - HELP_TEXT ("the position of the mouse when you release") - HELP_TEXT ("the mouse button. Then you can draw lines") - HELP_TEXT ("from the center to the current mouse") - HELP_TEXT ("position by clicking. To stop drawing") - HELP_TEXT ("concentric lines, use the opposite mouse") - HELP_TEXT ("button. This drawing tool allows to change") - HELP_TEXT ("the fore and back colors when being in use.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_LINES) - HELP_TEXT ("") - HELP_TEXT ("Toggles the different line-drawing modes and") - HELP_TEXT ("activates, at the same time, the") - HELP_TEXT ("line-drawing tool.") - -}; -static const T_Help_table helptable_airbrush[] = -{ - HELP_TITLE("SPRAY") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_AIRBRUSH) - HELP_TEXT ("") - HELP_TEXT ("Selects the spray as the active drawing") - HELP_TEXT ("tool. This drawing tool allows to change the") - HELP_TEXT ("fore and back colors when being in use.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_AIRBRUSH) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can configure the") - HELP_TEXT ("spray:") - HELP_TEXT ("") - HELP_TEXT ("- Size: Defines the diameter of the circle") - HELP_TEXT ("in which will effectively fit the spray.") - HELP_TEXT ("") - HELP_TEXT ("- Delay: Defines the number of VBLs that") - HELP_TEXT ("will be waited for between two flows of") - HELP_TEXT ("spray.") - HELP_TEXT ("") - HELP_TEXT ("- Mode: Defines whether you want to use a") - HELP_TEXT ("monochrome spray or a multi- colored one.") - HELP_TEXT ("") - HELP_TEXT ("- Mono-flow: Defines the number of") - HELP_TEXT ("paintbrushes that will be pasted in the") - HELP_TEXT ("circle of the spray at each cycle.") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Left-click on a color of the") - HELP_TEXT ("palette to see how much it will be used in") - HELP_TEXT ("the multicolored flow, and modify it by") - HELP_TEXT ("using the gauge on the right. If the flow of") - HELP_TEXT ("this color was equal to 0, then the \"Init\"") - HELP_TEXT ("value will be applied. Or set the flow of a") - HELP_TEXT ("color to 0 by clicking on it with the right") - HELP_TEXT ("mouse button.") - HELP_TEXT ("") - HELP_TEXT ("- Clear: Removes all the colors from the") - HELP_TEXT ("multicolored flow. Actually, this puts a 0") - HELP_TEXT ("value in the use of each color.") - HELP_TEXT ("") - HELP_TEXT ("- Init: Allows you to define a value that") - HELP_TEXT ("will be set to the color you click on in the") - HELP_TEXT ("palette if its value is equal to 0. This") - HELP_TEXT ("permits to tag a set of colors more quickly.") - HELP_TEXT ("") - HELP_TEXT ("- +1,-1,x2,/2: Modify the values of all the") - HELP_TEXT ("tagged colors (and only them).") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("Tip: If you often use the Shade mode, and") - HELP_TEXT ("are bored to click many times on a color to") - HELP_TEXT ("reach the color you want, you can define a") - HELP_TEXT ("spray with \"Size\"=1, \"Mono-flow\"=1, and") - HELP_TEXT ("\"Delay\"=2 (or more, according to your") - HELP_TEXT ("reflexes). And then, you'll just have to") - HELP_TEXT ("click a few hundredths of second to modify a") - HELP_TEXT ("color.") -}; -static const T_Help_table helptable_floodfill[] = -{ - HELP_TITLE("FLOODFILL") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_FLOODFILL) - HELP_TEXT ("") - HELP_TEXT ("Selects the filler as the active drawing") - HELP_TEXT ("tool. The filler, as any drawing tool, will") - HELP_TEXT ("be affected by all the effects!") - HELP_TEXT ("") - HELP_TEXT ("Note that only the visible part of the") - HELP_TEXT ("picture will be filled (as every other") - HELP_TEXT ("drawing tools, the floodfill only alters the") - HELP_TEXT ("visible part of the picture; this avoids") - HELP_TEXT ("unwanted effects that wouldn't be controlled") - HELP_TEXT ("by the user).") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_FLOODFILL) - HELP_TEXT ("") - HELP_TEXT ("Selects the color replacement as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Any rule has its exceptions and this one") - HELP_TEXT ("doesn't depart from that. Indeed, this tool") - HELP_TEXT ("is the only one to be affected by no effect") - HELP_TEXT ("(except Stencil) and to be able to modify") - HELP_TEXT ("non visible parts of the picture.") - HELP_TEXT ("The function of this tool being replacing") - HELP_TEXT ("all the occurences of a color in the picture") - HELP_TEXT ("by another, if would have been a shame to") - HELP_TEXT ("limit modifications only to the visible part") - HELP_TEXT ("of the picture.") -}; -static const T_Help_table helptable_polygons[] = -{ - HELP_TITLE("POLYGONS") - HELP_TITLE("POLYFORMS") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYGONS) - HELP_TEXT ("") - HELP_TEXT ("Selects the polygons as the active drawing") - HELP_TEXT ("tool.") - HELP_TEXT ("") - HELP_TEXT ("This works just like knotted-lines but loops") - HELP_TEXT ("the extremities when you're finished.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYGONS) - HELP_TEXT ("") - HELP_TEXT ("Selects the polyforms as the active drawing") - HELP_TEXT ("tool.") - HELP_TEXT ("") - HELP_TEXT ("This works like a combination of free-hand") - HELP_TEXT ("drawing and knotted-lines. If you keep the") - HELP_TEXT ("mouse button pressed, you'll draw as if you") - HELP_TEXT ("were in free-hand drawing mode. And, if you") - HELP_TEXT ("release the mouse button, it will work like") - HELP_TEXT ("knotted lines.") - HELP_TEXT ("") - HELP_TEXT ("Click on the opposite mouse button (i.e.:") - HELP_TEXT ("click right if you started to draw with the") - HELP_TEXT ("left mouse button, and vice versa) to") - HELP_TEXT ("terminate the operation. The two extremities") - HELP_TEXT ("will be linked automatically.") -}; -static const T_Help_table helptable_polyfill[] = -{ - HELP_TITLE("FILLED POLY") - HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYFILL) - HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYFILL) - HELP_TEXT (" Work exactly the same way as the polygons") - HELP_TEXT ("et polyforms above, but fill in the interior") - HELP_TEXT ("of the drawn shapes.") -}; -static const T_Help_table helptable_rectangles[] = -{ - HELP_TITLE("RECTANGLES") - HELP_LINK ("(Key:%s)",0x100+BUTTON_RECTANGLES) - HELP_TEXT ("") - HELP_TEXT ("Selects the empty rectangles as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Set a corner of a rectangle. Maintain the") - HELP_TEXT ("click to move the opposite corner and") - HELP_TEXT ("release the mouse button to set it") - HELP_TEXT ("definitively.") -}; -static const T_Help_table helptable_filled_rectangles[] = -{ - HELP_TITLE("FILLED RECT") - HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLRECT) - HELP_TEXT ("") - HELP_TEXT ("Selects the filled rectangles as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Works like an empty rectangle.") -}; -static const T_Help_table helptable_circles[] = -{ - HELP_TITLE("CIRCLES") - HELP_TITLE("ELLIPSES") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_CIRCLES) - HELP_TEXT ("") - HELP_TEXT ("Selects the empty circles as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Position the center of the cercle and") - HELP_TEXT ("maintain the mouse button to select its") - HELP_TEXT ("radius.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_CIRCLES) - HELP_TEXT ("") - HELP_TEXT ("Selects the empty ellipses as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Position the center of the cercle and") - HELP_TEXT ("maintain the mouse button to select its") - HELP_TEXT ("dimensions.") -}; -static const T_Help_table helptable_filled_circles[] = -{ - HELP_TITLE("FILLED CIRCLES") - HELP_TITLE(" AND ELLIPSES") - HELP_TEXT ("") - HELP_BOLD ("FILLED CIRCLES") - HELP_LINK ("(Key:%s)",0x100+BUTTON_CIRCLES) - HELP_TEXT ("") - HELP_TEXT ("Works like empty circles.") - HELP_TEXT ("") - HELP_BOLD ("FILLED ELLIPSES") - HELP_LINK ("(Key:%s)",0x200+BUTTON_CIRCLES) - HELP_TEXT ("") - HELP_TEXT ("Works like empty ellipses.") -}; -static const T_Help_table helptable_grad_rect[] = -{ - HELP_TITLE("GRAD RECTANGLE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_GRADRECT) - HELP_TEXT ("") - HELP_TEXT ("Selects the rectangle with gradations as") - HELP_TEXT ("the active drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Set a corner of a rectangle. Maintain the") - HELP_TEXT ("click to move the opposite corner and") - HELP_TEXT ("release the mouse button to set it") - HELP_TEXT ("definitively.") - HELP_TEXT ("") - HELP_TEXT ("If you don't like what you have done and") - HELP_TEXT ("want to restart, you can use the right") - HELP_TEXT ("click to cancel everything at this point.") - HELP_TEXT (" If you think it's nice, then click and hold") - HELP_TEXT ("the mouse in a point you want to have the") - HELP_TEXT ("starting color, drag to a point where you") - HELP_TEXT ("want the ending color, and release the") - HELP_TEXT ("button. You can press SHIFT to enforce your") - HELP_TEXT ("line to be vertical, horizontal, or") - HELP_TEXT ("diagonal.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_GRADRECT) - HELP_TEXT ("") - HELP_TEXT ("Opens a window where you can define the way") - HELP_TEXT ("gradations are processed. The different") - HELP_TEXT ("sections of this menu are:") - HELP_TEXT ("") - HELP_TEXT ("- Direction (arrow): Switches the direction") - HELP_TEXT ("of the gradation.") - HELP_TEXT ("") - HELP_TEXT ("- Dithering method: Toggles the 3 following") - HELP_TEXT ("methods:") - HELP_TEXT (" - No dithering") - HELP_TEXT (" - Basical dithering") - HELP_TEXT (" - Enhanced dithering") - HELP_TEXT ("") - HELP_TEXT ("- Mix: Mixes the gradation with a more or") - HELP_TEXT ("less random factor.") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Select a color range to build a") - HELP_TEXT ("gradation.") - HELP_TEXT ("") - HELP_TEXT ("- Index scroller: Defines the current") - HELP_TEXT ("gradation among a set of 16 that will be") - HELP_TEXT ("memorised.") -}; -static const T_Help_table helptable_spheres[] = -{ - HELP_TITLE("GRAD SPHERE") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_SPHERES) - HELP_TEXT ("") - HELP_TEXT ("Selects the spheres as the active drawing") - HELP_TEXT ("tool.") - HELP_TEXT ("") - HELP_TEXT ("Position the center of the sphere and") - HELP_TEXT ("maintain the mouse button to select its") - HELP_TEXT ("radius. Then place the spot-light.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_SPHERES) - HELP_TEXT ("") - HELP_TEXT ("Selects the ellipses with gradation as the") - HELP_TEXT ("active drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Draw the shape like a normal ellipse, and") - HELP_TEXT ("then position the spot-light and click the") - HELP_TEXT ("left mouse button to finish the shape.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("If you trace a sphere or an ellipse with") - HELP_TEXT ("gradation with the right mouse button, the") - HELP_TEXT ("result will be the same figure filled with") - HELP_TEXT ("the Back-color.") -}; -static const T_Help_table helptable_brush[] = -{ - HELP_TITLE("GRAB BRUSH") - HELP_BOLD (" OR RESTORE BRUSH") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH) - HELP_TEXT ("") - HELP_TEXT ("Engages a brush grabbing.") - HELP_TEXT ("") - HELP_TEXT ("Click on a corner of the rectangle") - HELP_TEXT ("containing the brush then maintain the click") - HELP_TEXT ("to define the opposite corner of the") - HELP_TEXT ("rectangle. Release the mouse button to grab") - HELP_TEXT ("the brush. Performing this operation with") - HELP_TEXT ("the right mouse button will erase the area") - HELP_TEXT ("where the brush was grabbed with the") - HELP_TEXT ("Back-color.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) - HELP_TEXT ("") - HELP_TEXT ("Restores the old brush.") -}; -static const T_Help_table helptable_polybrush[] = -{ - HELP_TITLE("POLY GRAB") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYBRUSH) - HELP_TEXT ("") - HELP_TEXT ("Grabs a brush of any shape by defining a") - HELP_TEXT ("polyform (please refer to section 8 for more") - HELP_TEXT ("explanations).") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) - HELP_TEXT ("") - HELP_TEXT ("Restores the old brush (same as above).") -}; -static const T_Help_table helptable_brush_fx[] = -{ - HELP_TITLE("BRUSH FX") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH_EFFECTS) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where the following options") - HELP_TEXT ("are available:") - HELP_TEXT ("") - HELP_LINK ("- X: (Key:%s)",SPECIAL_FLIP_X) - HELP_TEXT ("Flip horizontally.") - HELP_TEXT ("") - HELP_LINK ("- Y: (Key:%s)",SPECIAL_FLIP_Y) - HELP_TEXT ("Flip vertically.") - HELP_TEXT ("") - HELP_LINK ("- Rotate by 90°: (Key:%s)",SPECIAL_ROTATE_90) - HELP_TEXT ("Rotates the brush by an angle of 90 degrees.") - HELP_TEXT ("") - HELP_LINK ("- Rotate by 180°: (Key:%s)",SPECIAL_ROTATE_180) - HELP_TEXT ("Rotates the brush by an angle of 180") - HELP_TEXT ("degrees.") - HELP_TEXT ("") - HELP_TEXT ("- Rotate by any angle:") - HELP_LINK ("(Key:%s)",SPECIAL_ROTATE_ANY_ANGLE) - HELP_TEXT ("Triggers an interactive operation that") - HELP_TEXT ("allows you to rotate the brush. For this,") - HELP_TEXT ("start by placing the center or rotation with") - HELP_TEXT ("the left mouse button (if, at this moment,") - HELP_TEXT ("you press the right button, the operation") - HELP_TEXT ("with be cancelled). After that, you can") - HELP_TEXT ("define the angle of rotation as many times") - HELP_TEXT ("as you want by moving the mouse and") - HELP_TEXT ("left-clicking. Then validate with the right") - HELP_TEXT ("button when you are satisfied. Meanwhile,") - HELP_TEXT ("you can press on the 8 outer digits of the") - HELP_TEXT ("numeric pad for defining angles multiple of") - HELP_TEXT ("45 degrees:") - HELP_TEXT ("") - HELP_TEXT (" 135 90 45") - HELP_TEXT (" \\ | /") - HELP_TEXT (" '7' '8' '9'") - HELP_TEXT (" 180 -'4' '6'- 0") - HELP_TEXT (" '1' '2' '3'") - HELP_TEXT (" / | \\") - HELP_TEXT (" 225 270 315") - HELP_TEXT ("") - HELP_LINK ("- Stretch: (Key:%s)",SPECIAL_STRETCH) - HELP_TEXT ("Triggers an interactive operation") - HELP_TEXT ("that enables you to stretch the brush. For") - HELP_TEXT ("this, start by placing the upper-left") - HELP_TEXT ("cornerof the brush with the left mouse") - HELP_TEXT ("button (if, at this moment, you press the") - HELP_TEXT ("right button, the operation will be") - HELP_TEXT ("cancelled). after that, you can place the") - HELP_TEXT ("opposite corner as many times as you need,") - HELP_TEXT ("then validate with the right mouse button") - HELP_TEXT ("when you are satisfied. If you place this") - 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 ("") - HELP_LINK ("- Distort: (Key:%s)",SPECIAL_DISTORT) - HELP_TEXT ("Triggers an interactive operation") - HELP_TEXT ("that allows you to distort your brush.") - HELP_TEXT ("Start by placing the brush somewhere on the") - HELP_TEXT ("screen and left-click. The brush will") - HELP_TEXT ("appear, with a little peg at each corner.") - HELP_TEXT ("Use the left mouse button to displace the") - HELP_TEXT ("corners, which will deform the brush.") - HELP_TEXT ("When you're done, click the right mouse") - HELP_TEXT ("button.") - HELP_TEXT ("") - HELP_LINK ("- Outline: (Key:%s)",SPECIAL_OUTLINE) - HELP_TEXT ("This option permits to draw the") - HELP_TEXT ("outlines of the brush with the Fore- color.") - HELP_TEXT ("") - HELP_LINK ("- Nibble: (Key:%s)",SPECIAL_NIBBLE) - HELP_TEXT ("This option \"nibbles\" the outlines") - HELP_TEXT ("of the brush. It's in some way the opposite") - HELP_TEXT ("effect of the Outline option.") - HELP_TEXT ("") - HELP_LINK ("- Recolorize: (Key:%s)",SPECIAL_RECOLORIZE_BRUSH) - HELP_TEXT ("Remaps the brush so that it") - HELP_TEXT ("looks like it would in the spare page, using") - HELP_TEXT ("the current palette.") - HELP_TEXT ("") - HELP_LINK ("- Get brush colors: (Key:%s)",SPECIAL_GET_BRUSH_COLORS) - HELP_TEXT ("Transfers the spare") - HELP_TEXT ("page's colors used by the brush to the") - HELP_TEXT ("current palette.") - HELP_TEXT ("") - HELP_TEXT ("- Brush handle:") - HELP_TEXT ("Allows you to choose where to place the") - HELP_TEXT ("handle of the brush. Shortcuts are :") - HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) - HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) - HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) - HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) - HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) - HELP_TEXT ("") - HELP_LINK ("- Load : (Key:%s)",SPECIAL_LOAD_BRUSH) - HELP_TEXT ("Load a brush from disk.") - HELP_TEXT ("") - HELP_LINK ("- Save : (Key:%s)",SPECIAL_SAVE_BRUSH) - HELP_TEXT ("Save a brush to disk.") -}; -static const T_Help_table helptable_effects[] = -{ - HELP_TITLE("DRAW MODES") - HELP_LINK ("(Key:%s)",0x100+BUTTON_EFFECTS) - HELP_TEXT ("") - HELP_TEXT (" This button opens a menu where you can") - HELP_TEXT ("switch on or off the different drawing") - HELP_TEXT ("modes.") - HELP_TEXT (" In this menu, the \"All off\" button switches") - HELP_TEXT ("all the drawing modes off. The [Del] key") - HELP_TEXT ("is the keyboard shortcut for this button.") - HELP_TEXT (" The \"Feedback\" button is only used in") - HELP_TEXT ("\"Shade\", \"Quick-shade, \"Transparency\"") - HELP_TEXT ("and \"Smooth\" modes. When it is set, it means") - HELP_TEXT ("that the _current_ state of the picture") - HELP_TEXT ("has to be taken into account for the effect") - HELP_TEXT ("instead of the state in which the image") - HELP_TEXT ("was when you started to click for drawing.") - HELP_TEXT ("The best, as often, is that you try by") - HELP_TEXT ("yourself with and without Feedback to see") - HELP_TEXT ("the difference.") - HELP_TEXT (" The other buttons are the following:") - HELP_TEXT ("") - HELP_TITLE("SHADE") - HELP_TEXT (" It consists in increasing or decreasing the") - HELP_TEXT ("color number within a user-defined range.") - HELP_TEXT ("This shows its real dimension when used with") - HELP_TEXT ("a range of colors that shade off. Then,") - HELP_TEXT ("you can work on a part of your picture where") - HELP_TEXT ("colors belong to the same range without") - HELP_TEXT ("having to change your brush color all the") - HELP_TEXT ("time. You can choose the incrementation or") - HELP_TEXT ("decrementation of the color by pressing") - HELP_TEXT ("the left or right mouse button while") - HELP_TEXT ("drawing. If you click on a color that does") - HELP_TEXT ("not belong to the range, it will remain") - HELP_TEXT ("unchanged.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key : %s)", SPECIAL_SHADE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Shade mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SHADE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define one table") - HELP_TEXT ("of shades within a range of 8 memorised by") - HELP_TEXT ("the program. The different sections of this") - HELP_TEXT ("menu are:") - HELP_TEXT ("") - HELP_TEXT ("- Palette: You can define in it the color") - HELP_TEXT ("blocks that will be inserted") - HELP_TEXT ("into the table of shades.") - HELP_TEXT ("") - HELP_TEXT ("- Scroller: Used to change flick through the") - HELP_TEXT ("tables of shades.") - HELP_TEXT ("") - HELP_TEXT ("- Table of shades definition area: The 512") - HELP_TEXT ("squares should be widely") - HELP_TEXT ("sufficient to define the different shades") - HELP_TEXT ("since every 256 colors of") - HELP_TEXT ("the palette cannot be present more than once") - HELP_TEXT ("in each table.") - HELP_TEXT ("") - HELP_TEXT ("- A window (on the top-right side) permits") - HELP_TEXT ("to visualize the different") - HELP_TEXT ("shades defined in he current table.") - HELP_TEXT ("") - HELP_TEXT ("- Copy: Copy the contents of the table in a") - HELP_TEXT ("buffer.") - HELP_TEXT ("(Each time you open this menu, the current") - HELP_TEXT ("table is automatically") - HELP_TEXT ("transfered into this buffer).") - HELP_TEXT ("") - HELP_TEXT ("- Paste: Copy the contents of the buffer") - HELP_TEXT ("above in the current table.") - HELP_TEXT ("") - HELP_TEXT ("- Clear: Reset the \"shades\" table.") - HELP_TEXT ("") - HELP_TEXT ("- Insert: Used to insert the block selected") - HELP_TEXT ("in the palette at the") - HELP_TEXT ("cursor's position in the table of shades.") - HELP_TEXT ("IF you click with the left mouse button on") - HELP_TEXT ("this button THEN IF a block of more than one") - HELP_TEXT ("color is selected in the table THEN It is") - HELP_TEXT ("deleted and the block defined in the palette") - HELP_TEXT ("is inserted. ELSE The block defined in the") - HELP_TEXT ("palette is inserted at the postion just") - HELP_TEXT ("before the selected square. END IF") - HELP_TEXT ("ELSE The block defined in the palette is") - HELP_TEXT ("inserted by erasing the colors following the") - HELP_TEXT ("beginning of the bloc selected in the table.") - HELP_TEXT ("END IF") - HELP_TEXT ("") - HELP_TEXT ("- Delete: Delete the block selected in the") - HELP_TEXT ("table.") - HELP_TEXT ("") - HELP_TEXT ("- Blank: Follows this algorithm:") - HELP_TEXT ("IF you click with the left mouse button on") - HELP_TEXT ("this button THEN Replace the block selected") - HELP_TEXT ("in the table by blank squares.") - HELP_TEXT ("ELSE IF a block of more than one color is") - HELP_TEXT ("selected in the table THEN Insert blank") - HELP_TEXT ("squares to the left and to the right of the") - HELP_TEXT ("block. (this is useful for isolating a") - HELP_TEXT ("shade quickly) ELSE Insert blank squares") - HELP_TEXT ("to the left of the selected square. END IF") - HELP_TEXT ("END IF") - HELP_TEXT ("") - HELP_TEXT ("- Invert: Invert the order of the block") - HELP_TEXT ("selected in the table.") - HELP_TEXT ("") - HELP_TEXT ("- Swap: Allows you you move a block (this") - HELP_TEXT ("exchanges it with what is") - HELP_TEXT ("where you want to move it).") - HELP_TEXT ("") - HELP_TEXT ("- Undo: Cancel the last modification of the") - HELP_TEXT ("table.") - HELP_TEXT ("") - HELP_TEXT ("- The 2 numbers displayed on the right of") - HELP_TEXT ("these buttons are: (above) - the number of") - HELP_TEXT ("the color selected in the palette if only") - HELP_TEXT ("one color is selected. (below) - the number") - HELP_TEXT ("of the color contained in a square in the") - HELP_TEXT ("shades table if this square is the only one") - HELP_TEXT ("selected.") - HELP_TEXT ("") - HELP_TEXT ("- The \"mode\" button displays 3 different") - HELP_TEXT ("modes:") - HELP_TEXT ("\"Normal\": Shades in the range and saturates") - HELP_TEXT ("to its boundaries.") - HELP_TEXT ("\"Loop\": Shades in the range and loops if") - HELP_TEXT ("boundaries are passed.") - HELP_TEXT ("\"No saturation\": Shades in the range and") - HELP_TEXT ("doesn't saturate if boundaries are passed.") - HELP_TEXT ("If the Step (see below) is set to 1, this") - HELP_TEXT ("option does exactly the same as the Normal") - HELP_TEXT ("mode.") - HELP_TEXT ("") - HELP_TEXT ("- Set/Disable: If you want to define several") - HELP_TEXT ("shades in the same table") - HELP_TEXT ("but you'd like these shades not to be") - HELP_TEXT ("effective at the same time, you") - HELP_TEXT ("can mask (disable) some parts of the table") - HELP_TEXT ("so that they will be") - HELP_TEXT ("interpreted a blank squares.") - HELP_TEXT ("To do that, select a block in the table of") - HELP_TEXT ("shades and click on \"Set\".") - HELP_TEXT ("The block will be underlined with a white") - HELP_TEXT ("line; this means that it is") - HELP_TEXT ("disabled.") - HELP_TEXT ("") - HELP_TEXT ("- Clear/Enable: This does exactly the") - HELP_TEXT ("opposite as the button above.") - HELP_TEXT ("") - HELP_TEXT ("- Step: Defines the step of incrementation") - HELP_TEXT ("of the shade. The bigger,") - HELP_TEXT ("the faster you run through the colors of the") - HELP_TEXT ("shade.") - HELP_TEXT ("For example: if the step is 2 and that you") - HELP_TEXT ("have defined a shade with") - HELP_TEXT ("the colors 0,1,4,5,9 and that you click on a") - HELP_TEXT ("pixel of color 1, it will") - HELP_TEXT ("take the value 5 which is 2 positions next") - HELP_TEXT ("in the la table.") - HELP_TEXT ("") - HELP_TEXT ("(We are sorry for these technical") - HELP_TEXT ("considerations quite far from a purely") - HELP_TEXT ("artistic point of view; but know that this") - HELP_TEXT ("effect is really very useful and it is") - HELP_TEXT ("preferable that you understand its whole") - HELP_TEXT ("functionment if you want to fully take") - HELP_TEXT ("advantage of it).") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("QUICK SHADE") - HELP_TEXT (" This drawing mode has about the same effect") - HELP_TEXT ("as Shade mode's except that it is faster") - HELP_TEXT ("to configurate but a little bit less") - HELP_TEXT ("powerful. When you draw on a color of the") - HELP_TEXT ("image which is between the fore- and the") - HELP_TEXT ("back-color in the palette, the color tends") - HELP_TEXT ("towards the fore-color (according to the") - HELP_TEXT ("step defined) if you draw with the left") - HELP_TEXT ("mouse button, or it tends towards the") - HELP_TEXT ("back-color if you are using the right mouse") - HELP_TEXT ("button.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Quick-shade mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu with a few parameters that mean") - HELP_TEXT ("exactly the same as in the menu of Shade") - HELP_TEXT ("mode. These parameters are the step and the") - HELP_TEXT ("loop/satu- ration mode (normal, loop, no") - HELP_TEXT ("saturation).") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("STENCIL") - HELP_TEXT (" It is used to prevent some colors from") - HELP_TEXT ("being modified if you draw on them. The") - HELP_TEXT ("main application of the stencil is when you") - HELP_TEXT ("want to change one color or more into") - HELP_TEXT ("another.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Stencil mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define a stencil.") - HELP_TEXT ("The different sections of this menu are:") - HELP_TEXT ("") - HELP_TEXT ("- Clear: No color is protected.") - HELP_TEXT ("") - HELP_TEXT ("- Invert: Colors that were protected are") - HELP_TEXT ("unprotected and vice versa.") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Select colors that should be") - HELP_TEXT ("protected with the left mouse button or") - HELP_TEXT ("unprotect colors with the right mouse") - HELP_TEXT ("button.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("MASK") - HELP_TEXT (" This effect could have been called \"True") - HELP_TEXT ("stencil\" because it protects some parts of") - HELP_TEXT ("the picture instead of some colors. The") - HELP_TEXT ("colors you tag represent the pixels in the") - HELP_TEXT ("spare page, corresponding to the pixels in") - HELP_TEXT ("the current page, that you don't want to") - HELP_TEXT ("alter. For example, draw a simple white") - HELP_TEXT ("figure on a black background in the spare") - HELP_TEXT ("page. Then, tag the black color in the menu") - HELP_TEXT ("of the Mask mode. When you'll draw in the") - HELP_TEXT ("current page, only the pixels corresponding") - HELP_TEXT ("to the white (non-black) ones in the spare") - HELP_TEXT ("page will be modified.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_MASK_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Mask mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_MASK_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can set the colors of") - HELP_TEXT ("the Mask.") - HELP_TEXT ("This menu works the same way as the one of") - HELP_TEXT ("the Stencil, so please refer to the Stencil") - HELP_TEXT ("paragraph to know how to use it.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("GRID") - HELP_TEXT (" This is useful to snap the cursor to the") - HELP_TEXT ("cross-points of a grid. It's generally") - HELP_TEXT ("used to draw a grid before drawing sprites") - HELP_TEXT ("of the same size such as a font or tiles,") - HELP_TEXT ("or for drawing figures or grabbing brushes") - HELP_TEXT ("with their dimensions multiple of the step") - HELP_TEXT ("of the grid.');") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_GRID_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Grid mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_GRID_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the grid") - HELP_TEXT ("parameters. These parameters are:") - HELP_TEXT ("") - HELP_TEXT ("- X,Y: Steps of the grid.") - HELP_TEXT ("") - HELP_TEXT ("- dX,dY: Offsets of the grid.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("SIEVE") - HELP_TEXT (" This effect allows you, by defining a") - HELP_TEXT ("pattern, to draw only on particular points") - HELP_TEXT ("of the picture. If you are a Manga drawer,") - HELP_TEXT ("you might find this useful to make patterned") - HELP_TEXT ("shades or color transitions.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Sieve mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the Sieve") - HELP_TEXT ("parameters. This menu consists in:") - HELP_TEXT ("") - HELP_TEXT ("- 16x16 drawing area: You can define a") - HELP_TEXT ("pattern in it (left click => white pixel /") - HELP_TEXT ("right click => black pixel). All the white") - HELP_TEXT ("pixels indicate that, when you'll draw,") - HELP_TEXT ("pixels will be applied on the picture at the") - HELP_TEXT ("corresponding positions whereas black pixels") - HELP_TEXT ("won't modify the picture: whites pixels are") - HELP_TEXT ("the \"holes of the sieve\".") - HELP_TEXT ("") - HELP_TEXT ("- 12 default patterns: They can be copied to") - HELP_TEXT ("the drawing area.") - HELP_TEXT ("") - HELP_TEXT ("- \"Transfer to brush\": Copies the pattern to") - HELP_TEXT ("the brush (white pixels => Fore-color /") - HELP_TEXT ("black pixels => Back-color).") - HELP_TEXT ("") - HELP_TEXT ("- \"Get from brush\": Puts the brush into the") - HELP_TEXT ("drawing area (back-color => black pixels /") - HELP_TEXT ("others => white pixels).") - HELP_TEXT ("") - HELP_TEXT ("- Scrolling 4-arrows pad: Scrolls the") - HELP_TEXT ("pattern in the drawing area.") - HELP_TEXT ("") - HELP_TEXT ("- Resizing 4-arrows pad: Defines the") - HELP_TEXT ("dimensions of the pattern.") - HELP_TEXT ("") - HELP_TEXT ("- Default-value (black or white square):") - HELP_TEXT ("Indicates which value must be inserted when") - HELP_TEXT ("you increase the dimensions of the pattern.") - HELP_TEXT ("") - HELP_TEXT ("- \"Clear\": Sets the whole pattern with the") - HELP_TEXT ("default value (see above).") - HELP_TEXT ("") - HELP_TEXT ("- \"Invert\": It... inverts :) ... black and") - HELP_TEXT ("white pixels.") - HELP_LINK ("(Key: %s)", SPECIAL_INVERT_SIEVE) - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("TRANSPARENCY") - HELP_TEXT (" This allows to mix the color(s) of the") - HELP_TEXT ("paintbrush with the colors of the picture.") - HELP_TEXT ("It's used to make transparency effects like") - HELP_TEXT ("with watercolors.") - HELP_TEXT ("") - HELP_TEXT ("You can also use the following shortcuts to") - HELP_TEXT ("activate transparency mode and assign an") - HELP_TEXT ("amount of opacity:") - HELP_LINK (" 10%% : %s", SPECIAL_TRANSPARENCY_1) - HELP_LINK (" 20%% : %s", SPECIAL_TRANSPARENCY_2) - HELP_LINK (" 30%% : %s", SPECIAL_TRANSPARENCY_3) - HELP_LINK (" 40%% : %s", SPECIAL_TRANSPARENCY_4) - HELP_LINK (" 50%% : %s", SPECIAL_TRANSPARENCY_5) - HELP_LINK (" 60%% : %s", SPECIAL_TRANSPARENCY_6) - HELP_LINK (" 70%% : %s", SPECIAL_TRANSPARENCY_7) - HELP_LINK (" 80%% : %s", SPECIAL_TRANSPARENCY_8) - HELP_LINK (" 90%% : %s", SPECIAL_TRANSPARENCY_9) - HELP_LINK (" 100%% : %s", SPECIAL_TRANSPARENCY_0) - HELP_TEXT ("If you use two of these shortcuts quickly,") - HELP_TEXT ("the second will set the units for finer") - HELP_TEXT ("control. Ie: 4 5 makes 45%, 0 9 makes 9%.") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Transparency mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the") - HELP_TEXT ("Transparency parameters. These parameters") - HELP_TEXT ("are:") - HELP_TEXT ("") - HELP_TEXT ("- Interpolation rate: Indicates the") - HELP_TEXT ("percentage of the applied color that will be") - HELP_TEXT ("considered upon the replaced color.") - HELP_TEXT ("") - HELP_TEXT ("- Interpolation method: Uses an") - HELP_TEXT ("interpolation algorithm to compute the") - HELP_TEXT ("color, according to the interpolation rate.") - HELP_TEXT ("") - HELP_TEXT ("- Additive method: Uses the lightest colors") - HELP_TEXT ("to choose the color to apply. For example:") - HELP_TEXT ("if you want to apply a color RGB:30,20,40 on") - HELP_TEXT ("a color RGB:10,50,20, the color applied will") - HELP_TEXT ("be the one, in the palette, that is the") - HELP_TEXT ("closest to the theoretic color RGB:30,50,40.") - HELP_TEXT ("") - HELP_TEXT ("- Subtractive method: uses the darkest") - HELP_TEXT ("colors to choose the color to apply. For") - HELP_TEXT ("example: if you want to apply a color") - HELP_TEXT ("RGB:30,20,40 on a color RGB:10,50,20, the") - HELP_TEXT ("color applied will be the one, in the") - HELP_TEXT ("palette, that is the closest to the") - HELP_TEXT ("theoretic color RGB:10,20,20.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("SMOOTH") - HELP_TEXT (" It provides an easy but not as efficient") - HELP_TEXT ("anti-aliasing as any artist's touch.") - HELP_TEXT ("Anyway this effect finds a better use in") - HELP_TEXT ("making a blurry aspect.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Smooth mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the Smooth") - HELP_TEXT ("matrix or choose one among the 4 ones") - HELP_TEXT ("predefined.") - HELP_TEXT ("The middle square represents the pixel on") - HELP_TEXT ("which you draw and the 8 others represent") - HELP_TEXT ("the neighbour pixels. Then, the point on") - HELP_TEXT ("which one draw will be replaced by the") - HELP_TEXT ("weighted average (according to values of") - HELP_TEXT ("each squares) of the 9 defined points.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("SMEAR") - HELP_TEXT (" It smears pixels in the direction you are") - HELP_TEXT ("moving your paintbrush, just as if you") - HELP_TEXT ("wanted to spread fresh paint with your") - HELP_TEXT ("fingers. You can combine this effect with") - HELP_TEXT ("the transparency effect.") - HELP_TEXT ("") - HELP_LINK ("(Key: %s)", SPECIAL_SMEAR_MODE) - HELP_TEXT ("Switches the Smear mode.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("TILING") - HELP_TEXT (" It consists in displaying parts of the") - HELP_TEXT ("brush that are adjusted on a tiling when") - HELP_TEXT ("you are drawing. It's mainly used for") - HELP_TEXT ("quickly drawing a background with a") - HELP_TEXT ("pattern, but there is a great number of") - HELP_TEXT ("other possibilities.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_TILING_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Tiling mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_TILING_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the Tiling") - HELP_TEXT ("parameters. These parameters are the offsets") - HELP_TEXT ("of the tiling.") -}; -static const T_Help_table helptable_text[] = -{ - HELP_TITLE("TEXT") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_TEXT) - HELP_TEXT ("") - HELP_TEXT ("The text menu allows you to enter some text") - HELP_TEXT ("and render it as a brush.") - HELP_TEXT ("The current background and foreground colors") - HELP_TEXT ("are very important, they determine the text") - HELP_TEXT ("color, the transparent color, and also the") - HELP_TEXT ("color range to use for antialiasing.") - HELP_TEXT ("GrafX2 can use 'bitmap' fonts as long as") - HELP_TEXT ("they are in the special layout supported ") - HELP_TEXT ("by SFont.") - HELP_TEXT ("TrueType fonts can also be used if this") - HELP_TEXT ("version of GrafX2 was compiled with") - HELP_TEXT ("TrueType support.") - HELP_TEXT ("") - HELP_TEXT ("- Txt: Click and enter your text here, a") - HELP_TEXT ("line of up to 250 characters.") - HELP_TEXT ("") - HELP_TEXT ("- Clear txt: Empties the current text.") - HELP_TEXT ("When the text is empty, a standard string") - HELP_TEXT ("is shown instead in the preview area.") - HELP_TEXT ("") - HELP_TEXT ("- Antialias: Click to enable or disable") - HELP_TEXT ("Antialiasing. Only affects TrueType fonts.") - HELP_TEXT ("") - HELP_TEXT ("- Size: Determine the font height. Only") - HELP_TEXT ("affects TrueType fonts.") - HELP_TEXT ("") - HELP_TEXT ("- Font selector: Choose a font. You can") - HELP_TEXT ("use the arrow keys (up and down) to quickly") - HELP_TEXT ("browse your fonts.") - HELP_TEXT ("TrueType fonts are indicated by 'TT'.") - HELP_TEXT ("") - HELP_TEXT ("- Preview area: Shows what the brush will") - HELP_TEXT ("look like.") -}; -static const T_Help_table helptable_magnifier[] = -{ - HELP_TITLE("MAGNIFIER") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_MAGNIFIER) - HELP_TEXT ("") - HELP_TEXT ("Engages/Disengages the choice of the zoomed") - HELP_TEXT ("window. If you're already in magnifier mode,") - HELP_TEXT ("you'll return to normal mode.") - HELP_LINK ("Zoom in : %s",SPECIAL_ZOOM_IN) - HELP_LINK ("Zoom out: %s",SPECIAL_ZOOM_OUT) - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_MAGNIFIER) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can choose the") - HELP_TEXT ("magnifying factor.") - HELP_TEXT ("") - HELP_TEXT (" Note: When you are in Zoom mode, you can") - HELP_TEXT ("move the \"split\" bar by clicking on it and") - HELP_TEXT ("moving your mouse left or right while") - HELP_TEXT ("holding the mouse button down.") -}; -static const T_Help_table helptable_colorpicker[] = -{ - HELP_TITLE("PIPETTE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_COLORPICKER) - HELP_TEXT ("") - HELP_TEXT ("Engages a color grabbing.") - HELP_TEXT ("") - HELP_TEXT ("Click on the picture to get the color of the") - HELP_TEXT ("pixel you're on. You can either get a new") - HELP_TEXT ("Fore-color or Back-color with respectively") - HELP_TEXT ("left or right mouse button.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_COLORPICKER) - HELP_TEXT ("") - HELP_TEXT ("Swap Fore-color and Back-color.") - HELP_TEXT ("") - HELP_TEXT (" The color currently pointed will be") - HELP_TEXT ("displayed in the tool-bar right after the") - HELP_TEXT ("coordinates. If you click outside the") - HELP_TEXT ("picture, the color 0 will be returned.") -}; -static const T_Help_table helptable_resolution[] = -{ - HELP_TITLE("RESOLUTION AND") - HELP_TITLE(" IMAGE SIZE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_RESOL) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can define the") - HELP_TEXT ("size of your picture and choose the") - HELP_TEXT ("screen resolution.") - HELP_TEXT ("") - HELP_TEXT ("- Image size") - HELP_TEXT ("Click in the boxes named \"Width\" and") - HELP_TEXT ("\"Height\" to change the size of the image") - HELP_TEXT ("you're editing, up to 9999x9999.") - HELP_TEXT ("You can also right-click a video mode to") - HELP_TEXT ("copy its dimensions to the image's.") - HELP_TEXT ("") - HELP_TEXT ("- Pixel size") - HELP_TEXT ("If you choose any Pixel size other than") - HELP_TEXT ("Normal, Grafx2 will emulate a lower") - HELP_TEXT ("resolution by scaling up everything it") - HELP_TEXT ("displays, including the menus and mouse") - HELP_TEXT ("cursor. In Double, Triple and Quadruple") - HELP_TEXT ("mode, the image will appear zoomed x2, x3 or") - HELP_TEXT ("x4, keeping the original proportions. The") - HELP_TEXT ("scaling is done in software, with no linear") - HELP_TEXT ("interpolation, so it can't cause blur. This") - HELP_TEXT ("setting is especially useful if your") - HELP_TEXT ("hardware or drivers don't support the low") - HELP_TEXT ("resolutions you need, but it also allows you") - HELP_TEXT ("to draw in low-resolution while staying in") - HELP_TEXT ("window mode.") - HELP_TEXT ("If you choose one of the scalers called") - HELP_TEXT ("Wide, Tall, Wide2 and Tall2, this will") - HELP_TEXT ("emulate a video mode which has rectangular") - HELP_TEXT ("pixels (longer horizontally or vertically),") - HELP_TEXT ("like some video modes of the C64, Amstrad") - HELP_TEXT ("CPC, and Commodore Amiga.") - HELP_TEXT ("") - HELP_TEXT ("- Video mode") - HELP_TEXT ("Click on a video mode to select it.") - HELP_TEXT ("Grafx2 only lists modes that are detected") - HELP_TEXT ("as available on your computer. Depending on") - HELP_TEXT ("your video card and drivers, there can be") - HELP_TEXT ("a huge difference in the number of modes") - HELP_TEXT ("it can propose.") - HELP_TEXT ("The small buttons on the left-hand side of") - HELP_TEXT ("the lines in the list of modes have been") - HELP_TEXT ("designed to allow you to disable some modes") - HELP_TEXT ("that are not supported by your card. So, the") - HELP_TEXT ("modes that you will disable won't be used") - HELP_TEXT ("when loading pictures with \"Auto-set") - HELP_TEXT ("resolution\" ON.") - HELP_TEXT ("") - HELP_TEXT ("When you click on one of these buttons, its") - HELP_TEXT ("color changes to one of the 4 following. The") - HELP_TEXT ("signification for each color of these") - HELP_TEXT ("buttons is:") - HELP_TEXT ("") - HELP_TEXT ("- Light gray: The video mode is OK. It can") - HELP_TEXT ("be used by the auto-set resolution option") - HELP_TEXT ("when you load picture, and you can select it") - HELP_TEXT ("in the menu of resolutions.") - HELP_TEXT ("") - HELP_TEXT ("- White: It works exactly the same as above.") - HELP_TEXT ("Moreover, it allows you to tag your") - HELP_TEXT ("favourite modes. Indeed, the huge number of") - HELP_TEXT ("video modes makes it more difficult to find") - HELP_TEXT ("the mode your want in the list; so you can") - HELP_TEXT ("tag your favoutite ones in white, so that it") - HELP_TEXT ("will be easier to locate them. (Note: you") - HELP_TEXT ("cannot disable the standard windowed mode)") - HELP_TEXT ("") - HELP_TEXT ("- Dark gray: It allows you to indicate which") - HELP_TEXT ("modes are not really perfect (flickering,") - HELP_TEXT ("not centered, etc...) but which can be used") - HELP_TEXT ("even so. The difference with the light grey") - HELP_TEXT ("button is that these modes won't be used by") - HELP_TEXT ("the auto-set resolution option.") - HELP_TEXT ("") - HELP_TEXT ("- Black: Use it for totally unsupported") - HELP_TEXT ("modes. Thus, these modes won't be selected") - HELP_TEXT ("the \"auto-set res.\" and the program will") - HELP_TEXT ("not let you select them from the list of") - HELP_TEXT ("resolutions.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_RESOL) - HELP_TEXT ("") - HELP_TEXT (" Automaticaly switches to the 640x400 window") - HELP_TEXT ("mode.") -}; -static const T_Help_table helptable_page[] = -{ - HELP_TITLE("SPARE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_PAGE) - HELP_TEXT ("") - HELP_TEXT ("Jumps to spare page. The current page is") - HELP_TEXT ("then considered as the new spare page, and") - HELP_TEXT ("the spare page considered as the new current") - HELP_TEXT ("page.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_PAGE) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can choose whether") - HELP_TEXT ("you want to copy the whole picture (keyboard") - HELP_TEXT ("short-cut in this menu is [Return]), only") - HELP_TEXT ("the pixels, only the palette, or only some") - HELP_TEXT ("colors.") - HELP_TEXT ("In this last case, a second menu") - HELP_TEXT ("(stencil-like) will propose you to tag the") - HELP_TEXT ("colors you want to copy (they are all") - HELP_TEXT ("selected by default).") - HELP_TEXT ("Please refer to section \"Stencil\" to know") - HELP_TEXT ("how to use this last menu.") - HELP_TEXT ("The last option the menu (\"Copy palette and") - HELP_TEXT ("remap\"), remaps the spare page with the") - HELP_TEXT ("current palette and replicates this palette") - HELP_TEXT ("to the spare page. This option is useful to") - HELP_TEXT ("quickly remap a picture with the palette of") - HELP_TEXT ("another.") -}; -static const T_Help_table helptable_save[] = -{ - HELP_TITLE("SAVE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_SAVE) - HELP_TEXT ("") - HELP_TEXT ("Displays a fileselector where the following") - HELP_TEXT ("options are available:") - HELP_TEXT ("") - HELP_TEXT ("- Select drive: Allow you to change the") - HELP_TEXT ("current drive.or volume (depending on your") - HELP_TEXT ("operating system") - HELP_TEXT ("") - HELP_TEXT ("- Format: Allows you to choose the file") - HELP_TEXT ("format you want. (PAL and KCF file formats") - HELP_TEXT ("are \"palette\" files).") - HELP_TEXT ("") - HELP_TEXT ("- Filename: Allows you to give a new name to") - HELP_TEXT ("the picture. If no extension is given, the") - HELP_TEXT ("default (according to the format) will be") - HELP_TEXT ("used.") - HELP_TEXT ("") - HELP_TEXT ("- Bookmarks: The four dropdown buttons allow") - HELP_TEXT ("you to bookmark frequently used directories.") - HELP_TEXT ("Use right-click to open a contextual menu") - HELP_TEXT ("to Set it (memorize current directory),") - HELP_TEXT ("Rename it to change its label, and Clear it") - HELP_TEXT ("if you no longer need it. Use left-click to") - HELP_TEXT ("change to the memorized directory.") - HELP_TEXT ("") - HELP_TEXT ("- File-list: Allows you to flick through the") - HELP_TEXT ("disk tree or to overwrite an existing file.") - HELP_TEXT ("") - HELP_TEXT ("- Delete: Allows you to delete the item") - HELP_TEXT ("under the selection bar. If the item is a") - HELP_TEXT ("directory, it must be empty to be removed.") - HELP_TEXT ("") - HELP_TEXT ("- Save: Saves the picture with the current") - HELP_TEXT ("filename, with the chosen format. If the ") - HELP_TEXT ("current filename represents a directory,") - HELP_TEXT ("you'll enter it.") - HELP_TEXT ("") - HELP_TEXT ("- Comment (Txt): If you're using the PKM") - HELP_TEXT ("or PNG format, you can type in a comment on") - HELP_TEXT ("your picture. It will be memorized in the") - HELP_TEXT ("image.") - HELP_TEXT ("") - HELP_TEXT ("Note: The Backspace key brings you directly") - HELP_TEXT ("to the parent directory. You can also type") - HELP_TEXT ("the first letters of a filename you are") - HELP_TEXT ("looking for, to access it faster.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_SAVE) - HELP_TEXT ("") - HELP_TEXT ("Save the current picture with its current") - HELP_TEXT ("filename, format and comment.") - HELP_TEXT ("") - HELP_TEXT ("If the file already exists, a confirmation") - HELP_TEXT ("box will appear.") -}; -static const T_Help_table helptable_load[] = -{ - - HELP_TITLE("LOAD") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LOAD) - HELP_TEXT ("") - HELP_TEXT ("This works the same way as Save.") - HELP_TEXT ("") - HELP_TEXT ("You'll have access in the format selector to") - HELP_TEXT ("a \"*.*\" filter. And of course, you won't be") - HELP_TEXT ("able to type in any comment.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_LOAD) - HELP_TEXT ("") - HELP_TEXT ("Reloads the picture.") - HELP_TEXT ("") - HELP_TEXT ("If you want to load a picture and that you") - HELP_TEXT ("haven't saved the last modifications of the") - HELP_TEXT ("current picture, a confirmation box will") - HELP_TEXT ("appear.") -}; -static const T_Help_table helptable_settings[] = -{ - HELP_TITLE("SETTINGS") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_SETTINGS) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can configure some") - HELP_TEXT ("miscellaneous elements of the program:") - HELP_TEXT ("") - HELP_TEXT ("- Number of UNDO pages: indicates the total") - HELP_TEXT ("number of pages that GrafX2 will memorize.") - HELP_TEXT ("Each time you modify the picture, its") - HELP_TEXT ("current state is memorized in one of these") - HELP_TEXT ("pages. To flick through these pages, use the") - HELP_TEXT ("\"Oops\" button (Undo/Redo).") - HELP_TEXT ("") - HELP_TEXT ("- Mouse sensibility: Modifies the speed of") - HELP_TEXT ("the mouse when you're in fullscreen. With") - HELP_TEXT ("the normal setting (slider on top), you may") - HELP_TEXT ("find the mouse too fast, especially in ") - HELP_TEXT ("video modes which are much smaller than your") - HELP_TEXT ("desktop. You can lower the slider to divide") - HELP_TEXT ("the speed by 2, 3 or 4.") - HELP_TEXT ("When using videomodes with native skewed") - HELP_TEXT ("pixels like 640x240 or 320x512, you'll") - HELP_TEXT ("probably want to use a stronger reduction") - HELP_TEXT ("on the axis which has less pixels.") - HELP_TEXT ("") - HELP_TEXT ("- Show/Hide in file list: Defines whether") - HELP_TEXT ("some particular files or directories must be") - HELP_TEXT ("displayed by the fileselectors or not.") - HELP_TEXT ("") - HELP_TEXT ("- Show/Hide picture limits: Indicates if the") - HELP_TEXT ("picture boundaries must be displayed when") - HELP_TEXT ("you are in a resolution bigger than the") - HELP_TEXT ("picture.") - HELP_TEXT ("") - HELP_TEXT ("- Clear palette: Indicates if loading a file") - HELP_TEXT ("with a palette of less than 256 colors must") - HELP_TEXT ("erase the rest of the current palette") - HELP_TEXT ("(replace by the black color).") - HELP_TEXT ("") - HELP_TEXT ("- Maximize preview: maximizes the preview of") - HELP_TEXT ("the pictures so that it is as big as") - HELP_TEXT ("possible. If you're not in the same") - HELP_TEXT ("resolution as the picture's one, it can try") - HELP_TEXT ("to correct the aspect ratio, but if the") - HELP_TEXT ("picture does not fill the whole screen, it") - HELP_TEXT ("can be worse.") - HELP_TEXT ("") - HELP_TEXT ("- Backup: when you'll save a picture over an") - HELP_TEXT ("existing file, the program will rename this") - HELP_TEXT ("file to \"*.BAK\" where * is the name of the") - HELP_TEXT ("picture without its extension. If the backup") - HELP_TEXT ("file already exists in the directory, it") - HELP_TEXT ("will be replaced. If you save a picture with") - HELP_TEXT ("the name of the backup file, no backup file") - HELP_TEXT ("will be created (of course!) ;).") - HELP_TEXT ("") - HELP_TEXT ("- Safety colors: Brings back the 4 default") - HELP_TEXT ("colors of the menus if you run an operation") - HELP_TEXT ("that passes the image in less than four") - HELP_TEXT ("colors in the palette editor.") - HELP_TEXT ("") - HELP_TEXT ("- Adjust brush pick: This option is used") - HELP_TEXT ("when you grab a brush in Grid (Snap) mode.") - HELP_TEXT ("Then, the right-most and down-most pixels") - HELP_TEXT ("won't be picked up with the rest of the") - HELP_TEXT ("brush. This option has been made because, if") - HELP_TEXT ("people grab brushes in Grid mode, that's") - HELP_TEXT ("mostly when they want to grab sprites. For") - HELP_TEXT ("example: if you have 16x16 sprites on your") - HELP_TEXT ("page, you'll set the grid mode to 16x16. But") - HELP_TEXT ("the cursor will snap at points like (0,0),") - HELP_TEXT ("(16,0), (16,16) and so on... And the problem") - HELP_TEXT ("is that, from (0,0) to (16,16), there are 17") - HELP_TEXT ("pixels! But if you keep the") - HELP_TEXT ("adjust-brush-pick option on, the unwanted") - HELP_TEXT ("pixels will be ignored. Moreover, this") - HELP_TEXT ("option adjusts the brush handle so that the") - HELP_TEXT ("brush still fits in the grid, instead of") - HELP_TEXT ("placing the handle in the center of the") - HELP_TEXT ("brush.") - HELP_TEXT ("") - HELP_TEXT ("- Separate colors: Draws a squaring around") - HELP_TEXT ("the colors of the tool-bar.") - HELP_TEXT ("") - HELP_TEXT ("- Auto-set resolution: sets the best") - HELP_TEXT ("resolution for the loaded image.") - HELP_TEXT ("") - HELP_TEXT ("- Coordinates: Choose if you want to display") - HELP_TEXT ("relative or absolute coordinates when using") - HELP_TEXT ("tools such as circles, rectangles, etc...") - HELP_TEXT ("for example, if you draw a circle: if coords") - HELP_TEXT ("are relative, the radius of the circle will") - HELP_TEXT ("be displayed, while in absolute coords, the") - HELP_TEXT ("coordinates of the cursor will be displayed.") - HELP_TEXT ("") - HELP_TEXT ("- Reload: loads the previously saved") - HELP_TEXT ("configuration.") - HELP_TEXT ("") - HELP_TEXT ("- Auto-save: means that the configuration") - HELP_TEXT ("will be automatically saved when you'll quit") - HELP_TEXT ("the program.") - HELP_TEXT ("") - HELP_TEXT ("- Save: saves the configuration at once.") - HELP_TEXT (" All modifications will be effective just") - HELP_TEXT ("after closing the menu.") - HELP_TEXT ("") - HELP_TITLE("SKINS") - HELP_TEXT ("") - HELP_TEXT ("This window allow you to change the look and") - HELP_TEXT ("feel of the program.") - HELP_TEXT ("") - HELP_TEXT ("- Font: determines whether you want to use") - HELP_TEXT ("GrafX2 with a classical font, or another one") - HELP_TEXT ("a bit funnier.") - HELP_TEXT ("") - HELP_TEXT ("- Cursor: allows you to choose whether you") - HELP_TEXT ("prefer a solid cursor or a transparent") - HELP_TEXT ("cursor.") - HELP_TEXT ("") - HELP_TEXT ("- Graphic file: you can change the whole") - HELP_TEXT ("interface by selecting where the sprites for") - HELP_TEXT ("all buttons are. Look at the files in the") - HELP_TEXT ("\"skin\" directory if you want to create your") - HELP_TEXT ("own. There are two skins available, the") - HELP_TEXT ("default for 2.1 is called modern. Classic is") - HELP_TEXT ("for nostalgics who wish to remember the old") - HELP_TEXT ("days of Sunset Design. If you create a good") - HELP_TEXT ("skin, feel free to share it with us! We may") - HELP_TEXT ("include it in a future release...") -}; -static const T_Help_table helptable_clear[] = -{ - - HELP_TITLE("CLEAR") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_CLEAR) - HELP_TEXT ("") - HELP_TEXT ("Clears the picture with the color number 0.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_CLEAR) - HELP_TEXT ("") - HELP_TEXT ("Clears the picture with the Back-color.") -}; -static const T_Help_table helptable_general[] = -{ - - HELP_TITLE("HELP STATS") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_HELP) - HELP_TEXT ("") - HELP_TEXT ("Displays an info window where you'll find") - HELP_TEXT ("some credits, help about the credits,") - HELP_TEXT ("different effects, greetings, registering...") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_HELP) - HELP_TEXT ("") - HELP_TEXT ("Displays a window where you'll find") - HELP_TEXT ("miscellaneous informations about the system.") - HELP_TEXT (" Note: you should take care to keep more") - HELP_TEXT ("than 128 Kb in order to let the program") - HELP_TEXT ("run in a proper way.") -}; -static const T_Help_table helptable_undo[] = -{ - - HELP_TITLE("OOPS") - HELP_TEXT ("(UNDO/REDO)") - HELP_TEXT ("LEFT CLICK Allows you to undo the last") - HELP_TEXT ("modification on the picture.") - HELP_LINK ("(Key:%s)",0x100+BUTTON_UNDO) - HELP_TEXT ("") - HELP_TEXT ("RIGHT CLICK Allows you to redo the last") - HELP_TEXT ("modification undone on the picture.") - HELP_TEXT ("The maximum number of UNDO that you can") - HELP_TEXT ("perform can be defined in the settings") - HELP_TEXT ("menu.") - HELP_TEXT ("Undo/Redo aren't effective after page") - HELP_TEXT ("switching, picture loading and picture") - HELP_TEXT ("size modifications.") - HELP_LINK ("(Key:%s)",0x200+BUTTON_UNDO) -}; -static const T_Help_table helptable_kill[] = -{ - - HELP_TITLE("KILL") - HELP_TEXT ("KILL CURRENT PAGE") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_KILL) - HELP_TEXT ("") - HELP_TEXT ("Removes the current page from the list of") - HELP_TEXT ("\"Undo\" pages. This allows you to free some") - HELP_TEXT ("memory if you need it. For instance, this") - HELP_TEXT ("will allow you to delete the start-up page") - HELP_TEXT ("after having loaded an image. A message will") - HELP_TEXT ("appear if you've already erased all the") - HELP_TEXT ("pages except the last one.") - HELP_TEXT (" Note: Another way to free some memory is to") - HELP_TEXT ("decrease the number of \"Undo\" pages. Or") - HELP_TEXT ("else, if you have recentlt grabbed a very") - HELP_TEXT ("big brush that you don't use any more, you") - HELP_TEXT ("can grab a new smaller one. The memory") - HELP_TEXT ("allocated by the big brush will be thus") - HELP_TEXT ("freed.") -}; -static const T_Help_table helptable_quit[] = -{ - - HELP_TITLE("QUIT") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_QUIT) - HELP_TEXT ("") - HELP_TEXT ("Allows you to leave GrafX2. If there are") - HELP_TEXT ("unsaved modifications in the current or") - HELP_TEXT ("spare page, a confirmation box will ask you") - HELP_TEXT ("if you really want to quit GrafX2, if you") - HELP_TEXT ("want to save (Auto-save, no fileselector) or") - HELP_TEXT ("if you want to stay in GrafX2.") -}; -static const T_Help_table helptable_palette[] = -{ - - HELP_TITLE("PAL MENU") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_PALETTE) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where the following options") - HELP_TEXT ("are available:") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Allows you to choose a") - HELP_TEXT ("color-block to edit. If you click with the") - HELP_TEXT ("right mouse button, you'll choose a new") - HELP_TEXT ("Back-color.") - HELP_TEXT ("") - HELP_TEXT ("- Gauges: Allow you to modify the") - HELP_TEXT ("current selection.") - 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 ("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 ("into its reverse video equivalent.") - HELP_TEXT ("") - HELP_TEXT ("- Invert: Swaps the colors of the current") - HELP_TEXT ("selection so that the first colors become") - HELP_TEXT ("the last ones.") - HELP_TEXT ("") - HELP_TEXT ("- X-Invert: Works as above but modifies the") - HELP_TEXT ("picture so that it looks the same.") - HELP_TEXT ("") - HELP_TEXT ("- Swap: Swaps the current selection with") - HELP_TEXT ("another color-block. Click on the beginning") - HELP_TEXT ("of the new color-block.") - HELP_TEXT ("") - HELP_TEXT ("- X-Swap: Works as above but modifies the") - HELP_TEXT ("picture so that it looks the same. This may") - HELP_TEXT ("be useful if you want to sort your palette.") - HELP_TEXT ("") - HELP_TEXT ("- Copy: Copies the current selection to") - HELP_TEXT ("another color-block. Click on the beginning") - HELP_TEXT ("of the new color-block.") - HELP_TEXT ("") - HELP_TEXT ("- Spread: Computes a gradation between two") - HELP_TEXT ("colors. If your selection is only made up of") - HELP_TEXT ("one color, select the second color in the") - HELP_TEXT ("palette. Otherwise, the two colors used will") - HELP_TEXT ("be its extremities.") - HELP_TEXT ("") - HELP_TEXT ("- Sort: sorts the palette by color ranges.") - HELP_TEXT ("If you click with the left mouse button, it") - HELP_TEXT ("will sort by H S L; and if you click with") - HELP_TEXT ("the right mouse button, it will sort by L") - HELP_TEXT ("only. Note that you can choose a range of") - HELP_TEXT ("colors before sorting, and instead of the") - 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 ("") - 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).") - HELP_TEXT ("") - HELP_TEXT ("- Undo: Allows you to recover the last") - HELP_TEXT ("modifications made on the palette. If the") - HELP_TEXT ("last operation modified the picture, it") - HELP_TEXT ("won't recover them: you'll have to click on") - HELP_TEXT ("Cancel to do so.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("If you press , the program will") - HELP_TEXT ("replace, as well as possible, some unused") - HELP_TEXT ("colors by the four default colors of the") - HELP_TEXT ("menu. The image won't look altered because") - HELP_TEXT ("the modified colors (in the case they were") - HELP_TEXT ("used on a few points) will be replaced by") - HELP_TEXT ("the closest colors in the rest of the") - HELP_TEXT ("palette. This option is really useful when") - HELP_TEXT ("you modify the palette so that there are no") - HELP_TEXT ("colors that fit for the menu (eg: \"Zap") - HELP_TEXT ("unused\" while very little colors are used in") - HELP_TEXT ("the picture; or \"Reduce\" with a very small") - HELP_TEXT ("number of colors).") - HELP_TEXT ("") - HELP_TEXT ("If you press the key below or <,>") - HELP_TEXT ("(QWERTY), the menu will disappear and you") - HELP_TEXT ("will be able to pick up a color from the") - HELP_TEXT ("picture easily. Press to cancel.") - HELP_TEXT ("") - HELP_TEXT ("If only one color is selected (not a block),") - HELP_TEXT ("the <[> and <]> keys can be used to select") - HELP_TEXT ("the previous or next Forecolor (Backcolor if") - HELP_TEXT ("you press at the same time).") - HELP_TEXT ("") - HELP_TEXT ("Warning! If you press Undo after an action") - HELP_TEXT ("that modifies the picture (X-Swap, X-Invert") - HELP_TEXT ("and Reduce colors), the picture won't be") - HELP_TEXT ("remapped as it was just before this action.") - HELP_TEXT ("Only Cancel will.") - HELP_TEXT ("") - HELP_TITLE("PALETTE OPTIONS") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_PALETTE) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu from where you have the") - HELP_TEXT ("following options:") - HELP_TEXT ("") - HELP_TEXT ("- Colors for best match:") - HELP_TEXT ("A menu in which you can select the colors") - HELP_TEXT ("that have not to be used for smoothing, for") - HELP_TEXT ("the transparency mode, and for remapping.") - HELP_TEXT ("") - HELP_TEXT ("- User's color series:") - HELP_TEXT ("A menu in which you can define color series") - HELP_TEXT ("for next/previous user color shortcuts.") - HELP_TEXT ("It's the same settings than the shade mode.") - HELP_TEXT ("After you have some color ranges defined in") - HELP_TEXT ("this screen, you can use those shortcuts to") - HELP_TEXT ("move to the next or previous color according") - HELP_TEXT ("to your ranges:") - HELP_TEXT ("") - HELP_TEXT ("Foreground color") - HELP_TEXT ("") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) - HELP_TEXT ("") - HELP_TEXT ("Background color") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("- Palette layout:") - HELP_TEXT ("Lets you customize the palette that appears") - HELP_TEXT ("on the right of the menu. You can choose the") - HELP_TEXT ("number of lines and columns.") - HELP_TEXT ("If you want the colors to run top to bottom,") - HELP_TEXT ("check the 'Vertical' button, otherwise the") - HELP_TEXT ("colors runs left to right.") - HELP_TEXT ("") - HELP_TEXT ("- RGB Scale:") - HELP_TEXT ("Lets you set the scale of the R G B sliders") - HELP_TEXT ("in the palette screen. You should normally") - HELP_TEXT ("leave it at 256 to get the full 0-255 range,") - HELP_TEXT ("but if you want to constrain the palette") - HELP_TEXT ("to the capabilities of some specific") - HELP_TEXT ("computers and consoles, you can choose eg:") - HELP_TEXT (" 64 : VGA") - HELP_TEXT (" 16 : Amiga") - HELP_TEXT (" 4 : MSX2") - HELP_TEXT (" 2 : Amstrad CPC") - }; -static const T_Help_table helptable_pal_scroll[] = -{ - - HELP_TITLE("SCROLL PAL") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Scrolls the palette window in the right of") - HELP_TEXT ("the menu.") - HELP_LINK ("Key for back: %s", 0x100+BUTTON_PAL_LEFT) - HELP_LINK ("Key for forward: %s", 0x100+BUTTON_PAL_RIGHT) - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Same as above, but faster.") - HELP_LINK ("Key for back: %s", 0x200+BUTTON_PAL_LEFT) - HELP_LINK ("Key for forward: %s", 0x200+BUTTON_PAL_RIGHT) - HELP_TEXT ("") -}; -static const T_Help_table helptable_color_select[] = -{ - - HELP_TITLE("PALETTE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Defines the Fore-color.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Defines the Back-color.") -}; -static const T_Help_table helptable_hide[] = -{ - - HELP_TITLE("HIDE MENU") - HELP_TEXT ("") - HELP_TEXT ("Allows you to hide the menu. If you do this,") - HELP_TEXT ("take care to watch before the key to press") - HELP_TEXT ("to show the menu back (the key is") - HELP_LINK ("%s).",0x100+BUTTON_HIDE) - -}; - -#define HELP_TABLE_DECLARATION(x) {x, sizeof(x)/sizeof(const T_Help_table)}, - -T_Help_section Help_section[] = -{ - HELP_TABLE_DECLARATION(helptable_about) - HELP_TABLE_DECLARATION(helptable_licence) - HELP_TABLE_DECLARATION(helptable_help) - HELP_TABLE_DECLARATION(helptable_credits) - - // Attention, keep the same order as BUTTON_NUMBERS: - HELP_TABLE_DECLARATION(helptable_paintbrush) - HELP_TABLE_DECLARATION(helptable_adjust) - HELP_TABLE_DECLARATION(helptable_draw) - HELP_TABLE_DECLARATION(helptable_curves) - HELP_TABLE_DECLARATION(helptable_lines) - HELP_TABLE_DECLARATION(helptable_airbrush) - HELP_TABLE_DECLARATION(helptable_floodfill) - HELP_TABLE_DECLARATION(helptable_polygons) - HELP_TABLE_DECLARATION(helptable_polyfill) - HELP_TABLE_DECLARATION(helptable_rectangles) - HELP_TABLE_DECLARATION(helptable_filled_rectangles) - HELP_TABLE_DECLARATION(helptable_circles) - HELP_TABLE_DECLARATION(helptable_filled_circles) - HELP_TABLE_DECLARATION(helptable_grad_rect) - HELP_TABLE_DECLARATION(helptable_spheres) - HELP_TABLE_DECLARATION(helptable_brush) - HELP_TABLE_DECLARATION(helptable_polybrush) - HELP_TABLE_DECLARATION(helptable_brush_fx) - HELP_TABLE_DECLARATION(helptable_effects) - HELP_TABLE_DECLARATION(helptable_text) - HELP_TABLE_DECLARATION(helptable_magnifier) - HELP_TABLE_DECLARATION(helptable_colorpicker) - HELP_TABLE_DECLARATION(helptable_resolution) - HELP_TABLE_DECLARATION(helptable_page) - HELP_TABLE_DECLARATION(helptable_save) - HELP_TABLE_DECLARATION(helptable_load) - HELP_TABLE_DECLARATION(helptable_settings) - HELP_TABLE_DECLARATION(helptable_clear) - HELP_TABLE_DECLARATION(helptable_general) - HELP_TABLE_DECLARATION(helptable_undo) - HELP_TABLE_DECLARATION(helptable_kill) - HELP_TABLE_DECLARATION(helptable_quit) - HELP_TABLE_DECLARATION(helptable_palette) - HELP_TABLE_DECLARATION(helptable_pal_scroll) - HELP_TABLE_DECLARATION(helptable_pal_scroll) - HELP_TABLE_DECLARATION(helptable_color_select) - HELP_TABLE_DECLARATION(helptable_hide) -}; +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2009 Franck Charlet + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file helpfile.h +/// This is all the text that appears in contextual help and credits. +/// +/// Note: The source code is kept on a public website, so keep this in mind +/// if you're thinking of putting an e-mail address in there. At least, use +/// "\100" instead of @, to help against the most basic email address harvesters. +////////////////////////////////////////////////////////////////////////////// + +#include "const.h" // Uses enumerations BUTTON_NUMBERS and SPECIAL_ACTIONS + +// Some magic formulas: + +#define HELP_TEXT(x) {'N', x, 0}, +// Generates a 'N' line (Normal) + +#define HELP_LINK(x,y) {'K', x, y}, +// Generates a 'K' line (Key) + +#define HELP_BOLD(x) {'S', x, 0}, +// Generates a 'S' line (BOLD) + +#define HELP_TITLE(x) {'T', x, 0}, {'-', x, 0}, +// Generates a 'T' line (Title, upper half) +// and a second '-' line (Title, lower half), with the same text. + +static const T_Help_table helptable_about[] = +/* + Do not exceed 44 characters for normal lines: + HELP_TEXT ("--------------------------------------------") + Do not exceed 22 characters for title lines: + HELP_TITLE("======================") +*/ +{ + HELP_TEXT ("") // Leave enough room for a hard-coded logo, eventually. + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE(" GRAFX 2 ") + HELP_BOLD (" \"Summer Sunset\" Edition") + HELP_BOLD (" THE ULTIMATE MULTI-RESOLUTION GFX EDITOR") + HELP_TEXT (" http://grafx2.googlecode.com") + HELP_TEXT ("") + HELP_TEXT (" Copyright 2007 by the Grafx2 project team") + HELP_TEXT (" Copyright 1996-2001 by SUNSET DESIGN") +}; +static const T_Help_table helptable_licence[] = +{ + HELP_TITLE(" LICENSE") + HELP_TEXT ("") + HELP_TEXT ("Grafx2 is FREE SOFTWARE, you can") + HELP_TEXT ("redistribute it and/or modify it under the") + HELP_TEXT ("terms of the GNU General Public License as") + HELP_TEXT ("published by the Free Software Foundation;") + HELP_TEXT ("version 2 of the License.") + HELP_TEXT ("") + HELP_TEXT ("Grafx2 is distributed in the hope that it") + HELP_TEXT ("will be useful, but WITHOUT ANY WARRANTY;") + HELP_TEXT ("without even the implied warranty of") + HELP_TEXT ("MERCHANTABILITY or FITNESS FOR A PARTICULAR") + HELP_TEXT ("PURPOSE. See the GNU General Public License") + HELP_TEXT ("for more details.") + HELP_TEXT ("") + HELP_TEXT ("You should have received a copy of the GNU") + HELP_TEXT ("General Public License along with Grafx2;") + HELP_TEXT ("if not, see http://www.gnu.org/licenses/ or") + HELP_TEXT ("write to the Free Software Foundation, Inc.") + HELP_TEXT (" 59 Temple Place - Suite 330, Boston,") + HELP_TEXT (" MA 02111-1307, USA.") + +}; +static const T_Help_table helptable_help[] = +{ + HELP_TITLE(" HELP") + HELP_TEXT ("") + HELP_TEXT (" Contextual help is available by pressing") + HELP_LINK (" the %s key",0x100+BUTTON_HELP) + HELP_TEXT (" You can do it while hovering a menu icon,") + HELP_TEXT (" or while a window is open.") + HELP_TEXT (" When a keyboard shortcut is displayed it's") + HELP_TEXT (" your current configuration and you can") + HELP_TEXT (" change it by clicking it.") + HELP_TEXT ("") + HELP_TITLE(" KEYBOARD SHORTCUTS") + HELP_TEXT ("") + HELP_TEXT ("Scroll visible area") + HELP_LINK (" up: %s", SPECIAL_SCROLL_UP) + HELP_LINK (" down: %s", SPECIAL_SCROLL_DOWN) + HELP_LINK (" left: %s", SPECIAL_SCROLL_LEFT) + HELP_LINK (" right: %s", SPECIAL_SCROLL_RIGHT) + HELP_LINK (" up faster: %s", SPECIAL_SCROLL_UP_FAST) + HELP_LINK (" down faster: %s", SPECIAL_SCROLL_DOWN_FAST) + HELP_LINK (" left faster: %s", SPECIAL_SCROLL_LEFT_FAST) + HELP_LINK (" right faster: %s", SPECIAL_SCROLL_RIGHT_FAST) + HELP_LINK (" up slower: %s", SPECIAL_SCROLL_UP_SLOW) + HELP_LINK (" down slower: %s", SPECIAL_SCROLL_DOWN_SLOW) + HELP_LINK (" left slower: %s", SPECIAL_SCROLL_LEFT_SLOW) + HELP_LINK (" right slower: %s", SPECIAL_SCROLL_RIGHT_SLOW) + HELP_TEXT ("Emulate mouse") + HELP_LINK (" Up: %s", SPECIAL_MOUSE_UP) + HELP_LINK (" Down: %s", SPECIAL_MOUSE_DOWN) + HELP_LINK (" Left: %s", SPECIAL_MOUSE_LEFT) + HELP_LINK (" Right: %s", SPECIAL_MOUSE_RIGHT) + HELP_LINK (" Left click: %s", SPECIAL_CLICK_LEFT) + HELP_LINK (" Right click: %s", SPECIAL_CLICK_RIGHT) + HELP_LINK ("Show / Hide menu: %s", 0x100+BUTTON_HIDE) + HELP_LINK ("Show / Hide cursor: %s", SPECIAL_SHOW_HIDE_CURSOR) + HELP_LINK ("Paintbrush = \".\": %s", SPECIAL_DOT_PAINTBRUSH) + HELP_LINK ("Paintbrush choice: %s", 0x100+BUTTON_PAINTBRUSHES) + HELP_LINK ("Monochrome brush: %s", 0x200+BUTTON_PAINTBRUSHES) + HELP_LINK ("Freehand drawing: %s", 0x100+BUTTON_DRAW) + HELP_TEXT ("Switch freehand") + HELP_LINK (" drawing mode: %s", 0x200+BUTTON_DRAW) + HELP_TEXT ("Continuous freehand") + HELP_LINK (" drawing: %s", SPECIAL_CONTINUOUS_DRAW) + HELP_LINK ("Line: %s", 0x100+BUTTON_LINES) + HELP_LINK ("Knotted lines: %s", 0x200+BUTTON_LINES) + HELP_LINK ("Spray: %s", 0x100+BUTTON_AIRBRUSH) + HELP_LINK ("Spray menu: %s", 0x200+BUTTON_AIRBRUSH) + HELP_LINK ("Floodfill: %s", 0x100+BUTTON_FLOODFILL) + HELP_LINK ("Replace color: %s", 0x200+BUTTON_FLOODFILL) + HELP_LINK ("Bezier's curves: %s", 0x100+BUTTON_CURVES) + HELP_TEXT ("Bezier's curve with") + HELP_LINK (" 3 or 4 points %s", 0x200+BUTTON_CURVES) + HELP_LINK ("Empty rectangle: %s", 0x100+BUTTON_RECTANGLES) + HELP_LINK ("Filled rectangle: %s", 0x100+BUTTON_FILLRECT) + HELP_LINK ("Empty circle: %s", 0x100+BUTTON_CIRCLES) + HELP_LINK ("Empty ellipse: %s", 0x200+BUTTON_CIRCLES) + HELP_LINK ("Filled circle: %s", 0x100+BUTTON_FILLCIRC) + HELP_LINK ("Filled ellipse: %s", 0x200+BUTTON_FILLCIRC) + HELP_LINK ("Empty polygon: %s", 0x100+BUTTON_POLYGONS) + HELP_LINK ("Empty polyform: %s", 0x200+BUTTON_POLYGONS) + HELP_LINK ("Polyfill: %s", 0x100+BUTTON_POLYFILL) + 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 ("Spheres: %s", 0x100+BUTTON_SPHERES) + HELP_LINK ("Gradient ellipses: %s", 0x200+BUTTON_SPHERES) + HELP_LINK ("Adjust picture: %s", 0x100+BUTTON_ADJUST) + HELP_LINK ("Flip picture menu: %s", 0x200+BUTTON_ADJUST) + HELP_LINK ("Effects menu: %s", 0x100+BUTTON_EFFECTS) + HELP_LINK ("Effects all off %s", SPECIAL_EFFECTS_OFF) + HELP_LINK ("Shade mode: %s", SPECIAL_SHADE_MODE) + HELP_LINK ("Shade menu: %s", SPECIAL_SHADE_MENU) + HELP_LINK ("Quick-shade mode: %s", SPECIAL_QUICK_SHADE_MODE) + HELP_LINK ("Quick-shade menu: %s", SPECIAL_QUICK_SHADE_MENU) + HELP_LINK ("Stencil mode: %s", SPECIAL_STENCIL_MODE) + HELP_LINK ("Stencil menu: %s", SPECIAL_STENCIL_MENU) + HELP_LINK ("Mask mode: %s", SPECIAL_MASK_MODE) + HELP_LINK ("Mask menu: %s", SPECIAL_MASK_MENU) + HELP_LINK ("Grid mode: %s", SPECIAL_GRID_MODE) + HELP_LINK ("Grid menu: %s", SPECIAL_GRID_MENU) + HELP_LINK ("Sieve mode: %s", SPECIAL_SIEVE_MODE) + HELP_LINK ("Sieve menu: %s", SPECIAL_SIEVE_MENU) + HELP_LINK ("Invert Sieve: %s", SPECIAL_INVERT_SIEVE) + HELP_LINK ("Colorize mode: %s", SPECIAL_COLORIZE_MODE) + HELP_LINK (" At opacity 10%%: %s", SPECIAL_TRANSPARENCY_1) + HELP_LINK (" At opacity 20%%: %s", SPECIAL_TRANSPARENCY_2) + HELP_LINK (" At opacity 30%%: %s", SPECIAL_TRANSPARENCY_3) + HELP_LINK (" At opacity 40%%: %s", SPECIAL_TRANSPARENCY_4) + HELP_LINK (" At opacity 50%%: %s", SPECIAL_TRANSPARENCY_5) + HELP_LINK (" At opacity 60%%: %s", SPECIAL_TRANSPARENCY_6) + HELP_LINK (" At opacity 70%%: %s", SPECIAL_TRANSPARENCY_7) + HELP_LINK (" At opacity 80%%: %s", SPECIAL_TRANSPARENCY_8) + HELP_LINK (" At opacity 90%%: %s", SPECIAL_TRANSPARENCY_9) + HELP_LINK (" At opacity 100%%: %s", SPECIAL_TRANSPARENCY_0) + HELP_LINK ("Colorize menu: %s", SPECIAL_COLORIZE_MENU) + HELP_LINK ("Smooth mode: %s", SPECIAL_SMOOTH_MODE) + HELP_LINK ("Smooth menu: %s", SPECIAL_SMOOTH_MENU) + HELP_LINK ("Smear mode: %s", SPECIAL_SMEAR_MODE) + HELP_LINK ("Tiling mode: %s", SPECIAL_TILING_MODE) + HELP_LINK ("Tiling menu: %s", SPECIAL_TILING_MENU) + HELP_LINK ("Pick brush: %s", 0x100+BUTTON_BRUSH) + HELP_LINK ("Pick polyform brush: %s", 0x100+BUTTON_POLYBRUSH) + HELP_LINK ("Restore brush: %s", 0x200+BUTTON_BRUSH) + HELP_LINK ("Flip brush X: %s", SPECIAL_FLIP_X) + HELP_LINK ("Flip brush Y: %s", SPECIAL_FLIP_Y) + HELP_LINK ("90° brush rotation: %s", SPECIAL_ROTATE_90) + HELP_LINK ("180° brush rotation: %s", SPECIAL_ROTATE_180) + HELP_LINK ("Stretch brush: %s", SPECIAL_STRETCH) + HELP_LINK ("Distort brush: %s", SPECIAL_DISTORT) + HELP_LINK ("Outline brush: %s", SPECIAL_OUTLINE) + HELP_LINK ("Nibble brush: %s", SPECIAL_NIBBLE) + 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) + HELP_LINK ("Pipette: %s", 0x100+BUTTON_COLORPICKER) + HELP_LINK ("Swap fore/back color:%s", 0x200+BUTTON_COLORPICKER) + HELP_LINK ("Magnifier mode: %s", 0x100+BUTTON_MAGNIFIER) + HELP_LINK ("Zoom factor menu: %s", 0x200+BUTTON_MAGNIFIER) + HELP_LINK ("Zoom in: %s", SPECIAL_ZOOM_IN) + HELP_LINK ("Zoom out: %s", SPECIAL_ZOOM_OUT) + HELP_LINK ("Brush effects menu: %s", 0x100+BUTTON_BRUSH_EFFECTS) + HELP_LINK ("Text: %s", 0x100+BUTTON_TEXT) + HELP_LINK ("Resolution menu: %s", 0x100+BUTTON_RESOL) + HELP_LINK ("Safety resolution: %s", 0x200+BUTTON_RESOL) + HELP_LINK ("Help: %s", 0x100+BUTTON_HELP) + HELP_LINK ("Statistics: %s", 0x200+BUTTON_HELP) + HELP_LINK ("Go to spare page: %s", 0x100+BUTTON_PAGE) + HELP_LINK ("Copy to spare page: %s", 0x200+BUTTON_PAGE) + HELP_LINK ("Save as: %s", 0x100+BUTTON_SAVE) + HELP_LINK ("Save: %s", 0x200+BUTTON_SAVE) + HELP_LINK ("Load: %s", 0x100+BUTTON_LOAD) + HELP_LINK ("Re-load: %s", 0x200+BUTTON_LOAD) + HELP_LINK ("Save brush: %s", SPECIAL_SAVE_BRUSH) + HELP_LINK ("Load brush: %s", SPECIAL_LOAD_BRUSH) + HELP_LINK ("Larger brush size: %s", SPECIAL_BIGGER_PAINTBRUSH) + HELP_LINK ("Smaller brush size: %s", SPECIAL_SMALLER_PAINTBRUSH) + HELP_LINK ("Settings: %s", 0x100+BUTTON_SETTINGS) + HELP_LINK ("Undo: %s", 0x100+BUTTON_UNDO) + HELP_LINK ("Redo: %s", 0x200+BUTTON_UNDO) + HELP_LINK ("Kill page: %s", 0x100+BUTTON_KILL) + HELP_LINK ("Clear: %s", 0x100+BUTTON_CLEAR) + HELP_LINK ("Clear with BG color: %s", 0x200+BUTTON_CLEAR) + HELP_LINK ("Quit: %s", 0x100+BUTTON_QUIT) + HELP_LINK ("Palette menu: %s", 0x100+BUTTON_PALETTE) + HELP_LINK ("2nd Palette menu: %s", 0x200+BUTTON_PALETTE) + HELP_LINK ("Exclude colors menu: %s", SPECIAL_EXCLUDE_COLORS_MENU) + HELP_TEXT ("") + HELP_TEXT ("Scroll palette") + HELP_LINK (" Back: %s", 0x100+BUTTON_PAL_LEFT) + HELP_LINK (" Forward: %s", 0x100+BUTTON_PAL_RIGHT) + HELP_LINK (" Back faster: %s", 0x200+BUTTON_PAL_LEFT) + HELP_LINK (" Forward faster: %s", 0x200+BUTTON_PAL_RIGHT) + HELP_TEXT ("") + HELP_TEXT ("Change brush attachement") + HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) + HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) + HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) + HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) + HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) + HELP_TEXT ("") + HELP_TEXT ("Select foreground color") + HELP_TEXT ("") + HELP_LINK (" Next : %s", SPECIAL_NEXT_FORECOLOR) + HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_FORECOLOR) + HELP_TEXT ("") + HELP_TEXT ("Select background color") + HELP_LINK (" Next : %s", SPECIAL_NEXT_BACKCOLOR) + HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_BACKCOLOR) + HELP_TEXT ("") + HELP_TEXT ("Select user-defined foreground color") + HELP_TEXT ("") + HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) + HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) + HELP_TEXT ("") + HELP_TEXT ("Select user-defined background color") + HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) + HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) + HELP_TEXT ("") +}; +static const T_Help_table helptable_credits[] = +{ +//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") + HELP_TITLE(" GRAFX2 IS CREATED BY") + HELP_TEXT ("") + HELP_BOLD (" SUNSET DESIGN") + HELP_BOLD (" AUTHORS OF GRAFX2.0 BETA 96.5%") + HELP_TEXT ("") + HELP_TEXT (" Guillaume Dorme alias \"Robinson\" (code)") + HELP_TEXT (" Karl Maritaud alias \"X-Man\" (code&gfx)") +//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") + HELP_TEXT ("") + HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") + HELP_TEXT ("") + HELP_BOLD (" THE GRAFX2 PROJECT TEAM") + HELP_TEXT ("") + HELP_TEXT (" Adrien Destugues (pulkomandy)") + HELP_TEXT (" Yves Rizoud (yrizoud)") + HELP_TEXT ("") + HELP_TEXT (" Got the source back to life in 2006") + HELP_TEXT ("") + HELP_BOLD (" ART") + HELP_TEXT ("") + HELP_TEXT (" GrafX2 logo by Made (www.m4de.com)") + HELP_TEXT (" Icons and fonts by X-Man ") + HELP_TEXT (" Additional graphics and logo by iLKke") + HELP_TEXT (" (ilkke.blogspot.com)") + HELP_TEXT ("") + HELP_TEXT (" Pixelled all the graphics") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE(" OTHER MACHINES PORTS") + HELP_TEXT ("") + HELP_BOLD (" AMIGA OS 3 PORT") + HELP_TEXT ("") + HELP_TEXT (" Artur Jarosik") + HELP_TEXT ("") + HELP_BOLD (" AMIGA OS 4 PORT") + HELP_TEXT ("") + HELP_TEXT (" Peter Gordon (www.petergordon.org.uk)") + HELP_TEXT ("") + HELP_BOLD (" AROS PORT") + HELP_TEXT ("") + HELP_TEXT (" Fernando Mastandrea (masta.uy)") + HELP_TEXT (" Markus Weiss") + HELP_TEXT ("") + HELP_BOLD (" FREEBSD PORT") + HELP_TEXT ("") + HELP_TEXT (" Jean-Baptiste Berlioz (Tobe)") + HELP_TEXT ("") + HELP_BOLD (" HAIKU OS AND BEOS PORT") + HELP_TEXT ("") + HELP_TEXT (" Luc Schrijvers (Begasus)") + HELP_TEXT ("") + HELP_BOLD (" MAC OS X PORT") + HELP_TEXT ("") + HELP_TEXT (" Franck Charlet (hitchhikr)") + HELP_TEXT (" Per Olofsson (MagerValp)") + HELP_TEXT ("") + HELP_BOLD (" MORPHOS PORT") + HELP_TEXT ("") + HELP_TEXT (" Rusback") + HELP_TEXT ("") + HELP_BOLD (" SKYOS PORT") + HELP_TEXT ("") + HELP_TEXT (" Luc Schrijvers (Begasus)") + HELP_TEXT ("") + HELP_TEXT (" ... made it work on your favourite toaster") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE(" BUGFINDERS") + HELP_TEXT ("") +//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") + HELP_TEXT (" blumunkee BDCIron Ced ") + HELP_TEXT (" El Topo fallenblood Frost ") + HELP_TEXT (" Grimmy Gürkan Sengün HoraK-FDF ") + HELP_TEXT (" iLKke Jamon keito ") + HELP_TEXT (" kusma Lord Graga MagerValp ") + HELP_TEXT (" mind MooZ the Peach ") + HELP_TEXT (" richienyhus tape.wyrm TeeEmCee ") + HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") + HELP_TEXT (" Tobé 00ai99 ") + HELP_TEXT ("") + HELP_TEXT (" ... posted the annoying bug reports.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE(" FILE FORMATS CREDITS") + HELP_TEXT ("") + HELP_TEXT (" BMP : Microsoft") + HELP_TEXT (" CEL,KCF : K.O.S. (KISekae Set system)") + HELP_TEXT (" GIF : Compuserve") + HELP_TEXT (" IMG : Bivas (W. Wiedmann?)") + HELP_TEXT (" LBM : Electronic Arts") + HELP_TEXT (" PAL : ermmh... nobody (?)") + HELP_TEXT (" PCX : Z-Soft") + HELP_TEXT (" PI1,PC1 : Degas Elite") + HELP_TEXT (" PKM : Sunset Design") + HELP_TEXT (" PNG : W3C") + HELP_TEXT (" SCx : Colorix (?)") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE (" OUR HOMEPAGE") + HELP_TEXT ("") + HELP_BOLD (" http://grafx2.codegoogle.com") + HELP_TEXT ("") + HELP_TEXT (" Please report any bug you may find there") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE (" GREETINGS") + HELP_TEXT ("") + HELP_TEXT (" To the Pouet.net BBS posters, the #CPC") + HELP_TEXT (" trolls and the bitfellas") + HELP_TEXT (" To every people who makes the scene alive!") + HELP_TEXT (" To all guys making nice pixelled pictures") + HELP_TEXT (" (with or without GrafX2)") + HELP_TEXT ("") + HELP_BOLD (" We send our best regards to...") + HELP_TEXT ("") + HELP_TEXT (" Access Filter Pink") + HELP_TEXT (" Ace Fiver Pixel") + HELP_TEXT (" AcidJam Flan Profil") + HELP_TEXT (" Acryl Fred Prowler") + HELP_TEXT (" Alexel FreddyV Puznik") + HELP_TEXT (" Alias Frost Quick") + HELP_TEXT (" Amiral Gaël(GDC) Ra") + HELP_TEXT (" Arrakis GainX Raster") + HELP_TEXT (" Avocado Gandalf Ravian") + HELP_TEXT (" Baloo Goblin RedBug") + HELP_TEXT (" Barti Greenpix7 Rem") + HELP_TEXT (" Bat Grid Rez") + HELP_TEXT (" Biro GrosQuick Roudoudou") + HELP_TEXT (" Bisounours HackerCroll Sacrilege") + HELP_TEXT (" BlackAxe Haplo Sam") + HELP_TEXT (" Bonnie Hof SandMan") + HELP_TEXT (" Boo Hornet Scape") + HELP_TEXT (" Boz Hulud Sébastien") + HELP_TEXT (" Carine Java Shodan") + HELP_TEXT (" Chandra JBT Skal") + HELP_TEXT (" Cheetah Jérôme Skyfire") + HELP_TEXT (" Chill Julien(JCA) Sphair") + HELP_TEXT (" Cougar KalMinDo Sprocket") + HELP_TEXT (" Cremax KaneWood Stef") + HELP_TEXT (" Cyclone Karma Stony") + HELP_TEXT (" Dake Keith303 Sumaleth") + HELP_TEXT (" Danny Lazur Sunday") + HELP_TEXT (" Danube LightShow Suny") + HELP_TEXT (" Darjul Lluvia Sybaris") + HELP_TEXT (" Darwin Louie TBF") + HELP_TEXT (" DarkAngel Luk Tempest") + HELP_TEXT (" Das Made Thor") + HELP_TEXT (" Decker Mamos TMK") + HELP_TEXT (" DerPiipo Mandrixx TwoFace") + HELP_TEXT (" Destop Mangue Underking") + HELP_TEXT (" Diabolo Mars Unreal") + HELP_TEXT (" DineS Mephisto VaeVictis") + HELP_TEXT (" Drac Mercure Vastator") + HELP_TEXT (" DrYes Mirec Vatin") + HELP_TEXT (" Edyx Moa Veckman") + HELP_TEXT (" Eller Moxica Wain") + HELP_TEXT (" Ellyn MRK Wally") + HELP_TEXT (" EOF Nitch WillBe") + HELP_TEXT (" Fall Noal Xoomie") + HELP_TEXT (" Fame Nytrik Xtrm") + HELP_TEXT (" Fantom Optic YannSulu") + HELP_TEXT (" Fear Orome Z") + HELP_TEXT (" Feather Pahladin Zeb") + HELP_TEXT (" Fennec Phar Zebig") + HELP_TEXT ("") + HELP_TEXT (" and all #pixel, #demofr and #coders.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE (" SNAIL MAIL") + HELP_TEXT ("") + HELP_TEXT (" (From 2001, current status: unknown)") + HELP_TEXT ("") + HELP_TEXT (" GUILLAUME DORME (Robinson)") + HELP_TEXT (" 15, rue de l'observatoire") + HELP_TEXT (" 87000 LIMOGES (FRANCE)") + HELP_TEXT ("") + HELP_TEXT (" KARL MARITAUD (X-Man)") + HELP_TEXT (" 10, rue de la Brasserie") + HELP_TEXT (" 87000 LIMOGES (FRANCE)") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE(" THANKS") + HELP_TEXT ("") + HELP_TEXT (" Some information taken from several docs") + HELP_TEXT (" (PCGPE, Intervue, PC Interdit...)") + HELP_TEXT (" gave us an invaluable help.") + HELP_TEXT ("") + HELP_TEXT (" Thanks to Shawn Hargreaves for his filled") + HELP_TEXT (" polygon routine from Allegro v2.2.") + HELP_TEXT ("") + HELP_TEXT (" Thanks to Carlos \"Made\" Pardo for his") + HELP_TEXT (" great GrafX2 logo.") + HELP_TEXT ("") + HELP_TEXT (" This is our very first program compiled") + HELP_TEXT (" with the Gnu C Compiler.") + HELP_TEXT (" A thousand thanks to the authors of") + HELP_TEXT (" this compiler.") + HELP_TEXT ("") + HELP_TEXT (" We also would like to thank all the") + HELP_TEXT (" people who gave us ideas to improve") + HELP_TEXT (" GrafX2.") + HELP_TITLE("") +}; +static const T_Help_table helptable_paintbrush[] = +{ + HELP_TITLE("PAINTBRUSHES") + HELP_TEXT ("") + HELP_BOLD (" LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_PAINTBRUSHES) + HELP_TEXT ("") + HELP_TEXT ("Displays a menu where you can choose the") + HELP_TEXT ("shape of your paintbrush.") + HELP_TEXT ("") + HELP_TEXT ("Paintbrushes are sorted by family. You can") + HELP_TEXT ("see some paintbrushes of the same family but") + HELP_TEXT ("with different sizes. There is at least one") + HELP_TEXT ("paint-brush from each family displayed in") + HELP_TEXT ("this menu.") + HELP_TEXT ("Here is the list of all the different") + HELP_TEXT ("paintbrush families:") + HELP_TEXT ("") + HELP_TEXT ("******* *** * * * * * * ") + HELP_TEXT ("******* ***** * * * * * * ") + HELP_TEXT ("******* ******* * * * * * * * * ") + HELP_TEXT ("******* ******* * * * * * * ") + HELP_TEXT ("******* ******* * * * * * * * * ") + HELP_TEXT ("******* ***** * * * * * * ") + HELP_TEXT ("******* *** * * * * * * ") + HELP_TEXT ("") + HELP_TEXT ("Square Disc Sieve Sieve ") + HELP_TEXT (" square disc ") + HELP_TEXT (" ") + HELP_TEXT (" * * * ") + HELP_TEXT (" *** * * * ") + HELP_TEXT (" ***** * * ") + HELP_TEXT ("******* ******* * ") + HELP_TEXT (" ***** * * * * ") + HELP_TEXT (" *** * ") + HELP_TEXT (" * * * * ") + HELP_TEXT (" ") + HELP_TEXT ("Diamond Random Horiz. Vertical") + HELP_TEXT (" bar bar ") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT (" * * * * *") + HELP_TEXT (" * * * * *") + HELP_TEXT (" * * * * *") + HELP_TEXT (" * * * *******") + HELP_TEXT (" * * * * *") + HELP_TEXT (" * * * * *") + HELP_TEXT ("* * * * *") + HELP_TEXT ("") + HELP_TEXT (" Slash Back- Cross X Cross +") + HELP_TEXT (" slash") + HELP_TEXT ("") + HELP_TEXT ("When using one of these, you can change the") + 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_BOLD (" RIGHT CLICK ") + HELP_LINK ("(Key:%s)",0x200+BUTTON_PAINTBRUSHES) + HELP_TEXT ("") + HELP_TEXT ("Transforms your current user-defined brush") + HELP_TEXT ("into a paintbrush. This is actually a") + HELP_TEXT ("\"monochromisation\" of your user-defined") + HELP_TEXT ("brush. This means that every color of the") + HELP_TEXT ("brush that aren't the Back-color will be") + HELP_TEXT ("set to the Fore-color. But this option") + HELP_TEXT ("doesn't alter the brush: you'll just have") + HELP_TEXT ("to right-click on the \"Get brush\" buttons") + HELP_TEXT ("to get your brush back.") + HELP_TEXT ("") + HELP_TEXT ("Note: When you press (not in the menu) the") + HELP_LINK ("key %s, the current",SPECIAL_DOT_PAINTBRUSH) + HELP_TEXT ("paintbrush becomes the smallest member of") + HELP_TEXT ("the \"Disc\" family: i.e one pixel.") + +}; +static const T_Help_table helptable_adjust[] = +{ + HELP_TITLE("ADJUST OR TRANSFORM") + HELP_TITLE(" PICTURE") + HELP_TEXT ("") + HELP_BOLD (" LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_ADJUST) + HELP_TEXT ("") + HELP_TEXT ("Allows you to scroll the picture to") + HELP_TEXT ("re-center your graph for example.") + HELP_TEXT ("") + HELP_TEXT ("Any part of the picture that goes out of") + HELP_TEXT ("the image by a side comes back by the") + HELP_TEXT ("opposite one.") + HELP_TEXT ("") + HELP_TEXT ("It is assimilated to the drawing tools") + HELP_TEXT ("family.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_BOLD (" RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_ADJUST) + HELP_TEXT ("") + HELP_TEXT ("Opens the Picture Transform menu.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("PICTURE TRANSFORM") + HELP_TEXT ("") + HELP_BOLD ("RESCALE") + HELP_TEXT ("") + HELP_TEXT ("Allows you to change the image's size,") + HELP_TEXT ("rescaling it accordingly. Enter new size") + HELP_TEXT ("and press RESIZE to confirm.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("When 'Lock proportions' is checked and you") + HELP_TEXT ("change one dimension, the other one is") + HELP_TEXT ("automatically adjusted to preserve the") + HELP_TEXT ("proportions of the original image.") + HELP_TEXT ("") + HELP_TEXT ("You can use the dropdown button to choose") + HELP_TEXT ("between three ways to enter the dimensions:") + HELP_TEXT ("") + HELP_TEXT ("In 'Pixels' mode, the column 'old' shows") + HELP_TEXT ("the original dimensions, and you can set") + HELP_TEXT ("the new size in pixels.") + HELP_TEXT ("") + HELP_TEXT ("In 'Percent' mode, you set a percentage") + HELP_TEXT ("compared to the original image.") + HELP_TEXT ("") + HELP_TEXT ("In 'Ratio' mode, you can set 2 numbers for") + HELP_TEXT ("each dimension, and the resizing factor will") + HELP_TEXT ("be of 'new'÷'old'. For example you can use") + HELP_TEXT ("1:3 to divide the image by three, 2:1 to") + HELP_TEXT ("double it, and any fraction like 15:16.") + HELP_TEXT ("") + HELP_TEXT ("Be careful that moving from one mode to the") + HELP_TEXT ("next can lose precision, if the selected") + HELP_TEXT ("dimensions cannot be represented exactly in") + HELP_TEXT ("the new mode.") + HELP_TEXT ("") + HELP_BOLD ("MIRROR") + HELP_TEXT ("") + HELP_TEXT ("- X: Flip the picture horizontally.") + HELP_TEXT ("") + HELP_TEXT ("- Y: Flip the picture vertically.") + HELP_TEXT ("") + HELP_BOLD ("ROTATE") + HELP_TEXT ("") + HELP_TEXT ("-90°: Rotates the image by 90°") + HELP_TEXT (" clockwise.") + HELP_TEXT ("") + HELP_TEXT ("+90°: Rotates the image by 90°") + HELP_TEXT (" counter-clockwise.") + HELP_TEXT ("180°: Rotates the image by 180°") + HELP_TEXT ("") + HELP_TEXT ("") +}; +static const T_Help_table helptable_draw[] = +{ + HELP_TITLE("HAND-DRAWING") + HELP_TEXT ("") + HELP_BOLD (" LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_DRAW) + HELP_TEXT ("") + HELP_TEXT ("Selects the current hand-drawing mode as the") + HELP_TEXT ("active drawing tool. There are 4") + HELP_TEXT ("hand-drawing modes:") + HELP_TEXT ("") + HELP_TEXT ("Continuous hand-drawing: as you move the") + HELP_TEXT ("mouse, the paintbrush is regularily pasted") + HELP_TEXT ("on the picture. This drawing tool allows to") + HELP_TEXT ("change the fore and back colors when being") + HELP_TEXT ("in use.") + HELP_TEXT ("") + HELP_TEXT ("Discontinuous hand-drawing: as you move the") + HELP_TEXT ("mouse, the paintbrush is pasted on the") + HELP_TEXT ("picture every time a delay is passed") + HELP_TEXT ("(actually, the delay is 1 VBL") + HELP_TEXT ("(vertical blanking)). This drawing tool") + HELP_TEXT ("allows to change the fore and back colors") + HELP_TEXT ("when being in use.") + HELP_TEXT ("") + HELP_TEXT ("Dot by dot hand-drawing: the paintbrush is") + HELP_TEXT ("only pasted at the position where you first") + HELP_TEXT ("clicked.") + HELP_TEXT ("") + HELP_TEXT ("Contour fill: Draws pixels like continuous") + HELP_TEXT ("mode, but when you release the button Grafx2") + HELP_TEXT ("draws a line back to your starting position,") + HELP_TEXT ("and fills the area. This tool doesn't use the") + HELP_TEXT ("current brush, but single pixels.") + HELP_TEXT ("") + HELP_BOLD (" RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_DRAW) + HELP_TEXT ("") + HELP_TEXT ("Toggles the different hand-drawing modes") + HELP_TEXT ("and activates, at the same time, the") + HELP_TEXT ("hand-drawing tool.") +}; +static const T_Help_table helptable_curves[] = +{ + HELP_TITLE("SPLINES") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_CURVES) + HELP_TEXT ("") + HELP_TEXT ("Selects the current curve-drawing mode as") + HELP_TEXT ("the active drawing tool. There are 2") + HELP_TEXT ("different curve-drawing modes:") + HELP_TEXT ("") + HELP_TEXT ("* 4 control points curves: define the basic") + HELP_TEXT ("line like a classical line, then move, with") + HELP_TEXT ("the left mouse button, the inner control") + HELP_TEXT ("points to choose the shape of your curve.") + HELP_TEXT ("When the curve has the shape you want, click") + HELP_TEXT ("with the right mouse button to draw it") + HELP_TEXT ("definitively.") + HELP_TEXT ("") + HELP_TEXT ("* 3 control points curves: the same as") + HELP_TEXT ("above, but you'll have only one inner") + HELP_TEXT ("control point to place. Moreover, the spline") + HELP_TEXT ("will be traced just after placing this") + HELP_TEXT ("point.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_CURVES) + HELP_TEXT ("") + HELP_TEXT ("Toggles the different curve-drawing modes") + HELP_TEXT ("and activates, at the same time, the") + HELP_TEXT ("curve-drawing tool.") +}; +static const T_Help_table helptable_lines[] = +{ + HELP_TITLE("LINES") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_LINES) + HELP_TEXT ("") + HELP_TEXT ("Selects the current line-drawing mode as the") + HELP_TEXT ("active drawing tool. There are 3") + HELP_TEXT ("line-drawing modes:") + HELP_TEXT ("") + HELP_TEXT ("* Classical lines: when first clicking on") + HELP_TEXT ("the picture, you'll define the start of the") + HELP_TEXT ("line. Maintain your click to choose the end") + HELP_TEXT ("of the line and release the mouse button to") + HELP_TEXT ("set it.") + HELP_TEXT ("If you hold SHIFT when drawing, the line") + HELP_TEXT ("will be constrained to horizonal, vertical") + HELP_TEXT ("or diagonal.") + HELP_TEXT ("") + HELP_TEXT ("* Knotted lines: works like classical lines,") + HELP_TEXT ("but the end of your line will automatically") + HELP_TEXT ("become the start of the next one. When you") + HELP_TEXT ("want to stop chaining lines, use the") + HELP_TEXT ("opposite mouse button. \"The opposite button\"") + HELP_TEXT ("means that if you started to draw lignes") + HELP_TEXT ("with the left button (Fore-color), you'll") + HELP_TEXT ("have to stop the procedure with the right") + HELP_TEXT ("button; and conversely.") + HELP_TEXT ("") + HELP_TEXT ("* Concentric lines: when first clicking on") + HELP_TEXT ("the picture, you'll define center of the") + HELP_TEXT ("lines. In fact, the center is defined by the") + HELP_TEXT ("the position of the mouse when you release") + HELP_TEXT ("the mouse button. Then you can draw lines") + HELP_TEXT ("from the center to the current mouse") + HELP_TEXT ("position by clicking. To stop drawing") + HELP_TEXT ("concentric lines, use the opposite mouse") + HELP_TEXT ("button. This drawing tool allows to change") + HELP_TEXT ("the fore and back colors when being in use.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_LINES) + HELP_TEXT ("") + HELP_TEXT ("Toggles the different line-drawing modes and") + HELP_TEXT ("activates, at the same time, the") + HELP_TEXT ("line-drawing tool.") + +}; +static const T_Help_table helptable_airbrush[] = +{ + HELP_TITLE("SPRAY") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_AIRBRUSH) + HELP_TEXT ("") + HELP_TEXT ("Selects the spray as the active drawing") + HELP_TEXT ("tool. This drawing tool allows to change the") + HELP_TEXT ("fore and back colors when being in use.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_AIRBRUSH) + HELP_TEXT ("") + HELP_TEXT ("Displays a menu where you can configure the") + HELP_TEXT ("spray:") + HELP_TEXT ("") + HELP_TEXT ("- Size: Defines the diameter of the circle") + HELP_TEXT ("in which will effectively fit the spray.") + HELP_TEXT ("") + HELP_TEXT ("- Delay: Defines the number of VBLs that") + HELP_TEXT ("will be waited for between two flows of") + HELP_TEXT ("spray.") + HELP_TEXT ("") + HELP_TEXT ("- Mode: Defines whether you want to use a") + HELP_TEXT ("monochrome spray or a multi- colored one.") + HELP_TEXT ("") + HELP_TEXT ("- Mono-flow: Defines the number of") + HELP_TEXT ("paintbrushes that will be pasted in the") + HELP_TEXT ("circle of the spray at each cycle.") + HELP_TEXT ("") + HELP_TEXT ("- Palette: Left-click on a color of the") + HELP_TEXT ("palette to see how much it will be used in") + HELP_TEXT ("the multicolored flow, and modify it by") + HELP_TEXT ("using the gauge on the right. If the flow of") + HELP_TEXT ("this color was equal to 0, then the \"Init\"") + HELP_TEXT ("value will be applied. Or set the flow of a") + HELP_TEXT ("color to 0 by clicking on it with the right") + HELP_TEXT ("mouse button.") + HELP_TEXT ("") + HELP_TEXT ("- Clear: Removes all the colors from the") + HELP_TEXT ("multicolored flow. Actually, this puts a 0") + HELP_TEXT ("value in the use of each color.") + HELP_TEXT ("") + HELP_TEXT ("- Init: Allows you to define a value that") + HELP_TEXT ("will be set to the color you click on in the") + HELP_TEXT ("palette if its value is equal to 0. This") + HELP_TEXT ("permits to tag a set of colors more quickly.") + HELP_TEXT ("") + HELP_TEXT ("- +1,-1,x2,/2: Modify the values of all the") + HELP_TEXT ("tagged colors (and only them).") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("Tip: If you often use the Shade mode, and") + HELP_TEXT ("are bored to click many times on a color to") + HELP_TEXT ("reach the color you want, you can define a") + HELP_TEXT ("spray with \"Size\"=1, \"Mono-flow\"=1, and") + HELP_TEXT ("\"Delay\"=2 (or more, according to your") + HELP_TEXT ("reflexes). And then, you'll just have to") + HELP_TEXT ("click a few hundredths of second to modify a") + HELP_TEXT ("color.") +}; +static const T_Help_table helptable_floodfill[] = +{ + HELP_TITLE("FLOODFILL") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_FLOODFILL) + HELP_TEXT ("") + HELP_TEXT ("Selects the filler as the active drawing") + HELP_TEXT ("tool. The filler, as any drawing tool, will") + HELP_TEXT ("be affected by all the effects!") + HELP_TEXT ("") + HELP_TEXT ("Note that only the visible part of the") + HELP_TEXT ("picture will be filled (as every other") + HELP_TEXT ("drawing tools, the floodfill only alters the") + HELP_TEXT ("visible part of the picture; this avoids") + HELP_TEXT ("unwanted effects that wouldn't be controlled") + HELP_TEXT ("by the user).") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_FLOODFILL) + HELP_TEXT ("") + HELP_TEXT ("Selects the color replacement as the active") + HELP_TEXT ("drawing tool.") + HELP_TEXT ("") + HELP_TEXT ("Any rule has its exceptions and this one") + HELP_TEXT ("doesn't depart from that. Indeed, this tool") + HELP_TEXT ("is the only one to be affected by no effect") + HELP_TEXT ("(except Stencil) and to be able to modify") + HELP_TEXT ("non visible parts of the picture.") + HELP_TEXT ("The function of this tool being replacing") + HELP_TEXT ("all the occurences of a color in the picture") + HELP_TEXT ("by another, if would have been a shame to") + HELP_TEXT ("limit modifications only to the visible part") + HELP_TEXT ("of the picture.") +}; +static const T_Help_table helptable_polygons[] = +{ + HELP_TITLE("POLYGONS") + HELP_TITLE("POLYFORMS") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYGONS) + HELP_TEXT ("") + HELP_TEXT ("Selects the polygons as the active drawing") + HELP_TEXT ("tool.") + HELP_TEXT ("") + HELP_TEXT ("This works just like knotted-lines but loops") + HELP_TEXT ("the extremities when you're finished.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYGONS) + HELP_TEXT ("") + HELP_TEXT ("Selects the polyforms as the active drawing") + HELP_TEXT ("tool.") + HELP_TEXT ("") + HELP_TEXT ("This works like a combination of free-hand") + HELP_TEXT ("drawing and knotted-lines. If you keep the") + HELP_TEXT ("mouse button pressed, you'll draw as if you") + HELP_TEXT ("were in free-hand drawing mode. And, if you") + HELP_TEXT ("release the mouse button, it will work like") + HELP_TEXT ("knotted lines.") + HELP_TEXT ("") + HELP_TEXT ("Click on the opposite mouse button (i.e.:") + HELP_TEXT ("click right if you started to draw with the") + HELP_TEXT ("left mouse button, and vice versa) to") + HELP_TEXT ("terminate the operation. The two extremities") + HELP_TEXT ("will be linked automatically.") +}; +static const T_Help_table helptable_polyfill[] = +{ + HELP_TITLE("FILLED POLY") + HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYFILL) + HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYFILL) + HELP_TEXT (" Work exactly the same way as the polygons") + HELP_TEXT ("et polyforms above, but fill in the interior") + HELP_TEXT ("of the drawn shapes.") +}; +static const T_Help_table helptable_rectangles[] = +{ + HELP_TITLE("RECTANGLES") + HELP_LINK ("(Key:%s)",0x100+BUTTON_RECTANGLES) + HELP_TEXT ("") + HELP_TEXT ("Selects the empty rectangles as the active") + HELP_TEXT ("drawing tool.") + HELP_TEXT ("") + HELP_TEXT ("Set a corner of a rectangle. Maintain the") + HELP_TEXT ("click to move the opposite corner and") + HELP_TEXT ("release the mouse button to set it") + HELP_TEXT ("definitively.") +}; +static const T_Help_table helptable_filled_rectangles[] = +{ + HELP_TITLE("FILLED RECT") + HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLRECT) + HELP_TEXT ("") + HELP_TEXT ("Selects the filled rectangles as the active") + HELP_TEXT ("drawing tool.") + HELP_TEXT ("") + HELP_TEXT ("Works like an empty rectangle.") +}; +static const T_Help_table helptable_circles[] = +{ + HELP_TITLE("CIRCLES") + HELP_TITLE("ELLIPSES") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_CIRCLES) + HELP_TEXT ("") + HELP_TEXT ("Selects the empty circles as the active") + HELP_TEXT ("drawing tool.") + HELP_TEXT ("") + HELP_TEXT ("Position the center of the cercle and") + HELP_TEXT ("maintain the mouse button to select its") + HELP_TEXT ("radius.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_CIRCLES) + HELP_TEXT ("") + HELP_TEXT ("Selects the empty ellipses as the active") + HELP_TEXT ("drawing tool.") + HELP_TEXT ("") + HELP_TEXT ("Position the center of the cercle and") + HELP_TEXT ("maintain the mouse button to select its") + HELP_TEXT ("dimensions.") +}; +static const T_Help_table helptable_filled_circles[] = +{ + HELP_TITLE("FILLED CIRCLES") + HELP_TITLE(" AND ELLIPSES") + HELP_TEXT ("") + HELP_BOLD ("FILLED CIRCLES") + HELP_LINK ("(Key:%s)",0x100+BUTTON_CIRCLES) + HELP_TEXT ("") + HELP_TEXT ("Works like empty circles.") + HELP_TEXT ("") + HELP_BOLD ("FILLED ELLIPSES") + HELP_LINK ("(Key:%s)",0x200+BUTTON_CIRCLES) + HELP_TEXT ("") + HELP_TEXT ("Works like empty ellipses.") +}; +static const T_Help_table helptable_grad_rect[] = +{ + HELP_TITLE("GRAD RECTANGLE") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_GRADRECT) + HELP_TEXT ("") + HELP_TEXT ("Selects the rectangle with gradations as") + HELP_TEXT ("the active drawing tool.") + HELP_TEXT ("") + HELP_TEXT ("Set a corner of a rectangle. Maintain the") + HELP_TEXT ("click to move the opposite corner and") + HELP_TEXT ("release the mouse button to set it") + HELP_TEXT ("definitively.") + HELP_TEXT ("") + HELP_TEXT ("If you don't like what you have done and") + HELP_TEXT ("want to restart, you can use the right") + HELP_TEXT ("click to cancel everything at this point.") + HELP_TEXT (" If you think it's nice, then click and hold") + HELP_TEXT ("the mouse in a point you want to have the") + HELP_TEXT ("starting color, drag to a point where you") + HELP_TEXT ("want the ending color, and release the") + HELP_TEXT ("button. You can press SHIFT to enforce your") + HELP_TEXT ("line to be vertical, horizontal, or") + HELP_TEXT ("diagonal.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_GRADRECT) + HELP_TEXT ("") + HELP_TEXT ("Opens a window where you can define the way") + HELP_TEXT ("gradations are processed. The different") + HELP_TEXT ("sections of this menu are:") + HELP_TEXT ("") + HELP_TEXT ("- Direction (arrow): Switches the direction") + HELP_TEXT ("of the gradation.") + HELP_TEXT ("") + HELP_TEXT ("- Dithering method: Toggles the 3 following") + HELP_TEXT ("methods:") + HELP_TEXT (" - No dithering") + HELP_TEXT (" - Basical dithering") + HELP_TEXT (" - Enhanced dithering") + HELP_TEXT ("") + HELP_TEXT ("- Mix: Mixes the gradation with a more or") + HELP_TEXT ("less random factor.") + HELP_TEXT ("") + HELP_TEXT ("- Palette: Select a color range to build a") + HELP_TEXT ("gradation.") + HELP_TEXT ("") + HELP_TEXT ("- Index scroller: Defines the current") + HELP_TEXT ("gradation among a set of 16 that will be") + HELP_TEXT ("memorised.") +}; +static const T_Help_table helptable_spheres[] = +{ + HELP_TITLE("GRAD SPHERE") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_SPHERES) + HELP_TEXT ("") + HELP_TEXT ("Selects the spheres as the active drawing") + HELP_TEXT ("tool.") + HELP_TEXT ("") + HELP_TEXT ("Position the center of the sphere and") + HELP_TEXT ("maintain the mouse button to select its") + HELP_TEXT ("radius. Then place the spot-light.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_SPHERES) + HELP_TEXT ("") + HELP_TEXT ("Selects the ellipses with gradation as the") + HELP_TEXT ("active drawing tool.") + HELP_TEXT ("") + HELP_TEXT ("Draw the shape like a normal ellipse, and") + HELP_TEXT ("then position the spot-light and click the") + HELP_TEXT ("left mouse button to finish the shape.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("If you trace a sphere or an ellipse with") + HELP_TEXT ("gradation with the right mouse button, the") + HELP_TEXT ("result will be the same figure filled with") + HELP_TEXT ("the Back-color.") +}; +static const T_Help_table helptable_brush[] = +{ + HELP_TITLE("GRAB BRUSH") + HELP_BOLD (" OR RESTORE BRUSH") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH) + HELP_TEXT ("") + HELP_TEXT ("Engages a brush grabbing.") + HELP_TEXT ("") + HELP_TEXT ("Click on a corner of the rectangle") + HELP_TEXT ("containing the brush then maintain the click") + HELP_TEXT ("to define the opposite corner of the") + HELP_TEXT ("rectangle. Release the mouse button to grab") + HELP_TEXT ("the brush. Performing this operation with") + HELP_TEXT ("the right mouse button will erase the area") + HELP_TEXT ("where the brush was grabbed with the") + HELP_TEXT ("Back-color.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) + HELP_TEXT ("") + HELP_TEXT ("Restores the old brush.") +}; +static const T_Help_table helptable_polybrush[] = +{ + HELP_TITLE("POLY GRAB") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYBRUSH) + HELP_TEXT ("") + HELP_TEXT ("Grabs a brush of any shape by defining a") + HELP_TEXT ("polyform (please refer to section 8 for more") + HELP_TEXT ("explanations).") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) + HELP_TEXT ("") + HELP_TEXT ("Restores the old brush (same as above).") +}; +static const T_Help_table helptable_brush_fx[] = +{ + HELP_TITLE("BRUSH FX") + HELP_TEXT ("") + HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH_EFFECTS) + HELP_TEXT ("") + HELP_TEXT ("Displays a menu where the following options") + HELP_TEXT ("are available:") + HELP_TEXT ("") + HELP_LINK ("- X: (Key:%s)",SPECIAL_FLIP_X) + HELP_TEXT ("Flip horizontally.") + HELP_TEXT ("") + HELP_LINK ("- Y: (Key:%s)",SPECIAL_FLIP_Y) + HELP_TEXT ("Flip vertically.") + HELP_TEXT ("") + HELP_LINK ("- Rotate by 90°: (Key:%s)",SPECIAL_ROTATE_90) + HELP_TEXT ("Rotates the brush by an angle of 90 degrees.") + HELP_TEXT ("") + HELP_LINK ("- Rotate by 180°: (Key:%s)",SPECIAL_ROTATE_180) + HELP_TEXT ("Rotates the brush by an angle of 180") + HELP_TEXT ("degrees.") + HELP_TEXT ("") + HELP_TEXT ("- Rotate by any angle:") + HELP_LINK ("(Key:%s)",SPECIAL_ROTATE_ANY_ANGLE) + HELP_TEXT ("Triggers an interactive operation that") + HELP_TEXT ("allows you to rotate the brush. For this,") + HELP_TEXT ("start by placing the center or rotation with") + HELP_TEXT ("the left mouse button (if, at this moment,") + HELP_TEXT ("you press the right button, the operation") + HELP_TEXT ("with be cancelled). After that, you can") + HELP_TEXT ("define the angle of rotation as many times") + HELP_TEXT ("as you want by moving the mouse and") + HELP_TEXT ("left-clicking. Then validate with the right") + HELP_TEXT ("button when you are satisfied. Meanwhile,") + HELP_TEXT ("you can press on the 8 outer digits of the") + HELP_TEXT ("numeric pad for defining angles multiple of") + HELP_TEXT ("45 degrees:") + HELP_TEXT ("") + HELP_TEXT (" 135 90 45") + HELP_TEXT (" \\ | /") + HELP_TEXT (" '7' '8' '9'") + HELP_TEXT (" 180 -'4' '6'- 0") + HELP_TEXT (" '1' '2' '3'") + HELP_TEXT (" / | \\") + HELP_TEXT (" 225 270 315") + HELP_TEXT ("") + HELP_LINK ("- Stretch: (Key:%s)",SPECIAL_STRETCH) + HELP_TEXT ("Triggers an interactive operation") + HELP_TEXT ("that enables you to stretch the brush. For") + HELP_TEXT ("this, start by placing the upper-left") + HELP_TEXT ("cornerof the brush with the left mouse") + HELP_TEXT ("button (if, at this moment, you press the") + HELP_TEXT ("right button, the operation will be") + HELP_TEXT ("cancelled). after that, you can place the") + HELP_TEXT ("opposite corner as many times as you need,") + HELP_TEXT ("then validate with the right mouse button") + HELP_TEXT ("when you are satisfied. If you place this") + 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 ("") + HELP_LINK ("- Distort: (Key:%s)",SPECIAL_DISTORT) + HELP_TEXT ("Triggers an interactive operation") + HELP_TEXT ("that allows you to distort your brush.") + HELP_TEXT ("Start by placing the brush somewhere on the") + HELP_TEXT ("screen and left-click. The brush will") + HELP_TEXT ("appear, with a little peg at each corner.") + HELP_TEXT ("Use the left mouse button to displace the") + HELP_TEXT ("corners, which will deform the brush.") + HELP_TEXT ("When you're done, click the right mouse") + HELP_TEXT ("button.") + HELP_TEXT ("") + HELP_LINK ("- Outline: (Key:%s)",SPECIAL_OUTLINE) + HELP_TEXT ("This option permits to draw the") + HELP_TEXT ("outlines of the brush with the Fore- color.") + HELP_TEXT ("") + HELP_LINK ("- Nibble: (Key:%s)",SPECIAL_NIBBLE) + HELP_TEXT ("This option \"nibbles\" the outlines") + HELP_TEXT ("of the brush. It's in some way the opposite") + HELP_TEXT ("effect of the Outline option.") + HELP_TEXT ("") + HELP_LINK ("- Recolorize: (Key:%s)",SPECIAL_RECOLORIZE_BRUSH) + HELP_TEXT ("Remaps the brush so that it") + HELP_TEXT ("looks like it would in the spare page, using") + HELP_TEXT ("the current palette.") + HELP_TEXT ("") + HELP_LINK ("- Get brush colors: (Key:%s)",SPECIAL_GET_BRUSH_COLORS) + HELP_TEXT ("Transfers the spare") + HELP_TEXT ("page's colors used by the brush to the") + HELP_TEXT ("current palette.") + HELP_TEXT ("") + HELP_TEXT ("- Brush handle:") + HELP_TEXT ("Allows you to choose where to place the") + HELP_TEXT ("handle of the brush. Shortcuts are :") + HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) + HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) + HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) + HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) + HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) + HELP_TEXT ("") + HELP_LINK ("- Load : (Key:%s)",SPECIAL_LOAD_BRUSH) + HELP_TEXT ("Load a brush from disk.") + HELP_TEXT ("") + HELP_LINK ("- Save : (Key:%s)",SPECIAL_SAVE_BRUSH) + HELP_TEXT ("Save a brush to disk.") +}; +static const T_Help_table helptable_effects[] = +{ + HELP_TITLE("DRAW MODES") + HELP_LINK ("(Key:%s)",0x100+BUTTON_EFFECTS) + HELP_TEXT ("") + HELP_TEXT (" This button opens a menu where you can") + HELP_TEXT ("switch on or off the different drawing") + HELP_TEXT ("modes.") + HELP_TEXT (" In this menu, the \"All off\" button switches") + HELP_TEXT ("all the drawing modes off. The [Del] key") + HELP_TEXT ("is the keyboard shortcut for this button.") + HELP_TEXT (" The \"Feedback\" button is only used in") + HELP_TEXT ("\"Shade\", \"Quick-shade, \"Transparency\"") + HELP_TEXT ("and \"Smooth\" modes. When it is set, it means") + HELP_TEXT ("that the _current_ state of the picture") + HELP_TEXT ("has to be taken into account for the effect") + HELP_TEXT ("instead of the state in which the image") + HELP_TEXT ("was when you started to click for drawing.") + HELP_TEXT ("The best, as often, is that you try by") + HELP_TEXT ("yourself with and without Feedback to see") + HELP_TEXT ("the difference.") + HELP_TEXT (" The other buttons are the following:") + HELP_TEXT ("") + HELP_TITLE("SHADE") + HELP_TEXT (" It consists in increasing or decreasing the") + HELP_TEXT ("color number within a user-defined range.") + HELP_TEXT ("This shows its real dimension when used with") + HELP_TEXT ("a range of colors that shade off. Then,") + HELP_TEXT ("you can work on a part of your picture where") + HELP_TEXT ("colors belong to the same range without") + HELP_TEXT ("having to change your brush color all the") + HELP_TEXT ("time. You can choose the incrementation or") + HELP_TEXT ("decrementation of the color by pressing") + HELP_TEXT ("the left or right mouse button while") + HELP_TEXT ("drawing. If you click on a color that does") + HELP_TEXT ("not belong to the range, it will remain") + HELP_TEXT ("unchanged.") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key : %s)", SPECIAL_SHADE_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Shade mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_SHADE_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can define one table") + HELP_TEXT ("of shades within a range of 8 memorised by") + HELP_TEXT ("the program. The different sections of this") + HELP_TEXT ("menu are:") + HELP_TEXT ("") + HELP_TEXT ("- Palette: You can define in it the color") + HELP_TEXT ("blocks that will be inserted") + HELP_TEXT ("into the table of shades.") + HELP_TEXT ("") + HELP_TEXT ("- Scroller: Used to change flick through the") + HELP_TEXT ("tables of shades.") + HELP_TEXT ("") + HELP_TEXT ("- Table of shades definition area: The 512") + HELP_TEXT ("squares should be widely") + HELP_TEXT ("sufficient to define the different shades") + HELP_TEXT ("since every 256 colors of") + HELP_TEXT ("the palette cannot be present more than once") + HELP_TEXT ("in each table.") + HELP_TEXT ("") + HELP_TEXT ("- A window (on the top-right side) permits") + HELP_TEXT ("to visualize the different") + HELP_TEXT ("shades defined in he current table.") + HELP_TEXT ("") + HELP_TEXT ("- Copy: Copy the contents of the table in a") + HELP_TEXT ("buffer.") + HELP_TEXT ("(Each time you open this menu, the current") + HELP_TEXT ("table is automatically") + HELP_TEXT ("transfered into this buffer).") + HELP_TEXT ("") + HELP_TEXT ("- Paste: Copy the contents of the buffer") + HELP_TEXT ("above in the current table.") + HELP_TEXT ("") + HELP_TEXT ("- Clear: Reset the \"shades\" table.") + HELP_TEXT ("") + HELP_TEXT ("- Insert: Used to insert the block selected") + HELP_TEXT ("in the palette at the") + HELP_TEXT ("cursor's position in the table of shades.") + HELP_TEXT ("IF you click with the left mouse button on") + HELP_TEXT ("this button THEN IF a block of more than one") + HELP_TEXT ("color is selected in the table THEN It is") + HELP_TEXT ("deleted and the block defined in the palette") + HELP_TEXT ("is inserted. ELSE The block defined in the") + HELP_TEXT ("palette is inserted at the postion just") + HELP_TEXT ("before the selected square. END IF") + HELP_TEXT ("ELSE The block defined in the palette is") + HELP_TEXT ("inserted by erasing the colors following the") + HELP_TEXT ("beginning of the bloc selected in the table.") + HELP_TEXT ("END IF") + HELP_TEXT ("") + HELP_TEXT ("- Delete: Delete the block selected in the") + HELP_TEXT ("table.") + HELP_TEXT ("") + HELP_TEXT ("- Blank: Follows this algorithm:") + HELP_TEXT ("IF you click with the left mouse button on") + HELP_TEXT ("this button THEN Replace the block selected") + HELP_TEXT ("in the table by blank squares.") + HELP_TEXT ("ELSE IF a block of more than one color is") + HELP_TEXT ("selected in the table THEN Insert blank") + HELP_TEXT ("squares to the left and to the right of the") + HELP_TEXT ("block. (this is useful for isolating a") + HELP_TEXT ("shade quickly) ELSE Insert blank squares") + HELP_TEXT ("to the left of the selected square. END IF") + HELP_TEXT ("END IF") + HELP_TEXT ("") + HELP_TEXT ("- Invert: Invert the order of the block") + HELP_TEXT ("selected in the table.") + HELP_TEXT ("") + HELP_TEXT ("- Swap: Allows you you move a block (this") + HELP_TEXT ("exchanges it with what is") + HELP_TEXT ("where you want to move it).") + HELP_TEXT ("") + HELP_TEXT ("- Undo: Cancel the last modification of the") + HELP_TEXT ("table.") + HELP_TEXT ("") + HELP_TEXT ("- The 2 numbers displayed on the right of") + HELP_TEXT ("these buttons are: (above) - the number of") + HELP_TEXT ("the color selected in the palette if only") + HELP_TEXT ("one color is selected. (below) - the number") + HELP_TEXT ("of the color contained in a square in the") + HELP_TEXT ("shades table if this square is the only one") + HELP_TEXT ("selected.") + HELP_TEXT ("") + HELP_TEXT ("- The \"mode\" button displays 3 different") + HELP_TEXT ("modes:") + HELP_TEXT ("\"Normal\": Shades in the range and saturates") + HELP_TEXT ("to its boundaries.") + HELP_TEXT ("\"Loop\": Shades in the range and loops if") + HELP_TEXT ("boundaries are passed.") + HELP_TEXT ("\"No saturation\": Shades in the range and") + HELP_TEXT ("doesn't saturate if boundaries are passed.") + HELP_TEXT ("If the Step (see below) is set to 1, this") + HELP_TEXT ("option does exactly the same as the Normal") + HELP_TEXT ("mode.") + HELP_TEXT ("") + HELP_TEXT ("- Set/Disable: If you want to define several") + HELP_TEXT ("shades in the same table") + HELP_TEXT ("but you'd like these shades not to be") + HELP_TEXT ("effective at the same time, you") + HELP_TEXT ("can mask (disable) some parts of the table") + HELP_TEXT ("so that they will be") + HELP_TEXT ("interpreted a blank squares.") + HELP_TEXT ("To do that, select a block in the table of") + HELP_TEXT ("shades and click on \"Set\".") + HELP_TEXT ("The block will be underlined with a white") + HELP_TEXT ("line; this means that it is") + HELP_TEXT ("disabled.") + HELP_TEXT ("") + HELP_TEXT ("- Clear/Enable: This does exactly the") + HELP_TEXT ("opposite as the button above.") + HELP_TEXT ("") + HELP_TEXT ("- Step: Defines the step of incrementation") + HELP_TEXT ("of the shade. The bigger,") + HELP_TEXT ("the faster you run through the colors of the") + HELP_TEXT ("shade.") + HELP_TEXT ("For example: if the step is 2 and that you") + HELP_TEXT ("have defined a shade with") + HELP_TEXT ("the colors 0,1,4,5,9 and that you click on a") + HELP_TEXT ("pixel of color 1, it will") + HELP_TEXT ("take the value 5 which is 2 positions next") + HELP_TEXT ("in the la table.") + HELP_TEXT ("") + HELP_TEXT ("(We are sorry for these technical") + HELP_TEXT ("considerations quite far from a purely") + HELP_TEXT ("artistic point of view; but know that this") + HELP_TEXT ("effect is really very useful and it is") + HELP_TEXT ("preferable that you understand its whole") + HELP_TEXT ("functionment if you want to fully take") + HELP_TEXT ("advantage of it).") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("QUICK SHADE") + HELP_TEXT (" This drawing mode has about the same effect") + HELP_TEXT ("as Shade mode's except that it is faster") + HELP_TEXT ("to configurate but a little bit less") + HELP_TEXT ("powerful. When you draw on a color of the") + HELP_TEXT ("image which is between the fore- and the") + HELP_TEXT ("back-color in the palette, the color tends") + HELP_TEXT ("towards the fore-color (according to the") + HELP_TEXT ("step defined) if you draw with the left") + HELP_TEXT ("mouse button, or it tends towards the") + HELP_TEXT ("back-color if you are using the right mouse") + HELP_TEXT ("button.") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Quick-shade mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu with a few parameters that mean") + HELP_TEXT ("exactly the same as in the menu of Shade") + HELP_TEXT ("mode. These parameters are the step and the") + HELP_TEXT ("loop/satu- ration mode (normal, loop, no") + HELP_TEXT ("saturation).") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("STENCIL") + HELP_TEXT (" It is used to prevent some colors from") + HELP_TEXT ("being modified if you draw on them. The") + HELP_TEXT ("main application of the stencil is when you") + HELP_TEXT ("want to change one color or more into") + HELP_TEXT ("another.") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Stencil mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can define a stencil.") + HELP_TEXT ("The different sections of this menu are:") + HELP_TEXT ("") + HELP_TEXT ("- Clear: No color is protected.") + HELP_TEXT ("") + HELP_TEXT ("- Invert: Colors that were protected are") + HELP_TEXT ("unprotected and vice versa.") + HELP_TEXT ("") + HELP_TEXT ("- Palette: Select colors that should be") + HELP_TEXT ("protected with the left mouse button or") + HELP_TEXT ("unprotect colors with the right mouse") + HELP_TEXT ("button.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("MASK") + HELP_TEXT (" This effect could have been called \"True") + HELP_TEXT ("stencil\" because it protects some parts of") + HELP_TEXT ("the picture instead of some colors. The") + HELP_TEXT ("colors you tag represent the pixels in the") + HELP_TEXT ("spare page, corresponding to the pixels in") + HELP_TEXT ("the current page, that you don't want to") + HELP_TEXT ("alter. For example, draw a simple white") + HELP_TEXT ("figure on a black background in the spare") + HELP_TEXT ("page. Then, tag the black color in the menu") + HELP_TEXT ("of the Mask mode. When you'll draw in the") + HELP_TEXT ("current page, only the pixels corresponding") + HELP_TEXT ("to the white (non-black) ones in the spare") + HELP_TEXT ("page will be modified.") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_MASK_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Mask mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_MASK_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can set the colors of") + HELP_TEXT ("the Mask.") + HELP_TEXT ("This menu works the same way as the one of") + HELP_TEXT ("the Stencil, so please refer to the Stencil") + HELP_TEXT ("paragraph to know how to use it.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("GRID") + HELP_TEXT (" This is useful to snap the cursor to the") + HELP_TEXT ("cross-points of a grid. It's generally") + HELP_TEXT ("used to draw a grid before drawing sprites") + HELP_TEXT ("of the same size such as a font or tiles,") + HELP_TEXT ("or for drawing figures or grabbing brushes") + HELP_TEXT ("with their dimensions multiple of the step") + HELP_TEXT ("of the grid.');") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_GRID_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Grid mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_GRID_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can define the grid") + HELP_TEXT ("parameters. These parameters are:") + HELP_TEXT ("") + HELP_TEXT ("- X,Y: Steps of the grid.") + HELP_TEXT ("") + HELP_TEXT ("- dX,dY: Offsets of the grid.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("SIEVE") + HELP_TEXT (" This effect allows you, by defining a") + HELP_TEXT ("pattern, to draw only on particular points") + HELP_TEXT ("of the picture. If you are a Manga drawer,") + HELP_TEXT ("you might find this useful to make patterned") + HELP_TEXT ("shades or color transitions.") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Sieve mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can define the Sieve") + HELP_TEXT ("parameters. This menu consists in:") + HELP_TEXT ("") + HELP_TEXT ("- 16x16 drawing area: You can define a") + HELP_TEXT ("pattern in it (left click => white pixel /") + HELP_TEXT ("right click => black pixel). All the white") + HELP_TEXT ("pixels indicate that, when you'll draw,") + HELP_TEXT ("pixels will be applied on the picture at the") + HELP_TEXT ("corresponding positions whereas black pixels") + HELP_TEXT ("won't modify the picture: whites pixels are") + HELP_TEXT ("the \"holes of the sieve\".") + HELP_TEXT ("") + HELP_TEXT ("- 12 default patterns: They can be copied to") + HELP_TEXT ("the drawing area.") + HELP_TEXT ("") + HELP_TEXT ("- \"Transfer to brush\": Copies the pattern to") + HELP_TEXT ("the brush (white pixels => Fore-color /") + HELP_TEXT ("black pixels => Back-color).") + HELP_TEXT ("") + HELP_TEXT ("- \"Get from brush\": Puts the brush into the") + HELP_TEXT ("drawing area (back-color => black pixels /") + HELP_TEXT ("others => white pixels).") + HELP_TEXT ("") + HELP_TEXT ("- Scrolling 4-arrows pad: Scrolls the") + HELP_TEXT ("pattern in the drawing area.") + HELP_TEXT ("") + HELP_TEXT ("- Resizing 4-arrows pad: Defines the") + HELP_TEXT ("dimensions of the pattern.") + HELP_TEXT ("") + HELP_TEXT ("- Default-value (black or white square):") + HELP_TEXT ("Indicates which value must be inserted when") + HELP_TEXT ("you increase the dimensions of the pattern.") + HELP_TEXT ("") + HELP_TEXT ("- \"Clear\": Sets the whole pattern with the") + HELP_TEXT ("default value (see above).") + HELP_TEXT ("") + HELP_TEXT ("- \"Invert\": It... inverts :) ... black and") + HELP_TEXT ("white pixels.") + HELP_LINK ("(Key: %s)", SPECIAL_INVERT_SIEVE) + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("TRANSPARENCY") + HELP_TEXT (" This allows to mix the color(s) of the") + HELP_TEXT ("paintbrush with the colors of the picture.") + HELP_TEXT ("It's used to make transparency effects like") + HELP_TEXT ("with watercolors.") + HELP_TEXT ("") + HELP_TEXT ("You can also use the following shortcuts to") + HELP_TEXT ("activate transparency mode and assign an") + HELP_TEXT ("amount of opacity:") + HELP_LINK (" 10%% : %s", SPECIAL_TRANSPARENCY_1) + HELP_LINK (" 20%% : %s", SPECIAL_TRANSPARENCY_2) + HELP_LINK (" 30%% : %s", SPECIAL_TRANSPARENCY_3) + HELP_LINK (" 40%% : %s", SPECIAL_TRANSPARENCY_4) + HELP_LINK (" 50%% : %s", SPECIAL_TRANSPARENCY_5) + HELP_LINK (" 60%% : %s", SPECIAL_TRANSPARENCY_6) + HELP_LINK (" 70%% : %s", SPECIAL_TRANSPARENCY_7) + HELP_LINK (" 80%% : %s", SPECIAL_TRANSPARENCY_8) + HELP_LINK (" 90%% : %s", SPECIAL_TRANSPARENCY_9) + HELP_LINK (" 100%% : %s", SPECIAL_TRANSPARENCY_0) + HELP_TEXT ("If you use two of these shortcuts quickly,") + HELP_TEXT ("the second will set the units for finer") + HELP_TEXT ("control. Ie: 4 5 makes 45%, 0 9 makes 9%.") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Transparency mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can define the") + HELP_TEXT ("Transparency parameters. These parameters") + HELP_TEXT ("are:") + HELP_TEXT ("") + HELP_TEXT ("- Interpolation rate: Indicates the") + HELP_TEXT ("percentage of the applied color that will be") + HELP_TEXT ("considered upon the replaced color.") + HELP_TEXT ("") + HELP_TEXT ("- Interpolation method: Uses an") + HELP_TEXT ("interpolation algorithm to compute the") + HELP_TEXT ("color, according to the interpolation rate.") + HELP_TEXT ("") + HELP_TEXT ("- Additive method: Uses the lightest colors") + HELP_TEXT ("to choose the color to apply. For example:") + HELP_TEXT ("if you want to apply a color RGB:30,20,40 on") + HELP_TEXT ("a color RGB:10,50,20, the color applied will") + HELP_TEXT ("be the one, in the palette, that is the") + HELP_TEXT ("closest to the theoretic color RGB:30,50,40.") + HELP_TEXT ("") + HELP_TEXT ("- Subtractive method: uses the darkest") + HELP_TEXT ("colors to choose the color to apply. For") + HELP_TEXT ("example: if you want to apply a color") + HELP_TEXT ("RGB:30,20,40 on a color RGB:10,50,20, the") + HELP_TEXT ("color applied will be the one, in the") + HELP_TEXT ("palette, that is the closest to the") + HELP_TEXT ("theoretic color RGB:10,20,20.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("SMOOTH") + HELP_TEXT (" It provides an easy but not as efficient") + HELP_TEXT ("anti-aliasing as any artist's touch.") + HELP_TEXT ("Anyway this effect finds a better use in") + HELP_TEXT ("making a blurry aspect.") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Smooth mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can define the Smooth") + HELP_TEXT ("matrix or choose one among the 4 ones") + HELP_TEXT ("predefined.") + HELP_TEXT ("The middle square represents the pixel on") + HELP_TEXT ("which you draw and the 8 others represent") + HELP_TEXT ("the neighbour pixels. Then, the point on") + HELP_TEXT ("which one draw will be replaced by the") + HELP_TEXT ("weighted average (according to values of") + HELP_TEXT ("each squares) of the 9 defined points.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("SMEAR") + HELP_TEXT (" It smears pixels in the direction you are") + HELP_TEXT ("moving your paintbrush, just as if you") + HELP_TEXT ("wanted to spread fresh paint with your") + HELP_TEXT ("fingers. You can combine this effect with") + HELP_TEXT ("the transparency effect.") + HELP_TEXT ("") + HELP_LINK ("(Key: %s)", SPECIAL_SMEAR_MODE) + HELP_TEXT ("Switches the Smear mode.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE("TILING") + HELP_TEXT (" It consists in displaying parts of the") + HELP_TEXT ("brush that are adjusted on a tiling when") + HELP_TEXT ("you are drawing. It's mainly used for") + HELP_TEXT ("quickly drawing a background with a") + HELP_TEXT ("pattern, but there is a great number of") + HELP_TEXT ("other possibilities.") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_TILING_MODE) + HELP_TEXT ("") + HELP_TEXT ("Switches the Tiling mode.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key: %s)", SPECIAL_TILING_MENU) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can define the Tiling") + HELP_TEXT ("parameters. These parameters are the offsets") + HELP_TEXT ("of the tiling.") +}; +static const T_Help_table helptable_text[] = +{ + HELP_TITLE("TEXT") + HELP_TEXT ("") + HELP_LINK ("(Key:%s)",0x100+BUTTON_TEXT) + HELP_TEXT ("") + HELP_TEXT ("The text menu allows you to enter some text") + HELP_TEXT ("and render it as a brush.") + HELP_TEXT ("The current background and foreground colors") + HELP_TEXT ("are very important, they determine the text") + HELP_TEXT ("color, the transparent color, and also the") + HELP_TEXT ("color range to use for antialiasing.") + HELP_TEXT ("GrafX2 can use 'bitmap' fonts as long as") + HELP_TEXT ("they are in the special layout supported ") + HELP_TEXT ("by SFont.") + HELP_TEXT ("TrueType fonts can also be used if this") + HELP_TEXT ("version of GrafX2 was compiled with") + HELP_TEXT ("TrueType support.") + HELP_TEXT ("") + HELP_TEXT ("- Txt: Click and enter your text here, a") + HELP_TEXT ("line of up to 250 characters.") + HELP_TEXT ("") + HELP_TEXT ("- Clear txt: Empties the current text.") + HELP_TEXT ("When the text is empty, a standard string") + HELP_TEXT ("is shown instead in the preview area.") + HELP_TEXT ("") + HELP_TEXT ("- Antialias: Click to enable or disable") + HELP_TEXT ("Antialiasing. Only affects TrueType fonts.") + HELP_TEXT ("") + HELP_TEXT ("- Size: Determine the font height. Only") + HELP_TEXT ("affects TrueType fonts.") + HELP_TEXT ("") + HELP_TEXT ("- Font selector: Choose a font. You can") + HELP_TEXT ("use the arrow keys (up and down) to quickly") + HELP_TEXT ("browse your fonts.") + HELP_TEXT ("TrueType fonts are indicated by 'TT'.") + HELP_TEXT ("") + HELP_TEXT ("- Preview area: Shows what the brush will") + HELP_TEXT ("look like.") +}; +static const T_Help_table helptable_magnifier[] = +{ + HELP_TITLE("MAGNIFIER") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_MAGNIFIER) + HELP_TEXT ("") + HELP_TEXT ("Engages/Disengages the choice of the zoomed") + HELP_TEXT ("window. If you're already in magnifier mode,") + HELP_TEXT ("you'll return to normal mode.") + HELP_LINK ("Zoom in : %s",SPECIAL_ZOOM_IN) + HELP_LINK ("Zoom out: %s",SPECIAL_ZOOM_OUT) + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_MAGNIFIER) + HELP_TEXT ("") + HELP_TEXT ("Displays a menu where you can choose the") + HELP_TEXT ("magnifying factor.") + HELP_TEXT ("") + HELP_TEXT (" Note: When you are in Zoom mode, you can") + HELP_TEXT ("move the \"split\" bar by clicking on it and") + HELP_TEXT ("moving your mouse left or right while") + HELP_TEXT ("holding the mouse button down.") +}; +static const T_Help_table helptable_colorpicker[] = +{ + HELP_TITLE("PIPETTE") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_COLORPICKER) + HELP_TEXT ("") + HELP_TEXT ("Engages a color grabbing.") + HELP_TEXT ("") + HELP_TEXT ("Click on the picture to get the color of the") + HELP_TEXT ("pixel you're on. You can either get a new") + HELP_TEXT ("Fore-color or Back-color with respectively") + HELP_TEXT ("left or right mouse button.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_COLORPICKER) + HELP_TEXT ("") + HELP_TEXT ("Swap Fore-color and Back-color.") + HELP_TEXT ("") + HELP_TEXT (" The color currently pointed will be") + HELP_TEXT ("displayed in the tool-bar right after the") + HELP_TEXT ("coordinates. If you click outside the") + HELP_TEXT ("picture, the color 0 will be returned.") +}; +static const T_Help_table helptable_resolution[] = +{ + HELP_TITLE("RESOLUTION AND") + HELP_TITLE(" IMAGE SIZE") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_RESOL) + HELP_TEXT ("") + HELP_TEXT ("Displays a menu where you can define the") + HELP_TEXT ("size of your picture and choose the") + HELP_TEXT ("screen resolution.") + HELP_TEXT ("") + HELP_TEXT ("- Image size") + HELP_TEXT ("Click in the boxes named \"Width\" and") + HELP_TEXT ("\"Height\" to change the size of the image") + HELP_TEXT ("you're editing, up to 9999x9999.") + HELP_TEXT ("You can also right-click a video mode to") + HELP_TEXT ("copy its dimensions to the image's.") + HELP_TEXT ("") + HELP_TEXT ("- Pixel size") + HELP_TEXT ("If you choose any Pixel size other than") + HELP_TEXT ("Normal, Grafx2 will emulate a lower") + HELP_TEXT ("resolution by scaling up everything it") + HELP_TEXT ("displays, including the menus and mouse") + HELP_TEXT ("cursor. In Double, Triple and Quadruple") + HELP_TEXT ("mode, the image will appear zoomed x2, x3 or") + HELP_TEXT ("x4, keeping the original proportions. The") + HELP_TEXT ("scaling is done in software, with no linear") + HELP_TEXT ("interpolation, so it can't cause blur. This") + HELP_TEXT ("setting is especially useful if your") + HELP_TEXT ("hardware or drivers don't support the low") + HELP_TEXT ("resolutions you need, but it also allows you") + HELP_TEXT ("to draw in low-resolution while staying in") + HELP_TEXT ("window mode.") + HELP_TEXT ("If you choose one of the scalers called") + HELP_TEXT ("Wide, Tall, Wide2 and Tall2, this will") + HELP_TEXT ("emulate a video mode which has rectangular") + HELP_TEXT ("pixels (longer horizontally or vertically),") + HELP_TEXT ("like some video modes of the C64, Amstrad") + HELP_TEXT ("CPC, and Commodore Amiga.") + HELP_TEXT ("") + HELP_TEXT ("- Video mode") + HELP_TEXT ("Click on a video mode to select it.") + HELP_TEXT ("Grafx2 only lists modes that are detected") + HELP_TEXT ("as available on your computer. Depending on") + HELP_TEXT ("your video card and drivers, there can be") + HELP_TEXT ("a huge difference in the number of modes") + HELP_TEXT ("it can propose.") + HELP_TEXT ("The small buttons on the left-hand side of") + HELP_TEXT ("the lines in the list of modes have been") + HELP_TEXT ("designed to allow you to disable some modes") + HELP_TEXT ("that are not supported by your card. So, the") + HELP_TEXT ("modes that you will disable won't be used") + HELP_TEXT ("when loading pictures with \"Auto-set") + HELP_TEXT ("resolution\" ON.") + HELP_TEXT ("") + HELP_TEXT ("When you click on one of these buttons, its") + HELP_TEXT ("color changes to one of the 4 following. The") + HELP_TEXT ("signification for each color of these") + HELP_TEXT ("buttons is:") + HELP_TEXT ("") + HELP_TEXT ("- Light gray: The video mode is OK. It can") + HELP_TEXT ("be used by the auto-set resolution option") + HELP_TEXT ("when you load picture, and you can select it") + HELP_TEXT ("in the menu of resolutions.") + HELP_TEXT ("") + HELP_TEXT ("- White: It works exactly the same as above.") + HELP_TEXT ("Moreover, it allows you to tag your") + HELP_TEXT ("favourite modes. Indeed, the huge number of") + HELP_TEXT ("video modes makes it more difficult to find") + HELP_TEXT ("the mode your want in the list; so you can") + HELP_TEXT ("tag your favoutite ones in white, so that it") + HELP_TEXT ("will be easier to locate them. (Note: you") + HELP_TEXT ("cannot disable the standard windowed mode)") + HELP_TEXT ("") + HELP_TEXT ("- Dark gray: It allows you to indicate which") + HELP_TEXT ("modes are not really perfect (flickering,") + HELP_TEXT ("not centered, etc...) but which can be used") + HELP_TEXT ("even so. The difference with the light grey") + HELP_TEXT ("button is that these modes won't be used by") + HELP_TEXT ("the auto-set resolution option.") + HELP_TEXT ("") + HELP_TEXT ("- Black: Use it for totally unsupported") + HELP_TEXT ("modes. Thus, these modes won't be selected") + HELP_TEXT ("the \"auto-set res.\" and the program will") + HELP_TEXT ("not let you select them from the list of") + HELP_TEXT ("resolutions.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_RESOL) + HELP_TEXT ("") + HELP_TEXT (" Automaticaly switches to the 640x400 window") + HELP_TEXT ("mode.") +}; +static const T_Help_table helptable_page[] = +{ + HELP_TITLE("SPARE") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_PAGE) + HELP_TEXT ("") + HELP_TEXT ("Jumps to spare page. The current page is") + HELP_TEXT ("then considered as the new spare page, and") + HELP_TEXT ("the spare page considered as the new current") + HELP_TEXT ("page.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_PAGE) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu where you can choose whether") + HELP_TEXT ("you want to copy the whole picture (keyboard") + HELP_TEXT ("short-cut in this menu is [Return]), only") + HELP_TEXT ("the pixels, only the palette, or only some") + HELP_TEXT ("colors.") + HELP_TEXT ("In this last case, a second menu") + HELP_TEXT ("(stencil-like) will propose you to tag the") + HELP_TEXT ("colors you want to copy (they are all") + HELP_TEXT ("selected by default).") + HELP_TEXT ("Please refer to section \"Stencil\" to know") + HELP_TEXT ("how to use this last menu.") + HELP_TEXT ("The last option the menu (\"Copy palette and") + HELP_TEXT ("remap\"), remaps the spare page with the") + HELP_TEXT ("current palette and replicates this palette") + HELP_TEXT ("to the spare page. This option is useful to") + HELP_TEXT ("quickly remap a picture with the palette of") + HELP_TEXT ("another.") +}; +static const T_Help_table helptable_save[] = +{ + HELP_TITLE("SAVE") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_SAVE) + HELP_TEXT ("") + HELP_TEXT ("Displays a fileselector where the following") + HELP_TEXT ("options are available:") + HELP_TEXT ("") + HELP_TEXT ("- Select drive: Allow you to change the") + HELP_TEXT ("current drive.or volume (depending on your") + HELP_TEXT ("operating system") + HELP_TEXT ("") + HELP_TEXT ("- Format: Allows you to choose the file") + HELP_TEXT ("format you want. (PAL and KCF file formats") + HELP_TEXT ("are \"palette\" files).") + HELP_TEXT ("") + HELP_TEXT ("- Filename: Allows you to give a new name to") + HELP_TEXT ("the picture. If no extension is given, the") + HELP_TEXT ("default (according to the format) will be") + HELP_TEXT ("used.") + HELP_TEXT ("") + HELP_TEXT ("- Bookmarks: The four dropdown buttons allow") + HELP_TEXT ("you to bookmark frequently used directories.") + HELP_TEXT ("Use right-click to open a contextual menu") + HELP_TEXT ("to Set it (memorize current directory),") + HELP_TEXT ("Rename it to change its label, and Clear it") + HELP_TEXT ("if you no longer need it. Use left-click to") + HELP_TEXT ("change to the memorized directory.") + HELP_TEXT ("") + HELP_TEXT ("- File-list: Allows you to flick through the") + HELP_TEXT ("disk tree or to overwrite an existing file.") + HELP_TEXT ("") + HELP_TEXT ("- Delete: Allows you to delete the item") + HELP_TEXT ("under the selection bar. If the item is a") + HELP_TEXT ("directory, it must be empty to be removed.") + HELP_TEXT ("") + HELP_TEXT ("- Save: Saves the picture with the current") + HELP_TEXT ("filename, with the chosen format. If the ") + HELP_TEXT ("current filename represents a directory,") + HELP_TEXT ("you'll enter it.") + HELP_TEXT ("") + HELP_TEXT ("- Comment (Txt): If you're using the PKM") + HELP_TEXT ("or PNG format, you can type in a comment on") + HELP_TEXT ("your picture. It will be memorized in the") + HELP_TEXT ("image.") + HELP_TEXT ("") + HELP_TEXT ("Note: The Backspace key brings you directly") + HELP_TEXT ("to the parent directory. You can also type") + HELP_TEXT ("the first letters of a filename you are") + HELP_TEXT ("looking for, to access it faster.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_SAVE) + HELP_TEXT ("") + HELP_TEXT ("Save the current picture with its current") + HELP_TEXT ("filename, format and comment.") + HELP_TEXT ("") + HELP_TEXT ("If the file already exists, a confirmation") + HELP_TEXT ("box will appear.") +}; +static const T_Help_table helptable_load[] = +{ + + HELP_TITLE("LOAD") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_LOAD) + HELP_TEXT ("") + HELP_TEXT ("This works the same way as Save.") + HELP_TEXT ("") + HELP_TEXT ("You'll have access in the format selector to") + HELP_TEXT ("a \"*.*\" filter. And of course, you won't be") + HELP_TEXT ("able to type in any comment.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_LOAD) + HELP_TEXT ("") + HELP_TEXT ("Reloads the picture.") + HELP_TEXT ("") + HELP_TEXT ("If you want to load a picture and that you") + HELP_TEXT ("haven't saved the last modifications of the") + HELP_TEXT ("current picture, a confirmation box will") + HELP_TEXT ("appear.") +}; +static const T_Help_table helptable_settings[] = +{ + HELP_TITLE("SETTINGS") + HELP_TEXT ("") + HELP_LINK ("(Key:%s)",0x100+BUTTON_SETTINGS) + HELP_TEXT ("") + HELP_TEXT ("Displays a menu where you can configure some") + HELP_TEXT ("miscellaneous elements of the program:") + HELP_TEXT ("") + HELP_TEXT ("- Number of UNDO pages: indicates the total") + HELP_TEXT ("number of pages that GrafX2 will memorize.") + HELP_TEXT ("Each time you modify the picture, its") + HELP_TEXT ("current state is memorized in one of these") + HELP_TEXT ("pages. To flick through these pages, use the") + HELP_TEXT ("\"Oops\" button (Undo/Redo).") + HELP_TEXT ("") + HELP_TEXT ("- Mouse sensibility: Modifies the speed of") + HELP_TEXT ("the mouse when you're in fullscreen. With") + HELP_TEXT ("the normal setting (slider on top), you may") + HELP_TEXT ("find the mouse too fast, especially in ") + HELP_TEXT ("video modes which are much smaller than your") + HELP_TEXT ("desktop. You can lower the slider to divide") + HELP_TEXT ("the speed by 2, 3 or 4.") + HELP_TEXT ("When using videomodes with native skewed") + HELP_TEXT ("pixels like 640x240 or 320x512, you'll") + HELP_TEXT ("probably want to use a stronger reduction") + HELP_TEXT ("on the axis which has less pixels.") + HELP_TEXT ("") + HELP_TEXT ("- Show/Hide in file list: Defines whether") + HELP_TEXT ("some particular files or directories must be") + HELP_TEXT ("displayed by the fileselectors or not.") + HELP_TEXT ("") + HELP_TEXT ("- Show/Hide picture limits: Indicates if the") + HELP_TEXT ("picture boundaries must be displayed when") + HELP_TEXT ("you are in a resolution bigger than the") + HELP_TEXT ("picture.") + HELP_TEXT ("") + HELP_TEXT ("- Clear palette: Indicates if loading a file") + HELP_TEXT ("with a palette of less than 256 colors must") + HELP_TEXT ("erase the rest of the current palette") + HELP_TEXT ("(replace by the black color).") + HELP_TEXT ("") + HELP_TEXT ("- Maximize preview: maximizes the preview of") + HELP_TEXT ("the pictures so that it is as big as") + HELP_TEXT ("possible. If you're not in the same") + HELP_TEXT ("resolution as the picture's one, it can try") + HELP_TEXT ("to correct the aspect ratio, but if the") + HELP_TEXT ("picture does not fill the whole screen, it") + HELP_TEXT ("can be worse.") + HELP_TEXT ("") + HELP_TEXT ("- Backup: when you'll save a picture over an") + HELP_TEXT ("existing file, the program will rename this") + HELP_TEXT ("file to \"*.BAK\" where * is the name of the") + HELP_TEXT ("picture without its extension. If the backup") + HELP_TEXT ("file already exists in the directory, it") + HELP_TEXT ("will be replaced. If you save a picture with") + HELP_TEXT ("the name of the backup file, no backup file") + HELP_TEXT ("will be created (of course!) ;).") + HELP_TEXT ("") + HELP_TEXT ("- Safety colors: Brings back the 4 default") + HELP_TEXT ("colors of the menus if you run an operation") + HELP_TEXT ("that passes the image in less than four") + HELP_TEXT ("colors in the palette editor.") + HELP_TEXT ("") + HELP_TEXT ("- Adjust brush pick: This option is used") + HELP_TEXT ("when you grab a brush in Grid (Snap) mode.") + HELP_TEXT ("Then, the right-most and down-most pixels") + HELP_TEXT ("won't be picked up with the rest of the") + HELP_TEXT ("brush. This option has been made because, if") + HELP_TEXT ("people grab brushes in Grid mode, that's") + HELP_TEXT ("mostly when they want to grab sprites. For") + HELP_TEXT ("example: if you have 16x16 sprites on your") + HELP_TEXT ("page, you'll set the grid mode to 16x16. But") + HELP_TEXT ("the cursor will snap at points like (0,0),") + HELP_TEXT ("(16,0), (16,16) and so on... And the problem") + HELP_TEXT ("is that, from (0,0) to (16,16), there are 17") + HELP_TEXT ("pixels! But if you keep the") + HELP_TEXT ("adjust-brush-pick option on, the unwanted") + HELP_TEXT ("pixels will be ignored. Moreover, this") + HELP_TEXT ("option adjusts the brush handle so that the") + HELP_TEXT ("brush still fits in the grid, instead of") + HELP_TEXT ("placing the handle in the center of the") + HELP_TEXT ("brush.") + HELP_TEXT ("") + HELP_TEXT ("- Separate colors: Draws a squaring around") + HELP_TEXT ("the colors of the tool-bar.") + HELP_TEXT ("") + HELP_TEXT ("- Auto-set resolution: sets the best") + HELP_TEXT ("resolution for the loaded image.") + HELP_TEXT ("") + HELP_TEXT ("- Coordinates: Choose if you want to display") + HELP_TEXT ("relative or absolute coordinates when using") + HELP_TEXT ("tools such as circles, rectangles, etc...") + HELP_TEXT ("for example, if you draw a circle: if coords") + HELP_TEXT ("are relative, the radius of the circle will") + HELP_TEXT ("be displayed, while in absolute coords, the") + HELP_TEXT ("coordinates of the cursor will be displayed.") + HELP_TEXT ("") + HELP_TEXT ("- Reload: loads the previously saved") + HELP_TEXT ("configuration.") + HELP_TEXT ("") + HELP_TEXT ("- Auto-save: means that the configuration") + HELP_TEXT ("will be automatically saved when you'll quit") + HELP_TEXT ("the program.") + HELP_TEXT ("") + HELP_TEXT ("- Save: saves the configuration at once.") + HELP_TEXT (" All modifications will be effective just") + HELP_TEXT ("after closing the menu.") + HELP_TEXT ("") + HELP_TITLE("SKINS") + HELP_TEXT ("") + HELP_TEXT ("This window allow you to change the look and") + HELP_TEXT ("feel of the program.") + HELP_TEXT ("") + HELP_TEXT ("- Font: determines whether you want to use") + HELP_TEXT ("GrafX2 with a classical font, or another one") + HELP_TEXT ("a bit funnier.") + HELP_TEXT ("") + HELP_TEXT ("- Cursor: allows you to choose whether you") + HELP_TEXT ("prefer a solid cursor or a transparent") + HELP_TEXT ("cursor.") + HELP_TEXT ("") + HELP_TEXT ("- Graphic file: you can change the whole") + HELP_TEXT ("interface by selecting where the sprites for") + HELP_TEXT ("all buttons are. Look at the files in the") + HELP_TEXT ("\"skin\" directory if you want to create your") + HELP_TEXT ("own. There are two skins available, the") + HELP_TEXT ("default for 2.1 is called modern. Classic is") + HELP_TEXT ("for nostalgics who wish to remember the old") + HELP_TEXT ("days of Sunset Design. If you create a good") + HELP_TEXT ("skin, feel free to share it with us! We may") + HELP_TEXT ("include it in a future release...") +}; +static const T_Help_table helptable_clear[] = +{ + + HELP_TITLE("CLEAR") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_CLEAR) + HELP_TEXT ("") + HELP_TEXT ("Clears the picture with the color number 0.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_CLEAR) + HELP_TEXT ("") + HELP_TEXT ("Clears the picture with the Back-color.") +}; +static const T_Help_table helptable_general[] = +{ + + HELP_TITLE("HELP STATS") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_HELP) + HELP_TEXT ("") + HELP_TEXT ("Displays an info window where you'll find") + HELP_TEXT ("some credits, help about the credits,") + HELP_TEXT ("different effects, greetings, registering...") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_HELP) + HELP_TEXT ("") + HELP_TEXT ("Displays a window where you'll find") + HELP_TEXT ("miscellaneous informations about the system.") + HELP_TEXT (" Note: you should take care to keep more") + HELP_TEXT ("than 128 Kb in order to let the program") + HELP_TEXT ("run in a proper way.") +}; +static const T_Help_table helptable_undo[] = +{ + + HELP_TITLE("OOPS") + HELP_TEXT ("(UNDO/REDO)") + HELP_TEXT ("LEFT CLICK Allows you to undo the last") + HELP_TEXT ("modification on the picture.") + HELP_LINK ("(Key:%s)",0x100+BUTTON_UNDO) + HELP_TEXT ("") + HELP_TEXT ("RIGHT CLICK Allows you to redo the last") + HELP_TEXT ("modification undone on the picture.") + HELP_TEXT ("The maximum number of UNDO that you can") + HELP_TEXT ("perform can be defined in the settings") + HELP_TEXT ("menu.") + HELP_TEXT ("Undo/Redo aren't effective after page") + HELP_TEXT ("switching, picture loading and picture") + HELP_TEXT ("size modifications.") + HELP_LINK ("(Key:%s)",0x200+BUTTON_UNDO) +}; +static const T_Help_table helptable_kill[] = +{ + + HELP_TITLE("KILL") + HELP_TEXT ("KILL CURRENT PAGE") + HELP_TEXT ("") + HELP_LINK ("(Key:%s)",0x100+BUTTON_KILL) + HELP_TEXT ("") + HELP_TEXT ("Removes the current page from the list of") + HELP_TEXT ("\"Undo\" pages. This allows you to free some") + HELP_TEXT ("memory if you need it. For instance, this") + HELP_TEXT ("will allow you to delete the start-up page") + HELP_TEXT ("after having loaded an image. A message will") + HELP_TEXT ("appear if you've already erased all the") + HELP_TEXT ("pages except the last one.") + HELP_TEXT (" Note: Another way to free some memory is to") + HELP_TEXT ("decrease the number of \"Undo\" pages. Or") + HELP_TEXT ("else, if you have recentlt grabbed a very") + HELP_TEXT ("big brush that you don't use any more, you") + HELP_TEXT ("can grab a new smaller one. The memory") + HELP_TEXT ("allocated by the big brush will be thus") + HELP_TEXT ("freed.") +}; +static const T_Help_table helptable_quit[] = +{ + + HELP_TITLE("QUIT") + HELP_TEXT ("") + HELP_LINK ("(Key:%s)",0x100+BUTTON_QUIT) + HELP_TEXT ("") + HELP_TEXT ("Allows you to leave GrafX2. If there are") + HELP_TEXT ("unsaved modifications in the current or") + HELP_TEXT ("spare page, a confirmation box will ask you") + HELP_TEXT ("if you really want to quit GrafX2, if you") + HELP_TEXT ("want to save (Auto-save, no fileselector) or") + HELP_TEXT ("if you want to stay in GrafX2.") +}; +static const T_Help_table helptable_palette[] = +{ + + HELP_TITLE("PAL MENU") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_LINK ("(Key:%s)",0x100+BUTTON_PALETTE) + HELP_TEXT ("") + HELP_TEXT ("Displays a menu where the following options") + HELP_TEXT ("are available:") + HELP_TEXT ("") + HELP_TEXT ("- Palette: Allows you to choose a") + HELP_TEXT ("color-block to edit. If you click with the") + HELP_TEXT ("right mouse button, you'll choose a new") + HELP_TEXT ("Back-color.") + HELP_TEXT ("") + HELP_TEXT ("- Gauges: Allow you to modify the") + HELP_TEXT ("current selection.") + 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 ("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 ("into its reverse video equivalent.") + HELP_TEXT ("") + HELP_TEXT ("- Invert: Swaps the colors of the current") + HELP_TEXT ("selection so that the first colors become") + HELP_TEXT ("the last ones.") + HELP_TEXT ("") + HELP_TEXT ("- X-Invert: Works as above but modifies the") + HELP_TEXT ("picture so that it looks the same.") + HELP_TEXT ("") + HELP_TEXT ("- Swap: Swaps the current selection with") + HELP_TEXT ("another color-block. Click on the beginning") + HELP_TEXT ("of the new color-block.") + HELP_TEXT ("") + HELP_TEXT ("- X-Swap: Works as above but modifies the") + HELP_TEXT ("picture so that it looks the same. This may") + HELP_TEXT ("be useful if you want to sort your palette.") + HELP_TEXT ("") + HELP_TEXT ("- Copy: Copies the current selection to") + HELP_TEXT ("another color-block. Click on the beginning") + HELP_TEXT ("of the new color-block.") + HELP_TEXT ("") + HELP_TEXT ("- Spread: Computes a gradation between two") + HELP_TEXT ("colors. If your selection is only made up of") + HELP_TEXT ("one color, select the second color in the") + HELP_TEXT ("palette. Otherwise, the two colors used will") + HELP_TEXT ("be its extremities.") + HELP_TEXT ("") + HELP_TEXT ("- Sort: sorts the palette by color ranges.") + HELP_TEXT ("If you click with the left mouse button, it") + HELP_TEXT ("will sort by H S L; and if you click with") + HELP_TEXT ("the right mouse button, it will sort by L") + HELP_TEXT ("only. Note that you can choose a range of") + HELP_TEXT ("colors before sorting, and instead of the") + 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 ("") + 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).") + HELP_TEXT ("") + HELP_TEXT ("- Undo: Allows you to recover the last") + HELP_TEXT ("modifications made on the palette. If the") + HELP_TEXT ("last operation modified the picture, it") + HELP_TEXT ("won't recover them: you'll have to click on") + HELP_TEXT ("Cancel to do so.") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("If you press , the program will") + HELP_TEXT ("replace, as well as possible, some unused") + HELP_TEXT ("colors by the four default colors of the") + HELP_TEXT ("menu. The image won't look altered because") + HELP_TEXT ("the modified colors (in the case they were") + HELP_TEXT ("used on a few points) will be replaced by") + HELP_TEXT ("the closest colors in the rest of the") + HELP_TEXT ("palette. This option is really useful when") + HELP_TEXT ("you modify the palette so that there are no") + HELP_TEXT ("colors that fit for the menu (eg: \"Zap") + HELP_TEXT ("unused\" while very little colors are used in") + HELP_TEXT ("the picture; or \"Reduce\" with a very small") + HELP_TEXT ("number of colors).") + HELP_TEXT ("") + HELP_TEXT ("If you press the key below or <,>") + HELP_TEXT ("(QWERTY), the menu will disappear and you") + HELP_TEXT ("will be able to pick up a color from the") + HELP_TEXT ("picture easily. Press to cancel.") + HELP_TEXT ("") + HELP_TEXT ("If only one color is selected (not a block),") + HELP_TEXT ("the <[> and <]> keys can be used to select") + HELP_TEXT ("the previous or next Forecolor (Backcolor if") + HELP_TEXT ("you press at the same time).") + HELP_TEXT ("") + HELP_TEXT ("Warning! If you press Undo after an action") + HELP_TEXT ("that modifies the picture (X-Swap, X-Invert") + HELP_TEXT ("and Reduce colors), the picture won't be") + HELP_TEXT ("remapped as it was just before this action.") + HELP_TEXT ("Only Cancel will.") + HELP_TEXT ("") + HELP_TITLE("PALETTE OPTIONS") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_LINK ("(Key:%s)",0x200+BUTTON_PALETTE) + HELP_TEXT ("") + HELP_TEXT ("Opens a menu from where you have the") + HELP_TEXT ("following options:") + HELP_TEXT ("") + HELP_TEXT ("- Colors for best match:") + HELP_TEXT ("A menu in which you can select the colors") + HELP_TEXT ("that have not to be used for smoothing, for") + HELP_TEXT ("the transparency mode, and for remapping.") + HELP_TEXT ("") + HELP_TEXT ("- User's color series:") + HELP_TEXT ("A menu in which you can define color series") + HELP_TEXT ("for next/previous user color shortcuts.") + HELP_TEXT ("It's the same settings than the shade mode.") + HELP_TEXT ("After you have some color ranges defined in") + HELP_TEXT ("this screen, you can use those shortcuts to") + HELP_TEXT ("move to the next or previous color according") + HELP_TEXT ("to your ranges:") + HELP_TEXT ("") + HELP_TEXT ("Foreground color") + HELP_TEXT ("") + HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) + HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) + HELP_TEXT ("") + HELP_TEXT ("Background color") + HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) + HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT ("- Palette layout:") + HELP_TEXT ("Lets you customize the palette that appears") + HELP_TEXT ("on the right of the menu. You can choose the") + HELP_TEXT ("number of lines and columns.") + HELP_TEXT ("If you want the colors to run top to bottom,") + HELP_TEXT ("check the 'Vertical' button, otherwise the") + HELP_TEXT ("colors runs left to right.") + HELP_TEXT ("") + HELP_TEXT ("- RGB Scale:") + HELP_TEXT ("Lets you set the scale of the R G B sliders") + HELP_TEXT ("in the palette screen. You should normally") + HELP_TEXT ("leave it at 256 to get the full 0-255 range,") + HELP_TEXT ("but if you want to constrain the palette") + HELP_TEXT ("to the capabilities of some specific") + HELP_TEXT ("computers and consoles, you can choose eg:") + HELP_TEXT (" 64 : VGA") + HELP_TEXT (" 16 : Amiga") + HELP_TEXT (" 4 : MSX2") + HELP_TEXT (" 2 : Amstrad CPC") + }; +static const T_Help_table helptable_pal_scroll[] = +{ + + HELP_TITLE("SCROLL PAL") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_TEXT ("") + HELP_TEXT ("Scrolls the palette window in the right of") + HELP_TEXT ("the menu.") + HELP_LINK ("Key for back: %s", 0x100+BUTTON_PAL_LEFT) + HELP_LINK ("Key for forward: %s", 0x100+BUTTON_PAL_RIGHT) + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_TEXT ("") + HELP_TEXT ("Same as above, but faster.") + HELP_LINK ("Key for back: %s", 0x200+BUTTON_PAL_LEFT) + HELP_LINK ("Key for forward: %s", 0x200+BUTTON_PAL_RIGHT) + HELP_TEXT ("") +}; +static const T_Help_table helptable_color_select[] = +{ + + HELP_TITLE("PALETTE") + HELP_TEXT ("") + HELP_BOLD ("LEFT CLICK") + HELP_TEXT ("") + HELP_TEXT ("Defines the Fore-color.") + HELP_TEXT ("") + HELP_BOLD ("RIGHT CLICK") + HELP_TEXT ("") + HELP_TEXT ("Defines the Back-color.") +}; +static const T_Help_table helptable_hide[] = +{ + + HELP_TITLE("HIDE MENU") + HELP_TEXT ("") + HELP_TEXT ("Allows you to hide the menu. If you do this,") + HELP_TEXT ("take care to watch before the key to press") + HELP_TEXT ("to show the menu back (the key is") + HELP_LINK ("%s).",0x100+BUTTON_HIDE) + +}; + +#define HELP_TABLE_DECLARATION(x) {x, sizeof(x)/sizeof(const T_Help_table)}, + +T_Help_section Help_section[] = +{ + HELP_TABLE_DECLARATION(helptable_about) + HELP_TABLE_DECLARATION(helptable_licence) + HELP_TABLE_DECLARATION(helptable_help) + HELP_TABLE_DECLARATION(helptable_credits) + + // Attention, keep the same order as BUTTON_NUMBERS: + HELP_TABLE_DECLARATION(helptable_paintbrush) + HELP_TABLE_DECLARATION(helptable_adjust) + HELP_TABLE_DECLARATION(helptable_draw) + HELP_TABLE_DECLARATION(helptable_curves) + HELP_TABLE_DECLARATION(helptable_lines) + HELP_TABLE_DECLARATION(helptable_airbrush) + HELP_TABLE_DECLARATION(helptable_floodfill) + HELP_TABLE_DECLARATION(helptable_polygons) + HELP_TABLE_DECLARATION(helptable_polyfill) + HELP_TABLE_DECLARATION(helptable_rectangles) + HELP_TABLE_DECLARATION(helptable_filled_rectangles) + HELP_TABLE_DECLARATION(helptable_circles) + HELP_TABLE_DECLARATION(helptable_filled_circles) + HELP_TABLE_DECLARATION(helptable_grad_rect) + HELP_TABLE_DECLARATION(helptable_spheres) + HELP_TABLE_DECLARATION(helptable_brush) + HELP_TABLE_DECLARATION(helptable_polybrush) + HELP_TABLE_DECLARATION(helptable_brush_fx) + HELP_TABLE_DECLARATION(helptable_effects) + HELP_TABLE_DECLARATION(helptable_text) + HELP_TABLE_DECLARATION(helptable_magnifier) + HELP_TABLE_DECLARATION(helptable_colorpicker) + HELP_TABLE_DECLARATION(helptable_resolution) + HELP_TABLE_DECLARATION(helptable_page) + HELP_TABLE_DECLARATION(helptable_save) + HELP_TABLE_DECLARATION(helptable_load) + HELP_TABLE_DECLARATION(helptable_settings) + HELP_TABLE_DECLARATION(helptable_clear) + HELP_TABLE_DECLARATION(helptable_general) + HELP_TABLE_DECLARATION(helptable_undo) + HELP_TABLE_DECLARATION(helptable_kill) + HELP_TABLE_DECLARATION(helptable_quit) + HELP_TABLE_DECLARATION(helptable_palette) + HELP_TABLE_DECLARATION(helptable_pal_scroll) + HELP_TABLE_DECLARATION(helptable_pal_scroll) + HELP_TABLE_DECLARATION(helptable_color_select) + HELP_TABLE_DECLARATION(helptable_hide) +}; diff --git a/hotkeys.c b/hotkeys.c index 02a7bcb1..da8f0382 100644 --- a/hotkeys.c +++ b/hotkeys.c @@ -1,1334 +1,1334 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 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 "struct.h" -#include "global.h" -#include "hotkeys.h" - -T_Key_config ConfigKey[NB_SHORTCUTS] = { - {0, - "Scroll up", - "Scrolls the picture up, both in", - "magnify and normal mode.", - "", - false, - SDLK_UP, // HAUT - 0}, - {1, - "Scroll down", - "Scrolls the picture down, both in", - "magnify and normal mode.", - "", - false, - SDLK_DOWN, // BAS - 0}, - {2, - "Scroll left", - "Scrolls the picture to the left,", - "both in magnify and normal mode.", - "", - false, - SDLK_LEFT, // GAUCHE - 0}, - {3, - "Scroll right", - "Scrolls the picture to the right,", - "both in magnify and normal mode.", - "", - false, - SDLK_RIGHT, // DROITE - 0}, - {4, - "Faster scroll up", - "Used to scroll upwards in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_UP|MOD_SHIFT, // Shift + Haut - 0}, - {5, - "Faster scroll down", - "Used to scroll downwards in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_DOWN|MOD_SHIFT, // Shift + Bas - 0}, - {6, - "Faster scroll left", - "Used to scroll to the left in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_LEFT|MOD_SHIFT, // Shift + Gauche - 0}, - {7, - "Faster scroll right", - "Used to scroll to the right in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_RIGHT|MOD_SHIFT, // Shift + Droite - 0}, - {8, - "Slower scroll up", - "Used to scroll upwards in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_UP|MOD_ALT, // Alt + Haut - 0}, - {9, - "Slower scroll down", - "Used to scroll downwards in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_DOWN|MOD_ALT, // Alt + Bas - 0}, - {10, - "Slower scroll left", - "Used to scroll to the left in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_LEFT|MOD_ALT, // Alt + Gauche - 0}, - {11, - "Slower scroll right", - "Used to scroll to the right in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_RIGHT|MOD_ALT, // Alt + Droite - 0}, - {12, - "Move mouse cursor 1 pixel up", - "Used to simulate a very small mouse", - "deplacement up.It""s very useful", - "when you want ultra-high precision.", - true, - SDLK_UP|MOD_CTRL, // Ctrl + Haut - 0}, - {13, - "Move mouse cursor 1 pixel down", - "Used to simulate a very small mouse", - "deplacement down.It""s very useful", - "when you want ultra-high precision.", - true, - SDLK_DOWN|MOD_CTRL, // Ctrl + Bas - 0}, - {14, - "Move mouse cursor 1 pixel left", - "Used to simulate a very small mouse", - "deplacement left.It""s very useful", - "when you want ultra-high precision.", - true, - SDLK_LEFT|MOD_CTRL, // Ctrl + Gauche - 0}, - {15, - "Move mouse cursor 1 pixel right", - "Used to simulate a very small mouse", - "deplacement right.It""s very useful", - "when you want ultra-high precision.", - true, - SDLK_RIGHT|MOD_CTRL, // Ctrl + Droite - 0}, - {16, - "Simulate left mouse click", - "Used to simulate a click with the", - "left mouse button. It""s useful", - "when you want ultra-high precision.", - true, - SDLK_SPACE, // Space - 0}, - {17, - "Simulate right mouse click", - "Used to simulate a click with the", - "right mouse button.. It""s useful", - "when you want ultra-high precision.", - true, - SDLK_SPACE|MOD_SHIFT, // Shift + Space - 0}, - {18, - "Show/hide option menu", - "Switch the tool bar display on/off.", - "This hot-key cannot be removed.", - "", - false, - SDLK_F10, // F10 - 0}, - {19, - "Show/hide cursor", - "Switch the cursor display on/off.", - "This only works on the \"small cross\"", - "and \"hand\" cursors.", - true, - SDLK_F9, // F9 - 0}, - {20, - "Set paintbrush to 1 pixel", - "Useful when you want to use a", - "\"single-pixel-brush\".", - "", - true, - SDLK_DELETE, // Del - 0}, - {21, - "Paintbrush choice", - "Opens a menu where you can choose a", - "paintbrush out of 24 predefined", - "ones.", - true, - SDLK_F4, // F4 - 0}, - {22, - "Monochrome brush", - "Turn your current user-defined brush", - "into a single colored one. All non-", - "transparent colors are set to FG.", - true, - SDLK_F4|MOD_SHIFT, // Shift + F4 - 0}, - {23, - "Freehand drawing", - "Set the drawing mode to the", - "classical freehand one.", - "", - true, - SDLK_d, // D - 0}, - {24, - "Switch freehand drawing mode", - "Alternates between: continuous,", - "discontinuous, point by point,", - "and contour fill", - true, - SDLK_d|MOD_SHIFT, // Shift + D - 0}, - {25, - "Continuous freehand drawing", - "Switch directly to continuous", - "freehand drawing mode.", - "", - true, - SDLK_d|MOD_CTRL, // Ctrl + D - 0}, - {26, - "Line", - "Allows you to draw lines.", - "", - "", - true, - SDLK_l, // L - 0}, - {27, - "Knotted lines", - "Allows you to draw linked lines.", - "This mode can also be called", - "\"Polyline\".", - true, - SDLK_l|MOD_SHIFT, // Shift + L - 0}, - {28, - "Spray", - "Allows you to spray brushes", - "randomly in the picture.", - "", - true, - SDLK_a, // A (Q en AZERTY) - 0}, - {29, - "Spray menu", - "Opens a menu in which you can", - "configure the spray flow and size.", - "", - true, - SDLK_a|MOD_SHIFT, // Shift + A - 0}, - {30, - "Flood-fill", - "Allows you to fill an area of the", - "picture made of pixels of the same", - "color.", - true, - SDLK_f, // F - 0}, - {124, - "Replace color", - "This tool replaces all the pixels of", - "the clicked color to the fore-color", - "or the back-color.", - true, - SDLK_f|MOD_SHIFT, // Shift + F - 0}, - {31, - "Bezier""s curves", - "Allows you to draw Bezier""s curves.", - "", - "", - true, - SDLK_i, // I - 0}, - {32, - "Bezier""s curve with 3 or 4 points", - "Allows you to choose whether you", - "want to draw Bezier""s curves with", - "3 or 4 points.", - true, - SDLK_i|MOD_SHIFT, // Shift + I - 0}, - {33, - "Empty rectangle", - "Allows you to draw a rectangle using", - "the brush.", - "", - true, - SDLK_r, // R - 0}, - {34, - "Filled rectangle", - "Allows you to draw a filled", - "rectangle.", - "", - true, - SDLK_r|MOD_SHIFT, // Shift + R - 0}, - {35, - "Empty circle", - "Allows you to draw a circle using", - "the brush.", - "", - true, - SDLK_c, // C - 0}, - {36, - "Empty ellipse", - "Allows you to draw an ellipse using", - "the brush.", - "", - true, - SDLK_c|MOD_CTRL, // Ctrl + C - 0}, - {37, - "Filled circle", - "Allows you to draw a filled circle.", - "", - "", - true, - SDLK_c|MOD_SHIFT, // Shift + C - 0}, - {38, - "Filled ellipse", - "Allows you to draw a filled ellipse.", - "", - "", - true, - SDLK_c|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + C - 0}, - {39, - "Empty polygon", - "Allows you to draw a polygon using", - "the brush.", - "", - true, - SDLK_n, // N - 0}, - {40, - "Empty \"polyform\"", - "Allows you to draw a freehand", - "polygon using the brush.", - "", - true, - SDLK_n|MOD_CTRL, // Ctrl + N - 0}, - {41, - "Filled polygon", - "Allows you to draw a filled polygon.", - "", - "", - true, - SDLK_n|MOD_SHIFT, // Shift + N - 0}, - {42, - "Filled \"polyform\"", - "Allows you to draw a filled freehand", - "polygon.", - "", - true, - SDLK_n|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + N - 0}, - {43, - "Rectangle with gradation", - "Allows you to draw a rectangle with", - "a color gradation.", - "", - true, - SDLK_r|MOD_ALT, // Alt + R - 0}, - {44, - "Gradation menu", - "Allows you to configure the way", - "color gradations are calculated.", - "", - true, - SDLK_g|MOD_ALT, // Alt + G - 0}, - {45, - "Sphere with gradation", - "Allows you to draw a rectangle with", - "a color gradation.", - "", - true, - SDLK_c|MOD_ALT, // Alt + C - 0}, - {46, - "Ellipse with gradation", - "Allows you to draw an ellipse filled", - "with a color gradation.", - "", - true, - SDLK_c|MOD_SHIFT|MOD_ALT, // Shift + Alt + C - 0}, - {47, - "Adjust picture", - "Allows you to move the whole picture", - "Around. What gets out from a side", - "reappears on the other.", - true, - SDLK_KP5, // Kpad5 - 0}, - {48, - "Picture effects", - "Opens the 'Picture effects' window.", - "", - "", - true, - SDLK_KP5|MOD_SHIFT, // Shift + Kpad5 - 0}, - {49, - "Drawing effects", - "Opens a menu where you can enable/", - "disable and configure the drawing", - "effects.", - true, - SDLK_e, // E - 0}, - {50, - "Shade mode", - "Enables or disables Shade mode", - "", - "", - true, - SDLK_F5, // F5 - 0}, - {51, - "Shade menu", - "Opens a the menu for Shade settings.", - "", - "", - true, - SDLK_F5|MOD_SHIFT, // Shift + F5 - 0}, - {131, - "Quick-shade mode", - "Enables or disables Quick-shade", - "mode.", - "", - true, - SDLK_F5|MOD_CTRL, // Ctrl + F5 - 0}, - {132, - "Quick-shade menu", - "Opens a the menu for Quick-shade", - "settings.", - "", - true, - SDLK_F5|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + F5 - 0}, - {52, - "Stencil mode", - "Enables or disables Stencil mode.", - "", - "", - true, - SDLK_F6, // F6 - 0}, - {53, - "Stencil menu", - "Opens a the menu for Stencil", - "settings.", - "", - true, - SDLK_F6|MOD_SHIFT, // Shift + F6 - 0}, - {54, - "Mask mode", - "Enables or disables Mask mode.", - "", - "", - true, - SDLK_F6|MOD_ALT, // Alt + F6 - 0}, - {55, - "Mask menu", - "Opens a the menu for Mask settings.", - "", - "", - true, - SDLK_F6|MOD_SHIFT|MOD_ALT, // Shift + Alt + F6 - 0}, - {56, - "Grid mode", - "Enables or disables the Grid mode.", - "", - "", - true, - SDLK_g, // G - 0}, - {57, - "Grid menu", - "Open a menu where you can configure", - "the grid used by Grid mode.", - "", - true, - SDLK_g|MOD_SHIFT, // Shift + G - 0}, - {58, - "Sieve mode", - "Enables or disables the Sieve mode.", - "", - "", - true, - SDLK_g|MOD_CTRL, // Ctrl + G - 0}, - {59, - "Sieve menu", - "Opens a menu where you can configure", - "the sieve.", - "", - true, - SDLK_g|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + G - 0}, - {60, - "Invert sieve", - "Inverts the pattern defined in the", - "Sieve menu.", - "", - true, - SDLK_g|MOD_CTRL|MOD_ALT, // Ctrl + Alt + G - 0}, - {61, - "Colorize mode", - "Enables or disables the Colorize", - "mode.", - "", - true, - SDLK_F7, // F7 - 0}, - {62, - "Colorize menu", - "Opens a menu where you can give the", - "opacity percentage for Colorize", - "mode.", - true, - SDLK_F7|MOD_SHIFT, // Shift + F7 - 0}, - {63, - "Smooth mode", - "Enables or disables the Smooth", - "mode.", - "", - true, - SDLK_F8, // F8 - 0}, - {123, - "Smooth menu", - "Opens a menu where you can define", - "the Smooth matrix.", - "", - true, - SDLK_F8|MOD_SHIFT, // Shift + F8 - 0}, - {64, - "Smear mode", - "Enables or disables the Smear mode.", - "", - "", - true, - SDLK_F8|MOD_ALT, // Alt + F8 - 0}, - {65, - "Tiling mode", - "Enables or disables the Tiling", - "mode.", - "", - true, - SDLK_b|MOD_ALT, // Alt + B - 0}, - {66, - "Tiling menu", - "Opens a menu where you can configure", - "the origin of the tiling.", - "", - true, - SDLK_b|MOD_SHIFT|MOD_ALT, // Shift + Alt + B - 0}, - {67, - "Classical brush grabbing", - "Allows you to pick a brush defined", - "within a rectangle.", - "", - true, - SDLK_b, // B - 0}, - {68, - "\"Lasso\" brush grabbing", - "Allows you to pick a brush defined", - "within a freehand polygon.", - "", - true, - SDLK_b|MOD_CTRL, // Ctrl + B - 0}, - {69, - "Get previous brush back", - "Restore the last user-defined brush.", - "", - "", - true, - SDLK_b|MOD_SHIFT, // Shift + B - 0}, - {70, - "Horizontal brush flipping", - "Reverse brush horizontally.", - "", - "", - true, - SDLK_x, // X - 0}, - {71, - "Vertical brush flipping", - "Reverse brush vertically.", - "", - "", - true, - SDLK_y, // Y - 0}, - {72, - "90° brush rotation", - "Rotate the user-defined brush by 90°", - "(counter-clockwise).", - "", - true, - SDLK_z, // Z (W en AZERTY) - 0}, - {73, - "180° brush rotation", - "Rotate the user-defined brush by", - "180°.", - "", - true, - SDLK_z|MOD_SHIFT, // Shift + Z - 0}, - {74, - "Strech brush", - "Allows you to resize the", - "user-defined brush.", - "", - true, - SDLK_s, // S - 0}, - {75, - "Distort brush", - "Allows you to distort the", - "user-defined brush.", - "", - true, - SDLK_s|MOD_SHIFT, // Shift + S - 0}, - {76, - "Outline brush", - "Outlines the user-defined brush", - "with the fore color.", - "", - true, - SDLK_o, // O - 0}, - {77, - "Nibble brush", - "Deletes the borders of the", - "user-defined brush.This does the", - "opposite of the Outline option.", - true, - SDLK_o|MOD_SHIFT, // Shift + O - 0}, - {78, - "Get colors from brush", - "Copy colors of the spare page that", - "are used in the brush.", - "", - true, - SDLK_F11, // F11 - 0}, - {79, - "Recolorize brush", - "Recolorize the user-defined brush in", - "order to get a brush which looks as", - "if it was grabbed in the spare page.", - true, - SDLK_F12, // F12 - 0}, - {80, - "Rotate by any angle", - "Rotate the brush by an angle that", - "you can define.", - "", - true, - SDLK_w, // W (Z en AZERTY) - 0}, - {81, - "Pipette", - "Allows you to copy the color of a", - "pixel in the picture into the", - "foreground or background color.", - true, - SDLK_BACKQUOTE, // `~ (Key sous le Esc - ² en AZERTY) - 0}, - {82, - "Swap foreground/background colors", - "Invert foreground and background", - "colors.", - "", - true, - SDLK_BACKQUOTE|MOD_SHIFT, // Shift + `~ - 0}, - {83, - "Magnifier mode", - "Allows you to zoom into the picture.", - "", - "", - true, - SDLK_m, // M (, ? sur AZERTY) - KEY_MOUSEMIDDLE}, - {84, - "Zoom factor menu", - "Opens a menu where you can choose a", - "magnifying factor.", - "", - true, - SDLK_m|MOD_SHIFT, // Shift + M - 0}, - {85, - "Zoom in", - "Increase magnifying factor.", - "", - "", - true, - SDLK_KP_PLUS, // Grey + - KEY_MOUSEWHEELUP}, - {86, - "Zoom out", - "Decrease magnifying factor.", - "", - "", - true, - SDLK_KP_MINUS, // Grey - - KEY_MOUSEWHEELDOWN}, - {87, - "Brush effects menu", - "Opens a menu which proposes", - "different effects on the", - "user-defined brush.", - true, - SDLK_b|MOD_CTRL|MOD_ALT, // Ctrl + Alt + B - 0}, - {88, - "Text", - "Opens a menu which permits you to", - "type in a character string and", - "render it as a brush.", - true, - SDLK_t, // T - 0}, - {89, - "Screen resolution menu", - "Opens a menu where you can choose", - "the screen resolution and image", - "dimensions.", - true, - SDLK_RETURN, // Enter - 0}, - {90, - "\"Safety\" resolution", - "Resets the resolution to a 'safe'", - "mode that should work everywhere:", - "usually a 640x400 window.", - false, - SDLK_RETURN|MOD_SHIFT, // Shift + Enter - 0}, - {91, - "Help and credits", - "Opens a window where you can get", - "information about the program,", - "or contextual help.", - true, - SDLK_F1, // F1 - 0}, - {92, - "Statistics", - "Displays miscellaneous more or less", - "useful information.", - "", - true, - SDLK_F1|MOD_SHIFT, // Shift + F1 - 0}, - {93, - "Jump to spare page", - "Swap current page and spare page.", - "", - "", - true, - SDLK_TAB, // Tab - 0}, - {94, - "Copy current page to spare page", - "Copy current page to spare page.", - "", - "", - true, - SDLK_TAB|MOD_SHIFT, // Shift + Tab - 0}, - {95, - "Save picture as...", - "Opens a file-selector that allows", - "you to save your picture with a new", - "path-name.", - true, - SDLK_F2, // F2 - 0}, - {96, - "Save picture", - "Saves your picture with the last", - "name you gave it.", - "", - true, - SDLK_F2|MOD_SHIFT, // Shift + F2 - 0}, - {97, - "Load picture", - "Opens a file-selector that allows", - "you to load a new picture.", - "", - true, - SDLK_F3, // F3 - 0}, - {98, - "Re-load picture", - "Re-load the current picture. This", - "allows you to cancel modifications", - "made since last saving.", - true, - SDLK_F3|MOD_SHIFT, // Shift + F3 - 0}, - {99, - "Save brush", - "Opens a file-selector that allows", - "you to save your current", - "user-defined brush.", - true, - SDLK_F2|MOD_CTRL, // Ctrl + F2 - 0}, - {100, - "Load brush", - "Opens a file-selector that allows", - "you to load a brush.", - "", - true, - SDLK_F3|MOD_CTRL, // Ctrl + F3 - 0}, - {101, - "Settings", - "Opens a menu which permits you to", - "modify some parameters of the", - "program.", - true, - SDLK_F10|MOD_SHIFT, // Shift + F10 - 0}, - {102, - "Undo (Oops!)", - "Cancel the last action which", - "modified the picture.", - "", - true, - SDLK_u, // U - 0}, - {103, - "Redo", - "Redo the last undone action.", - "", - "", - true, - SDLK_u|MOD_SHIFT, // Shift + U - 0}, - {133, - "Kill", - "Kills the current page. It actually", - "removes the current page from the", - "list of \"Undo\" pages.", - true, - SDLK_DELETE|MOD_SHIFT, // Shift + Suppr - 0}, - {104, - "Clear page", - "Clears the picture with the first", - "color of the palette (usually black)", - "", - true, - SDLK_BACKSPACE, // BackSpace - 0}, - {105, - "Clear page with backcolor", - "Clears the picture with the", - "current backcolor.", - "", - true, - SDLK_BACKSPACE|MOD_SHIFT, // Shift + BackSpace - 0}, - {106, - "Quit program", - "Allows you to leave the program.", - "If modifications were not saved,", - "confirmation is asked.", - false, - SDLK_q, // Q (A en AZERTY) - 0}, - {107, - "Palette menu", - "Opens a menu which allows you to", - "modify the current palette.", - "", - true, - SDLK_p, // P - 0}, - {125, - "Secondary palette menu", - "Opens a menu which allows you to", - "define color series and some tagged", - "colors.", - true, - SDLK_p|MOD_SHIFT, // Shift + P - 0}, - {130, - "Exclude colors menu", - "Opens a menu which allows you to", - "define the colors you don""t want to", - "use in Smooth and Transparency", - true, - SDLK_p|MOD_CTRL, // Ctrl + P - 0}, - {108, - "Scroll palette to the left", - "Scroll palette in the tool bar to", - "the left, column by column.", - "", - true, - SDLK_PAGEUP, // PgUp - 0}, - {109, - "Scroll palette to the right", - "Scroll palette in the tool bar to", - "the right, column by column.", - "", - true, - SDLK_PAGEDOWN, // PgDn - 0}, - {110, - "Scroll palette to the left faster", - "Scroll palette in the tool bar to", - "the left, 8 columns by 8 columns.", - "", - true, - SDLK_PAGEUP|MOD_SHIFT, // Shift + PgUp - 0}, - {111, - "Scroll palette to the right faster", - "Scroll palette in the tool bar to", - "the right, 8 columns by 8 columns.", - "", - true, - SDLK_PAGEDOWN|MOD_SHIFT, // Shift + PgDn - 0}, - {112, - "Center brush attachment point", - "Set the attachement of the", - "user-defined brush to its center.", - "", - true, - SDLK_KP5|MOD_CTRL, // Ctrl + 5 (pavé numérique) - 0}, - {113, - "Top-left brush attachment point", - "Set the attachement of the", - "user-defined brush to its top-left", - "corner.", - true, - SDLK_HOME|MOD_CTRL, // Ctrl + 7 - 0}, - {114, - "Top-right brush attachment point", - "Set the attachement of the", - "user-defined brush to its top-right", - "corner.", - true, - SDLK_PAGEUP|MOD_CTRL, // Ctrl + 9 - 0}, - {115, - "Bottom-left brush attachment point", - "Set the attachement of the", - "user-defined brush to its", - "bottom-left corner.", - true, - SDLK_END|MOD_CTRL, // Ctrl + 1 - 0}, - {116, - "Bottom-right brush attachment point", - "Set the attachement of the", - "user-defined brush to its", - "bottom-right corner.", - true, - SDLK_PAGEDOWN|MOD_CTRL, // Ctrl + 3 - 0}, - {117, - "Next foreground color", - "Set the foreground color to the next", - "in the palette.", - "", - true, - SDLK_RIGHTBRACKET, // ] (0x en AZERTY) - 0}, - {118, - "Previous foreground color", - "Set the foreground color to the", - "previous in the palette.", - "", - true, - SDLK_LEFTBRACKET, // [ (^ en AZERTY) - 0}, - {119, - "Next background color", - "Set the background color to the next", - "in the palette.", - "", - true, - SDLK_RIGHTBRACKET|MOD_SHIFT, // Shift + ] - 0}, - {120, - "Previous background color", - "Set the background color to the", - "previous in the palette.", - "", - true, - SDLK_LEFTBRACKET|MOD_SHIFT, // Shift + [ - 0}, - {126, - "Next user-defined forecolor", - "Set the foreground color to the next", - "in the user-defined color series.", - "", - true, - SDLK_EQUALS, // "=+" - 0}, - {127, - "Previous user-defined forecolor", - "Set the foreground color to the", - "previous in the user-defined color", - "series.", - true, - SDLK_MINUS, // "-_" (")°" en AZERTY - 0}, - {128, - "Next user-defined backcolor", - "Set the background color to the next", - "in the user-defined color series.", - "", - true, - SDLK_EQUALS|MOD_SHIFT, // Shift + "=+" - 0}, - {129, - "Previous user-defined backcolor", - "Set the background color to the", - "previous in the user-defined color", - "series.", - true, - SDLK_MINUS|MOD_SHIFT, // Shift + "-_" (")°" en AZERTY - 0}, - {121, - "Shrink paintbrush", - "Decrease the width of the paintbrush", - "if it is special circle or square.", - "", - true, - SDLK_COMMA, // , < (;. en AZERTY) - 0}, - {122, - "Enlarge paintbrush", - "Increase the width of the paintbrush", - "if it is special circle or square.", - "", - true, - SDLK_PERIOD, // .> (:/ en AZERTY) - 0}, - {134, - "Effects off", - "Turns off all drawing effects. This", - "is the same as the 'All off' button", - "in the Effects screen", - true, - SDLK_e|MOD_SHIFT, // Shift-E - 0}, - {135, - "Transparency 10%", - "Turns transparency on and sets its", - "opacity at 10%.", - "", - true, - SDLK_1, // 1 - 0}, - {136, - "Transparency 20%", - "Turns transparency on and sets its", - "opacity at 20%.", - "", - true, - SDLK_2, // 2 - 0}, - {137, - "Transparency 30%", - "Turns transparency on and sets its", - "opacity at 30%.", - "", - true, - SDLK_3, // 3 - 0}, - {138, - "Transparency 40%", - "Turns transparency on and sets its", - "opacity at 40%.", - "", - true, - SDLK_4, // 4 - 0}, - {139, - "Transparency 50%", - "Turns transparency on and sets its", - "opacity at 50%.", - "", - true, - SDLK_5, // 5 - 0}, - {140, - "Transparency 60%", - "Turns transparency on and sets its", - "opacity at 60%.", - "", - true, - SDLK_6, // 6 - 0}, - {141, - "Transparency 70%", - "Turns transparency on and sets its", - "opacity at 70%.", - "", - true, - SDLK_7, // 7 - 0}, - {142, - "Transparency 80%", - "Turns transparency on and sets its", - "opacity at 80%.", - "", - true, - SDLK_8, // 8 - 0}, - {143, - "Transparency 90%", - "Turns transparency on and sets its", - "opacity at 90%.", - "", - true, - SDLK_9, // 9 - 0}, - {144, - "Transparency 0%", - "Turns transparency on and sets its", - "opacity at 0%.", - "", - true, - SDLK_0, // 0 - 0}, -}; - -word Ordering[NB_SHORTCUTS]= -{ - SPECIAL_SCROLL_UP, // Scroll up - SPECIAL_SCROLL_DOWN, // Scroll down - SPECIAL_SCROLL_LEFT, // Scroll left - SPECIAL_SCROLL_RIGHT, // Scroll right - SPECIAL_SCROLL_UP_FAST, // Scroll up faster - SPECIAL_SCROLL_DOWN_FAST, // Scroll down faster - SPECIAL_SCROLL_LEFT_FAST, // Scroll left faster - SPECIAL_SCROLL_RIGHT_FAST, // Scroll right faster - SPECIAL_SCROLL_UP_SLOW, // Scroll up slower - SPECIAL_SCROLL_DOWN_SLOW, // Scroll down slower - SPECIAL_SCROLL_LEFT_SLOW, // Scroll left slower - SPECIAL_SCROLL_RIGHT_SLOW, // Scroll right slower - SPECIAL_MOUSE_UP, // Emulate mouse up - SPECIAL_MOUSE_DOWN, // Emulate mouse down - SPECIAL_MOUSE_LEFT, // Emulate mouse left - SPECIAL_MOUSE_RIGHT, // Emulate mouse right - SPECIAL_CLICK_LEFT, // Emulate mouse click left - SPECIAL_CLICK_RIGHT, // Emulate mouse click right - 0x100+BUTTON_HIDE, // Show / Hide menu - SPECIAL_SHOW_HIDE_CURSOR, // Show / Hide cursor - SPECIAL_DOT_PAINTBRUSH, // Paintbrush = "." - 0x100+BUTTON_PAINTBRUSHES, // Paintbrush choice - 0x200+BUTTON_PAINTBRUSHES, // Monochrome brush - 0x100+BUTTON_DRAW, // Freehand drawing - 0x200+BUTTON_DRAW, // Switch freehand drawing mode - SPECIAL_CONTINUOUS_DRAW, // Continuous freehand drawing - 0x100+BUTTON_LINES, // Line - 0x200+BUTTON_LINES, // Knotted lines - 0x100+BUTTON_AIRBRUSH, // Spray - 0x200+BUTTON_AIRBRUSH, // Spray menu - 0x100+BUTTON_FLOODFILL, // Floodfill - 0x200+BUTTON_FLOODFILL, // Replace color - 0x100+BUTTON_CURVES, // Bézier's curves - 0x200+BUTTON_CURVES, // Bézier's curve with 3 or 4 points - 0x100+BUTTON_RECTANGLES, // Empty rectangle - 0x100+BUTTON_FILLRECT, // Filled rectangle - 0x100+BUTTON_CIRCLES, // Empty circle - 0x200+BUTTON_CIRCLES, // Empty ellipse - 0x100+BUTTON_FILLCIRC, // Filled circle - 0x200+BUTTON_FILLCIRC, // Filled ellipse - 0x100+BUTTON_POLYGONS, // Empty polygon - 0x200+BUTTON_POLYGONS, // Empty polyform - 0x100+BUTTON_POLYFILL, // Polyfill - 0x200+BUTTON_POLYFILL, // Filled polyform - 0x100+BUTTON_GRADRECT, // Gradient rectangle - 0x200+BUTTON_GRADRECT, // Gradation menu - 0x100+BUTTON_SPHERES, // Spheres - 0x200+BUTTON_SPHERES, // Gradient ellipses - 0x100+BUTTON_ADJUST, // Adjust picture - 0x200+BUTTON_ADJUST, // Flip picture menu - 0x100+BUTTON_EFFECTS, // Menu des effets - SPECIAL_SHADE_MODE, // Shade mode - SPECIAL_SHADE_MENU, // Shade menu - SPECIAL_QUICK_SHADE_MODE, // Quick-shade mode - SPECIAL_QUICK_SHADE_MENU, // Quick-shade menu - SPECIAL_STENCIL_MODE, // Stencil mode - SPECIAL_STENCIL_MENU, // Stencil menu - SPECIAL_MASK_MODE, // Mask mode - SPECIAL_MASK_MENU, // Mask menu - SPECIAL_GRID_MODE, // Grid mode - SPECIAL_GRID_MENU, // Grid menu - SPECIAL_SIEVE_MODE, // Sieve mode - SPECIAL_SIEVE_MENU, // Sieve menu - SPECIAL_INVERT_SIEVE, // Inverser la trame du mode Sieve - SPECIAL_COLORIZE_MODE, // Colorize mode - SPECIAL_COLORIZE_MENU, // Colorize menu - SPECIAL_SMOOTH_MODE, // Smooth mode - SPECIAL_SMOOTH_MENU, // Smooth menu - SPECIAL_SMEAR_MODE, // Smear mode - SPECIAL_TILING_MODE, // Tiling mode - SPECIAL_TILING_MENU, // Tiling menu - 0x100+BUTTON_BRUSH, // Pick brush - 0x100+BUTTON_POLYBRUSH, // Pick polyform brush - 0x200+BUTTON_BRUSH, // Restore brush - SPECIAL_FLIP_X, // Flip X - SPECIAL_FLIP_Y, // Flip Y - SPECIAL_ROTATE_90, // 90° brush rotation - SPECIAL_ROTATE_180, // 180° brush rotation - SPECIAL_STRETCH, // Stretch brush - SPECIAL_DISTORT, // Distort brush - SPECIAL_OUTLINE, // Outline brush - SPECIAL_NIBBLE, // Nibble brush - SPECIAL_GET_BRUSH_COLORS, // Get colors from brush - SPECIAL_RECOLORIZE_BRUSH, // Recolorize brush - SPECIAL_ROTATE_ANY_ANGLE, // Rotate brush by any angle - 0x100+BUTTON_COLORPICKER, // Pipette - 0x200+BUTTON_COLORPICKER, // Swap fore/back color - 0x100+BUTTON_MAGNIFIER, // Magnifier mode - 0x200+BUTTON_MAGNIFIER, // Zoom factor menu - SPECIAL_ZOOM_IN, // Zoom in - SPECIAL_ZOOM_OUT, // Zoom out - 0x100+BUTTON_BRUSH_EFFECTS, // Brush effects menu - 0x100+BUTTON_TEXT, // Text - 0x100+BUTTON_RESOL, // Resolution menu - 0x200+BUTTON_RESOL, // Safety resolution - 0x100+BUTTON_HELP, // Help & credits - 0x200+BUTTON_HELP, // Statistics - 0x100+BUTTON_PAGE, // Go to spare page - 0x200+BUTTON_PAGE, // Copy to spare page - 0x100+BUTTON_SAVE, // Save as - 0x200+BUTTON_SAVE, // Save - 0x100+BUTTON_LOAD, // Load - 0x200+BUTTON_LOAD, // Re-load - SPECIAL_SAVE_BRUSH, // Save brush - SPECIAL_LOAD_BRUSH, // Load brush - 0x100+BUTTON_SETTINGS, // Settings - 0x100+BUTTON_UNDO, // Undo - 0x200+BUTTON_UNDO, // Redo - 0x100+BUTTON_KILL, // Kill - 0x100+BUTTON_CLEAR, // Clear - 0x200+BUTTON_CLEAR, // Clear with backcolor - 0x100+BUTTON_QUIT, // Quit - 0x100+BUTTON_PALETTE, // Palette menu - 0x200+BUTTON_PALETTE, // Palette menu secondaire - SPECIAL_EXCLUDE_COLORS_MENU, // Exclude colors menu - 0x100+BUTTON_PAL_LEFT, // Scroll palette left - 0x100+BUTTON_PAL_RIGHT, // Scroll palette right - 0x200+BUTTON_PAL_LEFT, // Scroll palette left faster - 0x200+BUTTON_PAL_RIGHT, // Scroll palette right faster - SPECIAL_CENTER_ATTACHMENT, // Center brush attachement - SPECIAL_TOP_LEFT_ATTACHMENT, // Top-left brush attachement - SPECIAL_TOP_RIGHT_ATTACHMENT, // Top-right brush attachement - SPECIAL_BOTTOM_LEFT_ATTACHMENT, // Bottom-left brush attachement - SPECIAL_BOTTOM_RIGHT_ATTACHMENT, // Bottom right brush attachement - SPECIAL_NEXT_FORECOLOR, // Next foreground color - SPECIAL_PREVIOUS_FORECOLOR, // Previous foreground color - SPECIAL_NEXT_BACKCOLOR, // Next background color - SPECIAL_PREVIOUS_BACKCOLOR, // Previous background color - SPECIAL_NEXT_USER_FORECOLOR, // Next user-defined foreground color - SPECIAL_PREVIOUS_USER_FORECOLOR, // Previous user-defined foreground color - SPECIAL_NEXT_USER_BACKCOLOR, // Next user-defined background color - SPECIAL_PREVIOUS_USER_BACKCOLOR, // Previous user-defined background color - SPECIAL_SMALLER_PAINTBRUSH, // Sets paintbrush size: smaller - SPECIAL_BIGGER_PAINTBRUSH, // Sets paintbrush size: bigger - SPECIAL_EFFECTS_OFF, // Turns off all effects - SPECIAL_TRANSPARENCY_1, // Sets transparency level 10% - SPECIAL_TRANSPARENCY_2, // Sets transparency level 20% - SPECIAL_TRANSPARENCY_3, // Sets transparency level 30% - SPECIAL_TRANSPARENCY_4, // Sets transparency level 40% - SPECIAL_TRANSPARENCY_5, // Sets transparency level 50% - SPECIAL_TRANSPARENCY_6, // Sets transparency level 60% - SPECIAL_TRANSPARENCY_7, // Sets transparency level 70% - SPECIAL_TRANSPARENCY_8, // Sets transparency level 80% - SPECIAL_TRANSPARENCY_9, // Sets transparency level 90% - SPECIAL_TRANSPARENCY_0, // Sets transparency level 00% -}; +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2008 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 "struct.h" +#include "global.h" +#include "hotkeys.h" + +T_Key_config ConfigKey[NB_SHORTCUTS] = { + {0, + "Scroll up", + "Scrolls the picture up, both in", + "magnify and normal mode.", + "", + false, + SDLK_UP, // HAUT + 0}, + {1, + "Scroll down", + "Scrolls the picture down, both in", + "magnify and normal mode.", + "", + false, + SDLK_DOWN, // BAS + 0}, + {2, + "Scroll left", + "Scrolls the picture to the left,", + "both in magnify and normal mode.", + "", + false, + SDLK_LEFT, // GAUCHE + 0}, + {3, + "Scroll right", + "Scrolls the picture to the right,", + "both in magnify and normal mode.", + "", + false, + SDLK_RIGHT, // DROITE + 0}, + {4, + "Faster scroll up", + "Used to scroll upwards in the", + "picture fast, either in magnify and", + "normal mode.", + true, + SDLK_UP|MOD_SHIFT, // Shift + Haut + 0}, + {5, + "Faster scroll down", + "Used to scroll downwards in the", + "picture fast, either in magnify and", + "normal mode.", + true, + SDLK_DOWN|MOD_SHIFT, // Shift + Bas + 0}, + {6, + "Faster scroll left", + "Used to scroll to the left in the", + "picture fast, either in magnify and", + "normal mode.", + true, + SDLK_LEFT|MOD_SHIFT, // Shift + Gauche + 0}, + {7, + "Faster scroll right", + "Used to scroll to the right in the", + "picture fast, either in magnify and", + "normal mode.", + true, + SDLK_RIGHT|MOD_SHIFT, // Shift + Droite + 0}, + {8, + "Slower scroll up", + "Used to scroll upwards in the", + "picture pixel by pixel, either in", + "magnify and normal mode.", + true, + SDLK_UP|MOD_ALT, // Alt + Haut + 0}, + {9, + "Slower scroll down", + "Used to scroll downwards in the", + "picture pixel by pixel, either in", + "magnify and normal mode.", + true, + SDLK_DOWN|MOD_ALT, // Alt + Bas + 0}, + {10, + "Slower scroll left", + "Used to scroll to the left in the", + "picture pixel by pixel, either in", + "magnify and normal mode.", + true, + SDLK_LEFT|MOD_ALT, // Alt + Gauche + 0}, + {11, + "Slower scroll right", + "Used to scroll to the right in the", + "picture pixel by pixel, either in", + "magnify and normal mode.", + true, + SDLK_RIGHT|MOD_ALT, // Alt + Droite + 0}, + {12, + "Move mouse cursor 1 pixel up", + "Used to simulate a very small mouse", + "deplacement up.It""s very useful", + "when you want ultra-high precision.", + true, + SDLK_UP|MOD_CTRL, // Ctrl + Haut + 0}, + {13, + "Move mouse cursor 1 pixel down", + "Used to simulate a very small mouse", + "deplacement down.It""s very useful", + "when you want ultra-high precision.", + true, + SDLK_DOWN|MOD_CTRL, // Ctrl + Bas + 0}, + {14, + "Move mouse cursor 1 pixel left", + "Used to simulate a very small mouse", + "deplacement left.It""s very useful", + "when you want ultra-high precision.", + true, + SDLK_LEFT|MOD_CTRL, // Ctrl + Gauche + 0}, + {15, + "Move mouse cursor 1 pixel right", + "Used to simulate a very small mouse", + "deplacement right.It""s very useful", + "when you want ultra-high precision.", + true, + SDLK_RIGHT|MOD_CTRL, // Ctrl + Droite + 0}, + {16, + "Simulate left mouse click", + "Used to simulate a click with the", + "left mouse button. It""s useful", + "when you want ultra-high precision.", + true, + SDLK_SPACE, // Space + 0}, + {17, + "Simulate right mouse click", + "Used to simulate a click with the", + "right mouse button.. It""s useful", + "when you want ultra-high precision.", + true, + SDLK_SPACE|MOD_SHIFT, // Shift + Space + 0}, + {18, + "Show/hide option menu", + "Switch the tool bar display on/off.", + "This hot-key cannot be removed.", + "", + false, + SDLK_F10, // F10 + 0}, + {19, + "Show/hide cursor", + "Switch the cursor display on/off.", + "This only works on the \"small cross\"", + "and \"hand\" cursors.", + true, + SDLK_F9, // F9 + 0}, + {20, + "Set paintbrush to 1 pixel", + "Useful when you want to use a", + "\"single-pixel-brush\".", + "", + true, + SDLK_DELETE, // Del + 0}, + {21, + "Paintbrush choice", + "Opens a menu where you can choose a", + "paintbrush out of 24 predefined", + "ones.", + true, + SDLK_F4, // F4 + 0}, + {22, + "Monochrome brush", + "Turn your current user-defined brush", + "into a single colored one. All non-", + "transparent colors are set to FG.", + true, + SDLK_F4|MOD_SHIFT, // Shift + F4 + 0}, + {23, + "Freehand drawing", + "Set the drawing mode to the", + "classical freehand one.", + "", + true, + SDLK_d, // D + 0}, + {24, + "Switch freehand drawing mode", + "Alternates between: continuous,", + "discontinuous, point by point,", + "and contour fill", + true, + SDLK_d|MOD_SHIFT, // Shift + D + 0}, + {25, + "Continuous freehand drawing", + "Switch directly to continuous", + "freehand drawing mode.", + "", + true, + SDLK_d|MOD_CTRL, // Ctrl + D + 0}, + {26, + "Line", + "Allows you to draw lines.", + "", + "", + true, + SDLK_l, // L + 0}, + {27, + "Knotted lines", + "Allows you to draw linked lines.", + "This mode can also be called", + "\"Polyline\".", + true, + SDLK_l|MOD_SHIFT, // Shift + L + 0}, + {28, + "Spray", + "Allows you to spray brushes", + "randomly in the picture.", + "", + true, + SDLK_a, // A (Q en AZERTY) + 0}, + {29, + "Spray menu", + "Opens a menu in which you can", + "configure the spray flow and size.", + "", + true, + SDLK_a|MOD_SHIFT, // Shift + A + 0}, + {30, + "Flood-fill", + "Allows you to fill an area of the", + "picture made of pixels of the same", + "color.", + true, + SDLK_f, // F + 0}, + {124, + "Replace color", + "This tool replaces all the pixels of", + "the clicked color to the fore-color", + "or the back-color.", + true, + SDLK_f|MOD_SHIFT, // Shift + F + 0}, + {31, + "Bezier""s curves", + "Allows you to draw Bezier""s curves.", + "", + "", + true, + SDLK_i, // I + 0}, + {32, + "Bezier""s curve with 3 or 4 points", + "Allows you to choose whether you", + "want to draw Bezier""s curves with", + "3 or 4 points.", + true, + SDLK_i|MOD_SHIFT, // Shift + I + 0}, + {33, + "Empty rectangle", + "Allows you to draw a rectangle using", + "the brush.", + "", + true, + SDLK_r, // R + 0}, + {34, + "Filled rectangle", + "Allows you to draw a filled", + "rectangle.", + "", + true, + SDLK_r|MOD_SHIFT, // Shift + R + 0}, + {35, + "Empty circle", + "Allows you to draw a circle using", + "the brush.", + "", + true, + SDLK_c, // C + 0}, + {36, + "Empty ellipse", + "Allows you to draw an ellipse using", + "the brush.", + "", + true, + SDLK_c|MOD_CTRL, // Ctrl + C + 0}, + {37, + "Filled circle", + "Allows you to draw a filled circle.", + "", + "", + true, + SDLK_c|MOD_SHIFT, // Shift + C + 0}, + {38, + "Filled ellipse", + "Allows you to draw a filled ellipse.", + "", + "", + true, + SDLK_c|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + C + 0}, + {39, + "Empty polygon", + "Allows you to draw a polygon using", + "the brush.", + "", + true, + SDLK_n, // N + 0}, + {40, + "Empty \"polyform\"", + "Allows you to draw a freehand", + "polygon using the brush.", + "", + true, + SDLK_n|MOD_CTRL, // Ctrl + N + 0}, + {41, + "Filled polygon", + "Allows you to draw a filled polygon.", + "", + "", + true, + SDLK_n|MOD_SHIFT, // Shift + N + 0}, + {42, + "Filled \"polyform\"", + "Allows you to draw a filled freehand", + "polygon.", + "", + true, + SDLK_n|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + N + 0}, + {43, + "Rectangle with gradation", + "Allows you to draw a rectangle with", + "a color gradation.", + "", + true, + SDLK_r|MOD_ALT, // Alt + R + 0}, + {44, + "Gradation menu", + "Allows you to configure the way", + "color gradations are calculated.", + "", + true, + SDLK_g|MOD_ALT, // Alt + G + 0}, + {45, + "Sphere with gradation", + "Allows you to draw a rectangle with", + "a color gradation.", + "", + true, + SDLK_c|MOD_ALT, // Alt + C + 0}, + {46, + "Ellipse with gradation", + "Allows you to draw an ellipse filled", + "with a color gradation.", + "", + true, + SDLK_c|MOD_SHIFT|MOD_ALT, // Shift + Alt + C + 0}, + {47, + "Adjust picture", + "Allows you to move the whole picture", + "Around. What gets out from a side", + "reappears on the other.", + true, + SDLK_KP5, // Kpad5 + 0}, + {48, + "Picture effects", + "Opens the 'Picture effects' window.", + "", + "", + true, + SDLK_KP5|MOD_SHIFT, // Shift + Kpad5 + 0}, + {49, + "Drawing effects", + "Opens a menu where you can enable/", + "disable and configure the drawing", + "effects.", + true, + SDLK_e, // E + 0}, + {50, + "Shade mode", + "Enables or disables Shade mode", + "", + "", + true, + SDLK_F5, // F5 + 0}, + {51, + "Shade menu", + "Opens a the menu for Shade settings.", + "", + "", + true, + SDLK_F5|MOD_SHIFT, // Shift + F5 + 0}, + {131, + "Quick-shade mode", + "Enables or disables Quick-shade", + "mode.", + "", + true, + SDLK_F5|MOD_CTRL, // Ctrl + F5 + 0}, + {132, + "Quick-shade menu", + "Opens a the menu for Quick-shade", + "settings.", + "", + true, + SDLK_F5|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + F5 + 0}, + {52, + "Stencil mode", + "Enables or disables Stencil mode.", + "", + "", + true, + SDLK_F6, // F6 + 0}, + {53, + "Stencil menu", + "Opens a the menu for Stencil", + "settings.", + "", + true, + SDLK_F6|MOD_SHIFT, // Shift + F6 + 0}, + {54, + "Mask mode", + "Enables or disables Mask mode.", + "", + "", + true, + SDLK_F6|MOD_ALT, // Alt + F6 + 0}, + {55, + "Mask menu", + "Opens a the menu for Mask settings.", + "", + "", + true, + SDLK_F6|MOD_SHIFT|MOD_ALT, // Shift + Alt + F6 + 0}, + {56, + "Grid mode", + "Enables or disables the Grid mode.", + "", + "", + true, + SDLK_g, // G + 0}, + {57, + "Grid menu", + "Open a menu where you can configure", + "the grid used by Grid mode.", + "", + true, + SDLK_g|MOD_SHIFT, // Shift + G + 0}, + {58, + "Sieve mode", + "Enables or disables the Sieve mode.", + "", + "", + true, + SDLK_g|MOD_CTRL, // Ctrl + G + 0}, + {59, + "Sieve menu", + "Opens a menu where you can configure", + "the sieve.", + "", + true, + SDLK_g|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + G + 0}, + {60, + "Invert sieve", + "Inverts the pattern defined in the", + "Sieve menu.", + "", + true, + SDLK_g|MOD_CTRL|MOD_ALT, // Ctrl + Alt + G + 0}, + {61, + "Colorize mode", + "Enables or disables the Colorize", + "mode.", + "", + true, + SDLK_F7, // F7 + 0}, + {62, + "Colorize menu", + "Opens a menu where you can give the", + "opacity percentage for Colorize", + "mode.", + true, + SDLK_F7|MOD_SHIFT, // Shift + F7 + 0}, + {63, + "Smooth mode", + "Enables or disables the Smooth", + "mode.", + "", + true, + SDLK_F8, // F8 + 0}, + {123, + "Smooth menu", + "Opens a menu where you can define", + "the Smooth matrix.", + "", + true, + SDLK_F8|MOD_SHIFT, // Shift + F8 + 0}, + {64, + "Smear mode", + "Enables or disables the Smear mode.", + "", + "", + true, + SDLK_F8|MOD_ALT, // Alt + F8 + 0}, + {65, + "Tiling mode", + "Enables or disables the Tiling", + "mode.", + "", + true, + SDLK_b|MOD_ALT, // Alt + B + 0}, + {66, + "Tiling menu", + "Opens a menu where you can configure", + "the origin of the tiling.", + "", + true, + SDLK_b|MOD_SHIFT|MOD_ALT, // Shift + Alt + B + 0}, + {67, + "Classical brush grabbing", + "Allows you to pick a brush defined", + "within a rectangle.", + "", + true, + SDLK_b, // B + 0}, + {68, + "\"Lasso\" brush grabbing", + "Allows you to pick a brush defined", + "within a freehand polygon.", + "", + true, + SDLK_b|MOD_CTRL, // Ctrl + B + 0}, + {69, + "Get previous brush back", + "Restore the last user-defined brush.", + "", + "", + true, + SDLK_b|MOD_SHIFT, // Shift + B + 0}, + {70, + "Horizontal brush flipping", + "Reverse brush horizontally.", + "", + "", + true, + SDLK_x, // X + 0}, + {71, + "Vertical brush flipping", + "Reverse brush vertically.", + "", + "", + true, + SDLK_y, // Y + 0}, + {72, + "90° brush rotation", + "Rotate the user-defined brush by 90°", + "(counter-clockwise).", + "", + true, + SDLK_z, // Z (W en AZERTY) + 0}, + {73, + "180° brush rotation", + "Rotate the user-defined brush by", + "180°.", + "", + true, + SDLK_z|MOD_SHIFT, // Shift + Z + 0}, + {74, + "Strech brush", + "Allows you to resize the", + "user-defined brush.", + "", + true, + SDLK_s, // S + 0}, + {75, + "Distort brush", + "Allows you to distort the", + "user-defined brush.", + "", + true, + SDLK_s|MOD_SHIFT, // Shift + S + 0}, + {76, + "Outline brush", + "Outlines the user-defined brush", + "with the fore color.", + "", + true, + SDLK_o, // O + 0}, + {77, + "Nibble brush", + "Deletes the borders of the", + "user-defined brush.This does the", + "opposite of the Outline option.", + true, + SDLK_o|MOD_SHIFT, // Shift + O + 0}, + {78, + "Get colors from brush", + "Copy colors of the spare page that", + "are used in the brush.", + "", + true, + SDLK_F11, // F11 + 0}, + {79, + "Recolorize brush", + "Recolorize the user-defined brush in", + "order to get a brush which looks as", + "if it was grabbed in the spare page.", + true, + SDLK_F12, // F12 + 0}, + {80, + "Rotate by any angle", + "Rotate the brush by an angle that", + "you can define.", + "", + true, + SDLK_w, // W (Z en AZERTY) + 0}, + {81, + "Pipette", + "Allows you to copy the color of a", + "pixel in the picture into the", + "foreground or background color.", + true, + SDLK_BACKQUOTE, // `~ (Key sous le Esc - ² en AZERTY) + 0}, + {82, + "Swap foreground/background colors", + "Invert foreground and background", + "colors.", + "", + true, + SDLK_BACKQUOTE|MOD_SHIFT, // Shift + `~ + 0}, + {83, + "Magnifier mode", + "Allows you to zoom into the picture.", + "", + "", + true, + SDLK_m, // M (, ? sur AZERTY) + KEY_MOUSEMIDDLE}, + {84, + "Zoom factor menu", + "Opens a menu where you can choose a", + "magnifying factor.", + "", + true, + SDLK_m|MOD_SHIFT, // Shift + M + 0}, + {85, + "Zoom in", + "Increase magnifying factor.", + "", + "", + true, + SDLK_KP_PLUS, // Grey + + KEY_MOUSEWHEELUP}, + {86, + "Zoom out", + "Decrease magnifying factor.", + "", + "", + true, + SDLK_KP_MINUS, // Grey - + KEY_MOUSEWHEELDOWN}, + {87, + "Brush effects menu", + "Opens a menu which proposes", + "different effects on the", + "user-defined brush.", + true, + SDLK_b|MOD_CTRL|MOD_ALT, // Ctrl + Alt + B + 0}, + {88, + "Text", + "Opens a menu which permits you to", + "type in a character string and", + "render it as a brush.", + true, + SDLK_t, // T + 0}, + {89, + "Screen resolution menu", + "Opens a menu where you can choose", + "the screen resolution and image", + "dimensions.", + true, + SDLK_RETURN, // Enter + 0}, + {90, + "\"Safety\" resolution", + "Resets the resolution to a 'safe'", + "mode that should work everywhere:", + "usually a 640x400 window.", + false, + SDLK_RETURN|MOD_SHIFT, // Shift + Enter + 0}, + {91, + "Help and credits", + "Opens a window where you can get", + "information about the program,", + "or contextual help.", + true, + SDLK_F1, // F1 + 0}, + {92, + "Statistics", + "Displays miscellaneous more or less", + "useful information.", + "", + true, + SDLK_F1|MOD_SHIFT, // Shift + F1 + 0}, + {93, + "Jump to spare page", + "Swap current page and spare page.", + "", + "", + true, + SDLK_TAB, // Tab + 0}, + {94, + "Copy current page to spare page", + "Copy current page to spare page.", + "", + "", + true, + SDLK_TAB|MOD_SHIFT, // Shift + Tab + 0}, + {95, + "Save picture as...", + "Opens a file-selector that allows", + "you to save your picture with a new", + "path-name.", + true, + SDLK_F2, // F2 + 0}, + {96, + "Save picture", + "Saves your picture with the last", + "name you gave it.", + "", + true, + SDLK_F2|MOD_SHIFT, // Shift + F2 + 0}, + {97, + "Load picture", + "Opens a file-selector that allows", + "you to load a new picture.", + "", + true, + SDLK_F3, // F3 + 0}, + {98, + "Re-load picture", + "Re-load the current picture. This", + "allows you to cancel modifications", + "made since last saving.", + true, + SDLK_F3|MOD_SHIFT, // Shift + F3 + 0}, + {99, + "Save brush", + "Opens a file-selector that allows", + "you to save your current", + "user-defined brush.", + true, + SDLK_F2|MOD_CTRL, // Ctrl + F2 + 0}, + {100, + "Load brush", + "Opens a file-selector that allows", + "you to load a brush.", + "", + true, + SDLK_F3|MOD_CTRL, // Ctrl + F3 + 0}, + {101, + "Settings", + "Opens a menu which permits you to", + "modify some parameters of the", + "program.", + true, + SDLK_F10|MOD_SHIFT, // Shift + F10 + 0}, + {102, + "Undo (Oops!)", + "Cancel the last action which", + "modified the picture.", + "", + true, + SDLK_u, // U + 0}, + {103, + "Redo", + "Redo the last undone action.", + "", + "", + true, + SDLK_u|MOD_SHIFT, // Shift + U + 0}, + {133, + "Kill", + "Kills the current page. It actually", + "removes the current page from the", + "list of \"Undo\" pages.", + true, + SDLK_DELETE|MOD_SHIFT, // Shift + Suppr + 0}, + {104, + "Clear page", + "Clears the picture with the first", + "color of the palette (usually black)", + "", + true, + SDLK_BACKSPACE, // BackSpace + 0}, + {105, + "Clear page with backcolor", + "Clears the picture with the", + "current backcolor.", + "", + true, + SDLK_BACKSPACE|MOD_SHIFT, // Shift + BackSpace + 0}, + {106, + "Quit program", + "Allows you to leave the program.", + "If modifications were not saved,", + "confirmation is asked.", + false, + SDLK_q, // Q (A en AZERTY) + 0}, + {107, + "Palette menu", + "Opens a menu which allows you to", + "modify the current palette.", + "", + true, + SDLK_p, // P + 0}, + {125, + "Secondary palette menu", + "Opens a menu which allows you to", + "define color series and some tagged", + "colors.", + true, + SDLK_p|MOD_SHIFT, // Shift + P + 0}, + {130, + "Exclude colors menu", + "Opens a menu which allows you to", + "define the colors you don""t want to", + "use in Smooth and Transparency", + true, + SDLK_p|MOD_CTRL, // Ctrl + P + 0}, + {108, + "Scroll palette to the left", + "Scroll palette in the tool bar to", + "the left, column by column.", + "", + true, + SDLK_PAGEUP, // PgUp + 0}, + {109, + "Scroll palette to the right", + "Scroll palette in the tool bar to", + "the right, column by column.", + "", + true, + SDLK_PAGEDOWN, // PgDn + 0}, + {110, + "Scroll palette to the left faster", + "Scroll palette in the tool bar to", + "the left, 8 columns by 8 columns.", + "", + true, + SDLK_PAGEUP|MOD_SHIFT, // Shift + PgUp + 0}, + {111, + "Scroll palette to the right faster", + "Scroll palette in the tool bar to", + "the right, 8 columns by 8 columns.", + "", + true, + SDLK_PAGEDOWN|MOD_SHIFT, // Shift + PgDn + 0}, + {112, + "Center brush attachment point", + "Set the attachement of the", + "user-defined brush to its center.", + "", + true, + SDLK_KP5|MOD_CTRL, // Ctrl + 5 (pavé numérique) + 0}, + {113, + "Top-left brush attachment point", + "Set the attachement of the", + "user-defined brush to its top-left", + "corner.", + true, + SDLK_HOME|MOD_CTRL, // Ctrl + 7 + 0}, + {114, + "Top-right brush attachment point", + "Set the attachement of the", + "user-defined brush to its top-right", + "corner.", + true, + SDLK_PAGEUP|MOD_CTRL, // Ctrl + 9 + 0}, + {115, + "Bottom-left brush attachment point", + "Set the attachement of the", + "user-defined brush to its", + "bottom-left corner.", + true, + SDLK_END|MOD_CTRL, // Ctrl + 1 + 0}, + {116, + "Bottom-right brush attachment point", + "Set the attachement of the", + "user-defined brush to its", + "bottom-right corner.", + true, + SDLK_PAGEDOWN|MOD_CTRL, // Ctrl + 3 + 0}, + {117, + "Next foreground color", + "Set the foreground color to the next", + "in the palette.", + "", + true, + SDLK_RIGHTBRACKET, // ] (0x en AZERTY) + 0}, + {118, + "Previous foreground color", + "Set the foreground color to the", + "previous in the palette.", + "", + true, + SDLK_LEFTBRACKET, // [ (^ en AZERTY) + 0}, + {119, + "Next background color", + "Set the background color to the next", + "in the palette.", + "", + true, + SDLK_RIGHTBRACKET|MOD_SHIFT, // Shift + ] + 0}, + {120, + "Previous background color", + "Set the background color to the", + "previous in the palette.", + "", + true, + SDLK_LEFTBRACKET|MOD_SHIFT, // Shift + [ + 0}, + {126, + "Next user-defined forecolor", + "Set the foreground color to the next", + "in the user-defined color series.", + "", + true, + SDLK_EQUALS, // "=+" + 0}, + {127, + "Previous user-defined forecolor", + "Set the foreground color to the", + "previous in the user-defined color", + "series.", + true, + SDLK_MINUS, // "-_" (")°" en AZERTY + 0}, + {128, + "Next user-defined backcolor", + "Set the background color to the next", + "in the user-defined color series.", + "", + true, + SDLK_EQUALS|MOD_SHIFT, // Shift + "=+" + 0}, + {129, + "Previous user-defined backcolor", + "Set the background color to the", + "previous in the user-defined color", + "series.", + true, + SDLK_MINUS|MOD_SHIFT, // Shift + "-_" (")°" en AZERTY + 0}, + {121, + "Shrink paintbrush", + "Decrease the width of the paintbrush", + "if it is special circle or square.", + "", + true, + SDLK_COMMA, // , < (;. en AZERTY) + 0}, + {122, + "Enlarge paintbrush", + "Increase the width of the paintbrush", + "if it is special circle or square.", + "", + true, + SDLK_PERIOD, // .> (:/ en AZERTY) + 0}, + {134, + "Effects off", + "Turns off all drawing effects. This", + "is the same as the 'All off' button", + "in the Effects screen", + true, + SDLK_e|MOD_SHIFT, // Shift-E + 0}, + {135, + "Transparency 10%", + "Turns transparency on and sets its", + "opacity at 10%.", + "", + true, + SDLK_1, // 1 + 0}, + {136, + "Transparency 20%", + "Turns transparency on and sets its", + "opacity at 20%.", + "", + true, + SDLK_2, // 2 + 0}, + {137, + "Transparency 30%", + "Turns transparency on and sets its", + "opacity at 30%.", + "", + true, + SDLK_3, // 3 + 0}, + {138, + "Transparency 40%", + "Turns transparency on and sets its", + "opacity at 40%.", + "", + true, + SDLK_4, // 4 + 0}, + {139, + "Transparency 50%", + "Turns transparency on and sets its", + "opacity at 50%.", + "", + true, + SDLK_5, // 5 + 0}, + {140, + "Transparency 60%", + "Turns transparency on and sets its", + "opacity at 60%.", + "", + true, + SDLK_6, // 6 + 0}, + {141, + "Transparency 70%", + "Turns transparency on and sets its", + "opacity at 70%.", + "", + true, + SDLK_7, // 7 + 0}, + {142, + "Transparency 80%", + "Turns transparency on and sets its", + "opacity at 80%.", + "", + true, + SDLK_8, // 8 + 0}, + {143, + "Transparency 90%", + "Turns transparency on and sets its", + "opacity at 90%.", + "", + true, + SDLK_9, // 9 + 0}, + {144, + "Transparency 0%", + "Turns transparency on and sets its", + "opacity at 0%.", + "", + true, + SDLK_0, // 0 + 0}, +}; + +word Ordering[NB_SHORTCUTS]= +{ + SPECIAL_SCROLL_UP, // Scroll up + SPECIAL_SCROLL_DOWN, // Scroll down + SPECIAL_SCROLL_LEFT, // Scroll left + SPECIAL_SCROLL_RIGHT, // Scroll right + SPECIAL_SCROLL_UP_FAST, // Scroll up faster + SPECIAL_SCROLL_DOWN_FAST, // Scroll down faster + SPECIAL_SCROLL_LEFT_FAST, // Scroll left faster + SPECIAL_SCROLL_RIGHT_FAST, // Scroll right faster + SPECIAL_SCROLL_UP_SLOW, // Scroll up slower + SPECIAL_SCROLL_DOWN_SLOW, // Scroll down slower + SPECIAL_SCROLL_LEFT_SLOW, // Scroll left slower + SPECIAL_SCROLL_RIGHT_SLOW, // Scroll right slower + SPECIAL_MOUSE_UP, // Emulate mouse up + SPECIAL_MOUSE_DOWN, // Emulate mouse down + SPECIAL_MOUSE_LEFT, // Emulate mouse left + SPECIAL_MOUSE_RIGHT, // Emulate mouse right + SPECIAL_CLICK_LEFT, // Emulate mouse click left + SPECIAL_CLICK_RIGHT, // Emulate mouse click right + 0x100+BUTTON_HIDE, // Show / Hide menu + SPECIAL_SHOW_HIDE_CURSOR, // Show / Hide cursor + SPECIAL_DOT_PAINTBRUSH, // Paintbrush = "." + 0x100+BUTTON_PAINTBRUSHES, // Paintbrush choice + 0x200+BUTTON_PAINTBRUSHES, // Monochrome brush + 0x100+BUTTON_DRAW, // Freehand drawing + 0x200+BUTTON_DRAW, // Switch freehand drawing mode + SPECIAL_CONTINUOUS_DRAW, // Continuous freehand drawing + 0x100+BUTTON_LINES, // Line + 0x200+BUTTON_LINES, // Knotted lines + 0x100+BUTTON_AIRBRUSH, // Spray + 0x200+BUTTON_AIRBRUSH, // Spray menu + 0x100+BUTTON_FLOODFILL, // Floodfill + 0x200+BUTTON_FLOODFILL, // Replace color + 0x100+BUTTON_CURVES, // Bézier's curves + 0x200+BUTTON_CURVES, // Bézier's curve with 3 or 4 points + 0x100+BUTTON_RECTANGLES, // Empty rectangle + 0x100+BUTTON_FILLRECT, // Filled rectangle + 0x100+BUTTON_CIRCLES, // Empty circle + 0x200+BUTTON_CIRCLES, // Empty ellipse + 0x100+BUTTON_FILLCIRC, // Filled circle + 0x200+BUTTON_FILLCIRC, // Filled ellipse + 0x100+BUTTON_POLYGONS, // Empty polygon + 0x200+BUTTON_POLYGONS, // Empty polyform + 0x100+BUTTON_POLYFILL, // Polyfill + 0x200+BUTTON_POLYFILL, // Filled polyform + 0x100+BUTTON_GRADRECT, // Gradient rectangle + 0x200+BUTTON_GRADRECT, // Gradation menu + 0x100+BUTTON_SPHERES, // Spheres + 0x200+BUTTON_SPHERES, // Gradient ellipses + 0x100+BUTTON_ADJUST, // Adjust picture + 0x200+BUTTON_ADJUST, // Flip picture menu + 0x100+BUTTON_EFFECTS, // Menu des effets + SPECIAL_SHADE_MODE, // Shade mode + SPECIAL_SHADE_MENU, // Shade menu + SPECIAL_QUICK_SHADE_MODE, // Quick-shade mode + SPECIAL_QUICK_SHADE_MENU, // Quick-shade menu + SPECIAL_STENCIL_MODE, // Stencil mode + SPECIAL_STENCIL_MENU, // Stencil menu + SPECIAL_MASK_MODE, // Mask mode + SPECIAL_MASK_MENU, // Mask menu + SPECIAL_GRID_MODE, // Grid mode + SPECIAL_GRID_MENU, // Grid menu + SPECIAL_SIEVE_MODE, // Sieve mode + SPECIAL_SIEVE_MENU, // Sieve menu + SPECIAL_INVERT_SIEVE, // Inverser la trame du mode Sieve + SPECIAL_COLORIZE_MODE, // Colorize mode + SPECIAL_COLORIZE_MENU, // Colorize menu + SPECIAL_SMOOTH_MODE, // Smooth mode + SPECIAL_SMOOTH_MENU, // Smooth menu + SPECIAL_SMEAR_MODE, // Smear mode + SPECIAL_TILING_MODE, // Tiling mode + SPECIAL_TILING_MENU, // Tiling menu + 0x100+BUTTON_BRUSH, // Pick brush + 0x100+BUTTON_POLYBRUSH, // Pick polyform brush + 0x200+BUTTON_BRUSH, // Restore brush + SPECIAL_FLIP_X, // Flip X + SPECIAL_FLIP_Y, // Flip Y + SPECIAL_ROTATE_90, // 90° brush rotation + SPECIAL_ROTATE_180, // 180° brush rotation + SPECIAL_STRETCH, // Stretch brush + SPECIAL_DISTORT, // Distort brush + SPECIAL_OUTLINE, // Outline brush + SPECIAL_NIBBLE, // Nibble brush + SPECIAL_GET_BRUSH_COLORS, // Get colors from brush + SPECIAL_RECOLORIZE_BRUSH, // Recolorize brush + SPECIAL_ROTATE_ANY_ANGLE, // Rotate brush by any angle + 0x100+BUTTON_COLORPICKER, // Pipette + 0x200+BUTTON_COLORPICKER, // Swap fore/back color + 0x100+BUTTON_MAGNIFIER, // Magnifier mode + 0x200+BUTTON_MAGNIFIER, // Zoom factor menu + SPECIAL_ZOOM_IN, // Zoom in + SPECIAL_ZOOM_OUT, // Zoom out + 0x100+BUTTON_BRUSH_EFFECTS, // Brush effects menu + 0x100+BUTTON_TEXT, // Text + 0x100+BUTTON_RESOL, // Resolution menu + 0x200+BUTTON_RESOL, // Safety resolution + 0x100+BUTTON_HELP, // Help & credits + 0x200+BUTTON_HELP, // Statistics + 0x100+BUTTON_PAGE, // Go to spare page + 0x200+BUTTON_PAGE, // Copy to spare page + 0x100+BUTTON_SAVE, // Save as + 0x200+BUTTON_SAVE, // Save + 0x100+BUTTON_LOAD, // Load + 0x200+BUTTON_LOAD, // Re-load + SPECIAL_SAVE_BRUSH, // Save brush + SPECIAL_LOAD_BRUSH, // Load brush + 0x100+BUTTON_SETTINGS, // Settings + 0x100+BUTTON_UNDO, // Undo + 0x200+BUTTON_UNDO, // Redo + 0x100+BUTTON_KILL, // Kill + 0x100+BUTTON_CLEAR, // Clear + 0x200+BUTTON_CLEAR, // Clear with backcolor + 0x100+BUTTON_QUIT, // Quit + 0x100+BUTTON_PALETTE, // Palette menu + 0x200+BUTTON_PALETTE, // Palette menu secondaire + SPECIAL_EXCLUDE_COLORS_MENU, // Exclude colors menu + 0x100+BUTTON_PAL_LEFT, // Scroll palette left + 0x100+BUTTON_PAL_RIGHT, // Scroll palette right + 0x200+BUTTON_PAL_LEFT, // Scroll palette left faster + 0x200+BUTTON_PAL_RIGHT, // Scroll palette right faster + SPECIAL_CENTER_ATTACHMENT, // Center brush attachement + SPECIAL_TOP_LEFT_ATTACHMENT, // Top-left brush attachement + SPECIAL_TOP_RIGHT_ATTACHMENT, // Top-right brush attachement + SPECIAL_BOTTOM_LEFT_ATTACHMENT, // Bottom-left brush attachement + SPECIAL_BOTTOM_RIGHT_ATTACHMENT, // Bottom right brush attachement + SPECIAL_NEXT_FORECOLOR, // Next foreground color + SPECIAL_PREVIOUS_FORECOLOR, // Previous foreground color + SPECIAL_NEXT_BACKCOLOR, // Next background color + SPECIAL_PREVIOUS_BACKCOLOR, // Previous background color + SPECIAL_NEXT_USER_FORECOLOR, // Next user-defined foreground color + SPECIAL_PREVIOUS_USER_FORECOLOR, // Previous user-defined foreground color + SPECIAL_NEXT_USER_BACKCOLOR, // Next user-defined background color + SPECIAL_PREVIOUS_USER_BACKCOLOR, // Previous user-defined background color + SPECIAL_SMALLER_PAINTBRUSH, // Sets paintbrush size: smaller + SPECIAL_BIGGER_PAINTBRUSH, // Sets paintbrush size: bigger + SPECIAL_EFFECTS_OFF, // Turns off all effects + SPECIAL_TRANSPARENCY_1, // Sets transparency level 10% + SPECIAL_TRANSPARENCY_2, // Sets transparency level 20% + SPECIAL_TRANSPARENCY_3, // Sets transparency level 30% + SPECIAL_TRANSPARENCY_4, // Sets transparency level 40% + SPECIAL_TRANSPARENCY_5, // Sets transparency level 50% + SPECIAL_TRANSPARENCY_6, // Sets transparency level 60% + SPECIAL_TRANSPARENCY_7, // Sets transparency level 70% + SPECIAL_TRANSPARENCY_8, // Sets transparency level 80% + SPECIAL_TRANSPARENCY_9, // Sets transparency level 90% + SPECIAL_TRANSPARENCY_0, // Sets transparency level 00% +}; diff --git a/init.h b/init.h index 86053986..6031eef6 100644 --- a/init.h +++ b/init.h @@ -1,42 +1,42 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file init.h -/// Initialization (and some de-initialization) functions. -////////////////////////////////////////////////////////////////////////////// - -T_Gui_skin *Load_graphics(const char * skin_file); -void Init_buttons(void); -void Init_operations(void); -int Load_CFG(int reload_all); -int Save_CFG(void); -void Set_all_video_modes(void); -void Set_config_defaults(void); -void Init_sighandler(void); - -extern char Gui_loading_error_message[512]; - -/// -/// Loads a 8x8 monochrome font, the kind used in all menus and screens. -/// This function allocates the memory, and returns a pointer to it when -/// successful. -/// If an error is encountered, it frees what needs it, prints an error message -/// in ::Gui_loading_error_message, and returns NULL. -byte * Load_font(const char * font_name); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file init.h +/// Initialization (and some de-initialization) functions. +////////////////////////////////////////////////////////////////////////////// + +T_Gui_skin *Load_graphics(const char * skin_file); +void Init_buttons(void); +void Init_operations(void); +int Load_CFG(int reload_all); +int Save_CFG(void); +void Set_all_video_modes(void); +void Set_config_defaults(void); +void Init_sighandler(void); + +extern char Gui_loading_error_message[512]; + +/// +/// Loads a 8x8 monochrome font, the kind used in all menus and screens. +/// This function allocates the memory, and returns a pointer to it when +/// successful. +/// If an error is encountered, it frees what needs it, prints an error message +/// in ::Gui_loading_error_message, and returns NULL. +byte * Load_font(const char * font_name); diff --git a/keyboard.c b/keyboard.c index a9de06a3..5582d931 100644 --- a/keyboard.c +++ b/keyboard.c @@ -1,650 +1,650 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Franck Charlet - Copyright 2008 Yves Rizoud - 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 "global.h" -#include "keyboard.h" - -// Table de correspondance des scancode de clavier IBM PC AT vers -// les symboles de touches SDL (sym). -// La correspondance est bonne si le clavier est QWERTY US, ou si -// l'utilisateur est sous Windows. -// Dans l'ordre des colonnes: Normal, +Shift, +Control, +Alt -const word Scancode_to_sym[256][4] = -{ -/* 00 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 01 Esc */ { SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE }, -/* 02 1 ! */ { SDLK_1 ,SDLK_1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 03 2 @ */ { SDLK_2 ,SDLK_2 ,SDLK_2 ,SDLK_UNKNOWN }, -/* 04 3 # */ { SDLK_3 ,SDLK_3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 05 4 $ */ { SDLK_4 ,SDLK_4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 06 5 % */ { SDLK_5 ,SDLK_5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 07 6 ^ */ { SDLK_6 ,SDLK_6 ,SDLK_6 ,SDLK_UNKNOWN }, -/* 08 7 & */ { SDLK_7 ,SDLK_7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 09 8 * */ { SDLK_8 ,SDLK_8 ,SDLK_8 ,SDLK_UNKNOWN }, -/* 0A 9 ( */ { SDLK_9 ,SDLK_9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 0B 0 ) */ { SDLK_0 ,SDLK_0 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 0C - _ */ { SDLK_MINUS ,SDLK_MINUS ,SDLK_MINUS ,SDLK_UNKNOWN }, -/* 0D = + */ { SDLK_EQUALS ,SDLK_EQUALS ,SDLK_EQUALS ,SDLK_UNKNOWN }, -/* 0E BkSpc */ { SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE }, -/* 0F Tab */ { SDLK_TAB ,SDLK_TAB ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 10 Q */ { SDLK_q ,SDLK_q ,SDLK_q ,SDLK_q }, -/* 11 W */ { SDLK_w ,SDLK_w ,SDLK_w ,SDLK_w }, -/* 12 E */ { SDLK_e ,SDLK_e ,SDLK_e ,SDLK_e }, -/* 13 R */ { SDLK_r ,SDLK_r ,SDLK_r ,SDLK_r }, -/* 14 T */ { SDLK_t ,SDLK_t ,SDLK_t ,SDLK_t }, -/* 15 Y */ { SDLK_y ,SDLK_y ,SDLK_y ,SDLK_y }, -/* 16 U */ { SDLK_u ,SDLK_u ,SDLK_u ,SDLK_u }, -/* 17 I */ { SDLK_i ,SDLK_i ,SDLK_i ,SDLK_i }, -/* 18 O */ { SDLK_o ,SDLK_o ,SDLK_o ,SDLK_o }, -/* 19 P */ { SDLK_p ,SDLK_p ,SDLK_p ,SDLK_p }, -/* 1A [ */ { SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET }, -/* 1B ] */ { SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET}, -/* 1C Retrn */ { SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN }, -/* 1D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 1E A */ { SDLK_a ,SDLK_a ,SDLK_a ,SDLK_a }, -/* 1F S */ { SDLK_s ,SDLK_s ,SDLK_s ,SDLK_s }, -/* 20 D */ { SDLK_d ,SDLK_d ,SDLK_d ,SDLK_d }, -/* 21 F */ { SDLK_f ,SDLK_f ,SDLK_f ,SDLK_f }, -/* 22 G */ { SDLK_g ,SDLK_g ,SDLK_g ,SDLK_g }, -/* 23 H */ { SDLK_h ,SDLK_h ,SDLK_h ,SDLK_h }, -/* 24 J */ { SDLK_j ,SDLK_j ,SDLK_j ,SDLK_j }, -/* 25 K */ { SDLK_k ,SDLK_k ,SDLK_k ,SDLK_k }, -/* 26 L */ { SDLK_l ,SDLK_l ,SDLK_l ,SDLK_l }, -/* 27 ; : */ { SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON }, -/* 28 ' */ { SDLK_QUOTE ,SDLK_QUOTE ,SDLK_UNKNOWN ,SDLK_QUOTE }, -/* 29 ` ~ */ { SDLK_BACKQUOTE ,SDLK_BACKQUOTE ,SDLK_UNKNOWN ,SDLK_BACKQUOTE }, -/* 2A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 2B \\ */ { SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH }, -/* 2C Z */ { SDLK_z ,SDLK_z ,SDLK_z ,SDLK_z }, -/* 2D X */ { SDLK_x ,SDLK_x ,SDLK_x ,SDLK_x }, -/* 2E C */ { SDLK_c ,SDLK_c ,SDLK_c ,SDLK_c }, -/* 2F V */ { SDLK_v ,SDLK_v ,SDLK_v ,SDLK_v }, -/* 30 B */ { SDLK_b ,SDLK_b ,SDLK_b ,SDLK_b }, -/* 31 N */ { SDLK_n ,SDLK_n ,SDLK_n ,SDLK_n }, -/* 32 M */ { SDLK_m ,SDLK_m ,SDLK_m ,SDLK_m }, -/* 33 , < */ { SDLK_COMMA ,SDLK_COMMA ,SDLK_UNKNOWN ,SDLK_COMMA }, -/* 34 . > */ { SDLK_PERIOD ,SDLK_PERIOD ,SDLK_UNKNOWN ,SDLK_PERIOD }, -/* 35 / ? */ { SDLK_SLASH ,SDLK_SLASH ,SDLK_UNKNOWN ,SDLK_SLASH }, -/* 36 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 37 Grey* */ { SDLK_KP_MULTIPLY ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY }, -/* 38 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 39 Space */ { SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE }, -/* 3A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3B F1 */ { SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3C F2 */ { SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3D F3 */ { SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3E F4 */ { SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3F F5 */ { SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 40 F6 */ { SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 41 F7 */ { SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 42 F8 */ { SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 43 F9 */ { SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 44 F10 */ { SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 45 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 46 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 47 Home */ { SDLK_HOME ,SDLK_HOME ,SDLK_UNKNOWN ,SDLK_HOME }, -/* 48 Up */ { SDLK_UP ,SDLK_UP ,SDLK_UNKNOWN ,SDLK_UP }, -/* 49 PgUp */ { SDLK_PAGEUP ,SDLK_PAGEUP ,SDLK_UNKNOWN ,SDLK_PAGEUP }, -/* 4A Grey- */ { SDLK_KP_MINUS ,SDLK_KP_MINUS ,SDLK_UNKNOWN ,SDLK_KP_MINUS }, -/* 4B Left */ { SDLK_LEFT ,SDLK_LEFT ,SDLK_UNKNOWN ,SDLK_LEFT }, -/* 4C Kpad5 */ { SDLK_KP5 ,SDLK_KP5 ,SDLK_UNKNOWN ,SDLK_KP5 }, -/* 4D Right */ { SDLK_RIGHT ,SDLK_RIGHT ,SDLK_UNKNOWN ,SDLK_RIGHT }, -/* 4E Grey+ */ { SDLK_KP_PLUS ,SDLK_KP_PLUS ,SDLK_UNKNOWN ,SDLK_KP_PLUS }, -/* 4F End */ { SDLK_END ,SDLK_END ,SDLK_UNKNOWN ,SDLK_END }, -/* 50 Down */ { SDLK_DOWN ,SDLK_DOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, -/* 51 PgDn */ { SDLK_PAGEDOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN }, -/* 52 Ins */ { SDLK_INSERT ,SDLK_INSERT ,SDLK_UNKNOWN ,SDLK_INSERT }, -/* 53 Del */ { SDLK_DELETE ,SDLK_DELETE ,SDLK_UNKNOWN ,SDLK_DELETE }, -/* 54 ??? */ { SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 55 ??? */ { SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 56 Lft| */ { SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 57 ??? */ { SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 58 ??? */ { SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 59 ??? */ { SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5A ??? */ { SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5B ??? */ { SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5C ??? */ { SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5D ??? */ { SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN }, -/* 5F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN }, -/* 60 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN }, -/* 61 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN }, -/* 62 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN }, -/* 63 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN }, -/* 64 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN }, -/* 65 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN }, -/* 66 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN }, -/* 67 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN }, -/* 68 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 }, -/* 69 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 }, -/* 6A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 }, -/* 6B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 }, -/* 6C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 }, -/* 6D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 }, -/* 6E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 }, -/* 6F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 }, -/* 70 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 }, -/* 71 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 }, -/* 72 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 73 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT ,SDLK_UNKNOWN }, -/* 74 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT ,SDLK_UNKNOWN }, -/* 75 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END ,SDLK_UNKNOWN }, -/* 76 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN }, -/* 77 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME ,SDLK_UNKNOWN }, -/* 78 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_1 }, -/* 79 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_2 }, -/* 7A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_3 }, -/* 7B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_4 }, -/* 7C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_5 }, -/* 7D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_6 }, -/* 7E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_7 }, -/* 7F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_8 }, -/* 80 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_9 }, -/* 81 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_0 }, -/* 82 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MINUS }, -/* 83 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_EQUALS }, -/* 84 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP ,SDLK_UNKNOWN }, -/* 85 F11 */ { SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 86 F12 */ { SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 87 ??? */ { SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 88 ??? */ { SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 89 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN }, -/* 8A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN }, -/* 8B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 }, -/* 8C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 }, -/* 8D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP ,SDLK_UNKNOWN }, -/* 8E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MINUS ,SDLK_UNKNOWN }, -/* 8F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP5 ,SDLK_UNKNOWN }, -/* 90 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_PLUS ,SDLK_UNKNOWN }, -/* 91 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN ,SDLK_UNKNOWN }, -/* 92 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT ,SDLK_UNKNOWN }, -/* 93 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE ,SDLK_UNKNOWN }, -/* 94 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB ,SDLK_UNKNOWN }, -/* 95 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE ,SDLK_UNKNOWN }, -/* 96 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN }, -/* 97 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME }, -/* 98 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP }, -/* 99 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, -/* 9A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 9B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT }, -/* 9C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 9D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT }, -/* 9E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 9F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END }, -/* A0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, -/* A1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, -/* A2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT }, -/* A3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE }, -/* A4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE }, -/* A5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB }, -/* A6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_ENTER }, -/* A7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* A8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* A9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B6 Win L */ { SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B7 Win R */ { SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B8 Win M */ { SDLK_MENU ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C2 ??? */ { SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C3 ??? */ { SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN }, -/* CF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN }, -/* D0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU ,SDLK_UNKNOWN }, -/* D1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* DA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER }, -/* DB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER }, -/* DC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU }, -/* DD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* DE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* DF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E0 Enter */ { SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_UNKNOWN }, -/* E1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* ED ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -}; - -// Conversion de l'ancien codage des touches: -// 0x00FF le scancode (maintenant code sym sur 0x0FFF) -// 0x0100 shift (maintenant 0x1000) -// 0x0200 control (maintenant 0x2000) -// 0x0400 alt (maintenant 0x4000) -word Key_for_scancode(word scancode) -{ - if (scancode & 0x0400) - return Scancode_to_sym[scancode & 0xFF][3] | - (scancode & 0x0700) << 4; - else if (scancode & 0x0200) - return Scancode_to_sym[scancode & 0xFF][2] | - (scancode & 0x0700) << 4; - else if (scancode & 0x0100) - return Scancode_to_sym[scancode & 0xFF][1] | - (scancode & 0x0700) << 4; - else - return Scancode_to_sym[scancode & 0xFF][0]; -} - -// Convertit des modificateurs de touches SDL en modificateurs GrafX2 -word Key_modifiers(SDLMod mod) -{ - word modifiers=0; - - if (mod & KMOD_CTRL ) - modifiers|=MOD_CTRL; - if (mod & KMOD_SHIFT ) - modifiers|=MOD_SHIFT; - if (mod & (KMOD_ALT|KMOD_MODE)) - modifiers|=MOD_ALT; - if (mod & (KMOD_META)) - modifiers|=MOD_META; - - return modifiers; -} - -word Keysym_to_keycode(SDL_keysym keysym) -{ - word key_code = 0; - word mod; - - // On ignore shift, alt et control isolés. - if (keysym.sym == SDLK_RSHIFT || keysym.sym == SDLK_LSHIFT || - keysym.sym == SDLK_RCTRL || keysym.sym == SDLK_LCTRL || - keysym.sym == SDLK_RALT || keysym.sym == SDLK_LALT || - keysym.sym == SDLK_RMETA || keysym.sym == SDLK_LMETA || - keysym.sym == SDLK_MODE) // AltGr - return 0; - - // Les touches qui n'ont qu'une valeur unicode (très rares) - // seront codées sur 11 bits, le 12e bit est mis à 1 (0x0800) - if (keysym.sym != 0) - key_code = keysym.sym; - else if (keysym.scancode != 0) - { - key_code = (keysym.scancode & 0x07FF) | 0x0800; - } - - // Normally I should test keysym.mod here, but on windows the implementation - // is buggy: if you release a modifier key, the following keys (when they repeat) - // still name the original modifiers. - mod=Key_modifiers(SDL_GetModState()); - - // SDL_GetModState() seems to get the right up-to-date info. - key_code |= mod; - return key_code; -} - -const char * Key_name(word Key) -{ - typedef struct - { - word keysym; - char *Key_name; - } T_key_label; - T_key_label key_labels[] = - { - { SDLK_BACKSPACE , "Backspace" }, - { SDLK_TAB , "Tab" }, - { SDLK_CLEAR , "Clear" }, - { SDLK_RETURN , "Return" }, - { SDLK_PAUSE , "Pause" }, - { SDLK_ESCAPE , "Esc" }, - { SDLK_DELETE , "Del" }, - { SDLK_KP0 , "KP 0" }, - { SDLK_KP1 , "KP 1" }, - { SDLK_KP2 , "KP 2" }, - { SDLK_KP3 , "KP 3" }, - { SDLK_KP4 , "KP 4" }, - { SDLK_KP5 , "KP 5" }, - { SDLK_KP6 , "KP 6" }, - { SDLK_KP7 , "KP 7" }, - { SDLK_KP8 , "KP 8" }, - { SDLK_KP9 , "KP 9" }, - { SDLK_KP_PERIOD , "KP ." }, - { SDLK_KP_DIVIDE , "KP /" }, - { SDLK_KP_MULTIPLY, "KP *" }, - { SDLK_KP_MINUS , "KP -" }, - { SDLK_KP_PLUS , "KP +" }, - { SDLK_KP_ENTER , "KP Enter" }, - { SDLK_KP_EQUALS , "KP =" }, - { SDLK_UP , "Up" }, - { SDLK_DOWN , "Down" }, - { SDLK_RIGHT , "Right" }, - { SDLK_LEFT , "Left" }, - { SDLK_INSERT , "Ins" }, - { SDLK_HOME , "Home" }, - { SDLK_END , "End" }, - { SDLK_PAGEUP , "PgUp" }, - { SDLK_PAGEDOWN , "PgDn" }, - { SDLK_F1 , "F1" }, - { SDLK_F2 , "F2" }, - { SDLK_F3 , "F3" }, - { SDLK_F4 , "F4" }, - { SDLK_F5 , "F5" }, - { SDLK_F6 , "F6" }, - { SDLK_F7 , "F7" }, - { SDLK_F8 , "F8" }, - { SDLK_F9 , "F9" }, - { SDLK_F10 , "F10" }, - { SDLK_F11 , "F11" }, - { SDLK_F12 , "F12" }, - { SDLK_F13 , "F13" }, - { SDLK_F14 , "F14" }, - { SDLK_F15 , "F15" }, - { SDLK_NUMLOCK , "NumLock" }, - { SDLK_CAPSLOCK , "CapsLck" }, - { SDLK_SCROLLOCK , "ScrlLock" }, - { SDLK_RSHIFT , "RShift" }, - { SDLK_LSHIFT , "LShift" }, - { SDLK_RCTRL , "RCtrl" }, - { SDLK_LCTRL , "LCtrl" }, - { SDLK_RALT , "RAlt" }, - { SDLK_LALT , "LAlt" }, - { SDLK_RMETA , "RMeta" }, - { SDLK_LMETA , "LMeta" }, - { SDLK_LSUPER , "LWin" }, - { SDLK_RSUPER , "RWin" }, - { SDLK_MODE , "AltGr" }, - { SDLK_COMPOSE , "Comp" }, - { SDLK_HELP , "Help" }, - { SDLK_PRINT , "Print" }, - { SDLK_SYSREQ , "SysReq" }, - { SDLK_BREAK , "Break" }, - { SDLK_MENU , "Menu" }, - { SDLK_POWER , "Power" }, - { SDLK_EURO , "Euro" }, - { SDLK_UNDO , "Undo" }, - { KEY_MOUSEMIDDLE, "Mouse3" }, - { KEY_MOUSEWHEELUP, "WheelUp" }, - { KEY_MOUSEWHEELDOWN, "WheelDown" } - }; - - int index; - static char buffer[41]; - buffer[0] = '\0'; - - if (Key == SDLK_UNKNOWN) - return "None"; - - if (Key & MOD_CTRL) - strcat(buffer, "Ctrl+"); - if (Key & MOD_ALT) - strcat(buffer, "Alt+"); - if (Key & MOD_SHIFT) - strcat(buffer, "Shift+"); - if (Key & MOD_META) - strcat(buffer, "\201"); - // Note: Apple's "command" character is not present in the ANSI table, so we - // recycled an ANSI value that doesn't have any displayable character - // associated. - - - Key=Key & ~(MOD_CTRL|MOD_ALT|MOD_SHIFT); - - if (Key>=KEY_JOYBUTTON && Key<=KEY_JOYBUTTON+18) - { -#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; - } - strcat(buffer,button_name); -#else - sprintf(buffer+strlen(buffer), "[B%d]", Key-KEY_JOYBUTTON); -#endif - return buffer; - } - - if (Key & 0x800) - { - sprintf(buffer+strlen(buffer), "[%d]", Key & 0x7FF); - return buffer; - } - Key = Key & 0x7FF; - // Touches ASCII - if (Key>=' ' && Key < 127) - { - sprintf(buffer+strlen(buffer), "'%c'", toupper(Key)); - return buffer; - } - // Touches 'World' - if (Key>=SDLK_WORLD_0 && Key <= SDLK_WORLD_95) - { - sprintf(buffer+strlen(buffer), "w%d", Key - SDLK_WORLD_0); - return buffer; - } - - // Touches au libellé connu - for (index=0; index < (long)sizeof(key_labels)/(long)sizeof(T_key_label);index++) - { - if (Key == key_labels[index].keysym) - { - sprintf(buffer+strlen(buffer), "%s", key_labels[index].Key_name); - return buffer; - } - } - // Autres touches inconnues - sprintf(buffer+strlen(buffer), "0x%X", Key & 0x7FF); - return buffer; - -} - -// Obtient le caractère ANSI tapé, à partir d'un keysym. -// (Valeur 32 à 255) -// Renvoie 0 s'il n'y a pas de caractère associé (shift, backspace, etc) -word Keysym_to_ANSI(SDL_keysym keysym) -{ - // This part was removed from the MacOSX port, but I put it back for others - // as on Linux and Windows, it's what allows editing a text line with the keys - // SDLK_LEFT, SDLK_RIGHT, SDLK_HOME, SDLK_END etc. - #if !(defined(__macosx__) || defined(__FreeBSD__)) - if ( keysym.unicode == 0) - { - switch(keysym.sym) - { - case SDLK_DELETE: - case SDLK_LEFT: - case SDLK_RIGHT: - case SDLK_HOME: - case SDLK_END: - case SDLK_BACKSPACE: - case KEY_ESC: - case SDLK_RETURN: - return keysym.sym; - default: - return 0; - } - } - #endif - // - if ( keysym.unicode > 32 && keysym.unicode < 127) - { - return keysym.unicode; // Pas de souci, on est en ASCII standard - } - - // Quelques conversions Unicode-ANSI - switch(keysym.unicode) - { - case 0x8100: - return 'ü'; // ü - case 0x1A20: - return 'é'; // é - case 0x201A: - return 'è'; // è - case 0x9201: - return 'â'; // â - case 0x1E20: - return 'ä'; // ä - case 0x2620: - return 'à'; // à - case 0x2020: - return 'å'; // å - case 0x2120: - return 'ç'; // ç - case 0xC602: - return 'ê'; // ê - case 0x3020: - return 'ë'; // ë - case 0x6001: - return 'è'; // è - case 0x3920: - return 'ï'; // ï - case 0x5201: - return 'î'; // î - case 0x8D00: - return 'ì'; // ì - case 0x1C20: - return 'ô'; // ô - case 0x1D20: - return 'ö'; // ö - case 0x2220: - return 'ò'; // ò - case 0x1320: - return 'û'; // û - case 0x1420: - return 'ù'; // ù - case 0xDC02: - return 'ÿ'; // ÿ - case 0x5301: - return '£'; // £ - case 0xA000: - return 'á'; // á - case 0xA100: - return 'í'; // í - case 0xA200: - return 'ó'; // ó - case 0xA300: - return 'ú'; // ú - case 0xA400: - return 'ñ'; // ñ - case 0xA700: - return 'º'; // º - case 0xC600: - return 'ã'; // ã - } - - // Key entre 127 et 255 - if (keysym.unicode<256) - { -#if defined(__macosx__) || defined(__FreeBSD__) - // fc: Looks like there's a mismatch with delete & backspace - // i don't why SDLK_DELETE was returned instead of SDLK_BACKSPACE - if(keysym.unicode == 127) - { - return(SDLK_BACKSPACE); - } - // We don't make any difference between return & enter in the app context. - if(keysym.unicode == 3) - { - return(SDLK_RETURN); - } -#endif - return keysym.unicode; - } - - // Sinon c'est une touche spéciale, on retourne son scancode - return keysym.sym; -} +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2009 Franck Charlet + Copyright 2008 Yves Rizoud + 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 "global.h" +#include "keyboard.h" + +// Table de correspondance des scancode de clavier IBM PC AT vers +// les symboles de touches SDL (sym). +// La correspondance est bonne si le clavier est QWERTY US, ou si +// l'utilisateur est sous Windows. +// Dans l'ordre des colonnes: Normal, +Shift, +Control, +Alt +const word Scancode_to_sym[256][4] = +{ +/* 00 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 01 Esc */ { SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE }, +/* 02 1 ! */ { SDLK_1 ,SDLK_1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 03 2 @ */ { SDLK_2 ,SDLK_2 ,SDLK_2 ,SDLK_UNKNOWN }, +/* 04 3 # */ { SDLK_3 ,SDLK_3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 05 4 $ */ { SDLK_4 ,SDLK_4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 06 5 % */ { SDLK_5 ,SDLK_5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 07 6 ^ */ { SDLK_6 ,SDLK_6 ,SDLK_6 ,SDLK_UNKNOWN }, +/* 08 7 & */ { SDLK_7 ,SDLK_7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 09 8 * */ { SDLK_8 ,SDLK_8 ,SDLK_8 ,SDLK_UNKNOWN }, +/* 0A 9 ( */ { SDLK_9 ,SDLK_9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 0B 0 ) */ { SDLK_0 ,SDLK_0 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 0C - _ */ { SDLK_MINUS ,SDLK_MINUS ,SDLK_MINUS ,SDLK_UNKNOWN }, +/* 0D = + */ { SDLK_EQUALS ,SDLK_EQUALS ,SDLK_EQUALS ,SDLK_UNKNOWN }, +/* 0E BkSpc */ { SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE }, +/* 0F Tab */ { SDLK_TAB ,SDLK_TAB ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 10 Q */ { SDLK_q ,SDLK_q ,SDLK_q ,SDLK_q }, +/* 11 W */ { SDLK_w ,SDLK_w ,SDLK_w ,SDLK_w }, +/* 12 E */ { SDLK_e ,SDLK_e ,SDLK_e ,SDLK_e }, +/* 13 R */ { SDLK_r ,SDLK_r ,SDLK_r ,SDLK_r }, +/* 14 T */ { SDLK_t ,SDLK_t ,SDLK_t ,SDLK_t }, +/* 15 Y */ { SDLK_y ,SDLK_y ,SDLK_y ,SDLK_y }, +/* 16 U */ { SDLK_u ,SDLK_u ,SDLK_u ,SDLK_u }, +/* 17 I */ { SDLK_i ,SDLK_i ,SDLK_i ,SDLK_i }, +/* 18 O */ { SDLK_o ,SDLK_o ,SDLK_o ,SDLK_o }, +/* 19 P */ { SDLK_p ,SDLK_p ,SDLK_p ,SDLK_p }, +/* 1A [ */ { SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET }, +/* 1B ] */ { SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET}, +/* 1C Retrn */ { SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN }, +/* 1D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 1E A */ { SDLK_a ,SDLK_a ,SDLK_a ,SDLK_a }, +/* 1F S */ { SDLK_s ,SDLK_s ,SDLK_s ,SDLK_s }, +/* 20 D */ { SDLK_d ,SDLK_d ,SDLK_d ,SDLK_d }, +/* 21 F */ { SDLK_f ,SDLK_f ,SDLK_f ,SDLK_f }, +/* 22 G */ { SDLK_g ,SDLK_g ,SDLK_g ,SDLK_g }, +/* 23 H */ { SDLK_h ,SDLK_h ,SDLK_h ,SDLK_h }, +/* 24 J */ { SDLK_j ,SDLK_j ,SDLK_j ,SDLK_j }, +/* 25 K */ { SDLK_k ,SDLK_k ,SDLK_k ,SDLK_k }, +/* 26 L */ { SDLK_l ,SDLK_l ,SDLK_l ,SDLK_l }, +/* 27 ; : */ { SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON }, +/* 28 ' */ { SDLK_QUOTE ,SDLK_QUOTE ,SDLK_UNKNOWN ,SDLK_QUOTE }, +/* 29 ` ~ */ { SDLK_BACKQUOTE ,SDLK_BACKQUOTE ,SDLK_UNKNOWN ,SDLK_BACKQUOTE }, +/* 2A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 2B \\ */ { SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH }, +/* 2C Z */ { SDLK_z ,SDLK_z ,SDLK_z ,SDLK_z }, +/* 2D X */ { SDLK_x ,SDLK_x ,SDLK_x ,SDLK_x }, +/* 2E C */ { SDLK_c ,SDLK_c ,SDLK_c ,SDLK_c }, +/* 2F V */ { SDLK_v ,SDLK_v ,SDLK_v ,SDLK_v }, +/* 30 B */ { SDLK_b ,SDLK_b ,SDLK_b ,SDLK_b }, +/* 31 N */ { SDLK_n ,SDLK_n ,SDLK_n ,SDLK_n }, +/* 32 M */ { SDLK_m ,SDLK_m ,SDLK_m ,SDLK_m }, +/* 33 , < */ { SDLK_COMMA ,SDLK_COMMA ,SDLK_UNKNOWN ,SDLK_COMMA }, +/* 34 . > */ { SDLK_PERIOD ,SDLK_PERIOD ,SDLK_UNKNOWN ,SDLK_PERIOD }, +/* 35 / ? */ { SDLK_SLASH ,SDLK_SLASH ,SDLK_UNKNOWN ,SDLK_SLASH }, +/* 36 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 37 Grey* */ { SDLK_KP_MULTIPLY ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY }, +/* 38 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 39 Space */ { SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE }, +/* 3A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 3B F1 */ { SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 3C F2 */ { SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 3D F3 */ { SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 3E F4 */ { SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 3F F5 */ { SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 40 F6 */ { SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 41 F7 */ { SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 42 F8 */ { SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 43 F9 */ { SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 44 F10 */ { SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 45 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 46 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 47 Home */ { SDLK_HOME ,SDLK_HOME ,SDLK_UNKNOWN ,SDLK_HOME }, +/* 48 Up */ { SDLK_UP ,SDLK_UP ,SDLK_UNKNOWN ,SDLK_UP }, +/* 49 PgUp */ { SDLK_PAGEUP ,SDLK_PAGEUP ,SDLK_UNKNOWN ,SDLK_PAGEUP }, +/* 4A Grey- */ { SDLK_KP_MINUS ,SDLK_KP_MINUS ,SDLK_UNKNOWN ,SDLK_KP_MINUS }, +/* 4B Left */ { SDLK_LEFT ,SDLK_LEFT ,SDLK_UNKNOWN ,SDLK_LEFT }, +/* 4C Kpad5 */ { SDLK_KP5 ,SDLK_KP5 ,SDLK_UNKNOWN ,SDLK_KP5 }, +/* 4D Right */ { SDLK_RIGHT ,SDLK_RIGHT ,SDLK_UNKNOWN ,SDLK_RIGHT }, +/* 4E Grey+ */ { SDLK_KP_PLUS ,SDLK_KP_PLUS ,SDLK_UNKNOWN ,SDLK_KP_PLUS }, +/* 4F End */ { SDLK_END ,SDLK_END ,SDLK_UNKNOWN ,SDLK_END }, +/* 50 Down */ { SDLK_DOWN ,SDLK_DOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, +/* 51 PgDn */ { SDLK_PAGEDOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN }, +/* 52 Ins */ { SDLK_INSERT ,SDLK_INSERT ,SDLK_UNKNOWN ,SDLK_INSERT }, +/* 53 Del */ { SDLK_DELETE ,SDLK_DELETE ,SDLK_UNKNOWN ,SDLK_DELETE }, +/* 54 ??? */ { SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 55 ??? */ { SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 56 Lft| */ { SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 57 ??? */ { SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 58 ??? */ { SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 59 ??? */ { SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 5A ??? */ { SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 5B ??? */ { SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 5C ??? */ { SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 5D ??? */ { SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 5E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN }, +/* 5F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN }, +/* 60 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN }, +/* 61 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN }, +/* 62 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN }, +/* 63 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN }, +/* 64 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN }, +/* 65 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN }, +/* 66 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN }, +/* 67 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN }, +/* 68 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 }, +/* 69 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 }, +/* 6A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 }, +/* 6B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 }, +/* 6C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 }, +/* 6D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 }, +/* 6E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 }, +/* 6F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 }, +/* 70 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 }, +/* 71 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 }, +/* 72 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 73 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT ,SDLK_UNKNOWN }, +/* 74 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT ,SDLK_UNKNOWN }, +/* 75 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END ,SDLK_UNKNOWN }, +/* 76 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN }, +/* 77 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME ,SDLK_UNKNOWN }, +/* 78 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_1 }, +/* 79 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_2 }, +/* 7A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_3 }, +/* 7B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_4 }, +/* 7C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_5 }, +/* 7D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_6 }, +/* 7E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_7 }, +/* 7F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_8 }, +/* 80 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_9 }, +/* 81 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_0 }, +/* 82 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MINUS }, +/* 83 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_EQUALS }, +/* 84 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP ,SDLK_UNKNOWN }, +/* 85 F11 */ { SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 86 F12 */ { SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 87 ??? */ { SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 88 ??? */ { SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 89 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN }, +/* 8A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN }, +/* 8B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 }, +/* 8C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 }, +/* 8D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP ,SDLK_UNKNOWN }, +/* 8E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MINUS ,SDLK_UNKNOWN }, +/* 8F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP5 ,SDLK_UNKNOWN }, +/* 90 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_PLUS ,SDLK_UNKNOWN }, +/* 91 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN ,SDLK_UNKNOWN }, +/* 92 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT ,SDLK_UNKNOWN }, +/* 93 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE ,SDLK_UNKNOWN }, +/* 94 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB ,SDLK_UNKNOWN }, +/* 95 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE ,SDLK_UNKNOWN }, +/* 96 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN }, +/* 97 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME }, +/* 98 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP }, +/* 99 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, +/* 9A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 9B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT }, +/* 9C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 9D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT }, +/* 9E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* 9F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END }, +/* A0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, +/* A1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, +/* A2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT }, +/* A3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE }, +/* A4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE }, +/* A5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB }, +/* A6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_ENTER }, +/* A7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* A8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* A9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* AA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* AB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* AC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* AD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* AE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* AF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B6 Win L */ { SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B7 Win R */ { SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B8 Win M */ { SDLK_MENU ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* B9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* BA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* BB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* BC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* BD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* BE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* BF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C2 ??? */ { SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C3 ??? */ { SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* C9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* CA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* CB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* CC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* CD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* CE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN }, +/* CF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN }, +/* D0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU ,SDLK_UNKNOWN }, +/* D1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* D9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* DA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER }, +/* DB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER }, +/* DC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU }, +/* DD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* DE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* DF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E0 Enter */ { SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_UNKNOWN }, +/* E1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* E9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* EA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* EB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* EC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* ED ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* EE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* EF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* F9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* FA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* FB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* FC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* FD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* FE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +/* FF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, +}; + +// Conversion de l'ancien codage des touches: +// 0x00FF le scancode (maintenant code sym sur 0x0FFF) +// 0x0100 shift (maintenant 0x1000) +// 0x0200 control (maintenant 0x2000) +// 0x0400 alt (maintenant 0x4000) +word Key_for_scancode(word scancode) +{ + if (scancode & 0x0400) + return Scancode_to_sym[scancode & 0xFF][3] | + (scancode & 0x0700) << 4; + else if (scancode & 0x0200) + return Scancode_to_sym[scancode & 0xFF][2] | + (scancode & 0x0700) << 4; + else if (scancode & 0x0100) + return Scancode_to_sym[scancode & 0xFF][1] | + (scancode & 0x0700) << 4; + else + return Scancode_to_sym[scancode & 0xFF][0]; +} + +// Convertit des modificateurs de touches SDL en modificateurs GrafX2 +word Key_modifiers(SDLMod mod) +{ + word modifiers=0; + + if (mod & KMOD_CTRL ) + modifiers|=MOD_CTRL; + if (mod & KMOD_SHIFT ) + modifiers|=MOD_SHIFT; + if (mod & (KMOD_ALT|KMOD_MODE)) + modifiers|=MOD_ALT; + if (mod & (KMOD_META)) + modifiers|=MOD_META; + + return modifiers; +} + +word Keysym_to_keycode(SDL_keysym keysym) +{ + word key_code = 0; + word mod; + + // On ignore shift, alt et control isolés. + if (keysym.sym == SDLK_RSHIFT || keysym.sym == SDLK_LSHIFT || + keysym.sym == SDLK_RCTRL || keysym.sym == SDLK_LCTRL || + keysym.sym == SDLK_RALT || keysym.sym == SDLK_LALT || + keysym.sym == SDLK_RMETA || keysym.sym == SDLK_LMETA || + keysym.sym == SDLK_MODE) // AltGr + return 0; + + // Les touches qui n'ont qu'une valeur unicode (très rares) + // seront codées sur 11 bits, le 12e bit est mis à 1 (0x0800) + if (keysym.sym != 0) + key_code = keysym.sym; + else if (keysym.scancode != 0) + { + key_code = (keysym.scancode & 0x07FF) | 0x0800; + } + + // Normally I should test keysym.mod here, but on windows the implementation + // is buggy: if you release a modifier key, the following keys (when they repeat) + // still name the original modifiers. + mod=Key_modifiers(SDL_GetModState()); + + // SDL_GetModState() seems to get the right up-to-date info. + key_code |= mod; + return key_code; +} + +const char * Key_name(word Key) +{ + typedef struct + { + word keysym; + char *Key_name; + } T_key_label; + T_key_label key_labels[] = + { + { SDLK_BACKSPACE , "Backspace" }, + { SDLK_TAB , "Tab" }, + { SDLK_CLEAR , "Clear" }, + { SDLK_RETURN , "Return" }, + { SDLK_PAUSE , "Pause" }, + { SDLK_ESCAPE , "Esc" }, + { SDLK_DELETE , "Del" }, + { SDLK_KP0 , "KP 0" }, + { SDLK_KP1 , "KP 1" }, + { SDLK_KP2 , "KP 2" }, + { SDLK_KP3 , "KP 3" }, + { SDLK_KP4 , "KP 4" }, + { SDLK_KP5 , "KP 5" }, + { SDLK_KP6 , "KP 6" }, + { SDLK_KP7 , "KP 7" }, + { SDLK_KP8 , "KP 8" }, + { SDLK_KP9 , "KP 9" }, + { SDLK_KP_PERIOD , "KP ." }, + { SDLK_KP_DIVIDE , "KP /" }, + { SDLK_KP_MULTIPLY, "KP *" }, + { SDLK_KP_MINUS , "KP -" }, + { SDLK_KP_PLUS , "KP +" }, + { SDLK_KP_ENTER , "KP Enter" }, + { SDLK_KP_EQUALS , "KP =" }, + { SDLK_UP , "Up" }, + { SDLK_DOWN , "Down" }, + { SDLK_RIGHT , "Right" }, + { SDLK_LEFT , "Left" }, + { SDLK_INSERT , "Ins" }, + { SDLK_HOME , "Home" }, + { SDLK_END , "End" }, + { SDLK_PAGEUP , "PgUp" }, + { SDLK_PAGEDOWN , "PgDn" }, + { SDLK_F1 , "F1" }, + { SDLK_F2 , "F2" }, + { SDLK_F3 , "F3" }, + { SDLK_F4 , "F4" }, + { SDLK_F5 , "F5" }, + { SDLK_F6 , "F6" }, + { SDLK_F7 , "F7" }, + { SDLK_F8 , "F8" }, + { SDLK_F9 , "F9" }, + { SDLK_F10 , "F10" }, + { SDLK_F11 , "F11" }, + { SDLK_F12 , "F12" }, + { SDLK_F13 , "F13" }, + { SDLK_F14 , "F14" }, + { SDLK_F15 , "F15" }, + { SDLK_NUMLOCK , "NumLock" }, + { SDLK_CAPSLOCK , "CapsLck" }, + { SDLK_SCROLLOCK , "ScrlLock" }, + { SDLK_RSHIFT , "RShift" }, + { SDLK_LSHIFT , "LShift" }, + { SDLK_RCTRL , "RCtrl" }, + { SDLK_LCTRL , "LCtrl" }, + { SDLK_RALT , "RAlt" }, + { SDLK_LALT , "LAlt" }, + { SDLK_RMETA , "RMeta" }, + { SDLK_LMETA , "LMeta" }, + { SDLK_LSUPER , "LWin" }, + { SDLK_RSUPER , "RWin" }, + { SDLK_MODE , "AltGr" }, + { SDLK_COMPOSE , "Comp" }, + { SDLK_HELP , "Help" }, + { SDLK_PRINT , "Print" }, + { SDLK_SYSREQ , "SysReq" }, + { SDLK_BREAK , "Break" }, + { SDLK_MENU , "Menu" }, + { SDLK_POWER , "Power" }, + { SDLK_EURO , "Euro" }, + { SDLK_UNDO , "Undo" }, + { KEY_MOUSEMIDDLE, "Mouse3" }, + { KEY_MOUSEWHEELUP, "WheelUp" }, + { KEY_MOUSEWHEELDOWN, "WheelDown" } + }; + + int index; + static char buffer[41]; + buffer[0] = '\0'; + + if (Key == SDLK_UNKNOWN) + return "None"; + + if (Key & MOD_CTRL) + strcat(buffer, "Ctrl+"); + if (Key & MOD_ALT) + strcat(buffer, "Alt+"); + if (Key & MOD_SHIFT) + strcat(buffer, "Shift+"); + if (Key & MOD_META) + strcat(buffer, "\201"); + // Note: Apple's "command" character is not present in the ANSI table, so we + // recycled an ANSI value that doesn't have any displayable character + // associated. + + + Key=Key & ~(MOD_CTRL|MOD_ALT|MOD_SHIFT); + + if (Key>=KEY_JOYBUTTON && Key<=KEY_JOYBUTTON+18) + { +#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; + } + strcat(buffer,button_name); +#else + sprintf(buffer+strlen(buffer), "[B%d]", Key-KEY_JOYBUTTON); +#endif + return buffer; + } + + if (Key & 0x800) + { + sprintf(buffer+strlen(buffer), "[%d]", Key & 0x7FF); + return buffer; + } + Key = Key & 0x7FF; + // Touches ASCII + if (Key>=' ' && Key < 127) + { + sprintf(buffer+strlen(buffer), "'%c'", toupper(Key)); + return buffer; + } + // Touches 'World' + if (Key>=SDLK_WORLD_0 && Key <= SDLK_WORLD_95) + { + sprintf(buffer+strlen(buffer), "w%d", Key - SDLK_WORLD_0); + return buffer; + } + + // Touches au libellé connu + for (index=0; index < (long)sizeof(key_labels)/(long)sizeof(T_key_label);index++) + { + if (Key == key_labels[index].keysym) + { + sprintf(buffer+strlen(buffer), "%s", key_labels[index].Key_name); + return buffer; + } + } + // Autres touches inconnues + sprintf(buffer+strlen(buffer), "0x%X", Key & 0x7FF); + return buffer; + +} + +// Obtient le caractère ANSI tapé, à partir d'un keysym. +// (Valeur 32 à 255) +// Renvoie 0 s'il n'y a pas de caractère associé (shift, backspace, etc) +word Keysym_to_ANSI(SDL_keysym keysym) +{ + // This part was removed from the MacOSX port, but I put it back for others + // as on Linux and Windows, it's what allows editing a text line with the keys + // SDLK_LEFT, SDLK_RIGHT, SDLK_HOME, SDLK_END etc. + #if !(defined(__macosx__) || defined(__FreeBSD__)) + if ( keysym.unicode == 0) + { + switch(keysym.sym) + { + case SDLK_DELETE: + case SDLK_LEFT: + case SDLK_RIGHT: + case SDLK_HOME: + case SDLK_END: + case SDLK_BACKSPACE: + case KEY_ESC: + case SDLK_RETURN: + return keysym.sym; + default: + return 0; + } + } + #endif + // + if ( keysym.unicode > 32 && keysym.unicode < 127) + { + return keysym.unicode; // Pas de souci, on est en ASCII standard + } + + // Quelques conversions Unicode-ANSI + switch(keysym.unicode) + { + case 0x8100: + return 'ü'; // ü + case 0x1A20: + return 'é'; // é + case 0x201A: + return 'è'; // è + case 0x9201: + return 'â'; // â + case 0x1E20: + return 'ä'; // ä + case 0x2620: + return 'à'; // à + case 0x2020: + return 'å'; // å + case 0x2120: + return 'ç'; // ç + case 0xC602: + return 'ê'; // ê + case 0x3020: + return 'ë'; // ë + case 0x6001: + return 'è'; // è + case 0x3920: + return 'ï'; // ï + case 0x5201: + return 'î'; // î + case 0x8D00: + return 'ì'; // ì + case 0x1C20: + return 'ô'; // ô + case 0x1D20: + return 'ö'; // ö + case 0x2220: + return 'ò'; // ò + case 0x1320: + return 'û'; // û + case 0x1420: + return 'ù'; // ù + case 0xDC02: + return 'ÿ'; // ÿ + case 0x5301: + return '£'; // £ + case 0xA000: + return 'á'; // á + case 0xA100: + return 'í'; // í + case 0xA200: + return 'ó'; // ó + case 0xA300: + return 'ú'; // ú + case 0xA400: + return 'ñ'; // ñ + case 0xA700: + return 'º'; // º + case 0xC600: + return 'ã'; // ã + } + + // Key entre 127 et 255 + if (keysym.unicode<256) + { +#if defined(__macosx__) || defined(__FreeBSD__) + // fc: Looks like there's a mismatch with delete & backspace + // i don't why SDLK_DELETE was returned instead of SDLK_BACKSPACE + if(keysym.unicode == 127) + { + return(SDLK_BACKSPACE); + } + // We don't make any difference between return & enter in the app context. + if(keysym.unicode == 3) + { + return(SDLK_RETURN); + } +#endif + return keysym.unicode; + } + + // Sinon c'est une touche spéciale, on retourne son scancode + return keysym.sym; +} diff --git a/keyboard.h b/keyboard.h index d3776d8b..eca0352e 100644 --- a/keyboard.h +++ b/keyboard.h @@ -1,75 +1,75 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file keyboard.h -/// Functions to convert bewteen the SDL key formats and the keycode we use -/// in grafx2. -/// The keycode we're using is generalized to handle mouse and joystick shortcuts -/// as well. The format can be broken down as: -/// - 0x0000 + a number between 0 and SDLK_LAST (about 324) : the SDL "sym" key number. -/// - 0x0000 + SDLK_LAST+1: Mouse middle button. -/// - 0x0000 + SDLK_LAST+2: Mouse wheel up. -/// - 0x0000 + SDLK_LAST+3: Mouse wheel down. -/// - 0x0000 + SDLK_LAST+4+B : Joystick button number "B", starting at B=0. -/// - 0x0800 + a number between 0 and 0x7FF: The scancode key number, for keys which have no "sym", such as keys from multimedia keyboards, and "fn" and "Thinkpad" key for a laptop. -/// Add 0x1000 for the Shift modifier MOD_SHIFT -/// Add 0x2000 for the Control modifier ::MOD_CONTROL -/// Add 0x4000 for the Alt modifier ::MOD_ALT -/// Add 0x8000 for the "Meta" modifier ::MOD_META (On MacOS X it's the CMD key) -////////////////////////////////////////////////////////////////////////////// - -/*! - Convert an SDL keysym to an ANSI/ASCII character. - This is used to type text and numeric values in input boxes. - @param keysym SDL symbol to convert -*/ -word Keysym_to_ANSI(SDL_keysym keysym); - -/*! - Convert an SDL keysym to an internal keycode number. - This is needed because SDL tends to split the information across the unicode sym, the regular sym, and the raw keycode. - We also need to differenciate 1 (keypad) and 1 (regular keyboard), and some other things. - See the notice at the beginning of keyboard.h for the format of a keycode. - @param keysym SDL symbol to convert -*/ -word Keysym_to_keycode(SDL_keysym keysym); - -/*! - Helper function to convert between SDL system and the old coding for PC keycodes. - This is only used to convert configuration files from the DOS version of - Grafx2, where keyboard codes are in in the IBM PC AT form. - @param scancode Scancode to convert -*/ -word Key_for_scancode(word scancode); - -/*! - Returns key name in a string. Used to display them in the helpscreens and in the keymapper window. - @param Key keycode of the key to translate, including modifiers -*/ -const char * Key_name(word Key); - -/*! - Gets the modifiers in our format from the SDL_Mod information. - Returns a combination of ::MOD_SHIFT, ::MOD_ALT, ::MOD_CONTROL - @param mod SDL modifiers state -*/ -word Key_modifiers(SDLMod mod); - +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file keyboard.h +/// Functions to convert bewteen the SDL key formats and the keycode we use +/// in grafx2. +/// The keycode we're using is generalized to handle mouse and joystick shortcuts +/// as well. The format can be broken down as: +/// - 0x0000 + a number between 0 and SDLK_LAST (about 324) : the SDL "sym" key number. +/// - 0x0000 + SDLK_LAST+1: Mouse middle button. +/// - 0x0000 + SDLK_LAST+2: Mouse wheel up. +/// - 0x0000 + SDLK_LAST+3: Mouse wheel down. +/// - 0x0000 + SDLK_LAST+4+B : Joystick button number "B", starting at B=0. +/// - 0x0800 + a number between 0 and 0x7FF: The scancode key number, for keys which have no "sym", such as keys from multimedia keyboards, and "fn" and "Thinkpad" key for a laptop. +/// Add 0x1000 for the Shift modifier MOD_SHIFT +/// Add 0x2000 for the Control modifier ::MOD_CONTROL +/// Add 0x4000 for the Alt modifier ::MOD_ALT +/// Add 0x8000 for the "Meta" modifier ::MOD_META (On MacOS X it's the CMD key) +////////////////////////////////////////////////////////////////////////////// + +/*! + Convert an SDL keysym to an ANSI/ASCII character. + This is used to type text and numeric values in input boxes. + @param keysym SDL symbol to convert +*/ +word Keysym_to_ANSI(SDL_keysym keysym); + +/*! + Convert an SDL keysym to an internal keycode number. + This is needed because SDL tends to split the information across the unicode sym, the regular sym, and the raw keycode. + We also need to differenciate 1 (keypad) and 1 (regular keyboard), and some other things. + See the notice at the beginning of keyboard.h for the format of a keycode. + @param keysym SDL symbol to convert +*/ +word Keysym_to_keycode(SDL_keysym keysym); + +/*! + Helper function to convert between SDL system and the old coding for PC keycodes. + This is only used to convert configuration files from the DOS version of + Grafx2, where keyboard codes are in in the IBM PC AT form. + @param scancode Scancode to convert +*/ +word Key_for_scancode(word scancode); + +/*! + Returns key name in a string. Used to display them in the helpscreens and in the keymapper window. + @param Key keycode of the key to translate, including modifiers +*/ +const char * Key_name(word Key); + +/*! + Gets the modifiers in our format from the SDL_Mod information. + Returns a combination of ::MOD_SHIFT, ::MOD_ALT, ::MOD_CONTROL + @param mod SDL modifiers state +*/ +word Key_modifiers(SDLMod mod); + diff --git a/loadsave.h b/loadsave.h index 3f185d80..e8fd0c83 100644 --- a/loadsave.h +++ b/loadsave.h @@ -1,57 +1,57 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ -////////////////////////////////////////////////////////////////////////////// -///@file loadsave.h -/// Saving and loading different picture formats. -/// Also handles showing the preview in fileselectors. -////////////////////////////////////////////////////////////////////////////// - -void Pixel_load_in_current_screen(word x_pos,word y_pos,byte color); -void Pixel_load_in_preview (word x_pos,word y_pos,byte color); -void Pixel_load_in_brush (word x_pos,word y_pos,byte color); - -void Get_full_filename(char * filename, byte is_colorix_format); - -/// -/// High-level picture loading function. -/// Handles loading an image or a brush, or previewing only. -/// @param image true if the fileselector is the one for loading images (not brush) -void Load_image(byte image); -/// -/// High-level picture saving function. -/// @param image true if the image should be saved (instead of the brush) -void Save_image(byte image); - -/// Data for an image file format. -typedef struct { - char *Extension; ///< Three-letter file extension - Func_action Test; ///< Function which tests if the file is of this format - Func_action Load; ///< Function which loads an image of this format - Func_action Save; ///< Function which saves an image of this format - byte Backup_done; ///< Boolean, true if this format saves all the image, and considers it backed up. Set false for formats which only save the palette. - byte Comment; ///< This file format allows a text comment -} T_Format; - -/// Array of the known file formats -extern T_Format File_formats[NB_KNOWN_FORMATS]; - -/// -/// Function which attempts to save backups of the images (main and spare), -/// called in case of SIGSEGV. -void Image_emergency_backup(void); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ +////////////////////////////////////////////////////////////////////////////// +///@file loadsave.h +/// Saving and loading different picture formats. +/// Also handles showing the preview in fileselectors. +////////////////////////////////////////////////////////////////////////////// + +void Pixel_load_in_current_screen(word x_pos,word y_pos,byte color); +void Pixel_load_in_preview (word x_pos,word y_pos,byte color); +void Pixel_load_in_brush (word x_pos,word y_pos,byte color); + +void Get_full_filename(char * filename, byte is_colorix_format); + +/// +/// High-level picture loading function. +/// Handles loading an image or a brush, or previewing only. +/// @param image true if the fileselector is the one for loading images (not brush) +void Load_image(byte image); +/// +/// High-level picture saving function. +/// @param image true if the image should be saved (instead of the brush) +void Save_image(byte image); + +/// Data for an image file format. +typedef struct { + char *Extension; ///< Three-letter file extension + Func_action Test; ///< Function which tests if the file is of this format + Func_action Load; ///< Function which loads an image of this format + Func_action Save; ///< Function which saves an image of this format + byte Backup_done; ///< Boolean, true if this format saves all the image, and considers it backed up. Set false for formats which only save the palette. + byte Comment; ///< This file format allows a text comment +} T_Format; + +/// Array of the known file formats +extern T_Format File_formats[NB_KNOWN_FORMATS]; + +/// +/// Function which attempts to save backups of the images (main and spare), +/// called in case of SIGSEGV. +void Image_emergency_backup(void); diff --git a/misc.h b/misc.h index 88eb23d0..15ae058b 100644 --- a/misc.h +++ b/misc.h @@ -1,150 +1,150 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ -////////////////////////////////////////////////////////////////////////////// -///@file misc.h -/// Miscellanous unsorted functions. -////////////////////////////////////////////////////////////////////////////// - -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 Scroll_picture(short x_offset,short y_offset); -void Wait_end_of_click(void); -void Set_color(byte color, byte red, byte green, byte blue); -void Set_palette(T_Palette palette); -void Palette_256_to_64(T_Palette palette); -void Palette_64_to_256(T_Palette palette); -void Hide_current_image(byte color); -void Hide_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); -void Pixel_in_current_screen (word x,word y,byte color); -void Pixel_in_brush (word x,word y,byte color); -byte Read_pixel_from_current_screen (word x,word y); -byte Read_pixel_from_spare_screen(word x,word y); -byte Read_pixel_from_backup_screen (word x,word y); -byte Read_pixel_from_feedback_screen (word x,word y); -byte Read_pixel_from_brush (word x,word y); - -void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); -// Calcule les valeurs suivantes en fonction des deux paramètres: -// -// Ellipse_vertical_radius_squared -// Ellipse_horizontal_radius_squared -// Ellipse_Limit_High -// Ellipse_Limit_Low - - -byte Pixel_in_ellipse(void); -// Indique si le pixel se trouvant à Ellipse_cursor_X pixels -// (Ellipse_cursor_X>0 = à droite, Ellipse_cursor_X<0 = à gauche) et à -// Ellipse_cursor_Y pixels (Ellipse_cursor_Y>0 = en bas, -// Ellipse_cursor_Y<0 = en haut) du centre se trouve dans l'ellipse en -// cours. - -byte Pixel_in_circle(void); -// Indique si le pixel se trouvant à Circle_cursor_X pixels -// (Circle_cursor_X>0 = à droite, Circle_cursor_X<0 = à gauche) et à -// Circle_cursor_Y pixels (Circle_cursor_Y>0 = en bas, -// Circle_cursor_Y<0 = en haut) du centre se trouve dans le cercle en -// cours. - -// Gestion du chrono dans les fileselects -void Init_chrono(dword delay); -void Check_timer(void); - -void Replace_a_color(byte old_color, byte New_color); -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_sieve(word x,word y); - -/// -/// Inverts a pixel buffer, according to a horizontal axis. -/// @param src Pointer to the pixel buffer to process. -/// @param width Width of the buffer. -/// @param height Height of the buffer. -void Flip_Y_lowlevel(byte *src, short width, short height); - -/// -/// Inverts a pixel buffer, according to a vertical axis. -/// @param src Pointer to the pixel buffer to process. -/// @param width Width of the buffer. -/// @param height Height of the buffer. -void Flip_X_lowlevel(byte *src, short width, short height); -/// -/// Rotate a pixel buffer by 90 degrees, clockwise. -/// @param source Source pixel buffer. -/// @param dest Destination pixel buffer. -/// @param width Width of the original buffer (height of the destination one). -/// @param height Height of the original buffer (width of the destination one). -void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height); -/// -/// Rotate a pixel buffer by 90 degrees, counter-clockwise. -/// @param source Source pixel buffer. -/// @param dest Destination pixel buffer. -/// @param width Width of the original buffer (height of the destination one). -/// @param height Height of the original buffer (width of the destination one). -void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short height); -/// -/// Rotate a pixel buffer by 180 degrees. -/// @param src The pixel buffer (source and destination). -/// @param width Width of the buffer. -/// @param height Height of the buffer. -void Rotate_180_deg_lowlevel(byte *src, short width, short height); - -/// -/// Copies an image to another, rescaling it and optionally flipping it. -/// @param src_buffer Original image (address of first byte) -/// @param src_width Original image's width in pixels -/// @param src_height Original image's height in pixels -/// @param dst_buffer Destination image (address of first byte) -/// @param dst_width Destination image's width in pixels -/// @param dst_height Destination image's height in pixels -/// @param x_flipped Boolean, true to flip the image horizontally -/// @param y_flipped Boolean, true to flip the image vertically -void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped); - -void Zoom_a_line(byte * original_line,byte * zoomed_line,word factor,word width); -void Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width); - -// -- Gestion du chrono -- -byte Timer_state; // State du chrono: 0=Attente d'un Xème de seconde - // 1=Il faut afficher la preview - // 2=Plus de chrono à gerer pour l'instant -dword Timer_delay; // Nombre de 18.2ème de secondes demandés -dword Timer_start; // Heure de départ du chrono -byte New_preview_is_needed; // Booléen "Il faut relancer le chrono de preview" - - -unsigned long Memory_free(void); - -void Num2str(dword number,char * str,byte nb_char); - -short Round(float value); -short Round_div_max(short numerator,short divisor); - -int Min(int a,int b); -int Max(int a,int b); - -char* Mode_label(int mode); -int Convert_videomode_arg(const char *argument); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ +////////////////////////////////////////////////////////////////////////////// +///@file misc.h +/// Miscellanous unsorted functions. +////////////////////////////////////////////////////////////////////////////// + +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 Scroll_picture(short x_offset,short y_offset); +void Wait_end_of_click(void); +void Set_color(byte color, byte red, byte green, byte blue); +void Set_palette(T_Palette palette); +void Palette_256_to_64(T_Palette palette); +void Palette_64_to_256(T_Palette palette); +void Hide_current_image(byte color); +void Hide_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); +void Pixel_in_current_screen (word x,word y,byte color); +void Pixel_in_brush (word x,word y,byte color); +byte Read_pixel_from_current_screen (word x,word y); +byte Read_pixel_from_spare_screen(word x,word y); +byte Read_pixel_from_backup_screen (word x,word y); +byte Read_pixel_from_feedback_screen (word x,word y); +byte Read_pixel_from_brush (word x,word y); + +void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); +// Calcule les valeurs suivantes en fonction des deux paramètres: +// +// Ellipse_vertical_radius_squared +// Ellipse_horizontal_radius_squared +// Ellipse_Limit_High +// Ellipse_Limit_Low + + +byte Pixel_in_ellipse(void); +// Indique si le pixel se trouvant à Ellipse_cursor_X pixels +// (Ellipse_cursor_X>0 = à droite, Ellipse_cursor_X<0 = à gauche) et à +// Ellipse_cursor_Y pixels (Ellipse_cursor_Y>0 = en bas, +// Ellipse_cursor_Y<0 = en haut) du centre se trouve dans l'ellipse en +// cours. + +byte Pixel_in_circle(void); +// Indique si le pixel se trouvant à Circle_cursor_X pixels +// (Circle_cursor_X>0 = à droite, Circle_cursor_X<0 = à gauche) et à +// Circle_cursor_Y pixels (Circle_cursor_Y>0 = en bas, +// Circle_cursor_Y<0 = en haut) du centre se trouve dans le cercle en +// cours. + +// Gestion du chrono dans les fileselects +void Init_chrono(dword delay); +void Check_timer(void); + +void Replace_a_color(byte old_color, byte New_color); +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_sieve(word x,word y); + +/// +/// Inverts a pixel buffer, according to a horizontal axis. +/// @param src Pointer to the pixel buffer to process. +/// @param width Width of the buffer. +/// @param height Height of the buffer. +void Flip_Y_lowlevel(byte *src, short width, short height); + +/// +/// Inverts a pixel buffer, according to a vertical axis. +/// @param src Pointer to the pixel buffer to process. +/// @param width Width of the buffer. +/// @param height Height of the buffer. +void Flip_X_lowlevel(byte *src, short width, short height); +/// +/// Rotate a pixel buffer by 90 degrees, clockwise. +/// @param source Source pixel buffer. +/// @param dest Destination pixel buffer. +/// @param width Width of the original buffer (height of the destination one). +/// @param height Height of the original buffer (width of the destination one). +void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height); +/// +/// Rotate a pixel buffer by 90 degrees, counter-clockwise. +/// @param source Source pixel buffer. +/// @param dest Destination pixel buffer. +/// @param width Width of the original buffer (height of the destination one). +/// @param height Height of the original buffer (width of the destination one). +void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short height); +/// +/// Rotate a pixel buffer by 180 degrees. +/// @param src The pixel buffer (source and destination). +/// @param width Width of the buffer. +/// @param height Height of the buffer. +void Rotate_180_deg_lowlevel(byte *src, short width, short height); + +/// +/// Copies an image to another, rescaling it and optionally flipping it. +/// @param src_buffer Original image (address of first byte) +/// @param src_width Original image's width in pixels +/// @param src_height Original image's height in pixels +/// @param dst_buffer Destination image (address of first byte) +/// @param dst_width Destination image's width in pixels +/// @param dst_height Destination image's height in pixels +/// @param x_flipped Boolean, true to flip the image horizontally +/// @param y_flipped Boolean, true to flip the image vertically +void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped); + +void Zoom_a_line(byte * original_line,byte * zoomed_line,word factor,word width); +void Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width); + +// -- Gestion du chrono -- +byte Timer_state; // State du chrono: 0=Attente d'un Xème de seconde + // 1=Il faut afficher la preview + // 2=Plus de chrono à gerer pour l'instant +dword Timer_delay; // Nombre de 18.2ème de secondes demandés +dword Timer_start; // Heure de départ du chrono +byte New_preview_is_needed; // Booléen "Il faut relancer le chrono de preview" + + +unsigned long Memory_free(void); + +void Num2str(dword number,char * str,byte nb_char); + +short Round(float value); +short Round_div_max(short numerator,short divisor); + +int Min(int a,int b); +int Max(int a,int b); + +char* Mode_label(int mode); +int Convert_videomode_arg(const char *argument); diff --git a/mountlist.c b/mountlist.c index 43067554..74674df2 100644 --- a/mountlist.c +++ b/mountlist.c @@ -1,914 +1,914 @@ -/* mountlist.c -- return a list of mounted file systems - - Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 this program; if not, see . -*/ - -// This file is not used on some platforms, so don't do anything for them -#if(!defined(__WIN32__))&&(!defined(__amigaos4__))&&(!defined(__AROS__))&&(!defined(__MORPHOS__))&&(!defined(__amigaos__)) - -// We don't use autoconf and all that in grafx2, so let's do the config here ... -#if defined(__macosx__) || defined(__FreeBSD__) // MacOS X is POSIX compliant - #define MOUNTED_GETMNTINFO -#elif defined(__BEOS__) || defined(__HAIKU__) - #define MOUNTED_FS_STAT_DEV -#elif defined(__SKYOS__) - #warning "Your platform is missing some specific code here ! please check and fix :)" -#else - #define MOUNTED_GETMNTENT1 -#endif -// --- END GRAFX2 CUSTOM CONFIG --- - -#include "mountlist.h" - -#include -#include -#include -#include - -#include - -#include - -#include - -#if HAVE_SYS_PARAM_H -# include -#endif - -#if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ -# if HAVE_SYS_UCRED_H -# include /* needed on OSF V4.0 for definition of NGROUPS, - NGROUPS is used as an array dimension in ucred.h */ -# include /* needed by powerpc-apple-darwin1.3.7 */ -# endif -# if HAVE_SYS_MOUNT_H -# include -# endif -# if HAVE_SYS_FS_TYPES_H -# include /* needed by powerpc-apple-darwin1.3.7 */ -# endif -# if HAVE_STRUCT_FSSTAT_F_FSTYPENAME -# define FS_TYPE(Ent) ((Ent).f_fstypename) -# else -# define FS_TYPE(Ent) mnt_names[(Ent).f_type] -# endif -#endif /* MOUNTED_GETFSSTAT */ - -#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ -# include -# if !defined MOUNTED -# if defined _PATH_MOUNTED /* GNU libc */ -# define MOUNTED _PATH_MOUNTED -# endif -# if defined MNT_MNTTAB /* HP-UX. */ -# define MOUNTED MNT_MNTTAB -# endif -# if defined MNTTABNAME /* Dynix. */ -# define MOUNTED MNTTABNAME -# endif -# endif -#endif - -#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ -# include -#endif - -#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ -# include -#endif - -#ifdef MOUNTED_GETMNT /* Ultrix. */ -# include -# include -#endif - -#ifdef MOUNTED_FS_STAT_DEV /* BeOS. */ -# include -# include -#endif - -#ifdef MOUNTED_FREAD /* SVR2. */ -# include -#endif - -#ifdef MOUNTED_FREAD_FSTYP /* SVR3. */ -# include -# include -# include -#endif - -#ifdef MOUNTED_LISTMNTENT -# include -#endif - -#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ -# include -#endif - -#ifdef MOUNTED_VMOUNT /* AIX. */ -# include -# include -#endif - -#ifdef DOLPHIN -/* So special that it's not worth putting this in autoconf. */ -# undef MOUNTED_FREAD_FSTYP -# define MOUNTED_GETMNTTBL -#endif - -#if HAVE_SYS_MNTENT_H -/* This is to get MNTOPT_IGNORE on e.g. SVR4. */ -# include -#endif - -#undef MNT_IGNORE -#if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT -# define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE) -#else -# define MNT_IGNORE(M) 0 -#endif - -#if USE_UNLOCKED_IO -# include "unlocked-io.h" -#endif - -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) -#endif - -/* The results of open() in this file are not used with fchdir, - therefore save some unnecessary work in fchdir.c. */ -#undef open -#undef close - -/* The results of opendir() in this file are not used with dirfd and fchdir, - therefore save some unnecessary work in fchdir.c. */ -#undef opendir -#undef closedir - -// gcc2 under haiku and beos don't like these macros for some reason. -// As they are not used there anyways, we remove them and everyone is happy. -#if !defined(__HAIKU__) && !defined(__BEOS__) -#ifndef ME_DUMMY -# define ME_DUMMY(Fs_name, Fs_type) \ - (strcmp (Fs_type, "autofs") == 0 \ - || strcmp (Fs_type, "none") == 0 \ - || strcmp (Fs_type, "proc") == 0 \ - || strcmp (Fs_type, "subfs") == 0 \ - || strcmp (Fs_type, "sysfs") == 0 \ - || strcmp (Fs_type, "usbfs") == 0 \ - || strcmp (Fs_type, "devpts") == 0 \ - || strcmp (Fs_type, "tmpfs") == 0 \ - /* for NetBSD 3.0 */ \ - || strcmp (Fs_type, "kernfs") == 0 \ - /* for Irix 6.5 */ \ - || strcmp (Fs_type, "ignore") == 0 \ - /* for MacOSX */ \ - || strcmp (Fs_type, "devfs") == 0 \ - || strcmp (Fs_type, "fdesc") == 0 \ - || strcmp (Fs_type, "nfs") == 0 \ - || strcmp (Fs_type, "volfs") == 0) -#endif - -#ifndef ME_REMOTE -/* A file system is `remote' if its Fs_name contains a `:' - or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */ -# define ME_REMOTE(Fs_name, Fs_type) \ - (strchr (Fs_name, ':') != NULL \ - || ((Fs_name)[0] == '/' \ - && (Fs_name)[1] == '/' \ - && (strcmp (Fs_type, "smbfs") == 0 \ - || strcmp (Fs_type, "cifs") == 0))) -#endif -#endif // HAIKU / BEOS - -#ifdef MOUNTED_GETMNTINFO - -# if ! HAVE_STRUCT_STATFS_F_FSTYPENAME -static char * -fstype_to_string (short int t) -{ - switch (t) - { -# ifdef MOUNT_PC - case MOUNT_PC: - return "pc"; -# endif -# ifdef MOUNT_MFS - case MOUNT_MFS: - return "mfs"; -# endif -# ifdef MOUNT_LO - case MOUNT_LO: - return "lo"; -# endif -# ifdef MOUNT_TFS - case MOUNT_TFS: - return "tfs"; -# endif -# ifdef MOUNT_TMP - case MOUNT_TMP: - return "tmp"; -# endif -# ifdef MOUNT_UFS - case MOUNT_UFS: - return "ufs" ; -# endif -# ifdef MOUNT_NFS - case MOUNT_NFS: - return "nfs" ; -# endif -# ifdef MOUNT_MSDOS - case MOUNT_MSDOS: - return "msdos" ; -# endif -# ifdef MOUNT_LFS - case MOUNT_LFS: - return "lfs" ; -# endif -# ifdef MOUNT_LOFS - case MOUNT_LOFS: - return "lofs" ; -# endif -# ifdef MOUNT_FDESC - case MOUNT_FDESC: - return "fdesc" ; -# endif -# ifdef MOUNT_PORTAL - case MOUNT_PORTAL: - return "portal" ; -# endif -# ifdef MOUNT_NULL - case MOUNT_NULL: - return "null" ; -# endif -# ifdef MOUNT_UMAP - case MOUNT_UMAP: - return "umap" ; -# endif -# ifdef MOUNT_KERNFS - case MOUNT_KERNFS: - return "kernfs" ; -# endif -# ifdef MOUNT_PROCFS - case MOUNT_PROCFS: - return "procfs" ; -# endif -# ifdef MOUNT_AFS - case MOUNT_AFS: - return "afs" ; -# endif -# ifdef MOUNT_CD9660 - case MOUNT_CD9660: - return "cd9660" ; -# endif -# ifdef MOUNT_UNION - case MOUNT_UNION: - return "union" ; -# endif -# ifdef MOUNT_DEVFS - case MOUNT_DEVFS: - return "devfs" ; -# endif -# ifdef MOUNT_EXT2FS - case MOUNT_EXT2FS: - return "ext2fs" ; -# endif - default: - return "?"; - } -} -# endif - -static char * -fsp_to_string (const struct statfs *fsp) -{ -# if HAVE_STRUCT_STATFS_F_FSTYPENAME - return (char *) (fsp->f_fstypename); -# else - return fstype_to_string (fsp->f_type); -# endif -} - -#endif /* MOUNTED_GETMNTINFO */ - -#ifdef MOUNTED_VMOUNT /* AIX. */ -static char * -fstype_to_string (int t) -{ - struct vfs_ent *e; - - e = getvfsbytype (t); - if (!e || !e->vfsent_name) - return "none"; - else - return e->vfsent_name; -} -#endif /* MOUNTED_VMOUNT */ - - -#if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2 - -/* Return the device number from MOUNT_OPTIONS, if possible. - Otherwise return (dev_t) -1. */ - -static dev_t -dev_from_mount_options (char const *mount_options) -{ - /* GNU/Linux allows file system implementations to define their own - meaning for "dev=" mount options, so don't trust the meaning - here. */ -# ifndef __linux__ - - static char const dev_pattern[] = ",dev="; - char const *devopt = strstr (mount_options, dev_pattern); - - if (devopt) - { - char const *optval = devopt + sizeof dev_pattern - 1; - char *optvalend; - unsigned long int dev; - errno = 0; - dev = strtoul (optval, &optvalend, 16); - if (optval != optvalend - && (*optvalend == '\0' || *optvalend == ',') - && ! (dev == ULONG_MAX && errno == ERANGE) - && dev == (dev_t) dev) - return dev; - } - -# endif - - return -1; -} - -#endif - -/* Return a list of the currently mounted file systems, or NULL on error. - Add each entry to the tail of the list so that they stay in order. - If NEED_FS_TYPE is true, ensure that the file system type fields in - the returned list are valid. Otherwise, they might not be. */ - -struct mount_entry * -read_file_system_list (bool need_fs_type) -{ - struct mount_entry *mount_list; - struct mount_entry *me; - struct mount_entry **mtail = &mount_list; - -#ifdef MOUNTED_LISTMNTENT - { - struct tabmntent *mntlist, *p; - struct mntent *mnt; - struct mount_entry *me; - - /* the third and fourth arguments could be used to filter mounts, - but Crays doesn't seem to have any mounts that we want to - remove. Specifically, automount create normal NFS mounts. - */ - - if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0) - return NULL; - for (p = mntlist; p; p = p->next) { - mnt = p->ment; - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (mnt->mnt_fsname); - me->me_mountdir = xstrdup (mnt->mnt_dir); - me->me_type = xstrdup (mnt->mnt_type); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = -1; - *mtail = me; - mtail = &me->me_next; - } - freemntlist (mntlist); - } -#endif - -#ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ - { - struct mntent *mnt; - char *table = MOUNTED; - FILE *fp; - - fp = setmntent (table, "r"); - if (fp == NULL) - return NULL; - - while ((mnt = getmntent (fp))) - { - me = malloc (sizeof *me); - me->me_devname = strdup (mnt->mnt_fsname); - me->me_mountdir = strdup (mnt->mnt_dir); - me->me_type = strdup (mnt->mnt_type); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = dev_from_mount_options (mnt->mnt_opts); - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - if (endmntent (fp) == 0) - goto free_then_fail; - } -#endif /* MOUNTED_GETMNTENT1. */ - -#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ - { - struct statfs *fsp; - int entries; - - entries = getmntinfo (&fsp, MNT_NOWAIT); - if (entries < 0) - return NULL; - for (; entries-- > 0; fsp++) - { - me = malloc (sizeof *me); - me->me_devname = strdup (fsp->f_mntfromname); - me->me_mountdir = strdup (fsp->f_mntonname); -#if defined(__macosx__) - me->me_type = fsp->f_fstypename; -#else - me->me_type = fsp->fs_typename; -#endif - me->me_type_malloced = 0; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - } -#endif /* MOUNTED_GETMNTINFO */ - -#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ - { - struct statvfs *fsp; - int entries; - - entries = getmntinfo (&fsp, MNT_NOWAIT); - if (entries < 0) - return NULL; - for (; entries-- > 0; fsp++) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (fsp->f_mntfromname); - me->me_mountdir = xstrdup (fsp->f_mntonname); - me->me_type = xstrdup (fsp->f_fstypename); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - } -#endif /* MOUNTED_GETMNTINFO2 */ - -#ifdef MOUNTED_GETMNT /* Ultrix. */ - { - int offset = 0; - int val; - struct fs_data fsd; - - while (errno = 0, - 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, - (char *) 0))) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (fsd.fd_req.devname); - me->me_mountdir = xstrdup (fsd.fd_req.path); - me->me_type = gt_names[fsd.fd_req.fstype]; - me->me_type_malloced = 0; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = fsd.fd_req.dev; - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - if (val < 0) - goto free_then_fail; - } -#endif /* MOUNTED_GETMNT. */ - -#if defined MOUNTED_FS_STAT_DEV /* BeOS */ - { - /* The next_dev() and fs_stat_dev() system calls give the list of - all file systems, including the information returned by statvfs() - (fs type, total blocks, free blocks etc.), but without the mount - point. But on BeOS all file systems except / are mounted in the - rootfs, directly under /. - The directory name of the mount point is often, but not always, - identical to the volume name of the device. - We therefore get the list of subdirectories of /, and the list - of all file systems, and match the two lists. */ - - DIR *dirp; - struct rootdir_entry - { - char *name; - dev_t dev; - ino_t ino; - struct rootdir_entry *next; - }; - struct rootdir_entry *rootdir_list; - struct rootdir_entry **rootdir_tail; - int32 pos; - dev_t dev; - fs_info fi; - - /* All volumes are mounted in the rootfs, directly under /. */ - rootdir_list = NULL; - rootdir_tail = &rootdir_list; - dirp = opendir ("/"); - if (dirp) - { - struct dirent *d; - - while ((d = readdir (dirp)) != NULL) - { - char *name; - struct stat statbuf; - - if (strcmp (d->d_name, "..") == 0) - continue; - - if (strcmp (d->d_name, ".") == 0) - name = strdup ("/"); - else - { - name = malloc (1 + strlen (d->d_name) + 1); - name[0] = '/'; - strcpy (name + 1, d->d_name); - } - - if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) - { - struct rootdir_entry *re = malloc (sizeof *re); - re->name = name; - re->dev = statbuf.st_dev; - re->ino = statbuf.st_ino; - - /* Add to the linked list. */ - *rootdir_tail = re; - rootdir_tail = &re->next; - } - else - free (name); - } - closedir (dirp); - } - *rootdir_tail = NULL; - - for (pos = 0; (dev = next_dev (&pos)) >= 0; ) - if (fs_stat_dev (dev, &fi) >= 0) - { - /* Note: fi.dev == dev. */ - struct rootdir_entry *re; - - for (re = rootdir_list; re; re = re->next) - if (re->dev == fi.dev && re->ino == fi.root) - break; - - me = malloc (sizeof *me); - me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name); - me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name); - me->me_type = strdup (fi.fsh_name); - me->me_type_malloced = 1; - me->me_dev = fi.dev; - me->me_dummy = 0; - me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - *mtail = NULL; - - while (rootdir_list != NULL) - { - struct rootdir_entry *re = rootdir_list; - rootdir_list = re->next; - free (re->name); - free (re); - } - } -#endif /* MOUNTED_FS_STAT_DEV */ - -#if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */ - { - int numsys, counter; - size_t bufsize; - struct statfs *stats; - - numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT); - if (numsys < 0) - return (NULL); - if (SIZE_MAX / sizeof *stats <= numsys) - xalloc_die (); - - bufsize = (1 + numsys) * sizeof *stats; - stats = xmalloc (bufsize); - numsys = getfsstat (stats, bufsize, MNT_NOWAIT); - - if (numsys < 0) - { - free (stats); - return (NULL); - } - - for (counter = 0; counter < numsys; counter++) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (stats[counter].f_mntfromname); - me->me_mountdir = xstrdup (stats[counter].f_mntonname); - me->me_type = xstrdup (FS_TYPE (stats[counter])); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - free (stats); - } -#endif /* MOUNTED_GETFSSTAT */ - -#if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */ - { - struct mnttab mnt; - char *table = "/etc/mnttab"; - FILE *fp; - - fp = fopen (table, "r"); - if (fp == NULL) - return NULL; - - while (fread (&mnt, sizeof mnt, 1, fp) > 0) - { - me = xmalloc (sizeof *me); -# ifdef GETFSTYP /* SVR3. */ - me->me_devname = xstrdup (mnt.mt_dev); -# else - me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6); - strcpy (me->me_devname, "/dev/"); - strcpy (me->me_devname + 5, mnt.mt_dev); -# endif - me->me_mountdir = xstrdup (mnt.mt_filsys); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - me->me_type = ""; - me->me_type_malloced = 0; -# ifdef GETFSTYP /* SVR3. */ - if (need_fs_type) - { - struct statfs fsd; - char typebuf[FSTYPSZ]; - - if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1 - && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) - { - me->me_type = xstrdup (typebuf); - me->me_type_malloced = 1; - } - } -# endif - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - if (ferror (fp)) - { - /* The last fread() call must have failed. */ - int saved_errno = errno; - fclose (fp); - errno = saved_errno; - goto free_then_fail; - } - - if (fclose (fp) == EOF) - goto free_then_fail; - } -#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */ - -#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */ - { - struct mntent **mnttbl = getmnttbl (), **ent; - for (ent=mnttbl;*ent;ent++) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup ( (*ent)->mt_resource); - me->me_mountdir = xstrdup ( (*ent)->mt_directory); - me->me_type = xstrdup ((*ent)->mt_fstype); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - endmnttbl (); - } -#endif - -#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ - { - struct mnttab mnt; - char *table = MNTTAB; - FILE *fp; - int ret; - int lockfd = -1; - -# if defined F_RDLCK && defined F_SETLKW - /* MNTTAB_LOCK is a macro name of our own invention; it's not present in - e.g. Solaris 2.6. If the SVR4 folks ever define a macro - for this file name, we should use their macro name instead. - (Why not just lock MNTTAB directly? We don't know.) */ -# ifndef MNTTAB_LOCK -# define MNTTAB_LOCK "/etc/.mnttab.lock" -# endif - lockfd = open (MNTTAB_LOCK, O_RDONLY); - if (0 <= lockfd) - { - struct flock flock; - flock.l_type = F_RDLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - while (fcntl (lockfd, F_SETLKW, &flock) == -1) - if (errno != EINTR) - { - int saved_errno = errno; - close (lockfd); - errno = saved_errno; - return NULL; - } - } - else if (errno != ENOENT) - return NULL; -# endif - - errno = 0; - fp = fopen (table, "r"); - if (fp == NULL) - ret = errno; - else - { - while ((ret = getmntent (fp, &mnt)) == 0) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (mnt.mnt_special); - me->me_mountdir = xstrdup (mnt.mnt_mountp); - me->me_type = xstrdup (mnt.mnt_fstype); - me->me_type_malloced = 1; - me->me_dummy = MNT_IGNORE (&mnt) != 0; - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = dev_from_mount_options (mnt.mnt_mntopts); - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1; - } - - if (0 <= lockfd && close (lockfd) != 0) - ret = errno; - - if (0 <= ret) - { - errno = ret; - goto free_then_fail; - } - } -#endif /* MOUNTED_GETMNTENT2. */ - -#ifdef MOUNTED_VMOUNT /* AIX. */ - { - int bufsize; - char *entries, *thisent; - struct vmount *vmp; - int n_entries; - int i; - - /* Ask how many bytes to allocate for the mounted file system info. */ - if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0) - return NULL; - entries = xmalloc (bufsize); - - /* Get the list of mounted file systems. */ - n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries); - if (n_entries < 0) - { - int saved_errno = errno; - free (entries); - errno = saved_errno; - return NULL; - } - - for (i = 0, thisent = entries; - i < n_entries; - i++, thisent += vmp->vmt_length) - { - char *options, *ignore; - - vmp = (struct vmount *) thisent; - me = xmalloc (sizeof *me); - if (vmp->vmt_flags & MNT_REMOTE) - { - char *host, *dir; - - me->me_remote = 1; - /* Prepend the remote dirname. */ - host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off; - dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off; - me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2); - strcpy (me->me_devname, host); - strcat (me->me_devname, ":"); - strcat (me->me_devname, dir); - } - else - { - me->me_remote = 0; - me->me_devname = xstrdup (thisent + - vmp->vmt_data[VMT_OBJECT].vmt_off); - } - me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); - me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); - me->me_type_malloced = 1; - options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; - ignore = strstr (options, "ignore"); - me->me_dummy = (ignore - && (ignore == options || ignore[-1] == ',') - && (ignore[sizeof "ignore" - 1] == ',' - || ignore[sizeof "ignore" - 1] == '\0')); - me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - free (entries); - } -#endif /* MOUNTED_VMOUNT. */ - - *mtail = NULL; - return mount_list; - - - free_then_fail: - { - int saved_errno = errno; - *mtail = NULL; - - while (mount_list) - { - me = mount_list->me_next; - free (mount_list->me_devname); - free (mount_list->me_mountdir); - if (mount_list->me_type_malloced) - free (mount_list->me_type); - free (mount_list); - mount_list = me; - } - - errno = saved_errno; - return NULL; - } -} - -#endif - +/* mountlist.c -- return a list of mounted file systems + + Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 this program; if not, see . +*/ + +// This file is not used on some platforms, so don't do anything for them +#if(!defined(__WIN32__))&&(!defined(__amigaos4__))&&(!defined(__AROS__))&&(!defined(__MORPHOS__))&&(!defined(__amigaos__)) + +// We don't use autoconf and all that in grafx2, so let's do the config here ... +#if defined(__macosx__) || defined(__FreeBSD__) // MacOS X is POSIX compliant + #define MOUNTED_GETMNTINFO +#elif defined(__BEOS__) || defined(__HAIKU__) + #define MOUNTED_FS_STAT_DEV +#elif defined(__SKYOS__) + #warning "Your platform is missing some specific code here ! please check and fix :)" +#else + #define MOUNTED_GETMNTENT1 +#endif +// --- END GRAFX2 CUSTOM CONFIG --- + +#include "mountlist.h" + +#include +#include +#include +#include + +#include + +#include + +#include + +#if HAVE_SYS_PARAM_H +# include +#endif + +#if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ +# if HAVE_SYS_UCRED_H +# include /* needed on OSF V4.0 for definition of NGROUPS, + NGROUPS is used as an array dimension in ucred.h */ +# include /* needed by powerpc-apple-darwin1.3.7 */ +# endif +# if HAVE_SYS_MOUNT_H +# include +# endif +# if HAVE_SYS_FS_TYPES_H +# include /* needed by powerpc-apple-darwin1.3.7 */ +# endif +# if HAVE_STRUCT_FSSTAT_F_FSTYPENAME +# define FS_TYPE(Ent) ((Ent).f_fstypename) +# else +# define FS_TYPE(Ent) mnt_names[(Ent).f_type] +# endif +#endif /* MOUNTED_GETFSSTAT */ + +#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ +# include +# if !defined MOUNTED +# if defined _PATH_MOUNTED /* GNU libc */ +# define MOUNTED _PATH_MOUNTED +# endif +# if defined MNT_MNTTAB /* HP-UX. */ +# define MOUNTED MNT_MNTTAB +# endif +# if defined MNTTABNAME /* Dynix. */ +# define MOUNTED MNTTABNAME +# endif +# endif +#endif + +#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ +# include +#endif + +#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ +# include +#endif + +#ifdef MOUNTED_GETMNT /* Ultrix. */ +# include +# include +#endif + +#ifdef MOUNTED_FS_STAT_DEV /* BeOS. */ +# include +# include +#endif + +#ifdef MOUNTED_FREAD /* SVR2. */ +# include +#endif + +#ifdef MOUNTED_FREAD_FSTYP /* SVR3. */ +# include +# include +# include +#endif + +#ifdef MOUNTED_LISTMNTENT +# include +#endif + +#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ +# include +#endif + +#ifdef MOUNTED_VMOUNT /* AIX. */ +# include +# include +#endif + +#ifdef DOLPHIN +/* So special that it's not worth putting this in autoconf. */ +# undef MOUNTED_FREAD_FSTYP +# define MOUNTED_GETMNTTBL +#endif + +#if HAVE_SYS_MNTENT_H +/* This is to get MNTOPT_IGNORE on e.g. SVR4. */ +# include +#endif + +#undef MNT_IGNORE +#if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT +# define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE) +#else +# define MNT_IGNORE(M) 0 +#endif + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif + +/* The results of open() in this file are not used with fchdir, + therefore save some unnecessary work in fchdir.c. */ +#undef open +#undef close + +/* The results of opendir() in this file are not used with dirfd and fchdir, + therefore save some unnecessary work in fchdir.c. */ +#undef opendir +#undef closedir + +// gcc2 under haiku and beos don't like these macros for some reason. +// As they are not used there anyways, we remove them and everyone is happy. +#if !defined(__HAIKU__) && !defined(__BEOS__) +#ifndef ME_DUMMY +# define ME_DUMMY(Fs_name, Fs_type) \ + (strcmp (Fs_type, "autofs") == 0 \ + || strcmp (Fs_type, "none") == 0 \ + || strcmp (Fs_type, "proc") == 0 \ + || strcmp (Fs_type, "subfs") == 0 \ + || strcmp (Fs_type, "sysfs") == 0 \ + || strcmp (Fs_type, "usbfs") == 0 \ + || strcmp (Fs_type, "devpts") == 0 \ + || strcmp (Fs_type, "tmpfs") == 0 \ + /* for NetBSD 3.0 */ \ + || strcmp (Fs_type, "kernfs") == 0 \ + /* for Irix 6.5 */ \ + || strcmp (Fs_type, "ignore") == 0 \ + /* for MacOSX */ \ + || strcmp (Fs_type, "devfs") == 0 \ + || strcmp (Fs_type, "fdesc") == 0 \ + || strcmp (Fs_type, "nfs") == 0 \ + || strcmp (Fs_type, "volfs") == 0) +#endif + +#ifndef ME_REMOTE +/* A file system is `remote' if its Fs_name contains a `:' + or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */ +# define ME_REMOTE(Fs_name, Fs_type) \ + (strchr (Fs_name, ':') != NULL \ + || ((Fs_name)[0] == '/' \ + && (Fs_name)[1] == '/' \ + && (strcmp (Fs_type, "smbfs") == 0 \ + || strcmp (Fs_type, "cifs") == 0))) +#endif +#endif // HAIKU / BEOS + +#ifdef MOUNTED_GETMNTINFO + +# if ! HAVE_STRUCT_STATFS_F_FSTYPENAME +static char * +fstype_to_string (short int t) +{ + switch (t) + { +# ifdef MOUNT_PC + case MOUNT_PC: + return "pc"; +# endif +# ifdef MOUNT_MFS + case MOUNT_MFS: + return "mfs"; +# endif +# ifdef MOUNT_LO + case MOUNT_LO: + return "lo"; +# endif +# ifdef MOUNT_TFS + case MOUNT_TFS: + return "tfs"; +# endif +# ifdef MOUNT_TMP + case MOUNT_TMP: + return "tmp"; +# endif +# ifdef MOUNT_UFS + case MOUNT_UFS: + return "ufs" ; +# endif +# ifdef MOUNT_NFS + case MOUNT_NFS: + return "nfs" ; +# endif +# ifdef MOUNT_MSDOS + case MOUNT_MSDOS: + return "msdos" ; +# endif +# ifdef MOUNT_LFS + case MOUNT_LFS: + return "lfs" ; +# endif +# ifdef MOUNT_LOFS + case MOUNT_LOFS: + return "lofs" ; +# endif +# ifdef MOUNT_FDESC + case MOUNT_FDESC: + return "fdesc" ; +# endif +# ifdef MOUNT_PORTAL + case MOUNT_PORTAL: + return "portal" ; +# endif +# ifdef MOUNT_NULL + case MOUNT_NULL: + return "null" ; +# endif +# ifdef MOUNT_UMAP + case MOUNT_UMAP: + return "umap" ; +# endif +# ifdef MOUNT_KERNFS + case MOUNT_KERNFS: + return "kernfs" ; +# endif +# ifdef MOUNT_PROCFS + case MOUNT_PROCFS: + return "procfs" ; +# endif +# ifdef MOUNT_AFS + case MOUNT_AFS: + return "afs" ; +# endif +# ifdef MOUNT_CD9660 + case MOUNT_CD9660: + return "cd9660" ; +# endif +# ifdef MOUNT_UNION + case MOUNT_UNION: + return "union" ; +# endif +# ifdef MOUNT_DEVFS + case MOUNT_DEVFS: + return "devfs" ; +# endif +# ifdef MOUNT_EXT2FS + case MOUNT_EXT2FS: + return "ext2fs" ; +# endif + default: + return "?"; + } +} +# endif + +static char * +fsp_to_string (const struct statfs *fsp) +{ +# if HAVE_STRUCT_STATFS_F_FSTYPENAME + return (char *) (fsp->f_fstypename); +# else + return fstype_to_string (fsp->f_type); +# endif +} + +#endif /* MOUNTED_GETMNTINFO */ + +#ifdef MOUNTED_VMOUNT /* AIX. */ +static char * +fstype_to_string (int t) +{ + struct vfs_ent *e; + + e = getvfsbytype (t); + if (!e || !e->vfsent_name) + return "none"; + else + return e->vfsent_name; +} +#endif /* MOUNTED_VMOUNT */ + + +#if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2 + +/* Return the device number from MOUNT_OPTIONS, if possible. + Otherwise return (dev_t) -1. */ + +static dev_t +dev_from_mount_options (char const *mount_options) +{ + /* GNU/Linux allows file system implementations to define their own + meaning for "dev=" mount options, so don't trust the meaning + here. */ +# ifndef __linux__ + + static char const dev_pattern[] = ",dev="; + char const *devopt = strstr (mount_options, dev_pattern); + + if (devopt) + { + char const *optval = devopt + sizeof dev_pattern - 1; + char *optvalend; + unsigned long int dev; + errno = 0; + dev = strtoul (optval, &optvalend, 16); + if (optval != optvalend + && (*optvalend == '\0' || *optvalend == ',') + && ! (dev == ULONG_MAX && errno == ERANGE) + && dev == (dev_t) dev) + return dev; + } + +# endif + + return -1; +} + +#endif + +/* Return a list of the currently mounted file systems, or NULL on error. + Add each entry to the tail of the list so that they stay in order. + If NEED_FS_TYPE is true, ensure that the file system type fields in + the returned list are valid. Otherwise, they might not be. */ + +struct mount_entry * +read_file_system_list (bool need_fs_type) +{ + struct mount_entry *mount_list; + struct mount_entry *me; + struct mount_entry **mtail = &mount_list; + +#ifdef MOUNTED_LISTMNTENT + { + struct tabmntent *mntlist, *p; + struct mntent *mnt; + struct mount_entry *me; + + /* the third and fourth arguments could be used to filter mounts, + but Crays doesn't seem to have any mounts that we want to + remove. Specifically, automount create normal NFS mounts. + */ + + if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0) + return NULL; + for (p = mntlist; p; p = p->next) { + mnt = p->ment; + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (mnt->mnt_fsname); + me->me_mountdir = xstrdup (mnt->mnt_dir); + me->me_type = xstrdup (mnt->mnt_type); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = -1; + *mtail = me; + mtail = &me->me_next; + } + freemntlist (mntlist); + } +#endif + +#ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ + { + struct mntent *mnt; + char *table = MOUNTED; + FILE *fp; + + fp = setmntent (table, "r"); + if (fp == NULL) + return NULL; + + while ((mnt = getmntent (fp))) + { + me = malloc (sizeof *me); + me->me_devname = strdup (mnt->mnt_fsname); + me->me_mountdir = strdup (mnt->mnt_dir); + me->me_type = strdup (mnt->mnt_type); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = dev_from_mount_options (mnt->mnt_opts); + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + + if (endmntent (fp) == 0) + goto free_then_fail; + } +#endif /* MOUNTED_GETMNTENT1. */ + +#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ + { + struct statfs *fsp; + int entries; + + entries = getmntinfo (&fsp, MNT_NOWAIT); + if (entries < 0) + return NULL; + for (; entries-- > 0; fsp++) + { + me = malloc (sizeof *me); + me->me_devname = strdup (fsp->f_mntfromname); + me->me_mountdir = strdup (fsp->f_mntonname); +#if defined(__macosx__) + me->me_type = fsp->f_fstypename; +#else + me->me_type = fsp->fs_typename; +#endif + me->me_type_malloced = 0; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + } +#endif /* MOUNTED_GETMNTINFO */ + +#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ + { + struct statvfs *fsp; + int entries; + + entries = getmntinfo (&fsp, MNT_NOWAIT); + if (entries < 0) + return NULL; + for (; entries-- > 0; fsp++) + { + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (fsp->f_mntfromname); + me->me_mountdir = xstrdup (fsp->f_mntonname); + me->me_type = xstrdup (fsp->f_fstypename); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + } +#endif /* MOUNTED_GETMNTINFO2 */ + +#ifdef MOUNTED_GETMNT /* Ultrix. */ + { + int offset = 0; + int val; + struct fs_data fsd; + + while (errno = 0, + 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, + (char *) 0))) + { + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (fsd.fd_req.devname); + me->me_mountdir = xstrdup (fsd.fd_req.path); + me->me_type = gt_names[fsd.fd_req.fstype]; + me->me_type_malloced = 0; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = fsd.fd_req.dev; + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + if (val < 0) + goto free_then_fail; + } +#endif /* MOUNTED_GETMNT. */ + +#if defined MOUNTED_FS_STAT_DEV /* BeOS */ + { + /* The next_dev() and fs_stat_dev() system calls give the list of + all file systems, including the information returned by statvfs() + (fs type, total blocks, free blocks etc.), but without the mount + point. But on BeOS all file systems except / are mounted in the + rootfs, directly under /. + The directory name of the mount point is often, but not always, + identical to the volume name of the device. + We therefore get the list of subdirectories of /, and the list + of all file systems, and match the two lists. */ + + DIR *dirp; + struct rootdir_entry + { + char *name; + dev_t dev; + ino_t ino; + struct rootdir_entry *next; + }; + struct rootdir_entry *rootdir_list; + struct rootdir_entry **rootdir_tail; + int32 pos; + dev_t dev; + fs_info fi; + + /* All volumes are mounted in the rootfs, directly under /. */ + rootdir_list = NULL; + rootdir_tail = &rootdir_list; + dirp = opendir ("/"); + if (dirp) + { + struct dirent *d; + + while ((d = readdir (dirp)) != NULL) + { + char *name; + struct stat statbuf; + + if (strcmp (d->d_name, "..") == 0) + continue; + + if (strcmp (d->d_name, ".") == 0) + name = strdup ("/"); + else + { + name = malloc (1 + strlen (d->d_name) + 1); + name[0] = '/'; + strcpy (name + 1, d->d_name); + } + + if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) + { + struct rootdir_entry *re = malloc (sizeof *re); + re->name = name; + re->dev = statbuf.st_dev; + re->ino = statbuf.st_ino; + + /* Add to the linked list. */ + *rootdir_tail = re; + rootdir_tail = &re->next; + } + else + free (name); + } + closedir (dirp); + } + *rootdir_tail = NULL; + + for (pos = 0; (dev = next_dev (&pos)) >= 0; ) + if (fs_stat_dev (dev, &fi) >= 0) + { + /* Note: fi.dev == dev. */ + struct rootdir_entry *re; + + for (re = rootdir_list; re; re = re->next) + if (re->dev == fi.dev && re->ino == fi.root) + break; + + me = malloc (sizeof *me); + me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name); + me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name); + me->me_type = strdup (fi.fsh_name); + me->me_type_malloced = 1; + me->me_dev = fi.dev; + me->me_dummy = 0; + me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + *mtail = NULL; + + while (rootdir_list != NULL) + { + struct rootdir_entry *re = rootdir_list; + rootdir_list = re->next; + free (re->name); + free (re); + } + } +#endif /* MOUNTED_FS_STAT_DEV */ + +#if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */ + { + int numsys, counter; + size_t bufsize; + struct statfs *stats; + + numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT); + if (numsys < 0) + return (NULL); + if (SIZE_MAX / sizeof *stats <= numsys) + xalloc_die (); + + bufsize = (1 + numsys) * sizeof *stats; + stats = xmalloc (bufsize); + numsys = getfsstat (stats, bufsize, MNT_NOWAIT); + + if (numsys < 0) + { + free (stats); + return (NULL); + } + + for (counter = 0; counter < numsys; counter++) + { + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (stats[counter].f_mntfromname); + me->me_mountdir = xstrdup (stats[counter].f_mntonname); + me->me_type = xstrdup (FS_TYPE (stats[counter])); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + + free (stats); + } +#endif /* MOUNTED_GETFSSTAT */ + +#if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */ + { + struct mnttab mnt; + char *table = "/etc/mnttab"; + FILE *fp; + + fp = fopen (table, "r"); + if (fp == NULL) + return NULL; + + while (fread (&mnt, sizeof mnt, 1, fp) > 0) + { + me = xmalloc (sizeof *me); +# ifdef GETFSTYP /* SVR3. */ + me->me_devname = xstrdup (mnt.mt_dev); +# else + me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6); + strcpy (me->me_devname, "/dev/"); + strcpy (me->me_devname + 5, mnt.mt_dev); +# endif + me->me_mountdir = xstrdup (mnt.mt_filsys); + me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ + me->me_type = ""; + me->me_type_malloced = 0; +# ifdef GETFSTYP /* SVR3. */ + if (need_fs_type) + { + struct statfs fsd; + char typebuf[FSTYPSZ]; + + if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1 + && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) + { + me->me_type = xstrdup (typebuf); + me->me_type_malloced = 1; + } + } +# endif + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + + if (ferror (fp)) + { + /* The last fread() call must have failed. */ + int saved_errno = errno; + fclose (fp); + errno = saved_errno; + goto free_then_fail; + } + + if (fclose (fp) == EOF) + goto free_then_fail; + } +#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */ + +#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */ + { + struct mntent **mnttbl = getmnttbl (), **ent; + for (ent=mnttbl;*ent;ent++) + { + me = xmalloc (sizeof *me); + me->me_devname = xstrdup ( (*ent)->mt_resource); + me->me_mountdir = xstrdup ( (*ent)->mt_directory); + me->me_type = xstrdup ((*ent)->mt_fstype); + me->me_type_malloced = 1; + me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + endmnttbl (); + } +#endif + +#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ + { + struct mnttab mnt; + char *table = MNTTAB; + FILE *fp; + int ret; + int lockfd = -1; + +# if defined F_RDLCK && defined F_SETLKW + /* MNTTAB_LOCK is a macro name of our own invention; it's not present in + e.g. Solaris 2.6. If the SVR4 folks ever define a macro + for this file name, we should use their macro name instead. + (Why not just lock MNTTAB directly? We don't know.) */ +# ifndef MNTTAB_LOCK +# define MNTTAB_LOCK "/etc/.mnttab.lock" +# endif + lockfd = open (MNTTAB_LOCK, O_RDONLY); + if (0 <= lockfd) + { + struct flock flock; + flock.l_type = F_RDLCK; + flock.l_whence = SEEK_SET; + flock.l_start = 0; + flock.l_len = 0; + while (fcntl (lockfd, F_SETLKW, &flock) == -1) + if (errno != EINTR) + { + int saved_errno = errno; + close (lockfd); + errno = saved_errno; + return NULL; + } + } + else if (errno != ENOENT) + return NULL; +# endif + + errno = 0; + fp = fopen (table, "r"); + if (fp == NULL) + ret = errno; + else + { + while ((ret = getmntent (fp, &mnt)) == 0) + { + me = xmalloc (sizeof *me); + me->me_devname = xstrdup (mnt.mnt_special); + me->me_mountdir = xstrdup (mnt.mnt_mountp); + me->me_type = xstrdup (mnt.mnt_fstype); + me->me_type_malloced = 1; + me->me_dummy = MNT_IGNORE (&mnt) != 0; + me->me_remote = ME_REMOTE (me->me_devname, me->me_type); + me->me_dev = dev_from_mount_options (mnt.mnt_mntopts); + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + + ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1; + } + + if (0 <= lockfd && close (lockfd) != 0) + ret = errno; + + if (0 <= ret) + { + errno = ret; + goto free_then_fail; + } + } +#endif /* MOUNTED_GETMNTENT2. */ + +#ifdef MOUNTED_VMOUNT /* AIX. */ + { + int bufsize; + char *entries, *thisent; + struct vmount *vmp; + int n_entries; + int i; + + /* Ask how many bytes to allocate for the mounted file system info. */ + if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0) + return NULL; + entries = xmalloc (bufsize); + + /* Get the list of mounted file systems. */ + n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries); + if (n_entries < 0) + { + int saved_errno = errno; + free (entries); + errno = saved_errno; + return NULL; + } + + for (i = 0, thisent = entries; + i < n_entries; + i++, thisent += vmp->vmt_length) + { + char *options, *ignore; + + vmp = (struct vmount *) thisent; + me = xmalloc (sizeof *me); + if (vmp->vmt_flags & MNT_REMOTE) + { + char *host, *dir; + + me->me_remote = 1; + /* Prepend the remote dirname. */ + host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off; + dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off; + me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2); + strcpy (me->me_devname, host); + strcat (me->me_devname, ":"); + strcat (me->me_devname, dir); + } + else + { + me->me_remote = 0; + me->me_devname = xstrdup (thisent + + vmp->vmt_data[VMT_OBJECT].vmt_off); + } + me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); + me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); + me->me_type_malloced = 1; + options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; + ignore = strstr (options, "ignore"); + me->me_dummy = (ignore + && (ignore == options || ignore[-1] == ',') + && (ignore[sizeof "ignore" - 1] == ',' + || ignore[sizeof "ignore" - 1] == '\0')); + me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */ + + /* Add to the linked list. */ + *mtail = me; + mtail = &me->me_next; + } + free (entries); + } +#endif /* MOUNTED_VMOUNT. */ + + *mtail = NULL; + return mount_list; + + + free_then_fail: + { + int saved_errno = errno; + *mtail = NULL; + + while (mount_list) + { + me = mount_list->me_next; + free (mount_list->me_devname); + free (mount_list->me_mountdir); + if (mount_list->me_type_malloced) + free (mount_list->me_type); + free (mount_list); + mount_list = me; + } + + errno = saved_errno; + return NULL; + } +} + +#endif + diff --git a/mountlist.h b/mountlist.h index 04ac3535..43a15b21 100644 --- a/mountlist.h +++ b/mountlist.h @@ -1,47 +1,47 @@ -/* mountlist.h -- declarations for list of mounted file systems - - Copyright (C) 1991, 1992, 1998, 2000, 2001, 2002, 2003, 2004, 2005 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program 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 this program; if not, see . -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file mountlist.h -/// A function to enumerate the mounting points in the filesystem. -/// Used to display them in fileselectors. -////////////////////////////////////////////////////////////////////////////// - -#ifndef MOUNTLIST_H_ -# define MOUNTLIST_H_ - -# include -# include - -/* A mount table entry. */ -struct mount_entry -{ - char *me_devname; /* Device node name, including "/dev/". */ - char *me_mountdir; /* Mount point directory name. */ - char *me_type; /* "nfs", "4.2", etc. */ - dev_t me_dev; /* Device number of me_mountdir. */ - unsigned int me_dummy : 1; /* Nonzero for dummy file systems. */ - unsigned int me_remote : 1; /* Nonzero for remote fileystems. */ - unsigned int me_type_malloced : 1; /* Nonzero if me_type was malloced. */ - struct mount_entry *me_next; -}; - -struct mount_entry *read_file_system_list (bool need_fs_type); - -#endif +/* mountlist.h -- declarations for list of mounted file systems + + Copyright (C) 1991, 1992, 1998, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 this program; if not, see . +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file mountlist.h +/// A function to enumerate the mounting points in the filesystem. +/// Used to display them in fileselectors. +////////////////////////////////////////////////////////////////////////////// + +#ifndef MOUNTLIST_H_ +# define MOUNTLIST_H_ + +# include +# include + +/* A mount table entry. */ +struct mount_entry +{ + char *me_devname; /* Device node name, including "/dev/". */ + char *me_mountdir; /* Mount point directory name. */ + char *me_type; /* "nfs", "4.2", etc. */ + dev_t me_dev; /* Device number of me_mountdir. */ + unsigned int me_dummy : 1; /* Nonzero for dummy file systems. */ + unsigned int me_remote : 1; /* Nonzero for remote fileystems. */ + unsigned int me_type_malloced : 1; /* Nonzero if me_type was malloced. */ + struct mount_entry *me_next; +}; + +struct mount_entry *read_file_system_list (bool need_fs_type); + +#endif diff --git a/op_c.c b/op_c.c index 418ba8a6..6f62980e 100644 --- a/op_c.c +++ b/op_c.c @@ -1,1226 +1,1226 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -#include - -#include "op_c.h" -#include "errors.h" - -void RGB_to_HSL(int r,int g,int b,byte * hr,byte * sr,byte* lr) -{ - double rd,gd,bd,h,s,l,max,min; - - // convert RGB to HSV - rd = r / 255.0; // rd,gd,bd range 0-1 instead of 0-255 - gd = g / 255.0; - bd = b / 255.0; - - // compute L -// l=(rd*0.30)+(gd*0.59)+(bd*0.11); - - // compute maximum of rd,gd,bd - if (rd>=gd) - { - if (rd>=bd) - max = rd; - else - max = bd; - } - else - { - if (gd>=bd) - max = gd; - else - max = bd; - } - - // compute minimum of rd,gd,bd - if (rd<=gd) - { - if (rd<=bd) - min = rd; - else - min = bd; - } - else - { - if (gd<=bd) - min = gd; - else - min = bd; - } - - l = (max + min) / 2.0; - - if(max==min) - s = h = 0; - else - { - if (l<=0.5) - s = (max - min) / (max + min); - else - s = (max - min) / (2 - (max + min)); - - if (max == rd) - h = 42.5 * (gd-bd)/(max-min); - else if (max == gd) - h = 42.5 * (bd-rd)/(max-min)+85; - else - h = 42.5 * (rd-gd)/(max-min)+170; - if (h<0) h+=255; - } - - *hr = h; - *lr = (l*255.0); - *sr = (s*255.0); -} - -void HSL_to_RGB(byte h,byte s,byte l, byte* r, byte* g, byte* b) -{ - float rf =0 ,gf = 0,bf = 0; - float hf,lf,sf; - float p,q; - - if(s==0) - { - *r=*g=*b=l; - return; - } - - hf = h / 255.0; - lf = l / 255.0; - sf = s / 255.0; - - if (lf<=0.5) - q = lf*(1+sf); - else - q = lf+sf-lf*sf; - p = 2*lf-q; - - rf = hf + (1 / 3.0); - gf = hf; - bf = hf - (1 / 3.0); - - if (rf < 0) rf+=1; - if (rf > 1) rf-=1; - if (gf < 0) gf+=1; - if (gf > 1) gf-=1; - if (bf < 0) bf+=1; - if (bf > 1) bf-=1; - - if (rf < 1/6.0) - rf = p + ((q-p)*6*rf); - else if(rf < 0.5) - rf = q; - else if(rf < 2/3.0) - rf = p + ((q-p)*6*(2/3.0-rf)); - else - rf = p; - - if (gf < 1/6.0) - gf = p + ((q-p)*6*gf); - else if(gf < 0.5) - gf = q; - else if(gf < 2/3.0) - gf = p + ((q-p)*6*(2/3.0-gf)); - else - gf = p; - - if (bf < 1/6.0) - bf = p + ((q-p)*6*bf); - else if(bf < 0.5) - bf = q; - else if(bf < 2/3.0) - bf = p + ((q-p)*6*(2/3.0-bf)); - else - bf = p; - - *r = rf * (255); - *g = gf * (255); - *b = bf * (255); -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////// Méthodes de gestion des tables de conversion // -///////////////////////////////////////////////////////////////////////////// - -T_Conversion_table * CT_new(int nbb_r,int nbb_g,int nbb_b) -{ - T_Conversion_table * n; - int size; - - n=(T_Conversion_table *)malloc(sizeof(T_Conversion_table)); - if (n!=NULL) - { - // On recopie les paramŠtres demand‚s - n->nbb_r=nbb_r; - n->nbb_g=nbb_g; - n->nbb_b=nbb_b; - - // On calcule les autres - n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; - n->dec_g=nbb_b; - n->dec_b=0; - n->red_r=8-nbb_r; - n->red_g=8-nbb_g; - n->red_b=8-nbb_b; - - // On tente d'allouer la table - size=(n->rng_r)*(n->rng_g)*(n->rng_b); - n->table=(byte *)malloc(size); - if (n->table!=NULL) - // C'est bon! - memset(n->table,0,size); // Inutile, mais plus propre - else - { - // Table impossible … allouer - free(n); - n=NULL; - } - } - - return n; -} - -void CT_delete(T_Conversion_table * t) -{ - free(t->table); - free(t); -} - -byte CT_get(T_Conversion_table * t,int r,int g,int b) -{ - int index; - - // On réduit le nombre de bits par couleur - r=(r>>t->red_r); - g=(g>>t->red_g); - b=(b>>t->red_b); - - // On recherche la couleur la plus proche dans la table de conversion - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - - return t->table[index]; -} - -void CT_set(T_Conversion_table * t,int r,int g,int b,byte i) -{ - int index; - - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - t->table[index]=i; -} - - - -///////////////////////////////////////////////////////////////////////////// -/////////////////////////////// M‚thodes de gestion des tables d'occurence // -///////////////////////////////////////////////////////////////////////////// - -void OT_init(T_Occurrence_table * t) -{ - int size; - - size=(t->rng_r)*(t->rng_g)*(t->rng_b)*sizeof(int); - memset(t->table,0,size); // On initialise … 0 -} - -T_Occurrence_table * OT_new(int nbb_r,int nbb_g,int nbb_b) -{ - T_Occurrence_table * n; - int size; - - n=(T_Occurrence_table *)malloc(sizeof(T_Occurrence_table)); - if (n!=0) - { - // On recopie les paramŠtres demand‚s - n->nbb_r=nbb_r; - n->nbb_g=nbb_g; - n->nbb_b=nbb_b; - - // On calcule les autres - n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; - n->dec_g=nbb_b; - n->dec_b=0; - n->red_r=8-nbb_r; - n->red_g=8-nbb_g; - n->red_b=8-nbb_b; - - // On tente d'allouer la table - size=(n->rng_r)*(n->rng_g)*(n->rng_b)*sizeof(int); - n->table=(int *)malloc(size); - if (n->table!=0) - // C'est bon! On initialise … 0 - OT_init(n); - else - { - // Table impossible … allouer - free(n); - n=0; - } - } - - return n; -} - -void OT_delete(T_Occurrence_table * t) -{ - free(t->table); - free(t); -} - -int OT_get(T_Occurrence_table * t,int r,int g,int b) -{ - int index; - - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - return t->table[index]; -} - -void OT_inc(T_Occurrence_table * t,int r,int g,int b) -{ - int index; - - r=(r>>t->red_r); - g=(g>>t->red_g); - b=(b>>t->red_b); - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - t->table[index]++; -} - -void OT_count_occurrences(T_Occurrence_table * t,T_Bitmap24B image,int size) -{ - T_Bitmap24B ptr; - int index; - - for (index=size,ptr=image;index>0;index--,ptr++) - OT_inc(t,ptr->R,ptr->G,ptr->B); -} - -int OT_count_colors(T_Occurrence_table * t) -{ - int val; // Valeur de retour - int nb; // Nombre de couleurs … tester - int i; // Compteur de couleurs test‚es - - val=0; - nb=(t->rng_r)*(t->rng_g)*(t->rng_b); - for (i=0;itable[i]>0) - val++; - - return val; -} - - - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////// M‚thodes de gestion des clusters // -///////////////////////////////////////////////////////////////////////////// - -void Cluster_analyser(T_Cluster * c,T_Occurrence_table * to) -{ - int rmin,rmax,vmin,vmax,bmin,bmax; - int r,g,b; - - // On cherche les mins et les maxs de chaque composante sur la couverture - - // int nbocc; - - // On prédécale tout pour éviter de faire trop de bazar en se forçant à utiliser OT_get, plus rapide - rmin=c->rmax <<16; rmax=c->rmin << 16; - vmin=c->vmax << 8; vmax=c->vmin << 8; - bmin=c->bmax; bmax=c->bmin; - c->occurences=0; - /* - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for (b=c->bmin;b<=c->bmax;b++) - { - nbocc=to->table[r + g + b]; // OT_get - if (nbocc) - { - if (rrmax) rmax=r; - if (gvmax) vmax=g; - if (bbmax) bmax=b; - c->occurences+=nbocc; - } - } - */ - - // On recherche le minimum et le maximum en parcourant le cluster selon chaque composante, - // ça évite des accès mémoires inutiles, de plus chaque boucle est plus petite que la - // précédente puisqu'on connait une borne supplémentaire - - for(r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - rmin=r; - goto RMAX; - } - } -RMAX: - for(r=c->rmax<<16;r>=rmin;r-=1<<16) - for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - rmax=r; - goto VMIN; - } - } -VMIN: - for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for(r=rmin;r<=rmax;r+=1<<16) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - vmin=g; - goto VMAX; - } - } -VMAX: - for(g=c->vmax<<8;g>=vmin;g-=1<<8) - for(r=rmin;r<=rmax;r+=1<<16) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - vmax=g; - goto BMIN; - } - } -BMIN: - for(b=c->bmin;b<=c->bmax;b++) - for(r=rmin;r<=rmax;r+=1<<16) - for(g=vmin;g<=vmax;g+=1<<8) - { - if(to->table[r + g + b]) // OT_get - { - bmin=b; - goto BMAX; - } - } -BMAX: - for(b=c->bmax;b>=bmin;b--) - for(r=rmin;r<=rmax;r+=1<<16) - for(g=vmin;g<=vmax;g+=1<<8) - { - if(to->table[r + g + b]) // OT_get - { - bmax=b; - goto ENDCRUSH; - } - } -ENDCRUSH: - // Il faut quand même parcourir la partie utile du cluster, pour savoir combien il y a d'occurences - for(r=rmin;r<=rmax;r+=1<<16) - for(g=vmin;g<=vmax;g+=1<<8) - for(b=bmin;b<=bmax;b++) - { - c->occurences+=to->table[r + g + b]; // OT_get - } - - c->rmin=rmin>>16; c->rmax=rmax>>16; - c->vmin=vmin>>8; c->vmax=vmax>>8; - c->bmin=bmin; c->bmax=bmax; - - // On regarde la composante qui a la variation la plus grande - r=(c->rmax-c->rmin)*299; - g=(c->vmax-c->vmin)*587; - b=(c->bmax-c->bmin)*114; - - if (g>=r) - { - // G>=R - if (g>=b) - { - // G>=R et G>=B - c->plus_large=1; - } - else - { - // G>=R et Gplus_large=2; - } - } - else - { - // R>G - if (r>=b) - { - // R>G et R>=B - c->plus_large=0; - } - else - { - // R>G et Rplus_large=2; - } - } -} - -void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurrence_table * to) -{ - int limit; - int cumul; - int r,g,b; - - limit=(c->occurences)/2; - cumul=0; - if (hue==0) - { - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - { - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - { - for (b=c->bmin;b<=c->bmax;b++) - { - cumul+=to->table[r + g + b]; - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - - r>>=16; - g>>=8; - - if (r==c->rmin) - r++; - // R est la valeur de d‚but du 2nd cluster - - c1->Rmin=c->Rmin; c1->Rmax=r-1; - c1->rmin=c->rmin; c1->rmax=r-1; - c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; - c1->vmin=c->vmin; c1->vmax=c->vmax; - c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; - c1->bmin=c->bmin; c1->bmax=c->bmax; - c2->Rmin=r; c2->Rmax=c->Rmax; - c2->rmin=r; c2->rmax=c->rmax; - c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; - c2->vmin=c->vmin; c2->vmax=c->vmax; - c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; - c2->bmin=c->bmin; c2->bmax=c->bmax; - } - else - if (hue==1) - { - - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - { - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - { - for (b=c->bmin;b<=c->bmax;b++) - { - cumul+=to->table[r + g + b]; - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - - r>>=16; g>>=8; - - if (g==c->vmin) - g++; - // G est la valeur de d‚but du 2nd cluster - - c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; - c1->rmin=c->rmin; c1->rmax=c->rmax; - c1->Gmin=c->Gmin; c1->Vmax=g-1; - c1->vmin=c->vmin; c1->vmax=g-1; - c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; - c1->bmin=c->bmin; c1->bmax=c->bmax; - c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; - c2->rmin=c->rmin; c2->rmax=c->rmax; - c2->Gmin=g; c2->Vmax=c->Vmax; - c2->vmin=g; c2->vmax=c->vmax; - c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; - c2->bmin=c->bmin; c2->bmax=c->bmax; - } - else - { - - for (b=c->bmin;b<=c->bmax;b++) - { - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - { - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - { - cumul+=to->table[r + g + b]; - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - - r>>=16; g>>=8; - - if (b==c->bmin) - b++; - // B est la valeur de d‚but du 2nd cluster - - c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; - c1->rmin=c->rmin; c1->rmax=c->rmax; - c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; - c1->vmin=c->vmin; c1->vmax=c->vmax; - c1->Bmin=c->Bmin; c1->Bmax=b-1; - c1->bmin=c->bmin; c1->bmax=b-1; - c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; - c2->rmin=c->rmin; c2->rmax=c->rmax; - c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; - c2->vmin=c->vmin; c2->vmax=c->vmax; - c2->Bmin=b; c2->Bmax=c->Bmax; - c2->bmin=b; c2->bmax=c->bmax; - } -} - -void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) -{ - int cumul_r,cumul_g,cumul_b; - int r,g,b; - int nbocc; - - byte s=0; - - cumul_r=cumul_g=cumul_b=0; - for (r=c->rmin;r<=c->rmax;r++) - for (g=c->vmin;g<=c->vmax;g++) - for (b=c->bmin;b<=c->bmax;b++) - { - nbocc=OT_get(to,r,g,b); - if (nbocc) - { - cumul_r+=r*nbocc; - cumul_g+=g*nbocc; - cumul_b+=b*nbocc; - } - } - - c->r=(cumul_r<red_r)/c->occurences; - c->g=(cumul_g<red_g)/c->occurences; - c->b=(cumul_b<red_b)/c->occurences; - RGB_to_HSL(c->r,c->g,c->b,&c->h,&s,&c->l); -} - - - -///////////////////////////////////////////////////////////////////////////// -//////////////////////////// M‚thodes de gestion des ensembles de clusters // -///////////////////////////////////////////////////////////////////////////// - -/// Setup the first cluster before we start the operations -void CS_Init(T_Cluster_set * cs,T_Occurrence_table * to) -{ - cs->clusters->Rmin = cs->clusters->rmin = 0; - cs->clusters->Gmin = cs->clusters->vmin = 0; - cs->clusters->Bmin = cs->clusters->bmin = 0; - cs->clusters->Rmax = cs->clusters->rmax = to->rng_r-1; - cs->clusters->Vmax = cs->clusters->vmax = to->rng_g-1; - cs->clusters->Bmax = cs->clusters->bmax = to->rng_b-1; - cs->clusters->next = NULL; - Cluster_analyser(cs->clusters,to); - cs->nb=1; -} - -/// Allocate a new cluster set -T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to) -{ - T_Cluster_set * n; - - n=(T_Cluster_set *)malloc(sizeof(T_Cluster_set)); - if (n != NULL) - { - // On recopie les paramŠtres demand‚s - n->nb_max=OT_count_colors(to); - - // On vient de compter le nombre de couleurs existantes, s'il est plus grand que 256 on limite à 256 - // (nombre de couleurs voulu au final) - if (n->nb_max>nbmax) - { - n->nb_max=nbmax; - } - - // On tente d'allouer le premier cluster - n->clusters=(T_Cluster *)malloc(sizeof(T_Cluster)); - if (n->clusters!=NULL) - // C'est bon! On initialise - CS_Init(n,to); - else - { - // Table impossible … allouer - free(n); - n=0; - } - } - - return n; -} - -/// Free a cluster set -void CS_Delete(T_Cluster_set * cs) -{ - T_Cluster* nxt; - while(cs->clusters != NULL) - { - nxt = cs->clusters->next; - free(cs->clusters); - cs->clusters = nxt; - } - free(cs); -} - -void CS_Get(T_Cluster_set * cs,T_Cluster * c) -{ - T_Cluster* current = cs->clusters; - T_Cluster* prev = NULL; - - // Search a cluster with at least 2 distinct colors so we can split it - do - { - if ( (current->rmin < current->rmax) || - (current->vmin < current->vmax) || - (current->bmin < current->bmax) ) - break; - - prev = current; - - } while((current = current -> next)); - - // copy it to c - *c = *current; - - // remove it from the list - cs->nb--; - - if(prev) - prev->next = current->next; - else - cs->clusters = current->next; - free(current); - current = NULL; -} - -void CS_Set(T_Cluster_set * cs,T_Cluster * c) -{ - T_Cluster* current = cs->clusters; - T_Cluster* prev = NULL; - - // Search the first cluster that is smaller than ours - if(current != NULL) // don't search if the list is empty - do - { - if (current->occurences < c->occurences) - break; - prev = current; - } while((current = current -> next)); - - // Now insert our cluster just before the one we found - c -> next = current; - - current = malloc(sizeof(T_Cluster)); - *current = *c ; - - if(prev) prev -> next = current; - else cs->clusters = current; - - cs -> nb++; -} - -// Détermination de la meilleure palette en utilisant l'algo Median Cut : -// 1) On considère l'espace (R,G,B) comme 1 boîte -// 2) On cherche les extrêmes de la boîte en (R,G,B) -// 3) On trie les pixels de l'image selon l'axe le plus long parmi (R,G,B) -// 4) On coupe la boîte en deux au milieu, et on compacte pour que chaque bord corresponde bien à un pixel extreme -// 5) On recommence à couper selon le plus grand axe toutes boîtes confondues -// 6) On s'arrête quand on a le nombre de couleurs voulu -void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to) -{ - T_Cluster current; - T_Cluster Nouveau1; - T_Cluster Nouveau2; - - // Tant qu'on a moins de 256 clusters - while (cs->nbnb_max) - { - // On récupère le plus grand cluster - CS_Get(cs,¤t); - - // On le coupe en deux - Cluster_split(¤t,&Nouveau1,&Nouveau2,current.plus_large,to); - - // On compacte ces deux nouveaux (il peut y avoir un espace entre l'endroit de la coupure et les premiers pixels du cluster) - Cluster_analyser(&Nouveau1,to); - Cluster_analyser(&Nouveau2,to); - - // On met ces deux nouveaux clusters dans le clusterSet... sauf s'ils sont vides - if(Nouveau1.occurences>0) - CS_Set(cs,&Nouveau1); - if(Nouveau2.occurences>0) - CS_Set(cs,&Nouveau2); - } -} - -void CS_Compute_colors(T_Cluster_set * cs,T_Occurrence_table * to) -{ - T_Cluster * c; - - for (c=cs->clusters;c!=NULL;c=c->next) - Cluster_compute_hue(c,to); -} - -void CS_Sort_by_chrominance(T_Cluster_set * cs) -{ - T_Cluster* nc; - T_Cluster* prev = NULL; - T_Cluster* place; - T_Cluster* newlist = NULL; - - while((nc = cs->clusters)) - { - // Remove the first cluster from the original list - nc = cs->clusters; - cs->clusters = cs->clusters->next; - - // Find his position in the new list - for(place = newlist;place != NULL; place = place->next) - { - if(place->h > nc->h) break; - prev = place; - } - - // Chain it there - nc->next = place; - if(prev) prev->next = nc; - else newlist = nc; - - } - - // Put the new list bavk in place - cs->clusters = newlist; -} - -void CS_Sort_by_luminance(T_Cluster_set * cs) -{ - T_Cluster* nc; - T_Cluster* prev = NULL; - T_Cluster* place; - T_Cluster* newlist = NULL; - - while((nc = cs->clusters)) - { - // Remove the first cluster from the original list - nc = cs->clusters; - cs->clusters = cs->clusters->next; - - // Find his position in the new list - for(place = newlist;place != NULL; place = place->next) - { - if(place->l > nc->l) break; - prev = place; - } - - // Chain it there - nc->next = place; - if(prev) prev->next = nc; - else newlist = nc; - - } - - // Put the new list bavk in place - cs->clusters = newlist; -} - -void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * tc,T_Components * palette) -{ - int index; - int r,g,b; - T_Cluster* current = cs->clusters; - - for (index=0;indexnb;index++) - { - palette[index].R=current->r; - palette[index].G=current->g; - palette[index].B=current->b; - - for (r=current->Rmin; r<=current->Rmax; r++) - for (g=current->Gmin;g<=current->Vmax;g++) - for (b=current->Bmin;b<=current->Bmax;b++) - CT_set(tc,r,g,b,index); - current = current->next; - } -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////// Méthodes de gestion des dégradés // -///////////////////////////////////////////////////////////////////////////// - -void GS_Init(T_Gradient_set * ds,T_Cluster_set * cs) -{ - ds->gradients[0].nb_colors=1; - ds->gradients[0].min=cs->clusters->h; - ds->gradients[0].max=cs->clusters->h; - ds->gradients[0].hue=cs->clusters->h; - // Et hop : le 1er ensemble de d‚grad‚s est initialis‚ - ds->nb=1; -} - -T_Gradient_set * GS_New(T_Cluster_set * cs) -{ - T_Gradient_set * n; - - n=(T_Gradient_set *)malloc(sizeof(T_Gradient_set)); - if (n!=NULL) - { - // On recopie les paramŠtres demand‚s - n->nb_max=cs->nb_max; - - // On tente d'allouer la table - n->gradients=(T_Gradient *)malloc((n->nb_max)*sizeof(T_Gradient)); - if (n->gradients!=0) - // C'est bon! On initialise - GS_Init(n,cs); - else - { - // Table impossible … allouer - free(n); - n=0; - } - } - - return n; -} - -void GS_Delete(T_Gradient_set * ds) -{ - free(ds->gradients); - free(ds); -} - -void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) -{ - int id; // Les indexs de parcours des ensembles - int best_gradient; // Meilleur d‚grad‚ - int best_diff; // Meilleure diff‚rence de chrominance - int diff; // difference de chrominance courante - T_Cluster * current = cs->clusters; - - // Pour chacun des clusters … traiter - do - { - // On recherche le d‚grad‚ le plus proche de la chrominance du cluster - best_gradient=-1; - best_diff=99999999; - for (id=0;idnb;id++) - { - diff=abs(current->h - ds->gradients[id].hue); - if ((best_diff>diff) && (diff<16)) - { - best_gradient=id; - best_diff=diff; - } - } - - // Si on a trouv‚ un d‚grad‚ dans lequel inclure le cluster - if (best_gradient!=-1) - { - // On met … jour le d‚grad‚ - if (current->h < ds->gradients[best_gradient].min) - ds->gradients[best_gradient].min=current->h; - if (current->h > ds->gradients[best_gradient].max) - ds->gradients[best_gradient].max=current->h; - ds->gradients[best_gradient].hue=((ds->gradients[best_gradient].hue* - ds->gradients[best_gradient].nb_colors) - +current->h) - /(ds->gradients[best_gradient].nb_colors+1); - ds->gradients[best_gradient].nb_colors++; - } - else - { - // On cr‚e un nouveau d‚grad‚ - best_gradient=ds->nb; - ds->gradients[best_gradient].nb_colors=1; - ds->gradients[best_gradient].min=current->h; - ds->gradients[best_gradient].max=current->h; - ds->gradients[best_gradient].hue=current->h; - ds->nb++; - } - current->h=best_gradient; - } while((current = current->next)); - - // On redistribue les valeurs dans les clusters - current = cs -> clusters; - do - current->h=ds->gradients[current->h].hue; - while((current = current ->next)); -} - - - - -T_Conversion_table * Optimize_palette(T_Bitmap24B image,int size,T_Components * palette,int r,int g,int b) -{ - T_Occurrence_table * to; - T_Conversion_table * tc; - T_Cluster_set * cs; - T_Gradient_set * ds; - - // Création des éléments nécessaires au calcul de palette optimisée: - to=0; tc=0; cs=0; ds=0; - - to=OT_new(r,g,b); - if (to!=0) - { - tc=CT_new(r,g,b); - if (tc!=0) - { - - // Première étape : on compte les pixels de chaque couleur pour pouvoir trier là dessus - OT_count_occurrences(to,image,size); - - cs=CS_New(256,to); - if (cs!=0) - { - // C'est bon, on a pu tout allouer - - // On génère les clusters (avec l'algo du median cut) - CS_Generate(cs,to); - - // On calcule la teinte de chaque pixel (Luminance et chrominance) - CS_Compute_colors(cs,to); - - ds=GS_New(cs); - if (ds!=0) - { - GS_Generate(ds,cs); - GS_Delete(ds); - } - - // Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre sympa : par couleur, et par luminosité pour chaque couleur - CS_Sort_by_luminance(cs); - CS_Sort_by_chrominance(cs); - - // Enfin on génère la palette et la table de correspondance entre chaque couleur 24b et sa couleur palette associée. - CS_Generate_color_table_and_palette(cs,tc,palette); - - CS_Delete(cs); - OT_delete(to); - return tc; - } - CT_delete(tc); - } - OT_delete(to); - } - // Si on arrive ici c'est que l'allocation n'a pas réussi, - // l'appelant devra recommencer avec une précision plus faible (3 derniers paramètres) - return 0; -} - -int Modified_value(int value,int modif) -{ - value+=modif; - if (value<0) - { - value=0; - } - else if (value>255) - { - value=255; - } - return value; -} - -void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) -// Cette fonction dégrade au fur et à mesure le bitmap source, donc soit on ne -// s'en ressert pas, soit on passe à la fonction une copie de travail du -// bitmap original. -{ - T_Bitmap24B current; - T_Bitmap24B c_plus1; - T_Bitmap24B u_minus1; - T_Bitmap24B next; - T_Bitmap24B u_plus1; - T_Bitmap256 d; - int x_pos,y_pos; - int red,green,blue; - float e_red,e_green,e_blue; - - // On initialise les variables de parcours: - current =source; // Le pixel dont on s'occupe - next =current+width; // Le pixel en dessous - c_plus1 =current+1; // Le pixel à droite - u_minus1=next-1; // Le pixel en bas à gauche - u_plus1 =next+1; // Le pixel en bas à droite - d =dest; - - // On parcours chaque pixel: - for (y_pos=0;y_posR; - green =current->G; - blue =current->B; - // Cherche la couleur correspondant dans la palette et la range dans l'image de destination - *d=CT_get(tc,red,green,blue); - - // Puis on calcule pour chaque composante l'erreur dûe à l'approximation - red-=palette[*d].R; - green -=palette[*d].G; - blue -=palette[*d].B; - - // Et dans chaque pixel voisin on propage l'erreur - // A droite: - e_red=(red*7)/16.0; - e_green =(green *7)/16.0; - e_blue =(blue *7)/16.0; - if (x_pos+1R=Modified_value(c_plus1->R,e_red); - c_plus1->G=Modified_value(c_plus1->G,e_green ); - c_plus1->B=Modified_value(c_plus1->B,e_blue ); - } - // En bas à gauche: - if (y_pos+10) - { - u_minus1->R=Modified_value(u_minus1->R,e_red); - u_minus1->G=Modified_value(u_minus1->G,e_green ); - u_minus1->B=Modified_value(u_minus1->B,e_blue ); - } - // En bas: - e_red=(red*5/16.0); - e_green =(green*5 /16.0); - e_blue =(blue*5 /16.0); - next->R=Modified_value(next->R,e_red); - next->G=Modified_value(next->G,e_green ); - next->B=Modified_value(next->B,e_blue ); - // En bas à droite: - if (x_pos+1R=Modified_value(u_plus1->R,e_red); - u_plus1->G=Modified_value(u_plus1->G,e_green ); - u_plus1->B=Modified_value(u_plus1->B,e_blue ); - } - } - - // On passe au pixel suivant : - current++; - c_plus1++; - u_minus1++; - next++; - u_plus1++; - d++; - } - } - -} - - - -static const byte precision_24b[]= -{ - 8,8,8, - 6,6,6, - 6,6,5, - 5,6,5, - 5,5,5, - 5,5,4, - 4,5,4, - 4,4,4, - 4,4,3, - 3,4,3, - 3,3,3, - 3,3,2}; - - -// Convertie avec le plus de précision possible une image 24b en 256c -// Renvoie s'il y a eu une erreur ou pas.. - -// Cette fonction utilise l'algorithme "median cut" (Optimize_palette) pour trouver la palette, et diffuse les erreurs avec floyd-steinberg. - -int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) -{ - T_Conversion_table * table; // table de conversion - int ip; // index de précision pour la conversion - - // On essaye d'obtenir une table de conversion qui loge en mémoire, avec la - // meilleure précision possible - for (ip=0;ip<(10*3);ip+=3) - { - table=Optimize_palette(source,width*height,palette,precision_24b[ip+0], - precision_24b[ip+1],precision_24b[ip+2]); - if (table!=0) - break; - } - - if (table!=0) - { - Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); - CT_delete(table); - return 0; - } - else - return 1; -} - - - +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +#include + +#include "op_c.h" +#include "errors.h" + +void RGB_to_HSL(int r,int g,int b,byte * hr,byte * sr,byte* lr) +{ + double rd,gd,bd,h,s,l,max,min; + + // convert RGB to HSV + rd = r / 255.0; // rd,gd,bd range 0-1 instead of 0-255 + gd = g / 255.0; + bd = b / 255.0; + + // compute L +// l=(rd*0.30)+(gd*0.59)+(bd*0.11); + + // compute maximum of rd,gd,bd + if (rd>=gd) + { + if (rd>=bd) + max = rd; + else + max = bd; + } + else + { + if (gd>=bd) + max = gd; + else + max = bd; + } + + // compute minimum of rd,gd,bd + if (rd<=gd) + { + if (rd<=bd) + min = rd; + else + min = bd; + } + else + { + if (gd<=bd) + min = gd; + else + min = bd; + } + + l = (max + min) / 2.0; + + if(max==min) + s = h = 0; + else + { + if (l<=0.5) + s = (max - min) / (max + min); + else + s = (max - min) / (2 - (max + min)); + + if (max == rd) + h = 42.5 * (gd-bd)/(max-min); + else if (max == gd) + h = 42.5 * (bd-rd)/(max-min)+85; + else + h = 42.5 * (rd-gd)/(max-min)+170; + if (h<0) h+=255; + } + + *hr = h; + *lr = (l*255.0); + *sr = (s*255.0); +} + +void HSL_to_RGB(byte h,byte s,byte l, byte* r, byte* g, byte* b) +{ + float rf =0 ,gf = 0,bf = 0; + float hf,lf,sf; + float p,q; + + if(s==0) + { + *r=*g=*b=l; + return; + } + + hf = h / 255.0; + lf = l / 255.0; + sf = s / 255.0; + + if (lf<=0.5) + q = lf*(1+sf); + else + q = lf+sf-lf*sf; + p = 2*lf-q; + + rf = hf + (1 / 3.0); + gf = hf; + bf = hf - (1 / 3.0); + + if (rf < 0) rf+=1; + if (rf > 1) rf-=1; + if (gf < 0) gf+=1; + if (gf > 1) gf-=1; + if (bf < 0) bf+=1; + if (bf > 1) bf-=1; + + if (rf < 1/6.0) + rf = p + ((q-p)*6*rf); + else if(rf < 0.5) + rf = q; + else if(rf < 2/3.0) + rf = p + ((q-p)*6*(2/3.0-rf)); + else + rf = p; + + if (gf < 1/6.0) + gf = p + ((q-p)*6*gf); + else if(gf < 0.5) + gf = q; + else if(gf < 2/3.0) + gf = p + ((q-p)*6*(2/3.0-gf)); + else + gf = p; + + if (bf < 1/6.0) + bf = p + ((q-p)*6*bf); + else if(bf < 0.5) + bf = q; + else if(bf < 2/3.0) + bf = p + ((q-p)*6*(2/3.0-bf)); + else + bf = p; + + *r = rf * (255); + *g = gf * (255); + *b = bf * (255); +} + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////// Méthodes de gestion des tables de conversion // +///////////////////////////////////////////////////////////////////////////// + +T_Conversion_table * CT_new(int nbb_r,int nbb_g,int nbb_b) +{ + T_Conversion_table * n; + int size; + + n=(T_Conversion_table *)malloc(sizeof(T_Conversion_table)); + if (n!=NULL) + { + // On recopie les paramŠtres demand‚s + n->nbb_r=nbb_r; + n->nbb_g=nbb_g; + n->nbb_b=nbb_b; + + // On calcule les autres + n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; + n->dec_g=nbb_b; + n->dec_b=0; + n->red_r=8-nbb_r; + n->red_g=8-nbb_g; + n->red_b=8-nbb_b; + + // On tente d'allouer la table + size=(n->rng_r)*(n->rng_g)*(n->rng_b); + n->table=(byte *)malloc(size); + if (n->table!=NULL) + // C'est bon! + memset(n->table,0,size); // Inutile, mais plus propre + else + { + // Table impossible … allouer + free(n); + n=NULL; + } + } + + return n; +} + +void CT_delete(T_Conversion_table * t) +{ + free(t->table); + free(t); +} + +byte CT_get(T_Conversion_table * t,int r,int g,int b) +{ + int index; + + // On réduit le nombre de bits par couleur + r=(r>>t->red_r); + g=(g>>t->red_g); + b=(b>>t->red_b); + + // On recherche la couleur la plus proche dans la table de conversion + index=(r<dec_r) | (g<dec_g) | (b<dec_b); + + return t->table[index]; +} + +void CT_set(T_Conversion_table * t,int r,int g,int b,byte i) +{ + int index; + + index=(r<dec_r) | (g<dec_g) | (b<dec_b); + t->table[index]=i; +} + + + +///////////////////////////////////////////////////////////////////////////// +/////////////////////////////// M‚thodes de gestion des tables d'occurence // +///////////////////////////////////////////////////////////////////////////// + +void OT_init(T_Occurrence_table * t) +{ + int size; + + size=(t->rng_r)*(t->rng_g)*(t->rng_b)*sizeof(int); + memset(t->table,0,size); // On initialise … 0 +} + +T_Occurrence_table * OT_new(int nbb_r,int nbb_g,int nbb_b) +{ + T_Occurrence_table * n; + int size; + + n=(T_Occurrence_table *)malloc(sizeof(T_Occurrence_table)); + if (n!=0) + { + // On recopie les paramŠtres demand‚s + n->nbb_r=nbb_r; + n->nbb_g=nbb_g; + n->nbb_b=nbb_b; + + // On calcule les autres + n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; + n->dec_g=nbb_b; + n->dec_b=0; + n->red_r=8-nbb_r; + n->red_g=8-nbb_g; + n->red_b=8-nbb_b; + + // On tente d'allouer la table + size=(n->rng_r)*(n->rng_g)*(n->rng_b)*sizeof(int); + n->table=(int *)malloc(size); + if (n->table!=0) + // C'est bon! On initialise … 0 + OT_init(n); + else + { + // Table impossible … allouer + free(n); + n=0; + } + } + + return n; +} + +void OT_delete(T_Occurrence_table * t) +{ + free(t->table); + free(t); +} + +int OT_get(T_Occurrence_table * t,int r,int g,int b) +{ + int index; + + index=(r<dec_r) | (g<dec_g) | (b<dec_b); + return t->table[index]; +} + +void OT_inc(T_Occurrence_table * t,int r,int g,int b) +{ + int index; + + r=(r>>t->red_r); + g=(g>>t->red_g); + b=(b>>t->red_b); + index=(r<dec_r) | (g<dec_g) | (b<dec_b); + t->table[index]++; +} + +void OT_count_occurrences(T_Occurrence_table * t,T_Bitmap24B image,int size) +{ + T_Bitmap24B ptr; + int index; + + for (index=size,ptr=image;index>0;index--,ptr++) + OT_inc(t,ptr->R,ptr->G,ptr->B); +} + +int OT_count_colors(T_Occurrence_table * t) +{ + int val; // Valeur de retour + int nb; // Nombre de couleurs … tester + int i; // Compteur de couleurs test‚es + + val=0; + nb=(t->rng_r)*(t->rng_g)*(t->rng_b); + for (i=0;itable[i]>0) + val++; + + return val; +} + + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// M‚thodes de gestion des clusters // +///////////////////////////////////////////////////////////////////////////// + +void Cluster_analyser(T_Cluster * c,T_Occurrence_table * to) +{ + int rmin,rmax,vmin,vmax,bmin,bmax; + int r,g,b; + + // On cherche les mins et les maxs de chaque composante sur la couverture + + // int nbocc; + + // On prédécale tout pour éviter de faire trop de bazar en se forçant à utiliser OT_get, plus rapide + rmin=c->rmax <<16; rmax=c->rmin << 16; + vmin=c->vmax << 8; vmax=c->vmin << 8; + bmin=c->bmax; bmax=c->bmin; + c->occurences=0; + /* + for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) + for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + for (b=c->bmin;b<=c->bmax;b++) + { + nbocc=to->table[r + g + b]; // OT_get + if (nbocc) + { + if (rrmax) rmax=r; + if (gvmax) vmax=g; + if (bbmax) bmax=b; + c->occurences+=nbocc; + } + } + */ + + // On recherche le minimum et le maximum en parcourant le cluster selon chaque composante, + // ça évite des accès mémoires inutiles, de plus chaque boucle est plus petite que la + // précédente puisqu'on connait une borne supplémentaire + + for(r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) + for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + for(b=c->bmin;b<=c->bmax;b++) + { + if(to->table[r + g + b]) // OT_get + { + rmin=r; + goto RMAX; + } + } +RMAX: + for(r=c->rmax<<16;r>=rmin;r-=1<<16) + for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + for(b=c->bmin;b<=c->bmax;b++) + { + if(to->table[r + g + b]) // OT_get + { + rmax=r; + goto VMIN; + } + } +VMIN: + for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + for(r=rmin;r<=rmax;r+=1<<16) + for(b=c->bmin;b<=c->bmax;b++) + { + if(to->table[r + g + b]) // OT_get + { + vmin=g; + goto VMAX; + } + } +VMAX: + for(g=c->vmax<<8;g>=vmin;g-=1<<8) + for(r=rmin;r<=rmax;r+=1<<16) + for(b=c->bmin;b<=c->bmax;b++) + { + if(to->table[r + g + b]) // OT_get + { + vmax=g; + goto BMIN; + } + } +BMIN: + for(b=c->bmin;b<=c->bmax;b++) + for(r=rmin;r<=rmax;r+=1<<16) + for(g=vmin;g<=vmax;g+=1<<8) + { + if(to->table[r + g + b]) // OT_get + { + bmin=b; + goto BMAX; + } + } +BMAX: + for(b=c->bmax;b>=bmin;b--) + for(r=rmin;r<=rmax;r+=1<<16) + for(g=vmin;g<=vmax;g+=1<<8) + { + if(to->table[r + g + b]) // OT_get + { + bmax=b; + goto ENDCRUSH; + } + } +ENDCRUSH: + // Il faut quand même parcourir la partie utile du cluster, pour savoir combien il y a d'occurences + for(r=rmin;r<=rmax;r+=1<<16) + for(g=vmin;g<=vmax;g+=1<<8) + for(b=bmin;b<=bmax;b++) + { + c->occurences+=to->table[r + g + b]; // OT_get + } + + c->rmin=rmin>>16; c->rmax=rmax>>16; + c->vmin=vmin>>8; c->vmax=vmax>>8; + c->bmin=bmin; c->bmax=bmax; + + // On regarde la composante qui a la variation la plus grande + r=(c->rmax-c->rmin)*299; + g=(c->vmax-c->vmin)*587; + b=(c->bmax-c->bmin)*114; + + if (g>=r) + { + // G>=R + if (g>=b) + { + // G>=R et G>=B + c->plus_large=1; + } + else + { + // G>=R et Gplus_large=2; + } + } + else + { + // R>G + if (r>=b) + { + // R>G et R>=B + c->plus_large=0; + } + else + { + // R>G et Rplus_large=2; + } + } +} + +void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurrence_table * to) +{ + int limit; + int cumul; + int r,g,b; + + limit=(c->occurences)/2; + cumul=0; + if (hue==0) + { + for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) + { + for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + { + for (b=c->bmin;b<=c->bmax;b++) + { + cumul+=to->table[r + g + b]; + if (cumul>=limit) + break; + } + if (cumul>=limit) + break; + } + if (cumul>=limit) + break; + } + + r>>=16; + g>>=8; + + if (r==c->rmin) + r++; + // R est la valeur de d‚but du 2nd cluster + + c1->Rmin=c->Rmin; c1->Rmax=r-1; + c1->rmin=c->rmin; c1->rmax=r-1; + c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; + c1->vmin=c->vmin; c1->vmax=c->vmax; + c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; + c1->bmin=c->bmin; c1->bmax=c->bmax; + c2->Rmin=r; c2->Rmax=c->Rmax; + c2->rmin=r; c2->rmax=c->rmax; + c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; + c2->vmin=c->vmin; c2->vmax=c->vmax; + c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; + c2->bmin=c->bmin; c2->bmax=c->bmax; + } + else + if (hue==1) + { + + for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + { + for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) + { + for (b=c->bmin;b<=c->bmax;b++) + { + cumul+=to->table[r + g + b]; + if (cumul>=limit) + break; + } + if (cumul>=limit) + break; + } + if (cumul>=limit) + break; + } + + r>>=16; g>>=8; + + if (g==c->vmin) + g++; + // G est la valeur de d‚but du 2nd cluster + + c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; + c1->rmin=c->rmin; c1->rmax=c->rmax; + c1->Gmin=c->Gmin; c1->Vmax=g-1; + c1->vmin=c->vmin; c1->vmax=g-1; + c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; + c1->bmin=c->bmin; c1->bmax=c->bmax; + c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; + c2->rmin=c->rmin; c2->rmax=c->rmax; + c2->Gmin=g; c2->Vmax=c->Vmax; + c2->vmin=g; c2->vmax=c->vmax; + c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; + c2->bmin=c->bmin; c2->bmax=c->bmax; + } + else + { + + for (b=c->bmin;b<=c->bmax;b++) + { + for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + { + for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) + { + cumul+=to->table[r + g + b]; + if (cumul>=limit) + break; + } + if (cumul>=limit) + break; + } + if (cumul>=limit) + break; + } + + r>>=16; g>>=8; + + if (b==c->bmin) + b++; + // B est la valeur de d‚but du 2nd cluster + + c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; + c1->rmin=c->rmin; c1->rmax=c->rmax; + c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; + c1->vmin=c->vmin; c1->vmax=c->vmax; + c1->Bmin=c->Bmin; c1->Bmax=b-1; + c1->bmin=c->bmin; c1->bmax=b-1; + c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; + c2->rmin=c->rmin; c2->rmax=c->rmax; + c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; + c2->vmin=c->vmin; c2->vmax=c->vmax; + c2->Bmin=b; c2->Bmax=c->Bmax; + c2->bmin=b; c2->bmax=c->bmax; + } +} + +void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) +{ + int cumul_r,cumul_g,cumul_b; + int r,g,b; + int nbocc; + + byte s=0; + + cumul_r=cumul_g=cumul_b=0; + for (r=c->rmin;r<=c->rmax;r++) + for (g=c->vmin;g<=c->vmax;g++) + for (b=c->bmin;b<=c->bmax;b++) + { + nbocc=OT_get(to,r,g,b); + if (nbocc) + { + cumul_r+=r*nbocc; + cumul_g+=g*nbocc; + cumul_b+=b*nbocc; + } + } + + c->r=(cumul_r<red_r)/c->occurences; + c->g=(cumul_g<red_g)/c->occurences; + c->b=(cumul_b<red_b)/c->occurences; + RGB_to_HSL(c->r,c->g,c->b,&c->h,&s,&c->l); +} + + + +///////////////////////////////////////////////////////////////////////////// +//////////////////////////// M‚thodes de gestion des ensembles de clusters // +///////////////////////////////////////////////////////////////////////////// + +/// Setup the first cluster before we start the operations +void CS_Init(T_Cluster_set * cs,T_Occurrence_table * to) +{ + cs->clusters->Rmin = cs->clusters->rmin = 0; + cs->clusters->Gmin = cs->clusters->vmin = 0; + cs->clusters->Bmin = cs->clusters->bmin = 0; + cs->clusters->Rmax = cs->clusters->rmax = to->rng_r-1; + cs->clusters->Vmax = cs->clusters->vmax = to->rng_g-1; + cs->clusters->Bmax = cs->clusters->bmax = to->rng_b-1; + cs->clusters->next = NULL; + Cluster_analyser(cs->clusters,to); + cs->nb=1; +} + +/// Allocate a new cluster set +T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to) +{ + T_Cluster_set * n; + + n=(T_Cluster_set *)malloc(sizeof(T_Cluster_set)); + if (n != NULL) + { + // On recopie les paramŠtres demand‚s + n->nb_max=OT_count_colors(to); + + // On vient de compter le nombre de couleurs existantes, s'il est plus grand que 256 on limite à 256 + // (nombre de couleurs voulu au final) + if (n->nb_max>nbmax) + { + n->nb_max=nbmax; + } + + // On tente d'allouer le premier cluster + n->clusters=(T_Cluster *)malloc(sizeof(T_Cluster)); + if (n->clusters!=NULL) + // C'est bon! On initialise + CS_Init(n,to); + else + { + // Table impossible … allouer + free(n); + n=0; + } + } + + return n; +} + +/// Free a cluster set +void CS_Delete(T_Cluster_set * cs) +{ + T_Cluster* nxt; + while(cs->clusters != NULL) + { + nxt = cs->clusters->next; + free(cs->clusters); + cs->clusters = nxt; + } + free(cs); +} + +void CS_Get(T_Cluster_set * cs,T_Cluster * c) +{ + T_Cluster* current = cs->clusters; + T_Cluster* prev = NULL; + + // Search a cluster with at least 2 distinct colors so we can split it + do + { + if ( (current->rmin < current->rmax) || + (current->vmin < current->vmax) || + (current->bmin < current->bmax) ) + break; + + prev = current; + + } while((current = current -> next)); + + // copy it to c + *c = *current; + + // remove it from the list + cs->nb--; + + if(prev) + prev->next = current->next; + else + cs->clusters = current->next; + free(current); + current = NULL; +} + +void CS_Set(T_Cluster_set * cs,T_Cluster * c) +{ + T_Cluster* current = cs->clusters; + T_Cluster* prev = NULL; + + // Search the first cluster that is smaller than ours + if(current != NULL) // don't search if the list is empty + do + { + if (current->occurences < c->occurences) + break; + prev = current; + } while((current = current -> next)); + + // Now insert our cluster just before the one we found + c -> next = current; + + current = malloc(sizeof(T_Cluster)); + *current = *c ; + + if(prev) prev -> next = current; + else cs->clusters = current; + + cs -> nb++; +} + +// Détermination de la meilleure palette en utilisant l'algo Median Cut : +// 1) On considère l'espace (R,G,B) comme 1 boîte +// 2) On cherche les extrêmes de la boîte en (R,G,B) +// 3) On trie les pixels de l'image selon l'axe le plus long parmi (R,G,B) +// 4) On coupe la boîte en deux au milieu, et on compacte pour que chaque bord corresponde bien à un pixel extreme +// 5) On recommence à couper selon le plus grand axe toutes boîtes confondues +// 6) On s'arrête quand on a le nombre de couleurs voulu +void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to) +{ + T_Cluster current; + T_Cluster Nouveau1; + T_Cluster Nouveau2; + + // Tant qu'on a moins de 256 clusters + while (cs->nbnb_max) + { + // On récupère le plus grand cluster + CS_Get(cs,¤t); + + // On le coupe en deux + Cluster_split(¤t,&Nouveau1,&Nouveau2,current.plus_large,to); + + // On compacte ces deux nouveaux (il peut y avoir un espace entre l'endroit de la coupure et les premiers pixels du cluster) + Cluster_analyser(&Nouveau1,to); + Cluster_analyser(&Nouveau2,to); + + // On met ces deux nouveaux clusters dans le clusterSet... sauf s'ils sont vides + if(Nouveau1.occurences>0) + CS_Set(cs,&Nouveau1); + if(Nouveau2.occurences>0) + CS_Set(cs,&Nouveau2); + } +} + +void CS_Compute_colors(T_Cluster_set * cs,T_Occurrence_table * to) +{ + T_Cluster * c; + + for (c=cs->clusters;c!=NULL;c=c->next) + Cluster_compute_hue(c,to); +} + +void CS_Sort_by_chrominance(T_Cluster_set * cs) +{ + T_Cluster* nc; + T_Cluster* prev = NULL; + T_Cluster* place; + T_Cluster* newlist = NULL; + + while((nc = cs->clusters)) + { + // Remove the first cluster from the original list + nc = cs->clusters; + cs->clusters = cs->clusters->next; + + // Find his position in the new list + for(place = newlist;place != NULL; place = place->next) + { + if(place->h > nc->h) break; + prev = place; + } + + // Chain it there + nc->next = place; + if(prev) prev->next = nc; + else newlist = nc; + + } + + // Put the new list bavk in place + cs->clusters = newlist; +} + +void CS_Sort_by_luminance(T_Cluster_set * cs) +{ + T_Cluster* nc; + T_Cluster* prev = NULL; + T_Cluster* place; + T_Cluster* newlist = NULL; + + while((nc = cs->clusters)) + { + // Remove the first cluster from the original list + nc = cs->clusters; + cs->clusters = cs->clusters->next; + + // Find his position in the new list + for(place = newlist;place != NULL; place = place->next) + { + if(place->l > nc->l) break; + prev = place; + } + + // Chain it there + nc->next = place; + if(prev) prev->next = nc; + else newlist = nc; + + } + + // Put the new list bavk in place + cs->clusters = newlist; +} + +void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * tc,T_Components * palette) +{ + int index; + int r,g,b; + T_Cluster* current = cs->clusters; + + for (index=0;indexnb;index++) + { + palette[index].R=current->r; + palette[index].G=current->g; + palette[index].B=current->b; + + for (r=current->Rmin; r<=current->Rmax; r++) + for (g=current->Gmin;g<=current->Vmax;g++) + for (b=current->Bmin;b<=current->Bmax;b++) + CT_set(tc,r,g,b,index); + current = current->next; + } +} + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// Méthodes de gestion des dégradés // +///////////////////////////////////////////////////////////////////////////// + +void GS_Init(T_Gradient_set * ds,T_Cluster_set * cs) +{ + ds->gradients[0].nb_colors=1; + ds->gradients[0].min=cs->clusters->h; + ds->gradients[0].max=cs->clusters->h; + ds->gradients[0].hue=cs->clusters->h; + // Et hop : le 1er ensemble de d‚grad‚s est initialis‚ + ds->nb=1; +} + +T_Gradient_set * GS_New(T_Cluster_set * cs) +{ + T_Gradient_set * n; + + n=(T_Gradient_set *)malloc(sizeof(T_Gradient_set)); + if (n!=NULL) + { + // On recopie les paramŠtres demand‚s + n->nb_max=cs->nb_max; + + // On tente d'allouer la table + n->gradients=(T_Gradient *)malloc((n->nb_max)*sizeof(T_Gradient)); + if (n->gradients!=0) + // C'est bon! On initialise + GS_Init(n,cs); + else + { + // Table impossible … allouer + free(n); + n=0; + } + } + + return n; +} + +void GS_Delete(T_Gradient_set * ds) +{ + free(ds->gradients); + free(ds); +} + +void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) +{ + int id; // Les indexs de parcours des ensembles + int best_gradient; // Meilleur d‚grad‚ + int best_diff; // Meilleure diff‚rence de chrominance + int diff; // difference de chrominance courante + T_Cluster * current = cs->clusters; + + // Pour chacun des clusters … traiter + do + { + // On recherche le d‚grad‚ le plus proche de la chrominance du cluster + best_gradient=-1; + best_diff=99999999; + for (id=0;idnb;id++) + { + diff=abs(current->h - ds->gradients[id].hue); + if ((best_diff>diff) && (diff<16)) + { + best_gradient=id; + best_diff=diff; + } + } + + // Si on a trouv‚ un d‚grad‚ dans lequel inclure le cluster + if (best_gradient!=-1) + { + // On met … jour le d‚grad‚ + if (current->h < ds->gradients[best_gradient].min) + ds->gradients[best_gradient].min=current->h; + if (current->h > ds->gradients[best_gradient].max) + ds->gradients[best_gradient].max=current->h; + ds->gradients[best_gradient].hue=((ds->gradients[best_gradient].hue* + ds->gradients[best_gradient].nb_colors) + +current->h) + /(ds->gradients[best_gradient].nb_colors+1); + ds->gradients[best_gradient].nb_colors++; + } + else + { + // On cr‚e un nouveau d‚grad‚ + best_gradient=ds->nb; + ds->gradients[best_gradient].nb_colors=1; + ds->gradients[best_gradient].min=current->h; + ds->gradients[best_gradient].max=current->h; + ds->gradients[best_gradient].hue=current->h; + ds->nb++; + } + current->h=best_gradient; + } while((current = current->next)); + + // On redistribue les valeurs dans les clusters + current = cs -> clusters; + do + current->h=ds->gradients[current->h].hue; + while((current = current ->next)); +} + + + + +T_Conversion_table * Optimize_palette(T_Bitmap24B image,int size,T_Components * palette,int r,int g,int b) +{ + T_Occurrence_table * to; + T_Conversion_table * tc; + T_Cluster_set * cs; + T_Gradient_set * ds; + + // Création des éléments nécessaires au calcul de palette optimisée: + to=0; tc=0; cs=0; ds=0; + + to=OT_new(r,g,b); + if (to!=0) + { + tc=CT_new(r,g,b); + if (tc!=0) + { + + // Première étape : on compte les pixels de chaque couleur pour pouvoir trier là dessus + OT_count_occurrences(to,image,size); + + cs=CS_New(256,to); + if (cs!=0) + { + // C'est bon, on a pu tout allouer + + // On génère les clusters (avec l'algo du median cut) + CS_Generate(cs,to); + + // On calcule la teinte de chaque pixel (Luminance et chrominance) + CS_Compute_colors(cs,to); + + ds=GS_New(cs); + if (ds!=0) + { + GS_Generate(ds,cs); + GS_Delete(ds); + } + + // Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre sympa : par couleur, et par luminosité pour chaque couleur + CS_Sort_by_luminance(cs); + CS_Sort_by_chrominance(cs); + + // Enfin on génère la palette et la table de correspondance entre chaque couleur 24b et sa couleur palette associée. + CS_Generate_color_table_and_palette(cs,tc,palette); + + CS_Delete(cs); + OT_delete(to); + return tc; + } + CT_delete(tc); + } + OT_delete(to); + } + // Si on arrive ici c'est que l'allocation n'a pas réussi, + // l'appelant devra recommencer avec une précision plus faible (3 derniers paramètres) + return 0; +} + +int Modified_value(int value,int modif) +{ + value+=modif; + if (value<0) + { + value=0; + } + else if (value>255) + { + value=255; + } + return value; +} + +void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) +// Cette fonction dégrade au fur et à mesure le bitmap source, donc soit on ne +// s'en ressert pas, soit on passe à la fonction une copie de travail du +// bitmap original. +{ + T_Bitmap24B current; + T_Bitmap24B c_plus1; + T_Bitmap24B u_minus1; + T_Bitmap24B next; + T_Bitmap24B u_plus1; + T_Bitmap256 d; + int x_pos,y_pos; + int red,green,blue; + float e_red,e_green,e_blue; + + // On initialise les variables de parcours: + current =source; // Le pixel dont on s'occupe + next =current+width; // Le pixel en dessous + c_plus1 =current+1; // Le pixel à droite + u_minus1=next-1; // Le pixel en bas à gauche + u_plus1 =next+1; // Le pixel en bas à droite + d =dest; + + // On parcours chaque pixel: + for (y_pos=0;y_posR; + green =current->G; + blue =current->B; + // Cherche la couleur correspondant dans la palette et la range dans l'image de destination + *d=CT_get(tc,red,green,blue); + + // Puis on calcule pour chaque composante l'erreur dûe à l'approximation + red-=palette[*d].R; + green -=palette[*d].G; + blue -=palette[*d].B; + + // Et dans chaque pixel voisin on propage l'erreur + // A droite: + e_red=(red*7)/16.0; + e_green =(green *7)/16.0; + e_blue =(blue *7)/16.0; + if (x_pos+1R=Modified_value(c_plus1->R,e_red); + c_plus1->G=Modified_value(c_plus1->G,e_green ); + c_plus1->B=Modified_value(c_plus1->B,e_blue ); + } + // En bas à gauche: + if (y_pos+10) + { + u_minus1->R=Modified_value(u_minus1->R,e_red); + u_minus1->G=Modified_value(u_minus1->G,e_green ); + u_minus1->B=Modified_value(u_minus1->B,e_blue ); + } + // En bas: + e_red=(red*5/16.0); + e_green =(green*5 /16.0); + e_blue =(blue*5 /16.0); + next->R=Modified_value(next->R,e_red); + next->G=Modified_value(next->G,e_green ); + next->B=Modified_value(next->B,e_blue ); + // En bas à droite: + if (x_pos+1R=Modified_value(u_plus1->R,e_red); + u_plus1->G=Modified_value(u_plus1->G,e_green ); + u_plus1->B=Modified_value(u_plus1->B,e_blue ); + } + } + + // On passe au pixel suivant : + current++; + c_plus1++; + u_minus1++; + next++; + u_plus1++; + d++; + } + } + +} + + + +static const byte precision_24b[]= +{ + 8,8,8, + 6,6,6, + 6,6,5, + 5,6,5, + 5,5,5, + 5,5,4, + 4,5,4, + 4,4,4, + 4,4,3, + 3,4,3, + 3,3,3, + 3,3,2}; + + +// Convertie avec le plus de précision possible une image 24b en 256c +// Renvoie s'il y a eu une erreur ou pas.. + +// Cette fonction utilise l'algorithme "median cut" (Optimize_palette) pour trouver la palette, et diffuse les erreurs avec floyd-steinberg. + +int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) +{ + T_Conversion_table * table; // table de conversion + int ip; // index de précision pour la conversion + + // On essaye d'obtenir une table de conversion qui loge en mémoire, avec la + // meilleure précision possible + for (ip=0;ip<(10*3);ip+=3) + { + table=Optimize_palette(source,width*height,palette,precision_24b[ip+0], + precision_24b[ip+1],precision_24b[ip+2]); + if (table!=0) + break; + } + + if (table!=0) + { + Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); + CT_delete(table); + return 0; + } + else + return 1; +} + + + diff --git a/op_c.h b/op_c.h index 4fd6739f..a1339aea 100644 --- a/op_c.h +++ b/op_c.h @@ -1,215 +1,215 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file op_c.h -/// Color reduction and color conversion (24b->8b, RGB<->HSL). -/// This is called op_c because half of the process was originally -/// coded in op_asm, in assembler. -////////////////////////////////////////////////////////////////////////////// - -#ifndef _OP_C_H_ -#define _OP_C_H_ - -#include "struct.h" - -//////////////////////////////////////////////// Définition des types de base - -typedef T_Components * T_Bitmap24B; -typedef byte * T_Bitmap256; - - - -//////////////////////////////////////// Définition d'une table de conversion - -typedef struct -{ - int nbb_r; // Nb de bits de précision sur les rouges - int nbb_g; // Nb de bits de précision sur les verts - int nbb_b; // Nb de bits de précision sur les bleu - - int rng_r; // Nb de valeurs sur les rouges (= 1< +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file op_c.h +/// Color reduction and color conversion (24b->8b, RGB<->HSL). +/// This is called op_c because half of the process was originally +/// coded in op_asm, in assembler. +////////////////////////////////////////////////////////////////////////////// + +#ifndef _OP_C_H_ +#define _OP_C_H_ + +#include "struct.h" + +//////////////////////////////////////////////// Définition des types de base + +typedef T_Components * T_Bitmap24B; +typedef byte * T_Bitmap256; + + + +//////////////////////////////////////// Définition d'une table de conversion + +typedef struct +{ + int nbb_r; // Nb de bits de précision sur les rouges + int nbb_g; // Nb de bits de précision sur les verts + int nbb_b; // Nb de bits de précision sur les bleu + + int rng_r; // Nb de valeurs sur les rouges (= 1< -*/ -#include -#include -#include - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "engine.h" -#include "graph.h" -#include "operatio.h" -#include "buttons.h" -#include "pages.h" -#include "errors.h" -#include "sdlscreen.h" -#include "brush.h" -#include "windows.h" - -#if defined(__GP2X__) - #define M_PI 3.14159265358979323846 -#endif - -/// Time (in SDL ticks) when the next airbrush drawing should be done. Also used -/// for discontinuous freehand drawing. -Uint32 Airbrush_next_time; - -void Start_operation_stack(word new_operation) -{ - Brush_rotation_center_is_defined=0; - - // 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_ROTATE_BRUSH: - Operation_before_interrupt=Current_operation; - // On passe à l'operation demandée - Current_operation=new_operation; - break; - default : - // On passe à l'operation demandée - Current_operation=new_operation; - Operation_before_interrupt=Current_operation; - } - - // On spécifie si l'opération autorise le changement de couleur au clavier - switch(new_operation) - { - case OPERATION_CONTINUOUS_DRAW: - case OPERATION_DISCONTINUOUS_DRAW: - case OPERATION_AIRBRUSH: - case OPERATION_CENTERED_LINES: - Allow_color_change_during_operation=1; - break; - default : - Allow_color_change_during_operation=0; - } - - // Et on passe au curseur qui va avec - Cursor_shape=CURSOR_FOR_OPERATION[new_operation]; - Operation_stack_size=0; -} - - -void Init_start_operation(void) -{ - Operation_in_magnifier=(Mouse_X>=Main_X_zoom); - Smear_start=1; -} - - -void Operation_push(short value) -{ - Operation_stack[++Operation_stack_size]=value; -} - - -void Operation_pop(short * value) -{ - *value=Operation_stack[Operation_stack_size--]; -} - - -byte Paintbrush_shape_before_operation; -byte Paintbrush_hidden_before_scroll; - - - -short Distance(short x1, short y1, short x2, short y2) -{ - short x2_moins_x1=x2-x1; - short y2_minus_y1=y2-y1; - - return Round( sqrt( (x2_moins_x1*x2_moins_x1) + (y2_minus_y1*y2_minus_y1) ) ); -} - - -void Display_coords_rel_or_abs(short start_x, short start_y) -{ - char str[6]; - - if (Config.Coords_rel) - { - if (Menu_is_visible) - { - if (Paintbrush_X>start_x) - { - Num2str(Paintbrush_X-start_x,str,5); - str[0]='+'; - } - else if (Paintbrush_Xstart_y) - { - Num2str(Paintbrush_Y-start_y,str,5); - str[0]='+'; - } - else if (Paintbrush_YAirbrush_next_time) - { - Airbrush_next_time+=Airbrush_delay*10; - Hide_cursor(); - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); - Display_cursor(); - } - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -// ---------- - -void Freehand_mode2_2_0(void) -// Opération : OPERATION_DISCONTINUOUS_DRAW -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Print_coordinates(); - Airbrush_next_time = SDL_GetTicks() + Airbrush_delay*10; - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); -} - - -void Freehand_mode2_2_2(void) -// Opération : OPERATION_DISCONTINUOUS_DRAW -// Click Souris: 2 -// Taille_Pile : 2 -// -// Souris effacée: Non -{ - short start_x; - short start_y; - - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ( (start_x!=Paintbrush_X) || (start_y!=Paintbrush_Y) ) - { - Print_coordinates(); - if (SDL_GetTicks()>Airbrush_next_time) - { - Airbrush_next_time+=Airbrush_delay*10; - Hide_cursor(); - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); - Display_cursor(); - } - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -////////////////////////////////////////////////////// OPERATION_POINT_DRAW - -void Freehand_mode3_1_0(void) -// Opération : OPERATION_POINT_DRAW -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_left; - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); - Operation_push(0); // On change simplement l'état de la pile... -} - - -void Freehand_Mode3_2_0(void) -// Opération : OPERATION_POINT_DRAW -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); - Operation_push(0); // On change simplement l'état de la pile... -} - - -void Freehand_mode3_0_1(void) -// Opération : OPERATION_POINT_DRAW -// Click Souris: 0 -// Taille_Pile : 1 -// -// Souris effacée: Non -{ - Operation_stack_size--; -} - - -///////////////////////////////////////////////////////////// OPERATION_LINE - -void Line_12_0(void) -// Opération : OPERATION_LINE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui - -// Début du tracé d'une ligne (premier clic) -{ - Init_start_operation(); - Backup(); - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - if (Mouse_K==LEFT_SIDE) - { - Shade_table=Shade_table_left; - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - Operation_push(Fore_color); - } - else - { - Shade_table=Shade_table_right; - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - Operation_push(Back_color); - } - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Line_12_5(void) -// Opération : OPERATION_LINE -// Click Souris: 1 -// Taille_Pile : 5 -// -// Souris effacée: Non - -// Poursuite du tracé d'une ligne (déplacement de la souris en gardant le -// curseur appuyé) -{ - short start_x; - short start_y; - short end_x; - short end_y; - - short cursor_x; - short cursor_y; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - - cursor_x = Paintbrush_X; - cursor_y = Paintbrush_Y; - - // 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)) - { - Hide_cursor(); - - Display_coords_rel_or_abs(start_x,start_y); - - Hide_line_preview(start_x,start_y,end_x,end_y); - if (Mouse_K==LEFT_SIDE) - { - Pixel_figure_preview (start_x,start_y,Fore_color); - Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Fore_color); - } - else - { - Pixel_figure_preview (start_x,start_y,Back_color); - Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Back_color); - } - - Operation_push(start_x); - Operation_push(start_y); - Operation_push(cursor_x); - Operation_push(cursor_y); - - Display_cursor(); - } - else - { - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - } -} - - -void Line_0_5(void) -// Opération : OPERATION_LINE -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Oui - -// End du tracé d'une ligne (relachage du bouton) -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - Display_paintbrush (start_x,start_y,color,0); - Draw_line_permanet(start_x,start_y,end_x,end_y,color); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -/////////////////////////////////////////////////////////// OPERATION_K_LIGNE - - -void K_line_12_0(void) -// Opération : OPERATION_K_LIGNE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - // On place temporairement le début de la ligne qui ne s'afficherait pas sinon - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Mouse_K | 0x80); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 6 : phase d'appui, non interruptible -} - - -void K_line_12_6(void) -// Opération : OPERATION_K_LIGNE -// Click Souris: 1 ou 2 | 0 -// Taille_Pile : 6 | 7 -// -// Souris effacée: Non -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - - Operation_pop(&end_y); - Operation_pop(&end_x); - - if ((Paintbrush_X!=end_x) || (Paintbrush_Y!=end_y)) - { - Hide_cursor(); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - - Display_coords_rel_or_abs(start_x,start_y); - - Hide_line_preview(start_x,start_y,end_x,end_y); - Pixel_figure_preview (start_x,start_y,color); - Draw_line_preview (start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Operation_push(color); - Operation_push(start_x); - Operation_push(start_y); - Display_cursor(); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void K_line_0_6(void) -// Opération : OPERATION_K_LIGNE -// Click Souris: 0 -// Taille_Pile : 6 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - /* Doesn't work if fast moving - Pixel_figure_preview_xor (start_x,start_y, 0); - Draw_line_preview_xor (start_x,start_y,end_x,end_y,0); - */ - Paintbrush_shape=Paintbrush_shape_before_operation; - if (direction & 0x80) - { - Display_paintbrush(start_x,start_y,color,0); - direction=(direction & 0x7F); - } - Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - Operation_push(direction); - Operation_push(direction); // Valeur bidon servant de nouvel état de pile - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 7 : phase de "repos", interruptible (comme Elliot Ness :)) -} - - -void K_line_12_7(void) -// Opération : OPERATION_K_LIGNE -// Click Souris: 1 ou 2 -// Taille_Pile : 7 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - Operation_pop(&direction); - - if (direction==Mouse_K) - { - Operation_push(direction); - Operation_push(color); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - // Taille de pile 6 : phase d'appui, non interruptible - } - else - { - // La série de ligne est terminée, il faut donc effacer la dernière - // preview de ligne - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - - Display_cursor(); - Wait_end_of_click(); - Hide_cursor(); - Paintbrush_shape=Paintbrush_shape_before_operation; - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - } -} - - -// ---------------------------------------------------------- OPERATION_MAGNIFY - - -void Magnifier_12_0(void) - -// Opération : 4 (item d'une Loupe) -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui - -{ - - // On passe en mode loupe - Main_magnifier_mode=1; - - // La fonction d'affichage dans la partie image est désormais un affichage - // spécial loupe. - Pixel_preview=Pixel_preview_magnifier; - - // On calcule l'origine de la loupe - Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); - Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); - - // Calcul du coin haut_gauche de la fenêtre devant être zoomée DANS L'ECRAN - if (Main_magnifier_offset_X+Main_magnifier_width>=Limit_right-Main_offset_X) - Main_magnifier_offset_X=Limit_right-Main_magnifier_width-Main_offset_X+1; - if (Main_magnifier_offset_Y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) - Main_magnifier_offset_Y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; - - // Calcul des coordonnées absolues de ce coin DANS L'IMAGE - Main_magnifier_offset_X+=Main_offset_X; - Main_magnifier_offset_Y+=Main_offset_Y; - - if (Main_magnifier_offset_X<0) - Main_magnifier_offset_X=0; - if (Main_magnifier_offset_Y<0) - Main_magnifier_offset_Y=0; - - // On calcule les bornes visibles dans l'écran - Position_screen_according_to_zoom(); - Compute_limits(); - Display_all_screen(); - - // Repositionner le curseur en fonction des coordonnées visibles - Compute_paintbrush_coordinates(); - - // On fait de notre mieux pour restaurer l'ancienne opération: - Start_operation_stack(Operation_before_interrupt); - Display_cursor(); - Wait_end_of_click(); -} - -/////////////////////////////////////////////////// OPERATION_RECTANGLE_????? - -void Rectangle_12_0(void) -// Opération : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - Init_start_operation(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("\035: 1 \022: 1",0); - // On laisse une trace du curseur à l'écran - Display_cursor(); - - if (Mouse_K==LEFT_SIDE) - { - Shade_table=Shade_table_left; - Operation_push(Fore_color); - } - else - { - Shade_table=Shade_table_right; - Operation_push(Back_color); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Rectangle_12_5(void) -// Opération : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 5 -// -// Souris effacée: Non -{ - short start_x; - short start_y; - short old_x; - short old_y; - char str[5]; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) - { - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Num2str(((start_xcenter_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x - :center_x-Paintbrush_X; - vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y - :center_y-Paintbrush_Y; - Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); - - Display_cursor(); - } - - Operation_push(color); - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Empty_ellipse_0_5(void) -// -// Opération : OPERATION_EMPTY_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Draw_empty_ellipse_permanent(center_x,center_y,horizontal_radius,vertical_radius,color); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -void Filled_ellipse_0_5(void) -// -// Opération : OPERATION_FILLED_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,color); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -////////////////////////////////////////////////////////////// OPERATION_FILL - - -void Fill_1_0(void) -// -// Opération : OPERATION_FILL -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - 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 - // droite de la loupe. - // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. - Shade_table=Shade_table_left; - Fill_general(Fore_color); - Display_cursor(); - Wait_end_of_click(); -} - - -void Fill_2_0(void) -// -// Opération : OPERATION_FILL -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - 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 - // droite de la loupe. - // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. - Shade_table=Shade_table_right; - Fill_general(Back_color); - Display_cursor(); - Wait_end_of_click(); -} - - -///////////////////////////////////////////////////////// OPERATION_REPLACE - - -void Replace_1_0(void) -// -// Opération : OPERATION_REPLACE -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - 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 - // droite de la loupe. - Backup(); -// Shade_table=Shade_table_left; - Replace(Fore_color); - Display_cursor(); - Wait_end_of_click(); -} - - -void Replace_2_0(void) -// -// Opération : OPERATION_REPLACE -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - 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 - // droite de la loupe. - Backup(); -// Shade_table=Shade_table_right; - Replace(Back_color); - Display_cursor(); - Wait_end_of_click(); -} - - -/////////////////////////////////////////////////////////// OPERATION_COLORPICK - - -void Colorpicker_12_0(void) -// -// Opération : OPERATION_COLORPICK -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - - if (Mouse_K==LEFT_SIDE) - { - Set_fore_color(Colorpicker_color); - } - else - { - Set_back_color(Colorpicker_color); - } - Operation_push(Mouse_K); -} - - -void Colorpicker_1_1(void) -// -// Opération : OPERATION_COLORPICK -// Click Souris: 1 -// Taille_Pile : 1 -// -// Souris effacée: Non -// -{ - char str[4]; - - if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) - && (Paintbrush_X=0) && (Paintbrush_Y>=0) - && (Paintbrush_X=Limit_left+3) - start_x=0; - else - start_x=3-(x_pos-Limit_left); - - if (y_pos>=Limit_top+3) - start_y=0; - else - start_y=3-(y_pos-Limit_top); - - if (x_pos<=Limit_visible_right-3) - end_x=6; - else - end_x=3+(Limit_visible_right-x_pos); - - if (y_pos<=Limit_visible_bottom-3) - end_y=6; - else - end_y=3+(Limit_visible_bottom-y_pos); - - if (start_x<=end_x && start_y<=end_y) - { - for (i=start_x; i<=end_x; i++) - { - temp=x_pos+i-3; - Pixel_preview(temp,y_pos,~Read_pixel(temp -Main_offset_X, - y_pos-Main_offset_Y)); - } - for (i=start_y; i<=end_y; i++) - { - temp=y_pos+i-3; - Pixel_preview(x_pos,temp,~Read_pixel(x_pos-Main_offset_X, - temp -Main_offset_Y)); - } - Update_part_of_screen(x_pos+start_x-3,y_pos+start_y-3,end_x-start_x+1,end_y-start_y+1); - } -} - - -void Curve_34_points_1_0(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_left; - - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Fore_color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Curve_34_points_2_0(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Back_color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Curve_34_points_1_5(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 1 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - short x1,x2,y1,y2; - - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - - if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) - { - Hide_cursor(); - Display_coords_rel_or_abs(x1,y1); - - Hide_line_preview(x1,y1,x2,y2); - Pixel_figure_preview (x1,y1,Fore_color); - Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Fore_color); - - Display_cursor(); - } - - Operation_push(x1); - Operation_push(y1); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Curve_34_points_2_5(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 2 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - short x1,x2,y1,y2; - - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - - if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) - { - Hide_cursor(); - Display_coords_rel_or_abs(x1,y1); - - Hide_line_preview(x1,y1,x2,y2); - Pixel_figure_preview (x1,y1,Back_color); - Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Back_color); - - Display_cursor(); - } - - Operation_push(x1); - Operation_push(y1); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -byte Cursor_hidden_before_curve; - -void Curve_4_points_0_5(void) -// -// Opération : OPERATION_4_POINTS_CURVE -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Oui -// -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short third_x,third_y; - short color; - - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - third_x=Round_div(abs(x4-x1),3); - third_y=Round_div(abs(y4-y1),3); - - if (x1B=(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] -} - - -void Curve_3_points_0_5(void) -// -// Opération : OPERATION_3_POINTS_CURVE -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Oui -// -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short color; - - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - 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.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - - Operation_push(color); - Operation_push(x1); - Operation_push(y1); - Operation_push(x2); - Operation_push(y2); - Operation_push(x3); - Operation_push(y3); - Operation_push(x4); - Operation_push(y4); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Curve_3_points_0_11(void) -// -// Opération : OPERATION_3_POINTS_CURVE -// Click Souris: 0 -// Taille_Pile : 11 -// -// Souris effacée: Non -// -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short old_x,old_y; - short color; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) ) - { - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y3); - Operation_pop(&x3); - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - Hide_cursor(); - Print_coordinates(); - - Hide_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); - Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); - Draw_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); - Display_cursor(); - - Operation_push(color); - Operation_push(x1); - Operation_push(y1); - Operation_push(x2); - Operation_push(y2); - Operation_push(x3); - Operation_push(y3); - Operation_push(x4); - Operation_push(y4); - } - 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 -// -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short old_x,old_y; - short color; - - Operation_pop(&old_y); - Operation_pop(&old_x); - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y3); - Operation_pop(&x3); - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - Paintbrush_hidden=0; - - Hide_cursor(); - - Hide_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); - Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); - Draw_curve_permanent(x1,y1,x2,y2,x3,y3,x4,y4,color); - - Display_cursor(); - Wait_end_of_click(); -} - - -///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH - -void Airbrush_1_0(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_left; - - Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; - Airbrush(LEFT_SIDE); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Airbrush_2_0(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; - Airbrush(RIGHT_SIDE); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Airbrush_12_2(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 1 ou 2 -// Taille_Pile : 2 -// -// Souris effacée: Non -// -{ - short old_x,old_y; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) - { - Hide_cursor(); - Print_coordinates(); - Display_cursor(); - } - - if (SDL_GetTicks()>Airbrush_next_time) - { - Airbrush_next_time+=Airbrush_delay*10; - Airbrush(Mouse_K_unique); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Airbrush_0_2(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 0 -// Taille_Pile : 2 -// -// Souris effacée: Non -// -{ - Operation_stack_size-=2; -} - - -////////////////////////////////////////////////////////// OPERATION_POLYGON - - -void Polygon_12_0(void) -// Opération : OPERATION_POLYGON -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - // On place temporairement le début de la ligne qui ne s'afficherait pas sinon - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Mouse_K | 0x80); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 8 : phase d'appui, non interruptible -} - - - -void Polygon_12_9(void) -// Opération : OPERATION_POLYGON -// Click Souris: 1 ou 2 -// Taille_Pile : 9 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - Operation_pop(&direction); - - if (direction==Mouse_K) - { - Operation_push(direction); - Operation_push(color); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - // Taille de pile 8 : phase d'appui, non interruptible - } - else - { - // La série de ligne est terminée, il faut donc effacer la dernière - // preview de ligne et relier le dernier point avec le premier - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - Operation_pop(&end_y); - Operation_pop(&end_x); - Paintbrush_shape=Paintbrush_shape_before_operation; - // Le pied aurait été de ne pas repasser sur le 1er point de la 1ère ligne - // mais c'est pas possible :( - Draw_line_permanet(start_x,start_y,end_x,end_y,color); - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - Display_cursor(); - Wait_end_of_click(); - Hide_cursor(); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - - Paintbrush_shape=Paintbrush_shape_before_operation; - } -} - - -////////////////////////////////////////////////////////// OPERATION_POLYFILL - -short * Polyfill_table_of_points; -int Polyfill_number_of_points; - -void Polyfill_12_0(void) -// Opération : OPERATION_POLYFILL -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - Paintbrush_hidden=1; - - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - Polyfill_table_of_points=(short *) malloc((Config.Nb_max_vertices_per_polygon<<1)*sizeof(short)); - Polyfill_table_of_points[0]=Paintbrush_X; - Polyfill_table_of_points[1]=Paintbrush_Y; - Polyfill_number_of_points=1; - - // On place temporairement le début de la ligne qui ne s'afficherait pas sinon - Pixel_figure_preview_xor(Paintbrush_X,Paintbrush_Y,0); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Mouse_K | 0x80); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 8 : phase d'appui, non interruptible -} - - -void Polyfill_0_8(void) -// Opération : OPERATION_POLYFILL -// Click Souris: 0 -// Taille_Pile : 8 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); - - if (direction & 0x80) - direction=(direction & 0x7F); - - Operation_push(direction); // Valeur bidon servant de nouvel état de pile - Operation_push(direction); - Operation_push(color); - - Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0); - - if (Polyfill_number_of_points1) width--; - if (height>1) height--; - } - - Num2str(width,str,4); - Print_in_menu(str,2); - Num2str(height,str,4); - Print_in_menu(str,11); - } - else - Print_coordinates(); - } - - Display_all_screen(); - - x=Paintbrush_X; - y=Paintbrush_Y; - if (Snap_mode && Config.Adjust_brush_pick) - { - dx=Paintbrush_X-start_x; - dy=Paintbrush_Y-start_y; - if (dx<0) x++; else {if (dx>0) x--;} - if (dy<0) y++; else {if (dy>0) y--;} - Stretch_brush_preview(start_x,start_y,x,y); - } - else - Stretch_brush_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y); - - old_x=Paintbrush_X; - old_y=Paintbrush_Y; - Paintbrush_X=start_x; - Paintbrush_Y=start_y; - Display_cursor(); - Paintbrush_X=old_x; - Paintbrush_Y=old_y; - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(x); - Operation_push(y); - - Operation_push(start_x); - Operation_push(start_y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(2); -} - - - -void Stretch_brush_0_7(void) -// -// Opération : OPERATION_STRETCH_BRUSH -// Click Souris: 0 -// Taille_Pile : 7 -// -// Souris effacée: Non -// -{ - char str[5]; - short start_x; - short start_y; - short old_x; - short old_y; - short width=0; - short height=0; - byte size_change; - short prev_state; - - Operation_pop(&prev_state); - Operation_pop(&old_y); - Operation_pop(&old_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) - { - if (Menu_is_visible) - { - if (Config.Coords_rel) - { - width=((start_x1)?start_x+(Brush_width>>1)-1:1; - height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; - break; - case 'X': // Moitié X - width=(Brush_width>1)?start_x+(Brush_width>>1)-1:1; - height=start_y+Brush_height-1; - break; - case 'Y': // Moitié Y - width=start_x+Brush_width-1; - height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; - break; - case 'n': // Normal - width=start_x+Brush_width-1; - height=start_y+Brush_height-1; - break; - default : - size_change=0; - } - Key_ANSI=0; - } - else - size_change=0; - - if (size_change) - { - // On efface la preview de la brosse (et la croix) - Display_all_screen(); - - old_x=Paintbrush_X; - old_y=Paintbrush_Y; - Paintbrush_X=start_x; - Paintbrush_Y=start_y; - Display_cursor(); - Paintbrush_X=old_x; - Paintbrush_Y=old_y; - - Stretch_brush_preview(start_x,start_y,width,height); - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(width); - Operation_push(height); - } - - Operation_push(start_x); - Operation_push(start_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(3); -} - - -void Stretch_brush_2_7(void) -// -// Opération : OPERATION_STRETCH_BRUSH -// Click Souris: 2 -// Taille_Pile : 7 -// -// Souris effacée: Oui -// -{ - short computed_x; - short computed_y; - short start_x; - short start_y; - - - Operation_stack_size-=3; - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&computed_y); - Operation_pop(&computed_x); - - // On efface la preview de la brosse (et la croix) - Display_all_screen(); - - // Et enfin on stocke pour de bon la nouvelle brosse étirée - Stretch_brush(start_x,start_y,computed_x,computed_y); - - Return_to_draw_mode(); -} - - -//////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH - - -void Rotate_brush_12_0(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - if (Mouse_K==LEFT_SIDE) - { - Brush_rotation_center_X=Paintbrush_X+(Brush_width>>1)-Brush_width; - Brush_rotation_center_Y=Paintbrush_Y; - Brush_rotation_center_is_defined=1; - Operation_push(Paintbrush_X); // Dernière position calculée X - Operation_push(Paintbrush_Y); // Dernière position calculée Y - Operation_push(Paintbrush_X); // Dernière position X - Operation_push(Paintbrush_Y); // Dernière position Y - Operation_push(1); // State précédent - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("Angle: 0° ",0); - } - else - { - Start_operation_stack(Operation_before_interrupt); - Wait_end_of_click(); // FIXME: celui-la il donne un résultat pas très chouette en visuel - } -} - - - -void Rotate_brush_1_5(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 1 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - char str[4]; - short old_x; - short old_y; - short prev_state; - float angle; - int dx,dy; - - Operation_pop(&prev_state); - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=2) ) - { - if ( (Brush_rotation_center_X==Paintbrush_X) - && (Brush_rotation_center_Y==Paintbrush_Y) ) - angle=0.0; - else - { - dx=Paintbrush_X-Brush_rotation_center_X; - dy=Paintbrush_Y-Brush_rotation_center_Y; - angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); - if (dy>0) angle=M_2PI-angle; - } - - if (Menu_is_visible) - { - if (Config.Coords_rel) - { - Num2str((int)(angle*180.0/M_PI),str,3); - Print_in_menu(str,7); - } - else - Print_coordinates(); - } - - Display_all_screen(); - Rotate_brush_preview(angle); - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(2); -} - - - -void Rotate_brush_0_5(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - char str[4]; - short old_x; - short old_y; - short computed_x=0; - short computed_y=0; - byte angle_change; - short prev_state; - float angle=0.0; - int dx,dy; - - Operation_pop(&prev_state); - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) - { - if ( (Brush_rotation_center_X==Paintbrush_X) - && (Brush_rotation_center_Y==Paintbrush_Y) ) - angle=0.0; - else - { - dx=Paintbrush_X-Brush_rotation_center_X; - dy=Paintbrush_Y-Brush_rotation_center_Y; - angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); - if (dy>0) angle=M_2PI-angle; - } - - if (Menu_is_visible) - { - if (Config.Coords_rel) - { - Num2str(Round(angle*180.0/M_PI),str,3); - Print_in_menu(str,7); - } - else - Print_coordinates(); - } - } - - // Utilise Key_ANSI au lieu de Key, car Get_input() met ce dernier - // à zero si une operation est en cours (Operation_stack_size!=0) - if (Key_ANSI) - { - angle_change=1; - computed_x=Brush_rotation_center_X; - computed_y=Brush_rotation_center_Y; - switch (Key_ANSI) - { - case '6': angle= 0.0 ; computed_x++; break; - case '9': angle=M_PI*0.25; computed_x++; computed_y--; break; - case '8': angle=M_PI*0.5 ; computed_y--; break; - case '7': angle=M_PI*0.75; computed_x--; computed_y--; break; - case '4': angle=M_PI ; computed_x--; break; - case '1': angle=M_PI*1.25; computed_x--; computed_y++; break; - case '2': angle=M_PI*1.5 ; computed_y++; break; - case '3': angle=M_PI*1.75; computed_x++; computed_y++; break; - default : - angle_change=0; - } - Key_ANSI=0; - } - else - angle_change=0; - - if (angle_change) - { - // On efface la preview de la brosse - Display_all_screen(); - Rotate_brush_preview(angle); - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(computed_x); - Operation_push(computed_y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(3); -} - - -void Rotate_brush_2_5(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 2 -// Taille_Pile : 5 -// -// Souris effacée: Oui -// -{ - short computed_x; - short computed_y; - int dx,dy; - float angle; - - - // On efface la preview de la brosse - Display_all_screen(); - - Operation_stack_size-=3; - Operation_pop(&computed_y); - Operation_pop(&computed_x); - - // Calcul de l'angle par rapport à la dernière position calculée - if ( (Brush_rotation_center_X==computed_x) - && (Brush_rotation_center_Y==computed_y) ) - angle=0.0; - else - { - dx=computed_x-Brush_rotation_center_X; - dy=computed_y-Brush_rotation_center_Y; - angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); - if (dy>0) angle=M_2PI-angle; - } - - // Et enfin on stocke pour de bon la nouvelle brosse étirée - Rotate_brush(angle); - - Return_to_draw_mode(); -} - -///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH - -/// Draws a 2x2 XOR square at the specified picture coordinates, on the screen. -void Draw_stretch_spot(short x_pos, short y_pos) -{ - short x,y; - - for (y=y_pos-1;y=Limit_top && y<=Limit_visible_bottom) - for (x=x_pos-1;x=Limit_left && x<=Limit_visible_right) - Pixel_preview(x,y,~Read_pixel(x-Main_offset_X,y-Main_offset_Y)); - Update_part_of_screen(x_pos-1, y_pos-1, 2, 2); -} - -void Distort_brush_0_0(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 0 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - if ( Menu_is_visible ) - { - Print_in_menu("POSITION BRUSH TO START ",0); - } -} - -void Distort_brush_1_0(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - short x_pos, y_pos; - - Init_start_operation(); - Paintbrush_hidden=1; - Hide_cursor(); - - // Top left angle - x_pos=Paintbrush_X-Brush_offset_X; - y_pos=Paintbrush_Y-Brush_offset_Y; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - // Top right angle - x_pos+=Brush_width; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - // Bottom right angle - y_pos+=Brush_height; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - // Bottom left angle - x_pos-=Brush_width; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - Distort_brush_preview( - Operation_stack[1], - Operation_stack[2], - Operation_stack[3], - Operation_stack[4], - Operation_stack[5], - Operation_stack[6], - Operation_stack[7], - Operation_stack[8]); - Display_cursor(); - Update_part_of_screen(Paintbrush_X-Brush_offset_X, Paintbrush_Y-Brush_offset_Y, Brush_width, Brush_height); - Wait_end_of_click(); - // Erase the message in status bar - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - } -} - -void Distort_brush_1_8(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 1 -// Taille_Pile : 8 -// -// Souris effacée: No -// -{ - // How far (in pixels) you can catch a handle - #define REACH_DISTANCE 100 - short i; - short x[4]; - short y[4]; - long best_distance=REACH_DISTANCE; - short best_spot=-1; - - for (i=3;i>=0;i--) - { - long distance; - Operation_pop(&y[i]); - Operation_pop(&x[i]); - distance=Distance(Paintbrush_X,Paintbrush_Y,x[i],y[i]); - if (distance-1) - { - Operation_push(best_spot); - } - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - -void Distort_brush_1_9(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 1 -// Taille_Pile : 9 -// -// Souris effacée: No -// -{ - short i; - short x[4]; - short y[4]; - short selected_corner; - - // Pop all arguments - Operation_pop(&selected_corner); - for (i=3;i>=0;i--) - { - Operation_pop(&y[i]); - Operation_pop(&x[i]); - } - - if (Paintbrush_X!=x[selected_corner] || Paintbrush_Y!=y[selected_corner]) - { - Hide_cursor(); - - // Easiest refresh mode: make no assumptions on how the brush was - // displayed before. - Display_all_screen(); - - x[selected_corner]=Paintbrush_X; - y[selected_corner]=Paintbrush_Y; - - for (i=0;i<4;i++) - Draw_stretch_spot(x[i],y[i]); - - Distort_brush_preview(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); - - Display_cursor(); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - Update_rect(0,0,Screen_width,Menu_Y); - } - - // Push back all arguments - for (i=0;i<4;i++) - { - Operation_push(x[i]); - Operation_push(y[i]); - } - Operation_push(selected_corner); - -} -void Distort_brush_0_9(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 0 -// Taille_Pile : 9 -// -// Souris effacée: No -// -{ - short selected_corner; - Operation_pop(&selected_corner); - -} - -void Distort_brush_2_0(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Paintbrush_hidden=0; - Display_all_screen(); - // Erase the message in status bar - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - } - Return_to_draw_mode(); -} - -void Distort_brush_2_8(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 2 -// Taille_Pile : 8 -// -// Souris effacée: Oui -// -{ - short i; - short x[4]; - short y[4]; - - // Pop all arguments - for (i=3;i>=0;i--) - { - Operation_pop(&y[i]); - Operation_pop(&x[i]); - } - Distort_brush(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); - - Paintbrush_hidden=0; - Display_all_screen(); - - Return_to_draw_mode(); -} - -//////////////////////////////////////////////////////////// OPERATION_SCROLL - - -byte Cursor_hidden_before_scroll; - -void Scroll_12_0(void) -// -// Opération : OPERATION_SCROLL -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - Backup(); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Cursor_hidden_before_scroll=Cursor_hidden; - Cursor_hidden=1; - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); -} - - -void Scroll_12_4(void) -// -// Opération : OPERATION_SCROLL -// Click Souris: 1 ou 2 -// Taille_Pile : 4 -// -// Souris effacée: Non -// -{ - short center_x; - short center_y; - short x_pos; - short y_pos; - short x_offset; - short y_offset; - //char str[5]; - - Operation_pop(&y_pos); - Operation_pop(&x_pos); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - - if ( (Paintbrush_X!=x_pos) || (Paintbrush_Y!=y_pos) ) - { - // L'utilisateur a bougé, il faut scroller l'image - - if (Paintbrush_X>=center_x) - x_offset=(Paintbrush_X-center_x)%Main_image_width; - else - x_offset=Main_image_width-((center_x-Paintbrush_X)%Main_image_width); - - if (Paintbrush_Y>=center_y) - y_offset=(Paintbrush_Y-center_y)%Main_image_height; - else - y_offset=Main_image_height-((center_y-Paintbrush_Y)%Main_image_height); - - Display_coords_rel_or_abs(center_x,center_y); - - Scroll_picture(x_offset,y_offset); - - Display_all_screen(); - } - - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Scroll_0_4(void) -// -// Opération : OPERATION_SCROLL -// Click Souris: 0 -// Taille_Pile : 4 -// -// Souris effacée: Oui -// -{ - Operation_stack_size-=4; - Cursor_hidden=Cursor_hidden_before_scroll; - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -//////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE - - -void Grad_circle_12_0(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - Init_start_operation(); - Backup(); - - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - Paintbrush_hidden_before_scroll=Paintbrush_hidden; - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("Radius: 0 ",0); - - Operation_push(Mouse_K); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_circle_12_6(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 1 ou 2 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Non -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short radius; - char str[5]; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) - { - Hide_cursor(); - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Num2str(Distance(center_x,center_y,Paintbrush_X,Paintbrush_Y),str,4); - Print_in_menu(str,7); - } - else - Print_coordinates(); - - Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ - ((tangent_y-center_y)*(tangent_y-center_y)); - radius=sqrt(Circle_limit); - Hide_empty_circle_preview(center_x,center_y,radius); - - Circle_limit=((Paintbrush_X-center_x)*(Paintbrush_X-center_x))+ - ((Paintbrush_Y-center_y)*(Paintbrush_Y-center_y)); - radius=sqrt(Circle_limit); - Draw_empty_circle_preview(center_x,center_y,radius,color); - - Display_cursor(); - } - - Operation_push(color); - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_circle_0_6(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 0 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short click; - short radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - - Operation_pop(&color); - Operation_pop(&click); - - if (click==LEFT_SIDE) - { - Operation_push(click); - Operation_push(color); - - Operation_push(center_x); - Operation_push(center_y); - Operation_push(tangent_x); - Operation_push(tangent_y); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - - // On change la forme du curseur - Cursor_shape=CURSOR_SHAPE_XOR_TARGET; - - // On affiche une croix XOR au centre du cercle - Draw_curve_cross(center_x,center_y); - - if (Menu_is_visible) - { - if (Config.Coords_rel) - Print_in_menu("X: Y:",0); - else - Print_in_menu("X: Y: ",0); - Display_coords_rel_or_abs(center_x,center_y); - } - } - else - { - Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ - ((tangent_y-center_y)*(tangent_y-center_y)); - radius=sqrt(Circle_limit); - Hide_empty_circle_preview(center_x,center_y,radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - Draw_filled_circle(center_x,center_y,radius,Back_color); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - } -} - - -void Grad_circle_12_8(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 0 -// Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short old_mouse_k; - - short radius; - - Operation_stack_size-=2; // On fait sauter les 2 derniers élts de la pile - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - Operation_pop(&old_mouse_k); - - Hide_cursor(); - // On efface la croix XOR au centre du cercle - Draw_curve_cross(center_x,center_y); - - Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ - ((tangent_y-center_y)*(tangent_y-center_y)); - radius=sqrt(Circle_limit); - Hide_empty_circle_preview(center_x,center_y,radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - if (Mouse_K==old_mouse_k) - Draw_grad_circle(center_x,center_y,radius,Paintbrush_X,Paintbrush_Y); - - Display_cursor(); - Wait_end_of_click(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -void Grad_circle_or_ellipse_0_8(void) -// -// Opération : OPERATION_{CERCLE|ELLIPSE}_DEGRADE -// Click Souris: 0 -// Taille_Pile : 8 -// -// Souris effacée: Non -// -{ - short start_x; - short start_y; - short tangent_x; - short tangent_y; - short old_x; - short old_y; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) - { - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Display_coords_rel_or_abs(start_x,start_y); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(tangent_x); - Operation_push(tangent_y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE - - -void Grad_ellipse_12_0(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - Init_start_operation(); - Backup(); - - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - Paintbrush_hidden_before_scroll=Paintbrush_hidden; - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Mouse_K); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_ellipse_12_6(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 1 ou 2 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Non -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) - { - Hide_cursor(); - Display_coords_rel_or_abs(center_x,center_y); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x - :center_x-Paintbrush_X; - vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y - :center_y-Paintbrush_Y; - Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); - - Display_cursor(); - } - - Operation_push(color); - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_ellipse_0_6(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short click; - //short radius; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - - Operation_pop(&color); - Operation_pop(&click); - - if (click==LEFT_SIDE) - { - Operation_push(click); - Operation_push(color); - - Operation_push(center_x); - Operation_push(center_y); - Operation_push(tangent_x); - Operation_push(tangent_y); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - - // On change la forme du curseur - Cursor_shape=CURSOR_SHAPE_XOR_TARGET; - - // On affiche une croix XOR au centre du cercle - Draw_curve_cross(center_x,center_y); - - if (Menu_is_visible) - { - if (Config.Coords_rel) - Print_in_menu("X: Y:",0); - else - Print_in_menu("X: Y: ",0); - Display_coords_rel_or_abs(center_x,center_y); - } - } - else - { - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Back_color); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - } -} - - -void Grad_ellipse_12_8(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - short old_mouse_k; - - Operation_stack_size-=2; // On fait sauter les 2 derniers élts de la pile - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - Operation_pop(&old_mouse_k); - - Hide_cursor(); - // On efface la croix XOR au centre de l'ellipse - Draw_curve_cross(center_x,center_y); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - if (Mouse_K==old_mouse_k) - Draw_grad_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Paintbrush_X,Paintbrush_Y); - - Display_cursor(); - - Wait_end_of_click(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - -/****************************** -* Operation_Rectangle_Degrade * -******************************/ - -// 1) tracé d'un rectangle classique avec les lignes XOR -// 2) tracé d'une ligne vecteur de dégradé, comme une ligne normale -// 3) dessin du dégradé - - -void Grad_rectangle_12_0(void) -// Opération : OPERATION_GRAD_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui - -// Initialisation de l'étape 1, on commence à dessiner le rectangle -{ - Init_start_operation(); - Backup(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("\035: 1 \022: 1",0); - // On laisse une trace du curseur à l'écran - Display_cursor(); - - if (Mouse_K==LEFT_SIDE) - { - Shade_table=Shade_table_left; - Operation_push(Mouse_K); - } - else - { - Shade_table=Shade_table_right; - Operation_push(Mouse_K); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_rectangle_12_5(void) -// Opération : OPERATION_GRAD_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 5 -// -// Souris effacée: Non - -// Modification de la taille du rectangle -{ - short start_x; - short start_y; - short old_x; - short old_y; - char str[5]; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) - { - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Num2str(((start_x Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width)) // Tous les clippings à gérer sont là - offset_width = Max(rax,rbx) - Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width); - - if (Max(ray,rby)-Main_offset_Y > Min(Main_image_height,Menu_Y)) - offset_height = Max(ray,rby) - Min(Main_image_height,Menu_Y); - - // Dessin dans la zone de dessin normale - Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width - offset_width); - if(offset_height == 0) - Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Max(ray,rby)-1-Main_offset_Y,width - offset_width); - - Vertical_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); - if (offset_width == 0) // Sinon cette ligne est en dehors de la zone image, inutile de la dessiner - Vertical_XOR_line(Max(rax,rbx)-1-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); - - Update_rect(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width+1-offset_width,height+1-offset_height); - - // Dessin dans la zone zoomée - if(Main_magnifier_mode && Min(rax,rbx)Limit_left_zoom && Min(ray,rby)Limit_top_zoom ) - { - offset_width = 0; - offset_height=0; - - if(Min(rax,rbx)Limit_visible_right_zoom) // On dépasse du zoom à droite - offset_width += Max(rax,rbx) - Limit_visible_right_zoom; - - if(Min(ray,rby)Limit_visible_bottom_zoom) // On dépasse du zoom en bas - offset_height += Max(ray,rby) - Limit_visible_bottom_zoom; - - if(width > offset_width) - { - if(offset_top==0) // La ligne du haut est visible - Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rax,rbx),Min(ray,rby),width-offset_width); - - if(Max(ray,rby)0?offset_left:Min(rax,rbx),Max(ray,rby),width-offset_width); - } - - if(height>offset_height) - { - if(offset_left==0) // La ligne de gauche est visible - Vertical_XOR_line_zoom(Min(rax,rbx),offset_top>0?offset_top:Min(ray,rby),height-offset_height); - - if(Max(rax,rbx)0?offset_top:Min(ray,rby),height-offset_height); - } - } - - Operation_push(rax); - Operation_push(ray); - Operation_push(rbx); - Operation_push(rby); - - // On ajoute des trucs dans la pile pour forcer le passage à l'étape suivante - Operation_push(rbx); - Operation_push(rby); -} - -void Grad_rectangle_0_7(void) -// OPERATION_GRAD_RECTANGLE -// click souris 0 -// Taile pile : 5 -// -// Souris effacée : non - -// On continue à attendre que l'utilisateur clique en gardant les coords à jour -{ - Operation_stack_size -= 2; - Print_coordinates(); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Grad_rectangle_12_7(void) -// Opération : OPERATION_GRAD_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 7 -// -// Souris effacée: Oui - -// Début du tracé du vecteur (premier clic) -// On garde les anciennes coordonnées dans la pile, et on ajoute les nouvelles par dessus - -// Si l'utilisateur utilise le mauvais bouton, on annule le tracé. Mais ça nous oblige à vider toute la pile pour vérifier :( -{ - short rax,rbx,ray,rby,vax,vay,click; - - Operation_pop(&vay); - Operation_pop(&vax); - Operation_pop(&ray); - Operation_pop(&rax); - Operation_pop(&rby); - Operation_pop(&rbx); - Operation_pop(&click); - - - if(click==Mouse_K) - { - Operation_push(click); - Operation_push(rbx); - Operation_push(rby); - Operation_push(rax); - Operation_push(ray); - Operation_push(vax); - Operation_push(vay); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - - } - else - { - // Mauvais bouton > anulation de l'opération. - // On a déjà vidé la pile, il reste à effacer le rectangle XOR - short width, height; - short offset_width = 0; - short offset_height = 0; - short offset_left = 0; - short offset_top = 0; - - width = abs(rbx-rax); - height = abs(rby-ray); - - if (Max(rax,rbx)-Main_offset_X > Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width)) // Tous les clippings à gérer sont là - offset_width = Max(rax,rbx) - Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width); - - if (Max(ray,rby)-Main_offset_Y > Min(Main_image_height,Menu_Y)) - offset_height = Max(ray,rby) - Min(Main_image_height,Menu_Y); - - // Dessin dans la zone de dessin normale - Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width - offset_width); - if(offset_height == 0) - Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Max(ray,rby)-1-Main_offset_Y,width - offset_width); - - Vertical_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); - if (offset_width == 0) // Sinon cette ligne est en dehors de la zone image, inutile de la dessiner - Vertical_XOR_line(Max(rax,rbx)-1-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); - - Update_rect(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width+1-offset_width,height+1-offset_height); - - // Dessin dans la zone zoomée - if(Main_magnifier_mode && Min(rax,rbx)Limit_left_zoom && Min(ray,rby)Limit_top_zoom ) - { - offset_width = 0; - offset_height=0; - - if(Min(rax,rbx)Limit_visible_right_zoom) // On dépasse du zoom à droite - offset_width += Max(rax,rbx) - Limit_visible_right_zoom; - - if(Min(ray,rby)Limit_visible_bottom_zoom) // On dépasse du zoom en bas - offset_height += Max(ray,rby) - Limit_visible_bottom_zoom; - - if(width > offset_width) - { - if(offset_top==0) // La ligne du haut est visible - Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rax,rbx),Min(ray,rby),width-offset_width); - - if(Max(ray,rby)0?offset_left:Min(rax,rbx),Max(ray,rby),width-offset_width); - } - - if(height>offset_height) - { - if(offset_left==0) // La ligne de gauche est visible - Vertical_XOR_line_zoom(Min(rax,rbx),offset_top>0?offset_top:Min(ray,rby),height-offset_height); - - if(Max(rax,rbx)0?offset_top:Min(ray,rby),height-offset_height); - } - } - } -} - -void Grad_rectangle_12_9(void) - // Opération : OPERATION_GRAD_RECTANGLE - // Click Souris: 1 - // Taille_Pile : 5 - // - // Souris effacée: Oui - - // Poursuite du tracé du vecteur (déplacement de la souris en gardant le curseur appuyé) -{ - short start_x; - short start_y; - short end_x; - short end_y; - short cursor_x; - short cursor_y; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - - cursor_x = Paintbrush_X; - cursor_y = Paintbrush_Y; - // 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); - - if ((cursor_x!=end_x) || (cursor_y!=end_y)) - { - Display_coords_rel_or_abs(start_x,start_y); - - Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); - Draw_line_preview_xor(start_x,start_y,cursor_x,cursor_y,0); - - } - - - Operation_push(start_x); - Operation_push(start_y); - Operation_push(cursor_x); - Operation_push(cursor_y); -} - -void Grad_rectangle_0_9(void) - // Opération : OPERATION_GRAD_RECTANGLE - // Click Souris: 0 - // Taille_Pile : 9 - // - // Souris effacée: Oui - - // Ouf, fini ! on dessine enfin le rectangle avec son dégradé -{ - short rect_start_x; - short rect_start_y; - short rect_end_x; - short rect_end_y; - - short vector_start_x; - short vector_start_y; - short vector_end_x; - short vector_end_y; - - Operation_pop(&vector_end_y); - Operation_pop(&vector_end_x); - Operation_pop(&vector_start_y); - Operation_pop(&vector_start_x); - Operation_pop(&rect_end_y); - Operation_pop(&rect_end_x); - Operation_pop(&rect_start_y); - Operation_pop(&rect_start_x); - Operation_stack_size--; - - Hide_cursor(); - // Maintenant on efface tout le bazar temporaire : rectangle et ligne XOR - Hide_line_preview(vector_start_x,vector_start_y,vector_end_x,vector_end_y); - - // Et enfin on trace le rectangle avec le dégradé dedans ! - if (vector_end_x==vector_start_x && vector_end_y==vector_start_y) - { - // Vecteur nul > pas de rectangle tracé - // Du coup on doit effacer la preview xor ... - short width, height; - short offset_width = 0; - short offset_height = 0; - short offset_left = 0; - short offset_top = 0; - - width = abs(rect_end_x-rect_start_x); - height = abs(rect_end_y-rect_start_y); - - if (Max(rect_start_x,rect_end_x)-Main_offset_X > Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width)) // Tous les clippings à gérer sont là - offset_width = Max(rect_start_x,rect_end_x) - Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width); - - if (Max(rect_start_y,rect_end_y)-Main_offset_Y > Min(Main_image_height,Menu_Y)) - offset_height = Max(rect_start_y,rect_end_y) - Min(Main_image_height,Menu_Y); - - // Dessin dans la zone de dessin normale - Horizontal_XOR_line(Min(rect_start_x,rect_end_x)-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,width - offset_width); - if(offset_height == 0) - Horizontal_XOR_line(Min(rect_start_x,rect_end_x)-Main_offset_X,Max(rect_start_y,rect_end_y)-1-Main_offset_Y,width - offset_width); - - Vertical_XOR_line(Min(rect_start_x,rect_end_x)-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,height-offset_height); - if (offset_width == 0) // Sinon cette ligne est en dehors de la zone image, inutile de la dessiner - Vertical_XOR_line(Max(rect_start_x,rect_end_x)-1-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,height-offset_height); - - Update_rect(Min(rect_start_x,rect_end_x)-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,width+1-offset_width,height+1-offset_height); - - // Dessin dans la zone zoomée - if(Main_magnifier_mode && Min(rect_start_x,rect_end_x)Limit_left_zoom && Min(rect_start_y,rect_end_y)Limit_top_zoom ) - { - offset_width = 0; - offset_height=0; - - if(Min(rect_start_x,rect_end_x)Limit_visible_right_zoom) // On dépasse du zoom à droite - offset_width += Max(rect_start_x,rect_end_x) - Limit_visible_right_zoom; - - if(Min(rect_start_y,rect_end_y)Limit_visible_bottom_zoom) // On dépasse du zoom en bas - offset_height += Max(rect_start_y,rect_end_y) - Limit_visible_bottom_zoom; - - if(width > offset_width) - { - if(offset_top==0) // La ligne du haut est visible - Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rect_start_x,rect_end_x),Min(rect_start_y,rect_end_y),width-offset_width); - - if(Max(rect_start_y,rect_end_y)0?offset_left:Min(rect_start_x,rect_end_x),Max(rect_start_y,rect_end_y),width-offset_width); - } - - if(height>offset_height) - { - if(offset_left==0) // La ligne de gauche est visible - Vertical_XOR_line_zoom(Min(rect_start_x,rect_end_x),offset_top>0?offset_top:Min(rect_start_y,rect_end_y),height-offset_height); - - if(Max(rect_start_x,rect_end_x)0?offset_top:Min(rect_start_y,rect_end_y),height-offset_height); - } - } - } - else - Draw_grad_rectangle(rect_start_x,rect_start_y,rect_end_x,rect_end_y,vector_start_x,vector_start_y,vector_end_x,vector_end_y); - - Display_cursor(); - Wait_end_of_click(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} -/////////////////////////////////////////////////// OPERATION_CENTERED_LINES - - -void Centered_lines_12_0(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 1 ou 2 - // Taille_Pile : 0 - // - // Souris effacée: Oui -{ - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Mouse_K); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Centered_lines_12_3(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 1 ou 2 - // Taille_Pile : 3 - // - // Souris effacée: Non -{ - short start_x; - short start_y; - - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Centered_lines_0_3(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 0 - // Taille_Pile : 3 - // - // Souris effacée: Oui -{ - short start_x; - short start_y; - short Button; - short color; - - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&Button); - - color=(Button==LEFT_SIDE)?Fore_color:Back_color; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - Operation_push(Button); - Operation_push(Paintbrush_X); // Nouveau début X - Operation_push(Paintbrush_Y); // Nouveau début Y - Operation_push(Paintbrush_X); // Nouvelle dernière fin X - Operation_push(Paintbrush_Y); // Nouvelle dernière fin Y - Operation_push(Paintbrush_X); // Nouvelle dernière position X - Operation_push(Paintbrush_Y); // Nouvelle dernière position Y -} - - -void Centered_lines_12_7(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 1 ou 2 - // Taille_Pile : 7 - // - // Souris effacée: Non -{ - short Button; - short start_x; - short start_y; - short end_x; - short end_y; - short last_x; - short last_y; - short color; - - Operation_pop(&last_y); - Operation_pop(&last_x); - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&Button); - - if (Mouse_K==Button) - { - if ( (end_x!=Paintbrush_X) || (end_y!=Paintbrush_Y) || - (last_x!=Paintbrush_X) || (last_y!=Paintbrush_Y) ) - { - Hide_cursor(); - - color=(Button==LEFT_SIDE)?Fore_color:Back_color; - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,last_x,last_y); - - Smear_start=1; - Display_paintbrush (start_x,start_y,color,0); - Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Display_cursor(); - } - - Operation_push(Button); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - } - else - { - Hide_cursor(); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,last_x,last_y); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - - Display_cursor(); - Wait_end_of_click(); - } -} - - -void Centered_lines_0_7(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 0 - // Taille_Pile : 7 - // - // Souris effacée: Non -{ - short Button; - short start_x; - short start_y; - short end_x; - short end_y; - short last_x; - short last_y; - short color; - - Operation_pop(&last_y); - Operation_pop(&last_x); - Operation_pop(&end_y); - Operation_pop(&end_x); - - if ((Paintbrush_X!=last_x) || (Paintbrush_Y!=last_y)) - { - Hide_cursor(); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&Button); - - color=(Button==LEFT_SIDE)?Fore_color:Back_color; - - Display_coords_rel_or_abs(start_x,start_y); - - Hide_line_preview(start_x,start_y,last_x,last_y); - - Pixel_figure_preview(start_x,start_y,color); - Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Operation_push(Button); - Operation_push(start_x); - Operation_push(start_y); - Display_cursor(); - } - - Operation_push(end_x); - Operation_push(end_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2007 Adrien Destugues + Copyright 2009 Franck Charlet + 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 "const.h" +#include "struct.h" +#include "global.h" +#include "misc.h" +#include "engine.h" +#include "graph.h" +#include "operatio.h" +#include "buttons.h" +#include "pages.h" +#include "errors.h" +#include "sdlscreen.h" +#include "brush.h" +#include "windows.h" + +#if defined(__GP2X__) + #define M_PI 3.14159265358979323846 +#endif + +/// Time (in SDL ticks) when the next airbrush drawing should be done. Also used +/// for discontinuous freehand drawing. +Uint32 Airbrush_next_time; + +void Start_operation_stack(word new_operation) +{ + Brush_rotation_center_is_defined=0; + + // 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_ROTATE_BRUSH: + Operation_before_interrupt=Current_operation; + // On passe à l'operation demandée + Current_operation=new_operation; + break; + default : + // On passe à l'operation demandée + Current_operation=new_operation; + Operation_before_interrupt=Current_operation; + } + + // On spécifie si l'opération autorise le changement de couleur au clavier + switch(new_operation) + { + case OPERATION_CONTINUOUS_DRAW: + case OPERATION_DISCONTINUOUS_DRAW: + case OPERATION_AIRBRUSH: + case OPERATION_CENTERED_LINES: + Allow_color_change_during_operation=1; + break; + default : + Allow_color_change_during_operation=0; + } + + // Et on passe au curseur qui va avec + Cursor_shape=CURSOR_FOR_OPERATION[new_operation]; + Operation_stack_size=0; +} + + +void Init_start_operation(void) +{ + Operation_in_magnifier=(Mouse_X>=Main_X_zoom); + Smear_start=1; +} + + +void Operation_push(short value) +{ + Operation_stack[++Operation_stack_size]=value; +} + + +void Operation_pop(short * value) +{ + *value=Operation_stack[Operation_stack_size--]; +} + + +byte Paintbrush_shape_before_operation; +byte Paintbrush_hidden_before_scroll; + + + +short Distance(short x1, short y1, short x2, short y2) +{ + short x2_moins_x1=x2-x1; + short y2_minus_y1=y2-y1; + + return Round( sqrt( (x2_moins_x1*x2_moins_x1) + (y2_minus_y1*y2_minus_y1) ) ); +} + + +void Display_coords_rel_or_abs(short start_x, short start_y) +{ + char str[6]; + + if (Config.Coords_rel) + { + if (Menu_is_visible) + { + if (Paintbrush_X>start_x) + { + Num2str(Paintbrush_X-start_x,str,5); + str[0]='+'; + } + else if (Paintbrush_Xstart_y) + { + Num2str(Paintbrush_Y-start_y,str,5); + str[0]='+'; + } + else if (Paintbrush_YAirbrush_next_time) + { + Airbrush_next_time+=Airbrush_delay*10; + Hide_cursor(); + // On affiche définitivement le pinceau + Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); + Display_cursor(); + } + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +// ---------- + +void Freehand_mode2_2_0(void) +// Opération : OPERATION_DISCONTINUOUS_DRAW +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + Init_start_operation(); + Backup(); + Shade_table=Shade_table_right; + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Print_coordinates(); + Airbrush_next_time = SDL_GetTicks() + Airbrush_delay*10; + // On affiche définitivement le pinceau + Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); +} + + +void Freehand_mode2_2_2(void) +// Opération : OPERATION_DISCONTINUOUS_DRAW +// Click Souris: 2 +// Taille_Pile : 2 +// +// Souris effacée: Non +{ + short start_x; + short start_y; + + Operation_pop(&start_y); + Operation_pop(&start_x); + + if ( (start_x!=Paintbrush_X) || (start_y!=Paintbrush_Y) ) + { + Print_coordinates(); + if (SDL_GetTicks()>Airbrush_next_time) + { + Airbrush_next_time+=Airbrush_delay*10; + Hide_cursor(); + // On affiche définitivement le pinceau + Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); + Display_cursor(); + } + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +////////////////////////////////////////////////////// OPERATION_POINT_DRAW + +void Freehand_mode3_1_0(void) +// Opération : OPERATION_POINT_DRAW +// Click Souris: 1 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + Init_start_operation(); + Backup(); + Shade_table=Shade_table_left; + // On affiche définitivement le pinceau + Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); + Operation_push(0); // On change simplement l'état de la pile... +} + + +void Freehand_Mode3_2_0(void) +// Opération : OPERATION_POINT_DRAW +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + Init_start_operation(); + Backup(); + Shade_table=Shade_table_right; + // On affiche définitivement le pinceau + Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); + Operation_push(0); // On change simplement l'état de la pile... +} + + +void Freehand_mode3_0_1(void) +// Opération : OPERATION_POINT_DRAW +// Click Souris: 0 +// Taille_Pile : 1 +// +// Souris effacée: Non +{ + Operation_stack_size--; +} + + +///////////////////////////////////////////////////////////// OPERATION_LINE + +void Line_12_0(void) +// Opération : OPERATION_LINE +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui + +// Début du tracé d'une ligne (premier clic) +{ + Init_start_operation(); + Backup(); + Paintbrush_shape_before_operation=Paintbrush_shape; + Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; + + if (Mouse_K==LEFT_SIDE) + { + Shade_table=Shade_table_left; + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + Operation_push(Fore_color); + } + else + { + Shade_table=Shade_table_right; + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + Operation_push(Back_color); + } + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Line_12_5(void) +// Opération : OPERATION_LINE +// Click Souris: 1 +// Taille_Pile : 5 +// +// Souris effacée: Non + +// Poursuite du tracé d'une ligne (déplacement de la souris en gardant le +// curseur appuyé) +{ + short start_x; + short start_y; + short end_x; + short end_y; + + short cursor_x; + short cursor_y; + + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + + cursor_x = Paintbrush_X; + cursor_y = Paintbrush_Y; + + // 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)) + { + Hide_cursor(); + + Display_coords_rel_or_abs(start_x,start_y); + + Hide_line_preview(start_x,start_y,end_x,end_y); + if (Mouse_K==LEFT_SIDE) + { + Pixel_figure_preview (start_x,start_y,Fore_color); + Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Fore_color); + } + else + { + Pixel_figure_preview (start_x,start_y,Back_color); + Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Back_color); + } + + Operation_push(start_x); + Operation_push(start_y); + Operation_push(cursor_x); + Operation_push(cursor_y); + + Display_cursor(); + } + else + { + Operation_push(start_x); + Operation_push(start_y); + Operation_push(end_x); + Operation_push(end_y); + } +} + + +void Line_0_5(void) +// Opération : OPERATION_LINE +// Click Souris: 0 +// Taille_Pile : 5 +// +// Souris effacée: Oui + +// End du tracé d'une ligne (relachage du bouton) +{ + short start_x; + short start_y; + short end_x; + short end_y; + short color; + + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&color); + + Paintbrush_shape=Paintbrush_shape_before_operation; + + Pixel_figure_preview_auto (start_x,start_y); + Hide_line_preview (start_x,start_y,end_x,end_y); + Display_paintbrush (start_x,start_y,color,0); + Draw_line_permanet(start_x,start_y,end_x,end_y,color); + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + + +/////////////////////////////////////////////////////////// OPERATION_K_LIGNE + + +void K_line_12_0(void) +// Opération : OPERATION_K_LIGNE +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + byte color; + + Init_start_operation(); + Backup(); + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; + Paintbrush_shape_before_operation=Paintbrush_shape; + Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; + + color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; + + // On place temporairement le début de la ligne qui ne s'afficherait pas sinon + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Mouse_K | 0x80); + Operation_push(color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + // Taille de pile 6 : phase d'appui, non interruptible +} + + +void K_line_12_6(void) +// Opération : OPERATION_K_LIGNE +// Click Souris: 1 ou 2 | 0 +// Taille_Pile : 6 | 7 +// +// Souris effacée: Non +{ + short start_x; + short start_y; + short end_x; + short end_y; + short color; + + Operation_pop(&end_y); + Operation_pop(&end_x); + + if ((Paintbrush_X!=end_x) || (Paintbrush_Y!=end_y)) + { + Hide_cursor(); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&color); + + Display_coords_rel_or_abs(start_x,start_y); + + Hide_line_preview(start_x,start_y,end_x,end_y); + Pixel_figure_preview (start_x,start_y,color); + Draw_line_preview (start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + + Operation_push(color); + Operation_push(start_x); + Operation_push(start_y); + Display_cursor(); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void K_line_0_6(void) +// Opération : OPERATION_K_LIGNE +// Click Souris: 0 +// Taille_Pile : 6 +// +// Souris effacée: Oui +{ + short start_x; + short start_y; + short end_x; + short end_y; + short color; + short direction; + + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&color); + Operation_pop(&direction); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Pixel_figure_preview_auto (start_x,start_y); + Hide_line_preview (start_x,start_y,end_x,end_y); + /* Doesn't work if fast moving + Pixel_figure_preview_xor (start_x,start_y, 0); + Draw_line_preview_xor (start_x,start_y,end_x,end_y,0); + */ + Paintbrush_shape=Paintbrush_shape_before_operation; + if (direction & 0x80) + { + Display_paintbrush(start_x,start_y,color,0); + direction=(direction & 0x7F); + } + Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; + + Operation_push(direction); + Operation_push(direction); // Valeur bidon servant de nouvel état de pile + Operation_push(color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + // Taille de pile 7 : phase de "repos", interruptible (comme Elliot Ness :)) +} + + +void K_line_12_7(void) +// Opération : OPERATION_K_LIGNE +// Click Souris: 1 ou 2 +// Taille_Pile : 7 +// +// Souris effacée: Oui +{ + short start_x; + short start_y; + short end_x; + short end_y; + short color; + short direction; + + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&color); + Operation_pop(&direction); + Operation_pop(&direction); + + if (direction==Mouse_K) + { + Operation_push(direction); + Operation_push(color); + Operation_push(start_x); + Operation_push(start_y); + Operation_push(end_x); + Operation_push(end_y); + // Taille de pile 6 : phase d'appui, non interruptible + } + else + { + // La série de ligne est terminée, il faut donc effacer la dernière + // preview de ligne + Pixel_figure_preview_auto (start_x,start_y); + Hide_line_preview (start_x,start_y,end_x,end_y); + + Display_cursor(); + Wait_end_of_click(); + Hide_cursor(); + Paintbrush_shape=Paintbrush_shape_before_operation; + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + } +} + + +// ---------------------------------------------------------- OPERATION_MAGNIFY + + +void Magnifier_12_0(void) + +// Opération : 4 (item d'une Loupe) +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui + +{ + + // On passe en mode loupe + Main_magnifier_mode=1; + + // La fonction d'affichage dans la partie image est désormais un affichage + // spécial loupe. + Pixel_preview=Pixel_preview_magnifier; + + // On calcule l'origine de la loupe + Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); + Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); + + // Calcul du coin haut_gauche de la fenêtre devant être zoomée DANS L'ECRAN + if (Main_magnifier_offset_X+Main_magnifier_width>=Limit_right-Main_offset_X) + Main_magnifier_offset_X=Limit_right-Main_magnifier_width-Main_offset_X+1; + if (Main_magnifier_offset_Y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) + Main_magnifier_offset_Y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; + + // Calcul des coordonnées absolues de ce coin DANS L'IMAGE + Main_magnifier_offset_X+=Main_offset_X; + Main_magnifier_offset_Y+=Main_offset_Y; + + if (Main_magnifier_offset_X<0) + Main_magnifier_offset_X=0; + if (Main_magnifier_offset_Y<0) + Main_magnifier_offset_Y=0; + + // On calcule les bornes visibles dans l'écran + Position_screen_according_to_zoom(); + Compute_limits(); + Display_all_screen(); + + // Repositionner le curseur en fonction des coordonnées visibles + Compute_paintbrush_coordinates(); + + // On fait de notre mieux pour restaurer l'ancienne opération: + Start_operation_stack(Operation_before_interrupt); + Display_cursor(); + Wait_end_of_click(); +} + +/////////////////////////////////////////////////// OPERATION_RECTANGLE_????? + +void Rectangle_12_0(void) +// Opération : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + Init_start_operation(); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("\035: 1 \022: 1",0); + // On laisse une trace du curseur à l'écran + Display_cursor(); + + if (Mouse_K==LEFT_SIDE) + { + Shade_table=Shade_table_left; + Operation_push(Fore_color); + } + else + { + Shade_table=Shade_table_right; + Operation_push(Back_color); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Rectangle_12_5(void) +// Opération : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE +// Click Souris: 1 ou 2 +// Taille_Pile : 5 +// +// Souris effacée: Non +{ + short start_x; + short start_y; + short old_x; + short old_y; + char str[5]; + + Operation_pop(&old_y); + Operation_pop(&old_x); + + if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) + { + Operation_pop(&start_y); + Operation_pop(&start_x); + + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Num2str(((start_xcenter_x)?tangent_x-center_x + :center_x-tangent_x; + vertical_radius =(tangent_y>center_y)?tangent_y-center_y + :center_y-tangent_y; + Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); + + horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x + :center_x-Paintbrush_X; + vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y + :center_y-Paintbrush_Y; + Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); + + Display_cursor(); + } + + Operation_push(color); + Operation_push(center_x); + Operation_push(center_y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Empty_ellipse_0_5(void) +// +// Opération : OPERATION_EMPTY_ELLIPSE +// Click Souris: 0 +// Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) +// +// Souris effacée: Oui +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short horizontal_radius; + short vertical_radius; + + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + Operation_pop(&color); + + horizontal_radius=(tangent_x>center_x)?tangent_x-center_x + :center_x-tangent_x; + vertical_radius =(tangent_y>center_y)?tangent_y-center_y + :center_y-tangent_y; + Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); + + Paintbrush_shape=Paintbrush_shape_before_operation; + + Draw_empty_ellipse_permanent(center_x,center_y,horizontal_radius,vertical_radius,color); + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + + +void Filled_ellipse_0_5(void) +// +// Opération : OPERATION_FILLED_ELLIPSE +// Click Souris: 0 +// Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) +// +// Souris effacée: Oui +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short horizontal_radius; + short vertical_radius; + + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + Operation_pop(&color); + + horizontal_radius=(tangent_x>center_x)?tangent_x-center_x + :center_x-tangent_x; + vertical_radius =(tangent_y>center_y)?tangent_y-center_y + :center_y-tangent_y; + Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); + + Paintbrush_shape=Paintbrush_shape_before_operation; + + Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,color); + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + + +////////////////////////////////////////////////////////////// OPERATION_FILL + + +void Fill_1_0(void) +// +// Opération : OPERATION_FILL +// Click Souris: 1 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + 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 + // droite de la loupe. + // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. + Shade_table=Shade_table_left; + Fill_general(Fore_color); + Display_cursor(); + Wait_end_of_click(); +} + + +void Fill_2_0(void) +// +// Opération : OPERATION_FILL +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + 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 + // droite de la loupe. + // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. + Shade_table=Shade_table_right; + Fill_general(Back_color); + Display_cursor(); + Wait_end_of_click(); +} + + +///////////////////////////////////////////////////////// OPERATION_REPLACE + + +void Replace_1_0(void) +// +// Opération : OPERATION_REPLACE +// Click Souris: 1 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + 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 + // droite de la loupe. + Backup(); +// Shade_table=Shade_table_left; + Replace(Fore_color); + Display_cursor(); + Wait_end_of_click(); +} + + +void Replace_2_0(void) +// +// Opération : OPERATION_REPLACE +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + 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 + // droite de la loupe. + Backup(); +// Shade_table=Shade_table_right; + Replace(Back_color); + Display_cursor(); + Wait_end_of_click(); +} + + +/////////////////////////////////////////////////////////// OPERATION_COLORPICK + + +void Colorpicker_12_0(void) +// +// Opération : OPERATION_COLORPICK +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + Init_start_operation(); + + if (Mouse_K==LEFT_SIDE) + { + Set_fore_color(Colorpicker_color); + } + else + { + Set_back_color(Colorpicker_color); + } + Operation_push(Mouse_K); +} + + +void Colorpicker_1_1(void) +// +// Opération : OPERATION_COLORPICK +// Click Souris: 1 +// Taille_Pile : 1 +// +// Souris effacée: Non +// +{ + char str[4]; + + if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) + && (Paintbrush_X=0) && (Paintbrush_Y>=0) + && (Paintbrush_X=Limit_left+3) + start_x=0; + else + start_x=3-(x_pos-Limit_left); + + if (y_pos>=Limit_top+3) + start_y=0; + else + start_y=3-(y_pos-Limit_top); + + if (x_pos<=Limit_visible_right-3) + end_x=6; + else + end_x=3+(Limit_visible_right-x_pos); + + if (y_pos<=Limit_visible_bottom-3) + end_y=6; + else + end_y=3+(Limit_visible_bottom-y_pos); + + if (start_x<=end_x && start_y<=end_y) + { + for (i=start_x; i<=end_x; i++) + { + temp=x_pos+i-3; + Pixel_preview(temp,y_pos,~Read_pixel(temp -Main_offset_X, + y_pos-Main_offset_Y)); + } + for (i=start_y; i<=end_y; i++) + { + temp=y_pos+i-3; + Pixel_preview(x_pos,temp,~Read_pixel(x_pos-Main_offset_X, + temp -Main_offset_Y)); + } + Update_part_of_screen(x_pos+start_x-3,y_pos+start_y-3,end_x-start_x+1,end_y-start_y+1); + } +} + + +void Curve_34_points_1_0(void) +// +// Opération : OPERATION_COURBE_?_POINTS +// Click Souris: 1 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + Init_start_operation(); + Backup(); + Shade_table=Shade_table_left; + + Paintbrush_hidden=1; + + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Fore_color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +void Curve_34_points_2_0(void) +// +// Opération : OPERATION_COURBE_?_POINTS +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + Init_start_operation(); + Backup(); + Shade_table=Shade_table_right; + + Paintbrush_hidden=1; + + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Back_color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Curve_34_points_1_5(void) +// +// Opération : OPERATION_COURBE_?_POINTS +// Click Souris: 1 +// Taille_Pile : 5 +// +// Souris effacée: Non +// +{ + short x1,x2,y1,y2; + + Operation_pop(&y2); + Operation_pop(&x2); + Operation_pop(&y1); + Operation_pop(&x1); + + if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) + { + Hide_cursor(); + Display_coords_rel_or_abs(x1,y1); + + Hide_line_preview(x1,y1,x2,y2); + Pixel_figure_preview (x1,y1,Fore_color); + Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Fore_color); + + Display_cursor(); + } + + Operation_push(x1); + Operation_push(y1); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +void Curve_34_points_2_5(void) +// +// Opération : OPERATION_COURBE_?_POINTS +// Click Souris: 2 +// Taille_Pile : 5 +// +// Souris effacée: Non +// +{ + short x1,x2,y1,y2; + + Operation_pop(&y2); + Operation_pop(&x2); + Operation_pop(&y1); + Operation_pop(&x1); + + if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) + { + Hide_cursor(); + Display_coords_rel_or_abs(x1,y1); + + Hide_line_preview(x1,y1,x2,y2); + Pixel_figure_preview (x1,y1,Back_color); + Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Back_color); + + Display_cursor(); + } + + Operation_push(x1); + Operation_push(y1); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +byte Cursor_hidden_before_curve; + +void Curve_4_points_0_5(void) +// +// Opération : OPERATION_4_POINTS_CURVE +// Click Souris: 0 +// Taille_Pile : 5 +// +// Souris effacée: Oui +// +{ + short x1,y1,x2,y2,x3,y3,x4,y4; + short third_x,third_y; + short color; + + Operation_pop(&y4); + Operation_pop(&x4); + Operation_pop(&y1); + Operation_pop(&x1); + Operation_pop(&color); + + third_x=Round_div(abs(x4-x1),3); + third_y=Round_div(abs(y4-y1),3); + + if (x1B=(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] +} + + +void Curve_3_points_0_5(void) +// +// Opération : OPERATION_3_POINTS_CURVE +// Click Souris: 0 +// Taille_Pile : 5 +// +// Souris effacée: Oui +// +{ + short x1,y1,x2,y2,x3,y3,x4,y4; + short color; + + Operation_pop(&y4); + Operation_pop(&x4); + Operation_pop(&y1); + Operation_pop(&x1); + Operation_pop(&color); + + 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.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + + Operation_push(color); + Operation_push(x1); + Operation_push(y1); + Operation_push(x2); + Operation_push(y2); + Operation_push(x3); + Operation_push(y3); + Operation_push(x4); + Operation_push(y4); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Curve_3_points_0_11(void) +// +// Opération : OPERATION_3_POINTS_CURVE +// Click Souris: 0 +// Taille_Pile : 11 +// +// Souris effacée: Non +// +{ + short x1,y1,x2,y2,x3,y3,x4,y4; + short old_x,old_y; + short color; + + Operation_pop(&old_y); + Operation_pop(&old_x); + + if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) ) + { + Operation_pop(&y4); + Operation_pop(&x4); + Operation_pop(&y3); + Operation_pop(&x3); + Operation_pop(&y2); + Operation_pop(&x2); + Operation_pop(&y1); + Operation_pop(&x1); + Operation_pop(&color); + + Hide_cursor(); + Print_coordinates(); + + Hide_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); + Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); + Draw_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); + Display_cursor(); + + Operation_push(color); + Operation_push(x1); + Operation_push(y1); + Operation_push(x2); + Operation_push(y2); + Operation_push(x3); + Operation_push(y3); + Operation_push(x4); + Operation_push(y4); + } + 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 +// +{ + short x1,y1,x2,y2,x3,y3,x4,y4; + short old_x,old_y; + short color; + + Operation_pop(&old_y); + Operation_pop(&old_x); + Operation_pop(&y4); + Operation_pop(&x4); + Operation_pop(&y3); + Operation_pop(&x3); + Operation_pop(&y2); + Operation_pop(&x2); + Operation_pop(&y1); + Operation_pop(&x1); + Operation_pop(&color); + + Paintbrush_hidden=0; + + Hide_cursor(); + + Hide_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); + Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); + Draw_curve_permanent(x1,y1,x2,y2,x3,y3,x4,y4,color); + + Display_cursor(); + Wait_end_of_click(); +} + + +///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH + +void Airbrush_1_0(void) +// +// Opération : OPERATION_AIRBRUSH +// Click Souris: 1 +// Taille_Pile : 0 +// +// Souris effacée: Non +// +{ + Init_start_operation(); + Backup(); + Shade_table=Shade_table_left; + + Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; + Airbrush(LEFT_SIDE); + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +void Airbrush_2_0(void) +// +// Opération : OPERATION_AIRBRUSH +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Non +// +{ + Init_start_operation(); + Backup(); + Shade_table=Shade_table_right; + Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; + Airbrush(RIGHT_SIDE); + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +void Airbrush_12_2(void) +// +// Opération : OPERATION_AIRBRUSH +// Click Souris: 1 ou 2 +// Taille_Pile : 2 +// +// Souris effacée: Non +// +{ + short old_x,old_y; + + Operation_pop(&old_y); + Operation_pop(&old_x); + + if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) + { + Hide_cursor(); + Print_coordinates(); + Display_cursor(); + } + + if (SDL_GetTicks()>Airbrush_next_time) + { + Airbrush_next_time+=Airbrush_delay*10; + Airbrush(Mouse_K_unique); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +void Airbrush_0_2(void) +// +// Opération : OPERATION_AIRBRUSH +// Click Souris: 0 +// Taille_Pile : 2 +// +// Souris effacée: Non +// +{ + Operation_stack_size-=2; +} + + +////////////////////////////////////////////////////////// OPERATION_POLYGON + + +void Polygon_12_0(void) +// Opération : OPERATION_POLYGON +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + byte color; + + Init_start_operation(); + Backup(); + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; + Paintbrush_shape_before_operation=Paintbrush_shape; + Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; + + color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; + + // On place temporairement le début de la ligne qui ne s'afficherait pas sinon + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Mouse_K | 0x80); + Operation_push(color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + // Taille de pile 8 : phase d'appui, non interruptible +} + + + +void Polygon_12_9(void) +// Opération : OPERATION_POLYGON +// Click Souris: 1 ou 2 +// Taille_Pile : 9 +// +// Souris effacée: Oui +{ + short start_x; + short start_y; + short end_x; + short end_y; + short color; + short direction; + + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&color); + Operation_pop(&direction); + Operation_pop(&direction); + + if (direction==Mouse_K) + { + Operation_push(direction); + Operation_push(color); + Operation_push(start_x); + Operation_push(start_y); + Operation_push(end_x); + Operation_push(end_y); + // Taille de pile 8 : phase d'appui, non interruptible + } + else + { + // La série de ligne est terminée, il faut donc effacer la dernière + // preview de ligne et relier le dernier point avec le premier + Pixel_figure_preview_auto (start_x,start_y); + Hide_line_preview (start_x,start_y,end_x,end_y); + Operation_pop(&end_y); + Operation_pop(&end_x); + Paintbrush_shape=Paintbrush_shape_before_operation; + // Le pied aurait été de ne pas repasser sur le 1er point de la 1ère ligne + // mais c'est pas possible :( + Draw_line_permanet(start_x,start_y,end_x,end_y,color); + Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; + + Display_cursor(); + Wait_end_of_click(); + Hide_cursor(); + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + + Paintbrush_shape=Paintbrush_shape_before_operation; + } +} + + +////////////////////////////////////////////////////////// OPERATION_POLYFILL + +short * Polyfill_table_of_points; +int Polyfill_number_of_points; + +void Polyfill_12_0(void) +// Opération : OPERATION_POLYFILL +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + byte color; + + Init_start_operation(); + Backup(); + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; + Paintbrush_hidden=1; + + color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; + + Polyfill_table_of_points=(short *) malloc((Config.Nb_max_vertices_per_polygon<<1)*sizeof(short)); + Polyfill_table_of_points[0]=Paintbrush_X; + Polyfill_table_of_points[1]=Paintbrush_Y; + Polyfill_number_of_points=1; + + // On place temporairement le début de la ligne qui ne s'afficherait pas sinon + Pixel_figure_preview_xor(Paintbrush_X,Paintbrush_Y,0); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Mouse_K | 0x80); + Operation_push(color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + // Taille de pile 8 : phase d'appui, non interruptible +} + + +void Polyfill_0_8(void) +// Opération : OPERATION_POLYFILL +// Click Souris: 0 +// Taille_Pile : 8 +// +// Souris effacée: Oui +{ + short start_x; + short start_y; + short end_x; + short end_y; + short color; + short direction; + + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&color); + Operation_pop(&direction); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); + + if (direction & 0x80) + direction=(direction & 0x7F); + + Operation_push(direction); // Valeur bidon servant de nouvel état de pile + Operation_push(direction); + Operation_push(color); + + Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0); + + if (Polyfill_number_of_points1) width--; + if (height>1) height--; + } + + Num2str(width,str,4); + Print_in_menu(str,2); + Num2str(height,str,4); + Print_in_menu(str,11); + } + else + Print_coordinates(); + } + + Display_all_screen(); + + x=Paintbrush_X; + y=Paintbrush_Y; + if (Snap_mode && Config.Adjust_brush_pick) + { + dx=Paintbrush_X-start_x; + dy=Paintbrush_Y-start_y; + if (dx<0) x++; else {if (dx>0) x--;} + if (dy<0) y++; else {if (dy>0) y--;} + Stretch_brush_preview(start_x,start_y,x,y); + } + else + Stretch_brush_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y); + + old_x=Paintbrush_X; + old_y=Paintbrush_Y; + Paintbrush_X=start_x; + Paintbrush_Y=start_y; + Display_cursor(); + Paintbrush_X=old_x; + Paintbrush_Y=old_y; + Display_cursor(); + + Operation_stack_size-=2; + Operation_push(x); + Operation_push(y); + + Operation_push(start_x); + Operation_push(start_y); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(2); +} + + + +void Stretch_brush_0_7(void) +// +// Opération : OPERATION_STRETCH_BRUSH +// Click Souris: 0 +// Taille_Pile : 7 +// +// Souris effacée: Non +// +{ + char str[5]; + short start_x; + short start_y; + short old_x; + short old_y; + short width=0; + short height=0; + byte size_change; + short prev_state; + + Operation_pop(&prev_state); + Operation_pop(&old_y); + Operation_pop(&old_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + + if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) + { + if (Menu_is_visible) + { + if (Config.Coords_rel) + { + width=((start_x1)?start_x+(Brush_width>>1)-1:1; + height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; + break; + case 'X': // Moitié X + width=(Brush_width>1)?start_x+(Brush_width>>1)-1:1; + height=start_y+Brush_height-1; + break; + case 'Y': // Moitié Y + width=start_x+Brush_width-1; + height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; + break; + case 'n': // Normal + width=start_x+Brush_width-1; + height=start_y+Brush_height-1; + break; + default : + size_change=0; + } + Key_ANSI=0; + } + else + size_change=0; + + if (size_change) + { + // On efface la preview de la brosse (et la croix) + Display_all_screen(); + + old_x=Paintbrush_X; + old_y=Paintbrush_Y; + Paintbrush_X=start_x; + Paintbrush_Y=start_y; + Display_cursor(); + Paintbrush_X=old_x; + Paintbrush_Y=old_y; + + Stretch_brush_preview(start_x,start_y,width,height); + Display_cursor(); + + Operation_stack_size-=2; + Operation_push(width); + Operation_push(height); + } + + Operation_push(start_x); + Operation_push(start_y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(3); +} + + +void Stretch_brush_2_7(void) +// +// Opération : OPERATION_STRETCH_BRUSH +// Click Souris: 2 +// Taille_Pile : 7 +// +// Souris effacée: Oui +// +{ + short computed_x; + short computed_y; + short start_x; + short start_y; + + + Operation_stack_size-=3; + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&computed_y); + Operation_pop(&computed_x); + + // On efface la preview de la brosse (et la croix) + Display_all_screen(); + + // Et enfin on stocke pour de bon la nouvelle brosse étirée + Stretch_brush(start_x,start_y,computed_x,computed_y); + + Return_to_draw_mode(); +} + + +//////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH + + +void Rotate_brush_12_0(void) +// +// Opération : OPERATION_ROTATE_BRUSH +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + Init_start_operation(); + if (Mouse_K==LEFT_SIDE) + { + Brush_rotation_center_X=Paintbrush_X+(Brush_width>>1)-Brush_width; + Brush_rotation_center_Y=Paintbrush_Y; + Brush_rotation_center_is_defined=1; + Operation_push(Paintbrush_X); // Dernière position calculée X + Operation_push(Paintbrush_Y); // Dernière position calculée Y + Operation_push(Paintbrush_X); // Dernière position X + Operation_push(Paintbrush_Y); // Dernière position Y + Operation_push(1); // State précédent + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("Angle: 0° ",0); + } + else + { + Start_operation_stack(Operation_before_interrupt); + Wait_end_of_click(); // FIXME: celui-la il donne un résultat pas très chouette en visuel + } +} + + + +void Rotate_brush_1_5(void) +// +// Opération : OPERATION_ROTATE_BRUSH +// Click Souris: 1 +// Taille_Pile : 5 +// +// Souris effacée: Non +// +{ + char str[4]; + short old_x; + short old_y; + short prev_state; + float angle; + int dx,dy; + + Operation_pop(&prev_state); + Operation_pop(&old_y); + Operation_pop(&old_x); + + if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=2) ) + { + if ( (Brush_rotation_center_X==Paintbrush_X) + && (Brush_rotation_center_Y==Paintbrush_Y) ) + angle=0.0; + else + { + dx=Paintbrush_X-Brush_rotation_center_X; + dy=Paintbrush_Y-Brush_rotation_center_Y; + angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); + if (dy>0) angle=M_2PI-angle; + } + + if (Menu_is_visible) + { + if (Config.Coords_rel) + { + Num2str((int)(angle*180.0/M_PI),str,3); + Print_in_menu(str,7); + } + else + Print_coordinates(); + } + + Display_all_screen(); + Rotate_brush_preview(angle); + Display_cursor(); + + Operation_stack_size-=2; + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(2); +} + + + +void Rotate_brush_0_5(void) +// +// Opération : OPERATION_ROTATE_BRUSH +// Click Souris: 0 +// Taille_Pile : 5 +// +// Souris effacée: Non +// +{ + char str[4]; + short old_x; + short old_y; + short computed_x=0; + short computed_y=0; + byte angle_change; + short prev_state; + float angle=0.0; + int dx,dy; + + Operation_pop(&prev_state); + Operation_pop(&old_y); + Operation_pop(&old_x); + + if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) + { + if ( (Brush_rotation_center_X==Paintbrush_X) + && (Brush_rotation_center_Y==Paintbrush_Y) ) + angle=0.0; + else + { + dx=Paintbrush_X-Brush_rotation_center_X; + dy=Paintbrush_Y-Brush_rotation_center_Y; + angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); + if (dy>0) angle=M_2PI-angle; + } + + if (Menu_is_visible) + { + if (Config.Coords_rel) + { + Num2str(Round(angle*180.0/M_PI),str,3); + Print_in_menu(str,7); + } + else + Print_coordinates(); + } + } + + // Utilise Key_ANSI au lieu de Key, car Get_input() met ce dernier + // à zero si une operation est en cours (Operation_stack_size!=0) + if (Key_ANSI) + { + angle_change=1; + computed_x=Brush_rotation_center_X; + computed_y=Brush_rotation_center_Y; + switch (Key_ANSI) + { + case '6': angle= 0.0 ; computed_x++; break; + case '9': angle=M_PI*0.25; computed_x++; computed_y--; break; + case '8': angle=M_PI*0.5 ; computed_y--; break; + case '7': angle=M_PI*0.75; computed_x--; computed_y--; break; + case '4': angle=M_PI ; computed_x--; break; + case '1': angle=M_PI*1.25; computed_x--; computed_y++; break; + case '2': angle=M_PI*1.5 ; computed_y++; break; + case '3': angle=M_PI*1.75; computed_x++; computed_y++; break; + default : + angle_change=0; + } + Key_ANSI=0; + } + else + angle_change=0; + + if (angle_change) + { + // On efface la preview de la brosse + Display_all_screen(); + Rotate_brush_preview(angle); + Display_cursor(); + + Operation_stack_size-=2; + Operation_push(computed_x); + Operation_push(computed_y); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(3); +} + + +void Rotate_brush_2_5(void) +// +// Opération : OPERATION_ROTATE_BRUSH +// Click Souris: 2 +// Taille_Pile : 5 +// +// Souris effacée: Oui +// +{ + short computed_x; + short computed_y; + int dx,dy; + float angle; + + + // On efface la preview de la brosse + Display_all_screen(); + + Operation_stack_size-=3; + Operation_pop(&computed_y); + Operation_pop(&computed_x); + + // Calcul de l'angle par rapport à la dernière position calculée + if ( (Brush_rotation_center_X==computed_x) + && (Brush_rotation_center_Y==computed_y) ) + angle=0.0; + else + { + dx=computed_x-Brush_rotation_center_X; + dy=computed_y-Brush_rotation_center_Y; + angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); + if (dy>0) angle=M_2PI-angle; + } + + // Et enfin on stocke pour de bon la nouvelle brosse étirée + Rotate_brush(angle); + + Return_to_draw_mode(); +} + +///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH + +/// Draws a 2x2 XOR square at the specified picture coordinates, on the screen. +void Draw_stretch_spot(short x_pos, short y_pos) +{ + short x,y; + + for (y=y_pos-1;y=Limit_top && y<=Limit_visible_bottom) + for (x=x_pos-1;x=Limit_left && x<=Limit_visible_right) + Pixel_preview(x,y,~Read_pixel(x-Main_offset_X,y-Main_offset_Y)); + Update_part_of_screen(x_pos-1, y_pos-1, 2, 2); +} + +void Distort_brush_0_0(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 0 +// Taille_Pile : 0 +// +// Souris effacée: Non +// +{ + if ( Menu_is_visible ) + { + Print_in_menu("POSITION BRUSH TO START ",0); + } +} + +void Distort_brush_1_0(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 1 +// Taille_Pile : 0 +// +// Souris effacée: Non +// +{ + short x_pos, y_pos; + + Init_start_operation(); + Paintbrush_hidden=1; + Hide_cursor(); + + // Top left angle + x_pos=Paintbrush_X-Brush_offset_X; + y_pos=Paintbrush_Y-Brush_offset_Y; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + // Top right angle + x_pos+=Brush_width; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + // Bottom right angle + y_pos+=Brush_height; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + // Bottom left angle + x_pos-=Brush_width; + Draw_stretch_spot(x_pos,y_pos); + Operation_push(x_pos); + Operation_push(y_pos); + + Distort_brush_preview( + Operation_stack[1], + Operation_stack[2], + Operation_stack[3], + Operation_stack[4], + Operation_stack[5], + Operation_stack[6], + Operation_stack[7], + Operation_stack[8]); + Display_cursor(); + Update_part_of_screen(Paintbrush_X-Brush_offset_X, Paintbrush_Y-Brush_offset_Y, Brush_width, Brush_height); + Wait_end_of_click(); + // Erase the message in status bar + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + } +} + +void Distort_brush_1_8(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 1 +// Taille_Pile : 8 +// +// Souris effacée: No +// +{ + // How far (in pixels) you can catch a handle + #define REACH_DISTANCE 100 + short i; + short x[4]; + short y[4]; + long best_distance=REACH_DISTANCE; + short best_spot=-1; + + for (i=3;i>=0;i--) + { + long distance; + Operation_pop(&y[i]); + Operation_pop(&x[i]); + distance=Distance(Paintbrush_X,Paintbrush_Y,x[i],y[i]); + if (distance-1) + { + Operation_push(best_spot); + } + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + +void Distort_brush_1_9(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 1 +// Taille_Pile : 9 +// +// Souris effacée: No +// +{ + short i; + short x[4]; + short y[4]; + short selected_corner; + + // Pop all arguments + Operation_pop(&selected_corner); + for (i=3;i>=0;i--) + { + Operation_pop(&y[i]); + Operation_pop(&x[i]); + } + + if (Paintbrush_X!=x[selected_corner] || Paintbrush_Y!=y[selected_corner]) + { + Hide_cursor(); + + // Easiest refresh mode: make no assumptions on how the brush was + // displayed before. + Display_all_screen(); + + x[selected_corner]=Paintbrush_X; + y[selected_corner]=Paintbrush_Y; + + for (i=0;i<4;i++) + Draw_stretch_spot(x[i],y[i]); + + Distort_brush_preview(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); + + Display_cursor(); + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + Update_rect(0,0,Screen_width,Menu_Y); + } + + // Push back all arguments + for (i=0;i<4;i++) + { + Operation_push(x[i]); + Operation_push(y[i]); + } + Operation_push(selected_corner); + +} +void Distort_brush_0_9(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 0 +// Taille_Pile : 9 +// +// Souris effacée: No +// +{ + short selected_corner; + Operation_pop(&selected_corner); + +} + +void Distort_brush_2_0(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + Paintbrush_hidden=0; + Display_all_screen(); + // Erase the message in status bar + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + } + Return_to_draw_mode(); +} + +void Distort_brush_2_8(void) +// +// Opération : OPERATION_DISTORT_BRUSH +// Click Souris: 2 +// Taille_Pile : 8 +// +// Souris effacée: Oui +// +{ + short i; + short x[4]; + short y[4]; + + // Pop all arguments + for (i=3;i>=0;i--) + { + Operation_pop(&y[i]); + Operation_pop(&x[i]); + } + Distort_brush(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); + + Paintbrush_hidden=0; + Display_all_screen(); + + Return_to_draw_mode(); +} + +//////////////////////////////////////////////////////////// OPERATION_SCROLL + + +byte Cursor_hidden_before_scroll; + +void Scroll_12_0(void) +// +// Opération : OPERATION_SCROLL +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +// +{ + Init_start_operation(); + Backup(); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Cursor_hidden_before_scroll=Cursor_hidden; + Cursor_hidden=1; + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); +} + + +void Scroll_12_4(void) +// +// Opération : OPERATION_SCROLL +// Click Souris: 1 ou 2 +// Taille_Pile : 4 +// +// Souris effacée: Non +// +{ + short center_x; + short center_y; + short x_pos; + short y_pos; + short x_offset; + short y_offset; + //char str[5]; + + Operation_pop(&y_pos); + Operation_pop(&x_pos); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + + if ( (Paintbrush_X!=x_pos) || (Paintbrush_Y!=y_pos) ) + { + // L'utilisateur a bougé, il faut scroller l'image + + if (Paintbrush_X>=center_x) + x_offset=(Paintbrush_X-center_x)%Main_image_width; + else + x_offset=Main_image_width-((center_x-Paintbrush_X)%Main_image_width); + + if (Paintbrush_Y>=center_y) + y_offset=(Paintbrush_Y-center_y)%Main_image_height; + else + y_offset=Main_image_height-((center_y-Paintbrush_Y)%Main_image_height); + + Display_coords_rel_or_abs(center_x,center_y); + + Scroll_picture(x_offset,y_offset); + + Display_all_screen(); + } + + Operation_push(center_x); + Operation_push(center_y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +void Scroll_0_4(void) +// +// Opération : OPERATION_SCROLL +// Click Souris: 0 +// Taille_Pile : 4 +// +// Souris effacée: Oui +// +{ + Operation_stack_size-=4; + Cursor_hidden=Cursor_hidden_before_scroll; + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + + +//////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE + + +void Grad_circle_12_0(void) +// +// Opération : OPERATION_GRAD_CIRCLE +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + byte color; + + Init_start_operation(); + Backup(); + + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; + color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; + + Paintbrush_hidden_before_scroll=Paintbrush_hidden; + Paintbrush_hidden=1; + + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("Radius: 0 ",0); + + Operation_push(Mouse_K); + Operation_push(color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Grad_circle_12_6(void) +// +// Opération : OPERATION_GRAD_CIRCLE +// Click Souris: 1 ou 2 +// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) +// +// Souris effacée: Non +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short radius; + char str[5]; + + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + Operation_pop(&color); + + if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) + { + Hide_cursor(); + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Num2str(Distance(center_x,center_y,Paintbrush_X,Paintbrush_Y),str,4); + Print_in_menu(str,7); + } + else + Print_coordinates(); + + Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ + ((tangent_y-center_y)*(tangent_y-center_y)); + radius=sqrt(Circle_limit); + Hide_empty_circle_preview(center_x,center_y,radius); + + Circle_limit=((Paintbrush_X-center_x)*(Paintbrush_X-center_x))+ + ((Paintbrush_Y-center_y)*(Paintbrush_Y-center_y)); + radius=sqrt(Circle_limit); + Draw_empty_circle_preview(center_x,center_y,radius,color); + + Display_cursor(); + } + + Operation_push(color); + Operation_push(center_x); + Operation_push(center_y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Grad_circle_0_6(void) +// +// Opération : OPERATION_GRAD_CIRCLE +// Click Souris: 0 +// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) +// +// Souris effacée: Oui +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short click; + short radius; + + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + + Operation_pop(&color); + Operation_pop(&click); + + if (click==LEFT_SIDE) + { + Operation_push(click); + Operation_push(color); + + Operation_push(center_x); + Operation_push(center_y); + Operation_push(tangent_x); + Operation_push(tangent_y); + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + + // On change la forme du curseur + Cursor_shape=CURSOR_SHAPE_XOR_TARGET; + + // On affiche une croix XOR au centre du cercle + Draw_curve_cross(center_x,center_y); + + if (Menu_is_visible) + { + if (Config.Coords_rel) + Print_in_menu("X: Y:",0); + else + Print_in_menu("X: Y: ",0); + Display_coords_rel_or_abs(center_x,center_y); + } + } + else + { + Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ + ((tangent_y-center_y)*(tangent_y-center_y)); + radius=sqrt(Circle_limit); + Hide_empty_circle_preview(center_x,center_y,radius); + + Paintbrush_hidden=Paintbrush_hidden_before_scroll; + Cursor_shape=CURSOR_SHAPE_TARGET; + + Draw_filled_circle(center_x,center_y,radius,Back_color); + + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + } +} + + +void Grad_circle_12_8(void) +// +// Opération : OPERATION_GRAD_CIRCLE +// Click Souris: 0 +// Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) +// +// Souris effacée: Oui +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short old_mouse_k; + + short radius; + + Operation_stack_size-=2; // On fait sauter les 2 derniers élts de la pile + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + Operation_pop(&color); + Operation_pop(&old_mouse_k); + + Hide_cursor(); + // On efface la croix XOR au centre du cercle + Draw_curve_cross(center_x,center_y); + + Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ + ((tangent_y-center_y)*(tangent_y-center_y)); + radius=sqrt(Circle_limit); + Hide_empty_circle_preview(center_x,center_y,radius); + + Paintbrush_hidden=Paintbrush_hidden_before_scroll; + Cursor_shape=CURSOR_SHAPE_TARGET; + + if (Mouse_K==old_mouse_k) + Draw_grad_circle(center_x,center_y,radius,Paintbrush_X,Paintbrush_Y); + + Display_cursor(); + Wait_end_of_click(); + + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + + +void Grad_circle_or_ellipse_0_8(void) +// +// Opération : OPERATION_{CERCLE|ELLIPSE}_DEGRADE +// Click Souris: 0 +// Taille_Pile : 8 +// +// Souris effacée: Non +// +{ + short start_x; + short start_y; + short tangent_x; + short tangent_y; + short old_x; + short old_y; + + Operation_pop(&old_y); + Operation_pop(&old_x); + + if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) + { + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + Display_coords_rel_or_abs(start_x,start_y); + Operation_push(start_x); + Operation_push(start_y); + Operation_push(tangent_x); + Operation_push(tangent_y); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE + + +void Grad_ellipse_12_0(void) +// +// Opération : OPERATION_GRAD_ELLIPSE +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui +{ + byte color; + + Init_start_operation(); + Backup(); + + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; + color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; + + Paintbrush_hidden_before_scroll=Paintbrush_hidden; + Paintbrush_hidden=1; + + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); + Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Mouse_K); + Operation_push(color); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Grad_ellipse_12_6(void) +// +// Opération : OPERATION_GRAD_ELLIPSE +// Click Souris: 1 ou 2 +// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) +// +// Souris effacée: Non +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short horizontal_radius; + short vertical_radius; + + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + Operation_pop(&color); + + if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) + { + Hide_cursor(); + Display_coords_rel_or_abs(center_x,center_y); + + horizontal_radius=(tangent_x>center_x)?tangent_x-center_x + :center_x-tangent_x; + vertical_radius =(tangent_y>center_y)?tangent_y-center_y + :center_y-tangent_y; + Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); + + horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x + :center_x-Paintbrush_X; + vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y + :center_y-Paintbrush_Y; + Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); + + Display_cursor(); + } + + Operation_push(color); + Operation_push(center_x); + Operation_push(center_y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Grad_ellipse_0_6(void) +// +// Opération : OPERATION_GRAD_ELLIPSE +// Click Souris: 0 +// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) +// +// Souris effacée: Oui +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short click; + //short radius; + short horizontal_radius; + short vertical_radius; + + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + + Operation_pop(&color); + Operation_pop(&click); + + if (click==LEFT_SIDE) + { + Operation_push(click); + Operation_push(color); + + Operation_push(center_x); + Operation_push(center_y); + Operation_push(tangent_x); + Operation_push(tangent_y); + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + + // On change la forme du curseur + Cursor_shape=CURSOR_SHAPE_XOR_TARGET; + + // On affiche une croix XOR au centre du cercle + Draw_curve_cross(center_x,center_y); + + if (Menu_is_visible) + { + if (Config.Coords_rel) + Print_in_menu("X: Y:",0); + else + Print_in_menu("X: Y: ",0); + Display_coords_rel_or_abs(center_x,center_y); + } + } + else + { + horizontal_radius=(tangent_x>center_x)?tangent_x-center_x + :center_x-tangent_x; + vertical_radius =(tangent_y>center_y)?tangent_y-center_y + :center_y-tangent_y; + Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); + + Paintbrush_hidden=Paintbrush_hidden_before_scroll; + Cursor_shape=CURSOR_SHAPE_TARGET; + + Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Back_color); + + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + } +} + + +void Grad_ellipse_12_8(void) +// +// Opération : OPERATION_GRAD_ELLIPSE +// Click Souris: 0 +// Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) +// +// Souris effacée: Oui +// +{ + short tangent_x; + short tangent_y; + short center_x; + short center_y; + short color; + short horizontal_radius; + short vertical_radius; + short old_mouse_k; + + Operation_stack_size-=2; // On fait sauter les 2 derniers élts de la pile + Operation_pop(&tangent_y); + Operation_pop(&tangent_x); + Operation_pop(¢er_y); + Operation_pop(¢er_x); + Operation_pop(&color); + Operation_pop(&old_mouse_k); + + Hide_cursor(); + // On efface la croix XOR au centre de l'ellipse + Draw_curve_cross(center_x,center_y); + + horizontal_radius=(tangent_x>center_x)?tangent_x-center_x + :center_x-tangent_x; + vertical_radius =(tangent_y>center_y)?tangent_y-center_y + :center_y-tangent_y; + Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); + + Paintbrush_hidden=Paintbrush_hidden_before_scroll; + Cursor_shape=CURSOR_SHAPE_TARGET; + + if (Mouse_K==old_mouse_k) + Draw_grad_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Paintbrush_X,Paintbrush_Y); + + Display_cursor(); + + Wait_end_of_click(); + + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} + +/****************************** +* Operation_Rectangle_Degrade * +******************************/ + +// 1) tracé d'un rectangle classique avec les lignes XOR +// 2) tracé d'une ligne vecteur de dégradé, comme une ligne normale +// 3) dessin du dégradé + + +void Grad_rectangle_12_0(void) +// Opération : OPERATION_GRAD_RECTANGLE +// Click Souris: 1 ou 2 +// Taille_Pile : 0 +// +// Souris effacée: Oui + +// Initialisation de l'étape 1, on commence à dessiner le rectangle +{ + Init_start_operation(); + Backup(); + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("\035: 1 \022: 1",0); + // On laisse une trace du curseur à l'écran + Display_cursor(); + + if (Mouse_K==LEFT_SIDE) + { + Shade_table=Shade_table_left; + Operation_push(Mouse_K); + } + else + { + Shade_table=Shade_table_right; + Operation_push(Mouse_K); + } + + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Grad_rectangle_12_5(void) +// Opération : OPERATION_GRAD_RECTANGLE +// Click Souris: 1 ou 2 +// Taille_Pile : 5 +// +// Souris effacée: Non + +// Modification de la taille du rectangle +{ + short start_x; + short start_y; + short old_x; + short old_y; + char str[5]; + + Operation_pop(&old_y); + Operation_pop(&old_x); + + if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) + { + Operation_pop(&start_y); + Operation_pop(&start_x); + + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Num2str(((start_x Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width)) // Tous les clippings à gérer sont là + offset_width = Max(rax,rbx) - Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width); + + if (Max(ray,rby)-Main_offset_Y > Min(Main_image_height,Menu_Y)) + offset_height = Max(ray,rby) - Min(Main_image_height,Menu_Y); + + // Dessin dans la zone de dessin normale + Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width - offset_width); + if(offset_height == 0) + Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Max(ray,rby)-1-Main_offset_Y,width - offset_width); + + Vertical_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); + if (offset_width == 0) // Sinon cette ligne est en dehors de la zone image, inutile de la dessiner + Vertical_XOR_line(Max(rax,rbx)-1-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); + + Update_rect(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width+1-offset_width,height+1-offset_height); + + // Dessin dans la zone zoomée + if(Main_magnifier_mode && Min(rax,rbx)Limit_left_zoom && Min(ray,rby)Limit_top_zoom ) + { + offset_width = 0; + offset_height=0; + + if(Min(rax,rbx)Limit_visible_right_zoom) // On dépasse du zoom à droite + offset_width += Max(rax,rbx) - Limit_visible_right_zoom; + + if(Min(ray,rby)Limit_visible_bottom_zoom) // On dépasse du zoom en bas + offset_height += Max(ray,rby) - Limit_visible_bottom_zoom; + + if(width > offset_width) + { + if(offset_top==0) // La ligne du haut est visible + Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rax,rbx),Min(ray,rby),width-offset_width); + + if(Max(ray,rby)0?offset_left:Min(rax,rbx),Max(ray,rby),width-offset_width); + } + + if(height>offset_height) + { + if(offset_left==0) // La ligne de gauche est visible + Vertical_XOR_line_zoom(Min(rax,rbx),offset_top>0?offset_top:Min(ray,rby),height-offset_height); + + if(Max(rax,rbx)0?offset_top:Min(ray,rby),height-offset_height); + } + } + + Operation_push(rax); + Operation_push(ray); + Operation_push(rbx); + Operation_push(rby); + + // On ajoute des trucs dans la pile pour forcer le passage à l'étape suivante + Operation_push(rbx); + Operation_push(rby); +} + +void Grad_rectangle_0_7(void) +// OPERATION_GRAD_RECTANGLE +// click souris 0 +// Taile pile : 5 +// +// Souris effacée : non + +// On continue à attendre que l'utilisateur clique en gardant les coords à jour +{ + Operation_stack_size -= 2; + Print_coordinates(); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + +void Grad_rectangle_12_7(void) +// Opération : OPERATION_GRAD_RECTANGLE +// Click Souris: 1 ou 2 +// Taille_Pile : 7 +// +// Souris effacée: Oui + +// Début du tracé du vecteur (premier clic) +// On garde les anciennes coordonnées dans la pile, et on ajoute les nouvelles par dessus + +// Si l'utilisateur utilise le mauvais bouton, on annule le tracé. Mais ça nous oblige à vider toute la pile pour vérifier :( +{ + short rax,rbx,ray,rby,vax,vay,click; + + Operation_pop(&vay); + Operation_pop(&vax); + Operation_pop(&ray); + Operation_pop(&rax); + Operation_pop(&rby); + Operation_pop(&rbx); + Operation_pop(&click); + + + if(click==Mouse_K) + { + Operation_push(click); + Operation_push(rbx); + Operation_push(rby); + Operation_push(rax); + Operation_push(ray); + Operation_push(vax); + Operation_push(vay); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + + } + else + { + // Mauvais bouton > anulation de l'opération. + // On a déjà vidé la pile, il reste à effacer le rectangle XOR + short width, height; + short offset_width = 0; + short offset_height = 0; + short offset_left = 0; + short offset_top = 0; + + width = abs(rbx-rax); + height = abs(rby-ray); + + if (Max(rax,rbx)-Main_offset_X > Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width)) // Tous les clippings à gérer sont là + offset_width = Max(rax,rbx) - Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width); + + if (Max(ray,rby)-Main_offset_Y > Min(Main_image_height,Menu_Y)) + offset_height = Max(ray,rby) - Min(Main_image_height,Menu_Y); + + // Dessin dans la zone de dessin normale + Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width - offset_width); + if(offset_height == 0) + Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Max(ray,rby)-1-Main_offset_Y,width - offset_width); + + Vertical_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); + if (offset_width == 0) // Sinon cette ligne est en dehors de la zone image, inutile de la dessiner + Vertical_XOR_line(Max(rax,rbx)-1-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); + + Update_rect(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width+1-offset_width,height+1-offset_height); + + // Dessin dans la zone zoomée + if(Main_magnifier_mode && Min(rax,rbx)Limit_left_zoom && Min(ray,rby)Limit_top_zoom ) + { + offset_width = 0; + offset_height=0; + + if(Min(rax,rbx)Limit_visible_right_zoom) // On dépasse du zoom à droite + offset_width += Max(rax,rbx) - Limit_visible_right_zoom; + + if(Min(ray,rby)Limit_visible_bottom_zoom) // On dépasse du zoom en bas + offset_height += Max(ray,rby) - Limit_visible_bottom_zoom; + + if(width > offset_width) + { + if(offset_top==0) // La ligne du haut est visible + Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rax,rbx),Min(ray,rby),width-offset_width); + + if(Max(ray,rby)0?offset_left:Min(rax,rbx),Max(ray,rby),width-offset_width); + } + + if(height>offset_height) + { + if(offset_left==0) // La ligne de gauche est visible + Vertical_XOR_line_zoom(Min(rax,rbx),offset_top>0?offset_top:Min(ray,rby),height-offset_height); + + if(Max(rax,rbx)0?offset_top:Min(ray,rby),height-offset_height); + } + } + } +} + +void Grad_rectangle_12_9(void) + // Opération : OPERATION_GRAD_RECTANGLE + // Click Souris: 1 + // Taille_Pile : 5 + // + // Souris effacée: Oui + + // Poursuite du tracé du vecteur (déplacement de la souris en gardant le curseur appuyé) +{ + short start_x; + short start_y; + short end_x; + short end_y; + short cursor_x; + short cursor_y; + + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + + cursor_x = Paintbrush_X; + cursor_y = Paintbrush_Y; + // 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); + + if ((cursor_x!=end_x) || (cursor_y!=end_y)) + { + Display_coords_rel_or_abs(start_x,start_y); + + Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); + Draw_line_preview_xor(start_x,start_y,cursor_x,cursor_y,0); + + } + + + Operation_push(start_x); + Operation_push(start_y); + Operation_push(cursor_x); + Operation_push(cursor_y); +} + +void Grad_rectangle_0_9(void) + // Opération : OPERATION_GRAD_RECTANGLE + // Click Souris: 0 + // Taille_Pile : 9 + // + // Souris effacée: Oui + + // Ouf, fini ! on dessine enfin le rectangle avec son dégradé +{ + short rect_start_x; + short rect_start_y; + short rect_end_x; + short rect_end_y; + + short vector_start_x; + short vector_start_y; + short vector_end_x; + short vector_end_y; + + Operation_pop(&vector_end_y); + Operation_pop(&vector_end_x); + Operation_pop(&vector_start_y); + Operation_pop(&vector_start_x); + Operation_pop(&rect_end_y); + Operation_pop(&rect_end_x); + Operation_pop(&rect_start_y); + Operation_pop(&rect_start_x); + Operation_stack_size--; + + Hide_cursor(); + // Maintenant on efface tout le bazar temporaire : rectangle et ligne XOR + Hide_line_preview(vector_start_x,vector_start_y,vector_end_x,vector_end_y); + + // Et enfin on trace le rectangle avec le dégradé dedans ! + if (vector_end_x==vector_start_x && vector_end_y==vector_start_y) + { + // Vecteur nul > pas de rectangle tracé + // Du coup on doit effacer la preview xor ... + short width, height; + short offset_width = 0; + short offset_height = 0; + short offset_left = 0; + short offset_top = 0; + + width = abs(rect_end_x-rect_start_x); + height = abs(rect_end_y-rect_start_y); + + if (Max(rect_start_x,rect_end_x)-Main_offset_X > Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width)) // Tous les clippings à gérer sont là + offset_width = Max(rect_start_x,rect_end_x) - Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width); + + if (Max(rect_start_y,rect_end_y)-Main_offset_Y > Min(Main_image_height,Menu_Y)) + offset_height = Max(rect_start_y,rect_end_y) - Min(Main_image_height,Menu_Y); + + // Dessin dans la zone de dessin normale + Horizontal_XOR_line(Min(rect_start_x,rect_end_x)-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,width - offset_width); + if(offset_height == 0) + Horizontal_XOR_line(Min(rect_start_x,rect_end_x)-Main_offset_X,Max(rect_start_y,rect_end_y)-1-Main_offset_Y,width - offset_width); + + Vertical_XOR_line(Min(rect_start_x,rect_end_x)-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,height-offset_height); + if (offset_width == 0) // Sinon cette ligne est en dehors de la zone image, inutile de la dessiner + Vertical_XOR_line(Max(rect_start_x,rect_end_x)-1-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,height-offset_height); + + Update_rect(Min(rect_start_x,rect_end_x)-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,width+1-offset_width,height+1-offset_height); + + // Dessin dans la zone zoomée + if(Main_magnifier_mode && Min(rect_start_x,rect_end_x)Limit_left_zoom && Min(rect_start_y,rect_end_y)Limit_top_zoom ) + { + offset_width = 0; + offset_height=0; + + if(Min(rect_start_x,rect_end_x)Limit_visible_right_zoom) // On dépasse du zoom à droite + offset_width += Max(rect_start_x,rect_end_x) - Limit_visible_right_zoom; + + if(Min(rect_start_y,rect_end_y)Limit_visible_bottom_zoom) // On dépasse du zoom en bas + offset_height += Max(rect_start_y,rect_end_y) - Limit_visible_bottom_zoom; + + if(width > offset_width) + { + if(offset_top==0) // La ligne du haut est visible + Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rect_start_x,rect_end_x),Min(rect_start_y,rect_end_y),width-offset_width); + + if(Max(rect_start_y,rect_end_y)0?offset_left:Min(rect_start_x,rect_end_x),Max(rect_start_y,rect_end_y),width-offset_width); + } + + if(height>offset_height) + { + if(offset_left==0) // La ligne de gauche est visible + Vertical_XOR_line_zoom(Min(rect_start_x,rect_end_x),offset_top>0?offset_top:Min(rect_start_y,rect_end_y),height-offset_height); + + if(Max(rect_start_x,rect_end_x)0?offset_top:Min(rect_start_y,rect_end_y),height-offset_height); + } + } + } + else + Draw_grad_rectangle(rect_start_x,rect_start_y,rect_end_x,rect_end_y,vector_start_x,vector_start_y,vector_end_x,vector_end_y); + + Display_cursor(); + Wait_end_of_click(); + + if ((Config.Coords_rel) && (Menu_is_visible)) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } +} +/////////////////////////////////////////////////// OPERATION_CENTERED_LINES + + +void Centered_lines_12_0(void) + // Opération : OPERATION_CENTERED_LINES + // Click Souris: 1 ou 2 + // Taille_Pile : 0 + // + // Souris effacée: Oui +{ + Init_start_operation(); + Backup(); + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; + + if ((Config.Coords_rel) && (Menu_is_visible)) + Print_in_menu("X:± 0 Y:± 0",0); + + Operation_push(Mouse_K); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Centered_lines_12_3(void) + // Opération : OPERATION_CENTERED_LINES + // Click Souris: 1 ou 2 + // Taille_Pile : 3 + // + // Souris effacée: Non +{ + short start_x; + short start_y; + + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + +void Centered_lines_0_3(void) + // Opération : OPERATION_CENTERED_LINES + // Click Souris: 0 + // Taille_Pile : 3 + // + // Souris effacée: Oui +{ + short start_x; + short start_y; + short Button; + short color; + + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&Button); + + color=(Button==LEFT_SIDE)?Fore_color:Back_color; + + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); + Paintbrush_shape_before_operation=Paintbrush_shape; + Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; + + Operation_push(Button); + Operation_push(Paintbrush_X); // Nouveau début X + Operation_push(Paintbrush_Y); // Nouveau début Y + Operation_push(Paintbrush_X); // Nouvelle dernière fin X + Operation_push(Paintbrush_Y); // Nouvelle dernière fin Y + Operation_push(Paintbrush_X); // Nouvelle dernière position X + Operation_push(Paintbrush_Y); // Nouvelle dernière position Y +} + + +void Centered_lines_12_7(void) + // Opération : OPERATION_CENTERED_LINES + // Click Souris: 1 ou 2 + // Taille_Pile : 7 + // + // Souris effacée: Non +{ + short Button; + short start_x; + short start_y; + short end_x; + short end_y; + short last_x; + short last_y; + short color; + + Operation_pop(&last_y); + Operation_pop(&last_x); + Operation_pop(&end_y); + Operation_pop(&end_x); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&Button); + + if (Mouse_K==Button) + { + if ( (end_x!=Paintbrush_X) || (end_y!=Paintbrush_Y) || + (last_x!=Paintbrush_X) || (last_y!=Paintbrush_Y) ) + { + Hide_cursor(); + + color=(Button==LEFT_SIDE)?Fore_color:Back_color; + + Paintbrush_shape=Paintbrush_shape_before_operation; + + Pixel_figure_preview_auto (start_x,start_y); + Hide_line_preview (start_x,start_y,last_x,last_y); + + Smear_start=1; + Display_paintbrush (start_x,start_y,color,0); + Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + + Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; + Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); + Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + + Display_cursor(); + } + + Operation_push(Button); + Operation_push(start_x); + Operation_push(start_y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); + } + else + { + Hide_cursor(); + + Paintbrush_shape=Paintbrush_shape_before_operation; + + Pixel_figure_preview_auto (start_x,start_y); + Hide_line_preview (start_x,start_y,last_x,last_y); + + if ( (Config.Coords_rel) && (Menu_is_visible) ) + { + Print_in_menu("X: Y: ",0); + Print_coordinates(); + } + + Display_cursor(); + Wait_end_of_click(); + } +} + + +void Centered_lines_0_7(void) + // Opération : OPERATION_CENTERED_LINES + // Click Souris: 0 + // Taille_Pile : 7 + // + // Souris effacée: Non +{ + short Button; + short start_x; + short start_y; + short end_x; + short end_y; + short last_x; + short last_y; + short color; + + Operation_pop(&last_y); + Operation_pop(&last_x); + Operation_pop(&end_y); + Operation_pop(&end_x); + + if ((Paintbrush_X!=last_x) || (Paintbrush_Y!=last_y)) + { + Hide_cursor(); + Operation_pop(&start_y); + Operation_pop(&start_x); + Operation_pop(&Button); + + color=(Button==LEFT_SIDE)?Fore_color:Back_color; + + Display_coords_rel_or_abs(start_x,start_y); + + Hide_line_preview(start_x,start_y,last_x,last_y); + + Pixel_figure_preview(start_x,start_y,color); + Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + + Operation_push(Button); + Operation_push(start_x); + Operation_push(start_y); + Display_cursor(); + } + + Operation_push(end_x); + Operation_push(end_y); + Operation_push(Paintbrush_X); + Operation_push(Paintbrush_Y); +} + + diff --git a/operatio.h b/operatio.h index 89428cca..41f6f133 100644 --- a/operatio.h +++ b/operatio.h @@ -1,219 +1,219 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file operatio.h -/// Code for the operations, ie all drawing tools. -////////////////////////////////////////////////////////////////////////////// - -/// Do some housekeeping before starting work on a operation. -void Start_operation_stack(word new_operation); -/// Put a value on ::Operation_stack -void Operation_push(short value); -/// Take a value off ::Operation_stack -void Operation_pop(short * value); - -//////////////////////////////////////////////////// OPERATION_CONTINUOUS_DRAW -void Freehand_mode1_1_0(void); -void Freehand_mode1_1_2(void); -void Freehand_mode12_0_2(void); -void Freehand_mode1_2_0(void); -void Freehand_mode1_2_2(void); - -///////////////////////////////////////////////// OPERATION_DISCONTINUOUS_DRAW -void Freehand_mode2_1_0(void); -void Freehand_mode2_1_2(void); -void Freehand_mode2_2_0(void); -void Freehand_mode2_2_2(void); - -////////////////////////////////////////////////////// OPERATION_POINT_DRAW -void Freehand_mode3_1_0(void); -void Freehand_Mode3_2_0(void); -void Freehand_mode3_0_1(void); - -///////////////////////////////////////////////////////////// OPERATION_LINE - -void Line_12_0(void); -void Line_12_5(void); -void Line_0_5(void); - -///////////////////////////////////////////////////////////// OPERATION_MAGNIFY - -void Magnifier_12_0(void); - -/////////////////////////////////////////////////// OPERATION_RECTANGLE_????? - -void Rectangle_12_0(void); -void Rectangle_12_5(void); -void Empty_rectangle_0_5(void); -void Filled_rectangle_0_5(void); - -////////////////////////////////////////////////////// OPERATION_CERCLE_????? - -void Circle_12_0(void); -void Circle_12_5(void); -void Empty_circle_0_5(void); -void Filled_circle_0_5(void); - -///////////////////////////////////////////////////// OPERATION_ELLIPSE_????? - -void Ellipse_12_0(void); -void Ellipse_12_5(void); -void Empty_ellipse_0_5(void); -void Filled_ellipse_0_5(void); - -////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH - -void Brush_12_0(void); -void Brush_12_5(void); -void Brush_0_5(void); - -///////////////////////////////////////////////////// OPERATION_STRETCH_BRUSH - -void Stretch_brush_12_0(void); -void Stretch_brush_1_7(void); -void Stretch_brush_0_7(void); -void Stretch_brush_2_7(void); - -//////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH - -void Rotate_brush_12_0(void); -void Rotate_brush_1_5(void); -void Rotate_brush_0_5(void); -void Rotate_brush_2_5(void); - -///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH - -void Distort_brush_0_0(void); -void Distort_brush_1_0(void); -void Distort_brush_2_0(void); -void Distort_brush_1_8(void); -void Distort_brush_2_8(void); -void Distort_brush_1_9(void); -void Distort_brush_0_9(void); - -//////////////////////////////////////////////////////// OPERATION_POLYBRUSH - -void Polybrush_12_8(void); - -////////////////////////////////////////////////////////////// OPERATION_FILL - -void Fill_1_0(void); -void Fill_2_0(void); - -///////////////////////////////////////////////////////// OPERATION_REPLACE - -void Replace_1_0(void); -void Replace_2_0(void); - -/////////////////////////////////////////////////////////// OPERATION_COLORPICK - -void Pipette_0_0(void); -void Colorpicker_12_0(void); -void Colorpicker_1_1(void); -void Colorpicker_2_1(void); -void Colorpicker_0_1(void); - -/////////////////////////////////////////////////////////// OPERATION_K_LIGNE - -void K_line_12_0(void); -void K_line_12_6(void); -void K_line_0_6(void); -void K_line_12_7(void); - -/////////////////////////////////////////////////// OPERATION_COURBE_?_POINTS - -void Curve_34_points_1_0(void); -void Curve_34_points_2_0(void); -void Curve_34_points_1_5(void); -void Curve_34_points_2_5(void); - -void Curve_4_points_0_5(void); -void Curve_4_points_1_9(void); -void Curve_4_points_2_9(void); - -void Curve_3_points_0_5(void); -void Curve_3_points_0_11(void); -void Curve_3_points_12_11(void); - -///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH - -void Airbrush_1_0(void); -void Airbrush_2_0(void); -void Airbrush_12_2(void); -void Airbrush_0_2(void); - -//////////////////////////////////////////////////////////// OPERATION_*POLY* - -void Polygon_12_0(void); -void Polygon_12_9(void); - -void Polyfill_12_0(void); -void Polyfill_0_8(void); -void Polyfill_12_8(void); -void Polyfill_12_9(void); - -void Polyform_12_0(void); -void Polyform_12_8(void); -void Polyform_0_8(void); - -void Filled_polyform_12_0(void); -void Filled_polyform_12_8(void); -void Filled_polyform_0_8(void); -void Filled_contour_0_8(void); - -//////////////////////////////////////////////////////////// OPERATION_SCROLL - -void Scroll_12_0(void); -void Scroll_12_4(void); -void Scroll_0_4(void); - -//////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE - -void Grad_circle_12_0(void); -void Grad_circle_12_6(void); -void Grad_circle_0_6(void); -void Grad_circle_12_8(void); -void Grad_circle_or_ellipse_0_8(void); - -////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE - -void Grad_ellipse_12_0(void); -void Grad_ellipse_12_6(void); -void Grad_ellipse_0_6(void); -void Grad_ellipse_12_8(void); - -///////////////////////////////////////////////// OPERATION_GRAD_RECTANGLE - -void Grad_rectangle_12_0(void); -void Grad_rectangle_12_5(void); -void Grad_rectangle_0_5(void); -void Grad_rectangle_0_7(void); -void Grad_rectangle_12_7(void); -void Grad_rectangle_12_9(void); -void Grad_rectangle_0_9(void); - -/////////////////////////////////////////////////// OPERATION_CENTERED_LINES - -void Centered_lines_12_0(void); -void Centered_lines_12_3(void); -void Centered_lines_0_3(void); -void Centered_lines_12_7(void); -void Centered_lines_0_7(void); - +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file operatio.h +/// Code for the operations, ie all drawing tools. +////////////////////////////////////////////////////////////////////////////// + +/// Do some housekeeping before starting work on a operation. +void Start_operation_stack(word new_operation); +/// Put a value on ::Operation_stack +void Operation_push(short value); +/// Take a value off ::Operation_stack +void Operation_pop(short * value); + +//////////////////////////////////////////////////// OPERATION_CONTINUOUS_DRAW +void Freehand_mode1_1_0(void); +void Freehand_mode1_1_2(void); +void Freehand_mode12_0_2(void); +void Freehand_mode1_2_0(void); +void Freehand_mode1_2_2(void); + +///////////////////////////////////////////////// OPERATION_DISCONTINUOUS_DRAW +void Freehand_mode2_1_0(void); +void Freehand_mode2_1_2(void); +void Freehand_mode2_2_0(void); +void Freehand_mode2_2_2(void); + +////////////////////////////////////////////////////// OPERATION_POINT_DRAW +void Freehand_mode3_1_0(void); +void Freehand_Mode3_2_0(void); +void Freehand_mode3_0_1(void); + +///////////////////////////////////////////////////////////// OPERATION_LINE + +void Line_12_0(void); +void Line_12_5(void); +void Line_0_5(void); + +///////////////////////////////////////////////////////////// OPERATION_MAGNIFY + +void Magnifier_12_0(void); + +/////////////////////////////////////////////////// OPERATION_RECTANGLE_????? + +void Rectangle_12_0(void); +void Rectangle_12_5(void); +void Empty_rectangle_0_5(void); +void Filled_rectangle_0_5(void); + +////////////////////////////////////////////////////// OPERATION_CERCLE_????? + +void Circle_12_0(void); +void Circle_12_5(void); +void Empty_circle_0_5(void); +void Filled_circle_0_5(void); + +///////////////////////////////////////////////////// OPERATION_ELLIPSE_????? + +void Ellipse_12_0(void); +void Ellipse_12_5(void); +void Empty_ellipse_0_5(void); +void Filled_ellipse_0_5(void); + +////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH + +void Brush_12_0(void); +void Brush_12_5(void); +void Brush_0_5(void); + +///////////////////////////////////////////////////// OPERATION_STRETCH_BRUSH + +void Stretch_brush_12_0(void); +void Stretch_brush_1_7(void); +void Stretch_brush_0_7(void); +void Stretch_brush_2_7(void); + +//////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH + +void Rotate_brush_12_0(void); +void Rotate_brush_1_5(void); +void Rotate_brush_0_5(void); +void Rotate_brush_2_5(void); + +///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH + +void Distort_brush_0_0(void); +void Distort_brush_1_0(void); +void Distort_brush_2_0(void); +void Distort_brush_1_8(void); +void Distort_brush_2_8(void); +void Distort_brush_1_9(void); +void Distort_brush_0_9(void); + +//////////////////////////////////////////////////////// OPERATION_POLYBRUSH + +void Polybrush_12_8(void); + +////////////////////////////////////////////////////////////// OPERATION_FILL + +void Fill_1_0(void); +void Fill_2_0(void); + +///////////////////////////////////////////////////////// OPERATION_REPLACE + +void Replace_1_0(void); +void Replace_2_0(void); + +/////////////////////////////////////////////////////////// OPERATION_COLORPICK + +void Pipette_0_0(void); +void Colorpicker_12_0(void); +void Colorpicker_1_1(void); +void Colorpicker_2_1(void); +void Colorpicker_0_1(void); + +/////////////////////////////////////////////////////////// OPERATION_K_LIGNE + +void K_line_12_0(void); +void K_line_12_6(void); +void K_line_0_6(void); +void K_line_12_7(void); + +/////////////////////////////////////////////////// OPERATION_COURBE_?_POINTS + +void Curve_34_points_1_0(void); +void Curve_34_points_2_0(void); +void Curve_34_points_1_5(void); +void Curve_34_points_2_5(void); + +void Curve_4_points_0_5(void); +void Curve_4_points_1_9(void); +void Curve_4_points_2_9(void); + +void Curve_3_points_0_5(void); +void Curve_3_points_0_11(void); +void Curve_3_points_12_11(void); + +///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH + +void Airbrush_1_0(void); +void Airbrush_2_0(void); +void Airbrush_12_2(void); +void Airbrush_0_2(void); + +//////////////////////////////////////////////////////////// OPERATION_*POLY* + +void Polygon_12_0(void); +void Polygon_12_9(void); + +void Polyfill_12_0(void); +void Polyfill_0_8(void); +void Polyfill_12_8(void); +void Polyfill_12_9(void); + +void Polyform_12_0(void); +void Polyform_12_8(void); +void Polyform_0_8(void); + +void Filled_polyform_12_0(void); +void Filled_polyform_12_8(void); +void Filled_polyform_0_8(void); +void Filled_contour_0_8(void); + +//////////////////////////////////////////////////////////// OPERATION_SCROLL + +void Scroll_12_0(void); +void Scroll_12_4(void); +void Scroll_0_4(void); + +//////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE + +void Grad_circle_12_0(void); +void Grad_circle_12_6(void); +void Grad_circle_0_6(void); +void Grad_circle_12_8(void); +void Grad_circle_or_ellipse_0_8(void); + +////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE + +void Grad_ellipse_12_0(void); +void Grad_ellipse_12_6(void); +void Grad_ellipse_0_6(void); +void Grad_ellipse_12_8(void); + +///////////////////////////////////////////////// OPERATION_GRAD_RECTANGLE + +void Grad_rectangle_12_0(void); +void Grad_rectangle_12_5(void); +void Grad_rectangle_0_5(void); +void Grad_rectangle_0_7(void); +void Grad_rectangle_12_7(void); +void Grad_rectangle_12_9(void); +void Grad_rectangle_0_9(void); + +/////////////////////////////////////////////////// OPERATION_CENTERED_LINES + +void Centered_lines_12_0(void); +void Centered_lines_12_3(void); +void Centered_lines_0_3(void); +void Centered_lines_12_7(void); +void Centered_lines_0_7(void); + diff --git a/pages.h b/pages.h index efc816e5..a85a03f7 100644 --- a/pages.h +++ b/pages.h @@ -1,93 +1,93 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pages.h -/// Handler for the Undo/Redo system. -////////////////////////////////////////////////////////////////////////////// - -#ifndef _PAGES_H_ -#define _PAGES_H_ - - -////////////////////////////////////////////////////////////////////////// -/////////////////////////// GESTION DU BACKUP //////////////////////////// -////////////////////////////////////////////////////////////////////////// - - - /// - /// GESTION DES PAGES - /// - -void Init_page(T_Page * page); -void Download_infos_page_main(T_Page * page); -void Upload_infos_page_main(T_Page * page); -void Download_infos_page_spare(T_Page * page); -void Upload_infos_page_spare(T_Page * page); -void Download_infos_backup(T_List_of_pages * list); -void Free_a_page(T_Page * page); -void Copy_S_page(T_Page * dest,T_Page * source); -int Size_of_a_page(T_Page * page); - - - - /// - /// GESTION DES LISTES DE PAGES - /// - -void Init_list_of_pages(T_List_of_pages * list); -int Allocate_list_of_pages(T_List_of_pages * list,int size); -void Free_a_list_of_pages(T_List_of_pages * list); -int Size_of_a_list_of_pages(T_List_of_pages * list); -void Backward_in_list_of_pages(T_List_of_pages * list); -void Advance_in_list_of_pages(T_List_of_pages * list); -int New_page_is_possible(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list); -void Free_last_page_of_list(T_List_of_pages * list); -void Create_new_page(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list); -void Change_page_number_of_list(T_List_of_pages * list,int number); -void Free_page_of_a_list(T_List_of_pages * list); - - - - /// - /// GESTION DES BACKUPS - /// - -int Init_all_backup_lists(int size,int width,int height); -void Set_number_of_backups(int nb_backups); -int Backup_with_new_dimensions(int upload,int width,int height); -int Backup_and_resize_the_spare(int width,int height); -void Backup(void); -void Undo(void); -void Redo(void); -void Free_current_page(void); -void Exchange_main_and_spare(void); - - - - /// - /// GESTION DES EMPRUNTS DE MEMOIRE DE PAGE - /// - -int Can_borrow_memory_from_page(int size); -void * Borrow_memory_from_page(int size); - - - -#endif +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pages.h +/// Handler for the Undo/Redo system. +////////////////////////////////////////////////////////////////////////////// + +#ifndef _PAGES_H_ +#define _PAGES_H_ + + +////////////////////////////////////////////////////////////////////////// +/////////////////////////// GESTION DU BACKUP //////////////////////////// +////////////////////////////////////////////////////////////////////////// + + + /// + /// GESTION DES PAGES + /// + +void Init_page(T_Page * page); +void Download_infos_page_main(T_Page * page); +void Upload_infos_page_main(T_Page * page); +void Download_infos_page_spare(T_Page * page); +void Upload_infos_page_spare(T_Page * page); +void Download_infos_backup(T_List_of_pages * list); +void Free_a_page(T_Page * page); +void Copy_S_page(T_Page * dest,T_Page * source); +int Size_of_a_page(T_Page * page); + + + + /// + /// GESTION DES LISTES DE PAGES + /// + +void Init_list_of_pages(T_List_of_pages * list); +int Allocate_list_of_pages(T_List_of_pages * list,int size); +void Free_a_list_of_pages(T_List_of_pages * list); +int Size_of_a_list_of_pages(T_List_of_pages * list); +void Backward_in_list_of_pages(T_List_of_pages * list); +void Advance_in_list_of_pages(T_List_of_pages * list); +int New_page_is_possible(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list); +void Free_last_page_of_list(T_List_of_pages * list); +void Create_new_page(T_Page * new_page,T_List_of_pages * current_list,T_List_of_pages * secondary_list); +void Change_page_number_of_list(T_List_of_pages * list,int number); +void Free_page_of_a_list(T_List_of_pages * list); + + + + /// + /// GESTION DES BACKUPS + /// + +int Init_all_backup_lists(int size,int width,int height); +void Set_number_of_backups(int nb_backups); +int Backup_with_new_dimensions(int upload,int width,int height); +int Backup_and_resize_the_spare(int width,int height); +void Backup(void); +void Undo(void); +void Redo(void); +void Free_current_page(void); +void Exchange_main_and_spare(void); + + + + /// + /// GESTION DES EMPRUNTS DE MEMOIRE DE PAGE + /// + +int Can_borrow_memory_from_page(int size); +void * Borrow_memory_from_page(int size); + + + +#endif diff --git a/palette.c b/palette.c index 4b083c66..ce00dd00 100644 --- a/palette.c +++ b/palette.c @@ -1,2302 +1,2302 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "engine.h" -#include "readline.h" -#include "buttons.h" -#include "pages.h" -#include "help.h" -#include "sdlscreen.h" -#include "errors.h" -#include "op_c.h" -#include "windows.h" -#include "input.h" -#include "palette.h" -#include "shade.h" - -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" -}; - -// Nombre de graduations pour une composante RGB -int RGB_scale = 256; // 24bit -//int RGB_scale = 64; // VGA -//int RGB_scale = 16; // Amiga -//int RGB_scale = 4; // MSX2 -//int RGB_scale = 3; // Amstrad CPC - -// Nombre de graduations pour une composante dans le mode actuel -int Color_count=256; -// Les composantes vont de 0 à (Color_count-1) -int Color_max=255; -// Le demi-pas est une quantité que l'on ajoute à une composante -// avant de faire un arrondi par division. -int Color_halfstep=0; - - -void Set_palette_RGB_scale(int scale) -{ - if (scale>= 2 && scale <= 256) - RGB_scale = scale; -} - -byte Round_palette_component(byte comp) -{ - return ((comp+128/RGB_scale)*(RGB_scale-1)/255*255+(RGB_scale&1?1:0))/(RGB_scale-1); -} - -// Définir les unités pour les graduations R G B ou H S V -void Componant_unit(int count) -{ - Color_count = count; - Color_max = count-1; - Color_halfstep = 256/count/2; -} - -void Set_HSL(T_Palette start_palette, T_Palette end_palette, byte color, short diff_h, short diff_s, short diff_l) -{ - byte h, s, l; - RGB_to_HSL(start_palette[color].R,start_palette[color].G,start_palette[color].B,&h,&s,&l); - // La teinte (Hue) est cyclique - h=(diff_h+256+h); - // Pour les autres (Saturation, Lightness), au lieu d'additionner, - // on va faire un ratio, cela utilise mieux la plage de valeurs 0-255 - if (diff_s<0) - s=(255+diff_s)*s/255; - else if (diff_s>0) - s=255-(255-diff_s)*(255-s)/255; - if (diff_l<0) - l=(255+diff_l)*l/255; - else if (diff_l>0) - l=255-(255-diff_l)*(255-l)/255; - HSL_to_RGB(h,s,l,&end_palette[color].R,&end_palette[color].G,&end_palette[color].B); -} - -void Set_red(byte color, short new_color, T_Palette palette) -{ - if (new_color< 0) - new_color= 0; - if (new_color>255) - new_color=255; - // Arrondi - new_color=Round_palette_component(new_color); - - palette[color].R=new_color; - Set_color(color,palette[color].R,palette[color].G,palette[color].B); -} - - -void Set_green(byte color, short new_color, T_Palette palette) -{ - if (new_color< 0) - new_color= 0; - if (new_color>255) - new_color=255; - // Arrondi - new_color=Round_palette_component(new_color); - - palette[color].G=new_color; - Set_color(color,palette[color].R,palette[color].G,palette[color].B); -} - - -void Set_blue(byte color, short new_color, T_Palette palette) -{ - if (new_color< 0) - new_color= 0; - if (new_color>255) - new_color=255; - // Arrondi - new_color=Round_palette_component(new_color); - - palette[color].B=new_color; - Set_color(color,palette[color].R,palette[color].G,palette[color].B); -} - -void Format_componant(byte value, char *str) -// Formate une chaine de 4 caractères+\0 : "nnn " -{ - Num2str(value,str,3); - str[3]=' '; - str[4]='\0'; -} - -void Spread_colors(short start,short end,T_Palette palette) -// Modifie la palette pour obtenir un dégradé de couleur entre les deux bornes -// passées en paramètre -{ - short start_red; - short start_green; - short start_blue; - short end_red; - short end_green; - short end_blue; - short index; - - // On vérifie qu'il y ait assez de couleurs entre le début et la fin pour - // pouvoir faire un dégradé: - if ( (start!=end) && (start+1!=end) ) - { - start_red=palette[start].R; - start_green =palette[start].G; - start_blue =palette[start].B; - - end_red =palette[end ].R; - end_green =palette[end ].G; - end_blue =palette[end ].B; - - for (index=start+1;index=Window_pos_Y) && (y_pos=Window_pos_X) && (x_pos=Menu_Y_before_window) - end_y=Menu_Y_before_window; - else - end_y=Main_image_height; - - if (!Main_magnifier_mode) - { - if (Main_image_width>=Screen_width) - end_x=Screen_width; - else - end_x=Main_image_width; - - } - else - { - if (Main_image_width>=Main_separator_position) - end_x=Main_separator_position; - else - end_x=Main_image_width; - - if ((Main_X_zoom+(Main_image_width*Main_magnifier_factor))>=Screen_width) - end_x_mag=Screen_width; - else - end_x_mag=(Main_X_zoom+(Main_image_width*Main_magnifier_factor)); - - if (Main_image_height*Main_magnifier_factor>=Menu_Y_before_window) - end_y_mag=Menu_Y_before_window; - else - end_y_mag=Main_image_height*Main_magnifier_factor; - } - - // On doit maintenant faire la traduction à l'écran - Remap_zone_highlevel(0,0,end_x,end_y,conversion_table); - - if (Main_magnifier_mode) - { - Remap_zone_highlevel(Main_separator_position,0,end_x_mag,end_y_mag,conversion_table); - // Il peut encore rester le bas de la barre de split à remapper si la - // partie zoomée ne descend pas jusqu'en bas... - Remap_zone_highlevel(Main_separator_position,end_y_mag, - (Main_separator_position+(SEPARATOR_WIDTH*Menu_factor_X)), - Menu_Y_before_window,conversion_table); - } - // Remappe tous les fonds de fenetre (qui doivent contenir un bout d'écran) - Remap_window_backgrounds(conversion_table, 0, Menu_Y_before_window); -} - - -void Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette, dword * color_usage) -{ - short pos_1; - short pos_2; - short end_1; - short end_2; - dword temp; - byte conversion_table[256]; - - T_Components temp_palette[256]; - dword Utilisation_temporaire[256]; - - // 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 - memcpy(Utilisation_temporaire, color_usage, sizeof(dword) * 256); - - // On commence à initialiser la table de conversion à un état où elle ne - // fera aucune conversion. - for (pos_1=0;pos_1<=255;pos_1++) - conversion_table[pos_1]=pos_1; - - // On calcul les dernières couleurs de chaque bloc. - end_1=block_1_start+block_size-1; - end_2=block_2_start+block_size-1; - - if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) - { - // Le bloc destination commence dans le bloc source. - - for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) - { - // Il faut transformer la couleur pos_1 en pos_2: - - conversion_table[pos_2]=pos_1; - color_usage[pos_1]=Utilisation_temporaire[pos_2]; - palette[pos_1].R=temp_palette[pos_2].R; - palette[pos_1].G=temp_palette[pos_2].G; - palette[pos_1].B=temp_palette[pos_2].B; - - // On gère la mise à jour de pos_2 - if (pos_2==end_2) - pos_2=block_1_start; - else - pos_2++; - } - } - else - if ((block_2_start=block_1_start)) - { - // Le bloc destination déborde dans le bloc source. - - for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) - { - // Il faut transformer la couleur pos_1 en pos_2: - - conversion_table[pos_2]=pos_1; - color_usage[pos_1]=Utilisation_temporaire[pos_2]; - palette[pos_1].R=temp_palette[pos_2].R; - palette[pos_1].G=temp_palette[pos_2].G; - palette[pos_1].B=temp_palette[pos_2].B; - - // On gère la mise à jour de pos_2 - if (pos_2==end_1) - pos_2=block_2_start; - else - pos_2++; - } - } - else - { - // Le bloc source et le bloc destination sont distincts. - - for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) - { - // Il va falloir permutter la couleur pos_1 avec la couleur pos_2 - conversion_table[pos_1]=pos_2; - conversion_table[pos_2]=pos_1; - - // On intervertit le nombre d'utilisation des couleurs pour garder une - // cohérence lors d'un éventuel "Zap unused". - temp =color_usage[pos_1]; - color_usage[pos_1]=color_usage[pos_2]; - color_usage[pos_2]=temp; - - // On fait un changement de teinte: - temp =palette[pos_1].R; - palette[pos_1].R=palette[pos_2].R; - palette[pos_2].R=temp; - - temp =palette[pos_1].G; - palette[pos_1].G=palette[pos_2].G; - palette[pos_2].G=temp; - - temp =palette[pos_1].B; - palette[pos_1].B=palette[pos_2].B; - palette[pos_2].B=temp; - } - } - - if (with_remap) - { - Remap_image_highlevel(conversion_table); - } -} - - - -void Set_nice_menu_colors(dword * color_usage,int not_picture) -{ - short index,index2; - byte color; - byte replace_table[256]; - T_Components rgb[4]; - short new_colors[4]={255,254,253,252}; - - // On initialise la table de remplacement - for (index=0; index<256; index++) - replace_table[index]=index; - - // On recherche les 4 couleurs les moins utilisées dans l'image pour pouvoir - // les remplacer par les nouvelles couleurs. - for (index2=0; index2<4; index2++) - for (index=255; index>=0; index--) - { - if ((index!=new_colors[0]) && (index!=new_colors[1]) - && (index!=new_colors[2]) && (index!=new_colors[3]) - && (color_usage[index]new_colors[index+1]) - { - index2 =new_colors[index]; - new_colors[index] =new_colors[index+1]; - new_colors[index+1]=index2; - color=1; - } - } - } while (color); - - // On sauvegarde dans rgb les teintes qu'on va remplacer et on met les - // couleurs du menu par défaut - for (index=0; index<4; 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; - Main_palette[color].R=Fav_menu_colors[index].R; - Main_palette[color].G=Fav_menu_colors[index].G; - Main_palette[color].B=Fav_menu_colors[index].B; - } - - // Maintenant qu'on a placé notre nouvelle palette, on va chercher quelles - // sont les couleurs qui peuvent remplacer les anciennes - Hide_cursor(); - for (index=0; index<4; index++) - replace_table[new_colors[index]]=Best_color_nonexcluded - (rgb[index].R,rgb[index].G,rgb[index].B); - - if (not_picture) - { - // Remap caused by preview. Only remap screen - Remap_zone_highlevel(0,0,Screen_width,Screen_height,replace_table); - } - else - { - // On fait un changement des couleurs visibles à l'écran et dans l'image - Remap_image_highlevel(replace_table); - } - Display_cursor(); -} - - - -void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage) -{ - char str[5]; // buffer d'affichage du compteur - byte conversion_table[256]; // Table de conversion - int color_1; // |_ Variables de balayages - int color_2; // | de la palette - int best_color_1=0; - int best_color_2=0; - int difference; - int best_difference; - dword Utilisation; - dword Meilleure_utilisation; - - // On commence par initialiser la table de conversion dans un état où - // aucune conversion ne sera effectuée. - for (color_1=0; color_1<=255; color_1++) - conversion_table[color_1]=color_1; - - // Si on ne connait pas encore le nombre de couleurs utilisées, on le - // calcule! (!!! La fonction appelée Efface puis Affiche le curseur !!!) - if ((*used_colors)<0) - Update_color_count(used_colors,color_usage); - - Hide_cursor(); - - // On tasse la palette vers le début parce qu'elle doit ressembler à - // du Gruyère (et comme Papouille il aime pas le fromage...) - - // Pour cela, on va scruter la couleur color_1 et se servir de l'indice - // color_2 comme position de destination. - for (color_1=color_2=0;color_1<=255;color_1++) - { - if (color_usage[color_1]) - { - // On commence par s'occuper des teintes de la palette - palette[color_2].R=palette[color_1].R; - palette[color_2].G=palette[color_1].G; - palette[color_2].B=palette[color_1].B; - - // Ensuite, on met à jour le tableau d'occupation des couleurs. - color_usage[color_2]=color_usage[color_1]; - - // On va maintenant s'occuper de la table de conversion: - conversion_table[color_1]=color_2; - - // Maintenant, la place désignée par color_2 est occupée, alors on - // doit passer à un indice de destination suivant. - color_2++; - } - } - - // On met toutes les couleurs inutilisées en noir - for (;color_2<256;color_2++) - { - palette[color_2].R=0; - palette[color_2].G=0; - palette[color_2].B=0; - color_usage[color_2]=0; - } - - // 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) - { - // 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 - // une seule couleur qui est la moyenne pondérée de ces 2 couleurs - // en fonction de leur utilisation dans l'image. - - best_difference =0x7FFF; - Meilleure_utilisation=0x7FFFFFFF; - - for (color_1=0;color_1<(*used_colors);color_1++) - for (color_2=color_1+1;color_2<(*used_colors);color_2++) - if (color_1!=color_2) - { - difference =abs((short)palette[color_1].R-palette[color_2].R)+ - abs((short)palette[color_1].G-palette[color_2].G)+ - abs((short)palette[color_1].B-palette[color_2].B); - - if (difference<=best_difference) - { - Utilisation=color_usage[color_1]+color_usage[color_2]; - if ((differencebest_color_2) - { - // La color_1 va scroller en arrière. - - // Donc on transfère son utilisation dans l'utilisation de la - // couleur qui la précède. - color_usage[color_1-1]=color_usage[color_1]; - - // Et on transfère ses teintes dans les teintes de la couleur qui - // la précède. - palette[color_1-1].R=palette[color_1].R; - palette[color_1-1].G=palette[color_1].G; - palette[color_1-1].B=palette[color_1].B; - } - - // Une fois la palette et la table d'utilisation gérées, on peut - // s'occuper de notre table de conversion. - if (conversion_table[color_1]>best_color_2) - // La color_1 avait l'intention de se faire remplacer par une - // couleur que l'on va (ou que l'on a déjà) bouger en arrière. - conversion_table[color_1]--; - } - - // On vient d'éjecter une couleur, donc on peut mettre à jour le nombre - // de couleurs utilisées. - (*used_colors)--; - - // A la fin, on doit passer (dans la palette) les teintes du dernier - // élément de notre ensemble en noir. - palette[*used_colors].R=0; - palette[*used_colors].G=0; - palette[*used_colors].B=0; - - // Au passage, on va s'assurer que l'on a pas oublié de la mettre à une - // utilisation nulle. - color_usage[*used_colors]=0; - - // Après avoir éjecté une couleur, on le fait savoir à l'utilisateur par - // l'intermédiaire du compteur de nombre utilisées. - Num2str(*used_colors,str,3); - Print_in_window(186,23,str,MC_Black,MC_Light); - } - - // Maintenant, tous ces calculs doivent êtres pris en compte dans la - // palette, l'image et à l'écran. - Remap_image_highlevel(conversion_table); // Et voila pour l'image et l'écran - Display_cursor(); -} - - - -void Set_palette_slider(T_Scroller_button * slider, - word nb_elements, word position, - char * value, short x_pos) -{ - slider->Nb_elements=nb_elements; - slider->Position=position; - Compute_slider_cursor_height(slider); - Window_draw_slider(slider); - Print_counter(x_pos,172,value,MC_Black,MC_Light); -} - - - -void Display_sliders(T_Scroller_button * red_slider, - T_Scroller_button * green_slider, - T_Scroller_button * blue_slider, - byte block_is_selected, T_Components * palette) -{ - char str[5]; - - 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); - } - else - { - byte j1, j2, j3; - j1= palette[Fore_color].R; - j2= palette[Fore_color].G; - j3= palette[Fore_color].B; - if (!Palette_view_is_RGB) - { - RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); - } - - Format_componant(j1*Color_max/255,str); - Set_palette_slider(red_slider,Color_count,Color_max-j1*Color_max/255,str,176); - Format_componant(j2*Color_max/255,str); - Set_palette_slider(green_slider,Color_count,Color_max-j2*Color_max/255,str,203); - Format_componant(j3*Color_max/255,str); - Set_palette_slider(blue_slider,Color_count,Color_max-j3*Color_max/255,str,230); - } -} - - - -void Draw_all_palette_sliders(T_Scroller_button * red_slider, - T_Scroller_button * green_slider, - T_Scroller_button * blue_slider, - T_Palette palette,byte start,byte end) -{ - char str[5]; - - Hide_cursor(); - // Réaffichage des jauges: - if (start!=end) - { - // 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); - - green_slider->Position =Color_max; - Window_draw_slider(green_slider); - Print_counter(203,172,"± 0",MC_Black,MC_Light); - - blue_slider->Position =Color_max; - Window_draw_slider(blue_slider); - Print_counter(230,172,"± 0",MC_Black,MC_Light); - } - else - { - // Dans le cas d'une seule couleur, composantes. - byte j1, j2, j3; - j1= palette[start].R; - j2= palette[start].G; - j3= palette[start].B; - if (!Palette_view_is_RGB) - { - RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); - } - Format_componant(j1*Color_max/255,str); - red_slider->Position=Color_max-j1*Color_max/255; - Window_draw_slider(red_slider); - Print_counter(176,172,str,MC_Black,MC_Light); - - Format_componant(j2*Color_max/255,str); - green_slider->Position=Color_max-j2*Color_max/255; - Window_draw_slider(green_slider); - Print_counter(203,172,str,MC_Black,MC_Light); - - Format_componant(j3*Color_max/255,str); - blue_slider->Position=Color_max-j3*Color_max/255; - Window_draw_slider(blue_slider); - Print_counter(230,172,str,MC_Black,MC_Light); - } - Display_cursor(); -} - - -void Button_Palette(void) -{ - static short reducer_index=0; - static short reduce_colors_number=256; - short temp_color; // Variable pouvant reservir pour différents calculs intermédiaires - dword temp; - byte color,click; // Variables pouvant reservir pour différents calculs intermédiaires - short clicked_button; - word old_mouse_x; - word old_mouse_y; - byte old_mouse_k; - byte block_start; - byte block_end; - byte first_color; - byte last_color; - char str[10]; - word i; - //short x_pos,y_pos; - T_Normal_button * button_used; - T_Scroller_button * red_slider; - T_Scroller_button * green_slider; - T_Scroller_button * blue_slider; - T_Scroller_button * reduce_slider; - byte image_is_backed_up=0; - byte need_to_remap=0; - - dword color_usage[256]; - short used_colors=-1; // -1 <=> Inconnu - byte conversion_table[256]; - - T_Components * backup_palette; - T_Components * temp_palette; - T_Components * working_palette; - - 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); - - Open_window(299,188,"Palette"); - - memcpy(working_palette,Main_palette,sizeof(T_Palette)); - memcpy(backup_palette ,Main_palette,sizeof(T_Palette)); - memcpy(temp_palette,Main_palette,sizeof(T_Palette)); - - Window_set_palette_button(5,79); // 1 - - Window_display_frame (173, 67,121,116); - Window_display_frame (128, 16, 91, 39); - Window_display_frame (221, 16, 73, 39); - // Frame creux destiné à l'affichage de la(les) couleur(s) sélectionnée(s) - Window_display_frame_in(259, 88, 26, 74); - - // Graduation des jauges de couleur - Block(Window_pos_X+(Menu_factor_X*179),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*206),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*233),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*179),Window_pos_Y+(Menu_factor_Y*125),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*206),Window_pos_Y+(Menu_factor_Y*125),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*233),Window_pos_Y+(Menu_factor_Y*125),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*179),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*206),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X*233),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); - // Jauges de couleur - Palette_view_is_RGB=1; - 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 - 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); - - 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 - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*89),Menu_factor_X*24,Menu_factor_Y*72,Back_color); - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - - // Affichage des valeurs de la couleur courante (pour 1 couleur) - Format_componant(Main_palette[Fore_color].R*Color_max/255,str); - Print_counter(176,172,str,MC_Black,MC_Light); - Format_componant(Main_palette[Fore_color].G*Color_max/255,str); - Print_counter(203,172,str,MC_Black,MC_Light); - Format_componant(Main_palette[Fore_color].B*Color_max/255,str); - Print_counter(230,172,str,MC_Black,MC_Light); - - Print_in_window(129,58,"Color number:",MC_Dark,MC_Light); - Num2str(Fore_color,str,3); - Print_in_window(237,58,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(239,20,51,14,"Reduce" ,1,1,SDLK_r); // 11 - Print_in_window(241,41,"to",MC_Dark,MC_Light); - - 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 - - button_used = Window_set_normal_button(132,20,83,14,"Used: ???",4,1,SDLK_d);// 15 - Window_set_normal_button(132,37,83,14,"Zap unused",0,1,SDLK_DELETE);//16 - - // Jauge de réduction de palette - reduce_slider = Window_set_scroller_button(225,20,31,7,1,reducer_index);// 17 - - Window_set_repeatable_button(266, 74,12,11,"+",0,1,SDLK_KP_PLUS); // 18 - Window_set_repeatable_button(266,165,12,11,"-",0,1,SDLK_KP_MINUS); // 19 - - Window_set_normal_button(96,17,29,14,"Neg" ,1,1,SDLK_n); // 20 - Window_set_normal_button(66,62,29,14,"Inv" ,1,1,SDLK_i); // 21 - Window_set_normal_button( 6,62,59,14,"X-Inv." ,5,1,SDLK_v); // 22 - - Window_set_input_button(263,39,3); // 23 - - Window_set_normal_button(96,32,29,14,"HSL" ,1,1,SDLK_h); // 24 - Window_set_normal_button(96,47,29,14,"Srt" ,1,1,SDLK_s); // 25 - // Affichage du facteur de réduction de la palette - Num2str(reduce_colors_number,str,3); - Print_in_window(265,41,str,MC_Black,MC_Light); - - // 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); - - Update_window_area(0,0,299,188); - - Display_cursor(); - - if (Config.Auto_nb_used) - Update_color_count(&used_colors,color_usage); - - do - { - old_mouse_x=Mouse_X; - old_mouse_y=Mouse_Y; - old_mouse_k=Mouse_K; - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case 0 : // Nulle part - break; - case -1 : // Hors de la fenêtre - case 1 : // palette - if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) - { - Hide_cursor(); - temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); - if (Mouse_K==RIGHT_SIDE) - { - if (Back_color!=temp_color) - { - Back_color=temp_color; - // 4 blocks de back_color entourant la fore_color - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*157),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); - Block(Window_pos_X+(Menu_factor_X*280),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); - Update_rect(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*32,Menu_factor_Y*72); - } - } - else - { - if (!old_mouse_k) - { - // On vient de clicker sur une couleur (et une seule) - if ( (Fore_color!=temp_color) || (block_start!=block_end) ) - { - // La couleur en question est nouvelle ou elle annule un - // ancien bloc. Il faut donc sélectionner cette couleur comme - // unique couleur choisie. - - Fore_color=first_color=last_color=block_start=block_end=temp_color; - Tag_color_range(block_start,block_end); - - // Affichage du n° de la couleur sélectionnée - Block(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y*7,MC_Light); - Num2str(Fore_color,str,3); - Print_in_window(237,58,str,MC_Black,MC_Light); - Update_rect(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y*7); - - // Affichage des jauges - Block(Window_pos_X+(Menu_factor_X*176),Window_pos_Y+(Menu_factor_Y*172),Menu_factor_X*84,Menu_factor_Y*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 - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); - - memcpy(backup_palette ,working_palette,sizeof(T_Palette)); - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - } - } - else - { - // On maintient le click, on va donc tester si le curseur bouge - if (temp_color!=last_color) - { - // On commence par ordonner la 1ère et dernière couleur du bloc - if (first_colortemp_color) - { - block_start=temp_color; - block_end=first_color; - - // Affichage du n° de la couleur sélectionnée - Num2str(block_start,str ,3); - Num2str(block_end ,str+4,3); - str[3]=26; // Flèche vers la droite - Print_in_window(237,58,str,MC_Black,MC_Light); - - // 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); - } - else - { - block_start=block_end=first_color; - Block(Window_pos_X+(Menu_factor_X*176),Window_pos_Y+(Menu_factor_Y*172),Menu_factor_X*84,Menu_factor_Y*7,MC_Light); - - // Affichage du n° de la couleur sélectionnée - Block(Window_pos_X+(Menu_factor_X*261),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*32,Menu_factor_Y*7,MC_Light); - Num2str(Fore_color,str,3); - Print_in_window(237,58,str,MC_Black,MC_Light); - - // 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 - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); - } - - // On tagge le bloc (ou la couleur) - Tag_color_range(block_start,block_end); - } - - last_color=temp_color; - } - } - Display_cursor(); - } - break; - case 2 : // Jauge rouge - Hide_cursor(); - if (block_start==block_end) - { - 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_max/255,str); - } - else - { - HSL_to_RGB( - 255-red_slider->Position, - 255-green_slider->Position, - 255-blue_slider->Position, - &working_palette[Fore_color].R, - &working_palette[Fore_color].G, - &working_palette[Fore_color].B); - Format_componant((int)255-red_slider->Position,str); - } - Print_counter(176,172,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); - } - else - { - for (i=block_start; i<=block_end; i++) - Set_HSL( - temp_palette, - working_palette, - i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, - Color_max-blue_slider->Position - ); - } - - if (red_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-red_slider->Position),str,4); - str[0]='-'; - } - else if (red_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(176,172,str,MC_Black,MC_Light); - - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - case 3 : // Jauge verte - Hide_cursor(); - if (block_start==block_end) - { - 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_max/255,str); - } - else - { - HSL_to_RGB( - 255-red_slider->Position, - 255-green_slider->Position, - 255-blue_slider->Position, - &working_palette[Fore_color].R, - &working_palette[Fore_color].G, - &working_palette[Fore_color].B); - Format_componant((int)255-green_slider->Position,str); - } - Print_counter(203,172,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); - } - else - { - for (i=block_start; i<=block_end; i++) - Set_HSL( - temp_palette, - working_palette, - i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, - Color_max-blue_slider->Position - ); - } - - if (green_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-green_slider->Position),str,4); - str[0]='-'; - } - else if (green_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(203,172,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - - case 4 : // Jauge bleue - Hide_cursor(); - if (block_start==block_end) - { - 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_max/255,str); - } - else - { - HSL_to_RGB( - 255-red_slider->Position, - 255-green_slider->Position, - 255-blue_slider->Position, - &working_palette[Fore_color].R, - &working_palette[Fore_color].G, - &working_palette[Fore_color].B); - Format_componant((int)255-blue_slider->Position,str); - } - Print_counter(230,172,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); - } - else - { - for (i=block_start; i<=block_end; i++) - Set_HSL( - temp_palette, - working_palette, - i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, - Color_max-blue_slider->Position - ); - } - - if (blue_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-blue_slider->Position),str,4); - str[0]='-'; - } - else if (blue_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(230,172,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - 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); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - // On prépare la "modifiabilité" des nouvelles couleurs - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - - need_to_remap=1; - break; - - case 6 : // Grey scale - // Backup - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - // Grey Scale - for (i=block_start;i<=block_end;i++) - { - temp_color=(dword)( ((dword)working_palette[i].R*30) + ((dword)working_palette[i].G*59) + ((dword)working_palette[i].B*11) )/100; - Set_red(i,temp_color,working_palette); - Set_green (i,temp_color,working_palette); - Set_blue (i,temp_color,working_palette); - } - 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 7 : // Swap - case 8 : // X-Swap - temp_color=Wait_click_in_palette(Window_palette_button_list); - if ((temp_color>=0) - && (temp_color!=block_start)) - { - Hide_cursor(); - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - - // On calcule le nombre de couleurs a swapper sans risquer de sortir - // de la palette (La var. first_color est utilisée pour économiser 1 var; c'est tout) - first_color=(temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color; - - if (clicked_button==8) // On ne fait de backup de l'image que si on - // est en mode X-SWAP. - if (!image_is_backed_up) - { - Backup(); - image_is_backed_up=1; - } - - Swap(clicked_button==8,block_start,temp_color,first_color,working_palette,color_usage); - - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - - // On déplace le bloc vers les modifs: - last_color=block_end=temp_color+first_color-1; - Fore_color=first_color=block_start=temp_color; - // On raffiche le n° des bornes du bloc: - if (block_start!=block_end) - { - // Cas d'un bloc multi-couleur - Num2str(block_start,str ,3); - 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); - } - else - { - // Cas d'une seule couleur - Num2str(Fore_color,str,3); - Block(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y* 7,MC_Light); - // Affichage dans le block de visu de la couleur en cours - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - } - Print_in_window(237,58,str,MC_Black,MC_Light); - // On tag le bloc (ou la couleur) - Tag_color_range(block_start,block_end); - - need_to_remap=1; - - Set_palette(working_palette); - - Display_cursor(); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - - // En cas de X-Swap, tout l'ecran a pu changer de couleur. - if (clicked_button==8) - Update_rect(0, 0, Screen_width, Menu_Y_before_window); - Wait_end_of_click(); - } - break; - - case 9 : // Copy - temp_color=Wait_click_in_palette(Window_palette_button_list); - if ((temp_color>=0) && (temp_color!=block_start)) - { - Hide_cursor(); - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - memcpy(working_palette+temp_color,backup_palette+block_start, - ((temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color)*3); - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - Set_palette(working_palette); - // On déplace le bloc vers les modifs: - last_color=block_end=((temp_color+block_end-block_start<=255)?(temp_color+block_end-block_start):255); - Fore_color=first_color=block_start=temp_color; - // On raffiche le n° des bornes du bloc: - if (block_start!=block_end) - { - // Cas d'un bloc multi-couleur - Num2str(block_start,str ,3); - 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); - } - else - { - // Cas d'une seule couleur - Num2str(Fore_color,str,3); - Block(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y* 7,MC_Light); - // Affichage dans le block de visu de la couleur en cours - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - } - Print_in_window(237,58,str,MC_Black,MC_Light); - // On tag le bloc (ou la couleur) - Tag_color_range(block_start,block_end); - - need_to_remap=1; - - Display_cursor(); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Wait_end_of_click(); - } - break; - - case 10 : // Spread - if (block_start!=block_end) - { - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - Spread_colors(block_start,block_end,working_palette); - } - else - { - temp_color=Wait_click_in_palette(Window_palette_button_list); - if (temp_color>=0) - { - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - if (temp_colorPosition) - { - reducer_index=reduce_slider->Position; - // Affichage du facteur de réduction de la palette - Hide_cursor(); - Print_in_window(265,41,Palette_reduce_label[reducer_index],MC_Black,MC_Light); - Display_cursor(); - reduce_colors_number=atoi(Palette_reduce_label[reducer_index]); - } - break; - - case 18 : // [+] - if (!Palette_view_is_RGB) - break; - Hide_cursor(); - if (block_start==block_end) - { - if (red_slider->Position) - { - (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_max/255,str); - Print_counter(176,172,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_max/255,str); - Print_counter(203,172,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_max/255,str); - Print_counter(230,172,str,MC_Black,MC_Light); - } - } - else - { - if (red_slider->Position) - { - (red_slider->Position)--; - Window_draw_slider(red_slider); - } - if (green_slider->Position) - { - (green_slider->Position)--; - Window_draw_slider(green_slider); - } - if (blue_slider->Position) - { - (blue_slider->Position)--; - Window_draw_slider(blue_slider); - } - - 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); - } - - // -- red -- - if (red_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-red_slider->Position),str,4); - str[0]='-'; - } - else if (red_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(176,172,str,MC_Black,MC_Light); - - - // -- green -- - if (green_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-green_slider->Position),str,4); - str[0]='-'; - } - else if (green_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(203,172,str,MC_Black,MC_Light); - - - // -- blue -- - if (blue_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-blue_slider->Position),str,4); - str[0]='-'; - } - else if (blue_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(230,172,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - - case 19 : // [-] - if (!Palette_view_is_RGB) - break; - Hide_cursor(); - if (block_start==block_end) - { - if (red_slider->PositionPosition)++; - 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_max/255,str); - Print_counter(176,172,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_max/255,str); - Print_counter(203,172,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_max/255,str); - Print_counter(230,172,str,MC_Black,MC_Light); - } - } - else - { - if (red_slider->Position<(Color_max*2)) - { - (red_slider->Position)++; - Window_draw_slider(red_slider); - } - if (green_slider->Position<(Color_max*2)) - { - (green_slider->Position)++; - Window_draw_slider(green_slider); - } - if (blue_slider->Position<(Color_max*2)) - { - (blue_slider->Position)++; - Window_draw_slider(blue_slider); - } - - 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); - } - - // -- red -- - if (red_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-red_slider->Position),str,4); - str[0]='-'; - } - else if (red_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(176,172,str,MC_Black,MC_Light); - - - // -- green -- - if (green_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-green_slider->Position),str,4); - str[0]='-'; - } - else if (green_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(203,172,str,MC_Black,MC_Light); - - - // -- blue -- - if (blue_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-blue_slider->Position),str,4); - str[0]='-'; - } - else if (blue_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(230,172,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - - case 20 : // Negative - // Backup - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - // Negative - for (i=block_start;i<=block_end;i++) - { - Set_red(i,255-working_palette[i].R,working_palette); - Set_green (i,255-working_palette[i].G,working_palette); - Set_blue (i,255-working_palette[i].B,working_palette); - } - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Set_palette(working_palette); - // On prépare la "modifiabilité" des nouvelles couleurs - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - - need_to_remap=1; - break; - - case 21 : // Inversion - case 22 : // X-Inversion - // Backup - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - // On initialise la table de conversion - for (i=0; i<=255; i++) - conversion_table[i]=i; - // Inversion - for (i=block_start;i<=block_end;i++) - { - temp_color=block_end-(i-block_start); - Set_red(i,backup_palette[temp_color].R,working_palette); - Set_green (i,backup_palette[temp_color].G,working_palette); - Set_blue (i,backup_palette[temp_color].B,working_palette); - if (clicked_button==22) - { - conversion_table[i]=temp_color; - conversion_table[temp_color]=i; - - temp=color_usage[i]; - color_usage[i]=color_usage[temp_color]; - color_usage[temp_color]=temp; - } - } - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - // Si on est en X-Invert, on remap l'image (=> on fait aussi 1 backup) - if (clicked_button==22) - { - if (!image_is_backed_up) - { - Backup(); - image_is_backed_up=1; - } - Hide_cursor(); - Remap_image_highlevel(conversion_table); - Display_cursor(); - } - // 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 23 : // Saisie du nombre de couleurs pour la réduction de palette - Num2str(reduce_colors_number,str,3); - - if (Readline(265,41,str,3,1)) - { - temp_color=atoi(str); - // Correction de la valeur lue - if ( (temp_color>256) || (temp_color<2) ) - { - if (temp_color>256) - temp_color=256; - else - temp_color=2; - - Num2str(temp_color,str,3); - Window_input_content(Window_special_button_list,str); - } - - reduce_colors_number=temp_color; - } - Display_cursor(); - break; - - case 24 : // HSL <> RGB - - // Acte les changements en cours sur une ou plusieurs couleurs - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - memcpy(backup_palette ,working_palette,sizeof(T_Palette)); - - 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); - - // 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); - } - 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); - - // 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); - } - Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); - Update_window_area(265,73,14,103); - break; - - case 25 : // Sort palette - { - byte h = 0, l = 0, s=0; - byte oh=0,ol=0,os=0; // Valeur pour la couleur précédente - int swap=1; - byte remap_table[256]; - byte inverted_table[256]; - byte begin, end; - - if(block_start==block_end) - { - begin = 0; - end = 255; - } - else - { - begin = block_start; - end = block_end; - } - - // Init remap table - for (i=0;i<256;i++) - remap_table[i]=i; - // Make a backup because remapping is an undoable modification - if (!image_is_backed_up) - { - Backup(); - image_is_backed_up=1; - } - - if(Window_attribute1==LEFT_SIDE) - // Laft click on button: Sort by Hue (H) and Lightness (L) - while(swap==1) - { - swap=0; - h=0;l=255;s=0; - for(temp_color=begin;temp_color<=end;temp_color++) - { - oh=h; ol=l; os=s; - RGB_to_HSL(working_palette[temp_color].R, - working_palette[temp_color].G, - working_palette[temp_color].B,&h,&s,&l); - - if( - ((s==0) && (os>0)) // A grey is before a saturated color - || ((s>0 && os > 0) && (hol))) // 2 saturated colors: sort by H, then by L - || ((os==0 && s==0) && l>ol)) // Two greys: sort by L only - { - // Swap color with the previous one - byte swap_color; - Swap(0,temp_color,temp_color-1,1,working_palette,color_usage); - - swap_color=remap_table[temp_color]; - remap_table[temp_color]=remap_table[temp_color-1]; - remap_table[temp_color-1]=swap_color; - - swap=1; - } - } - } - - else // Right click > Sort only on L - while(swap==1) - { - swap=0; - l=255; - for(temp_color=begin;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); - - if(l>ol) - { - // Swap color with the previous one - byte swap_color; - Swap(0,temp_color,temp_color-1,1,working_palette,color_usage); - - swap_color=remap_table[temp_color]; - remap_table[temp_color]=remap_table[temp_color-1]; - remap_table[temp_color-1]=swap_color; - - swap=1; - } - } - } - - for (i=0;i<256;i++) - inverted_table[remap_table[i]]=i; - Remap_image_highlevel(inverted_table); - // Maintenant, tous ces calculs doivent êtres pris en compte dans la - // palette, l'image et à l'écran. - Set_palette(working_palette); - need_to_remap=1; - } - break; - } - - - if (!Mouse_K) - { - switch (Key) - { - case SDLK_LEFTBRACKET : // Décaler Forecolor vers la gauche - if (block_start==block_end) - { - Fore_color--; - first_color--; - last_color--; - block_start--; - block_end--; - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Hide_cursor(); - 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,58,str,MC_Black,MC_Light); - // Affichage dans le block de visu de la couleur en cours - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); - Display_cursor(); - } - Key=0; - break; - - case SDLK_RIGHTBRACKET : // Décaler Forecolor vers la droite - if (block_start==block_end) - { - Fore_color++; - first_color++; - last_color++; - block_start++; - block_end++; - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Hide_cursor(); - 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,58,str,MC_Black,MC_Light); - // Affichage dans le block de visu de la couleur en cours - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); - Display_cursor(); - } - Key=0; - break; - - case (SDLK_LEFTBRACKET|MOD_SHIFT) : // Decaler Backcolor vers la gauche - Back_color--; - case (SDLK_RIGHTBRACKET|MOD_SHIFT) : // Decaler Backcolor vers la droite - // attention: pas de break ci-dessus - if (Key==(SDLK_RIGHTBRACKET|MOD_SHIFT)) - Back_color++; - Hide_cursor(); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*157),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); - Block(Window_pos_X+(Menu_factor_X*280),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); - Update_rect(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*32,Menu_factor_Y*72); - Display_cursor(); - Key=0; - break; - - case SDLK_BACKSPACE : // Remise des couleurs du menu à l'état normal en essayant - // de ne pas trop modifier l'image. - if (!image_is_backed_up) - { - Backup(); - image_is_backed_up=1; - } - if (used_colors==-1) - Update_color_count(&used_colors,color_usage); - - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - memcpy(temp_palette,Main_palette,sizeof(T_Palette)); - memcpy(Main_palette,working_palette,sizeof(T_Palette)); - Set_nice_menu_colors(color_usage,0); - memcpy(working_palette,Main_palette,sizeof(T_Palette)); - memcpy(Main_palette,temp_palette,sizeof(T_Palette)); - Set_palette(working_palette); - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Update_color_count(&used_colors,color_usage); - need_to_remap=1; - Key=0; - break; - - case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu - case SDLK_COMMA : - Get_color_behind_window(&color,&click); - if (click) - { - Hide_cursor(); - if (click==RIGHT_SIDE) - { - if (Back_color!=color) - { - Back_color=color; - // 4 blocks de back_color entourant la fore_color - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*157),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); - Block(Window_pos_X+(Menu_factor_X*280),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); - Update_rect(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*32,Menu_factor_Y*72); - } - } - else - { - Fore_color=first_color=last_color=block_start=block_end=color; - Tag_color_range(block_start,block_end); - - // Affichage du n° de la couleur sélectionnée - Block(Window_pos_X+(Menu_factor_X*261),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*32,Menu_factor_Y*7,MC_Light); - Num2str(Fore_color,str,3); - Print_in_window(237,58,str,MC_Black,MC_Light); - - // 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 - Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); - Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); - - memcpy(backup_palette ,working_palette,sizeof(T_Palette)); - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - } - Display_cursor(); - Wait_end_of_click(); - } - Key=0; - break; - default: - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Key=0; - Window_help(BUTTON_PALETTE, NULL); - break; - } - } - - if (need_to_remap) - { - Hide_cursor(); - Compute_optimal_menu_colors(working_palette); - - // On remappe brutalement - Remap_screen_after_menu_colors_change(); - // Puis on remet les trucs qui ne devaient pas changer - Window_draw_palette_bouton(5,79); - Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*89),Menu_factor_X*24,Menu_factor_Y*72,Back_color); - Display_grad_block_in_window(264,93,block_start,block_end); - - Update_rect(Window_pos_X+8*Menu_factor_X,Window_pos_Y+82*Menu_factor_Y,Menu_factor_X*16*10,Menu_factor_Y*5*16); - - Display_cursor(); - need_to_remap=0; - } - } - } - while ((clicked_button!=13) && (clicked_button!=14)); - - if (clicked_button==14) // Sortie par OK - { - if ( (!image_is_backed_up) - && memcmp(Main_palette,working_palette,sizeof(T_Palette)) ) - Backup(); - memcpy(Main_palette,working_palette,sizeof(T_Palette)); - } - - Compute_optimal_menu_colors(Main_palette); - - // La variable employée ici n'a pas vraiment de rapport avec son nom... - need_to_remap=(Window_pos_Y+(Window_height*Menu_factor_Y)Position = rgb_scale_slider->Position>128?rgb_scale_slider->Position*2-256:0; - Num2str(256-rgb_scale_slider->Position,str,3); - Print_in_window(157,78,str,MC_Black,MC_Light); - Window_draw_slider(rgb_scale_slider); - break; - - case 10: - // /2 RGB scale - rgb_scale_slider->Position = rgb_scale_slider->Position>253?254:(rgb_scale_slider->Position)/2+128; - Num2str(256-rgb_scale_slider->Position,str,3); - Print_in_window(157,78,str,MC_Black,MC_Light); - Window_draw_slider(rgb_scale_slider); - } - } - while (clicked_button!=1 && clicked_button!=2 && clicked_button!=3 && clicked_button!=4); - - // We need to get the sliders positions before closing the window, because they will be freed. - palette_cols=256-columns_slider->Position; - palette_lines=16-lines_slider->Position; - rgb_scale=256-rgb_scale_slider->Position; - - Close_window(); - Unselect_button(BUTTON_PALETTE); - Display_cursor(); - - if (clicked_button==4) // Cancel - return; - - if (palette_vertical != Config.Palette_vertical) - { - Config.Palette_vertical=palette_vertical; - palette_needs_redraw=1; - } - if (palette_cols!=Config.Palette_cells_X || - palette_lines!=Config.Palette_cells_Y) - { - Config.Palette_cells_X = palette_cols; - Config.Palette_cells_Y = palette_lines; - palette_needs_redraw=1; - } - if (rgb_scale!=RGB_scale) - { - Set_palette_RGB_scale(rgb_scale); - Set_palette(Main_palette); - } - - if (clicked_button==1) - { - Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL); - } - else if (clicked_button==2) - { - // Open the menu with Shade settings. Same as the shortcut, except - // that this will not activate shade mode on exit. - Shade_settings_menu(); - } - - if (palette_needs_redraw) - { - Change_palette_cells(); - Display_menu(); - Display_sprite_in_menu(BUTTON_PAL_LEFT,18+(Config.Palette_vertical!=0)); - } -} +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 "const.h" +#include "struct.h" +#include "global.h" +#include "misc.h" +#include "engine.h" +#include "readline.h" +#include "buttons.h" +#include "pages.h" +#include "help.h" +#include "sdlscreen.h" +#include "errors.h" +#include "op_c.h" +#include "windows.h" +#include "input.h" +#include "palette.h" +#include "shade.h" + +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" +}; + +// Nombre de graduations pour une composante RGB +int RGB_scale = 256; // 24bit +//int RGB_scale = 64; // VGA +//int RGB_scale = 16; // Amiga +//int RGB_scale = 4; // MSX2 +//int RGB_scale = 3; // Amstrad CPC + +// Nombre de graduations pour une composante dans le mode actuel +int Color_count=256; +// Les composantes vont de 0 à (Color_count-1) +int Color_max=255; +// Le demi-pas est une quantité que l'on ajoute à une composante +// avant de faire un arrondi par division. +int Color_halfstep=0; + + +void Set_palette_RGB_scale(int scale) +{ + if (scale>= 2 && scale <= 256) + RGB_scale = scale; +} + +byte Round_palette_component(byte comp) +{ + return ((comp+128/RGB_scale)*(RGB_scale-1)/255*255+(RGB_scale&1?1:0))/(RGB_scale-1); +} + +// Définir les unités pour les graduations R G B ou H S V +void Componant_unit(int count) +{ + Color_count = count; + Color_max = count-1; + Color_halfstep = 256/count/2; +} + +void Set_HSL(T_Palette start_palette, T_Palette end_palette, byte color, short diff_h, short diff_s, short diff_l) +{ + byte h, s, l; + RGB_to_HSL(start_palette[color].R,start_palette[color].G,start_palette[color].B,&h,&s,&l); + // La teinte (Hue) est cyclique + h=(diff_h+256+h); + // Pour les autres (Saturation, Lightness), au lieu d'additionner, + // on va faire un ratio, cela utilise mieux la plage de valeurs 0-255 + if (diff_s<0) + s=(255+diff_s)*s/255; + else if (diff_s>0) + s=255-(255-diff_s)*(255-s)/255; + if (diff_l<0) + l=(255+diff_l)*l/255; + else if (diff_l>0) + l=255-(255-diff_l)*(255-l)/255; + HSL_to_RGB(h,s,l,&end_palette[color].R,&end_palette[color].G,&end_palette[color].B); +} + +void Set_red(byte color, short new_color, T_Palette palette) +{ + if (new_color< 0) + new_color= 0; + if (new_color>255) + new_color=255; + // Arrondi + new_color=Round_palette_component(new_color); + + palette[color].R=new_color; + Set_color(color,palette[color].R,palette[color].G,palette[color].B); +} + + +void Set_green(byte color, short new_color, T_Palette palette) +{ + if (new_color< 0) + new_color= 0; + if (new_color>255) + new_color=255; + // Arrondi + new_color=Round_palette_component(new_color); + + palette[color].G=new_color; + Set_color(color,palette[color].R,palette[color].G,palette[color].B); +} + + +void Set_blue(byte color, short new_color, T_Palette palette) +{ + if (new_color< 0) + new_color= 0; + if (new_color>255) + new_color=255; + // Arrondi + new_color=Round_palette_component(new_color); + + palette[color].B=new_color; + Set_color(color,palette[color].R,palette[color].G,palette[color].B); +} + +void Format_componant(byte value, char *str) +// Formate une chaine de 4 caractères+\0 : "nnn " +{ + Num2str(value,str,3); + str[3]=' '; + str[4]='\0'; +} + +void Spread_colors(short start,short end,T_Palette palette) +// Modifie la palette pour obtenir un dégradé de couleur entre les deux bornes +// passées en paramètre +{ + short start_red; + short start_green; + short start_blue; + short end_red; + short end_green; + short end_blue; + short index; + + // On vérifie qu'il y ait assez de couleurs entre le début et la fin pour + // pouvoir faire un dégradé: + if ( (start!=end) && (start+1!=end) ) + { + start_red=palette[start].R; + start_green =palette[start].G; + start_blue =palette[start].B; + + end_red =palette[end ].R; + end_green =palette[end ].G; + end_blue =palette[end ].B; + + for (index=start+1;index=Window_pos_Y) && (y_pos=Window_pos_X) && (x_pos=Menu_Y_before_window) + end_y=Menu_Y_before_window; + else + end_y=Main_image_height; + + if (!Main_magnifier_mode) + { + if (Main_image_width>=Screen_width) + end_x=Screen_width; + else + end_x=Main_image_width; + + } + else + { + if (Main_image_width>=Main_separator_position) + end_x=Main_separator_position; + else + end_x=Main_image_width; + + if ((Main_X_zoom+(Main_image_width*Main_magnifier_factor))>=Screen_width) + end_x_mag=Screen_width; + else + end_x_mag=(Main_X_zoom+(Main_image_width*Main_magnifier_factor)); + + if (Main_image_height*Main_magnifier_factor>=Menu_Y_before_window) + end_y_mag=Menu_Y_before_window; + else + end_y_mag=Main_image_height*Main_magnifier_factor; + } + + // On doit maintenant faire la traduction à l'écran + Remap_zone_highlevel(0,0,end_x,end_y,conversion_table); + + if (Main_magnifier_mode) + { + Remap_zone_highlevel(Main_separator_position,0,end_x_mag,end_y_mag,conversion_table); + // Il peut encore rester le bas de la barre de split à remapper si la + // partie zoomée ne descend pas jusqu'en bas... + Remap_zone_highlevel(Main_separator_position,end_y_mag, + (Main_separator_position+(SEPARATOR_WIDTH*Menu_factor_X)), + Menu_Y_before_window,conversion_table); + } + // Remappe tous les fonds de fenetre (qui doivent contenir un bout d'écran) + Remap_window_backgrounds(conversion_table, 0, Menu_Y_before_window); +} + + +void Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette, dword * color_usage) +{ + short pos_1; + short pos_2; + short end_1; + short end_2; + dword temp; + byte conversion_table[256]; + + T_Components temp_palette[256]; + dword Utilisation_temporaire[256]; + + // 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 + memcpy(Utilisation_temporaire, color_usage, sizeof(dword) * 256); + + // On commence à initialiser la table de conversion à un état où elle ne + // fera aucune conversion. + for (pos_1=0;pos_1<=255;pos_1++) + conversion_table[pos_1]=pos_1; + + // On calcul les dernières couleurs de chaque bloc. + end_1=block_1_start+block_size-1; + end_2=block_2_start+block_size-1; + + if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) + { + // Le bloc destination commence dans le bloc source. + + for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) + { + // Il faut transformer la couleur pos_1 en pos_2: + + conversion_table[pos_2]=pos_1; + color_usage[pos_1]=Utilisation_temporaire[pos_2]; + palette[pos_1].R=temp_palette[pos_2].R; + palette[pos_1].G=temp_palette[pos_2].G; + palette[pos_1].B=temp_palette[pos_2].B; + + // On gère la mise à jour de pos_2 + if (pos_2==end_2) + pos_2=block_1_start; + else + pos_2++; + } + } + else + if ((block_2_start=block_1_start)) + { + // Le bloc destination déborde dans le bloc source. + + for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) + { + // Il faut transformer la couleur pos_1 en pos_2: + + conversion_table[pos_2]=pos_1; + color_usage[pos_1]=Utilisation_temporaire[pos_2]; + palette[pos_1].R=temp_palette[pos_2].R; + palette[pos_1].G=temp_palette[pos_2].G; + palette[pos_1].B=temp_palette[pos_2].B; + + // On gère la mise à jour de pos_2 + if (pos_2==end_1) + pos_2=block_2_start; + else + pos_2++; + } + } + else + { + // Le bloc source et le bloc destination sont distincts. + + for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) + { + // Il va falloir permutter la couleur pos_1 avec la couleur pos_2 + conversion_table[pos_1]=pos_2; + conversion_table[pos_2]=pos_1; + + // On intervertit le nombre d'utilisation des couleurs pour garder une + // cohérence lors d'un éventuel "Zap unused". + temp =color_usage[pos_1]; + color_usage[pos_1]=color_usage[pos_2]; + color_usage[pos_2]=temp; + + // On fait un changement de teinte: + temp =palette[pos_1].R; + palette[pos_1].R=palette[pos_2].R; + palette[pos_2].R=temp; + + temp =palette[pos_1].G; + palette[pos_1].G=palette[pos_2].G; + palette[pos_2].G=temp; + + temp =palette[pos_1].B; + palette[pos_1].B=palette[pos_2].B; + palette[pos_2].B=temp; + } + } + + if (with_remap) + { + Remap_image_highlevel(conversion_table); + } +} + + + +void Set_nice_menu_colors(dword * color_usage,int not_picture) +{ + short index,index2; + byte color; + byte replace_table[256]; + T_Components rgb[4]; + short new_colors[4]={255,254,253,252}; + + // On initialise la table de remplacement + for (index=0; index<256; index++) + replace_table[index]=index; + + // On recherche les 4 couleurs les moins utilisées dans l'image pour pouvoir + // les remplacer par les nouvelles couleurs. + for (index2=0; index2<4; index2++) + for (index=255; index>=0; index--) + { + if ((index!=new_colors[0]) && (index!=new_colors[1]) + && (index!=new_colors[2]) && (index!=new_colors[3]) + && (color_usage[index]new_colors[index+1]) + { + index2 =new_colors[index]; + new_colors[index] =new_colors[index+1]; + new_colors[index+1]=index2; + color=1; + } + } + } while (color); + + // On sauvegarde dans rgb les teintes qu'on va remplacer et on met les + // couleurs du menu par défaut + for (index=0; index<4; 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; + Main_palette[color].R=Fav_menu_colors[index].R; + Main_palette[color].G=Fav_menu_colors[index].G; + Main_palette[color].B=Fav_menu_colors[index].B; + } + + // Maintenant qu'on a placé notre nouvelle palette, on va chercher quelles + // sont les couleurs qui peuvent remplacer les anciennes + Hide_cursor(); + for (index=0; index<4; index++) + replace_table[new_colors[index]]=Best_color_nonexcluded + (rgb[index].R,rgb[index].G,rgb[index].B); + + if (not_picture) + { + // Remap caused by preview. Only remap screen + Remap_zone_highlevel(0,0,Screen_width,Screen_height,replace_table); + } + else + { + // On fait un changement des couleurs visibles à l'écran et dans l'image + Remap_image_highlevel(replace_table); + } + Display_cursor(); +} + + + +void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage) +{ + char str[5]; // buffer d'affichage du compteur + byte conversion_table[256]; // Table de conversion + int color_1; // |_ Variables de balayages + int color_2; // | de la palette + int best_color_1=0; + int best_color_2=0; + int difference; + int best_difference; + dword Utilisation; + dword Meilleure_utilisation; + + // On commence par initialiser la table de conversion dans un état où + // aucune conversion ne sera effectuée. + for (color_1=0; color_1<=255; color_1++) + conversion_table[color_1]=color_1; + + // Si on ne connait pas encore le nombre de couleurs utilisées, on le + // calcule! (!!! La fonction appelée Efface puis Affiche le curseur !!!) + if ((*used_colors)<0) + Update_color_count(used_colors,color_usage); + + Hide_cursor(); + + // On tasse la palette vers le début parce qu'elle doit ressembler à + // du Gruyère (et comme Papouille il aime pas le fromage...) + + // Pour cela, on va scruter la couleur color_1 et se servir de l'indice + // color_2 comme position de destination. + for (color_1=color_2=0;color_1<=255;color_1++) + { + if (color_usage[color_1]) + { + // On commence par s'occuper des teintes de la palette + palette[color_2].R=palette[color_1].R; + palette[color_2].G=palette[color_1].G; + palette[color_2].B=palette[color_1].B; + + // Ensuite, on met à jour le tableau d'occupation des couleurs. + color_usage[color_2]=color_usage[color_1]; + + // On va maintenant s'occuper de la table de conversion: + conversion_table[color_1]=color_2; + + // Maintenant, la place désignée par color_2 est occupée, alors on + // doit passer à un indice de destination suivant. + color_2++; + } + } + + // On met toutes les couleurs inutilisées en noir + for (;color_2<256;color_2++) + { + palette[color_2].R=0; + palette[color_2].G=0; + palette[color_2].B=0; + color_usage[color_2]=0; + } + + // 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) + { + // 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 + // une seule couleur qui est la moyenne pondérée de ces 2 couleurs + // en fonction de leur utilisation dans l'image. + + best_difference =0x7FFF; + Meilleure_utilisation=0x7FFFFFFF; + + for (color_1=0;color_1<(*used_colors);color_1++) + for (color_2=color_1+1;color_2<(*used_colors);color_2++) + if (color_1!=color_2) + { + difference =abs((short)palette[color_1].R-palette[color_2].R)+ + abs((short)palette[color_1].G-palette[color_2].G)+ + abs((short)palette[color_1].B-palette[color_2].B); + + if (difference<=best_difference) + { + Utilisation=color_usage[color_1]+color_usage[color_2]; + if ((differencebest_color_2) + { + // La color_1 va scroller en arrière. + + // Donc on transfère son utilisation dans l'utilisation de la + // couleur qui la précède. + color_usage[color_1-1]=color_usage[color_1]; + + // Et on transfère ses teintes dans les teintes de la couleur qui + // la précède. + palette[color_1-1].R=palette[color_1].R; + palette[color_1-1].G=palette[color_1].G; + palette[color_1-1].B=palette[color_1].B; + } + + // Une fois la palette et la table d'utilisation gérées, on peut + // s'occuper de notre table de conversion. + if (conversion_table[color_1]>best_color_2) + // La color_1 avait l'intention de se faire remplacer par une + // couleur que l'on va (ou que l'on a déjà) bouger en arrière. + conversion_table[color_1]--; + } + + // On vient d'éjecter une couleur, donc on peut mettre à jour le nombre + // de couleurs utilisées. + (*used_colors)--; + + // A la fin, on doit passer (dans la palette) les teintes du dernier + // élément de notre ensemble en noir. + palette[*used_colors].R=0; + palette[*used_colors].G=0; + palette[*used_colors].B=0; + + // Au passage, on va s'assurer que l'on a pas oublié de la mettre à une + // utilisation nulle. + color_usage[*used_colors]=0; + + // Après avoir éjecté une couleur, on le fait savoir à l'utilisateur par + // l'intermédiaire du compteur de nombre utilisées. + Num2str(*used_colors,str,3); + Print_in_window(186,23,str,MC_Black,MC_Light); + } + + // Maintenant, tous ces calculs doivent êtres pris en compte dans la + // palette, l'image et à l'écran. + Remap_image_highlevel(conversion_table); // Et voila pour l'image et l'écran + Display_cursor(); +} + + + +void Set_palette_slider(T_Scroller_button * slider, + word nb_elements, word position, + char * value, short x_pos) +{ + slider->Nb_elements=nb_elements; + slider->Position=position; + Compute_slider_cursor_height(slider); + Window_draw_slider(slider); + Print_counter(x_pos,172,value,MC_Black,MC_Light); +} + + + +void Display_sliders(T_Scroller_button * red_slider, + T_Scroller_button * green_slider, + T_Scroller_button * blue_slider, + byte block_is_selected, T_Components * palette) +{ + char str[5]; + + 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); + } + else + { + byte j1, j2, j3; + j1= palette[Fore_color].R; + j2= palette[Fore_color].G; + j3= palette[Fore_color].B; + if (!Palette_view_is_RGB) + { + RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); + } + + Format_componant(j1*Color_max/255,str); + Set_palette_slider(red_slider,Color_count,Color_max-j1*Color_max/255,str,176); + Format_componant(j2*Color_max/255,str); + Set_palette_slider(green_slider,Color_count,Color_max-j2*Color_max/255,str,203); + Format_componant(j3*Color_max/255,str); + Set_palette_slider(blue_slider,Color_count,Color_max-j3*Color_max/255,str,230); + } +} + + + +void Draw_all_palette_sliders(T_Scroller_button * red_slider, + T_Scroller_button * green_slider, + T_Scroller_button * blue_slider, + T_Palette palette,byte start,byte end) +{ + char str[5]; + + Hide_cursor(); + // Réaffichage des jauges: + if (start!=end) + { + // 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); + + green_slider->Position =Color_max; + Window_draw_slider(green_slider); + Print_counter(203,172,"± 0",MC_Black,MC_Light); + + blue_slider->Position =Color_max; + Window_draw_slider(blue_slider); + Print_counter(230,172,"± 0",MC_Black,MC_Light); + } + else + { + // Dans le cas d'une seule couleur, composantes. + byte j1, j2, j3; + j1= palette[start].R; + j2= palette[start].G; + j3= palette[start].B; + if (!Palette_view_is_RGB) + { + RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); + } + Format_componant(j1*Color_max/255,str); + red_slider->Position=Color_max-j1*Color_max/255; + Window_draw_slider(red_slider); + Print_counter(176,172,str,MC_Black,MC_Light); + + Format_componant(j2*Color_max/255,str); + green_slider->Position=Color_max-j2*Color_max/255; + Window_draw_slider(green_slider); + Print_counter(203,172,str,MC_Black,MC_Light); + + Format_componant(j3*Color_max/255,str); + blue_slider->Position=Color_max-j3*Color_max/255; + Window_draw_slider(blue_slider); + Print_counter(230,172,str,MC_Black,MC_Light); + } + Display_cursor(); +} + + +void Button_Palette(void) +{ + static short reducer_index=0; + static short reduce_colors_number=256; + short temp_color; // Variable pouvant reservir pour différents calculs intermédiaires + dword temp; + byte color,click; // Variables pouvant reservir pour différents calculs intermédiaires + short clicked_button; + word old_mouse_x; + word old_mouse_y; + byte old_mouse_k; + byte block_start; + byte block_end; + byte first_color; + byte last_color; + char str[10]; + word i; + //short x_pos,y_pos; + T_Normal_button * button_used; + T_Scroller_button * red_slider; + T_Scroller_button * green_slider; + T_Scroller_button * blue_slider; + T_Scroller_button * reduce_slider; + byte image_is_backed_up=0; + byte need_to_remap=0; + + dword color_usage[256]; + short used_colors=-1; // -1 <=> Inconnu + byte conversion_table[256]; + + T_Components * backup_palette; + T_Components * temp_palette; + T_Components * working_palette; + + 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); + + Open_window(299,188,"Palette"); + + memcpy(working_palette,Main_palette,sizeof(T_Palette)); + memcpy(backup_palette ,Main_palette,sizeof(T_Palette)); + memcpy(temp_palette,Main_palette,sizeof(T_Palette)); + + Window_set_palette_button(5,79); // 1 + + Window_display_frame (173, 67,121,116); + Window_display_frame (128, 16, 91, 39); + Window_display_frame (221, 16, 73, 39); + // Frame creux destiné à l'affichage de la(les) couleur(s) sélectionnée(s) + Window_display_frame_in(259, 88, 26, 74); + + // Graduation des jauges de couleur + Block(Window_pos_X+(Menu_factor_X*179),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*206),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*233),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*179),Window_pos_Y+(Menu_factor_Y*125),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*206),Window_pos_Y+(Menu_factor_Y*125),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*233),Window_pos_Y+(Menu_factor_Y*125),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*179),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*206),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + Block(Window_pos_X+(Menu_factor_X*233),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); + // Jauges de couleur + Palette_view_is_RGB=1; + 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 + 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); + + 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 + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*89),Menu_factor_X*24,Menu_factor_Y*72,Back_color); + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + + // Affichage des valeurs de la couleur courante (pour 1 couleur) + Format_componant(Main_palette[Fore_color].R*Color_max/255,str); + Print_counter(176,172,str,MC_Black,MC_Light); + Format_componant(Main_palette[Fore_color].G*Color_max/255,str); + Print_counter(203,172,str,MC_Black,MC_Light); + Format_componant(Main_palette[Fore_color].B*Color_max/255,str); + Print_counter(230,172,str,MC_Black,MC_Light); + + Print_in_window(129,58,"Color number:",MC_Dark,MC_Light); + Num2str(Fore_color,str,3); + Print_in_window(237,58,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(239,20,51,14,"Reduce" ,1,1,SDLK_r); // 11 + Print_in_window(241,41,"to",MC_Dark,MC_Light); + + 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 + + button_used = Window_set_normal_button(132,20,83,14,"Used: ???",4,1,SDLK_d);// 15 + Window_set_normal_button(132,37,83,14,"Zap unused",0,1,SDLK_DELETE);//16 + + // Jauge de réduction de palette + reduce_slider = Window_set_scroller_button(225,20,31,7,1,reducer_index);// 17 + + Window_set_repeatable_button(266, 74,12,11,"+",0,1,SDLK_KP_PLUS); // 18 + Window_set_repeatable_button(266,165,12,11,"-",0,1,SDLK_KP_MINUS); // 19 + + Window_set_normal_button(96,17,29,14,"Neg" ,1,1,SDLK_n); // 20 + Window_set_normal_button(66,62,29,14,"Inv" ,1,1,SDLK_i); // 21 + Window_set_normal_button( 6,62,59,14,"X-Inv." ,5,1,SDLK_v); // 22 + + Window_set_input_button(263,39,3); // 23 + + Window_set_normal_button(96,32,29,14,"HSL" ,1,1,SDLK_h); // 24 + Window_set_normal_button(96,47,29,14,"Srt" ,1,1,SDLK_s); // 25 + // Affichage du facteur de réduction de la palette + Num2str(reduce_colors_number,str,3); + Print_in_window(265,41,str,MC_Black,MC_Light); + + // 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); + + Update_window_area(0,0,299,188); + + Display_cursor(); + + if (Config.Auto_nb_used) + Update_color_count(&used_colors,color_usage); + + do + { + old_mouse_x=Mouse_X; + old_mouse_y=Mouse_Y; + old_mouse_k=Mouse_K; + clicked_button=Window_clicked_button(); + + switch (clicked_button) + { + case 0 : // Nulle part + break; + case -1 : // Hors de la fenêtre + case 1 : // palette + if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) + { + Hide_cursor(); + temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); + if (Mouse_K==RIGHT_SIDE) + { + if (Back_color!=temp_color) + { + Back_color=temp_color; + // 4 blocks de back_color entourant la fore_color + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*157),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); + Block(Window_pos_X+(Menu_factor_X*280),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); + Update_rect(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*32,Menu_factor_Y*72); + } + } + else + { + if (!old_mouse_k) + { + // On vient de clicker sur une couleur (et une seule) + if ( (Fore_color!=temp_color) || (block_start!=block_end) ) + { + // La couleur en question est nouvelle ou elle annule un + // ancien bloc. Il faut donc sélectionner cette couleur comme + // unique couleur choisie. + + Fore_color=first_color=last_color=block_start=block_end=temp_color; + Tag_color_range(block_start,block_end); + + // Affichage du n° de la couleur sélectionnée + Block(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y*7,MC_Light); + Num2str(Fore_color,str,3); + Print_in_window(237,58,str,MC_Black,MC_Light); + Update_rect(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y*7); + + // Affichage des jauges + Block(Window_pos_X+(Menu_factor_X*176),Window_pos_Y+(Menu_factor_Y*172),Menu_factor_X*84,Menu_factor_Y*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 + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); + + memcpy(backup_palette ,working_palette,sizeof(T_Palette)); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + } + } + else + { + // On maintient le click, on va donc tester si le curseur bouge + if (temp_color!=last_color) + { + // On commence par ordonner la 1ère et dernière couleur du bloc + if (first_colortemp_color) + { + block_start=temp_color; + block_end=first_color; + + // Affichage du n° de la couleur sélectionnée + Num2str(block_start,str ,3); + Num2str(block_end ,str+4,3); + str[3]=26; // Flèche vers la droite + Print_in_window(237,58,str,MC_Black,MC_Light); + + // 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); + } + else + { + block_start=block_end=first_color; + Block(Window_pos_X+(Menu_factor_X*176),Window_pos_Y+(Menu_factor_Y*172),Menu_factor_X*84,Menu_factor_Y*7,MC_Light); + + // Affichage du n° de la couleur sélectionnée + Block(Window_pos_X+(Menu_factor_X*261),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*32,Menu_factor_Y*7,MC_Light); + Num2str(Fore_color,str,3); + Print_in_window(237,58,str,MC_Black,MC_Light); + + // 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 + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); + } + + // On tagge le bloc (ou la couleur) + Tag_color_range(block_start,block_end); + } + + last_color=temp_color; + } + } + Display_cursor(); + } + break; + case 2 : // Jauge rouge + Hide_cursor(); + if (block_start==block_end) + { + 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_max/255,str); + } + else + { + HSL_to_RGB( + 255-red_slider->Position, + 255-green_slider->Position, + 255-blue_slider->Position, + &working_palette[Fore_color].R, + &working_palette[Fore_color].G, + &working_palette[Fore_color].B); + Format_componant((int)255-red_slider->Position,str); + } + Print_counter(176,172,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); + } + else + { + for (i=block_start; i<=block_end; i++) + Set_HSL( + temp_palette, + working_palette, + i, + Color_max-red_slider->Position, + Color_max-green_slider->Position, + Color_max-blue_slider->Position + ); + } + + if (red_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-red_slider->Position),str,4); + str[0]='-'; + } + else if (red_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(176,172,str,MC_Black,MC_Light); + + } + + need_to_remap=1; + + Display_cursor(); + Set_palette(working_palette); + break; + case 3 : // Jauge verte + Hide_cursor(); + if (block_start==block_end) + { + 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_max/255,str); + } + else + { + HSL_to_RGB( + 255-red_slider->Position, + 255-green_slider->Position, + 255-blue_slider->Position, + &working_palette[Fore_color].R, + &working_palette[Fore_color].G, + &working_palette[Fore_color].B); + Format_componant((int)255-green_slider->Position,str); + } + Print_counter(203,172,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); + } + else + { + for (i=block_start; i<=block_end; i++) + Set_HSL( + temp_palette, + working_palette, + i, + Color_max-red_slider->Position, + Color_max-green_slider->Position, + Color_max-blue_slider->Position + ); + } + + if (green_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-green_slider->Position),str,4); + str[0]='-'; + } + else if (green_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(203,172,str,MC_Black,MC_Light); + } + + need_to_remap=1; + + Display_cursor(); + Set_palette(working_palette); + break; + + case 4 : // Jauge bleue + Hide_cursor(); + if (block_start==block_end) + { + 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_max/255,str); + } + else + { + HSL_to_RGB( + 255-red_slider->Position, + 255-green_slider->Position, + 255-blue_slider->Position, + &working_palette[Fore_color].R, + &working_palette[Fore_color].G, + &working_palette[Fore_color].B); + Format_componant((int)255-blue_slider->Position,str); + } + Print_counter(230,172,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); + } + else + { + for (i=block_start; i<=block_end; i++) + Set_HSL( + temp_palette, + working_palette, + i, + Color_max-red_slider->Position, + Color_max-green_slider->Position, + Color_max-blue_slider->Position + ); + } + + if (blue_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-blue_slider->Position),str,4); + str[0]='-'; + } + else if (blue_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(230,172,str,MC_Black,MC_Light); + } + + need_to_remap=1; + + Display_cursor(); + 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); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + // On prépare la "modifiabilité" des nouvelles couleurs + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + + need_to_remap=1; + break; + + case 6 : // Grey scale + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + // Grey Scale + for (i=block_start;i<=block_end;i++) + { + temp_color=(dword)( ((dword)working_palette[i].R*30) + ((dword)working_palette[i].G*59) + ((dword)working_palette[i].B*11) )/100; + Set_red(i,temp_color,working_palette); + Set_green (i,temp_color,working_palette); + Set_blue (i,temp_color,working_palette); + } + 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 7 : // Swap + case 8 : // X-Swap + temp_color=Wait_click_in_palette(Window_palette_button_list); + if ((temp_color>=0) + && (temp_color!=block_start)) + { + Hide_cursor(); + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + + // On calcule le nombre de couleurs a swapper sans risquer de sortir + // de la palette (La var. first_color est utilisée pour économiser 1 var; c'est tout) + first_color=(temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color; + + if (clicked_button==8) // On ne fait de backup de l'image que si on + // est en mode X-SWAP. + if (!image_is_backed_up) + { + Backup(); + image_is_backed_up=1; + } + + Swap(clicked_button==8,block_start,temp_color,first_color,working_palette,color_usage); + + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + + // On déplace le bloc vers les modifs: + last_color=block_end=temp_color+first_color-1; + Fore_color=first_color=block_start=temp_color; + // On raffiche le n° des bornes du bloc: + if (block_start!=block_end) + { + // Cas d'un bloc multi-couleur + Num2str(block_start,str ,3); + 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); + } + else + { + // Cas d'une seule couleur + Num2str(Fore_color,str,3); + Block(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y* 7,MC_Light); + // Affichage dans le block de visu de la couleur en cours + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + } + Print_in_window(237,58,str,MC_Black,MC_Light); + // On tag le bloc (ou la couleur) + Tag_color_range(block_start,block_end); + + need_to_remap=1; + + Set_palette(working_palette); + + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + + // En cas de X-Swap, tout l'ecran a pu changer de couleur. + if (clicked_button==8) + Update_rect(0, 0, Screen_width, Menu_Y_before_window); + Wait_end_of_click(); + } + break; + + case 9 : // Copy + temp_color=Wait_click_in_palette(Window_palette_button_list); + if ((temp_color>=0) && (temp_color!=block_start)) + { + Hide_cursor(); + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + memcpy(working_palette+temp_color,backup_palette+block_start, + ((temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color)*3); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + Set_palette(working_palette); + // On déplace le bloc vers les modifs: + last_color=block_end=((temp_color+block_end-block_start<=255)?(temp_color+block_end-block_start):255); + Fore_color=first_color=block_start=temp_color; + // On raffiche le n° des bornes du bloc: + if (block_start!=block_end) + { + // Cas d'un bloc multi-couleur + Num2str(block_start,str ,3); + 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); + } + else + { + // Cas d'une seule couleur + Num2str(Fore_color,str,3); + Block(Window_pos_X+(Menu_factor_X*237),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*56,Menu_factor_Y* 7,MC_Light); + // Affichage dans le block de visu de la couleur en cours + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + } + Print_in_window(237,58,str,MC_Black,MC_Light); + // On tag le bloc (ou la couleur) + Tag_color_range(block_start,block_end); + + need_to_remap=1; + + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + Wait_end_of_click(); + } + break; + + case 10 : // Spread + if (block_start!=block_end) + { + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + Spread_colors(block_start,block_end,working_palette); + } + else + { + temp_color=Wait_click_in_palette(Window_palette_button_list); + if (temp_color>=0) + { + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + if (temp_colorPosition) + { + reducer_index=reduce_slider->Position; + // Affichage du facteur de réduction de la palette + Hide_cursor(); + Print_in_window(265,41,Palette_reduce_label[reducer_index],MC_Black,MC_Light); + Display_cursor(); + reduce_colors_number=atoi(Palette_reduce_label[reducer_index]); + } + break; + + case 18 : // [+] + if (!Palette_view_is_RGB) + break; + Hide_cursor(); + if (block_start==block_end) + { + if (red_slider->Position) + { + (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_max/255,str); + Print_counter(176,172,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_max/255,str); + Print_counter(203,172,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_max/255,str); + Print_counter(230,172,str,MC_Black,MC_Light); + } + } + else + { + if (red_slider->Position) + { + (red_slider->Position)--; + Window_draw_slider(red_slider); + } + if (green_slider->Position) + { + (green_slider->Position)--; + Window_draw_slider(green_slider); + } + if (blue_slider->Position) + { + (blue_slider->Position)--; + Window_draw_slider(blue_slider); + } + + 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); + } + + // -- red -- + if (red_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-red_slider->Position),str,4); + str[0]='-'; + } + else if (red_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(176,172,str,MC_Black,MC_Light); + + + // -- green -- + if (green_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-green_slider->Position),str,4); + str[0]='-'; + } + else if (green_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(203,172,str,MC_Black,MC_Light); + + + // -- blue -- + if (blue_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-blue_slider->Position),str,4); + str[0]='-'; + } + else if (blue_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(230,172,str,MC_Black,MC_Light); + } + + need_to_remap=1; + + Display_cursor(); + Set_palette(working_palette); + break; + + case 19 : // [-] + if (!Palette_view_is_RGB) + break; + Hide_cursor(); + if (block_start==block_end) + { + if (red_slider->PositionPosition)++; + 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_max/255,str); + Print_counter(176,172,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_max/255,str); + Print_counter(203,172,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_max/255,str); + Print_counter(230,172,str,MC_Black,MC_Light); + } + } + else + { + if (red_slider->Position<(Color_max*2)) + { + (red_slider->Position)++; + Window_draw_slider(red_slider); + } + if (green_slider->Position<(Color_max*2)) + { + (green_slider->Position)++; + Window_draw_slider(green_slider); + } + if (blue_slider->Position<(Color_max*2)) + { + (blue_slider->Position)++; + Window_draw_slider(blue_slider); + } + + 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); + } + + // -- red -- + if (red_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-red_slider->Position),str,4); + str[0]='-'; + } + else if (red_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(176,172,str,MC_Black,MC_Light); + + + // -- green -- + if (green_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-green_slider->Position),str,4); + str[0]='-'; + } + else if (green_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(203,172,str,MC_Black,MC_Light); + + + // -- blue -- + if (blue_slider->Position>Color_max) + { + // Jauge dans les négatifs: + Num2str(-(Color_max-blue_slider->Position),str,4); + str[0]='-'; + } + else if (blue_slider->PositionPosition ,str,4); + str[0]='+'; + } + else + { + // Jauge nulle: + strcpy(str,"± 0"); + } + Print_counter(230,172,str,MC_Black,MC_Light); + } + + need_to_remap=1; + + Display_cursor(); + Set_palette(working_palette); + break; + + case 20 : // Negative + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + // Negative + for (i=block_start;i<=block_end;i++) + { + Set_red(i,255-working_palette[i].R,working_palette); + Set_green (i,255-working_palette[i].G,working_palette); + Set_blue (i,255-working_palette[i].B,working_palette); + } + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + Set_palette(working_palette); + // On prépare la "modifiabilité" des nouvelles couleurs + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + + need_to_remap=1; + break; + + case 21 : // Inversion + case 22 : // X-Inversion + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + // On initialise la table de conversion + for (i=0; i<=255; i++) + conversion_table[i]=i; + // Inversion + for (i=block_start;i<=block_end;i++) + { + temp_color=block_end-(i-block_start); + Set_red(i,backup_palette[temp_color].R,working_palette); + Set_green (i,backup_palette[temp_color].G,working_palette); + Set_blue (i,backup_palette[temp_color].B,working_palette); + if (clicked_button==22) + { + conversion_table[i]=temp_color; + conversion_table[temp_color]=i; + + temp=color_usage[i]; + color_usage[i]=color_usage[temp_color]; + color_usage[temp_color]=temp; + } + } + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + // Si on est en X-Invert, on remap l'image (=> on fait aussi 1 backup) + if (clicked_button==22) + { + if (!image_is_backed_up) + { + Backup(); + image_is_backed_up=1; + } + Hide_cursor(); + Remap_image_highlevel(conversion_table); + Display_cursor(); + } + // 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 23 : // Saisie du nombre de couleurs pour la réduction de palette + Num2str(reduce_colors_number,str,3); + + if (Readline(265,41,str,3,1)) + { + temp_color=atoi(str); + // Correction de la valeur lue + if ( (temp_color>256) || (temp_color<2) ) + { + if (temp_color>256) + temp_color=256; + else + temp_color=2; + + Num2str(temp_color,str,3); + Window_input_content(Window_special_button_list,str); + } + + reduce_colors_number=temp_color; + } + Display_cursor(); + break; + + case 24 : // HSL <> RGB + + // Acte les changements en cours sur une ou plusieurs couleurs + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + memcpy(backup_palette ,working_palette,sizeof(T_Palette)); + + 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); + + // 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); + } + 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); + + // 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); + } + Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); + Update_window_area(265,73,14,103); + break; + + case 25 : // Sort palette + { + byte h = 0, l = 0, s=0; + byte oh=0,ol=0,os=0; // Valeur pour la couleur précédente + int swap=1; + byte remap_table[256]; + byte inverted_table[256]; + byte begin, end; + + if(block_start==block_end) + { + begin = 0; + end = 255; + } + else + { + begin = block_start; + end = block_end; + } + + // Init remap table + for (i=0;i<256;i++) + remap_table[i]=i; + // Make a backup because remapping is an undoable modification + if (!image_is_backed_up) + { + Backup(); + image_is_backed_up=1; + } + + if(Window_attribute1==LEFT_SIDE) + // Laft click on button: Sort by Hue (H) and Lightness (L) + while(swap==1) + { + swap=0; + h=0;l=255;s=0; + for(temp_color=begin;temp_color<=end;temp_color++) + { + oh=h; ol=l; os=s; + RGB_to_HSL(working_palette[temp_color].R, + working_palette[temp_color].G, + working_palette[temp_color].B,&h,&s,&l); + + if( + ((s==0) && (os>0)) // A grey is before a saturated color + || ((s>0 && os > 0) && (hol))) // 2 saturated colors: sort by H, then by L + || ((os==0 && s==0) && l>ol)) // Two greys: sort by L only + { + // Swap color with the previous one + byte swap_color; + Swap(0,temp_color,temp_color-1,1,working_palette,color_usage); + + swap_color=remap_table[temp_color]; + remap_table[temp_color]=remap_table[temp_color-1]; + remap_table[temp_color-1]=swap_color; + + swap=1; + } + } + } + + else // Right click > Sort only on L + while(swap==1) + { + swap=0; + l=255; + for(temp_color=begin;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); + + if(l>ol) + { + // Swap color with the previous one + byte swap_color; + Swap(0,temp_color,temp_color-1,1,working_palette,color_usage); + + swap_color=remap_table[temp_color]; + remap_table[temp_color]=remap_table[temp_color-1]; + remap_table[temp_color-1]=swap_color; + + swap=1; + } + } + } + + for (i=0;i<256;i++) + inverted_table[remap_table[i]]=i; + Remap_image_highlevel(inverted_table); + // Maintenant, tous ces calculs doivent êtres pris en compte dans la + // palette, l'image et à l'écran. + Set_palette(working_palette); + need_to_remap=1; + } + break; + } + + + if (!Mouse_K) + { + switch (Key) + { + case SDLK_LEFTBRACKET : // Décaler Forecolor vers la gauche + if (block_start==block_end) + { + Fore_color--; + first_color--; + last_color--; + block_start--; + block_end--; + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + Hide_cursor(); + 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,58,str,MC_Black,MC_Light); + // Affichage dans le block de visu de la couleur en cours + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); + Display_cursor(); + } + Key=0; + break; + + case SDLK_RIGHTBRACKET : // Décaler Forecolor vers la droite + if (block_start==block_end) + { + Fore_color++; + first_color++; + last_color++; + block_start++; + block_end++; + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + Hide_cursor(); + 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,58,str,MC_Black,MC_Light); + // Affichage dans le block de visu de la couleur en cours + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); + Display_cursor(); + } + Key=0; + break; + + case (SDLK_LEFTBRACKET|MOD_SHIFT) : // Decaler Backcolor vers la gauche + Back_color--; + case (SDLK_RIGHTBRACKET|MOD_SHIFT) : // Decaler Backcolor vers la droite + // attention: pas de break ci-dessus + if (Key==(SDLK_RIGHTBRACKET|MOD_SHIFT)) + Back_color++; + Hide_cursor(); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*157),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); + Block(Window_pos_X+(Menu_factor_X*280),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); + Update_rect(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*32,Menu_factor_Y*72); + Display_cursor(); + Key=0; + break; + + case SDLK_BACKSPACE : // Remise des couleurs du menu à l'état normal en essayant + // de ne pas trop modifier l'image. + if (!image_is_backed_up) + { + Backup(); + image_is_backed_up=1; + } + if (used_colors==-1) + Update_color_count(&used_colors,color_usage); + + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + memcpy(temp_palette,Main_palette,sizeof(T_Palette)); + memcpy(Main_palette,working_palette,sizeof(T_Palette)); + Set_nice_menu_colors(color_usage,0); + memcpy(working_palette,Main_palette,sizeof(T_Palette)); + memcpy(Main_palette,temp_palette,sizeof(T_Palette)); + Set_palette(working_palette); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + Update_color_count(&used_colors,color_usage); + need_to_remap=1; + Key=0; + break; + + case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu + case SDLK_COMMA : + Get_color_behind_window(&color,&click); + if (click) + { + Hide_cursor(); + if (click==RIGHT_SIDE) + { + if (Back_color!=color) + { + Back_color=color; + // 4 blocks de back_color entourant la fore_color + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*157),Menu_factor_X*24,Menu_factor_Y<<2,Back_color); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); + Block(Window_pos_X+(Menu_factor_X*280),Window_pos_Y+(Menu_factor_Y* 93),Menu_factor_X<<2,Menu_factor_Y<<6,Back_color); + Update_rect(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y* 89),Menu_factor_X*32,Menu_factor_Y*72); + } + } + else + { + Fore_color=first_color=last_color=block_start=block_end=color; + Tag_color_range(block_start,block_end); + + // Affichage du n° de la couleur sélectionnée + Block(Window_pos_X+(Menu_factor_X*261),Window_pos_Y+(Menu_factor_Y*58),Menu_factor_X*32,Menu_factor_Y*7,MC_Light); + Num2str(Fore_color,str,3); + Print_in_window(237,58,str,MC_Black,MC_Light); + + // 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 + Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); + Update_rect(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64); + + memcpy(backup_palette ,working_palette,sizeof(T_Palette)); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + } + Display_cursor(); + Wait_end_of_click(); + } + Key=0; + break; + default: + if (Is_shortcut(Key,0x100+BUTTON_HELP)) + { + Key=0; + Window_help(BUTTON_PALETTE, NULL); + break; + } + } + + if (need_to_remap) + { + Hide_cursor(); + Compute_optimal_menu_colors(working_palette); + + // On remappe brutalement + Remap_screen_after_menu_colors_change(); + // Puis on remet les trucs qui ne devaient pas changer + Window_draw_palette_bouton(5,79); + Block(Window_pos_X+(Menu_factor_X*260),Window_pos_Y+(Menu_factor_Y*89),Menu_factor_X*24,Menu_factor_Y*72,Back_color); + Display_grad_block_in_window(264,93,block_start,block_end); + + Update_rect(Window_pos_X+8*Menu_factor_X,Window_pos_Y+82*Menu_factor_Y,Menu_factor_X*16*10,Menu_factor_Y*5*16); + + Display_cursor(); + need_to_remap=0; + } + } + } + while ((clicked_button!=13) && (clicked_button!=14)); + + if (clicked_button==14) // Sortie par OK + { + if ( (!image_is_backed_up) + && memcmp(Main_palette,working_palette,sizeof(T_Palette)) ) + Backup(); + memcpy(Main_palette,working_palette,sizeof(T_Palette)); + } + + Compute_optimal_menu_colors(Main_palette); + + // La variable employée ici n'a pas vraiment de rapport avec son nom... + need_to_remap=(Window_pos_Y+(Window_height*Menu_factor_Y)Position = rgb_scale_slider->Position>128?rgb_scale_slider->Position*2-256:0; + Num2str(256-rgb_scale_slider->Position,str,3); + Print_in_window(157,78,str,MC_Black,MC_Light); + Window_draw_slider(rgb_scale_slider); + break; + + case 10: + // /2 RGB scale + rgb_scale_slider->Position = rgb_scale_slider->Position>253?254:(rgb_scale_slider->Position)/2+128; + Num2str(256-rgb_scale_slider->Position,str,3); + Print_in_window(157,78,str,MC_Black,MC_Light); + Window_draw_slider(rgb_scale_slider); + } + } + while (clicked_button!=1 && clicked_button!=2 && clicked_button!=3 && clicked_button!=4); + + // We need to get the sliders positions before closing the window, because they will be freed. + palette_cols=256-columns_slider->Position; + palette_lines=16-lines_slider->Position; + rgb_scale=256-rgb_scale_slider->Position; + + Close_window(); + Unselect_button(BUTTON_PALETTE); + Display_cursor(); + + if (clicked_button==4) // Cancel + return; + + if (palette_vertical != Config.Palette_vertical) + { + Config.Palette_vertical=palette_vertical; + palette_needs_redraw=1; + } + if (palette_cols!=Config.Palette_cells_X || + palette_lines!=Config.Palette_cells_Y) + { + Config.Palette_cells_X = palette_cols; + Config.Palette_cells_Y = palette_lines; + palette_needs_redraw=1; + } + if (rgb_scale!=RGB_scale) + { + Set_palette_RGB_scale(rgb_scale); + Set_palette(Main_palette); + } + + if (clicked_button==1) + { + Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL); + } + else if (clicked_button==2) + { + // Open the menu with Shade settings. Same as the shortcut, except + // that this will not activate shade mode on exit. + Shade_settings_menu(); + } + + if (palette_needs_redraw) + { + Change_palette_cells(); + Display_menu(); + Display_sprite_in_menu(BUTTON_PAL_LEFT,18+(Config.Palette_vertical!=0)); + } +} diff --git a/palette.h b/palette.h index 273f792b..e28f280c 100644 --- a/palette.h +++ b/palette.h @@ -1,42 +1,42 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ -////////////////////////////////////////////////////////////////////////////// -///@file palette.h -/// Palette screen, and some palette-related high-level functions. -////////////////////////////////////////////////////////////////////////////// - -/// Open the palette menu and handles everything inside it. -void Button_Palette(void); -/// Open the secondary palette menu and handles it. -void Button_Secondary_palette(void); - -/// Choose the number of graduations for RGB components, from 2 to 256. -void Set_palette_RGB_scale(int); - -/// -/// Scale a component (R, G or B) according to the current RGB graduations. -/// Returns the resulting value, in the [0-255] range. -byte Round_palette_component(byte comp); - -/*! - Adds 4 menu colors in the current palette. - @param color_usage An up-to-date color usage table (byte[256]) (read only) - @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); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ +////////////////////////////////////////////////////////////////////////////// +///@file palette.h +/// Palette screen, and some palette-related high-level functions. +////////////////////////////////////////////////////////////////////////////// + +/// Open the palette menu and handles everything inside it. +void Button_Palette(void); +/// Open the secondary palette menu and handles it. +void Button_Secondary_palette(void); + +/// Choose the number of graduations for RGB components, from 2 to 256. +void Set_palette_RGB_scale(int); + +/// +/// Scale a component (R, G or B) according to the current RGB graduations. +/// Returns the resulting value, in the [0-255] range. +byte Round_palette_component(byte comp); + +/*! + Adds 4 menu colors in the current palette. + @param color_usage An up-to-date color usage table (byte[256]) (read only) + @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); diff --git a/pxdouble.c b/pxdouble.c index a52ec1a2..78b4f8e0 100644 --- a/pxdouble.c +++ b/pxdouble.c @@ -1,497 +1,497 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxdouble.h" -#include "pxwide.h" // for Display_transparent_line_on_screen_wide() - -#define ZOOMX 2 -#define ZOOMY 2 - -void Pixel_double (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH + 1)=color; -} - -byte Read_pixel_double (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_double (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_double (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_double (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_double (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_double( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_double(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *dest=*(dest+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=~*dest; - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_double(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_double(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_double(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_double(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_double(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_double(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_double( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_double(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_double(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_double( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_fast_double(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxdouble.h" +#include "pxwide.h" // for Display_transparent_line_on_screen_wide() + +#define ZOOMX 2 +#define ZOOMY 2 + +void Pixel_double (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH + 1)=color; +} + +byte Read_pixel_double (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_double (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_double (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_double (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_double (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_double( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_double(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *dest=*(dest+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=~*dest; + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_double(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_double(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_double(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_double(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_double(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_double(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_double( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_double(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_double(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_double( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + Display_line_on_screen_fast_double(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxdouble.h b/pxdouble.h index e7655ce9..3d8296f8 100644 --- a/pxdouble.h +++ b/pxdouble.h @@ -1,48 +1,48 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxdouble.h -/// Renderer for double pixels (2x2). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_double (word x,word y,byte color); - byte Read_pixel_double (word x,word y); - void Block_double (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_double (word x,word y,byte color); - void Pixel_preview_magnifier_double (word x,word y,byte color); - void Horizontal_XOR_line_double (word x_pos,word y_pos,word width); - void Vertical_XOR_line_double (word x_pos,word y_pos,word height); - void Display_brush_color_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_double (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_double (word width,word height,word image_width); - void Display_line_on_screen_double (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_double (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_double(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_double (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_double (word x_pos,word y_pos,word width,byte * line); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxdouble.h +/// Renderer for double pixels (2x2). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_double (word x,word y,byte color); + byte Read_pixel_double (word x,word y); + void Block_double (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_double (word x,word y,byte color); + void Pixel_preview_magnifier_double (word x,word y,byte color); + void Horizontal_XOR_line_double (word x_pos,word y_pos,word width); + void Vertical_XOR_line_double (word x_pos,word y_pos,word height); + void Display_brush_color_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_double (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_double (word width,word height,word image_width); + void Display_line_on_screen_double (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_double (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_double(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_double (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_double (word x_pos,word y_pos,word width,byte * line); diff --git a/pxquad.c b/pxquad.c index b257e316..fc401181 100644 --- a/pxquad.c +++ b/pxquad.c @@ -1,532 +1,532 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxquad.h" - -#define ZOOMX 4 -#define ZOOMY 4 - -void Pixel_quad (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 3)=color; -} - -byte Read_pixel_quad (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_quad (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_quad (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la triple - memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la quadruple - memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_quad (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_quad (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_quad( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_quad(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+3) = *(dest+3*VIDEO_LINE_WIDTH+2) = *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+3) = *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_quad(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_quad(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_quad(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_quad(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_quad(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_quad(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_quad( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_quad(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Triple the line - memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Quadruple it - memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_quad(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_quad( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_quad(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxquad.h" + +#define ZOOMX 4 +#define ZOOMY 4 + +void Pixel_quad (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 3)=color; +} + +byte Read_pixel_quad (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_quad (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_quad (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la triple + memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la quadruple + memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_quad (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_quad (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_quad( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_quad(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+3) = *(dest+3*VIDEO_LINE_WIDTH+2) = *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+3) = *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_quad(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_quad(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_quad(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_quad(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_quad(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_quad(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_quad( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_quad(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Triple the line + memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Quadruple it + memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_quad(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_quad( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_quad(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxquad.h b/pxquad.h index e5618472..66ed0713 100644 --- a/pxquad.h +++ b/pxquad.h @@ -1,48 +1,48 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxquad.h -/// Renderer for quadruple pixels (4x4). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_quad (word x,word y,byte color); - byte Read_pixel_quad (word x,word y); - void Block_quad (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_quad (word x,word y,byte color); - void Pixel_preview_magnifier_quad (word x,word y,byte color); - void Horizontal_XOR_line_quad (word x_pos,word y_pos,word width); - void Vertical_XOR_line_quad (word x_pos,word y_pos,word height); - void Display_brush_color_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_quad (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_quad (word width,word height,word image_width); - void Display_line_on_screen_quad (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_quad (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_quad(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_quad (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_quad (word x_pos,word y_pos,word width,byte * line); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxquad.h +/// Renderer for quadruple pixels (4x4). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_quad (word x,word y,byte color); + byte Read_pixel_quad (word x,word y); + void Block_quad (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_quad (word x,word y,byte color); + void Pixel_preview_magnifier_quad (word x,word y,byte color); + void Horizontal_XOR_line_quad (word x_pos,word y_pos,word width); + void Vertical_XOR_line_quad (word x_pos,word y_pos,word height); + void Display_brush_color_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_quad (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_quad (word width,word height,word image_width); + void Display_line_on_screen_quad (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_quad (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_quad(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_quad (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_quad (word x_pos,word y_pos,word width,byte * line); diff --git a/pxsimple.c b/pxsimple.c index c18020f0..35650b6f 100644 --- a/pxsimple.c +++ b/pxsimple.c @@ -1,470 +1,470 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxsimple.h" - -void Pixel_simple (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x + y * VIDEO_LINE_WIDTH)=color; -} - -byte Read_pixel_simple (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * VIDEO_LINE_WIDTH + x ); -} - -void Block_simple (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x; - rectangle.y=start_y; - rectangle.w=width; - rectangle.h=height; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_simple (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_simple (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_simple (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_simple( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_simple(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; - - int x; - - for (x=0;x 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH - width; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_simple(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *dest=color; - - // On passe au pixel suivant - src++; - dest++; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH-width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_simple(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_simple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH - width; - src = src + brush_width - width; - } -} - -void Remap_screen_simple(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *dest = conversion_table[*dest]; - dest ++; - } - - dest = dest + VIDEO_LINE_WIDTH - width; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_simple(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels. Utilisé pour les textes. */ -{ - memcpy(Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH,line,width); -} - -void Display_transparent_mono_line_on_screen_simple( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos * VIDEO_LINE_WIDTH + x_pos; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color) -{ - byte* src = line; - byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; - - word x; - - // Pour chaque pixel de la ligne - for(x = width;x > 0;x--) - { - if(*src!=transp_color) - *dest = *src; - src++; - dest++; - } -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_simple(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_simple(x_pos,y,width*Main_magnifier_factor,buffer,transp_color); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_simple(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_simple( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_simple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_simple(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxsimple.h" + +void Pixel_simple (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x + y * VIDEO_LINE_WIDTH)=color; +} + +byte Read_pixel_simple (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * VIDEO_LINE_WIDTH + x ); +} + +void Block_simple (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x; + rectangle.y=start_y; + rectangle.w=width; + rectangle.h=height; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_simple (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + memcpy(dest,src,width); + + // On passe à la ligne suivante + src+=image_width; + dest+=VIDEO_LINE_WIDTH; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_simple (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_simple (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_simple( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_simple(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; + + int x; + + for (x=0;x 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *dest = *src; + } + + // Pixel suivant + src++; dest++; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH - width; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_simple(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *dest=color; + + // On passe au pixel suivant + src++; + dest++; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH-width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_simple(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + memcpy(dest,src,width); + + // On passe à la ligne suivante + src+=image_width; + dest+=VIDEO_LINE_WIDTH; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_simple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *dest = *src; + } + + // Pixel suivant + src++; dest++; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH - width; + src = src + brush_width - width; + } +} + +void Remap_screen_simple(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *dest = conversion_table[*dest]; + dest ++; + } + + dest = dest + VIDEO_LINE_WIDTH - width; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_simple(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels. Utilisé pour les textes. */ +{ + memcpy(Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH,line,width); +} + +void Display_transparent_mono_line_on_screen_simple( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos * VIDEO_LINE_WIDTH + x_pos; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color) +{ + byte* src = line; + byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; + + word x; + + // Pour chaque pixel de la ligne + for(x = width;x > 0;x--) + { + if(*src!=transp_color) + *dest = *src; + src++; + dest++; + } +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_simple(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + Display_transparent_line_on_screen_simple(x_pos,y,width*Main_magnifier_factor,buffer,transp_color); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_simple(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_simple( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_simple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + Display_line_on_screen_simple(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxsimple.h b/pxsimple.h index 2bca1cb9..785a96a5 100644 --- a/pxsimple.h +++ b/pxsimple.h @@ -1,51 +1,51 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxsimple.h -/// Renderer for simple pixels (1x1). This is the normal one. -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_simple (word x,word y,byte color); - byte Read_pixel_simple (word x,word y); - void Block_simple (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_simple (word x,word y,byte color); - void Pixel_preview_magnifier_simple (word x,word y,byte color); - void Horizontal_XOR_line_simple (word x_pos,word y_pos,word width); - void Vertical_XOR_line_simple (word x_pos,word y_pos,word height); - void Display_brush_color_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_simple (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_simple (word width,word height,word image_width); - void Display_line_on_screen_simple (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_simple (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_simple(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_simple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - -void Display_transparent_mono_line_on_screen_simple( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color); -void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxsimple.h +/// Renderer for simple pixels (1x1). This is the normal one. +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_simple (word x,word y,byte color); + byte Read_pixel_simple (word x,word y); + void Block_simple (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_simple (word x,word y,byte color); + void Pixel_preview_magnifier_simple (word x,word y,byte color); + void Horizontal_XOR_line_simple (word x_pos,word y_pos,word width); + void Vertical_XOR_line_simple (word x_pos,word y_pos,word height); + void Display_brush_color_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_simple (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_simple (word width,word height,word image_width); + void Display_line_on_screen_simple (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_simple (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_simple(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_simple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + +void Display_transparent_mono_line_on_screen_simple( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color); +void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color); diff --git a/pxtall.c b/pxtall.c index 8e4c326e..d7e30162 100644 --- a/pxtall.c +++ b/pxtall.c @@ -1,453 +1,453 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxtall.h" -#include "pxsimple.h" - -#define ZOOMX 1 -#define ZOOMY 2 - -void Pixel_tall (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x + y*ZOOMY*VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x + (y*ZOOMY+1)*VIDEO_LINE_WIDTH)=color; -} - -byte Read_pixel_tall (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x ); -} - -void Block_tall (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x; - rectangle.y=start_y*ZOOMY; - rectangle.w=width; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_tall (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - dest+=VIDEO_LINE_WIDTH; - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_tall (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_tall (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_tall( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_tall(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; - - int x; - - for (x=0;x 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - *(dest+VIDEO_LINE_WIDTH) = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + ZOOMY*VIDEO_LINE_WIDTH - width; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_tall(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - { - *dest=color; - *(dest+VIDEO_LINE_WIDTH)=color; - } - - // On passe au pixel suivant - src++; - dest++; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=ZOOMY*VIDEO_LINE_WIDTH-width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_tall(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - dest+=VIDEO_LINE_WIDTH; - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_tall(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - *(dest+VIDEO_LINE_WIDTH) = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width; - src = src + brush_width - width; - } -} - -void Remap_screen_tall(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; - int x,y; - - // Pour chaque ligne - for(y=height*ZOOMY;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *dest = conversion_table[*dest]; - dest ++; - } - - dest = dest + VIDEO_LINE_WIDTH - width; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_tall(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels. Utilisé pour les textes. */ -{ - memcpy(Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width); - memcpy(Screen_pixels+x_pos+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width); -} - -void Read_line_screen_tall(word x_pos,word y_pos,word width,byte * line) -{ - memcpy(line,VIDEO_LINE_WIDTH*ZOOMY*y_pos + x_pos + Screen_pixels,width); -} - -void Display_part_of_screen_scaled_tall( - word width, // width non zoomée - word height, // height zoomée - word image_width,byte * buffer) -{ - byte* src = Main_screen + Main_magnifier_offset_Y * image_width - + Main_magnifier_offset_X; - int y = 0; // Ligne en cours de traitement - - // Pour chaque ligne à zoomer - while(1) - { - int x; - - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On l'affiche Facteur fois, sur des lignes consécutives - x = Main_magnifier_factor*ZOOMY; - // Pour chaque ligne - do{ - // On affiche la ligne zoomée - Display_line_on_screen_simple( - Main_X_zoom, y, width*Main_magnifier_factor, - buffer - ); - // On passe à la suivante - y++; - if(y==height*ZOOMY) - { - Update_rect(Main_X_zoom,0, - width*Main_magnifier_factor,height); - return; - } - x--; - }while (x > 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_tall(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_simple(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); - memcpy(Screen_pixels + (y*ZOOMY +1) * VIDEO_LINE_WIDTH + x_pos, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos, width*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_tall(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_simple( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_tall(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_tall(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxtall.h" +#include "pxsimple.h" + +#define ZOOMX 1 +#define ZOOMY 2 + +void Pixel_tall (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x + y*ZOOMY*VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x + (y*ZOOMY+1)*VIDEO_LINE_WIDTH)=color; +} + +byte Read_pixel_tall (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x ); +} + +void Block_tall (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x; + rectangle.y=start_y*ZOOMY; + rectangle.w=width; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_tall (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + memcpy(dest,src,width); + dest+=VIDEO_LINE_WIDTH; + memcpy(dest,src,width); + + // On passe à la ligne suivante + src+=image_width; + dest+=VIDEO_LINE_WIDTH; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_tall (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_tall (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_tall( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_tall(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; + + int x; + + for (x=0;x 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *dest = *src; + *(dest+VIDEO_LINE_WIDTH) = *src; + } + + // Pixel suivant + src++; dest++; + } + + // On passe à la ligne suivante + dest = dest + ZOOMY*VIDEO_LINE_WIDTH - width; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_tall(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + { + *dest=color; + *(dest+VIDEO_LINE_WIDTH)=color; + } + + // On passe au pixel suivant + src++; + dest++; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=ZOOMY*VIDEO_LINE_WIDTH-width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_tall(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + memcpy(dest,src,width); + dest+=VIDEO_LINE_WIDTH; + memcpy(dest,src,width); + + // On passe à la ligne suivante + src+=image_width; + dest+=VIDEO_LINE_WIDTH; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_tall(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *dest = *src; + *(dest+VIDEO_LINE_WIDTH) = *src; + } + + // Pixel suivant + src++; dest++; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width; + src = src + brush_width - width; + } +} + +void Remap_screen_tall(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; + int x,y; + + // Pour chaque ligne + for(y=height*ZOOMY;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *dest = conversion_table[*dest]; + dest ++; + } + + dest = dest + VIDEO_LINE_WIDTH - width; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_tall(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels. Utilisé pour les textes. */ +{ + memcpy(Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width); + memcpy(Screen_pixels+x_pos+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width); +} + +void Read_line_screen_tall(word x_pos,word y_pos,word width,byte * line) +{ + memcpy(line,VIDEO_LINE_WIDTH*ZOOMY*y_pos + x_pos + Screen_pixels,width); +} + +void Display_part_of_screen_scaled_tall( + word width, // width non zoomée + word height, // height zoomée + word image_width,byte * buffer) +{ + byte* src = Main_screen + Main_magnifier_offset_Y * image_width + + Main_magnifier_offset_X; + int y = 0; // Ligne en cours de traitement + + // Pour chaque ligne à zoomer + while(1) + { + int x; + + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On l'affiche Facteur fois, sur des lignes consécutives + x = Main_magnifier_factor*ZOOMY; + // Pour chaque ligne + do{ + // On affiche la ligne zoomée + Display_line_on_screen_simple( + Main_X_zoom, y, width*Main_magnifier_factor, + buffer + ); + // On passe à la suivante + y++; + if(y==height*ZOOMY) + { + Update_rect(Main_X_zoom,0, + width*Main_magnifier_factor,height); + return; + } + x--; + }while (x > 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_tall(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + Display_transparent_line_on_screen_simple(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); + memcpy(Screen_pixels + (y*ZOOMY +1) * VIDEO_LINE_WIDTH + x_pos, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos, width*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_tall(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_simple( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_tall(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + Display_line_on_screen_tall(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} diff --git a/pxtall.h b/pxtall.h index 2533b809..0499cf33 100644 --- a/pxtall.h +++ b/pxtall.h @@ -1,46 +1,46 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxtall.h -/// Renderer for tall pixels (1x2). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_tall (word x,word y,byte color); - byte Read_pixel_tall (word x,word y); - void Block_tall (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_tall (word x,word y,byte color); - void Pixel_preview_magnifier_tall (word x,word y,byte color); - void Horizontal_XOR_line_tall (word x_pos,word y_pos,word width); - void Vertical_XOR_line_tall (word x_pos,word y_pos,word height); - void Display_brush_color_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_tall (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_tall (word width,word height,word image_width); - void Display_line_on_screen_tall (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_tall (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_tall(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_tall (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxtall.h +/// Renderer for tall pixels (1x2). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_tall (word x,word y,byte color); + byte Read_pixel_tall (word x,word y); + void Block_tall (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_tall (word x,word y,byte color); + void Pixel_preview_magnifier_tall (word x,word y,byte color); + void Horizontal_XOR_line_tall (word x_pos,word y_pos,word width); + void Vertical_XOR_line_tall (word x_pos,word y_pos,word height); + void Display_brush_color_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_tall (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_tall (word width,word height,word image_width); + void Display_line_on_screen_tall (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_tall (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_tall(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_tall (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); diff --git a/pxtall2.c b/pxtall2.c index d4e4cf0e..9e046dae 100644 --- a/pxtall2.c +++ b/pxtall2.c @@ -1,524 +1,524 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxtall2.h" - -#define ZOOMX 2 -#define ZOOMY 4 - -void Pixel_tall2 (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; -} - -byte Read_pixel_tall2 (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_tall2 (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_tall2 (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la triple - memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la quadruple - memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_tall2 (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_tall2 (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_tall2( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_tall2(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=~*(dest); - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_tall2(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_tall2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_tall2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_tall2(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_tall2(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_tall2(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_tall2( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_tall2(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Triple the line - memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Quadruple it - memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_tall2(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_tall2( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_tall2(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxtall2.h" + +#define ZOOMX 2 +#define ZOOMY 4 + +void Pixel_tall2 (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; +} + +byte Read_pixel_tall2 (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_tall2 (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_tall2 (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la triple + memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la quadruple + memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_tall2 (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_tall2 (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_tall2( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_tall2(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=~*(dest); + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_tall2(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_tall2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_tall2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_tall2(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_tall2(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_tall2(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_tall2( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_tall2(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Triple the line + memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Quadruple it + memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_tall2(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_tall2( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_tall2(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxtall2.h b/pxtall2.h index 262c6e45..eaf40fe5 100644 --- a/pxtall2.h +++ b/pxtall2.h @@ -1,48 +1,48 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxtall2.h -/// Renderer for double-tall pixels (2x4). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_tall2 (word x,word y,byte color); - byte Read_pixel_tall2 (word x,word y); - void Block_tall2 (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_tall2 (word x,word y,byte color); - void Pixel_preview_magnifier_tall2 (word x,word y,byte color); - void Horizontal_XOR_line_tall2 (word x_pos,word y_pos,word width); - void Vertical_XOR_line_tall2 (word x_pos,word y_pos,word height); - void Display_brush_color_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_tall2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_tall2 (word width,word height,word image_width); - void Display_line_on_screen_tall2 (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_tall2 (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_tall2(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_tall2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_tall2 (word x_pos,word y_pos,word width,byte * line); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxtall2.h +/// Renderer for double-tall pixels (2x4). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_tall2 (word x,word y,byte color); + byte Read_pixel_tall2 (word x,word y); + void Block_tall2 (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_tall2 (word x,word y,byte color); + void Pixel_preview_magnifier_tall2 (word x,word y,byte color); + void Horizontal_XOR_line_tall2 (word x_pos,word y_pos,word width); + void Vertical_XOR_line_tall2 (word x_pos,word y_pos,word height); + void Display_brush_color_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_tall2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_tall2 (word width,word height,word image_width); + void Display_line_on_screen_tall2 (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_tall2 (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_tall2(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_tall2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_tall2 (word x_pos,word y_pos,word width,byte * line); diff --git a/pxtriple.c b/pxtriple.c index eb14ff20..4ce54c3d 100644 --- a/pxtriple.c +++ b/pxtriple.c @@ -1,520 +1,520 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxtriple.h" - -#define ZOOMX 3 -#define ZOOMY 3 - -void Pixel_triple (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; -} - -byte Read_pixel_triple (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_triple (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_triple (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+2)=*(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la triple - memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_triple (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_triple (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_triple( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_triple(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=~*dest; - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+2) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_triple(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_triple(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_triple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_triple(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_triple(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_triple(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_triple( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_triple(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+2)=*(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Triple the line - memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_triple(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_triple( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_triple(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxtriple.h" + +#define ZOOMX 3 +#define ZOOMY 3 + +void Pixel_triple (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; +} + +byte Read_pixel_triple (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_triple (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_triple (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+2)=*(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + // On la triple + memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_triple (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_triple (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_triple( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_triple(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=~*dest; + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+2) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_triple(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_triple(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_triple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_triple(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_triple(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_triple(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_triple( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_triple(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+2)=*(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + // Triple the line + memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_triple(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_triple( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_triple(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxtriple.h b/pxtriple.h index 15c03e6d..6e470548 100644 --- a/pxtriple.h +++ b/pxtriple.h @@ -1,48 +1,48 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxtriple.h -/// Renderer for triple pixels (3x3). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_triple (word x,word y,byte color); - byte Read_pixel_triple (word x,word y); - void Block_triple (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_triple (word x,word y,byte color); - void Pixel_preview_magnifier_triple (word x,word y,byte color); - void Horizontal_XOR_line_triple (word x_pos,word y_pos,word width); - void Vertical_XOR_line_triple (word x_pos,word y_pos,word height); - void Display_brush_color_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_triple (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_triple (word width,word height,word image_width); - void Display_line_on_screen_triple (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_triple (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_triple(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_triple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_triple (word x_pos,word y_pos,word width,byte * line); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxtriple.h +/// Renderer for triple pixels (3x3). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_triple (word x,word y,byte color); + byte Read_pixel_triple (word x,word y); + void Block_triple (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_triple (word x,word y,byte color); + void Pixel_preview_magnifier_triple (word x,word y,byte color); + void Horizontal_XOR_line_triple (word x_pos,word y_pos,word width); + void Vertical_XOR_line_triple (word x_pos,word y_pos,word height); + void Display_brush_color_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_triple (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_triple (word width,word height,word image_width); + void Display_line_on_screen_triple (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_triple (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_triple(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_triple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_triple (word x_pos,word y_pos,word width,byte * line); diff --git a/pxwide.c b/pxwide.c index ffabba61..204258c8 100644 --- a/pxwide.c +++ b/pxwide.c @@ -1,506 +1,506 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxwide.h" - -#define ZOOMX 2 -#define ZOOMY 1 - -void Pixel_wide (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; -} - -byte Read_pixel_wide (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_wide (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_wide (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_wide (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_wide (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_wide( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_wide(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *dest=*(dest+1)=~*dest; - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_wide(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_wide(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_wide(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_wide(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+1) = *dest = conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_wide(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_wide(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_wide( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color) -{ - byte* src = line; - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - word x; - - // Pour chaque pixel de la ligne - for(x = width;x > 0;x--) - { - if(*src!=transp_color) - { - *(dest+1) = *dest = *src; - } - src++; - dest+=ZOOMX; - } -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_wide(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_wide(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_wide( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_fast_wide(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxwide.h" + +#define ZOOMX 2 +#define ZOOMY 1 + +void Pixel_wide (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; +} + +byte Read_pixel_wide (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_wide (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_wide (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_wide (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_wide (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_wide( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_wide(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *dest=*(dest+1)=~*dest; + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_wide(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_wide(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_wide(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_wide(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+1) = *dest = conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_wide(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_wide(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_wide( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color) +{ + byte* src = line; + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + word x; + + // Pour chaque pixel de la ligne + for(x = width;x > 0;x--) + { + if(*src!=transp_color) + { + *(dest+1) = *dest = *src; + } + src++; + dest+=ZOOMX; + } +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_wide(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_wide(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_wide( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + Display_line_on_screen_fast_wide(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxwide.h b/pxwide.h index f7003c54..b1db7ec4 100644 --- a/pxwide.h +++ b/pxwide.h @@ -1,49 +1,49 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxwide.h -/// Renderer for wide pixels (2x1). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_wide (word x,word y,byte color); - byte Read_pixel_wide (word x,word y); - void Block_wide (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_wide (word x,word y,byte color); - void Pixel_preview_magnifier_wide (word x,word y,byte color); - void Horizontal_XOR_line_wide (word x_pos,word y_pos,word width); - void Vertical_XOR_line_wide (word x_pos,word y_pos,word height); - void Display_brush_color_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_wide (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_wide (word width,word height,word image_width); - void Display_line_on_screen_wide (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_wide (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_wide(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_wide (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_wide (word x_pos,word y_pos,word width,byte * line); - void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxwide.h +/// Renderer for wide pixels (2x1). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_wide (word x,word y,byte color); + byte Read_pixel_wide (word x,word y); + void Block_wide (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_wide (word x,word y,byte color); + void Pixel_preview_magnifier_wide (word x,word y,byte color); + void Horizontal_XOR_line_wide (word x_pos,word y_pos,word width); + void Vertical_XOR_line_wide (word x_pos,word y_pos,word height); + void Display_brush_color_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_wide (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_wide (word width,word height,word image_width); + void Display_line_on_screen_wide (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_wide (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_wide(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_wide (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_wide (word x_pos,word y_pos,word width,byte * line); + void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color); diff --git a/pxwide2.c b/pxwide2.c index 15358dbb..82d429fe 100644 --- a/pxwide2.c +++ b/pxwide2.c @@ -1,514 +1,514 @@ -/* 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 "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "pxwide2.h" - -#define ZOOMX 4 -#define ZOOMY 2 - -void Pixel_wide2 (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; -} - -byte Read_pixel_wide2 (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_wide2 (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_wide2 (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_wide2 (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_wide2 (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_wide2( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_wide2(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_wide2(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_wide2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_wide2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_wide2(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_wide2(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_wide2(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_wide2( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_wide2(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_wide2(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_wide2( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_wide2(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - +/* 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 "global.h" +#include "sdlscreen.h" +#include "misc.h" +#include "pxwide2.h" + +#define ZOOMX 4 +#define ZOOMY 2 + +void Pixel_wide2 (word x,word y,byte color) +/* Affiche un pixel de la color aux coords x;y à l'écran */ +{ + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; + *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; +} + +byte Read_pixel_wide2 (word x,word y) +/* On retourne la couleur du pixel aux coords données */ +{ + return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); +} + +void Block_wide2 (word start_x,word start_y,word width,word height,byte color) +/* On affiche un rectangle de la couleur donnée */ +{ + SDL_Rect rectangle; + rectangle.x=start_x*ZOOMX; + rectangle.y=start_y*ZOOMY; + rectangle.w=width*ZOOMX; + rectangle.h=height*ZOOMY; + SDL_FillRect(Screen_SDL,&rectangle,color); +} + +void Display_part_of_screen_wide2 (word width,word height,word image_width) +/* Afficher une partie de l'image telle quelle sur l'écran */ +{ + byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) + byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) + int y; + int dy; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + // On fait une copie de la ligne + for (dy=width;dy>0;dy--) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + src++; + dest+=ZOOMX; + } + // On double la ligne qu'on vient de copier + memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + //Update_rect(0,0,width,height); +} + +void Pixel_preview_normal_wide2 (word x,word y,byte color) +/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image + * dans l'écran, en mode normal (pas en mode loupe) + * Note: si on modifie cette procédure, il faudra penser à faire également + * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ +{ +// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) + Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); +} + +void Pixel_preview_magnifier_wide2 (word x,word y,byte color) +{ + // Affiche le pixel dans la partie non zoomée + Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); + + // Regarde si on doit aussi l'afficher dans la partie zoomée + if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom + && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) + { + // On est dedans + int height; + int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); + + if (Menu_Y - y_zoom < Main_magnifier_factor) + // On ne doit dessiner qu'un morceau du pixel + // sinon on dépasse sur le menu + height = Menu_Y - y_zoom; + else + height = Main_magnifier_factor; + + Block_wide2( + Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, + y_zoom, Main_magnifier_factor, height, color + ); + } +} + +void Horizontal_XOR_line_wide2(word x_pos,word y_pos,word width) +{ + //On calcule la valeur initiale de dest: + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; + + int x; + + for (x=0;x0;i--) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); + dest+=VIDEO_LINE_WIDTH*ZOOMY; + } +} + +void Display_brush_color_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = Brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; + } + + // Pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Display_brush_mono_wide2(word x_pos, word y_pos, + word x_offset, word y_offset, word width, word height, + byte transp_color, byte color, word brush_width) +/* On affiche la brosse en monochrome */ +{ + byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à + // l'écran + byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds + // la brosse + int x,y; + + for(y=height;y!=0;y--) + //Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + if (*src!=transp_color) + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=brush_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +void Clear_brush_wide2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) +{ + byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) + byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) + int y; + int x; + + for(y=height;y!=0;y--) + // Pour chaque ligne + { + for(x=width;x!=0;x--) + //Pour chaque pixel + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + + // On passe au pixel suivant + src++; + dest+=ZOOMX; + } + + // On passe à la ligne suivante + src+=image_width-width; + dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; + } + Update_rect(x_pos,y_pos,width,height); +} + +// Affiche une brosse (arbitraire) à l'écran +void Display_brush_wide2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) +{ + // dest = Position à l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + // src = Position dans la brosse + byte* src = brush + y_offset * brush_width + x_offset; + + word x,y; + + // Pour chaque ligne + for(y = height;y > 0; y--) + { + // Pour chaque pixel + for(x = width;x > 0; x--) + { + // On vérifie que ce n'est pas la transparence + if(*src != transp_color) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; + } + + // Pixel suivant + src++; dest+=ZOOMX; + } + + // On passe à la ligne suivante + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + src = src + brush_width - width; + } +} + +void Remap_screen_wide2(word x_pos,word y_pos,word width,word height,byte * conversion_table) +{ + // dest = coords a l'écran + byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + int x,y; + + // Pour chaque ligne + for(y=height;y>0;y--) + { + // Pour chaque pixel + for(x=width;x>0;x--) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= + conversion_table[*dest]; + dest +=ZOOMX; + } + + dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; + } + + Update_rect(x_pos,y_pos,width,height); +} + +void Display_line_on_screen_fast_wide2(word x_pos,word y_pos,word width,byte * line) +/* On affiche toute une ligne de pixels telle quelle. */ +/* Utilisée si le buffer contient déja des pixel doublés. */ +{ + memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); + memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); +} + +void Display_line_on_screen_wide2(word x_pos,word y_pos,word width,byte * line) +/* On affiche une ligne de pixels en les doublant. */ +{ + int x; + byte *dest; + dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; + for(x=width;x>0;x--) + { + *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; + dest+=ZOOMX; + line++; + } +} +void Display_transparent_mono_line_on_screen_wide2( + word x_pos, word y_pos, word width, byte* line, + byte transp_color, byte color) +// Affiche une ligne à l'écran avec une couleur + transparence. +// Utilisé par les brosses en mode zoom +{ + byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; + int x; + // Pour chaque pixel + for(x=0;x 0); + src += image_width; + } +// ATTENTION on n'arrive jamais ici ! +} + +// Affiche une partie de la brosse couleur zoomée +void Display_brush_color_zoom_wide2(word x_pos,word y_pos, + word x_offset,word y_offset, + word width, // width non zoomée + word end_y_pos,byte transp_color, + word brush_width, // width réelle de la brosse + byte * buffer) +{ + byte* src = Brush+y_offset*brush_width + x_offset; + word y = y_pos; + byte bx; + + // Pour chaque ligne + while(1) + { + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + // On affiche facteur fois la ligne zoomée + for(bx=Main_magnifier_factor;bx>0;bx--) + { + byte* line_src = buffer; + byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; + word x; + // Pour chaque pixel de la ligne + for(x = width*Main_magnifier_factor;x > 0;x--) + { + if(*line_src!=transp_color) + { + *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; + } + line_src++; + dest+=ZOOMX; + } + // Double the line + memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); + y++; + if(y==end_y_pos) + { + return; + } + } + src += brush_width; + } + // ATTENTION zone jamais atteinte +} + +void Display_brush_mono_zoom_wide2(word x_pos, word y_pos, + word x_offset, word y_offset, + word width, // width non zoomée + word end_y_pos, + byte transp_color, byte color, + word brush_width, // width réelle de la brosse + byte * buffer +) + +{ + byte* src = Brush + y_offset * brush_width + x_offset; + int y=y_pos*ZOOMY; + + //Pour chaque ligne à zoomer : + while(1) + { + int bx; + // src = Ligne originale + // On éclate la ligne + Zoom_a_line(src,buffer,Main_magnifier_factor,width); + + // On affiche la ligne Facteur fois à l'écran (sur des + // lignes consécutives) + bx = Main_magnifier_factor*ZOOMY; + + // Pour chaque ligne écran + do + { + // On affiche la ligne zoomée + Display_transparent_mono_line_on_screen_wide2( + x_pos, y, width * Main_magnifier_factor, + buffer, transp_color, color + ); + // On passe à la ligne suivante + y++; + // On vérifie qu'on est pas à la ligne finale + if(y == end_y_pos*ZOOMY) + { + Update_rect( x_pos, y_pos, + width * Main_magnifier_factor, end_y_pos - y_pos ); + return; + } + bx --; + } + while (bx > 0); + + // Passage à la ligne suivante dans la brosse aussi + src+=brush_width; + } +} + +void Clear_brush_scaled_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) +{ + + // En fait on va recopier l'image non zoomée dans la partie zoomée ! + byte* src = Main_screen + y_offset * image_width + x_offset; + int y = y_pos; + int bx; + + // Pour chaque ligne à zoomer + while(1){ + Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); + + bx=Main_magnifier_factor; + + // Pour chaque ligne + do{ + // TODO a verifier + Display_line_on_screen_fast_wide2(x_pos,y, + width * Main_magnifier_factor,buffer); + + // Ligne suivante + y++; + if(y==end_y_pos) + { + Update_rect(x_pos,y_pos, + width*Main_magnifier_factor,end_y_pos-y_pos); + return; + } + bx--; + }while(bx!=0); + + src+= image_width; + } +} + + diff --git a/pxwide2.h b/pxwide2.h index bcc5eed0..15dff2d9 100644 --- a/pxwide2.h +++ b/pxwide2.h @@ -1,48 +1,48 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxwide2.h -/// Renderer for double-wide pixels (4x2). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_wide2 (word x,word y,byte color); - byte Read_pixel_wide2 (word x,word y); - void Block_wide2 (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_wide2 (word x,word y,byte color); - void Pixel_preview_magnifier_wide2 (word x,word y,byte color); - void Horizontal_XOR_line_wide2 (word x_pos,word y_pos,word width); - void Vertical_XOR_line_wide2 (word x_pos,word y_pos,word height); - void Display_brush_color_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_wide2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_wide2 (word width,word height,word image_width); - void Display_line_on_screen_wide2 (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_wide2 (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_wide2(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_wide2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_wide2 (word x_pos,word y_pos,word width,byte * line); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file pxwide2.h +/// Renderer for double-wide pixels (4x2). +////////////////////////////////////////////////////////////////////////////// + +#include "struct.h" + + void Pixel_wide2 (word x,word y,byte color); + byte Read_pixel_wide2 (word x,word y); + void Block_wide2 (word start_x,word start_y,word width,word height,byte color); + void Pixel_preview_normal_wide2 (word x,word y,byte color); + void Pixel_preview_magnifier_wide2 (word x,word y,byte color); + void Horizontal_XOR_line_wide2 (word x_pos,word y_pos,word width); + void Vertical_XOR_line_wide2 (word x_pos,word y_pos,word height); + void Display_brush_color_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + void Display_brush_mono_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); + void Clear_brush_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); + void Remap_screen_wide2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); + void Display_part_of_screen_wide2 (word width,word height,word image_width); + void Display_line_on_screen_wide2 (word x_pos,word y_pos,word width,byte * line); + void Read_line_screen_wide2 (word x_pos,word y_pos,word width,byte * line); + void Display_part_of_screen_scaled_wide2(word width,word height,word image_width,byte * buffer); + void Display_brush_color_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); + void Display_brush_mono_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); + void Clear_brush_scaled_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); + void Display_brush_wide2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); + + void Display_line_on_screen_fast_wide2 (word x_pos,word y_pos,word width,byte * line); diff --git a/readini.h b/readini.h index 7715ac8b..02188f3d 100644 --- a/readini.h +++ b/readini.h @@ -1,27 +1,27 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file readini.h -/// Reading settings in gfx2.ini -////////////////////////////////////////////////////////////////////////////// - -int Load_INI(T_Config * conf); -int Load_INI_seek_pattern(char * buffer,char * pattern); -void Load_INI_clear_string(char * str, byte keep_comments); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file readini.h +/// Reading settings in gfx2.ini +////////////////////////////////////////////////////////////////////////////// + +int Load_INI(T_Config * conf); +int Load_INI_seek_pattern(char * buffer,char * pattern); +void Load_INI_clear_string(char * str, byte keep_comments); diff --git a/readline.c b/readline.c index 293de1b5..15c2e291 100644 --- a/readline.c +++ b/readline.c @@ -1,350 +1,350 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ -/************************************************************************ -* * -* READLINE (procédure permettant de saisir une chaîne de caractères) * -* * -************************************************************************/ - -#include -#include - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "errors.h" -#include "const.h" -#include "sdlscreen.h" -#include "readline.h" -#include "windows.h" -#include "input.h" - -#define TEXT_COLOR MC_Black -#define BACKGROUND_COLOR MC_Light -#define CURSOR_COLOR MC_Black -#define CURSOR_BACKGROUND_COLOR MC_Dark - -// Suppresion d'un caractère à une certaine POSITION dans une CHAINE. -void Remove_character(char * str, byte position) -{ - for (;str[position]!='\0';position++) - str[position]=str[position+1]; -} - - -void Insert_character(char * str, char letter, byte position) -// Insertion d'une LETTRE à une certaine POSITION -// dans une CHAINE d'une certaine TAILLE. -{ - char temp_char; - - for (;letter!='\0';position++) - { - // On mémorise le caractère qui se trouve en "position" - temp_char=str[position]; - // On splotch la lettre à insérer - str[position]=letter; - // On place le caractère mémorisé dans "letter" comme nouvelle lettre à insérer - letter=temp_char; - } - // On termine la chaine - str[position]='\0'; -} - -int Valid_character(int c) -{ - // Sous Linux: Seul le / est strictement interdit, mais beaucoup - // d'autres poseront des problèmes au shell, alors on évite. - // Sous Windows : c'est moins grave car le fopen() échouerait de toutes façons. - // AmigaOS4: Pas de ':' car utilisé pour les volumes. - #if defined(__WIN32__) - char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':', '\\'}; - #elif defined (__amigaos4__) - char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':'}; - #else - char forbidden_char[] = {'/', '|', '?', '*', '<', '>'}; - #endif - int position; - - if (c < ' ' || c > 255) - return 0; - - for (position=0; position<(long)sizeof(forbidden_char); position++) - if (c == forbidden_char[position]) - return 0; - return 1; -} - -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); -} - -/**************************************************************************** -* Enhanced super scanf deluxe pro plus giga mieux :-) * -****************************************************************************/ -byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type) -// Paramètres: -// x_pos, y_pos : Coordonnées de la saisie dans la fenêtre -// str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) -// max_size : Nombre de caractères logeant dans la zone de saisie -// input_type : 0=Chaîne, 1=Nombre, 2=Nom de fichier -// Sortie: -// 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) -{ - byte max_size; - // Grosse astuce pour les noms de fichiers: La taille affichée est différente - // de la taille maximum gérée. - if (input_type == 2) - max_size = 255; - else - max_size = visible_size; - return Readline_ex(x_pos,y_pos,str,visible_size,max_size,input_type); -} - -/**************************************************************************** -* Enhanced super scanf deluxe pro plus giga mieux :-) * -****************************************************************************/ -byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type) -// Paramètres: -// x_pos, y_pos : Coordonnées de la saisie dans la fenêtre -// str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) -// max_size : Nombre de caractères logeant dans la zone de saisie -// input_type : 0=Chaîne, 1=Nombre, 2=Nom de fichier -// Sortie: -// 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) -{ - char initial_string[256]; - char display_string[256]; - byte position; - byte size; - word input_key=0; - byte is_authorized; - - byte offset=0; // index du premier caractère affiché - - Hide_cursor(); - // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_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), - 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 - strcpy(initial_string,str); - - // 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) - snprintf(str,10,"%d",atoi(str)); // On tasse la chaine à gauche - - - size=strlen(str); - position=(sizevisible_size) - offset=position-visible_size+1; - // Formatage d'une partie de la chaine (si trop longue pour tenir) - strncpy(display_string, str + offset, visible_size); - display_string[visible_size]='\0'; - if (offset>0) - display_string[0]=LEFT_TRIANGLE_CHARACTER; - 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), - visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); - Flush_update(); - - while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) - { - Display_cursor(); - do - { - if(!Get_input()) SDL_Delay(20); - input_key=Key_ANSI; - } while(input_key==0); - Hide_cursor(); - switch (input_key) - { - case SDLK_DELETE : // Suppr. - if (position0) - { - // 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), - visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); - position--; - if (offset > 0 && (position == 0 || position < (offset + 1))) - offset--; - goto affichage; - } - break; - case SDLK_RIGHT : // Droite - if ((position visible_size + offset - 2) - //if (offset + visible_size < max_size && (position == size || (position > visible_size + offset - 2))) - if (display_string[position-offset]==RIGHT_TRIANGLE_CHARACTER || position-offset>=visible_size) - offset++; - goto affichage; - } - break; - case SDLK_HOME : // Home - if (position) - { - // 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), - visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); - position = 0; - offset = 0; - goto affichage; - } - break; - case SDLK_END : // End - if ((positionvisible_size) - offset=position-visible_size+1; - goto affichage; - } - break; - case SDLK_BACKSPACE : // Backspace : combinaison de gauche + suppr - - if (position) - { - position--; - if (offset > 0 && (position == 0 || position < (offset + 1))) - offset--; - 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), - visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); - goto affichage; - } - break; - case SDLK_RETURN : - break; - - case KEY_ESC : - // On restaure la chaine initiale - strcpy(str,initial_string); - size=strlen(str); - break; - default : - if (size=' ' && input_key<= 255) - is_authorized=1; - break; - case 1 : // Nombre - if ( (input_key>='0') && (input_key<='9') ) - is_authorized=1; - break; - default : // Nom de fichier - // On regarde si la touche est autorisée - if ( Valid_character(input_key)) - is_authorized=1; - } // End du "switch(input_type)" - - // Si la touche était autorisée... - if (is_authorized) - { - // ... alors on l'insère ... - Insert_character(str,input_key,position/*,size*/); - // ce qui augmente la taille de la chaine - size++; - // et qui risque de déplacer le curseur vers la droite - if (size=visible_size) - offset++; - } - // Enfin, on raffiche la chaine - goto affichage; - } // End du test d'autorisation de touche - } // End du test de place libre - break; - -affichage: - size=strlen(str); - // Formatage d'une partie de la chaine (si trop longue pour tenir) - strncpy(display_string, str + offset, visible_size); - display_string[visible_size]='\0'; - if (offset>0) - display_string[0]=LEFT_TRIANGLE_CHARACTER; - 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), - visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); - } // End du "switch(input_key)" - Flush_update(); - - } // End du "while" - - // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_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 (str[0]=='\0') - { - strcpy(str,"0"); - size=1; - } - Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); - } - else - { - 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), - visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); - - return (input_key==SDLK_RETURN); -} +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ +/************************************************************************ +* * +* READLINE (procédure permettant de saisir une chaîne de caractères) * +* * +************************************************************************/ + +#include +#include + +#include "const.h" +#include "struct.h" +#include "global.h" +#include "misc.h" +#include "errors.h" +#include "const.h" +#include "sdlscreen.h" +#include "readline.h" +#include "windows.h" +#include "input.h" + +#define TEXT_COLOR MC_Black +#define BACKGROUND_COLOR MC_Light +#define CURSOR_COLOR MC_Black +#define CURSOR_BACKGROUND_COLOR MC_Dark + +// Suppresion d'un caractère à une certaine POSITION dans une CHAINE. +void Remove_character(char * str, byte position) +{ + for (;str[position]!='\0';position++) + str[position]=str[position+1]; +} + + +void Insert_character(char * str, char letter, byte position) +// Insertion d'une LETTRE à une certaine POSITION +// dans une CHAINE d'une certaine TAILLE. +{ + char temp_char; + + for (;letter!='\0';position++) + { + // On mémorise le caractère qui se trouve en "position" + temp_char=str[position]; + // On splotch la lettre à insérer + str[position]=letter; + // On place le caractère mémorisé dans "letter" comme nouvelle lettre à insérer + letter=temp_char; + } + // On termine la chaine + str[position]='\0'; +} + +int Valid_character(int c) +{ + // Sous Linux: Seul le / est strictement interdit, mais beaucoup + // d'autres poseront des problèmes au shell, alors on évite. + // Sous Windows : c'est moins grave car le fopen() échouerait de toutes façons. + // AmigaOS4: Pas de ':' car utilisé pour les volumes. + #if defined(__WIN32__) + char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':', '\\'}; + #elif defined (__amigaos4__) + char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':'}; + #else + char forbidden_char[] = {'/', '|', '?', '*', '<', '>'}; + #endif + int position; + + if (c < ' ' || c > 255) + return 0; + + for (position=0; position<(long)sizeof(forbidden_char); position++) + if (c == forbidden_char[position]) + return 0; + return 1; +} + +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); +} + +/**************************************************************************** +* Enhanced super scanf deluxe pro plus giga mieux :-) * +****************************************************************************/ +byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type) +// Paramètres: +// x_pos, y_pos : Coordonnées de la saisie dans la fenêtre +// str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) +// max_size : Nombre de caractères logeant dans la zone de saisie +// input_type : 0=Chaîne, 1=Nombre, 2=Nom de fichier +// Sortie: +// 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) +{ + byte max_size; + // Grosse astuce pour les noms de fichiers: La taille affichée est différente + // de la taille maximum gérée. + if (input_type == 2) + max_size = 255; + else + max_size = visible_size; + return Readline_ex(x_pos,y_pos,str,visible_size,max_size,input_type); +} + +/**************************************************************************** +* Enhanced super scanf deluxe pro plus giga mieux :-) * +****************************************************************************/ +byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type) +// Paramètres: +// x_pos, y_pos : Coordonnées de la saisie dans la fenêtre +// str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) +// max_size : Nombre de caractères logeant dans la zone de saisie +// input_type : 0=Chaîne, 1=Nombre, 2=Nom de fichier +// Sortie: +// 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) +{ + char initial_string[256]; + char display_string[256]; + byte position; + byte size; + word input_key=0; + byte is_authorized; + + byte offset=0; // index du premier caractère affiché + + Hide_cursor(); + // Effacement de la chaîne + Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_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), + 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 + strcpy(initial_string,str); + + // 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) + snprintf(str,10,"%d",atoi(str)); // On tasse la chaine à gauche + + + size=strlen(str); + position=(sizevisible_size) + offset=position-visible_size+1; + // Formatage d'une partie de la chaine (si trop longue pour tenir) + strncpy(display_string, str + offset, visible_size); + display_string[visible_size]='\0'; + if (offset>0) + display_string[0]=LEFT_TRIANGLE_CHARACTER; + 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), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); + Flush_update(); + + while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) + { + Display_cursor(); + do + { + if(!Get_input()) SDL_Delay(20); + input_key=Key_ANSI; + } while(input_key==0); + Hide_cursor(); + switch (input_key) + { + case SDLK_DELETE : // Suppr. + if (position0) + { + // 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), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); + position--; + if (offset > 0 && (position == 0 || position < (offset + 1))) + offset--; + goto affichage; + } + break; + case SDLK_RIGHT : // Droite + if ((position visible_size + offset - 2) + //if (offset + visible_size < max_size && (position == size || (position > visible_size + offset - 2))) + if (display_string[position-offset]==RIGHT_TRIANGLE_CHARACTER || position-offset>=visible_size) + offset++; + goto affichage; + } + break; + case SDLK_HOME : // Home + if (position) + { + // 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), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); + position = 0; + offset = 0; + goto affichage; + } + break; + case SDLK_END : // End + if ((positionvisible_size) + offset=position-visible_size+1; + goto affichage; + } + break; + case SDLK_BACKSPACE : // Backspace : combinaison de gauche + suppr + + if (position) + { + position--; + if (offset > 0 && (position == 0 || position < (offset + 1))) + offset--; + 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), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); + goto affichage; + } + break; + case SDLK_RETURN : + break; + + case KEY_ESC : + // On restaure la chaine initiale + strcpy(str,initial_string); + size=strlen(str); + break; + default : + if (size=' ' && input_key<= 255) + is_authorized=1; + break; + case 1 : // Nombre + if ( (input_key>='0') && (input_key<='9') ) + is_authorized=1; + break; + default : // Nom de fichier + // On regarde si la touche est autorisée + if ( Valid_character(input_key)) + is_authorized=1; + } // End du "switch(input_type)" + + // Si la touche était autorisée... + if (is_authorized) + { + // ... alors on l'insère ... + Insert_character(str,input_key,position/*,size*/); + // ce qui augmente la taille de la chaine + size++; + // et qui risque de déplacer le curseur vers la droite + if (size=visible_size) + offset++; + } + // Enfin, on raffiche la chaine + goto affichage; + } // End du test d'autorisation de touche + } // End du test de place libre + break; + +affichage: + size=strlen(str); + // Formatage d'une partie de la chaine (si trop longue pour tenir) + strncpy(display_string, str + offset, visible_size); + display_string[visible_size]='\0'; + if (offset>0) + display_string[0]=LEFT_TRIANGLE_CHARACTER; + 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), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); + } // End du "switch(input_key)" + Flush_update(); + + } // End du "while" + + // Effacement de la chaîne + Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_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 (str[0]=='\0') + { + strcpy(str,"0"); + size=1; + } + Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); + } + else + { + 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), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); + + return (input_key==SDLK_RETURN); +} diff --git a/readline.h b/readline.h index b2a3675f..f76242a3 100644 --- a/readline.h +++ b/readline.h @@ -1,44 +1,44 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file readline.h -/// Text input functions. -////////////////////////////////////////////////////////////////////////////// - -/// -/// 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) -/// @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); - -/// -/// 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. -/// @param max_size Number of characters editable. -/// @param input_type 0=string, 1=number, 2=filename (255 editable characters) -/// @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); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file readline.h +/// Text input functions. +////////////////////////////////////////////////////////////////////////////// + +/// +/// 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) +/// @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); + +/// +/// 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. +/// @param max_size Number of characters editable. +/// @param input_type 0=string, 1=number, 2=filename (255 editable characters) +/// @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); diff --git a/saveini.h b/saveini.h index 6d1f58df..93f9647b 100644 --- a/saveini.h +++ b/saveini.h @@ -1,25 +1,25 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file saveini.h -/// Saving settings in gfx2.ini -////////////////////////////////////////////////////////////////////////////// - -int Save_INI(T_Config * conf); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file saveini.h +/// Saving settings in gfx2.ini +////////////////////////////////////////////////////////////////////////////// + +int Save_INI(T_Config * conf); diff --git a/setup.c b/setup.c index 5b54ce09..4e259390 100644 --- a/setup.c +++ b/setup.c @@ -1,182 +1,182 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Peter Gordon - 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 -#if defined(__WIN32__) - #include - #include // Mingw's _mkdir() -#elif defined(__macosx__) - #import - #import -#elif defined(__FreeBSD__) - #import -#endif - -#include "struct.h" -#include "io.h" -#include "setup.h" - -int Create_ConfigDirectory(char * config_dir) -{ - #ifdef __WIN32__ - // Mingw's mkdir has a weird name and only one argument - return _mkdir(config_dir); - #else - return mkdir(config_dir,S_IRUSR|S_IWUSR|S_IXUSR); - #endif -} - -#if defined(__macosx__) || defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - #define ARG_UNUSED __attribute__((unused)) -#else - #define ARG_UNUSED -#endif -// Determine which directory contains the executable. -// IN: Main's argv[0], some platforms need it, some don't. -// OUT: Write into program_dir. Trailing / or \ is kept. -// Note : in fact this is only used to check for the datafiles and fonts in -// this same directory. -void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) -{ - #undef ARG_UNUSED - - // MacOSX - #if defined(__macosx__) - CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFURLGetFileSystemRepresentation(url,true,(UInt8*)program_dir,MAXPATHLEN); - CFRelease(url); - // Append trailing slash - strcat(program_dir ,"/"); - - // AmigaOS and alike: hard-coded volume name. - #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - strcpy(program_dir,"PROGDIR:"); - - // Others: The part of argv[0] before the executable name. - // Keep the last \ or /. - // Note that on Unix, once installed, the executable is called from a shell - // script sitting in /usr/local/bin/, this allows argv[0] to contain the full - // path. On Windows, Mingw32 already provides the full path in all cases. - #else - Extract_path(program_dir, argv0); - #endif -} - -// Determine which directory contains the read-only data. -// IN: The directory containing the executable -// OUT: Write into data_dir. Trailing / or \ is kept. -void Set_data_directory(const char * program_dir, char * data_dir) -{ - // On all platforms, data is in the executable's directory - strcpy(data_dir,program_dir); - // Except MacOSX, here it is stored in a special folder: - #if defined(__macosx__) - strcat(data_dir,"Contents/Resources/"); - #endif -} - -// Determine which directory should store the user's configuration. -// -// For most Unix and Windows platforms: -// If a config file already exists in program_dir, it will return it in priority -// (Useful for development, and possibly for upgrading from DOS version) -// If the standard directory doesn't exist yet, this function will attempt -// to create it ($(HOME)/.grafx2, or %APPDATA%\GrafX2) -// If it cannot be created, this function will return the executable's -// own directory. -// 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) -{ - // AmigaOS4 - #if defined(__amigaos4__) || defined(__AROS__) - strcpy(config_dir,"PROGDIR:"); - // GP2X - #elif defined(__GP2X__) - // 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); - #else - char filename[MAX_PATH_CHARACTERS]; - - // In priority: check own directory - strcpy(config_dir, program_dir); - strcpy(filename, config_dir); - strcat(filename, "gfx2.cfg"); - - if (!File_exists(filename)) - { - char *config_parent_dir; - #if defined(__WIN32__) - // "%APPDATA%\GrafX2" - const char* Config_SubDir = "GrafX2"; - config_parent_dir = getenv("APPDATA"); - #elif defined(__BEOS__) || defined(__HAIKU__) - // "~/.grafx2", the BeOS way - const char* Config_SubDir = ".grafx2"; - config_parent_dir = getenv("$HOME"); - #elif defined(__macosx__) - // "~/Library/Preferences/com.googlecode.grafx2" - const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; - config_parent_dir = getenv("HOME"); - #else - // "~/.grafx2" - const char* Config_SubDir = ".grafx2"; - config_parent_dir = getenv("HOME"); - #endif - - if (config_parent_dir && config_parent_dir[0]!='\0') - { - int size = strlen(config_parent_dir); - strcpy(config_dir, config_parent_dir); - if (config_parent_dir[size-1] != '\\' && config_parent_dir[size-1] != '/') - { - strcat(config_dir,PATH_SEPARATOR); - } - strcat(config_dir,Config_SubDir); - if (Directory_exists(config_dir)) - { - // Répertoire trouvé, ok - strcat(config_dir,PATH_SEPARATOR); - } - else - { - // Tentative de création - if (!Create_ConfigDirectory(config_dir)) - { - // Réussi - strcat(config_dir,PATH_SEPARATOR); - } - else - { - // Echec: on se rabat sur le repertoire de l'executable. - strcpy(config_dir,program_dir); - } - } - } - } - #endif -} +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Peter Gordon + 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 +#if defined(__WIN32__) + #include + #include // Mingw's _mkdir() +#elif defined(__macosx__) + #import + #import +#elif defined(__FreeBSD__) + #import +#endif + +#include "struct.h" +#include "io.h" +#include "setup.h" + +int Create_ConfigDirectory(char * config_dir) +{ + #ifdef __WIN32__ + // Mingw's mkdir has a weird name and only one argument + return _mkdir(config_dir); + #else + return mkdir(config_dir,S_IRUSR|S_IWUSR|S_IXUSR); + #endif +} + +#if defined(__macosx__) || defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) + #define ARG_UNUSED __attribute__((unused)) +#else + #define ARG_UNUSED +#endif +// Determine which directory contains the executable. +// IN: Main's argv[0], some platforms need it, some don't. +// OUT: Write into program_dir. Trailing / or \ is kept. +// Note : in fact this is only used to check for the datafiles and fonts in +// this same directory. +void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) +{ + #undef ARG_UNUSED + + // MacOSX + #if defined(__macosx__) + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFURLGetFileSystemRepresentation(url,true,(UInt8*)program_dir,MAXPATHLEN); + CFRelease(url); + // Append trailing slash + strcat(program_dir ,"/"); + + // AmigaOS and alike: hard-coded volume name. + #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) + strcpy(program_dir,"PROGDIR:"); + + // Others: The part of argv[0] before the executable name. + // Keep the last \ or /. + // Note that on Unix, once installed, the executable is called from a shell + // script sitting in /usr/local/bin/, this allows argv[0] to contain the full + // path. On Windows, Mingw32 already provides the full path in all cases. + #else + Extract_path(program_dir, argv0); + #endif +} + +// Determine which directory contains the read-only data. +// IN: The directory containing the executable +// OUT: Write into data_dir. Trailing / or \ is kept. +void Set_data_directory(const char * program_dir, char * data_dir) +{ + // On all platforms, data is in the executable's directory + strcpy(data_dir,program_dir); + // Except MacOSX, here it is stored in a special folder: + #if defined(__macosx__) + strcat(data_dir,"Contents/Resources/"); + #endif +} + +// Determine which directory should store the user's configuration. +// +// For most Unix and Windows platforms: +// If a config file already exists in program_dir, it will return it in priority +// (Useful for development, and possibly for upgrading from DOS version) +// If the standard directory doesn't exist yet, this function will attempt +// to create it ($(HOME)/.grafx2, or %APPDATA%\GrafX2) +// If it cannot be created, this function will return the executable's +// own directory. +// 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) +{ + // AmigaOS4 + #if defined(__amigaos4__) || defined(__AROS__) + strcpy(config_dir,"PROGDIR:"); + // GP2X + #elif defined(__GP2X__) + // 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); + #else + char filename[MAX_PATH_CHARACTERS]; + + // In priority: check own directory + strcpy(config_dir, program_dir); + strcpy(filename, config_dir); + strcat(filename, "gfx2.cfg"); + + if (!File_exists(filename)) + { + char *config_parent_dir; + #if defined(__WIN32__) + // "%APPDATA%\GrafX2" + const char* Config_SubDir = "GrafX2"; + config_parent_dir = getenv("APPDATA"); + #elif defined(__BEOS__) || defined(__HAIKU__) + // "~/.grafx2", the BeOS way + const char* Config_SubDir = ".grafx2"; + config_parent_dir = getenv("$HOME"); + #elif defined(__macosx__) + // "~/Library/Preferences/com.googlecode.grafx2" + const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; + config_parent_dir = getenv("HOME"); + #else + // "~/.grafx2" + const char* Config_SubDir = ".grafx2"; + config_parent_dir = getenv("HOME"); + #endif + + if (config_parent_dir && config_parent_dir[0]!='\0') + { + int size = strlen(config_parent_dir); + strcpy(config_dir, config_parent_dir); + if (config_parent_dir[size-1] != '\\' && config_parent_dir[size-1] != '/') + { + strcat(config_dir,PATH_SEPARATOR); + } + strcat(config_dir,Config_SubDir); + if (Directory_exists(config_dir)) + { + // Répertoire trouvé, ok + strcat(config_dir,PATH_SEPARATOR); + } + else + { + // Tentative de création + if (!Create_ConfigDirectory(config_dir)) + { + // Réussi + strcat(config_dir,PATH_SEPARATOR); + } + else + { + // Echec: on se rabat sur le repertoire de l'executable. + strcpy(config_dir,program_dir); + } + } + } + } + #endif +} diff --git a/setup.h b/setup.h index c4df3f40..0fc2e25e 100644 --- a/setup.h +++ b/setup.h @@ -1,54 +1,54 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Peter Gordon - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file setup.h -/// Functions that determine where grafx2 is running, finds its data, and -/// reads and writes configuration files. -////////////////////////////////////////////////////////////////////////////// - -/// -/// Determine which directory contains the executable. -/// - IN: Main's argv[0], some platforms need it, some don't. -/// - OUT: Write into program_dir. Trailing / or \ is kept. -/// Note : in fact this is only used to check for the datafiles and fonts in this same directory. -void Set_program_directory(const char * argv0,char * program_dir); - -/// -/// Determine which directory contains the read-only data. -/// IN: The directory containing the executable -/// OUT: Write into data_dir. Trailing / or \ is kept. -void Set_data_directory(const char * program_dir, char * data_dir); - -/// -/// Determine which directory should store the user's configuration. -/// For most Unix and Windows platforms: -/// If a config file already exists in program_dir, it will return it in priority -/// (Useful for development, and possibly for upgrading from DOS version) -/// If the standard directory doesn't exist yet, this function will attempt -/// to create it ($(HOME)/.grafx2, or %APPDATA%\\GrafX2) -/// If it cannot be created, this function will return the executable's -/// own directory. -/// 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); - +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Peter Gordon + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file setup.h +/// Functions that determine where grafx2 is running, finds its data, and +/// reads and writes configuration files. +////////////////////////////////////////////////////////////////////////////// + +/// +/// Determine which directory contains the executable. +/// - IN: Main's argv[0], some platforms need it, some don't. +/// - OUT: Write into program_dir. Trailing / or \ is kept. +/// Note : in fact this is only used to check for the datafiles and fonts in this same directory. +void Set_program_directory(const char * argv0,char * program_dir); + +/// +/// Determine which directory contains the read-only data. +/// IN: The directory containing the executable +/// OUT: Write into data_dir. Trailing / or \ is kept. +void Set_data_directory(const char * program_dir, char * data_dir); + +/// +/// Determine which directory should store the user's configuration. +/// For most Unix and Windows platforms: +/// If a config file already exists in program_dir, it will return it in priority +/// (Useful for development, and possibly for upgrading from DOS version) +/// If the standard directory doesn't exist yet, this function will attempt +/// to create it ($(HOME)/.grafx2, or %APPDATA%\\GrafX2) +/// If it cannot be created, this function will return the executable's +/// own directory. +/// 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); + diff --git a/shade.h b/shade.h index 2a0d0b69..7f9e23c8 100644 --- a/shade.h +++ b/shade.h @@ -1,32 +1,32 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 -*/ -////////////////////////////////////////////////////////////////////////////// -///@file shade.h -/// Screens for Shade and Quick-shade settings. -////////////////////////////////////////////////////////////////////////////// - - -#ifndef SHADE_H_INCLUDED -#define SHADE_H_INCLUDED - -void Button_Quick_shade_menu(void); - -int Shade_settings_menu(void); - -#endif // SHADE_H_INCLUDED +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ +////////////////////////////////////////////////////////////////////////////// +///@file shade.h +/// Screens for Shade and Quick-shade settings. +////////////////////////////////////////////////////////////////////////////// + + +#ifndef SHADE_H_INCLUDED +#define SHADE_H_INCLUDED + +void Button_Quick_shade_menu(void); + +int Shade_settings_menu(void); + +#endif // SHADE_H_INCLUDED diff --git a/special.c b/special.c index 61a09152..9fa8483e 100644 --- a/special.c +++ b/special.c @@ -1,364 +1,364 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - 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 "const.h" -#include "struct.h" -#include "global.h" -#include "graph.h" -#include "engine.h" -#include "windows.h" -#include "special.h" - - - -//---------------------- Modifier le pinceau spécial ------------------------- - -void Set_paintbrush_size(int width, int height) -{ - int x_pos,y_pos; - int x,y; - float radius2; - - if (width<1) width=1; - if (height<1) height=1; - if (width>MAX_PAINTBRUSH_SIZE) width=MAX_PAINTBRUSH_SIZE; - if (height>MAX_PAINTBRUSH_SIZE) height=MAX_PAINTBRUSH_SIZE; - Paintbrush_width=width; - Paintbrush_height=height; - Paintbrush_offset_X=Paintbrush_width>>1; - Paintbrush_offset_Y=Paintbrush_height>>1; - switch (Paintbrush_shape) - { - case PAINTBRUSH_SHAPE_ROUND : - radius2=Paintbrush_offset_X+0.414213562; // [0.410..0.415[ - radius2*=radius2; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos1) - || (Paintbrush_height>1) ) ) - { - Hide_cursor(); - switch (Paintbrush_shape) - { - case PAINTBRUSH_SHAPE_ROUND: - case PAINTBRUSH_SHAPE_SIEVE_ROUND: - case PAINTBRUSH_SHAPE_CROSS: - case PAINTBRUSH_SHAPE_PLUS: - case PAINTBRUSH_SHAPE_DIAMOND: - case PAINTBRUSH_SHAPE_RANDOM: - if (Paintbrush_width&1) - Set_paintbrush_size(Paintbrush_width-2,Paintbrush_height-2); - else - Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); - break; - case PAINTBRUSH_SHAPE_SQUARE: - case PAINTBRUSH_SHAPE_SLASH: - case PAINTBRUSH_SHAPE_ANTISLASH: - case PAINTBRUSH_SHAPE_SIEVE_SQUARE: - Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); - break; - case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: - Set_paintbrush_size(Paintbrush_width-1,1); - break; - case PAINTBRUSH_SHAPE_VERTICAL_BAR: - Set_paintbrush_size(1,Paintbrush_height-1); - } - Display_paintbrush_in_menu(); - Display_cursor(); - } -} - -void Bigger_paintbrush(void) -{ - if ( (Paintbrush_shapeMain_image_width) - temp_x_offset=Main_image_width-Screen_width; - if (temp_y_offset+Menu_Y>Main_image_height) - temp_y_offset=Main_image_height-Menu_Y; - if (temp_x_offset<0) - temp_x_offset=0; - if (temp_y_offset<0) - temp_y_offset=0; - - if ( (Main_offset_X!=temp_x_offset) || - (Main_offset_Y!=temp_y_offset) ) - { - Hide_cursor(); - Main_offset_X=temp_x_offset; - Main_offset_Y=temp_y_offset; - - Compute_limits(); - Compute_paintbrush_coordinates(); - - Display_all_screen(); // <=> Display_screen + Display_image_limits - Display_cursor(); - } -} - - -// ---------------------- Scroller la fenêtre de la loupe -------------------- -void Scroll_magnifier(short delta_x,short delta_y) -{ - short temp_x_offset; - short temp_y_offset; - - temp_x_offset=Main_magnifier_offset_X+delta_x; - temp_y_offset=Main_magnifier_offset_Y+delta_y; - - if (temp_x_offset+Main_magnifier_width>Main_image_width) - temp_x_offset=Main_image_width-Main_magnifier_width; - if (temp_y_offset+Main_magnifier_height>Main_image_height) - temp_y_offset=Main_image_height-Main_magnifier_height; - if (temp_x_offset<0) - temp_x_offset=0; - if (temp_y_offset<0) - temp_y_offset=0; - - if ( (Main_magnifier_offset_X!=temp_x_offset) || - (Main_magnifier_offset_Y!=temp_y_offset) ) - { - Hide_cursor(); - Main_magnifier_offset_X=temp_x_offset; - Main_magnifier_offset_Y=temp_y_offset; - - Position_screen_according_to_zoom(); - - Compute_limits(); - Compute_paintbrush_coordinates(); - - Display_all_screen(); - Display_cursor(); - } -} - - -// -------------- Changer le Zoom (grâce aux touches [+] et [-]) ------------- -void Zoom(short delta) -{ - short index; - for (index=0; ZOOM_FACTOR[index]!=Main_magnifier_factor; index++); - index+=delta; - - if ( (index>=0) && (index +*/ +#include +#include +#include "const.h" +#include "struct.h" +#include "global.h" +#include "graph.h" +#include "engine.h" +#include "windows.h" +#include "special.h" + + + +//---------------------- Modifier le pinceau spécial ------------------------- + +void Set_paintbrush_size(int width, int height) +{ + int x_pos,y_pos; + int x,y; + float radius2; + + if (width<1) width=1; + if (height<1) height=1; + if (width>MAX_PAINTBRUSH_SIZE) width=MAX_PAINTBRUSH_SIZE; + if (height>MAX_PAINTBRUSH_SIZE) height=MAX_PAINTBRUSH_SIZE; + Paintbrush_width=width; + Paintbrush_height=height; + Paintbrush_offset_X=Paintbrush_width>>1; + Paintbrush_offset_Y=Paintbrush_height>>1; + switch (Paintbrush_shape) + { + case PAINTBRUSH_SHAPE_ROUND : + radius2=Paintbrush_offset_X+0.414213562; // [0.410..0.415[ + radius2*=radius2; + for (y_pos=0; y_pos>1; + for (y_pos=0; y_pos>1; + for (y_pos=0; y_pos>1; + for (y_pos=0; y_pos>1; + for (y_pos=0; y_pos>1; + for (y_pos=0; y_pos1) + || (Paintbrush_height>1) ) ) + { + Hide_cursor(); + switch (Paintbrush_shape) + { + case PAINTBRUSH_SHAPE_ROUND: + case PAINTBRUSH_SHAPE_SIEVE_ROUND: + case PAINTBRUSH_SHAPE_CROSS: + case PAINTBRUSH_SHAPE_PLUS: + case PAINTBRUSH_SHAPE_DIAMOND: + case PAINTBRUSH_SHAPE_RANDOM: + if (Paintbrush_width&1) + Set_paintbrush_size(Paintbrush_width-2,Paintbrush_height-2); + else + Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); + break; + case PAINTBRUSH_SHAPE_SQUARE: + case PAINTBRUSH_SHAPE_SLASH: + case PAINTBRUSH_SHAPE_ANTISLASH: + case PAINTBRUSH_SHAPE_SIEVE_SQUARE: + Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); + break; + case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: + Set_paintbrush_size(Paintbrush_width-1,1); + break; + case PAINTBRUSH_SHAPE_VERTICAL_BAR: + Set_paintbrush_size(1,Paintbrush_height-1); + } + Display_paintbrush_in_menu(); + Display_cursor(); + } +} + +void Bigger_paintbrush(void) +{ + if ( (Paintbrush_shapeMain_image_width) + temp_x_offset=Main_image_width-Screen_width; + if (temp_y_offset+Menu_Y>Main_image_height) + temp_y_offset=Main_image_height-Menu_Y; + if (temp_x_offset<0) + temp_x_offset=0; + if (temp_y_offset<0) + temp_y_offset=0; + + if ( (Main_offset_X!=temp_x_offset) || + (Main_offset_Y!=temp_y_offset) ) + { + Hide_cursor(); + Main_offset_X=temp_x_offset; + Main_offset_Y=temp_y_offset; + + Compute_limits(); + Compute_paintbrush_coordinates(); + + Display_all_screen(); // <=> Display_screen + Display_image_limits + Display_cursor(); + } +} + + +// ---------------------- Scroller la fenêtre de la loupe -------------------- +void Scroll_magnifier(short delta_x,short delta_y) +{ + short temp_x_offset; + short temp_y_offset; + + temp_x_offset=Main_magnifier_offset_X+delta_x; + temp_y_offset=Main_magnifier_offset_Y+delta_y; + + if (temp_x_offset+Main_magnifier_width>Main_image_width) + temp_x_offset=Main_image_width-Main_magnifier_width; + if (temp_y_offset+Main_magnifier_height>Main_image_height) + temp_y_offset=Main_image_height-Main_magnifier_height; + if (temp_x_offset<0) + temp_x_offset=0; + if (temp_y_offset<0) + temp_y_offset=0; + + if ( (Main_magnifier_offset_X!=temp_x_offset) || + (Main_magnifier_offset_Y!=temp_y_offset) ) + { + Hide_cursor(); + Main_magnifier_offset_X=temp_x_offset; + Main_magnifier_offset_Y=temp_y_offset; + + Position_screen_according_to_zoom(); + + Compute_limits(); + Compute_paintbrush_coordinates(); + + Display_all_screen(); + Display_cursor(); + } +} + + +// -------------- Changer le Zoom (grâce aux touches [+] et [-]) ------------- +void Zoom(short delta) +{ + short index; + for (index=0; ZOOM_FACTOR[index]!=Main_magnifier_factor; index++); + index+=delta; + + if ( (index>=0) && (index -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file special.h -/// Editor functions that can be hooked to a keyboard shortcut, but don't have -/// a menu button associated to them. -////////////////////////////////////////////////////////////////////////////// - -void Set_paintbrush_size(int width, int height); -void Smaller_paintbrush(void); -void Bigger_paintbrush(void); - -void Special_next_forecolor(void); -void Special_previous_forecolor(void); -void Special_next_backcolor(void); -void Special_previous_backcolor(void); - -void Special_next_user_forecolor(void); -void Special_previous_user_forecolor(void); -void Special_next_user_backcolor(void); -void Special_previous_user_backcolor(void); - -void Scroll_screen(short delta_x,short delta_y); -void Scroll_magnifier(short delta_x,short delta_y); - -void Zoom(short delta); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file special.h +/// Editor functions that can be hooked to a keyboard shortcut, but don't have +/// a menu button associated to them. +////////////////////////////////////////////////////////////////////////////// + +void Set_paintbrush_size(int width, int height); +void Smaller_paintbrush(void); +void Bigger_paintbrush(void); + +void Special_next_forecolor(void); +void Special_previous_forecolor(void); +void Special_next_backcolor(void); +void Special_previous_backcolor(void); + +void Special_next_user_forecolor(void); +void Special_previous_user_forecolor(void); +void Special_next_user_backcolor(void); +void Special_previous_user_backcolor(void); + +void Scroll_screen(short delta_x,short delta_y); +void Scroll_magnifier(short delta_x,short delta_y); + +void Zoom(short delta); diff --git a/struct.h b/struct.h index ed890449..93c1872b 100644 --- a/struct.h +++ b/struct.h @@ -1,410 +1,410 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file struct.h -/// Structures that can be used in the whole program. -////////////////////////////////////////////////////////////////////////////// -#ifndef _STRUCT_H_ -#define _STRUCT_H_ - -#if defined(__BEOS__) - #include -#else - #include -#endif - -#include "const.h" - - -// POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. -#ifdef WIN32 - #define strcasecmp stricmp -#endif - -// Definition of the base data types -/// 8bit unsigned integer -#define byte uint8_t -/// 16bit unsigned integer -#define word uint16_t -/// 32bit unsigned integer -#define dword uint32_t -/// 64bit unsigned integer -#define qword uint64_t - -// Named function prototypes -typedef void (* Func_action) (void); -typedef void (* Func_pixel) (word,word,byte); -typedef byte (* Func_read) (word,word); -typedef void (* Func_clear) (byte); -typedef void (* Func_display) (word,word,word); -typedef byte (* Func_effect) (word,word,byte); -typedef void (* Func_block) (word,word,word,word,byte); -typedef void (* Func_line_XOR) (word,word,word); -typedef void (* Func_display_brush_color) (word,word,word,word,word,word,byte,word); -typedef void (* Func_display_brush_mono) (word,word,word,word,word,word,byte,byte,word); -typedef void (* Func_gradient) (long,short,short); -typedef void (* Func_remap) (word,word,word,word,byte *); -typedef void (* Func_procsline) (word,word,word,byte *); -typedef void (* Func_display_zoom) (word,word,word,byte *); -typedef void (* Func_display_brush_color_zoom) (word,word,word,word,word,word,byte,word,byte *); -typedef void (* Func_display_brush_mono_zoom) (word,word,word,word,word,word,byte,byte,word,byte *); -typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word); -typedef void (* Func_draw_list_item) (word,word,word,byte); - -/// A set of RGB values. -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). - -/// A normal rectangular button in windows and menus. -typedef struct T_Normal_button -{ - short Number; ///< Unique identifier for all controls - 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 Width; ///< Width before scaling - word Height; ///< Height before scaling - byte Clickable; ///< Boolean, unused. - byte Repeatable; ///< Boolean, true if the button activates repeatedly until you release the mouse button. Used for "+" buttons, for example. - word Shortcut; ///< Keyboard shortcut that will emulate a click on this button. - struct T_Normal_button * Next;///< Pointer to the next normal button of current window. -} T_Normal_button; - -/// A window control that shows a complete 256-color palette -typedef struct T_Palette_button -{ - short Number; ///< Unique identifier for all controls - 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. - 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. -typedef struct T_Scroller_button -{ - short Number; ///< Unique identifier for all controls - 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 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. - struct T_Scroller_button * Next;///< Pointer to the next scroller of current window. -} T_Scroller_button; - -/// -/// A window control that only has a rectangular "active" area which catches mouse clicks, -// but no visible shape. It's used for custom controls where the drawing is done on -// a case by case basis. -typedef struct T_Special_button -{ - short Number; ///< Unique identifier for all controls - 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 Width; ///< Width before scaling - word Height; ///< Height before scaling - struct T_Special_button * Next;///< Pointer to the next special button of current window. -} T_Special_button; - -/// Data for a dropdown item, ie. one proposed choice. -typedef struct T_Dropdown_choice -{ - short Number; ///< Value that identifies the choice (for this dropdown only) - const char * Label; ///< String to display in the dropdown panel - struct T_Dropdown_choice * Next;///< Pointer to the next choice for this dropdown. -} T_Dropdown_choice; - -/// A window control that behaves like a dropdown button. -typedef struct T_Dropdown_button -{ - short Number; ///< Unique identifier for all controls - 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 Width; ///< Width before scaling - word Height; ///< Height before scaling - byte Display_choice; ///< Boolean, true if the engine should print the selected item's label in the dropdown area when the user chooses it. - byte Display_centered; ///< Boolean, true to center the labels (otherwise, align left) - byte Display_arrow; ///< Boolean, true to display a "down" arrow box in top right - byte Active_button; ///< Determines which mouse button(s) cause the dropdown panel to open: LEFT_SIDE || RIGHT_SIDE || (LEFT_SIDE|RIGHT_SIDE) - word Dropdown_width; ///< Width of the dropdown panel when it's open. Use 0 for "same as the dropdown button" - T_Dropdown_choice * First_item; ///< Linked list with the choices available for this dropdown. - struct T_Dropdown_button * Next;///< Pointer to the next dropdown button of current window. -} 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 - - 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. -} T_Fileselector_item; - -/// Data for a fileselector -typedef struct T_Fileselector -{ - /// Number of elements in the current fileselector's ::Filelist - short Nb_elements; - /// Number of files in the current fileselector's ::Filelist - short Nb_files; - /// Number of directories in the current fileselector's ::Filelist - short Nb_directories; - /// Head of the linked list for the fileselector. - T_Fileselector_item * First; - /// Index for direct access to element number N - T_Fileselector_item ** Index; -} T_Fileselector; - -typedef struct T_List_button -{ - short Number; ///< Unique identifier for all controls - short List_start; ///< Index of the font to appear as first line - short Cursor_position; ///< Index of the selected line (0=top) - - T_Special_button * Entry_button; ///< Pointer to the associated selection control. - T_Scroller_button * Scroller; ///< Pointer to the associated scroller - - Func_draw_list_item Draw_list_item; ///< - - struct T_List_button * Next; ///< Pointer to the next list button of current window. -} T_List_button; - -/// 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. - char * Text; ///< Displayed string. - int Line_parameter; ///< Generic parameter depending on line type. For 'K' lines: a shortcut identifier. For others: unused. -} T_Help_table; - -/// Data for one section of the "Help" screens, ie a page. -typedef struct -{ - const T_Help_table* Help_table; ///< Pointer to the array of ::T_Help_table that contains the lines - word Length; ///< Size of the array of lines -} T_Help_section; - -/// Data for one setting of gradients. Warning, this one is saved/loaded as binary. -typedef struct -{ - byte Start; ///< First color - byte End; ///< Last color - 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; - -/// Data for one setting of shade. Warning, this one is saved/loaded as binary. -typedef struct -{ - word List[512]; ///< List of entries, each one is either a color (0-255) or -1 for empty. - byte Step; ///< Step to increment/decrement on left-clicks. - byte Mode; ///< Shade mode: Normal, Loop, or No-saturation see ::SHADE_MODES -} T_Shade; - -/// Data for one fullscreen video mode in configuration file. Warning, this one is saved/loaded as binary. -typedef struct -{ - byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. - word Width; ///< Videomode width in pixels. - word Height;///< Videomode height in pixels. -} __attribute__((__packed__)) T_Config_video_mode; - -/// Header for gfx2.cfg. Warning, this one is saved/loaded as binary. -typedef struct -{ - char Signature[3]; ///< Signature for the file format. "CFG". - byte Version1; ///< Major version number (ex: 2) - byte Version2; ///< Minor version number (ex: 0) - byte Beta1; ///< Major beta version number (ex: 96) - byte Beta2; ///< Major beta version number (ex: 5) -} __attribute__((__packed__)) T_Config_header; - -/// Header for a config chunk in for gfx2.cfg. Warning, this one is saved/loaded as binary. -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; - -/// Configuration for one keyboard shortcut in gfx2.cfg. Warning, this one is saved/loaded as binary. -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 -} __attribute__((__packed__)) T_Config_shortcut_info; - -/// This structure holds all the settings which are saved and loaded as gfx2.ini. -typedef struct -{ - char *Font_file; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) - char *Skin_file; ///< String, name of the file where all the graphic data is stored - int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. - int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. -// int Show_system_directories; ///< (removed when converted from DOS) - byte Display_image_limits; ///< Boolean, true to display a dotted line at the borders of the image if it's smaller than screen. - byte Cursor; ///< Mouse cursor aspect: 1 Solid, 2 Transparent, 3 Thin - byte Maximize_preview; ///< Boolean, true to make previews in fileselector fit the whole rectangle. - byte Auto_set_res; ///< Boolean, true to make grafx2 switch to a new resolution whenever you load an image. - byte Coords_rel; ///< Boolean, true to display coordinates as relative (instead of absolute) - byte Backup; ///< Boolean, true to backup the original file whenever you save an image. - byte Adjust_brush_pick; ///< Boolean, true to omit the right and bottom edges when grabbing a brush in Grid mode. - byte Auto_save; ///< Boolean, true to save configuration when exiting program. - byte Max_undo_pages; ///< Number of steps to memorize for Undo/Redo. - byte Mouse_sensitivity_index_x; ///< Mouse sensitivity in X axis - byte Mouse_sensitivity_index_y; ///< Mouse sensitivity in Y axis - byte Mouse_fix_factor_X; ///< Mouse correction factor in X axis. - byte Mouse_fix_factor_Y; ///< Mouse correction factor in Y axis. - byte Mouse_merge_movement; ///< Number of SDL mouse events that are merged into a single change of mouse coordinates. - byte Delay_left_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. - byte Delay_right_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. - long Timer_delay; ///< Delay (in 1/55s) before showing a preview in a fileselector. - T_Components Fav_menu_colors[4]; ///< Favorite colors to use for the menu. - int Nb_max_vertices_per_polygon; ///< Limit for the number of vertices in polygon tools. - byte Clear_palette; ///< Boolean, true to reset the palette (to black) before loading an image. - byte Set_resolution_according_to; ///< When Auto_set_res is on, this determines if the mode should be chosen according to the "original screen" information in the file (1) or the picture dimensons (2) - byte Ratio; ///< Determines the scaling of menu and windows: 0 no scaling, 1 scaling, 2 slight scaling. - byte Fast_zoom; ///< Boolean, true if the magnifier shortcut should automatically view the mouse area. - byte Find_file_fast; ///< In fileselectors, this determines which entries should be sought when typing letters: 0 all, 1 files only, 2 directories only. - byte Separate_colors; ///< Boolean, true if the menu palette should separate color cells with a black outline. - word Palette_cells_X; ///< Number of colors to show in a row of the menu palette. - word Palette_cells_Y; ///< Number of colors to show in a column of the menu palette. - byte Palette_vertical; ///< Boolean, true if the menu palette should go top to bottom instead of left to right - byte FX_Feedback; ///< Boolean, true if drawing effects should read the image being modified (instead of the image before clicking) - byte Safety_colors; ///< Boolean, true to make the palette automatically re-create menu colors if needed after a "Zap" or color reduction. - byte Opening_message; ///< Boolean, true to display the splash screen on strtup. - byte Clear_with_stencil; ///< Boolean, true to take the stencil into effect (if active) when using the Clear function. - byte Auto_discontinuous; ///< Boolean, true to automatically switch to the discontinuous freehand draw after grabbing a brush. - byte Screen_size_in_GIF; ///< Boolean, true to store current resolution in GIF files. - byte Auto_nb_used; ///< Boolean, true to count colors in Palette screen. - byte Default_resolution; ///< Default video mode to use on startup. Index in ::Video_mode. - char *Bookmark_directory[NB_BOOKMARKS];///< Bookmarked directories in fileselectors: This is the full dierctory name. - char Bookmark_label[NB_BOOKMARKS][8+1];///< Bookmarked directories in fileselectors: This is the displayed name. - int Window_pos_x; ///< Last window x position (9999 if unsupportd/irrelevant for the platform) - int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) - word Double_click_speed; ///< Maximum delay for double-click, in ms. - word Double_key_speed; ///< Maximum delay for double-keypress, in ms. -} 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 -// pages. - -// 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. -typedef struct -{ - byte * Image; ///< Pixel data for the image. - int Width; ///< Image width in pixels. - int Height; ///< Image height in pixels. - T_Palette Palette; ///< Image palette. - - char Comment[COMMENT_SIZE+1]; ///< Comment to store in the image file. - - char File_directory[MAX_PATH_CHARACTERS];///< Directory that contains the file. - char Filename[MAX_PATH_CHARACTERS]; ///< Filename without directory. - byte File_format; ///< File format, in enum ::FILE_FORMATS - -} T_Page; - -/// Collection of undo/redo steps. -typedef struct -{ - int List_size; /// Number of ::T_Page in the vector "Pages". - int Nb_pages_allocated;/// Number of ::T_Page used so far in the vector "Pages". - T_Page * Pages; /// Vector of Pages, each one being a undo/redo step. -} T_List_of_pages; - - -/// GUI skin data -typedef struct -{ - // Mouse - - /// X coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_WIDTH - word Cursor_offset_X[NB_CURSOR_SPRITES]; - /// Y coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_HEIGHT - word Cursor_offset_Y[NB_CURSOR_SPRITES]; - /// 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) - word Sieve_pattern[12][16]; - - // Menu and other graphics - - /// Bitmap data for the menu, a single rectangle. - byte Menu_block[MENU_HEIGHT][MENU_WIDTH]; - /// Bitmap data for the icons that are displayed over the menu. - byte Menu_sprite[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]; - /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. - byte Logo_grafx2[231*56]; - /// Bitmap data for the 6x8 font used in help screens. - byte Help_font_norm [256][6][8]; - /// Bitmap data for the 6x8 font used in help screens ("bold" verstion). - byte Bold_font [256][6][8]; - // 12 - // 34 - /// Bitmap data for the title font used in help screens. Top-left quarter. - byte Help_font_t1 [64][6][8]; - /// Bitmap data for the title font used in help screens. Top-right quarter. - byte Help_font_t2 [64][6][8]; - /// Bitmap data for the title font used in help screens. Bottom-left quarter. - byte Help_font_t3 [64][6][8]; - /// Bitmap data for the title font used in help screens. Bottom-right quarter. - byte Help_font_t4 [64][6][8]; - /// Bitmap data for the small 8x8 icons. - byte Icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; - - /// A default 256-color palette. - T_Palette Default_palette; - - -} T_Gui_skin; - -#endif +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file struct.h +/// Structures that can be used in the whole program. +////////////////////////////////////////////////////////////////////////////// +#ifndef _STRUCT_H_ +#define _STRUCT_H_ + +#if defined(__BEOS__) + #include +#else + #include +#endif + +#include "const.h" + + +// POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. +#ifdef WIN32 + #define strcasecmp stricmp +#endif + +// Definition of the base data types +/// 8bit unsigned integer +#define byte uint8_t +/// 16bit unsigned integer +#define word uint16_t +/// 32bit unsigned integer +#define dword uint32_t +/// 64bit unsigned integer +#define qword uint64_t + +// Named function prototypes +typedef void (* Func_action) (void); +typedef void (* Func_pixel) (word,word,byte); +typedef byte (* Func_read) (word,word); +typedef void (* Func_clear) (byte); +typedef void (* Func_display) (word,word,word); +typedef byte (* Func_effect) (word,word,byte); +typedef void (* Func_block) (word,word,word,word,byte); +typedef void (* Func_line_XOR) (word,word,word); +typedef void (* Func_display_brush_color) (word,word,word,word,word,word,byte,word); +typedef void (* Func_display_brush_mono) (word,word,word,word,word,word,byte,byte,word); +typedef void (* Func_gradient) (long,short,short); +typedef void (* Func_remap) (word,word,word,word,byte *); +typedef void (* Func_procsline) (word,word,word,byte *); +typedef void (* Func_display_zoom) (word,word,word,byte *); +typedef void (* Func_display_brush_color_zoom) (word,word,word,word,word,word,byte,word,byte *); +typedef void (* Func_display_brush_mono_zoom) (word,word,word,word,word,word,byte,byte,word,byte *); +typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word); +typedef void (* Func_draw_list_item) (word,word,word,byte); + +/// A set of RGB values. +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). + +/// A normal rectangular button in windows and menus. +typedef struct T_Normal_button +{ + short Number; ///< Unique identifier for all controls + 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 Width; ///< Width before scaling + word Height; ///< Height before scaling + byte Clickable; ///< Boolean, unused. + byte Repeatable; ///< Boolean, true if the button activates repeatedly until you release the mouse button. Used for "+" buttons, for example. + word Shortcut; ///< Keyboard shortcut that will emulate a click on this button. + struct T_Normal_button * Next;///< Pointer to the next normal button of current window. +} T_Normal_button; + +/// A window control that shows a complete 256-color palette +typedef struct T_Palette_button +{ + short Number; ///< Unique identifier for all controls + 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. + 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. +typedef struct T_Scroller_button +{ + short Number; ///< Unique identifier for all controls + 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 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. + struct T_Scroller_button * Next;///< Pointer to the next scroller of current window. +} T_Scroller_button; + +/// +/// A window control that only has a rectangular "active" area which catches mouse clicks, +// but no visible shape. It's used for custom controls where the drawing is done on +// a case by case basis. +typedef struct T_Special_button +{ + short Number; ///< Unique identifier for all controls + 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 Width; ///< Width before scaling + word Height; ///< Height before scaling + struct T_Special_button * Next;///< Pointer to the next special button of current window. +} T_Special_button; + +/// Data for a dropdown item, ie. one proposed choice. +typedef struct T_Dropdown_choice +{ + short Number; ///< Value that identifies the choice (for this dropdown only) + const char * Label; ///< String to display in the dropdown panel + struct T_Dropdown_choice * Next;///< Pointer to the next choice for this dropdown. +} T_Dropdown_choice; + +/// A window control that behaves like a dropdown button. +typedef struct T_Dropdown_button +{ + short Number; ///< Unique identifier for all controls + 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 Width; ///< Width before scaling + word Height; ///< Height before scaling + byte Display_choice; ///< Boolean, true if the engine should print the selected item's label in the dropdown area when the user chooses it. + byte Display_centered; ///< Boolean, true to center the labels (otherwise, align left) + byte Display_arrow; ///< Boolean, true to display a "down" arrow box in top right + byte Active_button; ///< Determines which mouse button(s) cause the dropdown panel to open: LEFT_SIDE || RIGHT_SIDE || (LEFT_SIDE|RIGHT_SIDE) + word Dropdown_width; ///< Width of the dropdown panel when it's open. Use 0 for "same as the dropdown button" + T_Dropdown_choice * First_item; ///< Linked list with the choices available for this dropdown. + struct T_Dropdown_button * Next;///< Pointer to the next dropdown button of current window. +} 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 + + 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. +} T_Fileselector_item; + +/// Data for a fileselector +typedef struct T_Fileselector +{ + /// Number of elements in the current fileselector's ::Filelist + short Nb_elements; + /// Number of files in the current fileselector's ::Filelist + short Nb_files; + /// Number of directories in the current fileselector's ::Filelist + short Nb_directories; + /// Head of the linked list for the fileselector. + T_Fileselector_item * First; + /// Index for direct access to element number N + T_Fileselector_item ** Index; +} T_Fileselector; + +typedef struct T_List_button +{ + short Number; ///< Unique identifier for all controls + short List_start; ///< Index of the font to appear as first line + short Cursor_position; ///< Index of the selected line (0=top) + + T_Special_button * Entry_button; ///< Pointer to the associated selection control. + T_Scroller_button * Scroller; ///< Pointer to the associated scroller + + Func_draw_list_item Draw_list_item; ///< + + struct T_List_button * Next; ///< Pointer to the next list button of current window. +} T_List_button; + +/// 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. + char * Text; ///< Displayed string. + int Line_parameter; ///< Generic parameter depending on line type. For 'K' lines: a shortcut identifier. For others: unused. +} T_Help_table; + +/// Data for one section of the "Help" screens, ie a page. +typedef struct +{ + const T_Help_table* Help_table; ///< Pointer to the array of ::T_Help_table that contains the lines + word Length; ///< Size of the array of lines +} T_Help_section; + +/// Data for one setting of gradients. Warning, this one is saved/loaded as binary. +typedef struct +{ + byte Start; ///< First color + byte End; ///< Last color + 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; + +/// Data for one setting of shade. Warning, this one is saved/loaded as binary. +typedef struct +{ + word List[512]; ///< List of entries, each one is either a color (0-255) or -1 for empty. + byte Step; ///< Step to increment/decrement on left-clicks. + byte Mode; ///< Shade mode: Normal, Loop, or No-saturation see ::SHADE_MODES +} T_Shade; + +/// Data for one fullscreen video mode in configuration file. Warning, this one is saved/loaded as binary. +typedef struct +{ + byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. + word Width; ///< Videomode width in pixels. + word Height;///< Videomode height in pixels. +} __attribute__((__packed__)) T_Config_video_mode; + +/// Header for gfx2.cfg. Warning, this one is saved/loaded as binary. +typedef struct +{ + char Signature[3]; ///< Signature for the file format. "CFG". + byte Version1; ///< Major version number (ex: 2) + byte Version2; ///< Minor version number (ex: 0) + byte Beta1; ///< Major beta version number (ex: 96) + byte Beta2; ///< Major beta version number (ex: 5) +} __attribute__((__packed__)) T_Config_header; + +/// Header for a config chunk in for gfx2.cfg. Warning, this one is saved/loaded as binary. +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; + +/// Configuration for one keyboard shortcut in gfx2.cfg. Warning, this one is saved/loaded as binary. +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 +} __attribute__((__packed__)) T_Config_shortcut_info; + +/// This structure holds all the settings which are saved and loaded as gfx2.ini. +typedef struct +{ + char *Font_file; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) + char *Skin_file; ///< String, name of the file where all the graphic data is stored + int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. + int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. +// int Show_system_directories; ///< (removed when converted from DOS) + byte Display_image_limits; ///< Boolean, true to display a dotted line at the borders of the image if it's smaller than screen. + byte Cursor; ///< Mouse cursor aspect: 1 Solid, 2 Transparent, 3 Thin + byte Maximize_preview; ///< Boolean, true to make previews in fileselector fit the whole rectangle. + byte Auto_set_res; ///< Boolean, true to make grafx2 switch to a new resolution whenever you load an image. + byte Coords_rel; ///< Boolean, true to display coordinates as relative (instead of absolute) + byte Backup; ///< Boolean, true to backup the original file whenever you save an image. + byte Adjust_brush_pick; ///< Boolean, true to omit the right and bottom edges when grabbing a brush in Grid mode. + byte Auto_save; ///< Boolean, true to save configuration when exiting program. + byte Max_undo_pages; ///< Number of steps to memorize for Undo/Redo. + byte Mouse_sensitivity_index_x; ///< Mouse sensitivity in X axis + byte Mouse_sensitivity_index_y; ///< Mouse sensitivity in Y axis + byte Mouse_fix_factor_X; ///< Mouse correction factor in X axis. + byte Mouse_fix_factor_Y; ///< Mouse correction factor in Y axis. + byte Mouse_merge_movement; ///< Number of SDL mouse events that are merged into a single change of mouse coordinates. + byte Delay_left_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. + byte Delay_right_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. + long Timer_delay; ///< Delay (in 1/55s) before showing a preview in a fileselector. + T_Components Fav_menu_colors[4]; ///< Favorite colors to use for the menu. + int Nb_max_vertices_per_polygon; ///< Limit for the number of vertices in polygon tools. + byte Clear_palette; ///< Boolean, true to reset the palette (to black) before loading an image. + byte Set_resolution_according_to; ///< When Auto_set_res is on, this determines if the mode should be chosen according to the "original screen" information in the file (1) or the picture dimensons (2) + byte Ratio; ///< Determines the scaling of menu and windows: 0 no scaling, 1 scaling, 2 slight scaling. + byte Fast_zoom; ///< Boolean, true if the magnifier shortcut should automatically view the mouse area. + byte Find_file_fast; ///< In fileselectors, this determines which entries should be sought when typing letters: 0 all, 1 files only, 2 directories only. + byte Separate_colors; ///< Boolean, true if the menu palette should separate color cells with a black outline. + word Palette_cells_X; ///< Number of colors to show in a row of the menu palette. + word Palette_cells_Y; ///< Number of colors to show in a column of the menu palette. + byte Palette_vertical; ///< Boolean, true if the menu palette should go top to bottom instead of left to right + byte FX_Feedback; ///< Boolean, true if drawing effects should read the image being modified (instead of the image before clicking) + byte Safety_colors; ///< Boolean, true to make the palette automatically re-create menu colors if needed after a "Zap" or color reduction. + byte Opening_message; ///< Boolean, true to display the splash screen on strtup. + byte Clear_with_stencil; ///< Boolean, true to take the stencil into effect (if active) when using the Clear function. + byte Auto_discontinuous; ///< Boolean, true to automatically switch to the discontinuous freehand draw after grabbing a brush. + byte Screen_size_in_GIF; ///< Boolean, true to store current resolution in GIF files. + byte Auto_nb_used; ///< Boolean, true to count colors in Palette screen. + byte Default_resolution; ///< Default video mode to use on startup. Index in ::Video_mode. + char *Bookmark_directory[NB_BOOKMARKS];///< Bookmarked directories in fileselectors: This is the full dierctory name. + char Bookmark_label[NB_BOOKMARKS][8+1];///< Bookmarked directories in fileselectors: This is the displayed name. + int Window_pos_x; ///< Last window x position (9999 if unsupportd/irrelevant for the platform) + int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) + word Double_click_speed; ///< Maximum delay for double-click, in ms. + word Double_key_speed; ///< Maximum delay for double-keypress, in ms. +} 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 +// pages. + +// 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. +typedef struct +{ + byte * Image; ///< Pixel data for the image. + int Width; ///< Image width in pixels. + int Height; ///< Image height in pixels. + T_Palette Palette; ///< Image palette. + + char Comment[COMMENT_SIZE+1]; ///< Comment to store in the image file. + + char File_directory[MAX_PATH_CHARACTERS];///< Directory that contains the file. + char Filename[MAX_PATH_CHARACTERS]; ///< Filename without directory. + byte File_format; ///< File format, in enum ::FILE_FORMATS + +} T_Page; + +/// Collection of undo/redo steps. +typedef struct +{ + int List_size; /// Number of ::T_Page in the vector "Pages". + int Nb_pages_allocated;/// Number of ::T_Page used so far in the vector "Pages". + T_Page * Pages; /// Vector of Pages, each one being a undo/redo step. +} T_List_of_pages; + + +/// GUI skin data +typedef struct +{ + // Mouse + + /// X coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_WIDTH + word Cursor_offset_X[NB_CURSOR_SPRITES]; + /// Y coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_HEIGHT + word Cursor_offset_Y[NB_CURSOR_SPRITES]; + /// 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) + word Sieve_pattern[12][16]; + + // Menu and other graphics + + /// Bitmap data for the menu, a single rectangle. + byte Menu_block[MENU_HEIGHT][MENU_WIDTH]; + /// Bitmap data for the icons that are displayed over the menu. + byte Menu_sprite[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]; + /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. + byte Logo_grafx2[231*56]; + /// Bitmap data for the 6x8 font used in help screens. + byte Help_font_norm [256][6][8]; + /// Bitmap data for the 6x8 font used in help screens ("bold" verstion). + byte Bold_font [256][6][8]; + // 12 + // 34 + /// Bitmap data for the title font used in help screens. Top-left quarter. + byte Help_font_t1 [64][6][8]; + /// Bitmap data for the title font used in help screens. Top-right quarter. + byte Help_font_t2 [64][6][8]; + /// Bitmap data for the title font used in help screens. Bottom-left quarter. + byte Help_font_t3 [64][6][8]; + /// Bitmap data for the title font used in help screens. Bottom-right quarter. + byte Help_font_t4 [64][6][8]; + /// Bitmap data for the small 8x8 icons. + byte Icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; + + /// A default 256-color palette. + T_Palette Default_palette; + + +} T_Gui_skin; + +#endif diff --git a/text.h b/text.h index 11b0f7e8..cb96813a 100644 --- a/text.h +++ b/text.h @@ -1,54 +1,54 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file text.h -/// Functions related to rendering text as a brush, using TrueType or SFont. -////////////////////////////////////////////////////////////////////////////// - -/// Initialization of text settings, needs to be called once on program startup. -void Init_text(void); -/// Returns true if text.c was compiled with TrueType support. -int TrueType_is_supported(void); -/// Add a new font to the list to propose to the user. -void Add_font(const char *name); -/// -/// Creates a brush, from the parameters given: -/// @param str The text to render -/// @param font_number The index of the font to use. Pass 0 for the first font you declared with ::Add_font(), 1 for the second etc. -/// @param size The size in points (unused for bitmap fonts) -/// @param antialias Boolean, true to use antialiasing in TrueType -/// @param bold Boolean, true to use bold rendering in TrueType -/// @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. -/// 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); - -/// 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); -/// -/// Number of fonts declared with a series of ::Add_font(). This is public for -/// convenience, but functionaly it is read-only. -extern int Nb_fonts; +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2008 Yves Rizoud + Copyright 2008 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file text.h +/// Functions related to rendering text as a brush, using TrueType or SFont. +////////////////////////////////////////////////////////////////////////////// + +/// Initialization of text settings, needs to be called once on program startup. +void Init_text(void); +/// Returns true if text.c was compiled with TrueType support. +int TrueType_is_supported(void); +/// Add a new font to the list to propose to the user. +void Add_font(const char *name); +/// +/// Creates a brush, from the parameters given: +/// @param str The text to render +/// @param font_number The index of the font to use. Pass 0 for the first font you declared with ::Add_font(), 1 for the second etc. +/// @param size The size in points (unused for bitmap fonts) +/// @param antialias Boolean, true to use antialiasing in TrueType +/// @param bold Boolean, true to use bold rendering in TrueType +/// @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. +/// 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); + +/// 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); +/// +/// Number of fonts declared with a series of ::Add_font(). This is public for +/// convenience, but functionaly it is read-only. +extern int Nb_fonts; diff --git a/transform.c b/transform.c index 3f30c081..3305d89c 100644 --- a/transform.c +++ b/transform.c @@ -1,409 +1,409 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Yves Rizoud - Copyright 2009 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 "global.h" -#include "struct.h" -#include "transform.h" -#include "engine.h" -#include "sdlscreen.h" -#include "windows.h" -#include "input.h" -#include "help.h" -#include "misc.h" // Num2str -#include "readline.h" -#include "buttons.h" // Message_out_of_memory() -#include "pages.h" // Backup_with_new_dimensions() - -/// Reduces a fraction A/B to its smallest representation. ie (40,60) becomes (2/3) -void Factorize(short *a, short *b) -{ - // Method: brute-force. - short factor; - - factor=2; - while (factor<=*a && factor<=*b) - { - if (((*a % factor) == 0) && ((*b % factor) == 0)) - { - // common factor is found - *a/=factor; - *b/=factor; - // restart - factor=2; - } - else - factor++; - } -} - -/// Multiplies original_size by new_ratio/old_ratio, but keeps result in 1-9999 range. -short Compute_dimension(short original_size, short new_ratio, short old_ratio) -{ - long amount; - amount = (long)original_size*new_ratio/old_ratio; - if (amount>9999) - return 9999; - else if (amount<1) - return 1; - else - return amount; -} - -void Button_Transform_menu(void) -{ - enum RESIZE_UNIT { - UNIT_PIXELS = 1, - UNIT_PERCENT = 2, - UNIT_RATIO = 3 - }; - - char buffer[5]; - short clicked_button; - const char * unit_label[] = { - "", - "Pixels ", - "Percent", - "Ratio "}; - short last_unit_index = -1; - short old_ratio_width; - short old_ratio_height; - short new_ratio_width; - short new_ratio_height; - short new_width=Main_image_width; - short new_height=Main_image_height; - byte need_display_size = 0; - - // Persistent data - static short unit_index = 1; // 1= Pixels, 2= Percent, 3=Ratio - static short ratio_is_locked = 1; // True if X and Y resize should go together - - T_Dropdown_button * unit_button; - T_Special_button * input_button[4]; - short *input_value[4]; - - // Set initial ratio - if (unit_index == UNIT_PERCENT) - new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=100; - else - new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=1; - - Open_window(215,165,"Picture transform"); - - Window_display_frame( 5, 15,205,91); - Window_display_frame( 5,110, 55,49); - Window_display_frame(64,110, 85,49); - - Window_set_normal_button(154,140, 54,14,"Cancel",0,1,KEY_ESC); // 1 - - Print_in_window( 9,114,"Mirror",MC_Dark,MC_Light); - Window_set_normal_button( 17,125, 27,14,"X\035" ,1,1,SDLK_x); // 2 - Window_set_normal_button( 17,140, 27,14,"Y\022" ,1,1,SDLK_y); // 3 - - Print_in_window( 84,114,"Rotate",MC_Dark,MC_Light); - Window_set_normal_button( 69,125, 37,14,"-90°" ,0,1,SDLK_LAST); // 4 - Window_set_normal_button(107,125, 37,14,"+90°" ,0,1,SDLK_LAST); // 5 - Window_set_normal_button( 69,140, 75,14,"180°" ,0,1,SDLK_LAST); // 6 - - Print_in_window( 87, 19,"Resize",MC_Dark,MC_Light); - Window_set_normal_button( 80, 86, 60,14,"RESIZE",1,1,SDLK_r); // 7 - Print_in_window( 51, 34,"New",MC_Dark,MC_Light); - Print_in_window( 96, 34,"Old",MC_Dark,MC_Light); - Print_in_window( 30, 44,"X:",MC_Dark,MC_Light); - Print_in_window( 30, 59,"Y:",MC_Dark,MC_Light); - Print_in_window( 80, 44,":",MC_Dark,MC_Light); - Print_in_window( 80, 59,":",MC_Dark,MC_Light); - Print_in_window( 44, 75,"Lock proportions",MC_Dark,MC_Light); - - Window_set_normal_button( 28, 72, 13,13,ratio_is_locked?"X":" ",0,1,SDLK_l);// 8 - unit_button = Window_set_dropdown_button(128,50,69,11,69,unit_label[unit_index],1,0,1,LEFT_SIDE|RIGHT_SIDE);// 9 - Window_dropdown_add_item(unit_button,UNIT_PIXELS,unit_label[UNIT_PIXELS]); - Window_dropdown_add_item(unit_button,UNIT_PERCENT,unit_label[UNIT_PERCENT]); - Window_dropdown_add_item(unit_button,UNIT_RATIO,unit_label[UNIT_RATIO]); - - input_button[0] = Window_set_input_button(45,43,4); // 10 - input_button[1] = Window_set_input_button(89,43,4); // 11 - input_button[2] = Window_set_input_button(45,58,4); // 12 - input_button[3] = Window_set_input_button(89,58,4); // 13 - - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - // Display the coordinates with the right unit - if (last_unit_index != unit_index) - { - switch(unit_index) - { - case UNIT_PIXELS: - default: - input_value[0]=&new_width; - input_value[1]=&Main_image_width; // Don't worry, it's read-only - input_value[2]=&new_height; - input_value[3]=&Main_image_height; // Don't worry, it's read-only - break; - case UNIT_PERCENT: - case UNIT_RATIO: - input_value[0]=&new_ratio_width; - input_value[1]=&old_ratio_width; - input_value[2]=&new_ratio_height; - input_value[3]=&old_ratio_height; - break; - } - need_display_size=1; - last_unit_index=unit_index; - } - if (need_display_size) - { - short i; - Hide_cursor(); - for (i=0;i<4;i++) - { - // "Old" values are not editable, unless the unit is "ratio" - byte color = ((unit_index!=UNIT_RATIO) && (i==1 || i==3)) ? MC_Dark : MC_Black; - Num2str(*(input_value[i]),buffer,4); - Print_in_window_limited(input_button[i]->Pos_X+2,input_button[i]->Pos_Y+2,buffer,input_button[i]->Width/8,color,MC_Light); - } - Display_cursor(); - need_display_size=0; - } - - clicked_button=Window_clicked_button(); - - // Contextual help - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Key=0; - Window_help(BUTTON_ADJUST, "PICTURE TRANSFORM"); - } - else switch(clicked_button) - { - case 9: // Unit - switch(Window_attribute2) - { - case UNIT_PIXELS: - // Do nothing, pixel size was already computed. - break; - case UNIT_PERCENT: - if (unit_index == UNIT_RATIO) - { - // Approximate from current ratio - new_ratio_width = Compute_dimension(new_ratio_width,100,old_ratio_width); - new_ratio_height = Compute_dimension(new_ratio_height,100,old_ratio_height); - old_ratio_width = 100; - old_ratio_height = 100; - // Update pixel dimensions, to match percentage exactly - new_width=Compute_dimension(Main_image_width, new_ratio_width, old_ratio_width); - new_height=Compute_dimension(Main_image_height, new_ratio_height, old_ratio_height); - } - else // unit_index == UNIT_PIXELS - { - // Approximate from current pixel size - new_ratio_width = new_width*100/Main_image_width; - new_ratio_height = new_height*100/Main_image_height; - old_ratio_width = 100; - old_ratio_height = 100; - } - break; - case UNIT_RATIO: - if (unit_index == UNIT_PERCENT) - { - // Compute simplest ratio from current % - Factorize(&new_ratio_width, &old_ratio_width); - Factorize(&new_ratio_height, &old_ratio_height); - } - else // unit_index == UNIT_PIXELS - { - // Compute simplest ratio from current pixel size - new_ratio_width = new_width; - new_ratio_height = new_height; - old_ratio_width = Main_image_width; - old_ratio_height = Main_image_height; - Factorize(&new_ratio_width, &old_ratio_width); - Factorize(&new_ratio_height, &old_ratio_height); - } - break; - } - - unit_index = Window_attribute2; - break; - - case 8: // Lock proportions - ratio_is_locked = ! ratio_is_locked; - Hide_cursor(); - Print_in_window(31,75,(ratio_is_locked)?"X":" ",MC_Black,MC_Light); - Display_cursor(); - break; - - case 11: // input old width - case 13: // input old height - // "Old" values are not editable, unless the unit is "ratio" - if (unit_index!=UNIT_RATIO) - break; - case 10: // input new width - case 12: // input new height - Num2str(*( input_value[clicked_button-10]),buffer,4); - Hide_cursor(); - if (Readline(input_button[clicked_button-10]->Pos_X+2, - input_button[clicked_button-10]->Pos_Y+2, - buffer, - 4, - 1)) - { - // Accept entered value - *(input_value[clicked_button-10])=atoi(buffer); - // 0 is not acceptable size - if (*(input_value[clicked_button-10])==0) - { - *(input_value[clicked_button-10])=1; - } - // Adapt the other coordinate if X and Y are locked - if (ratio_is_locked) - { - if (clicked_button == 10 || clicked_button == 11 ) - { - // Get Y value because X changed - if (unit_index == UNIT_PIXELS) - { - new_height=Compute_dimension(Main_image_height, new_width, Main_image_width); - } - else - { - // Copy the whole ratio - new_ratio_height=new_ratio_width; - old_ratio_height=old_ratio_width; - } - } - else // (clicked_button == 12 || clicked_button == 13) - { - // Get X value because Y changed - if (unit_index == UNIT_PIXELS) - { - new_width=Compute_dimension(Main_image_width, new_height, Main_image_height); - } - else - { - // Copy the whole ratio - new_ratio_width=new_ratio_height; - old_ratio_width=old_ratio_height; - } - } - } - - // Re-compute ratio from size in pixels - if (unit_index == UNIT_PIXELS) - { - //new_width=(long)Main_image_width*new_ratio_width/old_ratio_width; - //new_height=(long)Main_image_height*new_ratio_height/old_ratio_height; - } - else // Re-compute size in pixels from ratio - { - new_width=Compute_dimension(Main_image_width,new_ratio_width,old_ratio_width); - new_height=Compute_dimension(Main_image_height,new_ratio_height,old_ratio_height); - } - need_display_size=1; - } - Display_cursor(); - break; - } - } - while (clicked_button<=0 || clicked_button>=8); - - Close_window(); - - // The Scroll operation uses the same button as transformation menu. - if (Current_operation != OPERATION_SCROLL) - Unselect_button(BUTTON_ADJUST); - - if (clicked_button != 1) // 1 is Cancel - { - short old_width; - short old_height; - - // Determine new image dimensions - switch (clicked_button) - { - case 7 : // Resize - // Keep new_width and new_height as entered. - break; - case 2 : // Flip X - case 3 : // Flip Y - case 6 : // 180° Rotation - new_width=Main_image_width; - new_height=Main_image_height; - break; - - case 4 : // -90° Rotation - case 5 : // +90° Rotation - - new_width=Main_image_height; - new_height=Main_image_width; - break; - } - // Memorize the current dimensions - old_width=Main_image_width; - old_height=Main_image_height; - - // Allocate a new page - if (Backup_with_new_dimensions(1,new_width,new_height)) - { - // The new image is allocated, the new dimensions are already updated. - - Main_image_is_modified=1; - - // Process the transformation: - switch(clicked_button) - { - case 2 : // Flip X - memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); - Flip_X_lowlevel(Main_screen, Main_image_width, Main_image_height); - break; - case 3 : // Flip Y - memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); - Flip_Y_lowlevel(Main_screen, Main_image_width, Main_image_height); - break; - case 4 : // -90° Rotation - Rotate_270_deg_lowlevel(Screen_backup, Main_screen, old_width, old_height); - break; - case 5 : // +90° Rotation - Rotate_90_deg_lowlevel(Screen_backup, Main_screen, old_width, old_height); - break; - case 6 : // 180° Rotation - memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); - Rotate_180_deg_lowlevel(Main_screen, Main_image_width, Main_image_height); - break; - case 7 : // Resize - Rescale(Screen_backup, old_width, old_height, Main_screen, Main_image_width, Main_image_height, 0, 0); - break; - } - Display_all_screen(); - } - else - { - Display_cursor(); - Message_out_of_memory(); - Hide_cursor(); - } - } - Display_cursor(); -} +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2009 Yves Rizoud + Copyright 2009 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 "global.h" +#include "struct.h" +#include "transform.h" +#include "engine.h" +#include "sdlscreen.h" +#include "windows.h" +#include "input.h" +#include "help.h" +#include "misc.h" // Num2str +#include "readline.h" +#include "buttons.h" // Message_out_of_memory() +#include "pages.h" // Backup_with_new_dimensions() + +/// Reduces a fraction A/B to its smallest representation. ie (40,60) becomes (2/3) +void Factorize(short *a, short *b) +{ + // Method: brute-force. + short factor; + + factor=2; + while (factor<=*a && factor<=*b) + { + if (((*a % factor) == 0) && ((*b % factor) == 0)) + { + // common factor is found + *a/=factor; + *b/=factor; + // restart + factor=2; + } + else + factor++; + } +} + +/// Multiplies original_size by new_ratio/old_ratio, but keeps result in 1-9999 range. +short Compute_dimension(short original_size, short new_ratio, short old_ratio) +{ + long amount; + amount = (long)original_size*new_ratio/old_ratio; + if (amount>9999) + return 9999; + else if (amount<1) + return 1; + else + return amount; +} + +void Button_Transform_menu(void) +{ + enum RESIZE_UNIT { + UNIT_PIXELS = 1, + UNIT_PERCENT = 2, + UNIT_RATIO = 3 + }; + + char buffer[5]; + short clicked_button; + const char * unit_label[] = { + "", + "Pixels ", + "Percent", + "Ratio "}; + short last_unit_index = -1; + short old_ratio_width; + short old_ratio_height; + short new_ratio_width; + short new_ratio_height; + short new_width=Main_image_width; + short new_height=Main_image_height; + byte need_display_size = 0; + + // Persistent data + static short unit_index = 1; // 1= Pixels, 2= Percent, 3=Ratio + static short ratio_is_locked = 1; // True if X and Y resize should go together + + T_Dropdown_button * unit_button; + T_Special_button * input_button[4]; + short *input_value[4]; + + // Set initial ratio + if (unit_index == UNIT_PERCENT) + new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=100; + else + new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=1; + + Open_window(215,165,"Picture transform"); + + Window_display_frame( 5, 15,205,91); + Window_display_frame( 5,110, 55,49); + Window_display_frame(64,110, 85,49); + + Window_set_normal_button(154,140, 54,14,"Cancel",0,1,KEY_ESC); // 1 + + Print_in_window( 9,114,"Mirror",MC_Dark,MC_Light); + Window_set_normal_button( 17,125, 27,14,"X\035" ,1,1,SDLK_x); // 2 + Window_set_normal_button( 17,140, 27,14,"Y\022" ,1,1,SDLK_y); // 3 + + Print_in_window( 84,114,"Rotate",MC_Dark,MC_Light); + Window_set_normal_button( 69,125, 37,14,"-90°" ,0,1,SDLK_LAST); // 4 + Window_set_normal_button(107,125, 37,14,"+90°" ,0,1,SDLK_LAST); // 5 + Window_set_normal_button( 69,140, 75,14,"180°" ,0,1,SDLK_LAST); // 6 + + Print_in_window( 87, 19,"Resize",MC_Dark,MC_Light); + Window_set_normal_button( 80, 86, 60,14,"RESIZE",1,1,SDLK_r); // 7 + Print_in_window( 51, 34,"New",MC_Dark,MC_Light); + Print_in_window( 96, 34,"Old",MC_Dark,MC_Light); + Print_in_window( 30, 44,"X:",MC_Dark,MC_Light); + Print_in_window( 30, 59,"Y:",MC_Dark,MC_Light); + Print_in_window( 80, 44,":",MC_Dark,MC_Light); + Print_in_window( 80, 59,":",MC_Dark,MC_Light); + Print_in_window( 44, 75,"Lock proportions",MC_Dark,MC_Light); + + Window_set_normal_button( 28, 72, 13,13,ratio_is_locked?"X":" ",0,1,SDLK_l);// 8 + unit_button = Window_set_dropdown_button(128,50,69,11,69,unit_label[unit_index],1,0,1,LEFT_SIDE|RIGHT_SIDE);// 9 + Window_dropdown_add_item(unit_button,UNIT_PIXELS,unit_label[UNIT_PIXELS]); + Window_dropdown_add_item(unit_button,UNIT_PERCENT,unit_label[UNIT_PERCENT]); + Window_dropdown_add_item(unit_button,UNIT_RATIO,unit_label[UNIT_RATIO]); + + input_button[0] = Window_set_input_button(45,43,4); // 10 + input_button[1] = Window_set_input_button(89,43,4); // 11 + input_button[2] = Window_set_input_button(45,58,4); // 12 + input_button[3] = Window_set_input_button(89,58,4); // 13 + + Update_window_area(0,0,Window_width, Window_height); + + Display_cursor(); + + do + { + // Display the coordinates with the right unit + if (last_unit_index != unit_index) + { + switch(unit_index) + { + case UNIT_PIXELS: + default: + input_value[0]=&new_width; + input_value[1]=&Main_image_width; // Don't worry, it's read-only + input_value[2]=&new_height; + input_value[3]=&Main_image_height; // Don't worry, it's read-only + break; + case UNIT_PERCENT: + case UNIT_RATIO: + input_value[0]=&new_ratio_width; + input_value[1]=&old_ratio_width; + input_value[2]=&new_ratio_height; + input_value[3]=&old_ratio_height; + break; + } + need_display_size=1; + last_unit_index=unit_index; + } + if (need_display_size) + { + short i; + Hide_cursor(); + for (i=0;i<4;i++) + { + // "Old" values are not editable, unless the unit is "ratio" + byte color = ((unit_index!=UNIT_RATIO) && (i==1 || i==3)) ? MC_Dark : MC_Black; + Num2str(*(input_value[i]),buffer,4); + Print_in_window_limited(input_button[i]->Pos_X+2,input_button[i]->Pos_Y+2,buffer,input_button[i]->Width/8,color,MC_Light); + } + Display_cursor(); + need_display_size=0; + } + + clicked_button=Window_clicked_button(); + + // Contextual help + if (Is_shortcut(Key,0x100+BUTTON_HELP)) + { + Key=0; + Window_help(BUTTON_ADJUST, "PICTURE TRANSFORM"); + } + else switch(clicked_button) + { + case 9: // Unit + switch(Window_attribute2) + { + case UNIT_PIXELS: + // Do nothing, pixel size was already computed. + break; + case UNIT_PERCENT: + if (unit_index == UNIT_RATIO) + { + // Approximate from current ratio + new_ratio_width = Compute_dimension(new_ratio_width,100,old_ratio_width); + new_ratio_height = Compute_dimension(new_ratio_height,100,old_ratio_height); + old_ratio_width = 100; + old_ratio_height = 100; + // Update pixel dimensions, to match percentage exactly + new_width=Compute_dimension(Main_image_width, new_ratio_width, old_ratio_width); + new_height=Compute_dimension(Main_image_height, new_ratio_height, old_ratio_height); + } + else // unit_index == UNIT_PIXELS + { + // Approximate from current pixel size + new_ratio_width = new_width*100/Main_image_width; + new_ratio_height = new_height*100/Main_image_height; + old_ratio_width = 100; + old_ratio_height = 100; + } + break; + case UNIT_RATIO: + if (unit_index == UNIT_PERCENT) + { + // Compute simplest ratio from current % + Factorize(&new_ratio_width, &old_ratio_width); + Factorize(&new_ratio_height, &old_ratio_height); + } + else // unit_index == UNIT_PIXELS + { + // Compute simplest ratio from current pixel size + new_ratio_width = new_width; + new_ratio_height = new_height; + old_ratio_width = Main_image_width; + old_ratio_height = Main_image_height; + Factorize(&new_ratio_width, &old_ratio_width); + Factorize(&new_ratio_height, &old_ratio_height); + } + break; + } + + unit_index = Window_attribute2; + break; + + case 8: // Lock proportions + ratio_is_locked = ! ratio_is_locked; + Hide_cursor(); + Print_in_window(31,75,(ratio_is_locked)?"X":" ",MC_Black,MC_Light); + Display_cursor(); + break; + + case 11: // input old width + case 13: // input old height + // "Old" values are not editable, unless the unit is "ratio" + if (unit_index!=UNIT_RATIO) + break; + case 10: // input new width + case 12: // input new height + Num2str(*( input_value[clicked_button-10]),buffer,4); + Hide_cursor(); + if (Readline(input_button[clicked_button-10]->Pos_X+2, + input_button[clicked_button-10]->Pos_Y+2, + buffer, + 4, + 1)) + { + // Accept entered value + *(input_value[clicked_button-10])=atoi(buffer); + // 0 is not acceptable size + if (*(input_value[clicked_button-10])==0) + { + *(input_value[clicked_button-10])=1; + } + // Adapt the other coordinate if X and Y are locked + if (ratio_is_locked) + { + if (clicked_button == 10 || clicked_button == 11 ) + { + // Get Y value because X changed + if (unit_index == UNIT_PIXELS) + { + new_height=Compute_dimension(Main_image_height, new_width, Main_image_width); + } + else + { + // Copy the whole ratio + new_ratio_height=new_ratio_width; + old_ratio_height=old_ratio_width; + } + } + else // (clicked_button == 12 || clicked_button == 13) + { + // Get X value because Y changed + if (unit_index == UNIT_PIXELS) + { + new_width=Compute_dimension(Main_image_width, new_height, Main_image_height); + } + else + { + // Copy the whole ratio + new_ratio_width=new_ratio_height; + old_ratio_width=old_ratio_height; + } + } + } + + // Re-compute ratio from size in pixels + if (unit_index == UNIT_PIXELS) + { + //new_width=(long)Main_image_width*new_ratio_width/old_ratio_width; + //new_height=(long)Main_image_height*new_ratio_height/old_ratio_height; + } + else // Re-compute size in pixels from ratio + { + new_width=Compute_dimension(Main_image_width,new_ratio_width,old_ratio_width); + new_height=Compute_dimension(Main_image_height,new_ratio_height,old_ratio_height); + } + need_display_size=1; + } + Display_cursor(); + break; + } + } + while (clicked_button<=0 || clicked_button>=8); + + Close_window(); + + // The Scroll operation uses the same button as transformation menu. + if (Current_operation != OPERATION_SCROLL) + Unselect_button(BUTTON_ADJUST); + + if (clicked_button != 1) // 1 is Cancel + { + short old_width; + short old_height; + + // Determine new image dimensions + switch (clicked_button) + { + case 7 : // Resize + // Keep new_width and new_height as entered. + break; + case 2 : // Flip X + case 3 : // Flip Y + case 6 : // 180° Rotation + new_width=Main_image_width; + new_height=Main_image_height; + break; + + case 4 : // -90° Rotation + case 5 : // +90° Rotation + + new_width=Main_image_height; + new_height=Main_image_width; + break; + } + // Memorize the current dimensions + old_width=Main_image_width; + old_height=Main_image_height; + + // Allocate a new page + if (Backup_with_new_dimensions(1,new_width,new_height)) + { + // The new image is allocated, the new dimensions are already updated. + + Main_image_is_modified=1; + + // Process the transformation: + switch(clicked_button) + { + case 2 : // Flip X + memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); + Flip_X_lowlevel(Main_screen, Main_image_width, Main_image_height); + break; + case 3 : // Flip Y + memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); + Flip_Y_lowlevel(Main_screen, Main_image_width, Main_image_height); + break; + case 4 : // -90° Rotation + Rotate_270_deg_lowlevel(Screen_backup, Main_screen, old_width, old_height); + break; + case 5 : // +90° Rotation + Rotate_90_deg_lowlevel(Screen_backup, Main_screen, old_width, old_height); + break; + case 6 : // 180° Rotation + memcpy(Main_screen,Screen_backup,Main_image_width*Main_image_height); + Rotate_180_deg_lowlevel(Main_screen, Main_image_width, Main_image_height); + break; + case 7 : // Resize + Rescale(Screen_backup, old_width, old_height, Main_screen, Main_image_width, Main_image_height, 0, 0); + break; + } + Display_all_screen(); + } + else + { + Display_cursor(); + Message_out_of_memory(); + Hide_cursor(); + } + } + Display_cursor(); +} diff --git a/transform.h b/transform.h index 38b91db6..899c4443 100644 --- a/transform.h +++ b/transform.h @@ -1,27 +1,27 @@ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Yves Rizoud - Copyright 2009 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 -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file transform.h -/// Screen and functions for picture transform. -////////////////////////////////////////////////////////////////////////////// - -/// Opens and handles the Picture transform screen. -void Button_Transform_menu(void); +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2009 Yves Rizoud + Copyright 2009 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 +*/ + +////////////////////////////////////////////////////////////////////////////// +///@file transform.h +/// Screen and functions for picture transform. +////////////////////////////////////////////////////////////////////////////// + +/// Opens and handles the Picture transform screen. +void Button_Transform_menu(void); From ff402b204bb6ddcd4bdc320cf0d8ec03e2140ca2 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 21 Jul 2009 22:13:05 +0000 Subject: [PATCH 50/95] Code cleanup in pages.c. No functional change git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@948 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pages.c | 118 +++++++------------------------------------------------- pages.h | 37 ++++++++++-------- 2 files changed, 35 insertions(+), 120 deletions(-) diff --git a/pages.c b/pages.c index 6cd0d106..ccd1b37c 100644 --- a/pages.c +++ b/pages.c @@ -49,21 +49,6 @@ void Init_page(T_Page * page) page->File_directory[0]='\0'; page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; -/* - page->X_offset=0; - page->Y_offset=0; - page->old_offset_x=0; - page->old_offset_y=0; - page->Split=0; - page->X_zoom=0; - page->Separator_proportion=INITIAL_SEPARATOR_PROPORTION; - page->Main_magnifier_mode=0; - page->Main_magnifier_factor=DEFAULT_ZOOM_FACTOR; - page->Main_magnifier_height=0; - page->Main_magnifier_width=0; - page->Main_magnifier_offset_X=0; - page->Main_magnifier_offset_Y=0; -*/ } } @@ -86,35 +71,7 @@ void Download_infos_page_main(T_Page * page) strcpy(Main_file_directory,page->File_directory); strcpy(Main_filename,page->Filename); Main_fileformat=page->File_format; -/* - Main_offset_X=page->X_offset; - Main_offset_Y=page->Y_offset; - // On corrige les décalages en fonction de la dimension de l'écran - if ( (Main_offset_X>0) && - (Main_offset_X+Screen_width>Main_image_width) ) - Main_offset_X=Max(0,Main_image_width-Screen_width); - if ( (Main_offset_Y>0) && - (Main_offset_Y+Menu_Y>Main_image_height) ) - Main_offset_Y=Max(0,Main_image_height-Menu_Y); - - Old_main_offset_X=page->old_offset_x; - Old_main_offset_Y=page->old_offset_y; - Main_separator_position=page->Split; - Main_X_zoom=page->X_zoom; - Main_separator_proportion=page->Separator_proportion; - Main_magnifier_mode=page->Main_magnifier_mode; - Main_magnifier_factor=page->Main_magnifier_factor; - Main_magnifier_height=page->Main_magnifier_height; - Main_magnifier_width=page->Main_magnifier_width; - Main_magnifier_offset_X=page->Main_magnifier_offset_X; - Main_magnifier_offset_Y=page->Main_magnifier_offset_Y; - - // Comme le facteur de zoom a des chances d'avoir changé, on appelle - // "Change_magnifier_factor". - for (factor_index=0; ZOOM_FACTOR[factor_index]!=Main_magnifier_factor; factor_index++); - Change_magnifier_factor(factor_index); -*/ if (size_is_modified) { Main_magnifier_mode=0; @@ -140,21 +97,6 @@ void Upload_infos_page_main(T_Page * page) strcpy(page->File_directory,Main_file_directory); strcpy(page->Filename,Main_filename); page->File_format=Main_fileformat; -/* - page->X_offset=Main_offset_X; - page->Y_offset=Main_offset_Y; - page->old_offset_x=Old_main_offset_X; - page->old_offset_x=Old_main_offset_Y; - page->Split=Main_separator_position; - page->X_zoom=Main_X_zoom; - page->Separator_proportion=Main_separator_proportion; - page->Main_magnifier_mode=Main_magnifier_mode; - page->Main_magnifier_factor=Main_magnifier_factor; - page->Main_magnifier_height=Main_magnifier_height; - page->Main_magnifier_width=Main_magnifier_width; - page->Main_magnifier_offset_X=Main_magnifier_offset_X; - page->Main_magnifier_offset_Y=Main_magnifier_offset_Y; -*/ } } @@ -170,21 +112,6 @@ void Download_infos_page_spare(T_Page * page) strcpy(Spare_file_directory,page->File_directory); strcpy(Spare_filename,page->Filename); Spare_fileformat=page->File_format; -/* - Spare_offset_X=page->X_offset; - Spare_offset_Y=page->Y_offset; - Old_spare_offset_X=page->old_offset_x; - Old_spare_offset_Y=page->old_offset_y; - Spare_separator_position=page->Split; - Spare_X_zoom=page->X_zoom; - Spare_separator_proportion=page->Separator_proportion; - Spare_magnifier_mode=page->Main_magnifier_mode; - Spare_magnifier_factor=page->Main_magnifier_factor; - Spare_magnifier_height=page->Main_magnifier_height; - Spare_magnifier_width=page->Main_magnifier_width; - Spare_magnifier_offset_X=page->Main_magnifier_offset_X; - Spare_magnifier_offset_Y=page->Main_magnifier_offset_Y; -*/ } } @@ -200,21 +127,6 @@ void Upload_infos_page_spare(T_Page * page) strcpy(page->File_directory,Spare_file_directory); strcpy(page->Filename,Spare_filename); page->File_format=Spare_fileformat; -/* - page->X_offset=Spare_offset_X; - page->Y_offset=Spare_offset_Y; - page->old_offset_x=Old_spare_offset_X; - page->old_offset_y=Old_spare_offset_Y; - page->Split=Spare_separator_position; - page->X_zoom=Spare_X_zoom; - page->Separator_proportion=Spare_separator_proportion; - page->Main_magnifier_mode=Spare_magnifier_mode; - page->Main_magnifier_factor=Spare_magnifier_factor; - page->Main_magnifier_height=Spare_magnifier_height; - page->Main_magnifier_width=Spare_magnifier_width; - page->Main_magnifier_offset_X=Spare_magnifier_offset_X; - page->Main_magnifier_offset_Y=Spare_magnifier_offset_Y; -*/ } } @@ -326,14 +238,14 @@ void Backward_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'équivalent d'un "Undo" dans la liste de pages. // Elle effectue une sorte de ROL (Rotation Left) sur la liste: - // ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» | - // º0º1³2³3³4³5³6³7³8³9³Aº | - // ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ | 0=page courante - // ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ |_ A=page la plus ancienne - // v v v v v v v v v v v | 1=Dernière page (1er backup) - // ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» | - // º1º2³3³4³5³6³7³8³9³A³0º | - // ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ | + // +---+-+-+-+-+-+-+-+-+-+ | + // ¦0¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦ | + // +---+-+-+-+-+-+-+-+-+-+ | 0=page courante + // ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ |_ A=page la plus ancienne + // v v v v v v v v v v v | 1=DerniÞre page (1er backup) + // +---+-+-+-+-+-+-+-+-+-+ | + // ¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦0¦ | + // +---+-+-+-+-+-+-+-+-+-+ | // Pour simuler un véritable Undo, l'appelant doit mettre la structure // de page courante à jour avant l'appel, puis en réextraire les infos en @@ -369,14 +281,14 @@ void Advance_in_list_of_pages(T_List_of_pages * list) { // Cette fonction fait l'équivalent d'un "Redo" dans la liste de pages. // Elle effectue une sorte de ROR (Rotation Right) sur la liste: - // ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» | - // º0º1³2³3³4³5³6³7³8³9³Aº | - // ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ | 0=page courante - // ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ |_ A=page la plus ancienne + // +-+-+-+-+-+-+-+-+-+-+-+ | + // |0|1|2|3|4|5|6|7|8|9|A| | + // +-+-+-+-+-+-+-+-+-+-+-+ | 0=page courante + // | | | | | | | | | | | |_ A=page la plus ancienne // v v v v v v v v v v v | 1=Dernière page (1er backup) - // ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» | - // ºAº0³1³2³3³4³5³6³7³8³9º | - // ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ | + // +-+-+-+-+-+-+-+-+-+-+-+ | + // |A|0|1|2|3|4|5|6|7|8|9| | + // +-+-+-+-+-+-+-+-+-+-+-+ | // Pour simuler un véritable Redo, l'appelant doit mettre la structure // de page courante à jour avant l'appel, puis en réextraire les infos en diff --git a/pages.h b/pages.h index a85a03f7..5472a7d4 100644 --- a/pages.h +++ b/pages.h @@ -27,17 +27,19 @@ ////////////////////////////////////////////////////////////////////////// -/////////////////////////// GESTION DU BACKUP //////////////////////////// +/////////////////////////// BACKUP /////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// - /// - /// GESTION DES PAGES - /// +/// +/// INDIVIDUAL PAGES +/// -void Init_page(T_Page * page); void Download_infos_page_main(T_Page * page); void Upload_infos_page_main(T_Page * page); + +// private +void Init_page(T_Page * page); void Download_infos_page_spare(T_Page * page); void Upload_infos_page_spare(T_Page * page); void Download_infos_backup(T_List_of_pages * list); @@ -47,11 +49,12 @@ int Size_of_a_page(T_Page * page); - /// - /// GESTION DES LISTES DE PAGES - /// +/// +/// LISTS OF PAGES +/// void Init_list_of_pages(T_List_of_pages * list); +// private int Allocate_list_of_pages(T_List_of_pages * list,int size); void Free_a_list_of_pages(T_List_of_pages * list); int Size_of_a_list_of_pages(T_List_of_pages * list); @@ -65,9 +68,9 @@ void Free_page_of_a_list(T_List_of_pages * list); - /// - /// GESTION DES BACKUPS - /// +/// +/// BACKUP HIGH-LEVEL FUNCTIONS +/// int Init_all_backup_lists(int size,int width,int height); void Set_number_of_backups(int nb_backups); @@ -76,18 +79,18 @@ int Backup_and_resize_the_spare(int width,int height); void Backup(void); void Undo(void); void Redo(void); -void Free_current_page(void); +void Free_current_page(void); // 'Kill' button void Exchange_main_and_spare(void); - /// - /// GESTION DES EMPRUNTS DE MEMOIRE DE PAGE - /// +/// +/// BORROWING MEMORY FROM PAGE +/// -int Can_borrow_memory_from_page(int size); void * Borrow_memory_from_page(int size); - +// private +int Can_borrow_memory_from_page(int size); #endif From 5a59dc4abb20f6ac22924b3196e8865787a77831 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 22 Jul 2009 15:48:23 +0000 Subject: [PATCH 51/95] Allow to use a negative number as menu ratio. This will set it as the max allowed zoom for the GUI display. Fixes issue 101 git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@949 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- graph.c | 15 ++++++++++----- readini.c | 2 +- struct.h | 6 +++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/graph.c b/graph.c index e97cb30a..14b41147 100644 --- a/graph.c +++ b/graph.c @@ -468,7 +468,7 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) Clear_border(MC_Black); // Requires up-to-date Screen_* and Pixel_* - // Taille des menus + // Set menu size (software zoom) if (Screen_width/320 > Screen_height/200) factor=Screen_height/200; else @@ -476,19 +476,23 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) switch (Config.Ratio) { - case 1: // adapter tout + case 1: // Always the biggest possible Menu_factor_X=factor; Menu_factor_Y=factor; break; - case 2: // adapter légèrement + case 2: // Only keep the aspect ratio Menu_factor_X=factor-1; if (Menu_factor_X<1) Menu_factor_X=1; Menu_factor_Y=factor-1; if (Menu_factor_Y<1) Menu_factor_Y=1; break; - default: // ne pas adapter + case 0: // Always smallest possible Menu_factor_X=1; Menu_factor_Y=1; + break; + default: // Stay below some reasonable size + Menu_factor_X=Min(factor,abs(Config.Ratio)); + Menu_factor_Y=Min(factor,abs(Config.Ratio)); } if (Pixel_height>Pixel_width && Screen_width>=Menu_factor_X*2*320) Menu_factor_X*=2; @@ -496,7 +500,8 @@ int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) Menu_factor_Y*=2; free(Horizontal_line_buffer); - Horizontal_line_buffer=(byte *)malloc(Pixel_width*((Screen_width>Main_image_width)?Screen_width:Main_image_width)); + Horizontal_line_buffer=(byte *)malloc(Pixel_width * + ((Screen_width>Main_image_width)?Screen_width:Main_image_width)); Set_palette(Main_palette); diff --git a/readini.c b/readini.c index ddbd8f80..41a27b59 100644 --- a/readini.c +++ b/readini.c @@ -519,7 +519,7 @@ int Load_INI(T_Config * conf) if ((return_code=Load_INI_get_values (file,buffer,"Menu_ratio",1,values))) goto Erreur_Retour; - if ((values[0]<0) || (values[0]>2)) + if (values[0]>2) goto Erreur_ERREUR_INI_CORROMPU; conf->Ratio=values[0]; diff --git a/struct.h b/struct.h index 93c1872b..ce688f9a 100644 --- a/struct.h +++ b/struct.h @@ -258,11 +258,11 @@ typedef struct word Key2; ///< Alternate keyboard shortcut: SDLK_something, or -1 for none } __attribute__((__packed__)) T_Config_shortcut_info; -/// This structure holds all the settings which are saved and loaded as gfx2.ini. +/// This structure holds all the settings saved and loaded as gfx2.ini. typedef struct { char *Font_file; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) - char *Skin_file; ///< String, name of the file where all the graphic data is stored + char *Skin_file; ///< String, name of the file where all the graphic data is stored int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. // int Show_system_directories; ///< (removed when converted from DOS) @@ -287,7 +287,7 @@ typedef struct int Nb_max_vertices_per_polygon; ///< Limit for the number of vertices in polygon tools. byte Clear_palette; ///< Boolean, true to reset the palette (to black) before loading an image. byte Set_resolution_according_to; ///< When Auto_set_res is on, this determines if the mode should be chosen according to the "original screen" information in the file (1) or the picture dimensons (2) - byte Ratio; ///< Determines the scaling of menu and windows: 0 no scaling, 1 scaling, 2 slight scaling. + int8_t Ratio; ///< Determines the scaling of menu and windows: 0 no scaling, 1 scaling, 2 slight scaling, negative= opposite of max scaling byte Fast_zoom; ///< Boolean, true if the magnifier shortcut should automatically view the mouse area. byte Find_file_fast; ///< In fileselectors, this determines which entries should be sought when typing letters: 0 all, 1 files only, 2 directories only. byte Separate_colors; ///< Boolean, true if the menu palette should separate color cells with a black outline. From 6698b78474c2e4862585ddeba09d064ca3498594 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Fri, 24 Jul 2009 08:13:31 +0000 Subject: [PATCH 52/95] Removed useless debug print. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@950 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- windows.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/windows.c b/windows.c index 7db430e0..e84d5244 100644 --- a/windows.c +++ b/windows.c @@ -410,8 +410,7 @@ int Pick_color_in_palette() return color; } - // -- Afficher tout le menu -- - +/// Display the whole menu void Display_menu(void) { word x_pos; @@ -421,17 +420,17 @@ void Display_menu(void) if (Menu_is_visible) { - // Affichage du sprite du menu + // display menu sprite for (y_pos=0;y_posMenu_block[y_pos][x_pos]); - // Affichage de la bande grise sous la palette + // Grey area for filename below palette Block(MENU_WIDTH*Menu_factor_X,Menu_status_Y-Menu_factor_Y,Screen_width-(MENU_WIDTH*Menu_factor_X),9*Menu_factor_Y,MC_Light); - // Affichage de la palette + // Display palette Display_menu_palette(); - // Affichage des couleurs de travail + // Display selected colors Display_foreback(); @@ -440,12 +439,14 @@ void Display_menu(void) if ((Mouse_Y=Main_X_zoom) )) { - // Dans ces deux cas, on met dans la barre les XY courant, même s'il y a des chances que ça soit recouvert si la souris est sur un bouton (trop chiant à vérifier) + // Prepare display of XY coordinates even if in some cases they will be + // erased with some other text if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) Print_in_menu("X: Y: ",0); else { + // The colorpicker display the color id between the parentheses Print_in_menu("X: Y: ( )",0); Num2str(Colorpicker_color,str,3); Print_in_menu(str,20); @@ -455,7 +456,8 @@ void Display_menu(void) } Print_filename(); } - Update_rect(0,Menu_Y,Screen_width,MENU_HEIGHT*Menu_factor_Y); // on met toute la largur à jour, ça inclut la palette et la zone d'état avec le nom du fichier + // Now update the area: menu height and whole screen width (including palette) + Update_rect(0,Menu_Y,Screen_width,MENU_HEIGHT*Menu_factor_Y); } } @@ -1718,7 +1720,6 @@ void Display_cursor(void) } else { - DEBUG("B",0); temp=(Config.Cursor)?CURSOR_SHAPE_THIN_COLORPICKER:CURSOR_SHAPE_COLORPICKER; start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; From cdd8a3276c510ec399a062fffdd72815905ab735 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Fri, 24 Jul 2009 08:34:20 +0000 Subject: [PATCH 53/95] Fix crashing bug when using pipette on a software-zoomed video mode from the palette menu. Fixes issue 196. Warning! Version 2.0 needs a new build! git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@951 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- engine.c | 165 ++++++++++++++++++++++++++----------------------------- gfx2.cfg | Bin 10133 -> 10133 bytes 2 files changed, 77 insertions(+), 88 deletions(-) diff --git a/engine.c b/engine.c index bef06ad1..5afabdc8 100644 --- a/engine.c +++ b/engine.c @@ -107,6 +107,7 @@ void Save_background(byte **buffer, int x_pos, int y_pos, int width, int height) int index; if(*buffer != NULL) DEBUG("WARNING : buffer already allocated !!!",0); *buffer=(byte *) malloc(width*Menu_factor_X*height*Menu_factor_Y*Pixel_width); + if(*buffer==NULL) Error(0); for (index=0; index<(height*Menu_factor_Y); index++) Read_line(x_pos,y_pos+index,width*Menu_factor_X,(*buffer)+((int)index*width*Menu_factor_X*Pixel_width)); } @@ -118,6 +119,7 @@ void Restore_background(byte *buffer, int x_pos, int y_pos, int width, int heigh for (index=0; index Date: Fri, 24 Jul 2009 15:22:18 +0000 Subject: [PATCH 54/95] Allows exiting a textfield with a mouse click (but not using space). Introduce a new global var to do it, however... git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@952 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- global.h | 1 + input.c | 4 ++-- main.c | 1 + readline.c | 10 +++++++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/global.h b/global.h index 5b1632ba..8887d7b5 100644 --- a/global.h +++ b/global.h @@ -78,6 +78,7 @@ GFX2_GLOBAL T_Components Fav_menu_colors[4]; GFX2_GLOBAL word Mouse_X; ///< Current mouse cursor position. GFX2_GLOBAL word Mouse_Y; ///< Current mouse cursor position. GFX2_GLOBAL byte Mouse_K; ///< Current mouse buttons state. Bitfield: 1 for RMB, 2 for LMB. +GFX2_GLOBAL byte Keyboard_click_allowed; ///< Set to 0 when you edit a textfield so you can use space without exiting it /// Helper macro to take only one button when both are pressed (LMB has priority) #define Mouse_K_unique (Mouse_K==0?0:(Mouse_K&1?1:(Mouse_K&2?2:0))) diff --git a/input.c b/input.c index 34148178..8900406f 100644 --- a/input.c +++ b/input.c @@ -345,13 +345,13 @@ int Handle_key_press(SDL_KeyboardEvent event) Directional_right=1; return 0; } - else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT)) + else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT) && Keyboard_click_allowed > 0) { Input_new_mouse_K=1; Directional_click=1; return Move_cursor_with_constraints(); } - else if(Is_shortcut(Key,SPECIAL_CLICK_RIGHT)) + else if(Is_shortcut(Key,SPECIAL_CLICK_RIGHT) && Keyboard_click_allowed > 0) { Input_new_mouse_K=2; Directional_click=2; diff --git a/main.c b/main.c index b2d4754a..38e944c8 100644 --- a/main.c +++ b/main.c @@ -398,6 +398,7 @@ 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; // SDL if(SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0) diff --git a/readline.c b/readline.c index 15c2e291..dd7e4f8c 100644 --- a/readline.c +++ b/readline.c @@ -158,6 +158,9 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz else if (input_type==1) snprintf(str,10,"%d",atoi(str)); // On tasse la chaine à gauche + Wait_end_of_click(); + Keyboard_click_allowed = 0; + size=strlen(str); position=(size Date: Fri, 24 Jul 2009 17:10:08 +0000 Subject: [PATCH 55/95] Fixes mose drops when entering textfields introduced by the click-to-exit. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@953 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- readline.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/readline.c b/readline.c index dd7e4f8c..8f2a509f 100644 --- a/readline.c +++ b/readline.c @@ -142,16 +142,6 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz byte offset=0; // index du premier caractère affiché - Hide_cursor(); - // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_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), - 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 - strcpy(initial_string,str); - // Si on a commencé à editer par un clic-droit, on vide la chaine. if (Mouse_K==RIGHT_SIDE) str[0]='\0'; @@ -160,7 +150,16 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz Wait_end_of_click(); 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), + 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), + 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 + strcpy(initial_string,str); size=strlen(str); position=(size Date: Tue, 28 Jul 2009 18:10:12 +0000 Subject: [PATCH 56/95] -Removed pic-samples folder in 2.0 branch. -Added some Arati ST IFF picture we can't load. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@962 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pic-samples/iff/2PLY.IFF | Bin 0 -> 9742 bytes pic-samples/iff/ATARI_~1.IFF | Bin 0 -> 21656 bytes pic-samples/iff/BLOCKS.IFF | Bin 0 -> 4244 bytes pic-samples/iff/COL_LOGO.IFF | Bin 0 -> 15794 bytes pic-samples/iff/DRIP.IFF | Bin 0 -> 9732 bytes pic-samples/iff/ILOGOS.IFF | Bin 0 -> 7328 bytes pic-samples/iff/KUNG-FU1.IFF | Bin 0 -> 5062 bytes pic-samples/iff/LOGO.IFF | Bin 0 -> 9674 bytes pic-samples/iff/MENU_M.IFF | Bin 0 -> 15018 bytes pic-samples/iff/MOCK_UP.IFF | Bin 0 -> 18600 bytes pic-samples/iff/OTH_1.IFF | Bin 0 -> 10274 bytes pic-samples/iff/OTH_2.IFF | Bin 0 -> 4180 bytes pic-samples/iff/PDQ.IFF | Bin 0 -> 22244 bytes pic-samples/iff/PIC.IFF | Bin 0 -> 6950 bytes pic-samples/iff/RASTERS.IFF | Bin 0 -> 9908 bytes pic-samples/iff/RASTERSP.IFF | Bin 0 -> 178 bytes pic-samples/iff/RASTERSU.IFF | Bin 0 -> 32214 bytes pic-samples/iff/ROXS.IFF | Bin 0 -> 10790 bytes pic-samples/iff/ROXS_SPR.IFF | Bin 0 -> 4262 bytes pic-samples/iff/SPRITES.IFF | Bin 0 -> 4510 bytes pic-samples/iff/TETBRD.IFF | Bin 0 -> 4996 bytes pic-samples/iff/TETMAP.IFF | Bin 0 -> 5714 bytes pic-samples/iff/TETRIS1.IFF | Bin 0 -> 5010 bytes pic-samples/iff/TETRIS2.IFF | Bin 0 -> 842 bytes pic-samples/iff/TITLE_PG.IFF | Bin 0 -> 18550 bytes pic-samples/iff/T_2X2_1.IFF | Bin 0 -> 3056 bytes pic-samples/iff/T_3X3_1.IFF | Bin 0 -> 9408 bytes pic-samples/iff/T_3X3_2.IFF | Bin 0 -> 7056 bytes pic-samples/iff/T_4X4_1.IFF | Bin 0 -> 3664 bytes pic-samples/iff/T_4X4_2.IFF | Bin 0 -> 4930 bytes pic-samples/iff/icons.iff | Bin 0 -> 240 bytes 31 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pic-samples/iff/2PLY.IFF create mode 100644 pic-samples/iff/ATARI_~1.IFF create mode 100644 pic-samples/iff/BLOCKS.IFF create mode 100644 pic-samples/iff/COL_LOGO.IFF create mode 100644 pic-samples/iff/DRIP.IFF create mode 100644 pic-samples/iff/ILOGOS.IFF create mode 100644 pic-samples/iff/KUNG-FU1.IFF create mode 100644 pic-samples/iff/LOGO.IFF create mode 100644 pic-samples/iff/MENU_M.IFF create mode 100644 pic-samples/iff/MOCK_UP.IFF create mode 100644 pic-samples/iff/OTH_1.IFF create mode 100644 pic-samples/iff/OTH_2.IFF create mode 100644 pic-samples/iff/PDQ.IFF create mode 100644 pic-samples/iff/PIC.IFF create mode 100644 pic-samples/iff/RASTERS.IFF create mode 100644 pic-samples/iff/RASTERSP.IFF create mode 100644 pic-samples/iff/RASTERSU.IFF create mode 100644 pic-samples/iff/ROXS.IFF create mode 100644 pic-samples/iff/ROXS_SPR.IFF create mode 100644 pic-samples/iff/SPRITES.IFF create mode 100644 pic-samples/iff/TETBRD.IFF create mode 100644 pic-samples/iff/TETMAP.IFF create mode 100644 pic-samples/iff/TETRIS1.IFF create mode 100644 pic-samples/iff/TETRIS2.IFF create mode 100644 pic-samples/iff/TITLE_PG.IFF create mode 100644 pic-samples/iff/T_2X2_1.IFF create mode 100644 pic-samples/iff/T_3X3_1.IFF create mode 100644 pic-samples/iff/T_3X3_2.IFF create mode 100644 pic-samples/iff/T_4X4_1.IFF create mode 100644 pic-samples/iff/T_4X4_2.IFF create mode 100644 pic-samples/iff/icons.iff diff --git a/pic-samples/iff/2PLY.IFF b/pic-samples/iff/2PLY.IFF new file mode 100644 index 0000000000000000000000000000000000000000..62d528fc253662b33bae856dbef33715247eead4 GIT binary patch literal 9742 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 literal 0 HcmV?d00001 diff --git a/pic-samples/iff/BLOCKS.IFF b/pic-samples/iff/BLOCKS.IFF new file mode 100644 index 0000000000000000000000000000000000000000..d6488cbaa09fde0975bdc6300b5db20aa7928d86 GIT binary patch literal 4244 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 FGxs_>Wi_PM2%}= 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 literal 0 HcmV?d00001 diff --git a/pic-samples/iff/DRIP.IFF b/pic-samples/iff/DRIP.IFF new file mode 100644 index 0000000000000000000000000000000000000000..e992c1179593c0f1aeecfaca21208d45f0f811d8 GIT binary patch literal 9732 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 literal 0 HcmV?d00001 diff --git a/pic-samples/iff/ILOGOS.IFF b/pic-samples/iff/ILOGOS.IFF new file mode 100644 index 0000000000000000000000000000000000000000..e9be09802b683a0f229d67de3cbf3c6b6435103d GIT binary patch literal 7328 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 T$O+*PE|uf1`hmbpWcmLAZO7^X literal 0 HcmV?d00001 diff --git a/pic-samples/iff/KUNG-FU1.IFF b/pic-samples/iff/KUNG-FU1.IFF new file mode 100644 index 0000000000000000000000000000000000000000..93b84fb5868cfdcc6c707616aa4c0e46ff7e47f5 GIT binary patch literal 5062 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 literal 0 HcmV?d00001 diff --git a/pic-samples/iff/LOGO.IFF b/pic-samples/iff/LOGO.IFF new file mode 100644 index 0000000000000000000000000000000000000000..727ee12f53d2c8937dd2a54047c0956f44abd7ac GIT binary patch literal 9674 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 literal 0 HcmV?d00001 diff --git a/pic-samples/iff/MENU_M.IFF b/pic-samples/iff/MENU_M.IFF new file mode 100644 index 0000000000000000000000000000000000000000..601e8ce79625b3ef97e15e90cdc9003b1a8c16b7 GIT binary patch literal 15018 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 M>08pdyg$?b04hK!{r~^~ literal 0 HcmV?d00001 diff --git a/pic-samples/iff/OTH_1.IFF b/pic-samples/iff/OTH_1.IFF new file mode 100644 index 0000000000000000000000000000000000000000..4965cb42dd0de4ba60e1ec3cab5eec7a05613941 GIT binary patch literal 10274 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 O`-S;lwuqnZ@cC~FlM~he literal 0 HcmV?d00001 diff --git a/pic-samples/iff/OTH_2.IFF b/pic-samples/iff/OTH_2.IFF new file mode 100644 index 0000000000000000000000000000000000000000..07aee3465e060a630f5b3ddfb7c327ed49937687 GIT binary patch literal 4180 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 II7?RlKk$gBZU6uP literal 0 HcmV?d00001 diff --git a/pic-samples/iff/PIC.IFF b/pic-samples/iff/PIC.IFF new file mode 100644 index 0000000000000000000000000000000000000000..7dcfa1fd12b5a30dcf8d4847f08eb1ae52ba8350 GIT binary patch literal 6950 zcmbtZYiu0Xbv|=vmNQE)ca|1yt(>X2TvM#85w8^k|^nrQz7>$nk6Gz#*=8A-0GB0=Q>Wm~`jGzxe$$cb=&Ji6W zI(+mqPho`-ts}#{{hPGgzZ3fH--bE(*`Y5IJv9D>p@HYX%cSzOa#Mtg_=S+E8_F*= z$@SwaN2Q9EXox0%cS$|Wt{mMM?OM6Dt%m}C`b||Hy(VO|{-zM2=vu*u7V>b=TB$Yf z>P?f1n5Pd;Hgrq>nqPi%mktl4Xg`H#`KtYs~0n+9;oZO6m9Z$X0Zw< z!kSRrJSxSF4W@2%tzk)%3AES&i|ZPHZ_NU?>tekN)3Ut0b)p*&2uoi?DP4wn}$Urvba_Q?dLUW~3SPkTt zN?joFbp4-78~Ym4CkoAYM{{8Qgj;kCn-!<%72Pb6PJdpw+8=ZfDgUWHCc0EoK!q|Q zqZY(fqQw#EmqsX4LjC2DOy-fyg|mM(qWh-bf!_ABrmy>n5qcn|V1MyaxWxaCZEcJQ~@dBtjFgIvyaSt;#BXczEk;A`I(;C z{ZpdE2urhL#E9eysYbP!OOy<1ufxphZ7e*TU3xM7${!!lSjv>u zEWImk{ZZs@!?Z8w3yyic2Oto0y`NhVw+|yIjszJe&u>^ z=VMA&vMZTt&TjHmF*4$8%pce7XIpwvpTq56kegO#Ix%rpZU9)@6P)*?)m{^dEnvF!;#C zCnkC)`X=&&`B!@SkKGF#e`A8E41Pv(aq*_?iHQNxqh8fI(@zlniTXZGLYWD_@6idI zLT!p+_^ZX=;yF5h({oraiWAObj-J-j$|POT96g0r8@cHZpw9(R01H$`S)SUXB$YkN zbrjUe0LG5 zb^iDDm%VDD&Y8S`9d~G_f32jinpdHr4bpE~kwQJ}e zm2&+Bws*EKc>l=0;#TbGO&@Ut6PXYAFq3rDZTMBU>Zv!T_B@$+GWYe|@8y0!)4Aub z-vE8HEOMeOTw$Xwh%8I9&6yGrn*0|P*+Rtu!w|C&PK_>baQTv_q9Uhf4 zZImX*@SO&wE!~<*U3Go`EYWsn{1G8?dq1Cx?~iXPvEf7a&+)bMQDBxCj>R6@4kVF@ zYUW%4j*F3)@w_svh&AO`sx$#|loj=6LYjahfJh9-+N3JN1W=i|CYl>~4A4ldt3jJI zZ>r4*m2LGfmRgH2SPPw9PfAm$Kxn&fMP|TaYGXHJvL?_>cndxYRUjZCZh{F0X*_s4 zOk-A=K^4qJgDt4G!Mi3^UM8^YH{jaVVX(6ZqrJBc<@Gq;nosO9k&8_D-J{$?w1e^qm%^d z94nVX1j(aMhu(KbxDI_B!Z$En2qd;9uft|-OnVC!-_#orb(vQIxlNeot*e@+HmJzR zt(uh$%wCe0gGhjccx2&)z6i%%Kd3Uu`jNNo&0qdv#R zIXRcGO)p_%DqQ--h8K8N*~)2JWUx!wMa#4Nu?oK*a5NNbx;-L06}BI>VIUD5B~Zp; zk!>JbCSUPDp+*PMbFWCNkH($Q9rtJiN2BNHV12Kw$qUkp@Gd+tD8X03P~mFs6;X+@ z?wMYPZIGDLJ-wj^rtAQk(y;Mz!w)LJZW`&NXGg6HWKsYk-#|?T#^(2qnYJh+#(}o! zz2(LF8OeJ?w;3s!ff`cU5iaES6G-sk8MT(ULNCw;O4=btx(lm0bXmW~$e}<*t*9H& z$_NwLJ4Zwx)#Cn^PC@_?1{$Txlus3?8w%r}yTLwpvc;e~)YB@I7AofgEg&MOY@Lc{T9IE9pubpHU^%IXv_7>}ai$_PcZXo#M8OyU6`k+#;u>j4h1) zUi+Ns>0ScX7Sko{9=SYtx$WZicG$%2^TxdpQ0L!qWp&i!@C^?3Ls?s1zYf<)8mDni z65|lh^2Q2AhA_qEX?H>)p(6DL@CSHnpVQeR7#b`eugL?!ZXj>=!wxap__eiUy=*D{ zD(nAtT$^x{(&=`)c^52WOHbGop}VS2uwnP&KKQcgE(kxpS_We^j5tkZyvhRK4(w^I(2bvX?@9Bw61Qb zGWh#{F#yMZxwuerFbyZ!i2BmuSg)eSiYC~`7rmG zJ84kpgl_1C{&-_N*dIozo9Mm5sBH&P+;rj?&KAl0Ew8PvzlKMFYGGFmw_>yV-bu7> zQOLl0@z(;E@GES?z=Yvq?d96THMOSjJ+&bsjqErse-y2}T)kFYGMDs=M97YmQ7Svl zPJ9&2eph)Hc?iDRyN$ftX?#!(tF_l^`nY}&u~%SMJBlr3w00P6IhPw*a|iN+Iqb*! zff##b^o)8&orX2)kbAg8)cJ@pG-$=p&A7?0 zdw7NIqR)0Q6IR`dn9=zWCsz^07OfYpTx=lh)NmDd;FF>|J=WX zM)rGX>Ck*pAB*P4mSv6pV3o&PmJtGnUWvwAy8HT-*Dv#oSkqRoEJgc)CPy;#Z_3!S imeyC-qTM#76*L+_U@?+Gn8ERuc|}VSj7yZKi2fG_F7^@t literal 0 HcmV?d00001 diff --git a/pic-samples/iff/RASTERS.IFF b/pic-samples/iff/RASTERS.IFF new file mode 100644 index 0000000000000000000000000000000000000000..efa4c0b58a22620192f4d9f8ace177eb4dc2c853 GIT binary patch literal 9908 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 Y5wTPL?>M; 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 L&E7Y_+4g?`sL*_W literal 0 HcmV?d00001 diff --git a/pic-samples/iff/ROXS_SPR.IFF b/pic-samples/iff/ROXS_SPR.IFF new file mode 100644 index 0000000000000000000000000000000000000000..b90cc178e00c6fecebc95ae54289fa9fba631af2 GIT binary patch literal 4262 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 Ql3b20usYr?h+Br}|1!_R-v9sr literal 0 HcmV?d00001 diff --git a/pic-samples/iff/SPRITES.IFF b/pic-samples/iff/SPRITES.IFF new file mode 100644 index 0000000000000000000000000000000000000000..eb906067bb31522943418264edfa62a6e52f0525 GIT binary patch literal 4510 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 O&-=6RbxhueGQdClFn<03 literal 0 HcmV?d00001 diff --git a/pic-samples/iff/TETMAP.IFF b/pic-samples/iff/TETMAP.IFF new file mode 100644 index 0000000000000000000000000000000000000000..7956aed2051eedff55329d2f83655d2e64c068c6 GIT binary patch literal 5714 zcmeHK&1)M+6#vcar{piiwNq#z-o%m(fk0AB>7jIG$N6v*C2rytN+Gz(DHkEf1-DS_ z4WW=zVtmO_I+oIdN)vpHdefm;z3X5d{0E2xoK-6A%bVYOZ)a!c zy?yiE%-PFVGQi<4r!G!pCNk$I0SvG-%7oCtEg%+`^6AX@G^tJ!rBbP>si|x>yRx#f zy1H7eRs~&v$U;ID$Wkj6Ra8%3xpa=+v5Dwn)=pV}MYg+kKJV_ExIFnSF!7+MBkApbqB|~5@oOw(nJTxGX8fQ z2KsRXAD_@}g?2pz>PTR@O?B9Z0hNFCG5l^(Zs--7(XX}i?uOmy5&Q`k8ROqLrR7AU zU#XsIBBM28o4iZ#XT710(sj!a)O9oN^FWf)bDuZ4xX|KSGsd|bj|baE*^FsTE$E`| zeb2YPcA;f7V*&RQG~8JD{j05OA+mPcFDQ)wHLHmlVVc@BVSyD{ofQqT(U{iiyg)Un zje~G;oVpCoxbAUcT;ag^et35Hmt*?KvE*MzZw~+9jHV`&BS|Lp4)vh!3>+r9aR_51 zX|T}OMn(nHRI+h~v~kjZjR3zAwm-&ZG+)j^t`k`!z3w!h{b07M)Js$Ts9-pU3O!OU zpBGR>jtcPS^sx_VXproqNdpRehoA5x7V!l=Rr(rk&}10S<2pXUXQ4hlSaLmSqCvCb z!1z~pp7Q4%+>KPwQSLT*n7t9^Zq>@n{a6%ps|$b5|1nq0Jzk0=6!OMh-ml*kM zw|G&WiPqrj^N;e5s=~4o?;UNg!E}fm&`rx^+lgYfk8&Z=BVbVriMaYuNW^*6!$Z$0 F;045J8La>S literal 0 HcmV?d00001 diff --git a/pic-samples/iff/TETRIS1.IFF b/pic-samples/iff/TETRIS1.IFF new file mode 100644 index 0000000000000000000000000000000000000000..8114bfb239fb7412385b60308bddef5347407374 GIT binary patch literal 5010 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 vnR-x(mYJ+*oj{$$XDVPSD7n2_>1?E+U@ zh>fj%4q%#DyV+@WZnOZ@ z)m40Cga_>dm8z>3I}0nME)ZFk_51xi&qbu4WqH3V`C9>`3t`BCE=Nb?$QM_au5(U6 z@KND-4R5@j@W<;QY%aI%0Q%+a*1}C11n?BX7r_5({Sa@oXzNK;v>caXazZ@D3BJK$ zrsbru6-wGxNmeP5Vxw!0WKu#hhGUIPtwt{+kyXlauu4uzlV}r>w1_2&N94Qqmj1=} z-f&VR$~iE9;M)JOc*LDTh!|;X(=tgK(~X%%oTRD5RH9(Kj*Fu`v5b0$9*6l%n8sJ) zByPlXn@*Cnj0>JfA*K8k5j?5LtW;#O)Pptg?K$z~4EJM$dAh$g66^a;nmagMXqTLy zD%MBBRH=oG%*ok3<#}8OR|x6?wa(N_ZEHU)lXH$a}{74ZS+RYoBY2`Ix|{-V7{n< z|Jb{zFC#LZc0JC$l+t(3yXL#uCU%*ZW{-GhcFb$_40Wt%cZvV3#^Nh1KH)unUS%8rl6k`;01|gSB8PXI4ol$YgENyYSsfX{hl)eYWDlx@B8PY-Z}4i_xE|9 z{dtd*XFT~Bz|uya@0% zzUIg+sko`a|0U`MRixZ!Gd?rJu-r6@Hej!NHEw_4E<8QEo{ShW0WDGP;xbjc#Nlh9C@DCRM8rvd#D= zDrhf4(Z3e~*L+@ai@r!VvmUw?`+SP4EvEqt!~{dgpjU_41|EoJjkJ*+QW3j&fFrKX z)Wc8*qagx%K{(t8Jwb=h-uN4VZ*pEP>y5t=5QgtP{Wg1JRZvO0_1M`&gKBFn9orBW9wV z6u|>+AZEc#%o4tnG1~qHvn}F)>O8g%jw`^?odJZ5g?QYV3e1ly)bXaVR1X+u8=XKk z#P2pVn=>9xdGMO~U3kuHGds+pSzyg0e(v31?lim1Ki$90Ty9QFK9)4UAE>N4co59_ z+GbeVbA_%gs5o4R-u`f9@&cVIj>NOt`uLFsGKey4Kq`?bh1~ddzwa^Yiz)YydJDi9 zHsUX)1!;~8Ts`@$X>j}U*Oq@fbW97opr?fw-l}FFF^!PM2?>H>%rL~pC)=>twziI3a zUn7xh#XH6wCVOH^9t>%ya+ZT)iw5{Ub`?+nn<%S70K2MLeN3^Xzda#avE$5~ug&(AIxe{1d;B$15H6qx11T>QW+I;poC&~4bxP#7uM!(>;nKwz`tqHc zsJh`9IL!@*GC>}~+iiCXdXqlx99`jgmRaAbh(|dq; zTq2Q(j}QyDn)Alkv~!~+gZs<6tdIAR4J*ymE{rw7eKo~>HFqVgNCkHxqE24F3SUyzqx%UqTS%A}lpM=FThKVU_G6pKX_{50`G%8>bIY zQjCQfzi8@T_XN3alFLZO-@2}(dHYi8MTpVkhvW=eJ5&_gvHYej>%D(!yJN%WFheJ9*jX{ru*>d6{p{iY^HPieYrhq{gQ&NG7)x?6`hdh#)V?m$GM&vl##v zoX)iL-D!L(Y`RjIsFDtoNvSGQy(shr`%TFz_ zy{C|xYlHHWH`ggstZ@mB&zh@>bkc`-u%8W>e=<+dKe)N@en_wYSP{BgEHIT)8$mxa z5)!QNILy>h$_cQ5JvN&88@&}FcoK~Swz z1Y}Jd8F8lHEaeh9n5OCP=_gU9{Z8+~{8#j=vY@61V15kUsr2R)PKeI%x2 zLePU(Q|sqfjf!8Dm~#Kx2j}mf{T}Rj=I?7Cx$lW5znuN~%Wn)@KJ5AQq_|b9iWV*l zb!Qx2;L5O>Nh;w8Cxu*Qv>NTJhU|Wv$C?%ooV|xLS!K}ATx4XU0Qvw?zXZ`%%oVjm|OYO$G(S;Qn@;xC39yl&l2h&M8-QG?vM_RaHs@|<6LgCf%0J%zlO6|%hlATe$&Ay6=#gYwqRLsGvov&t^wqlQH;}$&6w9LfQ?n^Ey z)19bZ!j7;Q<7*CPj!8Z9&`wQwY+}l^mo^@q_1%Ykm(T8-_fhs!Gr(EJS?w`68&eZzI8)QRe38Rr%iwThV{CA3KwtYb zV;Encw^T;gs(-3+5dBShYY2VnYW0WGy80w_N6SZb6zm7WI zz!a}T?4gd(cDmDOpf?OHGqys|Ln=@&w;ssd!hqIF8=3Vn4@7>{a;WfoE|g2yXOFD! z1<Av9g)Mc3E5@H7%;yfX3kV$4E=<@LF+Ta^ZN)#Xf>y5Ev@EpKLI=_~)TIh|MHz;=|Q#2M%6&%w|pbA0ySA~|2e zzIxL9mrxraoNMLpW2DgH$rM+$p3nW-taZ7$swx+8ClGQFK*!Eq(X?uBY;sJWi1lQ; zE%?L_wWhbeRLM{!mjVgE(Wb5WET!N3E8h?LdcAQ5kF`AR-%3i!1#N?Ks%dY}!8&zV zey^#$8X_7ZmWQcLYA5PuYW3?=#Rfxzt6?;jho1<;Rz20a{D_A8>K0wi?^D9^cpf;~ z=p<+2i7_(==b=%C8UPr}!>d})i^UPZ01;n=>PdN!Q92rLzKX5|zReHlb2NOksIfgK{ z7!qR}gz8cZKd20{2T9oBFCGga?#;5gz#SyS<%{FU2=ZfDdh@s&=Ul`ls}YD>gzWRl zxFt3gSX*Q4%#lsib&-#TOz%~1NIE|w#^{ILLZsdA#7wCgsW@Az5p80&bjpvBnI6qs zhRXf<`K)z~R$C0%oZ=ZyNqUeFAvj6>QBbU!4ay6CH{_d;wveaQ=hR9yqXrGFyv1Zu zylkziJQ@ww{i0qH4EZ|0QY}M~a81SUxjD6Ti%l?w4%SUXPBa)|a}H(k)~9Xxwk>4+ zwI|eztWJ;#ZV{LB+$K-difEuU!&JO8Ni)&dYwjBOC|a>nSDdxZM6Qdd(-5Bxe@GL8 z!*#>kLh3t7VM`&FI1t4ppFmD!9_0Q_&f5-S&%>j99T~s5UEht8du4j;SyyAf-JCL6pKD)JZMx8P)ZEv(BD8%-KPCJ$8W<+dFpn@n8$WD}IUpY=Oe zx8!>M0q00G-z+J+om2R6g3YX1mSg7!^o1T1RuvsSv*GZjr1xDA%ImI}PFfi*<+3?$VX$_$^yZ}H6BB;*77Ju$6=1qP{%ge|p;`v>Z7kQ90 zlHWkYhwC7Bofhc90lGX9_b5t|6+%nf9KyEpOQWz#tEESzQ zF}q;y>u(*~#Z0^1q6pmO=3ow7lR8;X|>?eDEUi$kroB02> z+b+6;SqS4t-0J=D*WqAYWQ5;sg++_~%e zlwN!&AFP`M?aV6072ji%{;cC&J`!X zZbMl)wg6`_j-hKebR3Ep_QVJKo*e-RuiGc388*emJ(DqV1($;;l0kgrHL{Uw;_&6T zyq9WAPn9LFhc3rh+R$-sQTz4bj|-EVYjsh4H8>jVbR~-RieBY;6;Rby&7TtOrizj0 z#Y*9a%{5P-`MMISjTh8M!Y{1*g|sJUOwcc+q6+iWuD_eVER zdJN0?6nG?Y-ak@*T_D$#J^kqu<5Q4gQ(!zj9VU#Nd}cves+fuvb?T@ENwd&Cc?A1R zW~ck6)y?1*rZ1G|A@hzt89eoXWr9UL9wu66oqlTP;|Ej!H3RGBr#_*XXS76F*v0S= z^qHv1QC2Yz2P6yC0FV-~mT)H$h66;cOo)m|V3U~Zh7IY*xt#3wzrDfb>Tk|FnxfU+ zH+M~jGvn6E)&zdV3?^v?%2`hGCy{G@rd)q&kUN`?GEbh6(hSA=*V2EQoid-4lW$64OJBPNCQ>{LmXA`PB6Z9y zXeT$|0W>4}!Wf`oJv<4oLMQwirojY!AAqS7Zo#jZ{*5hq`b+-;N8l@e`6pN+_mW%w z1;?3&rN6>U_$IfM(|Y{<02agdkO^K=2J6qIu{~J|{R_JChO7HLQ9rqR1Xjq#lN=)L z^q{5ETj4;?KNp}G9FoKb+g&9mEJwhp-0uAWAu8Lk_*YLz$_JqON{aCHX}a+6$DS3Q zXRkb>j!zq;O8&K~dVHCqM}BDT7@{P0@}a@WHKhu&4onEgaW<2oKnqh&O#~y=3ak3* z=qQGww=+JiJ=6(PYgIf#e=BJ6!Lyl8_@c?EYdmL!g!Q;{gLF1NJ@Y*m2*dT+viC%m zHkp^s{N{dr-LSWA=7;3~8`JBvKAWxGkVns^yEI3=m+3+2p0Gc8a?GCM!!{{UyH1A- zN=*lwWG)qqmsz;Vm5!^=FB zSCftwtZHj6J9Iy=H&^#D~X3YT14aPJK^RbwV zhJi2ypTn_iAjTaAV|g^9j{H6hf1_b2mdN!(F&~Fx$n9b=$)!eg%MS3DEyGzN#-7@@ zXz%9~oB-?0DASNSu}W+Vtc_bo2tUpQvZ8^$D^w6k-V1~w7PM-bo8N%b3{ zxSh6z=JHZhIGUULwf~)X3OJ93N7iMR6J>|c=GfoHCHK9+NCnkj-mssV@L3Pu{MqcI zn;MumqZ{1iZ@Hm3_iDWJTB{?Q2=(nP^-@Q#_s-szYB8LlH3Lz_u(G@c9i@4^9t2)% zNnXF%d4F1Hj_-7R%-+vj+u9mV3QfUd03<{Ok)LLFTT4x&w(`?~T^^gszSCB}+VKsk z+t>C>oA=yz?3VD@JeuA8bW6&fy25v*HgDTs+Wz&;%%w=#EQQ8fIQw&*t!~aauFcj) z&Phw*U6wUsosr!VJM!IcSJ#|#w~;oo`ux)0+n!#X$5JW4hOr;#so95CyU$5&NI#JYs zdu6_W0bywL5e3eY< zn4(QifIu87B8uvuC6!k#2K#~q6)l8xD%u&0BWZjXEvjVYDnaE@c!Go=kHRa*nKTkD z(PGd^tn2LEsU$HH>%n*uMwhg5bP9X)@+zfhQQ=i!OQs{}8cWpI*cO#nc|+|}dzBqH z{te}CG+m3)9t;|VNE#xCq||Pvjwa#mpzHM2uHcoVAS_|rtdG7y6ZI{c{)u)eMRjPf zKZX_JR=g%hu#^~eQprK54wVmsMgo0?!AKU*747*HZX{%}?ZU5&A$z{)V3<->s`wx0Q+#}(RzAvOgDvow-Yz@2q6gts` z0?mWPV0jgys*@&c3;m1sI!)iexEJmbBU(a;hdtf91^3p1VCYnN<^N=0U>M7#s`Gaj1;P-i&!@VD*qL@1+`Vl33HQ=K;x zv)5c;CZkcNMUqhbO(1Y+j3>02wm)R2cy;qQedv6n2Hpt%zE>Z3-uyn&h!F)YlVn#v z@IVA8F!mMKcNv(WkV#@414u$~9O*?M!=yED8}?3I$SCVjrvKvLL}piKTGZZv7(bjhmb5MwOEGIY!jNGu^?M4F0#+-a=Q~kF>jkM%R18OT36M- zu%`hLCvm;n1c_|Ykzu3g2Fn^d)bt{@EMqw3PzWY*hiq%xhynfHB}|D{9?VQSSGJ<1 zX7<}dYX}CduuSV7)4B4B`FKv}qWHZ{F@r7JzWy)7t*$93T99d@Mr6Y`8%dYh64`XL-0A)jw}Y{e z1K12BXhckCO~z~^`K{P{@MitB`3Y&d91HR(YD!l`h@d9g9T761%s2bxzVH2m;-?or z!62jO4Oh4s&123+d>#-fF0*Zu>qFb%Oy_{+(>z?&hm*dlq{{Aw^Q6LeR_Zl|+{?SMakEM5FKMWyRhYfF!whzv-_&taKIXAYQLGO=0)`NQBp$4P7 zRB9$p+#>o~aWAB>6|~|Y?$esFJi`wuP}cCd`AO&*;h;g~30bFw$(xjn9N8fT;=sKj zBshHd2L?;j+&L>e=+pvf5Ha6MHhNnWW13|0Tht1v#ph&$rG zSK@k6mIi!m2*(cMlVdXnKGuIcj;fr*zXoW$-W|CiBFV&7jkmUbWLjiJQI5UAiiD|0 zJpXgN=I}3B7dD)uXpFu5F)Bku!RP9z(0r<=O4T?HuEHOSDTTOvLO36X=cdA4s>oP> z3?>R=Fz_ZAd9@Sl7Q4}xkKO}6ywI9=k0=5wi@I$CO1)}jwUs1P6==--4D=Hb@=mGa zM5Ul_EOgcpvkeQn(>}}>lP}3Wm*hQ6cKOD9EXD0d{69c!wYFBqyrXuP&(;*9EtAT8 zW=D;$kZdKpA{b9DS^#pSAEPhGdzC(nv`nBsxgB*mLeon0|CwYih3x>I$e*iBaV!aIE2x;F1;UJ-&zaHM;>i4}f$^)<7W7YoC0fnt*~LoJ+Ra&K;?gsP zg>HXuY2c}WY5quxfg{WOSeT8qgt)~8^GRf#jQ;4wNY@$=b=AIC~rE`@Ew!ken?(j-!M#_(ehHSv@Y zB{9#Vov{*)bNSFqFxheKsA;2;joOBuG~>KDH|iZSsY7*2KgEW;s$~f18V852-rF$} zwEv*O7=Nm!)#o5wrnI>>_&Y>!ICAW^rE7A7decb9hk_AIml69VlEm$Jh(3xr{tA9#^s&+XhVsoc9nXwo8 zuCw(yznDgs5B>0!kZ!KT5euY}nedcyw&rQg)9RV!m=DGL@|n(=SYruzl4bZ3DLk`Y z>uS-$x}(ITl{pq-`Rz!FN1;)SWb+g(i-D2^*4iB(u>g+^k6B2c%fFFt9ZksIh~7nS zRnu5(p?H0TJJEf}<~p3&M6PAV@5sj}$N)qUT}7U;(zLevRBda1>;CPv!f0s(Df2{n zG+tgXw`0s8MXNW@AO^u8kR#m1;{*ANQPj*U_O;inDm#4WxjQ-%h<~(U)MF$f&7UJ9ZEy~r z#@LC!jz@Gu^pJT4kEY9A5fM0sz&qz$wf+4WGIz!JM`Cn=U%Uo^p+vjf5K9WUCgR0& zA7?&pn^I;N7tATmMouIBOs;qI@%Ts_B2cP_@KYJPSw)th?DI)KkTsBA7fne=agV)HR`X}`+DQuY_X%_^HEQ4)DM%Xa8wQoCbD(;{zW$B|Dh z!ikQZoNft-TMlI}_?N?hG5@T?%N{yBuWT2$pL|0;A&0niWh=|uE*z3lrAsyBWzm+5 zBN%23UzAum>PVy|>co9J&AJgVY>Ng*z(XZcmbmQJ;UE6-)%=KKBZrLP8^0@hva!`r z+jc=ffpDV+m+iyz%dW~kfa^>y9((L&>EA1FO8s#s?lK~|x~ygRlzcBa%ARfSOx>0BXk zgtTJ|o9J*9+g!Fbj;zU^G5e}?p|iG(jGjZxmmG2aA^xu|zAtmsJiEQqwa0A|YBLwj zDv_4@X4>-OaUC`0;g?+UIz*epZA-O9aVytsoKbmo_=Uc;uMjuR;&T*ZwY(SUS+TQz zkHb_@yKT|-l2?{KihFs@zZdC}+lAD2#rAf`xzqx~mFMSfJbQG)aK8V}m!;Ni(mCN~ z@$)F#E@249BAV;Jb|e=%`+aWscSffi8TnKEgWOUj3<{0YO~*KaY*nl9X@-7%iruzi z8?r5qWJ*~tx_yl=99LZpY1CL;2e#P_nmH=2&$uL=wl*ra8SbNHu7TWA)`eMJxH1&< z3P=k@*A!wegVL9Q1RmoMMLa+q@ED+ia=*O52L2ltOdb?DtE@gdF_K!}7X+2HKhj?) zJZM?LFSnQD2ui(1ukMo{R$l(cHV8SfpJUo83+Qw2>fasl_}?QT0d3txoVc31Vj#A) zpEnWbb7F52SsRf*+4&>N<`S87p&Ti_K78Jiiu9y1 zGf^czW&4uo$usWZwfdsS+NkgQtV_{Wz6>)ncyfntB=H;$(=QUua2rsld z41TfC5T%ywt0IicXh1lE(TJ@Wx$zpK@%eIxHN#0J5`|CY?s3RaI;hI_<6S%Vb1=O% ze({LOF_UTeeA4*E{A84K_wY7bh3i5__*OwRc9a>_Ry%Y@MapJ=ac?w4=Z}Zn6$3#| zbvypCAJ>MxbvV`ZhYnbXm#eXzk%ga+l#xK(!w8xQvWU_1MU(3fWC}GS(3ZekQ(~2k zTw5haJx(o&37UX+b$G=!>uT|4Me@qx>&TC9QMQl?KvB?NN2qmr+iRjl=r4=TUWFK@ zIfqkHm@WV<$2x4TRIj`)RI{mpFIgRDh5` zwDaS#O!!jfvxJ(siv!w%YvrLbBz?PNa*g#bl+^q7xhgq5395%Ayfue3VbvE+K2TAg zu(k+++$!1JWVk&}e(?J4;^n)97*plDg97cHHpm>P4P$?Be)++OHy>9Dm?8d?cVrCj@T_ zhG5I<5WF#1`G9d6yq<=6ET>5q-z8+HRGjIsA2EAyE;~X|wi`$%(ym_KknD&Lu**ygv7)` zjC{7Wx`e#z(uLDWIb)Dln+E zI_(tBfM>v=*c&S?i`UEGH^Txv9+%#gPNtkrD?g#CLZlo-8b=q*u#yT#kpWq_E%u4%7BKt{)kYR9}+gqVuT~>s{eKbt$$m(#lX1Pd(ux#gj9K$K( zGmsO9l6~Gml2mdG)o#Kd*>*=6e#K}3jd6oOG~rj+g)xS&u;h<%10RTphG^Z7i|98~ zRXbdLD=;!p3srty-5)7He!;byb*ZCmV~MZNWp3Nnalm3aJ#Fo&zx zPzO1lg|?oPiaS$~w_Hb;gMRjow$?_|&yk#oZhSh;~zdEqeEH4?>2B{%MiCL|V-R)u>{^)jKkZcce8K6N1^ZsJyo3 z2YmZDlI+|6UiR(dUc4w*QF&a(k&Kmd#5t)Xh5OJ!TC#}S%aOd7>yG0s!BlsPW1~A_ z%@ex*r^W)i$RK=}V=YYYUNPspM9x(IIDG9^LBMy4QI32(`5AX{7yWC zT;@)BjybOwMHFe{Sum|n)24lOb^)^{2tuP>ZmFjSN^)qSI_Vj^o9LMGnDW=ON`Xx1vjuZ1ny>_htMIZx@9hD3~H!rG5@d)}ox-i5aJ&gHeO zVD))M^p4-{Z6|H$Azyu??SXJh_}*B!$E)7dHhZTY1nCB@inbiETn! z8=I9j*4_hpBr74=vPigYw}+>|%Tt#a=fbi!jIsG8fi`WXW#?QT59TcUzO|XHfOKf& z#i+V8a+bs%0Q<;g%>%0^p6gS}%pmRRpBk%DU)kI4n zqFU@D=sSb)BZr>o91oU1M3BNrU%5t5NgIp@ccyIIp2hnX|?R4i5bQSlMbm&12?_>$>i}nPebA@S- zmA~Y`uR9b{xKHKn-Krx>k@Yb&x`Ms;Y&Py+~99e8~ka{&(oAX;|u zO~h?Cdi5GUXgEH&*NIQ?+Ba&jD(v?spYytgHG9?P(F z>}RRvd3>-A!6tDMvP2)bh|Hj~Q%XXFL@mHfq8q`&I6@?&kEx;;;hHE5IH?JcDx@|C z^xFVW?_T2{p9kc)qJUmd89Dvmr>Gyt36%y6F;blD_ryP(kdT#Poa+)gD-kSiA{{vT zSH8_!f~HXkHqVE)w4gL63THc}+cPk?J+>$$Zu@EFJn~F6yoW<;-NZ-#hkquzmh(?^ zg%dI=a0DK7DhNSKY>HbY_&tqI8O+e-@4$)f_Mry6YeM_N#AkZLbu~6ZIN&XJRB8R{ zKk6NJlmP#m*Ysh>;bGC6C|wY|#wzaZ+wCdkai<v-O=(k3O0u<`Fwu= zFhh=dj}|+R+tUTSX^ni*%2kg>&9Y~F|47-^xW|V%jb4AR=aM6T^is;~FUBI*zga_c=15`KwT{fB?MHqT;y*ln!MO2I$qZvjlmbYDk$&Pu% zM2wBx@f!ZoKL~stwJIuqa&^7?J6RB+22m_I1Wq(}qP2UYbw*7oj)N%KmC|iELzujd zUrg?D@?jxb%>)JQ(fUfwQ6)ZIm72;z%xmoa^QK(bR6f8ikDYv<`Ceb$U7k4#@a{zz z^vOH3DC2Oo`!YhANSHh*CG$xd$woR!7M#R(i~NUdYBt!LQ7H^ypJ3&2qO0jfH6IR; z$g82AU(4UZLK*Lh&F`D^$$C>1>ev?%!IWsg$O{Wl3Fng$T!os7naoGZy>qX)+jG`| zH;7T%lPt%jW5^JQ67Kbtai|5LPs6Xk6Pv6F`2AyeKNxq9cMq+)t;YG5o)E-SV7DjP z587+(t-Q~EiFcz)vKjiLHerHfu&M}|ArQLrB#cOCF4eo}Q_tJ&>%@F~P7AJboXB=iV2k?>O%JXJha2Cp3@0iFRO zEzVD>k*}<&)z_Jt`9?gO!MxpHjxeib1~Qe*M(iQyqnUChN6rUM0B!7IpZ2+_>5sHM zBJ^v!**V=evGcm{h_sfd*6cp}i0_dXKmR@6JFL|_{e_>W-k9EEYs(7sO-nd1-?OfH zP3Z+EZq|-BZ!RdeDg$Y*KR37QO)mX!C3=6o{42NYe#-go^xt~V_4k%%klS~^>HVeh z?^aCR&p_VSfi$d)QVv&+Qzk1{DAy=K8PHegrLdR6kTD6RBvd09Mky)TpwJ+tLiIAC zF{Z61^7|x=hKMXZFOVe)#-F9|mBMf~P2cnA8E7uwB4HR3im!5)WvzO|DtW3_y}zg2 z`|k8Vj3j?yhl9{kD10t+I0Is@0iSpY6@#T{t8thNw{w0T5jZX6MIa~C_C1Ixa!k%H zf2=0g=C5Z?FwKZt>*Vk95)Bqzi4uiU8lZPXnW-=bMmX)e&bK(r`EonJ+HF6)(~^sX zG%-*|2q%x~Bs|{OXy(!43}9EcCj`A83#eIC(7oOd8F#6?4?sG!fG46%#P|9-WEQ4| z#kxved_nrw?M;k{(RuP#L_f*yOo@IgXCt7J50jBiK8M#IlW{oYA_l(_;7+uFQJ!EC zdNB@1NJo$RSH-w%%X4!WU^vCJLR#7|ASXxA(>x1?V;%lpGdJhG82cmEqsyvBiF#)`Mm)C zTVsA4;V5nI4B(a-2AY%5A7Mu8k>k)WP=YK@yG*MwBxr$XJt)4w<>5+mA>O#iDWg!} zTqU%zeQ1rp3ZI~Le#a*N9q;YE3cut1y$=uqI5*BL_W%pBQDU=mWEi!a?H`7!6(QzM z!vO+?*i6O8SSY&+?Q0vZ)eNb4gkiuSk=~xMd*-h3GVsUd)X-~pZ*oJx+TusENfXR{1_N-S@UhUMf5`;SS18+7Pkt$ zu?_+4&E^`6F}i?Q)}f224=x5fMNw+fU`DEum9D^zF6oZO)h4z*vpe*gx#4L`DHiUr z9vyX0txjLM?dc-49^qX~cWGe(i?RLPnF8Wz11Z4k9LAX_)ObihqT!Ke%lefaa{3~OLSrRZLMvmKY^F&;5}IjJ6ie`$5Zf6S zXegqYh6=LUH^LKnV?f7)Xzk(u51>gBiv~$=>>9y(2L~)OxxhC7jl4*ePk}dsJajM7 zC|hJwAGFBAJhT)eSF~aljV%#PF-hM_6D1BP4$+_;hSnI`WMa_m>b{cvj{ziMoxhXc z7VFbaONssx{OCSlf}zdV1IOswsTOILW`<&|d>0Ex>NdY3(N>D>nq0QJ`s3XFy#6)y z_b-;km)mw$j8}_So(!z-0nZTcU7JQgA`lTCohsjmfPE#y3;*!|mKJ1y1*&B@2jJ>? zpmTsb3dN75TZg@EP4z~qkiX7Am+9U1lNoiWIGM^&iwoc}@_4^xgw~P&UXA?jYjiif zu)KKhhxy^^{Hcg_ep{)Vp6%Ej$rT@rnc*m+LLZ-eKLP!;g3PG8=;OaUQGN2SLAGo# zSVD?#6*uo`&UJzl=j!fv$40?hCD{JXdzYPpUzf|ao}3IghzC6w&E$aEgCiiq{?Q6S z(!;wNyRT3P zfj?Rf_;sl`LW=A9HwR4Wsdemi93(@k)Z<{jtVo)1?h*B) zG$ZQq=^CXOKFr3SuLtk;Rl+_G^YYw~g`l)e7s zC^1MD0V&_%j$1sn~q6^kUh?(qeN!W8a8}(T5Mz{qOquUHUpN*b#T_ zGK|%rG=^2yyhLhn{$|c;aH{ON{1skSHVE$3gUYkKiU1D^>^v}&U-?E}B}2@jhG+}6 zx`P4t>eJot5p~OM6?$z_K$oU~y+Vyed53h-ow`o|HQ`arHPnmI&w%-O<_hY?UEa() zvNuEs@r88YS7IIb6hiRpGK|b|0g2l6{g}Vz4TAq9gM1qF7GRkzYEQrBUd?8m%4&9U zB`A<^vrJ$w^88i&3j0b-RXo7)iv@iO3 zw-|DW1r>>a7UQQ|)L9V@JI>5(wlq-5cnGM&Y21zF1)%9zpIoT1&IglDK`A0?Aqfv?5=sKrv?P?c(K`{-rt2=rWTKs0-e-cjr zT|y2I+e|XVb(ZeF_db!{<(M2Va~I@y_2%~sswf7Vcg=NM;~9>3>!Wc?)^6>F$hdljA6#g7Hj?(~%D)v-Jl@L=GHbmXDDv3neszOLi?aYvgxpx0TegO0rFp{xh zV?$zK$v`BQNReOwiK51Nym$81PMi?iw!eGteeeA4WZ&I)aCFiJDx=o(M!V5&?gO}Q zIQYaCYbca}^18%(?cHOhwi#PnTdh{B)9G}(-CnOZ7z~InfI1K}06N?XF~DH&9?NO0)6WTx?fn^LMI^qy1Mrzvj#R-4}p)5AS`eU`=Y1SnJoOPyWQ>AjfQj%4GRv zdpc+AX~Vas*2K0aGsd@bW~O#I`H(Rt@^D3$X8}C^J`!u2m6!MUs}7r9^Rnsv7y`d& z17GOmBEUu%Ynzpq_qaa6q0@_FI%TVTZPRk9ztpkoFmvbP+gPl7qmRV=rPPalP~jJg4taAe(T5HGVq|N3`4pyB2w5cjHz z{TcG$rT3C}?;nPRDmgDfAfvoTu&sD7E(??+~E{DZfe{;JN8u%dk za1+C%=JOpW!~#Cl2+;`*)(iD0k+|XYt-*r95^<{%niiWbl@tkP$T(Z96Z878D)#ui zitCHS{0CR+#k@|einYGPEsvwLBCZi>e61}rR%$KOj-+CwVIsvzcrwyL4M{3T8YWVn zgs1++A}vWONE$}#M_h|Emt9M=21S};e8pRncTsT(noD@;e{9{2-T&*EHz$XG{arqI k=X{RjzHt_6n~-|iMHH`5R%j=&`LuyG?V{;qGFt&v4OfV468vWduUfr8H(ZPeY1zpkrE)X@Ac>TRQp6@797WENS^!vE?-o5)E?|A(A%lo_A zM4$e;_0`7q#`fl2BD$9I=?_R+BBw~Syu#%>+qZXMS_j>{d2?%P>+taK@#DwOpFcl2 zIT82~i9=#>LUahuh7&ruv-|Zu)Nw)h<%;q0(n#4Y#r>=0jr(`MMgP{mxqEvLeR=5Y z4GT^oEDSt%kWhx68!o*~m@fj^zcQizidYuNKU{X*Fja#cIYP8DaJ@l78Mn^8hY!`C2 zCdFi(^+|cM^jUlqyK+JV)DcGqiaOmRztauyEVI>U^ZHdLtcu=duz9o@yzW640tx zpUNO-4~$w!ELtr^+Nygozh7q(!l!+)v%W94!OVkYfz@hxW!OkqewRYZTJrB?NJS_nVlNWlWgpFVRZSZDtZV|R(?0WbMXLN-ww#v~z zkvoX*KmqQKy(48U>o{9dY`-}Z6?!RlTZ$@lcF|5y4{D&OWux(~H;YeYKubracD<26yW8n3l zA17592dI!08K`(+N!3ad*JUfkycQFhQDHY&loaD$l{o(hN5oZ~RCaD`*Dr=7!>&qh zj~fQAn-nTCSs}wj%~a`zD=PA@fETw-A7`5n)GwAK6-CLlX`Z<%@ig!qz#WM*cHEF& z9Wr{8M5y#R=bH$@1y%>}L*to+Dl7pFv!aPj3fS~{0r$;J7( zikQb{w}qWN=nFT%eA`;c)_xe-vzM$~c&7$TDs!xad_sgF`+QvyLzv1sI&qGB^D@y(CTV>B)(zz&y1Q`0XG8g7ZfLNmPXlcOS zAviqXGGZQ^)mE)m7dUX#iDFvEvS!hB4#NIJ_(MvgbpqCd$ez8VGoY$mvq)=eAzQ;x z@Yyb)>?NJ6iey#P)w0Z5SeCXddQ^{3Vzrt8F*wU%kuQ5{Igk98_sw7B(~x^ zKPVK7zi0Rp#c<$aK)Ea+%yuf>ghW`_r6C%a;g=?VCK=8ESws;a#@|Z(k!3g_G5}&0 zCT2U89t&YOjJp%(gS8Lsg=|e zo|cZH&2Ke0-Kd6fj78kikhZKgjn>7aoL@%Ynm9H2-KJ2wn#;x6Ij_!{uFLz3TfKl^ zRpl50^JUGE_zTf+Z@A|?Q$E>RgBqd@>`^qaj}V1NQ6H{|cO2F1v-Lgvz92q8QTwQ| z&$6+v+HK?4Xb>IY+DFfCwQseLQEqqIorX_z+)#0TTfj>6OyJ*8@8cKE-#=86^H+-I z@0gD1mb64G4TnJy5=ne%c0^irytLyDS!i`6V>j1048pE=)u57G*cc9k;`0PadhQk4N(u=`)C4 z;WuX^FArN+GH@?LjLMTeat%2@7(>~!{J)X4!gcGqY((+M>3ThGmM(Aa^4YyCr&GxC zOymamjCv9gHl9W4Pktg|Vnl0E`q>*INoSGd@|-$7B6->k&@k*b{xlOfm%y|bh7_|0#X#CwSl@ZjG{m%d+F+_vqf*2J$9+b z{slGAMI1U5MS&DuHCSWQ!4TjAPGgDJ@7?jlBSk9IkEs^ld*6F^_wJ5A?(XwvFOLq0 zK6sFI~g{3mt4pFtn{)>a>hY0OJo<4oLzrTNadU|njadmao?REwJ zh{P$e=@OknbD&Gz7e`-yjy5g?f0mQ<%PHSoN|rCLv|jFhL-gTaU++Huipbfpejirs zN>~|q?qCcIJvV&tZdFuxP*KaaqSk9gnM|ffv?>$Y56nt~VG1 zLpLfH)zEdTTr-V0E|5d4hVE+8AiyOP=T-|{p25I%-C-uuGkE_j(Olh#41n9Pm}%O4 z13cV`G(b>Tcw2nx1eZ-E9dUWmK}1DkG;g`eM0C^J^Y9>6~hqj2(yyZF*?ta~```i9Af19@H8KkabCZ4xE%B7w~f726vAvQNh??Kv!ng?A{gaK@t0#nzC%gmogtIO|eMar=j?gj3Q6 zd622Z`7*7n{gAcFmeDacl!Y6Pc!VoG2S7h%fNdb2~vO!7tc~;fOevG%@<@2VAN*ukvkK)C>DA!vYU|C4&SrNWU ze41FqSoj-Fcws30P?obsjd@~bcF)@q9&PoA66jh+gD76y)48y=AY-Jj1LfseE|vR1 za(6I2-V>Vb@ttAT7-utgj};<<_%ObK$&sF;%ck{pE)Tma1mA;+?)n_PyHoMvp3X)1 z9zDyWK1Mx`6F)qY4S45XNy=f z_l#u3H5Jh`HQ1-TA|A$P5I)qz8Uz${(_oy6ZJL_7rWVCHnQ&?W-Bgz*o#rGJj;A`} zojj94#5@(2$00ry8T{IuufoY$E6OPeXsnF;qR6K?U4>_uG!sunKTQq#sV-s3lTr=` z&1Rm{L_7K{7NpT+K5FvNJghlu!eY@%s`I^g`R`r?3 zQL~xrG|`xwW}$4pI?hsyL}HekMwsImZ#DU99@gA8VdXQzP8TRia@YBz%;fm_n><*@ z5YOeYS=_Z~%;dlsSdK?z@Y!*OTO^|2Zf3{P+ZQ8Irn2>qwGJtx-)X(LO%kbotkANp zP=qDyl`M;k#<|9kT=mrd+Zy;UM8n6tm^n)JIdvp%pGKHXAM4W}Cx=RaXYzGB)0ThM z`*ry@>-!QmNW1c&fUZ{_8^2Ao_#j6nm3akvQlsIT`8}9psTa;UX=Ibil5=0w9P;O9 zVKdso>LKNa#bF-|E>8$$x3}ncO3UZxS>)^t4I^0;UU?0o5CDk{?GpY1F2ie)Bpeg literal 0 HcmV?d00001 diff --git a/pic-samples/iff/T_4X4_1.IFF b/pic-samples/iff/T_4X4_1.IFF new file mode 100644 index 0000000000000000000000000000000000000000..878b76cdecec0c6e0077d8b60aa25f7cd35c5f0a GIT binary patch literal 3664 zcmcIn&u<$=6#mvW-fanuL6PcEz^h7;Kp^1*>Vb>hGy+E=q^b}S7kWb6{3pQXQ1!wo zchnyF4y9~)^Fte;MHvZ%IfCs)>pu5KYh7%{R^P}8{&DhX0BN{ zD_HY4o?jJrwPjtJ^YtKJqO-@`ELWvHZ^pJ_(4G~|Is0Wj4%U}Q#}s36I1gjbtj`l& zS3obvHYX0+^PnAjoRvRGStP<}e7~PX#OJPY$LHw>o*WIL!Tmw>MEINYq$QZO13YT)k56%k90Ja$EX){RPnH%Ge`)XT3yD z^5nYR;@zGSdyWh8xci`_M{$IRce}8v=YEQo{7R%;dmTu2_t#!f^Tl5E)DZ4D zy`)}Ztug9}e?@;yarmez;>#8D^Ej0$pmU~1b(y#9z~vIf$YObJ?JUDJ`Hnb*PFN4M zytx`ld6VJuPMA;PQQ7Z}GboL8#+p@VnOlh2$O%2V|GD>n2Yk`<+O_qm^|CAyFvqpi zsr9nV&y_b)(f+~Ft*8}s_}RdrDi(J%FE*KrRDt3X>*W~2Q;=tyX%EL` zjHnlJw-sB!#I?`D`vzDQ|Cke!+5X6t%kgoGK2K5Ob35=^nf4A1{Q^ADio;nCy%;kF zGHr-Z;~F*i0SLpL*|J86Q6yt!8Q0!-yR7l1cgbn!G*Qqz&%(GwNmWf9f;f>< z7qC)W5iAkYDZhUe@;uL|dqzD~K^;^C%Y*;7rdDa`i^e0q>GNvrvbI*)s>AvIQE#hN_B=g_dM7Jd*4ne!$?6Lloa%8-hg1D^nr!MO`iq43 zGS9?#PJbOcZOuJLlk4=?vCD;L=S|pFS*Y*AvOW2Cq|sD=ogOcAxb`uAt|uqME2ps6 zd^@?Wl~~>>quuQ9l#IQW8>^KTu>S+N@oAiAVJG@e!Q-|5tcYifao7veNubtR!+6!^Nc|T{~y!|oz z^`jd%mx-p|U;1Qzd473ufrw_DfPRCdJmrc+W8-39U%s{iR~49@on2a5T3cJ&+}zyR z*=aVLj6Wh?BN0uaHH_kDQuF%FPd~;S7r>uW?6&h6+nwl+mnP?LEPPIM?&r@IuHC|p zeswK98{~ z8IJi;AJyjzTnI0?ktKYdVk{L-xo(uzR4j*>Cm~z$RliQ;yP@w!PULx^=RsoE0*2;? zt{*upI}s^Wk;$qKYC*%Qn8RGhJ+iSK+--epr2*ACk+*Kq3>Ls#mM)ZezLL)w{AP^d47`Yb5EMfL3V* zkSm~8DzjHDj6=X=Wu%1BTh0rc{N;h z19-kC+Te}$ZC8(VY<7diy6r;$7Uv4L+pfz8?Uv9gX3?SjNc0c=)o~)naYBdfQ6dhh zi1-!g2cnKT-Rx0LyBK$%mSukc)~2AmH^)J+x2LWX-i#oCh6sEOZs<`g(YcYEHfP=F zRp*O@vt1TurCHmv6C~JNlu$QG65f`TpmdTX{H=FXyeMIC&(s34ge;UwFuTa2afZ%i zr6eg5Cw$HTJ2YfYPOLDdb6N-GO6Z*Ca`uRQze+}jw+hdoZpbpP!WN4XX#{dFsaud%5B;9+{~A}*E4u`$hmK+yw^?`uNE%FKUuF|jjS)*o7j?L zOF6a8-gUmN@1T~Qr{)p;fe+VK3Sj|fwZAze64deT3C?OCVy#2`pJb3c_!`A5oYl6L zvX>o7r%CK3gUMZ@U0{&hZ6I$j{>E1e-zWq5t{7b;?C*$*`(5~nXdj;aRwChPb&zc# dV{dc??Zhq2D=T0Xd1|(RSi-Yaw~?D6`VUpgE$09L literal 0 HcmV?d00001 diff --git a/pic-samples/iff/icons.iff b/pic-samples/iff/icons.iff new file mode 100644 index 0000000000000000000000000000000000000000..29886bd97b066331a9ae2e376ac1b8df8e06593f GIT binary patch literal 240 zcmZ?s5AtPTV0hu_)`@qi!c~4C;({&Mi2o4K)#c|OC*qW04&zP#QgmE0S6Y4 zoB|6&i~0dYAgSP>%)*d-{D2x*T!*Rt|Nnn(jDHvy?3)>WFfhnB)}NODedE7<$G`d; z^$gtdKO`6!IDXkjF#PA1+9C1(KgW;#5&t3Le>i^FN8kU$ExkkfJ_C>)!EgYi-u3{; z@Bb0D3>*>`5)6MpZ1z7a^M6>dGq5-S9r^!}@`VEP{}1OFJ}_qhxdiAu8GDc;nSrhV J`sV=y0|03HNkjku literal 0 HcmV?d00001 From cb147ca75971d915513acd7d81c7c8ff22b8a49a Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 29 Jul 2009 21:44:54 +0000 Subject: [PATCH 57/95] Added Hatch to the bugfinders list. Thanks for your testing! git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@967 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- helpfile.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/helpfile.h b/helpfile.h index 81a26cb2..89fddbf7 100644 --- a/helpfile.h +++ b/helpfile.h @@ -342,15 +342,15 @@ static const T_Help_table helptable_credits[] = HELP_TITLE(" BUGFINDERS") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT (" blumunkee BDCIron Ced ") - HELP_TEXT (" El Topo fallenblood Frost ") - HELP_TEXT (" Grimmy Gürkan Sengün HoraK-FDF ") - HELP_TEXT (" iLKke Jamon keito ") - HELP_TEXT (" kusma Lord Graga MagerValp ") - HELP_TEXT (" mind MooZ the Peach ") - HELP_TEXT (" richienyhus tape.wyrm TeeEmCee ") - HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") - HELP_TEXT (" Tobé 00ai99 ") + HELP_TEXT (" blumunkee BDCIron Ced ") + HELP_TEXT (" El Topo fallenblood Frost ") + HELP_TEXT (" Grimmy Gürkan Sengün Hatch ") + HELP_TEXT (" HoraK-FDF iLKke Jamon ") + HELP_TEXT (" keito kusma Lord Graga ") + HELP_TEXT (" MagerValp mind MooZ ") + HELP_TEXT (" the Peach richienyhus tape.wyrm ") + HELP_TEXT (" TeeEmCee tempest Timo Kurrpa ") + HELP_TEXT (" titus^Rab Tobé 00ai99 ") HELP_TEXT ("") HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") From 7f072fd89c217a429303ccefef6e95eb23039204 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 29 Jul 2009 22:03:37 +0000 Subject: [PATCH 58/95] Merged in trunk the fix for issue 198 git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@968 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- filesel.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/filesel.c b/filesel.c index 4a449f2f..b7b3cc2e 100644 --- a/filesel.c +++ b/filesel.c @@ -541,7 +541,11 @@ void Sort_list_of_files(T_Fileselector *list) } T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index) -{ +{ + // Safety + if (index >= list->Nb_elements) + index=list->Nb_elements-1; + if (list->Index) { return list->Index[index]; @@ -878,11 +882,37 @@ void Prepare_and_display_filelist(short Position, short offset, T_Scroller_butto } -void Reload_list_of_files(byte filter, short Position, short offset, T_Scroller_button * button) +void Reload_list_of_files(byte filter, T_Scroller_button * button) { Read_list_of_files(&Filelist, filter); Sort_list_of_files(&Filelist); - Prepare_and_display_filelist(Position,offset,button); + // + // Check and fix the fileselector positions, because + // the directory content may have changed. + // + // Make the offset absolute + Main_fileselector_offset += Main_fileselector_position; + // Ensure it's within limits + if (Main_fileselector_offset >= Filelist.Nb_elements) + { + Main_fileselector_offset = Filelist.Nb_elements-1; + } + // Ensure the position doesn't show "too many files" + if (Main_fileselector_position!=0 && Main_fileselector_position>(Filelist.Nb_elements-10)) + { + if (Filelist.Nb_elements<10) + { + Main_fileselector_position=0; + } + else + { + Main_fileselector_position=Filelist.Nb_elements-10; + } + } + // Restore the offset as relative to the position. + Main_fileselector_offset -= Main_fileselector_position; + + Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,button); } void Scroll_fileselector(T_Scroller_button * file_scroller) @@ -1113,7 +1143,7 @@ byte Button_Load_or_Save(byte load, byte image) } // Affichage des premiers fichiers visibles: - Reload_list_of_files(Main_format,Main_fileselector_position,Main_fileselector_offset,file_scroller); + Reload_list_of_files(Main_format,file_scroller); if (!load) { @@ -1210,7 +1240,7 @@ byte Button_Load_or_Save(byte load, byte image) } } // On relit les informations - Reload_list_of_files(Main_format,Main_fileselector_position,Main_fileselector_offset,file_scroller); + Reload_list_of_files(Main_format,file_scroller); // On demande la preview du nouveau fichier sur lequel on se trouve New_preview_is_needed=1; } @@ -1291,7 +1321,7 @@ byte Button_Load_or_Save(byte load, byte image) Main_fileselector_position=0; Main_fileselector_offset=0; // Affichage des premiers fichiers visibles: - Reload_list_of_files(Main_format,Main_fileselector_position,Main_fileselector_offset,file_scroller); + Reload_list_of_files(Main_format,file_scroller); Display_cursor(); New_preview_is_needed=1; *quicksearch_filename=0; From 48d04c2568c5c24f13252b800250532bfdf4dbfb Mon Sep 17 00:00:00 2001 From: Franck Charlet Date: Fri, 31 Jul 2009 10:20:35 +0000 Subject: [PATCH 59/95] Updated XCode Project git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@969 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- .DS_Store | Bin 15364 -> 15364 bytes Grafx2.xcodeproj/project.pbxproj | 54 ++++++++++------ Grafx2.xcodeproj/xx.pbxuser | 40 +++++++----- Grafx2.xcodeproj/xx.perspective | 108 +++++++++++++++++-------------- main.c | 28 ++++---- sdlscreen.c | 3 +- 6 files changed, 135 insertions(+), 98 deletions(-) diff --git a/.DS_Store b/.DS_Store index fe73a055d20bdf2899e3ab74598cef0ae3857fc7..fdc8668961d00f89117ef9ffe07afe2f46cd36af 100644 GIT binary patch delta 128 zcmZpvXsMXs&uF_bU^hRb?PMMS3(l0{_ KjnBdp8+ZYXY$A~W delta 58 zcmV-A0LA}=c!YS6PXRiyP`eKSI+F|#II~+20|B#;5uON>f*KODVj86dk$`Kn2O#?d Qvr82N1G5q+@)MDO4NTM%v;Y7A diff --git a/Grafx2.xcodeproj/project.pbxproj b/Grafx2.xcodeproj/project.pbxproj index 44ef9528..fa145b90 100644 --- a/Grafx2.xcodeproj/project.pbxproj +++ b/Grafx2.xcodeproj/project.pbxproj @@ -12,6 +12,12 @@ 002F3A2E09D0888800EBEB88 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 002F3A2C09D0888800EBEB88 /* SDLMain.m */; }; 002F3A3F09D088BA00EBEB88 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 002F3A3E09D088BA00EBEB88 /* main.c */; }; 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + F5142653101F6CC5006CF3C4 /* font_Classic.png in Copy skins */ = {isa = PBXBuildFile; fileRef = F514264D101F6CB8006CF3C4 /* font_Classic.png */; }; + F5142654101F6CC5006CF3C4 /* font_Fairlight.png in Copy skins */ = {isa = PBXBuildFile; fileRef = F514264E101F6CB8006CF3C4 /* font_Fairlight.png */; }; + F5142655101F6CC5006CF3C4 /* font_Fun.png in Copy skins */ = {isa = PBXBuildFile; fileRef = F514264F101F6CB9006CF3C4 /* font_Fun.png */; }; + F5142656101F6CC5006CF3C4 /* font_Melon.png in Copy skins */ = {isa = PBXBuildFile; fileRef = F5142650101F6CB9006CF3C4 /* font_Melon.png */; }; + F5142657101F6CC5006CF3C4 /* skin_classic.png in Copy skins */ = {isa = PBXBuildFile; fileRef = F5142651101F6CB9006CF3C4 /* skin_classic.png */; }; + F5142658101F6CC5006CF3C4 /* skin_modern.png in Copy skins */ = {isa = PBXBuildFile; fileRef = F5142652101F6CB9006CF3C4 /* skin_modern.png */; }; F51CBD2E0EC8A3E1005C06AC /* 5pxtinyfont.png in Copy fonts */ = {isa = PBXBuildFile; fileRef = F51CBD2B0EC8A3E1005C06AC /* 5pxtinyfont.png */; }; F51CBD2F0EC8A3E1005C06AC /* colorfont.pcx in Copy fonts */ = {isa = PBXBuildFile; fileRef = F51CBD2C0EC8A3E1005C06AC /* colorfont.pcx */; }; F51CBD300EC8A3E1005C06AC /* Tuffy.ttf in Copy fonts */ = {isa = PBXBuildFile; fileRef = F51CBD2D0EC8A3E1005C06AC /* Tuffy.ttf */; }; @@ -52,8 +58,6 @@ F5B19BA30EA4BE3E003F4BA4 /* shade.c in Sources */ = {isa = PBXBuildFile; fileRef = F5B19B8B0EA4BE3E003F4BA4 /* shade.c */; }; F5B19BA40EA4BE3E003F4BA4 /* special.c in Sources */ = {isa = PBXBuildFile; fileRef = F5B19B8C0EA4BE3E003F4BA4 /* special.c */; }; F5B19BE10EA4C65A003F4BA4 /* gfx2.cfg in Resources */ = {isa = PBXBuildFile; fileRef = F5B19BDF0EA4C65A003F4BA4 /* gfx2.cfg */; }; - F5B19BE10EA4C65A003F4BA5 /* base.gif in Copy skins */ = {isa = PBXBuildFile; fileRef = F5B19BDF0EA4C65A003F4BA5 /* base.gif */; }; - F5B19BE10EA4C65A003F4BA6 /* ilkke.png in Copy skins */ = {isa = PBXBuildFile; fileRef = F5B19BDF0EA4C65A003F4BA6 /* ilkke.png */; }; F5B19C1D0EA4D71C003F4BA4 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5B19C1C0EA4D71C003F4BA4 /* CoreFoundation.framework */; }; F5B19C3D0EA4DC91003F4BA4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F5B19C3B0EA4DC91003F4BA4 /* InfoPlist.strings */; }; F5B1EE850EAD0F4E00B087B5 /* gfx2def.ini in Resources */ = {isa = PBXBuildFile; fileRef = F5B1EE840EAD0F4E00B087B5 /* gfx2def.ini */; }; @@ -104,6 +108,22 @@ name = "Copy Frameworks into .app bundle"; runOnlyForDeploymentPostprocessing = 0; }; + F514264B101F6C5B006CF3C4 /* Copy skins */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = skins; + dstSubfolderSpec = 7; + files = ( + F5142653101F6CC5006CF3C4 /* font_Classic.png in Copy skins */, + F5142654101F6CC5006CF3C4 /* font_Fairlight.png in Copy skins */, + F5142655101F6CC5006CF3C4 /* font_Fun.png in Copy skins */, + F5142656101F6CC5006CF3C4 /* font_Melon.png in Copy skins */, + F5142657101F6CC5006CF3C4 /* skin_classic.png in Copy skins */, + F5142658101F6CC5006CF3C4 /* skin_modern.png in Copy skins */, + ); + name = "Copy skins"; + runOnlyForDeploymentPostprocessing = 0; + }; F5A33F1D0EC8A26C00F8052D /* Copy fonts */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -119,18 +139,6 @@ name = "Copy fonts"; runOnlyForDeploymentPostprocessing = 0; }; - F5A33F1D0EC8A26C00F8052E /* Copy skins */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = skins; - dstSubfolderSpec = 7; - files = ( - F5B19BE10EA4C65A003F4BA5 /* base.gif in Copy skins */, - F5B19BE10EA4C65A003F4BA6 /* ilkke.png in Copy skins */, - ); - name = "Copy skins"; - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -145,6 +153,12 @@ 32CA4F630368D1EE00C91783 /* Grafx2_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Grafx2_Prefix.pch; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Grafx2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Grafx2.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F514264D101F6CB8006CF3C4 /* font_Classic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = font_Classic.png; path = skins/font_Classic.png; sourceTree = ""; }; + F514264E101F6CB8006CF3C4 /* font_Fairlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = font_Fairlight.png; path = skins/font_Fairlight.png; sourceTree = ""; }; + F514264F101F6CB9006CF3C4 /* font_Fun.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = font_Fun.png; path = skins/font_Fun.png; sourceTree = ""; }; + F5142650101F6CB9006CF3C4 /* font_Melon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = font_Melon.png; path = skins/font_Melon.png; sourceTree = ""; }; + F5142651101F6CB9006CF3C4 /* skin_classic.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = skin_classic.png; path = skins/skin_classic.png; sourceTree = ""; }; + F5142652101F6CB9006CF3C4 /* skin_modern.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = skin_modern.png; path = skins/skin_modern.png; sourceTree = ""; }; F51CBD2B0EC8A3E1005C06AC /* 5pxtinyfont.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = 5pxtinyfont.png; path = fonts/5pxtinyfont.png; sourceTree = ""; }; F51CBD2C0EC8A3E1005C06AC /* colorfont.pcx */ = {isa = PBXFileReference; lastKnownFileType = file; name = colorfont.pcx; path = fonts/colorfont.pcx; sourceTree = ""; }; F51CBD2D0EC8A3E1005C06AC /* Tuffy.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = Tuffy.ttf; path = fonts/Tuffy.ttf; sourceTree = ""; }; @@ -186,8 +200,6 @@ F5B19B8B0EA4BE3E003F4BA4 /* shade.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = shade.c; sourceTree = ""; }; F5B19B8C0EA4BE3E003F4BA4 /* special.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = special.c; sourceTree = ""; }; F5B19BDF0EA4C65A003F4BA4 /* gfx2.cfg */ = {isa = PBXFileReference; lastKnownFileType = file; path = gfx2.cfg; sourceTree = ""; }; - F5B19BDF0EA4C65A003F4BA5 /* base.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = base.gif; path = skins/base.gif; sourceTree = ""; }; - F5B19BDF0EA4C65A003F4BA6 /* ilkke.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ilkke.png; path = skins/ilkke.png; sourceTree = ""; }; F5B19C1C0EA4D71C003F4BA4 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = SYSTEM_DEVELOPER_DIR; }; F5B19C3C0EA4DC91003F4BA4 /* English */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; F5B1EE840EAD0F4E00B087B5 /* gfx2def.ini */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = gfx2def.ini; sourceTree = ""; }; @@ -260,6 +272,12 @@ 29B97314FDCFA39411CA2CEA /* Grafx2 */ = { isa = PBXGroup; children = ( + F514264D101F6CB8006CF3C4 /* font_Classic.png */, + F514264E101F6CB8006CF3C4 /* font_Fairlight.png */, + F514264F101F6CB9006CF3C4 /* font_Fun.png */, + F5142650101F6CB9006CF3C4 /* font_Melon.png */, + F5142651101F6CB9006CF3C4 /* skin_classic.png */, + F5142652101F6CB9006CF3C4 /* skin_modern.png */, F539315D0FE171C3003CB103 /* pversion.c */, F5CDCE310F6EA6D600B31F63 /* pxdouble.c */, F5AC28B90F4873C700455509 /* hotkeys.c */, @@ -294,8 +312,6 @@ F5B19C3B0EA4DC91003F4BA4 /* InfoPlist.strings */, F5B19C1C0EA4D71C003F4BA4 /* CoreFoundation.framework */, F5B19BDF0EA4C65A003F4BA4 /* gfx2.cfg */, - F5B19BDF0EA4C65A003F4BA5 /* base.gif */, - F5B19BDF0EA4C65A003F4BA6 /* ilkke.png */, F5B19B7B0EA4BE3E003F4BA4 /* graph.c */, F5B19B7C0EA4BE3E003F4BA4 /* init.c */, F5B19B7D0EA4BE3E003F4BA4 /* io.c */, @@ -366,7 +382,7 @@ 002F39FD09D0883400EBEB89 /* Copy Frameworks into .app bundle */, 002F39FD09D0883400EBEB8A /* Copy Frameworks into .app bundle */, F5A33F1D0EC8A26C00F8052D /* Copy fonts */, - F5A33F1D0EC8A26C00F8052E /* Copy skins */, + F514264B101F6C5B006CF3C4 /* Copy skins */, ); buildRules = ( ); diff --git a/Grafx2.xcodeproj/xx.pbxuser b/Grafx2.xcodeproj/xx.pbxuser index 28c221dc..a3b5507f 100644 --- a/Grafx2.xcodeproj/xx.pbxuser +++ b/Grafx2.xcodeproj/xx.pbxuser @@ -18,9 +18,9 @@ }; 002F3A3E09D088BA00EBEB88 /* main.c */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1060, 11476}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRect = "{{0, 0}, {867, 536}}"; + sepNavIntBoundsRect = "{{0, 0}, {1044, 15086}}"; + sepNavSelRange = "{19535, 0}"; + sepNavVisRect = "{{0, 10961}, {867, 536}}"; sepNavWindowFrame = "{{14, 76}, {906, 665}}"; }; }; @@ -29,7 +29,6 @@ activeExecutable = F5B19B5D0EA4BD57003F4BA4 /* Grafx2 */; activeTarget = 8D1107260486CEB800E47090 /* Grafx2 */; addToTargets = ( - 8D1107260486CEB800E47090 /* Grafx2 */, ); breakpointsGroup = F5B19B700EA4BDA9003F4BA4 /* XCBreakpointsBucket */; codeSenseManager = F5B19B6A0EA4BD79003F4BA4 /* Code sense */; @@ -70,14 +69,15 @@ PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Built_ColumnID; PBXFileTableDataSourceColumnWidthsKey = ( 20, - 229, + 99, 20, 48, 43, 43, 20, - 79, - 88, + 264, + 10, + 20, ); PBXFileTableDataSourceColumnsKey = ( PBXFileDataSource_FiletypeID, @@ -89,6 +89,7 @@ PBXFileDataSource_Target_ColumnID, PBXFileDataSource_Path_ColumnID, PBXFileDataSource_Comments_ColumnID, + PBXFileDataSource_SCM_ColumnID, ); }; PBXConfiguration.PBXFileTableDataSource3.PBXFindDataSource = { @@ -165,8 +166,8 @@ PBXFileDataSource_Warnings_ColumnID, ); }; - PBXPerProjectTemplateStateSaveDate = 266433807; - PBXWorkspaceStateSaveDate = 266433807; + PBXPerProjectTemplateStateSaveDate = 270495112; + PBXWorkspaceStateSaveDate = 270495112; }; sourceControlManager = F5B19B690EA4BD79003F4BA4 /* Source Control */; userBuildSettings = { @@ -187,6 +188,11 @@ F5B19B5D0EA4BD57003F4BA4 /* Grafx2 */, ); }; + F51CBD2B0EC8A3E1005C06AC /* 5pxtinyfont.png */ = { + uiCtxt = { + sepNavWindowFrame = "{{15, 25}, {971, 716}}"; + }; + }; F5A33E690EC893F800F8052D /* 8pxfont.png */ = { uiCtxt = { sepNavWindowFrame = "{{15, 76}, {906, 665}}"; @@ -256,10 +262,10 @@ }; F5B19B7B0EA4BE3E003F4BA4 /* graph.c */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1620, 118579}}"; - sepNavSelRange = "{16112, 36}"; - sepNavVisRect = "{{0, 9964}, {867, 536}}"; - sepNavWindowFrame = "{{15, 76}, {906, 665}}"; + sepNavIntBoundsRect = "{{0, 0}, {1140, 52782}}"; + sepNavSelRange = "{6769, 0}"; + sepNavVisRect = "{{0, 0}, {867, 536}}"; + sepNavWindowFrame = "{{14, 76}, {906, 665}}"; }; }; F5B19B7C0EA4BE3E003F4BA4 /* init.c */ = { @@ -296,10 +302,10 @@ }; F5B19B890EA4BE3E003F4BA4 /* sdlscreen.c */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {1580, 11571}}"; - sepNavSelRange = "{0, 0}"; - sepNavVisRect = "{{0, 0}, {867, 536}}"; - sepNavWindowFrame = "{{61, 34}, {906, 665}}"; + sepNavIntBoundsRect = "{{0, 0}, {1396, 4351}}"; + sepNavSelRange = "{2375, 0}"; + sepNavVisRect = "{{0, 1072}, {867, 536}}"; + sepNavWindowFrame = "{{35, 15}, {906, 665}}"; }; }; F5B19C3C0EA4DC91003F4BA4 /* English */ = { diff --git a/Grafx2.xcodeproj/xx.perspective b/Grafx2.xcodeproj/xx.perspective index 30368fc1..f9c5d992 100644 --- a/Grafx2.xcodeproj/xx.perspective +++ b/Grafx2.xcodeproj/xx.perspective @@ -188,9 +188,9 @@ PerspectiveWidths - 970 - 970 - 970 + 971 + 971 + 971 Perspectives @@ -247,7 +247,7 @@ PBXSmartGroupTreeModuleColumnWidthsKey - 305 + 345 PBXSmartGroupTreeModuleColumnsKey_v4 @@ -259,7 +259,10 @@ PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA + 29B97317FDCFA39411CA2CEA 1C37FBAC04509CD000000102 + F56B73F7101F6D9500B6D9A4 + F56B7443101FA1C600B6D9A4 PBXSmartGroupTreeModuleOutlineStateSelectionKey @@ -268,7 +271,7 @@ PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 124}, {305, 575}} + {{0, 0}, {345, 600}} PBXTopSmartGroupGIDs @@ -278,17 +281,17 @@ GeometryConfiguration Frame - {{0, 0}, {322, 593}} + {{0, 0}, {362, 618}} GroupTreeTableConfiguration MainColumn - 305 + 345 Module PBXSmartGroupTreeModule Proportion - 322pt + 362pt Dock @@ -299,7 +302,7 @@ PBXProjectModuleGUID F5A33EBD0EC89C3000F8052D PBXProjectModuleLabel - asm pthread_mutex_lock 0x90001a38 + PBXSplitModuleInNavigatorKey Split0 @@ -307,7 +310,7 @@ PBXProjectModuleGUID F5A33EBE0EC89C3000F8052D PBXProjectModuleLabel - asm pthread_mutex_lock 0x90001a38 + SplitCount 1 @@ -320,7 +323,7 @@ GeometryConfiguration Frame - {{0, 0}, {643, 0}} + {{0, 0}, {604, 0}} Module PBXNavigatorGroup @@ -329,7 +332,7 @@ Proportion - 588pt + 613pt Tabs @@ -343,7 +346,7 @@ GeometryConfiguration Frame - {{10, 27}, {643, 561}} + {{10, 27}, {604, 586}} Module XCDetailModule @@ -359,7 +362,7 @@ GeometryConfiguration Frame - {{10, 27}, {650, 590}} + {{10, 27}, {644, 586}} Module PBXProjectFindModule @@ -375,7 +378,7 @@ GeometryConfiguration Frame - {{10, 31}, {603, 297}} + {{10, 27}, {644, 586}} Module PBXCVSModule @@ -384,7 +387,7 @@ Proportion - 643pt + 604pt Name @@ -402,11 +405,11 @@ TableOfContents - F5D646000F487ECB007E515F + F56B7444101FA1C600B6D9A4 1CA23ED40692098700951B8B - F5D646010F487ECB007E515F + F56B7445101FA1C600B6D9A4 F5A33EBD0EC89C3000F8052D - F5D646020F487ECB007E515F + F56B7446101FA1C600B6D9A4 1CA23EDF0692099D00951B8B 1CA23EE00692099D00951B8B 1CA23EE10692099D00951B8B @@ -468,18 +471,24 @@ PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA + F5B19C3B0EA4DC91003F4BA4 080E96DDFE201D6D7F000001 29B97315FDCFA39411CA2CEA 29B97317FDCFA39411CA2CEA + 29B97323FDCFA39411CA2CEA + 1058C7A0FEA54F0111CA2CBB + 1058C7A2FEA54F0111CA2CBB + 19C28FACFE9D520D11CA2CBB PBXSmartGroupTreeModuleOutlineStateSelectionKey + 42 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey - {{0, 0}, {275, 583}} + {{0, 475}, {275, 600}} PBXTopSmartGroupGIDs @@ -489,14 +498,14 @@ GeometryConfiguration Frame - {{0, 0}, {292, 601}} + {{0, 0}, {292, 618}} GroupTreeTableConfiguration MainColumn 275 RubberWindowFrame - 65 75 944 642 0 0 1024 746 + 151 75 971 659 0 0 1024 746 Module PBXSmartGroupTreeModule @@ -533,9 +542,9 @@ GeometryConfiguration Frame - {{0, 0}, {647, 0}} + {{0, 0}, {674, 0}} RubberWindowFrame - 65 75 944 642 0 0 1024 746 + 151 75 971 659 0 0 1024 746 Module PBXNavigatorGroup @@ -544,14 +553,14 @@ Proportion - 596pt + 613pt Tabs ContentConfiguration PBXBuildLogShowsTranscriptDefaultKey - {{0, 5}, {647, 564}} + {{0, 5}, {674, 581}} PBXProjectModuleGUID XCMainBuildResultsModuleGUID PBXProjectModuleLabel @@ -564,9 +573,9 @@ GeometryConfiguration Frame - {{10, 27}, {647, 569}} + {{10, 27}, {674, 586}} RubberWindowFrame - 65 75 944 642 0 0 1024 746 + 151 75 971 659 0 0 1024 746 Module PBXBuildResultsModule @@ -628,7 +637,7 @@ Proportion - 647pt + 674pt Name @@ -646,14 +655,14 @@ TableOfContents - F53931560FE170BC003CB103 + F56B7447101FA1C600B6D9A4 1CA23EE50692099D00951B8B - F53931570FE170BC003CB103 + F56B7448101FA1C600B6D9A4 F5A33EC20EC89C3000F8052D - F53931580FE170BC003CB103 + F56B7449101FA1C600B6D9A4 XCMainBuildResultsModuleGUID 1CA23EE80692099D00951B8B - F53931590FE170BC003CB103 + F56B744A101FA1C600B6D9A4 ToolbarConfiguration xcode.toolbar.config.buildAndRun @@ -697,7 +706,7 @@ GeometryConfiguration Frame - {{0, 0}, {1323, 0}} + {{0, 0}, {971, 0}} Module PBXDebugCLIModule @@ -721,8 +730,8 @@ yes sizes - {{0, 0}, {641, 197}} - {{641, 0}, {682, 197}} + {{0, 0}, {470, 295}} + {{470, 0}, {501, 295}} VerticalSplitView @@ -737,8 +746,8 @@ yes sizes - {{0, 0}, {1323, 197}} - {{0, 197}, {1323, 211}} + {{0, 0}, {971, 295}} + {{0, 295}, {971, 318}} @@ -760,12 +769,12 @@ DebugSTDIOWindowFrame {{200, 200}, {500, 300}} Frame - {{0, 5}, {1323, 408}} + {{0, 5}, {971, 613}} Module PBXDebugSessionModule Proportion - 408pt + 613pt Name @@ -784,15 +793,15 @@ TableOfContents - F5AED0700F1999130090A93F + F56B744B101FA1C600B6D9A4 1CCC7628064C1048000F2A68 1CCC7629064C1048000F2A68 - F5AED0710F1999130090A93F - F5AED0720F1999130090A93F - F5AED0730F1999130090A93F - F5AED0740F1999130090A93F - F5AED0410F1989EC0090A93F - F5AED0750F1999130090A93F + F56B744C101FA1C600B6D9A4 + F56B744D101FA1C600B6D9A4 + F56B744E101FA1C600B6D9A4 + F56B744F101FA1C600B6D9A4 + F56B7409101F6DEB00B6D9A4 + F56B7450101FA1C600B6D9A4 ToolbarConfiguration xcode.toolbar.config.debug @@ -801,7 +810,7 @@ PerspectivesBarVisible PinnedNavigatorIdentifier - F539315B0FE170D5003CB103 + F56B743E101F7E4F00B6D9A4 ShelfIsVisible SourceDescription @@ -824,10 +833,11 @@ 5 WindowOrderList + F56B7450101FA1C600B6D9A4 /Users/xx/Grafx2/Grafx2.xcodeproj WindowString - 65 75 944 642 0 0 1024 746 + 151 75 971 659 0 0 1024 746 WindowTools diff --git a/main.c b/main.c index 38e944c8..9ee547b0 100644 --- a/main.c +++ b/main.c @@ -344,6 +344,7 @@ int Init_program(int argc,char * argv[]) strcpy(Main_file_directory,Main_current_directory); strcpy(Main_filename,"NO_NAME.GIF"); Main_fileformat=DEFAULT_FILEFORMAT; + // On initialise les données sur le nom de fichier de l'image de brouillon: strcpy(Spare_current_directory,Main_current_directory); strcpy(Spare_file_directory,Main_file_directory); @@ -407,6 +408,7 @@ int Init_program(int argc,char * argv[]) printf("Couldn't initialize SDL.\n"); return(0); } + Joystick = SDL_JoystickOpen(0); SDL_EnableKeyRepeat(250, 32); SDL_EnableUNICODE(SDL_ENABLE); @@ -440,18 +442,18 @@ int Init_program(int argc,char * argv[]) Set_all_video_modes(); Pixel_ratio=PIXEL_SIMPLE; // On initialise les données sur l'état du programme: - // Donnée sur la sortie du programme: + // Donnée sur la sortie du programme: Quit_is_required=0; Quitting=0; - // Données sur l'état du menu: + // Données sur l'état du menu: Pixel_in_menu=Pixel_in_toolbar; Menu_is_visible=1; - // Données sur les couleurs et la palette: + // Données sur les couleurs et la palette: First_color_in_palette=0; - // Données sur le curseur: + // Données sur le curseur: Cursor_shape=CURSOR_SHAPE_TARGET; Cursor_hidden=0; - // Données sur le pinceau: + // Données sur le pinceau: Paintbrush_X=0; Paintbrush_Y=0; Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; @@ -515,6 +517,7 @@ int Init_program(int argc,char * argv[]) // Charger la configuration des touches Set_config_defaults(); + switch(Load_CFG(1)) { case ERROR_CFG_MISSING: @@ -583,7 +586,7 @@ int Init_program(int argc,char * argv[]) starting_videomode=Current_resolution; Horizontal_line_buffer=NULL; Screen_width=Screen_height=Current_resolution=0; - + Init_mode_video( Video_mode[starting_videomode].Width, Video_mode[starting_videomode].Height, @@ -684,16 +687,16 @@ void Program_shutdown(void) #endif // On libère le buffer de gestion de lignes - free(Horizontal_line_buffer); + if(Horizontal_line_buffer) free(Horizontal_line_buffer); // On libère le pinceau spécial - free(Paintbrush_sprite); + if (Paintbrush_sprite) free(Paintbrush_sprite); // On libère les différents écrans virtuels et brosse: - free(Brush); + if(Brush) free(Brush); Set_number_of_backups(0); - free(Spare_screen); - free(Main_screen); + if(Spare_screen) free(Spare_screen); + if(Main_screen) free(Main_screen); // Free the skin (Gui graphics) data if (Gfx) @@ -730,9 +733,9 @@ int main(int argc,char * argv[]) int phoenix2_found=0; char phoenix_filename1[MAX_PATH_CHARACTERS]; char phoenix_filename2[MAX_PATH_CHARACTERS]; - if(!Init_program(argc,argv)) { + Program_shutdown(); return 0; } @@ -752,6 +755,7 @@ int main(int argc,char * argv[]) strcpy(Main_file_directory,Config_directory); strcpy(Main_filename,"phoenix2.img"); chdir(Main_file_directory); + Button_Reload(); Main_image_is_modified=1; Warning_message("Spare page recovered"); diff --git a/sdlscreen.c b/sdlscreen.c index 6dd348d4..df0594a6 100644 --- a/sdlscreen.c +++ b/sdlscreen.c @@ -61,8 +61,9 @@ void Set_mode_SDL(int *width, int *height, int fullscreen) Screen_pixels=Screen_SDL->pixels; } else + { DEBUG("Error: Unable to change video mode!",0); - + } SDL_ShowCursor(0); // Hide the SDL mouse cursor, we use our own } From 7a8cea5af64378738fd189cbc92ab5f94be817a5 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 1 Aug 2009 15:11:07 +0000 Subject: [PATCH 60/95] Remember the HSL/RGB setting in the palette screen when you close it. The variable was global but reset when opening the dialog. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@970 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- palette.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/palette.c b/palette.c index ce00dd00..79b9165e 100644 --- a/palette.c +++ b/palette.c @@ -815,13 +815,21 @@ void Button_Palette(void) Block(Window_pos_X+(Menu_factor_X*206),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); Block(Window_pos_X+(Menu_factor_X*233),Window_pos_Y+(Menu_factor_Y*141),Menu_factor_X*17,Menu_factor_Y,MC_Dark); // Jauges de couleur - Palette_view_is_RGB=1; 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 - 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); + + 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); + } 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); + } first_color=last_color=block_start=block_end=Fore_color; Tag_color_range(block_start,block_end); @@ -831,12 +839,7 @@ void Button_Palette(void) Block(Window_pos_X+(Menu_factor_X*264),Window_pos_Y+(Menu_factor_Y*93),Menu_factor_X<<4,Menu_factor_Y*64,Fore_color); // Affichage des valeurs de la couleur courante (pour 1 couleur) - Format_componant(Main_palette[Fore_color].R*Color_max/255,str); - Print_counter(176,172,str,MC_Black,MC_Light); - Format_componant(Main_palette[Fore_color].G*Color_max/255,str); - Print_counter(203,172,str,MC_Black,MC_Light); - Format_componant(Main_palette[Fore_color].B*Color_max/255,str); - Print_counter(230,172,str,MC_Black,MC_Light); + Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); Print_in_window(129,58,"Color number:",MC_Dark,MC_Light); Num2str(Fore_color,str,3); @@ -1814,7 +1817,7 @@ void Button_Palette(void) // Acte les changements en cours sur une ou plusieurs couleurs memcpy(temp_palette,working_palette,sizeof(T_Palette)); - memcpy(backup_palette ,working_palette,sizeof(T_Palette)); + memcpy(backup_palette, working_palette,sizeof(T_Palette)); Palette_view_is_RGB = !Palette_view_is_RGB; From 951096eb8616b93215ab375aef8e81e8df98387e Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Mon, 3 Aug 2009 17:38:59 +0000 Subject: [PATCH 61/95] Patch by Magnus Bergman to allow setting zoom level with keyboard shortcuts. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@971 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- const.h | 15 ++++++- engine.c | 52 ++++++++++++++++++++++++ gfx2.cfg | Bin 10133 -> 10211 bytes helpfile.h | 22 ++++++++-- hotkeys.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++ special.c | 22 ++++++++++ special.h | 1 + 7 files changed, 224 insertions(+), 5 deletions(-) diff --git a/const.h b/const.h index c0fcc269..82b07cd8 100644 --- a/const.h +++ b/const.h @@ -33,7 +33,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 145 ///< Number of actions that can have a key combination associated to it. +#define NB_SHORTCUTS 158 ///< Number of actions that can have a key combination associated to it. #define NB_ZOOM_FACTORS 12 ///< 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. @@ -387,6 +387,19 @@ enum SPECIAL_ACTIONS SPECIAL_TRANSPARENCY_9, SPECIAL_TRANSPARENCY_0, SPECIAL_TILING_MENU, ///< This must be the last of the "effects" family + SPECIAL_ZOOM_1, + SPECIAL_ZOOM_2, + SPECIAL_ZOOM_3, + SPECIAL_ZOOM_4, + SPECIAL_ZOOM_5, + SPECIAL_ZOOM_6, + SPECIAL_ZOOM_8, + SPECIAL_ZOOM_10, + SPECIAL_ZOOM_12, + SPECIAL_ZOOM_14, + SPECIAL_ZOOM_16, + SPECIAL_ZOOM_18, + SPECIAL_ZOOM_20, NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; diff --git a/engine.c b/engine.c index 5afabdc8..6919cfc0 100644 --- a/engine.c +++ b/engine.c @@ -905,6 +905,58 @@ void Main_handler(void) Transparency_set(0); Key=0; break; + case SPECIAL_ZOOM_1 : + Zoom_set(-1); + Key=0; + break; + case SPECIAL_ZOOM_2 : + Zoom_set(0); + Key=0; + break; + case SPECIAL_ZOOM_3 : + Zoom_set(1); + Key=0; + break; + case SPECIAL_ZOOM_4 : + Zoom_set(2); + Key=0; + break; + case SPECIAL_ZOOM_5 : + Zoom_set(3); + Key=0; + break; + case SPECIAL_ZOOM_6 : + Zoom_set(4); + Key=0; + break; + case SPECIAL_ZOOM_8 : + Zoom_set(5); + Key=0; + break; + case SPECIAL_ZOOM_10 : + Zoom_set(6); + Key=0; + break; + case SPECIAL_ZOOM_12 : + Zoom_set(7); + Key=0; + break; + case SPECIAL_ZOOM_14 : + Zoom_set(8); + Key=0; + break; + case SPECIAL_ZOOM_16 : + Zoom_set(9); + Key=0; + break; + case SPECIAL_ZOOM_18 : + Zoom_set(10); + Key=0; + break; + case SPECIAL_ZOOM_20 : + Zoom_set(11); + Key=0; + break; default : // Gestion des touches de raccourci de bouton: // Pour chaque bouton shortcut_button=-1; diff --git a/gfx2.cfg b/gfx2.cfg index c0cd18498ec3b0ba4a3eaf8dd7257f3c74ce08ef..6bb5e522d12a04914f8c3d457d21061234aad7dd 100644 GIT binary patch delta 99 zcmbR0|Ja|?+0C7aA&G%u%SO(0X77m%Y6=VtlNeqC$;k{#KynI$I*^>opaCSOG3Wxx m=?pJ`Yp+0C7aA&G$@Z6jwo^X7fbswx0ghz6Sg diff --git a/helpfile.h b/helpfile.h index 89fddbf7..165d890f 100644 --- a/helpfile.h +++ b/helpfile.h @@ -206,10 +206,24 @@ static const T_Help_table helptable_help[] = HELP_LINK ("Rotate brush: %s", SPECIAL_ROTATE_ANY_ANGLE) HELP_LINK ("Pipette: %s", 0x100+BUTTON_COLORPICKER) HELP_LINK ("Swap fore/back color:%s", 0x200+BUTTON_COLORPICKER) - HELP_LINK ("Magnifier mode: %s", 0x100+BUTTON_MAGNIFIER) - HELP_LINK ("Zoom factor menu: %s", 0x200+BUTTON_MAGNIFIER) - HELP_LINK ("Zoom in: %s", SPECIAL_ZOOM_IN) - HELP_LINK ("Zoom out: %s", SPECIAL_ZOOM_OUT) + HELP_TEXT ("Magnifier mode") + HELP_LINK (" Toggle: %s", 0x100+BUTTON_MAGNIFIER) + HELP_LINK (" Zoom factor menu: %s", 0x200+BUTTON_MAGNIFIER) + HELP_LINK (" Zoom in: %s", SPECIAL_ZOOM_IN) + HELP_LINK (" Zoom out: %s", SPECIAL_ZOOM_OUT) + HELP_LINK (" 1:1 (off) %s", SPECIAL_ZOOM_1) + HELP_LINK (" 2:1 %s", SPECIAL_ZOOM_2) + HELP_LINK (" 3:1 %s", SPECIAL_ZOOM_3) + HELP_LINK (" 4:1 %s", SPECIAL_ZOOM_4) + HELP_LINK (" 5:1 %s", SPECIAL_ZOOM_5) + HELP_LINK (" 6:1 %s", SPECIAL_ZOOM_6) + HELP_LINK (" 8:1 %s", SPECIAL_ZOOM_8) + HELP_LINK (" 10:1 %s", SPECIAL_ZOOM_10) + HELP_LINK (" 12:1 %s", SPECIAL_ZOOM_12) + HELP_LINK (" 14:1 %s", SPECIAL_ZOOM_14) + HELP_LINK (" 16:1 %s", SPECIAL_ZOOM_16) + 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 ("Text: %s", 0x100+BUTTON_TEXT) HELP_LINK ("Resolution menu: %s", 0x100+BUTTON_RESOL) diff --git a/hotkeys.c b/hotkeys.c index da8f0382..b91c8a21 100644 --- a/hotkeys.c +++ b/hotkeys.c @@ -1182,6 +1182,110 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { true, SDLK_0, // 0 0}, + {145, + "Zoom 1:1", + "Turs magnifier mode off.", + "", + "", + true, + SDLK_1|MOD_CTRL, /* Ctrl + 1 */ + 0}, + {146, + "Zoom 2:1", + "Turs magnifier mode on and set its", + "factor to 2:1", + "", + true, + SDLK_2|MOD_CTRL, /* Ctrl + 2 */ + 0}, + {147, + "Zoom 3:1", + "Turs magnifier mode on and set its", + "factor to 3:1", + "", + true, + SDLK_3|MOD_CTRL, /* Ctrl + 3 */ + 0}, + {148, + "Zoom 4:1", + "Turs magnifier mode on and set its", + "factor to 4:1", + "", + true, + SDLK_4|MOD_CTRL, /* Ctrl + 4 */ + 0}, + {149, + "Zoom 5:1", + "Turs magnifier mode on and set its", + "factor to 5:1", + "", + true, + SDLK_5|MOD_CTRL, /* Ctrl + 5 */ + 0}, + {150, + "Zoom 6:1", + "Turs magnifier mode on and set its", + "factor to 6:1", + "", + true, + SDLK_6|MOD_CTRL, /* Ctrl + 6 */ + 0}, + {151, + "Zoom 8:1", + "Turs magnifier mode on and set its", + "factor to 8:1", + "", + true, + SDLK_7|MOD_CTRL, /* Ctrl + 7 */ + 0}, + {152, + "Zoom 10:1", + "Turs magnifier mode on and set its", + "factor to 10:1", + "", + true, + SDLK_8|MOD_CTRL, /* Ctrl + 8 */ + 0}, + {153, + "Zoom 12:1", + "Turs magnifier mode on and set its", + "factor to 12:1", + "", + true, + 0, + 0}, + {154, + "Zoom 14:1", + "Turs magnifier mode on and set its", + "factor to 14:1", + "", + true, + 0, + 0}, + {155, + "Zoom 16:1", + "Turs magnifier mode on and set its", + "factor to 16:1", + "", + true, + 0, + 0}, + {156, + "Zoom 18:1", + "Turs magnifier mode on and set its", + "factor to 18:1", + "", + true, + 0, + 0}, + {157, + "Zoom 20:1", + "Turs magnifier mode on and set its", + "factor to 20:1", + "", + true, + 0, + 0}, }; word Ordering[NB_SHORTCUTS]= @@ -1331,4 +1435,17 @@ word Ordering[NB_SHORTCUTS]= SPECIAL_TRANSPARENCY_8, // Sets transparency level 80% SPECIAL_TRANSPARENCY_9, // Sets transparency level 90% SPECIAL_TRANSPARENCY_0, // Sets transparency level 00% + SPECIAL_ZOOM_1, /**< Sets zoom factor to 1:1 (no magnification) */ + SPECIAL_ZOOM_2, /**< Sets zoom factor to 2:1 */ + SPECIAL_ZOOM_3, /**< Sets zoom factor to 3:1 */ + SPECIAL_ZOOM_4, /**< Sets zoom factor to 4:1 */ + SPECIAL_ZOOM_5, /**< Sets zoom factor to 5:1 */ + SPECIAL_ZOOM_6, /**< Sets zoom factor to 6:1 */ + SPECIAL_ZOOM_8, /**< Sets zoom factor to 8:1 */ + SPECIAL_ZOOM_10, /**< Sets zoom factor to 10:1 */ + SPECIAL_ZOOM_12, /**< Sets zoom factor to 12:1 */ + SPECIAL_ZOOM_14, /**< Sets zoom factor to 14:1 */ + SPECIAL_ZOOM_16, /**< Sets zoom factor to 16:1 */ + SPECIAL_ZOOM_18, /**< Sets zoom factor to 18:1 */ + SPECIAL_ZOOM_20, /**< Sets zoom factor to 20:1 */ }; diff --git a/special.c b/special.c index 9fa8483e..72f71ee4 100644 --- a/special.c +++ b/special.c @@ -362,3 +362,25 @@ void Zoom(short delta) Display_cursor(); } } + +/** + Set zoom value. Negative value means no zoom. +*/ +void Zoom_set(int index) +{ + Hide_cursor(); + if (index<0) + { + /* Zoom 1:1 */ + if (Main_magnifier_mode) + Unselect_button(BUTTON_MAGNIFIER); + } + else + { + Change_magnifier_factor(index); + if (!Main_magnifier_mode) + Select_button(BUTTON_MAGNIFIER,1); + Display_all_screen(); + } + Display_cursor(); +} diff --git a/special.h b/special.h index 30134671..78984697 100644 --- a/special.h +++ b/special.h @@ -41,3 +41,4 @@ void Scroll_screen(short delta_x,short delta_y); void Scroll_magnifier(short delta_x,short delta_y); void Zoom(short delta); +void Zoom_set(int index); From 01909c180b74e4bfb4ad1bf3014564c88f950fec Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 4 Aug 2009 19:02:49 +0000 Subject: [PATCH 62/95] Fixed typo in Zoom shortcuts description git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@972 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- hotkeys.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/hotkeys.c b/hotkeys.c index b91c8a21..d526efdd 100644 --- a/hotkeys.c +++ b/hotkeys.c @@ -1184,7 +1184,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {145, "Zoom 1:1", - "Turs magnifier mode off.", + "Turns magnifier mode off.", "", "", true, @@ -1192,7 +1192,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {146, "Zoom 2:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 2:1", "", true, @@ -1200,7 +1200,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {147, "Zoom 3:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 3:1", "", true, @@ -1208,7 +1208,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {148, "Zoom 4:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 4:1", "", true, @@ -1216,7 +1216,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {149, "Zoom 5:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 5:1", "", true, @@ -1224,7 +1224,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {150, "Zoom 6:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 6:1", "", true, @@ -1232,7 +1232,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {151, "Zoom 8:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 8:1", "", true, @@ -1240,7 +1240,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {152, "Zoom 10:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 10:1", "", true, @@ -1248,7 +1248,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {153, "Zoom 12:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 12:1", "", true, @@ -1256,7 +1256,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {154, "Zoom 14:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 14:1", "", true, @@ -1264,7 +1264,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {155, "Zoom 16:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 16:1", "", true, @@ -1272,7 +1272,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {156, "Zoom 18:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 18:1", "", true, @@ -1280,7 +1280,7 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { 0}, {157, "Zoom 20:1", - "Turs magnifier mode on and set its", + "Turns magnifier mode on and set its", "factor to 20:1", "", true, From 6e1355c7ae93c950fd8445e4d2466c95376f3c5c Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 5 Aug 2009 11:59:51 +0000 Subject: [PATCH 63/95] Display "Palette editor / setup" in the toolbar for the palette button instead of just "Palette editor" as some people seem to miss this dialog :) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@973 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine.c b/engine.c index 6919cfc0..085fdadb 100644 --- a/engine.c +++ b/engine.c @@ -94,7 +94,7 @@ char * Menu_tooltip[NB_BUTTONS]= "Undo / Redo ", "Kill current page ", "Quit ", - "Palette editor ", + "Palette editor / setup ", "Scroll pal. bkwd / Fast ", "Scroll pal. fwd / Fast ", "Color #" , From 4bf44d6d9e32554f6a153acc355400ac30237d86 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 5 Aug 2009 18:23:25 +0000 Subject: [PATCH 64/95] Some changes to the helpfile git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@975 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- helpfile.h | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/helpfile.h b/helpfile.h index 165d890f..5284e65d 100644 --- a/helpfile.h +++ b/helpfile.h @@ -288,6 +288,13 @@ static const T_Help_table helptable_credits[] = //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TITLE(" GRAFX2 IS CREATED BY") HELP_TEXT ("") + HELP_BOLD (" THE GRAFX2 PROJECT TEAM") + HELP_TEXT ("") + HELP_TEXT (" Adrien Destugues (pulkomandy)") + HELP_TEXT (" Yves Rizoud (yrizoud)") + HELP_TEXT ("") + HELP_TEXT (" Got the source back to life in 2006") + HELP_TEXT ("") HELP_BOLD (" SUNSET DESIGN") HELP_BOLD (" AUTHORS OF GRAFX2.0 BETA 96.5%") HELP_TEXT ("") @@ -296,24 +303,19 @@ static const T_Help_table helptable_credits[] = //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT ("") HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") - HELP_TEXT ("") - HELP_BOLD (" THE GRAFX2 PROJECT TEAM") - HELP_TEXT ("") - HELP_TEXT (" Adrien Destugues (pulkomandy)") - HELP_TEXT (" Yves Rizoud (yrizoud)") - HELP_TEXT ("") - HELP_TEXT (" Got the source back to life in 2006") + HELP_TEXT (" Huge thaks to them for their work !") HELP_TEXT ("") HELP_BOLD (" ART") HELP_TEXT ("") + HELP_TEXT (" CLASSIC THEME") HELP_TEXT (" GrafX2 logo by Made (www.m4de.com)") HELP_TEXT (" Icons and fonts by X-Man ") - HELP_TEXT (" Additional graphics and logo by iLKke") + HELP_TEXT (" MODERN THEME") + HELP_TEXT (" Graphics and logo by iLKke") HELP_TEXT (" (ilkke.blogspot.com)") HELP_TEXT ("") HELP_TEXT (" Pixelled all the graphics") HELP_TEXT ("") - HELP_TEXT ("") HELP_TITLE(" OTHER MACHINES PORTS") HELP_TEXT ("") HELP_BOLD (" AMIGA OS 3 PORT") @@ -384,14 +386,14 @@ static const T_Help_table helptable_credits[] = HELP_TEXT (" SCx : Colorix (?)") HELP_TEXT ("") HELP_TEXT ("") - HELP_TITLE (" OUR HOMEPAGE") + HELP_TITLE(" OUR HOMEPAGE") HELP_TEXT ("") HELP_BOLD (" http://grafx2.codegoogle.com") HELP_TEXT ("") HELP_TEXT (" Please report any bug you may find there") HELP_TEXT ("") HELP_TEXT ("") - HELP_TITLE (" GREETINGS") + HELP_TITLE(" GREETINGS") HELP_TEXT ("") HELP_TEXT (" To the Pouet.net BBS posters, the #CPC") HELP_TEXT (" trolls and the bitfellas") @@ -456,15 +458,22 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TITLE (" SNAIL MAIL") HELP_TEXT ("") - HELP_TEXT (" (From 2001, current status: unknown)") +//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") + HELP_TEXT (" ADRIEN DESTUGUES (PulkoMandy)") + HELP_TEXT (" 3, rue Lapouble") + HELP_TEXT (" 64000 PAU") + HELP_TEXT (" (Send emails! Welcome in 21th century!)") HELP_TEXT ("") HELP_TEXT (" GUILLAUME DORME (Robinson)") HELP_TEXT (" 15, rue de l'observatoire") HELP_TEXT (" 87000 LIMOGES (FRANCE)") + HELP_TEXT (" (May take some years to get an answer)") + HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" KARL MARITAUD (X-Man)") HELP_TEXT (" 10, rue de la Brasserie") HELP_TEXT (" 87000 LIMOGES (FRANCE)") + HELP_TEXT (" (From 2001, current status: unknown)") HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE(" THANKS") From c199ad22ebf9d45efe8d4a0d90032af5d7cb838c Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 5 Aug 2009 19:33:51 +0000 Subject: [PATCH 65/95] Moved the french html docs from trunk to the new french section of the wiki. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@976 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- doc/Le moteur des operations.html | 384 ------------------------------ doc/Les entrees.html | 176 -------------- 2 files changed, 560 deletions(-) delete mode 100644 doc/Le moteur des operations.html delete mode 100644 doc/Les entrees.html diff --git a/doc/Le moteur des operations.html b/doc/Le moteur des operations.html deleted file mode 100644 index 42c5bdd4..00000000 --- a/doc/Le moteur des operations.html +++ /dev/null @@ -1,384 +0,0 @@ - - - - - - - -GrafX2 - Le moteur des opérations - - - - -

    GrafX2 - Le moteur des opérations

    - -
    - -

    Explication du principe :

    - -

    Qu'appelle-t'on une opération? C'est l'emploi d'un outil de -dessin. Par exemple, le tracé libre à la main d'un pinceau (ou -d'une brosse) est une opération. Plus exactement, c'est tout -comportement de la souris lorsqu'elle se trouve sur les pixels de -l'image éditée. De ce fait, la gestion de la pipette se fait -également au travers des opérations.

    - -

    Le moteur chargé de gérer ces opérations est simplifié -autant que possible. Son principe est le suivant : lorsque -la souris est au-dessus de l'image, la boucle principale de -gestion de GrafX2 (située dans MOTEUR.C) détermine la partie -atomique d'instructions à exécuter, puis l'exécute, pour -chaque combinaison d'un type d'opération (un entier, que l'on -nommera pour les besoins de cette page ID_OP), d'un état de la -souris (état de ses boutons plus exactement, codé sur un entier -également), et d'un nombre de valeurs présentes dans une pile -(pas la pile système, mais une pile de mots 16-bits -spécialement mise en place pour les opérations, afin qu'elles y -stockent des paramètres pour les opérations suivantes). On -appelle "partie atomique" une séquence d'instructions -qui doivent être exécutées intégralement à chaque itération -de la boucle principale. Elle se contente de ne faire que ce -qu'elle doit faire face à la situation qu'implique la -combinaison (ID_OP,Code souris, Etat pile) pour laquelle elle est -appelée.

    - -

    En fait, le moteur doit être aidé pour déterminer les -insctructions à exécuter. Chacune de ces parties atomiques est -écrite sous la forme d'une fonction contenant tout le code qui -lui est nécessaire. Ces fonctions sont ce que l'on a appelé des -"Func_action" (définition dans STRUCT.H), c'est à -dire une simple fonction qui ne reçoit pas de paramètres et qui -n'en renvoie pas. Un simple void Ma_fonction(void)...

    - -

    Il n'est pas dans mon intention de vous apprendre à écrire -ces fonctions atomiques. Dans le cas des opérations les plus -simples à implémenter selon ce principe, la conception des -parties atomiques est assez intuitive, mais il arrive dans -certains cas que la méthode trouve certaines limites, il faut -alors tricher un peu (mais gentiment! - en plaçant des valeurs -arbitraires dans la pile uniquement pour permettre la transition -vers une autre combinaison choisie, donc une autre partie -atomique, par exemple). Vous pourrez trouver tous les exemples -que vous voudrez dans le fichier OPERATIO.C.

    - -

    Après avoir écrit les parties atomiques qui vont être -nécessaires pour la gestion complète d'une opération (dans le -fichier OPERATIO.C), et avoir renseigné les prototypes de ces -fonctions (dans OPERATIO.H), il faut indiquer au moteur dans -quelles conditions utiliser ces fonctions. Cela se fait dans la -phase d'initialisation du programme (située dans le fichier -INIT.C), où l'on renseigne chacune des fonctions atomiques, en -décrivant les valeurs de combinaison qui doivent déclencher -leur appel. La fonction appelée se contente d'en prendre note en -remplissant un tableau nommé "Operation" (variable -globale déclarée dans GLOBAL.H, et indexée par les 3 valeurs -de la combinaison : ID_OP, code souris, état pile) à l'aide de -l'adresse de la fonction à appeler. Ce tableau va servir au -moteur à faire un appel direct de la fonction atomique d'après -la combinaison, sans avoir à faire toute une série de tests -(swich/case) fastidieux.

    - -

    Comme nous avons pressenti qu'il arriverait fréquemment que -des fonctions atomiques auraient besoin systématiquement -d'effacer la souris pour faire des affichages à l'écran ou dans -l'image, et de la rafficher ensuite, et dans le souci d'éviter -de faire abusivement du copier/coller de code, nous avons -rajouté un booléen dans le tableau Operation qui permet -d'indiquer que la fonction atomique demande au moteur de se -charger lui-même de l'effacement et de la restauration du -curseur de la souris à l'écran. Finalement, je ne suis pas -certain que cela s'est révelé d'une grande utilité, mais je -vous le signale tout de même pour que vous compreniez -l'existance du paramètre "Effacer souris" qu'il faut -indiquer lorsqu'on renseigne une fonction atomique lors de -l'initialisation.

    - -

    Il est important de noter qu'une fonction atomique est -appelée en permanence par la boucle principale, indépendamment -du fait que la souris change d'état ou non. Ces appels -répétés permettent par exemple d'avoir un spray qui continue -à agir lorsqu'on presse le bouton de la souris sans la -déplacer.

    - -

    De plus, les fonctions atomiques n'ont pas à se soucier du -positionnement de la souris car dès que la pile contient des -données (généralement dès le premier clic), la souris est -limitée par le moteur afin de ne pas sortir de l'image. Le -moteur s'assure également que la souris ne franchis pas la barre -de split en mode "loupe". Enfin, n'oubliez pas de vider -complètement la pile en temps voulu, lorsque l'opération peut -s'achever! ;-)

    - -
    - -

    Informations pour l'implémentation :

    - -
      -
    • Le renseignement d'une fonction atomique se fait dans - INIT.C à l'aide de :
    • -
    - -
    -

    Initialisation_operation(ID_OP, Etat souris, Taille pile, - Callback, Effacer souris);

    -
    - -
      -
    • La pile à disposition des opérations pour le stockage - des paramètres :
        -
      • Elle contient des mots 16-bits (type word, - définit dans STRUCT.H)
      • -
      • Pour y poser une valeur : - Operation_push(val)
      • -
      • Pour en retirer une valeur : - Operation_pop(&var)
      • -
      • Exemples de valeurs à y mettre : - coordonnées de souris, de pinceau... des - couleurs... des valeurs bidons pour changer - l'état de la pile...
        -
      • -
      -
    • -
    • A l'intérieur d'une fonction atomique :
        -
      • Si la fonction correspond à la première étape - d'une opération, appeler - Init_start_operation()
      • -
      • Si la fonction correspond à la première étape - d'une opération qui peut modifier l'image, - appeler Backup() avant modification de l'image ; - ce qui permettra à l'utilisateur d'annuler la - modification avec "undo" s'il le - souhaite.
      • -
      • Pour afficher les coordonnées de la souris, - appeler Print_coordinates() sans vous soucier de - savoir si la barre d'outils est visible. Si vous - avez besoin d'afficher une coordonnée qui doit - s'adapter au mode relatif ou absolu (selon le - paramétrage effectué par l'utilisateur), - utilisez Display_coords_rel_or_abs(RefX,RefY). Si les - coordonnées sont configurées pour être - relatives, cette fonction affichera la - différence entre les coordonnées actuelles du - pinceau et les coordonnées de référence - passées en paramètres. Dans le cas d'infos - spéciales à afficher dans la barre de menu, on - pourra se servir de la fonction - Print_in_menu(texte,position en caractères).
      • -
      • Si vous avez besoin de vous assurer que les - boutons de la souris sont relâchés à un moment - de la fonction, utilisez Wait_end_of_click()
      • -
      • Etudiez OPERATIO.C pour avoir des exemples.
        -
      • -
      -
    • -
    • Pour démarrer une opération (après avoir cliqué sur - un bouton de la barre d'outils par exemple), appeler - Start_operation_stack(ID_OP). Note: il faut que le - curseur soit caché avant l'appel (et son état n'est pas - changé après). (voir exemples dans BOUTONS.C)
      -
    • -
    • On peut connaître l'ID_OP de l'opération en cours - grâce à la variable globale Current_operation
      -
    • -
    • La variable globale Operation_stack_size correspond à - la taille de la pile d'opérations. Elle peut être - consultée et éventuellement modifiée (même s'il est - préférable d'utiliser Operation_push et Operation_pop - dans ce dernier cas).
    • -
    - -
    - -

    Comment rajouter une opération?

    -
    - - - - - - - - - - - - - - - - - -
    Dans CONST.H :
      -
    • rajouter un identifiant (ID_OP) dans l'enum - OPERATIONS (exemple : OPERATION_DUMMY)
    • -
    -
    Dans GLOBAL.H :
      -
    • rajouter l'identifiant de la forme de curseur à - utiliser pour cette opération dans la table - CURSOR_FOR_OPERATION[]. Faites bien attention à - l'insérer au bon endroit (place correspondant à - ID_OP).
    • -
    -
    Dans OPERATIO.C :
      -
    • Ecrire chaque fonction atomique de l'opération.
    • -
    -
    -

    Exemple :

    -
    -
    -
    -

    void Dummy_1_0(void)
    - // Opération : OPERATION_DUMMY
    - // Click Souris: 1
    - // Taille_Pile : 0
    - // Souris effacée: Oui (précisé grâce à - Init_operation() dans INIT.C)
    - {
    -      Init_start_operation();
    -      Backup();
    -
    -      // ACTIONS...
    -
    -      Operation_push(une_valeur_nécessaire_pour_les_prochaines_étapes);
    -      Operation_push(une_autre_valeur_nécessaire_plus_tard);
    - }

    -
    -
    -
    -
    -

    (Pour cet exemple, l'étape suivante à - définir sera donc une étape avec la taille de - pile à 2)

    -
    -
    -
      -
    • Il y a une action par défaut qui se contente - d'afficher les coordonnées de la souris - lorsqu'on ne définit pas explicitement de - fonction atomique gérant une certaine - combinaison (ID_OP, Etat souris, Taille pile).
    • -
    • Si l'opération représente une interruption - temporaire, et qu'il vous paraît juste de - restaurer l'opération précédente une fois - qu'elle est terminée (cas de la loupe, de la - pipette, des prises de brosse, ...), rajouter - l'ID_OP dans la section correspondante de la - fonction Start_operation_stack(), en début de - fichier.
    • -
    • Si l'opération voit un intérêt à accepter que - l'utilisateur change de couleur de pinceau en - cours d'opération (cas du dessin continu, - discontinu, le spray, et les lignes centrées), - rajouter l'ID_OP dans la section correspondante - de la fonction Start_operation_stack(), en - début de fichier.
    • -
    -
    Dans OPERATIO.H :
      -
    • Ecrire le prototype des ces fonctions atomiques.
    • -
    -
    Dans INIT.C :
      -
    • Dans Init_operations(), pour chaque - fonction atomique de l'opération, écrire un - appel à Init_operation(ID_OP, Etat - souris, Taille pile, Callback, Effacer souris);
        -
      • ID_OP : identifiant de l'opération - dont dépend la fonction atomique - (défini dans CONST.H)
      • -
      • Etat souris :
          -
        • 0 = boutons relachés
        • -
        • 1 = bouton gauche enfoncé
        • -
        • 2 = bouton droit enfoncé
        • -
        • (note : l'état "boutons - gauche et droit enfoncés" - n'existe pas, seuls les 3 états - ci-dessus sont autorisés)
        • -
        -
      • -
      • Taille pile : nombre de paramètres - dans la pile
      • -
      • Callback : nom de la fonction - atomique à appeler pour la combinaison - des 3 paramètres précédents
      • -
      • Effacer souris : booléen indiquant - que le moteur se chargera d'effacer le - curseur souris avant l'appel à la - fonction atomique, et de le rafficher - après sa sortie.
      • -
      -
    • -
    -
    -

    Exemple :

    -
    -
    -
    -

    Init_operation(OPERATION_DUMMY, 1, 0, - Dummy_1_0, 1);

    -
    -
    -
    -
    - - - - - diff --git a/doc/Les entrees.html b/doc/Les entrees.html deleted file mode 100644 index d01ee1ba..00000000 --- a/doc/Les entrees.html +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - -GrafX2 - Les entrées - - - - -

    GrafX2 - Les entrées

    - -
    - -

    Get_input() (dans DIVERS.ASM):

    - -
      -
    • Touches :
        -
      • Met à jour la variable "Touche", un - mot 16-bits qui contient dans sa partie basse la - valeur du scan-code (valeur plutôt liée à la - géographie de la touche) de la touche enfoncée - à traiter, et dans sa partie haute un codage des - touches de contrôles enfoncées au moment de - l'appel.
          -
        • (Touche & 0x0100) => Shift
        • -
        • (Touche & 0x0200) => Control
        • -
        • (Touche & 0x0400) => Alt
        • -
        -
      • -
      • Met dans la variable "Touche_ASCII" la - valeur ASCII (valeur liée au caractère que - représente la touche) de la touche enfoncée à - traiter.
      • -
      • Dans le cas où la variable globale - "Autoriser_changement_de_couleur_pendant_operation" - serait à 0, et qu'il existerait au moins une - valeur dans la pile des opérations, la fonction - filtre les touches. Cela signifie que l'on ne - peut pas interrompre une opération en cours, - sauf pour changer la couleur du pinceau si - l'opération l'autorise (utile pour faire varier - la couleur du pinceau à l'aide des touches - pendant qu'on dessine).
      • -
      -
    • -
    • Souris :
        -
      • Met à jour la position (Mouse_X,Mouse_Y) de la - souris en fonction de sa position dans un écran - virtuel. Cet écran est volontairement plus grand - que la résolution réelle du mode vidéo car de - nombreux drivers ne fournissent pas la position - de la souris au pixel près...
      • -
      • Met à jour l'état des boutons de la souris - (Mouse_K). La variable vaut 0 si aucun bouton - n'est enfoncé, 1 si seul le bouton gauche est - enfoncé, et 2 si seul le bouton droit est - enfoncé. Dans le cas où les 2 boutons seraient - enfoncé, Get_input() considère qu'aucun bouton - n'est enfoncé (Mouse_K = 0).
      • -
      • La fonction corrige la position de la souris afin - de l'empêcher de sortir de la surface d'image - sur laquelle elle se trouve si au moins une - valeur est dans la pile des opérations (la - souris ne sort pas de la zone de dessin tant que - l'opération de dessin n'est pas terminée), et - elle simule également le déplacement et les - clics de la souris si la combinaison de touches - courante correspond à de telles commandes. Dans - ce dernier cas, la touche est ensuite filtrée - afin d'éviter de faire travailler la fonction - appelante pour rien.
      • -
      • Dans le cas où la souris change d'état ou que - la variable globale - "Forcer_affichage_curseur" est placée - à 1, le curseur de la souris est réaffiché. La - fonction laisse toujours la variable - Forcer_affichage_curseur à 0 en fin d'appel.
      • -
      • La fonction fait appel à - Calculer_coordonnees_pinceau() qui se charge de - calculer convenablement les coordonnées du - pinceau (Pinceau_X,Pinceau_Y) en fonction de la - position de la souris à l'écran, de la position - de la zone de dessin dans l'image, du facteur de - zoom et de l'effet de la grille.
      • -
      -

      Important : Dans la plupart des cas, - vous n'avez pas à appeler cette fonction car le moteur - (boucle principale, gestionnaire de fenêtre, sélecteurs - de fichier, ...) s'en est déjà chargé. Vous pouvez - donc considérer que les variables concernées sont - déjà à jour. Si vous appeliez vous-même la fonction - Get_input() à un moment inoportun, certaines commandes - de l'utilisateur, prises en compte par le moteur, ne - seraient pas traitées.

      -
    • -
    - -

    Attendre_fin_de_click() (dans DIVERS.ASM):

    - -
    -

    S'il vous arrive d'avoir besoin de vous assurer que - l'utilisateur n'appuie plus sur les boutons de la souris à - un instant donné, cette fonction attend jusqu'à ce que - l'utilisateur relache le bouton. La valeur de Mouse_K vaut - alors 0, mais s'il a déplacé la souris avant de suspendre - sa pression, la position (Mouse_X,Mouse_Y) n'est pas encore - à jour. Cependant, cela ne devrait pas être génant (au - pire, un appel à Get_input() mettra ces valeurs à jour).

    -
    - - - - - From f43502f7bec75110292be4a12dc8000e9b9f8d10 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Wed, 5 Aug 2009 20:36:34 +0000 Subject: [PATCH 66/95] typo. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@981 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- helpfile.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpfile.h b/helpfile.h index 5284e65d..fcd3592d 100644 --- a/helpfile.h +++ b/helpfile.h @@ -303,7 +303,7 @@ static const T_Help_table helptable_credits[] = //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT ("") HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") - HELP_TEXT (" Huge thaks to them for their work !") + HELP_TEXT (" Huge thanks to them for their work !") HELP_TEXT ("") HELP_BOLD (" ART") HELP_TEXT ("") From 8b340684bd3640d32bb253de01ba25ac80b67aaf Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 8 Aug 2009 18:53:30 +0000 Subject: [PATCH 67/95] Various internal changes, preparing for layers (mostly backup system) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@983 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 100 +++++++++++++++-------------------------------------- graph.c | 2 ++ misc.c | 21 ++++++----- operatio.c | 36 ++++++++++++++++++- pages.c | 4 +++ pages.h | 2 +- palette.c | 11 ++++++ 7 files changed, 93 insertions(+), 83 deletions(-) diff --git a/buttons.c b/buttons.c index 36ea052d..c9f75428 100644 --- a/buttons.c +++ b/buttons.c @@ -505,6 +505,7 @@ void Button_Clear(void) else Hide_current_image(0); Display_all_screen(); + End_of_modification(); Unselect_button(BUTTON_CLEAR); Display_cursor(); } @@ -518,6 +519,7 @@ void Button_Clear_with_backcolor(void) else Hide_current_image(Back_color); Display_all_screen(); + End_of_modification(); Unselect_button(BUTTON_CLEAR); Display_cursor(); } @@ -1306,97 +1308,51 @@ void Button_Skins(void) //---------------------------- Changement de page ---------------------------- void Button_Page(void) { - byte temp_byte; - word temp_word; - short temp_short; - float temp_float; + byte factor_index; char Temp_buffer[256]; + #define SWAP_BYTES(a,b) { byte c=a; a=b; b=c;} + #define SWAP_WORDS(a,b) { word c=a; a=b; b=c;} + #define SWAP_SHORTS(a,b) { short c=a; a=b; b=c;} + #define SWAP_FLOATS(a,b) { float c=a; a=b; b=c;} + Hide_cursor(); // On dégrossit le travail avec les infos des listes de pages Exchange_main_and_spare(); // On fait le reste du travail "à la main": - temp_short=Spare_offset_X; - Spare_offset_X=Main_offset_X; - Main_offset_X=temp_short; - - temp_short=Spare_offset_Y; - Spare_offset_Y=Main_offset_Y; - Main_offset_Y=temp_short; - - temp_short=Old_spare_offset_X; - Old_spare_offset_X=Old_main_offset_X; - Old_main_offset_X=temp_short; - - temp_short=Old_spare_offset_Y; - Old_spare_offset_Y=Old_main_offset_Y; - Old_main_offset_Y=temp_short; - - temp_short=Spare_separator_position; - Spare_separator_position=Main_separator_position; - Main_separator_position=temp_short; - - temp_short=Spare_X_zoom; - Spare_X_zoom=Main_X_zoom; - Main_X_zoom=temp_short; - - temp_float=Spare_separator_proportion; - Spare_separator_proportion=Main_separator_proportion; - Main_separator_proportion=temp_float; - - temp_byte=Spare_magnifier_mode; - Spare_magnifier_mode=Main_magnifier_mode; - Main_magnifier_mode=temp_byte; + SWAP_SHORTS(Main_offset_X,Spare_offset_X) + SWAP_SHORTS(Main_offset_Y,Spare_offset_Y) + SWAP_SHORTS(Old_main_offset_X,Old_spare_offset_X) + SWAP_SHORTS(Old_main_offset_Y,Old_spare_offset_Y) + SWAP_SHORTS(Main_separator_position,Spare_separator_position) + SWAP_SHORTS(Main_X_zoom,Spare_X_zoom) + SWAP_FLOATS(Main_separator_proportion,Spare_separator_proportion) + SWAP_BYTES (Main_magnifier_mode,Spare_magnifier_mode) Pixel_preview=(Main_magnifier_mode)?Pixel_preview_magnifier:Pixel_preview_normal; - temp_word=Spare_magnifier_factor; - Spare_magnifier_factor=Main_magnifier_factor; - Main_magnifier_factor=temp_word; - - temp_word=Spare_magnifier_height; - Spare_magnifier_height=Main_magnifier_height; - Main_magnifier_height=temp_word; - - temp_word=Spare_magnifier_width; - Spare_magnifier_width=Main_magnifier_width; - Main_magnifier_width=temp_word; - - temp_short=Spare_magnifier_offset_X; - Spare_magnifier_offset_X=Main_magnifier_offset_X; - Main_magnifier_offset_X=temp_short; - - temp_short=Spare_magnifier_offset_Y; - Spare_magnifier_offset_Y=Main_magnifier_offset_Y; - Main_magnifier_offset_Y=temp_short; - + SWAP_WORDS (Main_magnifier_factor,Spare_magnifier_factor) + SWAP_WORDS (Main_magnifier_height,Spare_magnifier_height) + SWAP_WORDS (Main_magnifier_width,Spare_magnifier_width) + SWAP_SHORTS(Main_magnifier_offset_X,Spare_magnifier_offset_X) + SWAP_SHORTS(Main_magnifier_offset_Y,Spare_magnifier_offset_Y) // Swap du booléen "Image modifiée" - temp_byte =Spare_image_is_modified; - Spare_image_is_modified=Main_image_is_modified; - Main_image_is_modified=temp_byte; + SWAP_BYTES (Main_image_is_modified,Spare_image_is_modified) // Swap des infos sur les fileselects strcpy(Temp_buffer ,Spare_current_directory); strcpy(Spare_current_directory,Main_current_directory); strcpy(Main_current_directory,Temp_buffer ); - temp_byte=Spare_format; - Spare_format=Main_format; - Main_format=temp_byte; - - temp_word =Spare_fileselector_position; - Spare_fileselector_position=Main_fileselector_position; - Main_fileselector_position=temp_word; - - temp_word =Spare_fileselector_offset; - Spare_fileselector_offset=Main_fileselector_offset; - Main_fileselector_offset=temp_word; - + SWAP_BYTES (Main_format,Spare_format) + SWAP_WORDS (Main_fileselector_position,Spare_fileselector_position) + SWAP_WORDS (Main_fileselector_offset,Spare_fileselector_offset) + // A la fin, on affiche l'écran - for (temp_byte=0; ZOOM_FACTOR[temp_byte]!=Main_magnifier_factor; temp_byte++); - Change_magnifier_factor(temp_byte); + for (factor_index=0; ZOOM_FACTOR[factor_index]!=Main_magnifier_factor; factor_index++); + Change_magnifier_factor(factor_index); Set_palette(Main_palette); Compute_optimal_menu_colors(Main_palette); diff --git a/graph.c b/graph.c index 14b41147..b473a193 100644 --- a/graph.c +++ b/graph.c @@ -681,6 +681,7 @@ void Get_colors_from_brush(void) Display_all_screen(); Display_menu(); Display_cursor(); + End_of_modification(); Main_image_is_modified=1; } @@ -999,6 +1000,7 @@ void Fill_general(byte fill_color) // on n'y a jamais touché à l'écran les autres: ils sont donc corrects. Update_rect(0,0,0,0); + End_of_modification(); } } diff --git a/misc.c b/misc.c index 17d77754..ed70e042 100644 --- a/misc.c +++ b/misc.c @@ -396,11 +396,12 @@ byte Effect_interpolated_colorize (word x,word y,byte color) // On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la // palette des teintes) et dans EDI, 3*color. - byte blue_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].B; + byte color_under = Read_pixel_from_feedback_screen(x,y); + byte blue_under=Main_palette[color_under].B; byte blue=Main_palette[color].B; - byte green_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].G; + byte green_under=Main_palette[color_under].G; byte green=Main_palette[color].G; - byte red_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].R; + byte red_under=Main_palette[color_under].R; byte red=Main_palette[color].R; // On récupère les 3 composantes RVB @@ -418,9 +419,10 @@ byte Effect_interpolated_colorize (word x,word y,byte color) byte Effect_additive_colorize (word x,word y,byte color) { - byte blue_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].B; - byte green_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].G; - byte red_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].R; + byte color_under = Read_pixel_from_feedback_screen(x,y); + byte blue_under=Main_palette[color_under].B; + byte green_under=Main_palette[color_under].G; + byte red_under=Main_palette[color_under].R; byte blue=Main_palette[color].B; byte green=Main_palette[color].G; byte red=Main_palette[color].R; @@ -433,9 +435,10 @@ byte Effect_additive_colorize (word x,word y,byte color) byte Effect_substractive_colorize(word x,word y,byte color) { - byte blue_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].B; - byte green_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].G; - byte red_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].R; + byte color_under = Read_pixel_from_feedback_screen(x,y); + byte blue_under=Main_palette[color_under].B; + byte green_under=Main_palette[color_under].G; + byte red_under=Main_palette[color_under].R; byte blue=Main_palette[color].B; byte green=Main_palette[color].G; byte red=Main_palette[color].R; diff --git a/operatio.c b/operatio.c index 30c447ea..d8ad8908 100644 --- a/operatio.c +++ b/operatio.c @@ -241,6 +241,7 @@ void Freehand_mode12_0_2(void) // Souris effacée: Non { Operation_stack_size=0; + End_of_modification(); } @@ -431,6 +432,7 @@ void Freehand_mode3_0_1(void) // // Souris effacée: Non { + End_of_modification(); Operation_stack_size--; } @@ -572,6 +574,7 @@ void Line_0_5(void) Display_paintbrush (start_x,start_y,color,0); Draw_line_permanet(start_x,start_y,end_x,end_y,color); + End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); @@ -750,6 +753,7 @@ void K_line_12_7(void) Hide_cursor(); Paintbrush_shape=Paintbrush_shape_before_operation; + End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); @@ -925,6 +929,8 @@ void Empty_rectangle_0_5(void) Paintbrush_X=old_paintbrush_x; Paintbrush_Y=old_paintbrush_y; + End_of_modification(); + if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("X: Y:",0); Print_coordinates(); @@ -970,6 +976,7 @@ void Filled_rectangle_0_5(void) Paintbrush_X=old_paintbrush_x; Paintbrush_Y=old_paintbrush_y; + End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y:",0); @@ -1102,6 +1109,8 @@ void Empty_circle_0_5(void) Draw_empty_circle_permanent(center_x,center_y,radius,color); + End_of_modification(); + if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y:",0); @@ -1141,6 +1150,7 @@ void Filled_circle_0_5(void) Draw_filled_circle(center_x,center_y,radius,color); + End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y:",0); @@ -1271,6 +1281,8 @@ void Empty_ellipse_0_5(void) Draw_empty_ellipse_permanent(center_x,center_y,horizontal_radius,vertical_radius,color); + End_of_modification(); + if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); @@ -1312,6 +1324,7 @@ void Filled_ellipse_0_5(void) Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,color); + End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); @@ -1340,6 +1353,7 @@ void Fill_1_0(void) Shade_table=Shade_table_left; Fill_general(Fore_color); Display_cursor(); + End_of_modification(); Wait_end_of_click(); } @@ -1361,6 +1375,7 @@ void Fill_2_0(void) Shade_table=Shade_table_right; Fill_general(Back_color); Display_cursor(); + End_of_modification(); Wait_end_of_click(); } @@ -1385,6 +1400,7 @@ void Replace_1_0(void) // Shade_table=Shade_table_left; Replace(Fore_color); Display_cursor(); + End_of_modification(); Wait_end_of_click(); } @@ -1406,6 +1422,7 @@ void Replace_2_0(void) // Shade_table=Shade_table_right; Replace(Back_color); Display_cursor(); + End_of_modification(); Wait_end_of_click(); } @@ -1895,6 +1912,7 @@ void Curve_4_points_2_9(void) Draw_curve_permanent(x1,y1,x2,y2,x3,y3,x4,y4,color); Display_cursor(); + End_of_modification(); Wait_end_of_click(); } @@ -2049,6 +2067,7 @@ void Curve_3_points_12_11(void) Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); Draw_curve_permanent(x1,y1,x2,y2,x3,y3,x4,y4,color); + End_of_modification(); Display_cursor(); Wait_end_of_click(); } @@ -2136,6 +2155,7 @@ void Airbrush_0_2(void) // { Operation_stack_size-=2; + End_of_modification(); } @@ -2226,6 +2246,7 @@ void Polygon_12_9(void) Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Display_cursor(); + End_of_modification(); Wait_end_of_click(); Hide_cursor(); @@ -2424,6 +2445,7 @@ void Polyfill_12_9(void) Polyfill(Polyfill_number_of_points,Polyfill_table_of_points,color); free(Polyfill_table_of_points); + End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) { Print_in_menu("X: Y: ",0); @@ -2546,6 +2568,7 @@ void Polyform_12_8(void) Draw_line_permanet(start_x,start_y,initial_x,initial_y,color); Display_cursor(); + End_of_modification(); Wait_end_of_click(); } } @@ -2755,6 +2778,7 @@ void Filled_polyform_12_8(void) Paintbrush_hidden=0; Display_cursor(); + End_of_modification(); Wait_end_of_click(); } } @@ -2838,6 +2862,7 @@ void Filled_contour_0_8(void) Paintbrush_hidden=0; Display_cursor(); + End_of_modification(); } ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH @@ -2980,6 +3005,7 @@ void Brush_0_5(void) Brush_offset_Y=(Brush_offset_Y/Snap_height)*Snap_height; } + End_of_modification(); Return_to_draw_mode(); } @@ -3103,6 +3129,8 @@ void Polybrush_12_8(void) Brush_offset_Y=(Brush_offset_Y/Snap_height)*Snap_height; } + if (click==RIGHT_SIDE) + End_of_modification(); Return_to_draw_mode(); Display_cursor(); } @@ -3952,6 +3980,7 @@ void Scroll_0_4(void) { Operation_stack_size-=4; Cursor_hidden=Cursor_hidden_before_scroll; + End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); @@ -4117,6 +4146,7 @@ void Grad_circle_0_6(void) Draw_filled_circle(center_x,center_y,radius,Back_color); + End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); @@ -4168,6 +4198,7 @@ void Grad_circle_12_8(void) Draw_grad_circle(center_x,center_y,radius,Paintbrush_X,Paintbrush_Y); Display_cursor(); + End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) @@ -4371,6 +4402,7 @@ void Grad_ellipse_0_6(void) Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Back_color); + End_of_modification(); if ((Config.Coords_rel) && (Menu_is_visible)) { Print_in_menu("X: Y: ",0); @@ -4423,7 +4455,7 @@ void Grad_ellipse_12_8(void) Draw_grad_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Paintbrush_X,Paintbrush_Y); Display_cursor(); - + End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) @@ -4903,6 +4935,7 @@ void Grad_rectangle_0_9(void) Draw_grad_rectangle(rect_start_x,rect_start_y,rect_end_x,rect_end_y,vector_start_x,vector_start_y,vector_end_x,vector_end_y); Display_cursor(); + End_of_modification(); Wait_end_of_click(); if ((Config.Coords_rel) && (Menu_is_visible)) @@ -5056,6 +5089,7 @@ void Centered_lines_12_7(void) } Display_cursor(); + End_of_modification(); Wait_end_of_click(); } } diff --git a/pages.c b/pages.c index ccd1b37c..a52c9c22 100644 --- a/pages.c +++ b/pages.c @@ -930,3 +930,7 @@ void * Borrow_memory_from_page(int size) // Pour que le compilateur ne dise pas qu'il manque une valeur de sortie: return 0; } + +void End_of_modification(void) +{ +} diff --git a/pages.h b/pages.h index 5472a7d4..8a6c8ca4 100644 --- a/pages.h +++ b/pages.h @@ -81,7 +81,7 @@ void Undo(void); void Redo(void); void Free_current_page(void); // 'Kill' button void Exchange_main_and_spare(void); - +void End_of_modification(void); /// diff --git a/palette.c b/palette.c index 79b9165e..f8bcaa00 100644 --- a/palette.c +++ b/palette.c @@ -1318,7 +1318,10 @@ void Button_Palette(void) // En cas de X-Swap, tout l'ecran a pu changer de couleur. if (clicked_button==8) + { Update_rect(0, 0, Screen_width, Menu_Y_before_window); + End_of_modification(); + } Wait_end_of_click(); } break; @@ -1418,6 +1421,7 @@ void Button_Palette(void) Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); memcpy(temp_palette,working_palette,sizeof(T_Palette)); + End_of_modification(); need_to_remap=1; break; @@ -1782,6 +1786,7 @@ void Button_Palette(void) Hide_cursor(); Remap_image_highlevel(conversion_table); Display_cursor(); + End_of_modification(); } // On prépare la "modifiabilité" des nouvelles couleurs Set_palette(working_palette); @@ -1943,6 +1948,8 @@ void Button_Palette(void) // Maintenant, tous ces calculs doivent êtres pris en compte dans la // palette, l'image et à l'écran. Set_palette(working_palette); + + End_of_modification(); need_to_remap=1; } break; @@ -2033,6 +2040,8 @@ void Button_Palette(void) memcpy(temp_palette,working_palette,sizeof(T_Palette)); Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); Update_color_count(&used_colors,color_usage); + // End_of_modification(); + // Not really needed, the change was in palette entries need_to_remap=1; Key=0; break; @@ -2117,6 +2126,8 @@ void Button_Palette(void) && memcmp(Main_palette,working_palette,sizeof(T_Palette)) ) Backup(); memcpy(Main_palette,working_palette,sizeof(T_Palette)); + // End_of_modification(); + // Not really needed, the change was in palette entries } Compute_optimal_menu_colors(Main_palette); From 4e0d95b5e7cd0e4fbc72e875ec0ab5f29d73e068 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 9 Aug 2009 16:54:39 +0000 Subject: [PATCH 68/95] New: PNG 24bit loader (issue 201). Fixed greyscale PNG loader which never worked. Fixed 24-bit image loading on program startup which didnt update palette. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@984 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 188 +++++++++++++++++++++++++++++++++++++++-------------- op_c.c | 32 ++++++++- 2 files changed, 171 insertions(+), 49 deletions(-) diff --git a/loadsave.c b/loadsave.c index 5aeecbbc..175dedfe 100644 --- a/loadsave.c +++ b/loadsave.c @@ -116,6 +116,8 @@ void Load_PNG(void); void Save_PNG(void); #endif +void Init_preview(short width,short height,long size,int format); + T_Format File_formats[NB_KNOWN_FORMATS] = { {"pkm", Test_PKM, Load_PKM, Save_PKM, 1, 1}, {"lbm", Test_LBM, Load_LBM, Save_LBM, 1, 0}, @@ -282,33 +284,38 @@ void Set_palette_fake_24b(T_Palette palette) } } -// Supplément à faire lors de l'initialisation d'une preview dans le cas -// d'une image 24b -void Init_preview_24b(int width,int height) +// Initialization for a 24bit image +void Init_preview_24b(short width,short height,long size,int format) { + // Call common processing + Init_preview(width,height,size,format); + + if (File_error) + return; + if (Pixel_load_function==Pixel_load_in_preview) { - // Aiguillage du chargement 24b + // Choose 24bit pixel "writer" Pixel_load_24b=Pixel_load_in_24b_preview; - // Changement de palette + // Load palette Set_palette_fake_24b(Main_palette); Set_palette(Main_palette); Remap_fileselector(); } else { - // Aiguillage du chargement 24b + // Choose 24bit pixel "writer" Pixel_load_24b=Pixel_load_in_24b_buffer; - // Allocation du buffer 24b + // Allocate 24bit buffer Buffer_image_24b= (T_Components *)Borrow_memory_from_page(width*height*sizeof(T_Components)); if (!Buffer_image_24b) { - // Afficher un message d'erreur + // Print an error message - // Pour être sûr que ce soit lisible. + // The following is to be sure the messagfe is readable Compute_optimal_menu_colors(Main_palette); Message_out_of_memory(); if (Pixel_load_function==Pixel_load_in_current_screen) @@ -334,10 +341,6 @@ void Init_preview(short width,short height,long size,int format) // { char str[10]; - int image_is_24b; - - image_is_24b=format & FORMAT_24B; - format =format & (~FORMAT_24B); if (Pixel_load_function==Pixel_load_in_preview) { @@ -448,10 +451,6 @@ void Init_preview(short width,short height,long size,int format) File_error=3; } } - - if (!File_error) - if (image_is_24b) - Init_preview_24b(width,height); } @@ -622,6 +621,10 @@ void Load_image(byte image) // Cas d'un chargement dans l'image if (Convert_24b_bitmap_to_256(Main_screen,Buffer_image_24b,Main_image_width,Main_image_height,Main_palette)) File_error=2; + else + { + Set_palette(Main_palette); + } } else { @@ -2595,7 +2598,7 @@ void Load_BMP(void) Main_image_width=header.Width; Main_image_height=header.Height; - Init_preview(header.Width,header.Height,file_size,FORMAT_BMP | FORMAT_24B); + Init_preview_24b(header.Width,header.Height,file_size,FORMAT_BMP); if (File_error==0) { switch (header.Compression) @@ -3974,7 +3977,7 @@ void Load_PCX(void) { // Image 24 bits!!! - Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_PCX | FORMAT_24B); + Init_preview_24b(Main_image_width,Main_image_height,file_size,FORMAT_PCX); if (File_error==0) { @@ -5866,7 +5869,7 @@ void Load_PNG(void) FILE *file; // Fichier du fichier char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier byte png_header[8]; - dword image_size; + byte row_pointers_allocated; png_structp png_ptr; png_infop info_ptr; @@ -5877,29 +5880,45 @@ void Load_PNG(void) if ((file=fopen(filename, "rb"))) { + // Load header (8 first bytes) if (Read_bytes(file,png_header,8)) { + // Do we recognize a png file signature ? if ( !png_sig_cmp(png_header, 0, 8)) { + // Prepare internal PNG loader png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr) { + // Prepare internal PNG loader info_ptr = png_create_info_struct(png_ptr); if (info_ptr) { png_byte color_type; png_byte bit_depth; + // Setup a return point. If a pnglib loading error occurs + // in this if(), the else will be executed. if (!setjmp(png_jmpbuf(png_ptr))) { png_init_io(png_ptr, file); + // Inform pnglib we already loaded the header. png_set_sig_bytes(png_ptr, 8); + // Load file information png_read_info(png_ptr, info_ptr); color_type = info_ptr->color_type; bit_depth = info_ptr->bit_depth; - if (bit_depth <= 8 && (color_type == PNG_COLOR_TYPE_PALETTE || PNG_COLOR_TYPE_GRAY)) + // If it's any supported file + // (Note: As of writing this, this test covers every possible + // image format of libpng) + if (color_type == PNG_COLOR_TYPE_PALETTE + || color_type == PNG_COLOR_TYPE_GRAY + || color_type == PNG_COLOR_TYPE_GRAY_ALPHA + || color_type == PNG_COLOR_TYPE_RGB + || color_type == PNG_COLOR_TYPE_RGB_ALPHA + ) { int num_text; png_text *text_ptr; @@ -5908,8 +5927,8 @@ void Load_PNG(void) png_uint_32 res_x; png_uint_32 res_y; - // Commentaire (tEXt) - Main_comment[0]='\0'; // On efface le commentaire + // Comment (tEXt) + Main_comment[0]='\0'; // Clear the previous comment if ((num_text=png_get_text(png_ptr, info_ptr, &text_ptr, NULL))) { while (num_text--) @@ -5920,7 +5939,7 @@ void Load_PNG(void) size = Min(text_ptr[num_text].text_length, COMMENT_SIZE); strncpy(Main_comment, text_ptr[num_text].text, size); Main_comment[size]='\0'; - break; // Pas besoin de vérifier les suivants + break; // Skip all others tEXt chunks } } } @@ -5941,35 +5960,62 @@ void Load_PNG(void) } } } - Init_preview(info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG); + if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) + Init_preview_24b(info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG); + else + Init_preview(info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG); if (File_error==0) { int x,y; png_colorp palette; int num_palette; - - if (color_type == PNG_COLOR_TYPE_GRAY) + + // 16-bit images + if (bit_depth == 16) { + // Reduce to 8-bit + png_set_strip_16(png_ptr); + } + else if (bit_depth < 8) + { + // Inform libpng we want one byte per pixel, + // even though the file was less than 8bpp + png_set_packing(png_ptr); + } + + // Images with alpha channel + if (color_type & PNG_COLOR_MASK_ALPHA) + { + // Tell libpng to ignore it + png_set_strip_alpha(png_ptr); + } + + // Greyscale images : + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + // Map low bpp greyscales to full 8bit (0-255 range) if (bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr); - // palette de niveaux de gris - for (x=0;xwidth; Main_image_height=info_ptr->height; - image_size=(dword)(Main_image_width*Main_image_height); - + png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); + + // Allocate row pointers + Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * Main_image_height); + row_pointers_allocated = 0; + /* read file */ if (!setjmp(png_jmpbuf(png_ptr))) { - Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * Main_image_height); - for (y=0; yrowbytes); - png_read_image(png_ptr, Row_pointers); - - for (y=0; yrowbytes); + row_pointers_allocated = 1; + + png_read_image(png_ptr, Row_pointers); + + for (y=0; yrowbytes); + row_pointers_allocated = 1; + + png_read_image(png_ptr, Row_pointers); + + for (y=0; yR; + green =current->G; + blue =current->B; + // Cherche la couleur correspondant dans la palette et la range dans l'image de destination + *d=CT_get(tc,red,green,blue); + + // On passe au pixel suivant : + current++; + d++; + } + } +} static const byte precision_24b[]= From d01f573e5724ba02b4286bd9e405e98abcc6b7e9 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 9 Aug 2009 18:24:03 +0000 Subject: [PATCH 69/95] Added a picture which we can't load (gui.bmp, 24bit bmp) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@985 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pic-samples/gui.bmp | Bin 0 -> 164382 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pic-samples/gui.bmp diff --git a/pic-samples/gui.bmp b/pic-samples/gui.bmp new file mode 100644 index 0000000000000000000000000000000000000000..93d0991ede0365426354e26b28c10cd6b8abd649 GIT binary patch literal 164382 zcmd>{1zeQr+W*--+iBNYYwg;B9czJfr+|WhfP!Fm2Z9QsC|x49qJRoW*h=Tn-8G}0 zbGG-q@B9DV_dWA44loR^EBpT(KF`iR6U>amcYasi*S$nz=)w2p$j?mt_dWhA$A3TL zzxU(@;FA6H`dm(q{Kx(Do*>t6s$BnRZI2JWnfb}ExnGR@;p;JrdwjQ~*I0%24#i&M zmh~R5+DY6K!w~64diR9Zw z@K=R5th!cfdag+KOp?;UsM+>D-|6l6<_C)&lQcdV@xup$XT3K-UgGnAf1vya-^}=U z=p!j6cZ+V`z5nu`|N6iG`@jGE=RZIF z^pij!sH&>s@p#F}$qyesO!&)wKuhm&a($%Ajt>`On)O(U<@9|0lCn*n^ zuJPRh{Ta&U^E9pIYuQXywirG~zt3dVFTYp#eDsp9#;f$1VesAZ{c{iAUgVj)_-yK8 zuQUbkbd8`qi)(f3qWBI`eESH#ZKS~VRG#xN|WqaZXDrEu_4;wJsy#Fk-zSH!3PgLs%(VV6Rp`5B< zx=7bX*<_vaicJfbZzgcS+HW5;uKVzmzSU%XrFvypiN1Hbs%!kB?N?^lp8igI%fNYNUyoP*Xvmy@44e)m z8Bm1H!81P{25p%C)hP14#DNb1e~!OeIw6`m)&@sJF=v@|0H&C6 zZ`X*wb|cta*?)#<-zj=vbHGI9VKcNQE;gR8VXa}l(a>(U@djsYM;8U#BXcbdOka6m z%1Y-MYrW>}xV+dke(~v~#a=`-*`X4UYj(MEZB&y(RLj~ZzHJ2Gny}eyb)(VhM*Ygm zRVL?43}pFT~Z zKhK{(fBg6{P?drwnE85?T<`HvsCMy$Y~f?z+&$@dem(k!FJRCIP5hwe(Dy#+5}W^! z``~lAPy5P!F-)$jd%tJxM*GB$B?v)TGqi`C8MRpCt**Xu0^r`5*6c^b#! zXWO`sSZdX0lJb`$7l6tyN6zmtdSUPH7xx*rwBH29-s2Q{!IvMiguqN# zXrQ2Pr@LyC)1G55Uj6HT|M!0-*sQ6k=_;F`_}Q~(X=!O$^d}=D1B?PsFxwHHVDrnN zay@|q@SN1H;|V;Wo}A;^k$^(cz8baQi{Z0B{bte!J%-AC(o^mO*mM@0NtMm_5dVB8 z_emeQFNVnV93$6D_)ef5oWqM36*;_6On|9|Sf#H#QOp6e%}AUhtJQAHW9uyd9MM!i zd4s-_H3v;r8#Y^enxdJ4!CC{`ovU}atvwoO=YHM#O!T(MY`63pzoHhOqL!nnbtad2 z;$X6Kn04iV9D}g3mDlSnA(yvWh;E7?wTj@=qlKMV-fV_*YV4o2Z0ALJ!!0A`>VGpu zdGJ&ms^3gifrR0t|77L9;}v=m>4ew0kSgpf{AvD-N7?T04xG4biJq?)f8@X3=W05dl?x1gY)u&@yBYI=G)WK@b}2Q)CFUkxV_F#>j~R&C$1 zIG&t+hmbKlOKlDDhCcsx?#F}WKkPUDy|0GIecV&-eOcJ#0`nnqJw}TZoa7DgqT-@S z*%T?}B+Y))^az-<-Wr(H*@Qt~4)1lqRIS0&HNT%{G+)z3$8w9sCTDvWKl_tc*ZRlr zj4trVY6vP5gjK)7;aALGA6wd%P28g3lc5%rZ+NM4<&6eQ!lr=3Q^Y1CRCs9_-e?w@ zuYWW`(dNiJy>&Cyt>EX5|G{v~9Nm$#b%x1n44kaof8sLW`Q@m^B0Oi~>-!etA{g{B zbF_6Wx9o8CY-noXtht14cGadsG-1TEv$KneipuE^PN1K-QHogyo5F<6w{pG4P&BA| zwh4`>2Sn79*>?ntEUN(|ae}MF4;nh_!+}%Y$MbwKNDfgAiG`#mkXT^elYBqE93j^W z@ekZg0;afVGJ{USEt0HaQMoQMMnY5mHWU-NB`TVxh^hKb)fyzPJ!+o83}p)y6Gsz= zeXI9*I=EkP^pD#gU*wh76kJZgJYV$^mwWYz_`>q9dgNWiW?Puv$W0?8egh1 z4+oyjAe3DaHpzJlE??s`yutcXsip5T6X&b?n@%d5ZJMWUIZbiJ#6`xV=jj4ZB((aB zSLi)f;p;I=KOaHV^W&j&Vb%U5o-Fub8KVW-))_g4Fy+7h{s*U+ZP|qI$?k8$cBiJM z=I7^ER8-W~)`%RGRIZE!+{&F9EMG`{NZ2J3h|M*z$!>?O2Mnt%U*(|&k7X?8viD<&d z{Z|`;Y$b%BU z!j_PV7eMk{#f#9&RyG-rfRRDU;fWJv{~YbmBEyT7CReIgT&shLw+L@q1%LA<41F`K z`D<)KUT-y9gV4)m)`2N2j@{DP=Cy3~!MXa5lN3ymG5B`2*1*Xs{U$2)9=Gi4@0NWz zM&YxOi#{2?05Lv3e`qK^x2|%^f}d}vtB+lvw^V;kN>=`lKm9C0r8t{i%^|^R!_&;n z%q%G>0ho=AjSUSAm6er@ZUjhD{LS}1qlp}53>?=AgQ zrV)>oh$fs(WZgfPd+!61_HX|Oiun=Y_tSpFqae8gWQ>Gh;#KgpTmVMdR3L%*By|#{ zw5E&TX1)=LZGH=)Ibfz~e|f`!^16d(>P}p2x=_!?z-EW__G1pNLF>-mK9W%EU(^C5 z0Va-+asfLJEEDX0T)jjTo{Lk7bI9m2-z?;lG(!q?Lre6-%8f2pEWca@B{jTQVR*6J z;6j-}SUJcwx?E{=snXy=xxvK>{jf6K^Tm4Siu6JXbOLj=y^_^jZZF>8Gt24-k^_?r zwvE-^Fk01q=tA>>GYyeK`*MupXGBBieKL%sK5>9h9BqBGc5flU&mto|>n$7hx!2S+ zN!W35NRfL-ep5V7mqHdt9F!4RdU%=;O@P_b($d`A46gt(3Ne-P3JjLG#YY=%(6j^h$GJ*2!YX7DChWU{cLu;z z^vT3sIEQ^#^2-6I>cM%c0X*obvVX3Uf6g+$Y&>k4U)D0;Y&=-eFAI++?tynY`^9Cx znM!_HN?vKpPCZ`c@krsseMOg8g+r0^HU&*GJ2+f%P46k%Uw^Lz4gF%&;?KS%$$84@ zTo^NOiVqWitahm+rhMS^K~t0!4D5Fu^@3b-A-On`+&RZ47Yj)ti?PX~AcQ@Le;}HC zJ|Ae~66Xkt5FNqXa}-OQ2u1BZqH!n|f)_|0;QDe1t;|qDJGSx!Scn}WC_DziK2npP z4a=$3$1ky}-$1`Ur`(>&6Wvc>SmzWv$-ousc zdr#BpIbN;DIF+xzS7ebA+^qYqV`@$s;^a9t5)E!45K*l@7Eu|+zV zAoPF!=YM|r<(HQ)Uox_wdQ!+@pdr*@Q4kzVh~}$Tum1I~e*w?>`g(*zU>5Pa1d`m< zR)Y&<{y{v%4?ZJd%%^>b2m0l3xgMjafU*$&_53^&Q`m8$nBNn{Bw+TU)*M;)jb3X>~& zOT9_ror)c0(+5JCEd{qXzDvO;69+_g8RYfE{ppT=qct`ToMqB$l4h?7YCXrP^c<`7 z^>+$L)Z_Sa6sf}F^ThE9iJjn?&i#1UynYi^rY$o!T)lJse)sa~`d9z@k<-VHPQd1` zzyA8qfBsXPEGY>}E_DQngb|0M`s0s3q9TuH0H<(2;e;ZM)X_7vvdPY1Z9kxdeo62l z0t#uPc=nwr*H2`2g;YW@;b4vr7dD&VTMaYR zYR$h_=rs=3T%#|`7!fevqGFQRTm+`!khw+^m#kQ%YpZL$ebqKMtHb9UeDAqFs|+q{ zRY|6m3`|Zp14{T_1ugrZRxiKAql%fa)C1pe$^*nI_fwI?3Tbo3jg z>^NYC0n)yt6JVlxuL-Jvw8!_$aC`+$$0&R`X6Y9r7s2j-K5EHlBNvXItFLapxwyO< zA^C5=|K1Ug;2wziEQ)y`_l0XP@q$DU|@!@GA9%rHnBq6)_`S-v74VM$S zBxIGOq>&`q6cPG90wky#g6RGj}ipS+PMmD!o|*e1^DAYMWP2nBNn z6w_$P9HViI&E{*b*0kDUvcbjjK+x*bcaA4jz?6eQz{oB+xx`gw-?`|>EwjPmMgiF5 zz>xyio81Lx0NyC|VY9@a0eCKUxi@9C+t9^U{ibT;tK5g+sR0iihQ8-`RUAFWDt|pz zxyM)~I7t1csEwXysJ3ErUU9{5zsW=;BNS}@@y8#~J~)ih18qnlz(k4&{K9s_2Y?-i zVghaa;297RAv9uXq>fUY?XyV*j(DIb*D&KdQWU&TrVi#L>R^tM`+5XPWx_=jW{jj{ zGZC=Entw)&{uk(fYu}o~;=lm0gl5n06?-B!M=QrPX3g6)ze&TeGkGQP4{%beI{%4nXC?19ZnJPi%{jAq&je##>B-YYUZ2rip!;hu_l0 zKL3?2*AB!NGE>eJlkv!za=4r*2eHx+@boQeIha&qe3{4mO>tyoIfoh|W>*i))eOqj z4#_hJ%`v->V|^*d?sB&E<(w54dBzut4Z=zcE|f06P-J>8*Z5qXRuB*TN<8@zuhgX{ zAI;x#Zi4=fVGGO#OxGGPO|$=0&Hhs~`cKvPMqYF946PBf^~V0NT-n44twrL+NRGZv zPvCL_F=mt@oyY^BG7dZeBjO_bux<_nIpD6ixENr?qsP~ znvz%Y;@wwgnC>0D&~)S+eH?l2sdqnL)gw2se zD-jnlxg=nINxC_tIhc%mRLno2v420x_-Ki~62w1DF{w3Q{Pp(=aNnP_E4SEekn zIpvWc$(^+CnWB3b>Cr*6Ob5+29x-qE6eY_gMvfY`dyRLTMWt}lwe-_j4V)J#0cL3B z3uHDKs)3~fx2y(-=#qBjlI1rMN+YLJbM{7;_$TtbFWuec>SML>kgoN% zj2m6in%+oZL$!7>YT|7+{WHvT}~L zt%~JtosAv_2QHa<#P5nL@hxZx6$Ly@A2~?jTEd8fN{{SD^mnv%Fkw;^y)u-%GL=B3 zcb1xOu7)2^C#XnrXcv@Y_^L$(tom~_C zBs1u0)M1a{-LBr%bq#`-|NP^R|8&Zoj1ORV{{H*#&_o2?NDcu~1W5S7IkXZ~A`>bu zm+YDGi@1@+>2Oy&jniSBf!ha^P!t*w)j$x@-bP|-EZspB^BWPEG=qsm5i(5gbqXd^ zOj>9XE=)t3T~aXtCT(e2#7sG|$9-B;nX+|d67Ldx7f|M3r}S?GLy}C#3egH@B<5eI;ZJqO5K*&iWOH1mXX?yu*IDTrGi(+ zGOtV(2&HeXrhlGxV1Zt6q49-Mv&-d{*DF@vL=SxR`nxsT;_CK3XgKt=(KV^bJ&o^? z$@k1|@#YDmlG2b+212*8m~4n`<6^jwJ`q(l%@42qi$J*#uPTV;H)7!^%% zJXc-fxj(49om&gn4lu%e%b2^AkxK4i%(%lqgHT`yNZAk0aSKN!9>)C&PH+|XvQSEv z{N`6fNx1!4UlMU6p^1ov96e}hXdux_BAT@3g9o7O-Z_|DiRnw);Y2e==;mNyzNn!C zrd*UUTJ+TzQkd*DLA@VYU}1tlMdqlShCoulWaQ3Xfu>Xd8a&%z^a7JmL*QfJ>qL$|nXcM4BuHv&Kj^9?o;{Gcyx@8jxKSBo_Lc|cFqCtJxU3$;TLm8j2T zsru$<1R#RW#|ldzx#Cip^^M9kw<;a)fXABM_v`mPZFGL#=$hK(p3!_Nv)MBTDhcz= zAqgtkAs~2)4nk<2AgDkPQY1KEA~;|6;zGsC&~kx)q2NS%^Y+9#{jhv-HuXZXHry%< zd|HK&SR9JK=p3x!2PRwmhuzrjE8;F#d6;{+0m$AXa6UyxyRhdL!l;Oju?)$8eK^jkCs%U|rYf-SH)7 zc+GBE0=MiJXYyaLK!}MZ&QIkwTHP#A^2s3d`SEb5`Q)hj=?XGIzbDxJL~yo1*l&cy<@Sf=YJnt^i0}p&GB$Ck?#t5( z$kz-g&?BHniK_uT zL2$m{9Plg=grPmJT!4&0Xr&;eOmIA--c(e|=LFO~yy)M*N_GZILFS#^1vX*&;g%w5 zLR{ZzA5wqx648u0s*-)ikped&7INU~L~@CAB-9gZA`ee=6P~8T52KRGCDuw}LIv;s0GJvAwln36OS>X9pve?oecWbdbF z50cj!Hd}AZ4<=Jot>>HWT;}MhvFGyEs9cnH4m=mwM+;U*VaAAG_O%5 zKvcFyW!y`oo79)o4JkGVEj0=&TYj?hTSKgaAD_)5is=wTsKfz0H^dV*ksng>6^1(aQv*zx zZ+M!}N}Zr0{c|M{%H@~Jt*%#Wh^YpWt|?9KFxk8o*lQMLlS>-Xbd|x59v?^|C4pBi zq9#F5i6FRCaE=lRNDn=)*1v#eyw*3Y7Lc|2TB-B>=3oB!d%+1dS$DE59iVb@qvvQ3 zn5cl&`5z5wZ`~dw6^OyUe>s>$N65F6SpEazbplf2T8g*TQMn|!A};a~<}tYjBh<

    im)f7yyx%Mu9`-A4q2^H|#n0bt@YKCOd;X?t6!m^P6D`@1b`Znu`jAwx)>Gb*WE zB25V+UXFC*cygQBX;iaePZt>ymN_%vrB6>n@_E z96qL^Xn{G3KOGHYt($>2}+i8jJ7Vcc2?dJ zurI!F>-|jNu1Sr1?pLqBQ)+P~PybxDvLDLyVr-J3H$0=T zg6$C{@H*cOce1<+*p#tgiI`nZ?p|DcMATiUUB`4*ZJwoKK5DjBzX@1hIuA?{0Y$4O zk0xpo3t!juMJ($);EQS%G|=5$@B1r`Ss9nWmOk+Sn)%bGhv#k9R6*p$Gx3@;N0 z6X{DWB+o-i5bzjZAkmI}RLze2^==tWp1I9F(8@wSsDxG`H{LEvZ~aC%o4&bxav(99 z)p9bm@xY^+O)+H_*Yb5kb5#7XDyfxC{991b)DFmUyuuUw_~zAfS#aypV`MK_QZ{K) zDG`K*N8GmAbV$Wy-82Q0!BbVf8vO&J7s4iyPKqaq*^z2ORtecAc6>*uM08I|B|4N6gim zsAxW2(|(@WE=32AjaQ!Te9*vwiQs2rg1{!Sm;)0IrmA0#ZZI-Kh`}o@u2-YvefW9( z$?OJHV|??P{R>+H3WQ+3bpWM2AxcJmxx&LYr^Pd)>FBe%ZE+RWH;VLyY_={~!aoNM z$7+5VHW#xS|M|<`BwR=0ony1pf@Le46wri(yD|5+A3kMZy>*7tiXrkUn63xJTJa?G zO(YnS)onN!k66r3BYIFQ8sf>o6w4I>Op-2Q)3y4sJ`UDh)R7u;w08Ia3iX_oEQ858 zm}EufxMcuy@N|uDXX}n#Y$~t0c8>A3#Wu$r&L!@-U&lq|2!0%*`S#IOoZ_H+O)Y>& zqMZvB=GUs$-K{t)AAgI8h_T5vy-Qz^(S}Xj00F%k9-(iwWy(_H-eVWH zT6QL&OhciML?RiIXxw;hjT=j1BD>B)a=N;l1V7w#EmUcQBRM+cuC22vaSL-WQHd00 zFqwl%*07IXhQTburfZIzt3Q5;>2wXdxyIXmSarzw=#?$eW$-I)XdV;eUuCb&cpSVXj-+Hgo@_M0OXtuKdYyKuR17xV3nt#T+Yk9AJ?!v;0F4^cVJs51VVmjLAu!0C( zpVF5b$;k;NQ|y1S_u@D0b6aM(X4o_}%+2N0P{tGB%<7ReS41ZB5ip4<$LfkdKV1t{ z;#i5Ad;gis`^u9HCUY<`!>jK&MNDNGEU!Lhp58=-6*Dx~=x*^?>3YHF$VH3bREN8b z@GeOnGm^hLvPnOzb&ipuZzkpzm|t(efZ_G`8V@JKe7E=)2_Te2D@z0*l!QHRJ2TXY zR*Knij!lRrBBE1i%}1U#Y>ln9x>2li4&9&5b#jhUxENpZz&9S6h17q&#?97rtN7*%Y2quM&MiGta(IWJCe;};rDRa!YucdhaUueCQT?C&%?#v*swY#l+s#N=Sh@Or(_ zV&;^=J3~{t5t2igj~T(=5YP9><->dvp#+=I&2FGl8kk<_iqB|qPi=O7+PEjNesgTy znusd1OU1guIcok{%6^$>-h-Pd&Zeq=hSg7xlcc;nzqPA&-f*eOQmimi^Gt!fyyBS+6VfE}2|TB63M)agJR!V4~7D zQ&qp6sXbwl@eCDq2Vr`d4eLG9LiHS6zI+1;vK zbsdu%DvU2-v=Z!lzE*H9(w(glkvH)=bL;>0pYAs6ZP|Py-HcC2*s%A+3?;KKM|I9- zdx}ZYMKrtQLTI zBBlArvj()@ZI7?p8e6mFUhS5+`mJ$Io9;Dkifh;sU%T^u<<7)XyIWWYf)#VE0t&D5 z)i2!~5sCYooi=ZFtef%i2~N9@$t%ia)4AoltR#tAIh|m{hOvv5{a|aAE=T16vqQP; zg^biVg?O|G&XsP{nU6`kgi-lf(u1s$R7QN#XNpc=OfVudue;JKOw*clVH%bI zAsBC8E-@z-^HKXxRKl?7k+ZcYE3Q~#ec0ec%*xP$RoCk=*ODU1v57&f%_bKsmHmXx zINOJ>Kr$B1)CzIFmOg?2o(Trij)NzB31)JD$H znXtrUvGrkNuji|-)mRd_6o>}@w~8jlv8wpzGB*=af^h{}Aw`xq8}094juD@PJrqn~ zW7}V6%30Z+yKMVHOs~Z*v9#?>c8h0L)7k9$vzawsIW_*gCPpQj8piP`adI*Tlafo6 z{95}u^+U31Uy-d?y75P%*F*Z`_(cSX9m`Kdk2skq=#3 zf$>G8AG1?1MdAp3Y&}rCq+qV>kAX0AEc%hHez2Vi3C2mtPvx@jc*XuGl*_A)nXf-_ zso5MITLZUPfGINHsFk=c$AeA2^G1;0QIwFSb-Pis$RIQ3Bj->c`fAp)9!yHGy znPx~nAs83Rb)Z8-KJDQ7$_0`(87$Z~hp{9gxJ zp@{haIn7*oGKrfz+7-MTxq4!3K}uUD!E z<*^we#9DZ#*n1|;4er_dKkOd^*WBj@UkUA%m% z>Z-X0_6ioeOnj49-KeLg9D7l)?I>E=glHn*;lPA?s`zFvzkmTRRhXOUN!WZR)gA~U zFht>#CQnHPlpVB#9p|8r-NJg>NtLvWJU*a^3{LRn3DuBk;+gE)qtCEbt_BTzj(6+U z-fpysgo}-XeFE&V+5Bd`?)g#-`C@n?Y&W~Wd--#Bt|MZhI@SPlWlO0u4%?MedShaE z(znl(B&5%Jh+&`Aap zl}M_X>=KWG1Y^b_s6;$IbcV*Ld3qC;n#!xMUSPIa_h|Ua3&qG<(mW7&eRa&&(#Wyr(0e-q!6DOrnNZ z-qS%?EevC-iQ5=d-0YoGcPg#?_|u{z4|oUSvv);jZMt2!F0y=WWUXyv13Cdj5-H9j zw36v2zM!p#>D5|HU_$K2zMbj;S;fsibqkf;i!zs!Ew$vvYPVY*lFBCVMBj(~4%Y=* zs}T_+XVYse>f_{iZNpOxVkw+qe;tF&d{=1WVT7g z!P(*ps*Gf39!?`VKH-~OtHWQ0TJtQEumaogQX-lu4PH4d!Z{jm3&VDwhp|Z&6KqOE z)9fmXWc>3R&*s#eN+~<`r0~dn-mW{D>m&2*ZL9SawCEfd%>?;Xtu1yz8vJsiB(T*$~!({0hl}I6p6jBaVO76;` z^Gv6yTF%k8Ut+Pt(CzN38x4d?nZP859(E0EqG?z!h-Y=Rc=O!~bmc-ckv*hq#$||h zSU`=KnugU~lUlG@NGndSC&@WT;c5EiH=N0=a(iCl@}%HULhhdE%#D$GcDKq`-)f5_ zxFZq?^#qStd+c6#pG(WMsPk?3RCgRNUeH- zQG?ycCNt~YYDiY!d0T+v+@DlSn64IbdgdiYK>A8rS(I`&?nx z7R+is#KEKt3Z;{Q31;bySQWf-g0j`(6`QrUoLU)@V~K5^g+^T5qDeXD>(X90G(nhM zD0GY}JNT&fR9d5t?4pSf8*m{3ijoo9tlplXyax%62 zbY`_Tug*8W(Icm2_hbH=yDb(so8V@FZ>~t^bhK z<=pmtor)$2lgP|B+PKjVoxwEt5%S0qouE<#CT<_K)LOx6x5?=Q1mk4KQd#AaqqSK* zC?5u0!#~URM#=7ksuRf#UfIpQ?F}Dl2Re`?Qau_qcfE_VP{^i)K__xq(BPR->GHVn zKwS3jJL%hQC2hO)d~3w>O_6zUEh&`@Nh|@lUMIw*cenw zcI09z98e-SlG3vFZvFDhmD=Zu)r0eq$wdeRDj}T+*tJ6n?62ni^jmj^>cClCIx*k_ zy_^_w4E4kqZXk(E%= zNvb`-x$pGlNM9n-N0(P-5=x zyJ_1aQnrLY-+J@;&fBT`qBHi~E8G%O?Qo}Y?VTp4n5Lcgn_Sac{4lFaG<>n66HH+| zmfpPPPNfdUANpo-ArNtCd@@j`)eOqFxLnlj{c>QF^Ewf*BM*<(4~(Dzp>RJTqd3Pc zvauNt>AZPc+j5J%k~vz@22R2%Miu0Z`eNoiN-b#Rlhi=9ddM#Z(-ALae!WSFJfU$1K4E zNP%Y;%sTT2Fq@E0FalEmGo*~~lh@#$QhFdRXGdi6=Ic*4Uw^hOB6)Xox^rUA@h61{ zhfbx`A5UpKmeJx@EI3~++yJ2?Byl^k@fhv5C+L(z#~qQ3XT$@r#Xz z&(swmr7;@Z;K(0FzjAHa4p>w-NCVHODaJEcZjJ zF~oBuYuP&TE+uZK&L(gcV-tza<}=yVM<3_!zLU23`jai!o@|dy-WQwc@~GfsYMEDV zU1&*jc;$;*Rjen~X})tPR+4d858FO#9I!=4+;$d77fjZgH% z!l1Kq5KV4Uj$q<3@38X7{oGx*Q@7nr!sWrZY-BT$Kng5w4y|}`rTS%f^~)P%4}_PU ziYA0Ops4v|di9k&_9G)`5}FvgP9+aa;b3fHHWs9ltZQo*M)4cbP6XXViJT_h znahbw|Dt9Td`=`49ZtwO5SMl2L9Sa;31S;i4;V3=_9ED?MydA%Hbi@xjZf1 z5?yK=fmKgU<~JG;p`&dYL7;L#E+9o9#E`@#S6&CLsIX%uNN&Tw|J8j15jjGkq1+FE zg{pRiO;~oUBieG{l#b=rIU1H@<{N!8Q-1*Jlry;|P4Gw#G0!r#yA%$vz zBxXkkE4JuB!#^T-qPkSh~!D+B{{QB0(M!X6R$=6 zR>C+9_JKBF4=N!&Z^$7@B!Q@dN!-k9)h}V$FH=;*s>r4t9UV+Jk3B2d5mVq8Ns34| zBxBzQ0mXV|94oHZnqICjzF1-qR%8%bsCTYFJ0xEQ2m>Z7$1Iczqzb_SjX*y9-o_BY3dy>!Zk4xy6v1oxewJV4%n zh^bH?I|Nho0AWgLsG_5ucScv)Bn#7GTQFk%WJ(i82NA^-ilz*Pm?O6XHe2yTHeMDy zMV6hz6CNd=1jlQ*i3Q^@@Kkfi2owt4~O=+X_*l}>l7 zFe=9}y3XltEv9=r-7a^EDshY~UKdfcCcM!4TApcGwss&kD<;y(T+wAd>1%Hk{M1dp zrv#O6sGEdM^ne^W6}ZA_|3bYr*a-#dIb@c>py_%TT0LN@cE71weK96svU8VfPoJz(yt5o()9Y3>-nS#a@t>G?RLLuA=_7ZRERn<&0xO!Lmf2G{2e zXEK_JkJ)u=P9&9P-C=^oZ91T6Ws|OYlQAel9}+q@8J?i29X6RVQUIZwu;!G_SHuJD zSTq@=ctQkGXS3@((yNXqR~}2LK9O2`4BKVV!#%CuBcs7HtKKuS;dEyGiR7xokC3>? zv%8*Y7?P&!i)t<*RKX|RB#hVaukKv5AwlRH=_c@mbJ#JA9#qyZ{lXY zA()I!8e&VZ2^^48!i^-EB>TcQs4y*j;}DuiPF!L-cA@c@c?P5A>W!SMJ9?hpck>L!Ei#_G)O4l_wm-9(qqAnR+M0>#_H&H4 z80_@0@r_>TcmI3sZ5@F*V9u&Ludzt5qb21g}%Nvnlb$I=b5W67&ffr@~WVqBXb5cP7-GfTu}CQ`Sx+&duabXs0@Bx|H~v zGd4+7gP@y^m6HWe(q2r>di%Nwaij-0x&$yuiu2X=>Q{)_nOSdFJzJsc%f1e>tz$atRgxv<;C+i8!x_2wfM>kpW& z*==OI6NjLzun|*PymMr3f#Z1OP7uI|I@Lj< z1e>@Dv(6%JNGI}1Bq-`E8xMY^u}KvZ1YM|pb&ZN94Ej}?PhxDgeGj-r7B<un;6u*U|#M6MH+PK5K7FS~if!rRbI5)@I#^OXOk!yWlAB-?(K<=LGk=p^cC3$h zOYI)Sd7xjfP`n~N#|z;(gUVkVPN`WHUZ5UCX2mP|rfY@dT3oMa`LTP-L>!Xb$)D3r z;0ebQVf&?RFM?lQJW>o8K(7k;3M{1*^YR+cMVt1i)P6nJmF0cU1vPCj;{>uy;iyrUW${dD8r6 z*@Otvq7c|@SFkt=pq^L?NeGo{+=*y%u@Jx%@xq>*Ie-^QY);rDib*el>IGU=KQA@K zi6`OS4>>^|pn@#Kg!4cy$<>#5MchSRj$VRI-=gN74=a~n%EdNHN`C1Y!C6KZ3ml?q ze*CT5D(oDU?Bp%5NdZkr1f+yh;R#_@bg&1|%f$OPc;!Lql^#ho&d=&qc7=8b=3L7W zT017LJ|mq<7$ZdtLI}!Vb+y{=W}SUh!}f$G=V#3rwubDH6cy{_E}GnAOV8S6lfyyW zxC`-Qz42liDg=``n^cG|R=v1TN%vu=rj`jA*t|rw5~6vzir{%k7`i~_q@~}vH^aar zNS349>19Y6F3Eu{vT(qNi}ad&IXrny*!*2HB#RhypES+jEVHXcTVv~g?Y`>JU&W>v zfKpBq6XPE|3`na#@uXqjp(PeqYi+_C>>?T+qnmc!Z*fU#!GucM)*;QvO2d=(wm}U$(oF^|SRiat z-;+F;Y|=~g5eFPf-B{MD-|!U3fZJZN@yZA=wiD0@?sT9ydz)- zm9m8D!goT$Gwz+>&EO!5-04dra-(6GfJvuEPNUszIGc3GSno7Iy7GGQ_Ivfe{kO6S z7xlqIzqIC~&sugRHVju>*OtveOC9Dq-(&U~1NAjLpK2eE({YQ}_IRM}`B>-l6YbNF zbp z7KJjS>qBkz>uzUijEnalmMO#*l(p#>I~s#f1@w7u25CZgFkvc>jx%Z6C~o`?Js zDVRD9#rzX&(o{Ksf?3C3vMmeZw+Pu338-)q2ZfQ;(Ah!By;Si6jhUeGQsoO^NCi=t zS_gf2PR1a)B36V+asbI`(Lz5{ZMJD4@hA!e!RT8-`#s#}azR)H@hGsz zg2SC6t&l7h2w@`_%kbh-!QUl;1pD3%Y(Dl&;k!KIYaP5bV4kJ8ZVp^%H+9Pes+g&Y zUa301X%@j**5`Sv!}4q{71~}eS#!PA_F9?E_43u%D{XIJo<+069lpbD{@N(MO(Y*X z{%wvE9C*a{NXNiR0j&tVsZB?!97Q2I?VwXO!PIMba*$FUnV#YjkGWj+;wnfdC$w)^ znA8!erx>1i&db%Wkmy8y^L%H{CLRnnA@M?ox4mqZkWh5dmkBOZytq_>#hp!?VoLN$ zT__#lkkN(Q)i+D)|MhoCAiaAw6Yqy-3%ry0&i7k1_lFNzvX*0W&?37@Ykk=S{Uu(h zS^?>fH;cDM*X&7b+WVks-@}I84;psfZ`>B&wE14shM49JF)iz3`8b^J^6jGdwo&|b zF@kN0{3Fl!r!$Fe(n|W9vMI9ZXuXt$P0+y(25Co^mnubJG9gYVl-%!1oY2sSSa}5L zR8J8Obr=z`8Y26o7cE0rc^f+Ey$!(PCqPnb$IEEpZ_ii zr0!tzQU>4i5r1!VrQwOY)6ATQDLA0!Gg^DctQ}Vtolc@`rYd=-t-74E_dePdnmn=v zr*rvknS9rDzDp|q&@=v?$Nb$7`M_{<0)JB+e`73R)9yAOyPxm8&v#A2;Aygxgl{gS zlkA-L&8 zlQ9ZALg%mdUcBR+l3VQ3GtY(A+&jfEBy&#!R$e!Nj({@0ZxR1&0pF9yKb^yO%iteP zCWP*O%HMIHzb%2kC62!qX8kUI(>(#4&Ev^@&rD|1|Abkmar#?llWAqUaIqVO05VAx z1@Dwo63a{ZMX(7Egp{Yma#xaHN;uKjft{Llu!;3_8)8fK&y)RMl>9R^gLAE}mH&N$ z^mnYAiHUdO9&GZ9HFJy9a}L)ya8-5RW#xUB)ec@$b-k_Z`AESlN!cseFeq(Tbis+_ z+MtqV7)R6OXLc!TQ{>g0qu~h!yB>uif{2dSY+Y|ZgWBBW$`CAhB2OkUE zQw7+K6g!g=(Ink*Z={vj4FlI##g@ogW&Jt1*6p_?5UboL=o zHbbzMxKsc(&mtDOU8E5#ELbZ0XIot@{rfZ_y<0Zp67FyJiCVrdM0tDQ(k($twgxTQ z8nSdpsLK8;T1RhbpN=>1eX=q%W$T?h_a{{Wc}?60A6hADOT%BFl<&pkyJzxUQuqg+ z^7lOA?|eY)`^I}jLk~YCTR3A5^`B)Ee@xoz0X88?+&g(&CrlsNWxLNw?;_qM_ed!Z z#>2QkNV;x9SVLGiR4(w!X;_0CQXm;@jP$#bUzXLilE2B$m&~}o!#F)AE^*bNz(s3M z%(Hc$zvlF!_1=p%`7hlOqI&qM{)xyHe(??$p6|TFJN~rFJGb$CSE68aA%XRK&S;wDMdgasyl{RA;3}LgqI0Vw^oi8|< zBS2_$;5iA6z~&CHnaDrw8au%{2Z& z$|lS@Y&v1{Dc>WFB#?-wDLSZ>bRAF8NDjQ*yK^}^2*x|b6KtaXBTJuNP@&*lDapWl zA`-K^X7CSFHaEs$jSw;Gho10HrU|@AEX3IS zv*8e_M|V2YwF96!RLs|1lnx&z_OvpwDT7TX8F*U1MDfZquhB84R2%tCQnN&Z9B=EL zs{jAjS-w_;l=;e)8xfP1n2uPueBO#3Iy*hBJuf?5PS|rN&Gkv4M|uUOTKE&fiR2 zv%}@PMMhI~)~c;{wQxJX>B_ys@tJNZC7#*Um`o8+gmHa@N_N1evm=y5M0|;Gh_IPQ z*gTTN-}#Wgh7^VP+fcB4EC8FHB=-(BA)0LtsqUC$AVF0IIc-*Pe3xuWh-s&-NHW@V zzzfq)8c)gvr}7%0n|kMSmib`>`^;x*%GA2W(1LM(OtgWWuHlHl46Z+ep#$;gQpT9y!v7M3<=Rgyimw zsr;{G6M@idZQGefPP#i!Is``^j7~b0TI7>g8(7r98FBCk2a_H6Vh5J+{fk-xO898* zlF%&5rr-o+b5oqa{thW#?tRF2N#c_nQWlEo9q49mCs~%)q?6X5!6pgS>7sH8Ir~em zO7e(WJieXeQgZDDZV~FHl%kO6ONnnAECC*WG6%!qg$vn`;?xe#*><<$zcCg{48Cw} zvWAV4!$F&~m-j?Ic6(Ofol_G~)PRtjQ%nv_gdhIJ0`ELNsz69(q9q6mRyjQJM+2K@ z^T8&m4xz<^210_vPxx+BG^w-M#+nOLN?l=-M_MP~$3bQOG@Bi^X|w})H5!`;iTEdX zda!jzs1e8#r!$*Q`m4$WZrNayEM%jlVz8OJ^}mr#% zR`?eR^O($hzXoOzqDX;zRtu)^q6Fjx{UYncX&)sG4H@+1%xz=IeCaH!ZM};mldx=Z>6~racNABp9P@zrlxY0xS&lK5o zuzVt;-Zm07%Pb_`F<(wAC}(3-<$qnxGBNDx%>^qqt8Y2x5EyarUW!L*kuR*dSgt6j zjPH_GyD_d5o!E}CCA%M1AAVZ5|55G!hxLb_HJ-%im_p%HbNaV^MRc=(u!*eux@f`n z1bCXLR-%&rHo?T-^R2K+)|iVJY^#!?>@L#5ENWt|lu0qgfdy-wGi^Qgr?cM}# zneaDD(C*F#!fOTd93m=z`=i@N$+b-j{Pl4<_8!!;-?zkO_bRt@yTc#2J)xSbBp^M6r4hnZ6C(R1e~OzSjmv1atwM}=I z$A-2a5X>%QR7W4=3DJUSLl+Ku!kr6DvtB61+H5Ow|9s-6tDP&3VB5j;|H zq?c%br>(}c6P`T(>p_kLiR=w@bSc!$PHj5-ww02ppe|_*R<~N&R1L_%@Hy}Br@DmoM?nhcre&Jl3KqiyjU$rXwxw> z*7!nk3ICVBkIVU2+H{Oe@C&^%*KCu{&XeoIZaY87@XRRn&8s7#Sq2+T(nY~#e9Q2B zMKRH&c&0A(N-+&gwZE3VJFd(lwJxBzMU2gt=;b_>%Xd!VqYwnqM85qjTZbW$%_LWa zV0LZUCCeVsbPJb2>N=amg=8o}B8d?fU6tgkqua&kll+y}?~+wFVbf^?3p$n#B-NW; zEmZOo#_5>5tr3`GbG4}I<*(hiL4ml}`B$=eJqb{f>N+B#X& zR%_ew^&yc*;?q3SOStfyi6+AHbnUF zNPQm9B8?sZ^T?AH_f!l^Xu<4k-yAZ|gI68uj?`4nUhoGC+T6L3Y zgH~Xs#Uv*^fgXZ_f6Xqm*<{Vh5dGfIT#uXgY(@&O1vWcRubTgd9vc?q>P48UB*}lT_FX6!zuOVHy{jIq7R(>6;%Dx zv9Zhg@B++!@7~R^{<1h7d80+TcB2-XDBA6}^SQbY70Q$%A0GD4X=GI({D~l%HW3BL z7_rYr*+0ve?mU7m9Ox}rqMl}THPbz%?0gvsgoFzdvB`KjSv7P#U2ynW%fUy@&Wz3U zrn8w%UYU(vnN8kV!s9hUJB<@qennJn#$Ou;-Y3u#r=aaQV-xQRIt#TW6+t@eg+3<{{w& zXM4L~>bp)*rqvbR-ssYnAAkS#kM5k?^%v+S1|OnAIdrD>L=9`rZ6}=0-*HJy_sl3` zg&>a2WAHS?Nb?{*7zHwqClA{yV=sE_hr?*adSLZ{v|aH9=gV7IgwFnY_&X3bvk9Ar zpOEo2?#Yd(QtLfa>&~R%sP{~(qmVW-NSUoiPm;6-c-BdbjyPt@MP+@C7bz#8g98(Q zK)(!GxARKLS5UzGqq4Y=WV(G^1e z?07cu95{7gg^)s3+eoLx(*~C`dnOm2Ni9B|RDjDfX(hh7HSp6E%m zyQ7}&jCiu+=A$iF6SiK7-+Aldk%Y|CsTKab#?Ji~6ua;yiv-6r7@HzzAG6Q=bCrCv zl`!}{5L?scZn{-)JfZyGzjj;3^KG+vFD}7y{lUHyl}9aHzQBC@isQk%ZaqAiROp*m z!%{~ao33fKbTDZazPkEhc@{Tn*d_xeSE?1fVdzttdYWF$CTxoQESvxY#OWTnn90@T z{JhEKX~T(U*n+&q{dtw!vkJGT74A>U-Je!?Bvk=bD5-ZQwiqIQsBbRY$r6N$L5dPH zU9%=ZjRZ1Mu7XYcE?I)x(S%r$8w*th!gw%~Li}Rer}fRPK85+D&+|_w7oJKgbbrD- zc0cRTo#)#w$8I0d&6i`~+jjwUs@KCM6gwEEcN^5YLnTptv_Q~!{I_WzJC`R9V1^RhywnP-7_TVt+IJHCRWwVvG+K|fzvdmXxXW6 za$Vzd?MPh8napxD5VO^jkPQ4~P|t;3#yVc-6v4q~e9Vf$AUNUXED_E6!FdW^DGX1I zz>NJ*D}e?Vsv}8*Q3_rKEvK`aPo#j&8kdLVM<0|p$LBl8@eal09FERD9Gi1AA>Z{u zvD@SFQ^_@F(i;#X`Q|`V#K6Q~2}%cE#O$mT2HU+0G~r()6iumNGI2je^S^?HE+uxW=a7IC}TFYizQ6?DNxiAGutK-s^o~(+U5Lu6|C3PB~z-{#Iw}jfZSD z99Xy8b^l5Kqk&hCoR8dhJ<;_6?`&pW=ekK7|NQe>4ky>Hi!RX!&eI4k(7#Y_daV}w zJeXW6N57nsPnxPGZY?_g}nkH2+;Wq*5YVzRb>$fY6EHG7R!_-2Oo41Gu4ogV9g zZaF7rp3SZxt(tTd5G*oq@XANuHJNXO`3IQIftjw>k=WykZX6WRY#iFkrdmM8-iMXK zS!zr=;onsVAf0D&nog!Q9D7#n^04f1T;9Rx>;qA0`yx{JMx^YEOg(Tn(>XrR^?uRG z=T(r-vl-Z+x~bKgQy&vdK`}WC3((pHu>BiZvj)j#QZ_qX=E#gGLU^jtR5uBmG(|7K zo|Mk987}uS4o5t8j(qGI`SA4Zhu%^51EUf{!(-1~zJ1E?^1+jSPP>kouiK+x>a@&w zje?$?j`?P%-N#S*hxwep>3k*DB`)JkdTl3c(&j46JA})5Hm}(wwbtTBxj|^Lu78g9 znH0@4$vR#sI(})W8LRlDsrzLZgk+(y0fqK=zg_U#WAp!UcNT6{ZEM^A8>G|PVbYD1 zNOyNPh@^mkA|c&fA_8_7sMtv(Ep`{^KIgpeclv$5>$}GoYfYBOb{n|2=kprZx~6lj zHJNM9-@Km~&luzAiFRdUZ-9v=qv4?CxzRnVHV#4h0UELim>7+@af+w`NaZMGw^0o^1$MfNR2`Mu8}nta_PMY_1LNI}((zb@&20c)Op zVKTjAc+0Wg#0Y&(oYTMoEtB`cE7CqDWnr#=gfVh)*P7pX4E`4 znDiV-cuvg#@mN14^^L6l44dRv08E?!R#eY8H@4+iciNE~S%)qa9llV0;7s-5Gc701 zoj7;>+|{o3b61=89L+3k^odNf@QhM7_faw4W< zhQbbw1J6Gr<@r0Vj5SYeB5#ym-Uw^Xv8f-J;+@x&xUVzs+DOgl44Vz88^)wD!|yOF zN5=Jc3FqI0a9|#P8+i1MbK7kg6lTy-kmPr0qG6JDrc?cl&i|-?M^i_p>|4 zx11bEK6oQ>@8!6*3-PVz<9A<7+;=tgNOwm2Af&VS`a`f;JH+?JAeyvWSx_;lkdgkG z4`Jlq;x_O_G+>1W7m^pA&xV4FxcD2CP3A)2Pyn-ja;l)`>DG&P>3zu-g7iHr^+=n$;c&Kah>}LU56jkER~HtEj^<* zrj_KDH?%RhOuwCiEx7(%{};fcqHL}hfUCp=zQLeQc7ir&VZ>LFz+e)%f?g(^WM zY7x~M@h#fv$JQ2IvaauQZ@Go6Qg-KqU;g^9->n#Ap4dFuab}?!vF5BT)^Rb8*y>-> zl63GQ5=b1I{3$u!7TkJ^A(C6Kzm05X)|{+^ z#!ky)@b$X1`*GgYds{n(QxA7<+L1Gf~?+Vs@N~-*o{Rnto~^7t(qCVMXtA zK{i>*1IL=+#w<1k-{QI?36=azJ4BNt76tQ0d^Bdw6h;J##zOcyz(h6Gwi}P5j*bWK z84TXl6S?d9mfe@j+B%wcpJ+SSapuy^fw4R9e)-eu>FNGkW7~HhP06YD2v0HhSg&T{ zu~N@zxt5)#xv#x%O!St5t@-u2^#{@qTrRwJw{Aqhb-`K9YSgB~^F{oIBtL##&B)Wx z-MyAMCk;34(vNS_i*3@2Yu1ZzhJfmAK4_4A+O+Jtebb=d?$PMO6Imqb`LBQfE)#Fh z6Pr8Q_H$rj<0nH;vkh566}wZ9UMapYR!ek~_?x6&ee7-V@VmSLGEZUr`RP!;Xkxia zM2O~e=}%a5bYx<>=MAUtSC3BZy!RfPOgbr>uS)wKXJ5Vp+nspedTh)2$j0`F+T#(m zC)U@Wh}v;FVeggAN4mG29WA={0Bp|KbR@>9ZGDeBeoVr#$=+oWNnRH-TU+3|NT3R$ea&0VbHC;VmLO1SDCCd^|Or4 z#jv&1<5!Dsj@OPprNh>y>TgdIPxBU;$|&_RnKUzqgy-*&H*(o^->e?1t) zX+E2{?@DIJP~L^xh=`DfC!OqLZ%N2J7n>|BVQg~PGAhX|?ucQadVDI8PA62(%Cz$p za}KM@L4kR-?!7G?nu_hjWc82z_e}Wh8uM-$a;&&ynsLZv%ieVxx37(^u}*2WOWWnL z?Esp4?jh%Ghip=JnQz)@oY-uf&}@{@j18;QHk+;c%(oseO*?3lcgnx%de+4|^`nGM zj!IZ?uHlE1-_Bp@2n)M_P44$%RrlJlm$^5eZ0dX%e(XWu{(GLg@4C0$b8en+*gkAi z(`#FI)1#?7?$B`Y`N_Y3`_-)HgG~%oQ#1GH*hF$u-a5o4p)joOQ0ghLIZ;E|#31yV z@##{`6@wXwdx>abJ!!K3^zmumgU^sqTSs%6=nJxM9f|9FSc8ZE?ps{2U2H-*0X6{+ za`+9mUzT(~$UHxue55<3^?XGAsi2BO{w4c-i+1}L?+Y$JxW3^OEc@moJvrxZBl}t2 z`?PN8O+AwEW78yhp#|;WkyQ@y>WA2fIe{^by#7eqOAb?r8_Q(q11ec|iuX#ZncsK% zzy^ep7Ph^yCSc ztY(1dCXY=#f0&~JNxp{Luc~i7D!DP4eQt2$kzT(YUCwn~c9l1+%5GScTrn#=Z&7;A zx9Mui;lW@2`p<7Io%6xw@l&T)>br1kBDtyTu-+lLG-CVFv{TnhyCxZ%4R_vDjZI^A zY|OC*HlsUv2~CKm!_Ens&?KUXWoco`>nA}aGLLUjg-qr<6aW+XBp#cSFN?bFXPy~J zJaltIb7xT15dvmGn^(?Gue=t&qCKHiM>aHdKswV;4&+_DQ*!eWdND~i(dbm;ZBWQzs~P_i50a; z=Ir=%;IV1%J&$b5Zy2Q=(o5J07}bJ{RRRlD0t!_8^GSRn*!=TV0}9Z1Zv_;p2AAr_ zHCbdG58KsO())~KkWfj%B#{r5d*X^vFkt}j+wnN^s-GXdMSU0&taW2gD+cZtULD!m z(Y0~!+0fcUF8OU18GDSj>^ItcKz~!K-li7&{Nw9et`(mi`^Pty&iP<-&w- zH#J;iowig)?KpwX-_q_oHDga3@4TwJ{ib4MnoNq_hs-8c5+H11XnP z;AVR49jO_A1umeBJ0HA-mkKs{;W?jB5QKs47CgX43hYqSEGx}1zn1|~i* z116lckC<#;KPd4rX^lNWmDjkm4Gn}45CTtJjqILR@#iqn;OmG}FC&gW@!xmHZTo;# z;d$NIChZNinh{l+;SkMAt@Sl%I?)ZfF^yG#e)E)KA!f&_zF?#c1<>+k*DM zoj0>C-K`pWRy~BC+Q*gskE#Zq)sDPq7=76|@n-vNpf|na&RYbQ1WY=n8lEO$lU!#Q zlGhF6&npKW6kHuiJ8>P!KmW2;r!D2{!nbO9$E!H6m$QvnWgjQ!yUieJhgVtqmP5V& z_4j{$Q|X)!HXB>^ipiOBx{2hbwpW5%Ms-Zf$@J4*Wj%LlDVsGDZ_0%>yqlq%;fb)MPHK@|t1cbwU@?^@QG;R1?h&A_Yr z@hKjgtQ7eDs&e2-9}XfeU=t>C&MU=2 ztm`VH<*-o4^#`jBYN188+xEpYU#>eh{;&V}hDCH=%_agNyMROvOl*Kn9iJqR>^eMq z8E3o7dhgVakyxl^{7u==bbdejDc|BX@xoj0L(i>tOt8v9BAPY5&O7=yogOXfK^5}! zj{9g+C=4TP62)XonUEwrg7oIQQwaZyuZ*Xk>W$oSCb0aVd(KYB)EeuJrDjoi#*sND z8}h8;iX1mrdu(eCDnA4~k&Vyp94oo;00kiRV{aInBrU{`(D@srgcocg5&1b_@>NoR z(}q#v+cw;u-i~$$PXm4qX{;LpP_XC=34E3+Wv{@txcgp7&%KOu!#P*R>nC0k5vL7j zh;QMt;CiBbrf&2}MgQHBn`7DMdQuKwjBY+2QnNpxq%ELyS9smwxVF<{;XOmrZvlo(M1Dz0d~H#3^AMSJmKy!s}xh?Kk6hpY|_pwN5P5^-q?!30-2~ zDye2CrerCmY%Qbjz0xDyIJqgXroG_Az+eCQZ>~&z-Z#FQ%`=_nw5$VXv8n5~2~&9B zCuW}QAu}b=s^Xf7snT0SF)_gw%sS>K^gj61v~dJf@>`!pU9aDs!L*C_N(R9);`-O< zh-YjPvrg3$Bf@ZR5n0s^KFqs#EBWx1@Ykg{ehB8R9o!wf*kv9e1a8kV*3ho^zhVterp-g)Mg0 z4dcL*O!Y$yI(;bNIN`{s{D#8jUmf0h>PFnIcK?z#yOdJH@N^ZosGm)Jm*~34YT8Mw z+equU{baXMXG67X(UC3tZ~p18|M+%2MPJS4v6CH()onjy(<`@eBiQWhB}GURF9=GE zP3UGfkxmdAcSS6L2M&=p>rfGX8X}HB{xW{XHCF%uiHjT`2NU8EI+)bqO za994t+vPn^8pd8X-JOPAn}q=PU&1C`v4_OtpMfMkOe{MAbL36U(DRyGPpfV{tGe|V z)xa2)0;xf~$}3DTK2SIIyn6U?Y0vGVYr|O` z*P)N-Z9`q0TTY!zdX;T*vE{}BZJ&)A9G@`!Y5G(VWa z(}3b{L9s?TjcGVqtbeXHeJzn0C5iRr~3WwWmgZqC>X zq)ciirYlI5$J?So#6o1s;k0XSBifOECmDFReUD7)F+PBm6caq{n+Ib~O_cOKX}(Ky zNc`I3wtH`oltOn?@}Y|XC9Rh6`5G=UD=dQ*Y{KQNLsyvi|775~M9*!BuG^3L9?MPq zle`(np0wH44KTkL5JPq(MM^KOV z661Lau8n7Q_Tg5??>!sUd@N%75sd6Z2pmwcJFub+h1WsVdxER?1y=3BwqIGBci|3? z+(x(TI=Ae4r>#{$(j+=eI1);&z)ao;QA3ZbIuQx^rKJwMb+r*^3f^Sbo2|Mq!=x~kF0WmdDB`zq!hIP}xhLg9;2cNevHd&e6Lj=5#qz8GIZpG|8>6}@u>zB0L)PK<$mmk-8 z|7_&DRM%~hwzI5;gS3YILT%?IdhRRC0@dB(EMp3N3w9^$xePWd`=2+APc_{^!kOkb z*${I6*j+*;=~kpc`e(4oOCZ6Z*A4;9XBC5w@~(`eo$gLJa4u@+$*}rEA=UdqrEf`# zcR`b9?sgB_fT8QQ8po}b)=9*3w203&iOO0Rkzp9N1xRZ7BxrcVsJcceJ4Gtmg{`s- zT5j&U3|gu0wrGvhLIx(0OG|($yxIgE#zHHNQ4l7kU?Htxi^2wZ+c3R=WCS*WWxF=+ z>%<)?@4E;80hf`miNK!*mY}t){~qFWD0t@CUd)l2bnrZaB1BWDi|{LM@hNEbDcs>- z-sV%e&%XGGc~QGv)uj!4`)e;vexn&>zmCn5?WYB^?hI1okT`!6adc__{mS8&<->1^ zZ%r2sO&1SMV`9znQFIVZ6PL5|Z7|hMzoTz3&W~dgO98vK4kmU^Rt>$Nxpy`u<88|W zbgH~48@QKswg>Tm)utjCaanCAab;^+Ek_W#Pz%=0PEy52LfKke*-Bc&4q3SsmLUk+ zJ#t!N+sw(bV#ePOD(lbEHI7Af-tR% zfJ&z5_$4B|QFo6~b%|1OTCZpyP88EJXob1oG9#a#480JRAmJ#h=^#aZsTE@riYdI> zRCpDsR1{rpik%C!9G08-s=LORN9TCwZI9jEzOA#b6dC8yr<`tLlnf$O!~~Ut@Qx=6 zu8rhf8G?h6(a{Y;HyysPanI@4wo}Mf$L?xRfC1Qj&b{%RNm-{w)zyHufs)SK7>qgZ z38b$cpT7Ul@mYZouF4FXdrm_*DsDZl7RUf6S?|!k&k9<1f*l&Koa8vczwYa!1ZIz5OO`weg0m73TiJ3KkFx zQ6(!-30I3yNp!?qM9xf9!9q&i{)crwYF>#BX?2l}9hsdYq+=c9GbY}W?q)Vd7q6^` z4|#F~=5RBy@oQt#<__C=Y@*JhVe}0Gq4I%;`LO9{dy|h`-q3s;@p4erK0m_db~u18 znbpqemB??~q!e2v7MR6kgG$5D&3b{*%8eSHacb_-aPbuELKSU8S6cI+kj zfCRqeB5fxbO?y0f@G&KnEYZXi%u&f82D2__%Cqe9W^h7(H1tq)jx>wP@hNJ7Gn;c^ zpuGPsVUtefhuk|NB4XC>yu#d*cnjASj%U%0afD&Hmj<)WVFW=}+KFphPTknraWkW{ zcgyL%kOMu|4cASoZ}_$K=boMT$F~X9zfLzBcJ7&F&^b1df!MgWv+%|kg3zi_BAVz% z&+10m=5$W)R9^2?ZrAIy%P-?Po`xQK>b~a@CY<4mX1{rTU+js&oEvv52OlH9N!UaV z=_z_?rfDYbX;Ie%hHrZ0H|YkZF6KKGFlR7ipi*1`o|ieXZmUd0u&rdZaE*(CU4-d| zJm2Cyn~(JrU%y{_>ow_F97iq+jp!pmk~OYx5*w_|4dbj3UXabH`e8`tlj5$sxfe&% zPTq{))gIn-G^7S>wtD2jqaw3Ie1~NNtf1}|VU&m&8e$||8>i8yk zc)`u_Z8sinzVbNj+Oyog>FlnznK!4iZcb%hf0cImSwhEy(8CYicHbAwz+)VS zd)wf)t9Og~9@dT$mz~rhArRso@1e(V=o9vzb4sgLb%};G=gxsh2DB0lqPg0H?8hFk zsqMVNJV@6+)iJ$3YG)^gyjAo(uSUrnon?*(Acy29kvI!XE>0)Ij9GFMUS~z$A=X7}EkpRRzB|AOywgXS+jB5MMW!9UDEaUTF&Ea6`2dA#_Pt@>?)gab9 zQh}LrE3oOm!pwKMu{W&w4+d^jHyx2HTBzj+Jf+obW!3R&hdBXc)NEzc?P2Se=(<8- zSDN|bIEaOO3wOk|bs!y8)-#EM4g~20Ow!N^hU7nDLUgGjwfYKV<@Ix(K3IEJj@@)XbZG$y%d7)STT-Rw^EQy#V0n7`6IfCH0ktTZO(jB9dc zLfD4erR%!FB3RQa$s)GMuXH~~Zxmg*TTUuE-_WU&Ko(SQPTW3sCr>>wrn7eVb@jlD z%HGFi-4FAxjHI`BCmy`Go}`8L`IohLmo$6i)H`KX+X2tSBGZ^{u;~UNTXX}GwY-r? zk5O}tRwAAz6151-gOIO8RqQeopP!99e?p#7AB4L8pzpd^#~Hro5%(axNC#1qnqVV%{tURDo0uk3qL()FUB5xCn?9nQVKs=G44?zxIR}o3|Uu_wPWk}!vDAqXbcG3^g}gdmPcXd*`pYyN&C^>VBib5^QX@V``Qe<>My8GP)v#r6T$=AqQ~ zJKt!8@K@;O{=>&U41_=jJRMc14W79?-Sjy)COBU2x+gME_e8gza!IREbzTqe5@52%JsdL| zt4u@{Eu}Rbe=-eFaf{ROOEw5fGmFXh%4@}tx7_pNMb{rx55Ah2ZjPs(A8P1_dwx?- ziDd_#HAAlmp8e0!QCixA2_D9?FAk<2yPA0LLj0aHh>=3;4j`@Rm|lf|-C=W?ZAz(G zT&`KnHuN~^hiuXDPsI8n2#sLq*Z6FNLDKSy2e}C3b^Vi!!qe7;Zq*G)(ho{m8FwC;sc(Oo;duY|a@7feS>7$m_Uf)ubG{2=94g=N-G2AvPx$ z7@V`2Hx7mz9?R=`R5OZdh*vNi=*g?R^{}%4UhS=iZIdtC;HKYtSaNj~sUvh*_!qYt zug`$-!k=5Pd>w7?Nhc4_RVKo6rc&y5KN$HaJ4I>xr6LKh@4wlSR&-_M@+yO`t*CZXffbt`xe~?J8K!Mx{R@~qn zKr#86$Oa^nYA2Kh&e_n1hI%P{02@_fZ~Tu=U=Bcxh;?Zldi9rod}leNqN=7Dh2oE} z#2%Pb7#-y7HtsqNKMRw3B%HhJ*fwlhKfq1G#Ssc-v20!JnLBl;F1-5&VK@SF)O%K7 zhP0dGsBXZ_K)c4C>>PfWhc3M%mt%LGhBZf#jiO@&>@{CBf#+;C7qC-;Sy!=MV&Exn z7op*e5I9lOGeO5M)oxQ|X!Q}yvQTjO4#p9^k0)E02*O9o*D0rDqkhKjGf3Yj@@i$h4`63e$cyp&+2;nfoV*^>dID)s%r>!p=gFA1Qven{ zns|+FIf)KVIE*OSK-+Zi!lpwPP+he7=;h5vuWUVW4T;FC&i>qs1E}Ue?h+w3+#yaS z5$6y9d6fecE`}H|6sXNZH^fY%sotG?UHI_Kios zd}nNC7F5s4CU#=6Uz5npu=<0UXHX+|w`TNNcK74hv-i9YjA8Vo3C66|k`i~~Oz#;< zx_G|xaIo zSI~=vYu^>p4eZRgfr&2OrCff887~S4r<`}s6gTd__3B%MLtkOj)AA~RjZL_mS{`wp z*$s*NJ997HLb(T)u0-ui!{n>%?kCY_?gSm12tGExp<{B}&4+apFMuR@7ary4Q%t>` zcXc@J#Ff}xr^0IYMb_*|Y&;NL)a1OS!aAW~U0AxRbF{3sGe~6CoZG;EKRh4gH>Fi= zWp!MCHuhU>9kSXcbfq~`GQnytu|^Tu-UV%#ZXxgd1cnFm`Qktm+~6P;+=*?bs@zWA z$7V(S$efZwi?<_pq$*L3#f}q1VN4Xs?EGk1W0144I;}Nkob1IqrWd@p% zNC!S~-CyWgs2+P))c-E$=2X^=Y0LnfdF?IMUCiksi#6qUzb)(~i#(tepx(9%L+Qzi zp;*usQ?carz4kwRo3nzD&e2!@HSf~-ZPTD zj$t;*XGln(UITN{U}QA%y_f_Qoe~Hni@PUtFAl;{McKAfdKD&MFbGIA4oouehb@j% zMJbF$;36$2!XTeb&flDa%~i(GO)==EuG>#W$PfB0Gxb}l=Z^NXp%<#@tm2D9YmTKH zxQ^KnKVTD}G3Xd^+^Zmo+%`6NU@~B-uL?;ex`~1j)X$TNwrR&bfrSnyMu+}(EG9dN z@eoMcpf47ayJGg&*R&QH+KPgaS2bveriRD{xzOX-Are{A_pWT<9aa&mgzX+8>)fGX z1AFimm<7d|H{KNWze>9JfSafvg*hF!r{{fq#+S2s(bzTeL!ILGNUK<*CKV%rgQ|8X z?!Sr+haukma6f%l(B%Z1bow|T$%>qK zgN;#If<_%Wypnex{DMYy(y9}xu!L*UVTC?ax)dcl6j4BYkxqYyQYxm5cqQ&3El~lF zWU^%5T(#&9Kt1VHITi=)pDON~F6o~x>wjA|KwA0WJ2V30AX#_53af_>W5toTwIgrq zr~?BZ1{>Iex61mb3wz!a_P`r?UN-m~Q=*&H^MYH``u^Lm|9gI=^P90LvdUzUmZP%s z1{Bs{Vx;wr$59=Nj3h9u9pv$qzkpq8EUJyDUPY`sX&eU){Xf z!sS5K4i3Ip%Spi|41+c>7PIiu&HT4aLQYz zfIpaySDr^lnej|8iuBN@&n9W05=^?VPy+zyKp*8AFcM%XjO@c?6g;g5K+k^t7|9Y; z3=%NQ2d1%rcLf7*=pB}^s~JWkF!FfBG7gN#nIAs$@YRh>V@7?<23^sIGX7^Zqp!+` zU%BlWWtJVUC&s4ccdDc>WfPr3AJN-A}#<-4yIkrFar0rNt?P zTv`Ues|T3*BtV<0zBOHWi!5*h)x#1@Fwo!;n#h8>_g~2hI3HMo88-12E>6v@S5<@0 zYlojVPGG>*RLt3Xa5h=Mj%iu2Fws0p=a;gH%1uMZaPH>++6L59QpswGo-4{|P*`IS zu*oDc-8?$iD!u>%U9iZdV``awN|{Y!v3Yd%+MrZabFH=rL_Zuv?Zaad3~6SFut@-< zFw&hIq4*XPP_n@k7SXz*<>Ga|O3rZ_UPQKp0bchXoax^D&-7)f3^%? zZXUeC*bg0)|Fk`LT(ICQx8^J_C;Mv>$;;Bxe8Q(4AD%3tEK-fl zA8NJn`~xie0<(@eDNl`0&12vCm+Iz$BPUkqI?voyYHI(${}MczHD^%}ha{X(x*vEV zpCqhcDJo}9i^EOC6fGrGY#^5eXWHO|A}65fu`#IpK;f0Uzv+Kb0TRTM+Xk4Qal_{T z`O`@G@Qb7)YbKjT`wM8V0Z%J=U0YvtZg`B4sAcQVlDT?#!vG5hUpck$)`_xg9C+~d zuk$6HU&?0do@0X+WhSC%EwtKf<|I*kyxNp=JfWn> zDxo_wtorEY!#6Rv*JqeNqD_1@30Yrs|GyMTK}cueNecr$I2oqb+@BMaZ|oHGWVyHK zbYmn{N+%-c*xdQ(7oS7pY~e?wlm?#tmIcZE2oglRP z@w~a5U!DEOxtj~tTN;O$|YvU8KO5LUJmQM3|TX)*&QRagk< z&qjXsDK*}?tzOwXJ#(6)nmSI7DSeXFr`znmyr_)A zh&>F+nz46f=n)zqy_@&|5luQdA{{$T*kmP5Atxt|_-vx?W4?x6ei56P-Cf0mwsrHHbvu$(#YB-VU}Tw@t6XZ_#|i@0K|gfh#xB21Ks z1r0ujO@5d}(EFpoWGcx-kk2Cl@cld%{!7RmN8iz#hA|Y{kZw_Qj+PI+F6bfa*kTp% z%sg|M2k-hyMP-U{VW?bD+98LntqV=Qzd3R++)9 z6R&fnsj!>{#=CK6jzZ)W))DF+iJIP+B_!D}INdv^1x0k9jpx^d9A7D^KoUowTFJ~b zlBBG^h^1CpzKX$EKZdcDqyw^Y@OfF^v%>Bd`CYH_yI$vazsc{JqP^{?@_3hh<6TbI zyQ&e|M*!&*2!tq`e-1r$hqLK^dq?K0WBrTRtZ8cd-keRs7g0%G*AUIj^ZZRtNwGmO zGzOJI#N{+bVo6jP%X`eIr-YirGE)o#560LxWa-z1W=1!iM!=3_%x4h#2Z|;&->}HU zWV41GK3l$;{+FmE$~^|(aSUDEFwO zz3r^$y%xGj%SL#G0Rr>rMt9z0YmFm~gi_=Go~JVSFJg0@a|EX~-_HhRkR;m$8y`%* zk}|K8ys}Oq6e?K?!M+o;Nwx|5CDk1l>bT3UaluRsayH>MNtOAR@6}?K_}}W%6M&c5 z^xx5}^PNiKLefk=a~MG)=R8u|4GaFZYIwS+Z%Uv7X}YKv1t4$H+YT5}bwv6#hu_t) zq7T;FK0-!HgLi@_oeYJ|Tgq&Dde>8He(w<0!hG_}-{vJ$|9mz(=bC5cdmxlAi=4m7 zngBXLD*F-2=p1uGeK2NjpN;F?nv{TTU!YMxJ4 z&)-uzX&D|5Mt&H>BawNXEC6TQW9Y&pvM5l2MD(%h7ODH7y_>xHX+cv#+-Hh8DMbB% z&H6jjD1&FcLnufZdNDs~q|av)y_Jj9<``c2hvP{-O`aX+q*DM)!XrVF_XtLhO}e6B|S;dBHmmPYNl2KS*4K zn0;ox`q@WbY4Vd}$_UdI_GNsGh$asxy=rkCd;ON)WElLs0T4k3=77BOWDJ zLB|dvh@s&2444d9p8A7CUMZ4b-x0%eraP1Gnb52#(M`rC^EdfyhMeH1k!t&IJe;55 zL!Ymkr#jBat#zAy1Bs{h2e=F)F*ddkBb#eRy`>i$`A z$M0;t__(+mv)FwKo@BVjZ{x{P1GxA_bl5=j!s?S4eY{tilw?&(0E89M@smI_HpkIE zh9qA}$sZ->Mu+LK5v8ASs#G`UwCV6V1=+mz;Fo!s_3-oAgiY77oLTAW4@Xk)1V9sO zWG8hVsZHl}li2YO8s5cDf-P-4mIV)sZD}o6k@Cqt^-Y3B_7OFj(274!k-JotR2Ho5eBZGYgt;dx2Fe?FUMJI}9k4x4rBzMuaxu_J_nHNjWDjPe;|oN`Fg#3;Jm z8PR;k+0odqTV&vCn!4Mk_Iz^3or12H6$6NlK8`0RNld2%W$XQIh$gk^ED9#0E4c9% zvG!Ku{z=C<&HkoRjxPc*vRkXc4I!RcW7p zB=+!d#)XFkH=kAXV>arK5=yKmWAnEJ6bR5kK~PB|kxU$E&ovv&!M&o(5Nr}LWo*tP zn1Y9*NRseeAVMdqjS3`AH<`Z)Hu?T0qILh>!}HQL^!aRJK_MI8xDSc=4)<`73TP#V zA*-EZCZ6pSH1}kWu)@r$+w9kgsn{XO6JP=p@C#}_gG~k?4$gc4`d@}2aaw63i2@pNVFRMf6dV(L;Lq*i z`xV@oaL(qeSSVoc@c;bp|NZ(j(&y{ug$oz*%Nw}c^&hiAvzY`^${>Z23xNbTX4Df# zUudNT&CH`J1i4Pq)42fko^s|AYR=1@lh&oSdRCneZoU?Cus^-?ZgCIhgC)bq;D@49 zWv+CgV1V>dLJ<^GIylF3mO&??34{K*Y*H#Y60t#G#6jpQgOTtE7}1bphXtn%-tI1v z)1=E~k@-5`n^cLGaPsq;wf!OcNB^K$2y9l?wFvX2W}bc2HvgDg`DqXuduS;A!lQ!jH>G`3 z7omsM+i^;i=BvqSoZT1?Kp&z8fzYs&_}9_ z$ODj!6kQb=Br>rkp% zGsnjl>1NyBLn3s-`~NI31<#h*amFUcDWjDnnJBhgwuyXE(N0v|Swz{M7Kt!mjm6a+ zRl_O_x9nS&+-jD#$1d-fU;WkCqZ1idUlw$|!4w5mgTRvwlHjsUT>bHokEFC?}dqtsY?E`n}SJrB}#(}dZ(+XdJ2x= z;mat6^s_XSL+tA}XyL{To}6P#Lmif{YJEhgL`Y8N-G2Pbt|z2n^37T6g#%L5y<`40 zh^A3(zvr&uzt7XU>R-g>=`-gP*0~GZqM4-2f9Osslr$V-ib-ni2(V02$&Zq=6jODU zHVBZ=_Cy6J_cMhRtd_ZKRg9=qiKtcd%Tw~p(~7FIDm)u{@Lp2qv&^f{i+kTx4#NEu z%ri0RWO~XYRKU=GrWAewrz}}Xqi>R_f^sJ3 za1jXJO(ZnkesnF`)nYht%MmR$|nJDza#R>s-!g6mHz2QcxLAf7Ps z9GeVP&JX=P*hF~FM)Q*Rhk2bWsmh|Dd%v{adq>+Zt#p>AR#x1>r8UXyvY7msG{Ha! zL)1g||FN~jNF(_~Wqyz4#WU9SOQam?N$}*Sns_#yT6VI3rJ0zTvy4H|V)JNWC4tnZ zoSBri=fbr?3)clLG79~{e1n{4md?gjr>dJ?b)AuWE^Tff%)NZSy!ROC#B`S+jcB=+ za{6}mm8Ye>FRKUNd?27qL-|VjAxGb04`q|7Cl|aUz9Jz!B$eN`k7KSelm))T1W47x zc($HYVS!>SKL#tdZ z^hCRy0a>HsKcvyb&x&6!gq!1s@cm8ZbwW&ubeae&*-L19h-rKCs^#fUQDu8%JTVU~ ziQ;J{R8+xw(b{0m$QtW{vjO{V$DMuw_cOKgVP+>*!@5`6_4ES)WitAEsV6`2PIB*z zeMT$Uk13R1V=m{C>kkSpPv%`1&FZ|Bd3G@S;t*EAD($+BnR^qC^?KKwF-&Pu4k-ND zW%Ca%TbB9euM8?tkKXQ6d@R1c{n^x?{`S>tSAQv+?Wa4{Exyxgq`4j!V-moiPICpq z82%JpbMVM})JSL~5U`Voh^0OWiKfDewqokeLKqN72O8m3Sl(J(-3dLK0vRThg_=sJ zJFRp~vB)_abm(dLkw@WsMk3m}quQ<~AMMY(bhmcs!^x8QCjMJ!rQk8giF-?DOJdV_ zVFU&phcWW5YVcL@)q7c|hfpAzD%SKxd zDF+rUcSu}l7Ab47VToK9_wL6j1ad@!IF*G5HvBU#C5$wC9~F zBW5qI9>RQ@SY?Kk0idCq05ftTrI3H+L3;ZwESMbA+_}E~lz-V#x4gY}=`9wUn@u-0 zS|!(-#8+uY*Qkb8uJ*`WVzyptZJ?w{sH{cwQimit?`-|>;&oy9R_k+u(yHFP`>F!? zFJ%)I9~Pe9bv4qj;0d$K@SN!-|KO7Xjtb4g;{#MWiF(qkl8G=GLX0Drkid!RFJY6U zN@*xX_wWw8%2ZO*ZJAwyPTUT+hC!#&i#Az@ZML?$=Isw}JiE1HjMa$<1W0`8#_$V(IXqR;^RnRj=IshBI~cX&Z2a!ak9I>#tEMrn8?tPRezO|J1SIqYB4=~H*bzMx}mVvD@n*2U{Wq_y0nbv$MD{TAx` z$>?~?8U-&h4*kI_V!3U+f^)Khee4gIRA0+sg}!Usp^n#6@4l?=<15&#Zfq50>zRHp z=>4`MNentHGT4;27LtQehKzC^D8Mummcx)>8^Z7VKZ+t`3%3|T#0IkRdhw_`IX@?DB>vSVZ*2R>&x*InK>U2}^}X+1OH*9@UN z&;*zzdzh7{`p7=Od&TUGRRb?8dY_ft#GqHpdJ<1ldzX9;y@aaDT>bw?y9uq~zSF0JjpNY7`PNysu|zr`93nB7+l6IZKP z*X%s_{Niz7q zV`(RcHXZ4U*>y9d>9R-pY5Uxx7HNBoH|@|}U#jk#q2L&|!YuR$L%*d4o{RN77izmK z(so^}>+yqu_YyrX8BIqCWg9U}35i9%vGTX7y|lL5BE!HX<`IicHc07siK{t_so06g zTf)78VZe|oab*Wd6&opKtA$wVLDdE`nc|9}CP+%ryrf~zgU8Q57tgO?69b2qYS{8` z_>2+!Blo}ugs~>7hk_wm*hV5BH28*ss!H%g>9B~Bqo}g8sFD*P6*a~VWQ$xN7O6)sn9E?m%Ic$0Fa%p^A95EG#W%fzx;gu=@1@f+`tL-d1EQ@oZkej+dr{W)q!1W(j&D6V zu<1}&%&yDfji&=EkNTD#_AWgfSb5UF>aNbS>}B+P zV9K#UChcJ!_bO8n1#59dD@=I?#l%def)`vu-n6`N@4ZJ)KMT*VU=!g`R#D9#NunS! zylqnwDZ^M3&}g=iyrP*C+f8(k1~BBqh^a9#l8uP6qo}H@sG7Sd7StLDF`E|&PEb6BSDQmXF@K~mt}`<^3|sm|DJ9FsUB{lieEsQoeg&Hd zhg$X={Qi0_X|8Cs6_q@wCmc*DDH`G*+Q2CZv8jw=-Y$7-QDrAlH4kxhFEKSw$f&TA zqp+fbh?0}23JCQOQ}+;6bpygAX+*wAEd;yjL@ptezlJCGE;eR0BCh~nM&BO|o*JTy zpG?ERk$GyfUB)h#oc$ifNBpZg!kaF~A0ElN@_O5~x0%;IE^7$}2L=3SPRCL+pqiwy%-Iwt;Lu^xF_VtB~!6)-%j z%p}xZ&_^q#>Ns1R*hQvuQILzn5xv6b2QB-9C(r-w@1I&h_jPQZY(FD!`27_mfk$$M zXgp3r9jcgwP#Og>YM%lC_9U*d5LTJO5iPZ zPgs8xBrTwKiO40-17&i_i6%4a3`TAz;q(JSNp*>clC_8u=3KN8Q?g!U;HTo3qaR(P z8(yj%l&c+5s2fpcl+b9KeaydgB;wf9fW7zpS|;7=`t0-1m~7gm6JDj{m9fG;?g!Ig zX?{uK56IyNy$teJb1z;EJy-0!?0@JO=@ zOz{+!v!(W(B{cCFxS3E@iY=1o1YWpBR0>y{izvavO=uPieg{DV;!Z2&keR@fPSM$88}Oo@$4{B#Tr>_~xD;3;i0Z z{PH{;2YsTL+Kx=Y$nGb(rGyBaB=acv$0SwYuq(v!8kO6 zSZ5-j{CI{6DB^T$680!L&@>Vs-c?p`1I0DHC3S+O^uh?C8r}$sgjJm3b%IujHAGc$ zOxQ}^-Jmyw3J2qH*6S>5&fc9RqaXV(pX*uKDI90!$js+up9Cp5F~$q;ns9D1+fN@O zf{cPSDfUA=!&64?Tl7(zIS98OobnzT-k-qWK6X_Z`{Yj}b;Jr@NT^OwWsQF{tVpWs z82RAIi+}v%pC6abuVxdOB&9#H240XyJe;!{98b7Ec8I}YnhAqMBH5KDJ}FBh!Koyy z$>UvIP9nG>igvKw5^Dmb^dh7UA|%%Y!Pyj{VLLk%@+I7Y2K)nZH}L%p9tZ?UCUcbH z8LTK`f^0JA*d7WpkA1<+h= z(OXAvCcCA)8%x6p$_OqOyQ@s^=-m^5k={w(ZRc&{U2>DTPcn%V_%H8(^fPpu5l3w? zE&`P^$}Iml1Qzlc@-#En$Sa5Eavrnf@3Q^)JT9rcy|ALQki6Z3RWKXun&ayL6RA5( zVMTipWj9eZq&48G+buxYxtz`kO@9UZbK;6Nawfs98*;PCTmR2r|Nar_{AxDga#qy0 z{1%(|5wmaLukT?}_*q|}atX^tj2BP^m2}!d;%$*sys#o7ZZ|PlXJt1L1&8fj_TibYa1^r*`WX(i5R^L$r+iC?=Hnqs-dkaY4C? z3I2;;#K2@5#4a;t`TNNpu%_%Ps_7@9?klS1E3ED%jDSbcNl3wdfxP_!1xH~eCt)Qw zF;$Y;5LNd^Qb~xf7l;SB5$I3-i)l(dBX?TgK;K{ck*b=uMe-4Wh zSd%2Yn!A{$7a>&10V@&F)5dCUR6w-@q;x_h*93~eH(=z>oF4x49KVhyH~1L2CzMct zIRhGDivC8>LHVKwBvQy7nUfoK1pa;k5#2-YHjhneolPNUnD1f1O7x6@L>w7=EEeF` z$=eAjI70P=RwHsJ=?f}qw2q2^$v=Mv5zH~M-B3m;<}L%y5ZtlfuiajFiyD0>`_CKf3c32 zx?Qx}`mC(7=70S2SG~^pU=u@v7k_LfV;1OrI%@LEC;@_6v+CvRG$+XjCJK+>} z36`B`2f86eHGRajL&R|v)w~dZlK_b%lkhRbn>M0K&Y~*r5^COv$`Sv-d{f5&v9p<| zqJua(ik_>}mNOX0R_S$# zlI!9n*TzceM@g-V1GzG$sWN8C(uQ#oYl7iWF>gv#-aXJ`Y91-3Dj^kMytKe98qrNiQvt0Qwh+HAfzW(lMP5Ebizbb+!w62#+8&( zaroIVK-)3KKR&-=`@vt!b^FRNau)L~|*^TLIKYe}AC6=yL-i3TxJ7HP6J`HLLN7ZW@S7ujr+ zHQg#@nk-|KBx8~+jdv|GWo@=C#D;02jNt}pxJDZ8D7OAl-$&Ux%sD(OqqOy}f1A4( zb3WKaI8@cx$|p$hUUA#h)G{6UBq^jFH~@{9E!+)y9DI>TA$1|ip|GD*B{CQSZZ|}b zJoe-*?oX2}Cw7u|5#*pxoR%Mv9!f2LF-?f0mxz+HkfIHYHR;em5>w5aq}dH3q}Rnt z8^%f*L`mvLNa;sN>(gj`O`wE^7Xg;!oIVVSsPw=m0iHy)1sac5hANLis*hAgc_)nh ztl>DUk=)`Uyo!zM{G=IOF_c?)gxWNmX~tg@ucQel)O^&`dgVkC?bWlYnhEVE>7 zau-?VNSkIz8E%x+35S6e*A11_ixAg~lro5wF-=}%y={pD?0eZF`@+S*(|oI}S(>bQ znhaho(iU2#EwN1d!FtPb+pQ~YQ{-(D6s@Aw?W6Tw6Wk(mwiGq}<-g}%I(UBAys+=k z@sEZ>)X1`{PQn$Qln4;SU2OgaxxMh4*a#nXCrQeOphuX+!Ygp-X{Rl-p{u~A4Frw` zq_ft&;3eUyIFh;|Atj90b%u{lx`4F(N$wJO;%~{J4-d&u7equ7x?xi5;$W0B=nS&I~Dqm9zW@v>%{p_ohU3YRz*EVjv7 zXt|X%t8{#3k>!@9rb$0rCo4E-YWo+Ptgp3?t#^yBbxo}BOR0>{Zz^v+`uAT+!p{?% z9jDJO(fG*X8G>xWm=qMLebsV#OcR$_XDznPTWpsji@UKdUfLi=+8`1#Dy2^dMNg5Kniqm7+PQ?#n9mf>8HXaq z9X*JaBrSl`md6>wX~nBOk!ge$BtCHvB|a~9+LHV~_{CT7_`c6O2~?O7Cx(IK7MYX4 zBNUfZ*+odzS4hoAL@PjaO@st=O(z6qS{Q5+x0-f;k>^kF$)K{1=LUX`R-m+5>JsPL zC9ZW#U2DMO5~qqK4rNQ6%9c1*Ep@G5>bZT1NBt7lav9qkDCt6|EgVdfRB3}~DV_B) zYvW|_;2Ld|GK`ZpjFws(18ikY6Be7r|70GgWS3;h{crQw2La zYWAM}KY#njuVvupiA}hiYaPP*sxc>PxK|{-L5YfrBep0M^ z680T8koV9)YLWM}LkdL3Bw;Zmz$!!5G)dAR3fXuu4Ic?DA5s#69!=d~H~?fPO6f>$ zlyr%Z-^d(8AcjWt5#v7)NDw^9iJ^}km7(ZpQgw%Flcq*0^oXaShTJu1f_sPS9=_RhdSF+_t-t>Lpa1+9;-GJu-$WrNT+aIDJ;KD7oD)p!MCO)SG2)2PPyw&+ zIffs85iui4?U1`VgA5zeV=JWO4w(?v3J`(QuZW5a2Z$yN7Rj-z`-me~gfNEG5}`94 z!!Ni}V>6m*cOf`v`ruU@lo9E~BwYS;P0@<@RlYBPv{Qjr2~Bohuok*0P<%2ia&8+TQlk-mn+U=nLW z;M2jWKtN3hB`y%VI5gH;P0RIBtBqZJHuwoPgIwHkmLU zGA0`(*TzYkq{>>RFSN*zG)^EIP3mHZ=Z-uRNloGTled#lc3Q0Mu3{eI7`!<6L20ncJiZU9X=6m3o^RYpc5&f>iNFq;@<>z zD_9tV+enA>Fg)>j;%r*eYwRJc<}a)UJbgrfD%3>D0e4A64a5aXqL)!OTnt^|8gL9f z#Z*aUJ3$o`!`W1Gm(uiEx-RS|!>~nb!=-glChJZp{=nHlK@ap)47nwIoqT{Jh4kS; zuVImi_e!)F3W!=Y5bA|^A3aF;JPqgg{xUel@foD(;Zs1m5bEiHtd+P{0JxA?6DFk_ zE@iM@3U0&NC@I5Oas5c}OCC^ip^S+>!tNsnu82QMy=GOUEM0IA0;UeQj*!p}7FG8a zRd85{tc{T}N|aicAh|Y1Qa4gkClo(HT*F5kwOlHWk{DX5>9%^E zzkzdf(8m0%%9ggnXQ7iH=TY$8`D63+*>l=fLGQyQD21>``1MRpaFO8FS)n(EfQCEv zYidhAW1es?9WCoR45Cs%O5GPa|qlp?#%p7~$dvDU- zwz*w5otw@{dz*Af(lkw)W=@=vrpaCF{+{nUY>#I^G^p6AYRtNQt5(NFk;CiP+T|8DjyqF6BykT7`JNN!j^GSwKtNRD>(Iada>iw8aQ1u z3cnNq32!^2%;{wnnN zCNMXK%Vl5(E^fnuRH9Lnbm6iK^}w!Cg_rfmRe(@;uy7t!;W4QZv9Q1bOP~t~|GuCm zAi9AdH*jIo*m-rP;0h;8{7^wKRFubJLb36s#<)?dsfi`0yi75?#7O?}FRIXE$-{4?q63&>38) z{uWk+L%Cy;92dTnJBwV=Sz*N-vtqwNhc2!Nh8gDwJOyNy*Q~9DCjsV6)jGsfQt=>s zn^6=%goty*O~|h#${Y^xM21DJOgR|WP_7Js`=vwoeA*mP}bIT8qJkhadHD|Jc{^-|wh0NGbYqzPMtXB=yr*Jx4`C!aocdY%w%tZLx=wE8ZfJbREIyU$I9bFO5JKUZO0Fp@!i`f$ zKuACwN-$20iCLHaLgW@L`Pu5)6J20c1jM%N)xhDPb&o)7tzH0rnhzS!H}I-?8w1uu zrl;OAFK8?|JC>iEn)J&wo0&8_LG8Vv}2| z#}_pC&(;kCB*Wnxy&7?`iAwH#z?1iL=CS}3v6W;rcR~wN_;wGD_y*vaqn4hzN+-s^ z=tW43IaWormAE!+M_BsS(9~|iHzIXw6Y;Hr3<-&xELRC#G|1tK;gdvP5~7kX&!Z2g zn)F=aO_`@M0tQJqBeDf9m+d=mmCh}xv$om*Yv$PPg$TvTLE+_z^5jK)!PEJ;KA1#V zf6VkHrc!|FzFa!J$tq-lDGdF%C?tIKL5M73kp3)JNW+ykw>l)TD?D>oSnj^CtQ|oK z9Rvn}L28f7LQs}Q;25!i5Y$OgGa6-$(HnaVskdwAQTfXPYp zKA@?H&8=Hfy}quaf8Dmbdv_n}JMh5v0}t|d|FIMIJ^myemV+qbywN(W*n~+cZ|e1r zO?))bKMR6_l7q96w-!yTxReyuq`KJ=fCE9obxsIQ^goqb0pJ`5Oqk<+L|kT@jiI_BZRy;W(K>EJcSEk2&;2KNv>!?SL|tz8{{T_DI#+q=PBW;<^qN@mveE47(qF{2{%WQ zi}|1=GIJ?ZJc|k25ftARnzWwEFT@N60vn|CKqR>rpnw32Fb89_JP@;D+#Fv5wT{h| zV~rA2d5MCOu_Npf*Ns3b(=TI+9rXIzfn^*xA%+QK|Iw%5_w|1JVB6y{@Dgv+xF(Ss z%*N5D6aw=Q={cIDdpdzip*b|G;-gJBRSA-)-cqs}7!3F=k-78hDBXa>ki?GAl%DXk zjp1pV!$oLrrSup|l_9w+NTu@?T*oR{>FUwl7<4jcD_W;%O7Ns<&K%dcsmV9Z&56ob zR?@hkbNitq52+0KnV~Q(;z-Z2nC{PbBhmYrVYZvhGydkS^Op>2I$0Lda}+JcdMeE@ z3J%i~seBfX?+Qpc@gUS#+bQVMi=n|)dBAr^Emw4jasik-K+x1y?gCUQFTAh`?F0TD zo*BAD8G39>NJ49n@}lZ7a3L<9+{sVvZCY^J!Uzlw1cE$$e7|fRGI>VBxxVR2ThNtxkq^Z4O zXiC<-v#g)8!zB(MWab@{<^BGDEF$i$=M+oP8(&Tnk!*tz@gBlzx%;)=Xc zX`dNxY<}yh|BlXB9x%mRX`aTyu89ID7i&qtMPjIPX=)}kK2lj`VddN%gTki_JgG+# z?vawuStcFK!ba>PIqc{e`Kq~VVR|futm1L=R|Lg1u@qEY z0+DCJ${AKEkjw$qhWsGc#JL;*NCGsT7mH5(1x8#KibN>FsYpq*$W%ZJhy+ZQLpViIl+cd#bT60T$|b*6 zmtU=7Pgd}@coLzAMMc@m+B>)1ecxkGUXdaHgr-U=V4e6q!^@0vjB^25mOBKs?HH+A$T)LAJ9dd}N%; zZRevCh5?951p90XzBRK46LVL=gzSrfkvmR?x#FT;iiHi=Vjt}SQegv ztTvars6bQl|qleoaVxJN{Y>;Or75unJdoLklRDKw1Y9+AyF2(e)&u zD2c~VT>*N^oydIiSvn$6l&|9vFR&D`&D4%a#>tCiAR@Ar1xvYEuk?Vp5`0;^;{j6r z*Emhgy@C_0s$n*Ps!COQ7=!|REa`x{53IS`M>rei!D-RMNDep<*TX6htTG9!XZ-bm zC53)9=Y$`!^gBIKl=v$EjIf+W6qE^OBrU*Mn{Zn&gcwI2WUa8Ys6^kK1bZsP;kzEjQ%g={!y&4n7Q94Csn|XP zRX$}(Oep-JCgFaFxRuD)jT76{7z`!qyDyL79X1;*L+1|$ea0Tl#tE379UNIOVP3(V zu}foeYl|AX*Kfc3*dtGT&ifCz<9F1kpZ@fxKmPHLfAE7JeD8bT8y0ka`>F4gH*Z{& z-!OGiG4~*X{2I+d`7|_gPpT1*p2ql`rSO=to`n81=NN~jm$0gKB^80PjC=$kj*u%2 z2qj&L;|Q=()571K9~^;>8^LdMU2uGR@Z$EMh0UxIj5=V!UyBMNpP5}kT1Aj03%j^I znELes6+jeM$Ot9_D_r5&C{f>*|#QkQ|hqwDwdc)#{Lx&j_uy1gp<-X3PT@ zuey+Vn^^Y&m#vh{re1V0mGOWEHygNVHjtJW8H=ZtFx+=Rg1XGtWHpqaXcfI6(UJiLX9U+^}I`PTd_b`BX6}vio-KEC_aR zs${-5%qo=bGJ>*$fv56f)hiSq386;NMMk03<0BYWc}XSpc=;KHkVXWIWX)8TU7Ux# z8X&HrEa%sXyh}i*O~Yz6L0$8k!tC!7?Lz0C;#z4Se zLxoTy*i=7`ivIcp9D1qgE(;+UlSmoyKrq>>9V1Et4(8miyY}-!+LlGQ!|++@cg7aR zWY^?ZuUpx*Yx{u*j-U8Cg3Mvb&@E0!jr#MS|NO^4{_*+epMUPT=YI98U;XT7KXV7^ zrMY`FN$a*9EUI4*=S3+icv^~YY;snl_@K`Rl~>VdT3P6#n(7Wu!{yk?n55E5c*v$D zfmA@J5{;~<5vt{)i4pY)>kd+6j0O;a^`w46p1!Ds5Fcd^!Rc6|Czg*R1)5ETl2THh zY>Gby)67GXm<>GzT1)BKq-xT{IpSQghpa_rLh{Du{+Tes{zcK_o~{9{-x=78Niefso=AAb1myYIgB z)?2T?{<=FzfAgE)U`c=Ri(e3v{^Tb=`QZnbddJ17%G;F*&t(_Q0vheoZG< zh9DkIFv0h%3N=v6i9^mC=Wfe#;AK{+L^+WN!-~W_5s|Sngnp#e)QC(3$3kh8tGsQY zzJY+zS&B&vD#v^Vt4|TT0HlzL$lMFmTy({h;oWWcQVah{hT16^7*ajdx zz%>_>RUL`kBt&61T%qN~LEzlZJ4fMT15a%L%Ows8d?c0X5hvR2u%uFoHu4?Pp zc91&=T@GLxyZOl{pM3oB$7j!;J$35T2OoT3L251O%P+r-yMN(@7l=upefHU3{_>X| z9)EC4`tASzPWzSv*_ExclFKK|#&p61`8jlK9I+LlWn=|C7Q~Oh6FVq)a^jhiOZusT z8FHMeF+_;+-H2k5xMSeR3J|uT0m~sU#E7_1YzAZ-($oGZ!y>bw`Dny8KD`E42(1~E zKxMftIBpeDq*9=%Alj{PV3*yU!Ng8stX*Wgp$o-hE*(7stveS=fgunP$;0Sa>PX`| zMLtQ)Lc9!4P4eUKRE+rNS;r~yMVXare*40UjL{q}rrp{~_rIe?snGe^XPHcM>qeBnYQ!+%$zCrDu7t z4L3{`X{$GIL_EZYAyD@QsgtMsxnxHYPRV~F;)}T%Uq#c#KfV0w`yZUVSUsjY?uN2G zYLtDKs~UekNUghn@4ffldFP!s-+a@<;}0b)MK!l!$Kk@duDNNIH%H|LO-mWfdXhhC z+8Z7jZ2}rYY!GX%LXGi>QnKNxkr@V(jnMFgBS!A7R)z{8j>Lv1=?jw{p)QcgZxBoL zx6toKny)Y|kuL<-B)OCrG1KJl^ib1EI3aIec=pcFl-{64ZG4piTf`vBYP=C@a72oY zc_l?rDlNWM&;x+Vh@dYa*fWjnl)zKPZWqO=j$cD@lD}a_snkPj@;w9+BMFA?I|E&G z>-@ablIEX3`@*ZQ{~belv8@$DfuYa$3}DlF(F3Ia_{Tp!`skxGXU=$gd?$DE2umTN zY-CCX#lNS%^FOP)cc+!En!dOcHa>7lvLCvWHOI39JWGSv!iE|7 z1fF53JrlBbP0ZalK5Hjxy5PmUzX_sV8eCl#@Tz_gDnQxZM-i{E2a;V72vg*fLemt} zq0?==$zQhN5P+)QX&(ckB7Yab)x#|L!K9dijI!0w|MAc7e|Yj@mB9|8E_uTXo6a`@ zQV*OCB`meZl*p7cpMS)sKY8Y-I}SWhxvH16j+<%_cm_`O$HrqB>9fvPnjvwTQVz!O z7_Qq)L|}QfhD^avlLaI}MiGY|TRr16($H6hJ!MpTO(4w*(G6tfAqkz~DI3E zV!cF3cCpeMn5T&Fwh{=UexGPkaLo#i)L(Sq; z^Afm>Wb_43$1-AYZR!G4-HVYU%dJnCot3k!otvpq9|r~wDz4;)e{8z%#RWl1So+t$ z{`D_^`3uIB^y&A%|2-Mh?*{(;`q}4t`tL1i?2gT=n*ux|GyT>wH9Cd_9E(Zv3n@a! z7Th>tBLWT4MPj)vdw2&oCCQ^Ug1|@=`aFntHPVckMTt)AG>F5?)1HcmHY{!9_>3)K zD2y4;lf)pD4WS8ZQHUu;!7$xU1sQD(zP<)89~j*zn+w|%*Fp*(7zI~P_0CM>yohw$ z0#JrhGF)NP+xS}U{eooZm4hv|lC*&0I1%MAsy5uQH1zGEVbl3OpCEM)OCh4bDUm4| z6lk^o;H6&p!=DH|3u-%&?N5y>!g>ZzOGT^XMJ!2ttbPR&aM(jiG%<~1?C_yk+~LPI zwAhgr7+D6hX9p;~L5B!aN!tt#y$TtK`dcud=)Tm{Mm@5fY$ue?jPxyGX$)umiW|Cd?hy&aw?yTt+U_X^fvuySu0keLn*$d#GP^7wriCd~W9LvuRKJP{#BBaS3umAn+%bk5Y z5W3*TrDD_hVnFJRQzBC`D35=qPoH_??{9VYA6d3~OG?SAIVqJiWm1;)%8p!J8t9X- zn3}7HiinxG8ZA*j25U(BD+ZLoDNf6Z^w{}Q6vZ?koP%Q*VCfE|S~9N+r5qaB@C=RI z3d`Icp0PDFWBd5bzOb}jnu}Cu^qX&Rp=gGP7^CUAV<@T9{0_HI%~}ksDy9SBq^(nq zAn)w|pggf3G%Yo;pb@h2f z*f#@GmnzdLFI?2RLQzGdW;QqV0#^yh!KvtlfiLm* zDHg?JnMT5YuQ)dCLDTL8JX?D9WLLG%Nv*ndzG!(LyeBCH5@gzAA}bls5ds^;2-B=R zjBgH2+e*^_J=YZ3r9!5?M`CPDXN|P8ajQZXw}V77^iakp#H|`LpYi4tlvZ$q2VSBv zI5>{UQ+2+E6xxvngCm8&gFHv{yZB0pq^T6S1jHiP*~X>|q{f(vW4EHX!N2zMzKX4+ z_JJ%6sw5_-=DFwpgq;`(F!Z?(R|%W!3zDk8zxD2_?mbymt&u5}U!Ifgl@~b+We`dk zC%S=F-mt8G4T#J;I6ikzNP2&8N>5;HvjiZfbxX87x9y#~EHJh~y$*xPnCkcks@;;d)=P)nthBcSu zpSMTnBdz`Yi?0x3`2@uXdGhLE)53G#y(j21NiSWE7;xg8Y=|X`P_OWlb%S0?r$o-^ zsIatc4_3W16QG-eJDsqw|pSu3(C+Fp9)waX_S@&~j_c>Zc*lU@GU#GdV2?ka2Em|D7eL00vwr1Hse zOK+RMWa8}XkZEavlqks^r;v}hW`_SU-7foYBep{hq|h@kQujkA-r z9q8Z{MKDBrdZkgxfjj0BCr;Fqw6wXnaRaXWngAxi7y;O1F9>{46KvUc->MCJDw=yy z`Y$eA2}mQ8Dkd!~ME)N>GXqOXc6qLA)AUo*$)S;cNnK$%yP2SWQ_<0zmL8dqvy+ZV z8hfN+!m+yOOIZ30dWRH>>c(NK$HlG=V5a1JdNL|)`?g^%X{D zg}KqWF>ak?Tq<6Zj9=9da^TQBfseW5L~+KLB#pUTm{S8|SGRUM7SrF2rY^y*UG9&J z3~X|gP@?#E?pwU$;Dc+o9;|8aD{bt_s%%}fq=7_!YFsg96r$d%(g~?UBA?&rb zgr{zvK+Pv-cX-B@ki>OV%yG)+)eALrpE^)@I&}*TK!^4-DB4ud zlh=nPbubHosfX%GC#aPFb?ggXUgOu$&zoC2ptR?%1=vRhb6CDo0JOFeb7`VZu$gy5 zM6L$;bLR=}B%tXIbdC7ec%J(?=XWpfhP%0(6jL}aV|jX6OI6FJ&c1t~L`F_A(j9<< zY>zN(x)Az*LMRjR?m7N79DUoS{nf2oX@ZW=Z)BuAm0uKGzB76zt#QL?ntmCz%WPOR ztv5=LMAHWT-4%XXfS4XS)2t~82^~tV$#O=wCf3qQh~O?Y0LzWL7)sA)1ITS>m#u2GYBf}OCu7SE`)yee{i55o;q{z zzOQWAdmj^U2}R-R<8te!Czj%{Adsz#KNo~rQzd;;)|go!w2FJE4cz*ik*WhDKOBq3 zP+oF#JhhrC^1z@HeCJh}TFV9jSbyB5EdgCk?YfimKoLd6mn_Vw&8}*#Z0=pVSI97-wx<5KzPTh7pWSdz8fPAoRhneslk^ub>lY?%GwlvWFR@6g#KIm--1pjb#C$ z3^bD5Lz7+oHg4aMAf>Wee@VtEjw69%=9|wDk|#a5O8~3eoN4~W)kuoGDWbH}7Erln zq7cBm;tEX*Or*eEptF)IEJf7R z+26bS=sWLzaQe(g*HB9C;L&~K8o?&Jj2;2sL@s~y(f{l}^e~;#wQKwGt2+}0f>88K zURk`wR6LQU9_RQZZ>$l1BDsftx1DIldTRQDPXp@f=n#Pec-4xo{$8WhFl}g8!&$qr=<}wj!%&pv)BDplBXjOT0Z`|?D3jQ#@)f_v3;#!)7gF4CPqD;Jbh;WvBx*|-`m*PpI_6FSh#Xt+Oj(q6x=j7 zo7J;iJ&QTWQhUAx5~=(!=vTKhGD0Fo!t#s|IutMO2_?_(AL3Qw>uuybhz%flsq;`e zODbwEY3Oe0-m~-WhiT2d7Bg{YHGOVev)Hsp17pvcoH}#%?)(33WB-w+uHEG;do#+{ z#OBpTrdHk=vlQb(O=(<2vPac(P{SN^21=E_P&4SaeO|O$Lm50h_2#)b z4Befdxjdtyl>r8AoAyzs5I=MoW)b-W%N2g|8poz{wut-b3nVk$b@-8WTMpKD?4&U% zy?l+L(X>kPCGL>G$S}VW5+8^Ip~i-)@!W8o&`6ixzk@{VBUch8GI&}VO@EUXFM4Q5?|)e@yB z|2M3pAo=O1|H6jSSw6e*FN#g~qr}A63aE_f{s%VfJk;E^yJA&u?sAN26a91;Q--Uc z$GaGhe{oTyL1hB>;R&0WcFVk6TA=5pFHb03nOV`AU$d^begjBczGib>=l0b-d)IG2 z)OX6|>=BF4x{@+dTI*m=06dpD&%I+qfcu8hg5nUzw3x1AKT z^!EArw?^l3Lp;Jj)cD*{lt<`{bO&VCFNv-j|08~YEpZrt0jZU+i{BGbI;by<~dM1SceEh#04TyAYr@k-1h!=D&Dx~gY)$JV=hb|2k#*KsW4{-cjG z<<~}zz!5Audvbll`wV=svFV%-KuVf{2?IEov;Kn*_1$&<#$89(?>N%6{ZMD$!Op(B zQ9QSAz6&o*Z)o%S-3=Z6bsc@xYx{7`)ookr+P5`z^|x-?*R%6*-+>3;dWYeuOftbJ z8mq`)Q)3suIGK!dZZCP`IySvdopAcuXV^7R1+;k3(ZpYn%L5+_;;0S+J*+K^4u5gZ z{N+jB026*aRP;Kjm-57QY+lM)yZ)IgaR#nq^GclM>%Va+XW%+EFXgOV|IC#*1J|*6 nCC>8o-?)@Ba2=bMa@MYY=1QD_>)5;!XZiYXT*?_3HR}HXCY$V| literal 0 HcmV?d00001 From d5b5ba6de358f4370f41c0cdcfaa8ef4546d19b0 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 9 Aug 2009 18:33:18 +0000 Subject: [PATCH 70/95] Fixed stupid bug and some comments in 24bit color reduction. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@986 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- op_c.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/op_c.c b/op_c.c index 947792c5..5a0f99e8 100644 --- a/op_c.c +++ b/op_c.c @@ -855,13 +855,13 @@ void CS_Sort_by_luminance(T_Cluster_set * cs) T_Cluster* place; T_Cluster* newlist = NULL; - while((nc = cs->clusters)) + while(cs->clusters) { // Remove the first cluster from the original list nc = cs->clusters; cs->clusters = cs->clusters->next; - // Find his position in the new list + // Find its position in the new list for(place = newlist;place != NULL; place = place->next) { if(place->l > nc->l) break; @@ -873,9 +873,12 @@ void CS_Sort_by_luminance(T_Cluster_set * cs) if(prev) prev->next = nc; else newlist = nc; + // reset prev pointer + prev = NULL; + } - // Put the new list bavk in place + // Put the new list back in place cs->clusters = newlist; } From 6cdc5e3042c2c6b5d9563c19bb920baf849424ad Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 9 Aug 2009 20:26:10 +0000 Subject: [PATCH 71/95] -Use nearest neighbour and no error diffusion when loading 24bit images -Some cleanup to the palette computing function, but no real improvement. I can't get it to perform better ... git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@987 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- op_c.c | 104 ++++++++++++++++++++++++++++----------------------------- op_c.h | 2 +- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/op_c.c b/op_c.c index 5a0f99e8..60fd3486 100644 --- a/op_c.c +++ b/op_c.c @@ -345,7 +345,7 @@ int OT_count_colors(T_Occurrence_table * t) ///////////////////////////////////////// M‚thodes de gestion des clusters // ///////////////////////////////////////////////////////////////////////////// -void Cluster_analyser(T_Cluster * c,T_Occurrence_table * to) +void Cluster_pack(T_Cluster * c,T_Occurrence_table * to) { int rmin,rmax,vmin,vmax,bmin,bmax; int r,g,b; @@ -667,7 +667,7 @@ void CS_Init(T_Cluster_set * cs,T_Occurrence_table * to) cs->clusters->Vmax = cs->clusters->vmax = to->rng_g-1; cs->clusters->Bmax = cs->clusters->bmax = to->rng_b-1; cs->clusters->next = NULL; - Cluster_analyser(cs->clusters,to); + Cluster_pack(cs->clusters,to); cs->nb=1; } @@ -798,14 +798,12 @@ void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to) Cluster_split(¤t,&Nouveau1,&Nouveau2,current.plus_large,to); // On compacte ces deux nouveaux (il peut y avoir un espace entre l'endroit de la coupure et les premiers pixels du cluster) - Cluster_analyser(&Nouveau1,to); - Cluster_analyser(&Nouveau2,to); + Cluster_pack(&Nouveau1,to); + Cluster_pack(&Nouveau2,to); - // On met ces deux nouveaux clusters dans le clusterSet... sauf s'ils sont vides - if(Nouveau1.occurences>0) - CS_Set(cs,&Nouveau1); - if(Nouveau2.occurences>0) - CS_Set(cs,&Nouveau2); + // On les remet dans le set + CS_Set(cs,&Nouveau1); + CS_Set(cs,&Nouveau2); } } @@ -1020,50 +1018,50 @@ T_Conversion_table * Optimize_palette(T_Bitmap24B image,int size,T_Components * to=0; tc=0; cs=0; ds=0; to=OT_new(r,g,b); - if (to!=0) + if (to == NULL) + return 0; + + tc=CT_new(r,g,b); + if (tc == NULL) { - tc=CT_new(r,g,b); - if (tc!=0) - { - - // Première étape : on compte les pixels de chaque couleur pour pouvoir trier là dessus - OT_count_occurrences(to,image,size); - - cs=CS_New(256,to); - if (cs!=0) - { - // C'est bon, on a pu tout allouer - - // On génère les clusters (avec l'algo du median cut) - CS_Generate(cs,to); - - // On calcule la teinte de chaque pixel (Luminance et chrominance) - CS_Compute_colors(cs,to); - - ds=GS_New(cs); - if (ds!=0) - { - GS_Generate(ds,cs); - GS_Delete(ds); - } - // Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre sympa : par couleur, et par luminosité pour chaque couleur - CS_Sort_by_luminance(cs); - CS_Sort_by_chrominance(cs); - - // Enfin on génère la palette et la table de correspondance entre chaque couleur 24b et sa couleur palette associée. - CS_Generate_color_table_and_palette(cs,tc,palette); - - CS_Delete(cs); - OT_delete(to); - return tc; - } - CT_delete(tc); - } - OT_delete(to); + OT_delete(to); + return 0; } - // Si on arrive ici c'est que l'allocation n'a pas réussi, - // l'appelant devra recommencer avec une précision plus faible (3 derniers paramètres) - return 0; + + // Première étape : on compte les pixels de chaque couleur pour pouvoir trier là dessus + OT_count_occurrences(to,image,size); + + cs=CS_New(256,to); + if (cs == NULL) + { + CT_delete(tc); + OT_delete(to); + return 0; + } + // C'est bon, on a pu tout allouer + + // On génère les clusters (avec l'algo du median cut) + CS_Generate(cs,to); + + // On calcule la teinte de chaque pixel (Luminance et chrominance) + CS_Compute_colors(cs,to); + + ds=GS_New(cs); + if (ds!=0) + { + GS_Generate(ds,cs); + GS_Delete(ds); + } + // Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre sympa : par couleur, et par luminosité pour chaque couleur + CS_Sort_by_luminance(cs); + CS_Sort_by_chrominance(cs); + + // Enfin on génère la palette et la table de correspondance entre chaque couleur 24b et sa couleur palette associée. + CS_Generate_color_table_and_palette(cs,tc,palette); + + CS_Delete(cs); + OT_delete(to); + return tc; } int Modified_value(int value,int modif) @@ -1173,7 +1171,6 @@ void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B sour d++; } } - } void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) @@ -1247,7 +1244,8 @@ int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int if (table!=0) { - Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); + //Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); + Convert_24b_bitmap_to_256_nearest_neighbor(dest,source,width,height,palette,table); CT_delete(table); return 0; } diff --git a/op_c.h b/op_c.h index a1339aea..4f12fa30 100644 --- a/op_c.h +++ b/op_c.h @@ -176,7 +176,7 @@ void OT_count_occurrences(T_Occurrence_table * t,T_Bitmap24B image,int size); ///////////////////////////////////////// Méthodes de gestion des clusters // ///////////////////////////////////////////////////////////////////////////// -void Cluster_analyser(T_Cluster * c,T_Occurrence_table * to); +void Cluster_pack(T_Cluster * c,T_Occurrence_table * to); void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurrence_table * to); void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to); From 562099f17f46a9368057c9b74e39dcebda1297e1 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 15 Aug 2009 01:15:39 +0000 Subject: [PATCH 72/95] Improved mouse experiment: Mouse merging is automatically off when drawing and on when not drawing.(ignores ini setting). Tools that paste the brush along a shape (lines, cont'freehand, circles, splines) now force a screen update about 10 times per second, but no more than once every 8 pixels drawn. See issue 183. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@990 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- graph.c | 30 +++++++++++++++++++++++++++--- graph.h | 2 +- input.c | 50 +++++++++++++++++++++++++++++++++----------------- operatio.c | 16 ++++++++-------- 4 files changed, 69 insertions(+), 29 deletions(-) diff --git a/graph.c b/graph.c index b473a193..9029f439 100644 --- a/graph.c +++ b/graph.c @@ -1011,11 +1011,32 @@ void Fill_general(byte fill_color) ////////////////////////// avec gestion de previews ////////////////////////// ////////////////////////////////////////////////////////////////////////////// + // Data used by ::Init_permanent_draw() and ::Pixel_figure_permanent() + static Uint32 Permanent_draw_next_refresh=0; + static int Permanent_draw_count=0; + + void Init_permanent_draw(void) + { + Permanent_draw_count = 0; + Permanent_draw_next_refresh = SDL_GetTicks() + 100; + } // Affichage d'un point de façon définitive (utilisation du pinceau) void Pixel_figure_permanent(word x_pos,word y_pos,byte color) { Display_paintbrush(x_pos,y_pos,color,0); + Permanent_draw_count ++; + + // Check every 8 pixels + if (! (Permanent_draw_count&7)) + { + Uint32 now = SDL_GetTicks(); + if (now>= Permanent_draw_next_refresh) + { + Permanent_draw_next_refresh = now+100; + Flush_update(); + } + } } // Affichage d'un point de façon définitive @@ -1157,6 +1178,7 @@ void Draw_empty_circle_general(short center_x,short center_y,short radius,byte c void Draw_empty_circle_permanent(short center_x,short center_y,short radius,byte color) { Pixel_figure=Pixel_figure_permanent; + Init_permanent_draw(); Draw_empty_circle_general(center_x,center_y,radius,color); Update_part_of_screen(center_x - radius, center_y - radius, 2* radius+1, 2*radius+1); } @@ -1299,6 +1321,7 @@ void Draw_empty_ellipse_general(short center_x,short center_y,short horizontal_r void Draw_empty_ellipse_permanent(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color) { Pixel_figure=Pixel_figure_permanent; + Init_permanent_draw(); Draw_empty_ellipse_general(center_x,center_y,horizontal_radius,vertical_radius,color); Update_part_of_screen(center_x - horizontal_radius, center_y - vertical_radius, 2* horizontal_radius+1, 2*vertical_radius+1); } @@ -1498,8 +1521,7 @@ void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte short incr_x,incr_y; short i,cumul; short delta_x,delta_y; - - + x_pos=start_x; y_pos=start_y; @@ -1563,11 +1585,12 @@ void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte // -- Tracer définitif d'une ligne -- -void Draw_line_permanet(short start_x,short start_y,short end_x,short end_y, byte color) +void Draw_line_permanent(short start_x,short start_y,short end_x,short end_y, byte color) { int w = end_x-start_x, h = end_y - start_y; Pixel_figure=Pixel_figure_permanent; + Init_permanent_draw(); Draw_line_general(start_x,start_y,end_x,end_y,color); Update_part_of_screen((start_x=Screen_height) { Input_new_mouse_Y=Screen_height-1; - bl=1; + Mouse_blocked=1; } if (Input_new_mouse_X>=Screen_width) { Input_new_mouse_X=Screen_width-1; - bl=1; + Mouse_blocked=1; } //Gestion "avancée" du curseur: interdire la descente du curseur dans le //menu lorsqu'on est en train de travailler dans l'image @@ -136,7 +136,7 @@ int Move_cursor_with_constraints() if(Menu_Y<=Input_new_mouse_Y) { //On bloque le curseur en fin d'image - bl++; + Mouse_blocked=1; Input_new_mouse_Y=Menu_Y-1; //La ligne !!au-dessus!! du menu } @@ -146,7 +146,7 @@ int Move_cursor_with_constraints() { if(Input_new_mouse_X>=Main_separator_position) { - bl++; + Mouse_blocked=1; Input_new_mouse_X=Main_separator_position-1; } } @@ -154,7 +154,7 @@ int Move_cursor_with_constraints() { if(Input_new_mouse_XConfig.Mouse_merge_movement) + if (Operation_stack_size != 0) feedback=1; } @@ -653,7 +657,10 @@ int Get_input(void) Key_ANSI = 0; Key = 0; - Mouse_count=0; + Mouse_moved=0; + Mouse_blocked=0; + Input_new_mouse_X = Mouse_X; + Input_new_mouse_Y = Mouse_Y; // Process as much events as possible without redrawing the screen. // This mostly allows us to merge mouse events for people with an high @@ -770,11 +777,20 @@ int Get_input(void) } } } - // Vidage de toute mise à jour de l'affichage à l'écran qui serait encore en attente. - // (c'est fait ici car on est sur que cette function est apellée partout ou on a besoin d'interragir avec l'utilisateur) + // If the cursor was moved since last update, + // it was erased, so we need to redraw it (with the preview brush) + if (Mouse_moved) + { + Compute_paintbrush_coordinates(); + Display_cursor(); + } + // Commit any pending screen update. + // This is done in this function because it's called after reading + // some user input. Flush_update(); - return user_feedback_required; + + return Mouse_moved || user_feedback_required; } void Adjust_mouse_sensitivity(word fullscreen) diff --git a/operatio.c b/operatio.c index d8ad8908..d9b359ce 100644 --- a/operatio.c +++ b/operatio.c @@ -224,7 +224,7 @@ void Freehand_mode1_1_2(void) { Hide_cursor(); Print_coordinates(); - Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,Fore_color); + Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,Fore_color); Display_cursor(); } @@ -279,7 +279,7 @@ void Freehand_mode1_2_2(void) { Print_coordinates(); Hide_cursor(); - Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,Back_color); + Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,Back_color); Display_cursor(); } @@ -572,7 +572,7 @@ void Line_0_5(void) Pixel_figure_preview_auto (start_x,start_y); Hide_line_preview (start_x,start_y,end_x,end_y); Display_paintbrush (start_x,start_y,color,0); - Draw_line_permanet(start_x,start_y,end_x,end_y,color); + Draw_line_permanent(start_x,start_y,end_x,end_y,color); End_of_modification(); if ( (Config.Coords_rel) && (Menu_is_visible) ) @@ -695,7 +695,7 @@ void K_line_0_6(void) Display_paintbrush(start_x,start_y,color,0); direction=(direction & 0x7F); } - Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Operation_push(direction); @@ -2242,7 +2242,7 @@ void Polygon_12_9(void) Paintbrush_shape=Paintbrush_shape_before_operation; // Le pied aurait été de ne pas repasser sur le 1er point de la 1ère ligne // mais c'est pas possible :( - Draw_line_permanet(start_x,start_y,end_x,end_y,color); + Draw_line_permanent(start_x,start_y,end_x,end_y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Display_cursor(); @@ -2534,7 +2534,7 @@ void Polyform_12_8(void) Hide_line_preview(start_x,start_y,end_x,end_y); // On l'affiche de façon définitive: - Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); // Et on affiche un pixel de preview en (Paintbrush_X,Paintbrush_Y): Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); @@ -2565,7 +2565,7 @@ void Polyform_12_8(void) Hide_line_preview(start_x,start_y,end_x,end_y); // On affiche de façon définitive le bouclage du polygone: - Draw_line_permanet(start_x,start_y,initial_x,initial_y,color); + Draw_line_permanent(start_x,start_y,initial_x,initial_y,color); Display_cursor(); End_of_modification(); @@ -5056,7 +5056,7 @@ void Centered_lines_12_7(void) Smear_start=1; Display_paintbrush (start_x,start_y,color,0); - Draw_line_permanet(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); + Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); From 025d27ff71013fbb2ab52cd763c187fea9f0722e Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 15 Aug 2009 16:56:20 +0000 Subject: [PATCH 73/95] (cont'd from previous commit) Fixed Issue 183. Added intermediate screen updates during expensive operations (including rectangle, I forgot it in previous commit). Display more responsive to users of fast mice. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@991 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- gfx2def.ini | 15 ++- global.h | 3 +- graph.c | 16 ++- init.c | 381 ++++++++++++++++++++++++++-------------------------- input.c | 31 ++--- 5 files changed, 229 insertions(+), 217 deletions(-) diff --git a/gfx2def.ini b/gfx2def.ini index fe166e40..38b5d657 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -262,12 +262,15 @@ Default_window_size = 640,480 ; (default '640,480') ; This setting allows you merge successive mouse movements into a single - ; mouse movement. Ideally you should leave it at zero, but if you have an - ; extremely fast mouse and you see the mouse cursor lagging WHEN YOU'RE NOT - ; DRAWING, you may want to set it to 1, 2 or more, so that GrafX2 skips small - ; steps. A very high value (100) guarantees that Grafx2 merges all the mouse - ; steps into a single one. - Merge_movement = 100 ; (default 100) + ; mouse movement. You should only use it if you are using a mouse which + ; reports at 200Hz or more, and you experience lag when using discontinuous + ; hand-drawing with large brushes (this tool tries to paste the brush and + ; update the screen on each new mouse position) In this case, set this to 2 + ; or more, to ignore some intermediate mouse reports when a more recent one + ; is present. + ; Note that with a value superior to 1, you lose precision with continuous + ; hand-drawing, as intermediate mouse positions are skipped. + Merge_movement = 0 ; (default 0) ; Number of columns in the palette of the menu bar. Can be any number from ; 1 to 256. If there is not enough room, the program will display less diff --git a/global.h b/global.h index 8887d7b5..4044ae73 100644 --- a/global.h +++ b/global.h @@ -878,8 +878,9 @@ GFX2_GLOBAL short Colorpicker_Y; /// each operation, and for each mouse state (no button,left button,right button) GFX2_GLOBAL struct { - byte Hide_cursor; ///< Boolean: Need to hide/unhide cursor during this step Func_action Action; ///< Function to call + byte Hide_cursor; ///< Boolean: Need to hide/unhide cursor during this step + byte Fast_mouse; ///< Operation should take shortcuts with mouse movements } Operation[NB_OPERATIONS][3][OPERATION_STACK_SIZE]; // -- misc diff --git a/graph.c b/graph.c index 9029f439..7be0f8fe 100644 --- a/graph.c +++ b/graph.c @@ -1670,18 +1670,20 @@ void Draw_empty_rectangle(short start_x,short start_y,short end_x,short end_y,by } // On trace le rectangle: - + Init_permanent_draw(); + for (x_pos=start_x;x_pos<=end_x;x_pos++) - Display_paintbrush(x_pos,start_y,color,0); + { + Pixel_figure_permanent(x_pos,start_y,color); + Pixel_figure_permanent(x_pos, end_y,color); + } for (y_pos=start_y+1;y_pos=Screen_height) { Input_new_mouse_Y=Screen_height-1; - Mouse_blocked=1; + mouse_blocked=1; } if (Input_new_mouse_X>=Screen_width) { Input_new_mouse_X=Screen_width-1; - Mouse_blocked=1; + mouse_blocked=1; } //Gestion "avancée" du curseur: interdire la descente du curseur dans le //menu lorsqu'on est en train de travailler dans l'image @@ -136,7 +137,7 @@ int Move_cursor_with_constraints() if(Menu_Y<=Input_new_mouse_Y) { //On bloque le curseur en fin d'image - Mouse_blocked=1; + mouse_blocked=1; Input_new_mouse_Y=Menu_Y-1; //La ligne !!au-dessus!! du menu } @@ -146,7 +147,7 @@ int Move_cursor_with_constraints() { if(Input_new_mouse_X>=Main_separator_position) { - Mouse_blocked=1; + mouse_blocked=1; Input_new_mouse_X=Main_separator_position-1; } } @@ -154,7 +155,7 @@ int Move_cursor_with_constraints() { if(Input_new_mouse_X Config.Mouse_merge_movement) + if (! Operation[Current_operation][Mouse_K_unique] + [Operation_stack_size].Fast_mouse) + feedback=1; } - + if (mouse_blocked) + Set_mouse_position(); return feedback; } @@ -654,11 +656,10 @@ int Get_input(void) { SDL_Event event; int user_feedback_required = 0; // Flag qui indique si on doit arrêter de traiter les évènements ou si on peut enchainer - + Key_ANSI = 0; Key = 0; Mouse_moved=0; - Mouse_blocked=0; Input_new_mouse_X = Mouse_X; Input_new_mouse_Y = Mouse_Y; @@ -790,7 +791,7 @@ int Get_input(void) Flush_update(); - return Mouse_moved || user_feedback_required; + return (Mouse_moved!=0) || user_feedback_required; } void Adjust_mouse_sensitivity(word fullscreen) From c957107d85bdbcf2fbbf5b2e34601399f0416503 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Mon, 17 Aug 2009 19:48:20 +0000 Subject: [PATCH 74/95] Fixed the same stupid bug about endless looping on palette reduction again. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@996 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- gfx2.cfg | Bin 10211 -> 10211 bytes op_c.c | 206 ++++++++++++++++++++++++++++++++----------------------- 2 files changed, 120 insertions(+), 86 deletions(-) diff --git a/gfx2.cfg b/gfx2.cfg index 6bb5e522d12a04914f8c3d457d21061234aad7dd..e8e9b110e067cdcf9655a7f493c36f3b68fafaa7 100644 GIT binary patch delta 16 VcmaFt|JZ-SZFLR~1`Y-g001{N1TO#p delta 16 VcmaFt|JZ-SZFLR@1_uTZ0025g1fKu^ diff --git a/op_c.c b/op_c.c index 60fd3486..f2bdee9a 100644 --- a/op_c.c +++ b/op_c.c @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ +#include #include #include #include @@ -315,24 +316,24 @@ void OT_inc(T_Occurrence_table * t,int r,int g,int b) t->table[index]++; } -void OT_count_occurrences(T_Occurrence_table * t,T_Bitmap24B image,int size) +void OT_count_occurrences(T_Occurrence_table* t, T_Bitmap24B image, int size) { T_Bitmap24B ptr; int index; - for (index=size,ptr=image;index>0;index--,ptr++) - OT_inc(t,ptr->R,ptr->G,ptr->B); + for (index = size, ptr = image; index > 0; index--, ptr++) + OT_inc(t, ptr->R, ptr->G, ptr->B); } int OT_count_colors(T_Occurrence_table * t) { int val; // Valeur de retour - int nb; // Nombre de couleurs … tester - int i; // Compteur de couleurs test‚es + int nb; // Nombre de couleurs … tester + int i; // Compteur de couleurs test‚es - val=0; + val = 0; nb=(t->rng_r)*(t->rng_g)*(t->rng_b); - for (i=0;itable[i]>0) val++; @@ -495,21 +496,22 @@ ENDCRUSH: } } -void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurrence_table * to) +void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, + T_Occurrence_table * to) { int limit; int cumul; - int r,g,b; + int r, g, b; - limit=(c->occurences)/2; - cumul=0; - if (hue==0) + limit = c->occurences / 2; + cumul = 0; + if (hue == 0) { - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) + for (r = c->rmin<<16; r<=c->rmax<<16; r+=1<<16) { - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) + for (g = c->vmin<<8; g<=c->vmax<<8; g+=1<<8) { - for (b=c->bmin;b<=c->bmax;b++) + for (b = c->bmin; b<=c->bmax; b++) { cumul+=to->table[r + g + b]; if (cumul>=limit) @@ -535,6 +537,7 @@ void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurre c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; + c2->Rmin=r; c2->Rmax=c->Rmax; c2->rmin=r; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; @@ -575,6 +578,7 @@ void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurre c1->vmin=c->vmin; c1->vmax=g-1; c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; c1->bmin=c->bmin; c1->bmax=c->bmax; + c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=g; c2->Vmax=c->Vmax; @@ -614,6 +618,7 @@ void Cluster_split(T_Cluster * c,T_Cluster * c1,T_Cluster * c2,int hue,T_Occurre c1->vmin=c->vmin; c1->vmax=c->vmax; c1->Bmin=c->Bmin; c1->Bmax=b-1; c1->bmin=c->bmin; c1->bmax=b-1; + c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; c2->rmin=c->rmin; c2->rmax=c->rmax; c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; @@ -648,7 +653,7 @@ void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) c->r=(cumul_r<red_r)/c->occurences; c->g=(cumul_g<red_g)/c->occurences; c->b=(cumul_b<red_b)/c->occurences; - RGB_to_HSL(c->r,c->g,c->b,&c->h,&s,&c->l); + RGB_to_HSL(c->r, c->g, c->b, &c->h, &s, &c->l); } @@ -657,22 +662,38 @@ void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) //////////////////////////// M‚thodes de gestion des ensembles de clusters // ///////////////////////////////////////////////////////////////////////////// +// Debug helper : check if a cluster set has the right count value +/* +void CS_Check(T_Cluster_set* cs) +{ + int i; + T_Cluster* c = cs->clusters; + for (i = cs->nb; i > 0; i--) + { + assert( c != NULL); + c = c->next; + } + + assert(c == NULL); +} +*/ + /// Setup the first cluster before we start the operations -void CS_Init(T_Cluster_set * cs,T_Occurrence_table * to) +void CS_Init(T_Cluster_set * cs, T_Occurrence_table * to) { cs->clusters->Rmin = cs->clusters->rmin = 0; cs->clusters->Gmin = cs->clusters->vmin = 0; cs->clusters->Bmin = cs->clusters->bmin = 0; - cs->clusters->Rmax = cs->clusters->rmax = to->rng_r-1; - cs->clusters->Vmax = cs->clusters->vmax = to->rng_g-1; - cs->clusters->Bmax = cs->clusters->bmax = to->rng_b-1; + cs->clusters->Rmax = cs->clusters->rmax = to->rng_r - 1; + cs->clusters->Vmax = cs->clusters->vmax = to->rng_g - 1; + cs->clusters->Bmax = cs->clusters->bmax = to->rng_b - 1; cs->clusters->next = NULL; - Cluster_pack(cs->clusters,to); - cs->nb=1; + Cluster_pack(cs->clusters, to); + cs->nb = 1; } /// Allocate a new cluster set -T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to) +T_Cluster_set * CS_New(int nbmax, T_Occurrence_table * to) { T_Cluster_set * n; @@ -680,25 +701,26 @@ T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to) if (n != NULL) { // On recopie les paramŠtres demand‚s - n->nb_max=OT_count_colors(to); + n->nb_max = OT_count_colors(to); - // On vient de compter le nombre de couleurs existantes, s'il est plus grand que 256 on limite à 256 + // On vient de compter le nombre de couleurs existantes, s'il est plus grand + // que 256 on limite à 256 // (nombre de couleurs voulu au final) - if (n->nb_max>nbmax) + if (n->nb_max > nbmax) { - n->nb_max=nbmax; + n->nb_max = nbmax; } // On tente d'allouer le premier cluster n->clusters=(T_Cluster *)malloc(sizeof(T_Cluster)); - if (n->clusters!=NULL) + if (n->clusters != NULL) // C'est bon! On initialise - CS_Init(n,to); + CS_Init(n, to); else { // Table impossible … allouer free(n); - n=0; + n = NULL; } } @@ -709,16 +731,16 @@ T_Cluster_set * CS_New(int nbmax,T_Occurrence_table * to) void CS_Delete(T_Cluster_set * cs) { T_Cluster* nxt; - while(cs->clusters != NULL) + while (cs->clusters != NULL) { nxt = cs->clusters->next; - free(cs->clusters); + free(cs->clusters); cs->clusters = nxt; } - free(cs); + free(cs); } -void CS_Get(T_Cluster_set * cs,T_Cluster * c) +void CS_Get(T_Cluster_set * cs, T_Cluster * c) { T_Cluster* current = cs->clusters; T_Cluster* prev = NULL; @@ -755,13 +777,11 @@ void CS_Set(T_Cluster_set * cs,T_Cluster * c) T_Cluster* prev = NULL; // Search the first cluster that is smaller than ours - if(current != NULL) // don't search if the list is empty - do + while (current && current->occurences > c->occurences) { - if (current->occurences < c->occurences) - break; prev = current; - } while((current = current -> next)); + current = current->next; + } // Now insert our cluster just before the one we found c -> next = current; @@ -769,20 +789,21 @@ void CS_Set(T_Cluster_set * cs,T_Cluster * c) current = malloc(sizeof(T_Cluster)); *current = *c ; - if(prev) prev -> next = current; + if (prev) prev->next = current; else cs->clusters = current; - cs -> nb++; + cs->nb++; } // Détermination de la meilleure palette en utilisant l'algo Median Cut : // 1) On considère l'espace (R,G,B) comme 1 boîte // 2) On cherche les extrêmes de la boîte en (R,G,B) // 3) On trie les pixels de l'image selon l'axe le plus long parmi (R,G,B) -// 4) On coupe la boîte en deux au milieu, et on compacte pour que chaque bord corresponde bien à un pixel extreme +// 4) On coupe la boîte en deux au milieu, et on compacte pour que chaque bord +// corresponde bien à un pixel extreme // 5) On recommence à couper selon le plus grand axe toutes boîtes confondues // 6) On s'arrête quand on a le nombre de couleurs voulu -void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to) +void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to) { T_Cluster current; T_Cluster Nouveau1; @@ -795,11 +816,12 @@ void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to) CS_Get(cs,¤t); // On le coupe en deux - Cluster_split(¤t,&Nouveau1,&Nouveau2,current.plus_large,to); + Cluster_split(¤t, &Nouveau1, &Nouveau2, current.plus_large, to); - // On compacte ces deux nouveaux (il peut y avoir un espace entre l'endroit de la coupure et les premiers pixels du cluster) - Cluster_pack(&Nouveau1,to); - Cluster_pack(&Nouveau2,to); + // On compacte ces deux nouveaux (il peut y avoir un espace entre l'endroit + // de la coupure et les premiers pixels du cluster) + Cluster_pack(&Nouveau1, to); + Cluster_pack(&Nouveau2, to); // On les remet dans le set CS_Set(cs,&Nouveau1); @@ -807,7 +829,7 @@ void CS_Generate(T_Cluster_set * cs,T_Occurrence_table * to) } } -void CS_Compute_colors(T_Cluster_set * cs,T_Occurrence_table * to) +void CS_Compute_colors(T_Cluster_set * cs, T_Occurrence_table * to) { T_Cluster * c; @@ -822,24 +844,25 @@ void CS_Sort_by_chrominance(T_Cluster_set * cs) T_Cluster* place; T_Cluster* newlist = NULL; - while((nc = cs->clusters)) + while (cs->clusters) { // Remove the first cluster from the original list nc = cs->clusters; cs->clusters = cs->clusters->next; // Find his position in the new list - for(place = newlist;place != NULL; place = place->next) + for (place = newlist; place != NULL; place = place->next) { - if(place->h > nc->h) break; + if (place->h > nc->h) break; prev = place; } // Chain it there nc->next = place; - if(prev) prev->next = nc; + if (prev) prev->next = nc; else newlist = nc; + prev = NULL; } // Put the new list bavk in place @@ -853,27 +876,26 @@ void CS_Sort_by_luminance(T_Cluster_set * cs) T_Cluster* place; T_Cluster* newlist = NULL; - while(cs->clusters) + while (cs->clusters) { // Remove the first cluster from the original list nc = cs->clusters; cs->clusters = cs->clusters->next; // Find its position in the new list - for(place = newlist;place != NULL; place = place->next) + for (place = newlist; place != NULL; place = place->next) { - if(place->l > nc->l) break; + if (place->l > nc->l) break; prev = place; } // Chain it there nc->next = place; - if(prev) prev->next = nc; + if (prev) prev->next = nc; else newlist = nc; // reset prev pointer prev = NULL; - } // Put the new list back in place @@ -1007,21 +1029,22 @@ void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) -T_Conversion_table * Optimize_palette(T_Bitmap24B image,int size,T_Components * palette,int r,int g,int b) +T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size, + T_Components * palette, int r, int g, int b) { - T_Occurrence_table * to; + T_Occurrence_table * to; T_Conversion_table * tc; - T_Cluster_set * cs; - T_Gradient_set * ds; + T_Cluster_set * cs; + T_Gradient_set * ds; // Création des éléments nécessaires au calcul de palette optimisée: - to=0; tc=0; cs=0; ds=0; + to = 0; tc = 0; cs = 0; ds = 0; - to=OT_new(r,g,b); + to = OT_new(r, g, b); if (to == NULL) return 0; - tc=CT_new(r,g,b); + tc = CT_new(r, g, b); if (tc == NULL) { OT_delete(to); @@ -1029,35 +1052,43 @@ T_Conversion_table * Optimize_palette(T_Bitmap24B image,int size,T_Components * } // Première étape : on compte les pixels de chaque couleur pour pouvoir trier là dessus - OT_count_occurrences(to,image,size); + OT_count_occurrences(to, image, size); - cs=CS_New(256,to); + cs = CS_New(256, to); if (cs == NULL) { CT_delete(tc); OT_delete(to); return 0; } + //CS_Check(cs); // C'est bon, on a pu tout allouer // On génère les clusters (avec l'algo du median cut) - CS_Generate(cs,to); + CS_Generate(cs, to); + //CS_Check(cs); // On calcule la teinte de chaque pixel (Luminance et chrominance) - CS_Compute_colors(cs,to); + CS_Compute_colors(cs, to); + //CS_Check(cs); - ds=GS_New(cs); - if (ds!=0) + ds = GS_New(cs); + if (ds!= NULL) { - GS_Generate(ds,cs); + GS_Generate(ds, cs); GS_Delete(ds); } - // Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre sympa : par couleur, et par luminosité pour chaque couleur + // Enfin on trie les clusters (donc les couleurs de la palette) dans un ordre + // sympa : par couleur, et par luminosité pour chaque couleur CS_Sort_by_luminance(cs); + //CS_Check(cs); CS_Sort_by_chrominance(cs); + //CS_Check(cs); - // Enfin on génère la palette et la table de correspondance entre chaque couleur 24b et sa couleur palette associée. - CS_Generate_color_table_and_palette(cs,tc,palette); + // Enfin on génère la palette et la table de correspondance entre chaque + // couleur 24b et sa couleur palette associée. + CS_Generate_color_table_and_palette(cs, tc, palette); + //CS_Check(cs); CS_Delete(cs); OT_delete(to); @@ -1173,30 +1204,33 @@ void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B sour } } -void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) +void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest, + T_Bitmap24B source, int width, int height, T_Components * palette, + T_Conversion_table * tc) { T_Bitmap24B current; T_Bitmap256 d; - int x_pos,y_pos; - int red,green,blue; + int x_pos, y_pos; + int red, green, blue; // On initialise les variables de parcours: - current =source; // Le pixel dont on s'occupe + current =source; // Le pixel dont on s'occupe - d =dest; + d =dest; // On parcours chaque pixel: - for (y_pos=0;y_posR; - green =current->G; - blue =current->B; - // Cherche la couleur correspondant dans la palette et la range dans l'image de destination - *d=CT_get(tc,red,green,blue); + red = current->R; + green = current->G; + blue = current->B; + // Cherche la couleur correspondant dans la palette et la range dans + // l'image de destination + *d = CT_get(tc, red, green, blue); // On passe au pixel suivant : current++; From 29ee887c78a04676296463c10778e5d2c5ca1c9b Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Tue, 18 Aug 2009 23:42:07 +0000 Subject: [PATCH 75/95] Brush container (unfinished). Temporarily bound to right-click 'Brush FX'. Only accepts monochrome brushes of any size at the moment. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@997 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- buttons.h | 2 + const.h | 8 ++- global.h | 2 + init.c | 22 ++++++- init.h | 1 + main.c | 3 + special.h | 4 ++ struct.h | 19 +++++- 9 files changed, 236 insertions(+), 12 deletions(-) diff --git a/buttons.c b/buttons.c index c9f75428..bcf9e1b4 100644 --- a/buttons.c +++ b/buttons.c @@ -51,6 +51,7 @@ #include "windows.h" #include "brush.h" #include "input.h" +#include "special.h" #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include @@ -5633,12 +5634,184 @@ void Button_Text() } } +void Display_stored_brush_in_window(word x_pos,word y_pos,int index) +{ + if (Brush_container[index].Paintbrush_shape <= PAINTBRUSH_SHAPE_MISC) + { + int x,y; + int offset_x=0, offset_y=0; + //int brush_offset_x=0, brush_offset_y=0; + + // Determine draw offset (small brushes are stacked on corner of their preview) + if (Brush_container[index].WidthBRUSH_CONTAINER_PREVIEW_WIDTH) + brush_offset_x = (Paintbrush_width-BRUSH_CONTAINER_PREVIEW_WIDTH)/2; + if (Paintbrush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) + brush_offset_y = (Paintbrush_height-BRUSH_CONTAINER_PREVIEW_HEIGHT)/2; + + for (y=0; y>1; + Paintbrush_offset_Y=Paintbrush_height>>1; + } + else + { + // Recreate the brush pixels from its shape and dimensions + Set_paintbrush_size(Paintbrush_width,Paintbrush_height); + } + } + + Change_paintbrush_shape(shape); + return 1; +} + +void Button_Brush_container(void) +{ + short clicked_button; + short x_pos,y_pos; + byte index; + + Open_window(BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+8, + BRUSH_CONTAINER_ROWS*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+40, + "Brushes"); + + Window_set_normal_button( + (BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)-59)/2, + (BRUSH_CONTAINER_ROWS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18, + 67,14,"Cancel",0,1,KEY_ESC); // 1 + + index=0; + for (index=0; index < BRUSH_CONTAINER_ROWS*BRUSH_CONTAINER_COLUMNS; index++) + { + x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; + y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; + Window_set_normal_button( + x_pos, + y_pos, + BRUSH_CONTAINER_PREVIEW_WIDTH+2, + BRUSH_CONTAINER_PREVIEW_HEIGHT+2, + "",0,1,SDLK_LAST); + Display_stored_brush_in_window(x_pos+1, y_pos+1, index); + } + Update_window_area(0,0,Window_width, Window_height); + + Display_cursor(); + + do + { + clicked_button=Window_clicked_button(); + //if (Is_shortcut(Key,0x100+BUTTON_HELP)) + // Window_help(BUTTON_PAINTBRUSHES, NULL); + + if (clicked_button == 1) + break; + + if (clicked_button>1) + { + index = clicked_button-2; + + if (Window_attribute1==RIGHT_SIDE) + { + // Store + + x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; + y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; + + Store_brush(index); + Hide_cursor(); + Display_stored_brush_in_window(x_pos+1, y_pos+1, index); + Display_cursor(); + } + else + { + // Restore and exit + + if (Restore_brush(index)) + break; + } + } + } + while (1); + Close_window(); + + //Unselect_button(BUTTON_PAINTBRUSHES); + Display_cursor(); +} \ No newline at end of file diff --git a/buttons.h b/buttons.h index 4e109c83..8376dcc5 100644 --- a/buttons.h +++ b/buttons.h @@ -651,5 +651,7 @@ void Button_Smooth_menu(void); */ void Button_Smear_mode(void); +void Button_Brush_container(void); + #endif diff --git a/const.h b/const.h index 82b07cd8..9b3b1596 100644 --- a/const.h +++ b/const.h @@ -65,6 +65,11 @@ /// Character to display in menus for an ellipsis. #define ELLIPSIS_CHARACTER '…' +#define BRUSH_CONTAINER_PREVIEW_WIDTH 16 ///< Size for preview of a brush in Brush container +#define BRUSH_CONTAINER_PREVIEW_HEIGHT 16 ///< Size for preview of a brush in Brush container +#define BRUSH_CONTAINER_COLUMNS 4 ///< Number of columns in the Brush container +#define BRUSH_CONTAINER_ROWS 3 ///< Number of rows in the Brush container + /// /// We force the dynamic backup page allocation to leave a minimum of /// 256Kb of free memory, to allow the rest of the program to work safely. @@ -210,7 +215,8 @@ enum PAINTBRUSH_SHAPES 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 colorpicker. PAINTBRUSH_SHAPE_COLOR_BRUSH, ///< User's brush, in color mode - PAINTBRUSH_SHAPE_MONO_BRUSH ///< User's brush, in mono mode + PAINTBRUSH_SHAPE_MONO_BRUSH, ///< User's brush, in mono mode + PAINTBRUSH_SHAPE_MAX ///< Upper limit. }; /// Normal resting state for a menu button. diff --git a/global.h b/global.h index 4044ae73..92395130 100644 --- a/global.h +++ b/global.h @@ -830,6 +830,8 @@ GFX2_GLOBAL short Colorpicker_X; /// Position of the colorpicker tool, in image coordinates. GFX2_GLOBAL short Colorpicker_Y; +/// Brush container +GFX2_GLOBAL T_Brush_template Brush_container[BRUSH_CONTAINER_COLUMNS*BRUSH_CONTAINER_ROWS]; #ifdef GLOBAL_VARIABLES byte CURSOR_FOR_OPERATION[NB_OPERATIONS]= diff --git a/init.c b/init.c index c8f8bf4d..1aa4b496 100644 --- a/init.c +++ b/init.c @@ -1063,7 +1063,7 @@ void Init_buttons(void) 106,18, 16,16, BUTTON_SHAPE_RECTANGLE, - Button_Brush_FX,Button_Brush_FX, + Button_Brush_FX,Button_Brush_container, Do_nothing, FAMILY_INSTANT); @@ -2446,3 +2446,23 @@ void Init_sighandler(void) #endif } +void Init_brush_container(void) +{ + int i; + + for (i=0; i Date: Thu, 20 Aug 2009 23:13:41 +0000 Subject: [PATCH 76/95] Brush container (Issue 135) now working with color brushes too. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1001 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- brush.c | 138 ++++++++++++++++++++++++++++++------------------------ brush.h | 8 ++++ buttons.c | 64 +++++++++++++++++++++---- 3 files changed, 140 insertions(+), 70 deletions(-) diff --git a/brush.c b/brush.c index 54d0f323..c6fe95ca 100644 --- a/brush.c +++ b/brush.c @@ -124,7 +124,7 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) byte * temp; if (is_preview==0 || Mouse_K==0) // pas de curseur si on est en preview et - // en train de cliquer + // en train de cliquer switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!! @@ -446,12 +446,12 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) temp_color=Read_pixel_from_current_screen(x_pos,y_pos); position=(counter_y*Smear_brush_width)+counter_x; if ( (Paintbrush_sprite[(MAX_PAINTBRUSH_SIZE*counter_y)+counter_x] != 0) - // Le pinceau sert de masque pour dire quels pixels on doit traiter dans le rectangle - && (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) - // On clippe l'effet smear entre Smear_Min et Smear_Max - ) - Display_pixel(x_pos,y_pos,Smear_brush[position]); + // Le pinceau sert de masque pour dire quels pixels on doit traiter dans le rectangle + && (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) + // On clippe l'effet smear entre Smear_Min et Smear_Max + ) + Display_pixel(x_pos,y_pos,Smear_brush[position]); Smear_brush[position]=temp_color; } Update_part_of_screen(start_x, start_y, width, height); @@ -477,6 +477,69 @@ 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) +{ + byte return_code=0; + + 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) + { + 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; + } + } + 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 == NULL) // Failed to allocate the 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; + } + return return_code; +} + + // -- Effacer le pinceau -- // // void Hide_paintbrush(short x,short y) @@ -655,56 +718,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 ( (((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) - { - Error(0); - - Brush=(byte *)malloc(1*1); - if(Brush == NULL) - { - Error(ERROR_MEMORY); - exit(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 == NULL) // On ne peut même pas allouer la brosse du smear! - { - Error(0); - - 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; - } + Realloc_brush(new_brush_width, new_brush_height); Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width); @@ -827,7 +841,7 @@ void Outline_brush(void) // On copie la brosse courante dans la nouvelle Copy_part_of_image_to_another(Brush, // source - 0, 0, Brush_width, Brush_height, Brush_width, + 0, 0, Brush_width, Brush_height, Brush_width, new_brush, // Destination 1, 1, width); @@ -858,8 +872,8 @@ void Outline_brush(void) } else if (state == 0) { - Pixel_in_brush(x_pos-1,y_pos,Fore_color); - state=1; + Pixel_in_brush(x_pos-1,y_pos,Fore_color); + state=1; } } // Cas du dernier pixel à droite de la ligne @@ -1088,7 +1102,7 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) Error(0); Brush=(byte *)malloc(1*1); - if(Brush==NULL) Error(ERROR_MEMORY); + if(Brush==NULL) Error(ERROR_MEMORY); new_brush_height=new_brush_width=1; *Brush=Fore_color; } @@ -1107,7 +1121,7 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) free(Brush); Brush=(byte *)malloc(1*1); - if(Brush==NULL) Error(ERROR_MEMORY); + if(Brush==NULL) Error(ERROR_MEMORY); Brush_height=1; Brush_width=1; diff --git a/brush.h b/brush.h index 02206059..437c43cc 100644 --- a/brush.h +++ b/brush.h @@ -105,4 +105,12 @@ void Nibble_brush(void); */ 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); + + + #endif diff --git a/buttons.c b/buttons.c index bcf9e1b4..d645acd5 100644 --- a/buttons.c +++ b/buttons.c @@ -5636,7 +5636,7 @@ void Button_Text() void Display_stored_brush_in_window(word x_pos,word y_pos,int index) { - if (Brush_container[index].Paintbrush_shape <= PAINTBRUSH_SHAPE_MISC) + if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX) { int x,y; int offset_x=0, offset_y=0; @@ -5655,14 +5655,19 @@ void Display_stored_brush_in_window(word x_pos,word y_pos,int index) // Draw up to 16x16 for (y=0; yBRUSH_CONTAINER_PREVIEW_WIDTH) brush_offset_x = (Paintbrush_width-BRUSH_CONTAINER_PREVIEW_WIDTH)/2; @@ -5698,6 +5703,36 @@ void Store_brush(int index) // Re-init the rest Brush_container[index].Transp_color=0; } + if (Paintbrush_shape == PAINTBRUSH_SHAPE_COLOR_BRUSH || + Paintbrush_shape == PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Brush_container[index].Brush=(byte *)malloc(Brush_width*Brush_height); + if (Brush_container[index].Brush) + { + Brush_container[index].Paintbrush_shape=Paintbrush_shape; + Brush_container[index].Width=Brush_width; + Brush_container[index].Height=Brush_height; + + memcpy(Brush_container[index].Brush, Brush,Brush_height*Brush_width); + + // Scale for preview + if (Brush_width>BRUSH_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); + } + 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); + } + } + else + { + Error(0); + } + } } byte Restore_brush(int index) @@ -5738,8 +5773,21 @@ byte Restore_brush(int index) Set_paintbrush_size(Paintbrush_width,Paintbrush_height); } } - + // Color brushes + if (shape == PAINTBRUSH_SHAPE_COLOR_BRUSH || + shape == PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Paintbrush_shape=shape; + Realloc_brush(Brush_container[index].Width,Brush_container[index].Height); + // Realloc sets Brush_width and Brush_height to new size. + memcpy(Brush, Brush_container[index].Brush, Brush_height*Brush_width); + + Brush_offset_X=Brush_width>>1; + Brush_offset_Y=Brush_height>>1; + + } Change_paintbrush_shape(shape); + return 1; } From 5c4219d3fafa80ba275acbe8558007bd71b485b2 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 22 Aug 2009 18:39:14 +0000 Subject: [PATCH 77/95] Improved built-in resizable brushes: circle brushes are no longer limited to even diameters (2 4 6), and random brush now only has isolated pixels (no pixels touch each other). git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1002 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- special.c | 81 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/special.c b/special.c index 72f71ee4..492037b4 100644 --- a/special.c +++ b/special.c @@ -30,11 +30,26 @@ //---------------------- Modifier le pinceau spécial ------------------------- +int Circle_squared_diameter(int diameter) +{ + int result = diameter*diameter; + // Trick to make some circles rounder, even though + // mathematically incorrect. + if (diameter==3 || diameter==9) + return result-2; + if (diameter==11) + return result-6; + if (diameter==14) + return result-4; + + return result; +} + void Set_paintbrush_size(int width, int height) { int x_pos,y_pos; int x,y; - float radius2; + int radius2; if (width<1) width=1; if (height<1) height=1; @@ -47,14 +62,12 @@ void Set_paintbrush_size(int width, int height) switch (Paintbrush_shape) { case PAINTBRUSH_SHAPE_ROUND : - radius2=Paintbrush_offset_X+0.414213562; // [0.410..0.415[ - radius2*=radius2; - for (y_pos=0; y_pos0) + Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos-1]=0; + if (y_pos>0) + Paintbrush_sprite[((y_pos-1)*MAX_PAINTBRUSH_SIZE)+x_pos]=0; + } } } } @@ -146,12 +173,9 @@ void Smaller_paintbrush(void) Hide_cursor(); switch (Paintbrush_shape) { - case PAINTBRUSH_SHAPE_ROUND: - case PAINTBRUSH_SHAPE_SIEVE_ROUND: case PAINTBRUSH_SHAPE_CROSS: case PAINTBRUSH_SHAPE_PLUS: case PAINTBRUSH_SHAPE_DIAMOND: - case PAINTBRUSH_SHAPE_RANDOM: if (Paintbrush_width&1) Set_paintbrush_size(Paintbrush_width-2,Paintbrush_height-2); else @@ -161,6 +185,9 @@ void Smaller_paintbrush(void) case PAINTBRUSH_SHAPE_SLASH: case PAINTBRUSH_SHAPE_ANTISLASH: case PAINTBRUSH_SHAPE_SIEVE_SQUARE: + case PAINTBRUSH_SHAPE_ROUND: + case PAINTBRUSH_SHAPE_SIEVE_ROUND: + case PAINTBRUSH_SHAPE_RANDOM: Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); break; case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: @@ -183,9 +210,6 @@ void Bigger_paintbrush(void) Hide_cursor(); switch (Paintbrush_shape) { - case PAINTBRUSH_SHAPE_ROUND: - case PAINTBRUSH_SHAPE_SIEVE_ROUND: - case PAINTBRUSH_SHAPE_RANDOM: case PAINTBRUSH_SHAPE_CROSS: case PAINTBRUSH_SHAPE_PLUS: case PAINTBRUSH_SHAPE_DIAMOND: @@ -198,6 +222,9 @@ void Bigger_paintbrush(void) case PAINTBRUSH_SHAPE_SLASH: case PAINTBRUSH_SHAPE_ANTISLASH: case PAINTBRUSH_SHAPE_SIEVE_SQUARE: + case PAINTBRUSH_SHAPE_ROUND: + case PAINTBRUSH_SHAPE_SIEVE_ROUND: + case PAINTBRUSH_SHAPE_RANDOM: Set_paintbrush_size(Paintbrush_width+1,Paintbrush_height+1); break; case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: From 8ac66726f2c42241c247dc59c76a117213baeb65 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 22 Aug 2009 22:11:01 +0000 Subject: [PATCH 78/95] Brush container integrated as the bottom row of Paintbrush screen (F4) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1003 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 88 +++++++++++++++++++++++++++++++++++++++++-------------- init.c | 2 +- 2 files changed, 67 insertions(+), 23 deletions(-) diff --git a/buttons.c b/buttons.c index d645acd5..142bee0f 100644 --- a/buttons.c +++ b/buttons.c @@ -2482,19 +2482,27 @@ void Button_Paintbrush_menu(void) short x_pos,y_pos; byte index; - Open_window(310,155,"Paintbrush menu"); + Open_window(310,180,"Paintbrush menu"); - Window_display_frame(8,21,294,107); + Window_display_frame(8,21,294,132); - Window_set_normal_button(122,133,67,14,"Cancel",0,1,KEY_ESC); // 1 + Window_set_normal_button(122,158,67,14,"Cancel",0,1,KEY_ESC); // 1 for (index=0; index(NB_PAINTBRUSH_SPRITES+1)) + { + index = clicked_button-NB_PAINTBRUSH_SPRITES-2; + + if (Window_attribute1==RIGHT_SIDE) + { + // Store + + x_pos=13+((index+NB_PAINTBRUSH_SPRITES)%12)*24; + y_pos=27+((index+NB_PAINTBRUSH_SPRITES)/12)*25; + + Store_brush(index); + 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(); + break; + } + } + + } + else if (clicked_button>1 && Window_attribute1==LEFT_SIDE) + // 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; + } + else if (clicked_button==1) + { + Close_window(); + break; + } } - while (clicked_button<=0); - - Close_window(); - - if (clicked_button!=1) // pas Cancel - { - 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]); - } + while (1); Unselect_button(BUTTON_PAINTBRUSHES); Display_cursor(); diff --git a/init.c b/init.c index 1aa4b496..2cc6761a 100644 --- a/init.c +++ b/init.c @@ -1063,7 +1063,7 @@ void Init_buttons(void) 106,18, 16,16, BUTTON_SHAPE_RECTANGLE, - Button_Brush_FX,Button_Brush_container, + Button_Brush_FX,Button_Brush_FX, Do_nothing, FAMILY_INSTANT); From 7bfdb28936cfd8fd67164b95b2a3c132dbd28dd8 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 23 Aug 2009 00:41:40 +0000 Subject: [PATCH 79/95] Keyboard shortcuts that open a window now also close it (Issue 88). Fixed a recent bug that made contextual help in FX window only work once. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1004 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 74 ++++++++++++++++++++++++++++++++++++----------------- buttons.h | 2 +- engine.c | 2 +- filesel.c | 14 +++++++++- help.c | 7 +++-- input.c | 2 +- palette.c | 7 ++++- shade.c | 4 +++ transform.c | 3 +++ 9 files changed, 85 insertions(+), 30 deletions(-) diff --git a/buttons.c b/buttons.c index 142bee0f..b368f470 100644 --- a/buttons.c +++ b/buttons.c @@ -429,6 +429,8 @@ byte Button_Quit_local_function(void) clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_QUIT, NULL); + else if (Is_shortcut(Key,0x100+BUTTON_QUIT)) + clicked_button=1; } while (clicked_button<=0); @@ -526,7 +528,7 @@ void Button_Clear_with_backcolor(void) } //---------- 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) +void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut) { short clicked_button; byte backup_table[256]; @@ -626,6 +628,10 @@ void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_ca Key=0; break; } + else if (Is_shortcut(Key,close_shortcut)) + { + clicked_button=4; + } } } while (clicked_button<4); @@ -664,7 +670,7 @@ void Stencil_update_color(byte color) void Button_Stencil_menu(void) { - Menu_tag_colors("Stencil",Stencil,&Stencil_mode,1, "STENCIL"); + Menu_tag_colors("Stencil",Stencil,&Stencil_mode,1, "STENCIL", SPECIAL_STENCIL_MENU); } @@ -677,7 +683,7 @@ void Button_Mask_mode(void) void Button_Mask_menu(void) { - Menu_tag_colors("Mask",Mask_table,&Mask_mode,1, "MASK"); + Menu_tag_colors("Mask",Mask_table,&Mask_mode,1, "MASK", SPECIAL_MASK_MENU); } @@ -805,7 +811,7 @@ void Button_Settings(void) // Button Show/Hide dans le fileselect Window_set_normal_button(167, 28,131,14,"Hidden files: ",0,1,SDLK_LAST); // 1 Window_set_normal_button(167, 43,131,14,"Hidden dir. : ",0,1,SDLK_LAST); // 2 -// Window_set_normal_button(167, 58,131,14,"System dir. : ",0,1,SDLK_LAST); // 3 +// Window_set_normal_button(167, 58,131,14,"System dir. : ",0,1,SDLK_LAST); // Button Show/Hide Picture limits Window_set_normal_button( 9, 81,107,14,"Limits : ",0,1,SDLK_LAST); // 3 @@ -817,31 +823,31 @@ void Button_Settings(void) Window_set_normal_button( 9,126,107,14,"Backup : ",0,1,SDLK_LAST); // 6 // Button Safety colors - Window_set_normal_button(117, 81,131,14,"Safe. colors: ",0,1,SDLK_LAST); // 8 + Window_set_normal_button(117, 81,131,14,"Safe. colors: ",0,1,SDLK_LAST); // 7 // Button Adjust Brush Pick - Window_set_normal_button(117, 96,131,14,"AdjBrushPick: ",0,1,SDLK_LAST); // 9 + Window_set_normal_button(117, 96,131,14,"AdjBrushPick: ",0,1,SDLK_LAST); // 8 // Button Separate colors - Window_set_normal_button(117,111,131,14,"Separate col: ",0,1,SDLK_LAST); // 10 + Window_set_normal_button(117,111,131,14,"Separate col: ",0,1,SDLK_LAST); // 9 // Button Passer dans la résolution appropriée après un chargement - Window_set_normal_button(117,126,131,14,"Auto-set res: ",0,1,SDLK_LAST); // 11 + Window_set_normal_button(117,126,131,14,"Auto-set res: ",0,1,SDLK_LAST); // 10 // Button Adapter la palette après un chargement (<=> Shift+BkSpc) - Window_set_normal_button(117,141,131,14,"Coords: ",0,1,SDLK_LAST); // 12 + Window_set_normal_button(117,141,131,14,"Coords: ",0,1,SDLK_LAST); // 11 // Button Reload - Window_set_normal_button( 6,163, 51,14,"Reload" ,0,1,SDLK_LAST); // 13 + Window_set_normal_button( 6,163, 51,14,"Reload" ,0,1,SDLK_LAST); // 12 // Button Auto-save - Window_set_normal_button( 73,163,107,14,"Auto-save: ",0,1,SDLK_LAST); // 14 + Window_set_normal_button( 73,163,107,14,"Auto-save: ",0,1,SDLK_LAST); // 13 // Button Save - Window_set_normal_button(183,163, 51,14,"Save" ,0,1,SDLK_LAST); // 15 + Window_set_normal_button(183,163, 51,14,"Save" ,0,1,SDLK_LAST); // 14 // Button Close - Window_set_normal_button(250,163, 51,14,"Close" ,0,1,KEY_ESC); // 16 + Window_set_normal_button(250,163, 51,14,"Close" ,0,1,KEY_ESC); // 15 // Jauges de sensibilité de la souris (X puis Y) - Window_set_scroller_button(265,99,56,4,1,0); // 17 - Window_set_scroller_button(279,99,56,4,1,0); // 18 + Window_set_scroller_button(265,99,56,4,1,0); // 16 + Window_set_scroller_button(279,99,56,4,1,0); // 17 // Zone de saisie du nb de pages de Undo - Window_set_input_button(140,50,2); // 19 + Window_set_input_button(140,50,2); // 18 Update_window_area(0,0,Window_width, Window_height); @@ -944,6 +950,8 @@ void Button_Settings(void) if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_SETTINGS, NULL); + else if (Is_shortcut(Key,0x100+BUTTON_SETTINGS)) + clicked_button=15; } while ( (clicked_button!=15) && (Key!=SDLK_RETURN) ); @@ -1418,7 +1426,7 @@ void Copy_some_colors(void) static byte mask_color_to_copy[256]; // static to use less stack memset(mask_color_to_copy,1,256); - Menu_tag_colors("Tag colors to copy",mask_color_to_copy,&confirmation,0, NULL); + Menu_tag_colors("Tag colors to copy",mask_color_to_copy,&confirmation,0, NULL, 0xFFFF); if (confirmation && (!Spare_image_is_modified || Confirmation_box("Spare page was modified. Proceed?"))) @@ -1455,6 +1463,8 @@ void Button_Copy_page(void) clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_PAGE, NULL); + else if (Is_shortcut(Key,0x200+BUTTON_PAGE)) + clicked_button=6; } while (clicked_button<=0); @@ -2374,6 +2384,8 @@ void Button_Gradients(void) Key=0; break; } + if (Is_shortcut(Key,0x200+BUTTON_GRADRECT)) + clicked_button=6; } } while (clicked_button<6); @@ -2512,7 +2524,6 @@ void Button_Paintbrush_menu(void) clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_PAINTBRUSHES, NULL); - // Brush container if (clicked_button>(NB_PAINTBRUSH_SPRITES+1)) { @@ -2559,7 +2570,7 @@ void Button_Paintbrush_menu(void) break; } - else if (clicked_button==1) + else if (clicked_button==1 || Is_shortcut(Key,0x100+BUTTON_PAINTBRUSHES)) { Close_window(); break; @@ -3371,6 +3382,8 @@ void Button_Magnify_menu(void) clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_MAGNIFIER, NULL); + else if (Is_shortcut(Key,0x200+BUTTON_MAGNIFIER)) + clicked_button=1; } while (clicked_button<=0); @@ -3684,6 +3697,10 @@ void Button_Brush_FX(void) Key=0; Window_help(BUTTON_BRUSH_EFFECTS, NULL); } + else if (Is_shortcut(Key,0x100+BUTTON_BRUSH_EFFECTS)) + { + clicked_button=1; + } } while (clicked_button<=0); @@ -3858,6 +3875,8 @@ void Button_Smooth_menu(void) } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "SMOOTH"); + else if (Is_shortcut(Key,SPECIAL_SMOOTH_MENU)) + clicked_button=2; } while ((clicked_button!=1) && (clicked_button!=2)); @@ -4023,6 +4042,8 @@ 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; } while (clicked_button<5); @@ -4558,7 +4579,11 @@ void Button_Airbrush_menu(void) Key=0; break; } - + if (Is_shortcut(Key,0x200+BUTTON_AIRBRUSH)) + { + clicked_button=2; + break; + } } } while ( (clicked_button!=1) && (clicked_button!=2) ); @@ -5175,14 +5200,13 @@ void Button_Effects(void) { clicked_button=Window_clicked_button(); - if (Key==KEY_ESC) + if (Key==KEY_ESC || Is_shortcut(Key,0x100+BUTTON_EFFECTS)) { clicked_button=11; Key=0; } else if (Is_shortcut(Key,0x100+BUTTON_HELP)) { - Key=0; // Aide contextuelle switch(Window_get_clicked_button()) { @@ -5219,7 +5243,9 @@ void Button_Effects(void) default: Window_help(BUTTON_EFFECTS, NULL); } - continue; + // Hack because we have used Window_get_clicked_button() + Input_sticky_control=0; + // } switch (clicked_button) @@ -5540,6 +5566,8 @@ void Button_Text() { if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_TEXT, NULL); + else if (Is_shortcut(Key,0x100+BUTTON_TEXT)) + clicked_button=12; } switch(clicked_button) { diff --git a/buttons.h b/buttons.h index 8376dcc5..a75b38de 100644 --- a/buttons.h +++ b/buttons.h @@ -637,7 +637,7 @@ void Save_picture(byte image); /*! Generic color tagging menu, for various effects. */ -void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section); +void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut ); /*! diff --git a/engine.c b/engine.c index 085fdadb..f4f104ab 100644 --- a/engine.c +++ b/engine.c @@ -778,7 +778,7 @@ void Main_handler(void) Key=0; break; case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu - Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL); + Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); Key=0; break; case SPECIAL_INVERT_SIEVE : diff --git a/filesel.c b/filesel.c index b7b3cc2e..4f2ed269 100644 --- a/filesel.c +++ b/filesel.c @@ -1030,6 +1030,12 @@ byte Button_Load_or_Save(byte load, byte image) char quicksearch_filename[MAX_PATH_CHARACTERS]=""; char save_filename[MAX_PATH_CHARACTERS]; char * most_matching_filename; + short window_shortcut; + + if (image) + window_shortcut = load?(0x100+BUTTON_LOAD):(0x100+BUTTON_SAVE); + else + window_shortcut = load?SPECIAL_LOAD_BRUSH:SPECIAL_SAVE_BRUSH; initial_palette=(T_Components *)malloc(sizeof(T_Palette)); memcpy(initial_palette,Main_palette,sizeof(T_Palette)); @@ -1550,7 +1556,7 @@ byte Button_Load_or_Save(byte load, byte image) } Key=0; break; - default: // Autre => On se place sur le nom de fichier qui correspond + default: if (clicked_button<=0) { if (Is_shortcut(Key,0x100+BUTTON_HELP)) @@ -1558,6 +1564,12 @@ byte Button_Load_or_Save(byte load, byte image) Window_help(load?BUTTON_LOAD:BUTTON_SAVE, NULL); break; } + if (Is_shortcut(Key,window_shortcut)) + { + 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) { diff --git a/help.c b/help.c index c8291ea7..7dc1079a 100644 --- a/help.c +++ b/help.c @@ -585,11 +585,12 @@ void Window_help(int section, const char *sub_section) } break; } - + if (Is_shortcut(Key,0x100+BUTTON_HELP)) + clicked_button=1; } while ((clicked_button!=1) && (Key!=SDLK_RETURN)); - if(Key==SDLK_RETURN) Key=0; + Key=0; Close_window(); Unselect_button(BUTTON_HELP); Display_cursor(); @@ -698,6 +699,8 @@ void Button_Stats(void) do { clicked_button=Window_clicked_button(); + if (Is_shortcut(Key,0x200+BUTTON_HELP)) + clicked_button=1; } while ( (clicked_button!=1) && (Key!=SDLK_RETURN) ); diff --git a/input.c b/input.c index 0e2ea19b..f5cb582d 100644 --- a/input.c +++ b/input.c @@ -82,7 +82,7 @@ short Joybutton_right_click=0; // Button number that serves as right-click int Is_shortcut(word Key, word function) { - if (Key == 0) + if (Key == 0 || function == 0xFFFF) return 0; if (function & 0x100) diff --git a/palette.c b/palette.c index f8bcaa00..c4df752e 100644 --- a/palette.c +++ b/palette.c @@ -2097,6 +2097,8 @@ void Button_Palette(void) Window_help(BUTTON_PALETTE, NULL); break; } + else if (Is_shortcut(Key,0x100+BUTTON_PALETTE)) + clicked_button=14; } if (need_to_remap) @@ -2221,6 +2223,9 @@ void Button_Secondary_palette(void) Key=0; Window_help(BUTTON_PALETTE, "PALETTE OPTIONS"); } + else if (Is_shortcut(Key,0x200+BUTTON_PALETTE)) + clicked_button=3; + switch(clicked_button) { case 5: @@ -2298,7 +2303,7 @@ void Button_Secondary_palette(void) if (clicked_button==1) { - Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL); + Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); } else if (clicked_button==2) { diff --git a/shade.c b/shade.c index 7d8e5782..32d0dfed 100644 --- a/shade.c +++ b/shade.c @@ -978,6 +978,8 @@ int Menu_shade(void) Key=0; Window_help(BUTTON_EFFECTS, "SHADE"); } + else if (Is_shortcut(Key,SPECIAL_SHADE_MENU)) + clicked_button=5; } } while ((clicked_button!=4) && (clicked_button!=5)); @@ -1097,6 +1099,8 @@ void Button_Quick_shade_menu(void) } if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "QUICK SHADE"); + else if (Is_shortcut(Key,SPECIAL_QUICK_SHADE_MENU)) + clicked_button=1; } while ((clicked_button!=1) && (clicked_button!=2)); diff --git a/transform.c b/transform.c index 3305d89c..1707ab6f 100644 --- a/transform.c +++ b/transform.c @@ -196,6 +196,9 @@ void Button_Transform_menu(void) Key=0; Window_help(BUTTON_ADJUST, "PICTURE TRANSFORM"); } + else if (Is_shortcut(Key,0x200+BUTTON_ADJUST)) + clicked_button=1; + else switch(clicked_button) { case 9: // Unit From d6bf9413bf5263d6f51e8191bff5711fa0b8cc17 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Wed, 26 Aug 2009 23:42:55 +0000 Subject: [PATCH 80/95] Displayable tile grid (Issue 171) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1007 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 7 +++++++ buttons.h | 5 +++++ const.h | 3 ++- engine.c | 4 ++++ gfx2def.ini | 11 +++++++++++ global.h | 4 +++- graph.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++-- graph.h | 2 ++ helpfile.h | 5 ++++- hotkeys.c | 9 +++++++++ pxdouble.c | 6 ++++++ pxquad.c | 6 ++++++ pxsimple.c | 8 ++++++-- pxtall.c | 6 ++++++ pxtall2.c | 6 ++++++ pxtriple.c | 6 ++++++ pxwide.c | 6 ++++++ pxwide2.c | 6 ++++++ readini.c | 8 ++++++++ saveini.c | 4 ++++ struct.h | 1 + windows.c | 16 ++++++++-------- 22 files changed, 169 insertions(+), 15 deletions(-) diff --git a/buttons.c b/buttons.c index b368f470..170fc4e0 100644 --- a/buttons.c +++ b/buttons.c @@ -3613,6 +3613,13 @@ void Button_Grid_menu(void) Display_cursor(); } +void Button_Show_grid(void) +{ + Show_grid = !Show_grid; + Hide_cursor(); + Display_all_screen(); + Display_cursor(); +} // ----------------------- Modifications de brosse --------------------------- diff --git a/buttons.h b/buttons.h index a75b38de..65db64a1 100644 --- a/buttons.h +++ b/buttons.h @@ -353,6 +353,11 @@ void Button_Snap_mode(void); */ void Button_Grid_menu(void); +/*! + Callback to toggle the grid visible in the magnified view. +*/ +void Button_Show_grid(void); + // Mode trame (Sieve) /*! diff --git a/const.h b/const.h index 9b3b1596..ff6d5483 100644 --- a/const.h +++ b/const.h @@ -33,7 +33,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 158 ///< Number of actions that can have a key combination associated to it. +#define NB_SHORTCUTS 159 ///< Number of actions that can have a key combination associated to it. #define NB_ZOOM_FACTORS 12 ///< 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. @@ -406,6 +406,7 @@ enum SPECIAL_ACTIONS SPECIAL_ZOOM_16, SPECIAL_ZOOM_18, SPECIAL_ZOOM_20, + SPECIAL_SHOW_GRID, NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; diff --git a/engine.c b/engine.c index f4f104ab..20223d15 100644 --- a/engine.c +++ b/engine.c @@ -825,6 +825,10 @@ void Main_handler(void) Button_Grid_menu(); Key=0; break; + case SPECIAL_SHOW_GRID : + Button_Show_grid(); + Key=0; + break; case SPECIAL_SIEVE_MODE : Button_Sieve_mode(); Key=0; diff --git a/gfx2def.ini b/gfx2def.ini index 38b5d657..7fdc4d94 100644 --- a/gfx2def.ini +++ b/gfx2def.ini @@ -328,5 +328,16 @@ ; want to use. | 8x8 utilisée dans les menus. ; Default : (empty to let the program choose) Font_file = + + ; This determines the color value for the grid. Each pixel of + ; the grid will be displayed by XOR-ing the original color with + ; the value of this setting. + ; For example, if you always paint 16-color images, you can set it + ; to 16 so the color of the grid are 16 for 0, 17 for 1, etc. + ; Then you can set colors 16-31 as lighter/darker variants + ; of your original palette, resulting in a pretty grid ! + ; + ; Valid values are 1 to 255. + Grid_XOR_color = 255; (Default 255) ; end of configuration diff --git a/global.h b/global.h index 92395130..371f198e 100644 --- a/global.h +++ b/global.h @@ -138,7 +138,7 @@ GFX2_GLOBAL byte Cursor_in_menu; /// Boolean, means the cursor was hovering over a menu GUI element. GFX2_GLOBAL byte Cursor_in_menu_previous; /// Storage for the graphics under the mouse cursor. Used by ::Hide_cursor and ::Display_cursor -GFX2_GLOBAL byte CURSOR_BACKGROUND[CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; +GFX2_GLOBAL byte Cursor_background[CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; // -- Paintbrush data @@ -645,6 +645,8 @@ GFX2_GLOBAL byte Stencil[256]; /// Boolean, true when the Grid mode is active. GFX2_GLOBAL byte Snap_mode; +/// Boolean, true when the Grid is displayed in zoomed view. +GFX2_GLOBAL byte Show_grid; /// Width of the grid in Grid mode. GFX2_GLOBAL word Snap_width; /// Height of the grid in Grid mode. diff --git a/graph.c b/graph.c index 7be0f8fe..d6947b8c 100644 --- a/graph.c +++ b/graph.c @@ -107,6 +107,7 @@ void Update_part_of_screen(short x, short y, short width, short height) if(effective_Y + effective_h > Menu_Y) effective_h = Menu_Y - effective_Y; + /* SDL_Rect r; r.x=effective_X; @@ -136,7 +137,7 @@ void Update_part_of_screen(short x, short y, short width, short height) } else effective_X += Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X; - diff = effective_X+effective_w-Screen_width; + diff = effective_X+effective_w-Min(Screen_width, Main_X_zoom+(Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); if (diff>0) { effective_w -=diff; @@ -153,7 +154,7 @@ void Update_part_of_screen(short x, short y, short width, short height) return; effective_Y = 0; } - diff = effective_Y+effective_h-Menu_Y; + diff = effective_Y+effective_h-Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); if (diff>0) { effective_h -=diff; @@ -161,6 +162,7 @@ void Update_part_of_screen(short x, short y, short width, short height) return; } + // Très utile pour le debug :) /*SDL_Rect r; r.x=effective_X; @@ -169,6 +171,7 @@ void Update_part_of_screen(short x, short y, short width, short height) r.w=effective_w; SDL_FillRect(Screen_SDL,&r,3);*/ + Redraw_grid(effective_X,effective_Y,effective_w,effective_h); Update_rect(effective_X,effective_Y,effective_w,effective_h); } } @@ -999,6 +1002,16 @@ void Fill_general(byte fill_color) // par l'utilisation de "Display_pixel()", et que les autres... eh bein // on n'y a jamais touché à l'écran les autres: ils sont donc corrects. + if(Main_magnifier_mode) + { + short w,h; + + w=Min(Screen_width-Main_X_zoom, (Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); + h=Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); + + Redraw_grid(Main_X_zoom,0,w,h); + } + Update_rect(0,0,0,0); End_of_modification(); } @@ -2803,3 +2816,41 @@ byte Effect_smooth(word x,word y,__attribute__((unused)) byte color) Read_pixel_from_current_screen(x,y); // C'est bien l'écran courant et pas // l'écran feedback car il s'agit de ne } // pas modifier l'écran courant. + +void Horizontal_grid_line(word x_pos,word y_pos,word width) +{ + int x; + + for (x=!(x_pos&1);xFont_file = strdup("font_Classic.png"); + conf->Grid_XOR_color=255; + // Optional, XOR color for grid overlay (>2.0) + if (!Load_INI_get_values (file,buffer,"Grid_XOR_color",1,values)) + { + if ((values[0]>0) || (values[0]<=255)) + conf->Grid_XOR_color=values[0]; + } + fclose(file); free(filename); diff --git a/saveini.c b/saveini.c index 3305e2e0..39a153b6 100644 --- a/saveini.c +++ b/saveini.c @@ -644,6 +644,10 @@ int Save_INI(T_Config * conf) if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,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))) + goto Erreur_Retour; Save_INI_flush(Ancien_fichier,Nouveau_fichier,buffer); diff --git a/struct.h b/struct.h index 80c30523..7ffed0b4 100644 --- a/struct.h +++ b/struct.h @@ -308,6 +308,7 @@ typedef struct int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) 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. } T_Config; // Structures utilisées pour les descriptions de pages et de liste de pages. diff --git a/windows.c b/windows.c index e84d5244..ef3a558d 100644 --- a/windows.c +++ b/windows.c @@ -1663,7 +1663,7 @@ void Display_cursor(void) { if( x_pos < 0 ) continue; color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; - CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); + Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } @@ -1733,8 +1733,8 @@ void Display_cursor(void) if(x_pos<0) continue; if(x_pos>=Screen_width) break; color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; - // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard - CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); + // On sauvegarde dans Cursor_background pour restaurer plus tard + Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } @@ -1762,8 +1762,8 @@ void Display_cursor(void) if(x_pos<0) continue; if(x_pos>=Screen_width) break; color=Gfx->Cursor_sprite[shape][counter_y][counter_x]; - // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard - CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos); + // On sauvegarde dans Cursor_background pour restaurer plus tard + Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); if (color!=MC_Trans) Pixel(x_pos,y_pos,color); } @@ -1966,7 +1966,7 @@ void Hide_cursor(void) { if(x_pos < 0) continue; else if (x_pos>=Screen_width) break; - Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]); + Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } @@ -2035,7 +2035,7 @@ void Hide_cursor(void) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; - Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]); + Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); @@ -2063,7 +2063,7 @@ void Hide_cursor(void) { if(x_pos<0) continue; if(x_pos>=Screen_width) break; - Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]); + Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); } } Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); From dcbbd07f8ad70dd155c245c78a2517de67da0a36 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 5 Sep 2009 12:55:09 +0000 Subject: [PATCH 81/95] Fixes issue 212 (segfault in gradrect). The operation is now cancelled if the rectangle is fully out of the picture. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1011 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- helpfile.h | 7 ++++--- operatio.c | 52 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/helpfile.h b/helpfile.h index 7f214357..383f4c58 100644 --- a/helpfile.h +++ b/helpfile.h @@ -365,9 +365,10 @@ static const T_Help_table helptable_credits[] = HELP_TEXT (" HoraK-FDF iLKke Jamon ") HELP_TEXT (" keito kusma Lord Graga ") HELP_TEXT (" MagerValp mind MooZ ") - HELP_TEXT (" the Peach richienyhus tape.wyrm ") - HELP_TEXT (" TeeEmCee tempest Timo Kurrpa ") - HELP_TEXT (" titus^Rab Tobé 00ai99 ") + HELP_TEXT (" the Peach petter richienyhus ") + HELP_TEXT (" tape.wyrm TeeEmCee tempest ") + HELP_TEXT (" Timo Kurrpa titus^Rab Tobé ") + HELP_TEXT (" 00ai99") HELP_TEXT ("") HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") diff --git a/operatio.c b/operatio.c index d9b359ce..bd15bcc2 100644 --- a/operatio.c +++ b/operatio.c @@ -4582,25 +4582,49 @@ void Grad_rectangle_0_5(void) Paintbrush_Y = ray; Hide_cursor(); - width = abs(rbx-rax); - height = abs(rby-ray); + width = abs(rbx - rax); + height = abs(rby - ray); - if (Max(rax,rbx)-Main_offset_X > Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width)) // Tous les clippings à gérer sont là - offset_width = Max(rax,rbx) - Min(Main_image_width,Main_magnifier_mode?Main_separator_position:Screen_width); + // Check if the rectangle is not fully outside the picture + if (Min(rax, rbx) > Main_image_width || Min(ray, rby) > Main_image_height) + { + Operation_pop(&rby); // reset the stack + return; // cancel the operation + } - if (Max(ray,rby)-Main_offset_Y > Min(Main_image_height,Menu_Y)) - offset_height = Max(ray,rby) - Min(Main_image_height,Menu_Y); + // Handle clipping + if (Max(rax, rbx)-Main_offset_X > Min(Main_image_width, + Main_magnifier_mode?Main_separator_position:Screen_width)) + { + offset_width = Max(rax, rbx) - Min(Main_image_width, + Main_magnifier_mode?Main_separator_position:Screen_width); + } - // Dessin dans la zone de dessin normale - Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width - offset_width); - if(offset_height == 0) - Horizontal_XOR_line(Min(rax,rbx)-Main_offset_X,Max(ray,rby)-1-Main_offset_Y,width - offset_width); + if (Max(ray, rby)-Main_offset_Y > Min(Main_image_height, Menu_Y)) + offset_height = Max(ray, rby) - Min(Main_image_height, Menu_Y); - Vertical_XOR_line(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); - if (offset_width == 0) // Sinon cette ligne est en dehors de la zone image, inutile de la dessiner - Vertical_XOR_line(Max(rax,rbx)-1-Main_offset_X,Min(ray,rby)-Main_offset_Y,height-offset_height); + // Dessin dans la zone de dessin normale + Horizontal_XOR_line(Min(rax, rbx)-Main_offset_X, + Min(ray, rby) - Main_offset_Y, width - offset_width); - Update_rect(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width+1-offset_width,height+1-offset_height); + // If not, this line is out of the picture so there is no need to draw it + if (offset_height == 0) + { + Horizontal_XOR_line(Min(rax, rbx) - Main_offset_X, Max(ray, rby) - 1 + - Main_offset_Y, width - offset_width); + } + + Vertical_XOR_line(Min(rax, rbx)-Main_offset_X, Min(ray, rby) + - Main_offset_Y, height - offset_height); + + if (offset_width == 0) + { + Vertical_XOR_line(Max(rax, rbx) - 1 - Main_offset_X, Min(ray, rby) + - Main_offset_Y,height-offset_height); + } + + Update_rect(Min(rax, rbx) - Main_offset_X, Min(ray, rby) - Main_offset_Y, + width + 1 - offset_width, height + 1 - offset_height); // Dessin dans la zone zoomée if(Main_magnifier_mode && Min(rax,rbx)Limit_left_zoom && Min(ray,rby)Limit_top_zoom ) From 04cbf954ca9aa2d2d77b001f8581995ceebed4a2 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 5 Sep 2009 13:41:23 +0000 Subject: [PATCH 82/95] Fixed a display bug with small picture in zoom mode and grad rect. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1012 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- operatio.c | 69 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/operatio.c b/operatio.c index bd15bcc2..c30a1f1b 100644 --- a/operatio.c +++ b/operatio.c @@ -4594,7 +4594,7 @@ void Grad_rectangle_0_5(void) // Handle clipping if (Max(rax, rbx)-Main_offset_X > Min(Main_image_width, - Main_magnifier_mode?Main_separator_position:Screen_width)) + Main_magnifier_mode?Main_separator_position:Screen_width)) { offset_width = Max(rax, rbx) - Min(Main_image_width, Main_magnifier_mode?Main_separator_position:Screen_width); @@ -4620,26 +4620,29 @@ void Grad_rectangle_0_5(void) if (offset_width == 0) { Vertical_XOR_line(Max(rax, rbx) - 1 - Main_offset_X, Min(ray, rby) - - Main_offset_Y,height-offset_height); + - Main_offset_Y, height - offset_height); } Update_rect(Min(rax, rbx) - Main_offset_X, Min(ray, rby) - Main_offset_Y, width + 1 - offset_width, height + 1 - offset_height); // Dessin dans la zone zoomée - if(Main_magnifier_mode && Min(rax,rbx)Limit_left_zoom && Min(ray,rby)Limit_top_zoom ) + if (Main_magnifier_mode && Min(rax, rbx) <= Limit_right_zoom + && Max(rax, rbx) > Limit_left_zoom + && Min(ray, rby) <= Limit_bottom_zoom + && Max(ray, rby) > Limit_top_zoom ) { - offset_width = 0; - offset_height=0; + offset_width = 0; + offset_height = 0; - if(Min(rax,rbx)Limit_visible_right_zoom) // On dépasse du zoom à droite - offset_width += Max(rax,rbx) - Limit_visible_right_zoom; + if(Max(rax,rbx)>Limit_right_zoom) // On dépasse du zoom à droite + offset_width += Max(rax,rbx) - Limit_right_zoom - 1; if(Min(ray,rby)Limit_visible_bottom_zoom) // On dépasse du zoom en bas - offset_height += Max(ray,rby) - Limit_visible_bottom_zoom; + if(Max(ray,rby)>Limit_bottom_zoom) // On dépasse du zoom en bas + offset_height += Max(ray,rby) - Limit_bottom_zoom - 1; if(width > offset_width) { if(offset_top==0) // La ligne du haut est visible Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rax,rbx),Min(ray,rby),width-offset_width); - if(Max(ray,rby)0?offset_left:Min(rax,rbx),Max(ray,rby),width-offset_width); } @@ -4664,7 +4667,7 @@ void Grad_rectangle_0_5(void) if(offset_left==0) // La ligne de gauche est visible Vertical_XOR_line_zoom(Min(rax,rbx),offset_top>0?offset_top:Min(ray,rby),height-offset_height); - if(Max(rax,rbx)0?offset_top:Min(ray,rby),height-offset_height); } } @@ -4761,7 +4764,9 @@ void Grad_rectangle_12_7(void) Update_rect(Min(rax,rbx)-Main_offset_X,Min(ray,rby)-Main_offset_Y,width+1-offset_width,height+1-offset_height); // Dessin dans la zone zoomée - if(Main_magnifier_mode && Min(rax,rbx)Limit_left_zoom && Min(ray,rby)Limit_top_zoom ) + if (Main_magnifier_mode && Min(rax, rbx) <= Limit_right_zoom + && Max(rax, rbx)>Limit_left_zoom && Min(ray, rby) <= Limit_bottom_zoom + && Max(ray,rby)>Limit_top_zoom ) { offset_width = 0; offset_height=0; @@ -4772,8 +4777,8 @@ void Grad_rectangle_12_7(void) offset_left = Limit_left_zoom; } - if(Max(rax,rbx)>Limit_visible_right_zoom) // On dépasse du zoom à droite - offset_width += Max(rax,rbx) - Limit_visible_right_zoom; + if(Max(rax,rbx)>Limit_right_zoom) // On dépasse du zoom à droite + offset_width += Max(rax,rbx) - Limit_right_zoom - 1; if(Min(ray,rby)Limit_visible_bottom_zoom) // On dépasse du zoom en bas - offset_height += Max(ray,rby) - Limit_visible_bottom_zoom; + if(Max(ray,rby)>Limit_bottom_zoom) // On dépasse du zoom en bas + offset_height += Max(ray,rby) - Limit_bottom_zoom - 1; if(width > offset_width) { if(offset_top==0) // La ligne du haut est visible Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rax,rbx),Min(ray,rby),width-offset_width); - if(Max(ray,rby)0?offset_left:Min(rax,rbx),Max(ray,rby),width-offset_width); } @@ -4798,7 +4803,7 @@ void Grad_rectangle_12_7(void) if(offset_left==0) // La ligne de gauche est visible Vertical_XOR_line_zoom(Min(rax,rbx),offset_top>0?offset_top:Min(ray,rby),height-offset_height); - if(Max(rax,rbx)0?offset_top:Min(ray,rby),height-offset_height); } } @@ -4913,7 +4918,11 @@ void Grad_rectangle_0_9(void) Update_rect(Min(rect_start_x,rect_end_x)-Main_offset_X,Min(rect_start_y,rect_end_y)-Main_offset_Y,width+1-offset_width,height+1-offset_height); // Dessin dans la zone zoomée - if(Main_magnifier_mode && Min(rect_start_x,rect_end_x)Limit_left_zoom && Min(rect_start_y,rect_end_y)Limit_top_zoom ) + if (Main_magnifier_mode + && Min(rect_start_x, rect_end_x) <= Limit_right_zoom + && Max(rect_start_x, rect_end_x) > Limit_left_zoom + && Min(rect_start_y, rect_end_y) <= Limit_bottom_zoom + && Max(rect_start_y, rect_end_y) > Limit_top_zoom ) { offset_width = 0; offset_height=0; @@ -4924,8 +4933,8 @@ void Grad_rectangle_0_9(void) offset_left = Limit_left_zoom; } - if(Max(rect_start_x,rect_end_x)>Limit_visible_right_zoom) // On dépasse du zoom à droite - offset_width += Max(rect_start_x,rect_end_x) - Limit_visible_right_zoom; + if(Max(rect_start_x,rect_end_x)>Limit_right_zoom) // On dépasse du zoom à droite + offset_width += Max(rect_start_x,rect_end_x) - Limit_right_zoom; if(Min(rect_start_y,rect_end_y)Limit_visible_bottom_zoom) // On dépasse du zoom en bas - offset_height += Max(rect_start_y,rect_end_y) - Limit_visible_bottom_zoom; + if(Max(rect_start_y,rect_end_y)>Limit_bottom_zoom) // On dépasse du zoom en bas + offset_height += Max(rect_start_y,rect_end_y) - Limit_bottom_zoom; if(width > offset_width) { if(offset_top==0) // La ligne du haut est visible Horizontal_XOR_line_zoom(offset_left>0?offset_left:Min(rect_start_x,rect_end_x),Min(rect_start_y,rect_end_y),width-offset_width); - if(Max(rect_start_y,rect_end_y)0?offset_left:Min(rect_start_x,rect_end_x),Max(rect_start_y,rect_end_y),width-offset_width); } @@ -4950,7 +4959,7 @@ void Grad_rectangle_0_9(void) if(offset_left==0) // La ligne de gauche est visible Vertical_XOR_line_zoom(Min(rect_start_x,rect_end_x),offset_top>0?offset_top:Min(rect_start_y,rect_end_y),height-offset_height); - if(Max(rect_start_x,rect_end_x)0?offset_top:Min(rect_start_y,rect_end_y),height-offset_height); } } From cc47a21ecaffa90fd9f57d8d27fa871bda85f146 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sat, 5 Sep 2009 13:55:51 +0000 Subject: [PATCH 83/95] Added support for loading and saving c64 fileformats. Please test it :) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1013 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- const.h | 11 +- gfx2.cfg | Bin 10211 -> 10217 bytes loadsave.c | 405 ++++++++++++++++++++- misc.c | 1009 +++++++++++++++++++++++++++------------------------- misc.h | 1 + windows.c | 4 +- 6 files changed, 922 insertions(+), 508 deletions(-) diff --git a/const.h b/const.h index ff6d5483..20892d2f 100644 --- a/const.h +++ b/const.h @@ -95,14 +95,14 @@ // -- File formats #ifndef __no_pnglib__ +#define NB_KNOWN_FORMATS 15 ///< Total number of known file formats. +#define NB_FORMATS_LOAD 15 ///< Number of file formats that grafx2 can load. +#define NB_FORMATS_SAVE 15 ///< Number of file formats that grafx2 can save. +#else +// Without pnglib #define NB_KNOWN_FORMATS 14 ///< Total number of known file formats. #define NB_FORMATS_LOAD 14 ///< Number of file formats that grafx2 can load. #define NB_FORMATS_SAVE 14 ///< Number of file formats that grafx2 can save. -#else -// Without pnglib -#define NB_KNOWN_FORMATS 13 ///< Total number of known file formats. -#define NB_FORMATS_LOAD 13 ///< Number of file formats that grafx2 can load. -#define NB_FORMATS_SAVE 13 ///< Number of file formats that grafx2 can save. #endif /// List of file formats recognized by grafx2 @@ -122,6 +122,7 @@ enum FILE_FORMATS FORMAT_NEO, FORMAT_KCF, FORMAT_PAL, + FORMAT_C64, FORMAT_PNG }; diff --git a/gfx2.cfg b/gfx2.cfg index e8e9b110e067cdcf9655a7f493c36f3b68fafaa7..eacf653bdb5c66e77dd7093073d60b5dd73ddf00 100644 GIT binary patch delta 53 zcmaFt|I%N{+0C7aA&G%u7c&EcAfu}yBZCm5n<5i~2&1bYGlMXro8U&JIm|5c7}5ha J?_pL~0RSpP3e*4q delta 48 zcmaFq|JYy2+0C7aA&G%u3o`?QAR_|>4; + for(y=0; y<8; y++) + { + pixel=bitmap[cy*320+cx*8+y]; + for(x=0; x<8; x++) + { + color=c[pixel&(1<<(7-x))?1:0]; + Pixel_load_function(cx*8+x,cy*8+y,color); + } + } + } + } +} + +void Load_C64_multi(byte *bitmap, byte *colors, byte *nybble, byte background) +{ + int cx,cy,x,y,c[4],pixel,color; + c[0]=background; + for(cy=0; cy<25; cy++) + { + 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]; + + for(y=0; y<8; y++) + { + pixel=bitmap[cy*320+cx*8+y]; + for(x=0; x<4; x++) + { + + color=c[(pixel&3)]; + pixel>>=2; + Pixel_load_function(cx*4+(3-x),cy*8+y,color); + } + } + } + } +} + +void Load_C64(void) +{ + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + long file_size; + int newPixel_ratio; + byte background; + + // Palette from http://www.pepto.de/projects/colorvic/ + byte pal[48]={ + 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, + 0x68, 0x37, 0x2B, + 0x70, 0xA4, 0xB2, + 0x6F, 0x3D, 0x86, + 0x58, 0x8D, 0x43, + 0x35, 0x28, 0x79, + 0xB8, 0xC7, 0x6F, + 0x6F, 0x4F, 0x25, + 0x43, 0x39, 0x00, + 0x9A, 0x67, 0x59, + 0x44, 0x44, 0x44, + 0x6C, 0x6C, 0x6C, + 0x9A, 0xD2, 0x84, + 0x6C, 0x5E, 0xB5, + 0x95, 0x95, 0x95}; + + byte bitmap[8000],colors[1000],nybble[1000]; + word width=320, height=200; + + Get_full_filename(filename,0); + file = fopen(filename,"rb"); + + if(file) + { + + memcpy(Main_palette,pal,48); // this set the software palette for grafx2 + Set_palette(Main_palette); // this set the hardware palette for SDL + Remap_fileselector(); // Always call it if you change the palette + + file_size = File_length_file(file); + + if(file_size>9002)width=160; + + Init_preview(width, height, file_size, FORMAT_C64); // Do this as soon as you can + + Main_image_width = width ; + Main_image_height = height; + + Read_bytes(file,bitmap,8000); + if(file_size>8002)Read_bytes(file,colors,1000); + + if(width==160) + { + Read_bytes(file,nybble,1000); + Read_byte(file,&background); + Load_C64_multi(bitmap,colors,nybble,background); + newPixel_ratio = PIXEL_WIDE; + } + else + { + Load_C64_hires(bitmap,colors); + newPixel_ratio = PIXEL_SIMPLE; + } + + //Pixel_ratio = newPixel_ratio; + + File_error = 0; + fclose(file); + } + else + File_error = 1; +} + +int Save_C64_hires(FILE *file) +{ + int cx,cy,x,y,c1,c2,i,pixel,bits; + word numcolors; + dword cusage[256]; + byte colors[1000]; + + for(x=0;x<1000;x++)colors[x]=1; // init colormem to black/white + + for(cy=0; cy<25; cy++) // Character line, 25 lines + { + for(cx=0; cx<40; cx++) // Character column, 40 columns + { + for(i=0;i<256;i++) cusage[i]=0; + + numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); + if(numcolors>2) + { + Warning_message("More than 2 colors in 8x8 pixels"); + // TODO here we should hilite the offending block + printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); + return 1; + } + for(i=0;i<16;i++) + { + if(cusage[i]) + { + c2=i; + break; + } + } + c1=c2; + for(i=c2+1;i<16;i++) + { + if(cusage[i]) + { + c1=i; + + } + } + colors[cx+cy*40]=(c2<<4)|c1; + + for(y=0; y<8; y++) + { + bits=0; + for(x=0; x<8; x++) + { + pixel=Read_pixel_function(x+cx*8,y+cy*8); + if(pixel>15) + { + Warning_message("Color above 15 used"); + // TODO hilite offending block here too? + // or make it smarter with color allocation? + // However, the palette is fixed to the 16 first colors + return 1; + } + bits=bits<<1; + if(pixel==c1) bits|=1; + } + Write_byte(file,bits&255); + } + } + } + Write_bytes(file,colors,1000); + return 0; +} + +int Save_C64_multi(FILE *file) +{ +/* +BITS COLOR INFORMATION COMES FROM +00 Background color #0 (screen color) +01 Upper 4 bits of screen memory +10 Lower 4 bits of screen memory +11 Color nybble (nybble = 1/2 byte = 4 bits) +*/ + + int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel; + byte screen[1000],nybble[1000]; + word numcolors,count; + dword cusage[256]; + byte i,background=0; + numcolors=Count_used_colors(cusage); + + count=0; + for(x=0;x<16;x++) + { + //printf("color %d, pixels %d\n",x,cusage[x]); + if(cusage[x]>count) + { + count=cusage[x]; + background=x; + + } + } + + for(cy=0; cy<25; cy++) + { + //printf("\ny:%2d ",cy); + for(cx=0; cx<40; cx++) + { + numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); + if(numcolors>4) + { + Warning_message("More than 4 colors in 4x8"); + // TODO hilite offending block + return 1; + } + color=1; + c[0]=background; + for(i=0; i<16; i++) + { + lut[i]=0; + if(cusage[i]) + { + if(i!=background) + { + lut[i]=color; + c[color]=i; + color++; + } + else + { + lut[i]=0; + } + } + } + // add to screen and nybble + screen[cx+cy*40]=c[1]<<4|c[2]; + nybble[cx+cy*40]=c[3]; + //printf("%x%x%x ",c[1],c[2],c[3]); + for(y=0;y<8;y++) + { + bits=0; + for(x=0;x<4;x++) + { + pixel=Read_pixel_function(cx*4+x,cy*8+y); + if(pixel>15) + { + Warning_message("Color above 15 used"); + // TODO hilite as in hires, you should stay to + // the fixed 16 color palette + return 1; + } + bits=bits<<2; + bits|=lut[pixel]; + + } + Write_byte(file,bits&255); + } + } + } + Write_bytes(file,screen,1000); + Write_bytes(file,nybble,1000); + Write_byte(file,background); + //printf("\nbg:%d\n",background); + return 0; +} + +void Save_C64(void) +{ + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + dword numcolors,cusage[256]; + numcolors=Count_used_colors(cusage); + + if(numcolors>16) + { + Warning_message("Error: Max 16 colors"); + File_error = 1; + return; + } + if(((Main_image_width!=320) && (Main_image_width!=160)) || Main_image_height!=200) + { + Warning_message("must be 320x200 or 160x200"); + File_error = 1; + return; + } + + Get_full_filename(filename,0); + file = fopen(filename,"wb"); + + if(!file) + { + Warning_message("File open failed"); + File_error = 1; + return; + } + + if(Main_image_width==320) + File_error = Save_C64_hires(file); + else + File_error = Save_C64_multi(file); + + fclose(file); + +} + ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //////////////////////////////////// PNG //////////////////////////////////// diff --git a/misc.c b/misc.c index ed70e042..fc6d00f9 100644 --- a/misc.c +++ b/misc.c @@ -35,696 +35,737 @@ #include "palette.h" #include "input.h" +///Count used palette indexes in the whole picture +///Return the total number of different colors +///Fill in "usage" with the count for each color word Count_used_colors(dword* usage) { - int nb_pixels=0; - Uint8* current_pixel=Main_screen; - Uint8 color; - word nb_colors=0; - int i; + int nb_pixels = 0; + Uint8* current_pixel = Main_screen; + Uint8 color; + word nb_colors = 0; + int i; - for (i=0;i<256;i++) usage[i]=0; + for (i = 0; i < 256; i++) usage[i]=0; - //Calcul du nombre de pixels dans l'image - nb_pixels=Main_image_height*Main_image_width; + // Compute total number of pixels in the picture + nb_pixels = Main_image_height * Main_image_width; - // On parcourt l'écran courant pour compter les utilisations des couleurs - for(i=0;i0;dx--) - { - // Pour chaque pixel - for(cx=width;cx>0;cx--) - { - *buffer = conversion_table[*buffer]; - buffer++; - } - buffer += buffer_width-width; - } + // Pour chaque ligne + for(dx=height;dx>0;dx--) + { + // Pour chaque pixel + for(cx=width;cx>0;cx--) + { + *buffer = conversion_table[*buffer]; + buffer++; + } + 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_screen; //Adr départ image (ESI) - byte* dest=Brush; //Adr dest brosse (EDI) - int dx; + byte* src=start_y*image_width+start_x+Main_screen; //Adr départ image (ESI) + byte* dest=Brush; //Adr dest brosse (EDI) + int dx; - for (dx=Brush_height;dx!=0;dx--) - //Pour chaque ligne - { + for (dx=Brush_height;dx!=0;dx--) + //Pour chaque ligne + { - // On fait une copie de la ligne - memcpy(dest,src,Brush_width); + // On fait une copie de la ligne + memcpy(dest,src,Brush_width); - // On passe à la ligne suivante - src+=image_width; - dest+=Brush_width; - } + // On passe à la ligne suivante + src+=image_width; + dest+=Brush_width; + } } byte Read_pixel_from_feedback_screen (word x,word y) { - return *(FX_feedback_screen+y*Main_image_width+x); + return *(FX_feedback_screen+y*Main_image_width+x); } dword Round_div(dword numerator,dword divisor) { - return numerator/divisor; + return numerator/divisor; } byte Effect_sieve(word x,word y) { - return Sieve[x % Sieve_width][y % Sieve_height]; + return Sieve[x % Sieve_width][y % Sieve_height]; } void Replace_colors_within_limits(byte * replace_table) { - int line; - int counter; - byte* Adresse; + int line; + int counter; + byte* Adresse; - byte old; + byte old; - // Pour chaque ligne : - for(line = Limit_top;line <= Limit_bottom; line++) - { - // Pour chaque pixel sur la ligne : - for (counter = Limit_left;counter <= Limit_right;counter ++) - { - Adresse = Main_screen+line*Main_image_width+counter; - old=*Adresse; - *Adresse = replace_table[old]; - } - } + // Pour chaque ligne : + for(line = Limit_top;line <= Limit_bottom; line++) + { + // Pour chaque pixel sur la ligne : + for (counter = Limit_left;counter <= Limit_right;counter ++) + { + Adresse = Main_screen+line*Main_image_width+counter; + old=*Adresse; + *Adresse = replace_table[old]; + } + } } byte Read_pixel_from_backup_screen (word x,word y) { - return *(Screen_backup + x + Main_image_width * y); + return *(Screen_backup + x + Main_image_width * y); } void Palette_256_to_64(T_Palette palette) { - int i; - for(i=0;i<256;i++) - { - palette[i].R = palette[i].R >> 2; - palette[i].G = palette[i].G >> 2; - palette[i].B = palette[i].B >> 2; - } + int i; + for(i=0;i<256;i++) + { + palette[i].R = palette[i].R >> 2; + palette[i].G = palette[i].G >> 2; + palette[i].B = palette[i].B >> 2; + } } void Palette_64_to_256(T_Palette palette) { - int i; - for(i=0;i<256;i++) - { - palette[i].R = (palette[i].R << 2)|(palette[i].R >> 4); - palette[i].G = (palette[i].G << 2)|(palette[i].G >> 4); - palette[i].B = (palette[i].B << 2)|(palette[i].B >> 4); - } + int i; + for(i=0;i<256;i++) + { + palette[i].R = (palette[i].R << 2)|(palette[i].R >> 4); + palette[i].G = (palette[i].G << 2)|(palette[i].G >> 4); + palette[i].B = (palette[i].B << 2)|(palette[i].B >> 4); + } } byte Effect_interpolated_colorize (word x,word y,byte color) { - // factor_a = 256*(100-Colorize_opacity)/100 - // factor_b = 256*( Colorize_opacity)/100 - // - // (Couleur_dessous*factor_a+color*facteur_B)/256 - // + // factor_a = 256*(100-Colorize_opacity)/100 + // factor_b = 256*( Colorize_opacity)/100 + // + // (Couleur_dessous*factor_a+color*facteur_B)/256 + // - // On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la - // palette des teintes) et dans EDI, 3*color. - byte color_under = Read_pixel_from_feedback_screen(x,y); - byte blue_under=Main_palette[color_under].B; - byte blue=Main_palette[color].B; - byte green_under=Main_palette[color_under].G; - byte green=Main_palette[color].G; - byte red_under=Main_palette[color_under].R; - byte red=Main_palette[color].R; + // On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la + // palette des teintes) et dans EDI, 3*color. + byte color_under = Read_pixel_from_feedback_screen(x,y); + byte blue_under=Main_palette[color_under].B; + byte blue=Main_palette[color].B; + byte green_under=Main_palette[color_under].G; + byte green=Main_palette[color].G; + byte red_under=Main_palette[color_under].R; + byte red=Main_palette[color].R; - // On récupère les 3 composantes RVB + // On récupère les 3 composantes RVB - // blue - blue = (Factors_inv_table[blue] - + Factors_table[blue_under]) / 256; - green = (Factors_inv_table[green] - + Factors_table[green_under]) / 256; - red = (Factors_inv_table[red] - + Factors_table[red_under]) / 256; - return Best_color(red,green,blue); + // blue + blue = (Factors_inv_table[blue] + + Factors_table[blue_under]) / 256; + green = (Factors_inv_table[green] + + Factors_table[green_under]) / 256; + red = (Factors_inv_table[red] + + Factors_table[red_under]) / 256; + return Best_color(red,green,blue); } byte Effect_additive_colorize (word x,word y,byte color) { - byte color_under = Read_pixel_from_feedback_screen(x,y); - byte blue_under=Main_palette[color_under].B; - byte green_under=Main_palette[color_under].G; - byte red_under=Main_palette[color_under].R; - byte blue=Main_palette[color].B; - byte green=Main_palette[color].G; - byte red=Main_palette[color].R; + byte color_under = Read_pixel_from_feedback_screen(x,y); + byte blue_under=Main_palette[color_under].B; + byte green_under=Main_palette[color_under].G; + byte red_under=Main_palette[color_under].R; + byte blue=Main_palette[color].B; + byte green=Main_palette[color].G; + byte red=Main_palette[color].R; - return Best_color( - red>red_under?red:red_under, - green>green_under?green:green_under, - blue>blue_under?blue:blue_under); + return Best_color( + red>red_under?red:red_under, + green>green_under?green:green_under, + blue>blue_under?blue:blue_under); } byte Effect_substractive_colorize(word x,word y,byte color) { - byte color_under = Read_pixel_from_feedback_screen(x,y); - byte blue_under=Main_palette[color_under].B; - byte green_under=Main_palette[color_under].G; - byte red_under=Main_palette[color_under].R; - byte blue=Main_palette[color].B; - byte green=Main_palette[color].G; - byte red=Main_palette[color].R; + byte color_under = Read_pixel_from_feedback_screen(x,y); + byte blue_under=Main_palette[color_under].B; + byte green_under=Main_palette[color_under].G; + byte red_under=Main_palette[color_under].R; + byte blue=Main_palette[color].B; + byte green=Main_palette[color].G; + byte red=Main_palette[color].R; - return Best_color( - redTimer_start) Timer_state=1; + if((SDL_GetTicks()/55)-Timer_delay>Timer_start) Timer_state=1; } void Flip_Y_lowlevel(byte *src, short width, short height) { - // ESI pointe sur la partie haute de la brosse - // EDI sur la partie basse - byte* ESI = src ; - byte* EDI = src + (height - 1) *width; - byte tmp; - word cx; + // ESI pointe sur la partie haute de la brosse + // EDI sur la partie basse + byte* ESI = src ; + byte* EDI = src + (height - 1) *width; + byte tmp; + word cx; - while(ESI < EDI) - { - // Il faut inverser les lignes pointées par ESI et - // EDI ("Brush_width" octets en tout) + while(ESI < EDI) + { + // Il faut inverser les lignes pointées par ESI et + // EDI ("Brush_width" octets en tout) - for(cx = width;cx>0;cx--) - { - tmp = *ESI; - *ESI = *EDI; - *EDI = tmp; - ESI++; - EDI++; - } + for(cx = width;cx>0;cx--) + { + tmp = *ESI; + *ESI = *EDI; + *EDI = tmp; + ESI++; + EDI++; + } - // On change de ligne : - // ESI pointe déjà sur le début de la ligne suivante - // EDI pointe sur la fin de la ligne en cours, il - // doit pointer sur le début de la précédente... - EDI -= 2 * width; // On recule de 2 lignes - } + // On change de ligne : + // ESI pointe déjà sur le début de la ligne suivante + // EDI pointe sur la fin de la ligne en cours, il + // doit pointer sur le début de la précédente... + EDI -= 2 * width; // On recule de 2 lignes + } } void Flip_X_lowlevel(byte *src, short width, short height) { - // ESI pointe sur la partie gauche et EDI sur la partie - // droite - byte* ESI = src; - byte* EDI = src + width - 1; + // ESI pointe sur la partie gauche et EDI sur la partie + // droite + byte* ESI = src; + byte* EDI = src + width - 1; - byte* line_start; - byte* line_end; - byte tmp; - word cx; + byte* line_start; + byte* line_end; + byte tmp; + word cx; - while(ESI0;cx--) - { - tmp=*ESI; - *ESI=*EDI; - *EDI=tmp; - EDI+=width; - ESI+=width; - } + // On échange par colonnes + for(cx=height;cx>0;cx--) + { + tmp=*ESI; + *ESI=*EDI; + *EDI=tmp; + EDI+=width; + ESI+=width; + } - // On change de colonne - // ESI > colonne suivante - // EDI > colonne précédente - ESI = line_start + 1; - EDI = line_end - 1; - } + // On change de colonne + // ESI > colonne suivante + // EDI > colonne précédente + ESI = line_start + 1; + EDI = line_end - 1; + } } // Rotate a pixel buffer 180º on itself. void Rotate_180_deg_lowlevel(byte *src, short width, short height) { - // ESI pointe sur la partie supérieure de la brosse - // EDI pointe sur la partie basse - byte* ESI = src; - byte* EDI = src + height*width - 1; - // EDI pointe sur le dernier pixel de la derniere ligne - byte tmp; - word cx; + // ESI pointe sur la partie supérieure de la brosse + // EDI pointe sur la partie basse + byte* ESI = src; + byte* EDI = src + height*width - 1; + // EDI pointe sur le dernier pixel de la derniere ligne + byte tmp; + word cx; - // In case of odd height, the algorithm in this function would - // miss the middle line, so we do it this way: - if (height & 1) - { - Flip_X_lowlevel(src, width, height); - Flip_Y_lowlevel(src, width, height); - return; - } + // In case of odd height, the algorithm in this function would + // miss the middle line, so we do it this way: + if (height & 1) + { + Flip_X_lowlevel(src, width, height); + Flip_Y_lowlevel(src, width, height); + return; + } - while(ESI < EDI) - { - // On échange les deux lignes pointées par EDI et - // ESI (Brush_width octets) - // En même temps, on échange les pixels, donc EDI - // pointe sur la FIN de sa ligne + while(ESI < EDI) + { + // On échange les deux lignes pointées par EDI et + // ESI (Brush_width octets) + // En même temps, on échange les pixels, donc EDI + // pointe sur la FIN de sa ligne - for(cx=width;cx>0;cx--) - { - tmp = *ESI; - *ESI = *EDI; - *EDI = tmp; + for(cx=width;cx>0;cx--) + { + tmp = *ESI; + *ESI = *EDI; + *EDI = tmp; - EDI--; // Attention ici on recule ! - ESI++; - } - } + EDI--; // Attention ici on recule ! + ESI++; + } + } } void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped) { - int offset,line,column; + int offset,line,column; - int x_pos_in_brush; // Position courante dans l'ancienne brosse - int y_pos_in_brush; - int delta_x_in_brush; // "Vecteur incrémental" du point précédent - int delta_y_in_brush; - int initial_x_pos; // Position X de début de parcours de ligne - - // Calcul du "vecteur incrémental": - delta_x_in_brush=(src_width<<16) * (x_flipped?-1:1) / (dst_width); - delta_y_in_brush=(src_height<<16) * (y_flipped?-1:1) / (dst_height); + int x_pos_in_brush; // Position courante dans l'ancienne brosse + int y_pos_in_brush; + int delta_x_in_brush; // "Vecteur incrémental" du point précédent + int delta_y_in_brush; + int initial_x_pos; // Position X de début de parcours de ligne - offset=0; + // Calcul du "vecteur incrémental": + delta_x_in_brush=(src_width<<16) * (x_flipped?-1:1) / (dst_width); + delta_y_in_brush=(src_height<<16) * (y_flipped?-1:1) / (dst_height); - // Calcul de la valeur initiale de y_pos: - if (y_flipped) - y_pos_in_brush=(src_height<<16)-1; // Inversion en Y de la brosse - else - y_pos_in_brush=0; // Pas d'inversion en Y de la brosse + offset=0; - // Calcul de la valeur initiale de x_pos pour chaque ligne: - if (x_flipped) - initial_x_pos = (src_width<<16)-1; // Inversion en X de la brosse - else - initial_x_pos = 0; // Pas d'inversion en X de la brosse - - // Pour chaque ligne - for (line=0;line>16) + (y_pos_in_brush>>16)*src_width); - // On passe à la colonne de brosse suivante: - x_pos_in_brush+=delta_x_in_brush; - // On passe au pixel suivant de la nouvelle brosse: - offset++; - } - // On passe à la ligne de brosse suivante: - y_pos_in_brush+=delta_y_in_brush; - } + // Calcul de la valeur initiale de x_pos pour chaque ligne: + if (x_flipped) + initial_x_pos = (src_width<<16)-1; // Inversion en X de la brosse + else + initial_x_pos = 0; // Pas d'inversion en X de la brosse + + // Pour chaque ligne + for (line=0;line>16) + (y_pos_in_brush>>16)*src_width); + // On passe à la colonne de brosse suivante: + x_pos_in_brush+=delta_x_in_brush; + // On passe au pixel suivant de la nouvelle brosse: + offset++; + } + // On passe à la ligne de brosse suivante: + y_pos_in_brush+=delta_y_in_brush; + } } void Slider_timer(byte speed) -//Boucle d'attente pour faire bouger les scrollbars à une vitesse correcte + //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()0;dx--) - { - // Pour chaque ligne - memcpy(edi,esi,ax); - memcpy(edi - x_offset,esi+ax,x_offset); + byte* esi = Screen_backup; //source de la copie + byte* edi = Main_screen + y_offset * Main_image_width + x_offset; + const word ax = Main_image_width - x_offset; // Nombre de pixels à copier à droite + word dx; + for(dx = Main_image_height - y_offset;dx>0;dx--) + { + // Pour chaque ligne + memcpy(edi,esi,ax); + memcpy(edi - x_offset,esi+ax,x_offset); - // On passe à la ligne suivante - edi += Main_image_width; - esi += Main_image_width; - } + // On passe à la ligne suivante + edi += Main_image_width; + esi += Main_image_width; + } - // On vient de faire le traitement pour otutes les lignes au-dessous de y_offset - // Maintenant on traite celles au dessus - edi = x_offset + Main_screen; - for(dx = y_offset;dx>0;dx--) - { - memcpy(edi,esi,ax); - memcpy(edi - x_offset,esi+ax,x_offset); + // On vient de faire le traitement pour otutes les lignes au-dessous de y_offset + // Maintenant on traite celles au dessus + edi = x_offset + Main_screen; + for(dx = y_offset;dx>0;dx--) + { + memcpy(edi,esi,ax); + memcpy(edi - x_offset,esi+ax,x_offset); - edi += Main_image_width; - esi += Main_image_width; - } + edi += Main_image_width; + esi += Main_image_width; + } - Update_rect(0,0,0,0); + Update_rect(0,0,0,0); } void Zoom_a_line(byte* original_line, byte* zoomed_line, - word factor, word width -) + word factor, word width + ) { - byte color; - word x; + byte color; + word x; - // Pour chaque pixel - for(x=0;x +#define _WIN32_WINNT 0x0500 +#include #elif defined(__macosx__) || defined(__FreeBSD__) - #include +#include #elif defined(__BEOS__) || defined(__HAIKU__) - // sysinfo not implemented +// sysinfo not implemented #elif defined(__AROS__) || defined(__amigaos4__) || defined(__MORPHOS__) || defined(__amigaos__) - #include +#include #elif defined(__SKYOS__) - #include +#include #else - #include // sysinfo() for free RAM +#include // sysinfo() for free RAM #endif // Indique quelle est la mémoire disponible unsigned long Memory_free(void) { - // Memory is no longer relevant. If there is ANY problem or doubt here, - // you can simply return 10*1024*1024 (10Mb), to make the "Pages"something - // memory allocation functions happy. + // Memory is no longer relevant. If there is ANY problem or doubt here, + // you can simply return 10*1024*1024 (10Mb), to make the "Pages"something + // memory allocation functions happy. - // However, it is still a good idea to make a proper function if you can... - // If Grafx2 thinks the memory is full, weird things may happen. And if memory - // ever becomes full and you're still saying there are 10MB free here, the - // program will crash without saving any picture backup ! You've been warned... - #if defined(__WIN32__) - MEMORYSTATUS mstt; - mstt.dwLength = sizeof(MEMORYSTATUS); - GlobalMemoryStatus(&mstt); - return mstt.dwAvailPhys; - #elif defined(__macosx__) || defined(__FreeBSD__) - int mib[2]; - int maxmem; - size_t len; + // However, it is still a good idea to make a proper function if you can... + // If Grafx2 thinks the memory is full, weird things may happen. And if memory + // ever becomes full and you're still saying there are 10MB free here, the + // program will crash without saving any picture backup ! You've been warned... +#if defined(__WIN32__) + MEMORYSTATUS mstt; + mstt.dwLength = sizeof(MEMORYSTATUS); + GlobalMemoryStatus(&mstt); + return mstt.dwAvailPhys; +#elif defined(__macosx__) || defined(__FreeBSD__) + int mib[2]; + int maxmem; + size_t len; - mib[0] = CTL_HW; - mib[1] = HW_USERMEM; - len = sizeof(maxmem); - sysctl(mib,2,&maxmem,&len,NULL,0); - return maxmem; - #elif defined(__BEOS__) || defined(__HAIKU__) || defined(__SKYOS__) || defined(__amigaos4__) || defined(__amigaos__) - // No on BeOS or Haiku - // AvailMem is misleading on os4 (os4 caches stuff in memory that you can still allocate) - #warning "There is missing code there for your platform ! please check and correct :)" - return 10*1024*1024; - #elif defined(__AROS__) || defined(__MORPHOS__) - return AvailMem(MEMF_ANY); - #else - struct sysinfo info; - sysinfo(&info); - return info.freeram*info.mem_unit; - #endif + mib[0] = CTL_HW; + mib[1] = HW_USERMEM; + len = sizeof(maxmem); + sysctl(mib,2,&maxmem,&len,NULL,0); + return maxmem; +#elif defined(__BEOS__) || defined(__HAIKU__) || defined(__SKYOS__) || defined(__amigaos4__) || defined(__amigaos__) + // No on BeOS or Haiku + // AvailMem is misleading on os4 (os4 caches stuff in memory that you can still allocate) +#warning "There is missing code there for your platform ! please check and correct :)" + return 10*1024*1024; +#elif defined(__AROS__) || defined(__MORPHOS__) + return AvailMem(MEMF_ANY); +#else + struct sysinfo info; + sysinfo(&info); + return info.freeram*info.mem_unit; +#endif } @@ -732,51 +773,51 @@ unsigned long Memory_free(void) // Transformer un nombre (entier naturel) en chaîne void Num2str(dword number,char * str,byte nb_char) { - int index; + int index; - for (index=nb_char-1;index>=0;index--) - { - str[index]=(number%10)+'0'; - number/=10; - if (number==0) - for (index--;index>=0;index--) - str[index]=' '; - } - str[nb_char]='\0'; + for (index=nb_char-1;index>=0;index--) + { + str[index]=(number%10)+'0'; + number/=10; + if (number==0) + for (index--;index>=0;index--) + str[index]=' '; + } + str[nb_char]='\0'; } // Arrondir un nombre réel à la valeur entière la plus proche short Round(float value) { - short temp=value; + short temp=value; - if (value>=0) - { if ((value-temp)>= 0.5) temp++; } - else - { if ((value-temp)<=-0.5) temp--; } + if (value>=0) + { if ((value-temp)>= 0.5) temp++; } + else + { if ((value-temp)<=-0.5) temp--; } - return temp; + return temp; } // Arrondir le résultat d'une division à la valeur entière supérieure short Round_div_max(short numerator,short divisor) { - if (!(numerator % divisor)) - return (numerator/divisor); - else - return (numerator/divisor)+1; + if (!(numerator % divisor)) + return (numerator/divisor); + else + return (numerator/divisor)+1; } // Retourne le minimum entre deux nombres int Min(int a,int b) { - return (ab)?a:b; + return (a>b)?a:b; } @@ -784,12 +825,12 @@ int Max(int a,int b) // Fonction retournant le libellé d'une mode (ex: " 320x200") char * Mode_label(int mode) { - static char str[24]; - if (! Video_mode[mode].Fullscreen) - return "window"; - sprintf(str, "%dx%d", Video_mode[mode].Width, Video_mode[mode].Height); + static char str[24]; + if (! Video_mode[mode].Fullscreen) + return "window"; + sprintf(str, "%dx%d", Video_mode[mode].Width, Video_mode[mode].Height); - return str; + return str; } // Trouve un mode video à partir d'une chaine: soit "window", @@ -797,12 +838,12 @@ char * Mode_label(int mode) // Renvoie -1 si la chaine n'est pas convertible int Convert_videomode_arg(const char *argument) { - // Je suis paresseux alors je vais juste tester les libellés - int mode_index; - for (mode_index=0; mode_index Date: Sat, 5 Sep 2009 16:22:35 +0000 Subject: [PATCH 84/95] Added c64 picture samples Put the correct version of loadsave.c. Sorry I'm a little ill today. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1014 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 155 ++++++++++++++++++++----------------- pic-samples/hires.c64 | Bin 0 -> 9000 bytes pic-samples/multicolor.c64 | Bin 0 -> 10001 bytes 3 files changed, 86 insertions(+), 69 deletions(-) create mode 100644 pic-samples/hires.c64 create mode 100644 pic-samples/multicolor.c64 diff --git a/loadsave.c b/loadsave.c index 81767e2c..511e2976 100644 --- a/loadsave.c +++ b/loadsave.c @@ -634,53 +634,50 @@ void Load_image(byte image) } else { - // Cas d'un chargement dans la brosse - if (Convert_24b_bitmap_to_256(Brush, Buffer_image_24b, Brush_width, - Brush_height, Main_palette)) - File_error = 2; + // Cas d'un chargement dans la brosse + if (Convert_24b_bitmap_to_256(Brush,Buffer_image_24b,Brush_width,Brush_height,Main_palette)) + File_error=2; } //if (!File_error) - // Palette_256_to_64(Main_palette); + // Palette_256_to_64(Main_palette); // Normalement plus besoin car 256 color natif, et c'etait probablement // un bug - yr } - free(Buffer_image_24b); - } + free(Buffer_image_24b); + } - if (image) - { + if (image) + { if ( (File_error!=1) && (File_formats[format].Backup_done) ) { if (Pixel_load_function==Pixel_load_in_preview) { - dword color_usage[256]; - Count_used_colors_screen_area(color_usage, Preview_pos_X, - Preview_pos_Y, Main_image_width / Preview_factor_X, - Main_image_height / Preview_factor_Y); + dword color_usage[256]; + Count_used_colors_area(color_usage,Preview_pos_X,Preview_pos_Y,Main_image_width/Preview_factor_X,Main_image_height/Preview_factor_Y); //Count_used_colors(color_usage); Display_cursor(); - Set_nice_menu_colors(color_usage, 1); + Set_nice_menu_colors(color_usage,1); Hide_cursor(); } // On considère que l'image chargée n'est plus modifiée - Main_image_is_modified = 0; + Main_image_is_modified=0; // Et on documente la variable Main_fileformat avec la valeur: - Main_fileformat = format + 1; + Main_fileformat=format+1; // Correction des dimensions if (Main_image_width<1) - Main_image_width = 1; + Main_image_width=1; if (Main_image_height<1) - Main_image_height = 1; + Main_image_height=1; } else if (File_error!=1) { // On considère que l'image chargée est encore modifiée - Main_image_is_modified = 1; + Main_image_is_modified=1; // Et on documente la variable Main_fileformat avec la valeur: - Main_fileformat = format + 1; + Main_fileformat=format+1; } else { @@ -5854,10 +5851,10 @@ void Test_C64(void) file = fopen(filename,"rb"); - if(file) + if (file) { file_size = File_length_file(file); - switch(file_size) + switch (file_size) { case 8000: // raw bitmap case 8002: // raw bitmap with loadaddr @@ -5871,7 +5868,7 @@ void Test_C64(void) File_error = 1; } - fclose(file); + fclose (file); } else { @@ -6003,12 +6000,13 @@ void Load_C64(void) File_error = 1; } -int Save_C64_hires(FILE *file) +int Save_C64_hires(char *filename) { - int cx,cy,x,y,c1,c2,i,pixel,bits; + int cx,cy,x,y,c1,c2,i,pixel,bits,pos=0; word numcolors; dword cusage[256]; - byte colors[1000]; + byte colors[1000],bitmap[8000]; + FILE *file; for(x=0;x<1000;x++)colors[x]=1; // init colormem to black/white @@ -6018,8 +6016,8 @@ int Save_C64_hires(FILE *file) { for(i=0;i<256;i++) cusage[i]=0; - numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); - if(numcolors>2) + numcolors=Count_used_colors_screen_area(cusage,cx*8,cy*8,8,8); + if (numcolors>2) { Warning_message("More than 2 colors in 8x8 pixels"); // TODO here we should hilite the offending block @@ -6040,7 +6038,6 @@ int Save_C64_hires(FILE *file) if(cusage[i]) { c1=i; - } } colors[cx+cy*40]=(c2<<4)|c1; @@ -6060,17 +6057,31 @@ int Save_C64_hires(FILE *file) return 1; } bits=bits<<1; - if(pixel==c1) bits|=1; + if (pixel==c1) bits|=1; } - Write_byte(file,bits&255); + bitmap[pos++]=bits; + //Write_byte(file,bits&255); } } } + + file = fopen(filename,"wb"); + + if(!file) + { + Warning_message("File open failed"); + File_error = 1; + return 1; + } + + Write_bytes(file,bitmap,8000); Write_bytes(file,colors,1000); + + fclose(file); return 0; } -int Save_C64_multi(FILE *file) +int Save_C64_multi(char *filename) { /* BITS COLOR INFORMATION COMES FROM @@ -6080,11 +6091,13 @@ BITS COLOR INFORMATION COMES FROM 11 Color nybble (nybble = 1/2 byte = 4 bits) */ - int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel; - byte screen[1000],nybble[1000]; + int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; + byte bitmap[8000],screen[1000],nybble[1000]; word numcolors,count; dword cusage[256]; byte i,background=0; + FILE *file; + numcolors=Count_used_colors(cusage); count=0; @@ -6104,7 +6117,7 @@ BITS COLOR INFORMATION COMES FROM //printf("\ny:%2d ",cy); for(cx=0; cx<40; cx++) { - numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); + numcolors=Count_used_colors_screen_area(cusage,cx*4,cy*8,4,8); if(numcolors>4) { Warning_message("More than 4 colors in 4x8"); @@ -6151,53 +6164,57 @@ BITS COLOR INFORMATION COMES FROM bits|=lut[pixel]; } - Write_byte(file,bits&255); + //Write_byte(file,bits&255); + bitmap[pos++]=bits; } } } - Write_bytes(file,screen,1000); - Write_bytes(file,nybble,1000); - Write_byte(file,background); - //printf("\nbg:%d\n",background); - return 0; -} - -void Save_C64(void) -{ - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - dword numcolors,cusage[256]; - numcolors=Count_used_colors(cusage); - - if(numcolors>16) - { - Warning_message("Error: Max 16 colors"); - File_error = 1; - return; - } - if(((Main_image_width!=320) && (Main_image_width!=160)) || Main_image_height!=200) - { - Warning_message("must be 320x200 or 160x200"); - File_error = 1; - return; - } - Get_full_filename(filename,0); file = fopen(filename,"wb"); if(!file) { Warning_message("File open failed"); File_error = 1; - return; + return 1; } - - if(Main_image_width==320) - File_error = Save_C64_hires(file); - else - File_error = Save_C64_multi(file); + Write_bytes(file,bitmap,8000); + Write_bytes(file,screen,1000); + Write_bytes(file,nybble,1000); + Write_byte(file,background); fclose(file); + //printf("\nbg:%d\n",background); + return 0; +} + +void Save_C64(void) +{ + char filename[MAX_PATH_CHARACTERS]; + dword numcolors,cusage[256]; + numcolors=Count_used_colors(cusage); + + Get_full_filename(filename,0); + + if (numcolors>16) + { + Warning_message("Error: Max 16 colors"); + File_error = 1; + return; + } + if (((Main_image_width!=320) && (Main_image_width!=160)) || Main_image_height!=200) + { + Warning_message("must be 320x200 or 160x200"); + File_error = 1; + return; + } + + if (Main_image_width==320) + File_error = Save_C64_hires(filename); + else + File_error = Save_C64_multi(filename); + + //fclose(file); } diff --git a/pic-samples/hires.c64 b/pic-samples/hires.c64 new file mode 100644 index 0000000000000000000000000000000000000000..86ed2f5fe268e096adb3cf52d9cbd6ce4c4374cb GIT binary patch literal 9000 zcmds6J#5=X6h2z1Y`8-G6Q|)2)R{VHD2R5+R4aRj3>LBk2!#}#(>;J_NNAU!$>`Bz zpbS~Ng|>ktL)Y#yvUN&_0zuH2eZSNlC5nz-@o9Kez+UXnSU!nIm&Vw^i_An$X0zH}GUunf-bDc^VhQcNf~S$w$cDU(nJx zKeYd#CM&r!Xi?KOLhd4HrtCV5F)P&4+)T0Mf3fhVACjJ?~PUf|LyCpV-0(+$lt8vW}RA7zn5zRY}V{AN4dl3 zy3}U%K5o}&Y*7AcwS@AwCUWm#=Qc|B^Z;@dMH~Lp!zVpshCx6dk;<+4H;z zI02<|)*<<9pLf0~xW$uRm3)h+ZR&Gj0&YjA z0OH$uSK``x9`C3qV%?FQr-v4y3G*Q4@yG93yIzWWnm;}zw?@ysig3$O!R|{v<0;uW z=Q+4#w!L2*_>x#?{xWQfxFsnYCgB#(dXhiHt+V%-ZBx!Di`%?-VKH>>({bpZoWyZV zi-d=z=oG)wAF6$x#xt_Rw}jdX&w1;F+NS2udg3ADTjxAxj&5F{C9hNR=)EJM)SQT1 zzu|A9>;_@j?S|p$tM9*jJ2d7!ysE_TQ8X>HZ3ee+(kr^JXqjTmaA6NxM?ep{n;ucXm4Y$a)7H-SEq2XG6 z5Y#}Ub<~)eymeP~UH1oaEwrP`{5ovwobx8&cJXtb#tW(2#r#3)&MAL{%FWHSU(Zf^ zAi?=hH7`lb>TYl|_yXS1;xNPyy?;@i=I;m?y!U180SdF!LoM8LWhLvU>b{gsp>E127%7`d>GaAy#4s>VmvxOv*hIss<0$ec zsBP-=G=o~MtE6mOz8+c>kB&>(v>|2Fn$}IFY}%5t>9Lee52b7x=>3Gz?C((m_SKC|-GtpIgnuM?y8et!H0b^OlvXN`MV>8}r*QH4{Pd{NU1`TV=n8QALX1(BPd`TL!n){EksJ-etL8*fz!O zEcH;Vi2mP1@PUsH67Fw}NybjPVs@Pcdpw}tq=@d#XeVY{x&GW~)f_dArj7VcH3Lq+wg~Xz?hn4k_>}jg_5xwa|fP^?RIu{(2vU4 zv^oHGDB2y_Wu|4bkzM{O)D`LMYMnu=liFpbMU!hRWIb)#DR$OOll@uKe$L|DvZeFR RXXpB`d*aV>XOE8l{|8$4K>+{& literal 0 HcmV?d00001 diff --git a/pic-samples/multicolor.c64 b/pic-samples/multicolor.c64 new file mode 100644 index 0000000000000000000000000000000000000000..5ba01d02990de3a6bab4991b2eb00f114359cb1c GIT binary patch literal 10001 zcmeHMyKdt~6eY1{lV%M?LLQ}^CP?Y+HU*7XO@IJ2AhK|=*vbZ6Z0j^Zl5SNk5La@g z0I8^YE4#=C*g$^3`UE>)5a!%FGvsKc$QAb4VD7JuZ3omu876d6v-4oF*vFV-c( z+gEW^6-WIMr=IZKGAt0Pr{pJUn7>#c$~bG9qCB-ueFO#{y>&E#Wdt+PPjp_|~g$JJ`A`tII2Uh{w%WzV^NubvhP<qo%@Io z#NFHZd``LiAB6Kq(huG@fjskKV5bm&BrWdf$&Vx*cCW`!X4Ix9*vsA`UFIoCw#qF?nx0CeVo_0COOooKN%)4 zS>hw-IkrYGS9%dCl+k!X>o`X=k)A&#F3ZWf|0F&7{Vss#<~}a@tLuokV@Z$#f{Np0 z>tK>)pnwHKEX-7zjd(E04@JNE9&D40lHWgJ#C{y316&zZ;9-`?$D!%;&zi{wwp~&v{-kzd+dTFSc_|>6yRJpSu3~UKgYOWS7q? zrlxydv2(h5PC9s2hM7P4EJueg=VM-Br*pi)iQheI+bM*d#%^~!V8Rv;R3Y~BO3aII zDpdNA)Z_9&vF^7UT!K=q(bI7OyaUdzH)Thr)g3Qlp>QY`{ITfis5T*5e5pyk67Ovx z9lxGHxc$?65rJrXp%LCE4CtQcQFgQ`-o+|w^|cyUeSgt^H-_;X##djwd+qeIZ@lkU zc#*Nf&h=a6n0htOPCX=vKUe((-`Bl-$-)rT++81Jqc1xl`-WnX)CKbuTHik2{dPow zIr#!veev~BJMuA5@n}?{IG;40jd||E_0zroH3AB*0}i^WAH$4%uZ6^2>t`zQdEWCr zY5QnKXwBVq>b<`N^X0F1fpEstgs!zh?&GIVzE8A(InjW9!&K;cM%%w{429q>EQhX_ zv%X=6YK)}Yclhr{kDcKEcew3zN9i4f(NMme_1&YLex84Q`^L+R7r?KL>aW3IXJ>bJ zcW>|2tAm5_c#IRVI6gi(IXU}G6FchcM1_CB*!B}GpsP`lWid_6B0xr6LUGI_3QQ z9H?^f4XnW9SIA_rLtphpbbe#hVxh<%D*1F($kt+UdHMP^CwZ_c7?bh`qpq&d<(0%@ zb_&_Ly1KrWgjwt5<3~bW-~6B!vgYeOn3y3f1a?Wb0K2)l#d6EqAy#>b1YrojLESFj zyipY<*PD!Sk~(U+G*HYwQNb?R}yt{k%j;dAFj4t)z4azL`B;pp{mM31>!+A5?`Igo*Gas;a_JRn_- Date: Sat, 5 Sep 2009 17:02:18 +0000 Subject: [PATCH 85/95] We're going to get it right... Some vocabulary : -We call "screen" the pixels that the user actually sees, including any menu, cursor, opened window. So the function count_used_colors_screen_area counts colors there. -We call "picture" the pixels that make the full picture, as you want to save it. count_used_colors and count_used_colors_area counts color there. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1015 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loadsave.c b/loadsave.c index 511e2976..06ad33fe 100644 --- a/loadsave.c +++ b/loadsave.c @@ -654,7 +654,7 @@ void Load_image(byte image) if (Pixel_load_function==Pixel_load_in_preview) { dword color_usage[256]; - Count_used_colors_area(color_usage,Preview_pos_X,Preview_pos_Y,Main_image_width/Preview_factor_X,Main_image_height/Preview_factor_Y); + Count_used_colors_screen_area(color_usage,Preview_pos_X,Preview_pos_Y,Main_image_width/Preview_factor_X,Main_image_height/Preview_factor_Y); //Count_used_colors(color_usage); Display_cursor(); Set_nice_menu_colors(color_usage,1); @@ -6016,7 +6016,7 @@ int Save_C64_hires(char *filename) { for(i=0;i<256;i++) cusage[i]=0; - numcolors=Count_used_colors_screen_area(cusage,cx*8,cy*8,8,8); + numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); if (numcolors>2) { Warning_message("More than 2 colors in 8x8 pixels"); @@ -6117,7 +6117,7 @@ BITS COLOR INFORMATION COMES FROM //printf("\ny:%2d ",cy); for(cx=0; cx<40; cx++) { - numcolors=Count_used_colors_screen_area(cusage,cx*4,cy*8,4,8); + numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); if(numcolors>4) { Warning_message("More than 4 colors in 4x8"); From 2e46820b83951c2b41930cbb4459c553b96ca6a8 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 5 Sep 2009 19:49:18 +0000 Subject: [PATCH 86/95] Fixed tabulations to 2spaces (the most common in this file). Tiny bit of error-check on saving. Implemented preview scaling to display c64 widepixel pictures properly. Not done yet: Auto-set wide or wide2 pixels after loading a picture with wide pixels. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1016 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 857 ++++++++++++++++++++++++++++------------------------- 1 file changed, 447 insertions(+), 410 deletions(-) diff --git a/loadsave.c b/loadsave.c index 06ad33fe..c09294d6 100644 --- a/loadsave.c +++ b/loadsave.c @@ -121,7 +121,7 @@ void Load_PNG(void); void Save_PNG(void); #endif -void Init_preview(short width,short height,long size,int format); +void Init_preview(short width,short height,long size,int format,enum PIXEL_RATIO ratio); T_Format File_formats[NB_KNOWN_FORMATS] = { {"pkm", Test_PKM, Load_PKM, Save_PKM, 1, 1}, @@ -177,10 +177,35 @@ byte HBPm1; // header.BitPlanes-1 void Pixel_load_in_preview(word x_pos,word y_pos,byte color) { if (((x_pos % Preview_factor_X)==0) && ((y_pos % Preview_factor_Y)==0)) - if ((x_pos 127 alors il faut répéter 256-'temp_byte' fois la couleur de l'octet suivant // Si temp_byte <= 127 alors il faut afficher directement les 'temp_byte' octets suivants if (temp_byte>127) { - if(Read_byte(LBM_file, &color)!=1) - { - File_error=2; - break; - } + if(Read_byte(LBM_file, &color)!=1) + { + File_error=2; + break; + } b256=(short)(256-temp_byte); for (counter=0; counter<=b256; counter++) if (x_pos=line_size || Read_byte(LBM_file, &(LBM_buffer[x_pos++]))!=1) - File_error=2; + File_error=2; } if (!File_error) Draw_ILBM_line(y_pos,real_line_size); @@ -1967,17 +2001,17 @@ void Load_LBM(void) for (x_pos=0; ((x_pos127) { if(Read_byte(LBM_file, &color)!=1) - { - File_error=2; - break; - } + { + File_error=2; + break; + } b256=256-temp_byte; for (counter=0; counter<=b256; counter++) Pixel_load_function(x_pos++,y_pos,color); @@ -1987,10 +2021,10 @@ void Load_LBM(void) { byte byte_read=0; if(Read_byte(LBM_file, &byte_read)!=1) - { - File_error=2; - break; - } + { + File_error=2; + break; + } Pixel_load_function(x_pos++,y_pos,byte_read); } } @@ -2407,7 +2441,7 @@ void Load_BMP(void) if (!File_error) { - Init_preview(header.Width,header.Height,file_size,FORMAT_BMP); + Init_preview(header.Width,header.Height,file_size,FORMAT_BMP,PIXEL_SIMPLE); if (File_error==0) { if (Read_bytes(file,local_palette,nb_colors<<2)) @@ -2470,7 +2504,7 @@ void Load_BMP(void) /*Init_lecture();*/ if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) - File_error=2; + File_error=2; while (!File_error) { if (a) // Encoded mode @@ -2486,8 +2520,8 @@ void Load_BMP(void) case 1 : // End of bitmap break; case 2 : // Delta - if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) - File_error=2; + if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) + File_error=2; x_pos+=a; y_pos-=b; break; @@ -2495,7 +2529,7 @@ void Load_BMP(void) while (b) { if(Read_byte(file, &a)!=1) - File_error=2; + File_error=2; //Read_one_byte(file, &c); Pixel_load_function(x_pos++,y_pos,a); //if (--c) @@ -2510,9 +2544,9 @@ void Load_BMP(void) if (a==0 && b==1) break; if(Read_byte(file, &a) !=1 || Read_byte(file, &b)!=1) - { - File_error=2; - } + { + File_error=2; + } } /*Close_lecture();*/ break; @@ -2523,7 +2557,7 @@ void Load_BMP(void) /*Init_lecture();*/ if(Read_byte(file, &a)!=1 || Read_byte(file, &b) != 1) - File_error =2; + File_error =2; while ( (!File_error) && ((a)||(b!=1)) ) { if (a) // Encoded mode (A fois les 1/2 pixels de B) @@ -2546,7 +2580,7 @@ void Load_BMP(void) break; case 2 : // Delta if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) - File_error=2; + File_error=2; x_pos+=a; y_pos-=b; break; @@ -2892,10 +2926,10 @@ void Test_GIF(void) if (GIF_remainder_byte==0) // Lire l'octet nous donnant la taille du bloc de Raster Data suivant if(Read_byte(GIF_file, &GIF_remainder_byte)!=1) - File_error=2; + File_error=2; - if(Read_byte(GIF_file,&GIF_last_byte)!=1) - File_error = 2; + if(Read_byte(GIF_file,&GIF_last_byte)!=1) + File_error = 2; GIF_remainder_byte--; GIF_remainder_bits=8; } @@ -3131,7 +3165,7 @@ void Load_GIF(void) Main_image_width=IDB.Image_width; Main_image_height=IDB.Image_height; - Init_preview(IDB.Image_width,IDB.Image_height,file_size,FORMAT_GIF); + Init_preview(IDB.Image_width,IDB.Image_height,file_size,FORMAT_GIF,PIXEL_SIMPLE); // Palette locale dispo = (IDB.Indicator and $80) // Image entrelacée = (IDB.Indicator and $40) @@ -3803,7 +3837,7 @@ void Load_PCX(void) if (PCX_header.Plane!=3) { - Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_PCX); + Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_PCX,PIXEL_SIMPLE); if (File_error==0) { // On prépare la palette à accueillir les valeurs du fichier PCX @@ -4300,7 +4334,7 @@ void Load_CEL(void) Main_image_height=header1.Height; Original_screen_X=Main_image_width; Original_screen_Y=Main_image_height; - Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_CEL); + Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_CEL,PIXEL_SIMPLE); if (File_error==0) { // Chargement de l'image @@ -4330,7 +4364,7 @@ void Load_CEL(void) Main_image_height=header2.Height+header2.Y_offset; Original_screen_X=Main_image_width; Original_screen_Y=Main_image_height; - Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_CEL); + Init_preview(Main_image_width,Main_image_height,file_size,FORMAT_CEL,PIXEL_SIMPLE); if (File_error==0) { // Chargement de l'image @@ -4823,7 +4857,7 @@ void Load_SCx(void) if ((Read_bytes(file,&SCx_header,sizeof(T_SCx_Header)))) { - Init_preview(SCx_header.Width,SCx_header.Height,file_size,FORMAT_SCx); + Init_preview(SCx_header.Width,SCx_header.Height,file_size,FORMAT_SCx,PIXEL_SIMPLE); if (File_error==0) { if (!SCx_header.Planes) @@ -5121,7 +5155,7 @@ void Load_PI1(void) if (Read_bytes(file,buffer,32034)) { // Initialisation de la preview - Init_preview(320,200,File_length_file(file),FORMAT_PI1); + Init_preview(320,200,File_length_file(file),FORMAT_PI1,PIXEL_SIMPLE); if (File_error==0) { // Initialisation de la palette @@ -5455,7 +5489,7 @@ void Load_PC1(void) if (Read_bytes(file,buffercomp,size)) { // Initialisation de la preview - Init_preview(320,200,File_length_file(file),FORMAT_PC1); + Init_preview(320,200,File_length_file(file),FORMAT_PC1,PIXEL_SIMPLE); if (File_error==0) { // Initialisation de la palette @@ -5690,12 +5724,12 @@ void Test_NEO(void) size=File_length_file(file); if ((size==32128)) { - // Flag word : toujours 0 - if (Read_word_le(file,&resolution)) - { - if (resolution == 0) - File_error = 0; - } + // Flag word : toujours 0 + if (Read_word_le(file,&resolution)) + { + if (resolution == 0) + File_error = 0; + } // Lecture et vérification de la résolution if (Read_word_le(file,&resolution)) @@ -5732,13 +5766,13 @@ void Load_NEO(void) if (Read_bytes(file,buffer,32128)) { // Initialisation de la preview - Init_preview(320,200,File_length_file(file),FORMAT_NEO); + Init_preview(320,200,File_length_file(file),FORMAT_NEO,PIXEL_SIMPLE); if (File_error==0) { // Initialisation de la palette if (Config.Clear_palette) memset(Main_palette,0,sizeof(T_Palette)); - // on saute la résolution et le flag, chacun 2 bits + // on saute la résolution et le flag, chacun 2 bits PI1_decode_palette(buffer+4,(byte *)Main_palette); Set_palette(Main_palette); Remap_fileselector(); @@ -5843,379 +5877,380 @@ void Save_NEO(void) ///////////////////////////////////////////////////////////////////////////// void Test_C64(void) { - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - long file_size; + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + long file_size; - Get_full_filename(filename,0); + Get_full_filename(filename,0); - file = fopen(filename,"rb"); + file = fopen(filename,"rb"); - if (file) - { - file_size = File_length_file(file); - switch (file_size) - { - case 8000: // raw bitmap - case 8002: // raw bitmap with loadaddr - case 9000: // bitmap + screen - case 9002: // bitmap + screen + loadaddr - case 10001: // multicolor - case 10003: // multicolor + loadaddr - File_error = 0; - break; - default: // then we don't know for now. - File_error = 1; - - } - fclose (file); - } - else - { - File_error = 1; - } + if (file) + { + file_size = File_length_file(file); + switch (file_size) + { + case 8000: // raw bitmap + case 8002: // raw bitmap with loadaddr + case 9000: // bitmap + screen + case 9002: // bitmap + screen + loadaddr + case 10001: // multicolor + case 10003: // multicolor + loadaddr + File_error = 0; + break; + default: // then we don't know for now. + File_error = 1; + } + fclose (file); + } + else + { + File_error = 1; + } } void Load_C64_hires(byte *bitmap, byte *colors) -{ - int cx,cy,x,y,c[4],pixel,color; - - for(cy=0; cy<25; cy++) +{ + int cx,cy,x,y,c[4],pixel,color; + + for(cy=0; cy<25; cy++) + { + for(cx=0; cx<40; cx++) { - for(cx=0; cx<40; cx++) - { - c[1]=colors[cy*40+cx]&15; - c[0]=colors[cy*40+cx]>>4; - for(y=0; y<8; y++) - { - pixel=bitmap[cy*320+cx*8+y]; - for(x=0; x<8; x++) - { - color=c[pixel&(1<<(7-x))?1:0]; - Pixel_load_function(cx*8+x,cy*8+y,color); - } - } - } + c[1]=colors[cy*40+cx]&15; + c[0]=colors[cy*40+cx]>>4; + for(y=0; y<8; y++) + { + pixel=bitmap[cy*320+cx*8+y]; + for(x=0; x<8; x++) + { + color=c[pixel&(1<<(7-x))?1:0]; + Pixel_load_function(cx*8+x,cy*8+y,color); + } + } } + } } void Load_C64_multi(byte *bitmap, byte *colors, byte *nybble, byte background) { - int cx,cy,x,y,c[4],pixel,color; - c[0]=background; - for(cy=0; cy<25; cy++) + int cx,cy,x,y,c[4],pixel,color; + c[0]=background; + for(cy=0; cy<25; cy++) + { + for(cx=0; cx<40; cx++) { - 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]; - - for(y=0; y<8; y++) - { - pixel=bitmap[cy*320+cx*8+y]; - for(x=0; x<4; x++) - { - - color=c[(pixel&3)]; - pixel>>=2; - Pixel_load_function(cx*4+(3-x),cy*8+y,color); - } - } - } + c[1]=colors[cy*40+cx]>>4; + c[2]=colors[cy*40+cx]&15; + c[3]=nybble[cy*40+cx]; + + for(y=0; y<8; y++) + { + pixel=bitmap[cy*320+cx*8+y]; + for(x=0; x<4; x++) + { + color=c[(pixel&3)]; + pixel>>=2; + Pixel_load_function(cx*4+(3-x),cy*8+y,color); + } + } } + } } void Load_C64(void) { - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - long file_size; - int newPixel_ratio; - byte background; - - // Palette from http://www.pepto.de/projects/colorvic/ - byte pal[48]={ - 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, - 0x68, 0x37, 0x2B, - 0x70, 0xA4, 0xB2, - 0x6F, 0x3D, 0x86, - 0x58, 0x8D, 0x43, - 0x35, 0x28, 0x79, - 0xB8, 0xC7, 0x6F, - 0x6F, 0x4F, 0x25, - 0x43, 0x39, 0x00, - 0x9A, 0x67, 0x59, - 0x44, 0x44, 0x44, - 0x6C, 0x6C, 0x6C, - 0x9A, 0xD2, 0x84, - 0x6C, 0x5E, 0xB5, - 0x95, 0x95, 0x95}; + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + long file_size; + byte background; + + // Palette from http://www.pepto.de/projects/colorvic/ + byte pal[48]={ + 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, + 0x68, 0x37, 0x2B, + 0x70, 0xA4, 0xB2, + 0x6F, 0x3D, 0x86, + 0x58, 0x8D, 0x43, + 0x35, 0x28, 0x79, + 0xB8, 0xC7, 0x6F, + 0x6F, 0x4F, 0x25, + 0x43, 0x39, 0x00, + 0x9A, 0x67, 0x59, + 0x44, 0x44, 0x44, + 0x6C, 0x6C, 0x6C, + 0x9A, 0xD2, 0x84, + 0x6C, 0x5E, 0xB5, + 0x95, 0x95, 0x95}; - byte bitmap[8000],colors[1000],nybble[1000]; - word width=320, height=200; + byte bitmap[8000],colors[1000],nybble[1000]; + word width=320, height=200; + + Get_full_filename(filename,0); + file = fopen(filename,"rb"); + + if(file) + { - Get_full_filename(filename,0); - file = fopen(filename,"rb"); - - if(file) + memcpy(Main_palette,pal,48); // this set the software palette for grafx2 + Set_palette(Main_palette); // this set the hardware palette for SDL + Remap_fileselector(); // Always call it if you change the palette + + file_size = File_length_file(file); + + if(file_size>9002) { - - memcpy(Main_palette,pal,48); // this set the software palette for grafx2 - Set_palette(Main_palette); // this set the hardware palette for SDL - Remap_fileselector(); // Always call it if you change the palette - - file_size = File_length_file(file); - - if(file_size>9002)width=160; - - Init_preview(width, height, file_size, FORMAT_C64); // Do this as soon as you can - - Main_image_width = width ; - Main_image_height = height; - - Read_bytes(file,bitmap,8000); - if(file_size>8002)Read_bytes(file,colors,1000); - - if(width==160) - { - Read_bytes(file,nybble,1000); - Read_byte(file,&background); - Load_C64_multi(bitmap,colors,nybble,background); - newPixel_ratio = PIXEL_WIDE; - } - else - { - Load_C64_hires(bitmap,colors); - newPixel_ratio = PIXEL_SIMPLE; - } - - //Pixel_ratio = newPixel_ratio; - - File_error = 0; - fclose(file); + width=160; + Ratio_of_loaded_image = PIXEL_WIDE; } else + { + Ratio_of_loaded_image = PIXEL_SIMPLE; + } + + Init_preview(width, height, file_size, FORMAT_C64, Ratio_of_loaded_image); // Do this as soon as you can + + Main_image_width = width ; + Main_image_height = height; + + Read_bytes(file,bitmap,8000); + if(file_size>8002) + Read_bytes(file,colors,1000); + + if(width==160) + { + Read_bytes(file,nybble,1000); + Read_byte(file,&background); + Load_C64_multi(bitmap,colors,nybble,background); + } + else + { + Load_C64_hires(bitmap,colors); + } + + File_error = 0; + fclose(file); + } + else File_error = 1; } int Save_C64_hires(char *filename) { - int cx,cy,x,y,c1,c2,i,pixel,bits,pos=0; - word numcolors; - dword cusage[256]; - byte colors[1000],bitmap[8000]; - FILE *file; - - for(x=0;x<1000;x++)colors[x]=1; // init colormem to black/white - - for(cy=0; cy<25; cy++) // Character line, 25 lines - { - for(cx=0; cx<40; cx++) // Character column, 40 columns - { - for(i=0;i<256;i++) cusage[i]=0; - - numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); - if (numcolors>2) - { - Warning_message("More than 2 colors in 8x8 pixels"); - // TODO here we should hilite the offending block - printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); - return 1; - } - for(i=0;i<16;i++) - { - if(cusage[i]) - { - c2=i; - break; - } - } - c1=c2; - for(i=c2+1;i<16;i++) - { - if(cusage[i]) - { - c1=i; - } - } - colors[cx+cy*40]=(c2<<4)|c1; + int cx,cy,x,y,c1,c2,i,pixel,bits,pos=0; + word numcolors; + dword cusage[256]; + byte colors[1000],bitmap[8000]; + FILE *file; + + for(x=0;x<1000;x++)colors[x]=1; // init colormem to black/white + + for(cy=0; cy<25; cy++) // Character line, 25 lines + { + for(cx=0; cx<40; cx++) // Character column, 40 columns + { + for(i=0;i<256;i++) cusage[i]=0; + + numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); + if (numcolors>2) + { + Warning_message("More than 2 colors in 8x8 pixels"); + // TODO here we should hilite the offending block + printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); + return 1; + } + for(i=0;i<16;i++) + { + if(cusage[i]) + { + c2=i; + break; + } + } + c1=c2; + for(i=c2+1;i<16;i++) + { + if(cusage[i]) + { + c1=i; + } + } + colors[cx+cy*40]=(c2<<4)|c1; - for(y=0; y<8; y++) - { - bits=0; - for(x=0; x<8; x++) - { - pixel=Read_pixel_function(x+cx*8,y+cy*8); - if(pixel>15) - { - Warning_message("Color above 15 used"); - // TODO hilite offending block here too? - // or make it smarter with color allocation? - // However, the palette is fixed to the 16 first colors - return 1; - } - bits=bits<<1; - if (pixel==c1) bits|=1; - } - bitmap[pos++]=bits; - //Write_byte(file,bits&255); - } - } - } - - file = fopen(filename,"wb"); - - if(!file) - { - Warning_message("File open failed"); - File_error = 1; - return 1; - } - - Write_bytes(file,bitmap,8000); - Write_bytes(file,colors,1000); - - fclose(file); - return 0; + for(y=0; y<8; y++) + { + bits=0; + for(x=0; x<8; x++) + { + pixel=Read_pixel_function(x+cx*8,y+cy*8); + if(pixel>15) + { + Warning_message("Color above 15 used"); + // TODO hilite offending block here too? + // or make it smarter with color allocation? + // However, the palette is fixed to the 16 first colors + return 1; + } + bits=bits<<1; + if (pixel==c1) bits|=1; + } + bitmap[pos++]=bits; + //Write_byte(file,bits&255); + } + } + } + + file = fopen(filename,"wb"); + + if(!file) + { + Warning_message("File open failed"); + File_error = 1; + return 1; + } + + if (!Write_bytes(file,bitmap,8000) || + !Write_bytes(file,colors,1000)) + File_error = 1; + + fclose(file); + return 0; } int Save_C64_multi(char *filename) { /* -BITS COLOR INFORMATION COMES FROM -00 Background color #0 (screen color) -01 Upper 4 bits of screen memory -10 Lower 4 bits of screen memory -11 Color nybble (nybble = 1/2 byte = 4 bits) +BITS COLOR INFORMATION COMES FROM +00 Background color #0 (screen color) +01 Upper 4 bits of screen memory +10 Lower 4 bits of screen memory +11 Color nybble (nybble = 1/2 byte = 4 bits) */ - int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; - byte bitmap[8000],screen[1000],nybble[1000]; - word numcolors,count; - dword cusage[256]; - byte i,background=0; - FILE *file; - - numcolors=Count_used_colors(cusage); - - count=0; - for(x=0;x<16;x++) - { - //printf("color %d, pixels %d\n",x,cusage[x]); - if(cusage[x]>count) - { - count=cusage[x]; - background=x; - - } - } - - for(cy=0; cy<25; cy++) - { - //printf("\ny:%2d ",cy); - for(cx=0; cx<40; cx++) - { - numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); - if(numcolors>4) - { - Warning_message("More than 4 colors in 4x8"); - // TODO hilite offending block - return 1; - } - color=1; - c[0]=background; - for(i=0; i<16; i++) - { - lut[i]=0; - if(cusage[i]) - { - if(i!=background) - { - lut[i]=color; - c[color]=i; - color++; - } - else - { - lut[i]=0; - } - } - } - // add to screen and nybble - screen[cx+cy*40]=c[1]<<4|c[2]; - nybble[cx+cy*40]=c[3]; - //printf("%x%x%x ",c[1],c[2],c[3]); - for(y=0;y<8;y++) - { - bits=0; - for(x=0;x<4;x++) - { - pixel=Read_pixel_function(cx*4+x,cy*8+y); - if(pixel>15) - { - Warning_message("Color above 15 used"); - // TODO hilite as in hires, you should stay to - // the fixed 16 color palette - return 1; - } - bits=bits<<2; - bits|=lut[pixel]; + int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; + byte bitmap[8000],screen[1000],nybble[1000]; + word numcolors,count; + dword cusage[256]; + byte i,background=0; + FILE *file; + + numcolors=Count_used_colors(cusage); + + count=0; + for(x=0;x<16;x++) + { + //printf("color %d, pixels %d\n",x,cusage[x]); + if(cusage[x]>count) + { + count=cusage[x]; + background=x; + } + } + + for(cy=0; cy<25; cy++) + { + //printf("\ny:%2d ",cy); + for(cx=0; cx<40; cx++) + { + numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); + if(numcolors>4) + { + Warning_message("More than 4 colors in 4x8"); + // TODO hilite offending block + return 1; + } + color=1; + c[0]=background; + for(i=0; i<16; i++) + { + lut[i]=0; + if(cusage[i]) + { + if(i!=background) + { + lut[i]=color; + c[color]=i; + color++; + } + else + { + lut[i]=0; + } + } + } + // add to screen and nybble + screen[cx+cy*40]=c[1]<<4|c[2]; + nybble[cx+cy*40]=c[3]; + //printf("%x%x%x ",c[1],c[2],c[3]); + for(y=0;y<8;y++) + { + bits=0; + for(x=0;x<4;x++) + { + pixel=Read_pixel_function(cx*4+x,cy*8+y); + if(pixel>15) + { + Warning_message("Color above 15 used"); + // TODO hilite as in hires, you should stay to + // the fixed 16 color palette + return 1; + } + bits=bits<<2; + bits|=lut[pixel]; - } - //Write_byte(file,bits&255); - bitmap[pos++]=bits; - } - } - } - - file = fopen(filename,"wb"); - - if(!file) - { - Warning_message("File open failed"); - File_error = 1; - return 1; - } - Write_bytes(file,bitmap,8000); - Write_bytes(file,screen,1000); - Write_bytes(file,nybble,1000); - Write_byte(file,background); - - fclose(file); - //printf("\nbg:%d\n",background); - return 0; + } + //Write_byte(file,bits&255); + bitmap[pos++]=bits; + } + } + } + + file = fopen(filename,"wb"); + + if(!file) + { + Warning_message("File open failed"); + File_error = 1; + return 1; + } + if (!Write_bytes(file,bitmap,8000) || + !Write_bytes(file,screen,1000) || + !Write_bytes(file,nybble,1000) || + !Write_byte(file,background)) + File_error = 1; + + fclose(file); + //printf("\nbg:%d\n",background); + return 0; } void Save_C64(void) { - char filename[MAX_PATH_CHARACTERS]; - dword numcolors,cusage[256]; - numcolors=Count_used_colors(cusage); + char filename[MAX_PATH_CHARACTERS]; + dword numcolors, cusage[256]; + numcolors=Count_used_colors(cusage); - Get_full_filename(filename,0); + Get_full_filename(filename,0); - if (numcolors>16) - { - Warning_message("Error: Max 16 colors"); - File_error = 1; - return; - } - if (((Main_image_width!=320) && (Main_image_width!=160)) || Main_image_height!=200) - { - Warning_message("must be 320x200 or 160x200"); - File_error = 1; - return; - } - - if (Main_image_width==320) - File_error = Save_C64_hires(filename); - else - File_error = Save_C64_multi(filename); - - //fclose(file); - + if (numcolors>16) + { + Warning_message("Error: Max 16 colors"); + File_error = 1; + return; + } + if (((Main_image_width!=320) && (Main_image_width!=160)) || Main_image_height!=200) + { + Warning_message("must be 320x200 or 160x200"); + File_error = 1; + return; + } + + if (Main_image_width==320) + File_error = Save_C64_hires(filename); + else + File_error = Save_C64_multi(filename); + } ///////////////////////////////////////////////////////////////////////////// @@ -6351,7 +6386,7 @@ void Load_PNG(void) if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) Init_preview_24b(info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG); else - Init_preview(info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG); + Init_preview(info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG,Ratio_of_loaded_image); if (File_error==0) { @@ -6567,9 +6602,11 @@ void Save_PNG(void) switch(Pixel_ratio) { case PIXEL_WIDE: + case PIXEL_WIDE2: png_set_pHYs(png_ptr, info_ptr, 3000, 6000, PNG_RESOLUTION_METER); break; case PIXEL_TALL: + case PIXEL_TALL2: png_set_pHYs(png_ptr, info_ptr, 6000, 3000, PNG_RESOLUTION_METER); break; default: From b92e8f288ee54666ee93f0880a18bf66f3872c61 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 5 Sep 2009 19:53:15 +0000 Subject: [PATCH 87/95] Updated copyright line git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1017 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 1 + 1 file changed, 1 insertion(+) diff --git a/loadsave.c b/loadsave.c index c09294d6..f2ff4884 100644 --- a/loadsave.c +++ b/loadsave.c @@ -1,5 +1,6 @@ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues From b934f1d57c5f8a3135af3f6db6b2e413c091c4ed Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 5 Sep 2009 20:52:43 +0000 Subject: [PATCH 88/95] 4-space tabs for c64 load/save code git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1018 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 639 +++++++++++++++++++++++++++-------------------------- 1 file changed, 320 insertions(+), 319 deletions(-) diff --git a/loadsave.c b/loadsave.c index f2ff4884..8d3f4258 100644 --- a/loadsave.c +++ b/loadsave.c @@ -5878,379 +5878,380 @@ void Save_NEO(void) ///////////////////////////////////////////////////////////////////////////// void Test_C64(void) { - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - long file_size; - - Get_full_filename(filename,0); - - file = fopen(filename,"rb"); - - if (file) - { - file_size = File_length_file(file); - switch (file_size) + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + long file_size; + + Get_full_filename(filename,0); + + file = fopen(filename,"rb"); + + if (file) { - case 8000: // raw bitmap - case 8002: // raw bitmap with loadaddr - case 9000: // bitmap + screen - case 9002: // bitmap + screen + loadaddr - case 10001: // multicolor - case 10003: // multicolor + loadaddr - File_error = 0; - break; - default: // then we don't know for now. - File_error = 1; + file_size = File_length_file(file); + switch (file_size) + { + case 8000: // raw bitmap + case 8002: // raw bitmap with loadaddr + case 9000: // bitmap + screen + case 9002: // bitmap + screen + loadaddr + case 10001: // multicolor + case 10003: // multicolor + loadaddr + File_error = 0; + break; + default: // then we don't know for now. + File_error = 1; + } + fclose (file); + } + else + { + File_error = 1; } - fclose (file); - } - else - { - File_error = 1; - } } void Load_C64_hires(byte *bitmap, byte *colors) { - int cx,cy,x,y,c[4],pixel,color; - - for(cy=0; cy<25; cy++) - { - for(cx=0; cx<40; cx++) + int cx,cy,x,y,c[4],pixel,color; + + for(cy=0; cy<25; cy++) { - c[1]=colors[cy*40+cx]&15; - c[0]=colors[cy*40+cx]>>4; - for(y=0; y<8; y++) - { - pixel=bitmap[cy*320+cx*8+y]; - for(x=0; x<8; x++) + for(cx=0; cx<40; cx++) { - color=c[pixel&(1<<(7-x))?1:0]; - Pixel_load_function(cx*8+x,cy*8+y,color); + c[1]=colors[cy*40+cx]&15; + c[0]=colors[cy*40+cx]>>4; + for(y=0; y<8; y++) + { + pixel=bitmap[cy*320+cx*8+y]; + for(x=0; x<8; x++) + { + color=c[pixel&(1<<(7-x))?1:0]; + Pixel_load_function(cx*8+x,cy*8+y,color); + } + } } - } } - } } void Load_C64_multi(byte *bitmap, byte *colors, byte *nybble, byte background) { - int cx,cy,x,y,c[4],pixel,color; - c[0]=background; - for(cy=0; cy<25; cy++) - { - for(cx=0; cx<40; cx++) + int cx,cy,x,y,c[4],pixel,color; + c[0]=background; + for(cy=0; cy<25; cy++) { - c[1]=colors[cy*40+cx]>>4; - c[2]=colors[cy*40+cx]&15; - c[3]=nybble[cy*40+cx]; - - for(y=0; y<8; y++) - { - pixel=bitmap[cy*320+cx*8+y]; - for(x=0; x<4; x++) + for(cx=0; cx<40; cx++) { - color=c[(pixel&3)]; - pixel>>=2; - Pixel_load_function(cx*4+(3-x),cy*8+y,color); + c[1]=colors[cy*40+cx]>>4; + c[2]=colors[cy*40+cx]&15; + c[3]=nybble[cy*40+cx]; + + for(y=0; y<8; y++) + { + pixel=bitmap[cy*320+cx*8+y]; + for(x=0; x<4; x++) + { + color=c[(pixel&3)]; + pixel>>=2; + Pixel_load_function(cx*4+(3-x),cy*8+y,color); + } + } } - } } - } } void Load_C64(void) { - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - long file_size; - byte background; - - // Palette from http://www.pepto.de/projects/colorvic/ - byte pal[48]={ - 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, - 0x68, 0x37, 0x2B, - 0x70, 0xA4, 0xB2, - 0x6F, 0x3D, 0x86, - 0x58, 0x8D, 0x43, - 0x35, 0x28, 0x79, - 0xB8, 0xC7, 0x6F, - 0x6F, 0x4F, 0x25, - 0x43, 0x39, 0x00, - 0x9A, 0x67, 0x59, - 0x44, 0x44, 0x44, - 0x6C, 0x6C, 0x6C, - 0x9A, 0xD2, 0x84, - 0x6C, 0x5E, 0xB5, - 0x95, 0x95, 0x95}; - - byte bitmap[8000],colors[1000],nybble[1000]; - word width=320, height=200; - - Get_full_filename(filename,0); - file = fopen(filename,"rb"); - - if(file) - { + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + long file_size; + byte background; - memcpy(Main_palette,pal,48); // this set the software palette for grafx2 - Set_palette(Main_palette); // this set the hardware palette for SDL - Remap_fileselector(); // Always call it if you change the palette - - file_size = File_length_file(file); - - if(file_size>9002) + // Palette from http://www.pepto.de/projects/colorvic/ + byte pal[48]={ + 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, + 0x68, 0x37, 0x2B, + 0x70, 0xA4, 0xB2, + 0x6F, 0x3D, 0x86, + 0x58, 0x8D, 0x43, + 0x35, 0x28, 0x79, + 0xB8, 0xC7, 0x6F, + 0x6F, 0x4F, 0x25, + 0x43, 0x39, 0x00, + 0x9A, 0x67, 0x59, + 0x44, 0x44, 0x44, + 0x6C, 0x6C, 0x6C, + 0x9A, 0xD2, 0x84, + 0x6C, 0x5E, 0xB5, + 0x95, 0x95, 0x95}; + + byte bitmap[8000],colors[1000],nybble[1000]; + word width=320, height=200; + + Get_full_filename(filename,0); + file = fopen(filename,"rb"); + + if(file) { - width=160; - Ratio_of_loaded_image = PIXEL_WIDE; + + memcpy(Main_palette,pal,48); // this set the software palette for grafx2 + Set_palette(Main_palette); // this set the hardware palette for SDL + Remap_fileselector(); // Always call it if you change the palette + + file_size = File_length_file(file); + + if(file_size>9002) + { + width=160; + Ratio_of_loaded_image = PIXEL_WIDE; + } + else + { + Ratio_of_loaded_image = PIXEL_SIMPLE; + } + + Init_preview(width, height, file_size, FORMAT_C64, Ratio_of_loaded_image); // Do this as soon as you can + + Main_image_width = width ; + Main_image_height = height; + + Read_bytes(file,bitmap,8000); + if(file_size>8002) + Read_bytes(file,colors,1000); + + if(width==160) + { + Read_bytes(file,nybble,1000); + Read_byte(file,&background); + Load_C64_multi(bitmap,colors,nybble,background); + } + else + { + Load_C64_hires(bitmap,colors); + } + + File_error = 0; + fclose(file); } else - { - Ratio_of_loaded_image = PIXEL_SIMPLE; - } - - Init_preview(width, height, file_size, FORMAT_C64, Ratio_of_loaded_image); // Do this as soon as you can - - Main_image_width = width ; - Main_image_height = height; - - Read_bytes(file,bitmap,8000); - if(file_size>8002) - Read_bytes(file,colors,1000); - - if(width==160) - { - Read_bytes(file,nybble,1000); - Read_byte(file,&background); - Load_C64_multi(bitmap,colors,nybble,background); - } - else - { - Load_C64_hires(bitmap,colors); - } - - File_error = 0; - fclose(file); - } - else - File_error = 1; + File_error = 1; } int Save_C64_hires(char *filename) { - int cx,cy,x,y,c1,c2,i,pixel,bits,pos=0; - word numcolors; - dword cusage[256]; - byte colors[1000],bitmap[8000]; - FILE *file; + int cx,cy,x,y,c1,c2,i,pixel,bits,pos=0; + word numcolors; + dword cusage[256]; + byte colors[1000],bitmap[8000]; + FILE *file; + + for(x=0;x<1000;x++) + colors[x]=1; // init colormem to black/white - for(x=0;x<1000;x++)colors[x]=1; // init colormem to black/white - - for(cy=0; cy<25; cy++) // Character line, 25 lines - { - for(cx=0; cx<40; cx++) // Character column, 40 columns + for(cy=0; cy<25; cy++) // Character line, 25 lines { - for(i=0;i<256;i++) cusage[i]=0; + for(cx=0; cx<40; cx++) // Character column, 40 columns + { + for(i=0;i<256;i++) cusage[i]=0; + + numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); + if (numcolors>2) + { + Warning_message("More than 2 colors in 8x8 pixels"); + // TODO here we should hilite the offending block + printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); + return 1; + } + for(i=0;i<16;i++) + { + if(cusage[i]) + { + c2=i; + break; + } + } + c1=c2; + for(i=c2+1;i<16;i++) + { + if(cusage[i]) + { + c1=i; + } + } + colors[cx+cy*40]=(c2<<4)|c1; - numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); - if (numcolors>2) - { - Warning_message("More than 2 colors in 8x8 pixels"); - // TODO here we should hilite the offending block - printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); - return 1; - } - for(i=0;i<16;i++) - { - if(cusage[i]) - { - c2=i; - break; + for(y=0; y<8; y++) + { + bits=0; + for(x=0; x<8; x++) + { + pixel=Read_pixel_function(x+cx*8,y+cy*8); + if(pixel>15) + { + Warning_message("Color above 15 used"); + // TODO hilite offending block here too? + // or make it smarter with color allocation? + // However, the palette is fixed to the 16 first colors + return 1; + } + bits=bits<<1; + if (pixel==c1) bits|=1; + } + bitmap[pos++]=bits; + //Write_byte(file,bits&255); + } } - } - c1=c2; - for(i=c2+1;i<16;i++) - { - if(cusage[i]) - { - c1=i; - } - } - colors[cx+cy*40]=(c2<<4)|c1; - - for(y=0; y<8; y++) - { - bits=0; - for(x=0; x<8; x++) - { - pixel=Read_pixel_function(x+cx*8,y+cy*8); - if(pixel>15) - { - Warning_message("Color above 15 used"); - // TODO hilite offending block here too? - // or make it smarter with color allocation? - // However, the palette is fixed to the 16 first colors - return 1; - } - bits=bits<<1; - if (pixel==c1) bits|=1; - } - bitmap[pos++]=bits; - //Write_byte(file,bits&255); - } } - } - file = fopen(filename,"wb"); + file = fopen(filename,"wb"); - if(!file) - { - Warning_message("File open failed"); - File_error = 1; - return 1; - } - - if (!Write_bytes(file,bitmap,8000) || - !Write_bytes(file,colors,1000)) - File_error = 1; - - fclose(file); - return 0; + if(!file) + { + Warning_message("File open failed"); + File_error = 1; + return 1; + } + + if (!Write_bytes(file,bitmap,8000) || + !Write_bytes(file,colors,1000)) + File_error = 1; + + fclose(file); + return 0; } int Save_C64_multi(char *filename) { -/* -BITS COLOR INFORMATION COMES FROM -00 Background color #0 (screen color) -01 Upper 4 bits of screen memory -10 Lower 4 bits of screen memory -11 Color nybble (nybble = 1/2 byte = 4 bits) -*/ + /* + BITS COLOR INFORMATION COMES FROM + 00 Background color #0 (screen color) + 01 Upper 4 bits of screen memory + 10 Lower 4 bits of screen memory + 11 Color nybble (nybble = 1/2 byte = 4 bits) + */ - int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; - byte bitmap[8000],screen[1000],nybble[1000]; - word numcolors,count; - dword cusage[256]; - byte i,background=0; - FILE *file; + int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; + byte bitmap[8000],screen[1000],nybble[1000]; + word numcolors,count; + dword cusage[256]; + byte i,background=0; + FILE *file; + + numcolors=Count_used_colors(cusage); - numcolors=Count_used_colors(cusage); - - count=0; - for(x=0;x<16;x++) - { - //printf("color %d, pixels %d\n",x,cusage[x]); - if(cusage[x]>count) + count=0; + for(x=0;x<16;x++) { - count=cusage[x]; - background=x; - } - } - - for(cy=0; cy<25; cy++) - { - //printf("\ny:%2d ",cy); - for(cx=0; cx<40; cx++) - { - numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); - if(numcolors>4) - { - Warning_message("More than 4 colors in 4x8"); - // TODO hilite offending block - return 1; - } - color=1; - c[0]=background; - for(i=0; i<16; i++) - { - lut[i]=0; - if(cusage[i]) + //printf("color %d, pixels %d\n",x,cusage[x]); + if(cusage[x]>count) { - if(i!=background) - { - lut[i]=color; - c[color]=i; - color++; - } - else - { - lut[i]=0; - } + count=cusage[x]; + background=x; } - } - // add to screen and nybble - screen[cx+cy*40]=c[1]<<4|c[2]; - nybble[cx+cy*40]=c[3]; - //printf("%x%x%x ",c[1],c[2],c[3]); - for(y=0;y<8;y++) - { - bits=0; - for(x=0;x<4;x++) - { - pixel=Read_pixel_function(cx*4+x,cy*8+y); - if(pixel>15) - { - Warning_message("Color above 15 used"); - // TODO hilite as in hires, you should stay to - // the fixed 16 color palette - return 1; - } - bits=bits<<2; - bits|=lut[pixel]; - - } - //Write_byte(file,bits&255); - bitmap[pos++]=bits; - } } - } - file = fopen(filename,"wb"); + for(cy=0; cy<25; cy++) + { + //printf("\ny:%2d ",cy); + for(cx=0; cx<40; cx++) + { + numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); + if(numcolors>4) + { + Warning_message("More than 4 colors in 4x8"); + // TODO hilite offending block + return 1; + } + color=1; + c[0]=background; + for(i=0; i<16; i++) + { + lut[i]=0; + if(cusage[i]) + { + if(i!=background) + { + lut[i]=color; + c[color]=i; + color++; + } + else + { + lut[i]=0; + } + } + } + // add to screen and nybble + screen[cx+cy*40]=c[1]<<4|c[2]; + nybble[cx+cy*40]=c[3]; + //printf("%x%x%x ",c[1],c[2],c[3]); + for(y=0;y<8;y++) + { + bits=0; + for(x=0;x<4;x++) + { + pixel=Read_pixel_function(cx*4+x,cy*8+y); + if(pixel>15) + { + Warning_message("Color above 15 used"); + // TODO hilite as in hires, you should stay to + // the fixed 16 color palette + return 1; + } + bits=bits<<2; + bits|=lut[pixel]; + + } + //Write_byte(file,bits&255); + bitmap[pos++]=bits; + } + } + } - if(!file) - { - Warning_message("File open failed"); - File_error = 1; - return 1; - } - if (!Write_bytes(file,bitmap,8000) || - !Write_bytes(file,screen,1000) || - !Write_bytes(file,nybble,1000) || - !Write_byte(file,background)) - File_error = 1; - - fclose(file); - //printf("\nbg:%d\n",background); - return 0; + file = fopen(filename,"wb"); + + if(!file) + { + Warning_message("File open failed"); + File_error = 1; + return 1; + } + if (!Write_bytes(file,bitmap,8000) || + !Write_bytes(file,screen,1000) || + !Write_bytes(file,nybble,1000) || + !Write_byte(file,background)) + File_error = 1; + + fclose(file); + //printf("\nbg:%d\n",background); + return 0; } void Save_C64(void) { - char filename[MAX_PATH_CHARACTERS]; - dword numcolors, cusage[256]; - numcolors=Count_used_colors(cusage); - - Get_full_filename(filename,0); - - if (numcolors>16) - { - Warning_message("Error: Max 16 colors"); - File_error = 1; - return; - } - if (((Main_image_width!=320) && (Main_image_width!=160)) || Main_image_height!=200) - { - Warning_message("must be 320x200 or 160x200"); - File_error = 1; - return; - } + char filename[MAX_PATH_CHARACTERS]; + dword numcolors, cusage[256]; + numcolors=Count_used_colors(cusage); - if (Main_image_width==320) - File_error = Save_C64_hires(filename); - else - File_error = Save_C64_multi(filename); + Get_full_filename(filename,0); + + if (numcolors>16) + { + Warning_message("Error: Max 16 colors"); + File_error = 1; + return; + } + if (((Main_image_width!=320) && (Main_image_width!=160)) || Main_image_height!=200) + { + Warning_message("must be 320x200 or 160x200"); + File_error = 1; + return; + } + + if (Main_image_width==320) + File_error = Save_C64_hires(filename); + else + File_error = Save_C64_multi(filename); } From ba42b3cb178051a4711e86a46c7a28fd3c28c533 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 5 Sep 2009 21:20:43 +0000 Subject: [PATCH 89/95] In fullscreen mode, auto-activate wide/tall pixels when you load a C64 multicolor picture, or a PNG picture you saved with wide/tall pixels. git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1019 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- buttons.c | 34 +++++++++++++++++++++++++++++----- loadsave.h | 3 +++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/buttons.c b/buttons.c index 170fc4e0..96d2348f 100644 --- a/buttons.c +++ b/buttons.c @@ -2842,8 +2842,6 @@ void Load_picture(byte image) } new_mode=Best_video_mode(); - // TODO : Utiliser ici Ratio_of_loaded_image pour passer dans la - // bonne taille de pixels. if ((Config.Auto_set_res) && (new_mode!=Current_resolution)) { Init_mode_video( @@ -2853,6 +2851,20 @@ void Load_picture(byte image) Pixel_ratio); Display_menu(); } + // In window mode, activate wide or tall pixels if the image says so. + else if (!Video_mode[Current_resolution].Fullscreen && + ((Ratio_of_loaded_image == PIXEL_WIDE && + Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || + (Ratio_of_loaded_image == PIXEL_TALL && + Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2))) + { + Init_mode_video( + Video_mode[Current_resolution].Width, + Video_mode[Current_resolution].Height, + Video_mode[Current_resolution].Fullscreen, + Ratio_of_loaded_image); + Display_menu(); + } else { Main_offset_X=0; @@ -2932,9 +2944,7 @@ void Button_Reload(void) Main_magnifier_mode=0; } - new_mode=Best_video_mode(); - // TODO : Utiliser içi Ratio_of_loaded_image pour passer dans la - // bonne taille de pixels. + new_mode=Best_video_mode(); if ( ((Config.Auto_set_res) && (new_mode!=Current_resolution)) && (!Resolution_in_command_line) ) { @@ -2945,6 +2955,20 @@ void Button_Reload(void) Pixel_ratio); Display_menu(); } + // In window mode, activate wide or tall pixels if the image says so. + else if (!Video_mode[Current_resolution].Fullscreen && + ((Ratio_of_loaded_image == PIXEL_WIDE && + Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || + (Ratio_of_loaded_image == PIXEL_TALL && + Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2))) + { + Init_mode_video( + Video_mode[Current_resolution].Width, + Video_mode[Current_resolution].Height, + Video_mode[Current_resolution].Fullscreen, + Ratio_of_loaded_image); + Display_menu(); + } else { Main_offset_X=0; diff --git a/loadsave.h b/loadsave.h index e8fd0c83..93025ae8 100644 --- a/loadsave.h +++ b/loadsave.h @@ -55,3 +55,6 @@ extern T_Format File_formats[NB_KNOWN_FORMATS]; /// Function which attempts to save backups of the images (main and spare), /// called in case of SIGSEGV. void Image_emergency_backup(void); + +/// Pixel ratio of last loaded image: one of :PIXEL_SIMPLE, :PIXEL_WIDE or :PIXEL_TALL +extern enum PIXEL_RATIO Ratio_of_loaded_image; From c894caf2f83fd4666f54a9f7650ac199ab398224 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sat, 5 Sep 2009 22:10:49 +0000 Subject: [PATCH 90/95] Merged in Petter's save options for c64 pictures. (issue 211 comment 25) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1020 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 216 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 184 insertions(+), 32 deletions(-) diff --git a/loadsave.c b/loadsave.c index 8d3f4258..94af0efa 100644 --- a/loadsave.c +++ b/loadsave.c @@ -44,6 +44,7 @@ #include "sdlscreen.h" #include "struct.h" #include "windows.h" +#include "engine.h" // -- PKM ------------------------------------------------------------------- void Test_PKM(void); @@ -138,7 +139,7 @@ T_Format File_formats[NB_KNOWN_FORMATS] = { {"neo", Test_NEO, Load_NEO, Save_NEO, 1, 0}, {"kcf", Test_KCF, Load_KCF, Save_KCF, 0, 0}, {"pal", Test_PAL, Load_PAL, Save_PAL, 0, 0}, - {"c64", Test_C64, Load_C64, Save_C64, 1, 0}, + {"c64", Test_C64, Load_C64, Save_C64, 1, 1}, #ifndef __no_pnglib__ {"png", Test_PNG, Load_PNG, Save_PNG, 1, 1} #endif @@ -5891,6 +5892,8 @@ void Test_C64(void) 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 @@ -5964,7 +5967,11 @@ void Load_C64(void) FILE* file; char filename[MAX_PATH_CHARACTERS]; long file_size; - byte background; + int i; + byte background,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"}; // Palette from http://www.pepto.de/projects/colorvic/ byte pal[48]={ @@ -5991,34 +5998,99 @@ void Load_C64(void) Get_full_filename(filename,0); file = fopen(filename,"rb"); - if(file) + if (file) { + File_error=0; + file_size = File_length_file(file); + + 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; + + case 8002: // raw bitmap with loadaddr + hasLoadAddr=1; + loadFormat=F_bitmap; + break; + + case 9000: // bitmap + screen + hasLoadAddr=0; + loadFormat=F_hires; + break; + + case 9002: // bitmap + screen + loadaddr + hasLoadAddr=1; + loadFormat=F_hires; + break; + + case 10001: // multicolor + hasLoadAddr=0; + loadFormat=F_multi; + break; + + case 10003: // multicolor + loadaddr + hasLoadAddr=1; + loadFormat=F_multi; + break; + + default: // then we don't know what it is. + File_error = 1; + + } memcpy(Main_palette,pal,48); // this set the software palette for grafx2 Set_palette(Main_palette); // this set the hardware palette for SDL Remap_fileselector(); // Always call it if you change the palette - file_size = File_length_file(file); + 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) { - width=160; Ratio_of_loaded_image = PIXEL_WIDE; } - else - { - Ratio_of_loaded_image = PIXEL_SIMPLE; - } - + sprintf(Main_comment,"C64 %s, %s", + c64_format_names[loadFormat],filename); Init_preview(width, height, file_size, FORMAT_C64, Ratio_of_loaded_image); // Do this as soon as you can Main_image_width = width ; Main_image_height = height; Read_bytes(file,bitmap,8000); - if(file_size>8002) + + if (file_size>8002) Read_bytes(file,colors,1000); - + else + { + for(i=0;i<1000;i++) + { + colors[i]=1; + } + } + if(width==160) { Read_bytes(file,nybble,1000); @@ -6037,7 +6109,61 @@ void Load_C64(void) File_error = 1; } -int Save_C64_hires(char *filename) +int Save_C64_window(byte *saveWhat, byte *loadAddr) +{ + int b; + T_Dropdown_button *what, *addr; + + 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); + + what=Window_set_dropdown_button(10,20,90,15,70,"Save what",1, 0, 1, LEFT_SIDE); + Window_dropdown_clear_items(what); + Window_dropdown_add_item(what,0,"All"); + Window_dropdown_add_item(what,1,"Bitmap"); + Window_dropdown_add_item(what,2,"Screen"); + Window_dropdown_add_item(what,3,"Color"); + + addr=Window_set_dropdown_button(110,20,70,15,70,"Addr",1, 0, 1, LEFT_SIDE); + Window_dropdown_clear_items(addr); + Window_dropdown_add_item(addr,0,"None"); + Window_dropdown_add_item(addr,1,"$2000"); + Window_dropdown_add_item(addr,2,"$4000"); + Window_dropdown_add_item(addr,3,"$6000"); + Window_dropdown_add_item(addr,4,"$8000"); + Window_dropdown_add_item(addr,5,"$A000"); + Window_dropdown_add_item(addr,6,"$C000"); + Window_dropdown_add_item(addr,7,"$E000"); + + Update_window_area(0,0,Window_width,Window_height); + Display_cursor(); + + do + { + b = Window_clicked_button(); + switch(b) + { + case 3: // Save what + *saveWhat=Window_attribute2; + //printf("what=%d\n",Window_attribute2); + break; + + case 4: // Load addr + *loadAddr=Window_attribute2*32; + //printf("addr=$%02x00 (%d)\n",loadAddr,Window_attribute2); + break; + + case 0: break; + } + }while(b!=1 && b!=2); + + Close_window(); + Display_cursor(); + return b==1; +} + +int Save_C64_hires(char *filename, byte saveWhat, byte loadAddr) { int cx,cy,x,y,c1,c2,i,pixel,bits,pos=0; word numcolors; @@ -6045,16 +6171,16 @@ int Save_C64_hires(char *filename) byte colors[1000],bitmap[8000]; FILE *file; - for(x=0;x<1000;x++) - colors[x]=1; // init colormem to black/white + for(x=0;x<1000;x++)colors[x]=1; // init colormem to black/white for(cy=0; cy<25; cy++) // Character line, 25 lines { for(cx=0; cx<40; cx++) // Character column, 40 columns { - for(i=0;i<256;i++) cusage[i]=0; + for(i=0;i<256;i++) + cusage[i]=0; - numcolors=Count_used_colors_area(cusage,cx*8,cy*8,8,8); + numcolors=Count_used_colors_screen_area(cusage,cx*8,cy*8,8,8); if (numcolors>2) { Warning_message("More than 2 colors in 8x8 pixels"); @@ -6112,15 +6238,21 @@ int Save_C64_hires(char *filename) return 1; } - if (!Write_bytes(file,bitmap,8000) || - !Write_bytes(file,colors,1000)) - File_error = 1; + if (loadAddr) + { + Write_byte(file,0); + Write_byte(file,loadAddr); + } + if (saveWhat==0 || saveWhat==1) + Write_bytes(file,bitmap,8000); + if (saveWhat==0 || saveWhat==2) + Write_bytes(file,colors,1000); fclose(file); return 0; } -int Save_C64_multi(char *filename) +int Save_C64_multi(char *filename, byte saveWhat, byte loadAddr) { /* BITS COLOR INFORMATION COMES FROM @@ -6155,7 +6287,7 @@ int Save_C64_multi(char *filename) //printf("\ny:%2d ",cy); for(cx=0; cx<40; cx++) { - numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); + numcolors=Count_used_colors_screen_area(cusage,cx*4,cy*8,4,8); if(numcolors>4) { Warning_message("More than 4 colors in 4x8"); @@ -6216,11 +6348,24 @@ int Save_C64_multi(char *filename) File_error = 1; return 1; } - if (!Write_bytes(file,bitmap,8000) || - !Write_bytes(file,screen,1000) || - !Write_bytes(file,nybble,1000) || - !Write_byte(file,background)) - File_error = 1; + + if (loadAddr) + { + Write_byte(file,0); + Write_byte(file,loadAddr); + } + + if (saveWhat==0 || saveWhat==1) + Write_bytes(file,bitmap,8000); + + if (saveWhat==0 || saveWhat==2) + Write_bytes(file,screen,1000); + + if (saveWhat==0 || saveWhat==3) + Write_bytes(file,nybble,1000); + + if (saveWhat==0) + Write_byte(file,background); fclose(file); //printf("\nbg:%d\n",background); @@ -6230,7 +6375,8 @@ int Save_C64_multi(char *filename) void Save_C64(void) { char filename[MAX_PATH_CHARACTERS]; - dword numcolors, cusage[256]; + byte saveWhat=0,loadAddr=0; + dword numcolors,cusage[256]; numcolors=Count_used_colors(cusage); Get_full_filename(filename,0); @@ -6248,11 +6394,17 @@ void Save_C64(void) return; } - if (Main_image_width==320) - File_error = Save_C64_hires(filename); - else - File_error = Save_C64_multi(filename); + if(!Save_C64_window(&saveWhat,&loadAddr)) + { + File_error = 1; + return; + } + //printf("saveWhat=%d, loadAddr=%d\n",saveWhat,loadAddr); + if (Main_image_width==320) + File_error = Save_C64_hires(filename,saveWhat,loadAddr); + else + File_error = Save_C64_multi(filename,saveWhat,loadAddr); } ///////////////////////////////////////////////////////////////////////////// From 2ce0a2538b81193c3126550739d18eae5e94cd87 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Sun, 6 Sep 2009 18:59:20 +0000 Subject: [PATCH 91/95] Merged in fix by Petter (issue 211 comment 26). Made the C64 save window remember its settings (while the program is open) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1021 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- loadsave.c | 57 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/loadsave.c b/loadsave.c index 94af0efa..de983439 100644 --- a/loadsave.c +++ b/loadsave.c @@ -6111,38 +6111,49 @@ void Load_C64(void) int Save_C64_window(byte *saveWhat, byte *loadAddr) { - int b; + int button; + unsigned int i; T_Dropdown_button *what, *addr; - + char * what_label[] = { + "All", + "Bitmap", + "Screen", + "Color" + }; + char * address_label[] = { + "None", + "$2000", + "$4000", + "$6000", + "$8000", + "$A000", + "$C000", + "$E000" + }; + 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); - what=Window_set_dropdown_button(10,20,90,15,70,"Save what",1, 0, 1, LEFT_SIDE); + 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); Window_dropdown_clear_items(what); - Window_dropdown_add_item(what,0,"All"); - Window_dropdown_add_item(what,1,"Bitmap"); - Window_dropdown_add_item(what,2,"Screen"); - Window_dropdown_add_item(what,3,"Color"); + for (i=0; i2) { Warning_message("More than 2 colors in 8x8 pixels"); @@ -6287,7 +6298,7 @@ int Save_C64_multi(char *filename, byte saveWhat, byte loadAddr) //printf("\ny:%2d ",cy); for(cx=0; cx<40; cx++) { - numcolors=Count_used_colors_screen_area(cusage,cx*4,cy*8,4,8); + numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); if(numcolors>4) { Warning_message("More than 4 colors in 4x8"); @@ -6375,7 +6386,7 @@ int Save_C64_multi(char *filename, byte saveWhat, byte loadAddr) void Save_C64(void) { char filename[MAX_PATH_CHARACTERS]; - byte saveWhat=0,loadAddr=0; + static byte saveWhat=0, loadAddr=0; dword numcolors,cusage[256]; numcolors=Count_used_colors(cusage); From e1d8ca9d05e317d98e7e297effb1312b88c6eeae Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Fri, 11 Sep 2009 19:52:09 +0000 Subject: [PATCH 92/95] Fixed one compilation warning, fixed typo in help, Updated help and credits (pending approval by Pulkomandy!) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1022 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- helpfile.h | 104 +++++++++++++++++++++++++++++++++++------------------ pxdouble.c | 1 + pxquad.c | 1 + pxsimple.c | 1 + pxtall.c | 1 + pxtall2.c | 1 + pxtriple.c | 1 + pxwide.c | 1 + pxwide2.c | 1 + 9 files changed, 78 insertions(+), 34 deletions(-) diff --git a/helpfile.h b/helpfile.h index 383f4c58..e328b02d 100644 --- a/helpfile.h +++ b/helpfile.h @@ -306,16 +306,28 @@ static const T_Help_table helptable_credits[] = HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") HELP_TEXT (" Huge thanks to them for their work !") HELP_TEXT ("") - HELP_BOLD (" ART") + HELP_BOLD (" OTHER CODE CONTRIBUTORS") HELP_TEXT ("") - HELP_TEXT (" CLASSIC THEME") - HELP_TEXT (" GrafX2 logo by Made (www.m4de.com)") - HELP_TEXT (" Icons and fonts by X-Man ") - HELP_TEXT (" MODERN THEME") - HELP_TEXT (" Graphics and logo by iLKke") - HELP_TEXT (" (ilkke.blogspot.com)") + HELP_TEXT (" Karl Bartel") + HELP_TEXT (" SFont: bitmap fonts rendering") HELP_TEXT ("") - HELP_TEXT (" Pixelled all the graphics") + HELP_TEXT (" Petter Lindquist") + HELP_TEXT (" C64 file and image formats") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TITLE(" ART") + HELP_TEXT ("") + HELP_TEXT (" Made (www.m4de.com)") + HELP_TEXT (" Logo (classic)") + HELP_TEXT ("") + HELP_TEXT (" X-Man") + HELP_TEXT (" Buttons and fonts (classic)") + HELP_TEXT ("") + HELP_TEXT (" iLKke (ilkke.blogspot.com)") + HELP_TEXT (" Buttons and logo (modern), extra fonts") + HELP_TEXT ("") + HELP_TEXT ("") + HELP_TEXT (" ...Pixelled all the graphics") HELP_TEXT ("") HELP_TITLE(" OTHER MACHINES PORTS") HELP_TEXT ("") @@ -340,6 +352,11 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") + HELP_BOLD (" LINUX BINARIES") + HELP_TEXT ("") + HELP_TEXT (" Gentoo : Matteo 'Peach' Pescarin") + HELP_TEXT (" Debian : Gürkan Sengün") + HELP_TEXT ("") HELP_BOLD (" MAC OS X PORT") HELP_TEXT ("") HELP_TEXT (" Franck Charlet (hitchhikr)") @@ -353,8 +370,8 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") - HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") + HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") HELP_TITLE(" BUGFINDERS") HELP_TEXT ("") @@ -370,8 +387,8 @@ static const T_Help_table helptable_credits[] = HELP_TEXT (" Timo Kurrpa titus^Rab Tobé ") HELP_TEXT (" 00ai99") HELP_TEXT ("") - HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") + HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") HELP_TITLE(" FILE FORMATS CREDITS") HELP_TEXT ("") @@ -397,13 +414,17 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TITLE(" GREETINGS") HELP_TEXT ("") + HELP_BOLD ("Pulkomandy:") + HELP_TEXT ("") HELP_TEXT (" To the Pouet.net BBS posters, the #CPC") HELP_TEXT (" trolls and the bitfellas") HELP_TEXT (" To every people who makes the scene alive!") HELP_TEXT (" To all guys making nice pixelled pictures") HELP_TEXT (" (with or without GrafX2)") HELP_TEXT ("") - HELP_BOLD (" We send our best regards to...") + HELP_BOLD ("Sunset Designs:") + HELP_TEXT ("") + HELP_TEXT (" We send our best regards to...") HELP_TEXT ("") HELP_TEXT (" Access Filter Pink") HELP_TEXT (" Ace Fiver Pixel") @@ -458,6 +479,25 @@ static const T_Help_table helptable_credits[] = HELP_TEXT (" and all #pixel, #demofr and #coders.") HELP_TEXT ("") HELP_TEXT ("") + HELP_TEXT (" Some information taken from several docs") + HELP_TEXT (" (PCGPE, Intervue, PC Interdit...)") + HELP_TEXT (" gave us an invaluable help.") + HELP_TEXT ("") + HELP_TEXT (" Thanks to Shawn Hargreaves for his filled") + HELP_TEXT (" polygon routine from Allegro v2.2.") + HELP_TEXT ("") + HELP_TEXT (" Thanks to Carlos \"Made\" Pardo for his") + HELP_TEXT (" great GrafX2 logo.") + HELP_TEXT ("") + HELP_TEXT (" This is our very first program compiled") + HELP_TEXT (" with the Gnu C Compiler.") + HELP_TEXT (" A thousand thanks to the authors of") + HELP_TEXT (" this compiler.") + HELP_TEXT ("") + HELP_TEXT (" We also would like to thank all the") + HELP_TEXT (" people who gave us ideas to improve") + HELP_TEXT (" GrafX2.") + HELP_TEXT ("") HELP_TITLE (" SNAIL MAIL") HELP_TEXT ("") //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") @@ -478,27 +518,6 @@ static const T_Help_table helptable_credits[] = HELP_TEXT (" (From 2001, current status: unknown)") HELP_TEXT ("") HELP_TEXT ("") - HELP_TITLE(" THANKS") - HELP_TEXT ("") - HELP_TEXT (" Some information taken from several docs") - HELP_TEXT (" (PCGPE, Intervue, PC Interdit...)") - HELP_TEXT (" gave us an invaluable help.") - HELP_TEXT ("") - HELP_TEXT (" Thanks to Shawn Hargreaves for his filled") - HELP_TEXT (" polygon routine from Allegro v2.2.") - HELP_TEXT ("") - HELP_TEXT (" Thanks to Carlos \"Made\" Pardo for his") - HELP_TEXT (" great GrafX2 logo.") - HELP_TEXT ("") - HELP_TEXT (" This is our very first program compiled") - HELP_TEXT (" with the Gnu C Compiler.") - HELP_TEXT (" A thousand thanks to the authors of") - HELP_TEXT (" this compiler.") - HELP_TEXT ("") - HELP_TEXT (" We also would like to thank all the") - HELP_TEXT (" people who gave us ideas to improve") - HELP_TEXT (" GrafX2.") - HELP_TITLE("") }; static const T_Help_table helptable_paintbrush[] = { @@ -560,6 +579,18 @@ static const T_Help_table helptable_paintbrush[] = HELP_TEXT ("to the \"miscellaneous\" family and their size") HELP_TEXT ("cannot be modified.") HELP_TEXT ("") + HELP_BOLD ("BRUSH CONTAINER") + HELP_TEXT ("") + HELP_TEXT ("The bottom row, initially showing empty") + HELP_TEXT ("buttons, is the brush container. You can") + HELP_TEXT ("right-click a button to store the current") + HELP_TEXT ("brush in it, and then whenever you need the") + HELP_TEXT ("brush back, open this menu again and") + HELP_TEXT ("left-click the button.") + HELP_TEXT ("The container can memorize resizable brushes") + HELP_TEXT ("as well as brushes grabbed from the image.") + HELP_TEXT ("Brushes are lost when you exit the program.") + HELP_TEXT ("") HELP_BOLD (" RIGHT CLICK ") HELP_LINK ("(Key:%s)",0x200+BUTTON_PAINTBRUSHES) HELP_TEXT ("") @@ -1483,7 +1514,7 @@ static const T_Help_table helptable_effects[] = HELP_TEXT ("of the same size such as a font or tiles,") HELP_TEXT ("or for drawing figures or grabbing brushes") HELP_TEXT ("with their dimensions multiple of the step") - HELP_TEXT ("of the grid.');") + HELP_TEXT ("of the grid.") HELP_BOLD ("LEFT CLICK") HELP_LINK ("(Key: %s)", SPECIAL_GRID_MODE) HELP_TEXT ("") @@ -1500,7 +1531,12 @@ static const T_Help_table helptable_effects[] = HELP_TEXT ("- dX,dY: Offsets of the grid.") HELP_TEXT ("") HELP_TEXT ("") - HELP_LINK ("Show/Hide grid : ", SPECIAL_SHOW_GRID) + HELP_TEXT ("The following shortcut hides or shows the") + HELP_TEXT ("grid in the magnified view:") + HELP_LINK ("%s", SPECIAL_SHOW_GRID) + HELP_TEXT ("The grid size will be according to your") + HELP_TEXT ("snap-to-grid settings.") + HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("SIEVE") HELP_TEXT (" This effect allows you, by defining a") diff --git a/pxdouble.c b/pxdouble.c index 41a61f6a..c4f4fd3a 100644 --- a/pxdouble.c +++ b/pxdouble.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxdouble.h" #include "pxwide.h" // for Display_transparent_line_on_screen_wide() diff --git a/pxquad.c b/pxquad.c index 328d2b81..1b1e328f 100644 --- a/pxquad.c +++ b/pxquad.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxquad.h" #define ZOOMX 4 diff --git a/pxsimple.c b/pxsimple.c index dfce3632..f7bfdebb 100644 --- a/pxsimple.c +++ b/pxsimple.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxsimple.h" void Pixel_simple (word x,word y,byte color) diff --git a/pxtall.c b/pxtall.c index e1d26a5a..c63df96d 100644 --- a/pxtall.c +++ b/pxtall.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxtall.h" #include "pxsimple.h" diff --git a/pxtall2.c b/pxtall2.c index 15d35fff..ca4b1b0d 100644 --- a/pxtall2.c +++ b/pxtall2.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxtall2.h" #define ZOOMX 2 diff --git a/pxtriple.c b/pxtriple.c index ae2b5511..99f58efd 100644 --- a/pxtriple.c +++ b/pxtriple.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxtriple.h" #define ZOOMX 3 diff --git a/pxwide.c b/pxwide.c index 7000b2d8..f0d60074 100644 --- a/pxwide.c +++ b/pxwide.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxwide.h" #define ZOOMX 2 diff --git a/pxwide2.c b/pxwide2.c index 336baa97..d0d2f400 100644 --- a/pxwide2.c +++ b/pxwide2.c @@ -25,6 +25,7 @@ #include "global.h" #include "sdlscreen.h" #include "misc.h" +#include "graph.h" #include "pxwide2.h" #define ZOOMX 4 From 8cf1266325d710c0a10e569f6219ecec662dde64 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Fri, 11 Sep 2009 21:18:42 +0000 Subject: [PATCH 93/95] Updated readme git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1023 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- doc/README.txt | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/README.txt b/doc/README.txt index 3f71681f..20e49006 100644 --- a/doc/README.txt +++ b/doc/README.txt @@ -52,7 +52,7 @@ executable; You can normally find it in a packed archive whose name begins by the Subversion repository: http://grafx2.googlecode.com/svn/trunk/ or you can find the latest versions as packed archives: -http://code.google.com/p/grafx2/downloads/list +http://code.google.com/p/grafx2/wiki/Downloads === COMPILING === @@ -76,17 +76,18 @@ Sends greetings and glops to pouet.net : http://pouet.net/prod.php?which=51865 === HISTORY === Short revision history : - * 06/2009 2.0 Completed the features planned by Sunset Design. - * 04/2009 2.0b99.0% Many new features and critical fixes. - * 01/2009 2.0b98.0% Now running Linux, Windows, Mac OS X, BeOS, Haiku, - AmigaOS 3.x and 4, MorphOS, SkyOS and gp2x. - * 10/2008 2.0b97.0% Our first public beta release. - * 07/2008 Our first public alpha release, Windows and Linux only - * 04/2007 Start of this project and port to SDL. - * 2001 Sunset Design releases the source under the GNU GPL. - * 12/1999 2.0b96.5% Last release from Sunset Design. - * 11/1996 2.0b90% First public release, at the Wired'96. - * 09/1995 Project starts. + * 09/2009 2.1 GUI improvements and some new features. + * 06/2009 2.0 Completed the features planned by Sunset Design. + * 04/2009 2.0b99.0% Many new features and critical fixes. + * 01/2009 2.0b98.0% Now running Linux, Windows, Mac OS X, BeOS, Haiku, + AmigaOS 3.x and 4, MorphOS, SkyOS and gp2x. + * 10/2008 2.0b97.0% Our first public beta release. + * 07/2008 Our first public alpha release, Windows and Linux only + * 04/2007 Start of this project and port to SDL. + * 2001 Sunset Design releases the source under the GNU GPL. + * 12/1999 2.0b96.5% Last release from Sunset Design. + * 11/1996 2.0b90% First public release, at the Wired'96. + * 09/1995 Project starts. Check http://code.google.com/p/grafx2/source/list for (very) detailed changelog. Check http://code.google.com/p/grafx2/wiki/History for an overview of the new From 0f5d002505f88abe833a41f1307b971be14ad26e Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Fri, 11 Sep 2009 22:16:41 +0000 Subject: [PATCH 94/95] version tag git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1025 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- pversion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pversion.c b/pversion.c index f7ca5bb4..f09c8e6b 100644 --- a/pversion.c +++ b/pversion.c @@ -1 +1 @@ -char Program_version[]="2.1wip"; +char Program_version[]="2.1"; From 2345a764d68c49352aa37b2bad40539a97287eb6 Mon Sep 17 00:00:00 2001 From: Yves Rizoud Date: Fri, 11 Sep 2009 22:40:47 +0000 Subject: [PATCH 95/95] Fix severe old bug where RGB scale couldn't be set back to 256. Update NSIS script (win32 installer) git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1026 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- install/WinInstaller.nsi | 18 ++++++++++++------ palette.c | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/install/WinInstaller.nsi b/install/WinInstaller.nsi index de83d47a..95552b64 100644 --- a/install/WinInstaller.nsi +++ b/install/WinInstaller.nsi @@ -11,7 +11,7 @@ ;Name and file Name "Grafx2" - OutFile "grafx2-2.0-svn853-win32.exe" + OutFile "grafx2-2.1.1026.win32.exe" ;Default installation folder InstallDir "$PROGRAMFILES\Grafx2" @@ -60,7 +60,7 @@ Section "Grafx2" SecProgram SetOutPath "$INSTDIR" ;ADD YOUR OWN FILES HERE... File ..\grafx2.exe - File ..\src-svn853.tgz + File ..\src-2.1.1026.tgz File ..\gfx2.gif File ..\gfx2def.ini File ..\SDL_image.dll @@ -70,7 +70,10 @@ Section "Grafx2" SecProgram File ..\zlib1.dll File ..\libpng13.dll SetOutPath "$INSTDIR\skins" - File ..\skins\base.gif + File ..\skins\font_Classic.png + File ..\skins\font_Fun.png + File ..\skins\skin_classic.png + File ..\skins\skin_modern.png SetOutPath "$INSTDIR\doc" File ..\doc\README.txt File ..\doc\COMPILING.txt @@ -97,7 +100,7 @@ Section "Grafx2" SecProgram WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "URLInfoAbout" "http://grafx2.googlecode.com" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ - "DisplayVersion" "2.0 final" + "DisplayVersion" "2.1.1026" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ "NoModify" 1 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Grafx2-SDL" \ @@ -139,7 +142,7 @@ Section "un.SecProgram" ;ADD YOUR OWN FILES HERE... Delete "$INSTDIR\grafx2.exe" - Delete "$INSTDIR\src-svn853.tgz" + Delete "$INSTDIR\src-2.1.1026.tgz" Delete "$INSTDIR\gfx2.gif" Delete "$INSTDIR\gfx2def.ini" Delete "$INSTDIR\SDL_image.dll" @@ -159,7 +162,10 @@ Section "un.SecProgram" Delete "$INSTDIR\fonts\8pxfont.png" Delete "$INSTDIR\fonts\Tuffy.ttf" RMDir "$INSTDIR\fonts" - Delete "$INSTDIR\skins\base.gif" + Delete "$INSTDIR\skins\font_Classic.png" + Delete "$INSTDIR\skins\font_Fun.png" + Delete "$INSTDIR\skins\skin_classic.png" + Delete "$INSTDIR\skins\skin_modern.png" RMDir "$INSTDIR\skins" Delete "$INSTDIR\Uninstall.exe" diff --git a/palette.c b/palette.c index c4df752e..8a1abb81 100644 --- a/palette.c +++ b/palette.c @@ -2176,7 +2176,8 @@ void Button_Secondary_palette(void) T_Scroller_button * rgb_scale_slider; char str[4]; byte palette_vertical = Config.Palette_vertical; - byte palette_cols, palette_lines, rgb_scale; + byte palette_cols, palette_lines; + word rgb_scale; byte palette_needs_redraw=0; Open_window(200,146,"Palettes");