From eba26aaa962d1db2c3da60793402f1582163bca3 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Sun, 13 Feb 2011 21:49:31 +0000 Subject: [PATCH] Merge trunk to the cpcmode5 branch. This gets us a more recent grafx2 with the cpcmode5 drawing. Now to make this mode optional so users can still work in regular mode :) git-svn-id: svn://pulkomandy.tk/GrafX2/branches/cpcmode5@1719 416bcca6-2ee7-4201-b75f-2eb2f807beb1 --- src/Makefile | 121 +++-- src/Makefile.dep | 46 +- src/SFont.c | 55 +- src/SFont.h | 5 +- src/brush.c | 769 +++++++++++++-------------- src/brush.h | 15 +- src/brush_ops.c | 110 +++- src/buttons.c | 1067 +++++++++++++++++++++++++------------ src/buttons.h | 4 + src/buttons_effects.c | 66 ++- src/const.h | 67 ++- src/engine.c | 664 +++++++++++++++++------ src/engine.h | 21 +- src/factory.c | 1036 ++++++++++++++++++++++++++++-------- src/factory.h | 10 + src/fileformats.c | 548 +++++++++++++++---- src/filesel.c | 502 ++++++++++++++---- src/filesel.h | 12 +- src/global.h | 182 ++++--- src/graph.c | 124 +++-- src/help.c | 256 +++++---- src/help.h | 12 + src/helpfile.h | 155 +++++- src/hotkeys.c | 189 ++++++- src/hotkeys.h | 2 + src/init.c | 847 ++++++++++++++++++++---------- src/init.h | 6 +- src/input.c | 658 +++++++++++++++++------ src/input.h | 10 +- src/io.c | 49 +- src/io.h | 7 + src/keyboard.c | 108 +++- src/loadsave.c | 373 ++++++++----- src/loadsave.h | 30 +- src/main.c | 164 +++--- src/misc.c | 58 +- src/misc.h | 4 +- src/miscfileformats.c | 124 +++-- src/mountlist.c | 2 +- src/op_c.c | 46 ++ src/op_c.h | 1 + src/operatio.c | 197 +++++-- src/operatio.h | 5 + src/pages.c | 234 +++++++-- src/pages.h | 12 +- src/palette.c | 1167 ++++++++++++++++++++++++++++------------- src/palette.h | 16 + src/readini.c | 46 +- src/readline.c | 302 +++++++++-- src/readline.h | 13 +- src/realpath.c | 7 +- src/saveini.c | 169 +++--- src/sdlscreen.c | 64 ++- src/sdlscreen.h | 7 + src/setup.c | 40 +- src/setup.h | 103 +++- src/shade.c | 6 +- src/special.c | 3 + src/struct.h | 124 +++-- src/text.c | 245 ++++++--- src/text.h | 5 +- src/tiles.c | 114 ++++ src/transform.c | 5 +- src/windows.c | 540 ++++++++++++------- src/windows.h | 6 +- 65 files changed, 8669 insertions(+), 3286 deletions(-) create mode 100644 src/tiles.c diff --git a/src/Makefile b/src/Makefile index fb0c92d5..7846d638 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,6 @@ # Grafx2 - The Ultimate 256-color bitmap paint program # +# Copyright 2011 Pawel Góralski # Copyright 2009 Per Olofsson # Copyright 2008 Peter Gordon # Copyright 2008-2010 Yves Rizoud @@ -25,6 +26,7 @@ bindir = $(exec_prefix)/bin datarootdir = $(prefix)/share datadir = $(datarootdir) + pixmapdir = $(datarootdir)/icons # Compile with OPTIM=0 to disable gcc optimizations, to enable debug. STRIP = strip @@ -42,8 +44,8 @@ ifdef COMSPEC RMDIR = rmdir CP = cp BIN = ../bin/grafx2.exe - COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(LUACOPT) $(LAYERCOPT) - LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) + COPT = -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -g -ggdb `sdl-config --cflags` $(TTFCOPT) $(JOYCOPT) $(VKEYCOPT) $(LUACOPT) $(LAYERCOPT) + LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng14 $(LUALOPT) LUALOPT = -llua CC = gcc OBJDIR = ../obj/win32 @@ -52,7 +54,7 @@ ifdef COMSPEC PLATFORMOBJ = $(OBJDIR)/winres.o PLATFORM = win32 #some misc files we have to add to the release archive under windows. - PLATFORMFILES = bin/SDL.dll bin/SDL_image.dll bin/libpng13.dll bin/zlib1.dll $(TTFLIBS) + PLATFORMFILES = bin/SDL.dll bin/SDL_image.dll bin/libpng14-14.dll bin/zlib1.dll $(TTFLIBS) ZIP = zip else @@ -88,7 +90,7 @@ else FWDIR = /Library/Frameworks SDLCOPT = -arch i386 -I$(FWDIR)/SDL.framework/Headers -I$(FWDIR)/SDL_image.framework/Headers -I$(FWDIR)/SDL_ttf.framework/Headers -D_THREAD_SAFE SDLLOPT = -arch i386 -L/usr/lib -framework SDL -framework SDL_image -framework SDL_ttf -framework Cocoa -framework Carbon -framework OpenGL - COPT = -D__macosx__ -D__linux__ -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g $(SDLCOPT) $(TTFCOPT) -I/usr/X11/include + COPT = -D_DARWIN_C_SOURCE -D__macosx__ -D__linux__ -W -Wall -Wdeclaration-after-statement -O$(OPTIM) -std=c99 -c -g $(SDLCOPT) $(TTFCOPT) -I/usr/X11/include LOPT = $(SDLLOPT) -L/usr/X11/lib -R/usr/X11/lib -lpng # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc @@ -152,8 +154,15 @@ else RMDIR = rmdir CP = cp BIN = ../bin/grafx2 - COPT = -W -Wall -c -g `sdl-config --cflags` $(TTFCOPT) -I/boot/common/include - LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) + ifeq ($(NOLUA),1) + LUACOPT = + LUALOPT = + else + LUACOPT = -D__ENABLE_LUA__ + LUALOPT = -llua + endif + COPT = -W -Wall -c -g `sdl-config --cflags` $(TTFCOPT) -I/boot/common/include $(LUACOPT) + LOPT = `sdl-config --libs` -lSDL_image -lpng -ljpeg -lz $(TTFLOPT) -lfreetype -lbe $(LUALOPT) CC = gcc OBJDIR = ../obj/haiku ZIP = zip @@ -197,19 +206,15 @@ else CP = cp ZIP = zip PLATFORMFILES = gfx2.png + ifneq ($(ATARICROSS),1) ifeq ($(NOLUA),1) LUACOPT = LUALOPT = else - ifeq (`pkg-config --exists lua --print-errors`,"") - LUACOPT = `pkg-config lua --cflags` - LUALOPT = `pkg-config lua --libs` - else - LUACOPT = `pkg-config lua5.1 --cflags` - LUALOPT = `pkg-config lua5.1 --libs` - endif + LUACOPT = `pkg-config lua --cflags --silence-errors ||pkg-config lua5.1 --cflags --silence-errors ||pkg-config lua-5.1 --cflags` + LUALOPT = `pkg-config lua --libs --silence-errors ||pkg-config lua5.1 --libs --silence-errors ||pkg-config lua-5.1 --libs` + endif endif - # These can only be used under linux and maybe freebsd. They allow to compile for the gp2x or to create a windows binary ifdef WIN32CROSS #cross compile a Win32 executable @@ -225,18 +230,41 @@ else #cross compile an exec for the gp2x CC = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-gcc BIN = ../bin/grafx2.gpe - COPT = -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -static -g -O$(OPTIM) -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --cflags` $(TTFCOPT) -D__GP2X__ $(TTFCOPT) $(JOYCOPT) $(LUACOPT) $(LAYERCOPT) + COPT = -W -Wall -Wdeclaration-after-statement -pedantic -std=c99 -static -g -O$(OPTIM) -I/opt/open2x/gcc-4.1.1-glibc-2.3.6/include `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --cflags` $(TTFCOPT) -D__GP2X__ $(TTFCOPT) $(JOYCOPT) $(VKEYCOPT) $(LUACOPT) $(LAYERCOPT) LOPT = -static -lSDL_image `/opt/open2x/gcc-4.1.1-glibc-2.3.6/bin/sdl-config --static-libs` -ljpeg -lpng -lz -lm $(TTFLOPT) $(LUALOPT) OBJDIR = ../obj/gp2x NOTTF = 1 PLATFORM = gp2x STRIP = /opt/open2x/gcc-4.1.1-glibc-2.3.6/arm-open2x-linux/bin/arm-open2x-linux-strip JOYCOPT = -DUSE_JOYSTICK + + else ifdef AROS32CROSS + #cross compile an Aros 32 bit executable + BIN = ../bin/grafx2 + COPT = -Wall -g `i386-linux-aros-sdl-config --cflags` $(TTFCOPT) + LOPT = -lSDL_image `i386-linux-aros-sdl-config --libs` -lpng -ljpeg -lz $(TTFLOPT) -lfreetype2shared + CC = i386-aros-gcc + OBJDIR = ../obj/aros + STRIP = strip --strip-unneeded --remove-section .comment + PLATFORM = AROS + ZIP = lha + ZIPOPT = a + else ifdef ATARICROSS + #cross compile an exec for atari TOS/MiNT machine + CC = m68k-atari-mint-gcc + BIN = ../bin/grafx2.ttp + LUALOPT = -llua + OBJDIR = ../obj/m68k-atari-mint + PLATFORM = m68k-atari-mint + STRIP = m68k-atari-mint-strip -s + X11LOPT = + COPT = -W -Wall -m68020-60 -fomit-frame-pointer -pedantic -std=c99 -Wdeclaration-after-statement -D__MINT__ -DNO_INLINE_MATH -O$(OPTIM) -c -I$(prefix)/include `$(prefix)/bin/libpng12-config --cflags` `$(prefix)/bin/sdl-config --cflags` $() $(JOYCOPT) $(LAYERCOPT) $(LUACOPT) + LOPT = -static -m68020-60 -lSDL_image `$(prefix)/bin/sdl-config --libs` -L$(prefix)/lib -ltiff -ljpeg `$(prefix)/bin/libpng12-config --libs` -lz -lm $(TTFLOPT) -lfreetype $(LUALOPT) $(LAYERLOPT) else # Compiles a regular linux executable for the native platform BIN = ../bin/grafx2 - COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) $(LUACOPT) + COPT = -W -Wall -Wdeclaration-after-statement -std=c99 -c -g `sdl-config --cflags` $(TTFCOPT) $(LUACOPT) $(JOYCOPT) $(VKEYCOPT) -O$(OPTIM) LOPT = `sdl-config --libs` -lSDL_image $(TTFLOPT) -lpng $(LUALOPT) -lm # Use gcc for compiling. Use ncc to build a callgraph and analyze the code. CC = gcc @@ -258,6 +286,7 @@ endif ### BUILD SETTINGS are set according to vars set in the platform selection, the "overridable defaults", and environment variables set before launching make #TrueType is optional: make NOTTF=1 to disable support and dependencies. +ifndef ($(ATARICROSS,1)) ifeq ($(NOTTF),1) TTFCOPT = -DNOTTF=1 TTFLOPT = @@ -265,10 +294,23 @@ ifeq ($(NOTTF),1) TTFLABEL = -nottf else TTFCOPT = - TTFLOPT = -L/usr/local/lib -lSDL_ttf $(X11LOPT) + TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(X11LOPT) TTFLIBS = bin/libfreetype-6.dll bin/SDL_ttf.dll TTFLABEL = endif +else +ifeq ($(NOTTF),1) + TTFCOPT = -DNOTTF=1 + TTFLOPT = + TTFLIBS = + TTFLABEL = -nottf +else + TTFCOPT = + TTFLOPT = -L$(prefix)/lib -lSDL_ttf $(X11LOPT) + TTFLIBS = + TTFLABEL = +endif +endif #Lua scripting is optional too ifeq ($(NOLUA),1) @@ -289,6 +331,14 @@ ifeq ($(USE_JOYSTICK),1) JOYCOPT = -DUSE_JOYSTICK endif +#To enable virtual keyboard input (mouse-driven), make VIRT_KEY=1 +#This is automatically enabled on some platforms, but this +#switch allows you to test the virtual keyboard on any other platform. +ifeq ($(VIRT_KEY),1) + VKEYCOPT = -DVIRT_KEY +endif + + #To speed up rendering, can disable the layered editing # with NOLAYERS=1 ifeq ($(NOLAYERS),1) @@ -304,11 +354,16 @@ endif # This is the list of the objects we want to build. Dependancies are built by "make depend" automatically. OBJ = $(OBJDIR)/main.o $(OBJDIR)/init.o $(OBJDIR)/graph.o $(OBJDIR)/sdlscreen.o $(OBJDIR)/misc.o $(OBJDIR)/special.o $(OBJDIR)/buttons.o $(OBJDIR)/palette.o $(OBJDIR)/help.o $(OBJDIR)/operatio.o $(OBJDIR)/pages.o $(OBJDIR)/loadsave.o $(OBJDIR)/readline.o $(OBJDIR)/engine.o $(OBJDIR)/filesel.o $(OBJDIR)/op_c.o $(OBJDIR)/readini.o $(OBJDIR)/saveini.o $(OBJDIR)/shade.o $(OBJDIR)/keyboard.o $(OBJDIR)/io.o $(OBJDIR)/version.o $(OBJDIR)/text.o $(OBJDIR)/SFont.o $(OBJDIR)/setup.o $(OBJDIR)/pxsimple.o $(OBJDIR)/pxtall.o $(OBJDIR)/pxwide.o $(OBJDIR)/pxdouble.o $(OBJDIR)/pxtriple.o $(OBJDIR)/pxtall2.o $(OBJDIR)/pxwide2.o $(OBJDIR)/pxquad.o $(OBJDIR)/windows.o $(OBJDIR)/brush.o $(OBJDIR)/realpath.o $(OBJDIR)/mountlist.o $(OBJDIR)/input.o $(OBJDIR)/hotkeys.o $(OBJDIR)/transform.o $(OBJDIR)/pversion.o $(OBJDIR)/factory.o $(PLATFORMOBJ) $(OBJDIR)/fileformats.o $(OBJDIR)/miscfileformats.o $(OBJDIR)/libraw2crtc.o $(OBJDIR)/brush_ops.o $(OBJDIR)/buttons_effects.o $(OBJDIR)/layers.o $(OBJDIR)/oldies.o -SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png +SKIN_FILES = ../share/grafx2/skins/skin_classic.png ../share/grafx2/skins/skin_modern.png ../share/grafx2/skins/skin_DPaint.png ../share/grafx2/skins/font_Classic.png ../share/grafx2/skins/font_Fun.png ../share/grafx2/skins/font_Fairlight.png ../share/grafx2/skins/font_Melon.png ../share/grafx2/skins/font_DPaint.png ../share/grafx2/skins/skin_scenish.png ../share/grafx2/skins/font_Seen.png ../share/grafx2/skins/skin_Aurora.png ../share/grafx2/skins/skin_Clax3.gif ../share/grafx2/skins/skin_Clax2.gif ../share/grafx2/skins/skin_Clax4.gif SCRIPT_FILES1 = ../share/grafx2/scripts/bru_db_Amigaball.lua ../share/grafx2/scripts/bru_db_ColorSphere.lua ../share/grafx2/scripts/bru_db_FindAA.lua ../share/grafx2/scripts/bru_db_Fisheye.lua ../share/grafx2/scripts/bru_db_GrayscaleAvg.lua ../share/grafx2/scripts/bru_db_GrayscaleDesat.lua ../share/grafx2/scripts/bru_db_Halfsmooth.lua ../share/grafx2/scripts/bru_db_Mandelbrot.lua ../share/grafx2/scripts/bru_db_Waves.lua ../share/grafx2/scripts/pal_db_Desaturate.lua ../share/grafx2/scripts/pal_db_ExpandColors.lua ../share/grafx2/scripts/pal_db_FillColorCube.lua ../share/grafx2/scripts/pal_db_InvertedRGB.lua ../share/grafx2/scripts/pal_db_Set3bit.lua ../share/grafx2/scripts/pal_db_Set6bit.lua ../share/grafx2/scripts/pal_db_SetC64Palette.lua ../share/grafx2/scripts/pal_db_ShiftHue.lua ../share/grafx2/scripts/pic_db_Pic2isometric.lua ../share/grafx2/scripts/pic_db_Rainbow-Dark2Bright.lua ../share/grafx2/scripts/pic_db_SierpinskyCarpet.lua -SCRIPT_FILES2 = ../share/grafx2/scripts/pic_db_SierpinskyTriangle.lua ../share/grafx2/scripts/pic_ni_Colorspace12bit.lua ../share/grafx2/scripts/pic_ni_Colorspace15bit.lua ../share/grafx2/scripts/pic_ni_Colorspace18bit.lua ../share/grafx2/scripts/pic_ni_GlassGridFilter.lua ../share/grafx2/scripts/pic_ni_Grid8.lua ../share/grafx2/scripts/pic_ni_Grid8red.lua ../share/grafx2/scripts/pic_ni_GridIso.lua ../share/grafx2/scripts/pic_ni_PaletteX1.lua ../share/grafx2/scripts/pic_ni_PaletteX8.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB_ed.lua ../share/grafx2/scripts/scn_db_RemapImageTo3bitPal.lua -SCRIPT_FILES1= SCRIPT_FILES1 SCRIPT_FILES2 +SCRIPT_FILES2 = ../share/grafx2/scripts/pic_db_SierpinskyTriangle.lua ../share/grafx2/scripts/pic_ni_GlassGridFilter.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB.lua ../share/grafx2/scripts/scn_db_RemapImage2RGB_ed.lua ../share/grafx2/scripts/scn_db_RemapImageTo3bitPal.lua +SCRIPT_FILES= $(SCRIPT_FILES1) $(SCRIPT_FILES2) + +SCRIPTLIB_FILES = ../share/grafx2/scripts/libs/memory.lua + +FONT_FILES = ../share/grafx2/fonts/8pxfont.png ../share/grafx2/fonts/Tuffy.ttf ../share/grafx2/fonts/PF_Arma_5__.png ../share/grafx2/fonts/PF_Easta_7_.png ../share/grafx2/fonts/PF_Easta_7__.png ../share/grafx2/fonts/PF_Ronda_7__.png ../share/grafx2/fonts/PF_Tempesta_5.png ../share/grafx2/fonts/PF_Tempesta_5_.png ../share/grafx2/fonts/PF_Tempesta_5__.png ../share/grafx2/fonts/PF_Tempesta_5___.png ../share/grafx2/fonts/PF_Tempesta_7.png ../share/grafx2/fonts/PF_Tempesta_7_.png ../share/grafx2/fonts/PF_Tempesta_7__.png ../share/grafx2/fonts/PF_Tempesta_7___.png ../share/grafx2/fonts/PF_Westa_7_.png ../share/grafx2/fonts/PF_Westa_7__.png + ifeq ($(PLATFORM),Darwin) all : $(MACAPPEXE) @@ -316,11 +371,11 @@ $(MACAPPEXE) : $(BIN) rm -rf Grafx2.app mkdir -p Grafx2.app Grafx2.app/Contents Grafx2.app/Contents/Frameworks Grafx2.app/Contents/MacOS Grafx2.app/Contents/Resources echo 'APPL????' > Grafx2.app/Contents/PkgInfo - cp Info.plist Grafx2.app/Contents + cp ../Info.plist Grafx2.app/Contents cp -r English.lproj Grafx2.app/Contents/Resources - cp -r fonts Grafx2.app/Contents/Resources - cp -r skins Grafx2.app/Contents/Resources - cp -r gfx2def.ini Grafx2.app/Contents/Resources + cp -r ../share/grafx2/fonts Grafx2.app/Contents/Resources + cp -r ../share/grafx2/skins Grafx2.app/Contents/Resources + cp -r ../share/grafx2/gfx2def.ini Grafx2.app/Contents/Resources cp -Rp $(FWDIR)/SDL.framework Grafx2.app/Contents/Frameworks cp -Rp $(FWDIR)/SDL_image.framework Grafx2.app/Contents/Frameworks cp -Rp $(FWDIR)/SDL_ttf.framework Grafx2.app/Contents/Frameworks @@ -341,9 +396,9 @@ ziprelease: version $(BIN) release echo `sed "s/.*=\"\(.*\)\";/\1/" pversion.c`.`svnversion` | tr " :" "_-" | sed -e "s/\(wip\)\\./\1/I" > $(OBJDIR)/versiontag tar cvzf "../src-`cat $(OBJDIR)/versiontag`.tgz" --strip=1 ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../src/gfx2.ico - cd .. && $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR:../%=%)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN:../%=%) share/grafx2/gfx2def.ini $(SCRIPT_FILES:../%=%) $(SKIN_FILES:../%=%) share/grafx2/gfx2.gif share/icons/grafx2.svg doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt share/grafx2/fonts/8pxfont.png doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt doc/README-lua.txt share/grafx2/fonts/Tuffy.ttf src-`cat $(OBJDIR:../%=%)/versiontag`.tgz $(PLATFORMFILES:../%=%) + cd .. && $(ZIP) $(ZIPOPT) "grafx2-`cat $(OBJDIR:../%=%)/versiontag`$(TTFLABEL)-$(PLATFORM).$(ZIP)" $(BIN:../%=%) share/grafx2/gfx2def.ini $(SCRIPT_FILES:../%=%) $(SCRIPTLIB_FILES:../%=%) $(SKIN_FILES:../%=%) share/grafx2/gfx2.gif share/icons/grafx2.svg doc/README.txt doc/COMPILING.txt doc/gpl-2.0.txt doc/PF_fonts.txt $(FONT_FILES:../%=%) doc/README-zlib1.txt doc/README-SDL.txt doc/README-SDL_image.txt doc/README-SDL_ttf.txt doc/README-lua.txt src-`cat $(OBJDIR:../%=%)/versiontag`.tgz $(PLATFORMFILES:../%=%) $(DELCOMMAND) "../src-`cat $(OBJDIR)/versiontag`.tgz" - tar cvzf "../grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --strip=1 --transform 's,^,grafx2/,g' ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../share/grafx2/gfx2def.ini $(SCRIPT_FILES) $(SKIN_FILES) ../src/gfx2.ico ../share/grafx2/gfx2.gif ../share/icons/grafx2.svg ../doc/README.txt ../doc/COMPILING.txt ../doc/gpl-2.0.txt ../misc/unix/grafx2.1 ../misc/unix/grafx2.xpm ../misc/unix/grafx2.desktop ../share/grafx2/fonts/8pxfont.png ../share/grafx2/fonts/Tuffy.ttf + tar cvzf "../grafx2-`cat $(OBJDIR)/versiontag`$(TTFLABEL)-src.tgz" --strip=1 --transform 's,^,grafx2/,g' ../src/*.c ../src/*.h ../src/Makefile ../src/Makefile.dep ../share/grafx2/gfx2def.ini $(SCRIPT_FILES) $(SCRIPTLIB_FILES) $(SKIN_FILES) ../src/gfx2.ico ../share/grafx2/gfx2.gif ../share/icons/grafx2.svg ../doc/README.txt ../doc/COMPILING.txt ../doc/gpl-2.0.txt ../doc/PF_fonts.txt ../misc/unix/grafx2.1 ../misc/unix/grafx2.xpm ../misc/unix/grafx2.desktop $(FONT_FILES) $(DELCOMMAND) "$(OBJDIR)/versiontag" testsed : @@ -400,8 +455,9 @@ install : $(BIN) test -d $(DESTDIR)$(datadir)/grafx2/fonts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/fonts test -d $(DESTDIR)$(datadir)/grafx2/skins || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/skins test -d $(DESTDIR)$(datadir)/grafx2/scripts || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts + test -d $(DESTDIR)$(datadir)/grafx2/scripts/libs || $(MKDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs test -d $(DESTDIR)$(datadir)/applications || $(MKDIR) $(DESTDIR)$(datadir)/applications - test -d $(DESTDIR)$(datadir)/icons || $(MKDIR) $(DESTDIR)$(datadir)/icons + test -d $(DESTDIR)$(pixmapdir) || $(MKDIR) $(DESTDIR)$(pixmapdir) # Copy files $(CP) $(BIN) $(DESTDIR)$(bindir) $(CP) ../share/grafx2/gfx2def.ini $(DESTDIR)$(datadir)/grafx2/ @@ -409,10 +465,11 @@ install : $(BIN) $(CP) ../share/grafx2/fonts/* $(DESTDIR)$(datadir)/grafx2/fonts/ $(CP) $(SKIN_FILES) $(DESTDIR)$(datadir)/grafx2/skins/ $(CP) $(SCRIPT_FILES) $(DESTDIR)$(datadir)/grafx2/scripts/ + $(CP) $(SCRIPTLIB_FILES) $(DESTDIR)$(datadir)/grafx2/scripts/libs/ # Icon and desktop file for debian $(CP) ../misc/unix/grafx2.desktop $(DESTDIR)$(datadir)/applications/ - $(CP) ../misc/unix/grafx2.xpm $(DESTDIR)$(datadir)/icons/ - $(CP) ../share/icons/grafx2.svg $(DESTDIR)$(datadir)/icons/ + $(CP) ../misc/unix/grafx2.xpm $(DESTDIR)$(pixmapdir) + $(CP) ../share/icons/grafx2.svg $(DESTDIR)$(pixmapdir) @echo Install complete # Linux uninstallation of the program @@ -424,13 +481,15 @@ uninstall : $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/fonts),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/fonts) $(DELCOMMAND) $(SKIN_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/skins),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/skins) + $(DELCOMMAND) $(SCRIPTLIB_FILES:../share%=$(DESTDIR)$(datadir)%) + $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts/libs),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts/libs) $(DELCOMMAND) $(SCRIPT_FILES:../share%=$(DESTDIR)$(datadir)%) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2/scripts),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2/scripts) $(if $(wildcard $(DESTDIR)$(datadir)/grafx2),,$(RMDIR) $(DESTDIR)$(datadir)/grafx2) # Icon and desktop file for debian $(DELCOMMAND) $(DESTDIR)$(datadir)/applications/grafx2.desktop - $(DELCOMMAND) $(DESTDIR)$(datadir)/icons/grafx2.xpm - $(DELCOMMAND) $(DESTDIR)$(datadir)/icons/grafx2.svg + $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.xpm + $(DELCOMMAND) $(DESTDIR)$(pixmapdir)/grafx2.svg @echo Uninstall complete endif diff --git a/src/Makefile.dep b/src/Makefile.dep index 73930c02..27c8461b 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -1,3 +1,4 @@ +$(OBJDIR)/SFont.o: SFont.c SFont.h $(OBJDIR)/brush.o: brush.c global.h struct.h const.h graph.h misc.h errors.h \ windows.h sdlscreen.h brush.h $(OBJDIR)/brush_ops.o: brush_ops.c brush.h struct.h const.h buttons.h engine.h \ @@ -5,12 +6,13 @@ $(OBJDIR)/brush_ops.o: brush_ops.c brush.h struct.h const.h buttons.h engine.h \ $(OBJDIR)/buttons.o: buttons.c const.h struct.h global.h misc.h graph.h engine.h \ readline.h filesel.h loadsave.h init.h buttons.h operatio.h pages.h \ palette.h errors.h readini.h saveini.h shade.h io.h help.h text.h \ - sdlscreen.h windows.h brush.h input.h special.h + sdlscreen.h windows.h brush.h input.h special.h setup.h $(OBJDIR)/buttons_effects.o: buttons_effects.c buttons.h struct.h const.h engine.h \ - global.h graph.h help.h input.h misc.h readline.h sdlscreen.h windows.h + global.h graph.h help.h input.h misc.h readline.h sdlscreen.h windows.h \ + brush.h $(OBJDIR)/engine.o: engine.c const.h struct.h global.h graph.h misc.h special.h \ buttons.h operatio.h shade.h errors.h sdlscreen.h windows.h brush.h \ - input.h engine.h pages.h layers.h + input.h engine.h pages.h layers.h factory.h loadsave.h io.h $(OBJDIR)/factory.o: factory.c brush.h struct.h const.h buttons.h engine.h errors.h \ filesel.h loadsave.h global.h graph.h io.h misc.h pages.h readline.h \ sdlscreen.h windows.h palette.h input.h help.h @@ -21,7 +23,8 @@ $(OBJDIR)/filesel.o: filesel.c const.h struct.h global.h misc.h errors.h io.h \ help.h filesel.h $(OBJDIR)/graph.o: graph.c global.h struct.h const.h engine.h buttons.h pages.h \ errors.h sdlscreen.h graph.h misc.h pxsimple.h pxtall.h pxwide.h \ - pxdouble.h pxtriple.h pxwide2.h pxtall2.h pxquad.h windows.h input.h + pxdouble.h pxtriple.h pxwide2.h pxtall2.h pxquad.h windows.h input.h \ + brush.h $(OBJDIR)/help.o: help.c const.h struct.h global.h misc.h engine.h helpfile.h \ help.h sdlscreen.h text.h keyboard.h windows.h input.h hotkeys.h \ errors.h pages.h @@ -29,9 +32,9 @@ $(OBJDIR)/hotkeys.o: hotkeys.c struct.h const.h global.h hotkeys.h $(OBJDIR)/init.o: init.c buttons.h struct.h const.h errors.h global.h graph.h \ init.h io.h factory.h help.h hotkeys.h keyboard.h loadsave.h misc.h \ mountlist.h operatio.h palette.h sdlscreen.h setup.h transform.h \ - windows.h layers.h + windows.h layers.h special.h $(OBJDIR)/input.o: input.c global.h struct.h const.h keyboard.h sdlscreen.h \ - windows.h errors.h misc.h input.h + windows.h errors.h misc.h buttons.h input.h loadsave.h $(OBJDIR)/io.o: io.c struct.h const.h io.h realpath.h $(OBJDIR)/keyboard.o: keyboard.c global.h struct.h const.h keyboard.h $(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h pages.h \ @@ -39,18 +42,20 @@ $(OBJDIR)/layers.o: layers.c const.h struct.h global.h windows.h engine.h pages. $(OBJDIR)/libraw2crtc.o: libraw2crtc.c const.h global.h struct.h loadsave.h $(OBJDIR)/loadsave.o: loadsave.c buttons.h struct.h const.h errors.h global.h io.h \ loadsave.h misc.h graph.h op_c.h pages.h palette.h sdlscreen.h windows.h \ - engine.h + engine.h brush.h setup.h $(OBJDIR)/main.o: main.c const.h struct.h global.h graph.h misc.h init.h buttons.h \ engine.h pages.h loadsave.h sdlscreen.h errors.h readini.h saveini.h \ - io.h text.h setup.h windows.h brush.h palette.h realpath.h + io.h text.h setup.h windows.h brush.h palette.h realpath.h input.h $(OBJDIR)/misc.o: misc.c struct.h const.h sdlscreen.h global.h errors.h buttons.h \ engine.h misc.h keyboard.h windows.h palette.h input.h graph.h pages.h $(OBJDIR)/miscfileformats.o: miscfileformats.c engine.h struct.h const.h errors.h \ global.h io.h libraw2crtc.h loadsave.h misc.h sdlscreen.h windows.h -$(OBJDIR)/mountlist.o: mountlist.c mountlist.h -$(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h errors.h +$(OBJDIR)/mountlist.o: mountlist.c +$(OBJDIR)/op_c.o: op_c.c op_c.h struct.h const.h errors.h global.h engine.h \ + windows.h $(OBJDIR)/operatio.o: operatio.c const.h struct.h global.h misc.h engine.h graph.h \ - operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h windows.h + operatio.h buttons.h pages.h errors.h sdlscreen.h brush.h windows.h \ + input.h $(OBJDIR)/pages.o: pages.c global.h struct.h const.h pages.h errors.h loadsave.h \ misc.h windows.h $(OBJDIR)/palette.o: palette.c const.h struct.h global.h misc.h engine.h readline.h \ @@ -63,34 +68,35 @@ $(OBJDIR)/pxquad.o: pxquad.c global.h struct.h const.h sdlscreen.h misc.h graph. pxquad.h $(OBJDIR)/pxsimple.o: pxsimple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxsimple.h -$(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxtall2.h $(OBJDIR)/pxtall.o: pxtall.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxtall.h pxsimple.h +$(OBJDIR)/pxtall2.o: pxtall2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ + pxtall2.h $(OBJDIR)/pxtriple.o: pxtriple.c global.h struct.h const.h sdlscreen.h misc.h \ graph.h pxtriple.h -$(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ - pxwide2.h $(OBJDIR)/pxwide.o: pxwide.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ pxwide.h -$(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h readini.h +$(OBJDIR)/pxwide2.o: pxwide2.c global.h struct.h const.h sdlscreen.h misc.h graph.h \ + pxwide2.h +$(OBJDIR)/readini.o: readini.c const.h errors.h global.h struct.h misc.h readini.h \ + setup.h $(OBJDIR)/readline.o: readline.c const.h struct.h global.h misc.h errors.h \ sdlscreen.h readline.h windows.h input.h $(OBJDIR)/realpath.o: realpath.c $(OBJDIR)/saveini.o: saveini.c const.h global.h struct.h readini.h io.h errors.h \ - misc.h saveini.h + misc.h saveini.h setup.h $(OBJDIR)/sdlscreen.o: sdlscreen.c global.h struct.h const.h sdlscreen.h errors.h \ misc.h $(OBJDIR)/setup.o: setup.c struct.h const.h io.h setup.h -$(OBJDIR)/SFont.o: SFont.c SFont.h $(OBJDIR)/shade.o: shade.c global.h struct.h const.h graph.h engine.h errors.h \ misc.h readline.h help.h sdlscreen.h windows.h input.h shade.h $(OBJDIR)/special.o: special.c const.h struct.h global.h graph.h engine.h windows.h \ special.h pages.h misc.h buttons.h $(OBJDIR)/text.o: text.c SFont.h struct.h const.h global.h sdlscreen.h io.h \ - errors.h + errors.h windows.h misc.h setup.h +$(OBJDIR)/tiles.o: tiles.c $(OBJDIR)/transform.o: transform.c global.h struct.h const.h transform.h engine.h \ sdlscreen.h windows.h input.h help.h misc.h readline.h buttons.h pages.h $(OBJDIR)/version.o: version.c $(OBJDIR)/windows.o: windows.c windows.h struct.h const.h engine.h errors.h \ - global.h graph.h input.h misc.h readline.h sdlscreen.h + global.h graph.h input.h misc.h op_c.h readline.h sdlscreen.h palette.h diff --git a/src/SFont.c b/src/SFont.c index 0e9a8c95..fef5b17f 100644 --- a/src/SFont.c +++ b/src/SFont.c @@ -69,7 +69,7 @@ static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y) SFont_Font* SFont_InitFont(SDL_Surface* Surface) { - int x = 0, i = 0; + int x = 0, i = 33; Uint32 pixel; SFont_Font* Font; Uint32 pink; @@ -78,21 +78,42 @@ SFont_Font* SFont_InitFont(SDL_Surface* Surface) return NULL; Font = (SFont_Font *) malloc(sizeof(SFont_Font)); + memset(Font, 0, sizeof(SFont_Font)); + Font->Surface = Surface; SDL_LockSurface(Surface); - pink = SDL_MapRGB(Surface->format, 255, 0, 255); + pink = GetPixel(Surface, 0, 0); while (x < Surface->w) { - if (GetPixel(Surface, x, 0) == pink) { - Font->CharPos[i++]=x; - while((x < Surface->w) && (GetPixel(Surface, x, 0)== pink)) + if (GetPixel(Surface, x, 0) != pink) { + Font->CharBegin[i]=x; + while((x < Surface->w) && (GetPixel(Surface, x, 0)!= pink)) x++; - Font->CharPos[i++]=x; + Font->CharWidth[i]=x-Font->CharBegin[i]; + i++; } x++; } - Font->MaxPos = x-1; + + // Create lowercase characters, if not present + for (i=0; i <26; i++) + { + if (Font->CharWidth['a'+i]==0) + { + Font->CharBegin['a'+i]=Font->CharBegin['A'+i]; + Font->CharWidth['a'+i]=Font->CharWidth['A'+i]; + } + } + + // Determine space width. + // This strange format doesn't allow font designer to write explicit + // space as a character. + // Rule: A space should be as large as the character " if available, + // or 'a' if it's not. + Font->Space = Font->CharWidth[(int)'"']; + if (Font->Space<2) + Font->Space = Font->CharWidth[(int)'a']; pixel = GetPixel(Surface, 0, Surface->h-1); SDL_UnlockSurface(Surface); @@ -111,7 +132,6 @@ void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y, const char *text) { const char* c; - int charoffset; SDL_Rect srcrect, dstrect; if(text == NULL) @@ -123,42 +143,39 @@ void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, srcrect.h = dstrect.h = Font->Surface->h - 1; for(c = text; *c != '\0' && x <= Surface->w ; c++) { - charoffset = ((int) (*c - 33)) * 2 + 1; // skip spaces and nonprintable characters - if (*c == ' ' || charoffset < 0 || charoffset > Font->MaxPos) { - x += Font->CharPos[2]-Font->CharPos[1]; + if (*c == ' ' || Font->CharWidth[(int)*c]==0) { + x += Font->Space; continue; } - srcrect.w = Font->CharPos[charoffset+2] - Font->CharPos[charoffset]; + srcrect.w = Font->CharWidth[(int)*c]; dstrect.w = srcrect.w; - srcrect.x = Font->CharPos[charoffset]; + srcrect.x = Font->CharBegin[(int)*c]; dstrect.x = x; SDL_BlitSurface(Font->Surface, &srcrect, Surface, &dstrect); - x += Font->CharPos[charoffset+1] - Font->CharPos[charoffset]; + x += Font->CharWidth[(int)*c]; } } int SFont_TextWidth(const SFont_Font *Font, const char *text) { const char* c; - int charoffset=0; int width = 0; if(text == NULL) return 0; for(c = text; *c != '\0'; c++) { - charoffset = ((int) *c - 33) * 2 + 1; // skip spaces and nonprintable characters - if (*c == ' ' || charoffset < 0 || charoffset > Font->MaxPos) { - width += Font->CharPos[2]-Font->CharPos[1]; + if (*c == ' ' || Font->CharWidth[(int)*c]==0) { + width += Font->Space; continue; } - width += Font->CharPos[charoffset+1] - Font->CharPos[charoffset]; + width += Font->CharWidth[(int)*c]; } return width; diff --git a/src/SFont.h b/src/SFont.h index bca5fae2..27a54937 100644 --- a/src/SFont.h +++ b/src/SFont.h @@ -56,8 +56,9 @@ extern "C" { /// and call InitFont( YourFont ); typedef struct { SDL_Surface *Surface; - int CharPos[512]; - int MaxPos; + int CharBegin[256]; + int CharWidth[256]; + int Space; } SFont_Font; /// diff --git a/src/brush.c b/src/brush.c index de28b7fd..bf4c0d39 100644 --- a/src/brush.c +++ b/src/brush.c @@ -587,66 +587,97 @@ void Display_paintbrush(short x,short y,byte color,byte is_preview) } } -/// -/// Changes the Brush size, discarding its previous content. -/// @return 0 OK, 1 Failed -byte Realloc_brush(word new_brush_width, word new_brush_height) +/// @return 0 on success, non-zero on failure (memory?). +/// @param new_brush: Optionally, you can provide an already allocated new +/// brush - otherwise, this function performs the allocation. +/// @param old_brush: If the caller passes NULL, this function will free the old +/// pixel data. If the caller provides the address of a (free) byte +/// pointer, the function will make it point to the original pixel data, +/// in this case it will be the caller's responsibility to free() it +/// (after transferring pixels to Brush, usually). +byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush) { - byte return_code=0; + + byte *new_smear_brush; + byte *new_brush_remapped; + word new_smear_brush_width; + word new_smear_brush_height; + byte new_brush_is_provided; + new_brush_is_provided = (new_brush!=NULL); + + if (!new_brush_is_provided) + { + new_brush=(byte *)malloc(((long)new_brush_height)*new_brush_width); + if (new_brush == NULL) + { + Error(0); + if (old_brush) + *old_brush=NULL; + return 1; + } + } + + new_smear_brush_width=(new_brush_width>MAX_PAINTBRUSH_SIZE)?new_brush_width:MAX_PAINTBRUSH_SIZE; + new_smear_brush_height=(new_brush_height>MAX_PAINTBRUSH_SIZE)?new_brush_height:MAX_PAINTBRUSH_SIZE; + new_smear_brush=NULL; + if ( (((long)Smear_brush_height)*Smear_brush_width) != + (((long)new_smear_brush_width)*new_smear_brush_height) ) + { + new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width); + if (new_smear_brush == NULL) + { + Error(0); + if (old_brush) + *old_brush=NULL; + if (!new_brush_is_provided) + free(new_brush); + return 2; + } + } + new_brush_remapped=NULL; if ( (((long)Brush_height)*Brush_width) != (((long)new_brush_height)*new_brush_width) ) { - free(Brush); - Brush=(byte *)malloc(((long)new_brush_height)*new_brush_width); - if (Brush == NULL) + new_brush_remapped=(byte *)malloc(((long)new_brush_height)*new_brush_width); + if (new_brush_remapped == NULL) { Error(0); - return_code=1; - - Brush=(byte *)malloc(1*1); - if(Brush == NULL) - { - Error(ERROR_MEMORY); - exit(ERROR_MEMORY); - } - new_brush_height=new_brush_width=1; - *Brush=Fore_color; + free(new_smear_brush); + if (old_brush) + *old_brush=NULL; + if (!new_brush_is_provided) + free(new_brush); + return 3; } } + + // All allocations successful: can replace globals Brush_width=new_brush_width; Brush_height=new_brush_height; + Brush_original_back_color=Back_color; - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (Smear_brush == NULL) // Failed to allocate the smear brush + if (new_smear_brush) { - Error(0); - return_code=1; - - free(Brush); - Brush=(byte *)malloc(1*1); - if(Brush == NULL) - { - Error(ERROR_MEMORY); - exit(ERROR_MEMORY); - } - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - if(Smear_brush == NULL) - { - Error(ERROR_MEMORY); - exit(ERROR_MEMORY); - } - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; + free(Smear_brush); + Smear_brush=new_smear_brush; } - return return_code; + Smear_brush_width=new_smear_brush_width; + Smear_brush_height=new_smear_brush_height; + + // Save or free the old brush pixels + if (old_brush) + *old_brush=Brush_original_pixels; + else + free(old_brush); + Brush_original_pixels=new_brush; + // Assign new brush + if (new_brush_remapped) + { + free(Brush); + Brush=new_brush_remapped; + } + return 0; } @@ -828,7 +859,7 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle if (start_y+new_brush_height>Main_image_height) new_brush_height=Main_image_height-start_y; - if (Realloc_brush(new_brush_width, new_brush_height) != 0) + if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL)) return; // Unable to allocate the new brush, keep the old one. Copy_image_to_brush(start_x,start_y,Brush_width,Brush_height,Main_image_width); @@ -843,6 +874,10 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle } Update_part_of_screen(start_x,start_y,Brush_width,Brush_height); } + // Grab palette + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + // Remap (no change) + Remap_brush(); // On centre la prise sur la brosse Brush_offset_X=(Brush_width>>1); @@ -851,32 +886,25 @@ void Capture_brush(short start_x,short start_y,short end_x,short end_y,short cle } -void Rotate_90_deg() +void Rotate_90_deg(void) { - short temp; - byte * new_brush; - - new_brush=(byte *)malloc(((size_t)Brush_height)*Brush_width); - if (new_brush) + byte * old_brush; + + if (Realloc_brush(Brush_height, Brush_width, NULL, &old_brush)) { - Rotate_90_deg_lowlevel(Brush,new_brush,Brush_width,Brush_height); - free(Brush); - Brush=new_brush; - - temp=Brush_width; - Brush_width=Brush_height; - Brush_height=temp; - - temp=Smear_brush_width; - Smear_brush_width=Smear_brush_height; - Smear_brush_height=temp; - - // On centre la prise sur la brosse - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - } - else Error(0); + return; + } + Rotate_90_deg_lowlevel(old_brush,Brush_original_pixels,Brush_height,Brush_width); + + free(old_brush); + + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); + + // On centre la prise sur la brosse + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); } @@ -884,34 +912,45 @@ void Remap_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse - byte used[256]; // Tableau de booléens "La couleur est utilisée" int color; // On commence par initialiser le tableau de booléens à faux for (color=0;color<=255;color++) - used[color]=0; + Brush_colormap[color]=0; // On calcule la table d'utilisation des couleurs for (y_pos=0;y_pos>1); - Brush_offset_Y=(Brush_height>>1); - - free(temp); // Libération de l'ancienne brosse - temp = NULL; - - // Réallocation d'un buffer de Smear - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_width)*Smear_brush_height); + // 2ème balayage (vertical) + for (x_pos=1; x_pos>1); + Brush_offset_Y=(Brush_height>>1); + + free(old_brush); // Libération de l'ancienne brosse + } @@ -1039,112 +1071,105 @@ void Nibble_brush(void) { long x_pos,y_pos; byte state; - byte * new_brush; - byte * temp; - word width; - word height; + byte * old_brush; + word old_width; + word old_height; + int i; if ( (Brush_width>2) && (Brush_height>2) ) { - width=Brush_width-2; - height=Brush_height-2; - new_brush=(byte *)malloc(((long)width)*height); - - if (new_brush) + old_width=Brush_width; + old_height=Brush_height; + + SWAP_PBYTES(Brush, Brush_original_pixels); + if (Realloc_brush(Brush_width-2, Brush_height-2, NULL, &old_brush)) { - // On copie la brosse courante dans la nouvelle - Copy_part_of_image_to_another(Brush, // source - 1, - 1, - width, - height, - Brush_width, - new_brush, // Destination - 0, - 0, - width); + Error(0); + SWAP_PBYTES(Brush, Brush_original_pixels); + return; + } + // On copie l'ancienne brosse dans la nouvelle + Copy_part_of_image_to_another(old_brush, // source + 1, + 1, + old_width-2, + old_height-2, + old_width, + Brush, // Destination + 0, + 0, + Brush_width); - // On intervertit la nouvelle et l'ancienne brosse: - temp=Brush; - Brush=new_brush; - Brush_width-=2; - Brush_height-=2; - width+=2; - height+=2; - - // 1er balayage (horizontal) - for (y_pos=0; y_pos0) - Pixel_in_brush(x_pos-1,y_pos,Back_color); - state=0; - } - } - else - { - if (state == 0) - { - Pixel_in_brush(x_pos,y_pos,Back_color); - state=1; - } - } - } - // Cas du dernier pixel à droite de la ligne - if (temp[((y_pos+1)*width)+x_pos+1]==Back_color) - Pixel_in_brush(x_pos-1,y_pos,Back_color); - } - - // 2ème balayage (vertical) + // 1er balayage (horizontal) + for (y_pos=0; y_pos0) - Pixel_in_brush(x_pos,y_pos-1,Back_color); - state=0; - } - } - else - { - if (state == 0) - { - Pixel_in_brush(x_pos,y_pos,Back_color); - state=1; - } + if (x_pos>0) + Pixel_in_brush(x_pos-1,y_pos,Back_color); + state=0; + } + } + else + { + if (state == 0) + { + Pixel_in_brush(x_pos,y_pos,Back_color); + state=1; } } - // Cas du dernier pixel en bas de la colonne - if (temp[((y_pos+1)*width)+x_pos+1]==Back_color) - Pixel_in_brush(x_pos,y_pos-1,Back_color); } - - // On recentre la prise sur la brosse - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - - free(temp); // Libération de l'ancienne brosse - temp = NULL; - - // Réallocation d'un buffer de Smear - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_width)*Smear_brush_height); + // Cas du dernier pixel à droite de la ligne + if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) + Pixel_in_brush(x_pos-1,y_pos,Back_color); } - else - Error(0); // Pas assez de mémoire! + + // 2ème balayage (vertical) + for (x_pos=0; x_pos0) + Pixel_in_brush(x_pos,y_pos-1,Back_color); + state=0; + } + } + else + { + if (state == 0) + { + Pixel_in_brush(x_pos,y_pos,Back_color); + state=1; + } + } + } + // Cas du dernier pixel en bas de la colonne + if (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) + Pixel_in_brush(x_pos,y_pos-1,Back_color); + } + + free(old_brush); + // Adopt the current palette. + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); + for (i=0; i<256; i++) + Brush_colormap[i]=i; + //-- + + // On recentre la prise sur la brosse + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); + } } @@ -1162,7 +1187,6 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) word new_brush_width; word new_brush_height; - // On recherche les bornes de la brosse: for (temp=0; temp<2*vertices; temp+=2) { @@ -1204,46 +1228,15 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) new_brush_width=(end_x-start_x)+1; new_brush_height=(end_y-start_y)+1; - if ( (((long)Brush_height)*Brush_width) != - (((long)new_brush_height)*new_brush_width) ) - { - free(Brush); - Brush=(byte *)malloc(((long)new_brush_height)*new_brush_width); - if (!Brush) - { - Error(0); - - Brush=(byte *)malloc(1*1); - if(Brush==NULL) Error(ERROR_MEMORY); - new_brush_height=new_brush_width=1; - *Brush=Fore_color; - } - } - Brush_width=new_brush_width; - Brush_height=new_brush_height; - - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (!Smear_brush) // On ne peut même pas allouer la brosse du smear! + if (Realloc_brush(new_brush_width, new_brush_height, NULL, NULL)) { Error(0); - - free(Brush); - Brush=(byte *)malloc(1*1); - if(Brush==NULL) Error(ERROR_MEMORY); - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; + return; } Brush_offset_X=start_x; Brush_offset_Y=start_y; + Pixel_figure=Pixel_figure_in_brush; memset(Brush,Back_color,(long)Brush_width*Brush_height); @@ -1271,6 +1264,13 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear) if (clear) Pixel_in_current_screen(x_pos,y_pos,Back_color,0); } + // Grab palette + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + // Init colormap + for (temp=0; temp<256; temp++) + Brush_colormap[temp]=temp; + // Copy Brush to original + memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); // On centre la prise sur la brosse Brush_offset_X=(Brush_width>>1); @@ -1304,50 +1304,27 @@ void Stretch_brush(short x1, short y1, short x2, short y2) } new_brush_height++; - // Free some memory - free(Smear_brush); - Smear_brush = NULL; - - if ((new_brush=((byte *)malloc(new_brush_width*new_brush_height)))) + new_brush=((byte *)malloc(new_brush_width*new_brush_height)); + if (!new_brush) { - Rescale(Brush, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (!Smear_brush) // On ne peut même pas allouer la brosse du smear! - { - Error(0); - - free(Brush); - Brush=(byte *)malloc(1*1); - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; - } - - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - } - else - { - // Ici la libération de mémoire n'a pas suffi donc on remet dans l'état - // où c'etait avant. On a juste à réallouer la Smear_brush car il y a - // normalement la place pour elle puisque rien d'autre n'a pu être alloué - // entre temps. - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); Error(0); + return; } + + Rescale(Brush_original_pixels, Brush_width, Brush_height, new_brush, new_brush_width, new_brush_height, x2>1); + Brush_offset_Y=(Brush_height>>1); + } @@ -1578,9 +1555,6 @@ void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, s short min_x, max_x, min_y, max_y; short width, height; byte * new_brush; - byte * new_smear_brush; - short new_smear_brush_width; - short new_smear_brush_height; // Move all coordinates to start on (0,0) min_x=Min4(x1,x2,x3,x4); @@ -1601,24 +1575,11 @@ void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, s width=Max(max_x-min_x, 1); height=Max(max_y-min_y, 1); - new_smear_brush_width=(width>MAX_PAINTBRUSH_SIZE)?width:MAX_PAINTBRUSH_SIZE; - new_smear_brush_height=(height>MAX_PAINTBRUSH_SIZE)?height:MAX_PAINTBRUSH_SIZE; - - new_smear_brush=(byte *)malloc(((long)new_smear_brush_height)*new_smear_brush_width); - if (! new_smear_brush) - { - // Out of memory while allocating new smear brush - Error(0); - return; - } - new_brush=((byte *)malloc((long)width*height)); if (!new_brush) { // Out of memory while allocating new brush Error(0); - free(new_smear_brush); - new_smear_brush = NULL; return; } @@ -1631,18 +1592,14 @@ void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, s Distort_buffer_width=width; Draw_brush_linear_distort(0, 0, (Brush_width<<16), (Brush_height<<16), (x1<<16), (y1<<16), (x2<<16), (y2<<16), (x3<<16), (y3<<16), (x4<<16), (y4<<16)); - // Free old brushes - free(Smear_brush); - free(Brush); - - // Point to the new ones - Brush=new_brush; - Brush_width=width; - Brush_height=height; - - Smear_brush=new_smear_brush; - Smear_brush_width=new_smear_brush_width; - Smear_brush_height=new_smear_brush_height; + if (Realloc_brush(width, height, new_brush, NULL)) + { + free(new_brush); + Error(0); + return; + } + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); // Re-center brush handle Brush_offset_X=(Brush_width>>1); @@ -1867,7 +1824,7 @@ void Compute_quad_texture(int x1,int y1,int xt1,int yt1, xt=Round((float)(ScanY_Xt[0][y])+(temp*(ScanY_Xt[1][y]-ScanY_Xt[0][y]))); yt=Round((float)(ScanY_Yt[0][y])+(temp*(ScanY_Yt[1][y]-ScanY_Yt[0][y]))); if (xt>=0 && yt>=0) - buffer[x+(y*width)]=Read_pixel_from_brush(xt,yt); + buffer[x+(y*width)]=*(Brush_original_pixels + yt * Brush_width + xt); } for (; xMAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); - - if (!Smear_brush) // On ne peut même pas allouer la brosse du smear! - { - Error(0); - - free(Brush); - Brush=(byte *)malloc(1*1); - Brush_height=1; - Brush_width=1; - - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; - } - - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - } - else - { - // Ici la libération de mémoire n'a pas suffit donc on remet dans l'état - // où c'etait avant. On a juste à réallouer la Smear_brush car il y a - // normalement la place pour elle puisque rien d'autre n'a pu être alloué - // entre temps. - Smear_brush=(byte *)malloc(((long)Smear_brush_height)*Smear_brush_width); Error(0); + return; } + // Et maintenant on calcule la nouvelle brosse tournée. + Compute_quad_texture(x1,y1, 0, 0, + x2,y2,Brush_width-1, 0, + x3,y3, 0,Brush_height-1, + x4,y4,Brush_width-1,Brush_height-1, + new_brush,new_brush_width,new_brush_height); + + if (Realloc_brush(new_brush_width, new_brush_height, new_brush, NULL)) + { + free(new_brush); + return; + } + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); + + // Center offsets + Brush_offset_X=(Brush_width>>1); + Brush_offset_Y=(Brush_height>>1); + } @@ -2090,3 +2025,25 @@ void Rotate_brush_preview(float angle) end_y=Max(Max(y1,y2),Max(y3,y4)); Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1); } +/* +/// Sets brush's original palette and color mapping. +void Brush_set_palette(T_Palette *palette) +{ + int i; + byte need_remap; + + need_remap=0; + + memcpy(Brush_original_palette,palette,sizeof(T_Palette)); + for (i=0;i<256;i++) + { + if (Brush_original_palette[i].R!=Main_palette[i].R + || Brush_original_palette[i].G!=Main_palette[i].G + || Brush_original_palette[i].B!=Main_palette[i].B) + { + need_remap=1; + } + } + +} +*/ \ No newline at end of file diff --git a/src/brush.h b/src/brush.h index 7369cd6d..9682b1fe 100644 --- a/src/brush.h +++ b/src/brush.h @@ -111,10 +111,19 @@ void Capture_brush_with_lasso(int vertices, short * points,short clear); /// -/// Changes the Brush size, discarding its previous content. -/// @return 0 OK, 1 Failed -byte Realloc_brush(word new_brush_width, word new_brush_height); +/// Changes the Brush size. +/// @return 0 on success, non-zero on failure (memory?). +/// @param new_brush: Optionally, you can provide an already allocated new +/// brush - otherwise, this function performs the allocation. +/// @param old_brush: If the caller passes NULL, this function will free the old +/// pixel data. If the caller provides the address of a (free) byte +/// pointer, the function will make it point to the original pixel data, +/// in this case it will be the caller's responsibility to free() it +/// (after transferring pixels to Brush, usually). +byte Realloc_brush(word new_brush_width, word new_brush_height, byte *new_brush, byte **old_brush); +/// Sets brush's original palette and color mapping. +void Brush_set_palette(T_Palette *palette); #endif diff --git a/src/brush_ops.c b/src/brush_ops.c index 79ba4710..405ca753 100644 --- a/src/brush_ops.c +++ b/src/brush_ops.c @@ -38,7 +38,7 @@ #include "sdlscreen.h" #include "windows.h" -#if defined(__VBCC__)||defined(__GP2X__) +#if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif @@ -251,6 +251,106 @@ void Colorpicker_0_1(void) Unselect_button(BUTTON_COLORPICKER); } +/////////////////////////////////////////////////////////// OPERATION_RMB_COLORPICK + + +byte Rightclick_colorpick(byte cursor_visible) +{ + // Check if the rightclick colorpick should take over: + if (!Config.Right_click_colorpick) + return 0; + if (Mouse_K!=RIGHT_SIDE) + return 0; + // In these modes, the Foreground color is ignored, + // so the RMB should act as normal. + if (Shade_mode||Quick_shade_mode||Tiling_mode) + return 0; + + Colorpicker_color=-1; + Colorpicker_X=-1; + Colorpicker_Y=-1; + + if (cursor_visible) + Hide_cursor(); + Start_operation_stack(OPERATION_RMB_COLORPICK); + + Init_start_operation(); + + // Just an indicator to go to next step + Operation_push(1); + Rightclick_colorpick_2_1(); + + if (cursor_visible) + Display_cursor(); + + return 1; +} + +void Rightclick_colorpick_2_1(void) +// +// Opération : OPERATION_RMB_COLORPICK +// Click Souris: 2 +// Taille_Pile : 1 +// +// Souris effacée: Non +// +{ + char str[4]; + + if ( (Colorpicker_X!=Paintbrush_X) + || (Colorpicker_Y!=Paintbrush_Y) ) + { + if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) + && (Paintbrush_X=Main_X_zoom) ) ) + Print_in_menu("X: Y: ",0); + + Print_coordinates(); + + Display_cursor(); +} ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH @@ -858,6 +958,10 @@ void Rotate_brush_1_5(void) Operation_pop(&old_y); Operation_pop(&old_x); + // On corrige les coordonnées de la ligne si la touche shift est appuyée... + if(SDL_GetModState() & KMOD_SHIFT) + Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&Paintbrush_X,&Paintbrush_Y); + if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=2) ) { if ( (Brush_rotation_center_X==Paintbrush_X) @@ -921,6 +1025,10 @@ void Rotate_brush_0_5(void) Operation_pop(&old_y); Operation_pop(&old_x); + // On corrige les coordonnées de la ligne si la touche shift est appuyée... + if(SDL_GetModState() & KMOD_SHIFT) + Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&Paintbrush_X,&Paintbrush_Y); + if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) { if ( (Brush_rotation_center_X==Paintbrush_X) diff --git a/src/buttons.c b/src/buttons.c index 7e7ca04b..d483ea53 100644 --- a/src/buttons.c +++ b/src/buttons.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2007-2010 Adrien Destugues (PulkoMandy) Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -72,11 +73,28 @@ #include "brush.h" #include "input.h" #include "special.h" +#include "setup.h" #ifdef __VBCC__ #define __attribute__(x) #endif +#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) + #include + #include + #define isHidden(x) (0) +#elif defined(__MINT__) + #include + #include + #define isHidden(x) (0) +#elif defined(__WIN32__) + #include + #include + #define isHidden(x) (GetFileAttributesA((x)->d_name)&FILE_ATTRIBUTE_HIDDEN) +#else + #include + #define isHidden(x) ((x)->d_name[0]=='.') +#endif extern char Program_version[]; // generated in pversion.c @@ -162,7 +180,8 @@ void Button_Message_initial(void) Display_cursor(); - while(!Mouse_K && !Key) if(!Get_input()) SDL_Delay(20); + while(!Mouse_K && !Key) + Get_input(20); if (Mouse_K) Wait_end_of_click(); @@ -204,7 +223,7 @@ void Button_Undo(void) Display_all_screen(); Unselect_button(BUTTON_UNDO); - Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode); + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } @@ -219,7 +238,7 @@ void Button_Redo(void) Display_all_screen(); Unselect_button(BUTTON_UNDO); - Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode); + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); Display_menu(); Display_cursor(); } @@ -332,8 +351,7 @@ void Button_Select_forecolor(void) // Wait loop after initial click while(Mouse_K) { - if(!Get_input()) - SDL_Delay(20); + Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) { @@ -369,8 +387,7 @@ void Button_Select_backcolor(void) // Wait loop after initial click do { - if(!Get_input()) - SDL_Delay(20); + Get_input(20); if (Button_under_mouse()==BUTTON_CHOOSE_COL) break; // This will repeat this button's action @@ -759,6 +776,13 @@ const T_Lookup Lookup_MouseSpeed[] = { {NULL,-1}, }; +const T_Lookup Lookup_SwapButtons[] = { + {"None",0}, + {"Control",MOD_CTRL}, + {"Alt",MOD_ALT}, + {NULL,-1}, +}; + typedef struct { const char* Label; byte Type; // 0: label, 1+: setting (size in bytes) @@ -916,8 +940,7 @@ void Button_Settings(void) T_Setting setting[SETTING_PER_PAGE*SETTING_PAGES] = { - {" --- GUI ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, + {" --- GUI ---",0,NULL,0,0,0,NULL}, {"Opening message:",1,&(selected_config.Opening_message),0,1,0,Lookup_YesNo}, {"Menu ratio adapt:",1,&(selected_config.Ratio),0,1,0,Lookup_MenuRatio}, {"Draw limits:",1,&(selected_config.Display_image_limits),0,1,0,Lookup_YesNo}, @@ -925,11 +948,11 @@ void Button_Settings(void) {"Separate colors:",1,&(selected_config.Separate_colors),0,1,0,Lookup_YesNo}, {"Safety colors:",1,&(selected_config.Safety_colors),0,1,0,Lookup_YesNo}, {"Grid XOR color:",1,&(selected_config.Grid_XOR_color),0,255,3,NULL}, + {"Sync views:",1,&(selected_config.Sync_views),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- Input ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Scrollbar speed",0,NULL,0,0,0,NULL}, {" on left click:",1,&(selected_config.Delay_left_click_on_slider),1,255,4,NULL}, {" on right click:",1,&(selected_config.Delay_right_click_on_slider),1,255,4,NULL}, @@ -939,9 +962,9 @@ void Button_Settings(void) {"Mouse speed (fullscreen)",0,NULL,0,0,0,NULL}, {" horizontally:",1,&(selected_config.Mouse_sensitivity_index_x),1,4,0,Lookup_MouseSpeed}, {" vertically:",1,&(selected_config.Mouse_sensitivity_index_y),1,4,0,Lookup_MouseSpeed}, + {"Key to swap buttons:",2,&(selected_config.Swap_buttons),0,0,0,Lookup_SwapButtons}, {" --- Editing ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Adjust brush pick:",1,&(selected_config.Adjust_brush_pick),0,1,0,Lookup_YesNo}, {"Undo pages:",1,&(selected_config.Max_undo_pages),1,99,5,NULL}, {"Vertices per polygon:",4,&(selected_config.Nb_max_vertices_per_polygon),2,16384,5,NULL}, @@ -949,11 +972,11 @@ void Button_Settings(void) {"Clear with stencil:",1,&(selected_config.Clear_with_stencil),0,1,0,Lookup_YesNo}, {"Auto discontinuous:",1,&(selected_config.Auto_discontinuous),0,1,0,Lookup_YesNo}, {"Auto count colors:",1,&(selected_config.Auto_nb_used),0,1,0,Lookup_YesNo}, + {"Right click colorpick:",1,&(selected_config.Right_click_colorpick),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {" --- File selector ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Show in fileselector",0,NULL,0,0,0,NULL}, {" Hidden files:",4,&(selected_config.Show_hidden_files),0,1,0,Lookup_YesNo}, {" Hidden dirs:",4,&(selected_config.Show_hidden_directories),0,1,0,Lookup_YesNo}, @@ -963,9 +986,9 @@ void Button_Settings(void) {"Auto set resolution:",1,&(selected_config.Auto_set_res), 0,1,0,Lookup_YesNo}, {" According to:",1,&(selected_config.Set_resolution_according_to), 1,2,0,Lookup_AutoRes}, {"Backup:",1,&(selected_config.Backup), 0,1,0,Lookup_YesNo}, + {"",0,NULL,0,0,0,NULL}, {" --- Format options ---",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, {"Screen size in GIF:",1,&(selected_config.Screen_size_in_GIF),0,1,0,Lookup_YesNo}, {"Clear palette:",1,&(selected_config.Clear_palette),0,1,0,Lookup_YesNo}, {"",0,NULL,0,0,0,NULL}, @@ -975,6 +998,7 @@ void Button_Settings(void) {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, {"",0,NULL,0,0,0,NULL}, + {"",0,NULL,0,0,0,NULL}, }; @@ -982,7 +1006,7 @@ void Button_Settings(void) const char * help_section[SETTING_PAGES] = { "GUI", "INPUT", - "EDITING" + "EDITING", "FILE SELECTOR", "FILE FORMAT OPTIONS", }; @@ -1076,7 +1100,7 @@ void Button_Settings(void) str[0]='\0'; if (! (old_mouse_k & RIGHT_SIDE)) Num2str(value,str,item.Digits+1); - if (Readline(panel->Pos_X+3+176, panel->Pos_Y+num*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2,str,item.Digits+1,1)) + if (Readline(panel->Pos_X+3+176, panel->Pos_Y+num*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2,str,item.Digits+1,INPUT_TYPE_INTEGER)) { value=atoi(str); if (value=10 && fname[0]!='_' && !strncasecmp(fname, "skin_", 5) + if (namelength>=10 && fname[0]!='_' && !strncasecmp(fname, SKIN_PREFIX, strlen(SKIN_PREFIX)) && (!strcasecmp(fname + namelength - 4,".png") || !strcasecmp(fname + namelength - 4,".gif"))) { - Add_element_to_list(&Skin_files_list, name, 0); + Add_element_to_list(&Skin_files_list, fname, Format_filename(fname, 19, 0), 0, ICON_NONE); if (fname[0]=='\0') return; - - // Remove directory from full name - strcpy(Skin_files_list.First->Full_name, fname); - // Reformat the short name differently - strcpy(Skin_files_list.First->Short_name, - Format_filename(Skin_files_list.First->Full_name, 0) - ); } - else if (namelength>=10 && !strncasecmp(fname, "font_", 5) + else if (namelength>=10 && !strncasecmp(fname, FONT_PREFIX, strlen(FONT_PREFIX)) && (!strcasecmp(fname + namelength - 4, ".png"))) { - Add_element_to_list(&Font_files_list, name, 0); + Add_element_to_list(&Font_files_list, fname, Format_font_filename(fname), 0, ICON_NONE); if (fname[0]=='\0') return; - - // Remove directory from full name - strcpy(Font_files_list.First->Full_name, fname); - // Reformat the short name differently - strcpy(Font_files_list.First->Short_name, - Format_font_filename(Font_files_list.First->Full_name)); } } @@ -1253,7 +1264,9 @@ void Button_Skins(void) int selected_cursor = Config.Cursor; byte separatecolors = Config.Separate_colors; byte showlimits = Config.Display_image_limits; - + byte need_load=1; + int button; + word x, y, x_pos, offs_y; char * cursors[] = { "Solid", "Transparent", "Thin" }; @@ -1270,7 +1283,7 @@ void Button_Skins(void) Free_fileselector_list(&Font_files_list); // Browse the "skins" directory strcpy(skinsdir, Data_directory); - strcat(skinsdir, "skins"); + strcat(skinsdir, SKINS_SUBDIRECTORY); // Add each found file to the list For_each_file(skinsdir, Add_font_or_skin); // Sort it @@ -1341,6 +1354,68 @@ void Button_Skins(void) do { + if (need_load) + { + need_load=0; + + Hide_cursor(); + // (Re-)load GUI graphics from selected skins + strcpy(skinsdir, Get_item_by_index(&Skin_files_list, + skin_list->List_start + skin_list->Cursor_position)->Full_name); + + gfx = Load_graphics(skinsdir, NULL); + if (gfx == NULL) // Error + { + Display_cursor(); + Verbose_message("Error!", Gui_loading_error_message); + Hide_cursor(); + // Update preview + Window_rectangle(6, 14, 173, 16, MC_Light); + } + else + { + // Update preview + + // Display the bitmap according to its own color indices + for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) + for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) + { + if (gfx->Preview[offs_y][x_pos] == gfx->Color[0]) + Pixel_in_window(x, y, MC_Black); + else if (gfx->Preview[offs_y][x_pos] == gfx->Color[1]) + Pixel_in_window(x, y, MC_Dark); + else if (gfx->Preview[offs_y][x_pos] == gfx->Color[3]) + Pixel_in_window(x, y, MC_White); + else if (gfx->Preview[offs_y][x_pos] == gfx->Color[2]) + Pixel_in_window(x, y, MC_Light); + } + // Actualize current screen according to preferred GUI colors + // Note this only updates onscreen colors + Set_color( + MC_Black, + gfx->Default_palette[gfx->Color[0]].R, + gfx->Default_palette[gfx->Color[0]].G, + gfx->Default_palette[gfx->Color[0]].B); + Set_color( + MC_Dark, + gfx->Default_palette[gfx->Color[1]].R, + gfx->Default_palette[gfx->Color[1]].G, + gfx->Default_palette[gfx->Color[1]].B); + Set_color( + MC_Light, + gfx->Default_palette[gfx->Color[2]].R, + gfx->Default_palette[gfx->Color[2]].G, + gfx->Default_palette[gfx->Color[2]].B); + Set_color( + MC_White, + gfx->Default_palette[gfx->Color[3]].R, + gfx->Default_palette[gfx->Color[3]].G, + gfx->Default_palette[gfx->Color[3]].B); + } + Update_window_area(6, 14, 173, 16); + Display_cursor(); + } + clicked_button=Window_clicked_button(); if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_SETTINGS, "SKINS"); @@ -1354,60 +1429,7 @@ void Button_Skins(void) case 3 : // doesn't happen break; case 4 : // a file is selected - - // (Re-)load GUI graphics from selected skins - strcpy(skinsdir, Get_item_by_index(&Skin_files_list, - skin_list->List_start + skin_list->Cursor_position)->Full_name); - - gfx = Load_graphics(skinsdir); - if (gfx == NULL) // Error - { - Verbose_message("Error!", Gui_loading_error_message); - // Update preview - Window_rectangle(6, 14, 173, 16, MC_Light); - } - else - { - // Update preview - - // Display the bitmap according to its own color indices - for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) - for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) - { - if (gfx->Preview[offs_y][x_pos] == gfx->Color[0]) - Pixel_in_window(x, y, MC_Black); - else if (gfx->Preview[offs_y][x_pos] == gfx->Color[1]) - Pixel_in_window(x, y, MC_Dark); - else if (gfx->Preview[offs_y][x_pos] == gfx->Color[3]) - Pixel_in_window(x, y, MC_White); - else if (gfx->Preview[offs_y][x_pos] == gfx->Color[2]) - Pixel_in_window(x, y, MC_Light); - } - // Actualize current screen according to preferred GUI colors - // Note this only updates onscreen colors - Set_color( - MC_Black, - gfx->Default_palette[gfx->Color[0]].R, - gfx->Default_palette[gfx->Color[0]].G, - gfx->Default_palette[gfx->Color[0]].B); - Set_color( - MC_Dark, - gfx->Default_palette[gfx->Color[1]].R, - gfx->Default_palette[gfx->Color[1]].G, - gfx->Default_palette[gfx->Color[1]].B); - Set_color( - MC_Light, - gfx->Default_palette[gfx->Color[2]].R, - gfx->Default_palette[gfx->Color[2]].G, - gfx->Default_palette[gfx->Color[2]].B); - Set_color( - MC_White, - gfx->Default_palette[gfx->Color[3]].R, - gfx->Default_palette[gfx->Color[3]].G, - gfx->Default_palette[gfx->Color[3]].B); - } - Update_window_area(6, 14, 173, 16); - + need_load=1; break; case 5 : // Font dropdown selected_font = Window_attribute2; // Get the index of the chosen font. @@ -1450,7 +1472,7 @@ void Button_Skins(void) Menu_font = new_font; fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name; free(Config.Font_file); - Config.Font_file = strdup(fname); + Config.Font_file = (char *)strdup(fname); } // Confirm the change of cursor shape Config.Cursor = selected_cursor; @@ -1471,6 +1493,22 @@ void Button_Skins(void) // Raffichage du menu pour que les inscriptions qui y figurent soient retracées avec la nouvelle fonte Display_menu(); + // Redraw all buttons, to ensure all specific sprites are in place. + // This is necessary for multi-state buttons, for example Freehand. + for (button=0; buttonOPERATION_FILLED_CONTOUR) Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; Hide_cursor(); - Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode); + switch(Selected_freehand_mode) + { + default: + case OPERATION_CONTINUOUS_DRAW: + icon=-1; + break; + case OPERATION_DISCONTINUOUS_DRAW: + icon=MENU_SPRITE_DISCONTINUOUS_DRAW; + break; + case OPERATION_POINT_DRAW: + icon=MENU_SPRITE_POINT_DRAW; + break; + case OPERATION_FILLED_CONTOUR: + icon=MENU_SPRITE_CONTOUR_DRAW; + break; + } + Display_sprite_in_menu(BUTTON_DRAW,icon); + Draw_menu_button(BUTTON_DRAW,BUTTON_PRESSED); Start_operation_stack(Selected_freehand_mode); Display_cursor(); /* NOUVEAU CODE AVEC POPUP (EN COURS DE TEST) *** @@ -2254,7 +2311,7 @@ void Button_Draw_switch_mode(void) while (Mouse_K); Close_popup(); - Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode); + //Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode+2); Start_operation_stack(Selected_freehand_mode); Display_cursor(); */ @@ -2373,17 +2430,19 @@ void Draw_button_gradient_style(short x_pos,short y_pos,int technique) void Load_gradient_data(int index) { - Gradient_lower_bound =Gradient_array[index].Start; - Gradient_upper_bound =Gradient_array[index].End; - Gradient_is_inverted =Gradient_array[index].Inverse; - Gradient_random_factor=Gradient_array[index].Mix+1; + if (Main_backups->Pages->Gradients->Range[index].Start>Main_backups->Pages->Gradients->Range[index].End) + Error(0); + Gradient_lower_bound =Main_backups->Pages->Gradients->Range[index].Start; + Gradient_upper_bound =Main_backups->Pages->Gradients->Range[index].End; + Gradient_is_inverted =Main_backups->Pages->Gradients->Range[index].Inverse; + Gradient_random_factor=Main_backups->Pages->Gradients->Range[index].Mix+1; Gradient_bounds_range=(Gradient_lower_boundPages->Gradients->Range[index].Technique) { case 0 : // Degradé de base Gradient_function=Gradient_basic; @@ -2422,10 +2481,12 @@ void Draw_gradient_preview(short start_x,short start_y,short width,short height, void Button_Gradients(void) { short clicked_button; - char str[3]; - T_Gradient_array backup_gradients[16]; + char str[4]; + T_Gradient_array backup_gradients; int old_current_gradient; T_Scroller_button * mix_scroller; + T_Scroller_button * speed_scroller; + T_Scroller_button * gradient_scroller; short old_mouse_x; short old_mouse_y; byte old_mouse_k; @@ -2434,44 +2495,57 @@ void Button_Gradients(void) byte last_color; byte color; byte click; + int changed_gradient_index; + byte cycling_mode=Cycling_mode; - + // Enable cycling while this window is open + Cycling_mode=1; + Gradient_pixel=Pixel; old_current_gradient=Current_gradient; - memcpy(backup_gradients,Gradient_array,sizeof(T_Gradient_array)*16); + changed_gradient_index=0; + memcpy(&backup_gradients,Main_backups->Pages->Gradients,sizeof(T_Gradient_array)); - Open_window(237,133,"Gradation menu"); + Open_window(235,146,"Gradation menu"); - Window_set_palette_button(48,21); // 1 - // Définition du scrolleur <=> indice du dégradé dans le tableau - Window_set_scroller_button(218,22,75,16,1,Current_gradient); // 2 - // Définition du scrolleur de mélange du dégradé - mix_scroller = Window_set_scroller_button(31,22,84,256,1, - Gradient_array[Current_gradient].Mix); // 3 - // Définition du bouton de sens - Window_set_normal_button(8,22,15,14, - (Gradient_array[Current_gradient].Inverse)?"\033":"\032",0,1,SDLK_TAB); // 4 - // Définition du bouton de technique - Window_set_normal_button(8,92,15,14,"",0,1,SDLK_TAB|MOD_SHIFT); // 5 - Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique); + Window_set_palette_button(48,19); // 1 + // Slider for gradient selection + gradient_scroller=Window_set_scroller_button(218,20,75,16,1,Current_gradient); // 2 + // Slider for mix + mix_scroller = Window_set_scroller_button(31,20,84,256,1, + Main_backups->Pages->Gradients->Range[Current_gradient].Mix); // 3 + // Direction + Window_set_normal_button(8,20,15,14, + (Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",0,1,SDLK_TAB); // 4 + // Technique + Window_set_normal_button(8,90,15,14,"",0,1,SDLK_TAB|MOD_SHIFT); // 5 + Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); - Window_set_normal_button(178,112,51,14,"OK",0,1,SDLK_RETURN); // 6 - Window_set_normal_button(123,112,51,14,"Cancel",0,1,KEY_ESC); // 7 - - Print_in_window(5,60,"MIX",MC_Dark,MC_Light); + Window_set_normal_button(178,128,51,14,"OK",0,1,SDLK_RETURN); // 6 + Window_set_normal_button(123,128,51,14,"Cancel",0,1,KEY_ESC); // 7 + // Scrolling speed + speed_scroller = Window_set_horizontal_scroller_button(99,111,130,106,1,Main_backups->Pages->Gradients->Range[Current_gradient].Speed); // 8 + Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); + Print_in_window(73,113,str,MC_Black,MC_Light); + + Print_in_window(5,58,"MIX",MC_Dark,MC_Light); + // Cycling mode on/off + Window_set_normal_button(8,109,62,14,"",0,1,KEY_NONE); // 9 + Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); + // On tagge les couleurs qui vont avec - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); Num2str(Current_gradient+1,str,2); Print_in_window(215,100,str,MC_Black,MC_Light); - // On affiche le cadre autour de la préview - Window_display_frame_in(7,111,110,16); - // On affiche la preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + // On affiche le cadre autour de la préview + Window_display_frame_in(7,127,110,16); + // On affiche la preview + Draw_gradient_preview(8,128,108,14,Current_gradient); - first_color=last_color=(Gradient_array[Current_gradient].Inverse)?Gradient_array[Current_gradient].End:Gradient_array[Current_gradient].Start; + first_color=last_color=(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?Main_backups->Pages->Gradients->Range[Current_gradient].End:Main_backups->Pages->Gradients->Range[Current_gradient].Start; Update_window_area(0,0,Window_width, Window_height); Display_cursor(); @@ -2481,8 +2555,53 @@ void Button_Gradients(void) old_mouse_x=Mouse_X; old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; + if (changed_gradient_index) + { + // User has changed which gradient (0-15) he's watching + changed_gradient_index=0; + + Hide_cursor(); + + // On affiche la valeur sous la jauge + Num2str(Current_gradient+1,str,2); + Print_in_window(215,100,str,MC_Black,MC_Light); + + // On tagge les couleurs qui vont avec + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); + + // On affiche le sens qui va avec + Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); + + // On raffiche le mélange (jauge) qui va avec + mix_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Mix; + Window_draw_slider(mix_scroller); + + // Update speed + speed_scroller->Position=Main_backups->Pages->Gradients->Range[Current_gradient].Speed; + Window_draw_slider(speed_scroller); + Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); + Print_in_window(73,113,str,MC_Black,MC_Light); + + // Gradient # + gradient_scroller->Position=Current_gradient; + Window_draw_slider(gradient_scroller); + + // Technique (flat, dithered, very dithered) + Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); + + // Rectangular gradient preview + Draw_gradient_preview(8,128,108,14,Current_gradient); + + Display_cursor(); + } clicked_button=Window_clicked_button(); + if (Input_sticky_control!=8 || !Mouse_K) + { + Allow_colorcycling=0; + // Restore palette + Set_palette(Main_palette); + } switch(clicked_button) { @@ -2498,11 +2617,11 @@ void Button_Gradients(void) // On vient de clicker // On met à jour l'intervalle du dégradé - first_color=last_color=Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=temp_color; + first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Tracé de la preview: - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); } else { @@ -2512,20 +2631,20 @@ void Button_Gradients(void) // On commence par ordonner la 1ère et dernière couleur du bloc if (first_colorPages->Gradients->Range[Current_gradient].Start=first_color; + Main_backups->Pages->Gradients->Range[Current_gradient].End =temp_color; } else if (first_color>temp_color) { - Gradient_array[Current_gradient].Start=temp_color; - Gradient_array[Current_gradient].End =first_color; + Main_backups->Pages->Gradients->Range[Current_gradient].Start=temp_color; + Main_backups->Pages->Gradients->Range[Current_gradient].End =first_color; } else - Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=first_color; + Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=first_color; // On tagge le bloc - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Tracé de la preview: - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); last_color=temp_color; } } @@ -2533,57 +2652,49 @@ void Button_Gradients(void) } break; case 2 : // Nouvel indice de dégradé - Hide_cursor(); // Nouvel indice dans Window_attribute2 Current_gradient=Window_attribute2; - - // On affiche la valeur sous la jauge - Num2str(Current_gradient+1,str,2); - Print_in_window(215,100,str,MC_Black,MC_Light); - - // On tagge les couleurs qui vont avec - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); - - // On affiche le sens qui va avec - Print_in_window(12,25,(Gradient_array[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); - - // On raffiche le mélange (jauge) qui va avec - mix_scroller->Position=Gradient_array[Current_gradient].Mix; - Window_draw_slider(mix_scroller); - - // On raffiche la technique qui va avec - Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique); - - // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); - - Display_cursor(); + changed_gradient_index=1; break; case 3 : // Nouveau mélange de dégradé Hide_cursor(); // Nouvel mélange dans Window_attribute2 - Gradient_array[Current_gradient].Mix=Window_attribute2; + Main_backups->Pages->Gradients->Range[Current_gradient].Mix=Window_attribute2; // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 4 : // Changement de sens Hide_cursor(); // On inverse le sens (par un XOR de 1) - Gradient_array[Current_gradient].Inverse^=1; - Print_in_window(12,25,(Gradient_array[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); + Main_backups->Pages->Gradients->Range[Current_gradient].Inverse^=1; + Print_in_window(12,23,(Main_backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light); // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); break; case 5 : // Changement de technique Hide_cursor(); // On change la technique par (+1)%3 - Gradient_array[Current_gradient].Technique=(Gradient_array[Current_gradient].Technique+1)%3; - Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique); + Main_backups->Pages->Gradients->Range[Current_gradient].Technique=(Main_backups->Pages->Gradients->Range[Current_gradient].Technique+1)%3; + Draw_button_gradient_style(8,90,Main_backups->Pages->Gradients->Range[Current_gradient].Technique); // On affiche la nouvelle preview - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); + case 8 : // Speed + Main_backups->Pages->Gradients->Range[Current_gradient].Speed=Window_attribute2; + Num2str(Main_backups->Pages->Gradients->Range[Current_gradient].Speed,str,3); + Hide_cursor(); + Print_in_window(73,113,str,MC_Black,MC_Light); + Display_cursor(); + Allow_colorcycling=1; + break; + case 9: // Cycling on/off + cycling_mode = !cycling_mode; + Hide_cursor(); + Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); + Display_cursor(); + break; } if (!Mouse_K) @@ -2598,16 +2709,31 @@ void Button_Gradients(void) temp_color=color; // On met à jour l'intervalle du dégradé - first_color=last_color=Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=temp_color; + first_color=last_color=Main_backups->Pages->Gradients->Range[Current_gradient].Start=Main_backups->Pages->Gradients->Range[Current_gradient].End=temp_color; // On tagge le bloc - Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End); + Tag_color_range(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); // Tracé de la preview: - Draw_gradient_preview(8,112,108,14,Current_gradient); + Draw_gradient_preview(8,128,108,14,Current_gradient); Display_cursor(); Wait_end_of_click(); } Key=0; break; + case KEY_MOUSEWHEELUP: + if (Current_gradient>0) + { + Current_gradient--; + changed_gradient_index=1; + } + break; + case KEY_MOUSEWHEELDOWN: + if (Current_gradient<15) + { + Current_gradient++; + changed_gradient_index=1; + } + break; + default: if (Is_shortcut(Key,0x100+BUTTON_HELP)) { @@ -2615,11 +2741,19 @@ void Button_Gradients(void) Key=0; break; } - if (Is_shortcut(Key,0x200+BUTTON_GRADRECT)) + else if (Is_shortcut(Key,0x200+BUTTON_GRADRECT)) clicked_button=6; + else if (Is_shortcut(Key,SPECIAL_CYCLE_MODE)) + { + // Cycling on/off + cycling_mode = !cycling_mode; + Hide_cursor(); + Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light); + Display_cursor(); + } } } - while (clicked_button<6); + while (clicked_button!=6 && clicked_button!=7); Close_window(); // The Grad rect operation uses the same button as Grad menu. @@ -2629,11 +2763,11 @@ void Button_Gradients(void) Display_cursor(); Gradient_pixel=Display_pixel; + Cycling_mode=cycling_mode; if (clicked_button==7) // Cancel { Current_gradient=old_current_gradient; - memcpy(Gradient_array,backup_gradients,sizeof(T_Gradient_array)*16); - Load_gradient_data(Current_gradient); + memcpy(Main_backups->Pages->Gradients,&backup_gradients,sizeof(T_Gradient_array)); } } @@ -2719,6 +2853,26 @@ void Button_Unselect_fill(void) //---------------------------- Menu des pinceaux ----------------------------- +/// Checks if the current brush is identical to a preset one. +byte Same_paintbrush(byte index) +{ + if (Paintbrush_shape!=Paintbrush[index].Shape || + Paintbrush_width!=Paintbrush[index].Width || + Paintbrush_height!=Paintbrush[index].Height) + return 0; + + if (Paintbrush_shape==PAINTBRUSH_SHAPE_MISC) + { + // Check all pixels + int x,y; + for(y=0;y(NB_PAINTBRUSH_SPRITES+1)) + if (clicked_button>=(NB_PAINTBRUSH_SPRITES+3)) { - index = clicked_button-NB_PAINTBRUSH_SPRITES-2; + index = clicked_button-NB_PAINTBRUSH_SPRITES-3; - if (Window_attribute1==RIGHT_SIDE) + if (Window_attribute2==1) // Set { // Store @@ -2771,41 +2946,82 @@ void Button_Paintbrush_menu(void) Hide_cursor(); Display_stored_brush_in_window(x_pos+2, y_pos+2, index); Display_cursor(); - } + } else { // Restore and exit if (Restore_brush(index)) { - Close_window(); + Close_window(); break; } } } - else if (clicked_button>1 && Window_attribute1==LEFT_SIDE) + else if (clicked_button>=3) // Standard paintbrushes - { - Close_window(); - index=clicked_button-2; - Paintbrush_shape=Gfx->Paintbrush_type[index]; - Paintbrush_width=Gfx->Preset_paintbrush_width[index]; - Paintbrush_height=Gfx->Preset_paintbrush_height[index]; - Paintbrush_offset_X=Gfx->Preset_paintbrush_offset_X[index]; - Paintbrush_offset_Y=Gfx->Preset_paintbrush_offset_Y[index]; - for (y_pos=0; y_posPaintbrush_sprite[index][y_pos][x_pos]; - Change_paintbrush_shape(Gfx->Paintbrush_type[index]); - - break; + { + if (Window_attribute2!=1) + { + // Select paintbrush + Close_window(); + Select_paintbrush(clicked_button-3); + break; + } + else if (Window_attribute2==1) + { + // Store current + index=clicked_button-3; + if (!Store_paintbrush(index)) + { + // Redraw + Hide_cursor(); + x_pos=13+(index%12)*24; + y_pos=27+(index/12)*25; + Window_rectangle(x_pos,y_pos,20,20,MC_White); + Display_paintbrush_in_window(x_pos+2,y_pos+2,index); + Display_cursor(); + } + } } else if (clicked_button==1 || Is_shortcut(Key,0x100+BUTTON_PAINTBRUSHES)) { Close_window(); break; } + else if (clicked_button==2) + { + int size; + // Pick a standard shape + Paintbrush_shape=Window_attribute2; + // Assign a reasonable size + size=Max(Paintbrush_width,Paintbrush_height); + if (size==1) + size=3; + + switch (Paintbrush_shape) + { + case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: + Set_paintbrush_size(size, 1); + break; + case PAINTBRUSH_SHAPE_VERTICAL_BAR: + Set_paintbrush_size(1, size); + break; + case PAINTBRUSH_SHAPE_CROSS: + case PAINTBRUSH_SHAPE_PLUS: + case PAINTBRUSH_SHAPE_DIAMOND: + Set_paintbrush_size(size|1,size|1); + break; + default: + Set_paintbrush_size(size,size); + break; + + } + Close_window(); + Change_paintbrush_shape(Paintbrush_shape); + break; + } } while (1); @@ -2897,7 +3113,6 @@ void Load_picture(byte image) // Image=0 => On charge/sauve une brosse { byte confirm; - byte use_brush_palette = 0; byte old_cursor_shape; int new_mode; T_IO_Context context; @@ -2925,8 +3140,6 @@ void Load_picture(byte image) if (Main_image_is_modified) confirm=Confirmation_box("Discard unsaved changes?"); } - else - use_brush_palette=Confirmation_box("Use the palette of the brush?"); } // confirm is modified inside the first if, that's why we check it @@ -2948,24 +3161,14 @@ void Load_picture(byte image) if (!image) { - //if (!use_brush_palette) - // memcpy(Main_palette,initial_palette,sizeof(T_Palette)); - - if (File_error==3) // On ne peut pas allouer la brosse + if (File_error==3) // Memory allocation error when loading brush { - free(Brush); - Brush=(byte *)malloc(1*1); - Brush_height=1; - Brush_width=1; - *Brush=Fore_color; - - free(Smear_brush); - Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE); - Smear_brush_height=MAX_PAINTBRUSH_SIZE; - Smear_brush_width=MAX_PAINTBRUSH_SIZE; + // Nothing to do here. + // Previous versions of Grafx2 would have damaged the Brush, + // and need reset it here, but now the loading is done in separate + // memory buffers. } - Tiling_offset_X=0; Tiling_offset_Y=0; @@ -3001,9 +3204,9 @@ void Load_picture(byte image) { if (Main_magnifier_mode) { - Draw_menu_button_frame(BUTTON_MAGNIFIER,0); Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); @@ -3104,9 +3307,9 @@ void Button_Reload(void) { if (Main_magnifier_mode) { - Draw_menu_button_frame(BUTTON_MAGNIFIER,0); Pixel_preview=Pixel_preview_normal; Main_magnifier_mode=0; + Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); } new_mode=Best_video_mode(); @@ -3341,18 +3544,34 @@ void Button_Lines(void) void Button_Lines_switch_mode(void) { + char icon; + if (Selected_line_mode==OPERATION_LINE) - Selected_line_mode=OPERATION_K_LIGNE; + Selected_line_mode=OPERATION_K_LINE; else { - if (Selected_line_mode==OPERATION_K_LIGNE) + if (Selected_line_mode==OPERATION_K_LINE) Selected_line_mode=OPERATION_CENTERED_LINES; else Selected_line_mode=OPERATION_LINE; } + switch(Selected_line_mode) + { + default: + case OPERATION_LINE: + icon=-1; + break; + case OPERATION_K_LINE: + icon=MENU_SPRITE_K_LINE; + break; + case OPERATION_CENTERED_LINES: + icon=MENU_SPRITE_CENTERED_LINES; + break; + } Hide_cursor(); - Display_sprite_in_menu(BUTTON_LINES,Selected_line_mode-OPERATION_LINE+7); + Display_sprite_in_menu(BUTTON_LINES,icon); + Draw_menu_button(BUTTON_LINES,BUTTON_PRESSED); Start_operation_stack(Selected_line_mode); Display_cursor(); } @@ -3446,6 +3665,7 @@ void Button_Colorpicker(void) void Button_Unselect_colorpicker(void) { + // Erase the color block which shows the picked color if (Operation_before_interrupt!=OPERATION_REPLACE) if ( (Mouse_Y=Main_X_zoom) ) ) @@ -3492,8 +3712,6 @@ void Button_Magnify(void) } else { - Old_main_offset_X=Main_offset_X; - Old_main_offset_Y=Main_offset_Y; Compute_magnifier_data(); if ((!Config.Fast_zoom) || (Mouse_Y>=Menu_Y) || Coming_from_zoom_factor_menu) { @@ -3586,24 +3804,20 @@ void Button_Unselect_magnifier(void) // On sort du mode loupe Main_magnifier_mode=0; - /* + // --> Recalculer le décalage de l'écran lorsqu'on sort de la loupe <-- // Centrage "brut" de lécran par rapport à la loupe Main_offset_X=Main_magnifier_offset_X-((Screen_width-Main_magnifier_width)>>1); Main_offset_Y=Main_magnifier_offset_Y-((Menu_Y-Main_magnifier_height)>>1); - */ + // Correction en cas de débordement de l'image - if (Old_main_offset_X+Screen_width>Main_image_width) + if (Main_offset_X+Screen_width>Main_image_width) Main_offset_X=Main_image_width-Screen_width; - else - Main_offset_X=Old_main_offset_X; if (Main_offset_X<0) Main_offset_X=0; - if (Old_main_offset_Y+Menu_Y>Main_image_height) + if (Main_offset_Y+Menu_Y>Main_image_height) Main_offset_Y=Main_image_height-Menu_Y; - else - Main_offset_Y=Old_main_offset_Y; if (Main_offset_Y<0) Main_offset_Y=0; @@ -3721,10 +3935,14 @@ void Button_Brush_FX(void) switch (clicked_button) { case 2 : // Flip X - Flip_X_lowlevel(Brush, Brush_width, Brush_height); + Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 3 : // Flip Y - Flip_Y_lowlevel(Brush, Brush_width, Brush_height); + Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); break; case 4 : // 90° Rotation Rotate_90_deg(); @@ -3811,7 +4029,8 @@ void Button_Curves_switch_mode(void) Selected_curve_mode=OPERATION_4_POINTS_CURVE; Hide_cursor(); - Display_sprite_in_menu(BUTTON_CURVES,Selected_curve_mode-OPERATION_3_POINTS_CURVE+5); + Display_sprite_in_menu(BUTTON_CURVES,Selected_curve_mode==OPERATION_4_POINTS_CURVE?MENU_SPRITE_4_POINTS_CURVE:-1); + Draw_menu_button(BUTTON_CURVES,BUTTON_PRESSED); Start_operation_stack(Selected_curve_mode); Display_cursor(); } @@ -4053,7 +4272,7 @@ void Button_Airbrush_menu(void) case 11 : // Size Num2str(Airbrush_size,str,3); - Readline(188,25,str,3,1); + Readline(188,25,str,3,INPUT_TYPE_INTEGER); Airbrush_size=atoi(str); // On corrige les dimensions if (Airbrush_size>256) @@ -4073,7 +4292,7 @@ void Button_Airbrush_menu(void) case 12 : // Delay Num2str(Airbrush_delay,str,2); - Readline(196,39,str,2,1); + Readline(196,39,str,2,INPUT_TYPE_INTEGER); Airbrush_delay=atoi(str); // On corrige le delai if (Airbrush_delay>99) @@ -4087,7 +4306,7 @@ void Button_Airbrush_menu(void) case 13 : // Mono-Flow Num2str(Airbrush_mono_flow,str,2); - Readline(113,24,str,2,1); + Readline(113,24,str,2,INPUT_TYPE_INTEGER); Airbrush_mono_flow=atoi(str); // On corrige le flux if (!Airbrush_mono_flow) @@ -4101,7 +4320,7 @@ void Button_Airbrush_menu(void) case 14 : // Init Num2str(spray_init,str,2); - Readline(113,40,str,2,1); + Readline(113,40,str,2,INPUT_TYPE_INTEGER); spray_init=atoi(str); // On corrige la valeur if (spray_init>=50) @@ -4231,11 +4450,11 @@ void Display_effect_sprite(short sprite_number, short start_x, short start_y) { short x,y,x_pos,y_pos; - for (y=0,y_pos=start_y;yEffect_sprite[sprite_number][y][x]); - Update_rect(ToWinX(start_x),ToWinY(start_y),MENU_SPRITE_WIDTH*Menu_factor_X,MENU_SPRITE_HEIGHT*Menu_factor_Y); + Update_rect(ToWinX(start_x),ToWinY(start_y),EFFECT_SPRITE_WIDTH*Menu_factor_X,EFFECT_SPRITE_HEIGHT*Menu_factor_Y); } @@ -4551,7 +4770,7 @@ void Draw_one_font_name(word x, word y, word index, byte highlighted) Print_in_window(x,y,Font_label(index), MC_Black, (highlighted)?MC_Dark:MC_Light); } -void Button_Text() +void Button_Text(void) { static char str[256]=""; static int font_size=32; @@ -4563,11 +4782,12 @@ void Button_Text() static short is_italic=0; byte * new_brush=NULL; + T_Palette text_palette; int new_width; int new_height; int clicked_button; const int NB_FONTS=8; - char size_buffer[3]; + char size_buffer[4]; T_Special_button * input_size_button; T_Special_button * input_text_button; T_Special_button * preview_button; @@ -4642,23 +4862,86 @@ void Button_Text() if (preview_is_needed) { const char * preview_string = "AaBbCcDdEeFf012345"; + byte is_truetype; + if (str[0]) preview_string=str; - Window_rectangle(8, 106, 273, 50,Back_color); + is_truetype=TrueType_font(selected_font_index); + Window_rectangle(8, 106, 273, 50,(antialias&&is_truetype)?MC_Black:Back_color); free(new_brush); - new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height); + new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height, text_palette); if (new_brush) { - Display_brush( - new_brush, - Window_pos_X+preview_button->Pos_X*Menu_factor_X, - Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, - 0, - 0, - Min(preview_button->Width*Menu_factor_X, new_width), - Min(preview_button->Height*Menu_factor_Y, new_height), - Back_color, - new_width); + if (!is_truetype || (is_truetype&&antialias)) + { + // Display brush in remapped form. + byte *remapped_brush; + + remapped_brush=(byte *)malloc(new_width*new_height); + if (remapped_brush) + { + // This code is mostly copied from Remap_brush() + short x_pos; + short y_pos; + int color; + byte colmap[256]; + + for (color=0;color<=255;color++) + colmap[color]=0; + + for (y_pos=0;y_posPos_X*Menu_factor_X, + Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, + 0, + 0, + Min(preview_button->Width*Menu_factor_X, new_width), + Min(preview_button->Height*Menu_factor_Y, new_height), + Back_color, + new_width); + + free(remapped_brush); + } + + } + else + { + // Solid + Display_brush( + new_brush, + Window_pos_X+preview_button->Pos_X*Menu_factor_X, + Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, + 0, + 0, + Min(preview_button->Width*Menu_factor_X, new_width), + Min(preview_button->Height*Menu_factor_Y, new_height), + Back_color, + new_width); + } + } Update_rect( Window_pos_X+preview_button->Pos_X*Menu_factor_X, @@ -4684,7 +4967,7 @@ void Button_Text() switch(clicked_button) { case 1: // Texte saisi - Readline_ex(50,20,str,29,250,0,0); + Readline_ex(50,20,str,29,250,INPUT_TYPE_STRING,0); preview_is_needed=1; break; @@ -4724,7 +5007,7 @@ void Button_Text() break; case 7: // Taille du texte (nombre) - Readline(222,45,size_buffer,3,1); + Readline(222,45,size_buffer,3,INPUT_TYPE_INTEGER); font_size=atoi(size_buffer); // On corrige les dimensions if (font_size < 1) @@ -4774,14 +5057,22 @@ void Button_Text() Error(0); return; } - free(Brush); + if (Realloc_brush(new_width, new_height, new_brush, NULL)) + { + free(new_brush); + Close_window(); + Unselect_button(BUTTON_TEXT); + Display_cursor(); + Error(0); + } + // Grab palette + memcpy(Brush_original_palette, text_palette,sizeof(T_Palette)); + // Remap to image's palette + Remap_brush(); - Brush=new_brush; - Brush_width=new_width; - Brush_height=new_height; Brush_offset_X=Brush_width>>1; Brush_offset_Y=Brush_height>>1; - + // Fermeture Close_window(); Unselect_button(BUTTON_TEXT); @@ -4792,6 +5083,20 @@ void Button_Text() Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); else Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); + // Activate alpha mode + if (antialias && TrueType_font(selected_font_index)) + { + Shade_mode=0; + Quick_shade_mode=0; + Smooth_mode=0; + Tiling_mode=0; + Smear_mode=0; + Colorize_mode=1; + Colorize_current_mode=3; + Effect_function=Effect_alpha_colorize; + + Draw_menu_button(BUTTON_EFFECTS,BUTTON_PRESSED); + } Select_button(BUTTON_DRAW,LEFT_SIDE); if (Config.Auto_discontinuous) @@ -4846,7 +5151,7 @@ void Display_stored_brush_in_window(word x_pos,word y_pos,int index) if (Brush_container[index].Paintbrush_shape <= PAINTBRUSH_SHAPE_MISC) color = Brush_container[index].Thumbnail[y][x]?MC_Black:MC_Light; else - color = Brush_container[index].Thumbnail[y][x]; + color = Brush_container[index].Colormap[Brush_container[index].Thumbnail[y][x]]; Pixel_in_window(x_pos+x+offset_x,y_pos+y+offset_y,color); } } @@ -4855,6 +5160,7 @@ void Display_stored_brush_in_window(word x_pos,word y_pos,int index) } } +/// Store the current brush in brush container void Store_brush(int index) { if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX) @@ -4887,29 +5193,51 @@ void Store_brush(int index) // Re-init the rest Brush_container[index].Transp_color=0; } - if (Paintbrush_shape == PAINTBRUSH_SHAPE_COLOR_BRUSH || + else if (Paintbrush_shape == PAINTBRUSH_SHAPE_MONO_BRUSH && + Brush_width <= BRUSH_CONTAINER_PREVIEW_WIDTH && + Brush_height <= BRUSH_CONTAINER_PREVIEW_HEIGHT) + { + // Color brush transformed into a real mono paintbrush + int x,y; + + Brush_container[index].Paintbrush_shape=PAINTBRUSH_SHAPE_MISC; + Brush_container[index].Width=Brush_width; + Brush_container[index].Height=Brush_height; + // Preview: pick center for big mono brush + for (y=0; yBRUSH_CONTAINER_PREVIEW_WIDTH || Brush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) { // Scale - Rescale(Brush, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0); + Rescale(Brush_original_pixels, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0); } else { // Direct copy - Copy_part_of_image_to_another(Brush, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH); + Copy_part_of_image_to_another(Brush_original_pixels, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH); } } else @@ -4919,6 +5247,81 @@ void Store_brush(int index) } } +/// Retrieve a normal paintbrush +void Select_paintbrush(int index) +{ + int x_pos,y_pos; + + Paintbrush_shape=Paintbrush[index].Shape; + + if (Paintbrush[index].Width<=PAINTBRUSH_WIDTH && + Paintbrush[index].Height<=PAINTBRUSH_HEIGHT) + { + Paintbrush_width=Paintbrush[index].Width; + Paintbrush_height=Paintbrush[index].Height; + Paintbrush_offset_X=Paintbrush[index].Offset_X; + Paintbrush_offset_Y=Paintbrush[index].Offset_Y; + + for (y_pos=0; y_posPAINTBRUSH_WIDTH) + x_off=(Paintbrush_width-PAINTBRUSH_WIDTH)/2; + if (Paintbrush_height>PAINTBRUSH_HEIGHT) + y_off=(Paintbrush_height-PAINTBRUSH_HEIGHT)/2; + + for (y_pos=0; y_pos>1; - Brush_offset_Y=Brush_height>>1; + if (!Realloc_brush(Brush_container[index].Width,Brush_container[index].Height,NULL,NULL)) + { + // Recover pixels + memcpy(Brush_original_pixels, Brush_container[index].Brush, (long)Brush_height*Brush_width); + // Grab palette + memcpy(Brush_original_palette, Brush_container[index].Palette, sizeof(T_Palette)); + // Recover colormap + memcpy(Brush_colormap, Brush_container[index].Colormap, 256); + // Remap using current colormap + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); + + Brush_offset_X=Brush_width>>1; + Brush_offset_Y=Brush_height>>1; + } } Change_paintbrush_shape(shape); diff --git a/src/buttons.h b/src/buttons.h index 7ccd4728..eed881dc 100644 --- a/src/buttons.h +++ b/src/buttons.h @@ -670,5 +670,9 @@ void Button_Smear_mode(void); void Button_Brush_container(void); +byte Store_paintbrush(int index); + +void Select_paintbrush(int index); + #endif diff --git a/src/buttons_effects.c b/src/buttons_effects.c index c76d1190..d95e1514 100644 --- a/src/buttons_effects.c +++ b/src/buttons_effects.c @@ -40,6 +40,7 @@ #include "sdlscreen.h" #include "struct.h" #include "windows.h" +#include "brush.h" //---------- Menu dans lequel on tagge des couleurs (genre Stencil) ---------- void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut) @@ -279,7 +280,7 @@ void Button_Grid_menu(void) { case 3 : Num2str(chosen_X,str,2); - Readline(39,26,str,2,1); + Readline(39,26,str,2,INPUT_TYPE_INTEGER); chosen_X=atoi(str); // On corrige les dimensions if ((!chosen_X) || (chosen_X>80)) @@ -301,7 +302,7 @@ void Button_Grid_menu(void) break; case 4 : Num2str(chosen_Y,str,2); - Readline(39,47,str,2,1); + Readline(39,47,str,2,INPUT_TYPE_INTEGER); chosen_Y=atoi(str); // On corrige les dimensions if ((!chosen_Y) || (chosen_Y>80)) @@ -323,7 +324,7 @@ void Button_Grid_menu(void) break; case 5 : Num2str(dx_selected,str,2); - Readline(97,26,str,2,1); + Readline(97,26,str,2,INPUT_TYPE_INTEGER); dx_selected=atoi(str); // On corrige les dimensions if (dx_selected>79) @@ -338,7 +339,7 @@ void Button_Grid_menu(void) break; case 6 : Num2str(dy_selected,str,2); - Readline(97,47,str,2,1); + Readline(97,47,str,2,INPUT_TYPE_INTEGER); dy_selected=atoi(str); // On corrige les dimensions if (dy_selected>79) @@ -479,7 +480,7 @@ void Button_Smooth_menu(void) Num2str(chosen_matrix[x][y],str,2); Readline(matrix_input[x][y]->Pos_X+2, matrix_input[x][y]->Pos_Y+2, - str,2,1); + str,2,INPUT_TYPE_INTEGER); chosen_matrix[x][y]=atoi(str); Display_cursor(); } @@ -553,6 +554,9 @@ void Button_Colorize_mode(void) break; case 2 : Effect_function=Effect_substractive_colorize; + break; + case 3 : + Effect_function=Effect_alpha_colorize; } Shade_mode=0; Quick_shade_mode=0; @@ -572,10 +576,12 @@ void Button_Colorize_display_selection(int mode) Print_in_window(4,37," ",MC_Black,MC_Light); Print_in_window(4,57," ",MC_Black,MC_Light); Print_in_window(4,74," ",MC_Black,MC_Light); + Print_in_window(4,91," ",MC_Black,MC_Light); // Partie droite Print_in_window(129,37," ",MC_Black,MC_Light); Print_in_window(129,57," ",MC_Black,MC_Light); Print_in_window(129,74," ",MC_Black,MC_Light); + Print_in_window(129,91," ",MC_Black,MC_Light); // Ensuite, on affiche la flèche là où il le faut: switch(mode) @@ -588,6 +594,9 @@ void Button_Colorize_display_selection(int mode) break; case 2 : // Méthode soustractive y_pos=74; + break; + case 3 : // Méthode alpha + y_pos=91; } Print_in_window(4,y_pos,"\020",MC_Black,MC_Light); Print_in_window(129,y_pos,"\021",MC_Black,MC_Light); @@ -600,7 +609,7 @@ void Button_Colorize_menu(void) short clicked_button; char str[4]; - Open_window(140,118,"Transparency"); + Open_window(140,135,"Transparency"); Print_in_window(16,23,"Opacity:",MC_Dark,MC_Light); Window_set_input_button(87,21,3); // 1 @@ -610,9 +619,10 @@ void Button_Colorize_menu(void) Window_set_normal_button(16,54,108,14,"Additive" ,2,1,SDLK_d); // 3 Window_set_normal_button(16,71,108,14,"Subtractive",1,1,SDLK_s); // 4 + Window_set_normal_button(16,88,108,14,"Alpha",1,1,SDLK_a); // 4 - Window_set_normal_button(16,94, 51,14,"Cancel" ,0,1,KEY_ESC); // 5 - Window_set_normal_button(73,94, 51,14,"OK" ,0,1,SDLK_RETURN); // 6 + Window_set_normal_button(16,111, 51,14,"Cancel" ,0,1,KEY_ESC); // 5 + Window_set_normal_button(73,111, 51,14,"OK" ,0,1,SDLK_RETURN); // 6 Num2str(Colorize_opacity,str,3); Window_input_content(Window_special_button_list,str); @@ -632,7 +642,7 @@ void Button_Colorize_menu(void) { case 1: // Zone de saisie de l'opacité Num2str(chosen_opacity,str,3); - Readline(89,23,str,3,1); + Readline(89,23,str,3,INPUT_TYPE_INTEGER); chosen_opacity=atoi(str); // On corrige le pourcentage if (chosen_opacity>100) @@ -643,9 +653,10 @@ void Button_Colorize_menu(void) } Display_cursor(); break; - case 2: // Méthode interpolée - case 3: // Méthode additive - case 4: // Méthode soustractive + case 2: // Interpolated method + case 3: // Additive method + case 4: // Substractive method + case 5: // Alpha method selected_mode=clicked_button-2; Hide_cursor(); Button_Colorize_display_selection(selected_mode); @@ -654,13 +665,13 @@ void Button_Colorize_menu(void) if (Is_shortcut(Key,0x100+BUTTON_HELP)) Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); else if (Is_shortcut(Key,SPECIAL_COLORIZE_MENU)) - clicked_button=6; + clicked_button=7; } - while (clicked_button<5); + while (clicked_button<6); Close_window(); - if (clicked_button==6) // OK + if (clicked_button==7) // OK { Colorize_opacity =chosen_opacity; Colorize_current_mode=selected_mode; @@ -724,7 +735,7 @@ void Button_Tiling_menu(void) if (clicked_button==3) // Zone de saisie du décalage X { Num2str(chosen_offset_x,str,4); - Readline(93,23,str,4,1); + Readline(93,23,str,4,INPUT_TYPE_INTEGER); chosen_offset_x=atoi(str); // On corrige le décalage en X if (chosen_offset_x>=Brush_width) @@ -739,7 +750,7 @@ void Button_Tiling_menu(void) if (clicked_button==4) // Zone de saisie du décalage Y { Num2str(chosen_offset_y,str,4); - Readline(93,37,str,4,1); + Readline(93,37,str,4,INPUT_TYPE_INTEGER); chosen_offset_y=atoi(str); // On corrige le décalage en Y if (chosen_offset_y>=Brush_height) @@ -975,8 +986,8 @@ void Button_Sieve_menu(void) { clicked_button=Window_clicked_button(); - origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); - origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); + origin_x=Window_pos_X+(Menu_factor_X*Window_special_button_list->Pos_X); + origin_y=Window_pos_Y+(Menu_factor_Y*Window_special_button_list->Pos_Y); switch (clicked_button) @@ -1063,15 +1074,22 @@ void Button_Sieve_menu(void) break; case 7 : // Transfer to brush - Brush_width=Sieve_width; - Brush_height=Sieve_height; - free(Brush); - Brush=(byte *)malloc(((long)Brush_height)*Brush_width); + + if (Realloc_brush(Sieve_width, Sieve_height, NULL, NULL)) + break; + for (y_pos=0; y_pos>1); Brush_offset_Y=(Brush_height>>1); + Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); break; diff --git a/src/const.h b/src/const.h index e4c60590..69c844ca 100644 --- a/src/const.h +++ b/src/const.h @@ -37,7 +37,6 @@ #define BETA1 98 ///< Version number for gfx2.cfg (3/4) #define BETA2 0 ///< Version number for gfx2.cfg (4/4) #define MAX_VIDEO_MODES 100 ///< Maximum number of video modes Grafx2 can propose. -#define NB_SHORTCUTS 183 ///< Number of actions that can have a key combination associated to it. #define NB_ZOOM_FACTORS 15 ///< Number of zoom levels available in the magnifier. #define MENU_WIDTH 254 ///< Width of the menu (not counting the palette) #define MENU_HEIGHT 44 ///< Height of the menu. @@ -45,9 +44,10 @@ #define CURSOR_SPRITE_WIDTH 15 ///< Width of a mouse cursor sprite. #define CURSOR_SPRITE_HEIGHT 15 ///< Height of a mouse cursor sprite. #define NB_EFFECTS_SPRITES 9 ///< Number of effect sprites. -#define NB_MENU_SPRITES 20 ///< Number of menu sprites. -#define MENU_SPRITE_WIDTH 14 ///< Width of a menu sprite in pixels -#define MENU_SPRITE_HEIGHT 14 ///< Height of a menu sprite in pixels +#define MENU_SPRITE_WIDTH 16 ///< Width of a menu sprite in pixels +#define MENU_SPRITE_HEIGHT 16 ///< Height of a menu sprite in pixels +#define EFFECT_SPRITE_WIDTH 14 ///< Width of an effect sprite in pixels +#define EFFECT_SPRITE_HEIGHT 14 ///< Height of an effect sprite in pixels #define LAYER_SPRITE_WIDTH 14 ///< Width of a layer button in pixels #define LAYER_SPRITE_HEIGHT 10 ///< Height of a layer button in pixels #define PAINTBRUSH_WIDTH 16 ///< Width of a preset paintbrush sprite @@ -120,6 +120,7 @@ enum FILE_FORMATS FORMAT_KCF, FORMAT_PAL, FORMAT_SCR, + FORMAT_XPM, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; @@ -210,9 +211,17 @@ enum PAINTBRUSH_SHAPES PAINTBRUSH_SHAPE_DIAMOND, PAINTBRUSH_SHAPE_SIEVE_ROUND, PAINTBRUSH_SHAPE_SIEVE_SQUARE, + PAINTBRUSH_SHAPE_RESERVED1, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED2, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED3, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED4, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED5, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED6, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED7, ///< Reserved for future use + PAINTBRUSH_SHAPE_RESERVED8, ///< Reserved for future use PAINTBRUSH_SHAPE_MISC, ///< A raw monochrome bitmap, can't be resized. This must be the last of the preset paintbrush types. PAINTBRUSH_SHAPE_POINT, ///< Used to reduce the paintbrush to a single pixel, during operations like floodfill. - PAINTBRUSH_SHAPE_NONE, ///< Used to display no cursor at all (colorpicker) + PAINTBRUSH_SHAPE_NONE, ///< Used to display no cursor at all (colorpicker) PAINTBRUSH_SHAPE_COLOR_BRUSH, ///< User's brush, in color mode PAINTBRUSH_SHAPE_MONO_BRUSH, ///< User's brush, in mono mode PAINTBRUSH_SHAPE_MAX ///< Upper limit. @@ -222,6 +231,8 @@ enum PAINTBRUSH_SHAPES #define BUTTON_RELEASED 0 /// State of a menu button that is being pressed. #define BUTTON_PRESSED 1 +/// State of a button temporarily highligted +#define BUTTON_HIGHLIGHTED 2 /// The different modes of the Shade enum SHADE_MODES @@ -243,7 +254,9 @@ enum CHUNKS_CFG CHUNK_SMOOTH = 6, ///< Smooth effect settings CHUNK_EXCLUDE_COLORS = 7, ///< List of excluded colors CHUNK_QUICK_SHADE = 8, ///< QShade effect settings - CHUNK_GRID = 9, + CHUNK_GRID = 9, ///< Grid settings + CHUNK_BRUSH =10, ///< Paintbrushes + CHUNK_SCRIPTS =11, ///< Callable scripts CHUNK_MAX }; @@ -257,7 +270,8 @@ enum ICON_TYPES ICON_NETWORK, ///< "Network" drive ICON_STAR, ///< Star (favorite) ICON_DROPDOWN, ///< Dropdown arrow - NB_ICON_SPRITES ///< Number of 8x8 icons + NB_ICON_SPRITES, ///< Number of 8x8 icons + ICON_NONE ///< None of the above }; /// Identifiers for the buttons in the menu. @@ -316,6 +330,24 @@ enum BUTTON_NUMBERS NB_BUTTONS ///< Number of buttons in the menu bar. }; +enum MENU_SPRITE +{ + MENU_SPRITE_COLOR_BRUSH=0, + MENU_SPRITE_MONO_BRUSH, + MENU_SPRITE_DISCONTINUOUS_DRAW, + MENU_SPRITE_POINT_DRAW, + MENU_SPRITE_CONTOUR_DRAW, + MENU_SPRITE_4_POINTS_CURVE, + MENU_SPRITE_K_LINE, + MENU_SPRITE_CENTERED_LINES, + MENU_SPRITE_ELLIPSES, + MENU_SPRITE_POLYFORM, + MENU_SPRITE_REPLACE, + MENU_SPRITE_GRAD_ELLIPSE, + MENU_SPRITE_VERTICAL_PALETTE_SCROLL, + NB_MENU_SPRITES ///< Number of menu sprites. +}; + /// /// Identifiers of special actions that can have a keyboard shortcut. /// They are special in the sense that there's no button in the menu for them, @@ -364,6 +396,10 @@ enum SPECIAL_ACTIONS SPECIAL_GET_BRUSH_COLORS, SPECIAL_RECOLORIZE_BRUSH, SPECIAL_ROTATE_ANY_ANGLE, + SPECIAL_BRUSH_DOUBLE, + SPECIAL_BRUSH_DOUBLE_WIDTH, + SPECIAL_BRUSH_DOUBLE_HEIGHT, + SPECIAL_BRUSH_HALVE, SPECIAL_LOAD_BRUSH, SPECIAL_SAVE_BRUSH, SPECIAL_INVERT_SIEVE, @@ -435,8 +471,22 @@ enum SPECIAL_ACTIONS SPECIAL_LAYER7_TOGGLE, SPECIAL_LAYER8_SELECT, SPECIAL_LAYER8_TOGGLE, + SPECIAL_REPEAT_SCRIPT, + SPECIAL_RUN_SCRIPT_1, + SPECIAL_RUN_SCRIPT_2, + SPECIAL_RUN_SCRIPT_3, + SPECIAL_RUN_SCRIPT_4, + SPECIAL_RUN_SCRIPT_5, + SPECIAL_RUN_SCRIPT_6, + SPECIAL_RUN_SCRIPT_7, + SPECIAL_RUN_SCRIPT_8, + SPECIAL_RUN_SCRIPT_9, + SPECIAL_RUN_SCRIPT_10, + SPECIAL_CYCLE_MODE, + SPECIAL_FORMAT_CHECKER, SPECIAL_FORMAT_CHECKER_MENU, + NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts }; @@ -448,7 +498,7 @@ enum OPERATIONS OPERATION_POINT_DRAW, ///< Freehand point-by-point draw OPERATION_FILLED_CONTOUR, ///< Filled contour OPERATION_LINE, ///< Lines - OPERATION_K_LIGNE, ///< Linked lines + OPERATION_K_LINE, ///< Linked lines OPERATION_CENTERED_LINES, ///< Centered lines OPERATION_EMPTY_RECTANGLE, ///< Empty rectangle OPERATION_FILLED_RECTANGLE, ///< Filled rectangle @@ -476,6 +526,7 @@ enum OPERATIONS OPERATION_STRETCH_BRUSH, ///< Stretch brush OPERATION_DISTORT_BRUSH, ///< Distort brush OPERATION_GRAD_RECTANGLE, ///< Gradient-filled rectangle + OPERATION_RMB_COLORPICK, ///< Colorpick on right mouse button NB_OPERATIONS ///< Number of operations handled by the engine }; diff --git a/src/engine.c b/src/engine.c index 514d4ea8..3c71c13a 100644 --- a/src/engine.c +++ b/src/engine.c @@ -40,6 +40,10 @@ #include "engine.h" #include "pages.h" #include "layers.h" +#include "factory.h" +#include "loadsave.h" +#include "io.h" + // we need this as global @@ -210,19 +214,20 @@ int Button_under_mouse(void) } -///Draw the frame for a menu button -void Draw_menu_button_frame(byte btn_number,byte pressed) +///Draw a menu button, selected or not +void Draw_menu_button(byte btn_number,byte pressed) { - byte color_top_left; - byte color_bottom_right; - byte color_diagonal; word start_x; word start_y; - word end_x; - word end_y; + word width; + word height; + byte * bitmap; + word bitmap_width; word x_pos; word y_pos; byte current_menu; + byte color; + char icon; // Find in which menu the button is for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) @@ -235,22 +240,114 @@ void Draw_menu_button_frame(byte btn_number,byte pressed) } } - start_x=Buttons_Pool[btn_number].X_offset; - start_y=Buttons_Pool[btn_number].Y_offset; - end_x =start_x+Buttons_Pool[btn_number].Width; - end_y =start_y+Buttons_Pool[btn_number].Height; + start_x = Buttons_Pool[btn_number].X_offset; + start_y = Buttons_Pool[btn_number].Y_offset; + width = Buttons_Pool[btn_number].Width+1; + height = Buttons_Pool[btn_number].Height+1; + icon = Buttons_Pool[btn_number].Icon; - if (!pressed) + if (icon==-1) { - color_top_left=MC_White; - color_bottom_right=MC_Dark; - color_diagonal=MC_Light; + // Standard button + bitmap_width = Menu_bars[current_menu].Skin_width; + bitmap=&(Menu_bars[current_menu].Skin[pressed][start_y*Menu_bars[current_menu].Skin_width+start_x]); } else { + // From Menu_buttons + bitmap_width = MENU_SPRITE_WIDTH; + bitmap=Gfx->Menu_sprite[pressed][(byte)icon][0]; + // For bottom right: offset +1,+1 + if (Buttons_Pool[btn_number].Shape==BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) + bitmap += MENU_SPRITE_WIDTH+1; + } + + switch(Buttons_Pool[btn_number].Shape) + { + case BUTTON_SHAPE_NO_FRAME : + break; + case BUTTON_SHAPE_RECTANGLE : + for (y_pos=0;y_posPages); + + flimit = Find_last_slash(Drop_file_name); + *(flimit++) = '\0'; + + Hide_cursor(); + old_cursor_shape=Cursor_shape; + Cursor_shape=CURSOR_SHAPE_HOURGLASS; + Display_cursor(); + + Init_context_layered_image(&context, flimit, Drop_file_name); + Load_image(&context); + if (File_error!=1) + { + Compute_limits(); + Compute_paintbrush_coordinates(); + Redraw_layered_image(); + End_of_modification(); + Display_all_screen(); + Main_image_is_modified=0; + } + Destroy_context(&context); + + Compute_optimal_menu_colors(Main_palette); + Display_menu(); + if (Config.Display_image_limits) + Display_image_limits(); + + Hide_cursor(); + Cursor_shape=old_cursor_shape; + Display_all_screen(); + Display_cursor(); + } + free(Drop_file_name); + Drop_file_name=NULL; + } - if(Get_input()) + if(Get_input(0)) { action = 0; @@ -732,13 +894,17 @@ void Main_handler(void) break; case SPECIAL_FLIP_X : // Flip X Hide_cursor(); - Flip_X_lowlevel(Brush, Brush_width, Brush_height); + Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; case SPECIAL_FLIP_Y : // Flip Y Hide_cursor(); - Flip_Y_lowlevel(Brush, Brush_width, Brush_height); + Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Display_cursor(); action++; break; @@ -751,6 +917,8 @@ void Main_handler(void) case SPECIAL_ROTATE_180 : // 180° brush rotation Hide_cursor(); Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height); + // Remap according to the last used remap table + Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width); Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); Display_cursor(); @@ -774,6 +942,46 @@ void Main_handler(void) Display_cursor(); action++; break; + case SPECIAL_BRUSH_DOUBLE: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width*2,Brush_height*2); + Display_cursor(); + } + action++; + break; + case SPECIAL_BRUSH_DOUBLE_WIDTH: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width*2,Brush_height); + Display_cursor(); + } + action++; + break; + case SPECIAL_BRUSH_DOUBLE_HEIGHT: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width,Brush_height*2); + Display_cursor(); + } + action++; + break; + case SPECIAL_BRUSH_HALVE: + if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH + || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH) + { + Hide_cursor(); + Stretch_brush(1,1,Brush_width/2,Brush_height/2); + Display_cursor(); + } + action++; + break; case SPECIAL_OUTLINE : // Outline brush Hide_cursor(); Outline_brush(); @@ -1088,6 +1296,36 @@ void Main_handler(void) C64_FLI_enforcer(); action++; break; + + case SPECIAL_REPEAT_SCRIPT: +#ifdef __ENABLE_LUA__ + Repeat_script(); + action++; +#endif + break; + case SPECIAL_RUN_SCRIPT_1: + case SPECIAL_RUN_SCRIPT_2: + case SPECIAL_RUN_SCRIPT_3: + case SPECIAL_RUN_SCRIPT_4: + case SPECIAL_RUN_SCRIPT_5: + case SPECIAL_RUN_SCRIPT_6: + case SPECIAL_RUN_SCRIPT_7: + case SPECIAL_RUN_SCRIPT_8: + case SPECIAL_RUN_SCRIPT_9: + case SPECIAL_RUN_SCRIPT_10: +#ifdef __ENABLE_LUA__ + Run_numbered_script(key_index-SPECIAL_RUN_SCRIPT_1); + action++; +#endif + break; + case SPECIAL_CYCLE_MODE: + Cycling_mode= !Cycling_mode; + // Restore palette + if (!Cycling_mode) + Set_palette(Main_palette); + action++; + break; + } } } // End of special keys @@ -1122,7 +1360,7 @@ void Main_handler(void) if (effect_modified) { Hide_cursor(); - Draw_menu_button_frame(BUTTON_EFFECTS, + Draw_menu_button(BUTTON_EFFECTS, (Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode)); Display_cursor(); } @@ -1132,21 +1370,8 @@ void Main_handler(void) } else { - // No event : we go asleep for a while, but we try to get waked up at constant intervals of time - // no matter the machine speed or system load. The time is fixed to 10ms (that should be about a cpu slice on most systems) - // This allows nice smooth mouse movement. - const int delay = 10; - - Uint32 debut; - debut = SDL_GetTicks(); - // Première attente : le complément de "delay" millisecondes - SDL_Delay(delay - (debut % delay)); - // Si ça ne suffit pas, on complète par des attentes successives de "1ms". - // (Remarque, Windows arrondit généralement aux 10ms supérieures) - while ( SDL_GetTicks()/delay <= debut/delay) - { - SDL_Delay(1); - } + // Removed all SDL_Delay() timing here: relying on Get_input() + SDL_Delay(10); } // Gestion de la souris @@ -1175,6 +1400,11 @@ void Main_handler(void) { // On nettoie les coordonnées Hide_cursor(); + + /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) + Draw_menu_button(prev_button_number, BUTTON_RELEASED); + */ + Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light); Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3); Display_cursor(); @@ -1190,7 +1420,17 @@ void Main_handler(void) if (button_index!=BUTTON_CHOOSE_COL) { Hide_cursor(); + + /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) + Draw_menu_button(prev_button_number, BUTTON_RELEASED); + */ + Print_in_menu(Menu_tooltip[button_index],0); + + /*if (Gfx->Hover_effect && !Buttons_Pool[button_index].Pressed) + Draw_menu_button(button_index, BUTTON_HIGHLIGHTED); + */ + Display_cursor(); } else @@ -1245,21 +1485,27 @@ void Main_handler(void) // Le curseur se trouve dans l'image if ( (!Cursor_in_menu) && (Menu_is_visible) && (Old_MY != Mouse_Y || Old_MX != Mouse_X || Key || Mouse_K)) // On ne met les coordonnées à jour que si l'utilisateur a fait un truc { - if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) - { - if(Cursor_in_menu_previous) - { - Print_in_menu("X: Y: ",0); - } - } - else - { - if(Cursor_in_menu_previous) - { - Print_in_menu("X: Y: ( )",0); - } - } - Cursor_in_menu_previous = 0; + if(Cursor_in_menu_previous) + { + Hide_cursor(); + + /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed) + Draw_menu_button(prev_button_number, BUTTON_RELEASED); + */ + + if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) ) + { + Print_in_menu("X: Y: ",0); + } + else + { + Print_in_menu("X: Y: ( )",0); + } + + Display_cursor(); + + Cursor_in_menu_previous = 0; + } } if(Cursor_in_menu) @@ -1300,7 +1546,17 @@ void Open_window(word width,word height, const char * title) size_t title_length; Hide_cursor(); - + + /*if (Windows_open == 0 && Gfx->Hover_effect) + { + if (Cursor_in_menu) + { + int button_index=Button_under_mouse(); + if (button_index > -1 && !Buttons_Pool[button_index].Pressed) + Draw_menu_button(button_index, BUTTON_RELEASED); + } + }*/ + Windows_open++; Window_width=width; @@ -1310,12 +1566,14 @@ void Open_window(word width,word height, const char * title) Window_pos_X=(Screen_width-(width*Menu_factor_X))>>1; Window_pos_Y=(Screen_height-(height*Menu_factor_Y))>>1; + + Window_draggable=1; // Sauvegarde de ce que la fenêtre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); // Fenêtre grise - Block(Window_pos_X+(Menu_factor_X<<1),Window_pos_Y+(Menu_factor_Y<<1),(width-4)*Menu_factor_X,(height-4)*Menu_factor_Y,MC_Light); + Block(Window_pos_X+(Menu_factor_X<<1),Window_pos_Y+(Menu_factor_Y<<1),(width-4)*Menu_factor_X,(height-4)*Menu_factor_Y,MC_Window); // -- Frame de la fenêtre ----- --- -- - - @@ -1342,6 +1600,13 @@ void Open_window(word width,word height, const char * title) Cursor_shape=CURSOR_SHAPE_ARROW; Paintbrush_hidden_before_window=Paintbrush_hidden; Paintbrush_hidden=1; + if (Allow_colorcycling) + { + Allow_colorcycling=0; + // Restore palette + Set_palette(Main_palette); + } + Allow_drag_and_drop(0); } // Initialisation des listes de boutons de la fenêtre @@ -1431,6 +1696,8 @@ void Close_window(void) Display_all_screen(); Display_menu(); + Allow_colorcycling=1; + Allow_drag_and_drop(1); } Key=0; @@ -1445,7 +1712,7 @@ void Close_window(void) //---------------- Dessiner un bouton normal dans une fenêtre ---------------- void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, - char * title,byte undersc_letter,byte clickable) + const char * title,byte undersc_letter,byte clickable) { byte title_color; word text_x_pos,text_y_pos; @@ -1532,14 +1799,14 @@ void Tag_color_range(byte start,byte end) // On efface les anciens TAGs for (index=0;index<=start;index++) - Block(Window_pos_X+(Window_palette_button_list->Pos_X+3+((index>>4)*10))*Menu_factor_X, - Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y, - Menu_factor_X*3,Menu_factor_Y*5,MC_Light); + Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), + Window_palette_button_list->Pos_Y+3+((index&15)* 5), + 3,5,MC_Light); for (index=end;index<256;index++) - Block(Window_pos_X+(Window_palette_button_list->Pos_X+3+((index>>4)*10))*Menu_factor_X, - Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y, - Menu_factor_X*3,Menu_factor_Y*5,MC_Light); + Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), + Window_palette_button_list->Pos_Y+3+((index&15)* 5), + 3,5,MC_Light); // On affiche le 1er TAG origin_x=(Window_palette_button_list->Pos_X+3)+(start>>4)*10; @@ -1567,9 +1834,9 @@ void Tag_color_range(byte start,byte end) // On TAG toutes les couleurs intermédiaires for (index=start+1;indexPos_X+3+((index>>4)*10))*Menu_factor_X, - Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y, - Menu_factor_X*2,Menu_factor_Y*5,MC_Black); + Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10), + Window_palette_button_list->Pos_Y+3+((index&15)* 5), + 2,5,MC_Black); // On efface l'éventuelle pointe d'une ancienne extrémité de l'intervalle Pixel_in_window(Window_palette_button_list->Pos_X+5+((index>>4)*10), Window_palette_button_list->Pos_Y+5+((index&15)* 5), @@ -1579,24 +1846,24 @@ void Tag_color_range(byte start,byte end) } - Update_rect(ToWinX(Window_palette_button_list->Pos_X+3),ToWinY(Window_palette_button_list->Pos_Y+3),ToWinL(12*16),ToWinH(5*16)); + Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } //------------------ Dessiner un scroller dans une fenêtre ------------------- -void Compute_slider_cursor_height(T_Scroller_button * button) +void Compute_slider_cursor_length(T_Scroller_button * button) { if (button->Nb_elements>button->Nb_visibles) { - button->Cursor_height=(button->Nb_visibles*(button->Height-24))/button->Nb_elements; - if (!(button->Cursor_height)) - button->Cursor_height=1; + button->Cursor_length=(button->Nb_visibles*(button->Length-24))/button->Nb_elements; + if (!(button->Cursor_length)) + button->Cursor_length=1; } else { - button->Cursor_height=button->Height-24; + button->Cursor_length=button->Length-24; } } @@ -1604,32 +1871,70 @@ void Window_draw_slider(T_Scroller_button * button) { word slider_position; - slider_position=button->Pos_Y+12; - - Block(Window_pos_X+(button->Pos_X*Menu_factor_X), - Window_pos_Y+(slider_position*Menu_factor_Y), - 11*Menu_factor_X,(button->Height-24)*Menu_factor_Y,MC_Black/*MC_Dark*/); - - if (button->Nb_elements>button->Nb_visibles) - slider_position+=Round_div(button->Position*(button->Height-24-button->Cursor_height),button->Nb_elements-button->Nb_visibles); - - Block(Window_pos_X+(button->Pos_X*Menu_factor_X), - Window_pos_Y+(slider_position*Menu_factor_Y), - 11*Menu_factor_X,button->Cursor_height*Menu_factor_Y,MC_Dark/*MC_White*/); - - Update_rect(Window_pos_X+(button->Pos_X*Menu_factor_X), - Window_pos_Y+button->Pos_Y*Menu_factor_Y, - 11*Menu_factor_X,(button->Height)*Menu_factor_Y); + if (button->Is_horizontal) + { + slider_position=button->Pos_X+12; + + Window_rectangle(slider_position, + button->Pos_Y, + button->Length-24,11,MC_Black/*MC_Dark*/); + + if (button->Nb_elements>button->Nb_visibles) + slider_position+= + ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); + + Window_rectangle(slider_position, + button->Pos_Y, + button->Cursor_length,11,MC_OnBlack/*MC_White*/); + + Update_window_area(button->Pos_X, + button->Pos_Y, + button->Length,11); + } + else + { + slider_position=button->Pos_Y+12; + + Window_rectangle(button->Pos_X, + slider_position, + 11,button->Length-24,MC_Black/*MC_Dark*/); + + if (button->Nb_elements>button->Nb_visibles) + slider_position+= + ((button->Length-24-button->Cursor_length)*(button->Position)+(button->Nb_elements-button->Nb_visibles)/2)/(button->Nb_elements-button->Nb_visibles); + // + //(button->Position*) / (button->Nb_elements-button->Nb_visibles)); + + Window_rectangle(button->Pos_X, + slider_position, + 11,button->Cursor_length,MC_OnBlack/*MC_White*/); + + Update_window_area(button->Pos_X, + button->Pos_Y, + 11,button->Length); + } } -void Window_draw_scroller_bouton(T_Scroller_button * button) +void Window_draw_scroller_button(T_Scroller_button * button) { - Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); - Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Height-22,MC_Black); - Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); - Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Height-11,11,11); - Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light); - Print_in_window(button->Pos_X+2,button->Pos_Y+button->Height-9,"\031",MC_Black,MC_Light); + if (button->Is_horizontal) + { + Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,button->Length+2,13,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); + Window_display_frame_mono(button->Pos_X+11,button->Pos_Y-1,button->Length-22,13,MC_Black); + Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); + Window_display_frame_out(button->Pos_X+button->Length-11,button->Pos_Y,11,11); + Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\033",MC_Black,MC_Light); + Print_in_window(button->Pos_X+button->Length-9,button->Pos_Y+2,"\032",MC_Black,MC_Light); + } + else + { + Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Length+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); + Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Length-22,MC_Black); + Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11); + Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Length-11,11,11); + Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light); + Print_in_window(button->Pos_X+2,button->Pos_Y+button->Length-9,"\031",MC_Black,MC_Light); + } Window_draw_slider(button); } @@ -1662,7 +1967,7 @@ void Window_clear_input_button(T_Special_button * button) T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, word width, word height, - char * title, byte undersc_letter, + const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; @@ -1692,7 +1997,7 @@ T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, word width, word height, - char * title, byte undersc_letter, + const char * title, byte undersc_letter, byte clickable, word shortcut) { T_Normal_button * temp=NULL; @@ -1745,21 +2050,47 @@ T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); temp->Number =++Window_nb_buttons; + temp->Is_horizontal =0; temp->Pos_X =x_pos; temp->Pos_Y =y_pos; - temp->Height =height; + temp->Length =height; temp->Nb_elements =nb_elements; temp->Nb_visibles =nb_elements_visible; temp->Position =initial_position; - Compute_slider_cursor_height(temp); + Compute_slider_cursor_length(temp); temp->Next=Window_scroller_button_list; Window_scroller_button_list=temp; - Window_draw_scroller_bouton(temp); + Window_draw_scroller_button(temp); return temp; } +T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos, + word width, + word nb_elements, + word nb_elements_visible, + word initial_position) +{ + T_Scroller_button * temp; + + temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button)); + temp->Number =++Window_nb_buttons; + temp->Is_horizontal =1; + temp->Pos_X =x_pos; + temp->Pos_Y =y_pos; + temp->Length =width; + temp->Nb_elements =nb_elements; + temp->Nb_visibles =nb_elements_visible; + temp->Position =initial_position; + Compute_slider_cursor_length(temp); + + temp->Next=Window_scroller_button_list; + Window_scroller_button_list=temp; + + Window_draw_scroller_button(temp); + return temp; +} T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width,word height) { @@ -1888,6 +2219,15 @@ void Window_redraw_list(T_List_button * list) list->List_start + i, i == list->Cursor_position); } + // Remaining rectangle under list + i=list->Scroller->Nb_visibles-list->Scroller->Nb_elements; + if (i>0) + Window_rectangle( + list->Entry_button->Pos_X, + list->Entry_button->Pos_Y+list->Scroller->Nb_elements*8, + list->Entry_button->Width, + i*8, + MC_Light); } //----------------------- Ouverture d'un pop-up ----------------------- @@ -1908,6 +2248,7 @@ void Open_popup(word x_pos, word y_pos, word width,word height) Window_height=height; Window_pos_X=x_pos; Window_pos_Y=y_pos; + Window_draggable=0; // Sauvegarde de ce que la fenêtre remplace Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height); @@ -2074,7 +2415,8 @@ short Wait_click_in_palette(T_Palette_button * button) for (;;) { - while(!Get_input())SDL_Delay(20); + while (Get_input(20)) + ; if (Mouse_K==LEFT_SIDE) { @@ -2155,7 +2497,7 @@ void Get_color_behind_window(byte * color, byte * click) do { - if(!Get_input())SDL_Delay(20); + Get_input(20); if ((Mouse_X!=old_x) || (Mouse_Y!=old_y)) { @@ -2242,7 +2584,10 @@ void Move_window(short dx, short dy) old_x=new_x; old_y=new_y; - while(!Get_input() && new_x==Mouse_X-dx && new_y==Mouse_Y-dy) SDL_Delay(20); + do + { + Get_input(20); + } while(Mouse_K && new_x==Mouse_X-dx && new_y==Mouse_Y-dy); new_x=Mouse_X-dx; @@ -2444,7 +2789,7 @@ T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, sh do { // Attente - if(!Get_input()) SDL_Delay(20); + Get_input(20); // Mise à jour du survol selected_index=Window_click_in_rectangle(2,2,button->Dropdown_width-2,box_height-1)? (((Mouse_Y-Window_pos_Y)/Menu_factor_Y-2)>>3) : -1; @@ -2515,7 +2860,7 @@ short Window_normal_button_onclick(word x_pos, word y_pos, word width, word heig Display_cursor(); while (Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1)) { - if(!Get_input()) SDL_Delay(20); + Get_input(20); if (!Mouse_K) { Hide_cursor(); @@ -2529,7 +2874,7 @@ short Window_normal_button_onclick(word x_pos, word y_pos, word width, word heig Display_cursor(); while (!(Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1))) { - if(!Get_input()) SDL_Delay(20); + Get_input(20); if (!Mouse_K) return 0; } @@ -2545,8 +2890,6 @@ short Window_get_clicked_button(void) T_Special_button * temp4; T_Dropdown_button * temp5; - long max_slider_height; - Window_attribute1=Mouse_K; // Test click on normal buttons @@ -2561,7 +2904,7 @@ short Window_get_clicked_button(void) Hide_cursor(); Window_select_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); - Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); + Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); Display_cursor(); @@ -2585,7 +2928,7 @@ short Window_get_clicked_button(void) } } - // Test click oin slider/scroller bars + // Test click on slider/scroller bars for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) { // Button Up arrow @@ -2608,7 +2951,7 @@ short Window_get_clicked_button(void) Display_cursor(); - Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); + Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); @@ -2619,12 +2962,16 @@ short Window_get_clicked_button(void) // Button Down arrow if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|2048)) - && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1)) + && ((temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,temp3->Pos_X+temp3->Length-1,temp3->Pos_Y+10)) + || (!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-1)))) { Input_sticky_control = temp3->Number | 2048; Hide_cursor(); - Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,11,11); - + if (temp3->Is_horizontal) + Window_select_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); + else + Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); + if (temp3->Position+temp3->Nb_visiblesNb_elements) { temp3->Position++; @@ -2637,38 +2984,50 @@ short Window_get_clicked_button(void) Display_cursor(); - Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); + Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); Hide_cursor(); - Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,11,11); + if (temp3->Is_horizontal) + Window_unselect_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11); + else + Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11); Display_cursor(); return (Window_attribute1)? temp3->Number : 0; } // Middle slider if ((Input_sticky_control == temp3->Number) || (Input_sticky_control==0 && - Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-13))) + ((!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-13)) + ||(temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+12,temp3->Pos_Y,temp3->Pos_X+temp3->Length-13,temp3->Pos_Y+10))))) { Input_sticky_control = temp3->Number; if (temp3->Nb_elements>temp3->Nb_visibles) { // If there is enough room to make the cursor move: - - max_slider_height=(temp3->Height-24); + long mouse_pos; + long origin; // Window_attribute2 receives the position of the cursor. - Window_attribute2 =(Mouse_Y-Window_pos_Y) / Menu_factor_Y; - Window_attribute2-=(temp3->Pos_Y+12+((temp3->Cursor_height-1)>>1)); - Window_attribute2*=(temp3->Nb_elements-temp3->Nb_visibles); + if (temp3->Is_horizontal) + mouse_pos =(Mouse_X-Window_pos_X) / Menu_factor_X - (temp3->Pos_X+12); + else + mouse_pos =(Mouse_Y-Window_pos_Y) / Menu_factor_Y - (temp3->Pos_Y+12); + // The following formula is wicked. The issue is that you want two + // different behaviors: + // *) If the range is bigger than the pixel precision, the last pixel + // should map to max value, exactly. + // *) Otherwise, the possible cursor positions are separated by + // at least one full pixel, so we should find the valid position + // closest to the center of the mouse cursor position pixel. + + origin = (temp3->Nb_visibles-1)*(temp3->Length-24)/temp3->Nb_elements/2; + Window_attribute2 = (mouse_pos - origin) * (temp3->Nb_elements-(temp3->Cursor_length>1?0:1)) / (temp3->Length-24-1); + if (Window_attribute2<0) Window_attribute2=0; - else - { - Window_attribute2 =Round_div(Window_attribute2,max_slider_height-temp3->Cursor_height); - if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements) - Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles; - } + else if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements) + Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles; // If the cursor moved @@ -2743,7 +3102,7 @@ short Window_get_button_shortcut(void) Window_select_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); Display_cursor(); - Slider_timer(Config.Delay_right_click_on_slider); + Delay_with_active_mouse(Config.Delay_right_click_on_slider); Hide_cursor(); Window_unselect_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); @@ -2793,7 +3152,7 @@ short Window_clicked_button(void) { short Button; - if(!Get_input())SDL_Delay(20); + Get_input(20); // Handle clicks if (Mouse_K) @@ -2813,7 +3172,7 @@ short Window_clicked_button(void) } } - if (!Input_sticky_control && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) + if (!Input_sticky_control && Window_draggable && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y)) { Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y); } @@ -3084,17 +3443,17 @@ void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y) EDI = Window_background[window_index]; // Pour chaque ligne - for(dx=0; dxMax_Y) + if (dx+Window_stack[window_index].Pos_Y>Max_Y) return; - if (dx+Window_stack_pos_Y[window_index]0;cx--) + for(cx=Window_stack[window_index].Width*Menu_factor_X*Pixel_width;cx>0;cx--) { *EDI = conversion_table[*EDI]; EDI ++; @@ -3102,3 +3461,16 @@ void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y) } } } + +void Delay_with_active_mouse(int speed) +{ + Uint32 end; + byte original_mouse_k = Mouse_K; + + end = SDL_GetTicks()+speed*10; + + do + { + Get_input(20); + } while (Mouse_K == original_mouse_k && SDL_GetTicks() @@ -50,11 +53,14 @@ #include #include // for DBL_MAX #include // chdir() +#include //for INT_MIN /// /// Number of characters for name in fileselector. /// Window is adjusted according to it. #define NAME_WIDTH 34 +/// Number of characters for the description block +#define DESC_WIDTH ((NAME_WIDTH+2)*8/6) /// Position of fileselector top, in window space #define FILESEL_Y 18 @@ -64,6 +70,8 @@ static word Brush_backup_width; static word Brush_backup_height; static byte Palette_has_changed; static byte Brush_was_altered; +static byte Original_fore_color; +static byte Original_back_color; /// Helper function to clamp a double to 0-255 range static inline byte clamp_byte(double value) @@ -109,6 +117,18 @@ do { \ dest = lua_tostring(L, (index)); \ } while (0) +/// +/// This macro checks that a Lua argument is a function. +/// If argument is invalid, it will break the caller and raise a verbose message. +/// This macro uses 2 existing symbols: L for the context, and nb_args=lua_gettop(L) +/// @param index Index of the argument to check, starting at 1. +/// @param func_name The name of the lua callback, to display a message in case of error. +#define LUA_ARG_FUNCTION(index, func_name) \ +do { \ + if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ + if (!lua_isfunction(L, (index))) return luaL_error(L, "%s: Argument %d is not a function.", func_name, index); \ +} while (0) + /// Check if 'num' arguments were provided exactly #define LUA_ARG_LIMIT(num, func_name) \ do { \ @@ -116,7 +136,17 @@ do { \ return luaL_error(L, "%s: Expected %d arguments, but found %d.", func_name, (num), nb_args); \ } while(0) - +// Updates the screen colors after a running screen has modified the palette. +void Update_colors_during_script(void) +{ + if (Palette_has_changed) + { + Set_palette(Main_palette); + Compute_optimal_menu_colors(Main_palette); + Display_menu(); + Palette_has_changed=0; + } +} // Wrapper functions to call C from Lua @@ -131,13 +161,18 @@ int L_SetBrushSize(lua_State* L) LUA_ARG_NUMBER(1, "setbrushsize", w, 1, 10000); LUA_ARG_NUMBER(2, "setbrushsize", h, 1, 10000); - if (Realloc_brush(w, h)) + if (Realloc_brush(w, h, NULL, NULL)) { return luaL_error(L, "setbrushsize: Resize failed"); } Brush_was_altered=1; // Fill with Back_color - memset(Brush,Back_color,(long)Brush_width*Brush_height); + memset(Brush_original_pixels,Back_color,(long)Brush_width*Brush_height); + // Grab palette + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + // Remap (no change) + Remap_brush(); + // Center the handle Brush_offset_X=(Brush_width>>1); Brush_offset_Y=(Brush_height>>1); @@ -169,7 +204,19 @@ int L_PutBrushPixel(lua_State* L) LUA_ARG_NUMBER(2, "putbrushpixel", y, INT_MIN, INT_MAX); LUA_ARG_NUMBER(3, "putbrushpixel", c, INT_MIN, INT_MAX); - Brush_was_altered=1; + if (!Brush_was_altered) + { + int i; + + // First time writing in brush: + // Adopt the current palette. + memcpy(Brush_original_palette, Main_palette,sizeof(T_Palette)); + memcpy(Brush_original_pixels, Brush, Brush_width*Brush_height); + for (i=0; i<256; i++) + Brush_colormap[i]=i; + //-- + Brush_was_altered=1; + } if (x<0 || y<0 || x>=Brush_width || y>=Brush_height) ; @@ -232,12 +279,23 @@ int L_SetPictureSize(lua_State* L) int w; int h; int nb_args=lua_gettop(L); + int i; LUA_ARG_LIMIT (2, "setpicturesize"); LUA_ARG_NUMBER(1, "setpicturesize", w, 1, 9999); LUA_ARG_NUMBER(2, "setpicturesize", h, 1, 9999); - Resize_image(w, h); // TODO: a return value to catch runtime errors + Backup_in_place(w, h); + // part of Resize_image() : the pixel copy part. + for (i=0; iPages->Nb_layers; i++) + { + Copy_part_of_image_to_another( + Main_backups->Pages->Next->Image[i],0,0,Min(Main_backups->Pages->Next->Width,Main_image_width), + Min(Main_backups->Pages->Next->Height,Main_image_height),Main_backups->Pages->Next->Width, + Main_backups->Pages->Image[i],0,0,Main_image_width); + } + Redraw_layered_image(); + return 0; } @@ -319,13 +377,16 @@ int L_GetBackupPixel(lua_State* L) LUA_ARG_NUMBER(2, "getbackuppixel", y, INT_MIN, INT_MAX); // Bound check - if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) + if (x<0 || y<0 || x>=Main_backups->Pages->Next->Width || y>=Main_backups->Pages->Next->Height) { // Silently return the image's transparent color - lua_pushinteger(L, Main_backups->Pages->Transparent_color); + lua_pushinteger(L, Main_backups->Pages->Next->Transparent_color); return 1; } - lua_pushinteger(L, Read_pixel_from_backup_screen(x,y)); + // Can't use Read_pixel_from_backup_screen(), because in a Lua script + // the "backup" can use a different screen dimension. + lua_pushinteger(L, *(Screen_backup + x + Main_backups->Pages->Next->Width * y)); + return 1; } @@ -506,6 +567,33 @@ int L_GetTransColor(lua_State* L) return 1; } +int L_SetForeColor(lua_State* L) +{ + byte c; + int nb_args=lua_gettop(L); + + LUA_ARG_LIMIT (1, "setforecolor"); + LUA_ARG_NUMBER(1, "setforecolor", c, -DBL_MAX, DBL_MAX); + + Fore_color = c; + + return 0; +} + +int L_SetBackColor(lua_State* L) +{ + byte c; + int nb_args=lua_gettop(L); + + LUA_ARG_LIMIT (1, "setbackcolor"); + LUA_ARG_NUMBER(1, "setbackcolor", c, -DBL_MAX, DBL_MAX); + + Back_color = c; + + return 0; +} + + int L_InputBox(lua_State* L) { const int max_settings = 9; @@ -577,7 +665,7 @@ int L_InputBox(lua_State* L) LUA_ARG_NUMBER(setting*args_per_setting+6, "inputbox", decimal_places[setting], -15.0, 15.0); if (decimal_places[setting]>15) decimal_places[setting]=15; - if (min_value[setting]!=0 || min_value[setting]!=1) + if (min_value[setting]!=0 || max_value[setting]!=1) if (decimal_places[setting]<0) decimal_places[setting]=0; // Keep current value in range @@ -593,6 +681,7 @@ int L_InputBox(lua_State* L) if (max_label_length>25) max_label_length=25; + Update_colors_during_script(); Open_window(115+max_label_length*8,44+nb_settings*17,window_caption); // Normally this index is unused, but this initialization avoids @@ -675,7 +764,7 @@ int L_InputBox(lua_State* L) case CONTROL_INPUT: Sprint_double(str,current_value[setting],decimal_places[setting],0); - Readline_ex(12+max_label_length*8+23, 22+setting*17,str,7,40,3,decimal_places[setting]); + Readline_ex(12+max_label_length*8+23, 22+setting*17,str,7,40,INPUT_TYPE_DECIMAL,decimal_places[setting]); current_value[setting]=atof(str); if (current_value[setting] < min_value[setting]) @@ -769,6 +858,88 @@ int L_InputBox(lua_State* L) return 1 + nb_settings; } +int L_SelectBox(lua_State* L) +{ + const int max_settings = 10; + const char * label[max_settings]; + + const char * window_caption; + unsigned int caption_length; + int nb_args; + + unsigned int max_label_length; + int button; + int nb_buttons; + short clicked_button; + //char str[40]; + //short close_window = 0; + + nb_args = lua_gettop (L); + + if (nb_args < 2) + { + return luaL_error(L, "selectbox: Less than 2 arguments"); + } + if ((nb_args - 1) % 2) + { + return luaL_error(L, "selectbox: Wrong number of arguments"); + } + + + nb_buttons=(nb_args-1) /2; + + max_label_length=4; // Minimum size + + // First argument is window caption + LUA_ARG_STRING(1, "selectbox", window_caption); + caption_length = strlen(window_caption); + if ( caption_length > max_label_length) + max_label_length = caption_length; + + for (button=0; button max_label_length) + max_label_length = strlen(label[button]); + LUA_ARG_FUNCTION(button*2+3, "selectbox"); + } + // Max is 25 to keep window under 320 pixel wide + if (max_label_length>25) + max_label_length=25; + + Update_colors_during_script(); + Open_window(28+max_label_length*8,26+nb_buttons*17,window_caption); + + for (button=0; buttonFull_name, NAME_WIDTH, MC_Black, - (highlighted)?MC_Dark:MC_Light); - name_size=strlen(current_item->Full_name); - // Clear remaining area on the right - if (name_sizeType==1) // Directories + { + fg=(highlighted)?MC_Black:MC_Dark; + bg=(highlighted)?MC_Dark:MC_Light; + } + else // Files + { + fg=MC_Black; + bg=(highlighted)?MC_Dark:MC_Light; + } + + Print_in_window(x, y, current_item->Short_name, fg,bg); Update_window_area(x,y,NAME_WIDTH*8,8); } @@ -826,11 +1148,12 @@ void Draw_script_information(T_Fileselector_item * script_item) { FILE *script_file; char full_name[MAX_PATH_CHARACTERS]; - char text_block[3][NAME_WIDTH+3]; + char text_block[3][DESC_WIDTH+1]; int x, y; + int i; // Blank the target area - Window_rectangle(7, FILESEL_Y + 89, (NAME_WIDTH+2)*8+2, 3*8, MC_Black); + Window_rectangle(7, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8, MC_Black); if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') { @@ -865,7 +1188,7 @@ void Draw_script_information(T_Fileselector_item * script_item) } else { - if (x < NAME_WIDTH+4) + if (x < DESC_WIDTH+2) { // Adding character text_block[y][x-2] = (c<32 || c>255) ? ' ' : c; @@ -879,250 +1202,525 @@ void Draw_script_information(T_Fileselector_item * script_item) fclose(script_file); } - Print_in_window(7, FILESEL_Y + 89 , text_block[0], MC_Light, MC_Black); - Print_in_window(7, FILESEL_Y + 89+ 8, text_block[1], MC_Light, MC_Black); - Print_in_window(7, FILESEL_Y + 89+16, text_block[2], MC_Light, MC_Black); + Print_help(8, FILESEL_Y + 89 , text_block[0], 'N', 0, 0); + Print_help(8, FILESEL_Y + 89+ 8, text_block[1], 'N', 0, 0); + Print_help(8, FILESEL_Y + 89+16, text_block[2], 'N', 0, 0); + // Display a line with the keyboard shortcut + Print_help(8, FILESEL_Y + 89+24, "Key:", 'N', 0, 0); + for (i=0; i<10; i++) + if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], script_item->Full_name)) + break; + + if (i<10) + { + const char *shortcut; + shortcut=Keyboard_shortcut_value(SPECIAL_RUN_SCRIPT_1+i); + Print_help(8+4*6, FILESEL_Y + 89+24, shortcut, 'K', 0, strlen(shortcut)); + } + else + { + Print_help(8+4*6, FILESEL_Y + 89+24, "None", 'K', 0, 4); + } } - Update_window_area(7, FILESEL_Y + 89, (NAME_WIDTH+2)*8+2, 3*8); + + + + Update_window_area(8, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8); } // Add a script to the list -void Add_script(const char *name) +void Add_script(const char *name, byte is_file, byte is_directory, byte is_hidden) { - Add_element_to_list(&Scripts_list, Find_last_slash(name)+1, 0); + const char * file_name; + int len; + + file_name=Find_last_slash(name)+1; + + if (is_file) + { + // Only files ending in ".lua" + len=strlen(file_name); + if (len<=4 || strcasecmp(file_name+len-4, ".lua")) + return; + // Hidden + //if (is_hidden && !Config.Show_hidden_files) + // return; + + Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 0), 0, ICON_NONE); + } + else if (is_directory) + { + // Ignore current directory + if ( !strcmp(file_name, ".")) + return; + // Hidden + //if (is_hidden && !Config.Show_hidden_directories) + // return; + + Add_element_to_list(&Scripts_selector, file_name, Format_filename(file_name, NAME_WIDTH+1, 1), 1, ICON_NONE); + } } -void Highlight_script(T_Fileselector *selector, T_List_button *list, const char *selected_script) +void Highlight_script(T_Fileselector *selector, T_List_button *list, const char *selected_file) { short index; - index=Find_file_in_fileselector(selector, selected_script); + index=Find_file_in_fileselector(selector, selected_file); + Locate_list_item(list, selector, index); +} - if ((list->Scroller->Nb_elements<=list->Scroller->Nb_visibles) || (indexScroller->Nb_visibles/2)) +static char Last_run_script[MAX_PATH_CHARACTERS]=""; + +// Before: Cursor hidden +// After: Cursor shown +void Run_script(const char *script_subdirectory, const char *script_filename) +{ + lua_State* L; + const char* message; + byte old_cursor_shape=Cursor_shape; + char scriptdir[MAX_PATH_CHARACTERS]; + + strcpy(scriptdir, Data_directory); + strcat(scriptdir, "scripts/"); + + // Some scripts are slow + Cursor_shape=CURSOR_SHAPE_HOURGLASS; + Display_cursor(); + Flush_update(); + + chdir(scriptdir); + + if (script_subdirectory && script_subdirectory[0]!='\0') { - list->List_start=0; - list->Cursor_position=index; + sprintf(Last_run_script, "%s%s%s", script_subdirectory, PATH_SEPARATOR, script_filename); } else { - if (index>=list->Scroller->Nb_elements-list->Scroller->Nb_visibles/2) + strcpy(Last_run_script, script_filename); + } + + + L = lua_open(); + putenv("LUA_PATH=libs\\?.lua"); + + lua_register(L,"putbrushpixel",L_PutBrushPixel); + lua_register(L,"getbrushpixel",L_GetBrushPixel); + lua_register(L,"getbrushbackuppixel",L_GetBrushBackupPixel); + lua_register(L,"putpicturepixel",L_PutPicturePixel); + lua_register(L,"getpicturepixel",L_GetPicturePixel); + lua_register(L,"getlayerpixel",L_GetLayerPixel); + lua_register(L,"getbackuppixel",L_GetBackupPixel); + lua_register(L,"setbrushsize",L_SetBrushSize); + lua_register(L,"setpicturesize",L_SetPictureSize); + lua_register(L,"getbrushsize",L_GetBrushSize); + lua_register(L,"getpicturesize",L_GetPictureSize); + lua_register(L,"setcolor",L_SetColor); + lua_register(L,"getcolor",L_GetColor); + lua_register(L,"getbackupcolor",L_GetBackupColor); + lua_register(L,"matchcolor",L_MatchColor); + lua_register(L,"getbrushtransparentcolor",L_GetBrushTransparentColor); + lua_register(L,"inputbox",L_InputBox); + lua_register(L,"messagebox",L_MessageBox); + lua_register(L,"statusmessage",L_StatusMessage); + lua_register(L,"selectbox",L_SelectBox); + lua_register(L,"getforecolor",L_GetForeColor); + lua_register(L,"getbackcolor",L_GetBackColor); + lua_register(L,"setforecolor",L_SetForeColor); + lua_register(L,"setbackcolor",L_SetBackColor); + lua_register(L,"gettranscolor",L_GetTransColor); + lua_register(L,"getsparepicturesize",L_GetSparePictureSize); + lua_register(L,"getsparelayerpixel",L_GetSpareLayerPixel); + lua_register(L,"getsparepicturepixel",L_GetSparePicturePixel); + lua_register(L,"getsparecolor",L_GetSpareColor); + lua_register(L,"getsparetranscolor",L_GetSpareTransColor); + lua_register(L,"clearpicture",L_ClearPicture); + lua_register(L,"wait",L_Wait); + lua_register(L,"waitbreak",L_WaitBreak); + lua_register(L,"waitinput",L_WaitInput); + lua_register(L,"updatescreen",L_UpdateScreen); + lua_register(L,"finalizepicture",L_FinalizePicture); + + // Load all standard libraries + luaL_openlibs(L); + + /* + luaopen_base(L); + //luaopen_package(L); // crashes on Windows, for unknown reason + luaopen_table(L); + //luaopen_io(L); // crashes on Windows, for unknown reason + //luaopen_os(L); + luaopen_string(L); + luaopen_math(L); + //luaopen_debug(L); + */ + + // TODO The script may modify the picture, so we do a backup here. + // If the script is only touching the brush, this isn't needed... + // The backup also allows the script to read from it to make something + // like a feedback off effect (convolution matrix comes to mind). + Backup(); + + Palette_has_changed=0; + Brush_was_altered=0; + Original_back_color=Back_color; + Original_fore_color=Fore_color; + + // Backup the brush + Brush_backup=(byte *)malloc(((long)Brush_height)*Brush_width); + Brush_backup_width = Brush_width; + Brush_backup_height = Brush_height; + + if (Brush_backup == NULL) + { + Verbose_message("Error!", "Out of memory!"); + } + else + { + memcpy(Brush_backup, Brush, ((long)Brush_height)*Brush_width); + + if (luaL_loadfile(L,Last_run_script) != 0) { - list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; - list->Cursor_position=index-list->List_start; + int stack_size; + stack_size= lua_gettop(L); + if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) + Verbose_message("Error!", message); + else + Warning_message("Unknown error loading script!"); + } + else if (lua_pcall(L, 0, 0, 0) != 0) + { + int stack_size; + stack_size= lua_gettop(L); + + Update_colors_during_script(); + + if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) + Verbose_message("Error running script", message); + else + Warning_message("Unknown error running script!"); + } + } + // Cleanup + free(Brush_backup); + Brush_backup=NULL; + Update_colors_during_script(); + End_of_modification(); + + lua_close(L); + + if (Brush_was_altered) + { + // Copy Brush to original + memcpy(Brush_original_pixels, Brush, (long)Brush_width*Brush_height); + Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); + } + + Hide_cursor(); + Display_all_screen(); + // Update changed pen colors. + if (Back_color!=Original_back_color || Fore_color!=Original_fore_color) + { + // This is done at end of script, in case somebody would use the + // functions in a custom window. + if (Back_color!=Original_back_color) + { + byte new_color = Back_color; + Back_color = Original_back_color; + Set_back_color(new_color); + } + if (Fore_color!=Original_fore_color) + { + byte new_color = Fore_color; + Fore_color = Original_fore_color; + Set_fore_color(new_color); + } + + } + Cursor_shape=old_cursor_shape; + Display_cursor(); +} + +void Run_numbered_script(byte index) +{ + + if (index>=10) + return; + if (Bound_script[index]==NULL) + return; + + Hide_cursor(); + Run_script(NULL, Bound_script[index]); +} + +void Repeat_script(void) +{ + + if (Last_run_script==NULL || Last_run_script[0]=='\0') + { + Warning_message("No script to repeat."); + return; + } + + Hide_cursor(); + Run_script(NULL, Last_run_script); +} + +void Set_script_shortcut(T_Fileselector_item * script_item) +{ + int i; + char full_name[MAX_PATH_CHARACTERS]; + + if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') + { + strcpy(full_name, Data_directory); + strcat(full_name, "scripts/"); + strcat(full_name, script_item->Full_name); + + // Find if it already has a shortcut + for (i=0; i<10; i++) + if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], script_item->Full_name)) + break; + if (i<10) + { + // Existing shortcut } else { - list->List_start=index-(list->Scroller->Nb_visibles-1)/2; - list->Cursor_position=(list->Scroller->Nb_visibles-1)/2; + // Try to find a "free" one. + for (i=0; i<10; i++) + if (Bound_script[i]==NULL + || !Has_shortcut(SPECIAL_RUN_SCRIPT_1+i) + || !File_exists(full_name)) + break; + if (i<10) + { + free(Bound_script[i]); + Bound_script[i]=strdup(script_item->Full_name); + } + else + { + Warning_message("Already 10 scripts have shortcuts."); + return; + } } + Window_set_shortcut(SPECIAL_RUN_SCRIPT_1+i); + if (!Has_shortcut(SPECIAL_RUN_SCRIPT_1+i)) + { + // User cancelled or deleted all shortcuts + free(Bound_script[i]); + Bound_script[i]=NULL; + } + // Refresh display + Hide_cursor(); + Draw_script_information(script_item); + Display_cursor(); } } void Button_Brush_Factory(void) { + static char selected_file[MAX_PATH_CHARACTERS]=""; + static char sub_directory[MAX_PATH_CHARACTERS]=""; + short clicked_button; T_List_button* scriptlist; T_Scroller_button* scriptscroll; + T_Special_button* scriptarea; char scriptdir[MAX_PATH_CHARACTERS]; - static char selected_script[MAX_PATH_CHARACTERS]=""; - - Open_window(33+8*NAME_WIDTH, 162, "Brush Factory"); - - // Here we use the same data container as the fileselectors. + T_Fileselector_item *item; + // Reinitialize the list - Free_fileselector_list(&Scripts_list); + Free_fileselector_list(&Scripts_selector); strcpy(scriptdir, Data_directory); strcat(scriptdir, "scripts/"); + strcat(scriptdir, sub_directory); // Add each found file to the list - For_each_file(scriptdir, Add_script); + For_each_directory_entry(scriptdir, Add_script); // Sort it - Sort_list_of_files(&Scripts_list); + Sort_list_of_files(&Scripts_selector); + // - Window_set_normal_button(85, 141, 67, 14, "Cancel", 0, 1, KEY_ESC); // 1 + Open_window(33+8*NAME_WIDTH, 180, "Brush Factory"); + + Window_set_normal_button(85, 149, 67, 14, "Cancel", 0, 1, KEY_ESC); // 1 Window_display_frame_in(6, FILESEL_Y - 2, NAME_WIDTH*8+4, 84); // File selector - scriptlist = Window_set_list_button( - // Fileselector - Window_set_special_button(8, FILESEL_Y + 1, NAME_WIDTH*8, 80), // 2 - // Scroller for the fileselector - (scriptscroll = Window_set_scroller_button(NAME_WIDTH*8+14, FILESEL_Y - 1, 82, - Scripts_list.Nb_elements,10, 0)), // 3 - Draw_script_name); // 4 + // Fileselector + scriptarea=Window_set_special_button(8, FILESEL_Y + 1, NAME_WIDTH*8, 80); // 2 + // Scroller for the fileselector + scriptscroll = Window_set_scroller_button(NAME_WIDTH*8+14, FILESEL_Y - 1, 82, + Scripts_selector.Nb_elements,10, 0); // 3 + scriptlist = Window_set_list_button(scriptarea,scriptscroll,Draw_script_name); // 4 - Window_set_normal_button(10, 141, 67, 14, "Run", 0, Scripts_list.Nb_elements!=0, SDLK_RETURN); // 5 + Window_set_normal_button(10, 149, 67, 14, "Run", 0, 1, SDLK_RETURN); // 5 - Window_display_frame_in(6, FILESEL_Y + 88, (NAME_WIDTH+2)*8+4, 3*8+2); // Descr. + Window_display_frame_in(6, FILESEL_Y + 88, DESC_WIDTH*6+4, 4*8+2); // Descr. + Window_set_special_button(7, FILESEL_Y + 89+24,DESC_WIDTH*6,8); // 6 - // Update position - Highlight_script(&Scripts_list, scriptlist, selected_script); - // Update the scroller position - scriptscroll->Position=scriptlist->List_start; - if (scriptscroll->Position) - Window_draw_slider(scriptscroll); - - Window_redraw_list(scriptlist); - Draw_script_information(Get_item_by_index(&Scripts_list, - scriptlist->List_start + scriptlist->Cursor_position)); - - Update_window_area(0, 0, Window_width, Window_height); - Display_cursor(); - - do + while (1) { - clicked_button = Window_clicked_button(); - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_BRUSH_EFFECTS, "BRUSH FACTORY"); - - switch (clicked_button) - { - case 4: - Hide_cursor(); - Draw_script_information(Get_item_by_index(&Scripts_list, - scriptlist->List_start + scriptlist->Cursor_position)); - Display_cursor(); - break; - - - default: - break; - } + // Locate selected file in view + Highlight_script(&Scripts_selector, scriptlist, selected_file); + // Update the scroller position + scriptscroll->Position=scriptlist->List_start; + Window_draw_slider(scriptscroll); - } while (clicked_button != 1 && clicked_button != 5); - - if (Scripts_list.Nb_elements == 0) - selected_script[0]='\0'; - else - strcpy(selected_script, Get_item_by_index(&Scripts_list, - scriptlist->List_start + scriptlist->Cursor_position)-> Full_name); + Window_redraw_list(scriptlist); + Draw_script_information(Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position)); + + Update_window_area(0, 0, Window_width, Window_height); + Display_cursor(); + + Reset_quicksearch(); + + do + { + clicked_button = Window_clicked_button(); + if (Key==SDLK_BACKSPACE && sub_directory[0]!='\0') + { + // Make it select first entry (parent directory) + scriptlist->List_start=0; + scriptlist->Cursor_position=0; + clicked_button=5; + } + if (Is_shortcut(Key,0x100+BUTTON_HELP)) + Window_help(BUTTON_BRUSH_EFFECTS, "BRUSH FACTORY"); + else if (Is_shortcut(Key,0x200+BUTTON_BRUSH_EFFECTS)) + clicked_button=1; // Cancel + // Quicksearch + if (clicked_button==4) + Reset_quicksearch(); + else if (clicked_button==0 && Key_ANSI) + clicked_button=Quicksearch_list(scriptlist, &Scripts_selector); + + switch (clicked_button) + { + case 4: + Hide_cursor(); + Draw_script_information(Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position)); + Display_cursor(); + { + // Test double-click + static long time_click = 0; + static int last_selected_item=-1; + static long time_previous; + time_previous = time_click; + time_click = SDL_GetTicks(); + if (scriptlist->List_start + scriptlist->Cursor_position == last_selected_item) + { + if (time_click - time_previous < Config.Double_click_speed) + clicked_button=5; + } + else + { + last_selected_item=scriptlist->List_start + scriptlist->Cursor_position; + } + } + break; + + case 6: + Set_script_shortcut(Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position)); + break; + + default: + break; + } + + } while (clicked_button != 1 && clicked_button != 5); + + // Cancel + if (clicked_button==1) + break; + + // OK + if (Scripts_selector.Nb_elements == 0) + { + // No items : same as Cancel + clicked_button=1; + break; + } + + // Examine selected file + item = Get_item_by_index(&Scripts_selector, + scriptlist->List_start + scriptlist->Cursor_position); + + if (item->Type==0) // File + { + strcpy(selected_file, sub_directory); + strcat(selected_file, item->Full_name); + break; + } + else if (item->Type==1) // Directory + { + if (!strcmp(item->Full_name,PARENT_DIR)) + { + // Going up one directory + long len; + char * slash_pos; + + // Remove trailing slash + len=strlen(sub_directory); + if (len && !strcmp(sub_directory+len-1,PATH_SEPARATOR)) + sub_directory[len-1]='\0'; + + slash_pos=Find_last_slash(sub_directory); + if (slash_pos) + { + strcpy(selected_file, slash_pos+1); + *slash_pos='\0'; + } + else + { + strcpy(selected_file, sub_directory); + sub_directory[0]='\0'; + } + } + else + { + // Going down one directory + strcpy(selected_file, PARENT_DIR); + + strcat(sub_directory, item->Full_name); + strcat(sub_directory, PATH_SEPARATOR); + } + + // No break: going back up to beginning of loop + + // Reinitialize the list + Free_fileselector_list(&Scripts_selector); + strcpy(scriptdir, Data_directory); + strcat(scriptdir, "scripts/"); + strcat(scriptdir, sub_directory); + // Add each found file to the list + For_each_directory_entry(scriptdir, Add_script); + // Sort it + Sort_list_of_files(&Scripts_selector); + // + + scriptlist->Scroller->Nb_elements=Scripts_selector.Nb_elements; + Compute_slider_cursor_length(scriptlist->Scroller); + + Hide_cursor(); + } + } + + Close_window(); + Unselect_button(BUTTON_BRUSH_EFFECTS); + if (clicked_button == 5) // Run the script { - lua_State* L; - const char* message; - - // Some scripts are slow - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - Flush_update(); - - chdir(scriptdir); - - L = lua_open(); - - lua_register(L,"putbrushpixel",L_PutBrushPixel); - lua_register(L,"getbrushpixel",L_GetBrushPixel); - lua_register(L,"getbrushbackuppixel",L_GetBrushBackupPixel); - lua_register(L,"putpicturepixel",L_PutPicturePixel); - lua_register(L,"getpicturepixel",L_GetPicturePixel); - lua_register(L,"getlayerpixel",L_GetLayerPixel); - lua_register(L,"getbackuppixel",L_GetBackupPixel); - lua_register(L,"setbrushsize",L_SetBrushSize); - lua_register(L,"setpicturesize",L_SetPictureSize); - lua_register(L,"getbrushsize",L_GetBrushSize); - lua_register(L,"getpicturesize",L_GetPictureSize); - lua_register(L,"setcolor",L_SetColor); - lua_register(L,"getcolor",L_GetColor); - lua_register(L,"getbackupcolor",L_GetBackupColor); - lua_register(L,"matchcolor",L_MatchColor); - lua_register(L,"getbrushtransparentcolor",L_GetBrushTransparentColor); - lua_register(L,"inputbox",L_InputBox); - lua_register(L,"messagebox",L_MessageBox); - lua_register(L,"getforecolor",L_GetForeColor); - lua_register(L,"getbackcolor",L_GetBackColor); - lua_register(L,"gettranscolor",L_GetTransColor); - lua_register(L,"getsparepicturesize ",L_GetSparePictureSize); - lua_register(L,"getsparelayerpixel ",L_GetSpareLayerPixel); - lua_register(L,"getsparepicturepixel",L_GetSparePicturePixel); - lua_register(L,"getsparecolor",L_GetSpareColor); - lua_register(L,"getsparetranscolor",L_GetSpareTransColor); - lua_register(L,"clearpicture",L_ClearPicture); - - - // For debug only - // luaL_openlibs(L); - - luaopen_base(L); - //luaopen_package(L); // crashes on Windows, for unknown reason - luaopen_table(L); - //luaopen_io(L); // crashes on Windows, for unknown reason - //luaopen_os(L); - //luaopen_string(L); - luaopen_math(L); - //luaopen_debug(L); - - strcat(scriptdir, selected_script); - - // TODO The script may modify the picture, so we do a backup here. - // If the script is only touching the brush, this isn't needed... - // The backup also allows the script to read from it to make something - // like a feedback off effect (convolution matrix comes to mind). - Backup(); - - Palette_has_changed=0; - Brush_was_altered=0; - - // Backup the brush - Brush_backup=(byte *)malloc(((long)Brush_height)*Brush_width); - Brush_backup_width = Brush_width; - Brush_backup_height = Brush_height; - - if (Brush_backup == NULL) - { - Verbose_message("Error!", "Out of memory!"); - } - else - { - memcpy(Brush_backup, Brush, ((long)Brush_height)*Brush_width); - - if (luaL_loadfile(L,scriptdir) != 0) - { - int stack_size; - stack_size= lua_gettop(L); - if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) - Verbose_message("Error!", message); - else - Warning_message("Unknown error loading script!"); - } - else if (lua_pcall(L, 0, 0, 0) != 0) - { - int stack_size; - stack_size= lua_gettop(L); - if (stack_size>0 && (message = lua_tostring(L, stack_size))!=NULL) - Verbose_message("Error running script", message); - else - Warning_message("Unknown error running script!"); - } - } - // Cleanup - free(Brush_backup); - Brush_backup=NULL; - if (Palette_has_changed) - { - Set_palette(Main_palette); - Compute_optimal_menu_colors(Main_palette); - } - End_of_modification(); - - lua_close(L); + Run_script("", selected_file); + } + else + { + Display_cursor(); } - - Close_window(); - if (Brush_was_altered) - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - Unselect_button(BUTTON_BRUSH_EFFECTS); - // If the image has been resized, Compute_limits() has been called and it - // has computed wrong values because a window was open : In this - // context, Menu_Y and Menu_is_visible are artificially set to "menu hidden". - // This whole "_before_window" looks like it's completely useless anyway, - // but we're too close to release to scrap it and re-test everything. - // So: call Compute_limits() one more time, and be done with it. - Compute_limits(); - - Display_all_screen(); - Display_cursor(); } #else // NOLUA diff --git a/src/factory.h b/src/factory.h index ff12d081..3a1a54f5 100644 --- a/src/factory.h +++ b/src/factory.h @@ -1,3 +1,13 @@ /* vim:expandtab:ts=2 sw=2: */ void Button_Brush_Factory(void); +void Repeat_script(void); + +/// Lua scripts bound to shortcut keys. +extern char * Bound_script[10]; + +/// +/// Run a lua script linked to a shortcut, 0-9. +/// Before: Cursor hidden +/// After: Cursor shown +void Run_numbered_script(byte index); diff --git a/src/fileformats.c b/src/fileformats.c index 433935f1..21d281e2 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -27,6 +28,19 @@ #ifndef __no_pnglib__ #include +#if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4) + // Compatibility layer to allow us to use libng 1.4 or any older one. + + // This function is renamed in 1.4 + #define png_set_expand_gray_1_2_4_to_8(x) png_set_gray_1_2_4_to_8(x) + + // Wrappers that are mandatory in 1.4. Older version allowed direct access. + #define png_get_rowbytes(png_ptr,info_ptr) ((info_ptr)->rowbytes) + #define png_get_image_width(png_ptr,info_ptr) ((info_ptr)->width) + #define png_get_image_height(png_ptr,info_ptr) ((info_ptr)->height) + #define png_get_bit_depth(png_ptr,info_ptr) ((info_ptr)->bit_depth) + #define png_get_color_type(png_ptr,info_ptr) ((info_ptr)->color_type) +#endif #endif #include @@ -59,11 +73,11 @@ void Test_IMG(T_IO_Context * context) if ((file=fopen(filename, "rb"))) { // Lecture et vérification de la signature - if (Read_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1)) + if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) - && Read_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2)) - && Read_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette)) + && Read_bytes(file,IMG_header.Filler2,118) + && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { if ( (!memcmp(IMG_header.Filler1,signature,6)) @@ -94,11 +108,11 @@ void Load_IMG(T_IO_Context * context) { file_size=File_length_file(file); - if (Read_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1)) + if (Read_bytes(file,IMG_header.Filler1,6) && Read_word_le(file,&(IMG_header.Width)) && Read_word_le(file,&(IMG_header.Height)) - && Read_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2)) - && Read_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette)) + && Read_bytes(file,IMG_header.Filler2,118) + && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { @@ -167,11 +181,11 @@ void Save_IMG(T_IO_Context * context) memcpy(IMG_header.Palette,context->Palette,sizeof(T_Palette)); - if (Write_bytes(file,IMG_header.Filler1,sizeof(IMG_header.Filler1)) + if (Write_bytes(file,IMG_header.Filler1,6) && Write_word_le(file,IMG_header.Width) && Write_word_le(file,IMG_header.Height) - && Write_bytes(file,IMG_header.Filler2,sizeof(IMG_header.Filler2)) - && Write_bytes(file,IMG_header.Palette,sizeof(IMG_header.Palette)) + && Write_bytes(file,IMG_header.Filler2,118) + && Write_bytes(file,IMG_header.Palette,sizeof(T_Palette)) ) { @@ -204,7 +218,6 @@ void Save_IMG(T_IO_Context * context) //////////////////////////////////// LBM //////////////////////////////////// -#pragma pack(1) typedef struct { word Width; @@ -221,7 +234,6 @@ typedef struct word X_screen; word Y_screen; } T_LBM_Header; -#pragma pack() byte * LBM_buffer; FILE *LBM_file; @@ -375,28 +387,42 @@ void Test_LBM(T_IO_Context * context) } } - // ------------------------- Attendre une section ------------------------- - byte Wait_for(byte * expected_section) - { - // Valeur retournée: 1=Section trouvée, 0=Section non trouvée (erreur) - dword Taille_section; - byte section_read[4]; +// Inspired by Allegro: storing a 4-character identifier as a 32bit litteral +#define ID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255))) +/// Skips the current section in an ILBM file. +/// This function should be called while the file pointer is right +/// after the 4-character code that identifies the section. +int LBM_Skip_section(void) +{ + dword size; + + if (!Read_dword_be(LBM_file,&size)) + return 0; + if (size&1) + size++; + if (fseek(LBM_file,size,SEEK_CUR)) + return 0; + return 1; +} + +// ------------------------- Attendre une section ------------------------- +byte LBM_Wait_for(byte * expected_section) +{ + // Valeur retournée: 1=Section trouvée, 0=Section non trouvée (erreur) + byte section_read[4]; + + if (! Read_bytes(LBM_file,section_read,4)) + return 0; + while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouvée + { + if (!LBM_Skip_section()) + return 0; if (! Read_bytes(LBM_file,section_read,4)) return 0; - while (memcmp(section_read,expected_section,4)) // Sect. pas encore trouvée - { - if (!Read_dword_be(LBM_file,&Taille_section)) - return 0; - if (Taille_section&1) - Taille_section++; - if (fseek(LBM_file,Taille_section,SEEK_CUR)) - return 0; - if (! Read_bytes(LBM_file,section_read,4)) - return 0; - } - return 1; } + return 1; +} // Les images ILBM sont stockés en bitplanes donc on doit trifouiller les bits pour // en faire du chunky @@ -509,7 +535,7 @@ void Load_LBM(T_IO_Context * context) byte temp_byte; short b256; dword nb_colors; - dword image_size; + dword section_size; short x_pos; short y_pos; short counter; @@ -531,7 +557,7 @@ void Load_LBM(T_IO_Context * context) Read_bytes(LBM_file,section,4); Read_dword_be(LBM_file,&dummy); Read_bytes(LBM_file,format,4); - if (!Wait_for((byte *)"BMHD")) + if (!LBM_Wait_for((byte *)"BMHD")) File_error=1; Read_dword_be(LBM_file,&dummy); @@ -551,7 +577,7 @@ void Load_LBM(T_IO_Context * context) && (Read_word_be(LBM_file,&header.Y_screen)) && header.Width && header.Height) { - if ( (header.BitPlanes) && (Wait_for((byte *)"CMAP")) ) + if ( (header.BitPlanes) && (LBM_Wait_for((byte *)"CMAP")) ) { Read_dword_be(LBM_file,&nb_colors); nb_colors/=3; @@ -604,16 +630,73 @@ void Load_LBM(T_IO_Context * context) if (Read_byte(LBM_file,&temp_byte)) File_error=2; - if ( (Wait_for((byte *)"BODY")) && (!File_error) ) + // Keep reading sections until we find the body + while (1) { - Read_dword_be(LBM_file,&image_size); - //swab((char *)&header.Width ,(char *)&context->Width,2); - //swab((char *)&header.Height,(char *)&context->Height,2); + if (! Read_bytes(LBM_file,section,4)) + { + File_error=2; + break; + } + // Found body : stop searching + if (!memcmp(section,"BODY",4)) + break; + else if (!memcmp(section,"CRNG",4)) + { + // Handle CRNG + + // The content of a CRNG is as follows: + word padding; + word rate; + word flags; + byte min_col; + byte max_col; + // + if ( (Read_dword_be(LBM_file,§ion_size)) + && (Read_word_be(LBM_file,&padding)) + && (Read_word_be(LBM_file,&rate)) + && (Read_word_be(LBM_file,&flags)) + && (Read_byte(LBM_file,&min_col)) + && (Read_byte(LBM_file,&max_col))) + { + if (section_size == 8 && min_col != max_col) + { + // Valid cycling range + if (max_colCycle_range[context->Color_cycles].Start=min_col; + context->Cycle_range[context->Color_cycles].End=max_col; + context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; + context->Cycle_range[context->Color_cycles].Speed=(flags&1) ? rate/78 : 0; + + context->Color_cycles++; + } + } + else + { + File_error=2; + break; + } + } + else + { + // ignore any number of unknown sections + if (!LBM_Skip_section()) + { + File_error=2; + break; + } + } + + } + + if ( !File_error ) + { + Read_dword_be(LBM_file,§ion_size); context->Width = header.Width; context->Height = header.Height; - //swab((char *)&header.X_screen,(char *)&Original_screen_X,2); - //swab((char *)&header.Y_screen,(char *)&Original_screen_Y,2); Original_screen_X = header.X_screen; Original_screen_Y = header.Y_screen; @@ -874,6 +957,7 @@ void Save_LBM(T_IO_Context * context) byte temp_byte; word real_width; int file_size; + int i; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); @@ -890,7 +974,6 @@ void Save_LBM(T_IO_Context * context) // On corrige la largeur de l'image pour qu'elle soit multiple de 2 real_width=context->Width+(context->Width&1); - //swab((byte *)&real_width,(byte *)&header.Width,2); header.Width=context->Width; header.Height=context->Height; header.X_org=0; @@ -923,7 +1006,23 @@ void Save_LBM(T_IO_Context * context) Write_dword_be(LBM_file,sizeof(T_Palette)); Write_bytes(LBM_file,context->Palette,sizeof(T_Palette)); - + + for (i=0; iColor_cycles; i++) + { + word flags=0; + flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not + flags|= context->Cycle_range[i].Inverse?2:0; // Inverted + + Write_bytes(LBM_file,"CRNG",4); + Write_dword_be(LBM_file,8); // Section size + Write_word_be(LBM_file,0); // Padding + Write_word_be(LBM_file,context->Cycle_range[i].Speed*78); // Rate + Write_word_be(LBM_file,flags); // Flags + Write_byte(LBM_file,context->Cycle_range[i].Start); // Min color + Write_byte(LBM_file,context->Cycle_range[i].End); // Max color + // No padding, size is multiple of 2 + } + Write_bytes(LBM_file,"BODY",4); Write_dword_be(LBM_file,0); // On mettra la taille à jour à la fin @@ -948,8 +1047,8 @@ void Save_LBM(T_IO_Context * context) file_size=File_length(filename); LBM_file=fopen(filename,"rb+"); - fseek(LBM_file,820,SEEK_SET); - Write_dword_be(LBM_file,file_size-824); + fseek(LBM_file,820+context->Color_cycles*16,SEEK_SET); + Write_dword_be(LBM_file,file_size-824-context->Color_cycles*16); if (!File_error) { @@ -1554,7 +1653,6 @@ void Save_BMP(T_IO_Context * context) //////////////////////////////////// GIF //////////////////////////////////// -#pragma pack(1) typedef struct { word Width; // Width of the complete image area @@ -1573,7 +1671,6 @@ typedef struct byte Indicator; // Misc image information byte Nb_bits_pixel; // Nb de bits par pixel } T_GIF_IDB; // Image Descriptor Block -#pragma pack() typedef struct { @@ -1735,7 +1832,7 @@ void Load_GIF(T_IO_Context * context) word color_index; // index de traitement d'une couleur byte size_to_read; // Nombre de données à lire (divers) byte block_identifier; // Code indicateur du type de bloc en cours - word initial_nb_bits; // Nb de bits au début du traitement LZW + byte initial_nb_bits; // Nb de bits au début du traitement LZW word special_case=0; // Mémoire pour le cas spécial word old_code=0; // Code précédent word byte_read; // Sauvegarde du code en cours de lecture @@ -1787,8 +1884,6 @@ void Load_GIF(T_IO_Context * context) // Ordre de Classement = (LSDB.Aspect and $80) nb_colors=(1 << ((LSDB.Resol & 0x07)+1)); - initial_nb_bits=(LSDB.Resol & 0x07)+2; - if (LSDB.Resol & 0x80) { // Palette globale dispo: @@ -1796,24 +1891,12 @@ void Load_GIF(T_IO_Context * context) if (Config.Clear_palette) memset(context->Palette,0,sizeof(T_Palette)); - // On peut maintenant charger la nouvelle palette: - if (!(LSDB.Aspect & 0x80)) - // Palette dans l'ordre: - for(color_index=0;color_indexPalette[color_index].R)); - Read_byte(GIF_file,&(context->Palette[color_index].G)); - Read_byte(GIF_file,&(context->Palette[color_index].B)); - } - else + // Load the palette + for(color_index=0;color_indexPalette[color_index].R)); - for (color_index=0;color_indexPalette[color_index].G)); - for (color_index=0;color_indexPalette[color_index].B)); + Read_byte(GIF_file,&(context->Palette[color_index].R)); + Read_byte(GIF_file,&(context->Palette[color_index].G)); + Read_byte(GIF_file,&(context->Palette[color_index].B)); } } @@ -1924,6 +2007,57 @@ void Load_GIF(T_IO_Context * context) } } } + else if (!memcmp(aeb,"CRNG\0\0\0\0" "1.0",0x0B)) + { + // Color animation. Similar to a LBM CRNG chunk. + word rate; + word flags; + byte min_col; + byte max_col; + // + Read_byte(GIF_file,&size_to_read); + for(;size_to_read>0 && !File_error;size_to_read-=6) + { + if ( (Read_word_be(GIF_file,&rate)) + && (Read_word_be(GIF_file,&flags)) + && (Read_byte(GIF_file,&min_col)) + && (Read_byte(GIF_file,&max_col))) + { + if (min_col != max_col) + { + // Valid cycling range + if (max_colCycle_range[context->Color_cycles].Start=min_col; + context->Cycle_range[context->Color_cycles].End=max_col; + context->Cycle_range[context->Color_cycles].Inverse=(flags&2)?1:0; + context->Cycle_range[context->Color_cycles].Speed=(flags&1)?rate/78:0; + + context->Color_cycles++; + } + } + else + { + File_error=1; + } + } + // Read end-of-block delimiter + if (!File_error) + Read_byte(GIF_file,&size_to_read); + if (size_to_read!=0) + File_error=1; + } + else + { + // Unknown extension, skip. + Read_byte(GIF_file,&size_to_read); + while (size_to_read!=0 && !File_error) + { + fseek(GIF_file,size_to_read,SEEK_CUR); + Read_byte(GIF_file,&size_to_read); + } + } } else { @@ -1961,7 +2095,6 @@ void Load_GIF(T_IO_Context * context) && Read_word_le(GIF_file,&(IDB.Image_width)) && Read_word_le(GIF_file,&(IDB.Image_height)) && Read_byte(GIF_file,&(IDB.Indicator)) - && Read_byte(GIF_file,&(IDB.Nb_bits_pixel)) && IDB.Image_width && IDB.Image_height) { @@ -1974,42 +2107,38 @@ void Load_GIF(T_IO_Context * context) { // Palette locale dispo + if (Config.Clear_palette) + memset(context->Palette,0,sizeof(T_Palette)); + nb_colors=(1 << ((IDB.Indicator & 0x07)+1)); - initial_nb_bits=(IDB.Indicator & 0x07)+2; - - if (!(IDB.Indicator & 0x40)) - // Palette dans l'ordre: - for(color_index=0;color_indexPalette[color_index].R)); - Read_byte(GIF_file,&(context->Palette[color_index].G)); - Read_byte(GIF_file,&(context->Palette[color_index].B)); - } - else - { - // Palette triée par composantes: - for (color_index=0;color_indexPalette[color_index].R)); - for (color_index=0;color_indexPalette[color_index].G)); - for (color_index=0;color_indexPalette[color_index].B)); + // Load the palette + for(color_index=0;color_indexPalette[color_index].R)); + Read_byte(GIF_file,&(context->Palette[color_index].G)); + Read_byte(GIF_file,&(context->Palette[color_index].B)); } + } Palette_loaded(context); + + File_error=0; + if (!Read_byte(GIF_file,&(initial_nb_bits))) + File_error=1; - value_clr =nb_colors+0; - value_eof =nb_colors+1; - alphabet_free=nb_colors+2; - GIF_nb_bits =initial_nb_bits; + value_clr =(1<Palette,768)) + for(i=0;i<256 && !File_error;i++) + { + if (!Write_byte(GIF_file,context->Palette[i].R) + ||!Write_byte(GIF_file,context->Palette[i].G) + ||!Write_byte(GIF_file,context->Palette[i].B)) + File_error=1; + } + if (!File_error) { // La palette a été correctement écrite. - // Le jour où on se servira des blocks d'extensions pour placer - // des commentaires, on le fera ici. - // Ecriture de la transparence //Write_bytes(GIF_file,"\x21\xF9\x04\x01\x00\x00\xNN\x00",8); @@ -2275,6 +2408,26 @@ void Save_GIF(T_IO_Context * context) Write_byte(GIF_file,strlen(context->Comment)); Write_bytes(GIF_file,context->Comment,strlen(context->Comment)+1); } + // Write cycling colors + if (context->Color_cycles) + { + int i; + + Write_bytes(GIF_file,"\x21\xff\x0B" "CRNG\0\0\0\0" "1.0",14); + Write_byte(GIF_file,context->Color_cycles*6); + for (i=0; iColor_cycles; i++) + { + word flags=0; + flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not + flags|= context->Cycle_range[i].Inverse?2:0; // Inverted + + Write_word_be(GIF_file,context->Cycle_range[i].Speed*78); // Rate + Write_word_be(GIF_file,flags); // Flags + Write_byte(GIF_file,context->Cycle_range[i].Start); // Min color + Write_byte(GIF_file,context->Cycle_range[i].End); // Max color + } + Write_byte(GIF_file,0); + } // Loop on all layers for (current_layer=0; @@ -2282,7 +2435,7 @@ void Save_GIF(T_IO_Context * context) current_layer++) { // Write a Graphic Control Extension - char GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00"; + byte GCE_block[] = "\x21\xF9\x04\x04\x05\x00\x00\x00"; // 'Default' values: // Disposal method "Do not dispose" // Duration 5/100s (minimum viable value for current web browsers) @@ -2542,7 +2695,6 @@ void Save_GIF(T_IO_Context * context) //////////////////////////////////// PCX //////////////////////////////////// -#pragma pack(1) typedef struct { byte Manufacturer; // |_ Il font chier ces cons! Ils auraient pu @@ -2564,7 +2716,6 @@ typedef struct word Screen_Y; // | l'écran d'origine byte Filler[54]; // Ca... J'adore! } T_PCX_Header; -#pragma pack() T_PCX_Header PCX_header; @@ -3010,14 +3161,14 @@ void Save_PCX(T_IO_Context * context) Write_word_le(file,PCX_header.Y_max) && Write_word_le(file,PCX_header.X_dpi) && Write_word_le(file,PCX_header.Y_dpi) && - Write_bytes(file,&(PCX_header.Palette_16c),sizeof(PCX_header.Palette_16c)) && + Write_bytes(file,&(PCX_header.Palette_16c),48) && Write_bytes(file,&(PCX_header.Reserved),1) && Write_bytes(file,&(PCX_header.Plane),1) && Write_word_le(file,PCX_header.Bytes_per_plane_line) && Write_word_le(file,PCX_header.Palette_info) && Write_word_le(file,PCX_header.Screen_X) && Write_word_le(file,PCX_header.Screen_Y) && - Write_bytes(file,&(PCX_header.Filler),sizeof(PCX_header.Filler)) ) + Write_bytes(file,&(PCX_header.Filler),54) ) { line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; @@ -3102,7 +3253,7 @@ void Test_SCx(T_IO_Context * context) if ((file=fopen(filename, "rb"))) { // Lecture et vérification de la signature - if (Read_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1)) + if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) @@ -3138,7 +3289,7 @@ void Load_SCx(T_IO_Context * context) { file_size=File_length_file(file); - if (Read_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1)) + if (Read_bytes(file,SCx_header.Filler1,4) && Read_word_le(file, &(SCx_header.Width)) && Read_word_le(file, &(SCx_header.Height)) && Read_byte(file, &(SCx_header.Filler2)) @@ -3259,7 +3410,7 @@ void Save_SCx(T_IO_Context * context) SCx_header.Filler2=0xAF; SCx_header.Planes=0x00; - if (Write_bytes(file,SCx_header.Filler1,sizeof(SCx_header.Filler1)) + if (Write_bytes(file,SCx_header.Filler1,4) && Write_word_le(file, SCx_header.Width) && Write_word_le(file, SCx_header.Height) && Write_byte(file, SCx_header.Filler2) @@ -3294,6 +3445,44 @@ void Save_SCx(T_IO_Context * context) } } +//////////////////////////////////// XPM //////////////////////////////////// +void Save_XPM(T_IO_Context* context) +{ + FILE* file; + char filename[MAX_PATH_CHARACTERS]; + int i,j; + + Get_full_filename(filename, context->File_name, context->File_directory); + File_error = 0; + + file = fopen(filename, "w"); + if (file == NULL) + { + File_error = 1; + return; + } + + fprintf(file, "/* XPM */\nstatic char* pixmap[] = {\n"); + fprintf(file, "\"%d %d 256 2\",\n", context->Width, context->Height); + + for (i = 0; i < 256; i++) + { + fprintf(file,"\"%2.2X c #%2.2x%2.2x%2.2x\",\n", i, context->Palette[i].R, context->Palette[i].G, + context->Palette[i].B); + } + + for (j = 0; j < context->Height; j++) + { + fprintf(file, "\""); + for (i = 0; i < context->Width; i++) + { + fprintf(file, "%2.2X", Get_pixel(context, i, j)); + } + fprintf(file,"\"\n"); + } + + fclose(file); +} //////////////////////////////////// PNG //////////////////////////////////// @@ -3322,7 +3511,71 @@ void Test_PNG(T_IO_Context * context) fclose(file); } } + +/// Used by a callback in Load_PNG +T_IO_Context * PNG_current_context; + +int PNG_read_unknown_chunk(__attribute__((unused)) png_structp ptr, png_unknown_chunkp chunk) +{ + // png_unknown_chunkp members: + // png_byte name[5]; + // png_byte *data; + // png_size_t size; + if (!strcmp((const char *)chunk->name, "crNg")) + { + // Color animation. Similar to a LBM CRNG chunk. + unsigned int i; + byte *chunk_ptr = chunk->data; + + // Should be a multiple of 6 + if (chunk->size % 6) + return (-1); + + + for(i=0;isize/6 && i<16; i++) + { + word rate; + word flags; + byte min_col; + byte max_col; + + // Rate (big-endian word) + rate = *(chunk_ptr++) << 8; + rate |= *(chunk_ptr++); + + // Flags (big-endian) + flags = *(chunk_ptr++) << 8; + flags |= *(chunk_ptr++); + + // Min color + min_col = *(chunk_ptr++); + // Max color + max_col = *(chunk_ptr++); + + // Check validity + if (min_col != max_col) + { + // Valid cycling range + if (max_colCycle_range[i].Start=min_col; + PNG_current_context->Cycle_range[i].End=max_col; + PNG_current_context->Cycle_range[i].Inverse=(flags&2)?1:0; + PNG_current_context->Cycle_range[i].Speed=(flags&1) ? rate/78 : 0; + + PNG_current_context->Color_cycles=i+1; + } + } + + return (1); // >0 = success + } + return (0); /* did not recognize */ + +} + + png_bytep * Row_pointers; // -- Lire un fichier au format PNG ----------------------------------------- void Load_PNG(T_IO_Context * context) @@ -3360,6 +3613,7 @@ void Load_PNG(T_IO_Context * context) { png_byte color_type; png_byte bit_depth; + png_voidp user_chunk_ptr; // Setup a return point. If a pnglib loading error occurs // in this if(), the else will be executed. @@ -3368,11 +3622,18 @@ void Load_PNG(T_IO_Context * context) png_init_io(png_ptr, file); // Inform pnglib we already loaded the header. png_set_sig_bytes(png_ptr, 8); - + + // Hook the handler for unknown chunks + user_chunk_ptr = png_get_user_chunk_ptr(png_ptr); + png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr, &PNG_read_unknown_chunk); + // This is a horrid way to pass parameters, but we don't get + // much choice. PNG loader can't be reintrant. + PNG_current_context=context; + // Load file information png_read_info(png_ptr, info_ptr); - color_type = info_ptr->color_type; - bit_depth = info_ptr->bit_depth; + color_type = png_get_color_type(png_ptr,info_ptr); + bit_depth = png_get_bit_depth(png_ptr,info_ptr); // If it's any supported file // (Note: As of writing this, this test covers every possible @@ -3425,9 +3686,9 @@ void Load_PNG(T_IO_Context * context) } } if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) - Pre_load(context,info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1); + Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,PIXEL_SIMPLE,1); else - Pre_load(context, info_ptr->width,info_ptr->height,File_length_file(file),FORMAT_PNG,context->Ratio,0); + Pre_load(context,png_get_image_width(png_ptr,info_ptr),png_get_image_height(png_ptr,info_ptr),File_length_file(file),FORMAT_PNG,context->Ratio,0); if (File_error==0) { @@ -3535,8 +3796,8 @@ void Load_PNG(T_IO_Context * context) } } - context->Width=info_ptr->width; - context->Height=info_ptr->height; + context->Width=png_get_image_width(png_ptr,info_ptr); + context->Height=png_get_image_height(png_ptr,info_ptr); png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); @@ -3556,7 +3817,7 @@ void Load_PNG(T_IO_Context * context) // 8bpp for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes); + Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); @@ -3575,7 +3836,7 @@ void Load_PNG(T_IO_Context * context) // It's a preview // Unfortunately we need to allocate loads of memory for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*) malloc(info_ptr->rowbytes); + Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); row_pointers_allocated = 1; png_read_image(png_ptr, Row_pointers); @@ -3646,6 +3907,8 @@ void Save_PNG(T_IO_Context * context) byte * pixel_ptr; png_structp png_ptr; png_infop info_ptr; + png_unknown_chunk crng_chunk; + byte cycle_data[16*6]; // Storage for color-cycling data, referenced by crng_chunk Get_full_filename(filename, context->File_name, context->File_directory); File_error=0; @@ -3674,9 +3937,15 @@ void Save_PNG(T_IO_Context * context) { // Commentaires texte PNG // Cette partie est optionnelle + #ifdef PNG_iTXt_SUPPORTED + png_text text_ptr[2] = { + {-1, "Software", "Grafx2", 6, 0, NULL, NULL}, + {-1, "Title", NULL, 0, 0, NULL, NULL} + #else png_text text_ptr[2] = { {-1, "Software", "Grafx2", 6}, {-1, "Title", NULL, 0} + #endif }; int nb_text_chunks=1; if (context->Comment[0]) @@ -3710,7 +3979,58 @@ void Save_PNG(T_IO_Context * context) break; default: break; - } + } + // Write cycling colors + if (context->Color_cycles) + { + // Save a chunk called 'crNg' + // The case is selected by the following rules from PNG standard: + // char 1: non-mandatory = lowercase + // char 2: private (not standard) = lowercase + // char 3: reserved = always uppercase + // char 4: can be copied by editors = lowercase + + // First, turn our nice structure into byte array + // (just to avoid padding in structures) + + byte *chunk_ptr = cycle_data; + int i; + + for (i=0; iColor_cycles; i++) + { + word flags=0; + flags|= context->Cycle_range[i].Speed?1:0; // Cycling or not + flags|= context->Cycle_range[i].Inverse?2:0; // Inverted + + // Big end of Rate + *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) >> 8; + // Low end of Rate + *(chunk_ptr++) = (context->Cycle_range[i].Speed*78) & 0xFF; + + // Big end of Flags + *(chunk_ptr++) = (flags) >> 8; + // Low end of Flags + *(chunk_ptr++) = (flags) & 0xFF; + + // Min color + *(chunk_ptr++) = context->Cycle_range[i].Start; + // Max color + *(chunk_ptr++) = context->Cycle_range[i].End; + } + + // Build one unknown_chuck structure + memcpy(crng_chunk.name, "crNg",5); + crng_chunk.data=cycle_data; + crng_chunk.size=context->Color_cycles*6; + crng_chunk.location=PNG_HAVE_PLTE; + + // Give it to libpng + png_set_unknown_chunks(png_ptr, info_ptr, &crng_chunk, 1); + // libpng seems to ignore the location I provided earlier. + png_set_unknown_chunk_location(png_ptr, info_ptr, 0, PNG_HAVE_PLTE); + } + + png_write_info(png_ptr, info_ptr); /* ecriture des pixels de l'image */ diff --git a/src/filesel.c b/src/filesel.c index 738bd94c..6a24a71a 100644 --- a/src/filesel.c +++ b/src/filesel.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Franck Charlet Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud @@ -22,14 +23,22 @@ along with Grafx2; if not, see */ +#include + #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include #include #include #define isHidden(x) (0) + +#elif defined (__MINT__) + #include + #include + #define isHidden(x) (0) #elif defined(__WIN32__) #include #include + #include #define isHidden(x) (GetFileAttributesA((x)->d_name)&FILE_ATTRIBUTE_HIDDEN) #else #include @@ -62,12 +71,66 @@ #include "help.h" #include "filesel.h" -#define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de fichier non sélectionné -#define NORMAL_DIRECTORY_COLOR MC_Dark // color du texte pour une ligne de répertoire non sélectionné -#define NORMAL_BACKGROUND_COLOR MC_Black // color du fond pour une ligne non sélectionnée -#define SELECTED_FILE_COLOR MC_White // color du texte pour une ligne de fichier sélectionnée -#define SELECTED_DIRECTORY_COLOR MC_Light // color du texte pour une ligne de repértoire sélectionnée -#define SELECTED_BACKGROUND_COLOR MC_Dark // color du fond pour une ligne sélectionnée +#define NORMAL_FILE_COLOR MC_Light // color du texte pour une ligne de + // fichier non sélectionné +#define NORMAL_DIRECTORY_COLOR MC_Dark // color du texte pour une ligne de + // répertoire non sélectionné +#define NORMAL_BACKGROUND_COLOR MC_Black // color du fond pour une ligne + // non sélectionnée +#define SELECTED_FILE_COLOR MC_White // color du texte pour une ligne de + // fichier sélectionnée +#define SELECTED_DIRECTORY_COLOR MC_Light // color du texte pour une ligne de + // repértoire sélectionnée +#define SELECTED_BACKGROUND_COLOR MC_Dark // color du fond pour une ligne + // sélectionnée + +// -- Native fileselector for WIN32 + +// Returns 0 if all ok, something else if failed +byte Native_filesel(byte load) +{ + //load = load; +#ifdef __WIN32__ + OPENFILENAME ofn; + char szFileName[MAX_PATH] = ""; + SDL_SysWMinfo wminfo; + HWND hwnd; + + SDL_VERSION(&wminfo.version); + SDL_GetWMInfo(&wminfo); + hwnd = wminfo.window; + + ZeroMemory(&ofn, sizeof(ofn)); + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_EXPLORER; + if(load) ofn.Flags |= OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = "txt"; + + if(load) + { + if (GetOpenFileName(&ofn)) + // Do something usefull with the filename stored in szFileName + return 0; + else + // error - check if its just user pressing cancel or something else + return CommDlgExtendedError(); + } else if(GetSaveFileName(&ofn)) { + return 0; + } else { + // Check if cancel + return CommDlgExtendedError(); + } +#else + return 255; // fail ! +#endif +} + +// -- "Standard" fileselector for other platforms // -- Fileselector data @@ -86,7 +149,7 @@ static char Selector_filename[256]; void Recount_files(T_Fileselector *list) { T_Fileselector_item *item; - + list->Nb_files=0; list->Nb_directories=0; list->Nb_elements=0; @@ -146,30 +209,48 @@ void Free_fileselector_list(T_Fileselector *list) Recount_files(list); } -char * Format_filename(const char * fname, int type) +char * Format_filename(const char * fname, word max_length, int type) { - static char result[19]; + static char result[40]; int c; int other_cursor; int pos_last_dot; + // safety + if (max_length>40) + max_length=40; + if (strcmp(fname,PARENT_DIR)==0) { strcpy(result,"<-PARENT DIRECTORY"); + // Append spaces + for (c=18; c= 18) - result[17]=ELLIPSIS_CHARACTER; + if (c >= max_length-1) + result[max_length-2]=ELLIPSIS_CHARACTER; } else { - strcpy(result," . "); + // Initialize as all spaces + for (c = 0; c 13) + if (c > max_length-6) { - result[13]=ELLIPSIS_CHARACTER; + result[max_length-6]=ELLIPSIS_CHARACTER; break; } result[c]=fname[c]; @@ -190,7 +271,7 @@ char * Format_filename(const char * fname, int type) // Ensuite on recopie la partie qui suit le point (si nécessaire): if (pos_last_dot != -1) { - for (c = pos_last_dot+1,other_cursor=15;fname[c]!='\0' && other_cursor < 18;c++,other_cursor++) + for (c = pos_last_dot+1,other_cursor=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++) result[other_cursor]=fname[c]; } } @@ -199,25 +280,29 @@ char * Format_filename(const char * fname, int type) // -- Rajouter a la liste des elements de la liste un element --------------- -void Add_element_to_list(T_Fileselector *list, const char * fname, int type) +void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon) // Cette procedure ajoute a la liste chainee un fichier passé en argument. { - // Pointeur temporaire d'insertion + // Working element T_Fileselector_item * temp_item; - // On alloue de la place pour un nouvel element - temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)); + // Allocate enough room for one struct + the visible label + temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+strlen(short_name)); - // On met a jour le nouvel emplacement: - strcpy(temp_item->Short_name,Format_filename(fname, type)); - strcpy(temp_item->Full_name,fname); + // Initialize element + strcpy(temp_item->Short_name,short_name); + strcpy(temp_item->Full_name,full_name); temp_item->Type = type; + temp_item->Icon = icon; + // Doubly-linked temp_item->Next =list->First; temp_item->Previous=NULL; if (list->First!=NULL) list->First->Previous=temp_item; + + // Put new element at the beginning list->First=temp_item; } @@ -275,8 +360,25 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) // Après effacement, il ne reste ni fichier ni répertoire dans la liste // On lit tous les répertoires: + +#if defined (__MINT__) + static char path[1024]; + static char path2[1024]; + path[0]='\0'; + path2[0]='\0'; + + char currentDrive='A'; + currentDrive=currentDrive+Dgetdrv(); + + Dgetpath(path,0); + sprintf(path2,"%c:\%s",currentDrive,path); + + strcat(path2,PATH_SEPARATOR); + current_directory=opendir(path2); +#else current_path=getcwd(NULL,0); current_directory=opendir(current_path); +#endif while ((entry=readdir(current_directory))) { // On ignore le répertoire courant @@ -294,7 +396,7 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) !isHidden(entry))) { // On rajoute le répertoire à la liste - Add_element_to_list(list, entry->d_name, 1); + Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 1), 1, ICON_NONE); list->Nb_directories++; } else if (S_ISREG(Infos_enreg.st_mode) && //Il s'agit d'un fichier @@ -307,7 +409,7 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) if (Check_extension(entry->d_name, ext)) { // On rajoute le fichier à la liste - Add_element_to_list(list, entry->d_name, 0); + Add_element_to_list(list, entry->d_name, Format_filename(entry->d_name, 19, 0), 0, ICON_NONE); list->Nb_files++; // Stop searching ext=NULL; @@ -323,12 +425,35 @@ void Read_list_of_files(T_Fileselector *list, byte selected_format) } #if defined(__MORPHOS__) || defined(__AROS__) || defined (__amigaos4__) || defined(__amigaos__) - Add_element_to_list(list, "/",1); // on amiga systems, / means parent. And there is no .. + Add_element_to_list(list, "/", Format_filename("/",19,1), 1, ICON_NONE); // on amiga systems, / means parent. And there is no .. list->Nb_directories ++; +#elif defined (__MINT__) + T_Fileselector_item *item=NULL; + // check if ".." exists if not add it + // FreeMinT lists ".." already, but this is not so for TOS + // simply adding it will cause double PARENT_DIR under FreeMiNT + + bool bFound= false; + + for (item = list->First; (((item != NULL) && (bFound==false))); item = item->Next){ + if (item->Type == 1){ + if(strncmp(item->Full_name,"..",(sizeof(char)*2))==0) bFound=true; + } + } + + if(!bFound){ + Add_element_to_list(list, "..",1,Format_filename("/",19,1),ICON_NONE); // add if not present + list->Nb_directories ++; + } + #endif closedir(current_directory); +#if defined (__MINT__) + +#else free(current_path); +#endif current_path = NULL; Recount_files(list); @@ -375,7 +500,7 @@ void Read_list_of_drives(T_Fileselector *list) { bstrtostr( dl->dol_Name, tmp, 254 ); strcat( tmp, ":" ); - Add_element_to_list(list, tmp, 2 ); + Add_element_to_list(list, tmp, Format_filename(tmp, 19, 2), 2, ICON_NONE ); list->Nb_directories++; } UnLockDosList( LDF_VOLUMES | LDF_READ ); @@ -387,6 +512,8 @@ void Read_list_of_drives(T_Fileselector *list) int drive_bits = GetLogicalDrives(); int drive_index; int bit_index; + byte icon; + // Sous Windows, on a la totale, presque aussi bien que sous DOS: drive_index = 0; for (bit_index=0; bit_index<26 && drive_index<23; bit_index++) @@ -395,35 +522,51 @@ void Read_list_of_drives(T_Fileselector *list) { // On a ce lecteur, il faut maintenant déterminer son type "physique". // pour profiter des jolies icones de X-man. - int drive_type; char drive_path[]="A:\\"; // Cette API Windows est étrange, je dois m'y faire... drive_path[0]='A'+bit_index; switch (GetDriveType(drive_path)) { case DRIVE_CDROM: - drive_type=ICON_CDROM; + icon=ICON_CDROM; break; case DRIVE_REMOTE: - drive_type=ICON_NETWORK; + icon=ICON_NETWORK; break; case DRIVE_REMOVABLE: - drive_type=ICON_FLOPPY_3_5; + icon=ICON_FLOPPY_3_5; break; case DRIVE_FIXED: - drive_type=ICON_HDD; + icon=ICON_HDD; break; default: - drive_type=ICON_NETWORK; + icon=ICON_NETWORK; break; } drive_name[0]='A'+bit_index; - Add_element_to_list(list, drive_name,2); + Add_element_to_list(list, drive_name, Format_filename(drive_name,18,2), 2, icon); list->Nb_directories++; drive_index++; } } } + #elif defined(__MINT__) + char drive_name[]="A:\\"; + unsigned long drive_bits = Drvmap(); //get drive map bitfield + int drive_index; + int bit_index; + drive_index = 0; + for (bit_index=0; bit_index<32; bit_index++) + { + if ( (1 << bit_index) & drive_bits ) + { + drive_name[0]='A'+bit_index; + Add_element_to_list(list, drive_name,Format_filename(drive_name,19,2),2,ICON_NONE); + list->Nb_directories++; + drive_index++; + } + } + #else { //Sous les différents unix, on va mettre @@ -440,11 +583,11 @@ void Read_list_of_drives(T_Fileselector *list) #else char * home_dir = getenv("HOME"); #endif - Add_element_to_list(list, "/", 2); + Add_element_to_list(list, "/", Format_filename("/",19,2), 2, ICON_NONE); list->Nb_directories++; if(home_dir) { - Add_element_to_list(list, home_dir, 2); + Add_element_to_list(list, home_dir, Format_filename(home_dir, 19, 2), 2, ICON_NONE); list->Nb_directories++; } @@ -454,7 +597,7 @@ void Read_list_of_drives(T_Fileselector *list) { if(mount_points_list->me_dummy == 0 && strcmp(mount_points_list->me_mountdir,"/") && strcmp(mount_points_list->me_mountdir,"/home")) { - Add_element_to_list(list, mount_points_list->me_mountdir,2); + Add_element_to_list(list, mount_points_list->me_mountdir, Format_filename(mount_points_list->me_mountdir, 19, 2), 2, ICON_NONE); list->Nb_directories++; } next = mount_points_list -> me_next; @@ -473,6 +616,15 @@ void Read_list_of_drives(T_Fileselector *list) Recount_files(list); } +// Comparison of file names: +#ifdef WIN32 +// case-insensitive + #define FILENAME_COMPARE strcasecmp +#else +// case-sensitive + #define FILENAME_COMPARE strcmp +#endif + // -- Tri de la liste des fichiers et répertoires --------------------------- void Sort_list_of_files(T_Fileselector *list) @@ -514,7 +666,7 @@ void Sort_list_of_files(T_Fileselector *list) // Si les deux éléments sont de même type et que le nom du suivant // est plus petit que celui du courant -> need_swap else if ( (current_item->Type==next_item->Type) && - (strcmp(current_item->Full_name,next_item->Full_name)>0) ) + (FILENAME_COMPARE(current_item->Full_name,next_item->Full_name)>0) ) need_swap=1; @@ -640,7 +792,14 @@ void Display_file_list(T_Fileselector *list, short offset_first,short selector_o } // On affiche l'élément - Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); + if (current_item->Icon != ICON_NONE) + { + // Name preceded by an icon + Print_in_window(16,95+index*8,current_item->Short_name,text_color,background_color); + Window_display_icon_sprite(8,95+index*8,current_item->Icon); + } else + // Name without icon + Print_in_window(8,95+index*8,current_item->Short_name,text_color,background_color); // On passe à la ligne suivante selector_offset--; @@ -889,7 +1048,7 @@ void Prepare_and_display_filelist(short Position, short offset, T_Scroller_butto { button->Nb_elements=Filelist.Nb_elements; button->Position=Position; - Compute_slider_cursor_height(button); + Compute_slider_cursor_length(button); Window_draw_slider(button); // On efface les anciens noms de fichier: Window_rectangle(8-1,95-1,144+2,80+2,MC_Black); @@ -984,12 +1143,8 @@ short Find_file_in_fileselector(T_Fileselector *list, const char * fname) return close_match; } - -void Highlight_file(char * fname) +void Highlight_file(short index) { - short index; - - index=Find_file_in_fileselector(&Filelist, fname); if ((Filelist.Nb_elements<=10) || (index<5)) { @@ -1012,15 +1167,17 @@ void Highlight_file(char * fname) } -char * Find_filename_match(T_Fileselector *list, char * fname) +short Find_filename_match(T_Fileselector *list, char * fname) { - char * best_name_ptr; + short best_match; T_Fileselector_item * current_item; - byte matching_letters=0; - byte counter; - - best_name_ptr=NULL; + short item_number; + byte matching_letters=0; + byte counter; + best_match=-1; + item_number=0; + for (current_item=list->First; current_item!=NULL; current_item=current_item->Next) { if ( (!Config.Find_file_fast) @@ -1031,12 +1188,96 @@ char * Find_filename_match(T_Fileselector *list, char * fname) if (counter>matching_letters) { matching_letters=counter; - best_name_ptr=current_item->Full_name; + best_match=item_number; } } + item_number++; } - return best_name_ptr; + return best_match; +} + +// Quicksearch system +char quicksearch_filename[MAX_PATH_CHARACTERS]=""; + +void Reset_quicksearch(void) +{ + quicksearch_filename[0]='\0'; +} + +short Quicksearch(T_Fileselector *selector) +{ + int len; + short most_matching_item; + + // Autre => On se place sur le nom de fichier qui correspond + len=strlen(quicksearch_filename); + if (Key_ANSI>= ' ' && Key_ANSI < 255 && len<50) + { + quicksearch_filename[len]=Key_ANSI; + quicksearch_filename[len+1]='\0'; + most_matching_item=Find_filename_match(selector, quicksearch_filename); + if ( most_matching_item >= 0 ) + { + return most_matching_item; + } + *quicksearch_filename=0; + } + return -1; +} + +// Translated from Highlight_file +void Locate_list_item(T_List_button * list, T_Fileselector * selector, short selected_item) +{ + + // Safety bounds + if (selected_item<0) + selected_item=0; + else if (selected_item>=list->Scroller->Nb_elements) + selected_item=list->Scroller->Nb_elements-1; + + + if ((list->Scroller->Nb_elements<=list->Scroller->Nb_visibles) || (selected_item<(list->Scroller->Nb_visibles/2))) + { + list->List_start=0; + list->Cursor_position=selected_item; + } + else + { + if (selected_item>=list->Scroller->Nb_elements-(list->Scroller->Nb_visibles/2)) + { + list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; + list->Cursor_position=selected_item-list->List_start; + } + else + { + list->List_start=selected_item-(list->Scroller->Nb_visibles/2-1); + list->Cursor_position=(list->Scroller->Nb_visibles/2-1); + } + } +} + +int Quicksearch_list(T_List_button * list, T_Fileselector * selector) +{ + // Try Quicksearch + short selected_item=Quicksearch(selector); + if (selected_item>=0 && selected_item!=list->Cursor_position+list->List_start) + { + Locate_list_item(list, selector, selected_item); + + Hide_cursor(); + // Mise à jour du scroller + list->Scroller->Position=list->List_start; + Window_draw_slider(list->Scroller); + + Window_redraw_list(list); + Display_cursor(); + // Store the selected value as attribute2 + Window_attribute2=list->List_start + list->Cursor_position; + // Return the control ID of the list. + return list->Number; + } + return 0; } byte Button_Load_or_Save(byte load, T_IO_Context *context) @@ -1048,17 +1289,20 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) T_Dropdown_button * formats_dropdown; T_Dropdown_button * bookmark_dropdown[4]; short temp; + unsigned int format; int dummy=0; // Sert à appeler SDL_GetKeyState byte save_or_load_image=0; byte has_clicked_ok=0;// Indique si on a clické sur Load ou Save ou sur //un bouton enclenchant Load ou Save juste après. byte initial_back_color; // | fout en l'air (c'te conne). char previous_directory[MAX_PATH_CHARACTERS]; // Répertoire d'où l'on vient après un CHDIR - char quicksearch_filename[MAX_PATH_CHARACTERS]=""; char save_filename[MAX_PATH_CHARACTERS]; char initial_comment[COMMENT_SIZE+1]; - char * most_matching_filename; short window_shortcut; + + Reset_quicksearch(); + + // if (Native_filesel(load) != 0); // TODO : handle this if (context->Type == CONTEXT_MAIN_IMAGE) window_shortcut = load?(0x100+BUTTON_LOAD):(0x100+BUTTON_SAVE); @@ -1099,7 +1343,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) } // Affichage du commentaire if (Get_fileformat(Main_format)->Comment) - Print_in_window(47,70,context->Comment,MC_Black,MC_Light); + Print_in_window(45,70,context->Comment,MC_Black,MC_Light); } Window_set_normal_button(253,180,51,14,"Cancel",0,1,KEY_ESC); // 2 @@ -1124,11 +1368,11 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) Get_fileformat(Main_format)->Label, 1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 6 - for (temp=0; temp < NB_KNOWN_FORMATS; temp++) + for (format=0; format < Nb_known_formats(); format++) { - if ((load && (File_formats[temp].Identifier <= FORMAT_ALL_FILES || File_formats[temp].Load)) || - (!load && File_formats[temp].Save)) - Window_dropdown_add_item(formats_dropdown,File_formats[temp].Identifier,File_formats[temp].Label); + if ((load && (File_formats[format].Identifier <= FORMAT_ALL_FILES || File_formats[format].Load)) || + (!load && File_formats[format].Save)) + Window_dropdown_add_item(formats_dropdown,File_formats[format].Identifier,File_formats[format].Label); } Print_in_window(70,18,"Format",MC_Dark,MC_Light); @@ -1161,13 +1405,30 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On prend bien soin de passer dans le répertoire courant (le bon qui faut! Oui madame!) if (load) { + #if defined(__MINT__) + chdir(Main_current_directory); + static char path[1024]={0}; + Dgetpath(path,0); + strcat(path,PATH_SEPARATOR); + strcpy(Main_current_directory,path); + #else chdir(Main_current_directory); getcwd(Main_current_directory,256); + #endif } else { + #if defined(__MINT__) chdir(context->File_directory); + static char path[1024]={0}; + Dgetpath(path,0); + strcat(path,PATH_SEPARATOR); + strcpy(Main_current_directory,path); + #else getcwd(Main_current_directory,256); + #endif + + } // Affichage des premiers fichiers visibles: @@ -1181,7 +1442,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On affiche le nouveau nom de fichier Print_filename_in_fileselector(); - Highlight_file(context->File_name); + Highlight_file(Find_file_in_fileselector(&Filelist, context->File_name)); Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); } @@ -1309,7 +1570,8 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On vient de changer de nom de fichier, donc on doit s'appreter // a rafficher une preview New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); + } else { @@ -1322,7 +1584,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) has_clicked_ok=1; New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); } } Display_cursor(); @@ -1340,26 +1602,40 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) Display_file_list(&Filelist, Main_fileselector_position,Main_fileselector_offset); Display_cursor(); New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); break; - case 6 : // Scroller des formats - Hide_cursor(); - // On met à jour le format de browsing du fileselect: - Main_format=Window_attribute2; - // Comme on change de liste, on se place en début de liste: - Main_fileselector_position=0; - Main_fileselector_offset=0; - // Affichage des premiers fichiers visibles: - Reload_list_of_files(Main_format,file_scroller); - Display_cursor(); - New_preview_is_needed=1; - *quicksearch_filename=0; + case 6 : // Scroller des formats + // On met à jour le format de browsing du fileselect: + if (Main_format != Window_attribute2) { + char* savename = (char *)strdup(Selector_filename); + int nameLength = strlen(savename); + DEBUG(Selector_filename, 42); + Main_format = Window_attribute2; + // Comme on change de liste, on se place en début de liste: + Main_fileselector_position = 0; + Main_fileselector_offset = 0; + // Affichage des premiers fichiers visibles: + Hide_cursor(); + Reload_list_of_files(Main_format, file_scroller); + New_preview_is_needed = 1; + Reset_quicksearch(); + strcpy(Selector_filename, savename); + if (Get_fileformat(Main_format)->Default_extension[0] != '\0' && + Selector_filename[nameLength - 4] == '.') + { + strcpy(Selector_filename + nameLength - 3, + Get_fileformat(Main_format)->Default_extension); + } + free(savename); + Print_filename_in_fileselector(); + Display_cursor(); + } break; case 7 : // Saisie d'un commentaire pour la sauvegarde if ( (!load) && (Get_fileformat(Main_format)->Comment) ) { - Readline(45,70,context->Comment,32,0); + Readline(45, 70, context->Comment, 32, INPUT_TYPE_STRING); Display_cursor(); } break; @@ -1368,7 +1644,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // Save the filename strcpy(save_filename, Selector_filename); - if (Readline(82,48,Selector_filename,27,2)) + if (Readline(82,48,Selector_filename,27,INPUT_TYPE_FILENAME)) { // On regarde s'il faut rajouter une extension. C'est-à-dire s'il // n'y a pas de '.' dans le nom du fichier. @@ -1382,7 +1658,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) if(!Directory_exists(Selector_filename)) { strcat(Selector_filename, "."); - strcat(Selector_filename,Get_fileformat(Main_format)->Default_extension); + strcat(Selector_filename, Get_fileformat(Main_format)->Default_extension); } } else @@ -1438,7 +1714,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); Display_cursor(); New_preview_is_needed=1; - *quicksearch_filename=0; + Reset_quicksearch(); break; default: if (clicked_button>=10 && clicked_button<10+NB_BOOKMARKS) @@ -1451,11 +1727,10 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) case -1: // bouton lui-même: aller au répertoire mémorisé if (Config.Bookmark_directory[clicked_button-10]) { - *quicksearch_filename=0; strcpy(Selector_filename,Config.Bookmark_directory[clicked_button-10]); Selected_type=1; has_clicked_ok=1; - *quicksearch_filename=0; + Reset_quicksearch(); } break; @@ -1490,7 +1765,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) strcpy(bookmark_label, Config.Bookmark_label[clicked_button-10]); if (bookmark_label[7]==ELLIPSIS_CHARACTER) bookmark_label[7]='\0'; - if (Readline_ex(bookmark_dropdown[clicked_button-10]->Pos_X+3+10,bookmark_dropdown[clicked_button-10]->Pos_Y+2,bookmark_label,8,8,0,0)) + if (Readline_ex(bookmark_dropdown[clicked_button-10]->Pos_X+3+10,bookmark_dropdown[clicked_button-10]->Pos_Y+2,bookmark_label,8,8,INPUT_TYPE_STRING,0)) strcpy(Config.Bookmark_label[clicked_button-10],bookmark_label); Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); Display_cursor(); @@ -1515,63 +1790,63 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) { case SDLK_UNKNOWN : break; case SDLK_DOWN : // Bas - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_scroll_down(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_UP : // Haut - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_scroll_up(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEDOWN : // PageDown - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_PAGEUP : // PageUp - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Main_fileselector_position,&Main_fileselector_offset,9); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_END : // End - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_end(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_HOME : // Home - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_home(&Main_fileselector_position,&Main_fileselector_offset); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELDOWN : - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,3); Scroll_fileselector(file_scroller); Key=0; break; case KEY_MOUSEWHEELUP : - *quicksearch_filename=0; + Reset_quicksearch(); Hide_cursor(); Selector_page_up(&Main_fileselector_position,&Main_fileselector_offset,3); Scroll_fileselector(file_scroller); Key=0; break; case SDLK_BACKSPACE : // Backspace - *quicksearch_filename=0; + Reset_quicksearch(); // Si le choix ".." est bien en tête des propositions... if (!strcmp(Filelist.First->Full_name,PARENT_DIR)) { @@ -1585,6 +1860,8 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) default: if (clicked_button<=0) { + short selected_item; + if (Is_shortcut(Key,0x100+BUTTON_HELP)) { Window_help(load?BUTTON_LOAD:BUTTON_SAVE, NULL); @@ -1595,30 +1872,22 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) clicked_button=2; break; } - // Autre => On se place sur le nom de fichier qui correspond - temp=strlen(quicksearch_filename); - if (Key_ANSI>= ' ' && Key_ANSI < 255 && temp<50) + + selected_item=Quicksearch(&Filelist); + if (selected_item>=0) { - quicksearch_filename[temp]=Key_ANSI; - quicksearch_filename[temp+1]='\0'; - most_matching_filename=Find_filename_match(&Filelist, quicksearch_filename); - if ( (most_matching_filename) ) - { temp=Main_fileselector_position+Main_fileselector_offset; Hide_cursor(); - Highlight_file(most_matching_filename); + Highlight_file(selected_item); Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); Display_cursor(); if (temp!=Main_fileselector_position+Main_fileselector_offset) New_preview_is_needed=1; - } - else - *quicksearch_filename=0; - Key=0; } + // Key=0; ? } else - *quicksearch_filename=0; + Reset_quicksearch(); } if (has_clicked_ok) @@ -1643,13 +1912,20 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On doit rentrer dans le répertoire: if (!chdir(Selector_filename)) { + #if defined (__MINT__) + static char path[1024]={0}; + char currentDrive='A'; + currentDrive=currentDrive+Dgetdrv(); + Dgetpath(path,0); + sprintf(Main_current_directory,"%c:\%s",currentDrive,path); + #else getcwd(Main_current_directory,256); - + #endif // On lit le nouveau répertoire Read_list_of_files(&Filelist, Main_format); Sort_list_of_files(&Filelist); // On place la barre de sélection sur le répertoire d'où l'on vient - Highlight_file(previous_directory); + Highlight_file(Find_file_in_fileselector(&Filelist, previous_directory)); } else Error(0); @@ -1659,7 +1935,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) New_preview_is_needed=1; // On est dans un nouveau répertoire, donc on remet le quicksearch à 0 - *quicksearch_filename=0; + Reset_quicksearch(); } else // Sinon on essaye de charger ou sauver le fichier { @@ -1681,7 +1957,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // On efface le commentaire précédent Window_rectangle(45,70,32*8,8,MC_Light); // On nettoie la zone où va s'afficher la preview: - Window_rectangle(183,95,120,80,MC_Light); + Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // On efface les dimensions de l'image Window_rectangle(143,59,72,8,MC_Light); // On efface la taille du fichier @@ -1697,7 +1973,7 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context) // Un update pour couvrir les 4 zones: 3 libellés plus le commentaire Update_window_area(45,48,256,30); // Zone de preview - Update_window_area(183,95,120,80); + Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); } New_preview_is_needed=0; diff --git a/src/filesel.h b/src/filesel.h index 3fd1fddb..19b6f777 100644 --- a/src/filesel.h +++ b/src/filesel.h @@ -31,12 +31,12 @@ byte Button_Load_or_Save(byte load, T_IO_Context *context); -void Add_element_to_list(T_Fileselector *list, const char * fname, int type); +void Add_element_to_list(T_Fileselector *list, const char * full_name, const char *short_name, int type, byte icon); /// /// Formats a display name for a file, directory, or similar name (drive, volume). -/// The returned value is a pointer to a single static buffer of 19 characters +/// The returned value is a pointer to a single static buffer of maximum 40 characters /// including the '\\0'. -char * Format_filename(const char * fname, int type); +char * Format_filename(const char * fname, word max_length, int type); void Free_fileselector_list(T_Fileselector *list); @@ -48,4 +48,10 @@ T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); short Find_file_in_fileselector(T_Fileselector *list, const char * fname); +void Locate_list_item(T_List_button * list, T_Fileselector * selector, short selected_item); + +int Quicksearch_list(T_List_button * list, T_Fileselector * selector); + +void Reset_quicksearch(void); + #endif diff --git a/src/global.h b/src/global.h index 086e227d..3746126b 100644 --- a/src/global.h +++ b/src/global.h @@ -73,6 +73,12 @@ GFX2_GLOBAL byte MC_Light; ///< Index of color to use as "light grey" in the GUI GFX2_GLOBAL byte MC_White; ///< Index of color to use as "white" in the GUI menus. GFX2_GLOBAL byte MC_Trans; ///< Index of color to use as "transparent" while loading the GUI file. +GFX2_GLOBAL byte MC_OnBlack; ///< Index of color immediately lighter than "black" in the GUI menus. +GFX2_GLOBAL byte MC_Window; ///< Index of color to use as window background in the GUI menus. +GFX2_GLOBAL byte MC_Lighter; ///< Index of color lighter than window in the GUI menus. +GFX2_GLOBAL byte MC_Darker; ///< Index of color darker than window in the GUI menus. + + // Input state GFX2_GLOBAL word Mouse_X; ///< Current mouse cursor position. GFX2_GLOBAL word Mouse_Y; ///< Current mouse cursor position. @@ -294,10 +300,6 @@ GFX2_GLOBAL short Main_image_height; GFX2_GLOBAL short Main_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Main_offset_Y; -/// Backup of ::Main_offset_X, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_main_offset_X; -/// Backup of ::Main_offset_Y, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_main_offset_Y; /// Name of the directory that holds the image currently edited. GFX2_GLOBAL char Main_file_directory[1024]; /// Filename (without directory) of the image currently edited. @@ -364,10 +366,6 @@ GFX2_GLOBAL short Spare_image_height; GFX2_GLOBAL short Spare_offset_X; /// Y position (in image space) of the pixel to display in the top left corner of screen. GFX2_GLOBAL short Spare_offset_Y; -/// Backup of ::Main_offset_X, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_spare_offset_X; -/// Backup of ::Main_offset_Y, used to store it while the magnifier is open. -GFX2_GLOBAL short Old_spare_offset_Y; /// Name of the directory that holds the image currently edited as spare page. GFX2_GLOBAL char Spare_file_directory[MAX_PATH_CHARACTERS]; /// Filename (without directory) of the image currently edited as spare page. @@ -432,8 +430,16 @@ GFX2_GLOBAL T_List_of_pages * Spare_backups; // -- Brush data -/// Pixel data of the current brush. +/// Pixel data of the current brush (remapped). GFX2_GLOBAL byte * Brush; +/// Pixel data of the current brush (before remap). +GFX2_GLOBAL byte * Brush_original_pixels; +/// Palette of the brush, from when it was grabbed. +GFX2_GLOBAL T_Palette Brush_original_palette; +/// Back_color used when the brush was grabbed +GFX2_GLOBAL byte Brush_original_back_color; +/// Color mapping from ::Brush_original_pixels to ::Brush +GFX2_GLOBAL byte Brush_colormap[256]; /// X coordinate of the brush's "hot spot". It is < ::Brush_width GFX2_GLOBAL word Brush_offset_X; /// Y coordinate of the brush's "hot spot". It is < ::Brush_height @@ -492,9 +498,9 @@ GFX2_GLOBAL word Menu_palette_cell_width; GFX2_GLOBAL T_Menu_Bar Menu_bars[MENUBAR_COUNT] #ifdef GLOBAL_VARIABLES = -{{MENU_WIDTH, 9, 1, 45, NULL, 20, BUTTON_HIDE }, // Status - {MENU_WIDTH, 10, 1, 35, NULL, 144, BUTTON_LAYER_SELECT }, // Layers - {MENU_WIDTH, 35, 1, 0, NULL, 254, BUTTON_CHOOSE_COL }} // Main +{{MENU_WIDTH, 9, 1, 45, {NULL,NULL,NULL}, 20, BUTTON_HIDE }, // Status + {MENU_WIDTH, 10, 1, 35, {NULL,NULL,NULL}, 144, BUTTON_LAYER_SELECT }, // Layers + {MENU_WIDTH, 35, 1, 0, {NULL,NULL,NULL}, 254, BUTTON_CHOOSE_COL }} // Main #endif ; @@ -510,71 +516,59 @@ GFX2_GLOBAL word Menu_Y_before_window; /// Backup of ::Paintbrush_hidden, used to store it while a window is open. GFX2_GLOBAL byte Paintbrush_hidden_before_window; -GFX2_GLOBAL word Window_stack_pos_X[8]; +/// The global stack of editor screens. +GFX2_GLOBAL T_Window Window_stack[8]; + /// Position of the left border of the topmost window (in screen coordinates) -#define Window_pos_X Window_stack_pos_X[Windows_open-1] +#define Window_pos_X Window_stack[Windows_open-1].Pos_X -GFX2_GLOBAL word Window_stack_pos_Y[8]; /// Position of the top border of the topmost window (in screen coordinates) -#define Window_pos_Y Window_stack_pos_Y[Windows_open-1] +#define Window_pos_Y Window_stack[Windows_open-1].Pos_Y -GFX2_GLOBAL word Window_stack_width[8]; /// /// Width of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_X to get screen pixels) -#define Window_width Window_stack_width[Windows_open-1] +#define Window_width Window_stack[Windows_open-1].Width -GFX2_GLOBAL word Window_stack_height[8]; /// /// Height of the topmost window, in "window pixels" /// (multiply by ::Menu_factor_Y to get screen pixels) -#define Window_height Window_stack_height[Windows_open-1] +#define Window_height Window_stack[Windows_open-1].Height -GFX2_GLOBAL word Window_stack_nb_buttons[8]; /// Total number of buttons/controls in the topmost window. -#define Window_nb_buttons Window_stack_nb_buttons[Windows_open-1] +#define Window_nb_buttons Window_stack[Windows_open-1].Nb_buttons -GFX2_GLOBAL T_Normal_button * Window_stack_normal_button_list[8]; /// List of normal buttons in the topmost window. -#define Window_normal_button_list Window_stack_normal_button_list[Windows_open-1] +#define Window_normal_button_list Window_stack[Windows_open-1].Normal_button_list -GFX2_GLOBAL T_Palette_button * Window_stack_palette_button_list[8]; /// List of "palette" buttons in the topmost window. -#define Window_palette_button_list Window_stack_palette_button_list[Windows_open-1] +#define Window_palette_button_list Window_stack[Windows_open-1].Palette_button_list -GFX2_GLOBAL T_Scroller_button * Window_stack_scroller_button_list[8]; /// List of sliders (scrollers) in the topmost window. -#define Window_scroller_button_list Window_stack_scroller_button_list[Windows_open-1] +#define Window_scroller_button_list Window_stack[Windows_open-1].Scroller_button_list -GFX2_GLOBAL T_Special_button * Window_stack_special_button_list[8]; /// List of special buttons in the topmost window. -#define Window_special_button_list Window_stack_special_button_list[Windows_open-1] +#define Window_special_button_list Window_stack[Windows_open-1].Special_button_list -GFX2_GLOBAL T_Dropdown_button * Window_stack_dropdown_button_list[8]; /// List of dropdown buttons in the topmost window. -#define Window_dropdown_button_list Window_stack_dropdown_button_list[Windows_open-1] +#define Window_dropdown_button_list Window_stack[Windows_open-1].Dropdown_button_list -GFX2_GLOBAL T_List_button * Window_stack_list_button_list[8]; /// List of list buttons in the topmost window. -#define Window_list_button_list Window_stack_list_button_list[Windows_open-1] +#define Window_list_button_list Window_stack[Windows_open-1].List_button_list - - -GFX2_GLOBAL int Window_stack_attribute1[8]; /// /// The function ::Window_clicked_button() set this to ::LEFT_SIDE or ::RIGHT_SIDE /// after a button is activated through left or right mouse click. -#define Window_attribute1 Window_stack_attribute1[Windows_open-1] +#define Window_attribute1 Window_stack[Windows_open-1].Attribute1 -GFX2_GLOBAL int Window_stack_attribute2[8]; /// /// The function ::Window_clicked_button() set this to return extra information: /// - When a scroller was clicked: the scroller position (0-n) /// - When a palette was clicked: the color index (0-255) /// - When a dropdown was used: the selected item's number T_Dropdown_choice::Number -#define Window_attribute2 Window_stack_attribute2[Windows_open-1] - +#define Window_attribute2 Window_stack[Windows_open-1].Attribute2 +#define Window_draggable Window_stack[Windows_open-1].Draggable /// Definition of the menu (toolbox) @@ -587,6 +581,7 @@ GFX2_GLOBAL struct word Height; ///< Button's active heigth byte Pressed; ///< Button is currently pressed byte Shape; ///< Shape, listed in enum ::BUTTON_SHAPES + char Icon; ///< Which icon to display: Either the one from the toolbar (-1) or one of ::MENU_SPRITE // Triggers on mouse/keyboard Func_action Left_action; ///< Action triggered by a left mouseclick on the button @@ -765,6 +760,8 @@ GFX2_GLOBAL long Gradient_bounds_range; GFX2_GLOBAL long Gradient_total_range; /// Amount of randomness to use in gradient (1-256+) GFX2_GLOBAL long Gradient_random_factor; +/// Gradient speed of cycling (0-64) +GFX2_GLOBAL byte Gradient_speed; /// Pointer to a gradient function, depending on the selected method. GFX2_GLOBAL Func_gradient Gradient_function; /// @@ -772,10 +769,10 @@ GFX2_GLOBAL Func_gradient Gradient_function; /// either ::Pixel (if the gradient must be drawn on menus only) /// or ::Display_pixel (if the gradient must be drawn on the image) GFX2_GLOBAL Func_pixel Gradient_pixel; -/// Settings for all gradients -GFX2_GLOBAL T_Gradient_array Gradient_array[16]; /// Index in ::Gradient_array of the currently selected gradient. GFX2_GLOBAL byte Current_gradient; +/// Boolean, true when the color cycling is active. +GFX2_GLOBAL byte Cycling_mode; // -- Airbrush data @@ -823,6 +820,9 @@ GFX2_GLOBAL byte * Menu_font; /// Pointer to the current active skin. GFX2_GLOBAL T_Gui_skin * Gfx; +/// Pointer to the current active skin. +GFX2_GLOBAL T_Paintbrush Paintbrush[NB_PAINTBRUSH_SPRITES]; + // -- Help data /// Index of the ::Help_section shown by the Help screen. @@ -894,6 +894,7 @@ GFX2_GLOBAL T_Brush_template Brush_container[BRUSH_CONTAINER_COLUMNS*BRUSH_CONTA CURSOR_SHAPE_XOR_TARGET , // Stretch brush CURSOR_SHAPE_TARGET , // Distort brush CURSOR_SHAPE_XOR_TARGET , // Gradient-filled rectangle + CURSOR_SHAPE_COLORPICKER , // Colorpick on right mouse button }; #else /// ::Cursor_shape to use for each operation. @@ -950,34 +951,83 @@ GFX2_GLOBAL SDL_Joystick* Joystick; /// It was chosen to not conflict with any SDL key number. #define KEY_JOYBUTTON (SDLK_LAST+4) -/// Button definitions for the gp2x -#define GP2X_BUTTON_UP (0) -#define GP2X_BUTTON_DOWN (4) -#define GP2X_BUTTON_LEFT (2) -#define GP2X_BUTTON_RIGHT (6) -#define GP2X_BUTTON_UPLEFT (1) -#define GP2X_BUTTON_UPRIGHT (7) -#define GP2X_BUTTON_DOWNLEFT (3) -#define GP2X_BUTTON_DOWNRIGHT (5) -#define GP2X_BUTTON_CLICK (18) -#define GP2X_BUTTON_A (12) -#define GP2X_BUTTON_B (13) -#define GP2X_BUTTON_Y (14) -#define GP2X_BUTTON_X (15) -#define GP2X_BUTTON_L (10) -#define GP2X_BUTTON_R (11) -#define GP2X_BUTTON_START (8) -#define GP2X_BUTTON_SELECT (9) -#define GP2X_BUTTON_VOLUP (16) -#define GP2X_BUTTON_VOLDOWN (17) +/// The joystick axis are {X,Y} - on all platforms so far. +/// If there is ever a platform where they are reversed, put +/// these lines in each platform "case" below. +#define JOYSTICK_AXIS_X (0) +#define JOYSTICK_AXIS_Y (1) -#ifdef __gp2x__ - #define KEY_ESC (KEY_JOYBUTTON+GP2X_BUTTON_X) +#ifdef __GP2X__ + + #define JOYSTICK_THRESHOLD (4096) + + /// Button definitions for the gp2x + #define JOY_BUTTON_UP (0) + #define JOY_BUTTON_DOWN (4) + #define JOY_BUTTON_LEFT (2) + #define JOY_BUTTON_RIGHT (6) + #define JOY_BUTTON_UPLEFT (1) + #define JOY_BUTTON_UPRIGHT (7) + #define JOY_BUTTON_DOWNLEFT (3) + #define JOY_BUTTON_DOWNRIGHT (5) + #define JOY_BUTTON_CLICK (18) + #define JOY_BUTTON_A (12) + #define JOY_BUTTON_B (13) + #define JOY_BUTTON_Y (14) + #define JOY_BUTTON_X (15) + #define JOY_BUTTON_L (10) + #define JOY_BUTTON_R (11) + #define JOY_BUTTON_START (8) + #define JOY_BUTTON_SELECT (9) + #define JOY_BUTTON_VOLUP (16) + #define JOY_BUTTON_VOLDOWN (17) + + #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) +#elif defined(__WIZ__) + /// Button definitions for the Wiz + #define JOY_BUTTON_UP (0) + #define JOY_BUTTON_DOWN (4) + #define JOY_BUTTON_LEFT (2) + #define JOY_BUTTON_RIGHT (6) + #define JOY_BUTTON_UPLEFT (1) + #define JOY_BUTTON_UPRIGHT (7) + #define JOY_BUTTON_DOWNLEFT (3) + #define JOY_BUTTON_DOWNRIGHT (5) + #define JOY_BUTTON_L (10) + #define JOY_BUTTON_R (11) + #define JOY_BUTTON_A (12) + #define JOY_BUTTON_B (13) + #define JOY_BUTTON_X (14) + #define JOY_BUTTON_Y (15) + #define JOY_BUTTON_MENU (8) + #define JOY_BUTTON_SELECT (9) + #define JOY_BUTTON_VOLUP (16) + #define JOY_BUTTON_VOLDOWN (17) + + #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_X) +#elif defined (__CAANOO__) + + #define JOYSTICK_THRESHOLD (4096) + + /// Button definitions for the Caanoo + #define JOY_BUTTON_A (0) + #define JOY_BUTTON_X (1) + #define JOY_BUTTON_B (2) + #define JOY_BUTTON_Y (3) + #define JOY_BUTTON_L (4) + #define JOY_BUTTON_R (5) + #define JOY_BUTTON_HOME (6) + #define JOY_BUTTON_HOLD (7) + #define JOY_BUTTON_I (8) + #define JOY_BUTTON_II (9) + #define JOY_BUTTON_JOY (10) + + #define KEY_ESC (KEY_JOYBUTTON+JOY_BUTTON_HOME) #else /// /// This is the key identifier for ESC. When hard-coding keyboard shortcuts /// for buttons, etc. we use this instead of SDLK_ESCAPE, - /// so the GP2X port can get a joybutton equivalent of it. + /// so the console ports can get a joybutton equivalent of it. #define KEY_ESC SDLK_ESCAPE #endif diff --git a/src/graph.c b/src/graph.c index c393ebc0..d2d09ae4 100644 --- a/src/graph.c +++ b/src/graph.c @@ -48,12 +48,13 @@ #include "pxquad.h" #include "windows.h" #include "input.h" +#include "brush.h" #ifdef __VBCC__ #define __attribute__(x) #endif -#if defined(__VBCC__)||defined(__GP2X__) +#if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) #define M_PI 3.141592653589793238462643 #endif @@ -522,6 +523,8 @@ try_again: Menu_factor_Y=1; break; default: // Stay below some reasonable size + if (factor>Max(Pixel_width,Pixel_height)) + factor/=Max(Pixel_width,Pixel_height); Menu_factor_X=Min(factor,abs(Config.Ratio)); Menu_factor_Y=Min(factor,abs(Config.Ratio)); } @@ -617,7 +620,8 @@ void Resize_image(word chosen_width,word chosen_height) // |B| | C = Nouvelle image // +-+-+ - if (Backup_with_new_dimensions(1,Main_backups->Pages->Nb_layers,chosen_width,chosen_height)) + Upload_infos_page_main(Main_backups->Pages); + if (Backup_with_new_dimensions(chosen_width,chosen_height)) { // La nouvelle page a pu être allouée, elle est pour l'instant pleine de // 0s. Elle fait Main_image_width de large. @@ -672,13 +676,16 @@ void Remap_spare(void) // ne seront pas utilisées par Remap_general_lowlevel. for (color=0;color<=255;color++) if (used[color]) - used[color]=Best_color(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B); + used[color]=Best_color_perceptual(Spare_palette[color].R,Spare_palette[color].G,Spare_palette[color].B); // Maintenant qu'on a une super table de conversion qui n'a que le nom // qui craint un peu, on peut faire l'échange dans la brosse de toutes les // teintes. for (layer=0; layerPages->Nb_layers; layer++) - Remap_general_lowlevel(used,Spare_backups->Pages->Image[layer],Spare_image_width,Spare_image_height,Spare_image_width); + Remap_general_lowlevel(used,Spare_backups->Pages->Image[layer],Spare_backups->Pages->Image[layer],Spare_image_width,Spare_image_height,Spare_image_width); + + // Change transparent color index + Spare_backups->Pages->Transparent_color=used[Spare_backups->Pages->Transparent_color]; } @@ -687,43 +694,89 @@ void Get_colors_from_brush(void) { short x_pos; // Variable de balayage de la brosse short y_pos; // Variable de balayage de la brosse - byte used[256]; // Tableau de booléens "La couleur est utilisée" + byte brush_used[256]; // Tableau de booléens "La couleur est utilisée" + dword usage[256]; int color; + int image_color; - if (Confirmation_box("Modify current palette ?")) + //if (Confirmation_box("Modify current palette ?")) + + // Backup with unchanged layers, only palette is modified + Backup_layers(0); + + // Init array of new colors + for (color=0;color<=255;color++) + brush_used[color]=0; + + // Tag used colors + for (y_pos=0;y_pos= Permanent_draw_next_refresh) { Permanent_draw_next_refresh = now+100; diff --git a/src/help.c b/src/help.c index 9fcf976e..7ce41b18 100644 --- a/src/help.c +++ b/src/help.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -31,6 +32,10 @@ #include #elif defined (__linux__) #include +#elif defined (__MINT__) + #include + #include + #include #endif #include "const.h" @@ -92,7 +97,7 @@ void Redefine_control(word *shortcut, int x_pos, int y_pos) Display_cursor(); while (1) { - while(!Get_input())SDL_Delay(20); + Get_input(20); if (Key==KEY_ESC) return; if (Key!=0) @@ -231,22 +236,102 @@ void Window_set_shortcut(int action_id) Display_cursor(); } -// -- Menu d'aide ----------------------------------------------------------- - -void Display_help(void) +/// +/// Print a line with the 'help' (6x8) font. +short Print_help(short x_pos, short y_pos, const char *line, char line_type, short link_position, short link_size) { + short width; // Largeur physique d'une ligne de texte short x; // Indices d'affichage d'un caractère short y; short x_position; // Parcours de remplissage du buffer de ligne - short line_index; // 0-15 (16 lignes de textes) short char_index; // Parcours des caractères d'une ligne - short start_line=Help_position; + byte * char_pixel; short repeat_menu_x_factor; short repeat_menu_y_factor; short real_x_pos; short real_y_pos; - byte * char_pixel; - short width; // Largeur physique d'une ligne de texte + + real_x_pos=ToWinX(x_pos); + real_y_pos=ToWinY(y_pos); + + // Calcul de la taille + width=strlen(line); + // Les lignes de titres prennent plus de place + if (line_type == 'T' || line_type == '-') + width = width*2; + + // Pour chaque ligne dans la fenêtre: + for (y=0;y<8;y++) + { + x_position=0; + // On crée une nouvelle ligne à splotcher + for (char_index=0;char_index'_' || line[char_index/2]<' ') + char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré + else if (char_index & 1) + char_pixel=&(Gfx->Help_font_t2[(unsigned char)(line[char_index/2])-' '][0][0]); + else + char_pixel=&(Gfx->Help_font_t1[(unsigned char)(line[char_index/2])-' '][0][0]); + } + else if (line_type=='-') + { + if (line[char_index/2]>'_' || line[char_index/2]<' ') + char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré + else if (char_index & 1) + char_pixel=&(Gfx->Help_font_t4[(unsigned char)(line[char_index/2])-' '][0][0]); + else + char_pixel=&(Gfx->Help_font_t3[(unsigned char)(line[char_index/2])-' '][0][0]); + } + else if (line_type=='S') + char_pixel=&(Gfx->Bold_font[(unsigned char)(line[char_index])][0][0]); + else if (line_type=='N' || line_type=='K') + char_pixel=&(Gfx->Help_font_norm[(unsigned char)(line[char_index])][0][0]); + else + char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Un garde-fou en cas de probleme + + for (x=0;x<6;x++) + for (repeat_menu_x_factor=0;repeat_menu_x_factor=link_position + && char_index<(link_position+link_size)) + { + if (color == MC_Light) + color=MC_White; + else if (color == MC_Dark) + color=MC_Light; + else if (y<7) + color=MC_Dark; + } + Horizontal_line_buffer[x_position++]=color; + while (repetition--) + Horizontal_line_buffer[x_position++]=color; + } + } + // On la splotche + for (repeat_menu_y_factor=0;repeat_menu_y_factor= Help_section[Current_help_section].Length) { - Block (real_x_pos, - real_y_pos, - 44*6*Menu_factor_X, + Window_rectangle (x_pos, + y_pos + line_index*8, + 44*6, // 44 = Nb max de char (+1 pour éviter les plantages en mode X // causés par une largeur = 0) - (Menu_factor_Y<<3) * (16 - line_index), + (16 - line_index)*8, MC_Black); break; } @@ -307,83 +390,16 @@ void Display_help(void) line = buffer; } - // Calcul de la taille - width=strlen(line); - // Les lignes de titres prennent plus de place - if (line_type == 'T' || line_type == '-') - width = width*2; - - // Pour chaque ligne dans la fenêtre: - for (y=0;y<8;y++) - { - x_position=0; - // On crée une nouvelle ligne à splotcher - for (char_index=0;char_index'_' || line[char_index/2]<' ') - char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré - else if (char_index & 1) - char_pixel=&(Gfx->Help_font_t2[(unsigned char)(line[char_index/2])-' '][0][0]); - else - char_pixel=&(Gfx->Help_font_t1[(unsigned char)(line[char_index/2])-' '][0][0]); - } - else if (line_type=='-') - { - if (line[char_index/2]>'_' || line[char_index/2]<' ') - char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Caractère pas géré - else if (char_index & 1) - char_pixel=&(Gfx->Help_font_t4[(unsigned char)(line[char_index/2])-' '][0][0]); - else - char_pixel=&(Gfx->Help_font_t3[(unsigned char)(line[char_index/2])-' '][0][0]); - } - else if (line_type=='S') - char_pixel=&(Gfx->Bold_font[(unsigned char)(line[char_index])][0][0]); - else if (line_type=='N' || line_type=='K') - char_pixel=&(Gfx->Help_font_norm[(unsigned char)(line[char_index])][0][0]); - else - char_pixel=&(Gfx->Help_font_norm['!'][0][0]); // Un garde-fou en cas de probleme - - for (x=0;x<6;x++) - for (repeat_menu_x_factor=0;repeat_menu_x_factor=link_position - && char_index<(link_position+link_size)) - { - if (color == MC_Light) - color=MC_White; - else if (color == MC_Dark) - color=MC_Light; - else if (y<7) - color=MC_Dark; - } - Horizontal_line_buffer[x_position++]=color; - while (repetition--) - Horizontal_line_buffer[x_position++]=color; - } - } - // On la splotche - for (repeat_menu_y_factor=0;repeat_menu_y_factorPosition=Help_position; - Compute_slider_cursor_height(scroller); + Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); Display_help(); Display_cursor(); @@ -510,7 +526,7 @@ void Window_help(int section, const char *sub_section) nb_lines=Help_section[Current_help_section].Length; scroller->Position=0; scroller->Nb_elements=nb_lines; - Compute_slider_cursor_height(scroller); + Compute_slider_cursor_length(scroller); Window_draw_slider(scroller); } else @@ -627,7 +643,51 @@ void Button_Stats(void) Print_in_window(10,35,"Build options:",STATS_TITLE_COLOR,MC_Black); Print_in_window(146,35,TrueType_is_supported()?"TTF fonts":"no TTF fonts",STATS_DATA_COLOR,MC_Black); +#if defined (__MINT__) + // Affichage de la mémoire restante + Print_in_window(10,43,"Free memory: ",STATS_TITLE_COLOR,MC_Black); + freeRam=0; + char helpBuf[64]; + + unsigned long STRAM,TTRAM; + Atari_Memory_free(&STRAM,&TTRAM); + freeRam=STRAM+TTRAM; + buffer[0]='\0'; + + if(STRAM > (100*1024*1024)) + sprintf(helpBuf,"ST:%u Mb ",(unsigned int)(STRAM/(1024*1024))); + else if(freeRam > 100*1024) + sprintf(helpBuf,"ST:%u Kb ",(unsigned int)(STRAM/1024)); + else + sprintf(helpBuf,"ST:%u b ",(unsigned int)STRAM); + + strncat(buffer,helpBuf,sizeof(char)*37); + + if(TTRAM > (100ULL*1024*1024*1024)) + sprintf(helpBuf,"TT:%u Gb",(unsigned int)(TTRAM/(1024*1024*1024))); + else if(TTRAM > (100*1024*1024)) + sprintf(helpBuf,"TT:%u Mb",(unsigned int)(TTRAM/(1024*1024))); + else if(freeRam > 100*1024) + sprintf(helpBuf,"TT:%u Kb",(unsigned int)(TTRAM/1024)); + else + sprintf(helpBuf,"TT:%u b",(unsigned int)TTRAM); + + strncat(buffer,helpBuf,sizeof(char)*37); + + if(freeRam > (100ULL*1024*1024*1024)) + sprintf(helpBuf,"(%u Gb)",(unsigned int)(freeRam/(1024*1024*1024))); + else if(freeRam > (100*1024*1024)) + sprintf(helpBuf,"(%u Mb)",(unsigned int)(freeRam/(1024*1024))); + else if(freeRam > 100*1024) + sprintf(helpBuf,"(%u Kb)",(unsigned int)(freeRam/1024)); + else + sprintf(helpBuf,"(%u b)",(unsigned int)freeRam); + strncat(buffer,helpBuf,sizeof(char)*37); + + Print_in_window(18,51,buffer,STATS_DATA_COLOR,MC_Black); + +#else // Affichage de la mémoire restante Print_in_window(10,51,"Free memory: ",STATS_TITLE_COLOR,MC_Black); @@ -641,8 +701,12 @@ void Button_Stats(void) sprintf(buffer,"%u Kilobytes",(unsigned int)(freeRam/1024)); else sprintf(buffer,"%u bytes",(unsigned int)freeRam); + Print_in_window(114,51,buffer,STATS_DATA_COLOR,MC_Black); + #endif + + // Used memory Print_in_window(10,59,"Used memory pages: ",STATS_TITLE_COLOR,MC_Black); if(Stats_pages_memory > (100LL*1024*1024*1024)) @@ -670,6 +734,14 @@ void Button_Stats(void) statfs(Main_current_directory,&disk_info); mem_size=(qword) disk_info.f_bfree * (qword) disk_info.f_bsize; } +#elif defined (__MINT__) + _DISKINFO drvInfo; + mem_size=0; + Dfree(&drvInfo,0); + //number of free clusters*sectors per cluster*bytes per sector; + // reports current drive + mem_size=drvInfo.b_free*drvInfo.b_clsiz*drvInfo.b_secsiz; + #else // Free disk space is only for shows. Other platforms can display 0. #warning "Missing code for your platform !!! Check and correct please :)" diff --git a/src/help.h b/src/help.h index 14c866d0..aca208bd 100644 --- a/src/help.h +++ b/src/help.h @@ -46,5 +46,17 @@ void Button_Stats(void); */ void Window_help(int section, const char * sub_section); +/// Opens a window where you can change a shortcut key(s). +void Window_set_shortcut(int action_id); + +/// +/// Print a line with the 'help' (6x8) font. +short Print_help(short x_pos, short y_pos, const char *line, char line_type, short link_position, short link_size); + +// Nom de la touche actuallement assignée à un raccourci d'après son numéro +// de type 0x100+BOUTON_* ou SPECIAL_* +const char * Keyboard_shortcut_value(word shortcut_number); + + #endif diff --git a/src/helpfile.h b/src/helpfile.h index 5e246059..fdeb8a8f 100644 --- a/src/helpfile.h +++ b/src/helpfile.h @@ -62,7 +62,11 @@ static const T_Help_table helptable_about[] = HELP_BOLD (" \"Dragon's Layers\" Edition") HELP_BOLD (" THE ULTIMATE MULTI-RESOLUTION GFX EDITOR") HELP_TEXT (" http://grafx2.googlecode.com") +#if defined(__MINT__) + HELP_TEXT (" atari build ") +#else HELP_TEXT ("") +#endif HELP_TEXT ("Copyright 2007-2010, the Grafx2 project team") HELP_TEXT (" Copyright 1996-2001, SUNSET DESIGN") }; @@ -156,6 +160,7 @@ static const T_Help_table helptable_help[] = HELP_LINK ("Filled polyform: %s", 0x200+BUTTON_POLYFILL) HELP_LINK ("Gradient rectangle: %s", 0x100+BUTTON_GRADRECT) HELP_LINK ("Gradation menu: %s", 0x200+BUTTON_GRADRECT) + HELP_LINK ("Toggle color cycling:%s", SPECIAL_CYCLE_MODE) HELP_LINK ("Spheres: %s", 0x100+BUTTON_SPHERES) HELP_LINK ("Gradient ellipses: %s", 0x200+BUTTON_SPHERES) HELP_LINK ("Adjust picture: %s", 0x100+BUTTON_ADJUST) @@ -204,6 +209,10 @@ static const T_Help_table helptable_help[] = HELP_LINK ("Distort brush: %s", SPECIAL_DISTORT) HELP_LINK ("Outline brush: %s", SPECIAL_OUTLINE) HELP_LINK ("Nibble brush: %s", SPECIAL_NIBBLE) + HELP_LINK ("Double brush size: %s", SPECIAL_BRUSH_DOUBLE) + HELP_LINK ("Halve brush size: %s", SPECIAL_BRUSH_HALVE) + HELP_LINK ("Double brush width: %s", SPECIAL_BRUSH_DOUBLE_WIDTH) + HELP_LINK ("Double brush height: %s", SPECIAL_BRUSH_DOUBLE_HEIGHT) HELP_LINK ("Get brush colors: %s", SPECIAL_GET_BRUSH_COLORS) HELP_LINK ("Recolorize brush: %s", SPECIAL_RECOLORIZE_BRUSH) HELP_LINK ("Rotate brush: %s", SPECIAL_ROTATE_ANY_ANGLE) @@ -228,6 +237,18 @@ static const T_Help_table helptable_help[] = HELP_LINK (" 18:1 %s", SPECIAL_ZOOM_18) HELP_LINK (" 20:1 %s", SPECIAL_ZOOM_20) HELP_LINK ("Brush effects menu: %s", 0x100+BUTTON_BRUSH_EFFECTS) + HELP_LINK ("Brush factory: %s", 0x200+BUTTON_BRUSH_EFFECTS) + HELP_LINK ("Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) + HELP_LINK ("Run script #1: %s", SPECIAL_RUN_SCRIPT_1) + HELP_LINK ("Run script #2: %s", SPECIAL_RUN_SCRIPT_2) + HELP_LINK ("Run script #3: %s", SPECIAL_RUN_SCRIPT_3) + HELP_LINK ("Run script #4: %s", SPECIAL_RUN_SCRIPT_4) + HELP_LINK ("Run script #5: %s", SPECIAL_RUN_SCRIPT_5) + HELP_LINK ("Run script #6: %s", SPECIAL_RUN_SCRIPT_6) + HELP_LINK ("Run script #7: %s", SPECIAL_RUN_SCRIPT_7) + HELP_LINK ("Run script #8: %s", SPECIAL_RUN_SCRIPT_8) + HELP_LINK ("Run script #9: %s", SPECIAL_RUN_SCRIPT_9) + HELP_LINK ("Run script #10: %s", SPECIAL_RUN_SCRIPT_10) HELP_LINK ("Text: %s", 0x100+BUTTON_TEXT) HELP_LINK ("Resolution menu: %s", 0x100+BUTTON_RESOL) HELP_LINK ("Safety resolution: %s", 0x200+BUTTON_RESOL) @@ -424,6 +445,14 @@ static const T_Help_table helptable_credits[] = HELP_TEXT ("") HELP_TEXT (" Luc Schrijvers (Begasus)") HELP_TEXT ("") + HELP_BOLD (" WIZ & CAANOO PORT") + HELP_TEXT ("") + HELP_TEXT (" Alexander Filyanov (PheeL)") + HELP_TEXT ("") + HELP_BOLD (" ATARI PORT") + HELP_TEXT ("") + HELP_TEXT (" Pawel Goralski (Saulot)") + HELP_TEXT ("") HELP_TEXT ("") HELP_TEXT (" ... made it work on your favourite toaster") HELP_TEXT ("") @@ -432,17 +461,18 @@ static const T_Help_table helptable_credits[] = //HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") HELP_TEXT (" anibiqme blumunkee BDCIron ") HELP_TEXT (" Ced DawnBringer El Topo ") - HELP_TEXT (" falenblood fano fogbot121 ") - HELP_TEXT (" Frost Grimmy grknsngn ") + HELP_TEXT (" falenblood fanickbux fano ") + HELP_TEXT (" fogbot121 Frost Grimmy ") HELP_TEXT (" Gürkan Sengün Hatch HoraK-FDF ") HELP_TEXT (" iLKke Iw2evk Jamon ") HELP_TEXT (" keito kusma Lord Graga ") HELP_TEXT (" Lorenzo Gatti MagerValp maymunbeyin ") HELP_TEXT (" mind MooZ Pasi Kallinen ") - HELP_TEXT (" the Peach petter richienyhus ") - HELP_TEXT (" tape.wyrm TeeEmCee tempest ") + HELP_TEXT (" the Peach petter PheeL ") + HELP_TEXT (" richienyhus sm4tik spratek ") + HELP_TEXT (" tape.yrm TeeEmCee tempest ") HELP_TEXT (" Timo Kurrpa titus^Rab Tobé ") - HELP_TEXT (" yakumo9275 00ai99") + HELP_TEXT (" yakumo2975 00ai99") HELP_TEXT ("") HELP_TEXT (" ... posted the annoying bug reports.") HELP_TEXT ("") @@ -631,9 +661,25 @@ static const T_Help_table helptable_paintbrush[] = HELP_TEXT ("brush size by using the keys:") HELP_LINK ("Reduce : %s", SPECIAL_SMALLER_PAINTBRUSH) HELP_LINK ("Increase : %s", SPECIAL_BIGGER_PAINTBRUSH) - HELP_TEXT ("The last 3 paintbrushes in the menu belong") - HELP_TEXT ("to the \"miscellaneous\" family and their size") - HELP_TEXT ("cannot be modified.") + HELP_TEXT ("") + HELP_TEXT ("Other brushes are bitmaps, their size can't") + HELP_TEXT ("be adjusted.") + HELP_TEXT ("") + HELP_TEXT ("Click with left mouse button to choose a ") + HELP_TEXT ("paintbrush, and right mouse button to store") + HELP_TEXT ("your current brush in the slot. If your") + HELP_TEXT ("current brush is a grabbed brush, it will") + HELP_TEXT ("store a monochrome version of it, maximum") + HELP_TEXT ("15x15. (See below 'Brush container' to store") + HELP_TEXT ("backups of a big brush)") + HELP_TEXT ("The stored brushes are saved when you exit") + HELP_TEXT ("the program.") + HELP_TEXT ("") + HELP_TEXT ("The 'Preset' button allows you to pick a") + HELP_TEXT ("brush from any family. It's useful if you've") + HELP_TEXT ("overwritten all normal slots with brushes") + HELP_TEXT ("that you use more often.") + HELP_TEXT ("") HELP_TEXT ("") HELP_BOLD ("BRUSH CONTAINER") HELP_TEXT ("") @@ -1123,6 +1169,27 @@ static const T_Help_table helptable_grad_rect[] = HELP_TEXT ("- Index scroller: Defines the current") HELP_TEXT ("gradation among a set of 16 that will be") HELP_TEXT ("memorised.") + HELP_TEXT ("") + HELP_BOLD ("COLOR CYCLING") + HELP_TEXT ("") + HELP_TEXT ("These options allow you to use animation of") + HELP_TEXT ("colors: Grafx2 will shift palette entries") + HELP_TEXT ("at real-time. Note that only the LBM file") + HELP_TEXT ("format can record these settings, and very") + HELP_TEXT ("few image viewers will play it back.") + HELP_TEXT ("") + HELP_TEXT ("- Cycling: Activates or desactivates the") + HELP_TEXT ("cycling of colors when you're in the editor.") + HELP_LINK ("Key: %s", SPECIAL_CYCLE_MODE) + HELP_TEXT ("") + HELP_TEXT ("- Speed: Sets the speed for the cycling of") + HELP_TEXT ("this range. Zero means this range doesn't") + HELP_TEXT ("cycle. With 1, the range shifts 0.2856 times") + HELP_TEXT ("per second; at speed 64 it's 18.28 times") + HELP_TEXT ("per second. The program activates cycling") + HELP_TEXT ("while you hold the speed slider, so you can") + HELP_TEXT ("preview the speed.") + HELP_TEXT ("") }; static const T_Help_table helptable_spheres[] = { @@ -1253,15 +1320,17 @@ static const T_Help_table helptable_brush_fx[] = HELP_TEXT ("point at coordinates inferior to the ones of") HELP_TEXT ("the first point, the brush will be inverted.") HELP_TEXT ("Meanwhile, you can press the following keys") - HELP_TEXT ("whose effects are: 'D' : double the") - HELP_TEXT ("brush in X and Y 'H' : reduce the") - HELP_TEXT ("brush by half in X and Y 'X' : double") - HELP_TEXT ("the brush in X 'Shift+X': reduce the brush") - HELP_TEXT ("by half in X 'Y' : double the brush") - HELP_TEXT ("in Y 'Shift+Y': reduce the brush by half") - HELP_TEXT ("in Y 'N' : restore the normal size of") - HELP_TEXT ("the brush (can be useful") - HELP_TEXT ("because it's the only way for cancelling)") + HELP_TEXT ("whose effects are:") + HELP_TEXT (" 'D' : Double the brush") + HELP_TEXT (" 'H' : Reduce the brush by half") + HELP_TEXT (" 'X' : Double the brush in X") + HELP_TEXT (" 'Shift+X': Reduce the brush by half in X") + HELP_TEXT (" 'Y' : Double the brush in Y") + HELP_TEXT (" 'Shift+Y': Reduce the brush by half in Y") + HELP_TEXT (" 'N' : Restore the normal size of the") + HELP_TEXT (" brush (can be useful because") + HELP_TEXT (" it's the only way for") + HELP_TEXT (" cancelling)") HELP_TEXT ("") HELP_LINK ("- Distort: (Key:%s)",SPECIAL_DISTORT) HELP_TEXT ("Triggers an interactive operation") @@ -1312,6 +1381,8 @@ static const T_Help_table helptable_brush_fx[] = HELP_TEXT ("") HELP_TITLE("BRUSH FACTORY") HELP_TEXT ("") + HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH_EFFECTS) + HELP_TEXT ("") HELP_TEXT ("This menu allows you to run scripts. Scripts") HELP_TEXT ("are written in the Lua language, and allow") HELP_TEXT ("you to modify the brush (hence the name") @@ -1331,6 +1402,8 @@ static const T_Help_table helptable_brush_fx[] = HELP_TEXT ("time you open the window. Scripts are loaded") HELP_TEXT ("from disk when you run them.") HELP_TEXT ("") + HELP_LINK ("- Repeat last script: %s", SPECIAL_REPEAT_SCRIPT) + HELP_TEXT ("") }; static const T_Help_table helptable_effects[] = { @@ -2273,6 +2346,13 @@ static const T_Help_table helptable_settings_details[] = HELP_TEXT ("variants of your original palette, resulting") HELP_TEXT ("in a pretty grid !") HELP_TEXT ("") + HELP_BOLD (" Sync views") + HELP_TEXT ("When this mode is active, scrolling the view") + HELP_TEXT ("(and the magnifier view) affects both the") + HELP_TEXT ("main image and the spare page - as long as") + HELP_TEXT ("they have the same dimensions.") + HELP_TEXT ("") + HELP_TEXT ("") HELP_TEXT ("") HELP_TITLE("INPUT") HELP_TEXT ("") @@ -2323,6 +2403,14 @@ static const T_Help_table helptable_settings_details[] = HELP_TEXT ("GrafX2 to recognize them as a combo.") HELP_TEXT ("") HELP_TEXT ("") + HELP_BOLD (" Swap buttons") + HELP_TEXT ("This setting determines which key inverts") + HELP_TEXT ("the mouse buttons when it's held : A left") + HELP_TEXT ("click is then interpreted as a right-click.") + HELP_TEXT ("It's especially useful for one-button") + HELP_TEXT ("controllers, such as touchscreens and") + HELP_TEXT ("tablets.") + HELP_TEXT ("") HELP_TITLE("EDITING") HELP_TEXT ("") HELP_TEXT ("") @@ -2359,7 +2447,14 @@ static const T_Help_table helptable_settings_details[] = HELP_TEXT ("window. (Set it to 'no' if you have a slow") HELP_TEXT ("computer or if you edit huge pictures)") HELP_TEXT ("") - HELP_TEXT ("") + HELP_BOLD (" Right click colorpick") + HELP_TEXT ("This enables a mode where the right mouse") + HELP_TEXT ("buttons acts as a color picker until") + HELP_TEXT ("it's released, and selects Foreground color.") + HELP_TEXT ("This mode prevents you from painting with") + HELP_TEXT ("Background color.") + HELP_TEXT ("This option is ignored when the Shade,") + HELP_TEXT ("Quick-shade, or Tiling mode is used.") }; static const T_Help_table helptable_clear[] = @@ -2474,16 +2569,28 @@ static const T_Help_table helptable_palette[] = HELP_TEXT ("- Gauges: Allow you to modify the") HELP_TEXT ("current selection.") HELP_TEXT ("") + HELP_TEXT ("- RGB or HSL above the gauges: Switches") + HELP_TEXT ("between RGB and HSL color spaces. In HSL") + HELP_TEXT ("mode, the three sliders allow you to set the") + HELP_TEXT ("Hue (tint), Saturation (from grayscale to") + HELP_TEXT ("pure color) and Lightness (from black to") + HELP_TEXT ("white).") + HELP_TEXT ("") + HELP_TEXT ("- numbers below the gauges: Allows you to") + HELP_TEXT ("type in a new color in hexadecimal RRGGBB") + HELP_TEXT ("or RGB: ie. to get blue, you can type either") + HELP_TEXT ("0000ff or 00f.") + HELP_TEXT ("") HELP_TEXT ("- \"+\" and \"-\": Allow you to lighten or") HELP_TEXT ("darken the current selection.") HELP_TEXT ("") - HELP_TEXT ("- Default: Restores the predifined GrafX2") + HELP_TEXT ("- Preset: Restores the predefined GrafX2") HELP_TEXT ("palette.") HELP_TEXT ("") HELP_TEXT ("- Gray: Transforms the current selection") HELP_TEXT ("into its gray-scaled equivalent.") HELP_TEXT ("") - HELP_TEXT ("- Negative: Transforms the current selection") + HELP_TEXT ("- Neg: Transforms the current selection") HELP_TEXT ("into its reverse video equivalent.") HELP_TEXT ("") HELP_TEXT ("- Invert: Swaps the colors of the current") @@ -2520,18 +2627,12 @@ static const T_Help_table helptable_palette[] = HELP_TEXT ("whole palette it will sort this range.") HELP_TEXT ("") HELP_TEXT ("- Used: Indicates the number of colors used") - HELP_TEXT ("in the picture.") + HELP_TEXT ("in the picture and opens a histogram screen.") HELP_TEXT ("") HELP_TEXT ("- Zap unused: Erases the unused colors with") HELP_TEXT ("copies of the current selection. (The") HELP_TEXT ("keyboard shortcut for this button is ).") HELP_TEXT ("") - HELP_TEXT ("- HSL: Switches between RGB and HSL color") - HELP_TEXT ("spaces. In HSL mode, the three sliders") - HELP_TEXT ("allow you to set the Hue (tint), Saturation") - HELP_TEXT ("(from grayscale to pure color) and") - HELP_TEXT ("Lightness (from black to white).") - HELP_TEXT ("") HELP_TEXT ("- Reduce: Allows you to reduce the palette") HELP_TEXT ("to the number of colors you want (and") HELP_TEXT ("modifies the picture).") diff --git a/src/hotkeys.c b/src/hotkeys.c index 46150eb7..302b5644 100644 --- a/src/hotkeys.c +++ b/src/hotkeys.c @@ -884,7 +884,16 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "", true, SDLK_u, // U - 0}, + // Secondary shortcut is button I on the Caanoo, L on the Wiz, unset on others + #if defined (__CAANOO__) + (KEY_JOYBUTTON+JOY_BUTTON_I) + #elif defined (__WIZ__) + (KEY_JOYBUTTON+JOY_BUTTON_L) + #else + 0 + #endif + // -- + }, {103, "Redo", "Redo the last undone action.", @@ -892,7 +901,16 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "", true, SDLK_u|MOD_SHIFT, // Shift + U - 0}, + // Secondary shortcut is button II on the Caanoo, R on the Wiz, unset on others + #if defined (__CAANOO__) + (KEY_JOYBUTTON+JOY_BUTTON_II) + #elif defined (__WIZ__) + (KEY_JOYBUTTON+JOY_BUTTON_R) + #else + 0 + #endif + // -- + }, {133, "Kill", "Kills the current page. It actually", @@ -924,7 +942,17 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { "confirmation is asked.", false, SDLK_q, // Q (A en AZERTY) - 0}, + // Secondary shortcut is button Home on the Caanoo, Menu on the Wiz, unset on others + #if defined (__CAANOO__) + (KEY_JOYBUTTON+JOY_BUTTON_HOME) + #elif defined (__WIZ__) + (KEY_JOYBUTTON+JOY_BUTTON_MENU) + #else + 0 + #endif + // -- + + }, {107, "Palette menu", "Opens a menu which allows you to", @@ -1478,13 +1506,149 @@ T_Key_config ConfigKey[NB_SHORTCUTS] = { SDLK_HOME|MOD_ALT, // Alt + Home 0}, {181, + "Brush factory", + "Opens a window where you can run a", + "Lua script.", + "", + true, + 0, // No shortcut + 0}, + {182, + "Repeat script", + "Re-run the last script selected", + "in the Brush factory window.", + "", + true, + 0, // No shortcut + 0}, + {183, + "Double brush size", + "Resizes the current user brush", + "by doubling width and height.", + "", + true, + SDLK_h|MOD_SHIFT, // Shift+H + 0}, + {184, + "Double brush width", + "Resizes the current user brush", + "by doubling its width.", + "", + true, + SDLK_x|MOD_SHIFT, // Shift+X + 0}, + {185, + "Double brush height", + "Resizes the current user brush", + "by doubling its height.", + "", + true, + SDLK_y|MOD_SHIFT, // Shift+Y + 0}, + {186, + "Halve brush size", + "Resizes the current user brush", + "by halving its width and height", + "", + true, + SDLK_h, // H + 0}, + {187, + "Run script #1", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {188, + "Run script #2", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {189, + "Run script #3", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {190, + "Run script #4", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {191, + "Run script #5", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {192, + "Run script #6", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {193, + "Run script #7", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {194, + "Run script #8", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {195, + "Run script #9", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {196, + "Run script #10", + "Runs a recorded Lua script.", + "", + "", + true, + 0, // No shortcut + 0}, + {197, + "Toggle color cycling", + "Activates or desactivates color", + "cycling, if the current image has", + "cycling colors. (See gradient menu)", + true, + SDLK_BACKQUOTE|MOD_CTRL, // Ctrl + `~ + 0}, + {198, "Format checker", "Performs a format check on the", "current image.", "", true, 0, - 0}, + 0} }; word Ordering[NB_SHORTCUTS]= @@ -1670,6 +1834,23 @@ word Ordering[NB_SHORTCUTS]= 0x100+BUTTON_LAYER_UP, 0x100+BUTTON_LAYER_DOWN, 0x100+BUTTON_LAYER_MENU, + 0x200+BUTTON_BRUSH_EFFECTS, + SPECIAL_REPEAT_SCRIPT, + SPECIAL_BRUSH_DOUBLE, + SPECIAL_BRUSH_DOUBLE_WIDTH, + SPECIAL_BRUSH_DOUBLE_HEIGHT, + SPECIAL_BRUSH_HALVE, + SPECIAL_RUN_SCRIPT_1, + SPECIAL_RUN_SCRIPT_2, + SPECIAL_RUN_SCRIPT_3, + SPECIAL_RUN_SCRIPT_4, + SPECIAL_RUN_SCRIPT_5, + SPECIAL_RUN_SCRIPT_6, + SPECIAL_RUN_SCRIPT_7, + SPECIAL_RUN_SCRIPT_8, + SPECIAL_RUN_SCRIPT_9, + SPECIAL_RUN_SCRIPT_10, + SPECIAL_CYCLE_MODE, SPECIAL_FORMAT_CHECKER, SPECIAL_FORMAT_CHECKER_MENU, }; diff --git a/src/hotkeys.h b/src/hotkeys.h index 98ef7256..e6f97c63 100644 --- a/src/hotkeys.h +++ b/src/hotkeys.h @@ -33,6 +33,8 @@ #endif #include +#define NB_SHORTCUTS 199 ///< Number of actions that can have a key combination associated to it. + /*** Types definitions and structs ***/ typedef struct diff --git a/src/init.c b/src/init.c index e356572d..2ff75c27 100644 --- a/src/init.c +++ b/src/init.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2009 Franck Charlet @@ -50,6 +51,12 @@ #if defined(__WIN32__) #include // GetLogicalDrives(), GetDriveType(), DRIVE_* #endif +#ifndef __GP2X__ + #include +#endif +#if defined (__MINT__) + #include +#endif #ifdef GRAFX2_CATCHES_SIGNALS #include #endif @@ -76,6 +83,8 @@ #include "transform.h" #include "windows.h" #include "layers.h" +#include "special.h" +#include "buttons.h" char Gui_loading_error_message[512]; @@ -250,7 +259,6 @@ void Center_GUI_cursor(T_Gui_skin *gfx, byte *cursor_buffer, int cursor_number) byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) { - int index; int i,j; int cursor_x=0,cursor_y=0; byte color; @@ -274,6 +282,7 @@ byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) sprintf(Gui_loading_error_message, "Not a 256-color palette"); return 1; } + // Read the default palette Get_SDL_Palette(SDLPal, gfx->Default_palette); @@ -351,31 +360,51 @@ byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) // Menu if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "menu")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block, Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"menu",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[0], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"menu",0)) return 1; // Preview cursor_x += Menu_bars[MENUBAR_TOOLS].Skin_width; if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "preview")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Preview, 173, 16, "logo", 0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Preview, 173, 16, "preview", 0)) return 1; cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; // Layerbar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "layer bar")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block, Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"layer bar",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[0], Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"layer bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; // Status bar if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "status bar")) return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block, Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"status bar",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[0], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"status bar",0)) return 1; cursor_y+= Menu_bars[MENUBAR_STATUS].Height; + // Menu (selected) + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected menu")) + return 1; + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_block[1], Menu_bars[MENUBAR_TOOLS].Skin_width, Menu_bars[MENUBAR_TOOLS].Height,"selected menu",0)) + return 1; + cursor_y+= Menu_bars[MENUBAR_TOOLS].Height; + + // Layerbar (selected) + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected layer bar")) + return 1; + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layerbar_block[1], Menu_bars[MENUBAR_LAYERS].Skin_width, Menu_bars[MENUBAR_LAYERS].Height,"selected layer bar",0)) + return 1; + cursor_y+= Menu_bars[MENUBAR_LAYERS].Height; + + // Status bar (selected) + if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "selected status bar")) + return 1; + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Statusbar_block[1], Menu_bars[MENUBAR_STATUS].Skin_width, Menu_bars[MENUBAR_STATUS].Height,"selected status bar",0)) + return 1; + cursor_y+= Menu_bars[MENUBAR_STATUS].Height; // Effects for (i=0; iEffect_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "effect sprite",0)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Effect_sprite[i], EFFECT_SPRITE_WIDTH, EFFECT_SPRITE_HEIGHT, "effect sprite",0)) return 1; - cursor_x+=MENU_SPRITE_WIDTH; + cursor_x+=EFFECT_SPRITE_WIDTH; } - cursor_y+=MENU_SPRITE_HEIGHT; + cursor_y+=EFFECT_SPRITE_HEIGHT; // Layer sprite for (j=0; j<3; j++) @@ -452,34 +481,31 @@ byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "menu sprite")) return 1; } - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_sprite[i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1)) + if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Menu_sprite[0][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "menu sprite",1)) + return 1; + cursor_x+=MENU_SPRITE_WIDTH; + } + cursor_y+=MENU_SPRITE_HEIGHT; + + // Menu sprites (selected) + for (i=0; iMenu_sprite[1][i], MENU_SPRITE_WIDTH, MENU_SPRITE_HEIGHT, "selected menu sprite",1)) return 1; cursor_x+=MENU_SPRITE_WIDTH; } cursor_y+=MENU_SPRITE_HEIGHT; - // Paintbrushes - for (i=0; iPaintbrush_sprite[i], PAINTBRUSH_WIDTH, PAINTBRUSH_HEIGHT, "brush icon",2)) - return 1; - cursor_x+=PAINTBRUSH_WIDTH; - } - cursor_y+=PAINTBRUSH_HEIGHT; - // Drive sprites for (i=0; iPreset_paintbrush_width [ 0]= 1; - gfx->Preset_paintbrush_height[ 0]= 1; - gfx->Paintbrush_type [ 0]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 1]= 2; - gfx->Preset_paintbrush_height[ 1]= 2; - gfx->Paintbrush_type [ 1]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 2]= 3; - gfx->Preset_paintbrush_height[ 2]= 3; - gfx->Paintbrush_type [ 2]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 3]= 4; - gfx->Preset_paintbrush_height[ 3]= 4; - gfx->Paintbrush_type [ 3]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 4]= 5; - gfx->Preset_paintbrush_height[ 4]= 5; - gfx->Paintbrush_type [ 4]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 5]= 7; - gfx->Preset_paintbrush_height[ 5]= 7; - gfx->Paintbrush_type [ 5]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 6]= 8; - gfx->Preset_paintbrush_height[ 6]= 8; - gfx->Paintbrush_type [ 6]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 7]=12; - gfx->Preset_paintbrush_height[ 7]=12; - gfx->Paintbrush_type [ 7]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 8]=16; - gfx->Preset_paintbrush_height[ 8]=16; - gfx->Paintbrush_type [ 8]=PAINTBRUSH_SHAPE_SQUARE; - - gfx->Preset_paintbrush_width [ 9]=16; - gfx->Preset_paintbrush_height[ 9]=16; - gfx->Paintbrush_type [ 9]=PAINTBRUSH_SHAPE_SIEVE_SQUARE; - - gfx->Preset_paintbrush_width [10]=15; - gfx->Preset_paintbrush_height[10]=15; - gfx->Paintbrush_type [10]=PAINTBRUSH_SHAPE_DIAMOND; - - gfx->Preset_paintbrush_width [11]= 5; - gfx->Preset_paintbrush_height[11]= 5; - gfx->Paintbrush_type [11]=PAINTBRUSH_SHAPE_DIAMOND; - - gfx->Preset_paintbrush_width [12]= 3; - gfx->Preset_paintbrush_height[12]= 3; - gfx->Paintbrush_type [12]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [13]= 4; - gfx->Preset_paintbrush_height[13]= 4; - gfx->Paintbrush_type [13]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [14]= 5; - gfx->Preset_paintbrush_height[14]= 5; - gfx->Paintbrush_type [14]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [15]= 6; - gfx->Preset_paintbrush_height[15]= 6; - gfx->Paintbrush_type [15]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [16]= 8; - gfx->Preset_paintbrush_height[16]= 8; - gfx->Paintbrush_type [16]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [17]=10; - gfx->Preset_paintbrush_height[17]=10; - gfx->Paintbrush_type [17]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [18]=12; - gfx->Preset_paintbrush_height[18]=12; - gfx->Paintbrush_type [18]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [19]=14; - gfx->Preset_paintbrush_height[19]=14; - gfx->Paintbrush_type [19]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [20]=16; - gfx->Preset_paintbrush_height[20]=16; - gfx->Paintbrush_type [20]=PAINTBRUSH_SHAPE_ROUND; - - gfx->Preset_paintbrush_width [21]=15; - gfx->Preset_paintbrush_height[21]=15; - gfx->Paintbrush_type [21]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - - gfx->Preset_paintbrush_width [22]=11; - gfx->Preset_paintbrush_height[22]=11; - gfx->Paintbrush_type [22]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - - gfx->Preset_paintbrush_width [23]= 5; - gfx->Preset_paintbrush_height[23]= 5; - gfx->Paintbrush_type [23]=PAINTBRUSH_SHAPE_SIEVE_ROUND; - - gfx->Preset_paintbrush_width [24]= 2; - gfx->Preset_paintbrush_height[24]= 1; - gfx->Paintbrush_type [24]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [25]= 3; - gfx->Preset_paintbrush_height[25]= 1; - gfx->Paintbrush_type [25]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [26]= 4; - gfx->Preset_paintbrush_height[26]= 1; - gfx->Paintbrush_type [26]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [27]= 8; - gfx->Preset_paintbrush_height[27]= 1; - gfx->Paintbrush_type [27]=PAINTBRUSH_SHAPE_HORIZONTAL_BAR; - - gfx->Preset_paintbrush_width [28]= 1; - gfx->Preset_paintbrush_height[28]= 2; - gfx->Paintbrush_type [28]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [29]= 1; - gfx->Preset_paintbrush_height[29]= 3; - gfx->Paintbrush_type [29]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [30]= 1; - gfx->Preset_paintbrush_height[30]= 4; - gfx->Paintbrush_type [30]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [31]= 1; - gfx->Preset_paintbrush_height[31]= 8; - gfx->Paintbrush_type [31]=PAINTBRUSH_SHAPE_VERTICAL_BAR; - - gfx->Preset_paintbrush_width [32]= 3; - gfx->Preset_paintbrush_height[32]= 3; - gfx->Paintbrush_type [32]=PAINTBRUSH_SHAPE_CROSS; - - gfx->Preset_paintbrush_width [33]= 5; - gfx->Preset_paintbrush_height[33]= 5; - gfx->Paintbrush_type [33]=PAINTBRUSH_SHAPE_CROSS; - - gfx->Preset_paintbrush_width [34]= 5; - gfx->Preset_paintbrush_height[34]= 5; - gfx->Paintbrush_type [34]=PAINTBRUSH_SHAPE_PLUS; - - gfx->Preset_paintbrush_width [35]=15; - gfx->Preset_paintbrush_height[35]=15; - gfx->Paintbrush_type [35]=PAINTBRUSH_SHAPE_PLUS; - - gfx->Preset_paintbrush_width [36]= 2; - gfx->Preset_paintbrush_height[36]= 2; - gfx->Paintbrush_type [36]=PAINTBRUSH_SHAPE_SLASH; - - gfx->Preset_paintbrush_width [37]= 4; - gfx->Preset_paintbrush_height[37]= 4; - gfx->Paintbrush_type [37]=PAINTBRUSH_SHAPE_SLASH; - - gfx->Preset_paintbrush_width [38]= 8; - gfx->Preset_paintbrush_height[38]= 8; - gfx->Paintbrush_type [38]=PAINTBRUSH_SHAPE_SLASH; - - gfx->Preset_paintbrush_width [39]= 2; - gfx->Preset_paintbrush_height[39]= 2; - gfx->Paintbrush_type [39]=PAINTBRUSH_SHAPE_ANTISLASH; - - gfx->Preset_paintbrush_width [40]= 4; - gfx->Preset_paintbrush_height[40]= 4; - gfx->Paintbrush_type [40]=PAINTBRUSH_SHAPE_ANTISLASH; - - gfx->Preset_paintbrush_width [41]= 8; - gfx->Preset_paintbrush_height[41]= 8; - gfx->Paintbrush_type [41]=PAINTBRUSH_SHAPE_ANTISLASH; - - gfx->Preset_paintbrush_width [42]= 4; - gfx->Preset_paintbrush_height[42]= 4; - gfx->Paintbrush_type [42]=PAINTBRUSH_SHAPE_RANDOM; - - gfx->Preset_paintbrush_width [43]= 8; - gfx->Preset_paintbrush_height[43]= 8; - gfx->Paintbrush_type [43]=PAINTBRUSH_SHAPE_RANDOM; - - gfx->Preset_paintbrush_width [44]=13; - gfx->Preset_paintbrush_height[44]=13; - gfx->Paintbrush_type [44]=PAINTBRUSH_SHAPE_RANDOM; - - gfx->Preset_paintbrush_width [45]= 3; - gfx->Preset_paintbrush_height[45]= 3; - gfx->Paintbrush_type [45]=PAINTBRUSH_SHAPE_MISC; - - gfx->Preset_paintbrush_width [46]= 3; - gfx->Preset_paintbrush_height[46]= 3; - gfx->Paintbrush_type [46]=PAINTBRUSH_SHAPE_MISC; - - gfx->Preset_paintbrush_width [47]= 7; - gfx->Preset_paintbrush_height[47]= 7; - gfx->Paintbrush_type [47]=PAINTBRUSH_SHAPE_MISC; - - for (index=0;indexPreset_paintbrush_offset_X[index]=(gfx->Preset_paintbrush_width [index]>>1); - gfx->Preset_paintbrush_offset_Y[index]=(gfx->Preset_paintbrush_height[index]>>1); - } + // Copy unselected bitmaps to current ones + memcpy(gfx->Menu_block[2], gfx->Menu_block[0], + Menu_bars[MENUBAR_TOOLS].Skin_width*Menu_bars[MENUBAR_TOOLS].Height); + memcpy(gfx->Layerbar_block[2], gfx->Layerbar_block[0], + Menu_bars[MENUBAR_LAYERS].Skin_width*Menu_bars[MENUBAR_LAYERS].Height); + memcpy(gfx->Statusbar_block[2], gfx->Statusbar_block[0], + Menu_bars[MENUBAR_STATUS].Skin_width*Menu_bars[MENUBAR_STATUS].Height); + + return 0; } -T_Gui_skin * Load_graphics(const char * skin_file) +T_Gui_skin * Load_graphics(const char * skin_file, T_Gradient_array *gradients) { T_Gui_skin * gfx; char filename[MAX_PATH_CHARACTERS]; @@ -820,10 +658,10 @@ T_Gui_skin * Load_graphics(const char * skin_file) // Read the "skin" file strcpy(filename,Data_directory); - strcat(filename,"skins" PATH_SEPARATOR); + strcat(filename,SKINS_SUBDIRECTORY PATH_SEPARATOR); strcat(filename,skin_file); - gui=Load_surface(filename); + gui=Load_surface(filename, gradients); if (!gui) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); @@ -899,9 +737,9 @@ byte * Load_font(const char * font_name) } // Read the file containing the image - sprintf(filename,"%sskins%s%s", Data_directory, PATH_SEPARATOR, font_name); + sprintf(filename,"%s" SKINS_SUBDIRECTORY "%s%s", Data_directory, PATH_SEPARATOR, font_name); - image=Load_surface(filename); + image=Load_surface(filename, NULL); if (!image) { sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); @@ -944,6 +782,7 @@ void Init_button(byte btn_number, Buttons_Pool[btn_number].Width =width-1; Buttons_Pool[btn_number].Height =height-1; Buttons_Pool[btn_number].Pressed =0; + Buttons_Pool[btn_number].Icon =-1; Buttons_Pool[btn_number].Shape =shape; Buttons_Pool[btn_number].Left_action =left_action; Buttons_Pool[btn_number].Right_action =right_action; @@ -1463,21 +1302,21 @@ void Init_operations(void) Init_operation(OPERATION_LINE,2,5, Line_12_5,0,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,1,0, + Init_operation(OPERATION_K_LINE,1,0, K_line_12_0,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,1,6, + Init_operation(OPERATION_K_LINE,1,6, K_line_12_6,0,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,1,7, + Init_operation(OPERATION_K_LINE,1,7, K_line_12_7,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,2,FAST_MOUSE, + Init_operation(OPERATION_K_LINE,2,FAST_MOUSE, K_line_12_0,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,2,6, + Init_operation(OPERATION_K_LINE,2,6, K_line_12_6,0,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,2,7, + Init_operation(OPERATION_K_LINE,2,7, K_line_12_7,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,0,6, + Init_operation(OPERATION_K_LINE,0,6, K_line_0_6,HIDE_CURSOR,FAST_MOUSE); - Init_operation(OPERATION_K_LIGNE,0,7, + Init_operation(OPERATION_K_LINE,0,7, K_line_12_6,0,FAST_MOUSE); Init_operation(OPERATION_EMPTY_RECTANGLE,1,0, @@ -1798,6 +1637,10 @@ void Init_operations(void) Centered_lines_12_7,0,FAST_MOUSE); Init_operation(OPERATION_CENTERED_LINES,0,7, Centered_lines_0_7,0,FAST_MOUSE); + + Init_operation(OPERATION_RMB_COLORPICK,0,1, + Rightclick_colorpick_0_1,0,FAST_MOUSE); + } @@ -1860,7 +1703,7 @@ void Set_all_video_modes(void) // The first mode will have index number 0. // It will be the default mode if an unsupported one // is requested in gfx2.ini - #if defined(__GP2X__) + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // Native GP2X resolution Set_video_mode( 320,240,0, 1); #else @@ -1870,7 +1713,7 @@ void Set_all_video_modes(void) Set_video_mode( 320,200,0, 1); Set_video_mode( 320,224,0, 1); - #if !defined(__GP2X__) + #if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) // For the GP2X, this one is already declared above. Set_video_mode( 320,240,0, 1); #endif @@ -1939,7 +1782,7 @@ void Set_all_video_modes(void) for (index=0; Modes[index]; index++) { int index2; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X the first mode is not windowed, so include it in the search. index2=0; #else @@ -1986,7 +1829,7 @@ int Load_CFG(int reload_all) if ((Handle=fopen(filename,"rb"))==NULL) return ERROR_CFG_MISSING; - if ( (file_size<(long)sizeof(cfg_header)) + if ( (file_size<7) || (!Read_bytes(Handle, &cfg_header.Signature, 3)) || memcmp(cfg_header.Signature,"CFG",3) || (!Read_byte(Handle, &cfg_header.Version1)) @@ -2027,7 +1870,7 @@ int Load_CFG(int reload_all) case CHUNK_KEYS: // Touches if (reload_all) { - for (index=0; index<(long)(Chunk.Size/sizeof(cfg_shortcut_info)); index++) + for (index=0; index<(long)(Chunk.Size/6); index++) { if (!Read_word_le(Handle, &cfg_shortcut_info.Number) || !Read_word_le(Handle, &cfg_shortcut_info.Key) || @@ -2080,14 +1923,14 @@ int Load_CFG(int reload_all) } break; case CHUNK_VIDEO_MODES: // Modes vidéo - for (index=0; index<(long)(Chunk.Size/sizeof(cfg_video_mode)); index++) + for (index=0; index<(long)(Chunk.Size/5); index++) { if (!Read_byte(Handle, &cfg_video_mode.State) || !Read_word_le(Handle, &cfg_video_mode.Width) || !Read_word_le(Handle, &cfg_video_mode.Height) ) goto Erreur_lecture_config; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) index2=0; #else index2=1; @@ -2161,7 +2004,10 @@ int Load_CFG(int reload_all) } break; case CHUNK_GRADIENTS: // Infos sur les dégradés - if (reload_all) + // The gradients chunk is deprecated since the data + // is now loaded/saved in GIF and LBM formats. + // The chunk will be completely ignored. + /*if (reload_all) { if (! Read_byte(Handle, &Current_gradient)) goto Erreur_lecture_config; @@ -2176,7 +2022,7 @@ int Load_CFG(int reload_all) } Load_gradient_data(Current_gradient); } - else + else*/ { if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) goto Erreur_lecture_config; @@ -2240,6 +2086,96 @@ int Load_CFG(int reload_all) goto Erreur_lecture_config; } break; + + case CHUNK_BRUSH: + if (reload_all) + { + int index; + for (index=0; index> (i&7))) != 0); + } + } + } + else + { + if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) + goto Erreur_lecture_config; + } + break; + + + case CHUNK_SCRIPTS: + if (reload_all) + { + int current_size=0; + int current_script=0; + + while(current_size=10) + break; + } + + + } + break; + default: // Chunk inconnu goto Erreur_lecture_config; } @@ -2272,7 +2208,7 @@ int Save_CFG(void) T_Config_video_mode cfg_video_mode={0,0,0}; strcpy(filename,Config_directory); - strcat(filename,"gfx2.cfg"); + strcat(filename,CONFIG_FILENAME); if ((Handle=fopen(filename,"wb"))==NULL) return ERROR_SAVING_CFG; @@ -2292,7 +2228,7 @@ int Save_CFG(void) // Enregistrement des touches Chunk.Number=CHUNK_KEYS; - Chunk.Size=NB_SHORTCUTS*sizeof(cfg_shortcut_info); + Chunk.Size=NB_SHORTCUTS*6; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) @@ -2323,7 +2259,7 @@ int Save_CFG(void) // D'abord compter les modes pour lesquels l'utilisateur a mis une préférence modes_to_save=0; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined (__WIZ__) || defined (__CAANOO__) index = 0; #else index = 1; @@ -2334,12 +2270,12 @@ int Save_CFG(void) // Sauvegarde de l'état de chaque mode vidéo Chunk.Number=CHUNK_VIDEO_MODES; - Chunk.Size=modes_to_save * sizeof(cfg_video_mode); + Chunk.Size=modes_to_save * 5; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; -#if defined(__GP2X__) +#if defined(__GP2X__) || defined (__WIZ__) || defined (__CAANOO__) index = 0; #else index = 1; @@ -2359,7 +2295,7 @@ int Save_CFG(void) // Ecriture des données du Shade (précédées du shade en cours) Chunk.Number=CHUNK_SHADE; - Chunk.Size=sizeof(Shade_list)+sizeof(Shade_current); + Chunk.Size=8209; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2379,7 +2315,7 @@ int Save_CFG(void) // Sauvegarde des informations du Masque Chunk.Number=CHUNK_MASK; - Chunk.Size=sizeof(Mask_table); + Chunk.Size=256; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2388,7 +2324,7 @@ int Save_CFG(void) // Sauvegarde des informations du Stencil Chunk.Number=CHUNK_STENCIL; - Chunk.Size=sizeof(Stencil); + Chunk.Size=256; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2396,8 +2332,11 @@ int Save_CFG(void) goto Erreur_sauvegarde_config; // Sauvegarde des informations des dégradés + // The gradients chunk is deprecated since the data + // is now loaded/saved in GIF and LBM formats. + /* Chunk.Number=CHUNK_GRADIENTS; - Chunk.Size=sizeof(Gradient_array)+1; + Chunk.Size=14*16+1; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2412,10 +2351,11 @@ int Save_CFG(void) !Write_dword_le(Handle, Gradient_array[index].Technique) ) goto Erreur_sauvegarde_config; } + */ // Sauvegarde de la matrice du Smooth Chunk.Number=CHUNK_SMOOTH; - Chunk.Size=sizeof(Smooth_matrix); + Chunk.Size=9; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2426,7 +2366,7 @@ int Save_CFG(void) // Sauvegarde des couleurs à exclure Chunk.Number=CHUNK_EXCLUDE_COLORS; - Chunk.Size=sizeof(Exclude_color); + Chunk.Size=256; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2435,7 +2375,7 @@ int Save_CFG(void) // Sauvegarde des informations du Quick-shade Chunk.Number=CHUNK_QUICK_SHADE; - Chunk.Size=sizeof(Quick_shade_step)+sizeof(Quick_shade_loop); + Chunk.Size=2; if (!Write_byte(Handle, Chunk.Number) || !Write_word_le(Handle, Chunk.Size) ) goto Erreur_sauvegarde_config; @@ -2459,7 +2399,104 @@ int Save_CFG(void) if (!Write_word_le(Handle, Snap_offset_Y)) goto Erreur_sauvegarde_config; + // Save brush data + { + long total_size=0; + int index; + // Compute size: monochrome paintbrushes + for (index=0; index> (i&7); + if ((i&7) == 7) + { + // Write one byte + if (!Write_byte(Handle, current_byte)) + goto Erreur_sauvegarde_config; + current_byte=0; + } + } + // Remainder + if ((i&7) != 0) + { + // Write one byte + if (!Write_byte(Handle, current_byte)) + goto Erreur_sauvegarde_config; + } + } + } + + // Save script shortcuts + { + int i; + Chunk.Number=CHUNK_SCRIPTS; + // Compute size : Data stored as 10 pascal strings + Chunk.Size=0; + for (i=0; i<10; i++) + { + if (Bound_script[i]==NULL) + Chunk.Size+=1; + else + Chunk.Size+=strlen(Bound_script[i])+1; + } + // Header + if (!Write_byte(Handle, Chunk.Number) || + !Write_word_le(Handle, Chunk.Size) ) + goto Erreur_sauvegarde_config; + + // Strings + for (i=0; i<10; i++) + { + byte size=0; + if (Bound_script[i]!=NULL) + size=strlen(Bound_script[i]); + + if (!Write_byte(Handle, size)) + goto Erreur_sauvegarde_config; + + if (size) + if (!Write_bytes(Handle, Bound_script[i], size)) + goto Erreur_sauvegarde_config; + } + } + if (fclose(Handle)) return ERROR_SAVING_CFG; @@ -2520,19 +2557,7 @@ void Set_config_defaults(void) // Stencil for (index=0; index<256; index++) Stencil[index]=1; - - // Dégradés - Current_gradient=0; - for(index=0;index<16;index++) - { - Gradient_array[index].Start=0; - Gradient_array[index].End=0; - Gradient_array[index].Inverse=0; - Gradient_array[index].Mix=0; - Gradient_array[index].Technique=0; - } - Load_gradient_data(Current_gradient); - + // Smooth Smooth_matrix[0][0]=1; Smooth_matrix[0][1]=2; @@ -2614,16 +2639,18 @@ void Init_brush_container(void) for (i=0; iColor[2]; MC_White = gfx->Color[3]; MC_Trans = gfx->Color_trans; + MC_OnBlack=MC_Dark; + MC_Window=MC_Light; + MC_Lighter=MC_White; + MC_Darker=MC_Dark; + // Set menubars to point to the new data - Menu_bars[MENUBAR_TOOLS].Skin = (byte*)&(gfx->Menu_block); - Menu_bars[MENUBAR_LAYERS].Skin = (byte*)&(gfx->Layerbar_block); - Menu_bars[MENUBAR_STATUS].Skin = (byte*)&(gfx->Statusbar_block); + for (i=0; i<3; i++) + { + Menu_bars[MENUBAR_TOOLS ].Skin[i] = (byte*)&(gfx->Menu_block[i]); + Menu_bars[MENUBAR_LAYERS].Skin[i] = (byte*)&(gfx->Layerbar_block[i]); + Menu_bars[MENUBAR_STATUS].Skin[i] = (byte*)&(gfx->Statusbar_block[i]); + } } /// @@ -2686,3 +2723,253 @@ void Compute_menu_offsets(void) Menu_Y = Screen_height - Menu_height * Menu_factor_Y; } +void Init_paintbrush(int index, int width, int height, byte shape, const char * bitmap) +{ + if (bitmap!=NULL) + { + int i; + + Paintbrush[index].Shape=shape; + Paintbrush[index].Width=width; + Paintbrush[index].Height=height; + Paintbrush[index].Offset_X=width>>1; + Paintbrush[index].Offset_Y=height>>1; + + // Decode pixels + for (i=0;i> (i&7))) != 0); + } + } + else + { + Paintbrush_shape=shape; + Set_paintbrush_size(width, height); + Store_paintbrush(index); + } + +} + + +void Init_paintbrushes(void) +{ + int index; + + Init_paintbrush( 0, 1, 1,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 1, 2, 2,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 2, 3, 3,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 3, 4, 4,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 4, 5, 5,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 5, 7, 7,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 6, 8, 8,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 7,12,12,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 8,16,16,PAINTBRUSH_SHAPE_SQUARE, NULL); + Init_paintbrush( 9,16,16,PAINTBRUSH_SHAPE_SIEVE_SQUARE, NULL); + Init_paintbrush(10,15,15,PAINTBRUSH_SHAPE_DIAMOND, NULL); + Init_paintbrush(11, 5, 5,PAINTBRUSH_SHAPE_DIAMOND, NULL); + Init_paintbrush(12, 3, 3,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(13, 4, 4,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(14, 5, 5,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(15, 6, 6,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(16, 8, 8,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(17,10,10,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(18,12,12,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(19,14,14,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(20,16,16,PAINTBRUSH_SHAPE_ROUND, NULL); + Init_paintbrush(21,15,15,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); + Init_paintbrush(22,11,11,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); + Init_paintbrush(23, 5, 5,PAINTBRUSH_SHAPE_SIEVE_ROUND, NULL); + Init_paintbrush(24, 2, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(25, 3, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(26, 4, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(27, 8, 1,PAINTBRUSH_SHAPE_HORIZONTAL_BAR, NULL); + Init_paintbrush(28, 1, 2,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(29, 1, 3,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(30, 1, 4,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(31, 1, 8,PAINTBRUSH_SHAPE_VERTICAL_BAR, NULL); + Init_paintbrush(32, 3, 3,PAINTBRUSH_SHAPE_CROSS, NULL); + Init_paintbrush(33, 5, 5,PAINTBRUSH_SHAPE_CROSS, NULL); + Init_paintbrush(34, 5, 5,PAINTBRUSH_SHAPE_PLUS, NULL); + Init_paintbrush(35,15,15,PAINTBRUSH_SHAPE_PLUS, NULL); + Init_paintbrush(36, 2, 2,PAINTBRUSH_SHAPE_SLASH, NULL); + Init_paintbrush(37, 4, 4,PAINTBRUSH_SHAPE_SLASH, NULL); + Init_paintbrush(38, 8, 8,PAINTBRUSH_SHAPE_SLASH, NULL); + Init_paintbrush(39, 2, 2,PAINTBRUSH_SHAPE_ANTISLASH, NULL); + Init_paintbrush(40, 4, 4,PAINTBRUSH_SHAPE_ANTISLASH, NULL); + Init_paintbrush(41, 8, 8,PAINTBRUSH_SHAPE_ANTISLASH, NULL); + + Init_paintbrush(42, 4, 4,PAINTBRUSH_SHAPE_RANDOM, "\x20\x81"); + Init_paintbrush(43, 8, 8,PAINTBRUSH_SHAPE_RANDOM, "\x44\x00\x11\x00\x88\x01\x40\x08"); + Init_paintbrush(44,13,13,PAINTBRUSH_SHAPE_RANDOM, "\x08\x00\x08\x90\x00\x10\x42\x10\x02\x06\x02\x02\x04\x02\x08\x42\x10\x44\x00\x00\x44\x00"); + + Init_paintbrush(45, 3, 3,PAINTBRUSH_SHAPE_MISC, "\x7f\x00"); + Init_paintbrush(46, 3, 3,PAINTBRUSH_SHAPE_MISC, "\xdd\x80"); + Init_paintbrush(47, 7, 7,PAINTBRUSH_SHAPE_MISC, "\x06\x30\x82\x04\x10\x20\x00"); + + for (index=0;index>1); + Paintbrush[index].Offset_Y=(Paintbrush[index].Height>>1); + } +} + +/// Set application icon(s) +void Define_icon(void) +{ +#ifdef WIN32 + // Specific code for Win32: + // Load icon from embedded resource. + // This will provide both the 16x16 and 32x32 versions. + do + { + HICON hicon; + HRSRC hresource; + HINSTANCE hInstance; + LPVOID lpResIconDir; + LPVOID lpResIcon16; + LPVOID lpResIcon32; + HGLOBAL hMem; + WORD nID; + SDL_SysWMinfo info; + + hInstance = (HINSTANCE)GetModuleHandle(NULL); + if (hInstance==NULL) + break; + + // Icon is resource #1 + hresource = FindResource(hInstance, + MAKEINTRESOURCE(1), + RT_GROUP_ICON); + if (hresource==NULL) + break; + + // Load and lock the icon directory. + hMem = LoadResource(hInstance, hresource); + if (hMem==NULL) + break; + + lpResIconDir = LockResource(hMem); + if (lpResIconDir==NULL) + break; + + SDL_VERSION(&info.version); + SDL_GetWMInfo(&info); + + // + // 16x16 + // + + // Get the identifier of the 16x16 icon + nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, + 16, 16, LR_DEFAULTCOLOR); + if (nID==0) + break; + + // Find the bits for the nID icon. + hresource = FindResource(hInstance, + MAKEINTRESOURCE(nID), + MAKEINTRESOURCE((long)RT_ICON)); + if (hresource==NULL) + break; + + // Load and lock the icon. + hMem = LoadResource(hInstance, hresource); + if (hMem==NULL) + break; + lpResIcon16 = LockResource(hMem); + if (lpResIcon16==NULL) + break; + + // Create a handle to the icon. + hicon = CreateIconFromResourceEx((PBYTE) lpResIcon16, + SizeofResource(hInstance, hresource), TRUE, 0x00030000, + 16, 16, LR_DEFAULTCOLOR); + if (hicon==NULL) + break; + + // Set it + SetClassLongPtr(info.window, GCL_HICONSM, (LONG_PTR)hicon); + + + // + // 32x32 + // + + // Get the identifier of the 32x32 icon + nID = LookupIconIdFromDirectoryEx((PBYTE) lpResIconDir, TRUE, + 32, 32, LR_DEFAULTCOLOR); + if (nID==0) + break; + + // Find the bits for the nID icon. + hresource = FindResource(hInstance, + MAKEINTRESOURCE(nID), + MAKEINTRESOURCE((long)RT_ICON)); + if (hresource==NULL) + break; + + // Load and lock the icon. + hMem = LoadResource(hInstance, hresource); + if (hMem==NULL) + break; + lpResIcon32 = LockResource(hMem); + if (lpResIcon32==NULL) + break; + + // Create a handle to the icon. + hicon = CreateIconFromResourceEx((PBYTE) lpResIcon32, + SizeofResource(hInstance, hresource), TRUE, 0x00030000, + 32, 32, LR_DEFAULTCOLOR); + if (hicon==NULL) + break; + + // Set it + SetClassLongPtr(info.window, GCL_HICON, (LONG_PTR)hicon); + + + // Success + return; + } while (0); + // Failure: fall back on normal SDL version: + +#endif + // General version: Load icon from the file gfx2.gif + { + char icon_path[MAX_PATH_CHARACTERS]; + SDL_Surface * icon; + sprintf(icon_path, "%s%s", Data_directory, "gfx2.gif"); + icon = IMG_Load(icon_path); + if (icon && icon->w == 32 && icon->h == 32) + { + Uint32 pink; + pink = SDL_MapRGB(icon->format, 255, 0, 255); + + if (icon->format->BitsPerPixel == 8) + { + // 8bit image: use color key + + SDL_SetColorKey(icon, SDL_SRCCOLORKEY, pink); + SDL_WM_SetIcon(icon,NULL); + } + else + { + // 24bit image: need to build a mask on magic pink + + byte *icon_mask; + int x,y; + + icon_mask=malloc(128); + memset(icon_mask,0,128); + for (y=0;y<32;y++) + for (x=0;x<32;x++) + if (Get_SDL_pixel_hicolor(icon, x, y) != pink) + icon_mask[(y*32+x)/8] |=0x80>>(x&7); + SDL_WM_SetIcon(icon,icon_mask); + free(icon_mask); + icon_mask = NULL; + } + SDL_FreeSurface(icon); + } + } +} \ No newline at end of file diff --git a/src/init.h b/src/init.h index 8d8ca318..3f64ae7a 100644 --- a/src/init.h +++ b/src/init.h @@ -24,7 +24,7 @@ /// Initialization (and some de-initialization) functions. ////////////////////////////////////////////////////////////////////////////// -T_Gui_skin *Load_graphics(const char * skin_file); +T_Gui_skin *Load_graphics(const char * skin_file, T_Gradient_array *gradients); void Set_current_skin(const char *skinfile, T_Gui_skin *gfx); void Init_buttons(void); void Init_operations(void); @@ -34,6 +34,10 @@ int Save_CFG(void); void Set_all_video_modes(void); void Set_config_defaults(void); void Init_sighandler(void); +void Init_paintbrushes(void); + +/// Set application icon(s) +void Define_icon(void); extern char Gui_loading_error_message[512]; diff --git a/src/input.c b/src/input.c index f9875245..45b54b6f 100644 --- a/src/input.c +++ b/src/input.c @@ -21,6 +21,12 @@ */ #include +#include + +#ifdef __WIN32__ + #include + #include +#endif #include "global.h" #include "keyboard.h" @@ -28,7 +34,9 @@ #include "windows.h" #include "errors.h" #include "misc.h" +#include "buttons.h" #include "input.h" +#include "loadsave.h" #ifdef __VBCC__ #define __attribute__(x) @@ -36,6 +44,7 @@ void Handle_window_resize(SDL_ResizeEvent event); void Handle_window_exit(SDL_QuitEvent event); +int Color_cycling(__attribute__((unused)) void* useless); // public Globals (available as extern) @@ -44,8 +53,11 @@ int Snap_axis = 0; int Snap_axis_origin_X; int Snap_axis_origin_Y; +char * Drop_file_name = NULL; + // -- +// Digital joystick state byte Directional_up; byte Directional_up_right; byte Directional_right; @@ -56,14 +68,22 @@ byte Directional_left; byte Directional_up_left; byte Directional_click; -long Directional_delay; +// Emulated directional controller. +// This has a distinct state from Directional_, because some joysticks send +// "I'm not moving" SDL events when idle, thus stopping the emulated one. +byte Directional_emulated_up; +byte Directional_emulated_right; +byte Directional_emulated_down; +byte Directional_emulated_left; + +long Directional_first_move; long Directional_last_move; -long Directional_step; int Mouse_moved; ///< Boolean, Set to true if any cursor movement occurs. word Input_new_mouse_X; word Input_new_mouse_Y; byte Input_new_mouse_K; +byte Button_inverter=0; // State of the key that swaps mouse buttons. byte Mouse_mode = 0; ///< Mouse mode = 0:normal, 1:emulated with custom sensitivity. short Mouse_virtual_x_position; @@ -71,21 +91,84 @@ short Mouse_virtual_y_position; short Mouse_virtual_width; short Mouse_virtual_height; -// TODO: move to config -#ifdef __GP2X__ -short Joybutton_shift=GP2X_BUTTON_L; // Button number that serves as a "shift" modifier -short Joybutton_control=GP2X_BUTTON_R; // Button number that serves as a "ctrl" modifier -short Joybutton_alt=GP2X_BUTTON_CLICK; // Button number that serves as a "alt" modifier -short Joybutton_left_click=GP2X_BUTTON_B; // Button number that serves as left click -short Joybutton_right_click=GP2X_BUTTON_Y; // Button number that serves as right-click -#else -short Joybutton_shift=-1; // Button number that serves as a "shift" modifier -short Joybutton_control=-1; // Button number that serves as a "ctrl" modifier -short Joybutton_alt=-1; // Button number that serves as a "alt" modifier -short Joybutton_left_click=0; // Button number that serves as left click -short Joybutton_right_click=0; // Button number that serves as right-click +// Joystick/pad configurations for the various console ports. +// See the #else for the documentation of fields. +// TODO: Make these user-settable somehow. +#if defined(__GP2X__) + + #define JOYSTICK_THRESHOLD (4096) + short Joybutton_shift= JOY_BUTTON_L; + short Joybutton_control= JOY_BUTTON_R; + short Joybutton_alt= JOY_BUTTON_CLICK; + short Joybutton_left_click= JOY_BUTTON_B; + short Joybutton_right_click=JOY_BUTTON_Y; + +#elif defined(__WIZ__) + + #define JOYSTICK_THRESHOLD (4096) + short Joybutton_shift= JOY_BUTTON_X; + short Joybutton_control= JOY_BUTTON_SELECT; + short Joybutton_alt= JOY_BUTTON_Y; + short Joybutton_left_click= JOY_BUTTON_A; + short Joybutton_right_click=JOY_BUTTON_B; + +#elif defined(__CAANOO__) + + #define JOYSTICK_THRESHOLD (4096) + short Joybutton_shift= JOY_BUTTON_L; + short Joybutton_control= JOY_BUTTON_R; + short Joybutton_alt= JOY_BUTTON_Y; + short Joybutton_left_click= JOY_BUTTON_A; + short Joybutton_right_click=JOY_BUTTON_B; + +#else // Default : Any joystick on a computer platform + /// + /// This is the sensitivity threshold for the directional + /// pad of a cheap digital joypad on the PC. It has been set through + /// trial and error : If value is too large then the movement is + /// randomly interrupted; if the value is too low the cursor will + /// move by itself, controlled by parasits. + /// YR 04/11/2010: I just observed a -8700 when joystick is idle. + #define JOYSTICK_THRESHOLD (10000) + + /// A button that is marked as "modifier" will + short Joybutton_shift=-1; ///< Button number that serves as a "shift" modifier; -1 for none + short Joybutton_control=-1; ///< Button number that serves as a "ctrl" modifier; -1 for none + short Joybutton_alt=-1; ///< Button number that serves as a "alt" modifier; -1 for none + + short Joybutton_left_click=0; ///< Button number that serves as left click; -1 for none + short Joybutton_right_click=1; ///< Button number that serves as right-click; -1 for none + #endif +int Has_shortcut(word function) +{ + if (function == 0xFFFF) + return 0; + + if (function & 0x100) + { + if (Buttons_Pool[function&0xFF].Left_shortcut[0]!=KEY_NONE) + return 1; + if (Buttons_Pool[function&0xFF].Left_shortcut[1]!=KEY_NONE) + return 1; + return 0; + } + if (function & 0x200) + { + if (Buttons_Pool[function&0xFF].Right_shortcut[0]!=KEY_NONE) + return 1; + if (Buttons_Pool[function&0xFF].Right_shortcut[1]!=KEY_NONE) + return 1; + return 0; + } + if(Config_Key[function][0]!=KEY_NONE) + return 1; + if(Config_Key[function][1]!=KEY_NONE) + return 1; + return 0; +} + int Is_shortcut(word key, word function) { if (key == 0 || function == 0xFFFF) @@ -177,16 +260,18 @@ int Move_cursor_with_constraints() feedback=1; if (Input_new_mouse_K == 0) + { Input_sticky_control = 0; + } } // Hide cursor, because even just a click change needs it if (!Mouse_moved) { - Mouse_moved++; // Hide cursor (erasing icon and brush on screen // before changing the coordinates. Hide_cursor(); } + Mouse_moved++; if (Input_new_mouse_X != Mouse_X || Input_new_mouse_Y != Mouse_Y) { Mouse_X=Input_new_mouse_X; @@ -194,8 +279,8 @@ int Move_cursor_with_constraints() } Mouse_K=Input_new_mouse_K; - if (Mouse_moved > Config.Mouse_merge_movement) - if (! Operation[Current_operation][Mouse_K_unique] + if (Mouse_moved > Config.Mouse_merge_movement + && !Operation[Current_operation][Mouse_K_unique] [Operation_stack_size].Fast_mouse) feedback=1; } @@ -254,11 +339,19 @@ int Handle_mouse_click(SDL_MouseButtonEvent event) switch(event.button) { case SDL_BUTTON_LEFT: - Input_new_mouse_K |= 1; + if (Button_inverter) + Input_new_mouse_K |= 2; + else + Input_new_mouse_K |= 1; + break; break; case SDL_BUTTON_RIGHT: - Input_new_mouse_K |= 2; + if (Button_inverter) + Input_new_mouse_K |= 1; + else + Input_new_mouse_K |= 2; + break; break; case SDL_BUTTON_MIDDLE: @@ -284,11 +377,17 @@ int Handle_mouse_release(SDL_MouseButtonEvent event) switch(event.button) { case SDL_BUTTON_LEFT: - Input_new_mouse_K &= ~1; + if (Button_inverter) + Input_new_mouse_K &= ~2; + else + Input_new_mouse_K &= ~1; break; case SDL_BUTTON_RIGHT: - Input_new_mouse_K &= ~2; + if (Button_inverter) + Input_new_mouse_K &= ~1; + else + Input_new_mouse_K &= ~2; break; } @@ -300,27 +399,64 @@ int Handle_mouse_release(SDL_MouseButtonEvent event) int Handle_key_press(SDL_KeyboardEvent event) { //Appui sur une touche du clavier + int modifier; + Key = Keysym_to_keycode(event.keysym); Key_ANSI = Keysym_to_ANSI(event.keysym); + switch(event.keysym.sym) + { + case SDLK_RSHIFT: + case SDLK_LSHIFT: + modifier=MOD_SHIFT; + break; + + case SDLK_RCTRL: + case SDLK_LCTRL: + modifier=MOD_CTRL; + break; + + case SDLK_RALT: + case SDLK_LALT: + case SDLK_MODE: + modifier=MOD_ALT; + break; + + case SDLK_RMETA: + case SDLK_LMETA: + modifier=MOD_META; + break; + + default: + modifier=0; + } + if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==0) + { + Button_inverter=1; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } if(Is_shortcut(Key,SPECIAL_MOUSE_UP)) { - Directional_up=1; + Directional_emulated_up=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_DOWN)) { - Directional_down=1; + Directional_emulated_down=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_LEFT)) { - Directional_left=1; + Directional_emulated_left=1; return 0; } else if(Is_shortcut(Key,SPECIAL_MOUSE_RIGHT)) { - Directional_right=1; + Directional_emulated_right=1; return 0; } else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT) && Keyboard_click_allowed > 0) @@ -349,26 +485,35 @@ int Release_control(int key_code, int modifier) Snap_axis = 0; need_feedback = 1; } + if (Config.Swap_buttons && modifier == Config.Swap_buttons && Button_inverter==1) + { + Button_inverter=0; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_UP][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_UP][1]&modifier)) { - Directional_up=0; + Directional_emulated_up=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_DOWN][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_DOWN][1]&modifier)) { - Directional_down=0; + Directional_emulated_down=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_LEFT][1]&modifier)) { - Directional_left=0; + Directional_emulated_left=0; } if((key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_MOUSE_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_MOUSE_RIGHT][1]&modifier)) { - Directional_right=0; + Directional_emulated_right=0; } if((key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][0]&modifier) || (key_code && key_code == (Config_Key[SPECIAL_CLICK_LEFT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_LEFT][1]&modifier)) @@ -445,54 +590,88 @@ int Handle_joystick_press(SDL_JoyButtonEvent event) if (event.button == Joybutton_control) { SDL_SetModState(SDL_GetModState() | KMOD_CTRL); + if (Config.Swap_buttons == MOD_CTRL && Button_inverter==0) + { + Button_inverter=1; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } return 0; } if (event.button == Joybutton_alt) { SDL_SetModState(SDL_GetModState() | (KMOD_ALT|KMOD_META)); + if (Config.Swap_buttons == MOD_ALT && Button_inverter==0) + { + Button_inverter=1; + if (Input_new_mouse_K) + { + Input_new_mouse_K ^= 3; // Flip bits 0 and 1 + return Move_cursor_with_constraints(); + } + } return 0; } if (event.button == Joybutton_left_click) { - Input_new_mouse_K=1; + Input_new_mouse_K = Button_inverter ? 2 : 1; return Move_cursor_with_constraints(); } if (event.button == Joybutton_right_click) { - Input_new_mouse_K=2; + Input_new_mouse_K = Button_inverter ? 1 : 2; return Move_cursor_with_constraints(); } - #ifdef __GP2X__ switch(event.button) { - case GP2X_BUTTON_UP: + #ifdef JOY_BUTTON_UP + case JOY_BUTTON_UP: Directional_up=1; break; - case GP2X_BUTTON_UPRIGHT: + #endif + #ifdef JOY_BUTTON_UPRIGHT + case JOY_BUTTON_UPRIGHT: Directional_up_right=1; break; - case GP2X_BUTTON_RIGHT: + #endif + #ifdef JOY_BUTTON_RIGHT + case JOY_BUTTON_RIGHT: Directional_right=1; break; - case GP2X_BUTTON_DOWNRIGHT: + #endif + #ifdef JOY_BUTTON_DOWNRIGHT + case JOY_BUTTON_DOWNRIGHT: Directional_down_right=1; break; - case GP2X_BUTTON_DOWN: + #endif + #ifdef JOY_BUTTON_DOWN + case JOY_BUTTON_DOWN: Directional_down=1; break; - case GP2X_BUTTON_DOWNLEFT: + #endif + #ifdef JOY_BUTTON_DOWNLEFT + case JOY_BUTTON_DOWNLEFT: Directional_down_left=1; break; - case GP2X_BUTTON_LEFT: + #endif + #ifdef JOY_BUTTON_LEFT + case JOY_BUTTON_LEFT: Directional_left=1; break; - case GP2X_BUTTON_UPLEFT: + #endif + #ifdef JOY_BUTTON_UPLEFT + case JOY_BUTTON_UPLEFT: Directional_up_left=1; break; + #endif + default: break; } - #endif + Key = (KEY_JOYBUTTON+event.button)|Key_modifiers(SDL_GetModState()); // TODO: systeme de répétition @@ -527,58 +706,75 @@ int Handle_joystick_release(SDL_JoyButtonEvent event) return Move_cursor_with_constraints(); } - #ifdef __GP2X__ switch(event.button) { - case GP2X_BUTTON_UP: - Directional_up=0; + #ifdef JOY_BUTTON_UP + case JOY_BUTTON_UP: + Directional_up=1; break; - case GP2X_BUTTON_UPRIGHT: - Directional_up_right=0; + #endif + #ifdef JOY_BUTTON_UPRIGHT + case JOY_BUTTON_UPRIGHT: + Directional_up_right=1; break; - case GP2X_BUTTON_RIGHT: - Directional_right=0; + #endif + #ifdef JOY_BUTTON_RIGHT + case JOY_BUTTON_RIGHT: + Directional_right=1; break; - case GP2X_BUTTON_DOWNRIGHT: - Directional_down_right=0; + #endif + #ifdef JOY_BUTTON_DOWNRIGHT + case JOY_BUTTON_DOWNRIGHT: + Directional_down_right=1; break; - case GP2X_BUTTON_DOWN: - Directional_down=0; + #endif + #ifdef JOY_BUTTON_DOWN + case JOY_BUTTON_DOWN: + Directional_down=1; break; - case GP2X_BUTTON_DOWNLEFT: - Directional_down_left=0; + #endif + #ifdef JOY_BUTTON_DOWNLEFT + case JOY_BUTTON_DOWNLEFT: + Directional_down_left=1; break; - case GP2X_BUTTON_LEFT: - Directional_left=0; + #endif + #ifdef JOY_BUTTON_LEFT + case JOY_BUTTON_LEFT: + Directional_left=1; break; - case GP2X_BUTTON_UPLEFT: - Directional_up_left=0; + #endif + #ifdef JOY_BUTTON_UPLEFT + case JOY_BUTTON_UPLEFT: + Directional_up_left=1; + break; + #endif + + default: break; } - #endif return Move_cursor_with_constraints(); } void Handle_joystick_movement(SDL_JoyAxisEvent event) { - if (event.axis==0) // X + if (event.axis==JOYSTICK_AXIS_X) { Directional_right=Directional_left=0; - if (event.value<-1000) + if (event.value<-JOYSTICK_THRESHOLD) { Directional_left=1; } - else if (event.value>1000) + else if (event.value>JOYSTICK_THRESHOLD) Directional_right=1; } - else if (event.axis==1) // Y + else if (event.axis==JOYSTICK_AXIS_Y) { Directional_up=Directional_down=0; - if (event.value<-1000) + if (event.value<-JOYSTICK_THRESHOLD) { Directional_up=1; } - else if (event.value>1000) + else if (event.value>JOYSTICK_THRESHOLD) Directional_down=1; } } @@ -616,138 +812,222 @@ int Cursor_displace(short delta_x, short delta_y) return Move_cursor_with_constraints(); } +// This function is the acceleration profile for directional (digital) cursor +// controllers. +int Directional_acceleration(int msec) +{ + const int initial_delay = 250; + const int linear_factor = 200; + const int accel_factor = 10000; + // At beginning there is 1 pixel move, then nothing for N milliseconds + if (msecmsg == WM_DROPFILES) + { + int file_count; + HDROP hdrop = (HDROP)(event.syswm.msg->wParam); + if((file_count = DragQueryFile(hdrop,(UINT)-1,(LPTSTR) NULL ,(UINT) 0)) > 0) + { + long len; + // Query filename length + len = DragQueryFile(hdrop,0 ,NULL ,0); + if (len) + { + Drop_file_name=calloc(len+1,1); + if (Drop_file_name) + { + if (DragQueryFile(hdrop,0 ,(LPTSTR) Drop_file_name ,(UINT) MAX_PATH)) + { + // Success + } + else + { + free(Drop_file_name); + // Don't report name copy error + } + } + else + { + // Don't report alloc error (for a file name? :/ ) + } + } + else + { + // Don't report weird Windows error + } + } + else + { + // Drop of zero files. Thanks for the information, Bill. + } + } +#endif + break; + + default: + //DEBUG("Unhandled SDL event number : ",event.type); + break; + } } // Directional controller if (!(Directional_up||Directional_up_right||Directional_right|| - Directional_down_right||Directional_down||Directional_down_left|| - Directional_left||Directional_up_left)) + Directional_down_right||Directional_down||Directional_down_left|| + Directional_left||Directional_up_left||Directional_emulated_up|| + Directional_emulated_right||Directional_emulated_down|| + Directional_emulated_left)) { - Directional_delay=-1; - Directional_last_move=SDL_GetTicks(); + Directional_first_move=0; } else { long time_now; + int step=0; time_now=SDL_GetTicks(); - if (time_now>Directional_last_move+Directional_delay) + if (Directional_first_move==0) + { + Directional_first_move=time_now; + step=1; + } + else + { + // Compute how much the cursor has moved since last call. + // This tries to make smooth cursor movement + // no matter the frequency of calls to Get_input() + step = + Directional_acceleration(time_now - Directional_first_move) - + Directional_acceleration(Directional_last_move - Directional_first_move); + + // Clip speed at 3 pixel per visible frame. + if (step > 3) + step=3; + + } + Directional_last_move = time_now; + if (step) { - // Speed parameters, acceleration etc. are here - if (Directional_delay==-1) - { - Directional_delay=150; - Directional_step=16; - } - else if (Directional_delay==150) - Directional_delay=40; - else if (Directional_delay!=0) - Directional_delay=Directional_delay*8/10; - else if (Directional_step<16*4) - Directional_step++; - Directional_last_move = time_now; - // Directional controller UP - if ((Directional_up||Directional_up_left||Directional_up_right) && - !(Directional_down_right||Directional_down||Directional_down_left)) + if ((Directional_up||Directional_emulated_up||Directional_up_left||Directional_up_right) && + !(Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left)) { - Cursor_displace(0, -Directional_step/16); + Cursor_displace(0, -step); } // Directional controller RIGHT - if ((Directional_up_right||Directional_right||Directional_down_right) && - !(Directional_down_left||Directional_left||Directional_up_left)) + if ((Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right) && + !(Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left)) { - Cursor_displace(Directional_step/16,0); + Cursor_displace(step,0); } // Directional controller DOWN - if ((Directional_down_right||Directional_down||Directional_down_left) && - !(Directional_up_left||Directional_up||Directional_up_right)) + if ((Directional_down_right||Directional_down||Directional_emulated_down||Directional_down_left) && + !(Directional_up_left||Directional_up||Directional_emulated_up||Directional_up_right)) { - Cursor_displace(0, Directional_step/16); + Cursor_displace(0, step); } // Directional controller LEFT - if ((Directional_down_left||Directional_left||Directional_up_left) && - !(Directional_up_right||Directional_right||Directional_down_right)) + if ((Directional_down_left||Directional_left||Directional_emulated_left||Directional_up_left) && + !(Directional_up_right||Directional_right||Directional_emulated_right||Directional_down_right)) { - Cursor_displace(-Directional_step/16,0); + Cursor_displace(-step,0); } } } @@ -757,14 +1037,15 @@ int Get_input(void) { Compute_paintbrush_coordinates(); Display_cursor(); + return 1; } - // Commit any pending screen update. - // This is done in this function because it's called after reading - // some user input. - Flush_update(); - + if (user_feedback_required) + return 1; - return (Mouse_moved!=0) || user_feedback_required; + // Nothing significant happened + if (sleep_time) + SDL_Delay(sleep_time); + return 0; } void Adjust_mouse_sensitivity(word fullscreen) @@ -796,3 +1077,74 @@ void Set_mouse_position(void) Mouse_virtual_y_position = 12*Mouse_Y*Pixel_height; } } + +int Color_cycling(__attribute__((unused)) void* useless) +{ + static byte offset[16]; + int i, color; + static SDL_Color PaletteSDL[256]; + int changed; // boolean : true if the palette needs a change in this tick. + + long now; + static long start=0; + + if (start==0) + { + // First run + start = SDL_GetTicks(); + return 1; + } + if (!Allow_colorcycling || !Cycling_mode) + return 1; + + + now = SDL_GetTicks(); + changed=0; + + // Check all cycles for a change at this tick + for (i=0; i<16; i++) + { + int len; + + len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; + if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) + { + int new_offset; + + new_offset=(now-start)/(int)(1000.0/(Main_backups->Pages->Gradients->Range[i].Speed*0.2856)) % len; + if (!Main_backups->Pages->Gradients->Range[i].Inverse) + new_offset=len - new_offset; + + if (new_offset!=offset[i]) + changed=1; + offset[i]=new_offset; + } + } + if (changed) + { + // Initialize the palette + for(color=0;color<256;color++) + { + PaletteSDL[color].r=Main_palette[color].R; + PaletteSDL[color].g=Main_palette[color].G; + PaletteSDL[color].b=Main_palette[color].B; + } + for (i=0; i<16; i++) + { + int len; + + len=Main_backups->Pages->Gradients->Range[i].End-Main_backups->Pages->Gradients->Range[i].Start+1; + if (len>1 && Main_backups->Pages->Gradients->Range[i].Speed) + { + for(color=Main_backups->Pages->Gradients->Range[i].Start;color<=Main_backups->Pages->Gradients->Range[i].End;color++) + { + PaletteSDL[color].r=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].R; + PaletteSDL[color].g=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].G; + PaletteSDL[color].b=Main_palette[Main_backups->Pages->Gradients->Range[i].Start+((color-Main_backups->Pages->Gradients->Range[i].Start+offset[i])%len)].B; + } + } + } + SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, PaletteSDL,0,256); + } + return 0; +} diff --git a/src/input.h b/src/input.h index dee65dd7..9ee0d7e7 100644 --- a/src/input.h +++ b/src/input.h @@ -33,11 +33,14 @@ /// The latest input variables are held in ::Key, ::Key_ANSI, ::Mouse_X, ::Mouse_Y, ::Mouse_K. /// Note that ::Key and ::Key_ANSI are not persistent, they will be reset to 0 /// on subsequent calls to ::Get_input(). -int Get_input(void); +int Get_input(int sleep_time); /// Returns true if the keycode has been set as a keyboard shortcut for the function. int Is_shortcut(word key, word function); +/// Returns true if the function has any shortcut key. +int Has_shortcut(word function); + /// Adjust mouse sensitivity (and actual mouse input mode) void Adjust_mouse_sensitivity(word fullscreen); @@ -56,3 +59,8 @@ extern int Snap_axis; extern int Snap_axis_origin_X; /// For the :Snap_axis mode, sets the origin's point (in image coordinates) extern int Snap_axis_origin_Y; + +/// +/// This malloced string is set when a drag-and-drop event +/// brings a file to Grafx2's window. +extern char * Drop_file_name; diff --git a/src/io.c b/src/io.c index 4707ed3c..d770a84f 100644 --- a/src/io.c +++ b/src/io.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -32,14 +33,24 @@ #include #include -#if defined(__amigaos4__) +#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) #include + #include #include + #define isHidden(x) (0) #elif defined(__WIN32__) #include #include + //#include + #define isHidden(x) (GetFileAttributesA((x)->d_name)&FILE_ATTRIBUTE_HIDDEN) +#elif defined(__MINT__) + #include + #include + #include + #define isHidden(x) (0) #else #include + #define isHidden(x) ((x)->d_name[0]=='.') #endif #include "struct.h" @@ -276,6 +287,38 @@ void For_each_file(const char * directory_name, void Callback(const char *)) closedir(current_directory); } +/// Scans a directory, calls Callback for each file or directory in it, +void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)) +{ + // Pour scan de répertoire + DIR* current_directory; //Répertoire courant + struct dirent* entry; // Structure de lecture des éléments + char full_filename[MAX_PATH_CHARACTERS]; + int filename_position; + strcpy(full_filename, directory_name); + current_directory=opendir(directory_name); + if(current_directory == NULL) return; // Répertoire invalide ... + filename_position = strlen(full_filename); + if (filename_position==0 || strcmp(full_filename+filename_position-1,PATH_SEPARATOR)) + { + strcat(full_filename, PATH_SEPARATOR); + filename_position = strlen(full_filename); + } + while ((entry=readdir(current_directory))) + { + struct stat Infos_enreg; + strcpy(&full_filename[filename_position], entry->d_name); + stat(full_filename,&Infos_enreg); + Callback( + full_filename, + S_ISREG(Infos_enreg.st_mode), + S_ISDIR(Infos_enreg.st_mode), + isHidden(entry)?1:0); + } + closedir(current_directory); +} + + void Get_full_filename(char * output_name, char * file_name, char * directory_name) { strcpy(output_name,directory_name); @@ -299,7 +342,7 @@ int Lock_file_handle = -1; byte Create_lock_file(const char *file_directory) { - #ifdef __amigaos__ + #if defined (__amigaos__)||(__AROS__) #warning "Missing code for your platform, please check and correct!" #else char lock_filename[MAX_PATH_CHARACTERS]; @@ -336,7 +379,7 @@ byte Create_lock_file(const char *file_directory) return -1; } #endif - #endif // __amigaos__ + #endif // __amigaos__ or __AROS__ return 0; } diff --git a/src/io.h b/src/io.h index 98cecb43..53237f3f 100644 --- a/src/io.h +++ b/src/io.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -71,6 +72,8 @@ char * Find_last_slash(const char * str); #if defined(__WIN32__) #define PATH_SEPARATOR "\\" +#elif defined(__MINT__) + #define PATH_SEPARATOR "\\" #else #define PATH_SEPARATOR "/" #endif @@ -90,6 +93,10 @@ int Directory_exists(char * directory); /// Scans a directory, calls Callback for each file in it, void For_each_file(const char * directory_name, void Callback(const char *)); +/// Scans a directory, calls Callback for each file or directory in it, +void For_each_directory_entry(const char * directory_name, void Callback(const char *, byte is_file, byte is_directory, byte is_hidden)); + + /// /// Creates a fully qualified name from a directory and filename. /// The point is simply to insert a PATH_SEPARATOR when needed. diff --git a/src/keyboard.c b/src/keyboard.c index 01071125..b459b83c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2010 Alexander Filyanov Copyright 2009 Franck Charlet Copyright 2008 Yves Rizoud Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -465,38 +466,93 @@ const char * Key_name(word key) key=key & ~(MOD_CTRL|MOD_ALT|MOD_SHIFT); - if (key>=KEY_JOYBUTTON && key<=KEY_JOYBUTTON+18) + // 99 is only a sanity check + if (key>=KEY_JOYBUTTON && key<=KEY_JOYBUTTON+99) { -#ifdef __GP2X__ char *button_name; switch(key-KEY_JOYBUTTON) - { - case GP2X_BUTTON_UP: button_name="[UP]"; break; - case GP2X_BUTTON_DOWN: button_name="[DOWN]"; break; - case GP2X_BUTTON_LEFT: button_name="[LEFT]"; break; - case GP2X_BUTTON_RIGHT: button_name="[RIGHT]"; break; - case GP2X_BUTTON_UPLEFT: button_name="[UP-LEFT]"; break; - case GP2X_BUTTON_UPRIGHT: button_name="[UP-RIGHT]"; break; - case GP2X_BUTTON_DOWNLEFT: button_name="[DOWN-LEFT]"; break; - case GP2X_BUTTON_DOWNRIGHT: button_name="[DOWN-RIGHT]"; break; - case GP2X_BUTTON_CLICK: button_name="[CLICK]"; break; - case GP2X_BUTTON_A: button_name="[A]"; break; - case GP2X_BUTTON_B: button_name="[B]"; break; - case GP2X_BUTTON_X: button_name="[X]"; break; - case GP2X_BUTTON_Y: button_name="[Y]"; break; - case GP2X_BUTTON_L: button_name="[L]"; break; - case GP2X_BUTTON_R: button_name="[R]"; break; - case GP2X_BUTTON_START: button_name="[START]"; break; - case GP2X_BUTTON_SELECT: button_name="[SELECT]"; break; - case GP2X_BUTTON_VOLUP: button_name="[VOL UP]"; break; - case GP2X_BUTTON_VOLDOWN: button_name="[VOL DOWN]"; break; - default: sprintf(buffer+strlen(buffer), "[B%d]", key);return buffer; + { + #ifdef JOY_BUTTON_UP + case JOY_BUTTON_UP: button_name="[UP]"; break; + #endif + #ifdef JOY_BUTTON_DOWN + case JOY_BUTTON_DOWN: button_name="[DOWN]"; break; + #endif + #ifdef JOY_BUTTON_LEFT + case JOY_BUTTON_LEFT: button_name="[LEFT]"; break; + #endif + #ifdef JOY_BUTTON_RIGHT + case JOY_BUTTON_RIGHT: button_name="[RIGHT]"; break; + #endif + #ifdef JOY_BUTTON_UPLEFT + case JOY_BUTTON_UPLEFT: button_name="[UP-LEFT]"; break; + #endif + #ifdef JOY_BUTTON_UPRIGHT + case JOY_BUTTON_UPRIGHT: button_name="[UP-RIGHT]"; break; + #endif + #ifdef JOY_BUTTON_DOWNLEFT + case JOY_BUTTON_DOWNLEFT: button_name="[DOWN-LEFT]"; break; + #endif + #ifdef JOY_BUTTON_DOWNRIGHT + case JOY_BUTTON_DOWNRIGHT: button_name="[DOWN-RIGHT]"; break; + #endif + #ifdef JOY_BUTTON_CLICK + case JOY_BUTTON_CLICK: button_name="[CLICK]"; break; + #endif + #ifdef JOY_BUTTON_A + case JOY_BUTTON_A: button_name="[A]"; break; + #endif + #ifdef JOY_BUTTON_B + case JOY_BUTTON_B: button_name="[B]"; break; + #endif + #ifdef JOY_BUTTON_X + case JOY_BUTTON_X: button_name="[X]"; break; + #endif + #ifdef JOY_BUTTON_Y + case JOY_BUTTON_Y: button_name="[Y]"; break; + #endif + #ifdef JOY_BUTTON_L + case JOY_BUTTON_L: button_name="[L]"; break; + #endif + #ifdef JOY_BUTTON_R + case JOY_BUTTON_R: button_name="[R]"; break; + #endif + #ifdef JOY_BUTTON_START + case JOY_BUTTON_START: button_name="[START]"; break; + #endif + #ifdef JOY_BUTTON_SELECT + case JOY_BUTTON_SELECT: button_name="[SELECT]"; break; + #endif + #ifdef JOY_BUTTON_VOLUP + case JOY_BUTTON_VOLUP: button_name="[VOL UP]"; break; + #endif + #ifdef JOY_BUTTON_VOLDOWN + case JOY_BUTTON_VOLDOWN: button_name="[VOL DOWN]"; break; + #endif + #ifdef JOY_BUTTON_MENU + case JOY_BUTTON_MENU: button_name="[MENU]"; break; + #endif + #ifdef JOY_BUTTON_HOME + case JOY_BUTTON_HOME: button_name="[HOME]"; break; + #endif + #ifdef JOY_BUTTON_HOLD + case JOY_BUTTON_HOLD: button_name="[HOLD]"; break; + #endif + #ifdef JOY_BUTTON_I + case JOY_BUTTON_I: button_name="[BUTTON I]"; break; + #endif + #ifdef JOY_BUTTON_II + case JOY_BUTTON_II: button_name="[BUTTON II]"; break; + #endif + #ifdef JOY_BUTTON_JOY + case JOY_BUTTON_JOY: button_name="[THUMB JOY]"; break; + #endif + + default: sprintf(buffer+strlen(buffer), "[B%d]", key-KEY_JOYBUTTON);return buffer; } strcat(buffer,button_name); -#else - sprintf(buffer+strlen(buffer), "[B%d]", key-KEY_JOYBUTTON); -#endif + return buffer; } diff --git a/src/loadsave.c b/src/loadsave.c index b8f1075e..87238a54 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -2,6 +2,8 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski + Copyright 2010 Alexander Filyanov Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -47,6 +49,8 @@ #include "struct.h" #include "windows.h" #include "engine.h" +#include "brush.h" +#include "setup.h" // -- PKM ------------------------------------------------------------------- void Test_PKM(T_IO_Context *); @@ -121,6 +125,10 @@ void Save_C64(T_IO_Context *); // -- SCR (Amstrad CPC) void Save_SCR(T_IO_Context *); +// -- XPM (X PixMap) +// Loading is done through SDL_Image +void Save_XPM(T_IO_Context*); + // -- PNG ------------------------------------------------------------------- #ifndef __no_pnglib__ void Test_PNG(T_IO_Context *); @@ -133,7 +141,7 @@ void Save_PNG(T_IO_Context *); void Load_SDL_Image(T_IO_Context *); // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts -T_Format File_formats[NB_KNOWN_FORMATS] = { +T_Format File_formats[] = { {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, @@ -143,7 +151,7 @@ T_Format File_formats[NB_KNOWN_FORMATS] = { {FORMAT_BMP, " bmp", Test_BMP, Load_BMP, Save_BMP, 0, 0, 0, "bmp", "bmp"}, {FORMAT_PCX, " pcx", Test_PCX, Load_PCX, Save_PCX, 0, 0, 0, "pcx", "pcx"}, {FORMAT_PKM, " pkm", Test_PKM, Load_PKM, Save_PKM, 0, 1, 0, "pkm", "pkm"}, - {FORMAT_LBM, " lbm", Test_LBM, Load_LBM, Save_LBM, 0, 0, 0, "lbm", "lbm;iff"}, + {FORMAT_LBM, " lbm", Test_LBM, Load_LBM, Save_LBM, 0, 0, 0, "lbm", "lbm;iff;ilbm"}, {FORMAT_IMG, " img", Test_IMG, Load_IMG, Save_IMG, 0, 0, 0, "img", "img"}, {FORMAT_SCx, " sc?", Test_SCx, Load_SCx, Save_SCx, 0, 0, 0, "sc?", "sci;scq;scf;scn;sco"}, {FORMAT_PI1, " pi1", Test_PI1, Load_PI1, Save_PI1, 0, 0, 0, "pi1", "pi1"}, @@ -154,9 +162,16 @@ T_Format File_formats[NB_KNOWN_FORMATS] = { {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa;koala;fli;bml;cdu;prg"}, {FORMAT_SCR, " cpc", NULL, NULL, Save_SCR, 0, 0, 0, "cpc", "cpc;scr"}, + {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, }; +/// Total number of known file formats +unsigned int Nb_known_formats(void) +{ + return sizeof(File_formats)/sizeof(File_formats[0]); +} + /// Set the color of a pixel (on load) void Set_pixel(T_IO_Context *context, short x_pos, short y_pos, byte color) { @@ -180,38 +195,32 @@ void Set_pixel(T_IO_Context *context, short x_pos, short y_pos, byte color) // Chargement des pixels dans la preview case CONTEXT_PREVIEW: // Skip pixels of transparent index if : - // - It's the first layer, and image has transparent background. - // - or it's a layer above the first one - if (color == context->Transparent_color && (context->Current_layer > 0 || context->Background_transparent)) + // it's a layer above the first one + if (color == context->Transparent_color && context->Current_layer > 0) break; + if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) { + // Tag the color as 'used' + context->Preview_usage[color]=1; + + // Store pixel if (context->Ratio == PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) { - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X*2), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X*2)+1, - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); + context->Preview_bitmap[x_pos/context->Preview_factor_X*2 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; + context->Preview_bitmap[x_pos/context->Preview_factor_X*2+1 + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } else if (context->Ratio == PIXEL_TALL && Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2) { - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y*2), - color); - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y*2)+1, - color); + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2)*PREVIEW_WIDTH*Menu_factor_X]=color; + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y*2+1)*PREVIEW_WIDTH*Menu_factor_X]=color; } else - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; @@ -234,8 +243,6 @@ void Palette_loaded(T_IO_Context *context) { case CONTEXT_MAIN_IMAGE: case CONTEXT_PREVIEW: - Set_palette(context->Palette); - break; case CONTEXT_BRUSH: case CONTEXT_SURFACE: break; @@ -243,67 +250,7 @@ void Palette_loaded(T_IO_Context *context) switch (context->Type) { - case CONTEXT_PREVIEW: - - Compute_optimal_menu_colors(context->Palette); - /* - if( - ( - context->Palette[MC_Black].R==context->Palette[MC_Dark].R && - context->Palette[MC_Black].G==context->Palette[MC_Dark].G && - context->Palette[MC_Black].B==context->Palette[MC_Dark].B - ) || - ( - context->Palette[MC_Light].R==context->Palette[MC_Dark].R && - context->Palette[MC_Light].G==context->Palette[MC_Dark].G && - context->Palette[MC_Light].B==context->Palette[MC_Dark].B - ) || - ( - context->Palette[MC_White].R==context->Palette[MC_Light].R && - context->Palette[MC_White].G==context->Palette[MC_Light].G && - context->Palette[MC_White].B==context->Palette[MC_Light].B - ) - ) - - { - // Si on charge une image monochrome, le fileselect ne sera plus visible. Dans ce cas on force quelques couleurs à des valeurs sures - - int black = - Main_palette[MC_Black].R + - Main_palette[MC_Black].G + - Main_palette[MC_Black].B; - int white = - Main_palette[MC_White].R + - Main_palette[MC_White].G + - Main_palette[MC_White].B; - - //Set_color(MC_Light,(2*white+black)/9,(2*white+black)/9,(2*white+black)/9); - //Set_color(MC_Dark,(2*black+white)/9,(2*black+white)/9,(2*black+white)/9); - Main_palette[MC_Dark].R=(2*black+white)/9; - Main_palette[MC_Dark].G=(2*black+white)/9; - Main_palette[MC_Dark].B=(2*black+white)/9; - Main_palette[MC_Light].R=(2*white+black)/9; - Main_palette[MC_Light].G=(2*white+black)/9; - Main_palette[MC_Light].B=(2*white+black)/9; - - Set_palette(Main_palette); - } - */ - Remap_screen_after_menu_colors_change(); - - // Preview palette - if (Get_fileformat(context->Format)->Palette_only) - { - short index; - - if (context->Type == CONTEXT_PREVIEW) - for (index=0; index<256; index++) - Window_rectangle(183+(index/16)*7,95+(index&15)*5,5,5,index); - - Update_window_area(183,95,120,80); - } - break; - + case CONTEXT_PREVIEW: case CONTEXT_MAIN_IMAGE: case CONTEXT_BRUSH: case CONTEXT_SURFACE: @@ -336,17 +283,17 @@ void Set_pixel_24b(T_IO_Context *context, short x_pos, short y_pos, byte r, byte break; case CONTEXT_PREVIEW: - { - if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) - { - color=((r >> 5) << 5) | - ((g >> 5) << 2) | - ((b >> 6)); - Pixel(context->Preview_pos_X+(x_pos/context->Preview_factor_X), - context->Preview_pos_Y+(y_pos/context->Preview_factor_Y), - color); - } + if (((x_pos % context->Preview_factor_X)==0) && ((y_pos % context->Preview_factor_Y)==0)) + { + color=((r >> 5) << 5) | + ((g >> 5) << 2) | + ((b >> 6)); + + // Tag the color as 'used' + context->Preview_usage[color]=1; + + context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; } break; } @@ -388,6 +335,11 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, // Preview case CONTEXT_PREVIEW: // Préparation du chargement d'une preview: + + context->Preview_bitmap=malloc(PREVIEW_WIDTH*PREVIEW_HEIGHT*Menu_factor_X*Menu_factor_Y); + if (!context->Preview_bitmap) + File_error=1; + // Affichage des données "Image size:" if ((width<10000) && (height<10000)) { @@ -426,11 +378,12 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, { Print_in_window( 59,59,Get_fileformat(format)->Label,MC_Black,MC_Light); } - + // On efface le commentaire précédent Window_rectangle(45,70,32*8,8,MC_Light); // Affichage du commentaire - Print_in_window(45,70,context->Comment,MC_Black,MC_Light); + if (Get_fileformat(format)->Comment) + Print_in_window(45,70,Main_comment,MC_Black,MC_Light); // Calcul des données nécessaires à l'affichage de la preview: if (ratio == PIXEL_WIDE && @@ -442,8 +395,8 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, Pixel_ratio != PIXEL_TALL2) height*=2; - context->Preview_factor_X=Round_div_max(width,122*Menu_factor_X); - context->Preview_factor_Y=Round_div_max(height, 82*Menu_factor_Y); + context->Preview_factor_X=Round_div_max(width,120*Menu_factor_X); + context->Preview_factor_Y=Round_div_max(height, 80*Menu_factor_Y); if ( (!Config.Maximize_preview) && (context->Preview_factor_X!=context->Preview_factor_Y) ) { @@ -457,17 +410,17 @@ void Pre_load(T_IO_Context *context, short width, short height, long file_size, context->Preview_pos_Y=Window_pos_Y+ 95*Menu_factor_Y; // On nettoie la zone où va s'afficher la preview: - Window_rectangle(183,95,120,80,MC_Light); + Window_rectangle(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT,MC_Light); // Un update pour couvrir les 4 zones: 3 libellés plus le commentaire Update_window_area(45,48,256,30); // Zone de preview - Update_window_area(183,95,120,80); + Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); break; // Other loading case CONTEXT_MAIN_IMAGE: - if (Backup_with_new_dimensions(0,1,width,height)) + if (Backup_new_image(1,width,height)) { // La nouvelle page a pu être allouée, elle est pour l'instant pleine // de 0s. Elle fait Main_image_width de large. @@ -605,7 +558,10 @@ void Load_image(T_IO_Context *context) { unsigned int index; // index de balayage des formats T_Format *format = &(File_formats[2]); // Format du fichier à charger - + int i; + + // Not sure it's the best place... + context->Color_cycles=0; // On place par défaut File_error à vrai au cas où on ne sache pas // charger le format du fichier: @@ -622,7 +578,7 @@ void Load_image(T_IO_Context *context) { // Sinon, on va devoir scanner les différents formats qu'on connait pour // savoir à quel format est le fichier: - for (index=0; index < NB_KNOWN_FORMATS; index++) + for (index=0; index < Nb_known_formats(); index++) { format = Get_fileformat(index); // Loadable format @@ -714,7 +670,7 @@ void Load_image(T_IO_Context *context) case CONTEXT_SURFACE: if (Convert_24b_bitmap_to_256(context->Surface->pixels,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) - File_error=1; + File_error=1; break; } @@ -722,11 +678,34 @@ void Load_image(T_IO_Context *context) free(context->Buffer_image_24b); context->Buffer_image_24b = NULL; } + else if (context->Type == CONTEXT_MAIN_IMAGE) + { + // Non-24b main image: Add menu colors + if (Config.Safety_colors) + { + dword color_usage[256]; + memset(color_usage,0,sizeof(color_usage)); + if (Count_used_colors(color_usage)<252) + { + int gui_index=0; + int c; + for (c=255; c>=0 && gui_index<4; c--) + { + if (color_usage[c]==0) + { + context->Palette[c]=*Favorite_GUI_color(gui_index); + gui_index++; + } + } + } + } + } if (context->Type == CONTEXT_MAIN_IMAGE) { if ( File_error!=1) { + Set_palette(context->Palette); if (format->Palette_only) { // Make a backup step @@ -773,6 +752,21 @@ void Load_image(T_IO_Context *context) Main_image_width=1; if (Main_image_height<1) Main_image_height=1; + + // Color cyling ranges: + for (i=0; i<16; i++) + Main_backups->Pages->Gradients->Range[i].Speed=0; + for (i=0; iColor_cycles; i++) + { + Main_backups->Pages->Gradients->Range[i].Start=context->Cycle_range[i].Start; + Main_backups->Pages->Gradients->Range[i].End=context->Cycle_range[i].End; + Main_backups->Pages->Gradients->Range[i].Inverse=context->Cycle_range[i].Inverse; + Main_backups->Pages->Gradients->Range[i].Speed=context->Cycle_range[i].Speed; + } + + // Comment + strcpy(Main_comment, context->Comment); + } } else if (File_error!=1) @@ -791,19 +785,16 @@ void Load_image(T_IO_Context *context) } else if (context->Type == CONTEXT_BRUSH && File_error==0) { - free(Brush); - Brush=context->Buffer_image; - context->Buffer_image = NULL; - - Brush_width=context->Width; - Brush_height=context->Height; - - free(Smear_brush); - Smear_brush_width=(Brush_width>MAX_PAINTBRUSH_SIZE)?Brush_width:MAX_PAINTBRUSH_SIZE; - Smear_brush_height=(Brush_height>MAX_PAINTBRUSH_SIZE)?Brush_height:MAX_PAINTBRUSH_SIZE; - Smear_brush=(byte *)malloc(Smear_brush_width*Smear_brush_height); - if (!Smear_brush) + + if (Realloc_brush(context->Width, context->Height, context->Buffer_image, NULL)) + { File_error=3; + free(context->Buffer_image); + } + memcpy(Brush_original_palette, context->Palette, sizeof(T_Palette)); + Remap_brush(); + + context->Buffer_image = NULL; } else if (context->Type == CONTEXT_SURFACE) { @@ -822,6 +813,91 @@ void Load_image(T_IO_Context *context) SDL_SetColors(context->Surface, colors, 0, 256); } } + else if (context->Type == CONTEXT_PREVIEW + /*&& !context->Buffer_image_24b*/ + /*&& !Get_fileformat(context->Format)->Palette_only*/) + { + + // Try to adapt the palette to accomodate the GUI. + int c; + int count_unused; + byte unused_color[4]; + + count_unused=0; + // Try find 4 unused colors and insert good colors there + for (c=255; c>=0 && count_unused<4; c--) + { + if (!context->Preview_usage[c]) + { + unused_color[count_unused]=c; + count_unused++; + } + } + // Found! replace them with some favorites + if (count_unused==4) + { + int gui_index; + for (gui_index=0; gui_index<4; gui_index++) + { + context->Palette[unused_color[gui_index]]=*Favorite_GUI_color(gui_index); + } + } + // All preview display is here + + // Update palette and screen first + Compute_optimal_menu_colors(context->Palette); + Remap_screen_after_menu_colors_change(); + Set_palette(context->Palette); + + // Display palette preview + if (Get_fileformat(context->Format)->Palette_only) + { + short index; + + if (context->Type == CONTEXT_PREVIEW) + for (index=0; index<256; index++) + Window_rectangle(183+(index/16)*7,95+(index&15)*5,5,5,index); + + } + // Display normal image + else if (context->Preview_bitmap) + { + int x_pos,y_pos; + int width,height; + width=context->Width/context->Preview_factor_X; + height=context->Height/context->Preview_factor_Y; + if (context->Ratio == PIXEL_WIDE && + Pixel_ratio != PIXEL_WIDE && + Pixel_ratio != PIXEL_WIDE2) + width*=2; + else if (context->Ratio == PIXEL_TALL && + Pixel_ratio != PIXEL_TALL && + Pixel_ratio != PIXEL_TALL2) + height*=2; + + for (y_pos=0; y_posPreview_bitmap[x_pos+y_pos*PREVIEW_WIDTH*Menu_factor_X]; + + // Skip transparent if image has transparent background. + if (color == context->Transparent_color && context->Background_transparent) + color=MC_Window; + + Pixel(context->Preview_pos_X+x_pos, + context->Preview_pos_Y+y_pos, + color); + } + } + // Refresh modified part + Update_window_area(183,95,PREVIEW_WIDTH,PREVIEW_HEIGHT); + + // Preview comment + Print_in_window(45,70,context->Comment,MC_Black,MC_Light); + //Update_window_area(45,70,32*8,8); + + } + } @@ -916,8 +992,10 @@ void Load_SDL_Image(T_IO_Context *context) } else { - // Hi/Trucolor - Pre_load(context, surface->w, surface->h, file_size ,FORMAT_ALL_IMAGES, PIXEL_SIMPLE, 1); + { + // Hi/Trucolor + Pre_load(context, surface->w, surface->h, file_size ,FORMAT_ALL_IMAGES, PIXEL_SIMPLE, 1); + } for (y_pos=0; y_posHeight; y_pos++) { @@ -938,8 +1016,10 @@ void Load_SDL_Image(T_IO_Context *context) SDL_FreeSurface(surface); } +/// /// Load an arbitrary SDL_Surface. -SDL_Surface * Load_surface(char *full_name) +/// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise +SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients) { SDL_Surface * bmp=NULL; T_IO_Context context; @@ -948,8 +1028,23 @@ SDL_Surface * Load_surface(char *full_name) Load_image(&context); if (context.Surface) + { bmp=context.Surface; - + // Caller wants the gradients: + if (gradients != NULL) + { + int i; + + memset(gradients, 0, sizeof(T_Gradient_array)); + for (i=0; iRange[i].Start=context.Cycle_range[i].Start; + gradients->Range[i].End=context.Cycle_range[i].End; + gradients->Range[i].Inverse=context.Cycle_range[i].Inverse; + gradients->Range[i].Speed=context.Cycle_range[i].Speed; + } + } + } Destroy_context(&context); return bmp; @@ -1011,10 +1106,12 @@ void Emergency_backup(const char *fname, byte *source, int width, int height, T_ void Image_emergency_backup() { +#ifndef NOLAYERS if (Main_backups && Main_backups->Pages && Main_backups->Pages->Nb_layers == 1) - Emergency_backup("a999999.bkp",Main_screen, Main_image_width, Main_image_height, &Main_palette); + Emergency_backup(SAFETYBACKUP_PREFIX_A "999999" BACKUP_FILE_EXTENSION,Main_screen, Main_image_width, Main_image_height, &Main_palette); if (Spare_backups && Spare_backups->Pages && Spare_backups->Pages->Nb_layers == 1) - Emergency_backup("b999999.bkp",Spare_visible_image.Image, Spare_image_width, Spare_image_height, &Spare_palette); + Emergency_backup(SAFETYBACKUP_PREFIX_B "999999" BACKUP_FILE_EXTENSION,Spare_visible_image.Image, Spare_image_width, Spare_image_height, &Spare_palette); +#endif } T_Format * Get_fileformat(byte format) @@ -1022,7 +1119,7 @@ T_Format * Get_fileformat(byte format) unsigned int i; T_Format * safe_default = File_formats; - for (i=0; i < NB_KNOWN_FORMATS; i++) + for (i=0; i < Nb_known_formats(); i++) { if (File_formats[i].Identifier == format) return &(File_formats[i]); @@ -1041,11 +1138,12 @@ byte Get_pixel(T_IO_Context *context, short x, short y) return *(context->Target_address + y*context->Pitch + x); } -/// Cleans up resources (currently: the 24bit buffer) +/// Cleans up resources void Destroy_context(T_IO_Context *context) { free(context->Buffer_image_24b); free(context->Buffer_image); + free(context->Preview_bitmap); memset(context, 0, sizeof(T_IO_Context)); } @@ -1069,6 +1167,8 @@ void Init_context_backup_image(T_IO_Context * context, char *file_name, char *fi /// Setup for loading/saving the current main image void Init_context_layered_image(T_IO_Context * context, char *file_name, char *file_directory) { + int i; + memset(context, 0, sizeof(T_IO_Context)); context->Type = CONTEXT_MAIN_IMAGE; @@ -1091,6 +1191,18 @@ void Init_context_layered_image(T_IO_Context * context, char *file_name, char *f context->Target_address=Main_backups->Pages->Image[0]; context->Pitch=Main_image_width; + // Color cyling ranges: + for (i=0; i<16; i++) + { + if (Main_backups->Pages->Gradients->Range[i].Start!=Main_backups->Pages->Gradients->Range[i].End) + { + context->Cycle_range[context->Color_cycles].Start=Main_backups->Pages->Gradients->Range[i].Start; + context->Cycle_range[context->Color_cycles].End=Main_backups->Pages->Gradients->Range[i].End; + context->Cycle_range[context->Color_cycles].Inverse=Main_backups->Pages->Gradients->Range[i].Inverse; + context->Cycle_range[context->Color_cycles].Speed=Main_backups->Pages->Gradients->Range[i].Speed; + context->Color_cycles++; + } + } } /// Setup for loading/saving the flattened version of current main image @@ -1332,8 +1444,13 @@ int Check_recovery(void) int restored_main; // First check if can write backups - if (Create_lock_file(Config_directory)) +#if defined (__MINT__) + //TODO: enable file lock under Freemint only + return 0; +#else +if (Create_lock_file(Config_directory)) return -1; +#endif Safety_backup_active=1; @@ -1389,7 +1506,7 @@ void Rotate_safety_backups(void) { // Clear a previous save (rotating saves) - sprintf(deleted_file, "%s%c%6.6d.bkp", + sprintf(deleted_file, "%s%c%6.6d" BACKUP_FILE_EXTENSION, Config_directory, Main_safety_backup_prefix, (Uint32)(Main_safety_number + 1000000l - Rotation_safety_backup) % (Uint32)1000000l); @@ -1400,7 +1517,7 @@ void Rotate_safety_backups(void) Main_time_of_safety_backup=now; // Create a new file name and save - sprintf(file_name, "%c%6.6d.bkp", + sprintf(file_name, "%c%6.6d" BACKUP_FILE_EXTENSION, Main_safety_backup_prefix, (Uint32)Main_safety_number); Init_context_backup_image(&context, file_name, Config_directory); @@ -1442,6 +1559,10 @@ void Delete_safety_backups(void) } // Release lock file +#if defined (__MINT__) + //TODO: release file lock under Freemint only +#else Release_lock_file(Config_directory); +#endif } diff --git a/src/loadsave.h b/src/loadsave.h index f82383b9..8fcd6376 100644 --- a/src/loadsave.h +++ b/src/loadsave.h @@ -37,6 +37,14 @@ enum CONTEXT_TYPE { CONTEXT_SURFACE, }; +/// Data for a cycling color series. Heavily cloned from T_Gradient_array. +typedef struct +{ + byte Start; ///< First color + byte End; ///< Last color + byte Inverse; ///< Boolean, true if the gradient goes in descending order + byte Speed; ///< Frequency of cycling, from 1 (slow) to 64 (fast) +} T_Color_cycle; typedef struct { @@ -71,6 +79,9 @@ typedef struct /// Original file directory, stored in GIF file char * Original_file_directory; + byte Color_cycles; + T_Color_cycle Cycle_range[16]; + /// Internal: during load, marks which layer is being loaded. short Current_layer; @@ -87,12 +98,17 @@ typedef struct short Preview_factor_Y; short Preview_pos_X; short Preview_pos_Y; + byte *Preview_bitmap; + byte Preview_usage[256]; // Internal: returned surface for SDL_Surface case SDL_Surface * Surface; } T_IO_Context; +#define PREVIEW_WIDTH 120 +#define PREVIEW_HEIGHT 80 + /// Type of a function that can be called for a T_IO_Context. Kind of a method. typedef void (* Func_IO) (T_IO_Context *); @@ -165,8 +181,10 @@ extern T_Format File_formats[]; /// is too high. void Image_emergency_backup(void); +/// /// Load an arbitrary SDL_Surface. -SDL_Surface * Load_surface(char *full_name); +/// @param gradients Pass the address of a target T_Gradient_array if you want the gradients, NULL otherwise +SDL_Surface * Load_surface(char *full_name, T_Gradient_array *gradients); /* @@ -178,12 +196,8 @@ T_Format * Get_fileformat(byte format); // -- File formats -#ifndef __no_pnglib__ -#define NB_KNOWN_FORMATS 19 ///< Total number of known file formats. -#else -// Without pnglib -#define NB_KNOWN_FORMATS 18 ///< Total number of known file formats. -#endif +/// Total number of known file formats +unsigned int Nb_known_formats(void); // Internal use @@ -210,7 +224,6 @@ void Set_layer(T_IO_Context *context, byte layer); // ================================================================= // This is here and not in fileformats.c because the emergency save uses it... -#pragma pack(1) typedef struct { byte Filler1[6]; @@ -219,7 +232,6 @@ typedef struct byte Filler2[118]; T_Palette Palette; } T_IMG_Header; -#pragma pack() // Data for 24bit loading diff --git a/src/main.c b/src/main.c index 54ce1bdb..3ba10ff9 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Pasi Kallinen Copyright 2008 Peter Gordon Copyright 2008 Franck Charlet @@ -40,7 +41,7 @@ // There is no WM on the GP2X... -#ifndef __GP2X__ +#if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) #include #endif @@ -65,11 +66,14 @@ #include "brush.h" #include "palette.h" #include "realpath.h" +#include "input.h" #if defined(__WIN32__) #include #include #define chdir(dir) SetCurrentDirectory(dir) +#elif defined (__MINT__) + #include #elif defined(__macosx__) #import #import @@ -85,6 +89,8 @@ extern DECLSPEC int SDLCALL SDL_putenv(const char *variable); #endif +extern char Program_version[]; // generated in pversion.c + //--- Affichage de la syntaxe, et de la liste des modes vidéos disponibles --- void Display_syntax(void) { @@ -139,7 +145,7 @@ void Error_function(int error_code, const char *filename, int line_number, const for (index=0;index<=255;index++) temp_palette[index].R=255; Set_palette(temp_palette); - SDL_Delay(500); + Delay_with_active_mouse(50); // Half a second of red flash Set_palette(Main_palette); } else @@ -400,22 +406,39 @@ int Analyze_command_line(int argc, char * argv[], char *main_filename, char *mai return file_in_command_line; } +// Compile-time assertions: +#define CT_ASSERT(e) extern char (*ct_assert(void)) [sizeof(char[1 - 2*!(e)])] + +// This line will raise an error at compile time +// when sizeof(T_Components) is not 3. +CT_ASSERT(sizeof(T_Components)==3); + +// This line will raise an error at compile time +// when sizeof(T_Palette) is not 768. +CT_ASSERT(sizeof(T_Palette)==768); + // ------------------------ Initialiser le programme ------------------------- // Returns 0 on fail int Init_program(int argc,char * argv[]) -{ +{ int temp; int starting_videomode; static char program_directory[MAX_PATH_CHARACTERS]; T_Gui_skin *gfx; int file_in_command_line; + T_Gradient_array initial_gradients; static char main_filename [MAX_PATH_CHARACTERS]; static char main_directory[MAX_PATH_CHARACTERS]; static char spare_filename [MAX_PATH_CHARACTERS]; static char spare_directory[MAX_PATH_CHARACTERS]; - - - + + #if defined(__MINT__) + printf("===============================\n"); + printf(" /|\\ GrafX2 %.19s\n", Program_version); + printf(" compilation date: %.16s\n", __DATE__); + printf("===============================\n"); + #endif + // On crée dès maintenant les descripteurs des listes de pages pour la page // principale et la page de brouillon afin que leurs champs ne soient pas // invalide lors des appels aux multiples fonctions manipulées à @@ -431,9 +454,12 @@ int Init_program(int argc,char * argv[]) Set_data_directory(program_directory,Data_directory); // Choose directory for settings (read/write) Set_config_directory(program_directory,Config_directory); - - // On détermine le répertoire courant: +#if defined(__MINT__) + strcpy(Main_current_directory,program_directory); +#else +// On détermine le répertoire courant: getcwd(Main_current_directory,256); +#endif // On en profite pour le mémoriser dans le répertoire principal: strcpy(Initial_directory,Main_current_directory); @@ -473,8 +499,6 @@ int Init_program(int argc,char * argv[]) // On initialise d'ot' trucs Main_offset_X=0; Main_offset_Y=0; - Old_main_offset_X=0; - Old_main_offset_Y=0; Main_separator_position=0; Main_X_zoom=0; Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; @@ -486,8 +510,6 @@ int Init_program(int argc,char * argv[]) Main_magnifier_offset_Y=0; Spare_offset_X=0; Spare_offset_Y=0; - Old_spare_offset_X=0; - Old_spare_offset_Y=0; Spare_separator_position=0; Spare_X_zoom=0; Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; @@ -497,62 +519,27 @@ int Init_program(int argc,char * argv[]) Spare_magnifier_width=0; Spare_magnifier_offset_X=0; Spare_magnifier_offset_Y=0; - Keyboard_click_allowed = 0; + Keyboard_click_allowed = 1; - Main_safety_backup_prefix = 'a'; - Spare_safety_backup_prefix = 'b'; + Main_safety_backup_prefix = SAFETYBACKUP_PREFIX_A[0]; + Spare_safety_backup_prefix = SAFETYBACKUP_PREFIX_B[0]; Main_time_of_safety_backup = 0; Spare_time_of_safety_backup = 0; // SDL - if(SDL_Init(SDL_INIT_TIMER|SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0) + if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_JOYSTICK) < 0) { // The program can't continue without that anyway printf("Couldn't initialize SDL.\n"); return(0); } - + Joystick = SDL_JoystickOpen(0); SDL_EnableKeyRepeat(250, 32); SDL_EnableUNICODE(SDL_ENABLE); SDL_WM_SetCaption("GrafX2","GrafX2"); - - { - // Routine pour définir l'icone. - char icon_path[MAX_PATH_CHARACTERS]; - SDL_Surface * icon; - sprintf(icon_path, "%s%s", Data_directory, "gfx2.gif"); - icon = IMG_Load(icon_path); - if (icon && icon->w == 32 && icon->h == 32) - { - Uint32 pink; - pink = SDL_MapRGB(icon->format, 255, 0, 255); - - if (icon->format->BitsPerPixel == 8) - { - SDL_SetColorKey(icon, SDL_SRCCOLORKEY, pink); - SDL_WM_SetIcon(icon,NULL); - } - else - { - byte *icon_mask; - int x,y; - - icon_mask=malloc(128); - memset(icon_mask,0,128); - for (y=0;y<32;y++) - for (x=0;x<32;x++) - if (Get_SDL_pixel_hicolor(icon, x, y) != pink) - icon_mask[(y*32+x)/8] |=0x80>>(x&7); - SDL_WM_SetIcon(icon,icon_mask); - free(icon_mask); - icon_mask = NULL; - } - - SDL_FreeSurface(icon); - } - } + Define_icon(); // Texte Init_text(); @@ -574,7 +561,6 @@ int Init_program(int argc,char * argv[]) // Données sur le pinceau: Paintbrush_X=0; Paintbrush_Y=0; - Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; Paintbrush_hidden=0; // On initialise tout ce qui concerne les opérations et les effets @@ -634,6 +620,25 @@ int Init_program(int argc,char * argv[]) Windows_open=0; + // Paintbrush + if (!(Paintbrush_sprite=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); + + // Load preset paintbrushes (uses Paintbrush_ variables) + Init_paintbrushes(); + + // Set a valid paintbrush afterwards + *Paintbrush_sprite=1; + Paintbrush_width=1; + Paintbrush_height=1; + Paintbrush_offset_X=0; + Paintbrush_offset_Y=0; + Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; + + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) + // Prefer cycling active by default + Cycling_mode=1; + #endif + // Charger la configuration des touches Set_config_defaults(); @@ -662,10 +667,10 @@ int Init_program(int argc,char * argv[]) Help_position=0; // Load sprites, palette etc. - gfx = Load_graphics(Config.Skin_file); + gfx = Load_graphics(Config.Skin_file, &initial_gradients); if (gfx == NULL) { - gfx = Load_graphics("skin_DPaint.png"); + gfx = Load_graphics(DEFAULT_SKIN_FILENAME, &initial_gradients); if (gfx == NULL) { printf("%s", Gui_loading_error_message); @@ -678,7 +683,10 @@ int Init_program(int argc,char * argv[]) // Gfx->Default_palette[MC_Dark] =Config.Fav_menu_colors[1]; // Gfx->Default_palette[MC_Light]=Config.Fav_menu_colors[2]; // Gfx->Default_palette[MC_White]=Config.Fav_menu_colors[3]; -// Compute_optimal_menu_colors(Gfx->Default_palette); + + // Even when using the skin's palette, if RGB range is small + // the colors will be unusable. + Compute_optimal_menu_colors(Gfx->Default_palette); // Infos sur les trames (Sieve) Sieve_mode=0; @@ -686,9 +694,9 @@ int Init_program(int argc,char * argv[]) // Font if (!(Menu_font=Load_font(Config.Font_file))) - if (!(Menu_font=Load_font("font_DPaint.png"))) + if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME))) { - printf("Unable to open the default font file: %s\n", "font_Classic.png"); + printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME); Error(ERROR_GUI_MISSING); } @@ -701,11 +709,6 @@ int Init_program(int argc,char * argv[]) if (!(Brush =(byte *)malloc( 1* 1))) Error(ERROR_MEMORY); if (!(Smear_brush =(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); - // Pinceau - if (!(Paintbrush_sprite=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); - *Paintbrush_sprite=1; - Paintbrush_width=1; - Paintbrush_height=1; starting_videomode=Current_resolution; Horizontal_line_buffer=NULL; @@ -731,6 +734,9 @@ int Init_program(int argc,char * argv[]) SetWindowPos(pInfo.window, 0, Config.Window_pos_x, Config.Window_pos_y, 0, 0, SWP_NOSIZE); } } + + // Open a console for debugging... + //ActivateConsole(); #endif Main_image_width=Screen_width/Pixel_width; @@ -745,15 +751,29 @@ int Init_program(int argc,char * argv[]) // Nettoyage de l'écran virtuel (les autres recevront celui-ci par copie) memset(Main_screen,0,Main_image_width*Main_image_height); + // Now that the backup system is there, we can store the gradients. + memcpy(Main_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); + memcpy(Spare_backups->Pages->Gradients->Range, initial_gradients.Range, sizeof(initial_gradients.Range)); + + Gradient_function=Gradient_basic; + Gradient_lower_bound=0; + Gradient_upper_bound=0; + Gradient_random_factor=1; + Gradient_bounds_range=1; + + Current_gradient=0; + // Initialisation de diverses variables par calcul: Compute_magnifier_data(); Compute_limits(); Compute_paintbrush_coordinates(); // On affiche le menu: - Display_menu(); Display_paintbrush_in_menu(); - Display_sprite_in_menu(BUTTON_PAL_LEFT,18+(Config.Palette_vertical!=0)); + Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); + Display_menu(); + Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); + Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); // On affiche le curseur pour débutter correctement l'état du programme: Display_cursor(); @@ -770,8 +790,11 @@ int Init_program(int argc,char * argv[]) // On initialise la brosse initiale à 1 pixel blanc: Brush_width=1; Brush_height=1; + for (temp=0;temp<256;temp++) + Brush_colormap[temp]=temp; Capture_brush(0,0,0,0,0); *Brush=MC_White; + *Brush_original_pixels=MC_White; // Test de recuperation de fichiers sauvés switch (Check_recovery()) @@ -843,6 +866,9 @@ int Init_program(int argc,char * argv[]) break; } } + + Allow_drag_and_drop(1); + return(1); } @@ -908,6 +934,12 @@ void Program_shutdown(void) Error(ERROR_MISSING_DIRECTORY); SDL_Quit(); + + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) + chdir("/usr/gp2x"); + execl("/usr/gp2x/gp2xmenu", "/usr/gp2x/gp2xmenu", NULL); + #endif + } diff --git a/src/misc.c b/src/misc.c index de374850..932cde1d 100644 --- a/src/misc.c +++ b/src/misc.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues @@ -177,7 +178,8 @@ void Wait_end_of_click(void) { // On désactive tous les raccourcis clavier - while(Mouse_K) if(!Get_input()) SDL_Delay(20); + while(Mouse_K) + Get_input(20); } void Clear_current_image_with_stencil(byte color, byte * stencil) @@ -339,7 +341,7 @@ void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short heig // Replace une couleur par une autre dans un buffer -void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,short height,short buffer_width) +void Remap_general_lowlevel(byte * conversion_table,byte * in_buffer, byte *out_buffer,short width,short height,short buffer_width) { int dx,cx; @@ -349,17 +351,19 @@ void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,sh // Pour chaque pixel for(cx=width;cx>0;cx--) { - *buffer = conversion_table[*buffer]; - buffer++; + *out_buffer = conversion_table[*in_buffer]; + in_buffer++; + out_buffer++; } - buffer += buffer_width-width; + in_buffer += buffer_width-width; + out_buffer += buffer_width-width; } } void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width) { byte* src=start_y*image_width+start_x+Main_backups->Pages->Image[Main_current_layer]; //Adr départ image (ESI) - byte* dest=Brush; //Adr dest brosse (EDI) + byte* dest=Brush_original_pixels; //Adr dest brosse (EDI) int dx; for (dx=Brush_height;dx!=0;dx--) @@ -499,6 +503,22 @@ byte Effect_substractive_colorize(word x,word y,byte color) blueTimer_start) Timer_state=1; @@ -659,17 +679,6 @@ void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buff } } -void Slider_timer(byte speed) - //Boucle d'attente pour faire bouger les scrollbars à une vitesse correcte -{ - Uint32 end; - byte original_mouse_k = Mouse_K; - end = SDL_GetTicks() + speed*10; - do - { - if (!Get_input()) SDL_Delay(20); - } while (Mouse_K == original_mouse_k && SDL_GetTicks() +#elif defined(__MINT__) + #include + #include #elif defined(__SKYOS__) #include #else #include // sysinfo() for free RAM #endif +#if defined (__MINT__) +// atari have two kinds of memory +// standard and fast ram +void Atari_Memory_free(unsigned long *stRam,unsigned long *ttRam){ + //TODO: return STRAM/TT-RAM + unsigned long mem=0; + *stRam=Mxalloc(-1L,0); + *ttRam = Mxalloc(-1L,1); +} +#else // Indique quelle est la mémoire disponible unsigned long Memory_free(void) { @@ -778,6 +800,8 @@ unsigned long Memory_free(void) return info.freeram*info.mem_unit; #endif } +#endif + // Arrondir un nombre réel à la valeur entière la plus proche diff --git a/src/misc.h b/src/misc.h index bd365211..cee6f39c 100644 --- a/src/misc.h +++ b/src/misc.h @@ -33,7 +33,7 @@ #define SWAP_PBYTES(a,b) { byte * c=a; a=b; b=c;} void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width); -void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,short height,short buffer_width); +void Remap_general_lowlevel(byte * conversion_table,byte * in_buffer, byte *out_buffer,short width,short height,short buffer_width); void Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset); void Wait_end_of_click(void); void Set_color(byte color, byte red, byte green, byte blue); @@ -42,7 +42,6 @@ void Palette_256_to_64(T_Palette palette); void Palette_64_to_256(T_Palette palette); void Clear_current_image(byte color); void Clear_current_image_with_stencil(byte color, byte * stencil); -void Slider_timer(byte speed); dword Round_div(dword numerator,dword divisor); word Count_used_colors(dword * usage); word Count_used_colors_area(dword* usage, word start_x, word start_y, word width, word height); @@ -86,6 +85,7 @@ void Replace_colors_within_limits(byte * replace_table); byte Effect_interpolated_colorize (word x,word y,byte color); byte Effect_additive_colorize (word x,word y,byte color); byte Effect_substractive_colorize(word x,word y,byte color); +byte Effect_alpha_colorize(word x,word y,byte color); byte Effect_sieve(word x,word y); /// diff --git a/src/miscfileformats.c b/src/miscfileformats.c index 28453236..dd3c518c 100644 --- a/src/miscfileformats.c +++ b/src/miscfileformats.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2009 Petter Lindquist Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -368,7 +369,8 @@ void Load_PKM(T_IO_Context * context) Compteur_de_donnees_packees=0; Compteur_de_pixels=0; - Taille_pack=(file_size)-sizeof(T_PKM_Header)-header.Jump; + // Header size is 780 + Taille_pack=(file_size)-780-header.Jump; // Boucle de décompression: while ( (Compteur_de_pixels>1)*header1.Height)!=size ) ) { // Tentative de reconnaissance de la signature des nouveaux fichiers @@ -735,7 +735,7 @@ void Load_CEL(T_IO_Context * context) short y_pos; byte last_byte=0; long file_size; - const long int header_size = (long int)(sizeof(header1.Width)+sizeof(header1.Height)); + const long int header_size = 4; File_error=0; Get_full_filename(filename, context->File_name, context->File_directory); @@ -775,7 +775,7 @@ void Load_CEL(T_IO_Context * context) // On réessaye avec le nouveau format fseek(file,0,SEEK_SET); - if (Read_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) @@ -783,7 +783,7 @@ void Load_CEL(T_IO_Context * context) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) - && Read_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Read_bytes(file,header2.Filler2,16) ) { // Chargement d'un fichier CEL avec signature (nouveaux fichiers) @@ -942,7 +942,7 @@ void Save_CEL(T_IO_Context * context) for (x_pos=0;x_pos<16;x_pos++) // Initialisation du filler 2 (?) header2.Filler2[x_pos]=0; - if (Write_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Write_bytes(file,header2.Signature,4) && Write_byte(file,header2.Kind) && Write_byte(file,header2.Nb_bits) && Write_word_le(file,header2.Filler1) @@ -950,7 +950,7 @@ void Save_CEL(T_IO_Context * context) && Write_word_le(file,header2.Height) && Write_word_le(file,header2.X_offset) && Write_word_le(file,header2.Y_offset) - && Write_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Write_bytes(file,header2.Filler2,14) ) { // Sauvegarde de l'image @@ -974,7 +974,6 @@ void Save_CEL(T_IO_Context * context) //////////////////////////////////// KCF //////////////////////////////////// -#pragma pack(1) typedef struct { struct @@ -986,7 +985,6 @@ typedef struct } color[16]; } Palette[10]; } T_KCF_Header; -#pragma pack() // -- Tester si un fichier est au format KCF -------------------------------- @@ -994,7 +992,7 @@ void Test_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; - T_KCF_Header buffer; + T_KCF_Header header1; T_CEL_Header2 header2; int pal_index; int color_index; @@ -1003,18 +1001,22 @@ void Test_KCF(T_IO_Context * context) Get_full_filename(filename, context->File_name, context->File_directory); if ((file=fopen(filename, "rb"))) { - if (File_length_file(file)==sizeof(T_KCF_Header)) + if (File_length_file(file)==320) { - Read_bytes(file,&buffer,sizeof(T_KCF_Header)); + for (pal_index=0;pal_index<10 && !File_error;pal_index++) + for (color_index=0;color_index<16 && !File_error;color_index++) + if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || + !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) + File_error=1; // On vérifie une propriété de la structure de palette: for (pal_index=0;pal_index<10;pal_index++) for (color_index=0;color_index<16;color_index++) - if ((buffer.Palette[pal_index].color[color_index].Byte2>>4)!=0) + if ((header1.Palette[pal_index].color[color_index].Byte2>>4)!=0) File_error=1; } else { - if (Read_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) @@ -1022,7 +1024,7 @@ void Test_KCF(T_IO_Context * context) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) - && Read_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Read_bytes(file,header2.Filler2,14) ) { if (memcmp(header2.Signature,"KiSS",4)==0) @@ -1049,7 +1051,7 @@ void Load_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; - T_KCF_Header buffer; + T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; @@ -1063,11 +1065,16 @@ void Load_KCF(T_IO_Context * context) if ((file=fopen(filename, "rb"))) { file_size=File_length_file(file); - if (file_size==sizeof(T_KCF_Header)) + if (file_size==320) { // Fichier KCF à l'ancien format + for (pal_index=0;pal_index<10 && !File_error;pal_index++) + for (color_index=0;color_index<16 && !File_error;color_index++) + if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) || + !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2)) + File_error=1; - if (Read_bytes(file,&buffer,sizeof(T_KCF_Header))) + if (!File_error) { // Pre_load(context, ?); // Pas possible... pas d'image... @@ -1079,9 +1086,9 @@ void Load_KCF(T_IO_Context * context) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; - context->Palette[index].R=((buffer.Palette[pal_index].color[color_index].Byte1 >> 4) << 4); - context->Palette[index].B=((buffer.Palette[pal_index].color[color_index].Byte1 & 15) << 4); - context->Palette[index].G=((buffer.Palette[pal_index].color[color_index].Byte2 & 15) << 4); + context->Palette[index].R=((header1.Palette[pal_index].color[color_index].Byte1 >> 4) << 4); + context->Palette[index].B=((header1.Palette[pal_index].color[color_index].Byte1 & 15) << 4); + context->Palette[index].G=((header1.Palette[pal_index].color[color_index].Byte2 & 15) << 4); } for (index=0;index<16;index++) @@ -1100,7 +1107,7 @@ void Load_KCF(T_IO_Context * context) { // Fichier KCF au nouveau format - if (Read_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (Read_bytes(file,header2.Signature,4) && Read_byte(file,&(header2.Kind)) && Read_byte(file,&(header2.Nb_bits)) && Read_word_le(file,&(header2.Filler1)) @@ -1108,7 +1115,7 @@ void Load_KCF(T_IO_Context * context) && Read_word_le(file,&(header2.Height)) && Read_word_le(file,&(header2.X_offset)) && Read_word_le(file,&(header2.Y_offset)) - && Read_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + && Read_bytes(file,header2.Filler2,14) ) { // Pre_load(context, ?); // Pas possible... pas d'image... @@ -1168,7 +1175,7 @@ void Save_KCF(T_IO_Context * context) { char filename[MAX_PATH_CHARACTERS]; FILE *file; - T_KCF_Header buffer; + T_KCF_Header header1; T_CEL_Header2 header2; byte bytes[3]; int pal_index; @@ -1196,12 +1203,16 @@ void Save_KCF(T_IO_Context * context) for (color_index=0;color_index<16;color_index++) { index=16+(pal_index*16)+color_index; - buffer.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4); - buffer.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4; + header1.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4); + header1.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4; } - if (! Write_bytes(file,&buffer,sizeof(T_KCF_Header))) - File_error=1; + // Write all + for (pal_index=0;pal_index<10 && !File_error;pal_index++) + for (color_index=0;color_index<16 && !File_error;color_index++) + if (!Write_byte(file,header1.Palette[pal_index].color[color_index].Byte1) || + !Write_byte(file,header1.Palette[pal_index].color[color_index].Byte2)) + File_error=1; } else { @@ -1218,7 +1229,7 @@ void Save_KCF(T_IO_Context * context) for (index=0;index<16;index++) // Initialisation du filler 2 (?) header2.Filler2[index]=0; - if (!Write_bytes(file,header2.Signature,sizeof(header2.Signature)) + if (!Write_bytes(file,header2.Signature,4) || !Write_byte(file,header2.Kind) || !Write_byte(file,header2.Nb_bits) || !Write_word_le(file,header2.Filler1) @@ -1226,7 +1237,7 @@ void Save_KCF(T_IO_Context * context) || !Write_word_le(file,header2.Height) || !Write_word_le(file,header2.X_offset) || !Write_word_le(file,header2.Y_offset) - || !Write_bytes(file,header2.Filler2,sizeof(header2.Filler2)) + || !Write_bytes(file,header2.Filler2,14) ) File_error=1; @@ -1322,17 +1333,29 @@ void PI1_decode_palette(byte * src,byte * palette) // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 - + ip=0; for (i=0;i<16;i++) { - w=((word)src[(i*2)+1]<<8) | src[(i*2)+0]; - - // Traitement des couleurs rouge, verte et bleue: - palette[ip++]=(((w & 0x0007) << 1) | ((w & 0x0008) >> 3)) << 4; - palette[ip++]=(((w & 0x7000) >> 11) | ((w & 0x8000) >> 15)) << 4; - palette[ip++]=(((w & 0x0700) >> 7) | ((w & 0x0800) >> 11)) << 4; - } + #if SDL_BYTEORDER == SDL_LIL_ENDIAN + + w=(((word)src[(i*2)+1]<<8) | (src[(i*2)+0])); + + // Traitement des couleurs rouge, verte et bleue: + palette[ip++]=(((w & 0x0007) << 1) | ((w & 0x0008) >> 3)) << 4; + palette[ip++]=(((w & 0x7000) >> 11) | ((w & 0x8000) >> 15)) << 4; + palette[ip++]=(((w & 0x0700) >> 7) | ((w & 0x0800) >> 11)) << 4; + + #else + w=(((word)src[(i*2+1)])|(((word)src[(i*2)])<<8)); + + palette[ip++] = (((w & 0x0700)>>7) | ((w & 0x0800) >> 7))<<4 ; + palette[ip++]=(((w & 0x0070)>>3) | ((w & 0x0080) >> 3))<<4 ; + palette[ip++] = (((w & 0x0007)<<1) | ((w & 0x0008)))<<4 ; + #endif + + + } } //// CODAGE de la PALETTE //// @@ -1345,20 +1368,31 @@ void PI1_code_palette(byte * palette,byte * dest) // Schéma d'un word = // - // Low High + // Low High // VVVV RRRR | 0000 BBBB // 0321 0321 | 0321 - + ip=0; for (i=0;i<16;i++) { + #if SDL_BYTEORDER == SDL_LIL_ENDIAN + // Traitement des couleurs rouge, verte et bleue: w =(((word)(palette[ip]>>2) & 0x38) >> 3) | (((word)(palette[ip]>>2) & 0x04) << 1); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 9) | (((word)(palette[ip]>>2) & 0x04) << 13); ip++; w|=(((word)(palette[ip]>>2) & 0x38) << 5) | (((word)(palette[ip]>>2) & 0x04) << 9); ip++; - + dest[(i*2)+0]=w & 0x00FF; dest[(i*2)+1]=(w>>8); + #else + + w=(((word)(palette[ip]<<3))&0x0700);ip++; + w|=(((word)(palette[ip]>>1))&0x0070);ip++; + w|=(((word)(palette[ip]>>5))&0x0007);ip++; + + dest[(i*2)+1]=w & 0x00FF; + dest[(i*2)+0]=(w>>8); + #endif } } @@ -2472,13 +2506,13 @@ int Save_C64_window(byte *saveWhat, byte *loadAddr) Print_in_window(13,18,"Data:",MC_Dark,MC_Light); what=Window_set_dropdown_button(10,28,90,15,70,what_label[*saveWhat],1, 0, 1, LEFT_SIDE,0); // 3 Window_dropdown_clear_items(what); - for (i=0; iR*26*color->R + + 55*color->G*55*color->G + + 19*color->B*19*color->B; +} + // Conversion table handlers // The conversion table is built after a run of the median cut algorithm and is // used to find the best color index for a given (RGB) color. GIMP avoids @@ -1342,6 +1355,10 @@ static const byte precision_24b[]= // Give this one a 24b source, get back the 256c bitmap and its palette int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) { + #if defined(__GP2X__) || defined(__gp2x__) || defined(__WIZ__) || defined(__CAANOO__) + return Convert_24b_bitmap_to_256_fast(dest, source, width, height, palette); + + #else T_Conversion_table * table; // table de conversion int ip; // index de précision pour la conversion @@ -1363,7 +1380,36 @@ int Convert_24b_bitmap_to_256(T_Bitmap256 dest,T_Bitmap24B source,int width,int } else return 1; + + #endif } +//Really small, fast and ugly converter(just for handhelds) +#include "global.h" +#include "limits.h" +#include "engine.h" +#include "windows.h" +extern void Set_palette_fake_24b(T_Palette palette); + +/// Really small, fast and dirty convertor(just for handhelds) +int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette) +{ + int size; + + Set_palette_fake_24b(palette); + + size = width*height; + + while(size--) + { + //Set palette color index to destination bitmap + *dest = ((source->R >> 5) << 5) | + ((source->G >> 5) << 2) | + ((source->B >> 6)); + source++; + dest++; + } + return 0; +} diff --git a/src/op_c.h b/src/op_c.h index ead494db..76b544a2 100644 --- a/src/op_c.h +++ b/src/op_c.h @@ -160,6 +160,7 @@ void CT_set(T_Conversion_table * t,int r,int g,int b,byte i); void RGB_to_HSL(int r, int g,int b, byte* h, byte*s, byte* l); void HSL_to_RGB(byte h, byte s, byte l, byte* r, byte* g, byte* b); +long Perceptual_lightness(T_Components *color); ///////////////////////////////////////////////////////////////////////////// /////////////////////////////// Méthodes de gestion des tables d'occurence // diff --git a/src/operatio.c b/src/operatio.c index 2c2bf4a1..d822fe29 100644 --- a/src/operatio.c +++ b/src/operatio.c @@ -36,6 +36,7 @@ #include "sdlscreen.h" #include "brush.h" #include "windows.h" +#include "input.h" // PI is NOT part of math.h according to C standards... #if defined(__GP2X__) || defined(__VBCC__) @@ -53,11 +54,12 @@ void Start_operation_stack(word new_operation) // On mémorise l'opération précédente si on démarre une interruption switch(new_operation) { - case OPERATION_MAGNIFY : - case OPERATION_COLORPICK : - case OPERATION_GRAB_BRUSH : - case OPERATION_POLYBRUSH : - case OPERATION_STRETCH_BRUSH : + case OPERATION_MAGNIFY: + case OPERATION_COLORPICK: + case OPERATION_RMB_COLORPICK: + case OPERATION_GRAB_BRUSH: + case OPERATION_POLYBRUSH: + case OPERATION_STRETCH_BRUSH: case OPERATION_ROTATE_BRUSH: Operation_before_interrupt=Current_operation; // On passe à l'operation demandée @@ -226,6 +228,9 @@ void Freehand_mode1_2_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -322,6 +327,9 @@ void Freehand_mode2_2_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -390,6 +398,9 @@ void Freehand_Mode3_2_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -422,6 +433,9 @@ void Line_12_0(void) // Début du tracé d'une ligne (premier clic) { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Paintbrush_shape_before_operation=Paintbrush_shape; @@ -480,9 +494,7 @@ void Line_12_5(void) // On corrige les coordonnées de la ligne si la touche shift est appuyée... if(SDL_GetModState() & KMOD_SHIFT) - { Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); - } // On vient de bouger if ((cursor_x!=end_x) || (cursor_y!=end_y)) @@ -557,11 +569,11 @@ void Line_0_5(void) } -/////////////////////////////////////////////////////////// OPERATION_K_LIGNE +/////////////////////////////////////////////////////////// OPERATION_K_LINE void K_line_12_0(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 0 // @@ -569,6 +581,9 @@ void K_line_12_0(void) { byte color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -594,7 +609,7 @@ void K_line_12_0(void) void K_line_12_6(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 1 ou 2 | 0 // Taille_Pile : 6 | 7 // @@ -634,7 +649,7 @@ void K_line_12_6(void) void K_line_0_6(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 0 // Taille_Pile : 6 // @@ -684,7 +699,7 @@ void K_line_0_6(void) void K_line_12_7(void) -// Opération : OPERATION_K_LIGNE +// Opération : OPERATION_K_LINE // Click Souris: 1 ou 2 // Taille_Pile : 7 // @@ -745,6 +760,9 @@ void Rectangle_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); if ((Config.Coords_rel) && (Menu_is_visible)) @@ -916,6 +934,9 @@ void Circle_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); @@ -1090,6 +1111,9 @@ void Ellipse_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); @@ -1284,9 +1308,12 @@ void Fill_2_0(void) // Click Souris: 2 // Taille_Pile : 0 // -// Souris effacée: Oui +// Souris effacée: Non // { + if (Rightclick_colorpick(1)) + return; + Hide_cursor(); // Pas besoin d'initialiser le début d'opération car le Smear n'affecte pas // le Fill, et on se fout de savoir si on est dans la partie gauche ou @@ -1309,7 +1336,7 @@ void Replace_1_0(void) // Click Souris: 1 // Taille_Pile : 0 // -// Souris effacée: Oui +// Souris effacée: Non // { Hide_cursor(); @@ -1331,9 +1358,12 @@ void Replace_2_0(void) // Click Souris: 2 // Taille_Pile : 0 // -// Souris effacée: Oui +// Souris effacée: Non // { + if (Rightclick_colorpick(1)) + return; + Hide_cursor(); // Pas besoin d'initialiser le début d'opération car le Smear n'affecte pas // le Replace, et on se fout de savoir si on est dans la partie gauche ou @@ -1433,6 +1463,9 @@ void Curve_34_points_2_0(void) // Souris effacée: Oui // { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; @@ -1711,17 +1744,17 @@ void Compute_3_point_curve(short x1, short y1, short x4, short y4, float cx,cy; // Centre de (x1,y1) et (x4,y4) float bx,by; // Intersect. des dtes ((x1,y1),(x2,y2)) et ((x3,y3),(x4,y4)) - cx=(float)(x1+x4)/2.0; // P1*--_ Légende: - cy=(float)(y1+y4)/2.0; // · \·· P2 -_\|/ : courbe - // · \ ·*· * : point important - bx=cx+((8.0/3.0)*(Paintbrush_X-cx));// · | ·· · : pointillÚ + cx=(float)(x1+x4)/2.0; // P1*--_ Legend: + cy=(float)(y1+y4)/2.0; // · \·· P2 -_\|/ : curve + // · \ ·*· * : important point + bx=cx+((8.0/3.0)*(Paintbrush_X-cx));// · | ·· · : dotted line by=cy+((8.0/3.0)*(Paintbrush_Y-cy));// · |P ·· B - // C *·····*·········* P=Pos. du pinceau - *x2=Round((bx+x1)/2.0); // · | ·· C=milieu de [P1,P4] - *y2=Round((by+y1)/2.0); // · | ·· B=point tel que - // · / ·*· C->B=(8/3) * C->P - *x3=Round((bx+x4)/2.0); // · _/·· P3 P2=milieu de [P1,B] - *y3=Round((by+y4)/2.0); // P4*-- P3=milieu de [P4,B] + // C *·····*·········* P=Pencil position + *x2=Round((bx+x1)/2.0); // · | ·· C=middle of [P1,P4] + *y2=Round((by+y1)/2.0); // · | ·· B=point computed as + // · / ·*· C->B=(8/3) * C->P + *x3=Round((bx+x4)/2.0); // · _/·· P3 P2=middle of [P1,B] + *y3=Round((by+y4)/2.0); // P4*-- P3=middle of [P4,B] } @@ -1745,8 +1778,11 @@ void Curve_3_points_0_5(void) Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); - Hide_line_preview(x1,y1,x4,y4); - Draw_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); + if (!Config.Stylus_mode) + { + Hide_line_preview(x1,y1,x4,y4); + Draw_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); + } if ( (Config.Coords_rel) && (Menu_is_visible) ) { @@ -1765,17 +1801,19 @@ void Curve_3_points_0_5(void) Operation_push(y4); Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); + + if (Config.Stylus_mode) + { + Display_cursor(); + while(!Mouse_K) + Get_input(20); + Hide_cursor(); + + Hide_line_preview(x1,y1,x4,y4); + } } - -void Curve_3_points_0_11(void) -// -// Opération : OPERATION_3_POINTS_CURVE -// Click Souris: 0 -// Taille_Pile : 11 -// -// Souris effacée: Non -// +void Curve_drag(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; @@ -1817,16 +1855,7 @@ void Curve_3_points_0_11(void) Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); } - - -void Curve_3_points_12_11(void) -// -// Opération : OPERATION_3_POINTS_CURVE -// Click Souris: 1 ou 2 -// Taille_Pile : 11 -// -// Souris effacée: Oui -// +void Curve_finalize(void) { short x1,y1,x2,y2,x3,y3,x4,y4; short old_x,old_y; @@ -1857,6 +1886,37 @@ void Curve_3_points_12_11(void) Wait_end_of_click(); } +void Curve_3_points_0_11(void) +// +// Opération : OPERATION_3_POINTS_CURVE +// Click Souris: 0 +// Taille_Pile : 11 +// +// Souris effacée: Non +// +{ + if (!Config.Stylus_mode) + Curve_drag(); + else + Curve_finalize(); +} + + +void Curve_3_points_12_11(void) +// +// Opération : OPERATION_3_POINTS_CURVE +// Click Souris: 1 ou 2 +// Taille_Pile : 11 +// +// Souris effacée: Oui +// +{ + if (!Config.Stylus_mode) + Curve_finalize(); + else + Curve_drag(); +} + ///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH @@ -1873,8 +1933,11 @@ void Airbrush_1_0(void) Backup(); Shade_table=Shade_table_left; - Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; - Airbrush(LEFT_SIDE); + if (SDL_GetTicks()>Airbrush_next_time) + { + Airbrush(LEFT_SIDE); + Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; + } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); @@ -1889,11 +1952,17 @@ void Airbrush_2_0(void) // Souris effacée: Non // { + if (Rightclick_colorpick(1)) + return; + Init_start_operation(); Backup(); Shade_table=Shade_table_right; - Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; - Airbrush(RIGHT_SIDE); + if (SDL_GetTicks()>Airbrush_next_time) + { + Airbrush(RIGHT_SIDE); + Airbrush_next_time = SDL_GetTicks()+Airbrush_delay*10; + } Operation_push(Paintbrush_X); Operation_push(Paintbrush_Y); @@ -1909,6 +1978,7 @@ void Airbrush_12_2(void) // { short old_x,old_y; + Uint32 now; Operation_pop(&old_y); Operation_pop(&old_x); @@ -1920,9 +1990,13 @@ void Airbrush_12_2(void) Display_cursor(); } - if (SDL_GetTicks()>Airbrush_next_time) + now=SDL_GetTicks(); + if (now>Airbrush_next_time) { - Airbrush_next_time+=Airbrush_delay*10; + //Airbrush_next_time+=Airbrush_delay*10; + // Time is now reset, because the += was death spiral + // if drawing took more time than the frequency. + Airbrush_next_time=now+Airbrush_delay*10; Airbrush(Mouse_K_unique); } @@ -1956,6 +2030,9 @@ void Polygon_12_0(void) { byte color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -2057,6 +2134,9 @@ void Polyfill_12_0(void) { byte color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -2255,6 +2335,9 @@ void Polyform_12_0(void) { short color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; @@ -2413,6 +2496,9 @@ void Filled_polyform_12_0(void) { short color; + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); // Cette opération étant également utilisée pour le lasso, on ne fait pas de @@ -2825,6 +2911,7 @@ void Grad_circle_12_0(void) Init_start_operation(); Backup(); + Load_gradient_data(Current_gradient); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; @@ -3082,6 +3169,8 @@ void Grad_ellipse_12_0(void) Init_start_operation(); Backup(); + Load_gradient_data(Current_gradient); + Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; @@ -3306,6 +3395,7 @@ void Grad_rectangle_12_0(void) { Init_start_operation(); Backup(); + Load_gradient_data(Current_gradient); if ((Config.Coords_rel) && (Menu_is_visible)) Print_in_menu("\035: 1 \022: 1",0); @@ -3712,6 +3802,9 @@ void Centered_lines_12_0(void) // // Souris effacée: Oui { + if (Rightclick_colorpick(0)) + return; + Init_start_operation(); Backup(); Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; diff --git a/src/operatio.h b/src/operatio.h index a228c582..62002a59 100644 --- a/src/operatio.h +++ b/src/operatio.h @@ -225,3 +225,8 @@ void Centered_lines_0_3(void); void Centered_lines_12_7(void); void Centered_lines_0_7(void); +/////////////////////////////////////////////////// OPERATION_RMB_COLORPICK + +byte Rightclick_colorpick(byte cursor_visible); +void Rightclick_colorpick_2_1(void); +void Rightclick_colorpick_0_1(void); diff --git a/src/pages.c b/src/pages.c index 4b3c5ee0..0669e963 100644 --- a/src/pages.c +++ b/src/pages.c @@ -75,6 +75,7 @@ T_Page * New_page(byte nb_layers) page->Filename[0]='\0'; page->File_format=DEFAULT_FILEFORMAT; page->Nb_layers=nb_layers; + page->Gradients=NULL; page->Transparent_color=0; // Default transparent color page->Background_transparent=0; page->Next = page->Prev = NULL; @@ -141,6 +142,24 @@ byte * Dup_layer(byte * layer) // ============================================================== +/// Adds a shared reference to the gradient data of another page. Pass NULL for new. +T_Gradient_array *Dup_gradient(T_Page * page) +{ + // new + if (page==NULL || page->Gradients==NULL) + { + T_Gradient_array *array; + array=(T_Gradient_array *)calloc(1, sizeof(T_Gradient_array)); + if (!array) + return NULL; + array->Used=1; + return array; + } + // shared + page->Gradients->Used++; + return page->Gradients; +} + void Download_infos_page_main(T_Page * page) // Affiche la page à l'écran { @@ -418,6 +437,16 @@ void Clear_page(T_Page * page) Free_layer(page, i); page->Image[i]=NULL; } + + // Free_gradient() : This data is reference-counted + if (page->Gradients) + { + page->Gradients->Used--; + if (page->Gradients->Used==0) + free(page->Gradients); + page->Gradients=NULL; + } + page->Width=0; page->Height=0; // On ne se préoccupe pas de ce que deviens le reste des infos de l'image. @@ -426,6 +455,7 @@ void Clear_page(T_Page * page) void Copy_S_page(T_Page * dest,T_Page * source) { *dest=*source; + dest->Gradients=NULL; } @@ -460,6 +490,10 @@ int Allocate_list_of_pages(T_List_of_pages * list) list->List_size=1; + page->Gradients=Dup_gradient(NULL); + if (!page->Gradients) + return 0; + return 1; // Succès } @@ -799,19 +833,10 @@ void Set_number_of_backups(int nb_backups) // (nb_backups = Nombre de backups, sans compter les pages courantes) } -int Backup_with_new_dimensions(int upload,byte layers,int width,int height) +int Backup_new_image(byte layers,int width,int height) { - // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et - // 0 sinon. - - T_Page * new_page; - int return_code=0; - int i; - - if (upload) - // On remet à jour l'état des infos de la page courante (pour pouvoir les - // retrouver plus tard) - Upload_infos_page_main(Main_backups->Pages); + // Retourne 1 si une nouvelle page est disponible et 0 sinon + T_Page * new_page; // On crée un descripteur pour la nouvelle page courante new_page=New_page(layers); @@ -820,36 +845,161 @@ int Backup_with_new_dimensions(int upload,byte layers,int width,int height) Error(0); return 0; } - Upload_infos_page_main(new_page); new_page->Width=width; new_page->Height=height; - strcpy(new_page->Filename, Main_backups->Pages->Filename); - strcpy(new_page->File_directory, Main_backups->Pages->File_directory); - if (Create_new_page(new_page,Main_backups,0xFFFFFFFF)) + new_page->Transparent_color=0; + new_page->Gradients=Dup_gradient(NULL); + if (!Create_new_page(new_page,Main_backups,0xFFFFFFFF)) { - for (i=0; iPages->Image[i], Main_backups->Pages->Transparent_color, width*height); - } - - Update_buffers(width, height); - - Download_infos_page_main(Main_backups->Pages); - - // Same code as in End_of_modification(): - #ifndef NOLAYERS - memcpy(Main_visible_image_backup.Image, - Main_visible_image.Image, - Main_image_width*Main_image_height); - #else - Update_screen_targets(); - #endif - Update_FX_feedback(Config.FX_Feedback); - // -- - - return_code=1; + Error(0); + return 0; } - return return_code; + + Update_buffers(width, height); + + Download_infos_page_main(Main_backups->Pages); + + return 1; +} + + +int Backup_with_new_dimensions(int width,int height) +{ + // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et + // 0 sinon. + + T_Page * new_page; + int i; + + // On crée un descripteur pour la nouvelle page courante + new_page=New_page(Main_backups->Pages->Nb_layers); + if (!new_page) + { + Error(0); + return 0; + } + new_page->Width=width; + new_page->Height=height; + new_page->Transparent_color=0; + if (!Create_new_page(new_page,Main_backups,0xFFFFFFFF)) + { + Error(0); + return 0; + } + + // Copy data from previous history step + memcpy(Main_backups->Pages->Palette,Main_backups->Pages->Next->Palette,sizeof(T_Palette)); + strcpy(Main_backups->Pages->Comment,Main_backups->Pages->Next->Comment); + Main_backups->Pages->File_format=Main_backups->Pages->Next->File_format; + strcpy(Main_backups->Pages->Filename, Main_backups->Pages->Next->Filename); + strcpy(Main_backups->Pages->File_directory, Main_backups->Pages->Next->File_directory); + Main_backups->Pages->Gradients=Dup_gradient(Main_backups->Pages->Next); + Main_backups->Pages->Background_transparent=Main_backups->Pages->Next->Background_transparent; + Main_backups->Pages->Transparent_color=Main_backups->Pages->Next->Transparent_color; + + // Fill with transparent color + for (i=0; iPages->Nb_layers;i++) + { + memset(Main_backups->Pages->Image[i], Main_backups->Pages->Transparent_color, width*height); + } + + Update_buffers(width, height); + + Download_infos_page_main(Main_backups->Pages); + + // Same code as in End_of_modification(), + // Without saving a safety backup: + #ifndef NOLAYERS + memcpy(Main_visible_image_backup.Image, + Main_visible_image.Image, + Main_image_width*Main_image_height); + #else + Update_screen_targets(); + #endif + Update_FX_feedback(Config.FX_Feedback); + // -- + + return 1; +} + +/// +/// Resizes a backup step in-place (doesn't add a Undo/Redo step). +/// Should only be called after an actual backup, because it loses the current. +/// pixels. This function is meant to be used from within Lua scripts. +int Backup_in_place(int width,int height) +{ + // Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et + // 0 sinon. + + int i; + byte ** new_layer; + + // Perform all allocations first + + new_layer=calloc(Main_backups->Pages->Nb_layers,1); + if (!new_layer) + return 0; + + for (i=0; iPages->Nb_layers; i++) + { + new_layer[i]=New_layer(height*width); + if (!new_layer[i]) + { + // Allocation error + for (; i>0; i--) + free(new_layer[i]); + free(new_layer); + return 0; + } + } + + // Now ok to proceed + + for (i=0; iPages->Nb_layers; i++) + { + // Replace layers + Free_layer(Main_backups->Pages,i); + Main_backups->Pages->Image[i]=new_layer[i]; + + // Fill with transparency + memset(Main_backups->Pages->Image[i], Main_backups->Pages->Transparent_color, width*height); + } + + Main_backups->Pages->Width=width; + Main_backups->Pages->Height=height; + + Download_infos_page_main(Main_backups->Pages); + + // The following is part of Update_buffers() + // (without changing the backup buffer) + #ifndef NOLAYERS + // At least one dimension is different + if (Main_visible_image.Width*Main_visible_image.Height != width*height) + { + // Current image + free(Main_visible_image.Image); + Main_visible_image.Image = (byte *)malloc(width * height); + if (Main_visible_image.Image == NULL) + return 0; + } + Main_visible_image.Width = width; + Main_visible_image.Height = height; + + if (Main_visible_image_depth_buffer.Width*Main_visible_image_depth_buffer.Height != width*height) + { + // Depth buffer + free(Main_visible_image_depth_buffer.Image); + Main_visible_image_depth_buffer.Image = (byte *)malloc(width * height); + if (Main_visible_image_depth_buffer.Image == NULL) + return 0; + } + Main_visible_image_depth_buffer.Width = width; + Main_visible_image_depth_buffer.Height = height; + +#endif + Update_screen_targets(); + + return 1; } int Backup_and_resize_the_spare(int width,int height) @@ -872,6 +1022,7 @@ int Backup_and_resize_the_spare(int width,int height) // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); + new_page->Gradients=Dup_gradient(Spare_backups->Pages); new_page->Width=width; new_page->Height=height; @@ -927,6 +1078,7 @@ void Backup_layers(dword layer_mask) // Fill it with a copy of the latest history Copy_S_page(new_page,Main_backups->Pages); + new_page->Gradients=Dup_gradient(Main_backups->Pages); Create_new_page(new_page,Main_backups,layer_mask); Download_infos_page_main(new_page); @@ -963,6 +1115,7 @@ void Backup_the_spare(dword layer_mask) // Fill it with a copy of the latest history Copy_S_page(new_page,Spare_backups->Pages); + new_page->Gradients=Dup_gradient(Spare_backups->Pages); Create_new_page(new_page,Spare_backups,layer_mask); // Copy the actual pixels from the backup to the latest page @@ -1099,6 +1252,11 @@ void End_of_modification(void) //Update_buffers(Main_image_width, Main_image_height); #ifndef NOLAYERS + // Backup buffer can have "wrong" size if a Lua script + // performs a resize. + Update_buffers(Main_image_width, Main_image_height); + // + memcpy(Main_visible_image_backup.Image, Main_visible_image.Image, Main_image_width*Main_image_height); diff --git a/src/pages.h b/src/pages.h index d6f44ebe..31a514c5 100644 --- a/src/pages.h +++ b/src/pages.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -39,13 +40,14 @@ extern byte * FX_feedback_screen; /////////////////////////// BACKUP /////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// +#ifndef NOLAYERS /// The pixels of visible layers, flattened copy. extern T_Bitmap Main_visible_image; /// The pixels of visible layers, flattened copy, used for no-feedback effects. extern T_Bitmap Main_visible_image_backup; /// The index of visible pixels from ::Visible image. Points to the right layer. extern T_Bitmap Main_visible_image_depth_buffer; - +#endif /// The pixels of visible layers for the spare page, flattened copy. extern T_Bitmap Spare_visible_image; @@ -93,7 +95,13 @@ void Free_page_of_a_list(T_List_of_pages * list); int Init_all_backup_lists(int width,int height); void Set_number_of_backups(int nb_backups); -int Backup_with_new_dimensions(int upload,byte layers,int width,int height); +int Backup_new_image(byte layers,int width,int height); +int Backup_with_new_dimensions(int width,int height); +/// +/// Resizes a backup step in-place (doesn't add a Undo/Redo step). +/// Should only be called after an actual backup, because it loses the current. +/// pixels. This function is meant to be used from within Lua scripts. +int Backup_in_place(int width,int height); /// Backup the spare image, the one you don't see. void Backup_the_spare(dword layer_mask); int Backup_and_resize_the_spare(int width,int height); diff --git a/src/palette.c b/src/palette.c index 3086727a..91bad838 100644 --- a/src/palette.c +++ b/src/palette.c @@ -40,11 +40,10 @@ byte Palette_view_is_RGB = 1; // Indique si on est en HSL ou en RGB -// --------------------------- Menu des palettes ----------------------------- -char * Palette_reduce_label[7]= -{ - "128"," 64"," 32"," 16"," 8"," 4"," 2" -}; +// Coordinates of the color count (on histogram button) +static const int COUNT_X = 258; +static const int COUNT_Y = 49; + // Nombre de graduations pour une composante RGB int RGB_scale = 256; // 24bit @@ -68,13 +67,41 @@ void Set_palette_RGB_scale(int scale) RGB_scale = scale; } +int Get_palette_RGB_scale(void) +{ + return RGB_scale; +} + +/// +/// Round a 0-255 RGB component according to the RGB_scale. +/// The result is also in the 0-255 range. byte Round_palette_component(byte comp) { return ((comp+128/RGB_scale)*(RGB_scale-1)/255*255+(RGB_scale&1?1:0))/(RGB_scale-1); } +/// +/// Turns a RGB component from 0-255 scale to 0-(RGB_scale-1). +/// The passed value should come from Round_palette_component(), +/// otherwise the rounding will be "down". +int Reduce_component(int comp) +{ + return (comp)*255/Color_max; +} + +/// +/// Turns a RGB component from 0-(RGB_scale-1) to 0-255. +int Expand_component(int comp) +{ + if (Color_max==255) + return comp; + return (comp+1)*Color_max/255; + // The +1 cancel any rounding down, the above test prevents + // the only case where it would be too much. +} + // Définir les unités pour les graduations R G B ou H S V -void Componant_unit(int count) +void Component_unit(int count) { Color_count = count; Color_max = count-1; @@ -138,7 +165,7 @@ void Set_blue(byte color, short new_color, T_Palette palette) palette[color].B=new_color; } -void Format_componant(byte value, char *str) +void Format_component(byte value, char *str) // Formate une chaine de 4 caractères+\0 : "nnn " { Num2str(value,str,3); @@ -183,38 +210,19 @@ void Spread_colors(short start,short end,T_Palette palette) void Update_color_count(short * used_colors, dword * color_usage) { - char str[10]; + char str[4]; Hide_cursor(); Cursor_shape=CURSOR_SHAPE_HOURGLASS; Display_cursor(); *used_colors=Count_used_colors(color_usage); - strcpy(str,"Used: "); - Num2str(*used_colors,str+6,3); + Num2str(*used_colors,str,3); Hide_cursor(); - Print_in_window(132,20,str,MC_Black,MC_Light); + Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light); Cursor_shape=CURSOR_SHAPE_ARROW; Display_cursor(); } -void Update_pixel_count(byte block_start, byte block_end, dword color_usage[]) -{ - int i; - int pixel_count = 0; - char str[10]; - - if (block_start<=block_end) - for (i = block_start; i <= block_end; i++) - pixel_count += color_usage[i]; - else - for (i = block_end; i <= block_start; i++) - pixel_count += color_usage[i]; - - Num2str(pixel_count, str, 7); - Print_in_window(230,50, str, MC_Black, MC_Light); - -} - void Remap_zone_highlevel(short x1, short y1, short x2, short y2, byte * conversion_table) // Attention: Remappe une zone de coins x1,y1 et x2-1,y2-1 !!! @@ -242,12 +250,12 @@ void Remap_image_highlevel(byte * conversion_table) int layer; // Remap the flatenned image view - Remap_general_lowlevel(conversion_table,Main_screen, + Remap_general_lowlevel(conversion_table,Main_screen,Main_screen, Main_image_width,Main_image_height,Main_image_width); // Remap all layers for (layer=0; layerPages->Nb_layers; layer++) - Remap_general_lowlevel(conversion_table,Main_backups->Pages->Image[layer],Main_image_width,Main_image_height,Main_image_width); + Remap_general_lowlevel(conversion_table,Main_backups->Pages->Image[layer],Main_backups->Pages->Image[layer],Main_image_width,Main_image_height,Main_image_width); // Remap transparent color Main_backups->Pages->Transparent_color = @@ -316,7 +324,7 @@ void Swap(int with_remap,short block_1_start,short block_2_start,short block_siz // On fait une copie de la palette memcpy(temp_palette, palette, sizeof(T_Palette)); - // On fait une copie de la table d'utilisation des couleurs + // On fait une copie de la table d'used des couleurs memcpy(temp_usage, color_usage, sizeof(dword) * 256); // On commence à initialiser la table de conversion à un état où elle ne @@ -381,7 +389,7 @@ void Swap(int with_remap,short block_1_start,short block_2_start,short block_siz conversion_table[pos_1]=pos_2; conversion_table[pos_2]=pos_1; - // On intervertit le nombre d'utilisation des couleurs pour garder une + // On intervertit le nombre d'used des couleurs pour garder une // cohérence lors d'un éventuel "Zap unused". SWAP_DWORDS(color_usage[pos_1], color_usage[pos_2]) @@ -449,14 +457,16 @@ void Set_nice_menu_colors(dword * color_usage,int not_picture) // couleurs du menu par défaut for (index=0; index<4; index++) { + const T_Components * target_rgb; + + target_rgb=Favorite_GUI_color(index); color=new_colors[index]; rgb[index].R=Main_palette[color].R; rgb[index].G=Main_palette[color].G; rgb[index].B=Main_palette[color].B; - // Should be Config.Fav_menu_colors[index] if using user colors - Main_palette[color].R=Gfx->Default_palette[Gfx->Color[index]].R; - Main_palette[color].G=Gfx->Default_palette[Gfx->Color[index]].G; - Main_palette[color].B=Gfx->Default_palette[Gfx->Color[index]].B; + Main_palette[color].R=Round_palette_component(target_rgb->R); + Main_palette[color].G=Round_palette_component(target_rgb->G); + Main_palette[color].B=Round_palette_component(target_rgb->B); } // Maintenant qu'on a placé notre nouvelle palette, on va chercher quelles @@ -491,8 +501,8 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw int best_color_2=0; int difference; int best_difference; - dword Utilisation; - dword Meilleure_utilisation; + dword used; + dword best_used; // On commence par initialiser la table de conversion dans un état où // aucune conversion ne sera effectuée. @@ -543,7 +553,8 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw // Maintenant qu'on a une palette clean, on va boucler en réduisant // le nombre de couleurs jusqu'à ce qu'on atteigne le nombre désiré. - while ((*used_colors)>nb_colors_asked) + // (The stop condition is further down) + while (1) { // Il s'agit de trouver les 2 couleurs qui se ressemblent le plus // parmis celles qui sont utilisées (bien sûr) et de les remplacer par @@ -551,7 +562,7 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw // en fonction de leur utilisation dans l'image. best_difference =0x7FFF; - Meilleure_utilisation=0x7FFFFFFF; + best_used=0x7FFFFFFF; for (color_1=0;color_1<(*used_colors);color_1++) for (color_2=color_1+1;color_2<(*used_colors);color_2++) @@ -563,16 +574,21 @@ void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dw if (difference<=best_difference) { - Utilisation=color_usage[color_1]+color_usage[color_2]; - if ((differenceNb_elements=nb_elements; slider->Position=position; - Compute_slider_cursor_height(slider); + Compute_slider_cursor_length(slider); Window_draw_slider(slider); - Print_counter(x_pos,172,value,MC_Black,MC_Light); + Print_counter(x_pos,NUMERIC_Y,value,MC_Black,MC_Light); } @@ -691,9 +717,9 @@ void Display_sliders(T_Scroller_button * red_slider, if (block_is_selected) { - Set_palette_slider(red_slider,Color_max*2+1,Color_max,"± 0",176); - Set_palette_slider(green_slider,Color_max*2+1,Color_max,"± 0",203); - Set_palette_slider(blue_slider,Color_max*2+1,Color_max,"± 0",230); + Set_palette_slider(red_slider,Color_max*2+1,Color_max,"± 0",NUMERIC_R_X); + Set_palette_slider(green_slider,Color_max*2+1,Color_max,"± 0",NUMERIC_G_X); + Set_palette_slider(blue_slider,Color_max*2+1,Color_max,"± 0",NUMERIC_B_X); } else { @@ -706,17 +732,15 @@ void Display_sliders(T_Scroller_button * red_slider, RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } - Format_componant(j1*Color_count/256,str); - Set_palette_slider(red_slider,Color_count,Color_max-j1*Color_max/255,str,176); - Format_componant(j2*Color_count/256,str); - Set_palette_slider(green_slider,Color_count,Color_max-j2*Color_max/255,str,203); - Format_componant(j3*Color_count/256,str); - Set_palette_slider(blue_slider,Color_count,Color_max-j3*Color_max/255,str,230); + Format_component(j1*Color_count/256,str); + Set_palette_slider(red_slider,Color_count,Color_max-Expand_component(j1),str,NUMERIC_R_X); + Format_component(j2*Color_count/256,str); + Set_palette_slider(green_slider,Color_count,Color_max-Expand_component(j2),str,NUMERIC_G_X); + Format_component(j3*Color_count/256,str); + Set_palette_slider(blue_slider,Color_count,Color_max-Expand_component(j3),str,NUMERIC_B_X); } } - - void Draw_all_palette_sliders(T_Scroller_button * red_slider, T_Scroller_button * green_slider, T_Scroller_button * blue_slider, @@ -731,15 +755,15 @@ void Draw_all_palette_sliders(T_Scroller_button * red_slider, // Dans le cas d'un bloc, tout à 0. red_slider->Position =Color_max; Window_draw_slider(red_slider); - Print_counter(176,172,"± 0",MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); green_slider->Position =Color_max; Window_draw_slider(green_slider); - Print_counter(203,172,"± 0",MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); blue_slider->Position =Color_max; Window_draw_slider(blue_slider); - Print_counter(230,172,"± 0",MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); } else { @@ -753,30 +777,35 @@ void Draw_all_palette_sliders(T_Scroller_button * red_slider, RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); } DEBUG("j1",j1); - Format_componant(j1*Color_count/256,str); - red_slider->Position=Color_max-j1*Color_max/255; + Format_component(j1*Color_count/256,str); + red_slider->Position=Color_max-Expand_component(j1); Window_draw_slider(red_slider); - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); - Format_componant(j2*Color_count/256,str); - green_slider->Position=Color_max-j2*Color_max/255; + Format_component(j2*Color_count/256,str); + green_slider->Position=Color_max-Expand_component(j2); Window_draw_slider(green_slider); - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); - Format_componant(j3*Color_count/256,str); - blue_slider->Position=Color_max-j3*Color_max/255; + Format_component(j3*Color_count/256,str); + blue_slider->Position=Color_max-Expand_component(j3); Window_draw_slider(blue_slider); - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } Display_cursor(); } -void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage) +int Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage) { int i, j; unsigned int max_count = 0; int old_height=0; + int hovered_color=-1; + int new_hovered_color; + int bar_width; + T_Special_button *histo; + int clicked_button; /* Draws an histogram of the selected range in a separate window */ @@ -796,15 +825,21 @@ void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* if(color_usage[i] > max_count) max_count = color_usage[i]; } - if (max_count == 0) { + if (max_count == 0) + { Warning_message("All these colors are unused!"); - return; + Hide_cursor(); + return -1; } + + Open_window(263, 150, "Histogram"); + Window_set_normal_button(120, 130, 42, 14, "Close",-1,1,SDLK_RETURN); - Open_window(263, 140, "Histogram"); - Window_set_normal_button(120, 120, 42, 14, "Close",-1,1,SDLK_RETURN); + Print_in_window(6, 17, "Color:", MC_Dark, MC_Light); + Print_in_window(110+12*8, 17, "Pixels", MC_Dark, MC_Light); // Step 2 : draw bars + bar_width=256/(block_end-block_start+1); j = 0; for(i=block_start; i<= block_end; i++) { int height = 100*color_usage[i]/max_count; @@ -816,30 +851,30 @@ void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* height=1; Window_rectangle( - 3+j*(256/(block_end-block_start+1)), - 117-height, - 256/(block_end-block_start+1), + 3+j*bar_width, + 127-height, + bar_width, height, i); //if (i == MC_Light) { Window_rectangle( - 3+j*(256/(block_end-block_start+1)), - 116-height, - 256/(block_end-block_start+1), + 3+j*bar_width, + 126-height, + bar_width, 1,MC_Black); //} } // vertical outline if (height>old_height) Window_rectangle( - 2+j*(256/(block_end-block_start+1)), - 116-height, + 2+j*bar_width, + 126-height, 1, height-old_height+1,MC_Black); else if (old_height>height) Window_rectangle( - 3+j*(256/(block_end-block_start+1)), - 116-old_height, + 3+j*bar_width, + 126-old_height, 1, old_height-height+1,MC_Black); @@ -850,20 +885,121 @@ void Window_Histogram(unsigned char block_start, unsigned char block_end, dword* if (old_height!=0) Window_rectangle( 3+j*(256/(block_end-block_start+1)), - 116-old_height, + 126-old_height, 1, old_height+1,MC_Black); - Update_window_area(0,0,263,140); - Display_cursor(); + histo = Window_set_special_button(3, 27, j*bar_width, 100); // 2 - while(Window_clicked_button() != 1); - Close_window(); + Update_window_area(0,0,263,150); Display_cursor(); + do + { + // Find hovered area + if (Window_click_in_rectangle(histo->Pos_X,histo->Pos_Y,histo->Pos_X+histo->Width-1,histo->Pos_Y+histo->Height-1)) + { + short x_pos; + x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; + new_hovered_color=block_start+(x_pos-histo->Pos_X)/bar_width; + } + else + new_hovered_color=-1; + + // When changing hovered color, update the info area + if (new_hovered_color!=hovered_color) + { + char str[12]; + + hovered_color=new_hovered_color; + Hide_cursor(); + if (hovered_color==-1) + { + Window_rectangle(6+6*8,17,3*8,7,MC_Light); + Update_window_area(6+6*8,17,3*8,7); + Window_rectangle(86,17,2*8,8,MC_Light); + Update_window_area(86,17,2*8,8); + Window_rectangle(110,17,11*8,7,MC_Light); + Update_window_area(110,17,11*8,7); + } + else + { + Num2str(hovered_color,str ,3); + Print_in_window(6+6*8,17,str,MC_Black,MC_Light); + Window_rectangle(86,17,2*8,8,hovered_color); + Update_window_area(86,17,2*8,8); + Num2str(color_usage[hovered_color],str ,11); + Print_in_window(110,17,str,MC_Black,MC_Light); + } + Display_cursor(); + } + clicked_button=Window_clicked_button(); + if (Key == KEY_ESC) + clicked_button=1; + + } while( clicked_button < 1); + Close_window(); + + if (clicked_button==2) + { + // This is a counter-hack. Close_window() sets Mouse_K to zero + // on exit, I don't know why (It will become 1 again if you move + // the mouse slightly) + // Here I force it back to 1, so that the Wait_end_of_click() + // will really wait for a release of mouse button. + Mouse_K=1; + return hovered_color; + } + return -1; +} + +void Print_RGB_or_HSL(byte mode) +{ + Print_in_window(184,68,mode?"H":"R",MC_Dark,MC_Light); + Print_in_window(211,68,mode?"S":"G",MC_Dark,MC_Light); + Print_in_window(238,68,mode?"L":"B",MC_Dark,MC_Light); +} + +void Tag_used_colors(byte color, dword color_usage[]) +{ + word index; + + for (index=0;index<=255;index++) + { + short x_pos=Window_palette_button_list->Pos_X+6+((index>>4)*10); + short y_pos=Window_palette_button_list->Pos_Y+3+((index&15)* 5); + byte col; + + col=(color&&color_usage[index])?MC_White:MC_Light; + Window_rectangle(x_pos+5,y_pos+0,1,5,col); + } + + Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16); } void Button_Palette(void) { + static const int BUTTON_PLUS_X = 268; + static const int BUTTON_PLUS_Y = 74; + static const int BUTTON_MINUS_X = 268; + static const int BUTTON_MINUS_Y = 165; + + // Coordinates of the block that displays Backcolor + static const int BGCOLOR_DISPLAY_X = 262; + static const int BGCOLOR_DISPLAY_Y = 89; + static const int BGCOLOR_DISPLAY_W = 24; + static const int BGCOLOR_DISPLAY_H = 72; + + // Coordinates of the block that displays Forecolor + static const int FGCOLOR_DISPLAY_X = 266; + static const int FGCOLOR_DISPLAY_Y = 93; + static const int FGCOLOR_DISPLAY_W = 16; + static const int FGCOLOR_DISPLAY_H = 64; + + // Coordinates of the Color# + static const int COLOR_X = 111; + static const int COLOR_Y = 69; + + static short reduce_colors_number = 256; short temp_color; // Variable pouvant reservir pour différents calculs intermédiaires dword temp; @@ -883,6 +1019,7 @@ void Button_Palette(void) T_Scroller_button * green_slider; T_Scroller_button * blue_slider; T_Dropdown_button * reduce_dropdown; + T_Dropdown_button * sort_dropdown; byte image_is_backed_up = 0; byte need_to_remap = 0; @@ -893,12 +1030,14 @@ void Button_Palette(void) T_Components * backup_palette; T_Components * temp_palette; T_Components * working_palette; + + static byte show_used_colors=0; backup_palette =(T_Components *)malloc(sizeof(T_Palette)); temp_palette=(T_Components *)malloc(sizeof(T_Palette)); working_palette=(T_Components *)malloc(sizeof(T_Palette)); - Componant_unit(RGB_scale); + Component_unit(RGB_scale); Open_window(299, 188,"Palette"); @@ -908,102 +1047,105 @@ void Button_Palette(void) Window_set_palette_button(5, 79); // 1 - Window_display_frame (173, 67, 121, 116); + Window_display_frame (172, 63, 122, 121); // Graduation des jauges de couleur - Window_rectangle(179,109,17,1,MC_Dark); - Window_rectangle(206,109,17,1,MC_Dark); - Window_rectangle(233,109,17,1,MC_Dark); - Window_rectangle(179,125,17,1,MC_Dark); - Window_rectangle(206,125,17,1,MC_Dark); - Window_rectangle(233,125,17,1,MC_Dark); - Window_rectangle(179,141,17,1,MC_Dark); - Window_rectangle(206,141,17,1,MC_Dark); - Window_rectangle(233,141,17,1,MC_Dark); + Window_rectangle(180,106,17,1,MC_Dark); + Window_rectangle(207,106,17,1,MC_Dark); + Window_rectangle(234,106,17,1,MC_Dark); + Window_rectangle(180,122,17,1,MC_Dark); + Window_rectangle(207,122,17,1,MC_Dark); + Window_rectangle(234,122,17,1,MC_Dark); + Window_rectangle(180,138,17,1,MC_Dark); + Window_rectangle(207,138,17,1,MC_Dark); + Window_rectangle(234,138,17,1,MC_Dark); // Jauges de couleur - red_slider = Window_set_scroller_button(182, 81, 88,Color_count,1,Color_max-working_palette[Fore_color].R*Color_max/255);// 2 - green_slider = Window_set_scroller_button(209, 81, 88,Color_count,1,Color_max-working_palette[Fore_color].G*Color_max/255);// 3 - blue_slider = Window_set_scroller_button(236, 81, 88,Color_count,1,Color_max-working_palette[Fore_color].B*Color_max/255);// 4 + red_slider = Window_set_scroller_button(183, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].R));// 2 + green_slider = Window_set_scroller_button(210, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].G));// 3 + blue_slider = Window_set_scroller_button(237, 79, 88,Color_count,1,Color_max-Reduce_component(working_palette[Fore_color].B));// 4 if(Palette_view_is_RGB==1) { - Print_in_window(184,71,"R",MC_Dark,MC_Light); - Print_in_window(211,71,"G",MC_Dark,MC_Light); - Print_in_window(238,71,"B",MC_Dark,MC_Light); - Componant_unit(RGB_scale); + Print_RGB_or_HSL(0); + Component_unit(RGB_scale); } else { - Print_in_window(184,71,"H",MC_Dark,MC_Light); - Print_in_window(211,71,"S",MC_Dark,MC_Light); - Print_in_window(238,71,"L",MC_Dark,MC_Light); - Componant_unit(256); + Print_RGB_or_HSL(1); + Component_unit(256); } first_color=last_color=block_start=block_end=Fore_color; Tag_color_range(block_start,block_end); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(260,89,24,72,Back_color); - Window_rectangle(264,93,16,64,Fore_color); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); // Affichage des valeurs de la couleur courante (pour 1 couleur) Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); - Print_in_window(129, 36, "Color number:", MC_Dark, MC_Light); + Print_in_window(7, 69, "Color number:", MC_Dark, MC_Light); Num2str(Fore_color, str, 3); - Print_in_window(237, 36, str, MC_Black, MC_Light); + Print_in_window(COLOR_X, COLOR_Y, str, MC_Black, MC_Light); - Window_set_normal_button( 6,17,59,14,"Default",3,1,SDLK_f); // 5 - Window_set_normal_button(66,17,29,14,"Gry" ,1,1,SDLK_g); // 6 - Window_set_normal_button(66,47,29,14,"Swp" ,0,1,KEY_NONE); // 7 - Window_set_normal_button( 6,47,59,14,"X-Swap" ,1,1,SDLK_x); // 8 - Window_set_normal_button(66,32,29,14,"Cpy" ,1,1,SDLK_c); // 9 - Window_set_normal_button( 6,32,59,14,"Spread" ,4,1,SDLK_e); // 10 + Window_set_normal_button( 7,16,55,14,"Merge" ,0,1,SDLK_m); // 5 + Window_set_normal_button( 63,16,36,14,"Gray" ,1,1,SDLK_g); // 6 + Window_set_normal_button( 7,46,55,14,"Swap" ,0,1,KEY_NONE); // 7 + Window_set_normal_button( 63,46,72,14,"X-Swap" ,1,1,SDLK_x); // 8 + Window_set_normal_button(136,31,54,14,"Copy" ,1,1,SDLK_c); // 9 + Window_set_normal_button(136,46,54,14,"Spread" ,4,1,SDLK_e); // 10 - reduce_dropdown = Window_set_dropdown_button(96, 62, 60, 14, 60, "Reduce", 0, - 0, 1, LEFT_SIDE, 0); // 11 - Window_dropdown_add_item(reduce_dropdown, 0, "to 128"); - Window_dropdown_add_item(reduce_dropdown, 1, "to 64"); - Window_dropdown_add_item(reduce_dropdown, 2, "to 32"); - Window_dropdown_add_item(reduce_dropdown, 3, "to 16"); - Window_dropdown_add_item(reduce_dropdown, 4, "to 8"); - Window_dropdown_add_item(reduce_dropdown, 5, "to 4"); - Window_dropdown_add_item(reduce_dropdown, 6, "to 2"); - Window_dropdown_add_item(reduce_dropdown, 7, "Other"); + reduce_dropdown = Window_set_dropdown_button(209, 46, 83, 14, 84, "Reduce", 0, + 0, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 11 + Window_dropdown_add_item(reduce_dropdown, 256, "to uniques"); + Window_dropdown_add_item(reduce_dropdown, 128, "to 128"); + Window_dropdown_add_item(reduce_dropdown, 64, "to 64"); + Window_dropdown_add_item(reduce_dropdown, 32, "to 32"); + Window_dropdown_add_item(reduce_dropdown, 16, "to 16"); + Window_dropdown_add_item(reduce_dropdown, 8, "to 8"); + Window_dropdown_add_item(reduce_dropdown, 4, "to 4"); + Window_dropdown_add_item(reduce_dropdown, 2, "to 2"); + Window_dropdown_add_item(reduce_dropdown, 0, "Other"); Window_set_normal_button( 6,168,35,14,"Undo" ,1,1,SDLK_u); // 12 Window_set_normal_button( 62,168,51,14,"Cancel",0,1,KEY_ESC); // 13 Window_set_normal_button(117,168,51,14,"OK" ,0,1,SDLK_RETURN); // 14 - // histogram button - button_used = Window_set_normal_button(228,47,64,14,"000000",0,1,SDLK_d);// 15 - Window_set_normal_button(209,17,83,14,"Zap unused",0,1,SDLK_DELETE);//16 + Window_set_normal_button(209,16,37,14,"Used",0,1,SDLK_d); // 15 + Window_set_normal_button(209,31,83,14,"Zap unused",0,1,SDLK_DELETE);//16 + + Window_set_repeatable_button(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1,SDLK_KP_PLUS); // 17 + Window_set_repeatable_button(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1,SDLK_KP_MINUS); // 18 - Window_set_repeatable_button(266, 74,12,11,"+",0,1,SDLK_KP_PLUS); // 17 - Window_set_repeatable_button(266,165,12,11,"-",0,1,SDLK_KP_MINUS); // 18 + Window_set_normal_button(100,16,35,14,"Neg" ,1,1,SDLK_n); // 19 + Window_set_normal_button(7,31,55,14,"Invert" ,1,1,SDLK_i); // 20 + Window_set_normal_button(63,31,72,14,"X-Invert" ,5,1,SDLK_v); // 21 - Window_set_normal_button(96,17,29,14,"Neg" ,1,1,SDLK_n); // 19 - Window_set_normal_button(66,62,29,14,"Inv" ,1,1,SDLK_i); // 20 - Window_set_normal_button( 6,62,59,14,"X-Inv." ,5,1,SDLK_v); // 21 + // Button without outline + Window_set_normal_button(175,66,81,11,"" ,0,1,SDLK_h); // 22 + Window_display_frame_mono(175-1,66-1,81+2,11+2,MC_Light); - Window_set_normal_button(96,32,29,14,"HSL" ,1,1,SDLK_h); // 22 - Window_set_normal_button(96,47,29,14,"Srt" ,1,1,SDLK_s); // 23 + sort_dropdown = Window_set_dropdown_button(136, 16, 54, 14, 80, " Sort", 0, + 1, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 23 + Window_dropdown_add_item(sort_dropdown, 0, "Hue/Light"); + Window_dropdown_add_item(sort_dropdown, 1, "Lightness"); + + Window_set_normal_button(NUMERIC_BOX_X,NUMERIC_BOX_Y,NUMERIC_BOX_W,NUMERIC_BOX_H,"" ,0,1,KEY_NONE); // 24 + // Button without outline + Window_display_frame_mono(NUMERIC_BOX_X-1,NUMERIC_BOX_Y-1,NUMERIC_BOX_W+2,NUMERIC_BOX_H+2,MC_Light); + button_used = Window_set_normal_button(247,16,45,14,"Histo",0,1,KEY_NONE);// 25 + // Dessin des petits effets spéciaux pour les boutons [+] et [-] - Draw_thingumajig(263, 74,MC_White,-1); - Draw_thingumajig(280, 74,MC_White,+1); - Draw_thingumajig(263,165,MC_Dark,-1); - Draw_thingumajig(280,165,MC_Dark,+1); + Draw_thingumajig(265, 74,MC_White,-1); + Draw_thingumajig(282, 74,MC_White,+1); + Draw_thingumajig(265,165,MC_Dark,-1); + Draw_thingumajig(282,165,MC_Dark,+1); Display_cursor(); Update_color_count(&used_colors,color_usage); + if (show_used_colors) + Tag_used_colors(1, color_usage); - Hide_cursor(); - Print_in_window(130, 49, "Pixel count:", MC_Dark, MC_Light); - - Update_pixel_count(Fore_color, Fore_color, color_usage); - - Display_cursor(); - Update_window_area(0,0,299,188); do @@ -1012,7 +1154,7 @@ void Button_Palette(void) old_mouse_y=Mouse_Y; old_mouse_k=Mouse_K; clicked_button=Window_clicked_button(); - + switch (clicked_button) { case 0 : // Nulle part @@ -1025,16 +1167,71 @@ void Button_Palette(void) temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); if (Mouse_K==RIGHT_SIDE) { - if (Back_color!=temp_color) + // Contextual menu + T_Dropdown_button dropdown; + T_Dropdown_choice *item; + + dropdown.Pos_X =0; + dropdown.Pos_Y =0; + dropdown.Height =0; + dropdown.Dropdown_width=48; + dropdown.First_item =NULL; + dropdown.Bottom_up =1; + + Window_dropdown_add_item(&dropdown, 1, "Copy"); + Window_dropdown_add_item(&dropdown, 2, "Paste"); + + item=Dropdown_activate(&dropdown,Mouse_X,Mouse_Y); + + if (item && item->Number == 1) { + // Copy + Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); + Display_cursor(); + } + else if (item && item->Number == 2) + { + // Paste + int nb_colors; + + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + + nb_colors = Get_clipboard_colors(working_palette, block_start); + if (nb_colors>0) + { + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + Set_palette(working_palette); + need_to_remap=1; + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + } + else + { + Display_cursor(); + } + } + else if (Back_color!=temp_color) + { + // Just select back color + Back_color=temp_color; // 4 blocks de back_color entourant la fore_color - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); + + Display_cursor(); } + else + { + Display_cursor(); + } + + + Window_dropdown_clear_items(&dropdown); } else { @@ -1051,21 +1248,18 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée - Window_rectangle(237,36,56,7,MC_Light); + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); - Update_window_area(237,36,56,7); - - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); + Update_window_area(COLOR_X,COLOR_Y,56,7); // Affichage des jauges - Window_rectangle(176,172,84,7,MC_Light); + Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); memcpy(backup_palette ,working_palette,sizeof(T_Palette)); memcpy(temp_palette,working_palette,sizeof(T_Palette)); @@ -1086,16 +1280,13 @@ void Button_Palette(void) Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(block_start, block_end, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,1,NULL); // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else if (first_color>temp_color) { @@ -1106,37 +1297,31 @@ void Button_Palette(void) Num2str(block_start,str ,3); Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(block_start, block_end, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,1,NULL); // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { block_start=block_end=first_color; - Window_rectangle(176,172,84,7,MC_Light); + Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); // Affichage du n° de la couleur sélectionnée - Window_rectangle(261,36,32,7,MC_Light); - Update_window_area(261,36,32,7); + Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); + Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); } // On tagge le bloc (ou la couleur) @@ -1145,8 +1330,9 @@ void Button_Palette(void) last_color=temp_color; } + Display_cursor(); } - Display_cursor(); + } break; case 2 : // Jauge rouge @@ -1155,8 +1341,8 @@ void Button_Palette(void) { if(Palette_view_is_RGB) { - Set_red(Fore_color,(Color_max-red_slider->Position)*255/Color_max,working_palette); - Format_componant((working_palette[Fore_color].R)*Color_count/256,str); + Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); + Format_component((working_palette[Fore_color].R)*Color_count/256,str); } else { @@ -1167,28 +1353,40 @@ void Button_Palette(void) &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); - Format_componant((int)255-red_slider->Position,str); + Format_component((int)255-red_slider->Position,str); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) - Set_red(i,temp_palette[i].R+(Color_max-red_slider->Position)*255/Color_max,working_palette); + Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); } else { + byte greys=0; + byte non_greys=0; + // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) + if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) + non_greys=1; + else + greys=1; + + for (i=block_start; i<=block_end; i++) + { + byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); + } } if (red_slider->Position>Color_max) @@ -1208,7 +1406,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } @@ -1223,8 +1421,8 @@ void Button_Palette(void) { if(Palette_view_is_RGB) { - Set_green (Fore_color,(Color_max-green_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].G*Color_count/256,str); + Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); + Format_component(working_palette[Fore_color].G*Color_count/256,str); } else { @@ -1235,28 +1433,40 @@ void Button_Palette(void) &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); - Format_componant((int)255-green_slider->Position,str); + Format_component((int)255-green_slider->Position,str); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) - Set_green (i,temp_palette[i].G+(Color_max-green_slider->Position)*255/Color_max,working_palette); + Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); } else { - for (i=block_start; i<=block_end; i++) + byte greys=0; + byte non_greys=0; + // Check if the range contains both greys and non-greys + for (i=block_start; i<=block_end; i++) + if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) + non_greys=1; + else + greys=1; + + for (i=block_start; i<=block_end; i++) + { + byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); + } } if (green_slider->Position>Color_max) @@ -1276,7 +1486,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1291,8 +1501,8 @@ void Button_Palette(void) { if(Palette_view_is_RGB) { - Set_blue (Fore_color,(Color_max-blue_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].B*Color_count/256,str); + Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); + Format_component(working_palette[Fore_color].B*Color_count/256,str); } else { @@ -1303,28 +1513,40 @@ void Button_Palette(void) &working_palette[Fore_color].R, &working_palette[Fore_color].G, &working_palette[Fore_color].B); - Format_componant((int)255-blue_slider->Position,str); + Format_component((int)255-blue_slider->Position,str); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } else { if(Palette_view_is_RGB) { for (i=block_start; i<=block_end; i++) - Set_blue(i,temp_palette[i].B+(Color_max-blue_slider->Position)*255/Color_max,working_palette); + Set_blue(i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } else { + byte greys=0; + byte non_greys=0; + // Check if the range contains both greys and non-greys for (i=block_start; i<=block_end; i++) + if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B) + non_greys=1; + else + greys=1; + + for (i=block_start; i<=block_end; i++) + { + byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B; Set_HSL( temp_palette, working_palette, i, - Color_max-red_slider->Position, - Color_max-green_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position, + is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position, Color_max-blue_slider->Position ); + } } if (blue_slider->Position>Color_max) @@ -1344,7 +1566,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1353,16 +1575,83 @@ void Button_Palette(void) Set_palette(working_palette); break; - case 5 : // Default - memcpy(backup_palette,working_palette,sizeof(T_Palette)); - memcpy(working_palette,Gfx->Default_palette,sizeof(T_Palette)); - memcpy(temp_palette,Gfx->Default_palette,sizeof(T_Palette)); - Set_palette(Gfx->Default_palette); + case 5 : // Merge + if (block_start!=block_end) + { + dword sum_r=0, sum_g=0, sum_b=0, used=0; + + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + // Compute weighted average + for (i=block_start; i<=block_end; i++) + { + used+=color_usage[i]; + sum_r+=working_palette[i].R * color_usage[i]; + sum_g+=working_palette[i].G * color_usage[i]; + sum_b+=working_palette[i].B * color_usage[i]; + } + // Do normal average if no pixels used + if (used==0) + { + sum_r=sum_g=sum_b=used=0; + for (i=block_start; i<=block_end; i++) + { + used+=1; + sum_r+=working_palette[i].R; + sum_g+=working_palette[i].G; + sum_b+=working_palette[i].B; + } + } + for (i=block_start; i<=block_end; i++) + { + Set_red (i,sum_r/used,working_palette); + Set_green(i,sum_g/used,working_palette); + Set_blue (i,sum_b/used,working_palette); + } + } + else + { + temp_color=Wait_click_in_palette(Window_palette_button_list); + if (temp_color>=0) + { + dword sum_r=0, sum_g=0, sum_b=0, used; + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + + // Compute weighted average + used=color_usage[temp_color]+color_usage[Fore_color]; + if (used) + { + sum_r=(working_palette[temp_color].R * color_usage[temp_color] + + working_palette[Fore_color].R * color_usage[Fore_color]) + / used; + sum_g=(working_palette[temp_color].G * color_usage[temp_color] + + working_palette[Fore_color].G * color_usage[Fore_color]) + / used; + sum_b=(working_palette[temp_color].B * color_usage[temp_color] + + working_palette[Fore_color].B * color_usage[Fore_color]) + / used; + } + else // Normal average + { + sum_r=(working_palette[temp_color].R+working_palette[Fore_color].R)/2; + sum_g=(working_palette[temp_color].G+working_palette[Fore_color].G)/2; + sum_b=(working_palette[temp_color].B+working_palette[Fore_color].B)/2; + } + Set_red (temp_color,sum_r,working_palette); + Set_green(temp_color,sum_g,working_palette); + Set_blue (temp_color,sum_b,working_palette); + Set_red (Fore_color,sum_r,working_palette); + Set_green(Fore_color,sum_g,working_palette); + Set_blue (Fore_color,sum_b,working_palette); + + Wait_end_of_click(); + } + } Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); // On prépare la "modifiabilité" des nouvelles couleurs + Set_palette(working_palette); memcpy(temp_palette,working_palette,sizeof(T_Palette)); - need_to_remap=1; + break; case 6 : // Grey scale @@ -1420,22 +1709,22 @@ void Button_Palette(void) Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); - Window_rectangle(237,36,56,7,MC_Light); + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); + if (show_used_colors) + Tag_used_colors(1, color_usage); - Update_pixel_count(block_start, block_end, color_usage); - need_to_remap=1; Set_palette(working_palette); @@ -1474,20 +1763,19 @@ void Button_Palette(void) Num2str(block_end ,str+4,3); str[3]=26; // Flèche vers la droite // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(264,93,block_start,block_end); + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); } else { // Cas d'une seule couleur Num2str(Fore_color,str,3); - Window_rectangle(237,36,56,7,MC_Light); + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); } - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // On tag le bloc (ou la couleur) Tag_color_range(block_start,block_end); - Update_pixel_count(block_start, block_end, color_usage); need_to_remap=1; @@ -1529,38 +1817,23 @@ void Button_Palette(void) case 11: // Reduce memcpy(backup_palette, working_palette, sizeof(T_Palette)); - switch(Window_attribute2) // Get the dropdown value + if (Window_attribute2==0) // User picked "other" choice { - case 0: // 128 - reduce_colors_number = 128; - break; - case 1: // 64 - reduce_colors_number = 64; - break; - case 2: // 32 - reduce_colors_number = 32; - break; - case 3: // 16 - reduce_colors_number = 16; - break; - case 4: // 8 - reduce_colors_number = 8; - break; - case 5: // 4 - reduce_colors_number = 4; - break; - case 6: // 2 - reduce_colors_number = 2; - break; - case 7: // other - reduce_colors_number - = Requester_window("Enter the max. number of colors", + int choice; + + choice=Requester_window("Enter the max. number of colors", reduce_colors_number); - if (reduce_colors_number < 2 || reduce_colors_number >= 256) - reduce_colors_number = -1; - break; + + if (choice < 2 || choice > 256) + break; // Cancel + + reduce_colors_number = choice; } - if (reduce_colors_number > 0) + else + // Each other dropdown item has a number of colors as id. + reduce_colors_number = Window_attribute2; + + if (reduce_colors_number >= 2) { if (!image_is_backed_up) { @@ -1600,8 +1873,9 @@ void Button_Palette(void) need_to_remap=1; break; - case 15 : // Used > open histogram - Window_Histogram(block_start, block_end, color_usage); + case 15 : // Used : show usage tags + show_used_colors = !show_used_colors; + Tag_used_colors(show_used_colors, color_usage); break; case 16 : // Zap unused @@ -1644,25 +1918,25 @@ void Button_Palette(void) { (red_slider->Position)--; Window_draw_slider(red_slider); - Set_red(Fore_color,(Color_max-red_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].R*Color_count/256,str); - Print_counter(176,172,str,MC_Black,MC_Light); + Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); + Format_component(working_palette[Fore_color].R*Color_count/256,str); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->Position) { (green_slider->Position)--; Window_draw_slider(green_slider); - Set_green (Fore_color,(Color_max-green_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].G*Color_count/256,str); - Print_counter(203,172,str,MC_Black,MC_Light); + Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); + Format_component(working_palette[Fore_color].G*Color_count/256,str); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->Position) { (blue_slider->Position)--; Window_draw_slider(blue_slider); - Set_blue (Fore_color,(Color_max-blue_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].B*Color_count/256,str); - Print_counter(230,172,str,MC_Black,MC_Light); + Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); + Format_component(working_palette[Fore_color].B*Color_count/256,str); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else @@ -1685,9 +1959,9 @@ void Button_Palette(void) for (i=block_start; i<=block_end; i++) { - Set_red(i,temp_palette[i].R+(Color_max-red_slider->Position)*255/Color_max,working_palette); - Set_green (i,temp_palette[i].G+(Color_max-green_slider->Position)*255/Color_max,working_palette); - Set_blue (i,temp_palette[i].B+(Color_max-blue_slider->Position)*255/Color_max,working_palette); + Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); + Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); + Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- @@ -1708,7 +1982,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- @@ -1729,7 +2003,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- @@ -1750,7 +2024,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1769,25 +2043,25 @@ void Button_Palette(void) { (red_slider->Position)++; Window_draw_slider(red_slider); - Set_red(Fore_color,(Color_max-red_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].R*Color_count/256,str); - Print_counter(176,172,str,MC_Black,MC_Light); + Set_red(Fore_color,Reduce_component(Color_max-red_slider->Position),working_palette); + Format_component(working_palette[Fore_color].R*Color_count/256,str); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (green_slider->PositionPosition)++; Window_draw_slider(green_slider); - Set_green (Fore_color,(Color_max-green_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].G*Color_count/256,str); - Print_counter(203,172,str,MC_Black,MC_Light); + Set_green (Fore_color,Reduce_component(Color_max-green_slider->Position),working_palette); + Format_component(working_palette[Fore_color].G*Color_count/256,str); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); } if (blue_slider->PositionPosition)++; Window_draw_slider(blue_slider); - Set_blue (Fore_color,(Color_max-blue_slider->Position)*255/Color_max,working_palette); - Format_componant(working_palette[Fore_color].B*Color_count/256,str); - Print_counter(230,172,str,MC_Black,MC_Light); + Set_blue (Fore_color,Reduce_component(Color_max-blue_slider->Position),working_palette); + Format_component(working_palette[Fore_color].B*Color_count/256,str); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } } else @@ -1810,9 +2084,9 @@ void Button_Palette(void) for (i=block_start; i<=block_end; i++) { - Set_red(i,temp_palette[i].R+(Color_max-red_slider->Position)*255/Color_max,working_palette); - Set_green (i,temp_palette[i].G+(Color_max-green_slider->Position)*255/Color_max,working_palette); - Set_blue (i,temp_palette[i].B+(Color_max-blue_slider->Position)*255/Color_max,working_palette); + Set_red(i,temp_palette[i].R+Reduce_component(Color_max-red_slider->Position),working_palette); + Set_green (i,temp_palette[i].G+Reduce_component(Color_max-green_slider->Position),working_palette); + Set_blue (i,temp_palette[i].B+Reduce_component(Color_max-blue_slider->Position),working_palette); } // -- red -- @@ -1833,7 +2107,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(176,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- green -- @@ -1854,7 +2128,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(203,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); // -- blue -- @@ -1875,7 +2149,7 @@ void Button_Palette(void) // Jauge nulle: strcpy(str,"± 0"); } - Print_counter(230,172,str,MC_Black,MC_Light); + Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); } need_to_remap=1; @@ -1958,34 +2232,35 @@ void Button_Palette(void) memcpy(temp_palette,working_palette,sizeof(T_Palette)); memcpy(backup_palette, working_palette,sizeof(T_Palette)); + Hide_cursor(); + Palette_view_is_RGB = !Palette_view_is_RGB; - if(! Palette_view_is_RGB) { // On passe en HSL - Print_in_window(184,71,"H",MC_Dark,MC_Light); - Print_in_window(211,71,"S",MC_Dark,MC_Light); - Print_in_window(238,71,"L",MC_Dark,MC_Light); - Componant_unit(256); + Print_RGB_or_HSL(1); + Component_unit(256); // Display the + and - button as disabled - Window_draw_normal_bouton(266, 74,12,11,"+",0,0); - Window_draw_normal_bouton(266,165,12,11,"-",0,0); + Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,0); + Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,0); } else { // On passe en RGB - Print_in_window(184,71,"R",MC_Dark,MC_Light); - Print_in_window(211,71,"G",MC_Dark,MC_Light); - Print_in_window(238,71,"B",MC_Dark,MC_Light); - Componant_unit(RGB_scale); + Print_RGB_or_HSL(0); + Component_unit(RGB_scale); // Display the + and - button as enabled - Window_draw_normal_bouton(266, 74,12,11,"+",0,1); - Window_draw_normal_bouton(266,165,12,11,"-",0,1); + Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1); + Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1); } Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette); - Update_window_area(265,73,14,103); + + Display_cursor(); + + Update_window_area(BUTTON_PLUS_X-1,BUTTON_PLUS_Y-1,14,14); + Update_window_area(BUTTON_MINUS_X-1,BUTTON_MINUS_Y-1,14,14); break; case 23 : // Sort palette @@ -1996,6 +2271,9 @@ void Button_Palette(void) byte remap_table[256]; byte inverted_table[256]; byte begin, end; + long lightness; + long old_lightness; + if(block_start==block_end) { @@ -2018,8 +2296,8 @@ void Button_Palette(void) image_is_backed_up=1; } - if(Window_attribute1==LEFT_SIDE) - // Laft click on button: Sort by Hue (H) and Lightness (L) + if(Window_attribute2==0) + // Sort by Hue (H) and Lightness (L) while(swap==1) { swap=0; @@ -2050,19 +2328,17 @@ void Button_Palette(void) } } - else // Right click > Sort only on L + else // Sort only on perceived lightness while(swap==1) { swap=0; - l=255; - for(temp_color=begin;temp_color<=end;temp_color++) + lightness=Perceptual_lightness(working_palette+begin); + for(temp_color=begin+1;temp_color<=end;temp_color++) { - ol=l; - RGB_to_HSL(working_palette[temp_color].R, - working_palette[temp_color].G, - working_palette[temp_color].B,&h,&s,&l); + old_lightness=lightness; + lightness=Perceptual_lightness(working_palette+temp_color); - if(l>ol) + if(lightness>old_lightness) { // Swap color with the previous one SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) @@ -2089,6 +2365,95 @@ void Button_Palette(void) need_to_remap=1; } break; + case 24: // R G B value: Hex entry + { + char str[7]; + unsigned int new_color; + + Hide_cursor(); + Print_in_window(NUMERIC_BOX_X+2,NUMERIC_BOX_Y+2,"Hex",MC_Black,MC_Light); + // Clear out remaining area + Window_rectangle(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3,MC_Light); + Update_window_area(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3); + + str[0]='\0'; + Display_cursor(); + if (Readline(NUMERIC_BOX_X+NUMERIC_BOX_W-2-6*8, NUMERIC_BOX_Y+2, str, 6, INPUT_TYPE_HEXA)) + { + int length = strlen(str); + short new_red, new_blue, new_green; + + if (length==3 || length==6) + { + sscanf(str, "%x", &new_color); + if (length==3) + { + new_color = + ((new_color&0xF00)*0x1100) | + ((new_color&0x0F0)*0x110) | + ((new_color&0x00F)*0x11); + } + new_red=(new_color&0xFF0000) >> 16; + new_green=(new_color&0x00FF00) >> 8; + new_blue=(new_color&0x0000FF); + + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + // Assign color + for (i=block_start;i<=block_end;i++) + { + Set_red(i,new_red,working_palette); + Set_green (i,new_green,working_palette); + Set_blue (i,new_blue,working_palette); + } + // On prépare la "modifiabilité" des nouvelles couleurs + Set_palette(working_palette); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + need_to_remap=1; + } + } + // Clear out numeric area + Window_rectangle(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2,MC_Light); + Update_window_area(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2); + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + } + break; + + case 25: // Number of colors used: Open histogram + { + int selected_col; + + selected_col=Window_Histogram(block_start, block_end, color_usage); + if (selected_col!=-1) + { + // Tag selected color + Fore_color=first_color=last_color=block_start=block_end=selected_col; + Tag_color_range(block_start,block_end); + + // Affichage du n° de la couleur sélectionnée + Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); + Num2str(Fore_color,str,3); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); + Update_window_area(COLOR_X,COLOR_Y,56,7); + + // Affichage des jauges + Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); + Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); + + // Affichage dans le block de visu de la couleur en cours + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); + + memcpy(backup_palette ,working_palette,sizeof(T_Palette)); + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + + } + Display_cursor(); + Input_sticky_control=0; + Wait_end_of_click(); + break; + } } @@ -2110,12 +2475,10 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; @@ -2134,12 +2497,10 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); Display_cursor(); } Key=0; @@ -2148,11 +2509,11 @@ void Button_Palette(void) { Back_color--; Hide_cursor(); - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } @@ -2160,11 +2521,11 @@ void Button_Palette(void) { Back_color++; Hide_cursor(); - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); Display_cursor(); Key=0; } @@ -2208,11 +2569,11 @@ void Button_Palette(void) { Back_color=color; // 4 blocks de back_color entourant la fore_color - Window_rectangle(260,89,24,4,Back_color); - Window_rectangle(260,157,24,4,Back_color); - Window_rectangle(260,93,4,64,Back_color); - Window_rectangle(280,93,4,64,Back_color); - Update_window_area(260,89,32,72); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color); + Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); } } else @@ -2221,20 +2582,17 @@ void Button_Palette(void) Tag_color_range(block_start,block_end); // Affichage du n° de la couleur sélectionnée - Window_rectangle(261,36,32,7,MC_Light); - Update_window_area(261,36,32,7); + Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light); + Update_window_area(COLOR_X+24,COLOR_Y,32,7); Num2str(Fore_color,str,3); - Print_in_window(237, 36, str,MC_Black,MC_Light); + Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // Pixel count - Update_pixel_count(Fore_color, Fore_color, color_usage); - // Affichage des jauges Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); // Affichage dans le block de visu de la couleur en cours - Window_rectangle(264,93,16,64,Fore_color); - Update_window_area(264,93,16,64); + Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color); + Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H); memcpy(backup_palette ,working_palette,sizeof(T_Palette)); memcpy(temp_palette,working_palette,sizeof(T_Palette)); @@ -2254,6 +2612,28 @@ void Button_Palette(void) // Close (confirm) clicked_button=14; } + else if (Key == (SDLK_c|MOD_CTRL)) // Ctrl-C + { + Set_clipboard_colors(block_end+1-block_start,working_palette + block_start); + } + else if (Key == (SDLK_v|MOD_CTRL)) // Ctrl-V + { + int nb_colors; + + Hide_cursor(); + // Backup + memcpy(backup_palette,working_palette,sizeof(T_Palette)); + + nb_colors = Get_clipboard_colors(working_palette, block_start); + if (nb_colors>0) + { + memcpy(temp_palette,working_palette,sizeof(T_Palette)); + Set_palette(working_palette); + need_to_remap=1; + Display_cursor(); + Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); + } + } } if (need_to_remap) @@ -2265,8 +2645,12 @@ void Button_Palette(void) Remap_screen_after_menu_colors_change(); // Puis on remet les trucs qui ne devaient pas changer Window_draw_palette_bouton(5,79); - Window_rectangle(260,89,24,72,Back_color); - Display_grad_block_in_window(264,93,block_start,block_end); + if (show_used_colors) + Tag_used_colors(1, color_usage); + Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color); + Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H); + + Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); Update_window_area(8,82,16*10,5*16); @@ -2319,8 +2703,6 @@ void Button_Palette(void) } - - //---------------------- Menu de palettes secondaires ------------------------ void Button_Secondary_palette(void) @@ -2456,6 +2838,7 @@ void Button_Secondary_palette(void) { Set_palette_RGB_scale(rgb_scale); Set_palette(Main_palette); + Compute_optimal_menu_colors(Main_palette); } if (clicked_button==1) @@ -2473,6 +2856,76 @@ void Button_Secondary_palette(void) { Change_palette_cells(); Display_menu(); - Display_sprite_in_menu(BUTTON_PAL_LEFT,18+(Config.Palette_vertical!=0)); + Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1); + Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED); + Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED); } } + +// ========= Clipboard management ============== + +int Palette_clipboard_count=0; +T_Palette Palette_clipboard; + +/// Put some colors in the clipboard. +/// @param nb_colors Number of colors to push +/// @param colors First color of the input array +void Set_clipboard_colors(int nb_colors, T_Components *colors) +{ + Palette_clipboard_count=nb_colors; + if (nb_colors) + { + memcpy(Palette_clipboard, colors, nb_colors*sizeof(T_Components)); + } +} + +/// Get some RGB colors from clipboard. +/// @param palette Target palette +/// @param start_color Index of first color to replace +/// @return Number of colors retrieved (0-256) +int Get_clipboard_colors(T_Palette palette, byte start_color) +{ + int nb_colors = Palette_clipboard_count; + + if (nb_colors==0) + return 0; + + if (start_color+nb_colors > 256) + { + nb_colors=256-start_color; + } + memcpy(palette+start_color, Palette_clipboard, nb_colors*sizeof(T_Components)); + return nb_colors; +} + +/// Get the favorite color to use for GUI's black,dark,light or white. +const T_Components * Favorite_GUI_color(byte color_index) +{ + static const T_Components cpc_colors[4] = { + { 0, 0, 0}, + { 0, 0,128}, // Dark blue + {128,128,128}, // Grey + {255,255,255} + }; + + if (RGB_scale==3) + { + // Check if ALL GUI colors are compatible with /rgb 3 + int i; + for (i=0; i<4; i++) + { + T_Components col; + col=Gfx->Default_palette[Gfx->Color[i]]; + if ((col.R!=255 && col.R!=128 && col.R!=0) + ||(col.G!=255 && col.G!=128 && col.G!=0) + ||(col.B!=255 && col.B!=128 && col.B!=0)) + // Specialized colors for CPC palette + return &cpc_colors[color_index]; + } + // Skin has suitable colors + return &(Gfx->Default_palette[Gfx->Color[color_index]]); + } + else + // Should be Config.Fav_menu_colors[index] if using user colors + return &(Gfx->Default_palette[Gfx->Color[color_index]]); +} diff --git a/src/palette.h b/src/palette.h index 65d3e2e7..5b68e1d4 100644 --- a/src/palette.h +++ b/src/palette.h @@ -31,6 +31,8 @@ void Button_Secondary_palette(void); /// Choose the number of graduations for RGB components, from 2 to 256. void Set_palette_RGB_scale(int); +int Get_palette_RGB_scale(void); + /// /// Scale a component (R, G or B) according to the current RGB graduations. /// Returns the resulting value, in the [0-255] range. @@ -42,3 +44,17 @@ byte Round_palette_component(byte comp); @param not_picture 0 if the caller is the palette screen, 1 if it's a preview in the file selector. */ void Set_nice_menu_colors(dword * color_usage,int not_picture); + +/// Put some colors in the clipboard. +/// @param nb_colors Number of colors to push +/// @param colors First color of the input array +void Set_clipboard_colors(int nb_colors, T_Components *colors); + +/// Get some RGB colors from clipboard. +/// @param palette Target palette +/// @param start_color Index of first color to replace +/// @return Number of colors retrieved (0-256) +int Get_clipboard_colors(T_Palette palette, byte start_color); + +/// Get the favorite color to use for GUI's black,dark,light or white. +const T_Components * Favorite_GUI_color(byte color_index); diff --git a/src/readini.c b/src/readini.c index 9dbd91a0..15473878 100644 --- a/src/readini.c +++ b/src/readini.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues @@ -32,6 +33,7 @@ #include "global.h" #include "misc.h" #include "readini.h" +#include "setup.h" void Load_INI_clear_string(char * str, byte keep_comments) { @@ -432,6 +434,13 @@ int Load_INI(T_Config * conf) char value_label[1024]; Line_number_in_INI_file=0; + +#if defined(__WIZ__) || defined(__CAANOO__) + conf->Stylus_mode = 1; +#else + conf->Stylus_mode = 0; +#endif + // On alloue les zones de mémoire: buffer=(char *)malloc(1024); @@ -439,14 +448,14 @@ int Load_INI(T_Config * conf) // On calcule le nom du fichier qu'on manipule: strcpy(filename,Config_directory); - strcat(filename,"gfx2.ini"); + strcat(filename,INI_FILENAME); file=fopen(filename,"r"); if (file==0) { // Si le fichier ini est absent on le relit depuis gfx2def.ini strcpy(filename,Data_directory); - strcat(filename,"gfx2def.ini"); + strcat(filename,INIDEF_FILENAME); file=fopen(filename,"r"); if (file == 0) { @@ -894,6 +903,39 @@ int Load_INI(T_Config * conf) Menu_bars[index].Visible = (values[0] & (1<Right_click_colorpick=0; + // Optional, right mouse button to pick colors (>=2.3) + if (!Load_INI_get_values (file,buffer,"Right_click_colorpick",1,values)) + { + conf->Right_click_colorpick=(values[0]!=0); + } + + conf->Sync_views=1; + // Optional, synced view of main and spare (>=2.3) + if (!Load_INI_get_values (file,buffer,"Sync_views",1,values)) + { + conf->Sync_views=(values[0]!=0); + } + + conf->Swap_buttons=0; + // Optional, key for swap buttons (>=2.3) + if (!Load_INI_get_values (file,buffer,"Swap_buttons",1,values)) + { + switch(values[0]) + { + case 1: + conf->Swap_buttons=MOD_CTRL; + break; + case 2: + conf->Swap_buttons=MOD_ALT; + break; + } + } + + + + // Insert new values here fclose(file); diff --git a/src/readline.c b/src/readline.c index d0292ca6..ce153024 100644 --- a/src/readline.c +++ b/src/readline.c @@ -40,6 +40,13 @@ #include "windows.h" #include "input.h" +// Virtual keyboard is mandatory on these platforms: +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) + #ifndef VIRT_KEY + #define VIRT_KEY 1 + #endif +#endif + #define TEXT_COLOR MC_Black #define BACKGROUND_COLOR MC_Light #define CURSOR_COLOR MC_Black @@ -98,8 +105,41 @@ int Valid_character(int c) void Display_whole_string(word x_pos,word y_pos,char * str,byte position) { - Print_in_window(x_pos,y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); - Print_char_in_window(x_pos+(position<<3),y_pos,str[position],CURSOR_COLOR,CURSOR_BACKGROUND_COLOR); + char cursor[2]; + Print_general(x_pos,y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); + + cursor[0]=str[position] ? str[position] : ' '; + cursor[1]='\0'; + Print_general(x_pos+(position<<3)*Menu_factor_X,y_pos,cursor,CURSOR_COLOR,CURSOR_BACKGROUND_COLOR); +} + +void Init_virtual_keyboard(word y_pos, word keyboard_width, word keyboard_height) +{ + int h_pos; + int v_pos; + int parent_window_x=Window_pos_X+2; + + h_pos= Window_pos_X+(keyboard_width-Window_width)*Menu_factor_X/-2; + if (h_pos<0) + h_pos=0; + else if (h_pos+keyboard_width*Menu_factor_X>Screen_width) + h_pos=Screen_width-keyboard_width*Menu_factor_X; + v_pos=Window_pos_Y+(y_pos+9)*Menu_factor_Y; + if (v_pos+(keyboard_height*Menu_factor_Y)>Screen_height) + v_pos=Window_pos_Y+(y_pos-keyboard_height-4)*Menu_factor_Y; + + Hide_cursor(); + Open_popup(h_pos,v_pos,keyboard_width,keyboard_height); + Window_rectangle(1,0,Window_width-1, Window_height-1, MC_Light); + Window_rectangle(0,0,1,Window_height-2, MC_White); + // white border on top left angle, when it exceeds border. + if (parent_window_x>Window_pos_X) + Window_rectangle(0,0,(parent_window_x-Window_pos_X)/Menu_factor_X, 1, MC_White); + Window_rectangle(2,Window_height-2,Window_width-2, 2, MC_Black); + if(keyboard_width<320) + { + Window_rectangle(Window_width-2,2,2,Window_height-2, MC_Black); + } } /**************************************************************************** @@ -143,28 +183,156 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz byte size; word input_key=0; byte is_authorized; - + word window_x=Window_pos_X; + word window_y=Window_pos_Y; byte offset=0; // index du premier caractère affiché + +#ifdef VIRT_KEY + // Virtual keyboard + byte use_virtual_keyboard=0; + static byte caps_lock=0; + word keymapping[] = + { + SDLK_CLEAR,SDLK_BACKSPACE,SDLK_RETURN,KEY_ESC, + '0','1','2','3','4','5','6','7','8','9','.',',', + 'Q','W','E','R','T','Y','U','I','O','P', + 'A','S','D','F','G','H','J','K','L', + SDLK_CAPSLOCK,'Z','X','C','V','B','N','M',' ', + '-','+','*','/','|','\\', + '(',')','{','}','[',']', + '_','=','<','>','%','@', + ':',';','`','\'','"','~', + '!','?','^','&','#','$' + }; +#endif // Si on a commencé à editer par un clic-droit, on vide la chaine. if (Mouse_K==RIGHT_SIDE) str[0]='\0'; - else if (input_type==1 && str[0]!='\0') + else if (input_type==INPUT_TYPE_INTEGER && str[0]!='\0') snprintf(str,10,"%d",atoi(str)); // On tasse la chaine à gauche - else if (input_type==3) + else if (input_type==INPUT_TYPE_DECIMAL) { // Nothing. The caller should have used Sprint_double, with min_positions // at zero, so there's no spaces on the left and no useless 0s on the right. } + else if (input_type==INPUT_TYPE_HEXA) + { + // Nothing. The caller should have initialized a valid hexa number. + } + + // Virtual keyboards +#ifdef VIRT_KEY + if (input_type == INPUT_TYPE_STRING || input_type == INPUT_TYPE_FILENAME ) + { + int x,y; - Wait_end_of_click(); + Init_virtual_keyboard(y_pos, 320, 87); + + use_virtual_keyboard=1; + + // The order is important, see the array + + Window_set_normal_button( 7,67,43,15,"Clr", 0,1,KEY_NONE); + Window_set_normal_button( 51,67,43,15,"Del", 0,1,KEY_NONE); + Window_set_normal_button( 95,67,43,15,"OK", 0,1,KEY_NONE); + Window_set_normal_button(139,67,43,15,"Esc", 0,1,KEY_NONE); + Window_display_frame_in(5,65,179,19); + + Window_set_normal_button(193,63,17,19,"0", 0,1,KEY_NONE); + Window_set_normal_button(193,43,17,19,"1", 0,1,KEY_NONE); + Window_set_normal_button(211,43,17,19,"2", 0,1,KEY_NONE); + Window_set_normal_button(229,43,17,19,"3", 0,1,KEY_NONE); + Window_set_normal_button(193,23,17,19,"4", 0,1,KEY_NONE); + Window_set_normal_button(211,23,17,19,"5", 0,1,KEY_NONE); + Window_set_normal_button(229,23,17,19,"6", 0,1,KEY_NONE); + Window_set_normal_button(193, 3,17,19,"7", 0,1,KEY_NONE); + Window_set_normal_button(211, 3,17,19,"8", 0,1,KEY_NONE); + Window_set_normal_button(229, 3,17,19,"9", 0,1,KEY_NONE); + Window_set_normal_button(211,63,17,19,".", 0,1,KEY_NONE); + Window_set_normal_button(229,63,17,19,",", 0,1,KEY_NONE); + + Window_set_normal_button( 3, 3,18,19,"Q", 0,1,KEY_NONE); + Window_set_normal_button( 22, 3,18,19,"W", 0,1,KEY_NONE); + Window_set_normal_button( 41, 3,18,19,"E", 0,1,KEY_NONE); + Window_set_normal_button( 60, 3,18,19,"R", 0,1,KEY_NONE); + Window_set_normal_button( 79, 3,18,19,"T", 0,1,KEY_NONE); + Window_set_normal_button( 98, 3,18,19,"Y", 0,1,KEY_NONE); + Window_set_normal_button(117, 3,18,19,"U", 0,1,KEY_NONE); + Window_set_normal_button(136, 3,18,19,"I", 0,1,KEY_NONE); + Window_set_normal_button(155, 3,18,19,"O", 0,1,KEY_NONE); + Window_set_normal_button(174, 3,18,19,"P", 0,1,KEY_NONE); + + Window_set_normal_button( 12,23,18,19,"A", 0,1,KEY_NONE); + Window_set_normal_button( 31,23,18,19,"S", 0,1,KEY_NONE); + Window_set_normal_button( 50,23,18,19,"D", 0,1,KEY_NONE); + Window_set_normal_button( 69,23,18,19,"F", 0,1,KEY_NONE); + Window_set_normal_button( 88,23,18,19,"G", 0,1,KEY_NONE); + Window_set_normal_button(107,23,18,19,"H", 0,1,KEY_NONE); + Window_set_normal_button(126,23,18,19,"J", 0,1,KEY_NONE); + Window_set_normal_button(145,23,18,19,"K", 0,1,KEY_NONE); + Window_set_normal_button(164,23,18,19,"L", 0,1,KEY_NONE); + + Window_set_normal_button( 3,43,18,19,caps_lock?"\036":"\037", 0,1,KEY_NONE); + Window_set_normal_button( 22,43,18,19,"Z", 0,1,KEY_NONE); + Window_set_normal_button( 41,43,18,19,"X", 0,1,KEY_NONE); + Window_set_normal_button( 60,43,18,19,"C", 0,1,KEY_NONE); + Window_set_normal_button( 79,43,18,19,"V", 0,1,KEY_NONE); + Window_set_normal_button( 98,43,18,19,"B", 0,1,KEY_NONE); + Window_set_normal_button(117,43,18,19,"N", 0,1,KEY_NONE); + Window_set_normal_button(136,43,18,19,"M", 0,1,KEY_NONE); + Window_set_normal_button(155,43,18,19," ", 0,1,KEY_NONE); + + for (y=0; y<5; y++) + { + for (x=0; x<6; x++) + { + char label[2]=" "; + label[0]=keymapping[x+y*6+44]; + Window_set_normal_button(247+x*12, 3+y*16,11,15,label, 0,1,KEY_NONE); + } + } + + Update_window_area(0,0,Window_width, Window_height); + Display_cursor(); + } + else if (input_type == INPUT_TYPE_INTEGER || input_type == INPUT_TYPE_DECIMAL ) + { + Init_virtual_keyboard(y_pos, 215, 47); + + use_virtual_keyboard=1; + + // The order is important, see the array + + Window_set_normal_button( 7,27,43,15,"Clr", 0,1,KEY_NONE); + Window_set_normal_button( 51,27,43,15,"Del", 0,1,KEY_NONE); + Window_set_normal_button( 95,27,43,15,"OK", 0,1,KEY_NONE); + Window_set_normal_button(139,27,43,15,"Esc", 0,1,KEY_NONE); + Window_display_frame_in(5,25,179,19); + + Window_set_normal_button(174, 3,18,19,"0", 0,1,KEY_NONE); + Window_set_normal_button( 3, 3,18,19,"1", 0,1,KEY_NONE); + Window_set_normal_button( 22, 3,18,19,"2", 0,1,KEY_NONE); + Window_set_normal_button( 41, 3,18,19,"3", 0,1,KEY_NONE); + Window_set_normal_button( 60, 3,18,19,"4", 0,1,KEY_NONE); + Window_set_normal_button( 79, 3,18,19,"5", 0,1,KEY_NONE); + Window_set_normal_button( 98, 3,18,19,"6", 0,1,KEY_NONE); + Window_set_normal_button(117, 3,18,19,"7", 0,1,KEY_NONE); + Window_set_normal_button(136, 3,18,19,"8", 0,1,KEY_NONE); + Window_set_normal_button(155, 3,18,19,"9", 0,1,KEY_NONE); + Window_set_normal_button(193, 3,18,19,".", 0,1,KEY_NONE); + + Update_window_area(0,0,Window_width, Window_height); + Display_cursor(); + } +#endif Keyboard_click_allowed = 0; Hide_cursor(); // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); // Mise à jour des variables se rapportant à la chaîne en fonction de la chaîne initiale @@ -182,19 +350,67 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz if (visible_size + offset + 1 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; - Display_whole_string(x_pos,y_pos,display_string,position - offset); - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); Flush_update(); - - while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC) && Mouse_K == 0) + if (Mouse_K) { Display_cursor(); - do + Wait_end_of_click(); + Hide_cursor(); + } + + while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) + { + Display_cursor(); +#ifdef VIRT_KEY + if (use_virtual_keyboard) { - if(!Get_input()) SDL_Delay(20); + int clicked_button; + + clicked_button=Window_clicked_button(); input_key=Key_ANSI; - } while(input_key==0 && Mouse_K == 0); + + if (clicked_button==-1) + input_key=SDLK_RETURN; + else if (clicked_button>0) + { + input_key=keymapping[clicked_button-1]; + if (input_key==SDLK_CAPSLOCK) + { + // toggle uppercase + caps_lock=!caps_lock; + Hide_cursor(); + Print_in_window(8, 49,caps_lock?"\036":"\037", MC_Black,MC_Light); + Display_cursor(); + } + else if (input_key==SDLK_BACKSPACE) + { + // A little hack: the button for backspace will: + // - backspace if the cursor is at end of string + // - delete otherwise + // It's needed for those input boxes that are completely full. + if (position='A' && input_key<='Z' && !caps_lock) + { + input_key+='a'-'A'; + } + } + } + else +#endif + { + do + { + Get_input(20); + input_key=Key_ANSI; + if (Mouse_K) + input_key=SDLK_RETURN; + } while(input_key==0); + } Hide_cursor(); switch (input_key) { @@ -205,7 +421,7 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz size--; // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; } @@ -215,7 +431,7 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz { // Effacement de la chaîne if (position==size) - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position--; if (offset > 0 && (position == 0 || position < (offset + 1))) @@ -239,7 +455,7 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz { // Effacement de la chaîne if (position==size) - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position = 0; offset = 0; @@ -265,11 +481,18 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz Remove_character(str,position); size--; // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; } break; + case SDLK_CLEAR : // Clear + str[0]='\0'; + position=offset=0; + // Effacement de la chaîne + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), + visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); + goto affichage; case SDLK_RETURN : break; @@ -285,15 +508,15 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz is_authorized=0; // On commence par supposer qu'elle est interdite switch(input_type) { - case 0 : // N'importe quelle chaîne: + case INPUT_TYPE_STRING : if (input_key>=' ' && input_key<= 255) is_authorized=1; break; - case 1 : // Nombre + case INPUT_TYPE_INTEGER : if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; break; - case 3: // Decimal number + case INPUT_TYPE_DECIMAL: if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; else if (input_key=='-' && position==0 && str[0]!='-') @@ -301,10 +524,18 @@ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_siz else if (input_key=='.') is_authorized=1; break; - default : // Nom de fichier + case INPUT_TYPE_FILENAME: // On regarde si la touche est autorisée if ( Valid_character(input_key)) is_authorized=1; + case INPUT_TYPE_HEXA: + if ( (input_key>='0') && (input_key<='9') ) + is_authorized=1; + else if ( (input_key>='A') && (input_key<='F') ) + is_authorized=1; + else if ( (input_key>='a') && (input_key<='f') ) + is_authorized=1; + break; } // End du "switch(input_type)" // Si la touche était autorisée... @@ -337,20 +568,29 @@ affichage: if (visible_size + offset + 0 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; - Display_whole_string(x_pos,y_pos,display_string,position - offset); - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); } // End du "switch(input_key)" Flush_update(); } // End du "while" Keyboard_click_allowed = 1; - + #ifdef VIRT_KEY + if (use_virtual_keyboard) + { + byte old_mouse_k = Mouse_K; + Close_popup(); + Mouse_K=old_mouse_k; + Input_sticky_control=0; + } + #endif + // Effacement de la chaîne - Block(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); // On raffiche la chaine correctement - if (input_type==1) + if (input_type==INPUT_TYPE_INTEGER) { if (str[0]=='\0') { @@ -359,7 +599,7 @@ affichage: } Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); } - else if (input_type==3) + else if (input_type==INPUT_TYPE_DECIMAL) { double value; // Discard extra digits @@ -377,10 +617,10 @@ affichage: { Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } - Update_rect(Window_pos_X+(x_pos*Menu_factor_X),Window_pos_Y+(y_pos*Menu_factor_Y), + Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); - return (input_key==SDLK_RETURN || Mouse_K != 0); + return (input_key==SDLK_RETURN); } void Sprint_double(char *str, double value, byte decimal_places, byte min_positions) diff --git a/src/readline.h b/src/readline.h index af7e1e62..99e6a2f2 100644 --- a/src/readline.h +++ b/src/readline.h @@ -24,13 +24,22 @@ /// Text input functions. ////////////////////////////////////////////////////////////////////////////// +enum INPUT_TYPE +{ + INPUT_TYPE_STRING=0, ///< Any string + INPUT_TYPE_INTEGER=1, ///< Decimal integer + INPUT_TYPE_FILENAME=2,///< Filename + INPUT_TYPE_DECIMAL=3, ///< Decimal value + INPUT_TYPE_HEXA=4, ///< Hexadecimal integer +}; + /// /// Lets the user input a line of text, exit by Esc or Return. /// @param x_pos Coordinates of input, in window coordinates before scaling. /// @param y_pos Coordinates of input, in window coordinates before scaling. /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible and editable. -/// @param input_type 0=string, 1=number, 2=filename (255 editable characters) +/// @param input_type one of enum ::INPUT_TYPE /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type); @@ -41,7 +50,7 @@ byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type /// @param str The original string value (will be modified, unless user cancels. /// @param visible_size Number of characters visible. /// @param max_size Number of characters editable. -/// @param input_type 0=string, 1=integer, 2=filename (255 editable characters) 3=decimal +/// @param input_type one of enum ::INPUT_TYPE /// @param decimal_places Number of decimal places (used only with decimal type) /// @return 0 if user cancelled (esc), 1 if accepted (return) byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places); diff --git a/src/realpath.c b/src/realpath.c index 34668c08..1a916e72 100644 --- a/src/realpath.c +++ b/src/realpath.c @@ -6,8 +6,11 @@ #include #include #include +#if defined(__AROS__) +#include +#endif -#if defined(__AROS__) || defined(__BEOS__) || defined(__MORPHOS__) || defined(__GP2X__) || defined(__amigaos__) +#if defined(__AROS__) || defined(__BEOS__) || defined(__MORPHOS__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // These platforms don't have realpath(). // We use the following implementation, found in: // http://amiga.sourceforge.net/amigadevhelp/FUNCTIONS/GeekGadgets/realpath/ex02_realpath.c @@ -17,7 +20,7 @@ // the path. So this implementation is limited, it's really better to // use realpath() if your platform has it. - #if defined(__GP2X__) || defined(__amigaos__) + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) // This is a random default value ... #define PATH_MAX 32768 #endif diff --git a/src/saveini.c b/src/saveini.c index ad3930cf..b512b7ac 100644 --- a/src/saveini.c +++ b/src/saveini.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues @@ -30,6 +31,7 @@ #include "errors.h" #include "misc.h" #include "saveini.h" +#include "setup.h" int Save_INI_reach_group(FILE * old_file,FILE * new_file,char * buffer,char * group) { @@ -393,8 +395,8 @@ void Save_INI_flush(FILE * old_file,FILE * new_file,char * buffer) int Save_INI(T_Config * conf) { - FILE * Ancien_fichier; - FILE * Nouveau_fichier; + FILE * old_file; + FILE * new_file; char * buffer; int values[3]; char filename[MAX_PATH_CHARACTERS]; @@ -409,13 +411,13 @@ int Save_INI(T_Config * conf) // On calcule les noms des fichiers qu'on manipule: strcpy(filename,Config_directory); - strcat(filename,"gfx2.ini"); + strcat(filename,INI_FILENAME); // On vérifie si le fichier INI existe if ((ini_file_exists = File_exists(filename))) { strcpy(temp_filename,Config_directory); - strcat(temp_filename,"gfx2.$$$"); + strcat(temp_filename,INISAVE_FILENAME); // On renome l'ancienne version du fichier INI vers un fichier temporaire: if (rename(filename,temp_filename)!=0) @@ -425,237 +427,237 @@ int Save_INI(T_Config * conf) } // On récupère un fichier INI "propre" à partir de gfx2def.ini strcpy(ref_ini_file,Data_directory); - strcat(ref_ini_file,"gfx2def.ini"); - Ancien_fichier=fopen(ref_ini_file,"rb"); - if (Ancien_fichier==0) + strcat(ref_ini_file,INIDEF_FILENAME); + old_file=fopen(ref_ini_file,"rb"); + if (old_file==0) { - fclose(Ancien_fichier); + fclose(old_file); free(buffer); return ERROR_INI_MISSING; } - Nouveau_fichier=fopen(filename,"wb"); - if (Nouveau_fichier==0) + new_file=fopen(filename,"wb"); + if (new_file==0) { free(buffer); return ERROR_SAVING_INI; } - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[MOUSE]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MOUSE]"))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_x; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"X_sensitivity",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=conf->Mouse_sensitivity_index_y; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Y_sensitivity",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_sensitivity",1,values,0))) goto Erreur_Retour; values[0]=0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"X_correction_factor",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"X_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Y_correction_factor",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Y_correction_factor",1,values,0))) goto Erreur_Retour; values[0]=(conf->Cursor)+1; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Cursor_aspect",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Cursor_aspect",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[MENU]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MENU]"))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[2].R>>2; values[1]=conf->Fav_menu_colors[2].G>>2; values[2]=conf->Fav_menu_colors[2].B>>2; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Light_color",3,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Light_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Fav_menu_colors[1].R>>2; values[1]=conf->Fav_menu_colors[1].G>>2; values[2]=conf->Fav_menu_colors[1].B>>2; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Dark_color",3,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Dark_color",3,values,0))) goto Erreur_Retour; values[0]=conf->Ratio; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Menu_ratio",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Menu_ratio",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[FILE_SELECTOR]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[FILE_SELECTOR]"))) goto Erreur_Retour; values[0]=conf->Show_hidden_files?1:0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Show_hidden_files",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_files",1,values,1))) goto Erreur_Retour; values[0]=conf->Show_hidden_directories?1:0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Show_hidden_directories",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_hidden_directories",1,values,1))) goto Erreur_Retour; /* values[0]=conf->Show_system_directories?1:0; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Show_system_directories",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Show_system_directories",1,values,1))) goto Erreur_Retour; */ values[0]=conf->Timer_delay; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Preview_delay",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Preview_delay",1,values,0))) goto Erreur_Retour; values[0]=conf->Maximize_preview; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Maximize_preview",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Maximize_preview",1,values,1))) goto Erreur_Retour; values[0]=conf->Find_file_fast; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Find_file_fast",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Find_file_fast",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[LOADING]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[LOADING]"))) goto Erreur_Retour; values[0]=conf->Auto_set_res; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_set_resolution",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_set_resolution",1,values,1))) goto Erreur_Retour; values[0]=conf->Set_resolution_according_to; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Set_resolution_according_to",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Set_resolution_according_to",1,values,0))) goto Erreur_Retour; values[0]=conf->Clear_palette; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Clear_palette",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_palette",1,values,1))) goto Erreur_Retour; - if ((return_code=Save_INI_reach_group(Ancien_fichier,Nouveau_fichier,buffer,"[MISCELLANEOUS]"))) + if ((return_code=Save_INI_reach_group(old_file,new_file,buffer,"[MISCELLANEOUS]"))) goto Erreur_Retour; values[0]=conf->Display_image_limits; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Draw_limits",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Draw_limits",1,values,1))) goto Erreur_Retour; values[0]=conf->Adjust_brush_pick; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Adjust_brush_pick",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Adjust_brush_pick",1,values,1))) goto Erreur_Retour; values[0]=2-conf->Coords_rel; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Coordinates",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Coordinates",1,values,0))) goto Erreur_Retour; values[0]=conf->Backup; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Backup",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Backup",1,values,1))) goto Erreur_Retour; values[0]=conf->Max_undo_pages; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Undo_pages",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Undo_pages",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_left_click_on_slider; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Gauges_scrolling_speed_Left",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Left",1,values,0))) goto Erreur_Retour; values[0]=conf->Delay_right_click_on_slider; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Gauges_scrolling_speed_Right",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Gauges_scrolling_speed_Right",1,values,0))) goto Erreur_Retour; values[0]=conf->Auto_save; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_save",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_save",1,values,1))) goto Erreur_Retour; values[0]=conf->Nb_max_vertices_per_polygon; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Vertices_per_polygon",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Vertices_per_polygon",1,values,0))) goto Erreur_Retour; values[0]=conf->Fast_zoom; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Fast_zoom",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Fast_zoom",1,values,1))) goto Erreur_Retour; values[0]=conf->Separate_colors; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Separate_colors",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Separate_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->FX_Feedback; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"FX_feedback",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"FX_feedback",1,values,1))) goto Erreur_Retour; values[0]=conf->Safety_colors; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Safety_colors",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Safety_colors",1,values,1))) goto Erreur_Retour; values[0]=conf->Opening_message; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Opening_message",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Opening_message",1,values,1))) goto Erreur_Retour; values[0]=conf->Clear_with_stencil; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Clear_with_stencil",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Clear_with_stencil",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_discontinuous; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_discontinuous",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_discontinuous",1,values,1))) goto Erreur_Retour; values[0]=conf->Screen_size_in_GIF; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Save_screen_size_in_GIF",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Save_screen_size_in_GIF",1,values,1))) goto Erreur_Retour; values[0]=conf->Auto_nb_used; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Auto_nb_colors_used",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Auto_nb_colors_used",1,values,1))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Default_video_mode",Mode_label(conf->Default_resolution)))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Default_video_mode",Mode_label(conf->Default_resolution)))) goto Erreur_Retour; values[0]=Video_mode[0].Width; values[1]=Video_mode[0].Height; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Default_window_size",2,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Default_window_size",2,values,0))) goto Erreur_Retour; values[0]=(conf->Mouse_merge_movement); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Merge_movement",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Merge_movement",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_X); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Palette_cells_X",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_X",1,values,0))) goto Erreur_Retour; values[0]=(conf->Palette_cells_Y); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Palette_cells_Y",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_cells_Y",1,values,0))) goto Erreur_Retour; for (index=0;indexBookmark_label[index]))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Bookmark_label",conf->Bookmark_label[index]))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Bookmark_directory",conf->Bookmark_directory[index]))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Bookmark_directory",conf->Bookmark_directory[index]))) goto Erreur_Retour; } values[0]=(conf->Palette_vertical); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Palette_vertical",1,values,1))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Palette_vertical",1,values,1))) goto Erreur_Retour; values[0]=conf->Window_pos_x; values[1]=conf->Window_pos_y; - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Window_position",2,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Window_position",2,values,0))) goto Erreur_Retour; values[0]=(conf->Double_click_speed); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Double_click_speed",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_click_speed",1,values,0))) goto Erreur_Retour; values[0]=(conf->Double_key_speed); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Double_key_speed",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Double_key_speed",1,values,0))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Skin_file",conf->Skin_file))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Skin_file",conf->Skin_file))) goto Erreur_Retour; - if ((return_code=Save_INI_set_strings (Ancien_fichier,Nouveau_fichier,buffer,"Font_file",conf->Font_file))) + if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Font_file",conf->Font_file))) goto Erreur_Retour; values[0]=(conf->Grid_XOR_color); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Grid_XOR_color",1,values,0))) + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Grid_XOR_color",1,values,0))) goto Erreur_Retour; values[0]=(Pixel_ratio); - if ((return_code=Save_INI_set_values (Ancien_fichier,Nouveau_fichier,buffer,"Pixel_ratio",1,values,0))) { + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Pixel_ratio",1,values,0))) { DEBUG("saving pixel ratio",return_code); goto Erreur_Retour; } @@ -670,14 +672,37 @@ int Save_INI(T_Config * conf) for (; index<8;index++) values[0] |= (1<Right_click_colorpick); + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Right_click_colorpick",1,values,1))) + goto Erreur_Retour; + + values[0]=(conf->Sync_views); + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Sync_views",1,values,1))) + goto Erreur_Retour; + + switch(conf->Swap_buttons) + { + case MOD_CTRL: + values[0]=1; + break; + case MOD_ALT: + values[0]=2; + break; + default: + values[0]=0; + } + if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Swap_buttons",1,values,0))) + goto Erreur_Retour; + + // Insert new values here + + Save_INI_flush(old_file,new_file,buffer); - Save_INI_flush(Ancien_fichier,Nouveau_fichier,buffer); - - fclose(Nouveau_fichier); - fclose(Ancien_fichier); + fclose(new_file); + fclose(old_file); // On efface le fichier temporaire <=> Ancienne version du .INI if (ini_file_exists) @@ -689,8 +714,8 @@ int Save_INI(T_Config * conf) Erreur_Retour: - fclose(Nouveau_fichier); - fclose(Ancien_fichier); + fclose(new_file); + fclose(old_file); free(buffer); return return_code; diff --git a/src/sdlscreen.c b/src/sdlscreen.c index 34ca890b..a8ef9476 100644 --- a/src/sdlscreen.c +++ b/src/sdlscreen.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2007 Adrien Destugues @@ -23,6 +24,15 @@ #include #include #include +#include +#if defined(__WIN32__) + #include +#endif +// There is no WM on the GP2X... +#ifndef __GP2X__ + #include +#endif + #include "global.h" #include "sdlscreen.h" #include "errors.h" @@ -42,14 +52,21 @@ #ifndef UPDATE_METHOD #if defined(__macosx__) #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE + #elif defined(__MINT__) + #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #else #define UPDATE_METHOD UPDATE_METHOD_CUMULATED #endif #endif +volatile int Allow_colorcycling=1; + /// Sets the new screen/window dimensions. void Set_mode_SDL(int *width, int *height, int fullscreen) { + static SDL_Cursor* cur = NULL; + static byte cursorData = 0; + Screen_SDL=SDL_SetVideoMode(*width,*height,8,(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE); if(Screen_SDL != NULL) { @@ -66,7 +83,15 @@ void Set_mode_SDL(int *width, int *height, int fullscreen) { DEBUG("Error: Unable to change video mode!",0); } - SDL_ShowCursor(0); // Hide the SDL mouse cursor, we use our own + + // Trick borrowed to Barrage (http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg737265.html) : + // Showing the cursor but setting it to fully transparent allows us to get absolute mouse coordinates, + // this means we can use tablet in fullscreen mode. + SDL_ShowCursor(1); // Hide the SDL mouse cursor, we use our own + + SDL_FreeCursor(cur); + cur = SDL_CreateCursor(&cursorData, &cursorData, 1,1,0,0); + SDL_SetCursor(cur); } #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) @@ -194,16 +219,36 @@ byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y) return ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]; } +/// Writes a pixel in a 8-bit SDL surface. +void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color) +{ + ((byte *)(bmp->pixels))[(y*bmp->pitch+x)]=color; +} + + /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y) { + byte * ptr; + switch(bmp->format->BytesPerPixel) { case 4: default: return *((dword *)((byte *)bmp->pixels+(y*bmp->pitch+x*4))); case 3: - return *(((dword *)((byte *)bmp->pixels+(y*bmp->pitch+x*3)))) & 0xFFFFFF; + // Reading a 4-byte number starting at an address that isn't a multiple + // of 2 (or 4?) is not supported on Caanoo console at least (ARM CPU) + // So instead, we will read the 3 individual bytes, and re-construct the + // "dword" expected by SDL. + ptr = ((byte *)bmp->pixels)+(y*bmp->pitch+x*3); + #ifdef SDL_LIL_ENDIAN + // Read ABC, output _CBA : Most Significant Byte is zero. + return (*ptr) | (*(ptr+1)<<8) | (*(ptr+2)<<16); + #else + // Read ABC, output ABC_ : Least Significant Byte is zero. + return ((*ptr)<<24) | (*(ptr+1)<<16) | (*(ptr+2)<<8); + #endif case 2: return *((word *)((byte *)bmp->pixels+(y*bmp->pitch+x*2))); } @@ -257,3 +302,18 @@ void Clear_border(byte color) } } +/// Activates or desactivates file drag-dropping in program window. +void Allow_drag_and_drop(int flag) +{ + // Inform Windows that we accept drag-n-drop events or not + #ifdef __WIN32__ + SDL_SysWMinfo wminfo; + HWND hwnd; + + SDL_VERSION(&wminfo.version); + SDL_GetWMInfo(&wminfo); + hwnd = wminfo.window; + DragAcceptFiles(hwnd,flag?TRUE:FALSE); + SDL_EventState (SDL_SYSWMEVENT,flag?SDL_ENABLE:SDL_DISABLE ); + #endif +} \ No newline at end of file diff --git a/src/sdlscreen.h b/src/sdlscreen.h index a7b83c2e..d0b7d004 100644 --- a/src/sdlscreen.h +++ b/src/sdlscreen.h @@ -56,6 +56,8 @@ SDL_Color Color_to_SDL_color(byte); byte Get_SDL_pixel_8(SDL_Surface *bmp, int x, int y); /// Reads a pixel in a multi-byte SDL surface. dword Get_SDL_pixel_hicolor(SDL_Surface *bmp, int x, int y); +/// Writes a pixel in a 8-bit SDL surface. +void Set_SDL_pixel_8(SDL_Surface *bmp, int x, int y, byte color); /// Convert a SDL Palette to a grafx2 palette void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette); @@ -65,4 +67,9 @@ void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette); /// size, eg: 3x3 pixels in 1024x768 leaves 1 column on the right, 0 rows on bottom. void Clear_border(byte color); +extern volatile int Allow_colorcycling; + +/// Activates or desactivates file drag-dropping in program window. +void Allow_drag_and_drop(int flag); + #endif // SDLSCREEN_H_INCLUDED diff --git a/src/setup.c b/src/setup.c index 898e2cd2..e1c18dfc 100644 --- a/src/setup.c +++ b/src/setup.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -35,6 +36,9 @@ #import #elif defined(__FreeBSD__) #import +#elif defined(__MINT__) + #include + #include #elif defined(__linux__) #include #include @@ -44,7 +48,7 @@ #include "io.h" #include "setup.h" -#if defined(__GP2X__) +#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // This is a random default value ... #define PATH_MAX 32768 #endif @@ -84,7 +88,16 @@ void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) // AmigaOS and alike: hard-coded volume name. #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) strcpy(program_dir,"PROGDIR:"); + #elif defined(__MINT__) + static char path[1024]={0}; + char currentDrive='A'; + currentDrive=currentDrive+Dgetdrv(); + + Dgetpath(path,0); + sprintf(program_dir,"%c:\%s",currentDrive,path); + // Append trailing slash + strcat(program_dir,PATH_SEPARATOR); // Linux: argv[0] unreliable #elif defined(__linux__) if (argv0[0]!='/') @@ -115,9 +128,14 @@ void Set_data_directory(const char * program_dir, char * data_dir) #if defined(__macosx__) strcat(data_dir,"Contents/Resources/"); // On GP2X, executable is not in bin/ - #elif defined (__gp2x__) + #elif defined (__GP2X__) || defined (__gp2x__) || defined (__WIZ__) || defined (__CAANOO__) strcat(data_dir,"share/grafx2/"); + //on tos the same directory + #elif defined (__MINT__) + strcpy(data_dir, program_dir); // All other targets, program is in a "bin" subdirectory + #elif defined (__AROS__) + strcat(data_dir,"/share/grafx2/"); #else strcat(data_dir,"../share/grafx2/"); #endif @@ -140,21 +158,23 @@ void Set_config_directory(const char * program_dir, char * config_dir) #if defined(__amigaos4__) || defined(__AROS__) strcpy(config_dir,"PROGDIR:"); // GP2X - #elif defined(__GP2X__) + #elif defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) // On the GP2X, the program is installed to the sdcard, and we don't want to mess with the system tree which is // on an internal flash chip. So, keep these settings locals. strcpy(config_dir,program_dir); + #elif defined(__MINT__) + strcpy(config_dir,program_dir); #else char filename[MAX_PATH_CHARACTERS]; // In priority: check root directory strcpy(config_dir, program_dir); - // On all these targets except OSX and GP2X, the executable is in ./bin - #if !defined(__macosx__) && !defined(__gp2x__) - strcat(config_dir, "../"); + // On all the remaining targets except OSX, the executable is in ./bin + #if !defined(__macosx__) + strcat(config_dir, "../"); #endif strcpy(filename, config_dir); - strcat(filename, "gfx2.cfg"); + strcat(filename, CONFIG_FILENAME); if (!File_exists(filename)) { @@ -171,6 +191,10 @@ void Set_config_directory(const char * program_dir, char * config_dir) // "~/Library/Preferences/com.googlecode.grafx2" const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; config_parent_dir = getenv("HOME"); + #elif defined(__MINT__) + const char* Config_SubDir = ""; + printf("GFX2.CFG not found in %s\n",filename); + strcpy(config_parent_dir, config_dir); #else // "~/.grafx2" const char* Config_SubDir = ".grafx2"; @@ -203,7 +227,7 @@ void Set_config_directory(const char * program_dir, char * config_dir) { // Echec: on se rabat sur le repertoire de l'executable. strcpy(config_dir,program_dir); - #if !defined(__macosx__) && !defined(__gp2x__) + #if defined(__macosx__) strcat(config_dir, "../"); #endif } diff --git a/src/setup.h b/src/setup.h index 58a22b97..67869512 100644 --- a/src/setup.h +++ b/src/setup.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Peter Gordon Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet @@ -53,4 +54,104 @@ void Set_data_directory(const char * program_dir, char * data_dir); /// IN: The directory containing the executable /// OUT: Write into config_dir. Trailing / or \ is kept. void Set_config_directory(const char * program_dir, char * config_dir); - + + +/// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) +#if defined (__MINT__) + #define FONTS_SUBDIRECTORY "FONTS" +#else + #define FONTS_SUBDIRECTORY "fonts" +#endif + +/// Name of the subdirectory containing fonts, under the data directory (::Set_data_directory()) +#if defined (__MINT__) + #define SKINS_SUBDIRECTORY "SKINS" +#else + #define SKINS_SUBDIRECTORY "skins" +#endif + +/// Name of the binary file containing some configuration settings. +#if defined (__MINT__) + #define CONFIG_FILENAME "GFX2.CFG" +#else + #define CONFIG_FILENAME "gfx2.cfg" +#endif + +/// Name of the text file containing some settings in INI format. +#if defined (__MINT__) + #define INI_FILENAME "GFX2.INI" +#else + #define INI_FILENAME "gfx2.ini" +#endif + +/// Name of the backup of the INI file. +#if defined (__MINT__) + #define INISAVE_FILENAME "GFX2.$$$" +#else + #define INISAVE_FILENAME "gfx2.$$$" +#endif + +/// Name of the default .INI file (read-only: gives .INI format and defaults) +#if defined (__MINT__) + #define INIDEF_FILENAME "GFX2DEF.INI" +#else + #define INIDEF_FILENAME "gfx2def.ini" +#endif + +/// Prefix for filenames of safety backups (main) +#if defined (__MINT__) + #define SAFETYBACKUP_PREFIX_A "A" +#else + #define SAFETYBACKUP_PREFIX_A "a" +#endif + +/// Prefix for filenames of safety backups (spare) +#if defined (__MINT__) + #define SAFETYBACKUP_PREFIX_B "B" +#else + #define SAFETYBACKUP_PREFIX_B "b" +#endif + +/// Name of the image file that serves as an application icon. +#if defined (__MINT__) + #define GFX2_ICON_FILENAME "GFX2.GIF" +#else + #define GFX2_ICON_FILENAME "gfx2.gif" +#endif + +/// Name of the image file for the default (and fallback) GUI skin. +#if defined (__MINT__) + #define DEFAULT_SKIN_FILENAME "SDPAINT.PNG" +#else + #define DEFAULT_SKIN_FILENAME "skin_DPaint.png" +#endif + +/// Name of the image file for the default (and fallback) 8x8 font. +#if defined (__MINT__) + #define DEFAULT_FONT_FILENAME "FDPAINT.PNG" +#else + #define DEFAULT_FONT_FILENAME "font_DPaint.png" +#endif + +/// File extension for safety backups +#if defined (__MINT__) + #define BACKUP_FILE_EXTENSION ".BKP" +#else + #define BACKUP_FILE_EXTENSION ".bkp" +#endif + +/// File prefix for fonts +#if defined (__MINT__) + #define FONT_PREFIX "F" +#else + #define FONT_PREFIX "font_" +#endif + +/// File prefix for skins +#if defined (__MINT__) + #define SKIN_PREFIX "S" +#else + #define SKIN_PREFIX "skin_" +#endif + + diff --git a/src/shade.c b/src/shade.c index 71579428..bab856db 100644 --- a/src/shade.c +++ b/src/shade.c @@ -348,7 +348,7 @@ short Wait_click_in_shade_table() while (selected_cell<0) { - Get_input(); + Get_input(20); if ( (Mouse_K==LEFT_SIDE) && ( ( (Window_click_in_rectangle(8,127,263,179)) && (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) ) @@ -837,7 +837,7 @@ int Menu_shade(void) case 15 : // Saisie du pas Num2str(Shade_list[Shade_current].Step,str,3); - Readline(276,176,str,3,1); + Readline(276,176,str,3,INPUT_TYPE_INTEGER); temp=atoi(str); // On corrige le pas if (!temp) @@ -1089,7 +1089,7 @@ void Button_Quick_shade_menu(void) case 4 : // Saisie du pas Num2str(Quick_shade_step,str,3); - Readline(42,21,str,3,1); + Readline(42,21,str,3,INPUT_TYPE_INTEGER); temp=atoi(str); // On corrige le pas if (!temp) diff --git a/src/special.c b/src/special.c index 4f7a60cc..6e3dc579 100644 --- a/src/special.c +++ b/src/special.c @@ -431,6 +431,9 @@ void Transparency_set(byte amount) break; case 2 : Effect_function=Effect_substractive_colorize; + break; + case 3 : + Effect_function=Effect_alpha_colorize; } Shade_mode=0; Quick_shade_mode=0; diff --git a/src/struct.h b/src/struct.h index f46c2560..e3888068 100644 --- a/src/struct.h +++ b/src/struct.h @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) @@ -73,14 +74,23 @@ typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word typedef void (* Func_draw_list_item) (word,word,word,byte); ///< Draw an item inside a list button. This is done with a callback so it is possible to draw anything, as the list itself doesn't handle the content /// A set of RGB values. +#ifdef __GNUC__ +typedef struct +{ + byte R; ///< Red + byte G; ///< Green + byte B; ///< Blue +} __attribute__((__packed__)) T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). +#else #pragma pack(1) typedef struct { byte R; ///< Red byte G; ///< Green byte B; ///< Blue -} T_Components, T_Palette[256]; ///< A complete 256-entry RGB palette (768 bytes). +} T_Components, T_Palette[256] ; ///< A complete 256-entry RGB palette (768 bytes). #pragma pack() +#endif /// A normal rectangular button in windows and menus. typedef struct T_Normal_button @@ -105,17 +115,18 @@ typedef struct T_Palette_button struct T_Palette_button * Next;///< Pointer to the next palette of current window. } T_Palette_button; -/// A window control that represents a vertical scrollbar, with a slider, and two arrow buttons. +/// A window control that represents a scrollbar, with a slider, and two arrow buttons. typedef struct T_Scroller_button { short Number; ///< Unique identifier for all controls + byte Is_horizontal; ///< Boolean: True if slider is horizontal instead of vertical. word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. - word Height; ///< Height before scaling. + word Length; ///< Length before scaling. word Nb_elements; ///< Number of distinct values it can take. word Nb_visibles; ///< If this slider is meant to show several elements of a collection, this is their number (otherwise, it's 1). word Position; ///< Current position of the slider: which item it's pointing. - word Cursor_height; ///< Vertical dimension of the slider, in pixels before scaling. + word Cursor_length; ///< Dimension of the slider, in pixels before scaling. struct T_Scroller_button * Next;///< Pointer to the next scroller of current window. } T_Scroller_button; @@ -162,12 +173,20 @@ typedef struct T_Dropdown_button /// Data for one item (file, directory) in a fileselector. typedef struct T_Fileselector_item { - char Short_name[19]; ///< Name to display. char Full_name[256]; ///< Filesystem value. byte Type; ///< Type of item: 0 = File, 1 = Directory, 2 = Drive + byte Icon; ///< One of ::ICON_TYPES, ICON_NONE for none. struct T_Fileselector_item * Next; ///< Pointer to next item of the current fileselector. struct T_Fileselector_item * Previous;///< Pointer to previous item of the current fileselector. + + word Length_short_name; ///< Number of bytes allocated for :Short_name + #if __GNUC__ < 3 + char Short_name[0]; ///< Name to display. +#else + char Short_name[]; ///< Name to display. +#endif + // No field after Short_name[] ! Dynamic allocation according to name length. } T_Fileselector_item; /// Data for a fileselector @@ -201,6 +220,25 @@ typedef struct T_List_button struct T_List_button * Next; ///< Pointer to the next list button of current window. } T_List_button; +/// A stackable window (editor screen) +typedef struct +{ + word Pos_X; + word Pos_Y; + word Width; + word Height; + word Nb_buttons; + T_Normal_button *Normal_button_list; + T_Palette_button *Palette_button_list; + T_Scroller_button *Scroller_button_list; + T_Special_button *Special_button_list; + T_Dropdown_button *Dropdown_button_list; + T_List_button *List_button_list; + int Attribute1; + int Attribute2; + byte Draggable; +} T_Window; + /// Data for one line of the "Help" screens. typedef struct { char Line_type; ///< Kind of line: 'N' for normal line, 'S' for a bold line, 'K' for a line with keyboard shortcut, 'T' and '-' for upper and lower titles. @@ -223,7 +261,15 @@ typedef struct dword Inverse; ///< Boolean, true if the gradient goes in descending order dword Mix; ///< Amount of randomness to add to the mix (0-255) dword Technique;///< Gradient technique: 0 (no pattern) 1 (dithering), or 2 (big dithering) -} T_Gradient_array; + byte Speed; ///< Speed of cycling. 0 for disabled, 1-64 otherwise. +} T_Gradient_range; + +/// Data for a full set of gradients. +typedef struct +{ + int Used; ///< Reference count + T_Gradient_range Range[16]; +} T_Gradient_array; /// Data for one setting of shade. Warning, this one is saved/loaded as binary. typedef struct @@ -233,7 +279,6 @@ typedef struct byte Mode; ///< Shade mode: Normal, Loop, or No-saturation see ::SHADE_MODES } T_Shade; -#pragma pack(1) // is it useful ? /// Data for one fullscreen video mode in configuration file. Warning, this one is saved/loaded as binary. typedef struct { @@ -242,8 +287,7 @@ typedef struct word Height;///< Videomode height in pixels. } T_Config_video_mode; - -/// Header for gfx2.cfg. Warning, this one is saved/loaded as binary. +/// Header for gfx2.cfg typedef struct { char Signature[3]; ///< Signature for the file format. "CFG". @@ -253,24 +297,22 @@ typedef struct byte Beta2; ///< Major beta version number (ex: 5) } T_Config_header; -#pragma pack() - -/// Header for a config chunk in for gfx2.cfg. Warning, this one is saved/loaded as binary. +/// Header for a config chunk in for gfx2.cfg typedef struct { byte Number; ///< Section identfier. Possible values are in enum ::CHUNKS_CFG word Size; ///< Size of the configuration block that follows, in bytes. } T_Config_chunk; -#pragma pack(1) -/// Configuration for one keyboard shortcut in gfx2.cfg. Warning, this one is saved/loaded as binary. + +/// Configuration for one keyboard shortcut in gfx2.cfg typedef struct { word Number; ///< Indicates the shortcut action. This is a number starting from 0, which matches ::T_Key_config.Number word Key; ///< Keyboard shortcut: SDLK_something, or -1 for none word Key2; ///< Alternate keyboard shortcut: SDLK_something, or -1 for none } T_Config_shortcut_info; -#pragma pack() + /// This structure holds all the settings saved and loaded as gfx2.ini. typedef struct @@ -321,6 +363,10 @@ typedef struct word Double_click_speed; ///< Maximum delay for double-click, in ms. word Double_key_speed; ///< Maximum delay for double-keypress, in ms. byte Grid_XOR_color; ///< XOR value to apply for grid color. + byte Right_click_colorpick; ///< Boolean, true to enable a "tablet" mode, where RMB acts as instant colorpicker + byte Sync_views; ///< Boolean, true when the Main and Spare should share their viewport settings. + byte Stylus_mode; ///< Boolean, true to tweak some tools (eg:Curve) for single-button stylus. + word Swap_buttons; ///< Sets which key swaps mouse buttons : 0=none, or MOD_CTRL, or MOD_ALT. } T_Config; // Structures utilisées pour les descriptions de pages et de liste de pages. @@ -347,6 +393,7 @@ typedef struct T_Page byte File_format; ///< File format, in enum ::FILE_FORMATS struct T_Page *Next; ///< Pointer to the next backup struct T_Page *Prev; ///< Pointer to the previous backup + T_Gradient_array *Gradients; ///< Pointer to the gradients used by the image. byte Background_transparent; ///< Boolean, true if Layer 0 should have transparent pixels byte Transparent_color; ///< Index of transparent color. 0 to 255. byte Nb_layers; ///< Number of layers @@ -381,6 +428,7 @@ typedef struct word Height; byte * Brush; /// < Color brush (if any) T_Palette Palette; + byte Colormap[256]; byte Transp_color; } T_Brush_template; @@ -396,21 +444,6 @@ typedef struct /// Graphic resources for the mouse cursor. byte Cursor_sprite[NB_CURSOR_SPRITES][CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; - // Preset paintbrushes - - /// Graphic resources for the preset paintbrushes. - byte Paintbrush_sprite [NB_PAINTBRUSH_SPRITES][PAINTBRUSH_HEIGHT][PAINTBRUSH_WIDTH]; - /// Width of the preset paintbrushes. - word Preset_paintbrush_width[NB_PAINTBRUSH_SPRITES]; - /// Height of the preset paintbrushes. - word Preset_paintbrush_height[NB_PAINTBRUSH_SPRITES]; - /// Type of the preset paintbrush: index in enum PAINTBRUSH_SHAPES - byte Paintbrush_type[NB_PAINTBRUSH_SPRITES]; - /// Brush handle for the preset brushes. Generally ::Preset_paintbrush_width[]/2 - word Preset_paintbrush_offset_X[NB_PAINTBRUSH_SPRITES]; - /// Brush handle for the preset brushes. Generally ::Preset_paintbrush_height[]/2 - word Preset_paintbrush_offset_Y[NB_PAINTBRUSH_SPRITES]; - // Sieve patterns /// Preset sieve patterns, stored as binary (one word per line) @@ -419,13 +452,13 @@ typedef struct // Menu and other graphics /// Bitmap data for the menu, a single rectangle. - byte Menu_block[35][MENU_WIDTH]; - byte Layerbar_block[10][144]; - byte Statusbar_block[9][20]; + byte Menu_block[3][35][MENU_WIDTH]; + byte Layerbar_block[3][10][144]; + byte Statusbar_block[3][9][20]; /// Bitmap data for the icons that are displayed over the menu. - byte Menu_sprite[NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; + byte Menu_sprite[2][NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; /// Bitmap data for the different "effects" icons. - byte Effect_sprite[NB_EFFECTS_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; + byte Effect_sprite[NB_EFFECTS_SPRITES][EFFECT_SPRITE_HEIGHT][EFFECT_SPRITE_WIDTH]; /// Bitmap data for the different Layer icons. byte Layer_sprite[3][16][LAYER_SPRITE_HEIGHT][LAYER_SPRITE_WIDTH]; /// Bitmap data for the Grafx2 logo that appears on splash screen. All 256 colors allowed. @@ -458,16 +491,33 @@ typedef struct /// Transparent GUI color index in skin file byte Color_trans; - } T_Gui_skin; +typedef struct { + // Preset paintbrushes + + /// Graphic resources for the preset paintbrushes. + byte Sprite[PAINTBRUSH_HEIGHT][PAINTBRUSH_WIDTH]; + /// Width of the preset paintbrushes. + word Width; + /// Height of the preset paintbrushes. + word Height; + /// Type of the preset paintbrush: index in enum PAINTBRUSH_SHAPES + byte Shape; + /// Brush handle for the preset brushes. Generally ::Width[]/2 + word Offset_X; + /// Brush handle for the preset brushes. Generally ::Height[]/2 + word Offset_Y; + +} T_Paintbrush; + // A menubar. typedef struct { word Width; word Height; byte Visible; word Top; ///< Relative to the top line of the menu, hidden bars don't count. - byte* Skin; + byte* Skin[3]; ///< [0] has normal buttons, [1] has selected buttons, [2] is current. word Skin_width; byte Last_button_index; } T_Menu_Bar; diff --git a/src/text.c b/src/text.c index 1a6ce573..701ba06e 100644 --- a/src/text.c +++ b/src/text.c @@ -2,6 +2,7 @@ */ /* Grafx2 - The Ultimate 256-color bitmap paint program + Copyright 2011 Pawel Góralski Copyright 2008 Yves Rizoud Copyright 2008 Franck Charlet Copyright 2008 Adrien Destugues @@ -36,19 +37,18 @@ #include #endif -#if defined(__linux__) -#if defined(__macosx__) +#if defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__) +// No X11 +#elif defined(__macosx__) #include #import #import -#else +#elif defined(__linux__) #include #endif #endif -#endif #include -// SFont #include "SFont.h" #include "struct.h" @@ -56,6 +56,9 @@ #include "sdlscreen.h" #include "io.h" #include "errors.h" +#include "windows.h" +#include "misc.h" +#include "setup.h" typedef struct T_Font { @@ -282,7 +285,7 @@ void Init_text(void) Nb_fonts=0; // Parcours du répertoire "fonts" strcpy(directory_name, Data_directory); - strcat(directory_name, "fonts"); + strcat(directory_name, FONTS_SUBDIRECTORY); For_each_file(directory_name, Add_font); #if defined(__WIN32__) @@ -321,6 +324,8 @@ void Init_text(void) CFRelease(url); #endif + #elif defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__) + // No X11 : Only use fonts from Grafx2 #elif defined(__linux__) #ifndef NOTTF #define USE_XLIB @@ -343,15 +348,22 @@ void Init_text(void) #ifndef NOTTF For_each_file( "FONTS:_TrueType", Add_font ); #endif - #elif defined(__BEOS__) || defined(__HAIKU__) + #elif defined(__BEOS__) #ifndef NOTTF For_each_file("/etc/fonts/ttfonts", Add_font); #endif - + #elif defined(__HAIKU__) + #ifndef NOTTF + For_each_file("/boot/system/data/fonts/ttfonts/", Add_font); + #endif #elif defined(__SKYOS__) #ifndef NOTTF For_each_file("/boot/system/fonts", Add_font); #endif + #elif defined(__MINT__) + #ifndef NOTTF + For_each_file("C:/BTFONTS", Add_font); + #endif #endif } @@ -368,17 +380,15 @@ int TrueType_is_supported() #ifndef NOTTF -byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height) +byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette) { - TTF_Font *font; - SDL_Surface * TexteColore; - SDL_Surface * Texte8Bit; + TTF_Font *font; + SDL_Surface * text_surface; byte * new_brush; - int index; int style; - SDL_Color Couleur_Avant; - SDL_Color Couleur_Arriere; + SDL_Color fg_color; + SDL_Color bg_color; // Chargement de la fonte font=TTF_OpenFont(Font_name(font_number), size); @@ -386,6 +396,7 @@ byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, { return NULL; } + // Style style=0; if (italic) @@ -393,82 +404,170 @@ byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, if (bold) style|=TTF_STYLE_BOLD; TTF_SetFontStyle(font, style); - // Couleurs - if (antialias) - { - Couleur_Avant = Color_to_SDL_color(Fore_color); - Couleur_Arriere = Color_to_SDL_color(Back_color); - } - else - { - Couleur_Avant = Color_to_SDL_color(MC_White); - Couleur_Arriere = Color_to_SDL_color(MC_Black); - } - - // Rendu du texte: crée une surface SDL RGB 24bits + // Colors: Text will be generated as white on black. + fg_color.r=fg_color.g=fg_color.b=255; + bg_color.r=bg_color.g=bg_color.b=0; + // The following is alpha, supposedly unused + bg_color.unused=fg_color.unused=255; + + // Text rendering: creates a 8bit surface with its dedicated palette if (antialias) - TexteColore=TTF_RenderText_Shaded(font, str, Couleur_Avant, Couleur_Arriere ); + text_surface=TTF_RenderText_Shaded(font, str, fg_color, bg_color ); else - TexteColore=TTF_RenderText_Solid(font, str, Couleur_Avant); - if (!TexteColore) + text_surface=TTF_RenderText_Solid(font, str, fg_color); + if (!text_surface) { TTF_CloseFont(font); return NULL; } - - Texte8Bit=SDL_DisplayFormat(TexteColore); - - SDL_FreeSurface(TexteColore); - new_brush=Surface_to_bytefield(Texte8Bit, NULL); + new_brush=Surface_to_bytefield(text_surface, NULL); if (!new_brush) { - SDL_FreeSurface(TexteColore); - SDL_FreeSurface(Texte8Bit); + SDL_FreeSurface(text_surface); TTF_CloseFont(font); return NULL; } - if (!antialias) + + // Import palette + Get_SDL_Palette(text_surface->format->palette, palette); + + if (antialias) { - // Mappage des couleurs - for (index=0; index < Texte8Bit->w * Texte8Bit->h; index++) + int black_col; + // Shaded text: X-Swap the color that is pure black with the BG color number, + // so that the brush is immediately 'transparent' + + // Find black (c) + for (black_col=0; black_col<256; black_col++) { - if (*(new_brush+index) == MC_Black) - *(new_brush+index)=Back_color; - else if (*(new_brush+index) == MC_White) - *(new_brush+index)=Fore_color; + if (palette[black_col].R==0 && palette[black_col].G==0 && palette[black_col].B==0) + break; + } // If not found: c = 256 = 0 (byte) + + if (black_col != Back_color) + { + int c; + byte colmap[256]; + // Swap palette entries + + SWAP_BYTES(palette[black_col].R, palette[Back_color].R) + SWAP_BYTES(palette[black_col].G, palette[Back_color].G) + SWAP_BYTES(palette[black_col].B, palette[Back_color].B) + + // Define a colormap + for (c=0; c<256; c++) + colmap[c]=c; + + // The swap + colmap[black_col]=Back_color; + colmap[Back_color]=black_col; + + Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w); + + // Also, make the BG color in brush palette have same RGB values as + // the current BG color : this will help for remaps. + palette[Back_color].R=Main_palette[Back_color].R; + palette[Back_color].G=Main_palette[Back_color].G; + palette[Back_color].B=Main_palette[Back_color].B; } } - *width=Texte8Bit->w; - *height=Texte8Bit->h; - SDL_FreeSurface(Texte8Bit); + else + { + // Solid text: Was rendered as white on black. Now map colors: + // White becomes FG color, black becomes BG. 2-color palette. + // Exception: if BG==FG, FG will be set to black or white - any different color. + long index; + byte new_fore=Fore_color; + + if (Fore_color==Back_color) + { + if (Main_palette[Back_color].R+Main_palette[Back_color].G+Main_palette[Back_color].B > 128*3) + // Back color is rather light: + new_fore=MC_Black; + else + // Back color is rather dark: + new_fore=MC_White; + } + + for (index=0; index < text_surface->w * text_surface->h; index++) + { + if (palette[*(new_brush+index)].G < 128) + *(new_brush+index)=Back_color; + else + *(new_brush+index)=new_fore; + } + + // Now copy the current palette to brushe's, for consistency + // with the indices. + memcpy(palette, Main_palette, sizeof(T_Palette)); + + } + *width=text_surface->w; + *height=text_surface->h; + SDL_FreeSurface(text_surface); TTF_CloseFont(font); return new_brush; } #endif -byte *Render_text_SFont(const char *str, int font_number, int *width, int *height) +byte *Render_text_SFont(const char *str, int font_number, int *width, int *height, T_Palette palette) { SFont_Font *font; - SDL_Surface * TexteColore; - SDL_Surface * Texte8Bit; - SDL_Surface *Surface_fonte; + SDL_Surface * text_surface; + SDL_Surface *font_surface; byte * new_brush; SDL_Rect rectangle; // Chargement de la fonte - Surface_fonte=IMG_Load(Font_name(font_number)); - if (!Surface_fonte) + font_surface=IMG_Load(Font_name(font_number)); + if (!font_surface) { - DEBUG("Font loading failed",0); + Verbose_message("Warning","Error loading font.\nThe file may be corrupt."); return NULL; } - font=SFont_InitFont(Surface_fonte); + // Font is 24bit: Perform a color reduction + if (font_surface->format->BitsPerPixel>8) + { + SDL_Surface * reduced_surface; + int x,y,color; + SDL_Color rgb; + + reduced_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, font_surface->w, font_surface->h, 8, 0, 0, 0, 0); + if (!reduced_surface) + { + SDL_FreeSurface(font_surface); + return NULL; + } + // Set the quick palette + for (color=0;color<256;color++) + { + rgb.r=((color & 0xE0)>>5)<<5; + rgb.g=((color & 0x1C)>>2)<<5; + rgb.b=((color & 0x03)>>0)<<6; + SDL_SetColors(reduced_surface, &rgb, color, 1); + } + // Perform reduction + for (y=0; yh; y++) + for (x=0; xw; x++) + { + SDL_GetRGB(Get_SDL_pixel_hicolor(font_surface, x, y), font_surface->format, &rgb.r, &rgb.g, &rgb.b); + color=((rgb.r >> 5) << 5) | + ((rgb.g >> 5) << 2) | + ((rgb.b >> 6)); + Set_SDL_pixel_8(reduced_surface, x, y, color); + } + + SDL_FreeSurface(font_surface); + font_surface=reduced_surface; + } + font=SFont_InitFont(font_surface); if (!font) { DEBUG("Font init failed",1); + SDL_FreeSurface(font_surface); return NULL; } @@ -476,40 +575,36 @@ byte *Render_text_SFont(const char *str, int font_number, int *width, int *heigh *height=SFont_TextHeight(font); *width=SFont_TextWidth(font, str); // Allocation d'une surface SDL - TexteColore=SDL_CreateRGBSurface(SDL_SWSURFACE, *width, *height, 24, 0, 0, 0, 0); + text_surface=SDL_CreateRGBSurface(SDL_SWSURFACE, *width, *height, 8, 0, 0, 0, 0); + // Copy palette + SDL_SetPalette(text_surface, SDL_LOGPAL, font_surface->format->palette->colors, 0, 256); // Fill with backcolor rectangle.x=0; rectangle.y=0; rectangle.w=*width; rectangle.h=*height; - SDL_FillRect(TexteColore, &rectangle, SDL_MapRGB( - TexteColore->format, - Main_palette[Back_color].R, - Main_palette[Back_color].G, - Main_palette[Back_color].B - )); + SDL_FillRect(text_surface, &rectangle, Back_color); // Rendu du texte - SFont_Write(TexteColore, font, 0, 0, str); - if (!TexteColore) + SFont_Write(text_surface, font, 0, 0, str); + if (!text_surface) { DEBUG("Rendering failed",2); SFont_FreeFont(font); return NULL; } - - Texte8Bit=SDL_DisplayFormat(TexteColore); - SDL_FreeSurface(TexteColore); - new_brush=Surface_to_bytefield(Texte8Bit, NULL); + new_brush=Surface_to_bytefield(text_surface, NULL); if (!new_brush) { DEBUG("Converting failed",3); - SDL_FreeSurface(TexteColore); - SDL_FreeSurface(Texte8Bit); + SDL_FreeSurface(text_surface); SFont_FreeFont(font); return NULL; } - SDL_FreeSurface(Texte8Bit); + + Get_SDL_Palette(font_surface->format->palette, palette); + + SDL_FreeSurface(text_surface); SFont_FreeFont(font); return new_brush; @@ -524,7 +619,7 @@ byte *Render_text_SFont(const char *str, int font_number, int *width, int *heigh // Crée une brosse à partir des paramètres de texte demandés. // Si cela réussit, la fonction place les dimensions dans width et height, // et retourne l'adresse du bloc d'octets. -byte *Render_text(const char *str, int font_number, TTFONLY int size, int TTFONLY antialias, TTFONLY int bold, TTFONLY int italic, int *width, int *height) +byte *Render_text(const char *str, int font_number, TTFONLY int size, int TTFONLY antialias, TTFONLY int bold, TTFONLY int italic, int *width, int *height, T_Palette palette) { T_Font *font = font_list_start; int index=font_number; @@ -538,14 +633,14 @@ byte *Render_text(const char *str, int font_number, TTFONLY int size, int TTFONL if (font->Is_truetype) { #ifndef NOTTF - return Render_text_TTF(str, font_number, size, antialias, bold, italic, width, height); + return Render_text_TTF(str, font_number, size, antialias, bold, italic, width, height, palette); #else return NULL; #endif } else { - return Render_text_SFont(str, font_number, width, height); + return Render_text_SFont(str, font_number, width, height, palette); } } diff --git a/src/text.h b/src/text.h index 48b3e20b..6d65b274 100644 --- a/src/text.h +++ b/src/text.h @@ -41,15 +41,16 @@ void Add_font(const char *name); /// @param italic Boolean, true to use italic rendering in TrueType /// @param width Returns the width of the created brush, in pixels. /// @param height Returns the height of the created brush, in pixels. +/// @param palette Returns the custom palette for the brush. /// Returns true on success. -byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height); +byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette); /// Finds a label to display for a font declared with ::Add_font(). char * Font_label(int index); /// Finds the filename of a font declared with ::Add_font(). char * Font_name(int index); /// Returns true if the font of this number is TrueType, false if it's a SFont bitmap. -char * TrueType_font(int index); +int TrueType_font(int index); /// /// Number of fonts declared with a series of ::Add_font(). This is public for /// convenience, but functionaly it is read-only. diff --git a/src/tiles.c b/src/tiles.c new file mode 100644 index 00000000..32078abc --- /dev/null +++ b/src/tiles.c @@ -0,0 +1,114 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +/* Grafx2 - The Ultimate 256-color bitmap paint program + + Copyright 2010 Adrien Destugues + + Grafx2 is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 + of the License. + + Grafx2 is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grafx2; if not, see +*/ + +/// \file Handle tiles. + +/// Build the tile-area from the current picture +void build_tile_area() +{ + word tileAreaWidth = Main_image_width / Snap_width + 1; + word tileAreaHeight = Main_image_height / Snap_height + 1; + + int* tileArea = malloc(tileAreaWidth*tileAreaHeight*sizeof(int)); + + word tile_x, tile_y, pixel_x, pixel_y; + + // For each tile, we have to crawl up to the top of the picture and + // find the first identical tile + for (tile_y = 0; tile_y < tileAreaWidth; tile_y++) + for(tile_x = 0; tile_x < tileAreaHeight; tile_x++) + { + // So, this is the "for each tile" + word ctx, cty; + // First we compare the tile with the others one in the same line at the left + for(ctx = tile_x - 1; ctx >= 0; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, tile_y*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = tile_y*tileAreaWidth+ctx; + goto found; + } + + // Then we look at all the lines above + for(cty = tile_y - 1; cty >= 0; cty--) + for(ctx = tileAreaWidth - 1; ctx >= 0; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, cty*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = cty*tileAreaWidth+ctx; + goto found; + } + + // Then we look at all the lines below + for(cty = tileAreaHeight - 1; cty >= tile_y; cty--) + for(ctx = tileAreaWidth - 1; ctx >= 0; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, cty*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = cty*tileAreaWidth+ctx; + goto found; + } + + // Then we look at the tiles at the right of this one + // (including the tile itself, so we are sure we match something this time) + for(ctx = tileAreaHeight; ctx >= tile_x; ctx--) + if(compare_tiles(tile_x*Snap_width, tile_y*Snap_height, ctx*Snap_width, tile_y*Snap_height)) + { + // We found a match ! + tileArea[tile_y*tileAreaWidth+tile_x] = tile_y*tileAreaWidth+ctx; + } + +found: + } +} + + +// Compare tiles +// The parameters are in pixel-space. +void compare_tiles(word x1, word y1, word x2, word y2) +{ + word pixel_x, pixel_y; + byte c1, c2; + + for (pixel_y = 0; pixel_y < Snap_width; pixel_y++) + for (pixel_x = 0; pixel_x < Snap_height; pixel_x++) + { + c1 = Main_screen + (y1+pixel_y) * Main_image_width + (x1+pixel_x); + c2 = Main_screen + (y2+pixel_y) * Main_image_width + (x2+pixel_x); + if (c1 != c2) return 0; + } + + return 1; +} + +/// Copy a tile pixeldata to all the identical ones +// Call this after the end of an operation +void update_tile(word pixel_x, word pixel_y) +{ + int tileOffset = (pixel_y/Snap_height)*tileAreaHeight + pixel_x/Snap_width; + int firstTileOffset = tileOffset + 1; // to make sure they are not equal + + while(firstTileOffset != tileOffset) + { + tileOffset = tileArea[tileOffset]; + + //do the copy of a block starting at (pixel_x, pixel_y) + } +} diff --git a/src/transform.c b/src/transform.c index a59963bc..f603fa4a 100644 --- a/src/transform.c +++ b/src/transform.c @@ -273,7 +273,7 @@ void Button_Transform_menu(void) input_button[clicked_button-10]->Pos_Y+2, buffer, 4, - 1)) + INPUT_TYPE_INTEGER)) { // Accept entered value *(input_value[clicked_button-10])=atoi(buffer); @@ -369,8 +369,9 @@ void Button_Transform_menu(void) old_width=Main_image_width; old_height=Main_image_height; + Upload_infos_page_main(Main_backups->Pages); // Allocate a new page - if (Backup_with_new_dimensions(1,Main_backups->Pages->Nb_layers,new_width,new_height)) + if (Backup_with_new_dimensions(new_width,new_height)) { // The new image is allocated, the new dimensions are already updated. diff --git a/src/windows.c b/src/windows.c index f3d28505..49c3d456 100644 --- a/src/windows.c +++ b/src/windows.c @@ -36,8 +36,11 @@ #include "graph.h" #include "input.h" #include "misc.h" +#include "op_c.h" #include "readline.h" #include "sdlscreen.h" +#include "palette.h" + /// Width of one layer button, in pixels before scaling word Layer_button_width = 1; @@ -67,7 +70,7 @@ void Pixel_in_menu(word bar, word x, word y, byte color) void Pixel_in_menu_and_skin(word bar, word x, word y, byte color) { Pixel_in_menu(bar, x, y, color); - Menu_bars[bar].Skin[y*Menu_bars[bar].Skin_width + x] = color; + Menu_bars[bar].Skin[2][y*Menu_bars[bar].Skin_width + x] = color; } // Affichage d'un pixel dans la fenêtre (la fenêtre doit être visible) @@ -454,7 +457,7 @@ void Draw_bar_remainder(word current_menu, word x_off) for (y_pos=0;y_pos=0) && (Paintbrush_Y>=0) @@ -1073,7 +1077,7 @@ int Requester_window(char* message, int initial_value) { clicked_button = Window_clicked_button(); if (clicked_button == 1) - Readline(11, 39, str, 4, 1); + Readline(11, 39, str, 4, INPUT_TYPE_INTEGER); if (Key == SDLK_ESCAPE) clicked_button = 2; } while (clicked_button <= 0); @@ -1179,90 +1183,34 @@ void Verbose_message(const char *caption, const char * message ) // -- Redessiner le sprite d'un bouton dans le menu -- -void Display_sprite_in_menu(int btn_number,int sprite_number) +void Display_sprite_in_menu(int btn_number,char sprite_number) { - word x_pos; - word y_pos; - word menu_x_pos; - word menu_y_pos; - byte color; + Buttons_Pool[btn_number].Icon=sprite_number; - menu_y_pos=Buttons_Pool[btn_number].Y_offset; - menu_x_pos=Buttons_Pool[btn_number].X_offset; - if (Buttons_Pool[btn_number].Shape != BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) - { - menu_y_pos+=1; - menu_x_pos+=1; - } - - for (y_pos=0;y_posMenu_sprite[sprite_number][y_pos][x_pos]; - Pixel_in_menu_and_skin(MENUBAR_TOOLS, menu_x_pos+x_pos, menu_y_pos+y_pos, color); - } -if (Menu_is_visible && Menu_bars[MENUBAR_TOOLS].Visible) - Update_rect(Menu_factor_X*(Buttons_Pool[btn_number].X_offset+1), - (Buttons_Pool[btn_number].Y_offset+1+Menu_bars[MENUBAR_TOOLS].Top)*Menu_factor_Y+Menu_Y, - MENU_SPRITE_WIDTH*Menu_factor_X,MENU_SPRITE_HEIGHT*Menu_factor_Y); + if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_TOP_LEFT) + Buttons_Pool[btn_number+1].Icon=sprite_number; + + else if (Buttons_Pool[btn_number].Shape == BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT) + Buttons_Pool[btn_number-1].Icon=sprite_number; } // -- Redessiner la forme du pinceau dans le menu -- void Display_paintbrush_in_menu(void) { - short x_pos,y_pos; - short start_x; - short menu_x_pos,menu_y_pos; - short menu_start_x; - byte color; - - switch (Paintbrush_shape) + switch(Paintbrush_shape) { - case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur - case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome - for (menu_y_pos=2,y_pos=0;y_posMenu_sprite[4][y_pos][x_pos]; - Pixel_in_menu_and_skin(MENUBAR_TOOLS, menu_x_pos, menu_y_pos, color); - } + case PAINTBRUSH_SHAPE_COLOR_BRUSH: + Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_COLOR_BRUSH); + break; + case PAINTBRUSH_SHAPE_MONO_BRUSH: + Display_sprite_in_menu(BUTTON_PAINTBRUSHES, MENU_SPRITE_MONO_BRUSH); + break; + default: + Display_sprite_in_menu(BUTTON_PAINTBRUSHES, -1); break; - default : // Pinceau - // On efface le pinceau précédent - for (menu_y_pos=2,y_pos=0;y_posPreset_paintbrush_offset_X[number])*x_size+Window_pos_X; - origin_y = (y + 8)*Menu_factor_Y - (Gfx->Preset_paintbrush_offset_Y[number])*y_size+Window_pos_Y; + width=Min(Paintbrush[number].Width,PAINTBRUSH_WIDTH); + height=Min(Paintbrush[number].Height,PAINTBRUSH_WIDTH); + + origin_x = (x + 8)*Menu_factor_X - (width/2)*x_size+Window_pos_X; + origin_y = (y + 8)*Menu_factor_Y - (height/2)*y_size+Window_pos_Y; - for (window_y_pos=0,y_pos=0; y_posPreset_paintbrush_height[number]; window_y_pos++,y_pos++) - for (window_x_pos=0,x_pos=0; x_posPreset_paintbrush_width[number]; window_x_pos++,x_pos++) - Block(origin_x+window_x_pos*x_size,origin_y+window_y_pos*y_size,x_size,y_size,(Gfx->Paintbrush_sprite[number][y_pos][x_pos])?MC_Black:MC_Light); + for (window_y_pos=0,y_pos=0; y_posPreset_paintbrush_width[number]), - ToWinH(Gfx->Preset_paintbrush_height[number]) + ToWinL(Paintbrush[number].Width), + ToWinH(Paintbrush[number].Height) ); } @@ -1553,6 +1507,7 @@ void Compute_paintbrush_coordinates(void) { // Operations that don't implement it case OPERATION_LINE: + case OPERATION_ROTATE_BRUSH: Snap_axis=0; break; // Operations that implement it @@ -1857,7 +1812,36 @@ void Change_magnifier_factor(byte factor_index, byte point_at_mouse) Compute_paintbrush_coordinates(); } +void Copy_view_to_spare(void) +{ + + // Don't do anything if the pictures have different dimensions + if (Main_image_width!=Spare_image_width || Main_image_height!=Spare_image_height) + return; + + // Copie des décalages de la fenêtre principale (non zoomée) de l'image + Spare_offset_X=Main_offset_X; + Spare_offset_Y=Main_offset_Y; + // Copie du booléen "Mode loupe" de l'image + Spare_magnifier_mode=Main_magnifier_mode; + + // Copie du facteur de zoom du brouillon + Spare_magnifier_factor=Main_magnifier_factor; + + // Copie des dimensions de la fenêtre de zoom + Spare_magnifier_width=Main_magnifier_width; + Spare_magnifier_height=Main_magnifier_height; + + // Copie des décalages de la fenêtre de zoom + Spare_magnifier_offset_X=Main_magnifier_offset_X; + Spare_magnifier_offset_Y=Main_magnifier_offset_Y; + + // Copie des données du split du zoom + Spare_separator_position=Main_separator_position; + Spare_X_zoom=Main_X_zoom; + Spare_separator_proportion=Main_separator_proportion; +} // -- Afficher la barre de séparation entre les parties zoomées ou non en // mode Loupe -- @@ -2629,7 +2613,7 @@ void Display_all_screen(void) byte Best_color(byte r,byte g,byte b) { - short col; + int col; int delta_r,delta_g,delta_b; int dist; int best_dist=0x7FFFFFFF; @@ -2663,7 +2647,7 @@ byte Best_color(byte r,byte g,byte b) byte Best_color_nonexcluded(byte red,byte green,byte blue) { - short col; + int col; int delta_r,delta_g,delta_b; int dist; int best_dist=0x7FFFFFFF; @@ -2692,65 +2676,50 @@ byte Best_color_nonexcluded(byte red,byte green,byte blue) return best_color; } -void Compute_4_best_colors_for_1_menu_color - (byte red, byte green, byte blue, T_Components * palette, byte * table) + + +byte Best_color_perceptual(byte r,byte g,byte b) { - short col; - int delta_r,delta_g,delta_b; - int dist; - int best_dist[4]={0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF,0x7FFFFFFF}; - + + int col; + float best_diff=255.0*1.56905; + byte best_color=0; + float target_bri; + float bri; + float diff_b, diff_c, diff; + // Similar to Perceptual_lightness(); + target_bri = sqrt(0.26*r*0.26*r + 0.55*g*0.55*g + 0.19*b*0.19*b); + for (col=0; col<256; col++) { - delta_r=(int)palette[col].R-red; - delta_g=(int)palette[col].G-green; - delta_b=(int)palette[col].B-blue; + if (Exclude_color[col]) + continue; - dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11); + diff_c = sqrt( + (0.26*(Main_palette[col].R-r))* + (0.26*(Main_palette[col].R-r))+ + (0.55*(Main_palette[col].G-g))* + (0.55*(Main_palette[col].G-g))+ + (0.19*(Main_palette[col].B-b))* + (0.19*(Main_palette[col].B-b))); + // Exact match + if (diff_c==0) + return col; - if (distDefault_palette[Gfx->Color[0]].R, Gfx->Default_palette[Gfx->Color[0]].G, Gfx->Default_palette[Gfx->Color[0]].B,palette,table); - MC_Black=table[0]; - - // Recherche du blanc - Compute_4_best_colors_for_1_menu_color - (Gfx->Default_palette[Gfx->Color[3]].R, Gfx->Default_palette[Gfx->Color[3]].G, Gfx->Default_palette[Gfx->Color[3]].B,palette,table); - if (MC_Black!=table[0]) - MC_White=table[0]; - else - MC_White=table[1]; - - // Recherche du gris clair - Compute_4_best_colors_for_1_menu_color - (Gfx->Default_palette[Gfx->Color[2]].R, Gfx->Default_palette[Gfx->Color[2]].G, Gfx->Default_palette[Gfx->Color[2]].B,palette,table); - if ( (MC_Black!=table[0]) && (MC_White!=table[0]) ) - MC_Light=table[0]; - else + // First method: + // If all close matches for the ideal colors exist, pick them. + for (i=255; i>=0; i--) { - if ( (MC_Black!=table[1]) && (MC_White!=table[1]) ) - MC_Light=table[1]; - else - MC_Light=table[2]; - } - - // Recherche du gris foncé - Compute_4_best_colors_for_1_menu_color - (Gfx->Default_palette[Gfx->Color[1]].R, Gfx->Default_palette[Gfx->Color[1]].G, Gfx->Default_palette[Gfx->Color[1]].B,palette,table); - if ( (MC_Black!=table[0]) && (MC_White!=table[0]) && (MC_Light!=table[0]) ) - MC_Dark=table[0]; - else - { - if ( (MC_Black!=table[1]) && (MC_White!=table[1]) && (MC_Light!=table[1]) ) - MC_Dark=table[1]; - else + + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[3]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[3]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[3]].B/tolerence) { - if ( (MC_Black!=table[2]) && (MC_White!=table[2]) && (MC_Light!=table[2]) ) - MC_Dark=table[2]; - else - MC_Dark=table[3]; + MC_White=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[2]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[2]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[2]].B/tolerence) + { + MC_Light=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[1]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[1]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[1]].B/tolerence) + { + MC_Dark=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==Gfx->Default_palette[Gfx->Color[0]].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==Gfx->Default_palette[Gfx->Color[0]].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==Gfx->Default_palette[Gfx->Color[0]].B/tolerence) + { + MC_Black=i; + // On cherche une couleur de transparence différente des 4 autres. + for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || + (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); + // Easy case + MC_OnBlack=MC_Dark; + MC_Window=MC_Light; + MC_Lighter=MC_White; + MC_Darker=MC_Dark; + Remap_menu_sprites(); + return; + } + } + } + } + } + } } } - - // C'est peu probable mais il est possible que MC_Light soit plus foncée que - // MC_Dark. Dans ce cas, on les inverse. - if ( ((palette[MC_Light].R*30)+(palette[MC_Light].G*59)+(palette[MC_Light].B*11)) < - ((palette[MC_Dark].R*30)+(palette[MC_Dark].G*59)+(palette[MC_Dark].B*11)) ) + // Second method: For CPC 27-color modes only + // Try to find colors that just work + if (Get_palette_RGB_scale()==3) + for (i=255; i>=0; i--) { - SWAP_BYTES(MC_Light, MC_Dark); + + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[3].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[3].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[3].B/tolerence) + { + MC_White=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[2].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[2].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[2].B/tolerence) + { + MC_Light=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[1].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[1].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[1].B/tolerence) + { + MC_Dark=i; + for (i=255; i>=0; i--) + { + if (Round_palette_component(palette[i].R)/tolerence==cpc_colors[0].R/tolerence + && Round_palette_component(palette[i].G)/tolerence==cpc_colors[0].G/tolerence + && Round_palette_component(palette[i].B)/tolerence==cpc_colors[0].B/tolerence) + { + MC_Black=i; + // On cherche une couleur de transparence différente des 4 autres. + for (MC_Trans=0; ((MC_Trans==MC_Black) || (MC_Trans==MC_Dark) || + (MC_Trans==MC_Light) || (MC_Trans==MC_White)); MC_Trans++); + // Easy case + MC_OnBlack=MC_Dark; + MC_Window=MC_Light; + MC_Lighter=MC_White; + MC_Darker=MC_Dark; + Remap_menu_sprites(); + return; + } + } + } + } + } + } + } } + + // Third method: + + // Compute luminance for whole palette + // Take the darkest as black, the brightest white + for(i = 0; i < 256; i++) + { + RGB_to_HSL(palette[i].R, palette[i].G, palette[i].B, &h, &s[i], &l[i]); + // Another formula for lightness, in 0-255 range + //l[i]=Perceptual_lightness(&palette[i])/4062/255; + if (l[i] > max_l) + { + max_l = l[i]; + MC_White = i; + } + } + for(i = 0; i < 256; i++) + { + if (l[i] < min_l && i!=MC_White) + { + min_l = l[i]; + MC_Black = i; + } + } + // Alter the S values according to the L range - this is for the future + // comparisons, so that highly variable saturation doesn't weigh + // too heavily when the the lightness is in a narrow range. + for(i = 0; i < 256; i++) + { + s[i]=s[i]*(max_l-min_l)/255; + } + for(i = 0; i < 256; i++) + { + // Adjust (reduce) perceived saturation at both ends of L spectrum + if (l[i]>192) + s[i]=s[i]*(255-l[i])/64; + else if (l[i]<64) + s[i]=s[i]*l[i]/64; + } + + + // Find color nearest to min+2(max-min)/3 + // but at the same time we try to minimize the saturation so that the menu + // still looks grey + hi_l = min_l + 2*(max_l - min_l)/3; + + for (i = 0; i < 256; i++) + { + if ( abs(l[i] - hi_l) + s[i]/2 < delta_high && i!=MC_White && i!=MC_Black) + { + delta_high = abs(l[i] - hi_l) + s[i]/2; + MC_Light = i; + } + } + + // Target "Dark color" is 2/3 between Light and Black + low_l = ((int)l[MC_Light]*2+l[MC_Black])/3; + for (i = 0; i < 256; i++) + { + if ( abs((int)l[i] - low_l) + s[i]/6 < delta_low && i!=MC_White && i!=MC_Black && i!=MC_Light) + { + delta_low = abs((int)l[i] - low_l)+ s[i]/6; + MC_Dark = i; + } + } + + + //if (l[MC_Light]Cursor_sprite[k][j][i]); // Main menu bar - for (j=0; jMenu_block[j][i]); + for (k=0; k<3; k++) + for (j=0; jMenu_block[k][j][i]); // Menu sprites - for (k=0; kMenu_sprite[k][j][i]); + for (l=0; l<2; l++) + for (k=0; kMenu_sprite[l][k][j][i]); // Effects sprites for (k=0; kEffect_sprite[k][j][i]); // Layers buttons for (l=0; l<3; l++) @@ -2944,13 +3082,15 @@ void Remap_menu_sprites() Remap_pixel(&Gfx->Layer_sprite[l][k][j][i]); // Status bar - for (j=0; jStatusbar_block[j][i]); + for (k=0; k<3; k++) + for (j=0; jStatusbar_block[k][j][i]); // Layer bar - for (j=0; jLayerbar_block[j][i]); + for (k=0; k<3; k++) + for (j=0; jLayerbar_block[k][j][i]); // Help fonts for (k=0; k<256; k++) diff --git a/src/windows.h b/src/windows.h index 420d44c5..b5484247 100644 --- a/src/windows.h +++ b/src/windows.h @@ -89,7 +89,7 @@ void Window_display_frame_in(word x_pos,word y_pos,word width,word height); void Window_display_frame_out(word x_pos,word y_pos,word width,word height); void Window_display_frame(word x_pos,word y_pos,word width,word height); -void Display_sprite_in_menu(int btn_number,int sprite_number); +void Display_sprite_in_menu(int btn_number,char sprite_number); void Display_paintbrush_in_menu(void); void Display_paintbrush_in_window(word x,word y,int number); @@ -99,6 +99,7 @@ void Window_display_icon_sprite(word x_pos,word y_pos,byte type); byte Best_color(byte red,byte green,byte blue); byte Best_color_nonexcluded(byte red,byte green,byte blue); +byte Best_color_perceptual(byte r,byte g,byte b); void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width); void Vertical_XOR_line_zoom(short x_pos, short y_pos, short height); @@ -108,4 +109,7 @@ void Change_magnifier_factor(byte factor_index, byte point_at_mouse); /// Width of one layer button, in pixels before scaling extern word Layer_button_width; +/// Copy viewport settings and offsets from the Main to the Spare. +void Copy_view_to_spare(void); + #endif