From 7aa34454a8e56922f0d5bd21cb7f8c462c8a3218 Mon Sep 17 00:00:00 2001 From: Sergii Pylypenko Date: Thu, 27 Mar 2014 21:48:18 +0200 Subject: [PATCH] Updated GrafX2 --- project/jni/application/grafx2/.gitignore | 1 + .../application/grafx2/AndroidAppSettings.cfg | 8 +- .../application/grafx2/AndroidData/data.zip | Bin 221520 -> 0 bytes .../application/grafx2/AndroidData/data2.zip | Bin 0 -> 408272 bytes .../jni/application/grafx2/AndroidPreBuild.sh | 7 + project/jni/application/grafx2/android.patch | 111 + .../application/grafx2/grafx2/src/SDLMain.h | 11 - .../jni/application/grafx2/grafx2/src/SFont.c | 224 - .../jni/application/grafx2/grafx2/src/SFont.h | 100 - .../jni/application/grafx2/grafx2/src/brush.c | 1944 ------ .../jni/application/grafx2/grafx2/src/brush.h | 129 - .../application/grafx2/grafx2/src/brush_ops.c | 1392 ----- .../application/grafx2/grafx2/src/buttons.c | 5478 ----------------- .../application/grafx2/grafx2/src/buttons.h | 678 -- .../grafx2/grafx2/src/buttons_effects.c | 1259 ---- .../jni/application/grafx2/grafx2/src/const.h | 529 -- .../application/grafx2/grafx2/src/engine.c | 3499 ----------- .../application/grafx2/grafx2/src/engine.h | 123 - .../application/grafx2/grafx2/src/errors.h | 54 - .../application/grafx2/grafx2/src/factory.c | 1882 ------ .../application/grafx2/grafx2/src/factory.h | 13 - .../grafx2/grafx2/src/fileformats.c | 4091 ------------ .../application/grafx2/grafx2/src/filesel.c | 2037 ------ .../application/grafx2/grafx2/src/filesel.h | 59 - .../application/grafx2/grafx2/src/global.h | 1037 ---- .../jni/application/grafx2/grafx2/src/graph.c | 2994 --------- .../jni/application/grafx2/grafx2/src/graph.h | 123 - .../jni/application/grafx2/grafx2/src/haiku.h | 8 - .../jni/application/grafx2/grafx2/src/help.c | 863 --- .../jni/application/grafx2/grafx2/src/help.h | 66 - .../application/grafx2/grafx2/src/helpfile.h | 2966 --------- .../application/grafx2/grafx2/src/hotkeys.c | 1846 ------ .../application/grafx2/grafx2/src/hotkeys.h | 60 - .../jni/application/grafx2/grafx2/src/init.c | 2976 --------- .../jni/application/grafx2/grafx2/src/init.h | 56 - .../jni/application/grafx2/grafx2/src/input.c | 1103 ---- .../jni/application/grafx2/grafx2/src/input.h | 66 - .../jni/application/grafx2/grafx2/src/io.c | 498 -- .../jni/application/grafx2/grafx2/src/io.h | 125 - .../application/grafx2/grafx2/src/keyboard.c | 713 --- .../application/grafx2/grafx2/src/keyboard.h | 77 - .../application/grafx2/grafx2/src/layers.c | 391 -- .../application/grafx2/grafx2/src/layers.h | 35 - .../grafx2/grafx2/src/libraw2crtc.c | 190 - .../grafx2/grafx2/src/libraw2crtc.h | 14 - .../application/grafx2/grafx2/src/loadsave.c | 1587 ----- .../application/grafx2/grafx2/src/loadsave.h | 259 - .../jni/application/grafx2/grafx2/src/main.c | 966 --- .../jni/application/grafx2/grafx2/src/misc.c | 880 --- .../jni/application/grafx2/grafx2/src/misc.h | 167 - .../grafx2/grafx2/src/miscfileformats.c | 2701 -------- .../application/grafx2/grafx2/src/mountlist.c | 934 --- .../application/grafx2/grafx2/src/mountlist.h | 54 - .../jni/application/grafx2/grafx2/src/op_c.c | 1415 ----- .../jni/application/grafx2/grafx2/src/op_c.h | 218 - .../application/grafx2/grafx2/src/operatio.c | 4006 ------------ .../application/grafx2/grafx2/src/operatio.h | 232 - .../jni/application/grafx2/grafx2/src/pages.c | 1418 ----- .../jni/application/grafx2/grafx2/src/pages.h | 141 - .../application/grafx2/grafx2/src/palette.c | 2992 --------- .../application/grafx2/grafx2/src/palette.h | 60 - .../application/grafx2/grafx2/src/pversion.c | 2 - .../application/grafx2/grafx2/src/pxdouble.c | 510 -- .../application/grafx2/grafx2/src/pxdouble.h | 50 - .../application/grafx2/grafx2/src/pxquad.c | 545 -- .../application/grafx2/grafx2/src/pxquad.h | 50 - .../application/grafx2/grafx2/src/pxsimple.c | 481 -- .../application/grafx2/grafx2/src/pxsimple.h | 53 - .../application/grafx2/grafx2/src/pxtall.c | 466 -- .../application/grafx2/grafx2/src/pxtall.h | 48 - .../application/grafx2/grafx2/src/pxtall2.c | 537 -- .../application/grafx2/grafx2/src/pxtall2.h | 50 - .../application/grafx2/grafx2/src/pxtriple.c | 533 -- .../application/grafx2/grafx2/src/pxtriple.h | 50 - .../application/grafx2/grafx2/src/pxwide.c | 519 -- .../application/grafx2/grafx2/src/pxwide.h | 51 - .../application/grafx2/grafx2/src/pxwide2.c | 527 -- .../application/grafx2/grafx2/src/pxwide2.h | 50 - .../application/grafx2/grafx2/src/readini.c | 980 --- .../application/grafx2/grafx2/src/readini.h | 29 - .../application/grafx2/grafx2/src/readline.c | 675 -- .../application/grafx2/grafx2/src/readline.h | 64 - .../application/grafx2/grafx2/src/realpath.c | 121 - .../application/grafx2/grafx2/src/realpath.h | 36 - .../application/grafx2/grafx2/src/saveini.c | 735 --- .../application/grafx2/grafx2/src/saveini.h | 27 - .../application/grafx2/grafx2/src/sdlscreen.c | 373 -- .../application/grafx2/grafx2/src/sdlscreen.h | 77 - .../jni/application/grafx2/grafx2/src/setup.c | 240 - .../jni/application/grafx2/grafx2/src/setup.h | 157 - .../jni/application/grafx2/grafx2/src/shade.c | 1132 ---- .../jni/application/grafx2/grafx2/src/shade.h | 34 - .../application/grafx2/grafx2/src/special.c | 468 -- .../application/grafx2/grafx2/src/special.h | 58 - .../application/grafx2/grafx2/src/struct.h | 539 -- .../jni/application/grafx2/grafx2/src/text.c | 667 -- .../jni/application/grafx2/grafx2/src/text.h | 57 - .../application/grafx2/grafx2/src/transform.c | 446 -- .../application/grafx2/grafx2/src/transform.h | 29 - .../application/grafx2/grafx2/src/version.c | 1 - .../application/grafx2/grafx2/src/windows.c | 3174 ---------- .../application/grafx2/grafx2/src/windows.h | 116 - project/jni/application/grafx2/icon.png | Bin 1652 -> 10294 bytes 103 files changed, 123 insertions(+), 72500 deletions(-) create mode 100644 project/jni/application/grafx2/.gitignore delete mode 100644 project/jni/application/grafx2/AndroidData/data.zip create mode 100644 project/jni/application/grafx2/AndroidData/data2.zip create mode 100755 project/jni/application/grafx2/AndroidPreBuild.sh create mode 100644 project/jni/application/grafx2/android.patch delete mode 100644 project/jni/application/grafx2/grafx2/src/SDLMain.h delete mode 100644 project/jni/application/grafx2/grafx2/src/SFont.c delete mode 100644 project/jni/application/grafx2/grafx2/src/SFont.h delete mode 100644 project/jni/application/grafx2/grafx2/src/brush.c delete mode 100644 project/jni/application/grafx2/grafx2/src/brush.h delete mode 100644 project/jni/application/grafx2/grafx2/src/brush_ops.c delete mode 100644 project/jni/application/grafx2/grafx2/src/buttons.c delete mode 100644 project/jni/application/grafx2/grafx2/src/buttons.h delete mode 100644 project/jni/application/grafx2/grafx2/src/buttons_effects.c delete mode 100644 project/jni/application/grafx2/grafx2/src/const.h delete mode 100644 project/jni/application/grafx2/grafx2/src/engine.c delete mode 100644 project/jni/application/grafx2/grafx2/src/engine.h delete mode 100644 project/jni/application/grafx2/grafx2/src/errors.h delete mode 100644 project/jni/application/grafx2/grafx2/src/factory.c delete mode 100644 project/jni/application/grafx2/grafx2/src/factory.h delete mode 100644 project/jni/application/grafx2/grafx2/src/fileformats.c delete mode 100644 project/jni/application/grafx2/grafx2/src/filesel.c delete mode 100644 project/jni/application/grafx2/grafx2/src/filesel.h delete mode 100644 project/jni/application/grafx2/grafx2/src/global.h delete mode 100644 project/jni/application/grafx2/grafx2/src/graph.c delete mode 100644 project/jni/application/grafx2/grafx2/src/graph.h delete mode 100644 project/jni/application/grafx2/grafx2/src/haiku.h delete mode 100644 project/jni/application/grafx2/grafx2/src/help.c delete mode 100644 project/jni/application/grafx2/grafx2/src/help.h delete mode 100644 project/jni/application/grafx2/grafx2/src/helpfile.h delete mode 100644 project/jni/application/grafx2/grafx2/src/hotkeys.c delete mode 100644 project/jni/application/grafx2/grafx2/src/hotkeys.h delete mode 100644 project/jni/application/grafx2/grafx2/src/init.c delete mode 100644 project/jni/application/grafx2/grafx2/src/init.h delete mode 100644 project/jni/application/grafx2/grafx2/src/input.c delete mode 100644 project/jni/application/grafx2/grafx2/src/input.h delete mode 100644 project/jni/application/grafx2/grafx2/src/io.c delete mode 100644 project/jni/application/grafx2/grafx2/src/io.h delete mode 100644 project/jni/application/grafx2/grafx2/src/keyboard.c delete mode 100644 project/jni/application/grafx2/grafx2/src/keyboard.h delete mode 100644 project/jni/application/grafx2/grafx2/src/layers.c delete mode 100644 project/jni/application/grafx2/grafx2/src/layers.h delete mode 100644 project/jni/application/grafx2/grafx2/src/libraw2crtc.c delete mode 100644 project/jni/application/grafx2/grafx2/src/libraw2crtc.h delete mode 100644 project/jni/application/grafx2/grafx2/src/loadsave.c delete mode 100644 project/jni/application/grafx2/grafx2/src/loadsave.h delete mode 100644 project/jni/application/grafx2/grafx2/src/main.c delete mode 100644 project/jni/application/grafx2/grafx2/src/misc.c delete mode 100644 project/jni/application/grafx2/grafx2/src/misc.h delete mode 100644 project/jni/application/grafx2/grafx2/src/miscfileformats.c delete mode 100644 project/jni/application/grafx2/grafx2/src/mountlist.c delete mode 100644 project/jni/application/grafx2/grafx2/src/mountlist.h delete mode 100644 project/jni/application/grafx2/grafx2/src/op_c.c delete mode 100644 project/jni/application/grafx2/grafx2/src/op_c.h delete mode 100644 project/jni/application/grafx2/grafx2/src/operatio.c delete mode 100644 project/jni/application/grafx2/grafx2/src/operatio.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pages.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pages.h delete mode 100644 project/jni/application/grafx2/grafx2/src/palette.c delete mode 100644 project/jni/application/grafx2/grafx2/src/palette.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pversion.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxdouble.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxdouble.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pxquad.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxquad.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pxsimple.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxsimple.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pxtall.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxtall.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pxtall2.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxtall2.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pxtriple.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxtriple.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pxwide.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxwide.h delete mode 100644 project/jni/application/grafx2/grafx2/src/pxwide2.c delete mode 100644 project/jni/application/grafx2/grafx2/src/pxwide2.h delete mode 100644 project/jni/application/grafx2/grafx2/src/readini.c delete mode 100644 project/jni/application/grafx2/grafx2/src/readini.h delete mode 100644 project/jni/application/grafx2/grafx2/src/readline.c delete mode 100644 project/jni/application/grafx2/grafx2/src/readline.h delete mode 100644 project/jni/application/grafx2/grafx2/src/realpath.c delete mode 100644 project/jni/application/grafx2/grafx2/src/realpath.h delete mode 100644 project/jni/application/grafx2/grafx2/src/saveini.c delete mode 100644 project/jni/application/grafx2/grafx2/src/saveini.h delete mode 100644 project/jni/application/grafx2/grafx2/src/sdlscreen.c delete mode 100644 project/jni/application/grafx2/grafx2/src/sdlscreen.h delete mode 100644 project/jni/application/grafx2/grafx2/src/setup.c delete mode 100644 project/jni/application/grafx2/grafx2/src/setup.h delete mode 100644 project/jni/application/grafx2/grafx2/src/shade.c delete mode 100644 project/jni/application/grafx2/grafx2/src/shade.h delete mode 100644 project/jni/application/grafx2/grafx2/src/special.c delete mode 100644 project/jni/application/grafx2/grafx2/src/special.h delete mode 100644 project/jni/application/grafx2/grafx2/src/struct.h delete mode 100644 project/jni/application/grafx2/grafx2/src/text.c delete mode 100644 project/jni/application/grafx2/grafx2/src/text.h delete mode 100644 project/jni/application/grafx2/grafx2/src/transform.c delete mode 100644 project/jni/application/grafx2/grafx2/src/transform.h delete mode 100644 project/jni/application/grafx2/grafx2/src/version.c delete mode 100644 project/jni/application/grafx2/grafx2/src/windows.c delete mode 100644 project/jni/application/grafx2/grafx2/src/windows.h diff --git a/project/jni/application/grafx2/.gitignore b/project/jni/application/grafx2/.gitignore new file mode 100644 index 000000000..25522dd94 --- /dev/null +++ b/project/jni/application/grafx2/.gitignore @@ -0,0 +1 @@ +grafx2 diff --git a/project/jni/application/grafx2/AndroidAppSettings.cfg b/project/jni/application/grafx2/AndroidAppSettings.cfg index e64e99273..fdef2199a 100644 --- a/project/jni/application/grafx2/AndroidAppSettings.cfg +++ b/project/jni/application/grafx2/AndroidAppSettings.cfg @@ -7,10 +7,10 @@ AppName="grafx2" AppFullName=com.grafx2 # Application version code (integer) -AppVersionCode=23178103 +AppVersionCode=24206704 # Application user-visible version name (string) -AppVersionName="2.3.1781.03" +AppVersionName="2.4.2067.04" # Specify path to download application data in zip archive in the form 'Description|URL|MirrorURL^Description2|URL2|MirrorURL2^...' # If you'll start Description with '!' symbol it will be enabled by default, other downloads should be selected by user from startup config menu @@ -18,7 +18,7 @@ AppVersionName="2.3.1781.03" # If the URL does not contain 'http://' it is treated as file from 'project/jni/application/src/AndroidData' dir - # these files are put inside .apk package by build system # Also please avoid 'https://' URLs, many Android devices do not have trust certificates and will fail to connect to SF.net over HTTPS -AppDataDownloadUrl="!Data|data.zip" +AppDataDownloadUrl="!Data|data2.zip" # Reset SDL config when updating application to the new version (y) / (n) ResetSdlConfigForThisVersion=y @@ -209,7 +209,7 @@ AppMinimumRAM=0 # Optional shared libraries to compile - removing some of them will save space # MP3 support by libMAD is encumbered by patents and libMAD is GPL-ed # Available libraries: mad (GPL-ed!) sdl_mixer sdl_image sdl_ttf sdl_net sdl_blitpool sdl_gfx sdl_sound intl xml2 lua jpeg png ogg flac tremor vorbis freetype xerces curl theora fluidsynth lzma lzo2 mikmod openal timidity zzip bzip2 yaml-cpp python boost_date_time boost_filesystem boost_iostreams boost_program_options boost_regex boost_signals boost_system boost_thread glu avcodec avdevice avfilter avformat avresample avutil swscale swresample bzip2 -CompiledLibraries="jpeg png sdl_image sdl_ttf lua" +CompiledLibraries="jpeg png sdl_image sdl_ttf lua fontconfig" # Application uses custom build script AndroidBuild.sh instead of Android.mk (y) or (n) CustomBuildScript=n diff --git a/project/jni/application/grafx2/AndroidData/data.zip b/project/jni/application/grafx2/AndroidData/data.zip deleted file mode 100644 index b665c316c803d8c1a53ae3b9b359bd3071c803de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 221520 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 YX0x(^To=X=#xPfvfnlySGXnzy061|S9{>OV diff --git a/project/jni/application/grafx2/AndroidData/data2.zip b/project/jni/application/grafx2/AndroidData/data2.zip new file mode 100644 index 0000000000000000000000000000000000000000..d2e86930891a3d44551f4f73e6fe727d90a9459f GIT binary patch literal 408272 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%0Dj~cSE89C24Gcqvj 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%0D=qa}F;~f1({0id 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

hh#lfff_*80kJRG-3%cpZsK}!?d8< z8|tqX>?wQ^)T(r}i{Fp6KURF6fu*v_t?di`q&2TP=vcm@ribsSW(gAavR8BeA@ zj{E#{m&KRZ6-F%onncytv_;rCEWMGr%R@KEvmmJwUS_eWbudhtKDL@ z8UE)Lu7*DAp6BfFYViTbsaJLN8Xo)USXFrNn;w#AD_peDJmTe@#%GE1Wwtu3V1D-H zUi_TeKVKf!eE4U7|H}oXl7jEuGj{38ytJG%)#>QI<7{lJjN4cB@@h7`*lWMn=Kl{t zvAJ>Iel_$i;;QB6VLcQc{2^%4iyvzxq-SYrJhtD^XmQ!RZPR+!%q!Jgsp8BBwzb9e z1UCP>zcBho*PkyxHqn- zWA&nG0x3=rmj6BWyI-_*Nj-7e{E}$&+RZD1RkT+IIsSWZcX0o%mD=yk`EAvda*7u$ zy!+16TtT=m^F~AF$=@7&=~8NMK6Xmx2!3AJ{802n)23d*Z?DX@*DD0>t||ZZ>CxNQ zzjw<{STXl+#jl57f6o5AUEaB@?ADc|GBM?gHuF^9{2CQ|uYH_aD*VpmGl}G+(c|AV+E!8%V?^fP*Lb;yztk~lt{T>}< zzMhwNOsRc;DL*1?f8(}$4L=TWrIqc;s-AMNKE%nn$=QCx%*u(!FYi;W+pD!A``%2J zkJD`aRPFJ)D{_VH(pRo?GX<*y&M7B6))0ETcj23+<{!Q5)*LJG@8|wdBT?admTAEn z<|pzFLc96X%OajMZmLWD_eJ^Pm&lG6%2^)TF~?`?T3)^3zvjC`_CNQS>W!Y>w@=NG z>EqZI{O{MIA4eYFybu)eSUIB1&9Ag?Zo(X+h2~S|C|XFW9CZ>|Su}U0oJH5lqw_72 zUuwqByj*-)I6&&1CzCLXbZ*F+rvV4U1A=&p)_(mVeXHsGp`}t`Op^B>P01>#{d_J= zdWWN_uY03g!z*CNV|1yVw&2_ z#yRaQ&tIch{>u0CeAF3h4VywBJ!b!UF2E>nHsf6e2x zqTxG>->PexVi>*KZ@A{4l5*8Qw9qWA_x_949{#r9caBUs``hq#U)viVo_``K_fw^6 znoFNvR&e|w86v!C@5Ybw`lA1bRV6DZe>^u~ll7S?8z1(!9NYD2ZQIs)!7+-l)e&Ve zsTWvN<~aWkyPW5!EY@f?%fQr<|H5U5xlh$SBm-RjOy@nYo&ViZF2rSB_uEYOP|E z@y2zRa~Ll4upG553EDL|Xq%Vt+*O6fYtA1}Ue#T+zF|4XA+uR8CiSSferQ@3_MvCe z#;?n!`c{8Q@RrZ?G*DoZ3;6U+`BoLn@jZ1N_ck}l=%oCcZS`Oe^Far`ZCrozIlSZ- z%v-u!?RJ=}LGHS0E4BOkYC{_yx(Zg_{`)^NbwklXE7P5MUOO#XXD+&IUQ)_%E@177 zR?#e*#-}_Nx14>(ZkI4$>d!fmOFEjN^$9NDpIPPKWN!L3^~%>m)3}X}Q)kTHDKbC5 zS)9k<HL=MOZT%LxhlrWHf`nSJttlE2cO`1lfUp+$Fs7! zQ)M2d7t8PS+GxprQ;o{o^J5~%j}KhC(-Q75^t`ZR^i*EM1Si!&M-pv6rkD0B6KW|<8^mv(7?Cz+Cn;wO&3)7L*jXNr^-%n$wp+>p3 z-1>VZoXkHaUN4zbZt}HzMZ~w!WZD}kouFGDVs=DKDmFTRu z5jhu4S4SCmw$K;oLwMsf4|wopzG4MXMfIG z|3l@~@oTQl>xkwCAJIcwerB~!&tJ9m(82G8w()wz&DL=lSL@JDTVHT+w(s z_yq67!*|Z#^i^Y?D%N@Xb1Ij;zvc|fJ*iim1isfxu`uQtKY9@aSJ$H`9 z+GqaCKg^ddxO&H*c35dP_u?0>YtPzV^Ud2}tukqunXkzq;UW#K=E`Muy~{cGv)Br? z_DwGT`HeSz$4|N@tNx0OVxGI2wiq)`44$GG?>l{tZ(sTBA4$2_oIcjR z6A~7fKe5AMW5~Dm=XJ-;S&E+@pT4$v+o5AQ6;D#S*^jnv?pP5xKdN0=XSVqziCeeU zPCsN?!l^#h(0JBH7rCG-6TKfV{oeUjZP5)A?d=haTkclHd*n~Q6_oYDEcta%eSXf4 zPn^qRMEY*ca(MWj~tPvDZDmtX$UdAhZ|^2xlzK1*`t7s|Nl zGz;G2khxjYa%X>dMPS_afSi=T#}og4l#IOAcI4a^UXPth0%>y|J=Q2*{$*W){e~VJ zYlig#62>)>TdePgW!&A(f9Q{pn1@i;)7y==_8L`OY@RH8rd0YqN9!IH@nesxBkwr# z#k$z+eV>2nNJOyfihJ`(iaz(f*tG-Ls~<70$?w=6PZ<@ygHt zS@UH&8c#4Rnq{^mZSVfS?(63sJIbndJ8PTrHiw2QrB9N3UqmQdUE>a%)2H}hv4;PW z`^x-B-xpVG%J@G$_WRYW+20=pIX8DM;4Czq{IFw2`Qp>N?$|$_x|;7KkIOf16MJjB z7xMP@FE|3`t-YHwak|WuV?1XkMmg!S>6H6UN?5bwWgD1 zINH2e%4l7eoxT3YjBL|B_EUQ%-E;aRbKs|j*@P<}9y~a1J#XzJ1qNG&&gUSNL7g*u+m!op--K!BQSohNUV$*Bdc=usVmcy zg|>V+#DDFYh2F!(4sm|xlKH#jzn%TDDq(-=Rf|a+=DI&pK6J!0J-OlV`H1BX_Souo z)$1-Kn(7As;F73flVAUHtHE<=&-<&lyXrn|?0L3>rj>bfrn-Ew>I zy>L^1_%*W$FZs{Q`jzJ{{NeeuNUNasi7Cr_+ZFlmY)hoKKbSnLQcmk$hL6Oi@?C{> z$7=0s3jGi9n|UtDmD5v=`{8nb*9w;)(J2rA?(jaE+IHvik}idmA0B5N{xZb%9Q%Jj zk1MM4Wluqbf8nM0mf5v?bh&(Y@%<26Za-r`ySvfXc0T6Sk%hCnEk3^gex~)JB;Rd! z`^4W*B|luWesVbd3V%#`>aoce*7nq}2=mY17_7W6d39*|_Ns?W%XeLzZ~o+xWcSUg z*MfD&%2gH#Z&|xozUz?`(}AroW26p=&GeVKy*lN`B;N1BQgxNwJx=eoUOeIu&}(FC zHe*t`+_sDl-S$lX_}%{7?iPBp-B~q3u_QAg_wM_S;3eLlW9TaKNdm!VNb> z`8tiV3zyG0R^IqxTC(TnON-WBbh{RGc7nv;n!2ryJMJ`Jt*~I|c*4EkRd9vr?zfHS ze^1#b@_Ns=yP`8f_AyJcesx&zO2^=kgIZ#C`X)}5#A|arGM-&G|M7g{arPy(?DOsZ zi3&>0JGpw}53@Daf%*Qs8!sCzG;JxBT5{%Kf^Pi8Hj{Jwimz@rwX5_^5&r+2Bff2| z3Pa7TQPUihm5*}Xux8C%T>xTzT?A~u1W)#nS&KdpU^6^T;v%4>;rGJ~a<9|qg zN}{tfpRKDGJ@^(UqvSWOeYAE6)_}RbD?iyBy!PycBQ778L{~UW?5=;`8|PMg?_{Iyn(&fdi)E`$ZCkUee$Um< zyY2Q(-p}JJbMf*<>lvSW{$~f9yL|b#><8D`tP1^{DQZ@OaxY`^13` ziG)Yj6P91);hOZ}?~}VL`%{@Je8d{kMVEVAdh{`UK5KSwy!dcetx+0qCCgq{Fx8z|MEK?g_?3$?YcQLaxKf+I>VNdg6ENU z=bcSh6@Btm(3Ayo@0x#jHFB>iHCmGLQbcsw!CooZxvIineK*{WxxF-h(mI8&FZ9@J zg!W(f(R4%hx1+wkaN-jG-BHqq?w%8pR(`JK8yv7{<_d;3?gR4}QaU!26|~5ht+$j* zx)(ch>-dluO5{~5R8#g;!@mz?awS0#UXJp0$> zSK1s)7Puzzdi}NDowRk^_Vwm>w_hm!zO8!0*QOmG&iK79uz7nb&-wiP{`-sW9-bR( zUKZJ9`7f`={qt@IgJ0)2L>+Y5a75OM@BKWZx24Jpjt4a*M1~nK3I%$Io@4yo@u)Sc zM%W;!agtk+82=jdi!V^*wR#BlVoqv#d04|if(5`QoUi1K}lh?!;?D}3qT^+(Zc?ybD0 z>}?ZXRH=QN%pX!a`^llJFN`Jn?)aDh>mR-Ma=SdUK#rRXkm)nc2j=73QpILtX>8=mk`wp!(+2xh@K02dc zg(34KtK+##%!wUlyWjP^zY@GlrEFpbtK|G(TY}#xVj|uO?Gkh!OWgpmHc!%vq;l{4} z=H>gVI=la7d@?-6xa_-!)MZECKK1Pz{!E@N&GX}KV1)i=@x*WavcmOC^0(~om2Ca8 z;@f?#?i0S>PTEJzWUUsTl%!PJbB=q)-4$(nZad0}OCDnsz#eGUK51e#;TzV}KPeU7y_JCmd>R6j4ioORotf#HiY1A{Vl!$3yHC+8#<7iT8x z72sdsaCT3n#g&Ku&8;?d3rs3?a@DxG>AXs`s*BPg1+TK3l5RJ(qPr*Lt_l1$Y3|0h zj;>9!C2vQxNggvw-j@8!?tJOo&o<}Z+dPlC{`2vS>~}luzd!$5cmMm}s`cN0e0a2N zCnx`O4RHpB2RjSzUf^O#Sj50^Jjr54zuTF|TW&Hiq#bx0ea(&GnE%g<+yQZM|JH}+ zoqZ8yT&Ll#pUu_!X}$Z;@5?T~jL<17D=Vw0*s*r)+D)5`%+1X$EhV{HtE#K5EiCTr zD)kNz4-X6sjER{ud-m^)FdYU1ZU!D^hFk^*RfY-N3@XeF0SpJE844H}@)#L*F*GPK zDDW{9Ff)j7F?6$@Imgu2&X}9qaLUUePfx*8lA)Dp&t678zJ}=S47+wQxVkp%uxOZl z@WcQ0oEi*VVhwXy&+sv~-Db$0+HfkyA*Pi;e`7&oQPfk}4XAPIU!oVdj|Lx4o zo2RF@uaC>!yiKpX_%s(+m7KWvw0Z9emposlcDRvo>&cUwSFdiG^51~rh$cfU*MUZ+ zh9HKWA`a552Gu3(tP4t*G*}tDcp4t@EQnzZIQQrN#Q)P}{=YwQo2xAQa=7=r#hVs9 zKKbvkVcuNF@2_n0rdr3G-L-aFjt2Wxk?-M8ipALPh_S@j28oMkvA4#xI=y#X_%9$s zMr0OiYnao*xdAUMM0RntdU<=_-sSe=$B&v{UsmqhS7)2>*`u4`p2Fg4$MQdNY^}R& z3fX7a6jn+s3koPX{`tkUzs>5;`X%BHv8QZFpCa)#)nM`7tb-Z(&Jt@k%P;=g&M1*L z?bwU`O~$`iO?&Een=ZbWN&Ql5%j`dHcUPKCaCJNuhO(dW1Wsa@7dMc8g{veyV8STl%VVik<5ti3r_1u~>I8$K`utDtL9*etZAz5%c{Y zC&K0|S^O=!=$-H4ki17JlNly-emi#Z_lL-8-`4+yfv05{48Gl!{_wLeQ$z4>fwxUi zSHueS8$!{uJ7ze^tI0<=3dgTF)w%U!g?Jf%W>?U(+iK;JrEb!PQ^F1Z8I}Z_1k}ve zVtBYmvhvnD#nN}v{rBjKXMPA$`Plw^!xG=^Y*rC-KHCciU0vTQ()J}|Pe`SBca^~7 zQ-2l-3!eyHb585h_Ctn+Trve^nYYBh-cGL9={acNv|`sezhnE?9_=;T;M_W)$*FwK zk~J!)`&Z6S`}o-7SHv&R2|1CgUe&0nZqIITy*y_}mdZK*%}HmLu;ZRaroWin&$GS9(uLn0bbg*>bq{l z*B%jI;)U?})A6mlRSh-X$ z$l3Yd(2eu*cSld-a5Ki~!XMvez3vEDtjKNitH%GCm*ZPcL(6HGKkdEyi2s{qO^)5i zeP8$NUH)Wq*sYi}p=J%sS?6!+*@!HbTK0~y_r}EOu9NfrRV-`SJ>g&JJnuK#&wQ9I zw6^8!@{j9}esNVge@oBj{i%n><*~Yy$AZSDO< z+a{OlKCiL=i_RnkAtMeA-iXGd(&1kB4w#pXn zcWZY}v*h<-{gB0w95v57H7mvUQ_TsfBn}8 zY=7c&xOVpPq?*+i`Sy6KD}P+RQ|n`j?6mvL_n*|%tMhh=|7?6;v#7?zYKN3@)rK8k zx4&cwF!?Ygpu0uh&FALVwdbukeWH%ClzyMpF8fRBnf6U(f7L3!Yb%$g#ZOCI8}k3y zvOOwuv=u(G>8h;?u+M(D)%Fap=hNpBb5E?R)UaJO@ng_EgPR3KD!EJ5mli8E%&+hh zIw?JML5R-zX00zTHwD|D@SVl)yy1Fg#;c@f$2J{a^IO2G(6lW-TaQ~T;n&R49TUB6 zWq)m8tGs>a`3m-TE`dxTN;bFV%bj9ORA2SBL_9lKe*fh=m7QyYtM4&(#rFN*V&L$g zpQ-GQRlLE0yO;lGZ830b3DErbAU4x#$E<>bZ`jUn{rPHr`05FwGZd%Xxuarzx_gIv z{Z!?xb`@peRr4&4Zey6Ga8g=M`1zgf9Vedmnw#Ekn`d16rRMEC4gVAWw%q>eGxa{- z-Az?|?ILrv4$UdItW&zEFQ~grG^-$c>F1SgtQqr*DqDS@2{Y`uJ%35>p1r@~ita1C zRynxHtaGmICz&ggniF|gpZl|vdwkD1_CUqQH>mgVS6+E0>#pp-yUu%cywSIt_R)9p zWTv7Co45IX^JDt`vAj|C`%V%_rxjgJ89l?I63S0N7>26)k$psV4?E& znDCSnj9;ujzFoJzg1!FgZcCd>pQgI5Jf+queBSHXcn#GQ&3cV;kf(yzYvd-FOzmjZTmUn?Rvkv`f7*d&$Q|q z=3f?l@1%NOc28Q@)xLsk1~oU$34hOB5e-?!>sU6wrR3m*8)^0)%n!Nmz2JL)EC1y3 z^YQuJXJ?l6w>{W*{a57UI`8L4<^1iq?=IVs_P6eVmyXshp#pZ~^FSZPWEj-myx60F(r#I$nSAD$Y8Yi`rXJ&@sKDNwYPYH!-fCEd03sYkB!Jqs!gzYK)&Qj16#~SoTHxu2H>8K)8o={-Z3D z=f{&|?cAPR4mQ`g<#=8C!DE%Z=R90XlV+A~T~+?AiRaSiWbqvZ|BAJ*ovHfO^DDVH z?!*=s<(m3#zZXT0$Lcb-Sbd89x=E0`^{PfmRNe%0buRID`|}_FO88!}Uyf?==!eTXK!$?xW0AM3mx-B*Ic!L9aj!oO?=RL z^~b&qsz;>WpQvWPYAodX#A)8IZllV|9ObKXZdty_GAvRv(r{?!Hriooe_tx8;#{PM zMqTTZq+ZQ~G zU-EjJ^1bPbS7taWAJ>!JnEpJM%`D0Lkq*mO`i_-=jC*}|!nrgyC}mph8z z{d+Dp@$kPFPBL%5JeHd``G}8>{e#xtDb_1D$Q;!3Jdvq(Ty|lg$0cvBcWZXWFaM({ zHqWNIugp5vR_w<5diQ3d%2gumGi%ze=AGWMv$|;>lU)Cedncc_S}!>?_stZI%T0G> zGkP6)AI<;tVX>Chj~BM0cfZS8C5do*&bp>*cxt7WS<7mxz!i&DKfCuoBJ=O}=-s=6 z?|!n|az0G{zct<#T&|LeKDWJNKx^wYC4($~pV4H}`G7oY70SeUe8tpK1NCk+IHOC2k%Y;j_n6 z#8KkG{l7o+!mjUFe7fz1fMNOTHt~yg|{7*AKn-aSbJ(%xgQRvP@I{a&x`ssl(q@?8241K9qc~*7&z?&MxLCfwjASoL$d< zI%l))1c}u0`@Wj3#XA|2KOLW8{_Ba|Esx$6M?X*SIeV?<*uLfLQ}?8>JGLjSdG?d# zu;Yv+c}}N3{ELW*vb6t_uznfy{`P%`zy5LEC$#_T>cb+x-it2fQhSv5VbVcY+2*_P z?aUV+EwH-hyUy;rxM`EC^74g?{ZfA}J{7zD@cm77HU*}(U4N{9e6I>UZ*QBj)m!}3 z_5=U4lxN;yu8n!1seJnUNt-x+38|H{cWmkGUT$SL{gB?t?wVIjRSA=Hbl%PBi+(1h z;T3nS&0kaJ#0`tnpZ-lWII&*S==(1MPT!kw(&JsmqV|gUZ%^~C5O5KxZT~v!tpvN!*Y=>}rJMB4`4)d*U%I)+iecsd zSzjg`z5lsre&DU2tNdmDf7`ZxlK7n@R*V1E7vp0$as8eA|LQ}wHr*%c4;NW&)^MHR zCV1Grc>i_gOD$}h?^e{-9obs%cZVlnd-k6G zUfC1tEwu8VyiQ}fWFEU^S!|y9ISw~*!wWSAHs!U+VyCRPsJcwE_^;X|)be@S)(+R2 z$O#R5*4@zCJoEa-qip_t*~-st|81zl-WSoccK)b#;+?-@aq4fg z#cRZ0^{kz#ap2!_n@Nj~ypNx~cYT?)+)|qh7fTza&fMtE)~}nl=Eu7Dr zBX-&{bmxl3$E*Iz*>Am4Ka)pw*)7J_Q-9gS?sYd*{P^|ha>!wBue_db*@Zp3_dNPk zy=$@kG}(i^hWn&Xf8Wd)I#bs2(wjS)H)pT!&e09NuUCIl|ECqb@zXwoc*?lpX;itc>0d3OIjCy z*ea=!bF}x)Rn{_|S$~$_(X?L?eEOf|(hnTpHzn{KwUgR)%>AbG`5gkA-*Gs2n_lc~ zy|l9G#Fn($4M9>1CNo<&dO4V|+su4YTB$j2?(FkrAU+(&{BFPp#ER(@rod=2wI!&Wc#D>9E}Ppw}pwAtlIO>6(EIq!Yt zE{Q#DWSb!KKC0}odis0S3HhI652(90$py)|XUu81a=XK6?$k7o@{)(af4SOL-JkD& z?8#@NQ_@~De0gt8`EY7`=7x3Kmi3)`CSrYK@{ScbKi+YjS;x2dS4pX%&yvM!CarzzTi+P_d_e@*;Tt{7KuykYRIeNz2x`)-G8Rt zu?g1}cE#E_DL=~H9FaXUH%2<=_1%5z7Wu6`6Ro{kS$p5_x66LHw>f8QSUF>D_N-~2 zBKD?E(HFln_os=IKi!yW&_qz}rm>Dx~FYpZhb z&Dv|`t0Qh~Ju7m{wsL;>&8*Z;FO!cqH+atQ?J7Ev?|#`MA@8?!n|L;>yYjrV%$dyQ zze4+MZ?I>&X&J1#?(k)I%*a`77#< z-}u-ZvCE@fyKoOfwSvxb$+RB-E%mzgUmxBMJ1pp-FS(UV zeqigBFY}F_-rJ?|G_HEN&0haRgYvI+I&mv@dMfRERn&%gaj0)da*2?5vl-^iV6Jq}$Oa5Q-3~TA|r?K8^XY0o%>0VQ|UQom3wof~? zFEdtb*MzkN+b=SIYWlD|E_hzX%V-V8N0Tp2{(0bM%2PR~jV`m4-O^?389yH3{v&bI zTtiytW1Ef2QfWW?3Xf+CJGa+!zI<@#I+}w zgrwidbAL~`Z?hsT;LNO!TR9)!O?5U9&EfF;JHa>Dp``n2VC+I^ulhSSH(z(J-|$31 z{mGdRE~~4bIlp@Ix$hqD1S`>s2l`iBE|wQv{`Eg5^UwOO2|u5RawsiMH1n9w>Gglb zzpCBp#o8Gj(H{kt|4hlaete0Uox%oTwm!2WlWXtXT>-}P6oa{H))QUyjSz8#{obl`UoeRO7gaP)l7!b;1!ot_MF}s<5&p&OvF9DroW2u9 zb((Qo#L`-$roHE_V|jb(JtM2&j@O(s?3ZYM{`2XG$@%X&Up}Qjn`Cq@^~bXt0Xxi< zB+5@7JHGSG*VR|<{CAt$we(%xYb(A_b}NdPxt$R&{3rie4d{sr=KH%5vvoAM$9W=M~T_-y8=bk$UuBvg?%%A&Zg=c!p{uz&UYyU8R zAMyW+&kv7#-%p=BJW1zj+?Lk{&Spyro_U@>Az%0+|8wGy@@Q3uD`+C{kaqHQ)i#PkkJ1to3)A4!1q?0~37S#OE zO3xKULlg$ayfbS+4fY=l!?LrwYZbOK#s0cxL_idH1@~Uo79G zBVWb;+U~0Mb*f8Mil=eZj*e=Yj@KSiLv z``O(3v)9>g#0&iRCDi%n_=VKJYsKzfJG^#>?5dW1k5abIU4Qw*>)xWh+aD~QtIaQD z^fCOo{65Yz2|Cvg9Eg3@JzM+Z_cKnKfu9|n*tS1 zHl<6{t`83Q+O}K#-dW%7o#%D6bF7g#dQ@Sny2!sTXXj{~*!RBm=+n2J=K{W#PV#d;{ZU4` zr`2d7r`oH{#q&e7U6*YA=Ob~ocUvm|;-9&>uVUvk?q16xQ2p+{?c=At@5(i&>=sfA2Q8 zrQhS||9DCK2e;UvIcu+9*K5D~=AW&PwAaLgYggQ}moYzWscQGLbFE^j-Gonn%U}0R zN~{n4m2djl%ad#Jq|mU+*2CtWvrA9izqMrNrtTFR8E)-e|Jm%sl^fS4i$}}dUmmyT zLW%@;NXX7wg-%sVKP%BhtuT+f$Bw35y~3*zn78>o|4Q4>`{Yd0&nIot+`_osvC=R2 zr%!Aa=e`dj5_fKtg|pv`d{(s5ieIiIc~Qs)=SjQGJ~8~4%Mbr2AP}p5bEAn&O`~Ml z&uo_rk;=D!+pc!Lc=;*kI^)7CUoW{|T~_AeJj3JTv^Q&NpYi=OeJi!UW&ZTX-}kFb z*d-MH@W=gWU)Y?oJ=dwL#YI*Bd$B6`u+f)`tbLc-_AgbfGx+td?#YtcXYEr;JJ&s2 zs4U2THtf)g@8)Zg8tp=t%?_C~;ZT@G-mD!DpLFY7GuWBgbmhCj@27Epbd5z`q-%+# zOgr0a^VU50b?xeJuP=+Ay={_fd$Reh;?I@36Arb^Q|B?UU7Dg`x?!eSNW6LTitF<& zq}xOGZaMqYxB1$NTO#adc5o*w5-An8pJ%itch!3y%g59ES|(^k?LYC_>g&<(+t1j9 zey_FPv~&HF&%uA$Uaxo>TyUg)@sq2K)-|vHSFDn`8ZckI?)y=P@Z7cS9TNni|1Ukq z+~1)2@Ji#xomv-fFh9(CP#?j~9CYu=^w)e=)*MgzV&%_D+}ipkzG|W50)_QI4w{`l z+-Gmp_Brsy+!qWHE2X1uwuK8B#Xk7@?AD^ff4kqg#7xyLj8?T`S|agt$?MeuE1wfDeq~cEdpSv;l{>QP zqkJ>Bo_O)&`P;-xk0dLQ>cdy_rnUY_A&=FHyEESWc*?xyt@Kozc8l!U8fAGMu@nD3-)qpfDtgvwlP@{W z;(JQkBcG?u67nmq`#=Am-i2MvVx`-1_n$j7!>cmtT>af+f2Z%Xy{q^5gTvQ`wD*(r zOH7q(?PL;I|kUWvWQFQXRwWs-KL?~6Tqeb=W*_G$** zi@wgUld)KwtyU(w_Hb_5gKkm5FWVZW-)s@`b6dVPN3F8V?)w$_FK<#DzvNz1-|f(r zp3mV@hl#~ICLR5} zS@)INKbso$}AKu55NF}?Nm;*JlaT%>rwBC5sO0&!hSZn*P+UQ>k_oi;~Pe-lA7jORGoKSr+Md@Fs>ayh{#r1xVw z|EV`kTYl(>yP7BOzn3}bMn(UAD`?YvKWO=5` zT#VgW#w5bKAzt}+X8cuK#;9i|_5L=~*TfBjY;==X2Cve4UqGxv*T?%5{Ae&9%3 z4_i~o2j9E@KK?s$ZRVUV;V0c4gf+x65f&Dw=;iP3Qhfc~kr0(dpIOb1hf> z-DdQz=*PAj=dU&vM(^;SDZi!M**QIE5}&+n)Ab*6ZB~XAA(OSgeNt1Xd9uV|jyBum z%@?o#E?KtqtCmsm6BFC~r1#PBA`@KJX|Fjiyzj#clV<|1g3mTT?bmvIbWX!fri>j6 zbPg#V-_!Etc9+v(`RK4Ka~3l_;%9Q;cX>BcF8BY98UM;}hCVaUvikNu@x0tsh08%5 z;sGyC?VIl}KI?yO(;rVZpR>u^QkYlp%(1?zR&?%-Q}T;gTjBQk-7o(M#9lM#i#1vC zS0PY6>1)*YwEJD(ADQJmd1D_j&yGzt>#)+|N4pTk9HCJas zZQ*z6PN9HbA&tw_nR84dEp#4Tyra8)!Y{bC!ct-X{|P|Ww`Z;g(eKw z-g|vbPsy`bnrx@*`>~@{TeZOF$>|HvHcwl6u-xa@m;C;B?QL@U3;O@R+W+!r>y!R9 zhu;P;d{E$guvgiD_3f|slNx#FZdqH&93`=4Ywh1uADx`+1y@f66}zY3Ka}+B_`Z}N z^}FKbZ+|<9_2^~FN18V6sZd>;R6oUZRZEcj3X8bZ1P%5_H)P{)-@6yTKgoB(f@K!U zv3%b$c(+}bY?ycFe%|%Do=0cSyr5ruf6|xGPq(X{MLoQ|;$ep7rh{gZpWeKE7~xT| zW;)*#rncSVs!c^>8viL?-n;~!JgVt;g(KLsO=E&0rPBKcSscKGe zZN1p<&*=Q3&(3PI(4yYk&%WAhVLoz<^9jG%><99D*O0DhHkBwc2&L$ z)%anSkg}^LZqNHa!h0@>9^c&Y*7kxwi&ItUw#~`cruwc+&t{!+=JA!@S#g=#Z4)n? zVcdK#I(pw#uZK1M+zxzUhW~D?sOE5CkKglKd?mkwLcE9^SA5cZy)M=p=p{ zZCOu#?sHe#=UzH1-aCVD z&w8PUYp3$W`=51t&sX+aLg}LJ4An18PiM%fDnIH>{_#sVNvn0&&h0h--v6H8#~HZs zgY~-SY-$W8oeOwv^LslvZ=X5CXy0t#&TA~#`22ju_IXQZCD-3mUB2{Y-M_Yo+xv6N zGk*7EJt<`8dYdu7oJQTE(n}Zxi|dDCz9Va$8+$ zQufg+=~JoaoGpPJ7L{`lM06aFrJs1fmEwCP#*;jO~SATpPuXE`@iEPZ5rP?KbC$9EB)AGFP zN1*X!@1Cz*-p%VbKKvlycZ)G!`= zEbLd9(EEH{wp(ZA=gbYWePX#$O697q$mW-ek3Fh*GVhxDqE`OwSq9tvjz00pi+Wb` z@o(tXW!@@lCtkbu=9crdv(pW!|8>%E=(s^Qk5gO^Qx zLiTEZdT^b+k#oZej|hhvEj^D8Zi7YjjT`;qI_|BR9B8sUKgD4yn|i0dle@smMwzwe z+LKO*T1PDFd--1Rt)h|6XLg6}t!*nbu8A3l7+2NVif@ZD*|FV7ZFbdUoKOA|r z<@&E*#;jScQD+^Ox%}{*)^_27Tdz$@N6wK~9uk?kJnGl_U6#wb|2^6vBa?E=Ypu?u zy+-HTwv_yMcKG-?2jQ3BZiOfLUVE*t<<|O6=}S|mg9UeLlG3Hk`tSQRxuha5Ce$8V zIHj&*dc$S)z?1VUx9_-oNr6LRZrQ;JkFNYvouOWq65XCwEv3IzdbM{N^Yo9x{ugq2 zn)_o9-DzsOWVKCKqnq6{GgB-x^Td~q4+ZDeZ|R-4{%A<3m%;lxFEX|UdOYaxf8Bp} z;ljOJR2GO#ig7>mRkyKHZ7 zPsX#3>oY$KzTDyZ!o%lC?5ydEhhN-aj0j;7zG%of^JmDKdb`wFU1!TX_B@s7jCTv> z^V`zQ*RlA+A6==PZ3PT0&NF8zEnZ>lRLQaHY;cs4KGUPx&UyQ?0`9Cm_mZV>g|azE z?)le>>uVEJZuifrn9J;9oRQ)DFN|%f+DGG(T7`@9?M^SYeLH{Ppw*AH|9;F6-p?9# zddd%%+=C)qoSB7FCZuby@7VwM&YP0`7ua~t1D{K++m6|$KKvQR%xSbx|ISXYct5X6@}a9VdpHDs zHk@eHXJ_x*+kNwirGmjKxzc}qoUfkk%Q&(=%YFUXCz-1`Qx+dd_^-U|;db_l9V&kd z^ft}?W@y;=U+eFYb;)uHf`K9(42=oWD=ySjN$$z2PM>-IO4yB!+xG2!d?ZIj`31`& zK9`Lb?^A+Q@RD|;m zIDc;Z>{&fUe!?b2&%!=(3jiNq=g;T?<^R`}ay& zz=C~u0z)F6-!7DLeRe!=i*>kLyZEYpuOR8a30K};d*1$mFL%*S*1M0coDMv0e>>v1 z=8rGoPNzSrxkT>(6~A?NSn|BQVO{=t!T0cz4+ou&ye#>YeVVDQ^2OD! zS6IyAZdv`=vfpL}PxXy8O-3E(-YkFTd*Gptw?~WI<)TR5J9}k!%CKg8c3gB6FP`%{ zAjgi?GQ!KDRc?EL)*p>Ex*Up0zosR6wQ;naD4TM~qdZQ-qH3~O-TO@K_i`@jJYqi# zt%{AV^nKD0RexxA(B`$1^&Ow0Wx|u(_#4(&$lKzuU zmp7R?oi5}4Jg*>S?%kW;a&zPNEZZr0R-*DO&e`LNYw~HO#ov(CWP{m~8dxKT7 zbuS-JJlx0jWuv>Wa^}qd36q3!KdvB){&N4Q#NxcV+czQ|AGfSMoVaEAgX()fj#PbX zu)U~OG<%5+!#m;iwd?Do`P%K`&f3lSy9M; zi=QShrBU1FO*Zp>@rB=Stn|jXw78*@N!$FO5^G zv&!*3;Wh2OY**^?C)*vIF6~=$G1bnUSN_V}F9+%`+U@PN-?}+{_Uq#zjP0 z+_11{yZvY+SFd9&MU>!zP@OD|9YCt6xVrE zzn;{K{^$Mc&cW3WrX?*DNINEA6XIHN%jxmL%hzA`sr>!B#V^wq%s+HY!{(5Aths%|V4HpFuUOcdBZ+_g_i_e$*y=(Kt zwtjZk zDsSWGAI{vZI1`gw{^sw!$hW+|kFG4R+>>DU`}Tzs6?=DT^RMvJ(+ta4_C9}C>#K*q zj_m((*<3~X-0h;}3!Pb>ACY3aS=iT}K*0~?{udQ4Z*i(A= z{@+#V^=UHej#=1=o{(QVv(f0s)#6-D`^Q{b(Hb&O&b;2jDgTQ7i~BA=rv1imYkvIV zImOgI?^#vb7a5N~rdFYafgQ0rLMj4<f53z%U?b;(mMHP%Z=x& zn=O}}H~YaA^+m@j?S{R4aDq^1iT)*XMd6fBZ~R`m7fie?De;Bld^Jzstf%`P*a%Np zeA_<%gw*!)cDE!J+<5sl>FC6F)1*JnJ~rW1->)XY+ks&jkrsCwQ(gB8M!b0zys6)5 zp|Q#C>ARiFJXNp%{>NaZ=>B@!Pqv5tw@zpOsEk+SI`<>@Y0}(^=dSkGr+qUPt5|%} z=eXSIVAn+=&G%lf3H-CZV$I3@oKZgK%@;6Lp6}bQ!J4_0%kQ3iFBi8*_o|DMFW#0c zKP+)Ak=?)Y=H=?HJ>HE!-`4i+IxAru$=S9q`Hj-Oyc30=QzuqM2CSXz9etwRrF7eg z4bKh*`}Z7nKg4zJ`7O!ZS>HrA?|mb#=k`@1 zm%|&r-adM8%WJ7c>F#+wbt&f;>7L}7|9;K(0s#(%{cHOV$BLN9&6o1lD|#$c`gqpm zwI&~nmH#PiJ2u<eQ zkM1+a4R3abC-&)fFI|>g)X}wlD>vJ^WXlrU=T|!Go_}X<6`H>IYkuPWqnz zVUTh4@{P0Br!GWft>0R`-oJ$5s`4$fY3Hu(&6X;2ymofSk=VLlecZF%E3ZYKi>XUH zJHPzLlJ$T8O_AK1-dU%~AhmfxXHb>bKdlp;Mq7TotBKG(+_% zo{97v-@aD;QX+-+I6ZoirY#{#bVv-bRuUV7VF z*yHcnXCGWQm({mT5eRM8T$&Yoac|r+-#w0k6TLpYc-PO(`1JhUZ#%>8)UH{)@+kZH z>Pr=?J(W#g5S^J2L=}BqXK-HrLDy7dD?nb~=i661V}sq#mMHP; ztCg%u(6RnJaijFX_1#a4g&z3l*$4S%aqZs{EN_rA>FEM5@ilE{4ql0Q+hxqL>}=fS z^kb*_1SOTW{OlI9ms5=SDP4W2&GAmW*bbMJA7}12I9i?*)Rh*robUIw_x1J1ry>s* z9XINq7BZ_#WUJ}L-_M!XK8m~jiHGTR%5P5($5jV|WFBvFT5I|({(!*sN){pKEr!cZ zl~sChOkDVLs&Uva1MNSiVLgXpJ}ulBQ_1;m*1eBY69P}%6nsC^e}4FD$-4PzFC;$q zpRO%^bNt2cEVj$1R5+KWteJU0qCRqC@j|cekmY}~A07T+@$vQhu#3xP_lWAA5w!g) zer{`S1IHS<@D-O;n-_ghowy==$H^MD7XM~;@frT>S>Hvz_p*{roBnEV+$0^=i*HieX`sXFS zH$v_yFE1Z`oBi3zVD)Miug9@sFC5g5c6#+Fy*IF4Q}HUPovHU>lYL-^liB7!#p~L+ z?mPcKYVq}-VDNiUUZv`t9%t)+`kI72oc{MlQsrN-xC?v3JNwnGRTFsGPn^9!J8#A9 z{JHb4XvcVj31wEEW@vL=y2>cUW@qBBo{vgDu^EUKuus1c&?pXfsqN!NMhDlX!b=wL=<9A4%sq@e1p2(`j&fzn$!haX@3hPH- zWaBn9Uc36UYIgXZrLjVHrX?*r)w;PbpUcxzDX2|j@8zlK>*n5!OnamiW_9cWn|;aV z<;oNP&&*0OnRm|QRNc?-%=6<4=H$mlU1sk%En8vlIKUUf;RaRY&MYTKDb{jXT$B%rcsvpI;{SlJUI7?~_e>t3NMt{F?CL z{r7i&R8zN#^`vS!U(~!g<>tNbkqwi3n;RpHU#~8TF`U7BHh8Xyj%T$05}p0871)_| z9<{x5=5>(o$vIkWbeoaSKStJpwe#quJ;HncOmC6ya!>7jvRc0Kf}~a0!o7Rc``mv@ z$u|kDWL*50e@oJyXVuM0Uq1(WZms)zU)k!N!7{&X|1yJw7wLb~%<7%O{et&hMdCk` ze>pKMVLy*#zr1_5qUTiWz1(ZxE2cLr;XQT#;DJx)6$}?15f}e{-Q&y8(()q4YC%w*%b8iM9#h(v zhv&WM`||#Ou-xiD@}DCP)t^rOwOeIz<^ANcyIks}DQ$VO>c2gYFMa7>_dcV9>3LM= z`}hSiFO+5;H+}0Kxj(xjUgGMFZN<}sD`(!BeJk?Mb;D`@E{Ntx7rcKz<>wNWl0fx4 zw)`CaGNsSlj=sO|erN5c&oT$~Zy`JMw(Yuh|A)-eZo>_}r&-gOD?XRx zU(46^I{Q4|fT{TY<=sq0^IsQ9H%fJLZ*|~(s9(t|Q`W|$ux)nX{e1#ajB?k$Teaq@ z_i^oc$Jp7NUutST^~^HQyT$#==a2JvHr;q~sqST*M;@oBl;!)0{K0Qdhev(iqu#J1 zKgPeH{b^0N+PuDh29q)Zb~h-g#1>5nZfsiZcHrmZbne|JB*nJfnRILItD3X}$Ae8$ zx87*kALzV^%irhDXLIKN(^sB}GclO6^L=helq&O#@R^5e_q<$ud6CG%*LwYN`*tqA z6kYRK-z?|5?}O8eEMe*p{RLhU(dd|?0I|s3Oh)KyiC|I`}o?nzwtun zzs=eq*30O%q50J5BL}YR&iQ}o?#anP^L!@Fh&?7`XP5D!P+h!EHD#LRvO3;m9m9xw zKa|2=mhHbXIlJfd?wiH2JS*c?R<8OW(jnaZ`uJ1*_omX}um1O{?-7@K^MWb4I2;IBTnJjvv8b zQVRb1=v%VJf_`clfV+yO51hVC5v%mhkW2TRS*U_?ztdrJPMF<^sdmi}x zM&J|q=7_R0Qw-0hZ%y|cKw!|Qy2f|%)%4P^&f3n#ofbJ62Zl!f1Q`z2kqCLewVRj`R$ zRQeT#Tl?N~NM0~w_sn}el}z(_Z={N*9Ltb=_d>4UeOr5Fs)dYw?HSV-5+C@hZ-0ET zKxm?OTV3lK+ujB9#f!fjvirm3!vB@Maq1B(y(_bYGdKR8nY7#Hp}a-n#e;iJPAyn$ z(<1RA`u18I?oCftWdxZv)-v^7&*I&5K_v0yT>V0!$}O8-e`vk&=E3%7|IN17FW1|6 zcm|Uc&pQ#mmRXY*gkSyfG)p(2f6crrwO-X(=Tj!vY5ge+@YYK+Ic2!UdPi{P#3MCA zPX7(A3GLJR_w!lA?|F{)dFkq0N<2**L3d0yY}~68{&VJ4nr^b!&-( z)$^qa)dP<%k4S8`ndn@7s>6|go0q^A%URuv!i+n&a2_sOJjG-~{IJ~ysM{aSUxwR$t--A1mErL$L7s@ZL;tT0tHxFlye`NqsH)tr|~*Ir5X zU$J#e+;_D<_xJ61lN&qcntr#smwmOMUU`jzqw^L$dv%Xe?F;*BRdWBk-|#rw823D* zNF~4M(V3k0pREq9l~Bk}bmDSduN$rYfmuj6OyrQ`%)2wpJ*&9hF^X`XsCm5a5M%oH z7$dvCk@uZUjXr(c_k>;NQKMJ=^oBlO<1@@RWcGUPaw*X@_~twP)U0`}5Dg&BuLt*)PNj1PMGzF+V?l|0!lKPU$0?zfU+?r53||&cFJI zsou0D7IHq06Ef{NG&VL|kiBGcC*s3mwUXPWmyWi5uQ?%{utO=&C*8zKKC_&^!H&gT z-HktXHQT!Ked)}*U%hiOPGK`R{etT+`y+1^!Divu1O6=@J`W9Y!i{vaUS$6ec_FiB z-9&{?42?XpJH`A&E);)k@IN(icgxm)K5d(G1Lg&Fw^uxybi!l*=SA}rUqAhs`SX2w zI`hLrogI%apVA2SU32ea!gkVazMF8BF&%IIY|M?|NmWBp5mG zAn)q=oR40dh`mr6Jo`=j&ppxZ+j>6j4&57Qan)6}Tj$2_(4yaOd%YV=?%9XEh)CWR zotJp>q+W8hex2qa$BD(KEIKzFO$|Bo{>!coyB)i7sztan_>@!6`*P|UIeiJgCbM&6 zfK5vJ!83pV-@IS_x4!yy_{q;63=9QbA9W7=_i$rQ->FsHl`3js{BQCBUghG$ud>gb z|HltHgg^v-_3Fi2^Y$-hXJAO@Vqj3her`ZoeqKquOF&{~UJ0RN1Kv*kZ7=+b`I!Cf zoMgSiJ6x8p%UX)|ABj0MVYgcOMuA&vG6PQ@OFOkT#>*m1a_WqvOT0VdC#8s3^@W~( zsdm|8-Nw25>W_clQ(qBx{`dFiU#m9N?u~sKD5b&Bu;(_T4j;pb^<3Y)57(uN8~xCS?KQx!_MXX0ewv2rzXxY zR(s=R&&1%dMEcsp3o}iOTSH|#s!N9ugk@XIfH-IFoXE9l7l>sd>VKJ5Cz zem=xCcfZ79wrA-||1{^{_&7C8=J512lQM&D_iEna3Z2DQSvp_&%Tg=84*{HA>$0O5 zdQCUyUTcU}O5icl*!rRFmGf&=wL5=ux;TzMTrL-Xz%;h~6q}^|$EFy*DV0Sk7bVVq z(ebHebIb1Kw^7Jn#&5+S`f`oFb;61pQn4~Vvx^!Zir-zCKKK8f4#CYz?5V%Yr+n*+ zExaQV8Mfrefs|!6te*Di-KjH*ig!N_xMXmC;cn%`=hs|U z_-B1t@cX9Hl032b7w!LF7m9o>n!GKg>*uYb-&-W>?ytHmU-{^U;T2Q$CC1rhLN|A= zYievh`=KJ^l$Z9S*KyY^cmAEQ_Y2pXyW2lr^!U{>-|1Uov~jWU-i2I(X1bperXKz~ z@yx}A*~xWp8usysNZrdRwvRk$uK=b_Gdqep3T1U>Hca}qc7cOYToRw%2|11XK=6Jtt-zXjYU7O9nQ?ze`wdt{G#0t zgW2c$_-o|{v@=I`ofx|`m92o#OUyfoR`fOT_a z_o^6nwWp7?-y5%r7s>8raIN4kwx|n`zO#E__m6KK?-$jFi$=74eYZ@TVaBhXg)&uA zmt|)~&X^N$*Wr{)V-q8r>*-aWx=lBENG|!$;qunW#(?Lsrr8PRt-+rKgZtD^Ot3hW z!+v67mdyR6ke@4M+EcrBeW|r}$cyS+q{eabOwiQx#f5Hk81&1DORhE3nW-do?6_d+MW$Z6 zSVxyjXAUuCo2>Zu?iXLcr!r^RBTpCE=iCgu;1aWM*|9B-FSdOx>|Ih{#N_;?xkBcW z@VY$NlN+vY+!=N0)3O4t=Noiq%eHt)a2l4B#Hz-G<}cO1%&o&7u*Bg?ODp?H8*f#u zn-_FhOA>!hsCZF&BCTCA|I(KoY^KkTExUI7_^+u48U9AiU_WBfE`DQi|Gm6jn>KOZ znZPB#__k}^{7GJxYego^%zhY@sI=GR$Az^H7LT)!XRB`0k@yy+;rVY@){3u9J{ff@ zZTBRETGwWtTDiXTb^pWY_g1Obr--fm{W##Q-_~>K-Ph*WhKHE?OL-JF-_~1d{r#7N z*Jq~d?_1uO^6H5TX-s^z+tTa9+@$iz(D=RLeatN-S8uH`HPZTOXO!#ARcXwS|7W6u z#N3XL_75J1q|3KnxKqJC_wnhqI$|=X*6s-ZsrzTEA3vLUQuP!&28;VuFS>7a8!ABM(6Gcht=9*H*Bir@62O=zH72y-SsOwj^`RD-F$lCp2PY%0=ML|f*6)Ru{$88 z{WzT2NIigU!iuXKZ+@N3`1;!#L+3XFtS{d^x;uZ3vaxqeNnlmfp*yjzoMQcP_nD`h zQP=${;;ItL1y1 z)cuQgf0%Y@*9>1%#(8f8;sa+KSfs{hq!SwZIwXJgrMJr%9fFS7^T*kkJPkAUtMz%s z{JXD5?MM0f&x$#*yP^wcnjC0u)_Jw@gW7hJg&WH5S1xAmS)f{Pa$|~7<)PlKTg6}e zzT)C?tj9-RzOEr`)v9fa)<09vRerNkc}BmmO;GT+F4nlX(5KeIY=#_)`O(Yz)|g&O zn0{lzQlq@WciGHK=OiDMKbLSkWs8;F9L{|e1uqgT=GL#DS$0k+SVq<51DoeR=HK%S zyZ?rG3oI+XvyG`C^X8339fAI-{julzGH&wf-h6OG{R+>yD;?9Gwr&qt-v6;_L-^Kj z_E%Q7zUg%1-&*(4psiPDb?(e-oF7G=W(7aKql?rNs*jg6J;zd))=ZYH+!}AUz+N8u~;c|#XX+l_fZ~q zZz{Sj4ZH9xyhf+GCrrWO2UB5M-N|E9{+!5bG;qrC++A(0qxr35Ud{VN{mCCo_P=1g zI%D#qqg(yn&QH=`E#GYCqDUzr$v-r0QWbhFW{kO}xd zd3Hiy!s@$59~&~SIy>I`_2ba?tp`hPE_JHl)ZMwTf7-OXTZh$lJ=5rFD@n}%`bk2` z=NjeB$iZ|O{w3_P)~CC6B0<%Nh%`o^15 z=O#)Rr&ZQ1yZ-yvAG`gp|5n%j|Fdh}>pSOnzAv8t+wOGjxt+1+ZFW{2_3?>_lVD-$ zoEdLZ&&%>CsmbBa#3mbS+i*F|Qzmot1lZ1i@15@EV4grQg%`Hs~ zHtdqW_~jU1oiXt>p0IoG=Y6eN%mEtbnq3(W*n8M<9azk8?Eixd5iS-d&87f0g(;>S zPx+i$n|v%{7wnH+Q9nUhVTx*cOY{3TY1h}qYH4Y`di84AvSr)0ZF~3bU1MY8#*G_i z&YbD$>dMQ@J9q9}7N$lQB}Rq>PA1C+hkptIIvg!*jaiNgHXJ7Z`(?Vi8kVUgmQdwM#ZBO<2kKB$_$&9)p?Kf#*yt zYnED`I4Jd`US6b|Y2jsut*Ht%>=|{l7K<~eI4pJJ6Pv_F24(St1V?M>TNnK_ zIHvG0J#BX2RS2->*mC6N1f>NlxHE1sUHjKi&Ll9K|H(GShzXsXCk`?`dC%X~%ewI5 zf?H7na{ROA-+%ay!GMX;jfr6aqZ>0r3Dbca=T>Q{EqKhQ5L-VXQ|E*fZ_z5&yT_ZE zo|nH_JcB1=5#wv61G^bLUa%CkGralICsk(lgzphA>qoWbigL4-zw>!DVGr-YsoXFt#5 zSyV2-Q!4KJZQ3c`&^5glO|CD?RH7eU&g*~5?ia4Azx8SU*X?gF6!-j#_ve)PxBsH7 z{N`fb-#*86oY_>8J6e&?N7Ip@yndDhP2cje+f z-pJf}b)if~&e6v3M41#}6337gxCC0IY z$;duGN%&Km>h0GLZ!9l;Rs8Z$zu|r<<@6bwbnm}EA@Dov-HZP|hhKk_^L)2sQm(b~ zONPk5pH0*DuiWV+^yuvNzfLQ%9r{0hx#`o(Z*CtUzIT?*DXS|vYa5%UawrA*g8fwF>Zt=GIe=e*fhG+#r>>9Ufl z94GgaV`iLAB6Z6Ce|B&zjcvPm?*EkEhI02;T~V!My2z(c%kstP*&0hIh9VN^H*mQ7Ec$;;Zo%DSzj^VzReayp0wP zwmRSQJ~L-;t!M9*@5ax2Ma8#ve%`2kPj78`qmpZ4^UdNLU6bl=7YKbcn3jHLvGC%8 z|Buq|7w%r}aV`3<`EqA3?g^iigze+m?}fDTzj~o8<8t7`ZSDG1V$aP#ow#oMl=u4Y zpEs%tJ9y>3*!5Ium%OQq{IAeBDe8OUk2xKTQa``ccRggXJ~8oW3sduLrnNibzx%KH z?rUOO^i1>WM|sPg6Td2XsjOfBAyI70A8FT=3x?A+tgorzi{ImS=J36b3(qWHXVZ19 z!t|%f%qx@KvQA|bKgrK@N?2&TsdxLg(>p#0>1p1Gm?qtSH15m=OVj+5r&g^0uk6=x zbGhc^J!|tMo{Rl#RP>1HlijcUSGUh@ijwMz%Fi}CqYZ---+tO>THW|+!@B0$U#|9P zG5vMd446vI_x))8L1>C-TK>UecS&}C8o-u3r_RL zp0imb`C;FScPf7(b#M$nG;V`X2)3V$e9#smt%J7O#S`0 z3u8sx*BKs&X3aO-Qt_c_|DTr%^Il*7CY`^k_u;Db6;_9KvA=y)@K`?2dg}JQ3cvF9 z8u~ED>v_giKG>ctkvVU@=sB)Duhma-TP~Z`259<6>YiBU)I0x0nw!!k+qn~_WgM!T zdHL~|2j;iJ57pm4|Ih311>T8=``%5h{~o#T;LWes>!fyRynm7M>B*ezPyUI9d5b*Q zi+a{nEj?efdG9)%u;GEljp(f8ie-c^(`CiYpu-X`H{Ns>e zaMC?H<#_JdtDgV6xcl}cPfm^d{K*?8G)+G}U3TW7(&~$y{A@AzYikco-#c;J2hEQ& z(rSEmHbh09@|p2r%F&HcdG@vMgDzZtxsA_c<<-SuU1eLQdv2LJ?f<1km&MvnM_2IksQ=fhTkET(|e?=e*o| zVq-cdPOEP}H09()r6u+O)!NHt-mbfMTb1RV)kBtl`zq(3+Wl=}_3mc<;`C#F9LgrVN28MgPzklXa_alkL zzWDl_Gmjk}2MC{if4R#IrH$47uQ`*qq`lCwQo2}mAMGP`?ab{D{>!gi<8?Q3!(Ps+Pp=%JH$2OIxc#!c)IA=*%6t0?IGQ>mHmvZT z_~-JB?FDhlYgfG87kra-(?6xjb4p#c-a8wq{g(=lP>m5tR1@nwZ#!${+zk=$J~1b| zgjr3TWiaXQZT~EF?R_rOME2iU=`srxjG{jAIU2>1MePn`$lqi_9s z*LiwY{30pWUvZntinmTs`h0N9>lag$GLKx{yK0NSqNu$}#{P>f51+D|YTCFJFJ>w$ ze|kO7^YY&*6$RyMGqXEBFH12$pAmFdKDA=Ex@F$G2Wnw0e?z zt^e7yi2oLs)9gP7Mtpv;GUTJ-?bMqZXH0LmK2H#Na#1nrd+|#7*Rt37;ym|Um9^L< z+ZXHZ;cPk4GMYiKz~-6q=IhT^bSM5~)teD%Ca>gRye$3fvhDTK*Y?)@-^8bKJ5ODY zujk;>P5;!F|5dpZZ7Wxq6ttl_~FFZYe;eSAB-#oA2$>EHj z=TDg`bi&KNFw3y2Z*umzj8}i^YRk@xo_hWK_Tu-pPG|1SVq5od*Fndb2iae;9$xk2 zl8rHQlSZiJsqOFkMXQcq43=MBp_4n$|Kdxr9bp{2kH1d2;UoS%Cy)DZ+9mJe>S@8Y zsWO#C))AW@Wxry-{^&xTDU02ke!bauzuuMDt@Y2Ezy4p>WR0>PSqY7vi+Mkcq_Wh5sQ~Y-{QtbEFtF?9OpC1x!&rFpH%Y9n#=fbALGk$#c z|9quuOzQLg%T#C6eUZ@@qa?jNJdC5HPHJ977?8=ue)6BMO z$E}-Upx~k5_TcS=aJv_UhegWw&bM^%PWn;sZR+NPBfPymPuJ}X(0$Nb%6fmf$nwl) z!54EL{S0t%{&>OfWvZ0(9KFpG%`fS=cCucc^JnU+v(sw+=G6(?9(Y@qxVirQ)0+o; z!%ZIA1h(JW*8cOcrT>w(+n4noMvK}wdT)+cMIC_;opEK3`H>YKlLza_T0`qlqqoY5v-@9tw zvfo$oG&uh6lmqs)_tc;Nn^M5FOsuQU@LPA!Lj4Jv=Xqy`d`a~-65qG|maEMDF9*uM ztGwHruzLN1I7P|HLf+X{iGTkd3O95-!fN%?MZvk{OKOB*qJ_GWfcL(KUlvY$!!$SJ zYGL<7R-^y-Rc;>UYXTP|=>d7ECV#6jO>p4!ZAu8WtY?>NC%b7T+e^wmL4 zIlB8+UM_1fyy>s+e6i)xyDuHyOb;gSiSb+z7E_n=AZ@aGgy;V{CBd?}!t+=Y*LH6% z>2Lq5KmCVY%yz4m={Gv}m?xNszbq4tntA(g%#*vjK2FF^n&fzKiSVn?hfN)aJc}l+ zRNi=b&5zOzsd2k5a5&!4XxQ`p+LGIc1k|5%a#Wc<(yM6nF-?2W^?#?OY%L6T_#E#txqsIp)%C}Sos%ylYh5sNu9XRZ}*}QQ$eV z`@`O;>#}O5NPW0@*5uf^>z(>l4^JOHyg@`kLFD$HqHBG-R(&bz{xWxea*n<3DY;~! zLi-~&#|=+Uzs<2v=T+|mMt{BYdv`1@T+jV-wueYWNK~X$-j08PO8jzDs`#Dnyb6t& zCH``iRM`U7!Zz0fc1eLVb}n4y;QGe=`Lfq9)%x~akZa926lVXt-MILYAG4RA zSf@JE{GW6-=p;EeoorvPv5tt@7GHF^Z0}P^?m=(%YN7|uxrVr z+cy-KYrCZS*KZ9eT~m9XdH#YQV%c+_9t!yr<56y)@x*BLUzyuk>mIO9+;sDe#1z*r z6=638{%%{OQ4q82&5jmJT}fjZlk9iKTi#Y{Bp;ry_G{;!xfh1n;cdl-q zCs*aZSNLAdd~M4g^;h?9$^I0(^OyOC@3F@}EjAruH958dveAL=VN7O>KfD}Yq#=mKERFZtp6&`XH7O89am%kia(1RGY$C3&4m4jdFHvxE&hO*%(qpx13v@2T zraL{(^XgeVZ}I)h+u58t+$Fd#``(K@`=e6g^}Bkj z*S7E88(qvl_b8{txc`bD`#k%$=hJVhckM2#bb7q%*51O?sm#(_rv>%>`ZoDE&;RXL z&bwTDXd}rUZ1+d@tm@{bDchLcG$ZXVYR;Q|0 ztLI;tKBr7z>L>XR_ZA&Zu2fziqqsHPRoyeUbM~7DA+@si_vF?-o^!%y-~Q@tlP0E^ z-aoDJC&}*n!u)BM?Z1>fFlTd%k9WA5D_0r0ec|#C{Gx|46(3Fv>5%%nH16UCzne03 z?IjcWgBRyihfHTRveNzE^XcFk3*Ggn&vxCBuXexn`pm}HzRR_HdBiT}tXuc-^5@LT zdy1M}o27pr3S_yiwEah7ZBjJ9tJSL;Ic|UWbvHwCe!{9*KYpH#IMwg%^(Ml2xdf+MMeE*cyPB@)@40#XNzbn%KQm9K zT4fsE$Yri$)Gd5ceRh?=!4+}OQ}kY6xF_1rF4CU4&*%H%KL?67@3%OnoLzd+cB0hY zDc|DyW|l3E10j%rTeS`#srY{vKJ6Kjs^D70YF$KiGHdYf=?^`Jskurcoy^*u3&=IJDS%o&B$8R&S>6 zP24bP>nF}tTkm{KmRVI>dE01fa>Uge%0*hbcXpgzz-7)XH_QC~=P-TGWuLfB9$sI? z`PTiu`6ci2cTa5(vV~@{_sJKAUoZOYvdpqYr($VR^5YhP6N`Jf1HAM0tG-KrFLv(9 z{hH}n3w(TLe!UmG@KR3sU-8cm-(PrZvN&wT(~N^g&m#Qa${sm#M5FkmNlvRxqRH2d zPxP)c|EsO!?RppyenQ@JnWw0fSl_YR)mx89-cA+f=HXcTC*^Vxt;&{ z&~d*?{yU4GhAq=y-^d=4A;?_3SNq|$wl2}=Umrw!GinY;oqrkm>+VL8RhJdxV!A~B zynA0@m>9ny_PlD~?Z+2Xe>pY$IrsPWVUrh5-?nZ!6nLrq)cJt+{~EVVKK6Xre`ns$ z1OL*0Y(0||+;?@R$e!wZT<@HOw^!K-%CgV*Tg$T5Xr?i4E5@SR%q=a4E#m3rN)&HMHq^#13pcZ%mM$G;-)q8~>Mj{H6- z%DVpYWuArcyN|}ohuyJFT-Vo8J5%w&)bAUQ*u*cFc%60q<=x^dHX_xV{SN(KKlRn> zdl9?p=RZq|pW|bc@0e>5?Z>FEz?9avPmxS6)iK zzH-sIQ$LS6u<3t_Jo!hU>fe_IHkI-HPZMti?s1=$n9{{$t`}e1xk~GIZu-XeiZa|P zZ3qCr@ouPWFEIa^Ljj za=L-7H?)2q;8!aDeC11rpZR}TBrZfUltZc=RK9-R(`*_WF(ZH#$4eKyB6 zwXD5j=S|h#2;M!vb3xcbu%wqBi+vqvcHJVxG)6ZOd0V{Zx1N z?&XQ!^0zv&)!e+ia+bmOhmYpWNI8C{QGVa@+c)}RU7KG!HI?hj-I`^u^G)Z?+_g%J zL}V{2emt`Hm!h!w?3&M;W4|sx5V~jT9o1L{+?=JJsQ8Rv*57+;epU6S(6#3}j3v)cb> zQpA|9ceir5-*dgzJ2Uud3&&KCA5Ys~?hoQ;xv>3ru;b>G#8V$7BD70quyDCIramrs z?4j1&a@h4nPRGUIOj-F;>5a3>kK3^BSI){ZZxX$A^NnBFbxCFM4O&YC@}DnNI;N8l zm0WvY`kqqKf%nfQH43kD=yBbev*Xk9PuD*b}Y5 zx=_TnVRhU6yhC3$yn8U`OXBydKis~(+3@P`+l^B-jf(%K8DC?F-{n$K+Zn*PW;b__ z!|{5qq8*AqBhr=~nBiyh=t)a4>p}sWL(zJob$pdK7;f$?IxY5X#T1i0D*g^9rB<>A zR9DP6-)aAwgWvp6nSRNvHMMJ9b}uuy`DOw4lb5zngaub$X<7F(vVUWtd)8aSbW^Po zKgE|D?W$eFYK}$nOLI$FZdaW2$qqj~Aa+PDpo}*8G^a zec>t-#bT)gNe_yiKihg^deQShX-~14<;_{a=FcS0Zk2kz5(Y3~2qEMlyG$#I6mrfufSh3w@zUrRNfseSt@ntA?wi-jEPIQ}g@azo}k@4Sb< zI}4Yxu-O$Ku~eS&o+qR=Z@)j|Vtyk&d-Yk@K1MuL6zKk_*mF`#|H~1bzq9;8S#+3w z>=Zb#?Lcr-;-wXzY!9?@-T3(PkNnc@UaCnyMVzhYDz~2~6L`5#vwbxO`~F*>R&7>1 zZ*K4+?|Ojjg}-^&God9(S@YU8Y~+MeWX*?V`7>RSN7^ zh!&=0TyGBIuz!E~WwCVU#fv+9HVf`<%ifgIlWX=32JzDI-3N2skE^n->bNCZ zcFywf$(=<4$uA22hd;Q<+;gVx+3AqSzL(xMZ49{FDZL=Mx#fM`kqfhO-kUs|{e9Vz z8wPRLIs=aAR&JZ&eQN%rE)lkAOy-Tbdp5sbbKlxPnsIw{(GoYaiHCP2^dDFj6D+XW zXPT$M%w;-9)>Is8HU0JENZAwR)t>r+J2Kh*`2S1vdfnH*_~#r~Z)NMDw^{4f7al#C z7g07{Ug0;};etfzbP3jW@ohVA+H4fsJHgs>!pb7)_vcH`B|ZGR{%xcgKL?}9Ui+T4 zUExVN>$d%5Qhxva@{Vp<=Vi;xg8t|n{$jMNU72gnza4+dGqev)f3s~ZN6d?p5A1|cTY&DKQwk=PNX3A5TaCLv&1I^=Kjh&Twj;v=U*H25jY;Jbh`cl<4WvBY=k~eC~>pq(w44B@)^HXK!^7|p} zo7I}bbK|FJD=DT$uT1tnw&6jqw5z-Ow6cxjJcYdTUN_eKC|>B*JjFzP=JU@s8z*?* zx6T*WX7axjc=7OL#tI3?d|SrZn)~Lbz4ia?D5;a?yN|(d9(QQ&@h^`h=5J1HI9Rc$ z^0L|3D1Nj*_!exF2nP7;{|s!4ma#SDlofU4s=ZiF9>cv_k<8z- zWukg#PpbPPG2`u?Pm*GhnHE=GulP}-zCrJ)X^+$2ZJaZ%WGv7ydJEuyiHg-Cd7S#dtXrgC#U|-!|O!m-S{Lk!K}IF?Uv7fE?rc9op$4-^P=gK z!VWI-Ir04Lh3C6NBn!6hiagy{xbdp+?nB?11WRpl4o#CYtl9qc`jI*8ip&ZVoVcDx zH?;S&G)|Oqn>=6L_dSOpS8cr55eGiI(B34y_cuC^L};Lnfqz`3{6sh%)Wf=`i~p$^N;#{Utu&|ZC2>6xf8N}+eXi| z7e4jlfzPwXNj~s;uv)OSvvOJK0>L#Oas7npe-4NGbgO_r`L` zw%)hOw;1K#2)v$krjyZeS?vxEy>!il-7C)Z%-P;)bXTq zoAa*aRYWSK`_DPovnnvBWY5pN_4eYMo`tTucx}QV6Va`lDS{pC9pZAj8Ezi4^?Ebw zZ?3rCP;Xw@{YP}E3se7W{+D-*8o$huDDSzGF2vjN>)1v!?^DLq}prF`CWF#)mA_Ee!o`EVsO>0pFe-^PH8vAh@%rZOx%9=%0(m@EnAi&o441! zYvofW!+3qCYlWuLJj@0HzDFFx0tEx>1K<5Pbi|ycn)73v+K-d(epj2$elo*#&8c9q z^mmeu{J+Xoc02sIK83%HTkw@+VzhT|;Y(-d&lh!f*d8qZyDfWfx_ZTr39K%HT0$G7 z>zB`xt8y~iE^K~Lpy|%u7fBrvv)_3-@wCjZ8(Q zZi$!INbdSC{8u54?QfXrn;)Uk56n(yXKO`$49~dbZ`1!ybjj`f^8$0Ps2$&tb@RbD z`SVlPZhrLrxsM`eUdZ&C&C8?bzS6CAu5l6F#bK)bH7r&2()GT$bw{>kv#)4=eky;> z`=mOn13C49y{}`ZU1i+7eE}207D4`Hhju7w#pbd3UH>}qmG$o23avlWm!6+v`A0Wl z&zavd-#9bcO}~3PA~slaLff5NjH(}wd^u>kLeX{4+B@r}pI`R%eCOY=>(YI4M^9^s z_XgNayfvXq=Rv1g!o95R53M7@%Wuit%-DT3c#HO)vP1J`&8T|6^Nn=Q%jct}=KE(ig<}+jAI$6AbKm@)A4{%Z`JO+;T-~WgGy31We!M@2 z!FsBkxpiXqp`#Kn`j}_1EKzel&D_2vj?KC|-1j=~ac!28&A&u*TJ;_o25h@q;q_T> zVyjiFw#4@PsTS#as~S2!ReZZxZuHve&HBx6%ZqO8=2zdA-p2mACuY{2Xr;|k@n>#5 zP4&_EA6jxv!q$D~zIJZsZF#Bj7WL~_o!j0qvo-z@^X|!t_ZirhHrr0ye&W4xhH3k^ z5&?lba_PZm$~1Og)0ratdbX4B?UJ7BI>uY)pVZ6ON_Bhm>2zfoQ%9me$0xw^waE<<`HP`7KM7cWi z0miyIwY%w)F^CP*9NZ{;MYrT=;O(v+7cz;s+f&|4tiMzS{5) z?DzLI?k}`+n^?Qj^?3KU&W0oBT(0wmy?vf`FmQ(W#1k*x$6Yabvv%IEllBuQtDijY z+snUXx>##$PIbio>cz50S55DpWcs8?&GOQYg$I2!d~dz@yXMDx_k@fiZ7DB06nJ;$ zY?%G?6~i5w9R?2D{d0DQnN9r}b$G$AS34iqN_3pB+}G8ZYFF{T?!Nw$kI`(mmgRny znjzs~{O0qX-Im$=YEEWt)LRp?XifE+XQyu43f}Q&^Z#15@MuTN$=2rloG`xa{ts*K z2bT7kO8zzc_2t)uEh%sR#k~2N>iv23GPNVS{y7~F_$}>oUGt`e$D!}sxdwOVI&C=Y z#pK+4=@Y}}CP&8a!3$&C6E5_8K2q3tV39`34tMEGlP~?BEhBRww}kQ8^i|Kiem!9` z)sc-_etYMpn^&YSmrYa6cU$A?v_;ae$^J*v&k0`-lz18cDi(|Du}o|I_)#`#nR3MY z6(6)1Urb*6bz#ur{1XTNPMv=LZ;sDfiKzd{$JkF#j^*N;rgZ(t_J=9KZ&ou29y?)m za_RPcr8~>oJ@0R5{M){IveB|Qz4CgO?Q>>)Heb8aCHjKK=F)(`u-Yw0CfVEacRUcA zarOBd+5Z{!o8Qd7B-?8d*V?N zYd))HJ4;af;t85Zt@S=?39a8?(#;@qBPBVkw9ay8v18*pCE2QVZ}znCpDKI(dGdki z?ugU(syt0p@(TTC{H;Fo=6A|`*_(#br!M+_=K7z!dJk=}RuKtzVQxO3iE`|(d2i-s zDBio|ThunqQ~0ARuT5e(`(OJf64QN?gzlU1SZqI&zSt^gLhC}Ww)K*qYkEsQ)I`pa ztXxye6{-Jr|K7O0#||A&ihu2;|9Xx5S+5K}>9glrHSA8PKia=zfpc2jrmwY{Uq4UK zZ8W~Ws!{pKHVdv|l|O}*rPoWZ>^;83Kj_2V`F;+Sb}5H?CNy%~Rc1(YD>B{uz@M#nN9{qLZ%7=zsG3Mo8wksPoPE4PZC9;1{ zrGjvIjh~~@g2epI$*vLXpB}xOTea1+_Vv0CW}mDNyjhU=Hg;8f2>W}MN%lKjk1Nbh zJ8^UKsi4#{tNb9luk6enlQ$|bsUBXEGRrsmcC6LiRbqR-1?<$j_V{gY$dpMNZQjjs z;bu;BomS&0_ruW4;2%!{-@ys%x%=KMz4lG#X`oZpADUJ1_JH*B$FDHR`_g`{k(@zfaniI^4LqY5k`)Rn8(7rb3UR>uZ@Eay_(5 z-`_cM*lf{;=M70BOTM(6zpz5VxBY>(XyLM;+|rwt^Zb9le)ctVPHo4{Wp%~N)uw;T z*4iC7-LYlPy`wrJt(UdUUif$vTAwM-pL94@woB;Y=L@HoUY>kae|qh7eu4FpE*tb} z*fQ?!EvpWaaI!mmE$YrW-S1C#zWQCZG&$>E1L z_mkx+I((f17xJS#H8^exr89e4y*qX8P{aP`pC3)Qet$}kb62_6d8V2c_M`nK-csvp zKOeK3G%NOlug%fh_Y^AkP3Qkz@mqcJTajIgNA^j1q;ZMuP}P3^dRx$zb-@k0cK9qh zvcOX6Pe9$&d%tI|maMA$KG(aOHGAuqu4jt1(_QXA@NfHiFa4a#)zaI4wfN@U{^V2UE zT)?jDy-^>ya&~Pl`LVnFbfDnWEKSza>0dsbd31BC_}A*9gnm7NT)CSj*{l4|dzibg zZumRD|MUKpw@Q0OZS6kYax5$Vw)JJk)V%+H_;1-2Dyt;k^#7E4@W=tp^_hzgue~rO z{qyr_;=B(Hqh@Ku*9U~oTxXd3?%daw$9~_Ue~G5Pt8>?lzqik9xo^!;@uc@sq1Vl> zI0w#n9J$zi{~g=UqJOg|IxVePWu*N0yX}vk5efEgNg{TBmkT#e{vEj9SHMzn`i%KX zhvvuXFMBPwLej?1ZVFOfF-Z8BYS>IE%?Lp59LeRfB1a$`PvNv3v4W`MarLDexIH^@p}FT zrMAmIeRoEk{p7IKSa184>u0ANeSCYFe;T*L>N9g^H9}KW7j`*Qa&19n*Wt~(hioD zdi|>3+P{ha&|NVtxRUi)ke_YHhu;$?EIc7!wZw5o^!KG2?`!vOYPxpe{Lv%kzDFz;oWelkfWSvSj=XXR_{zzMs=v#)UJKKmEyRTglhPNT$GpF2MDm!iYDT^6b_ znkU!P1^wJQ=T*v|s}?JtzEb`7SL&dhYGUcSnBdoWgM)rZ1S=ouKPPctXHH(g&5Q3pTHBhe*Xyn`d6+gydDC7u4%I}C zeYFz&Ygf-W|9bD$V)Z-Hj7ob1OheWz&elGodG~FWx7`=73Aw*q-#1@)()gf!QrEPZ z_Qu7LovlLt`>!3;{ z#eZJ3J>q7|w;k#)e+LFA@}BHwUR!s_c+={z8{Y5bUopqYFwMML#T>Er6VKnL#&2)C z-c>oStoJm>mhbse?~m%-|FkwlJzUS^A9c3=o=cJ1Qu!R|`Y)gV@+b2tRZsivSCR6o zT)A(B;}_4n$EtJsZfmnn`SPz+U%xlT|H)&vi_f!;TfF#T^#6X|;su+EV!fLV-wzJ= zTv%(}+ceMojnNL5r><_d@-?r!C{C6+RF-trQney|4`aYDMb+JV{-ueR3Rq^()?cv2fv(=Bv=yw~=p77-Qy5Ebht}^r4VC=o) zjPr`x>qj}GxvKoD{Lg$S+sjvfU2V(585Nd?lRrwNYfJST9QU8gbu(t|9T#)&>&vhA ziO$NIK4Icb@Jw`v3E8=GOi3m2=HqfM+todn&DY&r=2mh0*0uTmb9;0) z#F~7Yw3A1Bp4|%$)8}jWtNz~mXSa&mvfy<~epR?u$JFXsyA{myKiX!!fB4DXYtNS- zNA?%lN3)#&^XKMOf&b5^+RXS~_bK!AtoC2A9J~E>nd{ElJXJE-y4Kj~&4uG^3E|e4 zrbL~*efNXQy!6JmG4o6L(qngT{;;!AK(s>X)}y**FHQ%`9NxC&tzc%*p<{~@r5;q+ z{5TsdYW-@r^b9K>_f?8qnswF>CLGkW+LNC5OS^CP$In;io0dGUUi)p9;Pxy33%_x<8_h1goo|`93wr7|8xUtVeeJ>CHOSZ-9!d_bR>AzRso@m<7!7X+2 zbEu5S3^&{Mb-yLGwb=C~F3gM8)9do=+7Vu3bn?f-Wdc7Hvh99te)4?B-uKH{*8E&q zAo69AoBPDVGt9@?B^FP*>nfgFbIP@2yH5W5jZ?)`Wt&a%dl&GezsQaMwd#cV?{nV| zuDdlUxl?HG+dw~aOTJ^~1*_s8KAFEDjJO__;Am#I{n7)_Pa&9ECM|G zu3OHquo5j&cu{nu+ily*Un$4>LNaSUE|x3&yX59Kp4(kl4j%r>wp}zjP;y1tJAJ+L zESFMjG=Dh9Yh4rWxjOy!tUpJXT6Z7YVjNO8eX_XK4`B#){{LwInpyP~$uH`XjntLC$nJ`9?iY9%E!Qx!kZo>DReF5kns>q? zb9Y_lJEwQ&*O6xyUxTjB?Qyy08C`d7OIvJp$gzr9dcl^(TDmK8^SKQJ7SGzisCn+m zK`G1EQZFKx-^jnT@_+Yr-V>HH>eaUWvY(job|<^Ok)4k6m#douq(gRQy*SByB0T?1 zNZ-b)EnDs`%sKu#p*Eu7ax8z}8s;DSGPln)T5OO-_BSZl8a4R!GfOBb^#~+g(#4 z7XD6>V;1JQDSSVN{aD$9=hN2|%w{*@JG{OzYGGwO$2pOznHQP-|Xzk2j{8}miOo690SH#)M< zJM_l+;(RYj#@Ex@ip`6%dd2%)f1Udv@v(WcESF2w`HWqcCVBmp$z zfBVz;=+n~P#PsBO-b!pv?>333O}kL(9^NCC#c=m}=eDh~*YqO#x9qXpoiw%g&8sa* zmghHeb!ztJJ>7hG`T9>GJio=FYScud>yIsP=+PFHeCfF8$rA3G6MCx0uFvYb!O^i- z@Q<)x%gVTA)`iJ=e=4 zJ=6MUYlC=}w%nO(Rr=#foFV@T^|!y3R(G#imM5!gcf;t~+}TgsUaC)M+ZB04F{%D_ zmVaYf)~+MbxlFs%}ue$v`~VZ&|+l|5*18Iv>}qw%eT~kR~p^OSCaCDf^Ch|CAY*rbc*e_Bwdl z!qs!roLBluf!=qrx`K19o*z5(eW6Ov(WIK|kJ(Ma4c;zP+}tmBSos&GS>sHLVzdW*XNoDII zzkrUoT_xu~g|OtlH+uAVV*klKFQ>K?N110#_w$fj#bN#b>%H`_ko7fHN8Fmfr(9dU zH8}m=zao9->^E~GXMD4+E}3m-x_-v(+f5-;@0;xDzPoZx9f$Mt+h?8sKmBg?f4hL# zrO$6yPmlh4x@M02vDvfZEaS_rv3~u}fO_=E^P8n@^Vt~~;L$v2u$N&`up6M-qs^>A79BFbJ-sL ztzR`S`L6i7j$=LIi_c8%E_bO}RK*i_lw0Tn@2Mo`8|zjt{Jm+?DQhP=lew}y-ORsh zV&88ziD|!@7kA-U%?#g$O0!Piu*)lS1J}Qa(MSp`o7|;V_h|xSxqW!y%I%qsj2Ulj zk5%_Z>9RR2c42*A^QMwjNRab!p|iooRiWuKf2BRMJ5=N8bLpM+;qyG|6=lMXMyE;` z{f|YlPrLli}m1V(qy;vzwyCA%KX~JaOd;7JN-C%?IV}* zbuBQD@%EaVv7`KI%o6LWD}k?Gb~JxMQ`g~u zXWwg9_O|b;3SL&5)1qUas_;5$RcEUH@)vohz2b^zPD$?%eWRZDrXW(SH08(U8ouW< zRql7>f4N%r^uVj#-CxWO)okBBDeF{yT1i9jp2ixWitZ`*U32b%5n7w%hhKR+5kIAJnf(>|ghA(r(F9t@7eYinq^1R%Q6O zHr!jiXYopI%W(Gk44-Lhxl7+(_41K>xgzguK!HPffZd5k<0i!~$F1ZRM+XGEeA(mS zI@{&--Oe9o;s>={*I)8;;S1|wcegvyd*g=m^bPYLf4E&B{gm%d#|D{H<&;_0vnzY} zHB0aRu6xhqURJi{c+!&+rLs`1Ppr0XxynD@ot&7{5aJ`%w^gOf|1F>G)Mp$Uz6Kb) z;_VMgad@neaalXRBB|tvFeqF<*zdqQYwjmucY1OjekD) z-W9p)9>KD>Ri=&gaq_jN4UJO|&2sm((w$X*-luJ%Lnhz-`Aqx6!b>YR>3;a)(^AKG zamrbhO;^@=*Y7@9qNb8{^}M>I_A;Lv9IsbC^$%=Oo-}b+=+V5DcGpgC>S+;mR*2qv zY>!=fqr~~y7j?JZ{3&?%`dPmB77kyZ9u2RuHqh+awBY}g1F8HftdIO2`bNwRy)-X; zsra;Hqu-Ct6s2A|ywA_J@b04}Op)_m=YLx%Ail5s_r=>%-&XyP$!KKP7dMMfdpTKT z#iuDD(pN;bKF(jOe?4iV)$0oOwg3M7-NF=ScBRZ#PO|i?k>(HA3G6(}uk7Addt1qG z!d=&emDb6>Zwhr8{!~-2UHf%f99!qNdkL2pR<`W2c#&{;vE76T%~H=!d~!~AnpRV@ zeFn4iDitOo!s)n+>-eKIAI#fpOKj zwUfl&rSbIdsr8vsnUe1DpL6o6BZ?=a)%Ul)&GDZVwS9&i3*V#DPj_qWyu35|&=g*U zvy1fW9=WaAVO?Ifd>OZ|SM=!>wP*bdlMB|m-ToIkL3H1;;++qst3QdW{@8X@7Eo3|rfX788JMIXIVh1{mCsoQbUA?Z;{SViDJ>2>-K!wxRm*!l1G zPDy^#Y#*m}@+mj}c;ETb?eDLtIwkpf4A0`_IsOv0<{a;C^zFP9oOkeJ|p_MF#8QhL+0@J7ek9yH$%bVuz@YurXVn}iF*IW6O9{%|} z5u1Y5cz11m{^z}EZs)hKrPJmW{zt3(byjO-G_f-<*l;m0DB!94gHu!U2v+=4Us_+` zW^SwBEIB22jj_s2zsN-^`Gk&5tG(ZAGRLFkV2ar39uc?67dPr#PTniw6_PS@lXmo{ zNpCI{nItbUQBA*hZ~tT4@9od4-n~CxYFknsZp~RZ#e#uBi0_-(JO+kep^QBmPr~iI z`4bozSPII&ZDVbyS{T6b=k)$R_JXpqwcp>}jXy0fb#2Gj(@QzF{bN~wqkzd!#g1n~ zH$SKP!pNy{6B!hY-X|o#^wo;z-{CmZT*UXk+usv+8=g7|pI*GrxA$F8lEA6(rM>b~ z*FElhdgTgZXUJ8_PiM^L8cyC6P_mc%X7}G6Th{-`uFv0e(R=PzS;oqRl4(aJ>V5=# z68Kqq`&D5_j>tpvK)cCVb9D~Z?D72b;*`k00Gk<)-|U}J$vpGn(Ob7@9iNklh}sACezwz} z*Q#Y_oO`iBe)~b;v+u8nov~$*-7#bLt|(D4HS>R$R!h}sPICOt#eTAwo&Dp43Hr;v zZ8@?f$~G?8?&yaKJ7-OfvRj;Sxmg0y4b7YMBCHahsD+&INo*|tc1i8({$%429lO;` z>`Ug{c;B(w{>+}u=gj%lH|9I!{<#$+dEvpVBNG)_f_x`Gp8j1+OHDf4!N9P;`^LkG zt`ln)M<*@V++N1I-Tq(S<|UrGdh(akoKu|De|rUH$mUI7rr6Y)!}Ivu@xM=+Unzb_ z`cwD9bW2ZS>51j#vOi^`#Mjil&ttG~(^)2#cx11c&x^lYGEXlGPW`iJGs~hEEXzDZ z<4@1HbSElKI$8I-FU?ZH}Hr7TnhYt$H_A z`$`v!#Q&Xm;pXDTVjaJ4Z$g&yC&&c6xFD4Blkr`l!iG9`#=?b{g+*E7%p)A@^7lDS zmS0qB_B8e1mLf?-^&V{oHjig6-pM$CbBMf8YFT?T3yRCBpL} zs)Wv~KKE5l{j)Z9$GZ1v7AfIkS3=msgLP-eE!*g9u#a>7>kxLKN_*L`T2E)g_H)j5 zKif(ls2}+2{?%ZGrue40jBQ~ZW|=twELEACXSb~4e=B7nDA>TUmVG{x=wi%;z45P4((d;IpXnj ztLc-MpnqDtQ^yX7*_RX6fHX$ZF^7*!|&J!dceY01|Pc7`6@1A}0oZrSLOXfwyYM;{Ao&CF}>r$fP<`dJrSCy5q zCpvsTF!hUEwx7(!ZM(HIKAxEIa;u7g>Mjju$L=ySBZc>K7XIF|JlV%c>1lJN!WcB3^>VFym0*-|%er|yaszp@JUWkzk9da*L&duQ#DL+z64kN5tr ztXp zoOgN6ZF$kBF_Kb3(S`R#bNqk&Zv{fuQQlc7hZXfT}BX5$QddzxzMss%`!=kUZ zHPXHuh=^CU*^nThY0bF$k&pKt{|!q;nYb85N)6bSNY0gYi@GjWX8&1P*rrI(h)Gtm zFZR;x{#LGCeG1zmc}p!G{ESf7KeR(dN!|HSyv6DpH~Sv zpWB!-l$X{W<$T7PqV;9XbG|uRCHJ{=ilYMxdpSz4uYI%Wlw|#am{RW9Dl>PyU+qxC znco~N7@4L2AJ5oueEqg%I#Px~(LVw|C7%8<$8h4AiKmyl zZ`XAAaQ}zTq(_&M)_z}Kd%OBZ?bDR2 zpRHB|3A(Y_`n5bW{>JAmZYDb+^iIQJyUeruFR#3EL2LTiP|bEn-7a_E-`(XIE<00Y z=CjV9esIgmGd5m3#7!G--2A{G5?=Nq`f!Yvt8Vcc_G0$wi`EOC*}dW1I*anif5i#H zpZ~hH3{}@A_mOmE=C45%7(3o=C#K{r)8zO1EZiIu!d;AGKe9BY)<+ zbWa9`M}9c_^`PE;d~tGWUS@Fyq3ZqYp7N03``h)U9IApDU%CbgzVy)N>}c>1&h*m1 zR4wk&RI+rHf~=CS$jiMRPJ#lOj#d17r(Y1}c*1zU_}uTg)%D-|ejk@Ew{bfrRsG)d z`mF48KWC<{&H40i=QJ%-R&G`Xh6Q2Ozn-u%I5aRbaNM6H7;AHpYqBCELkGio(=Su> z^STcth>K4@bm-7buM-w7dZ${Vp9y|HxM=a;@}s|>Wd%C#4(i|h^ikL;pF5vi92jgG zc=;zBX7>5Wz#%uGmHog+1`)Z2{XcXVKIAgg@G;0U9f)T7(8XYLoz*gdoxy>T!GnQ; zk6{V}LnMQP3`NL=C8#fq2rZfNhfAoP9uXTg02tzB2!b64%&IKym6GYiN zni&-I7{r4cR;oD!^C=wXe~`|+Au#q5bJ@Ch_rgNO*4BqzU9G=t z{MFieikCO(?%i^A^_S*m>$dRh*jGH4`>1M40OSBAL7_8nZ2iNz1X`*yz$IQS*=!>+rvyv}-4 z(|eL8@dVjy5t3nuvXR@rZ?kpFEO&+Weag3ly|NbVU(#MzBQ22h_)%U;-mlR4n)mMyi)zf|3?e_V9>#I4}d?~1OTKdXQH z^_=Ot(=ViI^X$qI-J&1Oz5VnxTaJR4X&E-y{b_;exyGM1{k5*S+1C@l zZL{^o=BhOD&x}{*X}sEd^2Vtc&WH(GwcH1#)tn#v_M7znW#4wqnUkg*$y2kFn7S(9 z@6vOyW}Hfem!6A@?L+y z{($)=&y=(Gl=tm(OyIt-bmG?->GwuKkyvRc{0Xo!Cp~InaD31KSM8`I?q^g^K)L$l3y{h?eQ}%%of>x&12ubox%I$ z5~d0)zmQ&%(QCAf!<$w3{IA8bE~j+ddaE=aF7RCQE91zitM{%X*w`_>obf-)s43hr zZ0cmzAD!WI%8J(f)_XQ}&y&Lu*Zgm~H@$eXTXo<4xh+-o-t&5verH&n9nUYh{H;db zlqNk8zje%1F=VfJF(1qP2U$5_wpQ9tbB=-SD@>9n1#5l1Kg zrI`;dhyR`!`cr57+u6&P&XQ37XyO09@b8XQchCJjb!p`%n>EYBSk?;adQLIi-h79D zDOWf1;hMIM54L1?h?TJ)>%4a9THvO=I+~ofs-HOM$GN{a*cVq&(Xd*M+nRGqtWi#= zRzuf?5TTsu$7@%ME1FMfcu@Y!LT&c1;M-D@x37NL7U8_V{I`)h=cMMGmv7t`?>xW7 zz>;(Jq;lK5usZ!e75|T#Ti3F`pZ@yFodlJix7{NSgDmG7AcW}9bC?=RHe z|LSpXf=RK;nqyZt&c4-G;4Sa`<@v46@)`PvAFdHNr^{cY(A_Lsn_#f&!nrF4>+Xi| zrSk=vtQW_Qi@c#?CVWY2M~)vc9N_2WWB<}cfOv!ukOv+ru) zd1_@u*1bo;@;;Y-x(Ej5w&!<$TeggS?Yz{yU5v(8&L}QoKXF=TO{%&#UlCWyv)J7$ z%O4!?_^tWxjmHhaRZgiLg?Zm4IUY}$vY5f>|HR_2G9UBI?)11_SDq|yCoiZOyYcLG z&VU_rBUbjT+}Tzkxhmbkamm#)!Rs`aOn)Eu)oW$BYs8B=wqeVpq*EX55#+sZqS5fv zX-2`Wn#_!km#q`F?&B}K?-aqmd|zkn{0o=AOu4YpxzFaK;NN$jr1Gqm9QJ58cMWE9 ze0gs5QTMo449k9B;}&$wZR=%k>G&j5SbcX!?UQpK-1|ZmUf-2ld?M>q=|TBr+p8^$ z+7B1*Uu;%)bx!>Qo`c2gt|za#$*JYPI-NT&WFLRMKeJS2Xq?LHEtmIAsky&;otu5Z zwW1Zd z%IA&FC$)a${C}g%Rdn=0WZ@>y9*uQ|*F@{tneN`!y?bZ*l=dj0Nq-^))ZH47e^PW1 z{(bCtjvu4H#U!IvnRBf|O!v5&n{Tapcd^oxf!FKn&wZ`Wvellg-1Pk5o*4O$H{R{t z|2DAdOLwLDmxCt`m#uj$?W%kD>)#u9_d8!ay=Ld;Tp@{ikKMA%?o7POY&ZQ>Okw-x zS2O+AR?Y5U-+16(>23Sysq$Ajw04$oKYDRyN!G+2vv*94Kf`UgM`730-t}xD?bqje zZwOv~ZNZO|a#s#?t#7PndI?Jt)e&hgw*?8&xMw-Ij^!5tGV?s^_g#T z=B?omJfc#7ij%56x-~d?jHL78?U^du-(K2wG@ls zqFUDX=RCQiRWu&&yeINS%gXa%PN|RLJMNsNuhh!jqKu`2PE5#Iv3j>W-%HDV^;3j- z*F`J!KYMsH!i~Sp@ZU?DwM#ZLI}~QUDbb#9@;!f_hn&t%yWc9_@1DH*r}*xC=AK{; z!(R=%FW>v~ZD!2D^xqpA=2R$4bKMO$_xIj)gH5L8pp(D@!$sxq3{87fBiAkw{rzv^ zDNhB{EJ<6PYgQrAXUlti<_e!L?$9nf9sO~Fjn#em*|N{oq!?D4i>}LA_9D4{Z}p;F z<8o%TXVbOkNLksCUOLcm_G!04c;(sS0So<41O%?(yZ#_@*PAt6 zH?=Iz?cc4C#q<7FQ<3sNy=SRGB45vIOw+l0_r1q4uk8;bL%miUNl&_4YT0*gy57G< z6O+}Rh;HP6XEy6fgq-B%nYO*xuATdFdSd9(qAi^-6^u;9bS!77t}F0rlsIcrme zUry2Aq;=Q8#A9K+=Z~eIv>i2`p9%eZ_MO=~@y!Xh`!^&M3VzeyTfh}JQ&{HU@AT?& z_oSb1H6NPP8+YqmN;Ii|E&ZD>#$57q-VKo>rkd6F>o)EG|1a?M1O7PIPCM0&>(2K2 z*v$#i+Wspm&1J&tyG_ppYc{$|K9lpFCSrdW!e0frFhMmFHU6l%pk1wvd_?q#`#@99cjQ<-A$}i0N`!lGbpz>n*Z*_i|O<}vs za;nO{>9hoA{`Rff<;E~KOYE-nyvVT1BeK%$r*_?VcT4ZzJ13n-jcU)58Qv9Vo`3sW zyl%!V+u3#8Yqb01&n|zqW?E`x^w*}6+iZ&u$={lOc!JF5xXQ@bdV7y>w=*^`Zl{~h z&WLV#yz}yJj_v-wi@D3WUe-N?b@wA1~gX zzBl95bk*1wuNeDpbVfStmgHGN(MR@PWX{n)+wy+f{)w*zBc+U1@lD-%tD@-F z%}hVjk~tzi{)OJJZ~1=X{&sBMqXaowVb3{pD!SHQ-WT1#wDh#cp|sQ+#geDxE}S-R zvY$0$;o%)icF$O=q;bP+mCNhw1M_`D&-`7V7{<2b;_;`yDoYo9Iq~Mn44bmw$2YGx z&{9}<(qZBIiLDWh>)aEj=Kc=Uu_!*_9g^}}YKC9EmNC!N{U7D*E>2|oJTZO!_FpG| z9pu}tuySeUjo06LcK1#!S)Z6!A0H6#X^Z~;XWsl*c5M8$Fs1NB^;_Y{ERnx4Rf^x_ z*4xHRoAr5LTP35J1CQ>F*V}p8W_CZet&HYT3C}_nxAy^1`KIv)XIxpuvY|8Mr$?EjlxrvjK_UL2P<-=v&#?XmT3 z{pUP^Cx3ZQsuX8^7kg&jH3ioRAC^yxYWu7|-G5%a($`;y3hvd5&k*5j3}(^fac~Vi z?C5i*U4ZHDq?KAvP(q{{_Z;GSPKmb9E+p#&}=8mJ(?Eecz>^ zj}30xLN3BvX3amy@c)P;llGF?-Zw+!3@vMee@lj65K-GN?r-Cv@=j;@L60-$vsEvs zwe&`xn!KOW&gIq)$>|G97hQ-uyy(SVTm3H&lbId_pT2ZI@@chfN~8&A%Zuv03|DfL zUmW}H^7`lzA+HzL_I>OYSXi<5;Ulrx4)4Q)eE*4^44I#Lv8Au^SeN;hgpbk5e3xwZ zYpTDx>-#7*TJmYtk!QCg!Y<5uw0zbc-Lk99uFG=2=s#Riz;tfiku4s}&#GE&i1s_K z{K3jFV%_rjzvkV{S#at4{hLo>W;D*o{;>Sfa+~h{|65<_yk-4$XRFpl&8tfqSvAAo zO)x*Yobzmp{OY&ayW~!qSB5N~dy#j|!lUVxey^IXR+qo<)1DUkF^cEg7xT}j_q-1& ztXzJ^a9v`+U}t_2Gj4=L`S(>TA{AYSx+ifIi99xpVhIQfk3D#1 zz4>d!8uQ$0aX4#8jbujt?~otI&#Vgn{+*er>Cc;VxdO4x{LNPio@BhRGH%RD^w=s8 zf6V1}fBxk7=RvQWEdFlm-uv2xd-C+YPu20_HKqGL2pu|>J!k2{XE$|^Zom9ZuJS;v ztYpLChwtZ08vcE>jiG4SHiP0z?aRG;KZ)!AX&6O~U;<`!3pY3(T^{lC}=R}zHui2^>dSvgfroFzO zb~kRGxhzfp@k9=-TAiqZ{B^Gi|IJP}K4r4v+{_7kV}&B7YX7p`_HLQQ@sBm!FQd;b z5TCpMRs7<*HeOxXm}mCy6s=BNaDKgLZ+@xho&S*@h5x-3m&Q7A{CCU=t7-S^+LOT9 z7qouU=T~1RvvnWmlHcXP(=5<`c|zXZexnXQ1|oE)Tu|E=cKy{ zu;20OsC&riZn^cvw2VLdN-i35$9yT-rXL@E_hzWq(@d#Lm)0cC+uzUr`O{H>hzaMv zUVrYr(Y~`u{#&C)pxpi&eRmhn@;VcL_GMbe{gk~6dF#tncI)3;w|v$)#k_s$2f1?+ zc`FKYW!E@n#Yg_KSS9d#gZ9IvDM!T_d(KS0)g>Ul;>_f!xib$QEBef@)j8A1efz(* z`29C(GG`ZwDqYIcJ9pZ)@#}%~SJ97!muMeKlQGcNnkQnG%>2zmr&;m%r+Hu2m{bH^ zVD07GbnBgh--LTt*3>-GicZPBSn0jtmC@QY>K>Cncq@HzN$}de>(%X(KMs2zt`=Ok zrG1IlhpSaEma*;yaeT)oza4 zv&lL8&jlyV8*OeWdX-|Ceod?9+U{ME#1d<8f7ySgPj;twaBr23Hmts{wJy5lL-#E4 zWe+d2Z`!EtbySMK_o(03?`N+bJ+R@d8lT%-pH`t9Q==1$_Z44yE8u-s=j8hP-PcPt z9OO_tDJicR8yeInn0I#GEJ5q4dAD`Ge)=I=a`KrUd)_ zZAzfV|Dcvh1%6r4EWh6Db?W>2-F#1Y%cF#S|5F{8v@>!}a89i+I22S|r&4oX$aXJd z|MRncl6f<)m!v(o>!ugI?w)W_$C5eRHYuB}BcB}()iGjj{jKRT;qNCFvg;=m? zDH@A3y=QM)7Cv1jaYgmw#^st5eQhT%PP_2+xr}u*H&69uFUk35o@I$o6)#w0(v)^y zFZ-LK)|J~!o#rm>cZY1R32@l_KD=94 z^zgl%&;Ree_wo1tZTBhZ0V)h)*l}Rbjq)N zbo$pVD|J@GBc3TW1z(pQpRq&M#eSEC(!G3>UZ(%sMc)cN6W(PLp)=_Xi%4>B$-~T8 z%c)8JeK9waE%>)Cls~^#f!$lj*orASYpYaJz4EcJtmjOB8NHl$DEcg%Gfh;dgEdZc z`Rp{gMydGB*}=Eh%jx?bUS0o-lhIsKkm0x4^oZq)(-%}uFQkj&2{V% zMHvph>t1O7Jr@7w(pnj=n(pVhca*G(CBi%B{l1fHdi5-i$))$U=l81f>dkmNhet#5 z=+8rsq$j*-oMr94r)|sZP~UWkiUf%xN9&)iDDi)_JLvHKTW{`5hm`oM-Tf#tkN^4M zCAXe*zDrgq641L}uCZX-ncb3&8`=wHrR%ShpI5Q%>9sjKX{}bQirVzAL74%`ig(#_ zxI7MT^Zan7o%&Vd&-pGoNej){@gTwmwoYF`(@8nb0lVD{k$Op#4&ujj1GR%RCUK3Dp4X3*rQ@H<;N zat(_;-v0`2x%Td#nD?YRGnRamuj(l23+mr-^oZ7!Fwxh$KO3#mn^t!xW3M60H!oGM z@W2k6Pw}P#8B@a!|6aWFT*=yX&mX>;n)`|IhnCQ8zL**LZ|D2Y%+=cPZ}a+yLx%a+ z@6_))De!n{?;=xKp}ME1%aqIAw{sr6#v9su`HPx;)jAF)zs^YoPyd{@J{BHx{eH}e z-&fz?|M`8Fns(r&QS>i(>v42B6|Qg~;{XZxC*FCs70niJIrm$A>DL~s$YpC5 ztq3owJ5h67?8>z%zxLnR?AGpPcx{se3(FH}fdk@M`TqHr&P++zKF4BG!Sw?|Gqs$) z&A5MAQ|iQ#!eheHXToKl_a1s%H|M=Vu#n!GwGE*^RbI24@qN9#`qc+x2|1}L@pC5s z3;lL9>#p;R(}_8S%@uW;DFVsC^|Dn0!J>05R!8l4cg2iz*G8tz>5`wqI*cMDgyIWN ze!Q;#CnmyJQ!;y=OOxnxddw_I^uZ zUOTJtk|dA0we(BQuDj*GeK^u$r=~PtpK5+DQ-pQ%bD!-z)6Dm84=e7uVfY}|uCA-% zUtrNo53~Hfv}YGvc3#hXYh0AUH&4&}z_aSS2D9t7J+}OM} z)xtj_ofe;3j-2o4-qv?{b!0$Dxw`**4vomSd~XxQeFAyZ&%1oLno;~y>-9m?>Z9vE zEn9x~z%EV4b8F5|G3a}jag+7@`=b0`G5!Zr9sdh>KRLGSU`xjjVV0h^eCJm#GTgp0 zVa`XjFMs^jOn!e*Y_8{$=WEupsJ`QWJF#K8fVIekYL=->`6jQOx3gL=?s2N{TC16< zng_O7^vp9oAkI@G{4o2`ET3KcUW{GL^|O3qdKKL3*IfMnX3Df}e>Ls(bQeEmo_10> z^izoQb=SPKLzRC{UJUTEuf1`}+gS2lN@z*p_xXO8FHfpF>~GHVfR8;^D|cPrg=x1t zS+$$zaorWX{B7^yRKwdUe`d`-u6+6~v!<(j_8OVEzmh&(62?b*{?%PL6}!sr_tR}Z zHf885KU@C!kELtnJbNv~d9Gkiwq5$UvwNeJ-``jfwrzik(TQ8R zrAwYIeb)H2uVlCO=XcpZWMUu0=X;yqjEp_0Up!^GNQGEh(YD5w*}YGLo!6_X&6zCc zdH4Abg}>JvX1>t<#L4z|#=YL#kzGQpnPrX|9H%?dv9!dcm6;7nAg+>!Q?x+Nzvcu~p{ZXDz9k74d2B z!8`M;UQgd|da!iEx-GH+Rc~!H$HBw+kdjXII1d8(xqbF&AW`o%vFC&Zn^wy zJ#4Q#&2D|{-&-aj4+FN``f(#B_iyQ)|H}?}?_QvnThtcQxc2Jfqv@>|_BTKH_*pVA z;n2JF+-Iy@-vk&KH>bbiuAcV&*#94Wu-n-GB9O zxWm0j`2L27i_i9c^Y?$x?Zcn7 z@8s$I(ayUbG<(Z`>%5h+(p&#CZ_hsb&-3=z(A{??T7Ul+|KQz;Gw-s^0uG$^y0}!{ z-t7Lnt2)VVuU*-4_U+cGe6bM<9;#7Sg_#o$B+gkY6lPtibe(zYi z}I{=@USm3dG0!|m`}p zWmB=yuva_v_gC&+wk-+Y-^xT5QfO67#=AM;y}rS<#oSyf{E z^S|5?v;RyJQ&jRpShzpX}i_Dzv3O%|Amj_+5MM2Vk|jbq3kF7 z5kt|5uBG|k{CEHKw_c=|J8k*aGhgiA`21tNV&-46Uo7#qP}*|KtDo`@&fgbt>Dr&Z z#bReO4O3L}SrX61U;O4!5Vo1go?*_aTK+-~)u}vIL1zvIHwtW5dvoaBo!vUhP1l}$ zI@$cke##VW_a_bt;?Bkoe@0Jp{y+7CQfBZ)j?|+YSeSUSFxKbtCl7l{)8($>7 zyF9ma8RzmB0&i143&%vdAFy0FQQC6D@;}@Ygs)zx-;)xt-i!a(-8r!tmv! z+kblB!u5X4+RGeW%k6u=MC7zxl(}{I+V&4u^o5@MGk2{y<8vhU#EX6J#^(q!ss@D67NnY%`Q=8c!7rVj5 zC+}p<6AQ2SO}k3J-@duA{OOkLJ(X%yia%tH!}0^DX4U*~9OP_9*vB=R4Xr zSru}*+xWG5ZT)ESxUh3u^^+CbE*d{yR`^`%TXXVJ(?!DfOz!x-{GfY(?S>nIsllOF z6!i)p=ytd?OMY7W`RJvenmfBx*QJE0c%<`I`dAm~Y`T4Kqvg*y!&I$KebiwZFl9Z(iAKliyQkFTHK6Tlro4@z1mfTZ&FugIp>#8ZBumbFrEGJv|xTDSF~qb zoB6J?D6^e&jpgS%9En--xpiCHCCi2N%MH1|IX(UUGjf^4Ugg&x7KZyza_#Su;b)T; zKj3X#Db-@{&N}h&Yn{qC@jZ+;9@ngte{{n*>-ru`r>t{%r>?JW)L!xaJm=&$nib}= zI9|QEb@6;_v^`(wkv;awQx_;df6>tBD)z~5or3qXqD!3#MV#xFrB45M+F2`JzICZg}d%_XZ7Z|KR-T9y8# zXK zejlV~JoFVfswo!YpOCTgl@-4Z^WM2N#j=`A)6#$cZeCL^+-hffshS?=Z3o4lz@ z{-}#=+$ns}G06U*2e$&xe7y(k3R}C>Yi{nmwQ;J;hBtRzW_fqd`+fJF$E(vjJ9ip} z%}SZKefuxrMb!-Q&t*P($&|OnbZ53*^KS`#c82>Zo7@G~(?2!y3(m4`G2=*KS@G)5 zPwAHT_iJlk?&-gHv&LlKv!eK|&tLcKTQl*?s-!w*`xe{RMefV<VwiTro<|M5>W+2PQo`sDWKW``eN&gJkN{Q0`*)bFCw8)`|Q7H@=af+|NJ+2&Z~uZGt{pREnR)S8XIDvn(%X4B&@=j~XqExT&< zlt0e@9>^V-Ya#sS&j$0(R~8T0x-WUpTDkrCAIb71D^lO8ZmMUwzrU{gn`Q^E+?szu z8@Q)!I?y`B=7CSZv|Ss0q|S%!`nBbg(L0S@jbGS8*JkK0m+e2YvpUp&)9_d z+`Rp>@ScmtDmLeDFC%Ap7HM^s_f9ohSDgF3UZ$Aa_SuAkWvnjWH`+1OTH7yM^=U1? z_Qti9FRk`TN!GuRv0Ym6_svGZ@9}?XugtmZd;gp3!%pL!AM5NZ1O9#P3EH*GVUuX| zXMTN-vPGQPOXLk$UKqZeG*4;TI?ILr_fMUk@ZJ8M`OA%|M_Uf0YwU^az9oCQvvtA8 z=&%D4huy1_NsuGHsuNhu@>K4D^PvxVS z327^o5;fxvm~AYs5Gt8H`{v|#8lTqYPj<2iHTzUHKXQg^S|4+y_Xj&qy$kblg7!6C z>26bda_eJO+J=>{O4O$>HF@c|xFT}dx5ozz8IL3v3sgF4gx)`^>2uTTirUh@8_h4) zzV;AW^mAY2dyeK^(VIeJ-foaifAL8_so`?cuPA1pXAV*R2KmccrTX(E)5MfET>3jr zxrf!k>Qi@dRHC4{e-C)e$qIp;HTi(_3@tXOY3BlIJdWE`2?skXOqw zrMmau#y8)4_$;!OD*pbN<;i=^I^f-`*>@%!IkK%aJ)<}Kr&EfXJm>Ge^I87fD{k)g zZ_AuN{g?QRKRs5{Ha%Z0{nGl5M|r(_QN_I7p#BghCVCP@s$_0=z8(h??vDW zj+?z=w-Y!uTw|)IyfutC;1|KH+htr9IxXL&p-(3RuibPeEFU4<}?=5|mlJ|2{^v{-yav~ePm47Ol`CQCE=8h6?O_OM#a<6sgrw|YE^|#l_+*|VI zPRs3Z-JKJ}iY~EN`rPG{N$%KSt(MxCKRw$sT6B}~d=(|N*Y(C?HkpZPUsz`EHEo~$ zPF_E&?0P`dLh&gThtE7er*x@em8-~u2mwxA4=y><Gw?%i{3A7ykJ_@j7H`++U72d<u*n96gN!OTu}G&Z-w#kKOf(Oy{>je84qS}E zTTI+F&eZxS&u;H=)%_8|<6Aht_}=QijbJa87qHa(($XI%X7B!0JcIN7x#V8=SA$9MIOd<#X=Pl=RWVm6(btTOL-X8qE; zITtrtE&QD}Wm1sk(b8jny+F z*UPQs!8Qd+fg9hChb-PE^jag+?)*{F!$%5Pp6&MYzGA=hg0)MYq<5vh&MfF&cDCmqmdeXiFJY}6A!b}n9K2Y-5I z*?g7`Kgm6o^NVb_#Lg+}E}L?>^xXX3j(`siug)Y2Y?=0~_~d%w_nKb*E?&v|RQ-%H z*6tID`I`DaSbmRSd0Ek!P0X7QEU0gNTT&T(d0&Ml&&q?|e;?dVd70UL^6u;XS97lR zbgO1{#aC^FQn$d+^h{9g+`ORd-FbzOd!lvOd%G@dpg< zn4j6Iux3wcz1bw^?IsfW@(f8tTm@_H{+gwyaP`X@BICB zb-w(rtrz36m1Gs~O;#-DTlZY(q00nO*7X}!Gr3Nam$(_N^UB@-r3cdAUzAH+@^6mpz2@()ZBpl7)UdH#wk_7L{_`>DmZlrSm4xdiPp5l?W#lHm2RhOUU_Q<}`cd%x@^A^?cU&i*;OZVC&i$9Jz_C0m>`GQ47TP7Mm zb}X`Azw%x8#=j{Q^GpvkcdNI)zAX6i&D-TC{AGo3=?S`;grUd^Pxyxerp8m2h)|_3=Gpq2F!`;X0Zawvx zdHMQ3QDx1;e%-J6r#iX5UBJM;-|(8$_Q=>-``?u-ZuhCmShRajb5N6(`Yj((t)rix z%l6%y>gxCYl0)^cg$3Uvxw)fix{ah)DSwTb9>Q3qumA7w%_Idw_BA_&H}*{`bbb*P zF`;N%_o@vdiFf`@+8h00a`JDN)eDx1A9CA&&}DDxo|`OP{`Oxc%+T34|AO_*EA?-6 zdbqB5noa8pu-#NPr6E$3<+RNW*09z&Z?z)Wwia%D8qT&^=#A6zWMv1zDa8}3*{5^u zZtL$2_~38#wnma6W5%DH^ODcs9NYVDql|0a-@Cf10$-Lg2(G&x_C-{hH&s?n%JjI8 z>y5QjrX@)m7<2_bnvrnr@eiTQKD!?}JLOy#%4&T-+4pCkYcN-eH_x1lYd0J3Db!Zl zC$MEs-G(Rfisi~piysxYKa=<0R=X&AkJ53|XDvIN!zUg3acA?@t*vR7mCJ+ww{vT= zYOS$-9=Z2`jnf;cD^>4b)~Pe9zrFwRsNeqR@b>02a#zFbM5n#Ad1UAQYH5&xyG?#U}!PRp&HM_0?tP_U}1(eva9uz^ntm{>;B0c`?b6 zSKxb0j4-R6vfHZt&T5vI3iP)B5;l>@*N91P-MlQjPH47y#O=LD9Gm_&IhgL;qO&`8 zGJ9&G>E;!T9$%g}{jPuUgs+%CJ&moSUi6Co@!Ms0HZa?p@$qZDk2hdhoA~+T+b_0+Tf>&{s||8$|%uGr|r+xGdlnyvXG!r$fT2%dX)#C?5asIa21rO@AhM%Q0X zez;aF@QcW$yOYD)O^&5aofpE-Jo%Z7YrtA(k%a0?n)>T^iJZ7DSpVWX*ifrz|Pv9-+TQ)>PoXIe?Hu=z5O?Seboc;kIzHdcGTwf$Z2ro z+~t0~;9$7y;+3z{e_kvuuKDq~HtJk(Ze5;-I+xL|D|f&4HZ=I#IVLS~-r{m9;^?lw za=(sQWxO}Jw|2kC-p`S-JQwSNrUX~VEZ;Hzmu!3SkD#V|o{L1B_pHr~Z~n&Rc|mM` z?n&uZ=_}c(SC!n)Kk@$kbfKEOJD<U+CB;SyBC8QehFZ_v|@)_Pw9dxc<&>&c^;Z8`d<;i}8tmRd}z= zk;5$hz{;}K@<~U3e^~!-a-7=LU-h3qoj!hBuJ-MTmdeSU>+T99oR1d@JG_x^`^M_o z>#xuAXZn1!vX1x0rfJXK1~lZ(c)xd9AouJKJ5B3m|9c|2>YxAYoBndoy=FbG{K#jL z`PDXWU*(E}Yjn=}-KkGRBUCus-|8L~aM;p!T0@FU_u0FM4eRG+~Z7uPD z)yE<-AAhyYn=kNn+qqL^Q&SWSCrmE&D>ra_I_qbq=jOyo$Lw~lnQT!a;^wOL@8gaG z(_cStnrLJ&<+6Hf>xHdR>Oqn-6E0XBOABg}P0~`gH{jKKx}Py+>zarwnzg(BbLnfd zWpC?Wn|5r!-KK|ME(Sd?nus0ELk@+en^`frHb{A?&9&rmBMV;oHc=z4K z?KTE>N7kwDzbqbLWhazSGjCz4O}U`{-cPG%DM-)%bbqO1!#Vl9tdlb9pTxgn@oxC| zqV2+N)i|%p^`$1Bt8OfA%-FdueQwU~jIT9w!j0B(&K8+l)zg1==K1~Vk#&|G+m8nH zuDtx_bkQ=whj+8XG&cX9!szj{eZ3Y-bo%(bL6#m#NF4{ zcd9Yp=Usa_)g|$t4Zn7T_Z!U<2FiXbX)&0l=wqTTi#tBh|< z3chC`Q`eL6=WpQZ;-Jc-5uYFOo%~~Yq+pu=-qgOn`DzQ*HdgFlyjJ|~!t9*64iBC$ zm~E`Nr<_@@N=td(!}{OZ+D@TvGE2+CqqS3KI5|wtPQQQjLFePxgHMn8|CFDjSpRI= z4FAxSI(_rsbK=)J{5tlly1peMV(}8uj{aM`WvsKSX6{qy-0GdX+UJXjij~(t(?_0t z(uunAwRI6!Kk7J5x>5M~;;t8U2Hg*SyuMqrHD=Q9jZWKSZLVZj&3J6@Z{7YlWcvQc zt1Bg)68Sn8{77T(`KivSx!B`s*l&J*dB?{y(+zhjuy;PNI#K1uq5ZU6YRb3w_s{%1 zC|4?*!hgj3mf4iZmj&l`WX=`mzt+sLIl^hqksY#3lXivF{nK2Z^Wy62BgOX}w@ojSVfCNt+=*WLu3FDixg6Sw}`<7{+)*Bf)rr;E1BKe7-mVe4A{Lp9R* zidtRGB#BuuiTu?kKHq$FZ^>NsV+rrWE5GMwuQ9s z{gb$D%4Io1&!_$^SStUs#{Ff~rN8yDOy|_}Fa2ZnGFbQP>!!1D67xIWEmk&ry7f`K zynXb!?;DG`?-u{1A0~41|4w>(xO#_5{<39Z+djN;|9d`A&eS`aHE4tQ zC&qwkFHO1sGgiF)d)rv>_3`Q6C$`qle8+e_N8+t~M4GpFb=L8=@~G7z1`<0@-+RXB zU$V7q_e!aA4BtMQ?kNxmG#A+Pc;3qm7hSIWd){_VH)+u%_k>US2l{GEy(g+I-(Bx} z^ zx%q1sn!7jj-(dGW_ulyVo$kOOh1*XLZ}GCyydEHO!QiJ?;FhfFpv6*a9o9}h-C($_ zY5r4vrtmi{ah2)Uza5Y){uZPB{P5XD+OJ}ko%?1LxhG=d4%vX^4{vIURjxd?)UPn& zcA;We$LV)0&yTD+^G!@&F22h0VEsOu9pBlUqnr1a%z3wM=Tw$fh0WS!D;Q&z{J*{W z`0CyDum8N=7{2dmv*JT{0p&~QDulQZm#g%=fenKqXVk|%MGGfASn&9Tw9NMP z6?Qj%D1WK@dEnOaq%W&E^BIdI;v~X<_RpEUXX~31r)<^bYp48GTYfdG=WcdZ#oYDWqB8SlZ%z09_$6EVCANflb?N{Aa^A0V zX4H1a^}8lTJW>4qLjGmJoK+V#h}?Tus&st1;WxRLCFM_zb6@TJJ?X`&Wp#(oM}9ef z^kbP><-xjN?|9o3T4r0Ws66R$>*)#gQk%vPhsuRYdF+k%$w&8D$+N_DE_h$)C*GK9 zkuDx(q#>vZmkH&Bmh$y^;K}&lJ|mLK6JY|{hGS9 zI*nW9z1b`sWxM}o7IN_=@wac>$P1L7dEdWpnrWe2x%b~7rMTk3 z0$#M^Gw%xya;@+Y3LXgzWrYmVGeXP3n8cr9;|(IuD-G;uZUI?uwa= ziP3-K##Bk+jhPY>%bk|}meT8~xn zHn@K<*=uvi?bcjbE4?wDI4{Ks-l>g>6?3u3oft;t!&e6QrYZ{WY3Oo3Mq z$lJ0WOU{k>`TAuxcbhP4IM>X_#g-QwcjfGV{`AvzgUv;&Rdz=56f`Kua%@XTT5+p8 z<=AFM*<-BF7#;XNM9fV6+uo$Rc>O)T%Bop6z9;X`+~O!UUrZf?PhE%myK=vp`KL~}`0vt<*J&qQ9<6fWu~@T(z3#_X>1nS|>2psjtzCJ(<-S$8 zec1BfwOoGbJ7lGo-TY#e_NVpt^@^6@gP-}1tumVz*EqL!xxaSWf3w-O?&mg6JGy6O zFz1}U?zJVWKChcqd0iwhLSfz%&B+cL>q>Sh&eGiV{NwNM`D(lArBYMCvof zuXi`!`n1D~zsz`H=ak6Zt#jA-_m_Ssd9mt>?-Ck&!fma8Z(Xe6t;{g0=5Th4+%}1=tKLi5YuUVeE%K!AIA5~%#$`Oux9qQ?;m-i zL+^I$EA6rRsPi?f&i-Ay$GiQzyIA})|J%vNp5H3wq47<<CmpW&|3bO{C%v=h-cOyzaLLGRwIsW^=*p8W60NHIJhPZ= zzQk>lxFu^mXZF3D_P5H-BroWn)1PMaU(O;`%|`q3G@gj;O`E^m3(@ocbn=4P z$qj%0Nv(h0w*TSEIUAW*#+W^;UUrIM{x==LJzei)=8Kg-T$wnbXSIS~YnHg@vp*m1 zZ=RWyS(q)rxOrB_Z!P`LzY?x`uzfojzuxQI<<&d-R!4t3G^6uzr?_c?qu$Q<9Tz&D z-aUN!WX-%^v8};<-MYUohHiYO-^zSH#&uP^#(kF;Lmwb><;Q*RRSr)_TL z!PfzYr*Hf6S@YW4`ZK9%|J`?<`TsvouXx9E|Bb;iPhJ%|eB&)Xa#3|}-Hv-VmX{T6 z7Z=)ka97c%i=0|rhQ@n~^}=t-+a7ee$zrTys4wffaglgm=#sBeea6$5?T|Klb7N7tsfV^cUk`<^t?`$Mw+7VrkrbQ4w(j7OY6EZaJO!> zHre#=>ObG>&(inLnyUBy!`Ff>r6Su(zs=!2_(2k`*YxPJsd%!T{t}rl5xED}XD-`&_9=UGQOxCy z(T_Gt&0*2Gw^OO}L-j1jZ`qe6d^IETP5!*D(pzvqL+VGvdKG@_s=QxG*H%`#m&Skd zyj+?8_GMA$itaF(k zo43vs5@zJD?XflFb^ofJ_mAK3#7fbt_ilYme`EPJ$kt|0$o}_>8dURUm*_?&YcFly z(cW=-K1MI~hN&ztwpw z^0sC2+|)N2lip?+mu~p=^=|M7-5#^*^^Y44^L+EPx>lXu4DOozphM8ju)S4NzBABsdaZm(Ve^@rH;WGP&Ss4Kkht8%|6^vL~R5YBV!Vas~aqb6O7^Xg4p&F4J`S@Qo~ z^PiQn3j0i@?azlDJS`k~zKZX>`x4Fbw*=0=lu zWc`QxeVZJ28-EDQ_ci~cQNZ3C!n22M*|S24&5=eQ3o_HEWw|r{{eEV`6!xzZmvY=$ z-;&OM@W|`58RA;8%#t6L?6FJ;{~KTNc+%N5KMydkJ-=&)Py6NSE78G^&bm(CwY;uE zw?pTN*)bh^*S*DU{GP4#wt=pk=V#5oRKB9?`R90Tjh7;;^}ZW&M^CdXGY&Uu%nS+< zULPVeXVy>Ygm<4NWQ6?uZj-ZGZf)(2+4k~#mFC|+qL=y1`}2X2D+h8H6zyEa_HEkc zlKGDh^*FwN%J($aRKGuTR#f>n@vr`N|Ko4>^TOPV%o)3wQy zj*BV&=MV5^W)WdvVBlbISXAv2#gp_e*q4FfTOb32687^Mi?cKH;&by;Qi}+l(0F!F zddTF1`|P9~4>|?2ENSE8x>U`%w_Gsb<=*lM(*j%^t0wocI64G4xGZ6xptrZ&iF2>| z76*mtJI>$xUwqE$_nm6{J6rYS(|qq~?w^@n_jcyjeJ(GvRtwx;x|5rMq2p?Z=zK;7 za{~s3xEHy9UaQ~ASLI+}sA*XDtXP%d-TEs+0a9l>F@6DZEO4VE>?$O13$w7#s)_Q1~!H%%nUmj9BddsXE-r}&T!&pn83ua zgOS0Cp@DkHZp9g zHFC31zOOJ}#^>CED+kO@Uo*dDuB4!J)^P2W1zX})?h9X0KCQIu_d~OF<_z9$+s>ch zc>Y*=%H(EAi7B^krTzTn=I+9>WU1w}X;N3NYk&R5b@tq*ynOp3|B@LR__!w=V)EI@ zz#%rFoAtm3h99M;xfpJ<9eBpPA)g__n<0#^A@$GwUH@+j{(ryg@F)NJCAs3R>r))n z9^10tzp?G-zCTY_gl1_?U#c#${s^bw;?GaiHZNg*VaswNR$iRNiM8>AgMybp2PexT z-o_&i3O@xrWLb<@8V!t%Z{NI`nwGX}*RE;Prky)~K0UnXcU&~X%Kl5-^0npG^7h{P z(G6YGm(Jbq5VvpN<ZcJ?C|zVaKG2;^Ci8KJbc^jaix9r>%RZaH%`TIv(Ex zQ#&ubX3}5J6#oBS&+6?wk6t+!#O&PBUtRQAY@NyuWxcZHkE`+;W-Yo?{C`gD<(FGT z-*p{2IiV<`a%JALD&=W4O^>22tY@BZIM*L&t-PN-NK9)>`4yct9d-AoXVn(Civ4-w zrSJUrRQ!7O6aQJxE;=K2=^yLF4;rGy``>aj`4`@l@_sF4=DJWx{oMf2H{xo$=E z1-xXGTe{mRzP#srK*^Qq#s}Z#`?poJa34}Ie_j>NU2*4+v4M}`W#PVm{IMxtN~J!< z`)pHOGq>Mt;_U4!U8cXk|2==+26ee*dhfINKmJr$nC$h~&fF*A*8i>P@^`Htbu1H_ z`Qg23T?bpnZBm&!Uu(U@qr1zu z&tC4edfp$A4W8ni%P0C3&cE;962Ij3H~vFEw!NC(v;TDX?eD>cf$>38OQV&gau!%t z|69d#D!It^$GiPfDJCICk-};y;e)CHEZ|ucR zi_R5oPx&};z0O^i2Z{Pl(+}q-pShDN6Y{Y(RptJw$hTcQ&w|W7X4w6Cw!ynyVrDLT zNuGv;h-tvFZnyn@*PnHIfgbTr^E~a7obO$}b5NyVdwu6N+rKM~H6FF7$oO`~ z-3#5QZhGzi$vgXR%<1i%aO$J0d%>iu#)Z*Ksx*1Dmnpq7-%>Q`LtK&Vs)7r*MG7L0 zzfnJVjE7Zr)2uZ+<5~GYE^m`g4kSFXu%t&va z6Q8{R-~SU{VeemM$Pevjr4(K(a4-YHRU){^)N)7~V3 zNu?&+7wjyNt&qQ#vG@JLzkl0Gcl}zLL_tthPlP&+ngfVg1(t0i{2mY^VIbb3xhMZ`X!pOZny;YQFH} zxjoaGeawU*NviEw}_O4lE@M~}E;$OK7-(K0OC3a4` zb=B(lO_BQ!?LBLC_;$}{v3h~x;MXC~PuzDZ44dfq?SjDZZCM-{=MK);Sbt0+C4)`- zW4YV^sCn)ZmzQ1HC?wq@?t|7hCAW5SiY$~rb!X?9HyoTKr!$SH+$Zye9DjVa~Jj;)%uSiNiCwai6aePR0| z?n>MJe)P_>U(TWPxBsapJ;&u-vnMLHHrv;$Fqj za>sn#?=3IGs{3GWYuT`;Kc*?DM?iKe23y#tR3v#>*N(OOs9Ao!ks8cc1#@ z$G>osg0a^cFZV4!EoN6$E6)y^9_gicg?mw~@7B`j1@^V!+>yE!_8MxrXREKW&ioYd zHM6AOOD67F{)1b*@frpHniUS+p1n8z`1?%{Le*K7GGZAbC9?0WRg+p}Z+YFH$+qxL z^2D3|e;qa}yH%FpjgU92)YvOW~82oEtn9%;mOCQtA@( zG?vZ6uiIkoin(yR{H9@$$cy`lI>zBINRR5ePHGmr@DD|azfpg4{K_tc)7MF8Sq~I-1$tRhc|8O zoxnFu(tATPF3HWWUY5r_sV37Zb4S`a4sn;+rBWZ3IrN`-;c!{(G>f;v#~tTBzcbi+ zac+CRcT2IGp>%u9iK}k!vo+^h`WUI6H9VDns4;4TZ`$YhtSX`KPo?uOTwWu&Ub|h> z^z%l2+w~d(G1Zs(^XET1zTtN7vO81v{9hY?!{%YZGndJUQ@<{La5O9`^;*Aa{wL8% z>$^6*3i_E?pyyrmeV2XyrgIA;KYp>>p0RzRZ=>|}^D`XPB(u^MYDGVJ{C@e#$ysYf zt27_+zu>TAc`tD}%=0#mt(B}fi zmtLX80YOa}j`9{Vi#xsMPLs5mxzFt90*wiU4?gccp8x!>Xlvg&`Jy9+tT81rQ@dk$ zZY=RP@VH>M<12sJ|Nb0# zbwqrwOx(|MwT8bO%yf8?MWqKd3%x>s&HbKqIJOvXMLo1BdKKId;l?{-=E zbKymO{RN%xp50PVw^wXPW;_|A-?VL#htjbLvuFLup5JyzKh2RfcSY~C$|$idl5!KKdp3HlwQJrmsUzuVR(X3u=cR43I^JPNw{%TEeWpe8cjdt? zeo_tr!AE|-sdin_<0Q3U^{&j7o8L~AW{t`!`7Nt-JFQ+d?O>xC_w0hEW&0+~+&RHu zQICq$hwi2ghi2+8G7J`TIaZ;)(JC`nJ6Xj`A%6|arPz%r7v}P;d30h1>)cK1I>xnU z&s{xjvg}ZyP-`Z;t6Rt7{V^e7lit49sqETxZ2OWgAHG!{^tdq7%D-c3z}2#cell@e ztrHe@|0$lQ@X1KCjZZMFkP@spTAAMeOp;G_0zfc&u^Ud>2cPZ5Zb2D8{e@0lcJYz)~?m%I>&ZK zf02EDV$K`Ukez?L)bE{+DvSHMXpY*YNR6}de?H%7n>9P+-}jW7>7~`b8Z_!3xM|G@ zKkp(U`{2lSv7QNjMfDAA+1|6FBXrZ$4r)%>q~>t1I`6wc-N^}Fb%wv?<6gH{J^UIc zZnu#wlgpls?dHbl`Hp>=tK7>cvQBZm@1b_*=AHTVc@lLJzh^F-!|C;C+MBwtpS4Do z4{caluW=d9((w~mD{-vG*YZ10P1bwWKzG-|tozDZhX1E>B&i;j6I|5(YS&7ZqIEZ~ z+m~=)KGc0_D$-qghjaG&MN3-6FG+oU;#@a5Im%L7nmjl|Lah0oXoUrMY@b3Y#*X*5YNF140T zcANWE$;$^16!dZzeA)Nqa^ssTMP&-i3;(>Ic6{RUt+l2(Zx)|qcHX3T`r6eg%NCs$ z@_R9DUYb<9|F89a^IZ5gWyxI7i;r3*pkFMDux$%*L}a`9^O)w*8MSD{&|>Vf>h-1!`-pJ)Ef2N+hy$+ur%eVO>sVC zpeZ@m@rw45-?wi4WAS^Lw#cJL_Tt^OAA@xtS*OaZ|DN_KSFN~bT))OG1v|G&C)6OVJ--7Bl*6jlm{9DB91+Qa(!_KxgbW%>fA676{YtY5NL z;pZ;yAl0zHum092m(=a)mH2M+{qW@(roz_M4-PFlee`WlXTle8y|-33 zyqI|VENj5u-U&y~Gn(heD}KFHdW%bH>nw4eeIm18)&8Ev6MM+Ho>RucekXsCwa~+d zo2F;~pO?dQ>Gz2T7gjy#VYnpD_hR|+(;g+_`P1}@nmRqQ|Mk?1%io$FpXT{7Jh*Th zr^9RxbN7V;tQ*|D?1c7P-#lEGXL{FZ)n4PU$g0ct)(altJEd#%Bz$A^u7#2Ht6MJ2 zFmXLDQM>rxnwy$G+G@{hmiz0pc(xsj;ZBpUnNrX^H)%nM26vX1u+fk9lb@t-U6`=_ zLBCwpWTUY1@2pwDtERo2vC3zv?=oK*PQe!@)_)grES_QRw1MMX{g=r<4)>Y(y^r}X zvebyDP3_|)^{X24PkFW^#!l1}QRS#MWWDe-fBmT$j~ElrAN^yS`dVeN{e%aXrp1V9 z*!-NeV`gwu6i-#fsk8x-2cKUo?Ast^Y(pT{bQZV`OA~f zhc+L5tamB(UGbW;ed<&9r(Ijwb~WLh`&-Wmhd(_OdM`WqX4%UrU5^T$|7+1svp?hV zF(qpDMV1*E-#_*$rhPtkx>wfwdB)-MS7uyZ9)9q!*Fm+SqMP~0titATY&{&3nieLv zK$~6oS;(7@J8H`vq?!1VHP_DZwCdX5ayI^@pzLge4(@|74^ICM*>*y0Kf|gn&EIUj zvVC>39#3;WFK6SQrMJIx&Dk?OQ|r=R+5J;wD-_(f#{+ z&vb8>70(iD?wy@h*EK8m#-_?RXY@|8aH!ziH5s#pbIo+iP8R|Nbo`;IKyJ zmiyP7zD<$ctkie^=+f?UKhr8#EnfEC{zzSwWYg@Dl)Vwf3l2n^RE22Fs(Y{eWYvU< zPb_Z(89Fn~o;zz_KC$Lxb1-TE7*C%w0Eaxl?2w?TvL|KvZ#U*{jme)C^o{jL2+ zPA_Rs_V-SCcXpej_{W>!<&#Pt9O2S`VQ(?@|E$WB$6tsZxzYKkw{?xU=cL?3Vk zCWT~Xc^&<=YYKO(68p;Pvg}_8g|(q#>Z>Zi`OEeO_!FKYc4)@$8H*%$B`3j z+LU_^+Fo~?EHa;aoBNd<8I6p?+ipI*UB9yHqW#LQ7p9?+f6YT!uQ5LVYv&Pq^mLF& ztzyHy8$vd+3paB1uYIrbxTqztQa#;ilW%p`-L9{JvK*r2E2QHYT6it1eqZj_zSAXt z^uOXGDNok|lR#I#GFQ*P6IPdA*L(2%<0c8wNg+YyN^#NGmTDZXeWW(w(gO#tWg&`v;tdOG=P#+P3y#0cw4b^4(sAx5f89#Wd#id5`QfIFu$s$dfSOj;w{j_j9E;uL zHriHx)%LGYFF-iI{#!w z_?oP&;yKUs-xn_C?QYH}E!&^5-N)ZnCwB6}E;j!iXVdyrzjUmh+LGM0>@S8*6^P&x3zs8#rFM><)j9w{|@T+-}zXY zMgO$mzJEIZXV?D9X-g_^@-BDof3{EO&GW}1zn9!D(U5!=x9g30$}{`92LCnYP59gO z$?i6%_$*fa)ca~L-ES8pA>*LtC(vehA6 z{ikY2+AQTi_DR_j4t7D5bCT=$Axy$S@^7nf zsQLjfg(wluBF)+gXYJJeaU5|HMQbkyh<`hU)hkp zQqP}p_ENEYnE+;IzB)0UUFi-xb}SK@m>R$N!H@1m{xAIX-IR8VoeoKqU=TRg@lW@! z;gaHMT$;Y;dtan3+ds`&mi5_wkN0Ko9fXxDnf2=$?v@3L3!Vw6ir{%=!F+6ioVy6ab{Pxfc^UKaEDA}drZ6rRs&xNwWHd9RVQ!ABPd`*$Hcp%t61 zB>Ky626ZQ%Hh*wvo4uo2mOgV&;HJB?iul%CoVaP*g9OXH#W@W;J0Gup^}W7+&)jIe zXe0e?J<%dcUyPWqt&f_2@S_Av2ixncD>f}^XDX}~_$TSj`zkT}*q3=%b~^OdFt1sO};eQ4R*oG)VkU$L*ww7W(ur)}mr!=9*Oas94t!JDz1 ze}Y#;Exx+P@Lc7el8K$Er+=&FPmzwvwQMN6v7jQTd$RMhO>@iQ?;GTNULv6S!PK9* z==}cKlh0h&iMe1EvGd@K?_b^b8*FHF6O8)z``sKb#W&NYoIR|ud~)uLWgAVm{1o-N zV0rWBuJ+=?=i7d^KUmMagU_X&MO$p$x0z>a^&0M2?983^D-LX(wc~`w9-Wo{k{&EEh}<&IsCs*rRLI8CD;iVccnmM@ zxiDw;lgdo9qg%Cqd`i}0JGxSOU(~!imyInaPwR70O^g2eqRn#Mlhv^~GDqxx+pL}y z^-cWYji;0LlpH-#d+qSC9le(>=6>VXd>6RbzBKNh)+}H77k|ICv2TCGbaNxaqs9o6 zuj_9A*z*36?vjI-&upz;>w51%$Q`Gz5#GzS^;lvaD}?*~ZN7iy)bo7B$7b%|;$F*7 z@r;QnPx!SVtlst4_I#my{ZI0@Kere!%Cz5kUty`4!0-7hCeGQ?Dp&CA%opS6tF>z) zIoBzFpZxWSYpi!?eZz&x7kq?*KU@0!>fdGiJ~>IH@0|U^ zwoGi1_{rm@+M%r(|DR7jt|1(i_S1yNVcugu*GN__{W$^8zGbz^ch<>$v{S>a+ z)6q-2m)V?py+16qHR4mzd0lHq=SN0tlN-(B&spxjap%d3ecc?pg#O(zxL>8%qdGO} zLjJBlx9pa)oGR1YF`dv~{4xetyqP1w&om!XhI_^u2&n(@q9lw?t ze=ak&XS&~(14^^q&uCe8sm#y4Qk42W?6~ROmfaWD{PA;L@nVLljBDa9@AJ#~{Mc?^ z{1(Y_=*yhNTB_1}LbBsYEinhl6}W!ADjx}9^KeS*XxiEryqv^OS~tq`g0y)(=7m)Y+fiCcH8E$vS9 z{TmtkUT(o+y|>BRYwj;*Zu-{v_}t_m8~I(OuTqn~`kj5QQrS|aw6nP`;RCmMP4ljM zH(8hM{t;=Sp8TCVB8zSH9gZvQ+t+_RBN8uk(c_O|ebMxJr+U+#eERZb|B8q9t1dVy z{O8wrd|TNk;Mcc*$86@6iq84Cq9&+eYLUTI@m=+fI~8}TH1#-kJgw35ThaNMYbp13 z*;o$`(aq~xetuqhGps?Psg&ENvE+kPvbb5=C+iR?4e-a zoeVZVbuT`?f8$r^LZ36-Mo;$`dfkj>Q+JvQIAO-wFg+O+<* ze&#v9Img2$R8kJ+n?ucT8)(!n$QiZPT^KR%HdYCv6|^`8!)@ z|MAT{5f42ZMfTb=Io_NmQ!Cj!b^hI`+-HopQ>|a_XApU%U4Afj?rG=v(#ICt)`g#( z7p^o#W#`HTUpH?!o?07s?Zeld_Sx@*-&>eJTjKNOaEH~zfAY2GeSH7@)N9z<7V1}_ za;s(Q&7j_&CZfr20=HdzkZUa`!Bv;`sKlA`hLqckc}tQf**^Vmc0zX=OPAN%9OY{s zH_ykPbx*|92#v3uOPaL&Nb>A)K6x<~dpd}|0Sz0=2R_e#o^qqCR59+P&wbWEZcR(f(HWZRoy+Ll@28 zuFXCab3FH&>Aj^%8Ma%Bv|gFd+k54m-U$+7`qDPkM$u~&)y|FF7zS-n$KcbAi0?0vV!tPVa8 z#y<9k28ry`LKKyAIOfmK02h61e;AaplxK8*>9h z50&!Gd1TMHxPEcsyo5UiEjoRzuh z_SKE&n0EG`bv#>^o~OHxW7WJ3*2XUmE7?wRdHr5*v-nj0JDu~(?A5l^Rc_jPDdh9J znvXnXuVZHOc>a#&woGgOU-G^EZGZFfcO`FR+@e=Zde!`3hF0Tpo_Foh>2oqI->o<| z_5J)?^&!&Ne#ItBba7Ng7|%?dEV<}tU!~H2&){d3J9gLX%uD>UYqibp>@9B}$k_i{ zWA>>zz1ZHbwX%P@2ot}dMPtnwwbm?~dX~rsT5&g5r`tyc+X|k|TCnQinzyUuzg64D z>B^t<<7e*Q)4AxtHJA8iR=r*8w@&lJn7JTr7WU(b;o7JD>aKnX>3uK8gEjVX@@TZSA19JFna9cls+kR8;eSxb^2_0*4)_S4RR;TaWHTmmRx>8-(C(46`ktq?*znya#e)5Rr!rpJ zn>zKxpGN=KH=Bb?i$r4YeUP|bcW#SU{-mk;{6GJFXpUmP%Kz}ng!b9LZNJr*t`Mq*>eHQ$7;Wb}o0Go0t>D;e?F(P+SG=fCVRL!-ea_Lh&41-h)Ltxp&lu@F zL5J&+Kt%!j>7-S&J9{N=+RoJXOT4$msQ+9LuSBC3^ZuX3ced&K?T|PWVf|ZphxZhL zN#_oVJ?5GbpzBb6DE40N5yK}6=uf@mRPE6?>=V{oN^y--Ft#4L8gx<=MyLyw309qf(6{UIn4&7TkT2wjlntw@1E1 zQm$9TlY@r8J_y8Gu(HlRXV;N$@lELj$FsktyNhggCff+CTd{Cnkf8L^V+Z+pf6q0j zDB4t`zVzvIZ#@gA_=guF6*?t~Unp-au3ETup1{u6Dt=YBIkjzff8XU;|LOAO#miq8 z{fzoN`St6U{v2}`l{+=%mpxMT`7YBEake1ineFDuhLO9j_uBezbH3NKt#oVS>SuTV zyeMzTcjMUpMs~v4-Hk01*H3<|Hsx7pf%VBp`xd&^9=tL2P2=7J+7F!h&!)A!$PH6@ z;WOu+Wlv}HPIK#%52aRZ{j%=%pH${~Mw#Uw4oOdXQ)s{wz^m#}c)wK9<;MFLCBaU7 z*DJG|Z*D00$&uDOjmLU{7XNdWvX0ox%X23({ts-wf8t;H_4}3b(GI5h%LOX`NgBW7 z-7fe;T(kM?fm2Ky_j>Y5w|y=)+0MQ#^P!#R70Z|6T{m_Y+qR_LnfhUt%pvRfk813$ zB+l2hxwYY^m$y`{j#s;l+`qaHk8Gl{HCvk$yZAq+mtXwD{)^7v+U>Vw zi)Yu=Exdo@rt0U-6A9lNlajD}vyX!4>nS$z=dw=Q2<*!WUZ!yE_`wfm0V{eRtSt(D zI^o(K_4i8klXgy+t?nhjr?JK40r#873;tPsW@U^$yl1w8iG_+w`rPdFt!l>#7njT0 zb^m8A;fZ>(NAh0H<}-WNZ)IQg_-A%hg4U-?ydHv+e6HsTwwEVfyr5L{oN2jCPqmRk zDC^Fd`cI!d*`GJ5Tc^8yHuL@^`t|JzdfzvOzj-cmWRg#d?2}E}bz63M|L*SnTV|MI z|B~0d>X)Xw@6UH7cONSE-ZlQ?_3?>T`_7Bbw;TOUD=H5<8Dw4*x~ZtOBJ7v=+O@Hg zIkOM%&7aWwPNU;`Ks3wFMXuSGeeA?Ncc*Q-*}O^Mjpm#H1CJ#CbKC!4aXs>9cE^*G zho)~(&AJ=8U8+p#x~n7qjEZxwtK(LOgjS}<>daFtHs5~fX~2)^&PtzR@5j5O`S09* z^z93Gr~M_Y>lamUN}dTeY+AVK`@1`L?7biUE814JxZ>%D-)n9k`L-kYvUYjpx%jnH zdfrs@nsT0Xc=I&%^o0b!7dO`h@9i<0>b6_Ba?KIJFu5mJb52#vxt_N%*S_kEfp3*d zg`kd@qh|o`pS4r;$}{TUTc?%OUtZabiP9eLfBOW zd3)XFs+t*HX#Hf9$a?;}+aC4YBR$K#e@g9|Ve{qs@~!2~dro*B){Dq`9K!eV)~>L3 zCa(NnV`C3EJMl!d6-4Zp%b449l6Mm)Thr+q`>yX<_@}PDLC|=2c(?wy2VctOy_ep; zGokC9Ot?_@VuKAc%I`Y;uvwU5aPOYV^kb7-8Y2Uj{=I2-UhC$*uQ{I<-Yymu-Ymy< z-tckt!h>gOnwK4Z(^G5}y#J8tH~H0@=bdP%S-PyyXlCQr(_+hIuRTA*Gg->%b7e;8 z1aX7M&(vQ(SU$%t<-CUzeab1dFn!{xMgO<3Hj zn2f4OmC17&=Iz+%F#8%2~@O$c#?^@pTfkio5Vp`41Wq&KO<}9rH9A-MV z`-;v!e(U3Ik-Rs{Wq)6vaz8{?Wb<*?^L(rO)@QvhHF|w%M-1QPt6RLEA27P(uOoKo zoOpTO0w?Qx6{ZKHnRnji`F-KLe$g2(!GJ%)Umkr+E;40%)hoJMj_1F?sS5KipE4H) zX8)a?vD8+p+jdo4)%?JG@r^m#=KKmjU~^BpVzRSs3)_didHmnE`2We@E7rMu!9*$Z zZe7pcH)~tk^G?a{yWc6Z_T!H4Q<;40`uQ6Bc5GUwzUWtPWKYz>1?4t7%Qjc|PVaGT zetRjucKd6)WotIZY*{c_+NpHr^)~izDL0x9KmMq9ZAGioe63sAI=dfNpE9meJF-1G z$aEgx*B2dLzjRJ4dfGSp`sY>qgMM%<4x77cN~%=sH5I`x3zPS>9^%(~z;RO3ePg?3 zF5hwuY1TR7LcgOvE|~V=+b^l7o7KAo_D+j$aQfM@TPIvBV!sUcql5+SO=kD}jTE&+ zW(iFR4|F#0e-M+o?YfY1^2HBMlTR_9Joj?jLY~Ewc<)Js8)Sy;z&-iim=9^5pA?H6%E6>UI zw>j6Pu=sQQ1}SBgZC@te%|6S?pPn<7Z_D->SFE3g*M2nl@@dk7Yazjk8LJMZChx8| zslD-Qs)Vk=Jr&lXWb^A=ucoEna4PGwN>6yPZbfLyt>?!1+B4nW9Y3ObFh(|YrNmpF zvVBfP?|kK%yb_X+?hrjH?iBmy=(IJ)P8YiaPA`2hW3RVWUdQp8)7`T#<-h#$>D|n2 z@2w^}xa7CK$ag4@b(p?0^=OUJwf!QiJnXimC*JD+X!4usuN`-0{)euda+Wg1HKp=} z{Y`Tt^xRsFyILC1?bS(LDUEt=0Iun(G{zbH{V{3F~K3_7A+D>$+vh_AJp2+TGbD*s{1x;_1;M52+6A z*~Ut0dAtd4b)E(st>k5Y7k=cF!=&^7_&*)KS(hp|-{OVbD;`@;^Z$MME_`x3N|g1I z*ZWrJo)hAHo@n*;{p)onn%w_NsV`j_=pv^7uOjQZ!KwHAmCPSs5V+@T6MSEc|H~wU zZj+X0MGaJ8C%F+VR!;>G!6a z&E^Xd+k7L(f6=jnDm!0X|CoC<^hn%UttP8CWjsP6C)Ag)NF=>CfAiASX;gB%?l47V~IJpJ5y1ltMN`W|GDXA@*8Bh zZ=dZl)oXbtc72!enV<4HhO+-69&GiG*`@x-KUq}ZGV_I23y&?go=)JgjX$03|3}YP zf0D*Fhx0FQY%oZf-8Spo(g`Omrn1hz$^Y`{j>+4~K5hH*vFqHniz$<3VtHiS`uFu8 zyO(v@>!yR0VzutKuzfr`uHIQW#Y63`3zQ50SzdUk} zlRf!;d;66AtbY>3oj-28Hbd>@o&A@B0v_^iw!HD4Z~C8O^5V0Eez<9Wz9tv^_4}M? zu0J`kMsb|KT=snwwRo~y|FYnI%WDiXd3RSle{kEKOETo{vpY3REiDJH+&AFoc)oI4 zz|K?imY@4)d8TKMPIexbPWh>*y49Dy{}ntx#m@5glJd`&LjDDQKD+!`ewC-0r2Nt| zpLxU?GFTr@Wbuhy^5wgkqsw#eR_{|&ZcgYuvT*ixk$v0uq?&aGeyiPl=eOheOs46T zjGH_UFTAjLrQMP0E0HWjlg0F9*%cJhhTKz!UU|IF!=l^a=I`*%< zG3Q+3#b?~SRVx$9mtT&L6PZx0KJ8-e#S8IXQ&M!F1bpV&rnPj|#vOZ)>{>f{siJb8 z;fGt7jAv9dA6mXT{LjU*{YP#a?qigEtoZKpSqCT0UnW<$R1;?`%-O(dw&K^*b^E7w zu)j>aaPVZ*`=_;+J7UxRyV(7l@9Oh#9lP=5!<(;NoBGk3YsRe7sjDic=Bt~}zxQB4 zUDV7Y#+o}tdX_W@r8K*nxL<94FMQ+bT_e}$qTALe=c8vuva5d=0N2y|U%i zQ*rGb$26`jW3y7&Bh2tmZNugTxt4`Fp?ifM+`lDv*GNgwjZ40N1MJrC5qayo_x%#<{gTJu ze76WPJfnN@;2&|_OG&S4!}&$uPpp=fy4~_(%UnIXH=hqkmv6K_Q)B9?%VJaS%yuDl zk1U@+#PRB)=WiEi1PgL=|NS)k=+vqC#jEueJ-hFhtl{yYZhyR0j^_dEC(K_i-`}#G z{4Z=1hcH4?p4ZJQ{;Eo zT4Z06t!!VG`2FN(`6atq=E~J5^;DnD*UvxuKwglqa%aW9eTpU4#~&?!IxWGCU-6Oj zn^iluF-?@SI#bTZHjCLdJt9Tqbsj@wS$4PkoO-KLUQW(=5B(3D7F8@3;3~Uh&$;{I z`5#+uuXVLKR1s&CckP+Z*Mnhu_Z*$Tw%_ze!+fomf4A%1Uw7pB*N?Wmy%w3m>le*e zJXh&puqQ$NZ()Ph<0q**|IeS$d%*nrx&Dc=55W1^bwklC*zMzW=tuSMdFktP}fh|MQydC7G2U zGv)T@*IARQ-mbJ0=le3t>cXGI4H7;!{u&b|X#UPnsd*Ik?s5Ei8xfIDf5i7!DENOZ zl=gd4d)bKRRd%T69PQ6j-WLUV-?%2LVD|C$%p5V>!*_fXpC+-tzHxb9z}7c6SMGXK zmAT6#<=_Ul=~6$r9Xj_v^Am3k-0L%a(XkT~_0Pxe2Blo>%H7gd|MBXD8_!G_P5S-6 zb}1yC`jqnEaru*R+WOSjBA{Y53odC8G)SA(79-#z`au%7?_3HSeDhnL^})mwQk zd(zCb%h8jS@6YICWLy(}AgXwA)3i>j>_GDw>mnKQx4zY$X~Su-H|wz%cXNb6qk_kY z$>}cbd%{9^gyOwVseERca;0XTw!xoFgYfN2IxZ_XC93n(H-4Jz$z;I0EOvLt#%p$m z8BT9|%J%-%iQ~7#tJ4Keg?EPCi=P#>#Ccw|a;MJvE;j?)ShM}_T_3EodU9Ks@9Y76 z4{K4TeSsS1J303FIOp}g)tk+7EX?TK|6euHyK0@ky;}SC%M0@lf=fB#%YF77{k}7Y z_1bsU*l+EJmftAw^Z0b+-||<#uDADniS&PEFU+=9xqn^E9@U76Q!i;Q*=%9Ab;@Z2 zUp}UlekYSB7d_^>R;l*0dn$kb%1OczOLqC&KJ|>fUvO1KnIXUSK~0-^{I&@vw_EVM zHWgyO#lZA;vC9t;mg%e3hFmPwFSafExr*_it0r$qB@a*f=iOGX+WTwu$tn9G+q%g5Aa=N%F-*o55xVMkzuHW`m z!>M@os#!~=@^39}d2xWhl-K;^`jU{Q`I8^NRt%JM{1@FK_^|X;$DPjNJ9{skwOV@X zM&Z$#2@X|9*k3TmZCt_56P$F~$uDx1;?G0L8}?~$+HmjeLiKfgLi<;7EjP7Y$$4PA zW&Wb%dEc%Z&g=PS_MR=*NydEk@((#bIGL6=d1WmOJ6&|<(hBL>)0;U>Ue_h+N$^?! z|M;TEdFP{xDq1hUuh?X4QYhE_BeXAX`=%$~eLp1rJs!7Z`49JBKP1WzEBxQhx55AX z(qEGA-s@I2+-G2|pS9jHB4R?4_|2_vCz+?#FmfpW{M-|jQQ-QT%ktBOAD1#}uk)XO zw$^QFn$ku^wa0Vnf4)hs5oe13?zl?Jb4z~75trYGj($7;bB^hi)CEUs#P-Vl6x_+s z)_3&KzgKm#A=|nBI!yWz{eyXd&GZPrKZk__7v0Yi+VU?Y<-*BIb(MB@Z{_8DeOY_i zu^PMAo%xE55wa zEl~M8L!)8li(|!>^VAf@U5wJDH~(F3a_x>y_OVAT zSDvQKGhvjn%nbH=Gw|TB)@#07`|g_l?3^F1o_CF3a~21OU98?>_1LBVt7TWmmh5_Ae>Ey! z?8~dy%T|3|+ts!+x;{VfYVQBPzvTs|DxOGt;nL!B;{E#P5!q3X6QrDalrK!$R`&B` z<5eMVW3kOodUK~sY-E2gy?m!|pV7UF>AyWsZ&jE!Ej_8?RI|j|U93C@!i44*EEJxW z`RlH&V%6czTE+7()T&CXS-dXO|Aew~`-2UVUUONVKRCtE9$WsP;N|&L!9}wUp7hTA zuK4o7&Li>e{?*yHZ1fI6uaB?aHn(^K|G&qU|7AGr6x(FK|L4kj=fWR%zF}cx{<7cq z*Z+<;+s49pmc2gyhswJBj9>dF1$163^SWfK@bQyoshRvqkuN_iZ!7N1l-cFKWXj4z z|Bfy9Ow|AQaHrN6)uc}0FArR79G_0O^y|%CpCX};3nkc8LZF7@(A8@U$qwBW2fb=LhP&Q&<+yu$Z@Ocg6;3 zZ4>SAj-NTJ*cg_di&4J+*R1Z_rbvfB-XamJr0P8{on3HVZlP1Wh@e!8RhnhbFB?7~ z#TKjPmZ`BH6u$G>-Fv?={i4t0TZ;-dhEtp{Ydgx|fp$|<#!&pc=0vCYw5m+V+$m)w1PMekqN zgq<(Xnr>!r{%RBaru|~)3ZdKedtTh#aZJVR_uQ9vAKzN+Zdmv8oq0mj&y=e%Cp`E_Bb2nYy{=gvy4uo$Dt{c*RZT zt)3q`_t7K%#ZRtzewAWZd~A2>O2ElZ(JgHrdOjtMebi_*rbHfLI>YATbzueUOy*l^Ei4WP+gr!_%AInJB|J~yk z;J8!a!|9-DVoNKhO_+T2#LTI(6)J(Vc~_@Dj@&y>WP@nZs(Tw>_-wX1@yM}w>c5#5 zbxE3&`=5Od)44Ls;Z4>iCynSbz9*}{c1~N}!lHNM(59tkvxH4Qe3;hzDZEy-Z;=e!K zP)gINI=x-yNlwu9ZSzbM&b2)~Z?RWZrrmf(@0)8U66bJgh<{JJ>bdmTiwWI|{?GYl z=XYM3TD(Wlb?@n zWVY*o$mv?sMKSx+e@R^0%CNe$W0&`D8zor=h02C%@dZxv>lg0&`03%Ux|OFCR=)nr zXxi5Fhx^0tS^m%K&-a{&EI8o*cFMD>K7FNJ2h-kE6-&K{J3oKT`FlysFO8R3N1cw} zXFPlMxp?cf=K9~3WL&Q0nIpTCt!JBr-^z|GcD@@Q`i?qAl_#6|MlQPMby4)w(-)Vz z7A=1f*r?7tIYaPX!)BQtn~>!{P6r)~Ts!yKv&~Z;7R-EgP@v0>d6Pk)*^fg32g3eu zSi|w8_<^e{_eSsP_{UAt)#Joj0)q|z@wJELMm%~mU14iq_Wt{i+yxeU$EXVP|Jx}4 zS^VJrm+GpniedSA4zPH zt2)osD)1Ga|Ikx8#fa_KzxN(H_Z6_{NOHfh-WNZ&vC&>@PubUZ-Q~~aZQdXEt7=KV zbNPfi;~&{+lf)m%*%bV_t}m%DV~mXM~qy3KNt_*Z7V)`hRa zpB(O=ct+=G>HH1$r3D>l4c8mHE(kVk+4bJ#|6gt~uDBdwy%zv$_>srw&uw(9MSeQ@Wa*!|E(pN9t;Hom&ne?W5n`5)ZrYZT@R zd$vYOPm^Em^>^7R1>+?5`EG%N&#L0oC#h@*esIb6`{qyk_tl8Z`M+_NTiWdmx7$^( z;|m?c_9xD zom;#5W$Nz-PR})uyuqd~7rqvX zUgDH^YrWC?JRSKwF8`X-+YYQKd$`6eQrc{hPqoeVS+ftGnRQ{Y;q?!?J`=soPT##9 zv8{XY{^_^{qO?VAvo5?<@BB6cQg9_PmEmz?kZ$d;YM zW^LH^@UUy%vvUXI7*sg&vKO36T6x|(_wVb(bI(paIP;jleR~=Il|9w^29X^N?OyV~ zH{S|+A1@Q1_+0jn{=I)+nf^Qzt$(}ww(`3rakH+;z1#TmLVzT~_)-Q%5STs75IJ-|@?fYEKo4{@rok7`-|{jz9i>HD?PCj4c} z-Jj;?LxomscJa_!b~>ps%jbpsxhV`kuFtglb>i`!wwiOym!jUZRhK7fKDWvGdNO)5 z^R2=QpIG;WuQOk=wESGjOZD#?jve~^3nsK`=dMZlGD-c_9ETr;`$f;WC8R&xB$|3Mf@xoh z?>~pH9S#pSEe}ci&V1Kz&e{J}tDkVc`}eh3ZMpWXfTb%xmj2**Zp08Q$Z+iCzlFyR zs|m%VMqKIN!Z6)&7BAnCH~)N}NL^kLthDFsG0uN&>Pz|Oyxq>PvzN^jO?e`c~T2D94hW9TYgicv8(>f!Cj2!+p4_(yU&?&aLe6w z6ONiH_*^`6xa7c-P5kSHryOxQ<>yoD%T+kJzjvN!rT%8m-(f9tikq|UY);)&+rnNl zp>~Q#roHr?3oi4U$~@a|yj^=nHp{rrQKY6*<9MvYqvz+&Y@Rov{qRK7{flLGyZw3_ z8@5Nk;?%90xd)%VREv4dKk>$|=h`z$-6k-;KhrHZ?=AbXs)*XwTX9L6<@b~?9}2O# zv)$y1_p*vx&C#!$ci-ObbH|ElmDaZ3Jn!oqPu%%`;*9o&Ij+^~ia(miR=hfzFg5X> zFq6TD|MB}S)h?a(sk**tikZ2t$*#&q*O;XzMT`{JO|w-A4Y~a!GR&qu>*czei)@Zm zojBQ3`cLMT``?{+?%96lJ3i;?%ZYuvci!?=KjFt^=g#(KPR%WM`_*6h%l~|MdE(8V z=tGbDLlhVOWZkJ%dHc$o7fbIc1hzzWPpaw57FvIpxj-b%y}0OKZQhOEDSsa-K6q3v=zGq;wi(>slMGij?Q0cN?Y{88qM=N;&-&!m8UBl#r$!qu zs9dN1zKx~7@pA0(8F5Fq?K}~EYSUtWo8~a1kaDB7>yP}_KIc=IzHLf|pYf|{0ynSP zfBszh?2GN@TTWq&=DanD$CLg>)`spkJCVJ8*40D_-4zx8o6Il%x%l#)@}WrJ;d5#LX4zAee~KK)BqyOpT8 zf0oIqzf0GM#+@~-uV20Hrpu1}H-`=x{$jlKa@T2z-A7h;ERd75pW9!Uv%W!7@l=pO zTDV!plDB)mo?ANe+}BmXUy7f+n*aI7`JXcPr!38xFzK(jrmd-8<(tj3Sx*l0n^&xJTgyMWPTs*F__KU!Oy2{)cPbeunjdbq z-tQVK{mnpJD(Tvc{D1kzxBh>fz2$$uRQLvSwZmrOTPi*l{!oL=g@$l4Fh^#a1cPvC1vdjD%L`@( z1~752eHujOhQEKm^ZxtqmV(dkpX@1JE4cAl zPmE#Fxf3GOMIJvf`oqTgV=CW|diS6I)fVj8^XGra&QtY4PxpWPyMN`UzkmPMzxw@O zPC=lews!B{y|%WtckkYfjg6fV`u?(S}GcJ}YQ z3^B|Mw;2wYFkIke2w`ThWN_eNc)-kXg8_838V|z(ZiWj?3_BPYWEejD<=wH5EhnFO z*>c9acN<=1Ir#A@sIfhG%)DVE<^NeH(X?Vae^VGf^p9lhNu_@J(&mp|2R6`Qd60emhwhS z;K%&;l4@##dU|q-iej3YT2G%Uy?wjp@#7`0UuQgj{{QbEbB32vodvTe6wV4<5bdxu z=BUcyBdUi~k0`4gRazRebWiM(+Bu~)b4&ipy#2F3X<9`Gg{qen4j-(&V0dd=?#DP z>;GEpsL9|b>ry!hc`;fIf$A3vV_@Nwn0 zk1xM}R8&(lGd4bb=FFe?qqlF}3JVMSw|+)v!-hj%MUVcMG78%+zE+>F()8cs#0PoF zpZ^y({HYJQ@V}q!+y9FP|J$=2`G36S&;N(vj(6*K?R#&3*Z%wbdG~+!|1SUk@gKLt z7e+QVmVfaJ|D50Qzf@jDMBoEs@9wy8g9qRFTYvpr`|kY&dyb7FbDU!zdYFiHU;S3$ zd@;giVS&iHl;n>tMoWv9o^we)8Dh0~qwu;Tdk;Ej@GzG1ElqkEv(LeRXI@D0Pp644 zFO+5-72X*mVSX{W(5?8X*HpL3SI;eZJ$2H2olo;4UWI(#s@A>K>+Z_1+b^vS*DMrW zcjeStz5eB==W3RIdKi%VO_f@df zFM5An{L0;()<@!Q*UwkZ{Z;p0?ASLZg?euZ3+A}fJT(gg?s3;lu)fOqH^A=dzgG#H zw*Tk-tIA$_qF$b(?nS>mYpO)xwaIQW-wvAz$)B;%j(g&5_j_CJzq00?kH542-7}S8 zmPK3!U+QYdH9VWL97T8n4oCGWT71zE+SSh!>i1x-t!bHv#8QiM2?r0T^@rO}3Gmov z^4R84eZ#T~ealtTOvN_wo!04_V))s{OY7wUrO&1==7wIZJ9|yeTrpZ?)%)N_d+Ccg z6Q)OsEU&Gqo3`&0Q>Ii&^Swwx(VJF|k+1ShGGAt`FsTgaIl%L0LEp#6dfPSPq8^;_ zYY1#vHZiy6;kOCfO*P*BYFGaD zZLjW>%Q8<}q{yRmt0qFgX?MvH%N5<%W+!f`{rBE`sat4k;jQVeD9#s{JNtzJz#WQrnnBciXx+}$+qS*5UC#c9b8x(Vh- zw>?>U#g8&eBa}Gr*>CwpR~P5w>u%)o>%zIs|{~c<#ajjf9|c% ziw}-IR&)DYTb*ys-Ypkv1jPJK-kuS*^3j{ZrTH$uZP!@}pN@-JqW#q<)>87)a&(tAY~IQllke@>5h}H2|MX`IlcsQguzX&fvgeA^xkDYNC%-rzxP9}X znTo6{BJ#zU{6nox%AVYD$oz6MR$tF!WtIPZiWO&1*#QKt=3 zn^*ll+kNtrgsGrRVdLF5i#^PRi+baCIf}j25sTq+%*E`_j|HYmUJk0!DgCSHdM~8QY)vdky`3rcQu9?WH`H4Howw0#_U4Cx6=J?Yi9r>Mpa|*4NsZL5^ zS$BV_;spUy4qacz|0ZsG*dJfN=^AjT+~UKuLz=wb{|mLtPT_0gaFLg-otl+4yC_G) z&eCtg1P|}jEs<{83of-VnK?dFwC4XX$JADz^TthG(Iu&~#s58A^I@8|-~TTMAJsRm z__)8!m zmFFUPqO{zE7f$*6>qmZ(Mqs%7XP^CEE8RY+Gk&<>bau1fqh}Xgt@j+#zB~2g)u$&U zR=w4(+52R}B9#^Y?@nmZaJ#VSrTgM1QcBLN%>^n>s9n7zl@yx$B_q=#&D>M^{J|^* zj)E=EvT~&#-^ke+x?Mz3`bv^;O>U~W((VZjwwWw9g}0?eIY;lFpVgOt-+bETC%0Fh zefVm|p`Q~Ls75dMO4{=|=i|K1=PITiqoNo*X}oy7ZY`zc_jphE4Z=F>Pha z;Z6SE{@p5N`<2T)hkdE4)a0Ji1-coBCa=}CJpJmQL+0Xnb)5g_CWNfpZ6;T}SX0&{ z_4E1kr-zRCS8dcaVUCyJWq#r^?b5fSo!PgtZ`SNNQpRggq`mR<%QyD|lM;4UaPgkv zoLcfs#p%)Fg3o14UEkR_JETGdrd^wpqWD=NVrx~s)c1`{n?x>fm4E$Xw$es^Qgc}M z58?8oS~oI;V-ipNH<-Ntp?5g*6Qf7>CR=V@db`O@cD9S}`kg!cpD9_T91dOQxblG2 z+KsxR(Z|IWDt!34hV$m>)ea5sGk^Abon5T1)1LbMkruAH~;3&;6)3{c_%7smbQQQs!l@n7;U%xzIB{wyNy4 z#$TCREcz2YyN+*q@>aOlY^5{v&gsiV%U8!gta_xN-e>tMzBtj#wchsT%Tp&W3-<_p zb>~TsnbW<8+iddgRZ1_UnPE!{T{Z>PHjEq}v#N&Z!@ z_XfEF>mx?9x6LX(E#mT6&zfhO{=D!BTBR9ruO@sgwW+uFSbe5)ZCiQB8_}|q#CKIk ze%;lJ^|E6!^qX>f6Ax#Pe2tLC$9JpZSBr&zJU{K&lDE2R4yT-${`z0+GqK&l6S8?6 zS_3O)-cC*W&@#Ph(!LcDD<``wm{`Ac0;_^?UvY(zXy6yVTeh=LSMSm^RQpw5RIz8{ z%kA@n?(Gej-1|B3*GWP!xVGV~8MAKwfNXaEhf#+YLOvbllv=v2Jq5jJ)Zx8vRGKQzLT9 zzl8R8eeLL#7nh3b-y6?g{Gg})S%~Flj{5rWGVT6y_s;+BFC8CC&s2H>FB^v&xCIz5J$|zKQq#VQ zn5?upIhUH+VvTMlpZp$qRaIuvgzrr+{9Cs*q;Xkscb{-eI#+#)(bYvfiqI1`^(K!W(v-VG=Bdk@4~1xA%1`#A+1Z(0&XM2V&kUTD(kgo6=&Z~c0g}FA zE4gKqs`Dg0o^`sWTiPb07c;Y_&73TMY3qURJK5bi{rpd6sW0B>^QN=w z1T*)w+x=U5j5VFl{Kd(7QNFqdbrabE8J;PQhqIb^dRq{ zhd%As+xGN0Onp;5_SbEEX9{q&ZvlxLPy70%?G#5DJUq2`5`cc;DNdA&rO zzjemToR*mu9|Bj-6Lu+gslO~9#Jcjy0h{2rwwq>I2Djb%tgAZnrvIXFjg$PQMzZQ$ za~EpzIZS#G;T4hCWiQ7yfvfuxTbIPn7%OM5BW9bD^p%$G@QBvgo33=`yM4^g$safa zx~J@joU!KUig{5xZ5O~A5C2bWy(I9cGzmMS&%A*;|;hPkPGR%~?K zA#}-C_)qfTXYM8GCsQL-Q?go@#H1C~R6VqtrY@{HEj=`>EG(>iQKnZ|QDmr^ z(8I$5p@t4&nbM)LON6$EguUGP^1EB&)|tkq^+I`TUR~cA*3Nr_Wd>J>NZ9%R>lO+u zX{=u#_hnV&d!7H&m9!^CZvGv)*h$V{&e2%b&}yz==aj(OYmv95MQe;AtN-tQH*xp7 z$kp$zu6}2``rYQu@2WSyyPq!0u>7C6zwL}N+m>?MkTP4JaN9d!wui!Ph5Vc^M5)dy zV{R*VW({mU=PWT>)bo2fvq@p*qpIes3CtTybTg-_3g%c`4Ly8-``dfHFR!LOSaXgm zdqLr4`R^^ClzGp5QtRa4J-13A?8YitR{3@4mcvT41W)ZN0q6?2^lx&UcS- zX-BM;+AenCRNCri(}EwT?bDBc8n0_SUAIt^OFC`dwL@#o!p{kA$SpIGm9p7Ccm1r& z-LvlQ>$$u&pz<2;-(68lmqb@hvHp22>T;Zk%RcG8a+6B6{r;ZvjH=HGyWjOxA7!rY-B(rL`{mm5S$lN96?k4|kNSSN|66T} zdFrPv1r^^nw0zU|DsQMNt$y@HuCjc;uj%0%3l5f+Z;9A`zWRIWE<=__UlK~5@2D?* z>=zyq$!~Y4Y{x-9ueNWK=bk98`F^A1sl^4J>FL6kk1jAg!0Qpn=l}7GN5faa9ehR} z-?KuuugsH{axeeQ|7C6c*G}E%3qtvw51l;miSPfht5HW}1f^btUzGF|edpO`dZgv` z_2%EQ;oO4zQ+|YMIFZ6BOBxe=!Z?1r`gPyUX*Ok9Y&NgHMUnzbzifS)me6_B*E;E7A*aKEWq5?P}Vgm(>&AuGV~AJ!kK( zmzUGGJ*r~hvTn0pT&cDE=k$kj1U{8;zRz!&eKYAvYnx1^$e#NdySP0b7<=s6zp>bK z!>abuP2vweT-dNjd}pl`*EVfY1=WuFwk}a|Rvzid#t*$3e!bt=Ze4^V#2Z zV#fQ}%eMViUNW0&o7$Tawa}_*H#3&)4EnWVxw~+1`s>;{^_=a6e(MdaPi30$O<3xe z=vOTHtjzbv7wbd3-^=>7xOs1WE%|@+?W%cspU=y5v(HcIiL_onuV`M}V#^55OR>T? zKujDGwkXZwp&eeW{4oBKtZ;ipMC!84K^w3>?*>|7! zy*jWucJ`v^EvH1;?({9YG`Hs$-^tToFCTqtd}3|@SKjpBYcl>@Mzp+de>YRMarWM+ zbDw^m-NJM$xBa+`ay;#^n@ZMxu^El!i4{KrZ?Iwxb@HPPTYa%wFi1)54@^&U_19ec85B5jLNfmmEQF# zQ`|l8>KL8MTJpAf$$52_@|rtrNuer%>N(Z<&L8eK{Jj799`BJr`%v!;u_wHD@7OH3 zU(%lcc3qh)fBpRbe|GMj8Y{Y?Urho{ASCB**m_|X^S?O zd{Q^78iw~O<#uKE3Na=dTT&x1<85}jkbw*0re zzgpwRccq30Q3>YOVaj`%W9nzw@+tl(&*-l?6Cilwt6*!x7v?sHRSO+Xy#LNvH}CVXdvNw? zRrQ{YC2H{s5?v0v<06RF*%USfUcSaFu87qK_53#Llbj?p*dZ zMfaZ1)g*Q1y%EN8iD8$kKJ9NVQfu3iVPG!&H)^krfXu|0^uPBCB3`^t^FH#rw_^6n zmsy?XvgamDRhnDA;{58VF3Y~U<@WUNp6apW^lX`*B3_?EbX6MdYz>nCUM<^w_$%L{ z%ZoF1Sp9!ilw#CAk$81+ULM_wdlu`+4^B z&!nY!@117fD^6Oh_FLrG>3@%py-4-{bM5o5Tod=3+mfC5zD=upyh~u3YU@YAO-6ri z3uYD^JM_bkqc1hGkxT9F?pc5M#LF6=HqA1dx7)96>#Em`&mtFA3x4R0n7l@)CirTv zd{Q{i%bGt5eRdmODmcp6zE$`!SH$UX(=@5i7s_O(_FU+^_9@#>V)A{~x*40^t?K&S zQX)CCM}YmiC)=;ZnQ=|Er&*_VnuMoKYl*Rc>d6-_%vZ+Xy+bqd-J6dZl?}zs7C-d` z>fKuXCT5?18X2fGPs&$L{E~^EC!3_rF4f-2XIy`_S&8R{^!bJ4IXOjMEoJ?3>S=0f zl=k$<$nN`*p}F@LxR&~w7vI<#bXQ((X`JaSUEeVM$g94Wb#8wRy}U@{s_$u=eNRKV z`x0*Y-u9Dc^}3zNaX0q(%9Tr&UCH#k8hbt0`|2`j=Nl(u&%a*P>b&*ni>E>7-@ksE zo6oLvY@Pwbw7+*1REmn$o)*9Q_O8LB$7$1EFE;;nSEG&fVC>V0U%%e9NaW{jHjbL{ z_ppj<|2`?wV~IlR;9&WXFFHSYw5PHGz?!xnnO<4OU zCEvd$`unL(MOS=Y_}|T|*2;G5|NHjJ?Paq+_c*9*oonBA{n&GxuFcba8>Ct+{(R-Q z!nxy@l}}7`-x~92_i@{mEUDA;grx%A+1@w*d8wQdy7us?h}v2*eU z>B)z$r-j_>djIi-hs?93r8n+p73~b)A5;C!m+x!h+hyl={_uLQdw$R3e@D;VjIVga ztkb!Cz0M;7tSSomT`-o~$awzpUpRtY=Z zNZk-0aPQ&&*mIIcyx$kvn*KccL(k@u&r7Q*Yj>wVyZDpsynvV0TJ{XB$NMiAY*_yG z-cN-Z@dZo$7JR&E)pA@%?A`qpf^v+ehwf=Pu@zetswcJX>e}paMGhz9I zADnq=eCM^_=6;@Fv6ufz=CyxHwjybY^a}W*HrBj;Y~<8^>4t{jgNbvd-*;WMb=t-S<*m>7ukY5^ zn|?D%edQdcle=}(Zdp#eI5)>rH&pYn<;E%B|Ay!_1n7#ZZ4T=B8lWRhLLt7Ho^5?{K*OiCz&5FF#-sdOpCA9YQf#CmZrdn#W(PiBw)6OOl}NVjnd?NCO`Lk}!mTy61vyuj zZLN_G*`BYLr!(JZ*Yky!qc?oWd2haMn}6R8i?r(exiLznO6@lyLrZcC1NWO=h>O{6 zdXUe@a%-vD_Y2(BrG~b`gireksemTysZt(1{Hm$N^V8>Z!{o9INkNkXihI z!J6&6`?}oriav+^_u8MHke%eSw!fg@%Ce^NIXu?;d?gQUlrH%gX|ycktQ4==mP?{j zb8onxv1rWM{4Mj`PI0?uJB(wB|E==peX9SAX+qTJgHO)?-@PchBOpW9W%f>yhkqkH zIvg}S*viV1&rjOG^X5$P`}ddjn#(`3dvWWiY{-$#-0g4goyts=-`BK%?Y7HtYzq5& z5B)3bG5_bIaO%0t!o~Z){{D6A_K^oKGF}yWUHmz}@ZbBhzY6&!tF78k7oFO?VE4Jm zgZJ7iN@dTkE7H?D8Mm81YyRb?-RBP`-##tzDQ&JKb z*7f6mVon9rp5J%K?)a%M^KKuh=R0b!ciYqSx2wM>uPd?KGyS#7`l{Bg=g-AiuPXm{ zhtDi`-n-6HJ@?m^rAN!}pIB3>H{pqW`KAwd6FE2Xw?4jk=J#vceuWRQ9lzuC#r{_3 z-TKQn_4BKh@2^&0J^MFsyV{3)Hn(fv$}s=C^DVb(@1o4T{DD7gk1(zLuKC4&*_prd ziW=>nKl(M_JGHJ@BU&{4*pvA8HRtkQTv}d!Gv>b7;`&e0VUNlmr_@<({ju7dGb8@^ zw>r7QjrYxe{X723!Oi|fgx4b$JA3RgWJXl~$Ujo31+ zF!wuafYpU9K1{c~|1@(|Iwb38E%I3+(#YH$^2Vb?el&lQaGBruq_%P4U%QmUbsOIQvuNK`t+DWRX-U!+$AU|Y60;enJaX9~a&Y4> z#z$EZ7mn0*35YO7SvUzhhDbU#H`aZc;^-Bon6g3f7k7!m>T?W!UlopQ5C}c&;QaeR z+|C2<-#VV^c4Uc4aT8@^m~$atp7F!8kcICZFFdU)x|f(G`sZ-f!c+h1b_oc+%T$z* zo_ON#LdJf(xBF|0?$&-fT+6jX`40PGuk(jbB`DwFR$}g1^s7nvm6ozphO*XC@hLrWCg;eR+9Nvaj2R`9!mcJ=yPITI zznUF$U$3}^Z3KU z>ACk_yuY~P>BS$ZoYf|t^RqjbJl)75TX^7C#r7>Jo4Qj>-nUeDq=cMuu~=*Iz{cjP zi_JNABYQU^ZC54hG@JcVM(!-)S+$4$Mr~>cd!;`ogymhzlG7=cw<69Nt6bR;;@MT9 zxq8au!U~By5kGdc^!h}Z-3r-zcFE!Liq9J*`mRsmz7uhEi%3YNi|^Nnwf!N^#(|GF zM|ggj^0ltHM^@evHR?rUuLzd(2CPpxw(z$8ozeT`8WHY8l8Rc zbK65njXg)>^|`~=co|=w^Y(DpwFJhwT9dWc6kpW(y#Dg$fPJ48w7ovxH4dBp$smV& z+U2+PTb_7Ur#gghe$fAzH+ANP(07$n>yGLz-tQ1J-y?CK&qI5S?;lqcoIi2t zlIB(Rt<1GgB5pk6-}W@(#WByE&|4RtX{4wp&l2aXnY#33n27fiH+He)g#TR)Ygl4V zbIs|oJh@`kFRfFn&wZHX_hF&;|7)|jRbuzd6_aL;UH5P6D{+;4!$qqUt)D;Hyoi~< zpe6ikc3A3B?Tzm7hF+l}H)1BNpS7MjdSU!Tv$c`79)VxQBbg%?P7nxXys_?L=PK13 zCtfG5X1};r`S`jQ&$=cq$YzmSZ`i2M^!Mj9i|8xj%T1HYt}RYpsuccg>#A#y4qUxn z`piGVeA16=DG$?i?5}DcFnM&s%qiG3`J>r^dXsC3kA1RCHYb?|7ny(ZH``Qd&gUdF zCEBDn)%0(rdDp?MLA6(Z^`-m9n|WO{*Y-B^4%y1oW?Fkt)hm6=sRLVAU)cJ;F1w{B z`|8>Z)~=kbE3()(=3Tv&clC5$>5@FtDLJV}JHE~cdi?n5mnMC!*v#)rufLq$#QQ1t z`=+TUwDYw&@?Ud&|9aqXY3Q@1RZrE-U%lXaWuljJUH-)t+nnnSFZ2{%ud5XEd6suP z=aq%)%PE{M^v+EPPZkbV7ZWU0U#}^4_OHmvR7FGY$-RWh# z&_XrMH(S+JW!Ar7sC%zF{Y7)A>zvzedsClr*uUBH@)h&TFAH_bQ`MA{>JA?&SpH|m zyGP#dPW%a)&3ON)^o@IOZgxNP+nIN>jq5b?3DKulCPbS{^_+h(-9to9Rbs(4A-ijD zCJRpvPk%f2)}r}W6mHGCa_;_%x{g)*|JDYfs}tH%QG``O?8|1xE{@H@v7PybGk zo#G+Td{;_@L;gp|rGH-9hl}sTmz&i5cf4n`^rqcSJFXiG4{01W)84g3lcni(>7%Ja ze_kD$UuOExz}98r?fQ^APsMCf;Vs28`&I)AHql|ht|uA7{#UW(0+J@(VMjfGV0P2CJGyfoOstj_Y@ z^vbKN!VArp#o93av3gRb{U_qs;Y`~#x9qP8TVHE8SRJMF!#wGaR&_^cmXdxtn~bBl z|Lt@cTM>TasQ zKXupMN11f&yxXsJ_VzBz=}YYev$xJDvi&4uYW2}%f2XaVYJ246y(xEZl$GtX$+3LC z`)H?;vB9F{7qhpt+&H>=hiTg(1KS%Lo4PLXPTc$}yTDSl%5-g3tX}!nC%cO!Gu|HE zXFj!>^?c3Kf8ut0*551sX8k<0tNv=#X~CuX{`CvQ*F~R8b2*=Oqh71 zCAs|~S6p77Rjbu15aG_8Vldy(+I0ityU+Wki}H#FvU2iR$=#Fs|G{8i^_?=SM{Nf; ztvjmdSaslCj%eAh=8K0vPmBFM?H|L;GU@yj=ZS>pm0f9T{^0(HBYVbymf!Q7 ztZ9@5XaB z91;)6m@(0cnNNq?Pf}=m`|=EdXJ!s3zDS7G{y5NDvCY&Xf-Pm0;lY1LZ=d3*Hc~kB zeZ`0Q(Z?-1r<^MEd9(RRWovt(<@4KbLf#ZupQyN9{=9-~S;#$Wi#-)8er*w69LIT2 zv(&K(DtTO~>}}`Yu6{;_%c(R(D&hTc;kJfO;SJaP3g5h(qA{`PyQB>7S1IMzNsj~P zJ^Y!pHC+GyPdokQmD-|5Y#h~NKU808%y}F6Sg-HFxlZ%630Lon7Ar8_y&vW(TPc6v z*M4%@ftQUx-nHsoF0C<|b@GW{=)cI`N1E&IzAZe}D<}5Uuz+E;PW7P^@20VQ`y)41 z)F^fBU(SDL`HIi7wjD~XxjHTO#$&r1Ve$WJjo-6%7`-Tad0c2>-CPgTCDyh=#cHcI z+9cihyKei(zWX_ok35)p=KV~i_cK?$pPBZ4=DYVZ5Att*QuS(YK5y!rC${s_i$fmk ziYYz`T_*T;=G+~VBi>os{xgjICwMh7R5&nHI?|wL&HwFs!F?xBf8OABde@sj2R`pw zzG{Jfjo9}!hvaWhdtW${ds|)KmV5IaJU#IGbAz5%NcshfO^Wi>Q{JxD@3}btJm>wJ zr}wwF1(dtL_V-G!O1mEEoBSg@u*%Z&X7P{Oe?eE$#rOKNT`!+zA3X0*x?jN*0j|E* zX?ic?=l3w4KWaLE>9!R)>T_6Y?}t|3H?6<_wc>tn&Hb}h_t(~BEzXR8aPD6JO=kwD zT82Az42F!!Uypq6xc~kKPfkmbjC98_Vc-oxwbrG5ulPp^H`q zkN=YSUBR^a3{(O7Aw{$#bLni+X^$*pnKL6)(cbE8HzwLYV*YC~D4nO}k zxh$NzozMIzC7A|)c9%A#t^H`YeT#0EOe??Mm0JpXtLPo zz5n&~Dfii`y>gLG>lg(!QpDz+e!KZ8W5VzCJ1xt5ze@kj+a6vQuyJbk1+V?Pwp{hK z519I`z=CUY)~w$Rp2D|kG7BmW`AR%mA6${>b6ooL&zglhjHRY&XTFGV2wi!r_j;{{ z46Bm&+PC4aRb=F6`>?EiaQc|e+|{zFF%KSuF{Y&Yo%9uY{rP9oO+h)auGNn9xzZoL zsZ|@46kIc$ndtwu{`tc^@%<6=5`I5%&Sf6ISb_}u$;H6hFNT$2Bp%g-2JOBHNB!1CvHaH@g(55bu9#_p|0 zGkjO`8Kr&@RcLLK{<8m4lf^rCe&d3FQD$>oqAfLojyKGoq{EzL?!;7Wa;M42m`5~Y z>IZ#yy;J)adTDV^xH@Yg^8<+tDc6lQmGYk=|7<_cdUIyGKzir7?wLE!%?N9GeZ-3+ zCB-Ol>fGs51^PI5KB!sv`nl_yFLT6a)_=J)NqCc;edyCI=VMFu@YYY{o|Qc7Yw(MT zrJ-qVNh1D1+t++a(=l7Maj(3(u+-b=h(Z~^Ng0X0+tyx*by;}XiSLo~G_{4DSJtb% zO79JK-}ln!+Lk{xpPqQV^iNy7{o#v>#FKx&9o(twHgnmIPy43)@>}b^z5Gb)gI5b9 z*=^g8o$csZRvVJd_viC515Z(&9A7OL$6tDK4HAzWCRI;+tDdQ>6SGt5S#~zt{Oj9( zNON5*IOR3B@rHcub(by)D+Ax)lc%>SUH`BqueCI;_pxcxjg>5(CI{!eUmPJOw4;j8 z&vi*+;FZH>wPm|_HZ{L5pWDv8Z%r;&SAJZP#PaAY`}a9{aw3Iyv+mExX_^)su;|j6UyBl*R-L%pQ(eQ_ zq`h|WYPFBw_&s)5HJuKw{*-&qA z=HH_^T-8@BWd8ot_vl-1o8|fCn>nYa*-l*bi6x*afj?a7;0;?w_uVI|;xrlG{qjpw zk`(9(^Vt$9sMd3^m#Hx}fpCner>#RM`Vl{-5@I zy`U$QiF4yDtrz#F73G%(-TivVW5Yeug*>IU_l})iX=}`X=k!1CX?xyzzG!`H7Ng`H z|9_J$_bfI;m1L*=Hu9V5KTNcE6(oI6q{gG6GoZ0{CCl*{xjUqfSuNNwDX74K)w4d$ zD0bnF+J=LiM`x~7x>xm0{IsG($%?9@ay;{2M6|NboLS5lXmp{m@=dX$CR_2}>3?7C z5a>Bt_h)^lkP}mKTFbl0jq}bh94tELb!pmfgH~maFBP8>{cM+{d{PjOe8&~}Gf?=f z?vu&o+ov8-p3AWH$7!V>t4o$81b?zVEQBn&Ak^a zwzf40$v(U!dzV=vZE{ek_%^k2Gj&UE5l#-<@0kaKf{v#LXs%=B*b)#LIOFOv8?!#8 z3Cr%xaM~%xb5m!HV~=N5y|lB9$7-&tr)rD2F2%Su*JsZ8!c?46u_|TtmG1|(wP!xL z^y2VIt?4HN<8uVNE7}D%{Ptc^cg`u@beZ=K>#LGhi+{%RhEzZKIrX)Z_TdF*4)4#6 z=?P!;hG*5hwtmGG=MDECIO@=wT551#^y;hXDM{Ko{>yfXZaF4;G$|?9rKmR`?Lj7c zcMX@X!M`>>3&lBqE}8hm9b0fw@RaHI>dim1J9~KVU(P}Zr^VuK@C0k zW_{K-y;XNqN10>Y+W6;zS+)l&Ppw{=eP#TcHP2+?-V7l{gs8D&n)X*+Q3Z;}hcp;d2+qB|Y`RA;>OHTsb@ zy>H&hrR4`FMyc@ayH@hx5~t`pE02qwC)vGn-fp~RTw!kI_2@qL%0Nk(RTqLk-<3VE z1<{~Td*Bfp;eSMut`l_Ir7nu)pD5ozq z7F4;CTfge0#s+vs7q}@H^vNj^G2YYyK)7FaNgg=ThBsQY}4U z=Nb7@mv}ozcf<&rM|{1uCdy!)Bd4XErR}fXk>nK%0F1kYzZ znjLq$^M*vvl35e4o|0hscKujxcfr&=uYG^FadNajd*8;&nmy;`J$?_9`Ac(h)fXAP z57<>%FiD0@<^H-};leZ5DmA>0-RZX49qf3Vqdnx(JV(cCuWqe>9Txk##o6|ZWOP|; zcB0f--bGJx1^&oKZG9k$L`&Y=zqsGr|p2W{b6B2g~lUER!kQ27AVf)otE`Dcr{6Is0V<(clk$4@*6!5buX)ozjSJ?X^asQuf^Co4!i$C4)v+geE>Bip?Tf0T?wntp`4i@+# z5>wL1XfoBIMD}1OSIvpQ*vz{QB~uwq7zIk2nK-PSJT^C0&fgNh)XLcQ=er9D5>^Ty z&2}dUHJ!eZb*XbD_rhP_MXgk8Sl4a3RbW4J_48jr=MU6~lzngsYgxo1IrqDX@aYYT zw`G%>>nv;?Z^SjvoFwD(X-6gRL1wkT?q4e2>}fvUKG&y_QDXnqYX8ISa?Isg%ssWT z8?u;6gqOIUW_Fpex4NRK+F2%Gv#JPB($epljK|JwY6&PfWZ|-W|BUvXEK#o?&r-ON z>9SR6w#3ul7GVk>B3*9Ox6F#>GhzF;%bF|cgVfH|j~3qM`B3kyFsF}GL_$zv>0v9u zkFyh$5?h4!N_7fLaW=h8l;GI*Np@0!xPaI*o~F~2M1_uK^B4%7e>CCrLs>W5$xjzs z3M4C@n56Zz_Oa;1Tf7SvzrA_b(L=F0Ht)@jS$qn1Vgc2xm*&geyU56`!bky4Z&|~C)=9qBe3S3a_@MhW?cVW5>2HxXhiBS-wq5cd-poDGynI{J z#yXo_4{rU}(o8#|FEl~9jQ4l;>MiO^!cQ!6|Fp#0Xtn1r;S7(bTffPz*1sDUCNxv6 zqUPE5=x5x_Vv_DJ>u0||UlTSx!E47(VTZcDBfdQ^Lu>M9oLgLCp%+zPxrzCEWuG2% z6Ju&;VqgI$zscMWx*k4OA`K@V7i{_vqxbo=)^}T*?i$p(2RW83u zg{*f>uJxMss9Vt>@}ic9s8ry)<)srRr3$t-O}!pHDVj^{S!5hnp`^g}?=BJVK4lu{ zZ;I?IjM*3Q@vn2l(K^X#OXg1snYYMg?yibytHW33mPy7*7ctJAKd*hZ_3q_@p^V(d zIbX9*2)bX8n09|hl-#oR^XEO^R_4dWMBH2CKD8|4>+?-PR!g>+bgo%&(MBxs2G`Ox zpQeB9%iMTFe$}=Wm##TKUZ?SZL+6a*T=AcK)lWR!u`p!oRcraetrEUp?O(r{^Erv< zR^w6c#&=pXuW27TJ7HPWT+eu^BNrcf?fz`=;nl;AV*8$lSqo2P?S5^gb?e)plsa>4iC zmEFp#yg8Tk>OA+WabNGvGryL%>2~a$OR*AH-^JXLJ>oh4iSL{vSMNmLowrZu{*_yD zJFePYyA;3dV*G~N^8YsPZP`(KYSZnu9ke$Na&EEf)g>FAr^Zh{0@2k*LW=AD4f4_~ygEnoo?qixS_5+g_894f=L=ViC=lXRxNI;aoU@`Bx=#}Y3YmZWH0zpRHLwV@y^B1=M+B@DBovS`D8*~3UjVg zGNV!RQuEp?W`;+NW$xQKM4BrdHJ&SCxAvsn#?RJ9MFtONY;JJc6`*Hmc+ub^i*w@W*KkMD?oO<hj8B$VT}@IvLWWqJ_fc&!b~rO`CbXjbrBSn zE8D6ZK36|HSSn$4qWJ8%$*U)BU2W*MdW!REPS4erS~K(}_!=BK+w$bpJu9l!JGB9$a13cX!5vs~Y=`wz>J<{~sEC(|7%wv&Ac}W_6s+?7y3|=IF^; zhfVLFE$=?uvH$Gv)1lSfv9sF`|L!}yu;Z}wm(ay0&$4e0Ro@w^KhOC~>)EZnvE4@x zm!7yP_d{sckwo?!V~L{j6XnIq1?D#&6=+rWay;h=tmi)Xg+n33IHKrlciHCKRfZz@ z#g8+?!*VY&Zexqs-F~Scs(8;zF~<9gIBf1*w=lhX`|;^0<|+4UBQ0c3Md_T5>bbHr zr7xPP?_TrT#7ooSt}eGQ;k+08$MWs0+r?|`T?o-}!WJ$EP{AK0o$qxY!q8vFC2S zziLseZKM1v&Nr#0cl2WO*evF)>$rFEJW#OT+Jk z&af#nvAOv(r|pr<*N^k2=FXe?@ySD~>4R`da=cbje{dVrn*PHQC z{_`rM-+v3u-N^Hf)jgik_kD8oy=k#=wiauf?{P}W&3#&(__kJd@4dN;bJZuG`*=D1 z{^8quCZxpjzPcwh;caqx-sfX$duP}$^?pu5ex9+jS+i-@e)TxtH_*HtqBJte^i_uJ&zyGTXkb zCH)tb@0;e|7nOc5>+((_y|1Fl-Y{1-*hFsctF?E3#pj;7<9(_A)ievMy^ZUSowKb@ zpDXxLc6I2K-~aY4OwDEYwmd%^~zv7qc$l1oe z-~Ml}YGS>gaa8%KJ$#q;3%$KxbGY(Nq1CHR)%}Nmy6v;ezh343*53Q?{a^Ecl)bAd zRy2G+HJSPNpJ~_QxS!O!?YH=2Q8(vSlzq!iKSArWKmPAXsFI(#ed~+=ISqA3Vk@WB z{uO57`OMnnl)RxzL6WQWP}1hzdz2+RT^0qcG_6*U=luP!V5jYV<=Gx8lRTDftXed~ zYw0D8I;(h7wj?cJ&LQH2#QA+n4&)X>*9y#B(b5?ABkN{$aUr z-Pg7-IdALcg#JoXNJc1i2N-C``ldeL?H#V@6rbuw#e zECaJuwCDf%+32|Zw*L2jQGY(VrQdqPwWj*-##<|{&*4a6*gH3-SVCIlu6OeHzi+cd zeQKO)xqqKDvHfiRf8!IYm+$sC?^k;f&ok}wRS&)mmzkawb_;af7+xvc{ z=D$;8{_9u7v2PQWzOnOL@~w5Z?B%at`d0ftY1Sj_eRn2_O3dFs`Cas?iIWnotqo_r zwsf>=O7T2cQaiz2oN-G>?t!lx^k%#}Ul*ZrQQvS@_B}2n-<;S~Li+f~-mrP1kcK1||nsjcu)bg3% zYu2Py_N<-s{NJCF?(>`tkC$o$Fjrm_GjQDX`uWihHKATECyIhuvOYLpn3i(GPf6_Q zj~_37eCuBQICM#9_iO9MqLdu%RkteiS81(UxGrnfF7@-?R_m5c_TqnI|3a$fT}7tU zPKkxzmu$XXkU4A9#eEX94I_7E&bD#2mAEB1)jBhpwbx$a_QAO&deVKiA7~ZwL2% z9_31-KhKV3Oq$iBEV!-y?d-xu{{#9b8-3j1f1}ey+;`H{zZ;ex*_&(EW1RC?PQ+Iy z{J#I^3BDWnxZFZac(|CqUOV3%_;t%U=9<4&Q;)=!oA#c{4tsj$*Xe9~y=>M}>uuRq zahulN=5U?5UVHhMEiaE)6>ZU2_-Fs~($q8Y3-f>1tlB0LRsYY$F!cMW9i0yjD8JJA z{(JH2Y5Wz3KArh8u`pt7$(hxT#oK49TldWWwX$wHBVWPIEVY#5D~?S$(rZ4~EU9M3 zYyZm3O)=)jw^ZxZO$)5A>bh6)@t!g3Jk9u^4d04>#LZ5xJkwa*xc{%)GQ*M;_w*xI z{H>@yT7T5|?y~m7)#bLf!L^gmO?g{q7aSP=W69lLA7xB8uXy&qdxmN7pXYU3r}O{$ z&aA@0;CP$eA)BM&kus~(>No!n#fdlkX%=ajvx)zkxYEgZ^+uM@)jG3HlN9cy+Wj!U z#lmvB+Q!^USCen0qP@A8T9Mq0|Myj0GXgss?c$Fm+-G%io>_k6XUoqERRYSgD~nxr z9Q&={x{UcL1NTI^?%xG(xs{fDD4Q7Nkfib7P-RQjZ;saME*9@vCRRjPK1+P$Jf-Z^ z!de5u)kuFU{E|)ALkXN zb{CyVj~_L67v4P278fv4sVS=Kq2^H!2@B~aroDWEmWPl3Xo_L&YUWlsce=iw-J7RW z#@=8}_;dlDsi!~u&{V(TC%*VsaPQ~EN7VVuq%Rm1`rg=RtbTg2=q3L>{Cx&?ERnnC zZ2B^T_r*QEBTwYyKkiP}{&2!nP0~!5`)tIi)}N}+4;=ruH2oUnHzfuc+_MgsnZk+h({-FPf0D$*`;Jql|Ec z-kQ(;DxaUv>zSNdyw&B*&J7=bPdF}_t(F#|c%FTY#PY<=oVtFBp&WB&eQ?b7)m!!Q z{n|~e$7IfUDVSC*Qn|nMmd2D-yDxE{&;L+d8Gi0coN233eI!>=z4lf{?QO?SJ>v3I z%Uyfne%@84ny@qXCM~MjzKV6p#FCe07Tv|O%~Dcwu2tzzmhN!;b~ftzg=gYX!BeG9 zo4(C?c5av0>*-nNSkG=`|F&;^_KE*e##*cTb;VWOw+mQ&@`-yBlD+AIuhz}a#lfq3 zKbpBOy{xm^y?Pak)w(N<^}MsVnas0OY&WyB$KOA5;L0n}2{{p0T0^8oeZBYa?^Agl zc9GlQWB-(UR;e{BqLbJU$ka+yY}5O+;ZjV>%oN95G4?}U>=ILD4;!CueJM3j$~tOB zPF8`L*yd@MgM+#RtLAGRbMqksfCl(an4?lVO(qiWd zS>HH4-bi-aX4Z23OUrhcNA0{VRC9GjufNLHC5vN!@2HOa&UE42TM!4_;2ryZp#%^te+jThv{nAwbb`sJJY0=B<`5JBvabw-m1dT-fQev z*Ugn$@-eJHQtEk7>^#fX(k*q|`FzdCHf4J2MX6s(%zb?OU+&|B8;ZB}-*k)K^=Xn= z)I`4EXruj^8cARDvM(0D44<6+dd`kHIvK9fJLB!v@4mUMy0TQJt2R%XW$V0#hYuwl zzD#`17{q&fSM_^Esngf~pAB3y`)rik?Ab4qSKshB^kmk;C;5k_9=~koUSQRevR|`f z$~ESMZIcq#7Zw>`h*NX;v_|>s)n`iYwY-0n<^}xKe0F7debF?pynOS8`nkIe-|u~L zRW>+v<*H9cyFX>kPdxqiMaYuUGy0#`oKpE5*L-#Bgy7o}Onuu**3`A`+%;oe*ukCE z7h*hfp0?`GEm#<;J>h}1K-@o|!gFW+{ zlb0>$l5K^?H)})mAHHEfvqSrXQjnywkDYzN{@BS0b(Rr*A?hL@*WUQCyL@Za-h=o4 z-8tj3k1zY_yPmUKZFU{|F=yY}dYu>F?b1L0UZun&uY2InyM@VhZ}>liv!_(vE77mF z5$3G(`}xz}`qjTkbB6ghV*k#5F1Y{x^qhZZ**`|}Kl%0hqu`nF>$Oe_wM|$1m$ud& zQekkAb#QoRzwfolwa5E8g-tw!8x%k8?{KT%Y22{MvSHTs#$B^!G3hxLo;c8OZc$oR zX~F~bgg@$CT6_-{s6HrJtgwPpVZ&yDYo8f@vv^#u5=d9ka1Z9_5-xDB;;7cvFfuAQ zS*;Q5_9BFR!<)(te=3u0RXT*+Zhfjup8D%1$D^>0osXldThCQ>mAUO;4vcX5&{nIt zwJryzQk&j zcUUZ(d*@^3@5!BMJ}E-HpIZ3SGcK0@=JeRb?atMAp_Ff`WKaEHp^3GLhP{eONg~o; zE$BIFdWaIwsv&a;g zRGGHt$nAtxD)Ww+wewakSM}JcdSUwk{yho>Tgz)w7jaIwr`P_oJHE3$-KzNAj4QcU zl$f@A{<65@D=jt2ZOl`Rz>g2T9L&Lt~uSn}fYy*)l<#hFtpa#W8TF7UOUa_a2fQ2n%1 zZ?5UQ`F3un*g2!s-;Y+E5wZ8mcj{kLt|4j=G-uzrBj$cNGXrW3winkGznSQ5Vs$E) z?Oe>m6*m9;@927msQB8f(%JI-yFTa1J)QkI^9)LC3v_tT)iC?_u$;5mrC}p_Zb?Re z$-@)>8lv`1R==k#*0o(NP9SXF#()jo%k6U?oG9+zBI{pc?;V+t;pB6sMn6?Vc~eV= zW{QAL?Ds29s@*jkeRx!R4@v7>Ilz|saFej$k5oG~@mrsd{hFZeSF%NoS@hJAl#Lf8 z7X_%grJEEk2zpwwNzG?-z$cFF%eZICNVO~}*7Q;JHmW(H5aH-${LfLTzO(Dfv7G{Z zGc$f{a=E@~%c2Px^SjPStnT?D^e>#bS76neRLg^hoddhNJw#9cF=t|3R#dex$mQJT zo(-Etrf<&ao%&}QxBL?>-7Tv;wspUIV&u7{nC1K885X+YR{i#I<8!rICrwJ(ETbVM9PAxBZ}KOf zrwh7Q&9I*>)!6-jv%Br1l5TxB7wc@3iyfA}Ogn!zjdOxV&NY`PV(O2KuO*qc?;$~R54`|SAm>#g5i z>t1&4`_TR4W|!R(DSrQ1E1aTcx9sJU(c=Emz2_%ach%IK`DbN>W^epIDUN;Zwg)OJ zKX(~^Xl+diz4kfslgd>kskt(yM}uz0d4E1SiKE%;``1{G=7YOK|7(PvoqsmwXV7W+ zQ?us(EnhY3T!8Y_jolp^v-U`J8LF&K*!L-1F>8mn@TR1dzL!@iPMCkyX|L;Szq6~J zoBF+oygpy{|LL=e63y>2A|p#uyZ(l{3-H=bzkBD-Rn9H9J}@4R3_82Qx^B>O4ZVk@lr*VU4aQC^j0yNXYHm#6YBUFBWbw!8SX(>#>Zbd=Mw zY}5F(%RH6Kc(qTb*p~5Yzw=Ojr=$EX%k~|g_CHVMf4a*5vTfx$rZTLW$uM&!!|sU< z9dl2(xN$Ii_+yWHEM+FnMFC7=@}(@1$pWCj;4G&?YF(~FXm(R#Z93WB4{>!Qjs?2MAaf~>ve@i)?BkirXCV7-8c8i4wLKCzPJk^j<_JX@FmO04)$I>2d3YxA=Imd) zQ_8$mPA^PZtMjt0^Uteg-?wBRdVS95@z4H{_;3Fe1<$YEa*q46RPE+)?l$FY_scrm zPtA(g+x*-7l>73YEqRaZ?>s!cF#5&L4C9Xr4mOHyR&9;jbIn^PB33Hy`^?+Bgr=Te zF^NaKJmb|>wigQPbBa&?_-7d$+BHu|rQ7#ve=zHe6zO*R=G3gZhNI7nruC-+QJeV&k3%+IJrR+I#8ph7Ahp&kp_U zkmh(>!TzBB1pBilxeuGvZJs;*EUb8c-EHbctFpc}R^ zSFH1vSiaGITT<~iGW13JPlrj?+qZU1SvN&a{GR5$2FG{ZIaT@M2CvoKAK#6)?`?cj zc+5qt%iA~BWMSyp%`(Bf>+R(8(r$5fiQJo>*_{4)(u@55d#Sxo*Pr};%&^4u)79QD zMz#M`wnpf3=5lMK@Kpu8N-JHs>8M_8-^{D`^X98IsOB>11crLdJf)V9E1kKCb@TBO z>mRe1EnXLSprq7EErqRd%b{TB6y~fi@s-)eT0t!N&yDUz_w0$-v_;|16S1`>uYX?s zRlUG}q5IB#-aj3K6pG*4HLdH&xpRfZjPaXv*Yo?5b{?UXX$)z)3eFNfB83O@{jTe! zUY86zneAQqxF=sqO76|k)5e@x(f<6Yc8sbs8O(nd>)LMOnYPJUZ1=wxF*Aak!mWc( zI!`W&ogXz_YR4dWvoq^GPH($r z-_0|>Nafny8!yE@epoJ9ug%N$)64Jf)$a=Ox>2Fu)PhA$YkvLbc{e!aC2wQpVUy2F zVP0OUwVPz#lr*O(UfNLh>RbLUwwDv$1aAzP%XKJz;ZJ`N zy4Fh0W`m2*gULye8#^XGRt)5u7I!T9ebA+=)4!(IHzl%men0Ur==!Oxbzw|z7W`DO z`(`%%aA5VuMF*=kmOS3k8M5Ny_2}a#4iIba_ z^!;$jIKSbbz_KO-Ud6M~)o+Reg&iX;7v&cwtcoqox;*pKrX7hJ5zNsp^Wm)F$Rzsp78k(q9^M6rAt8X8X9m&TUn~uZ9lye{w#f?6AQxsx-aM3c4f+T z@qB5^1y=SI`E2*QQs-Jf;r;sbAy+c{Y32v2-0Xf+%Xrw1nq*!=v_7M|Xfynl7>vB@tt)qnmt_U=ZG9#ylTWATrdemi;RyUsE;+07>! z&oiF8cy+1TGuE$jQa&z|_O2^@dP^(*hT+Dekt?R8&MN=oxc-CCV`t|-XWnj4KQ6xS z)i0kX`&aF~ALIMRGOF=X&ikMrd*(`;r5oK$EGqpcDwr%)TiRdc?YOP>en##o7Rmh+ zJVTexa?fU&NH>b@Z5%$kP9HGjLrfNTGJ`S)F#()}&r4t`}fjxGIsD{6C+xk8+> z^2P~AR?E9OxqW;;Tgk|K%a*_QxTk#StlEC>f3Nn$2aW3s7peafM{Oo3pSv6S(wBkZ zkskvCq0_5P^oTgUT6N#&1HJR+%HH05SoZd|jmfvSZG1da7JQ0z?&F@bpKI#>KmWQn z^!r_3t@$OYcRj<)gF0K5Sg22b_?(}2L&$;u(Wm~cZrHSG)Bnk*LjI|*`m?^~UwEjU zz5RdxUw`(qF*P8tE(#~ zCud{xN1cIzg<%^*gC@fQZiW?144W7lG#Cy@Gi+dFC}CibWM~j)Sis8gfq|id;lXEN z1{S7m+Zcj_8`kMLgo-L?a|?*Fe)z_A;|4=X34@UlLtGq#t}X*VKf{0f=Kue1JrMrD z$-=OmAv(BWrJh5$=mIV738JhWpV%sHGvt&oSQ#-$#xdyYHi+>zu=D@e|3g7JUr@-; z(5Q@)>!0{{6XD4Q;^N;ID0DATnYzj7;x@Bu8x1dQHT|-A^MA|#oDOVC!g+#5eui9S zoU5j+oUvr)j+UJ)JK0quRi>_-vbA$t@5a8h6W7gMIRCG|^oPzK9u<{4Nhx!LMBW4i zY8o4Q78i1Ia~1h}ZTg{qJ~ww!a`Kw&>?P^xFXsPW&&cpz_`q+@3qM&Z>X|m#F~-hs zSo=Ti8^iqChVwQDmfJtL%U)egFT9_TTDzPXFaksNDL0^6RSq$M@a*Uzqp3{?6{7^7-}* zF8L20C|vk2JLP}VxBG9Ko7foZ93HQ|`t0lPy2U~EPEVhAJN#Fe)>OViSEBFF(WI@W zVeuAH-Wo!U>Nf*S=6S4)S!jGOz-H#Dj5jUcpI=*GFY(R1Tx@C5$((fw3Of5jf^XJ5 zod1Beq?^5Hr$FAK-;1^^>w4$dtW=XGz@1|6tW=6+1+%Sk_dHEs6ir{_x2U!Tp3U+{5yNcio$4C4W2r}YE`E_`O*J1@EU{ZE;{3(oxf&Rp#2p73-=vcAB_=%x$IK3rAz#SI!LC)4nt--|kk-?*X^Ru@di?EPfruKbDW#a?$ zO;0b{*EIzT$%lFOF)_}WX#d+u#(JUK#of>AzqI}gThQ;)a#hD;aqr8^n}to(uJuiN z(&_4XfU$|8Cq(ztr^6W=Cv8|HajLKIbB^eN6CUmPvifPkmM`7Aw`>ZjE&C#r z`n^~Du7v;Y!n#eS*Lp9 z*Vdm4j_Yi!lC8ckzHH~ONqe@+9f}Gp+$Zy_z`E(_6{~5QKISq@E=ya-@t^t@wa0Yo z9-fr1GyS3_ZYw>>E~k>+vT{?aZL4j)hO+QgH4Zbogu=7pW-n?_h)*+$o5faO>}cc9 zs%5^%SKBS#tkmv{snylVdpo?>z2#A<2<>*0mR@`LN`h&=+=<=c>pAt`OgeS3ZTh{p zuUqOHOBt7JEm_un_KjqTX3nH5e(pa5Z2FyJf7MK7XZ=1^-S}7C7oMsJ-U^$}`^;5^ z;UV9G*H~Bb+s-xDw0|l&tv`ETZ+Jv*>REYlp*J_&e4RFX-7TwHt9#5}{>Kl#wOTgu zNzaW~f6U`^4|#27%>L2q$t2H`fF#SGt{i6FC#nyw(fX3DR`x&FR{imo^Fed}-KhR8 zlgN5n@_TzhShPLZz{Pg zZ*%UkUM`kvc~E#Edy>!B&x?${yp&sc`^?s<9?i>mF5c6f&?c3QS9Df`*emi@f(()S(Uzg zkel}So7yGQ^JN>=9g=S}@SW<5zFZL>n6aw$w1lXuWN>VBg-(gfKkNU++m1Cla|MNc z`#8@vSfnoFmG>39>kC;r)c)DTBu(1JA!2OBc6a}bqWYH8?MrU5&OSJ$dv7S$Z$(R$ z^w~2y3n#u7SDm(KdG`BH=^F#)G#2yOO4u%a=IA)#$fg~+m5%8<_FuVJy@h@1Zo@av zFMixy;kxc*XR_v*jo(h|cfB;(bU`T3!b>AvyU_nOtGuh&RGlniuEwf#^-Z0dOdU}qHUnDV*j+p$NpRA z9ow;M`i8998QL~s{w5s1BBYc%-n1$%n|jJ+y4GLqzMB~r+v*&fX9X7a_f~RT6%)E7 z%`JJ}H+9q1ti|VRaOYbh86=C!0@dDOuUdxrDg_rf5J^1}On{mt*xfi}npA*Z@ z9n-gR`Qx{VO?B%vOZnMnTD<0d?%2F-&2r(jA^P9$N|nT(JihmjHBWH5_#K(B=IBo>uc`w63vPNb`}c`{fj2}cSm*a+`6;{FCttP*i@y^~f2nB9Q7Ke6apB%WZY8RYMGAU1=B3wb z3*VZ)Dv4Kh>f4f)^WtaO{b*J#6xy5pgFVRS#ryW7U93jG;??KWCw+NW{a`hRfZUD{ z_txp(!>mdt&9SkZW4Q3|o-XTPg>0T~EltDl(@PB3C!18;iD%YT>qS2cU)NHZDWbRR z?cOtcc-&3x{G@zjA3shnniIAxbn4B#TU?pxulNOvPu9;B`g5&=ucgGRaPEZP>UN*6 ztJrQjbnoPr2kkwdSZkjtr&w8ft~YB>IkEa&-bFj@*(Jo#I!IkZk{E`P87s zn0-o0$N#9$+PwK!*fZl>Kfj#*eeSKTe!EI#tZFr%ujne151ZSVW?WHb^SN!;>3?eG zm!EyyVh1HnCKTuG3Y_^-AYu0O>gU@Izr3~1_MqI2uZg}-IKtMw+_Qi4_5Zqi_PO3H zzqWCzsH;v4_r3E6F6=$ld^I(A8SkAm|J?Gtt(Nsw_jWBvd%v!#(op#F@z?{u>ZHP+ ze&)Qq@1~||MV9PW#;Vv`xjJ3u{U^WQS$?i=-iL;J3NwD>imTKf2t0RhcJ6mQrmy?g z?RAi!{qerSY`e<%OlP;!*P{QXSN;C}+wX$7iPj6A@MZIV#IEY~2>*HO*k5b^@0X@* zzHoi}jU^Y(zWcV`{);}-CV6{<-+v#P1_)gLGx7X{_)ixM{{7j_e{{>?B=fRuC5AzL zbwAvlmlbV067 zLE&mgmX$)?ljr@kT(#@Mv|HZ0wV9^IJ~fQ&c9X$Eo@oK<0htZw7H7?f$`INjUs-Q(KBC~*{Q6xN5^r@q+`(P< zBz<0?lpx!af0dbn6WAYy{uB&j@{D_l z6E}I<>Ank0&J5I?lF?khNI_wbdY!9&ft&m{_p?2Ttt&gG{OPsyrFHUkIwozV#Vhrt!K8q+A6krn_9^q?Qey;-+uS=`_{e4j>&)Zi_*3?MIg-6WrEHN3<4Ki+ zB_CHZ?WtLF#O1IGUyh~Nj3*t(RTh4A@mQFms;Bwzvx}TWv&=)6v!7BpCDeYg=1F?z z>@1u3{Lc|T^~6^5+R1-K)+`kH`SD5Q^DEKIQ$qD#X)Fw34oSK^F{StOmH&1o)0un3 zmb94V|5}j9&aU??bNQ4je^s&`n&kO-w|)uv`%%PMVws4Z=63T<1^rtp&Rhxc)GoSY zvhB;2IUij7S6$hEBXiGl&DR<{l5#T-KECrYzC`A!jFP?#Vxwm3C;c*2%YWk$+fk-kxe&(h*6uROEl=PRe5Zy*0$IxUj-wdIC@oh(;EcKf+*SSlIu z{$+~A&APWYU(Kk@ejStll7%N|zqYyvT+5OCLTyy79Gfosvo%B(27+5)%5$*AO3Z#DwcM| zyxU_t6Q`I)GxxE#2i@CWm#Bwsy-#W(t?idit{Z#?G(PQbi>)KWOY+xA1DZ|5p3VMLug@EilTS zs@t8V^=du;>#D@p*$$Jox=w5Rzam(4{s<1=H|K_d|5}jEm+#+ zH+Q+Uk<0y0ORcj43nq(Z7%kZ`dA;gv6_we-R`Q?EYHx5u_D4kPb+=5{d%w{IwRb& zBu(PMGT%AdZ`7OYXuE#ge_Kwuh<9pO%7N5^tf%(pwsRi0j_}(S9-^imc1`6$*^)

qB)Dp!ONr2wm~C6PJ_&Odb3d^4cifX%QB$XcEHRk#jM;Rxy0W$V zq02vS7aQN^-to-(`LUDkJA=<9O0znOe=)ixyH`FVcY>|r?3mTpTy1opUJFZg7Gyef zC^USws*8oKlF82B*CN{zj%r_9=JfX1vDKD6QjsGS z{<*?B;Zo$%E3B($FZ~s>ck3Nqy(^WS(yGrdN%qdVn_AGTWRutP>S)OOm3Qa)TD@#> zmweT(^&uP`Ma+E^Q#%VXKvH+;9j+@e#+|T=c+MNx+BUihh8;w z`dT@czw1Hi^6d2NoX~@n{8?YWXYlaxq*`gDm-xm+Ww<>}Oz+`2eDO*V@2ZM#AJW3M zxTtwCRjh_=+C7YTG-Rm>IuRqjx<6f^!(~Z~1x6b;0u==HW_unmCQ_X*I zD;OWY?Row9=G6&oLZzoZS!wUx<8Gk%`ONk&2?u5|X$!43GJ0jU`o`j8IXvAQTCY>{4K(%cDhiamg>M5wb#45{EE=Fr+%x0RkJU~ ztlG1Fu>*ge=Q8EvSJ;ieCA+q(uf4iUGQC>&XVKg9-%RG0ORiz(F`+REI-(^|F=gqz(>^`%hc!{u? zZ)3i}{>5oatE9TN?R!)+X;$7-gY4H&Pk&!q^9u zoF<%|{r+qAd;Z|%yWOwf3_bX=EQ|BH+^N9+fO5fuUnA}uH!I|^d+Ade|9#=pr;L(! z^P~@5d=}2%K2Lx8J;wZV69djqJaJA?@~z;Wdl%o`SML1FYkEJqcP6i>bxGo?O^j%j`pL8thUxv%dK3&x@XlHRo@u>sbbV+b8=t?(RC<<;m}s*WUVS zdBx}6pY*5c%bQ$ydldFOUNFyCwA=W}`6U`n#aA~QXYKgRa{sgE&CfmaKChYkdCvRK zHcj13|GJg-b_?C_-ZZDXYhL%Nx!qE~PS*Z8o$B@0?U(lr`{`@TroXshz17;nRDea| z^ZppaM*fN=&X&QPD;!P-UOcrnYD)QId%ry#TU!2FaxHk9nD>LTh3$(ZDJ=vOF zl2`cP+T71AbDvC!d;L#(!_nUiQmh&atF}&J&iO5trL*gm;)V3r?DND@Hd)068^)XO zkTP@)X2|21mc6dNBL4i@J0&{;7-~<;7hkyLDiL43?!twh^zyt<@(qvFj5b^6+&l8! zyvlrSYIA(lcaC2w+gU;ss&bj$K9UXSkDqrr)^*SE^z**zzrGeS{u6B6`s(ps>r92@ zx4LJKyxpU(D4W61`laxo*bO)RJ?sA*kn8@u^T75GwMR8eWT#fmy%6QVT2}2}ruuI- z%fGfP>HiiW<=4ek}y zZQf=SJ^#=@$Q(^7rb07pI?~&tl8(!&V+Bjn6}jR{+{g=;cOAQU##qt;-Bz; zQyBWz8Xs(lY2S7rSL?#1m;VyOUtIHeaC6VMZR@|+UHAVd!1?oaY)3$H-uBzCrT@z2 zuFWe~5SZn&&LjDsgAUj1v+pu;{{<-ZdFZr-6hHJZ>J;j><&aX1x0t}UTAgdzL<5aC zw;6c~UQbY;(7fb)&61N$*L3g z5!w&g^gHX)gG2CAIngn**;}AAY#_zhhD7g=^ny50zixZF%*f>O7# z60c_0^II$Kbh58FpxrCvwd;?d+R~SM1Rc{ZB?>v6y6QRMhzR4kzRO$G7WfH;9y0g& zC-NglqDq#@UuDs{Huu?!<{x(!Jw3N6e8x(jjHJYWuTFP~pFd?$G$&PP)~xv=C!X(} z%o6COcXVRmti$FfFX`ezMWU*p8sIg=;0 zri)H)>GX@cw!}It^5TZrG{GeK`Cf|-esRiJXe4x~;*!L#<^t>GTEAQOEt>lFu9E7s znMcj^W4L18s6Pv=opI@Yd{&s*k^>$OuCF`NaIK_y^Sa5uHflf9VyKJxbLI8V2agx< zmwjEbj(=O{K~HwR#jO*KyKHV^>IQ!s+$v3B>+hJU1mrTEQ zz#u#)WnM@5GtrpMhkup-$#6O|qn#4@;`O&XY>!DAOey9|yI3-<_VIcL z=L*w8tq(!5Z*v)^f9@1N_PfRQc{d9WYps28Nlp6kT?*Cz{~3BI{+XHc{3ZYN@|9xO z3>9BK_`GCJ`FXi(|J6L@e_Zfvd0=?0`NhkG1fAY)p{PqmXU%2RR>wA2y)<*t^AlI> zExW+3;e;0;vkt6@m9{Gn=(%)U`^c<+s^{KB%QJ3U*|__!);Y_jq>R{`o^ZRwElR%KB-h?YH8q?O4Nz68qi&=d_Ufm`-N`5cex}016;q{F&EZ<9#7^}p#=q{b} zwAD-Ld+^WZvon3Zw5)mES+woX7SZh0Q@xf+xpf(^ElNr{I!At4_PU)}OK&W@wy3r{ zYvZ?1J6FwrK4-DC+tPzYGw=02PjZxze(o_zw022*8>3d5-)4=qhPRfnotO~6R#9#D zjR)}$XEF9gJJ%SlwTyrI%jZC`@{h8qtvSoDJlS61vvlR!t?%6LUh0VQPTsh7?b_+z zu60IbKi{}^@A>v`a!V3!E6kjmyyd!B!t3W5tyXqkJ>)50z|17jp*^`N;fy7V z>ERdZ&vIK<&7alw@vOwM6`R|CeJt-Ve17i!jI#G{BBwCLpS3Frc`2}A_O;^|4vBns zO#T$ivc&FHU8KBqMoCG<|J9RUtJo}<5Z>11R4n6A_ul17dKHtV`O=*7xe60n z?@jb6n7>GB?cxS0o0tQ9!E#x(3op*v$MpBk5|M+#>ZaXWpM5zqD=;!uWQX11TU(n1 z6co1Jm*syZ_#xon-5QQ&6T4r^>lYi|Fi!g>{$%oLk=Jb@H=To0|CcUZ_gn3xQh8m$ zn%dBq4@E6ke_z`9`jS-c-+SeY|NWZ1;(6f|xgF6fij(C|P1Sw>z0!I|)$GF$zSiCO zxmEw5{-JgEt9dt7?lkoK|IX^K&bmDx&zg!=a0+x-zFw)Bta$gy&I*BsD}pUbPaRcX zcBj4h{qtn~)|3D26n<<}_%ZV!$7YeTTv3MAtljXYW0WR z9~fRvJg{)HL29@?>ko#D*BBBXI=Gddx7( zoZ#Z#vfTU0dke$+(>Uw{Tpk3w1ZyY)=PqKu2og8^H#BQF#04Swpw1Lq$+Yjpz10f zK5uW`yuFr593p#7Ww!AP1#v0`m%hAst81f$RNVuaTCK;$eq9&lc9|{`P2Q^>x>ay7 zx5T!rCU?Q51;2Y<$cbNmEtNMv`O^i-(1VUfLSo^?g5Mp){p+Vr;1=2>C&Ogf@sD$| zptbDp$FFQJZBu)ATKgHV-8DP=DSN_I?y5XY3KIIp@p#(T<403fBsAX5Fje9f;THOv zE7F?u(NgM--b_A;`7YBuI;DbhJ3_>#oq8qZ`#|s@p=V^Et0^t|=g!zOU)k?q+*@k@V9SIdbC zUn9M01@Etv{{f3ir$+pmSaErA#qKjDQ#}iPCRLn%>@l}wn-v+R?)N#-fuxOFLB+b*TXd@Vk5*Ck5bVT*!xl09df zRO}~@v}Ipp!yMgqZOq7;8oEZh#_fGZPT!VN-}EqJ&n!8M#Xr>2b9K5msmR|q`6j?p z`&i*Pzuwk&x?<04r<}Cfd0Kk)J=X6Jnf^;IWw>m^GE1tlamKsC`M+NTIqaGBc=fE+ z)gdchE4eKQc6l7^GClOjh0r5gLXUh3{3E)yWA54$VkcW~ukA2j+p&MG$A?zmQ*%5T zHaN^!f1_iK%c12iTDu#*o1R~?!$FKkVOjHHhZ7B(Jj5mDE{np!?aI1$&Wb}PTiuu_-MMw zdfl|O{{`oTnJs8aJKW!L+)a3yx8n2D3;g^P4ZSw{gikydcc$X7plGzt^fL)5rybtu zE7bN^m&UKMY}OSzloS*zec-Jl z?Jv~HH@z{y=u^OE0dDbaJ=52^{fb?C=Kh{nGIK9%>tA*{{J`Tb&Gp?Af3|&EI5F^^ zxS#v-MXPqN5?Z_H-QsyCRy^!j$hfLEe(I@f41#)>be6aKFP^dU(52T&Q{Jp+by#vC zd+kRV?_ZDC&-|6qGO^YALu$~J^-E3FT-B5_{j-~TpoJ15yde{s*6|A7)} ze1@UwpCb4-$A;U)O_>pYa>Ct$<(GMU!$KcM_Zf%!%k=#S?|E}p{CxG+N9CsBU?7Fln=H8asaRM{d%Tx|~taQu2cDHAK@FBnZ zKkmxR-eY_Jr^)^Pg*?^EmHs7P&8<+rT(T`suSvlx&gC4a>p*WSo|?!qK9GK zl~UKd>cEFy%It}~Pb;#YY2|E-F83~L{O6T4^*zS6aRd)%Cj+N;ag ztS(PlUH)oux!BtBd27o9*OphZ#=f_D7uv>^(HxbO_Hys#%k1x1rXMXYN{jimqEMay)^#;ZcG;fnQlER|L++7|j596?XME~sSm`q)O*KxtY@D{;_}K^3 zXCms(R?G)_83png=j?ku$NJcx>&KYxA8Yy|7-P-QV#p9P({RylL-|FWJLYz_tmpi1 z>QKR|VERa3sqVsh&M zo?+6>jY@wf8tv!Y(`GpT-o^+?hIQxVAHMOJeDBPR`#dYpgv|aIG3$PO)$gON6yULes|-;uPg6=pLu}CL6coz!Xx>>VhJhdv|Y>|l8gtgF*=>`TY0)CIeXQe zV86u6=k`STEncT9eDb`o*Pn;i{EQWJxu5n3@|=5oQg_kO^QOHzr_264yrX+JOK-_j zpF>qTjD_iuw(6EFVyY9wIcF@tQ26hs`oDAP%RT0V>HbMSnf83E^70Mup1nG9{6jKB zg;TLb^8&8T#;*+jGZpU2@~H0@`n=-#=c-S}8TIuUyt5k&>UaFF<9sx|w(Q#E2@MLi zr(aC`AM@#bHJipodB^BEUeD(&|2#XyaazYk_bL5z(wyV0gkt(`+`KY{@z_uQKnqsFr#{jFzD)URZ|(#70a+{yDRTw*R8p^=XDR=+q!Fx zq|;nam#+G>IrWlzSIR7Vtg?vtre4IWj{Rc$7jIu*A9#N5^{-23uvOgJx|PfEZZueCO7EzwWAdgIv}3%MYhr zd*AXi-*B(X#`I3sJ&nbC=7gTwI`>!W{#QNqk!M;L*htzuPY&eVVEH6q)iqa<(>s0M zvIyQ1eR)m3^OL9B{)lULBI~XPGQRelcqp`T%FI08o;rO8$3rq3&s!!Pue|!^%f$Z{ zwX7dnUn||ol1nVtVJ}@?BgOah-T#ldU->Wg{JdgQcHDl|^J8cJMReX*TmNKL;S+&_ z3_JWje7actcE;=bdg;+Wo+};~wD9?0!iq%~TR7RZHkOxfZrHT>N;zZi>6wA=?O3kNICL~Jdiorv=ZshU7+rX-B`jZ8 zw)gzb8DcipGe4a8&iJoBQA7WAvfks3=WZ3BXewj)@b7xNv0S@x{*|@jm(t2CetEaC zo5kt&FWNu%?Ygsqum3o2$Wsbh!|S}pV}s2e=QrWmeoi-JuVnqb>uj5I=G?>2ewQ4? zUoPKfx={aJy=}s;7(v##d!6s(DA;me=8LVed1Se+zIWcArlRul-G*yEoR2IFHY!g2 zX8mnqLC?3ZTULJ558i%Bx7Pn{<=0u2R}=Ry{qfrH%*UA5&$%}I;Mlp*B&EZ{Yp++L zMZSB{)x8_HWPf#!IQ%x_>j^2_vv#Fr+8+)5f1U^qXRA$(bGa&E{4(0_#opUzc1$nY z!TbMT+gi-1y<#lQv6Iz}Z zxLUnPRo*HhF4;VPf71IfKVSdi6AF1c<=*{Ce(MEg&po{K#zygQ!hsbNGEH9{Xlbr1 zy!Gbj+uz^Y8;y5P*~%%&$-Yon`-~_LKS!JMh7}Bq)k_#y48F2W{vw}JpD^R>(n}(9 zm{lfg{E!h*@5^^L`rQ9>%3YLN(B8nHwBy$4<$Q1L8z!0A zo)(egxP7I3pYvZUsd?q!wQpPv*5#eISkaj2MgII5jjw;{Cue<>YiV>YZdRRWlf;uL zt&!B6zEZizZHc%Pi=kQc<$`7M-FS* zg+eyo{Sa`T%lPaEh4UNU2q=dgwtRF!Ty$NWaZ`$m=z0DoB^{&o3Daezj(usrqj7{w zFF> zVY|Zi+@^y@!iM`al-6hNf3bsSt6|i?>5?nM=W+MVQFolMcxrN~56{v-_KPOzTjx)f zU&Y40VZr8>-|U@l^KzL~c?FfG_$Q`q)#zT=u#THGWJv>u*2HMz{1rzf|24KA=ZJiC z!J@8ka#yBOR}6RK>$4UKpWJ#w%>#-WXTRPi;HlfP?%mwQHo7r7*G$Ua=grp4Htpp4 z$9-cC?@wcfmU-$eFZZcG>pLgaU@EDuw{(frqqZFGLT#OvJFWA?9A`6c|G#me#-DAG zv!k{rP0PIfMY*pqGSvE4(Se`s*Y~&mD(L)`7@~aE@~H=RzM~JvO23X8^&U>enJmY9 zcqYgDD*jD&>8ky|;X`I;VT;i|%P9wU+BP*^S8mUUXq7PBZmtr~xvV+Z@y-tu^-q^- z{7>JEyB~9I)`Bf(OnD#be14a?T4(h!t+s{)PL9<-5phfIIwD*p1&?MaF1VKC$>?C1 z-T%0x^No4^9frEb^~-$(Ztf1BKk<<7&&dS=nNzx~s+EHox^BId*l^C?La_Ew@AQbL z>cU0hJ(HL!O&&Hay3AeOrob?5Yn=>}jsO8EoF3&6Da*^6A}@=ebv~=4^${ z5uwS(;mecP&Fc&C;R)#2utj;|%vt77w9i#H6sZR`Fs#}7Z`sALMBRt~935V8Br^3~ zoS^QJz4<>sqeVh*%^i0B*wu|^Dl4QLOa+QV+1lmV9iCrX@N`Pkl|!Wr>KgI9kA>H{ z9$Xr8NXbXo&uTYs*okKM@8Q23eI;`%t!C;zuNCp}Kf$s5Ci@SQri95~r+oVR+0!dB zR_W9`FAvr8-rG1b4Skv=#aG_m-pl&Snq}in-G9XaEi7{s>V(?l-^lw1aQ)4hW%Bwj z6X(D6GD1g|1bVDvn4%maX5_d_Gi2%y|D;`|PYa`17uIY2V}2pZcF<%> zF=xkZ_GPAQ2d@~}CxnVRY8U%S;pT$h!o1%S&sO#y=oVqSUh4HDW6w#J z)rx=qCaQaEQ)hT`tnI~d@mYDsp^qkWF%I&?jjDAK@{8R1riN|lm{>&@ta!Ou2EA34Bo{N{3 z-$=O{pVCpkC@o{(rKN2PR~VZmyos>#Sf0Sq9wVkFS{JZy$L2R?>N&ZtCUzHc)uOL| zE)`|--mJR6k2BnGZFc(Jom`shmQDQ;x->49-SK|W@wE29mH%dIR7B;^Tw?L7MdW(b z-o-K9l;liTrg8R0XM;{j`ejK`ZH_PH_ z7q+OKKN2&^O?Bld151WC%U^TNebL|7sFgT1YR;y|4Of>5UG=^DE_zPVg?TfD)=38V zzbQVnk8S6yrIpdgW|Wyf-&NZ3*Xoe}p-nvV7r&Ete6Z6e{brW3R#~pow=##V3M^CI zq8B_(%#>5Gm=QHWnRmBD&Xw@xXM#K|H@x+n5nz|VYM0r2>rvN^1zbHd7tG5(^6a+H z)l0u8ylzXLB0c$(XM76VrIoc3x@?oV|6iY{Y-uEO&nTiu`3{$_=-reP#%tYntGm3g zUe&Zzdumqx&rUUoM8DHD_v6dzLtai#JNJIwty`P5R z!}K#c+VErd-?qbN5-vp@Y|gonP^);xvmh`v!(?{zopJ_~Mazq>T`S*uYMxlL*DlqW z7ufkcD$5ub%Ys&Xwq$ zS2cX^Y`(HQlWWSUcarJd4{fuPHcYNp|dq%7EjiD+qWCG zzg|3B{cYT<24y|fjLY-%uNgUAIQ8M+L343Wo22vM$C9qSbFlNNczIV%D2*|a)#CTu zYPnhAPa9cpnfxqU+%(nV_SXc}r-pgSdcUIL&#X#i6f=1~dA7A(`ifsMlW$i^>FQYT z6Rfkj-cr`DbolOT!v*T^erU6JS-IS2JUg|rz9nW}O5){}3dJ@(5*Pu+kDr|F&mk)kjIYhyB~D zbF%_p--uTIt&(wRPsz8No9{nLvx-!E!FaRobIh6JI}D4z);Y5O`lb0PHuB}OEAk#a z;TK=lyDPn9mpA%QZ@08gLE=mE`&hQsFCPEz`aQ9im2dY_?PHR2xcH_id}rrnFtE_S z7JL4FtpE9W*N*%ZoHYHT_WE!A|4xOyTmNtCva&Be7x!|;?(lRzbpG#J^Zq^GOPDmy zv%JV|{<33FbKac!c^USl?e3Y2_dF_6xaU}DRa{wn@#gEBRUM)k9z|_ir?eSP;~d^q<`xnZ5tt|}{Qi$hn!bXX{R8Ij>PKx9rWz?tQ&zjEq;^?( znSlDT4a&<}L{!3+mlYYW`W~SATyH_2hC;sKBB5`~4_F?!W}`4yaT%xQvad%KW-2bz zw@`4gQCMlIAf>qMu*$;ECX3!!E_iLRV1kiSt7)2xZptCel&RJ!LV7BahDqO4)As2r zd^cIf7qGNFc8R*igBtsU29>nu=8M{No;*}fR8&utW0bsnL}KF-nGZqIlb6Z_ZIvmC zp7=ph@}jbsp`84M;}YDl5}eN`6ik&6E)y|YCAz6le$(xV9C0E-yfQ`nG99NxyH1I6 za!j7|OrTg$`eLfc#e34%e~WA^6fbn2vElZ_NlufBR!rP9N9NPf38!v}dTh-8Cuk>P zt+@2A#e)sXYUy@C=B9}q8dKPmrwN)*3s4f|S9~^AJME#lYNo~{0rS*fdcT-6wWcNc zG*=$+uUqpa=7?+Fsy}n}nIF3dTX zy3Eh_-|eoL`)e++Y`pQLp(nrj$dSG~ds^l!U)Cb~H6rMJMCYv|28Tmb7PmOOJaVLC zPTIqWw3az%xMqa~>hfOC|EjTi9Pe|#}E3%Uh zWj4i3`X8d!=ET$!!*TpfTz8XH&mHOKN8YO3Ke+OQ<=YJ9R2&8r08JXVjegzVlIary8TBt+DFCb1U!n ztUS&!^Q3XBPgm<=!JX;skpin$I-c72oxxS2xbTKs-2;|PmXwL6rk)!v2I^ENe&BFD zVSC~Z_a&dArb7wKeO@17vVW-KFefN^iGkA}4TpDk?swiPZ@aXpS!Zjbk!G8g?NS@t zcCE!rY!UOQ?Pww0^h($1X1YYa+e`7@FS;@a~ zV*jJ`J=P_`YfV7@jt}#=95PiI>J?Wy&CUP1oFjDYg>$PomNWfr;*$QXB+e6XC?@cn zPwYhDkOk#|7Xuc)iVb9}3_MpCxX?{^YkKJ4+PJKg(7OE4t4X16ssl|DrfyFNwKR+= zFAD68)JzW!tW&&IP!P!JJ^6TC;I!l!{soc!o|nC90$YCFUpBp!(Ik}j%G#o^rFm0# zUb!;&eps&Ng41Q@v-m!C-4a@Tr}LEG`BT@vf1dUJ^fSg;r+8np`6Pt8yNYfN^=1pS z^h^C{S~}CBKw#6V*|V2zZ(Wx1Xw%<)n+gwBZF#;Zdi|o#-J7;GFZ+LFmz(yEoeVR= zoiD4EN6t@*b;^%*<9G4dkQKU1CuT!t@S?o)J7#R%{8DD)%8G4yr+2Q|xOi>hYN@pC z^Xyl|^e}FVyUgdzC#kA^|@|xK#FJI|@T2|hmt1J38?`o~&wb#O;TMunHecdEh zF?26yc(0ql-xb&XMs2a4VB)KMWw&w3!+)a5jN7smTMQCRg)PFAzlhF#v`sZ@=4rv7 z(j3*pEoI|h?4AOD_e}}4-1$|3F?O-~SINJj@h$I|cIU=-pY>z-Izi^G zi>I$ALv1Yk*OuV3Q5=6)2yfW4q=;?uw$8sr3l}}AIhgm9=f>H%;FIx|tHSSYbTF@H zjImjGd*}LFCl{`_T+uj>W1sc{%@sQ;F0HaP-L$(P`NWc?J7=%h7qocgiv_!L7RY~C z5`Ah%<)@U2h>df%ZK^NWQa)#MT*QV-_3ctqnB;=5i(Cuv=Znx!40~^U|K9T$`;;p- z6XM@+1h4-bUb9$g&7Vc}dzb6>tjP7+QTKhVUGe_63)W@dSXeEvzB+$L>(iCC-%Bib z3VxUsTkKiQYH-0nFTkAT#^JVm-}YL+@vxk8uqkVL^{OuRyj@pbsI7Q;K|wTpe@2PRjcVJk+W%QF_sTA<`gOBDZMDx^S?|BI z>fv&0?G+V1437#dzcr$xI;dd9Ch#ca2h`>_@g#q1*_oYE8wY-#Fq@!hVRzpEw{e2 zXPxnxY1XsRVcB%6D6V7SuXZ07JH}R5&A`fS%zsxz#o1#0XGQ51lRW0NzSIAF((7!- zA?MqrsxP&;mBS7n@k}ml`73+lsqQ0R`)cMJy>EXu82hWAeim*!@jz^Lx2@I`Q#)qi zUR&?YQNgubUnflCZrv(8%S^x}M!n&f(~Jt$GYP7PK3hyar(%4ogeOulcDC;3(^|{l zX`EirEO%4jQBwcuj|}&s+|?XDY;D}D>e{@{UZ;HL*USB172CFU?WuBIztU`F;ku;{ z%X51(mYPoZlNa>1as6e-lIxxR53Y4j^_466J+a_#(1DuMzQ1>0Yi&H#TD<9_x_4~9 z{^J@y(gRE|k+@3+o3A#rP7snp9Km}55o^{q0kD@Bs7 z{xe;xWVcMPSYxs2UCsNt1ECCT#kOYaufM$6qZGera*{)`y8`A|9Cs=x8TROsVI+R<_;bdC7*n z>JLwNHs*70W@qc#!m4qbecHBE_1)>pTPo)oxrJPx5nk|J~_SJzuy%f`?Td~ z&aUG|2Yx#>-uk{T{%PP2qtLiVYPTQN7pXSLeSc}IWMLE46z}}MXqm1q@ zd;e0a;?|?vPHR_7d?-v^uyo1)kkcF1A8x5SopABwoUa??^QO;#ekzma{JpOh?FDBA zcb>}(J@>Zutn8KZ**;(Xy`9#-dwTrpIcg7Pc3qp3_AgB2Mc|S%u~Tlu<-CoPSQT>M zLgAxhzMT(#DsND>pClccaozay-}r^yaW0LWm4)B7|5>}hcKQmI6?ZS*Xj?a7oy&jQ)+0-wG*4Z9Vd3$AYikRq#r`(j zY%VghW$O12an?rrcb9Mcp1yZxP3(!q;eRzhE1W#OJMguNrMvjy`*w|U%(B-PO-N>E z{uA(^Cp;kh@{8ZkUE1SIt}pdJ?xOVYNyhanI`6+^UH_u@{!HfeGraHLcwg5!QGHfp zhGBiiyAog7XW9RjKd_0}9&>F^fB5cI3;s9NweET(URJiY-|FxltNSr)4hr207u1Q` zx?z9Af`o}v{C(TbKl1+S^yvC0Zv|!PuT{!l-7?C5a@?=UKKg9cd9$HNJZN~pI-+nK8CB9Aj>$wNlx7z&wv+S#$ zP)7R3YWMxWBkr4rus`}#{@wTK^*t^3H!*Z%UU;Rr`T4TXzl%QnzIpF^>euS%C)JBT z*t7oo+Wd~);Ge91kM#QYZfE8h3+*?ZwW@l>)6nYsi#_i%GyePS5I<@Dg9ml-3||yj zQyc;mbfmO4Of9Te5Mb+ze|lbK;RboB=|b5Or~W0d=uF(7Az`#JMMRG|VlLaOj};m_ z6M5Dz2|k#>pnHU4t@Wf74XRg~TGi<{`)?i7-36D$-|d-vbV+N3)^6SHldl#nOf*X6}HHZHmTUNY!V(XyQ zlHs~r=%B1zgIu!AG3Uq8{@J@EIU^Tr&F_CcB~RdOmenee{r4w#zHZ+)D{4-MIQt>K zlAedEXE}uz>T(=A!+J;9jp<`vb&{yddeM5Z*9STuFKxO%C5BH%uW-BZ?|{zD*7j-> z*blx|(_j5mUE$PO$p`UYvu~A|pVqFoP+kA(r^A7DQY?>`XGr||n7EF+b7Arajf#qE zA9MNY*58XxoYmd&;CaO4;B)q>=jO;}YOk)^@V4Mn z;D0;MM^%@jcg;9s(-=JUiBr}tN$#83I{GigLT8!R%-vi&=Y)dX#tE`-1X7oEa;hCj z?Dx(6Wj*tk((SrQAC1#u4K~!xZd3G=TOZo`zodDSly8pmUxyF8qSs55dgQN{`ONtH zei=X4!DofnBPYyZC`s~q9=f{Wx%@o2MeFyw{l6e6^W;}StVP%_@h_X+X?^9|vhAt+ z+;=)PmMJzJ!CX!E=X9+Mn7CtEXUE5B7g}$;^S_mSQE6(}ku@LZU4OMQc%FGq^~cC- zvE|!$o7X!0Sbs}ye{tNBLe8AmL9CUf^Bj&g21I2uxZZbr*8J+m+evP^t8>nGOv%XA zU!FPp_1*Oo)!EmpF)TIOKO;>$^Q~ zjm)mR@i`Ks@Tz9z@{svf*HpetPj;ECUsrF-bGoiH4wy{;Dcb33uOqNQpn= zbKLK-w@K3Uu20Nis!wa*#~NSkzpN*gRs1J#^6Bnvnx=_e9VebldOf-8?G}@zoJ}j4 z|6O`u_eRwBmEfHv=MGHFugpFr@jzpFZ{zRFOTC}17PeS=Mt$bl)QnShs+Jo?f=??= zS?B*gb5Sbq-MIyQ*=ZI}78J^@o>TOm?eyPVj+1gc29HH6Cw~^=KbgsG@uXJb{r6vS zDZgGtl|?HD-(X$v+&v)GD7o@f%Ov|J);g1n6N>#?ITnla-OS)9u1sS2wQ1RdTuCqANwa(wA?^kEW+{Ezf@u9gg5&oqi_jkX~pPG4MYgms8dnX%n zz|mcz`qR5zOeQ5xP5yUE$S2BTxzn>C!ActW%cTU zN=8qF-mwX*bGEAfI1>>W)#b4LlK4{7vwxJUJk)RAnD+CuU4#1!iH}P~d12u{2dKi4@!`bAyF)ynxBqbiSX!zsj?{Iq`pI%kto9{k5&FsD$&^c4^hh2(tnD?lP*7X7KA{ZNHGdNau5QU}I421Iuvbl$6#}*NVb=)ITqbEfG-;zRCYejx#MGEBd9Nqc7L(WzCY{lITi)WsGK2gE;O$+18nTPX^Z_MngR&)J4V?o^1 zPT|tEA#V=bYC8S=xWjQ)XJStpm;BF-`DZ@NxcqgA#s5u)-7d){dmcHnojo7?I%`K| zbY0NP_sYRi7GENpC$paX+L+8JP|GpxQH3J!t-z~SW`))HI{U2p%<}I1H_Zoz+~F!~ zpSr~yk6CytdD+T0OP^`JD0Ow6^K<={jmNfBzu=Lo6|oKtKfbK`wt^#H>OzLOf_+wUWL zC}HmX+K$v?f@iB5uP(gXy1)9f*`bK%0=u@XZEn18a&omcH^)b-Yt;*9@A_T&V7i|wNozWM0 zE%mnQhNHE;Jf~OG6&824&PhKts_Md>Qd4@%!% zKYf`)GP_^uWcjlt|0*ZUc=#{g=soLSt7_$+FMdDZ2vIw6+4<$40`@b-eW@yOcb{jj zeLU%hZ-IY>)UsOJFc!OYw%KzxZ{lo_wuv%7t~X!y^7X5_sduf*CrrG^VfVlCf0d@{ z{cAj7wcm19YO=5Y`S73q_1yp4?_cd+e_SYN%XQ!6?;jscJD;-K;qbHf_pW~qo4+}O z(Lb+j>(rjP7MDD0?fG7AKhInFZ(;lW~E_iq<%7OeaCzx?(HT*+LnJ< zt75MoC6Z#q?q|xL*7>D)FPBUv-=x!dAAOc>Ilkyk{~`a#C#v_e3wVCr?y%~}{mF91 zN=))np+|JU&9l~j-*SKc!1qZv<wHc;oT)#*rL5As`m!v=Q%+J- z?&W%>DMwCZ#mHVMl$cT^Mt+E%rSlrgigL^_M)!GlJ$^ccg`+ z#D!0>Gh6Xq-m>Bi+vZ0NzBaF3s79^37Bm z$Kx+?W@jI4*?h4=rb|UY{6>E1_xU}qvv~CXd~8ntYX2hR=-UYb26MJ73edGn7PEh< zuqse?=j#jmXWZixIpsR@{oyyu*n~DQ3uUASzFZ*kD_rP>nfQycz?b|}U-%2Z&=-G^ zA0R0=MIt0#NWxA`!eK>^{Zz??LXr=~Bqv^&abe2L4MH;u#AntmHk_-OfdG;SUCzsckT@Eefc9|4^r7}VKX}O}?@)a!tTnzK)-YxXrKBN7;t?|3M zBL^n$yt8w)enqIz(WW{L0T1sUsa(aSC(d4|emi;k_ier^$vRw%@4MeFYpvXPY8CH! z^VIxpr>=ZzcQM1{-P+c&+oo^(dg$Jyd*Wyk(&$QYauydmIS`CFe({|m@QudrS>x2l?t1h|uo)_b* zdfT3tUfuJycKMRIFXr!AIAOWlv+o6mV5w12M& zZB=Y~#>aoq#MxMwvvGaD)csj2mbt9)esg&1111$uxo>G({(duiz(r1+pQxNMVam8 zH*EQJeBH!2Yv-SC`!ama?U=MFrsMj>&-&-~opk!-U-+o}QpVHHCWVbwCr-5GFr1AQ z`gLrlUP@%PqpMt>&hjOa$B!+XKi7Bb^<7po>N3rCwh?=_Rkhc=_porqzs3`RS%r6nx&=(tzA3%d{VZo?_GI(!8#+s0T7OA;^zzcN4F)Ge ztgAjdRXt;Fh}`gc;xG5^xH+Z~Px+>DDsvp z3uellI^ndhZ??vs<%j&QziV=DYP%`!m(H^LUB;R1K6f&*VmoTLPpnQ#*vhkS{R?lC z{dz8CtXp5&>1?wttG&Zw*!Fz!Z3ExL_a@rY*CZdecvvU>!*SiRhjMLYfgD;wnU5b$ z(k?n-#k+m+5+j8vc2UhQCo(8y|>v@5y z>(uXkPTD8up`;^w=B3KPrOtnOLneMvymi7du6V|Jwp*_nW@ofJ-F#{)xbaELg*d_ZchlhYPNO#oe0~h(}gr@yX0#whB<8y zyZQgdyQ1e}KN{E9?1``G^!sjAV!CCj-L&6^LMM#%x>epRJ}U5PHoyF41z)Fr#m`qF z9Mg~cwkjL-zYmvJJSujw=Ce@61znvVi&a)8ZJP7Z@|w4MMTblGH+w6-pL>cv&s@j( z>5yILdSxD4hLg(!g_!^U@;01Yp7JZMmvzy?=GNu1e$^s*7SkS`__EDvx%JjhV(q6~ zR=1cu*(j5GMbGYRw!pko@>}kIg5KJ5cW-W-dHbf&mbibewa1IH zw`;~uX1;swHb38S)0jeQ6Z>5w3 z*7SWmeof$MvjdCEr%#=`bNtlBtJ|t`zMWB8x4oVH^fqg;&{s=M_sZ27%zgLw`|9QF ztOeJm{yq8gt$P5s&E|u@CcO^Mdh+Z?>5GtCH{Ry`z4iX5r$^%bHcwY$pOhc5PF{QW z&Fa2%qj`axwSoHoQ;#kvOMZB#dL{MeoDGiiOi~!UR&Q99b=PO%E5;9RQ^RjG|4_K^ zxZ>_~?bwDJZnHUkBeUBc$~d&`YU4;~5^DC7brUh2xA$pb?~8J2txe@#l6P+9NL=F& z_iPWDHTCHJk8j?FtG~1@xx6{6-NrXU;6qyHv^d^~907IR^0=f6_t!l8@GZYIplsu2 z?SJc!&O91>N28`;5A)eOwG$I&XwBBQnIsoeTHRJ-nxL|)DYf$DtedCJoVinZv~E7W z_p(a%?21pWd(WLp%JG@2H1AW#ul8Gyn@l&oFMc)OPJOfR?TyDaJ?}en{8@3CBh%j4 zf8hNV7KOD{_LNuI?37%oz2{rt^8>dw_Ux?a5iNRleBG?`um2pBWI9oz!BiW+B#XLW+wY30@RxR!aISV6#bn){-0F`)eAKWiGQwz7#TMh-Pw4-((?t zgYj>|zl)(Zt;;p#lJj<%GhSAE*SKj(@2}a0g{_sn!gk>**N)#Wo4kK-|DIEl#b>8^ zt~WH;X7=Hu@dFLL&GmfyeH1vVL<9PT!vhj$C4RM1*}kjOI%VPCwa?7bru^7lRr>sa z+Ox&p_r*>2OiDa>?aRKx3$eTS+pifV+9t>5{903?d+CJppWT|>B0mpxXtayZ{MTT6 zUS*5>pAZQLlYPmDHD|1U;qm;>~!hW`6@qRmhHM>Q_w1MZS577 zNBVwR6OvRLc$f=I^YT~!{eSQJxmz!PY);28LPwI2#e5Q|sfM za}q0z2p&ZHJ-I;j9Oxk0y9vplvuCBNAJ4f_W_I$}wpMGDCSPveEUE3%NYLM5Bz1%IAz+jfAhmu{hGh(*Zm)V=C7!$tNS^+va+zSu(Y%^H#fJc>gwp|=-01aojQ5)MRWh9^Zsyg+NGj&Dklkvd=Sj>!Sl=ivw!|CKK?)d+1#D|TRWGxF5JEHUiZXrlmDshJvXb@ zVP{b6!VuMM9)?=^dN$QoD$F(wLQ)Pd>R*2P=Jx&DvX9@yzI+S&`fb~XZ{I$D^ZW8m z@AEe`MMXnnV{dQo-|4j&|A(m@`tNb%hx|;I z|BEL)st@_~S)TXJzr}m+*MI5%*}u{9zv1?0_Se4sIeu^Ee~aCp<;(LKj^sZ89YH(w z#Q#HI_m_X?=3=R6J{G<9nRC8l4nd z+JEdb*t)T1rPJnvMcH?rI^7JHi&W@RJ6W@oaYw*9^NTsgk;yZZHyxQ9vhU)HfsC)ln%~nS1E&FX-UvJxc_qX`8fQ6gCzDtN$?4Go1^V^3@?)#g# zJN92rE#BF;^>kQ!b`6c`CZ@o9-3;%zf(X#J-zzyz23LYAoVNa(<^cZlkF=b!>%6|0Ww2=G_ zQj^k(3s&v>&i(aq-zlkID<_#g{$d>Xqda2bM2_yNS8MX!qp}aiugf~?6kB#Ze6a-M z-|IQodzHWM-SKpJz?Fm>A1>~B^4o0P%_WC-1vQ5-&%RXZp2%c&IfaiYW3$W3#GYiq zFHbk#)TxxyRWAPZuHI|W{mGe}8y5t0IG1~$C=ZstSpH)2hsV1%Om+&FF%PPo|1JFU zg98~KgQh$Gy#B`Fn8U|MkJdb#^yxrXm7cfv0>Kk9_A=b6Z*`7tlg)bk{)WsI$D+kw zv?H%|_TS3v`90YxH&m+Ez17^dm3`&?10QbWIo>aud3FE6C)bE2F<{qvKwrg8$ zLtKB%fAwo=!0$csbsMHVyI}O*T2bX!_VbnQ7hZ1*YHl;KVl|a`a3HI!R-!p(TYS-) zyccCfY^4@U;-nt$6|ylE_LrF&@@b9q)c(maVYe*f>TOd4qrYCYm2x+K6@28-=;V6rP`eiSWqZ_v_|^dS67Fa z1y_oby!OqWy^}p{`OgQ!zmGhUN@ipF-qx#OciPq8`f#;1?;D;=iZ|q6d0#wNtj*=$ zRI_q!#{5p@cP?2?vlq#3f26(a^UD<7*ORvP=UvO_*(4sBwvOQDzs$unqHr8K?{V{9Tgzias_F*r_ zxibf3<~pC+cUm*cutfOprlXCkyxwT1|8YBWIi!n6g+)#3g!>hf=xIsYH+X1QSj>%> zFf;9Q>7$-~PY!0aIyf#Du6uL;e1%QH)cA;l%Re=0J*dxFb(ZzSsW;6VPj2e})@|Ij z>(o)1Efcn8-OMPBU2%27>#xBE->P|i-q$D}|HvN{eKc*&%+|d^g|nR-S&l>%uUmU0 zW#v}ZN#_rihu!PuEc7_68^YmZxTMkBJ%O6@NduR_%$3U!rh-wDd&cZkhfqtjiW8l!w^X4y-AAI7$e@3y7}Z8#sE7g<6NI()27;mGU^2f>`!y5t}a@TWv{ zFnM#UhsBhj@71dee6m^g$V|Ff@pt!~`6jH(oBe%feo7STmNm9iF}dQUH~l87{H#6N zBF4GB&xF!*FWm^{E)Hwsw`3RRyrlX1)(1bg+u(A1#5G?Ui!(#Huj04Tf%-@J+VdCdPVDx=4Ul5 z5GlMjS5@GcfXdFqke3-TmCN-v&UmX)5WQt`X75SmD-RMaT61!G_HHv$ymgMF>fY(k z8vs!sbP10+d6JJF0Z@>LhTduJSBpolyRDudmUr^fw-zr+w#eYIUnj z+9R}aUXj>-J3XNW??*mgjlRk@hF{&D%9*<|>!bP9kkeP?&oE1@S-bqv!(JxGo8;baI^Sm z>@;KJGtFr`MHc8~{hRe*5&uCO-+LXo|AHe-nnE1ed9~d)pK1#_C;suEo5ap359U|C znN_*()yjpr+PNyzBpZ%f)w!$E_olB}d{g`EOZ_e4_og%7lV1Jv_xUg3XTqv-<#*28 z&-k9bLU!lY+G*`^-)%Evyidb zaVNFcyKh~e`{>-`g)SGICTVp~6TQ%L=fKxn)nC@l{a5y;p)bBl;`du7FRK}PPColC zE$>Qh&-E3b{5|;=7yrE}_UVj7`7HfB#)^ zZ;_nG4zt_ai)@w!MyHF$#n0T;Azx<8wa)Kh{PYhzaY6-G*FD}DAO5ZGV%O^1=aZY` zufH?jRkZw9Uh-z0kL}mqt+Wodes_UMGW?p@owmRFck3f3|9&3+=KKC#N>*myGK)I; z6Y|}TJMQ0^=412uF54Y<5AkiC(q{*qIXzG<7ZFV(l#FGXmm57(H;hmDa71pw z?iCW}QxBfs&ta`|B|KH$a|4UKL|Iv9cWfsefw$a?sullT5bI(BcZ$U!lFcn-k0&JT0)OQD@_wN zxO;UxT`_;>?rB%EJN~ZjKf5Ap^RNA3*X!4<{C_9fUKl$~%n1s*@NvWc) zPwxbz?n%wsmGg(|)aK43T;1}n$J8z!f5_wgluO!cfnPMQ_i-WrxYCo)xVB$R>7N*+ z=flhI!>b$5`&^!P{jshU&$}|N^kkIvXZZGJ3vbx`{HQVo9A6JS9)a1`el53 zW%7IH#PrUo>z#A7YgW1YnqRV8-^gv9CAIaQ)Yi_{%@exx)EDhjKU(`>-O6)9x&jis zf--ZT3DsJz+Ron7Hlu%^UT>Sh(Tx?ILFc>oJ@5Ki(|a@8)#gao&RS6hY31Kisy`M= zon7el#aLJDn9?y5lV^8jWfL4(et5FF%Kl#M^Riu1T(0C!^aQ15uRs3WDl$2OT*{BW zD0OLkobmpmg-u4Cp?b3Yv=)yE7Un(^h0^6s-4@7i%er$s!$jF!+qB%LZLykaX^&8G zlcw9Bj4NlUO*Q$>uWl9DpAw=w$9$E`N%@WT zA-o}{lZ<7O>o+W0F;8{VURBwtY9HUI7WE|NuAIraAb4h$n$`E?>}ys3c6C1wT(+pj zZ;_36Z??C{^uEn}&YNw66GhD@Jo5W`vFrc#DII6$`D|LYd`+s@TrvK{X(79&3DqoP z6%_J!pS$7ilq{yR^2?UVdCtA|Q%sw8u10%X(aU*mF9h0E=f2vo?D;9#+c^^_{ht=r zG1oj``c_~{YJN0t5kIt%ce}cdTwr7*|Jo{-sG)qZ?3plSG3vq z%sn%I+RD_dl&Y3%FD4mv&wXk&|8d>?xYoH^+opXIx30VV)c;6?&9%ljGnXjstp_zq ze;JmaGct?&Kl}U9P zNfMG594GHBg`GJjk}^+Ok94wnU#gt5Zpxe}%PY4oF0we6o7QU4HuKWc z)~)G=5eYx@Z`|B1cT{!4PPb{6A6~m!8C5R1(Yo$+>lTa5>QvTc3$`tiE*Ji{v1Rqn zq#vv<)pLYw<_SIjY#}*k56?7_Dc>edH|5*b|7Hyzy+RLTD+ zc9Mz2X^Dt;HnYCv?Ae(!clsj{$?6TCHm&*QQ$Mf8hO<=Z1(*KJ9|g1CeA>L{)7L|; z-6e^V#)m(YgncXeyE!C9(q^%lopau$BgLCj=A8QXF=G4Y7l|{1IOcru^`7K8ODgL; zlVM=#+OIKoZ&#&CDr(JqvUTyQ@)=JyZJJV{SfyxB#iflaBq(ASHriZ_S2-VdcF#^ zdbP3Qv&JEIUEbB$cY~#hEEJ!?^DMBR{1po+i_E53XF$uhe(#N$$r@8e9Kl z7_}-HZ8Dnlxx;x&Mp(`1v(eg3XMVhXKSfhM?#!xb36G~b|NIxdSm|A{YhTRNdL~2>0i#=`FzIo775aXOofjn?*Sc0 zy4+y1Jp0~irQMdl-`=pQiOzK2@>AzZ=9>$KFEhJ1=4-4JG`+LD zck|;b6Ekb)Cu;snk8JXO>usZFRgbE?XUQLnXb7pO7hg(+JEKD9`kEY<*xnsFqZxC)9vryKG1L$m^sDD z;O*0=mNC+v*LLiT7C8K+bbs%QsshInS*hpD?e920*}K(Of78qi+P!D#dhO{Q4^`_w zEpc=C)*QZUbKiII>XKjK)24mub^Exq&1X@74FA;!+aw=8sSFT*`nh-KDc;;oPd>z` z^nCty_`tRNe(|Q-vXwDv4cC7CEo4{Qds=Y?`@!kQGvD9ZmlAEIlWm>3*!e<`%MtE> zY1_CMX$Z)OGKWM;aVZ1e^=v|v$<=L`Mw+1a{kSH;5j$I((b9l zolh%b*9l!S3!c|p7C33w#p`Uhoh0IXET&!PFlM;0?$p$ol0QNN_^+Q*Fn3F~^b5OJ z&~f`e^V*&@tETTTdKi91XUS=m*f3+&SiRp)I$h@%uyvHPIqOf}o5WYDG;P=F)u%SK zre`_umKjdU6J*_<$i%?({86ly;&96RClr`FUU9lVrzNl;^K>}YcDq3 z3ytSzbz5Uct>kuwMDLt+f0t0HjP$#S%(FaBO^j3Cu}W-7-eaqH&ht_)&d2Pw zk3HBLb$VGu_O6tVvtR8wthtvf|Ic(&N%5O24QJjAFr|wrYZjRJB zZnnYnTh7*7J^M2snlAR-9VZ}mJv3ER-+s=D?N?Xro@NkfacQgAs_Vk6uVQ@fN6c;D zo%efF!H1jEx^KuFj^5H2wR6Jj#}{s=@!hPubF1w0&5t{7i8b8cwSA+(oJqfT-KywX zwPE#y&1Y^^_GWE85w+{0Ht(TZu21g%4c%*fY}@yTo1Z6c-7dZLxV>Q0mfU8g3D&C0 z_g8NZ&Dkm@yz~9By=}I8fBSBKyYbq^n(fE?ch>6}KNnnRJ@ZlEDj^rUxyn%&r!T!8 z9C`1!@y3&hp(Tm2OSDQ0iuN2**t=5SHs+e$8Tp%fE>a>!LL8=s#nKzM@z$To*v?hbX|JBN-BjVpljYlAY1Hg}_G9kzId`uwFMl&HQop!% z)Bds(Y@6;zy^Q+*N@m}FAN^AnO!=bTE*jZgucW?9`mOWIIlU_5#I5{!Hp<7X9X?;( zzSb`EpPj(WIi535@hr9uxWI8~+NVpi{CjWp zDXaKn^4h`@M@}7CtGZ){(eeeX|JHkJEe-ToxKhsSqisvyHI=&Ek6L&4E&Cj{!S=xx z)d%~&WyM+w6o1#go?m+I-j{3kSMKh(v8wO(|8-G*yCt1&Sch5EE(ugvzmH=^#@CbU zZr#W`)Vr^9`dW)-uS5O&^{(w_`>Ds}ck<;TM*|=Ts+m7ik?#CW_pK$lh z;cIs;-oCdt{cgSBn_o$`Kbm*QMf|hb@YA;7iOmTa8F>@^k6(5E{i=9yWc{)0`*tp_ zUvj0grr_+9pgD<~*7!u$x~!!-jzvp;U%&Q<;t z_y5Yjwv}^}>$yjvil@Ia^jIuerquVVcXPv);Gb)29_YHxw|J7K9}=L#>#MWr`P9Nx z%_zgIKitd zpy7Vz!Q)0R)oDKSr{%A`I>COzk_u%;{li&`;b(XZna`QKTTYbYa(e%%g5{j}!}F1B zg}V1=`z_meTQ+~)#;jun8{gf2a8_JqOXr99^w=x2Wm8q2{9tRm7Z$U8(kI!1EBhxk z?p6-+{Mb2t6}z-?vS-h;+q3ier`~a$RPkZ{RQ8Qa7~Ps=HR3L_POJLq8h*OxlkXl? z&7M0oOT7;7zF;~3QvIIg-dUgX{L0E4>KJbP$e!o+eSSyE^;68oQ;(kVD~tK&u%={zM;LGm$CsxnReh#VVYeWB&i1c&BUO$`w`}*B?*3v0Y)c=$T8$-|zS4efFx# z_lwhg$@?bxe^j6($<|jBTkpCowD$fmRDV;jq-utUv@a0=3Kw)gx1}qE3DL1``4+hKRQok z<)V$P%U0!H{jy};>n%?fEqwp=%aX(o;&($YYc&0hysYAQHuSX4;ir+@5fh%Q%8k7E zWliqg4Nq1j-~RYzO|pH%yJfE}4*py8dd;)9i=OX#_-WDex(QE~y{{~ES^M1fNvECm z|1#6<%zv95E+#ykSsQ9v(63%<=n)ZJY{*i6=WIq;x$Fv~b60G3Njx=OS#d$5<-tXH z-92+=iTkfFNSv~z{d(BU6G`2i?Cq8sBxB-+umKUfuMW zQ}_n$vbWj!`cA>Cy!QDi>m|PL=-40mJmv7Cme)(uAJ6z+ zc06m@<$ZP$g8x(gubTZjLzP)L^ZkAIE8ovWI-S^_?!mfn*>#WRC##OH^_x8V`(GCI z6Td(5)IEP&c$oLe=c)(Ko_(&n$n@!NO~l8~zyDSIjAwPy`q?~D@=rs#xDj`o*u~3c zCz#@e4vF>gI#jl_pD=j!TeV2KW7ACTrj*#Xt{i**a&x=$=vHd62=<9=m_C1X&8`dm zE6<2DP4eW)+j^_}^now@nYHKdecmG9+-?;j(97~pUyQTNbkaKSogrZz8MpMaItn6n zn>PflTF4xm!uZoesK-ppL}TrJ!E=``Wf&$M*3WpF`0T-wDhb|FnVWnM#peHfk-nT$ zwV5x_tv69a_Ql~IiSk4y`<@F6SGrp&MmjOQI8moOhu7hf#j#tg6B7fndlzju?rPvC zmo#r8-|1hQj-**k7Bmky`GIr6h7{Rnf@L$k0*xG8q)&_fbJ3Tbe5cH3+d|``+dfDn zx2@?jn5m;wE-`z;*VJjBZ?z=lJf3BsyRU!#WbG6k=0fkR8s+1kQpJ=e?Cb5Ct$5ru zd{W`$?Y@>;_tWQHdTZ<*?ICTUwOsz;L}B^Nlht3;%DS?g52pEFez|zrf2&i|9iIQ>{Zn>nqKdNP#tA`wE(v;* z0=7=LS`~h5U7EI-t9Eu6+qd*5*V!iP2RU2KO<(-4M$6IGB!J8M{prawbRVYbhxc8G z+aMRL6Rx=_WOqZrYLnpA7c4hjc~KR{XG5EXbVW7W1DpRR;nJ$cLL z86)@pO(nA;q9;GhSX;Shd-36`v5FOfpUVI6{!!m&rExLl_BsFbti+||T1?jy>%(vE zKe6jt;_gc}{|j@io-BQQdhJ5V)kT@I%NAGrHlGxKbx5M3qkEIf$4e!)M>4V>er+%I zZ2o`w%Q2y_a|wc+t0h0(I+n?~?NiX-rN!RoceQ5~X`8%h&COe-lyWHRx0d|oZ|Yi~ zFMn%iymIu?g86ZG&TB2_HYRh;uvL0&zt+?DMEjMM=ai?(tkvZH z+O}n@ukkavH<^E*w4X7HEsk5gweYXu@-zH4#&!bV*YGzMo2@z9`GV*BoW1*skDX4N z^nmI6o_TMRt(Kne%whcA^n6>f(c1GHlaAk>b51gP)|=}SPuZV8`6+$5k?xP+tBody zYM8`J7q2ds-Tr;)kHqOx)7L)k@SOK@*|TL*=k&B^PX2!NW9GK1wE2%ytTtagm^Xv% zn09vMoxZJ4bGD`B%}!R(I`Sr|wD>c_T+`(l?4IwoCO=D?W*U%Q8~p!w{PO_yY2}^Q zpTwCK{hl)?x3%^d%Za;BmhN8hrEMRR>WAMm*KX8!b**Gca{2b3OL@yQ?lJ02ezyG4 z>jt(zrgFyj%x;|MY@YFU=Xv`*e|Z^~>v=J5o-*q!=jDSl-OAX$WUSs2J5Ac%@^991 zi4E%y2Q{(Z=-306|%tzN}t~>eTOYiyQ7l!>Q+w<9f$NxCJ#xnV2*Vq1}`d!l^ z&c@%4&gl>C{kZ;uVC3?KKYCA%Wuvd@zO@Z!>OZtd;LM>Yn__9Z{s!+o&3@5-g(A`4 z|IO}sEg!V!C0EIkek=MCc2+b zDfzhRAN`}xWTVsaa*wC)%3rJeE8MAR!L?=?z2k2?`rbde&jL*6Fd-TtD#R{8h*K{Kl~n4_y}U zZV--Z+jC(07SV$YxJln_Hs5A9mNZvg~^?8Xg>n^w6s|%_Vi&Old(C3nLFzedBN_|J49mh8BzmXqT zEAgQAt?=B^`r8U0TR!SVZ#?pgX=&AT`IZfKtuN(waI(GpnAVaIy% z2g}p|SEkNio+nx!E4L);yLj;b{B!@-LbKKxKV4iyA{-ZME&39+s3#-mOGN-r5%ZLs z7@wRNzGJm}_o(QvSTkiJ^P2}wOpbr9r1aj&SZLF`XouR~E$8Oim$u$f3TPF-opIxa zh1JnE<6W*drH+Q&zBr{?^~tT%uF_LOr9*wBLhad(HYYJmKfCH&@2u{mRh@h86gAuQ zuFMx)TQAktqJNZ^uf3=D=*5EzcSpJM%2)gB`T3uRZ&v3<$;RzlnXI<#Vc+^t#YbKB zjM(gk*}6efolf059JWhnR>q{PbH3XiB;Bf+bZxd!UxD(vl1bZ|ANh4U&)YRAZsMeO z_mr(>GEbYHq&0U^nA)U$^PSt~Cpi`^F7?q-EV5i!D*ANVkAtf;6{jv)u}FLhRKs7ZVy_2kMG!)4JbGv9bOeequT$#5k{qNG^fF4Kiqrfqpx zW74D(Iw!<(%^j;drl-FwjcKbmyz%ydZw*!}9{-#XRIr32aYybuofS+gjvc?^w=Gex zyK~mDk1?CBNQBOu8u#Yek&bKEr||v$cpqGRl+IhOJvIUan@Gyf9$j-GFVI zCkmP@x4PPAw(Xm8_bJC+j$F%@7*}nWaMRvzpRZ5i4uN|8{7*W9`}BCj0 zQZ=s{^cGbG*_Ezc{5-5qvMt$Kzt|+>nTpwFLGOK!0^SAtD607CwEMkV8L*BoX4~rG ztY-miIb78mB3A1Iww;XnrI+z-ci67foNappKi;+4_@}_^dtl<9ow zYur&*;fgcLN5r{VbLOjT+LD-&m6;>Ia`DzTnZiG3dM{<(QkfK7xo4e7ka)}VZ8tkN z{1l4yS*2UKy+Kpp$h{igxi55Qa$UQkk!;}P@{}o$t(Yg?*1U!5{Z*&vO4<9DnC$nh z;@G=NWB;lddsgk3x2mOg)sp^IAy*z*n|Jz5U6nI^)txD;Y7Dj>y0)lh(i9VxHA?$t z8SR~Q>T;5eU#Hi_B&I1*bDs$bdL=#6z38p+apr!hMjl_MA3-`B1fKVv?`yg7AmgM! zlf-w~C}z29H%dB1*pJPLvkkYt!yz}(pdfNzw&wnrs|wki)%M>E1*P<5qx|=jNX)r$ zO8q=bZRa*SHARC-3UR&5^{&gx9{ZHdxxN0TWa>@>TmNobf9bl)A3@Ch>So@Sr&fD8 zN2D!H3*j|xs89*#EtZLVzgoCu*13+5X$JfKA2#|w{ui1SJ@q;F#y5dmMRrbE{dbAv zQa0f~EW(vb+upA1tmzX{h?|$Tc&o+i?SFPo3f(VLwPjnb{~V#E^SIaNHug<$?*GQN z^rL%?713)3v+IJat(%)R@wiY01y9#ChKSC^^DIl0c``Q(&l*BKSodv!c=HycekGBy6L zZp8Lq-4>6sHhc8nOU`1>o?B6q!8<2p_l8o=Eq6TkKHibo-M>L&eY?^AIigE%-*Sn$ z<|_Mok+8*-*%dB(o^4twzx8j#ijVra$t-bqFQ?|#bGVgz9`Bg*E4Dg1&!avui&ZS@ zx>@|)+if|2J@z~0%d%TN+@}49&nY^#?xjhV`?^>CG1tTP{kU~JJdox5JFDOC8gJc7 z5B(87h4IUWNw2O6efezGwwy6!JL93PjX78K&V1uLvx$+bS#ec^;;bgcUHcT<)+#Pr zuNe02klB$b;vr{Jp6hRKw4JS`vFEknlg%0W4sz4#&OQHUKPQ>x(o5Sr4H8VHRzdgg zRM)4f{`ouA$Rwz7m4}9MSA`1m&%cXnG=61WVOVAM>d{}vms$e4hj?V0OFpf+I3Z1? zFWjxaugm)o?zOUj5g&`b4F5N34#U z@EzP9r#IPi^%cdlg>r8)|_myc}*)9?aCAvT9|fYir1Ev zVcS-gZC&ZNedW6?EAMSv`R}V>f!|4ngJ&ijIMZ?POvHgRE(gy{ImGi(gu$B2VaHc< z+k3_5j5fbA+dR)~^G!43ZMJRmzqYUbYHt5+d%*QAq6Xz*2IUvc`z^k1k7nD!&n&}n z#`mgeqT63Vo-?)E&epC!yZFx8yUu=ZHv69uJ<~M(Phu3~ffQr==m+-k3r-p`h_G>P zSmruj>ALKb7e>VNkX4_GjD|44U;Ff&m2&7yPFX42s^FK@|j6PXak+i>!0 zzZ~0v_E|^sqf_*?9rw?3d_GG${d6d-@N_&f7|&5@#l*tF;+^Xaq>L>u=ty4KldJ;Gy6U*u*fX4&40<} z;vV0yOkwS`dHTQionMgjH@%s;N_?~8y*=UaOZa~uzQ%M(@{Qc2zw8p@yz}?h z9JsFb`q#e~w*?s=n5?P)9r=b|v`S`KUG>s`1zT%*U;kh5=))bH5(xGJ(^pJk5Sw>5>u$4X)aEu0&Q z-1mHSUsCn8Ec>Hj`PbWp-;UStE+}FDt7@`1{_n{R(l7QW<@;^Hxpeht#`w|5ty>`+eJ}?a|IpKbZD?WjcOGS%Ue-#~RkJ`}1;d|2I5h zxBlrr@n_a0D|Byot?=}GH@PKtUYqRN1<$=pm=3=^ud%{<_XPE~vgNi1txb+Swm3E2 zKYnvUuef!~@egqhUGv$K&dlzfAM5mSGVij`2;&DPzt@;ZF(g0eYxuIo{ewX2yQ#Bt zS-;g@%L_21-}+>o+3#Xs*9gLGy|%yG(MSP-=Pe92eu9Rb~f#p?sDKkM3` z4?6UEPHJ^a*a4$O`X77CMJ}vaaHG2Sli#XmK3reoa$aXdytOy|`z-%iUJBouNhR;j zY||?L8#J#le)YzJ7vF9zuu1(`Y&qpix0YpldHMINUvls5?D@<3^!Mb@F0K0yU@6*JreIJgtEIqwXFJ3He=H0663r>C#SCX3>^zz-MqX|0{ zQ=g>&yw{jwdb7*t@w$SeRlUjmPT6ZMX1MH~xMb;XSB8&e=?bapw=^{L_vZ^t_0jv% z)9Ir0kALsM%=bR?q->T&{0&XFu{01g*OgoRW#ZeKjWLT4etUKIr;ey~bV}FCl`(4t z=X{1@*RyfRIF zIpc=gg3GqdIw0HFsJf$v#k^(huk{n=?b`D0we*Aq|M?|W@W$J4FJ&m4tiGA&>bAwH zHuGOa!yZue3{p0s($K@9GpZoQH+Cw$}AmvJ>$wwZ08F3tp zVQo$MbM(EO)1TH^|CXtFd;Hn9 z&*seg_b@}&V#}n1k8drX5&2}&>b!R|uZm3gP}%9sbFk|FbqD!gUzL43&TZJ)pJEW* zBjs`1WYL?ecb|P@4!Rn`ySzky&h&-83Os6zLEBe|9`?4EKhCr1)aDZ|ZDn24FAARC zm$%|~@qd{`;_uwkj;{BcbxE{Pr1_S7Rw&z7lOF_M12;L+-5x{Fm`n?2*SyEbWZ-G}>epFbuQK2S(6JF`xe>y5ThWOVy+ z%eRhiZpH0vXN)obvYsi?!}Q+Ph6y>&4sTCbFtdufT)I#c-_~TZ>1f6xqp-zmb{*zl z)gt%I_!8%H&R-&i+q(76&0S?`b0u>U*QTBF-+x>6RM%^=-bmTnStGYvL~RbQ*wo&9 z-?L3u+%=Zw+SZA$4{$X%;$2g>@b>>nmo_|ia6Wm-`U}gYjE8?WU5-<_TV!=|Uzgyo z$~Ns6%-Sc))&IEmYqd$bINJQ4{>3`izG+i*R^O>B0v78(TQ*)>{kVDl+|%FlpJqKQ zKa;?qW*1wtRN|L@u4;kJ&w2rW!JP^}`X#TFp3HOJE!REG_v*7>^5;3;)ox+24|J~P zpP}fnAxOAfbV_#7#nm?Hnb#E!n48XTNJ-c_VTplj)N7`$yt=kZ7EbM@T@KIhDIGua zYqrzIl>2R+&4T4z6N8R)%{n$S!yAY`l&&lZ+s$TwFyYYSKVPGgnHS8|*}CZD65Cy!Oa98%vAkqBcroJA z68qyv?yh^}5ppX(`lY+OigoFwyjT8(`5*F>SMBZha`?NpW#j5ejr~u5S@>OwO;}~R z&rI#Xi?1$|O0HF3)SKRTaYCAMLGRXQ3g43=bQ4aUh_ckF(_!FE>%D6Agry^!|D5Os zsaFN@-96k9NB1n9#K-CC8Q|pPwp*n6#+*s~>ef?My_?hez(~36=q%NRftL??zg>I2 z^-S0D=GZ?U+2W?U&)wMg__Nu;#!C#|r@~{dcBwSwUzE1_ZRwj@g1)yK4W zj766RFdciqGw*)Ao9fAw6jQyjL(EcKV&;`6oDzeUN9WFCVX%`-pRG3wv(&GKyu z^2k|o>6}DgX3e%ofpcGo=6G}c*z-3$?o9mBn9P%14CTjmb~&w|mUC&*s{Do?);%un zCoYJ@tzv^^+^xLvMAcwSbWGABLTu4)9Lr zoKyPda+JE!>qrg0;t+=!cP@XkGrh=axj_1-nwqbN4Xc-j^n2s<0^Zn@;s4e?_*bmn zcvCXURqE*ORUW@*Trry_((!y@w4?sFppnOW|B_SJ;X z+xp#VW9i6}3rX{SrM7rKR^oSZt7(0|>{F;#%V7?qoC`tqU+moj zt$J5+y!+bD+f`0Iz1lNawmP!6>)zFq+&|AhxbXVVjx9m$pP$OESYqwJ%KY|=1B;&P zJbwFq*H7)!k5zhV>(_n#vQTs}u5cHKzcqSepoa$WZkcaQEI$r+2RnLB(f z?F)`?j-4&Xrx*Edhq?6vx$w2d-b+_!_pI3cO)%P~ZU4EKZ`VI5>3<*G*Y;t(?B@v$ zuJ>i;CUB;-7e;^M@9U5{qoBLKw>9HB!-50NxjkQ&y_kP)oAgQV=Z*<~j+;G}J{x7X zy20#pu$1)mJ^61NzCI1*6=u1+lwr;1tDT<{ex2ge4O>2A!Rv)v=4WpfJ~;L1+2?H* zi~Y;*Y`=Rboa@TXm3(4v4{3WeY`&Z1R-wLB#Lc(MGeGQE_ur@4C12)$zns5s{r3H5 z?#uAMjSi3N+REx3f980JXzWd&RBOLB!<%|l@`obkXSWsJKPoqhNfL z_vd>*^yl74J#RISSWEGn;FSHBm5!ROYMi}5g?C0}?2O6_rw(3xbpG9)t!gzUeRq-{+JCsc^Tn%6 z97k6(CpX{sw|sY{lG|a=%5`&%Yp&Ro$gpPC_8chvlJ;ncmopDnX}{i^#w9jqZg(zM zEO@$h&HO&c4Nu!7*0DU`_~|0FyJ+nZ6@!3^n;YDtTI>onUEOCcYfEMky2%~H;=-eH z{Lqo?HeL=i++{ z4-2epS>2gY$9UalWkhY`j>v^QHx~-<&D`;Lp~NZ0|Gyebc6IuEU3kW9rqkZeKP8P7 z)-ww>cV7A4D8xT=aeJo^gQWh!i6J(U*Nr9Z{TFUw+WDtoVNUVFSv)gOR4nYcIPpzo zqmlQ*RVOAcnz?d;`pmMzMJWn1i+)Z_vEIq$I??MvV^-P1Lthu(@h@8XM7cLB*;Fw2 zV{K7uZqeV2;Jv9qfn33Hr=68+h0j*m9DeN_+o*iF+^G2}lkN$nzYm>w-34||lx&^A z;3~Rp=AYV$JAW-?;o5m&^F}?#Q}aI@zRz`h&a0!J4AQvHyB>P=WZUHwv&YBOIF6b< zO%Y=`D)!vvM;+RfR)0+L`pYk%E^V5QSVQ(?6-T#v3eiAD?hSjreChUXpT3sBw}|>f=BEHtF;TnKl;ft$X#VhPyueRZ>rIy2t86 zsk5rOx~kZ2vGsMaG2U|P>~dqhrS`Q;t@c*h=B~8pTVmI{roC6#d42y{9mlor6P9|4 zuRZ+W?a{E@kBYe;MVtB+47vlgcSf$h_Pen!eM8xd1@DqpH(ce~YIy73*Y2{;rPIFc z`Bo8i(0#QZ+iSl*uZ4cMuTk8v`*m~8EmxjjFMpl-S$@k?X4l!=36AzXXTR*ZYS`y%el)b+=I}b7tAhSd zwfO!zDcoI`{q$Yw)s&rYPnjIH(UKWv*Iy`#+VX^M zzZw47#N7GfwdmtKt6zmyUkq*jJ+-LS?D5m^+v`k|PfvAL>>YbHd)=%oU&1ESM7TG>Qyd>d-PWRt( z;l8p0>+%))-`sD0;aKr?zQy+$3eV0Oq|IU6?Hv7@v&TBfY1-Exzo!4)C2zU?`l;)8 zZ=E^)d|QUOS@z|xZ$-AV=x&=b6B{xl8mH%<$8v7pkx<5>J zedX_Oc6-5}WBf4OKp@`Y--5NOCpR8FnecDH&SOiL9M4-g`*=dL_!>3QJ(7;d5a!ayY<09=b}bc zP_1*(@7MV)KN$8MVY9vC%iPa*dUv+wl0 z4g8gRNNx6^Gmn3m&i>`syhwg;SAwW|`rM96;kd)hhRLEXU5?I5G} z*4|}~Wnsp}0ma8lTVKvkGq&eju&8n8-L{k-Zw3+L-(AKB9fW_n@g0kQyZp8EvX1lx zv(5f_U6qd%PrmSVzRb4!Ow&n^D;xk}shPWoKo>D9{9Jxjx9^M+?>KcBzi zOp@mI*+QizqTiS-zyFb5qh#5ueS7OJ-QJ2VC99bAjz87$FYGa$Y;+kYHA2u-N*4(~a zPB7L-ww62X(aF3`;(0|~Y6h*+5{G5Wo-devaBiUUoVbOBMLF{g57%CM`mpl2gL1UA z$EiQx+oBDhn?7G`$UaeBe5pP%(b|x*Kv7gf*(!`TzI&7_a{G_w~>Vp zC;opF`1!-U@2eLtd$8`=^=e(keBG7d?_76(h^ubqt2%tP+PPmnxHbLpfttlX+uQFQ z?{RhS)<{2nM9k%5@#*&1)%Rmo_qj)(s+%pYp||t#(!GZlH=Avf`@VPEvTc2v7XNP9 zp8k08@58IvKOfF+`@Zh-YT>C{`-4{QeYP(Dz=rvOoQ?;R54^8s*lfJ>QF6iK^8#x3 zH(a%SeCp|W;pJW%)=X?Ff8BB3`t|wfyU~wk_`Q}}ce3x=&$_lwsl#tNe;llj=@q?a zJ@cIkv-}dyIZvka8F+A|I!bwkoDWULEg5* zF4kOU*Z&{BZ}y4FJ#dzeIvyvp#bxIbuNxAQcU(68X!e>TE+=zcDMdVeUs+k~jVvki zGqNugThH-rddq6~Yd1{#aqXR`jaqZVUYu-)2wnSe05oZ@-F{gI3(e~kvD)I}-eYff{(hW3m%D1ho61mu8t(;ve_a2(_0rx}j-&$ue;A}i zzWn9v{qS%Rjm@t_c5lJ^j;CHKUm>Jo^?f-CsHPqJx1* zp;2sfOrwts-=dkFt;#0@KB?a>R1G*;V$jlc>*EF9i%vT|%z6($l|37@)n}>C-jl+z zDNEy)UVio~(~zuH`%C89m%s!nEo9(GaeX&2{I9L!lE@1M3bV8*uq(~FNc z8t?0To45Vqkw%$172D{)yG0wXY(FV|`(%z*^X<1gC;u%<;?X%%RIK|o#cb0Z#>Lz( zLTsl$F+S3`d}+$QS+dC=&xcnvpVZTf`j@AeNoGUy0tn{4-~v&*G<56E7Q` zDSuGC(Q38JulZZ&7L}!*o_svk@kV>Y0kxfVe&(8PoC^<}{PMdy-u8leGVTDv6rcS=%df{U;UCo(6OpF4~{=SdiKHgp1eB( zZE`yC3@w&nB(9R&jIlqN#^Mo^71H zKmYK`kPqVazb0v^=RRUte9m%}&8k^?x_@=$egvJpx4S2J|2o!crkQ6#7xXf;Oy^EY z+_Wn0)2zt5Hj{TqSXD>z{XgCm+r8xSl1ZyBdfWfvxqo*t*WAVN0#e`e@3@5veb$xt z`RjCc>HWV|M^w6Qy}#G}=GD2{FH%hkH}CVCFLv8-_ME9muu_o`%Z*5x*mqBEuJ4|4 z$joQ)j+V&!77;H<>H0K#On3>$kI`rX1`Q z@rk={!&Os!*zA*yT)f1#9CQCyt2RFKl-7Ofe_NXORyEJNzn*7z)O=Iz;W4;2%{8*0 ztJdO~m5ZbG;rGA(f8bnp{c!kp3!hy-9cOQ`y>Qv4xK+^X!{q+H)0d>~Y*D|VTe{S7 z>gg%W2c?%tPn`IoY+?36UhO(&`^|CRS0|L5ub3BLJ=f8ao!$3VY>HWTxeoWySFCHl z)@kXvDKDxhD&vfN^PKxc4oiH$q|TP}ulH9L_&ePC$-}&-EjrjSqCOxh_;kTwN{YUWe2LhbC=a}w4b1^dd*@K01{~cz` z`cODEh^^Q;cwtDe(L29e`K;GIoD!P6*#AdNx{2e*$GanX7FqT+pS~n9K+ zQg2`Xl0L(lT>gWer3F8Q8$bD^JX1W;Iq}IJw^hf4`U?5Iazx+iz1flc`fO0PSE!6< z^M=IwH@iJmPAWNGYDyJ(&!h34MOpYv-;<%L{wlPo`|Y*d-)9egoc+Vn}{MH{at zjkU@Arr(cWUBzI+tNCk!lirqFnHFbu2?fo_JmglDn5y{w{jWtgYo;s==DhXsKHsv8 z)^5M$K_AX}vG8QLUJ0+b6g4k$pUT6w!#1u)VkWgGZ}-}~@lNM@mZ)X9Pf_*Ii)pg^ z6mqX-?pVUJa^;o#nbVfIrWI69u`_uidCU81(Tk^-zKgsP7RxeCbN~6{h4`dD7O%b< ztvPz^jrgrMPfwq{`Npk&Qif^tR?|JpFJ_0lTI056c9>QFh3xS6dORyOny}{_&N|#w z&bx7M(u2uUU%BM!@!pKS?Y4gIYv(H+J0*>usVh!i-SIJV_0fdzw8`^VdBv>Jxl$0G z_AORw(~I!bMAYllRwH!z0Re=7#$lJ=W?xakZsm+lqzVnLB+h zTXXjZ+*a8B<&4C1R^R_}`Y+!3L}fook~ra=w<-BLhX~JO(=5Mtfx*_NDz+~%{=%Vv4k=o@iHV@>0cG{#3V!=OKABqmm5YsyHR4iZ2TY|9EMk z@vZgtveQ0Ta(?_gPf_WJ+~lzR{r0cAkx9{8oN5 z<9oPL!dvH^6VE4IS}^P7`;s)BXt$Fh%coC%ShcL`(U#*0pVDhxJQK}?lZ2mk>y&7j z&0fH<=Gz(ry|^FcLI(5aOnxNqUZtqv8!1#~dzo8kGNa3OjtwCad2WgP8CmwB$8^iT zty7bG_G#sbu4`&utHZdq?Qj<=WZo)1x%*(fM!D|B({k&+$ZnoCSubK`!xryFkLE47 zS8{sl_buL9PG7wK|D1Dp-^F6(&42Qm&QA*TkBAQn$xciEezIBMq{g#lw=?>?lqQwD zW?1K6JZ16fsIOXke{V6-H;rhCwm7#W-(lg7qOcG5Z!LKA_V1;NT&B&kx6Z|Q?|oJ0 z=`2?I;Dl#zdS`)Fknq9>!8)^}%&On4pICn9;+7ccZ8>Z2#1#9ydl{0fv z8S?H6TZrGaxsmp?V)vo@`%CZNywkt7X!`4?+fyI?h*7zw(^DW^R6h0P{ps3ybF+IZ z_^uz;nkHB!`!=znNAi>X_5T;Go2I>q$lbW~;@1VJ*p%j0xcOcEBYR%s57j<*Q~W-!)rbk`u4|F@w>!SV{@sG8FddzMxao$!czX9* zHYgX!Y8_dx>wdG6zwn!nvDrp0kLEq!{t49mF#Bn@{q2vQ+WefeXSXo1aGvpBW1PIf zWM6t@SswGMHF-+4g3Li@Sl_?-F|RQ-Ge7U@f{xykR|{DiR>(F8FI>3&nTkv!zvn-8 z%a<}ThqTYV-FoLr<>D7she|cBJYnm6;_uZqH*#0-{R8rcwp+e7=U?zktHI*&E2q&BpKnRSweT#TUhwHERj?dJ3Ifhi}=acn?F?f zl>hG9?DCC6e0#ZtImZl+-#q(0Pc(_&UH;(Fn?Sb-^X3W)YEGQsI#Jv@xBdL;i-+~1 zCrp_3eXYH?vY^6@qq_C+Oi6~XW|&=^;M$oLKKuW=FZb%cpMS@Fb6@E7MGk-LOd1X| zzC3&Ii%)Wp@%alL^AFx_^gg$6%FV|vR}Vfl%rW76*l@IT<*~m#t7{DkRKJ6g3 z#Mvsc|J|bn7R}n$X2}+L`u=%y4)g6k`opmQlPSBMNc&c!@?Gn9C>`w)YTv?Uy#I-W z@txZ0^Pl2`Z?PCx#osae@U4?mQub;i(-IBYy4uHQ17215 zYex7l7VO{E?o!0m&#>0#-qVKVGyJbE@>%>T zJGUG?W0c&U@^SXJF2UK?I$aB2t-aFN8^IK3IPV2W?FuoX}P@C^?1>B^_($++%bkL?r>_|(d4`%$$iIig$=8gjVh;&D7TI2 ziaoqqdvrPX$a3$oT~WiVRin&VBg|c6yy6eH)*o%oKhoTPtXD9xYcZ*FGKq6DnXhQ# z*J{$|Y?9}0QV3Br2wfQ8>9nESsUzdiidBbZbROE#eW)cvX~`<3DV<7Nx|Mn|7Oh#e zXin#%J>83%GLjapN}AM}v|>|tQdh)UmX4`#5oTQLmuvx{_A`ZoM=5`P@b3_ujFa(SLFI$|u_HT*WOszrX#p z-Z%d_|N7&vfBt^mem!(i`{b4#i!2x%4jsMuPl91Wyr{sDg#DY|E{d09FmNdOUdHfX zWq=0D|4;h={pZ+LZ(FtM)%8!it4-wp6|H1pzt0j>5^<>Y!H$3jBH}XBGJN!vT^Sk_ zcHg*NsV?UK^VzXl1ChysTzi=mFgc~?#)(T7m)lq`3uV&+dSPW@5-F&rFGmJ zwtZQ5H=TQP(L2A0BhwNlwC;MBtunQ9=M&faf-Nb`@jdb(MeD2`SUOn0$7`x?fBId( zPP?%!`&!Mii(Y$=Za5I5eZVxM=-T2>!jf8%xgTHhC9d#zvS8sPx7B$&bb;I zwY}FAq|Pn;dd;iQ>clJgd2{^*19orRvhuCjH0?|A&FOKorvBe$xYF*Qeb26UuUMOV zgzlQU@SaO4E!m%DmuRBuxv<>w%bc+5A9z=N|H8X_{lkOJXD8I|-Do9r?_7W1Hie^N zOVauK9>vJXzigM?8++T*Mb6n+_Z!y&2albPR!=Nt(6_d|@7e)6$n zYiE>eig(^yczCD5gB2xLmP9d5>uckfJ7=v)@GYLHk8Vwu3J;!aWWB^^QS$BHlkcvz zx~#Zr+qJn~+xy|SWlVkE%MV;!!W>^*E0Xw+zb+EG{uay)HtB)KsxA2$}ac=qj?I)Jy9(c~X=N-$ThTF_Oe-3M~?&&>In`s@J`=Fs& zULmfq^_%SU^0f*vx9%q~+>SHZ5u){IL2G8ziUn&7btATSuiBz)wp=)I!I$^nXCJJU z-*33h;)D32BDQnW%BMjl2Bm z2d%lhGkA`@IS@VhPpwpI-U=a&!mB$oTUeIYmdu&n`@U%T}Dwe%b!?ob$Z2 z9htI?2OI9*H*fy1*CW_@>y+OS0K7W4b_ukM@X#zcATxU_WLQt_sTH+xKj*IqgIeL>!j6}@jfjPE^( z>bhcnwS@7$z4hbfvy)$}ud(YbxSgMQKG8ya3HSR~%;#q8+<9GId9%m5iils&85t`8BOS5{mY@Uf8D|O;sWXA8~D!{99)!}#v@0|Qa7#_sJ{O6Zc+U%ug~{BzWOM){LHC$=UVgn zRqfgD#VcLj`{@766B!FNzn7=o`mtR)BqlgC_?U*|ZL2Q3%Y|+ZRvWdXU$||a_cyY5`sT>G^{i*U|xQgaZ}wssRp)<_OlOr{92@H@H=u!ic}28+#8%%8Lm%z?ZK|H zCf`A#ebY+YI$OClM=xGbPyHnL;kmUwPmTS~ryoDPKHgWmVtTTw-0q)Wm%VTZ5jY1*opDb07ELHyQyLr?T>2{R(uZfM zQ-!+UzqYqH!})){r1G05+OJ$DeG!Vkv*fl}!_oB_e*6nx7ga3X)FNsxsr~8j>AvR| zeysDZiVi$>@>TVAs|j)+C%*Z#X!3{DjPPl%h`Y1bbC1-|{r+4rGB$6r z`PftciK8|tCVnx}=gDGVP|RguP{Q7%05vS)9ZQSyixLSP&VTf8c}Q@guwB=siBhaf zJcLC9Ch#elYAAWRTX8t9Dw)8ixKP<6@TDo&rRwR^0$7$P@8wWY+S@9pprZbx_WsWO zrPnR9@BV*hf3x!Y?X+ieE9cETYv%SkW96m5`-{|+lonP0d~{P=NhwK3P|)*(Y0x3r zwFQw}N=iXWvb?pTPM?qUN|(R8GjYO%if?abHa0fSojZ5^`uD%TzrTF>vbUF4R8$lj zJG;1;SXp`b#|j%k5iS>njt>Pm;08#$B?#VTnqby%ob?c@2G&(6frB4pLz z!l5C+uX;$?>7TEXlS0FV)qF|{Odc)jtB!;}y3O7p&@y$s+e-GoIcsy|H9GZvd=i{A z<%yIOYvI;Ej~KGPSDQ;cZau|wORLj1@088Y$jTn6!;h!;K6zp@|HN@=i78c8-_%re zrcX;c_Uyy%-KY01wJ)*}w&}IuRBqWZ-)86QmzvWjButr|9T5M2-FEZDymck%%ePNA zSZJ;&m-k?1LW<0iA2IH8dbtb2-J{NV_#Jn1KlgcQVAI6(mCJprGo13B-udWp6~}GA z9lz_2Y^eBpVHPF}o99Bis=uEsw)FR(ed$umy?d9QKE3z1_J_o-E#*5`yexOhTp#GP zeqwsloQdiUz8$lp{rt|oc5DgXLmhbyTBx%?k;ukTKt`C!?aMl&BX|Bf|BR?e5+;8~x@{nztJ`*p_$ zvb)dkH%UxQ4&V9b*1FS6JhSSOCT*+#r`0LI%%CrttZ!>>t$*MAeNJb{{k-W{`^8EfaS%7nUXPjO2qW9Cc zPWJuT>il$5_^%J2y`4Wx-#^qev*hHwyWj3- z_np^S&P<)Brmr@2&#$to=ihQ)+`RYTUgoo#7rvDhMR&iyx10Oy(bk7|-`?N-AoQie z@7?j0^E>XU%PB4LJ{7QcW>22sqoZ8XL5g+~CGR2yXB`Va+Zj9S_vEhl@EY&zJe#>^ zE2n;a96Gl*>(~>=GKMuidarluxe4q2-CI|!aZDsfAzY4AYQc|-p-wzE=ll-|D-M70 zP+;%LKh0To3)j2}|6aG8t9^>wz0`h&x4g0iWhq(DG^?(bDW&aqPvc7!Who7=zx_XF zv8ltyH)mBiIYiPwFN@05u@O=`&3d}Gsi#s*u4t7 zYJG#nFEdvw?Ow=z>j`VT$Mh@FKBjlxu&%J*qrYmuq0)q^MxzC?5$tu}uT5{U5cHq6 zLbUp0Z`QNOPGe3B#TO4heQT-`NxAE{NbsuZ-uw!yD=!Uvu4`XdS|21}wNGQ+>o4!_ z#Vh(Iuk6cQI=5zD@gyV7)8THq_a8-?%FMUxRr6gbvT4T@lg9X}VAD_1hc)H*EGzL_ zGNaa+Y1OXVf^VLN-meUJz1y5CqM~Bi)(?S6d2a;yb${Bk_V_-qI(le-iqJY+;Y~ko zMP!;A@Rn3g?Qt&Kzn(4nP?}2Sl9V|Xk}-^Sub)RAcGz^zjlH>A!hipt{`yJ_r-mo&jzN(`VFuV)@=Gvj6eF=j^+G zF3MNaOc2oP?AfyPHFM+fygl_hiw`S^>Fj#SpJ3mi)5_k>I~bn3nyP|d08=iy5`JBP6tda zB%j$#S=hGk|B)RLJ8!+qoV4*pKK@?)}wtZDiwA+`&WTT@fFTof%maQmC@rI!4!`$Sxt-}DyGs@s_z zU#-9F)pg;+F=bD)JTv#@e~4eR!si!%o2>Hw+fy1@pq&(W-+agF*sDVey*$gi_?}nd}pbpzTckl`-|D)gI1~Uls9kv z9^bvre?{xh8FB6TTgvMa8h%K=XEDBg|Kfx>oZ%a{_U!%HUiw^pep$zv>lsx^>wd4V zsB#zlo@cEe;d}CKeBD;Hv+F7jSC@a(F5i4|cI4|H&rd#b{OH9zb$Qv7GoNlxOnMaSbi|^sM;b;wZx| zfBVb3G*8A~TIxSjL+PLAc`=Q3S0Aok5>}ZQ?jyBFA*;IZ-mk|ivi58Ag?Q z@%7!X_j)Mz)vMP3KV>|06}|CjvQT+(#CzRKLDQT1E{MLqwPN|@0`0VSGhc|#d6L>3 zc0b?=$K0K>)~{mASKd-qGWk|S;qtv((+rLO`~7IrSoV44sh105-zireD7!U({@jKw zKSJ8Y9j3+4IxpH8!B?_(am>l&eMdvKUAA_RJ{jz?V*AB)BII{ z+f=x$n=W@JuJ?=G&k-;F^vS~|zd{fF{L(J6Y>BDAxbwf8PtBHJe7Su7><<^5qVG36 z?I~f?+q*(Oa%HmD_tP3{w0AG*5l*$czxsx5nZ_L6?OB=}wZZ!3cJW>Z-)AN-{~lf( z+P?0W%&p}P*MG+;v@1{c1ty~f26Y{){MEwjn zaw+Rq=zkaQS7+OIo=W_C-d6L@_v=>W2V{g;CrrN=U;e02oyqX%B`&$5y!7Ui#;Yxb zCwn!&YZH-^uhlr1sg@(Wqw(Q`SMGgIIz{U=P8LjboU6W&`&rrg-%0%?#hHuGXTI0| zaMV=o^gc1)@OS+Bl|M~mH&i}V3=}xN$#&YLfmx17kR zT{wYp^PH+_lLB}We44d$UzJzf*}Op7SFL`MSIWN&@8<_(eQjqeW#YYf@mAjID|XJ` ztN1GBKMC8By6xpgqr?4jO)086|IaL0EIFms`S8Bmb6#?nw+996yr8XX|B@x&NOL{c z@v~KYBB%Cco^;-FG(vYp@Ph98-`gq#S6gu(oVE7u>9+LyA7;MH4^{)E~- z?SmPGQx43Y(y#N#sO|kG8SxE&lT!KX#U{?!Tdw@MawYUOq5|k>})r*O*n!k15rwaD$<*6Gx)l{zqb#`RR zPS_(*Zf6~|cjb&9XJ)aP9a-BYxm$hh^)J`Huei8k$-%X18N&8=?%kew<7mB7=EsuV z?-$IlU7Vu+cJkg>>$ZzcWi@KAf0}07uIc+fuQzU{?SiDV8P6@<{(sDAer&&b%k3J` z>tTg6tO{nHk({$6)ZMONA9Kg=iE?MZ`S?tl;?Hz-?%%Exe}0~6dG4IBM=jb#=BIQ+ zUxkG^bNiz!53e76sr`NP74|)U9~$oXx~fX-s^(jz*r%uLFKHyYNJoejit{Y(U|ke) z;pLh*$?Jx%n%R%qaypo=4Uqcya``-q_o;VpH?CQqcZ~7g@4Ee;_w}!_4^a5j^Wy9I z=0{xBj31t<&s@3h!v1p;4>i~S{r>IdT`T*R;ynRDs%NX#iTlKa^ZJDpXI_w7RQe!! z#?iv9lV0|AaOfUgxAOk|&0nK?1ygPI%l&!Exb{Wtu4#9Xr0=R;(xAolAV_vERA+Hs{5XpnqOp zX8#HlEXwuY)41rF{HM*zad%c0+jwcGRL7rl1xQ=#F~^0WQE^IV=if&JaGvQ4kP zKCWj=b-TX4{lbozx!1hx+kYNDwc^xs-+AASuh}0D_1LGiaJy-Yu94u~-BT}rVS0Uj zLDIg2#^+UQKkfLPIsc)=`lf@|Syq`dMX?6fOw6vo|3k%9?aFSMe>qE~&Mx_H9HDY6 zdh7b+uFWDGy(T}-WJy%5eeS1Q@85A~2gd>SWh_h{LDBvHUoBMm`>uAyw8CqXnF=kq zcfT)cvrIZMH>uD5;=V66)!%kDtM2;sDDtdt{Cacw%T51TF1IZGkr~jhFCC{VquiLs zysOrr@p}9nVKJu(&rbi0Z)X?$dPFWnbHWal?=lmvvb~yHCfjmk;+c?Trk(67&+6DK zRdeid4XZ!6)cWGK(mQsAvqOJB{rgi;=;8jp4$*kG9EYk!sge3&X$LLe{gzSZ7c5!! zs`v2cmmdo`4cKZQzx$len)LqPzbj{}=bbMSTg&@zGRNV6x*;}t>%0%|*jP;1UNMYrcY-CFI=viW6n2upYCS#{C0;`Q-&&!nCEeOE_eb;i9Z*Wdqg zYbvw7+WJcU*cDfiJrjBhrWGBn+PVDfl?g?x1t;Dm$HvDdHQxVmXzJVZ_abG^dRlFa zGvC0-IOE#Uo`c`Bu1@RQck%Wq>;JElj&Rjv$4;L!RpMNIfx7M5hKlaKmF?vdTJ|Mo zmQ2{x!ela;Z{COf{haHxuXfg&eb`V|z}sQJ+1K=YW|XI4^PII3lKVRa7#C--Xz%-< z=$Np}waM%X>*?3Wf&_0&O;P6lpTg`c{N9uKh+|P|K`VQr7^E;Mr2jy0?Jds*xm|JQYoYVEBy$?xa6IOD3q$zrx!=QU!T3(E_+7re=T zSG+;*|GN6Up~2A#x4vwjHQ(@{@X3t8$Fn|r=P7sfPhrfKIk0lpex=%Wrjp$17^~kk zP42tP;!R!!ikEzPD3l`R`TEzf$4SWwe|lvn{%~mee=vR96-D#P#j;`U(S6P`(|5DRp3&F6rIK}sfAjYP%XPiE;~vkt^!eP@YRBrv$E~*v3}4T? z>SKQAshr3!#}$pHY-@j}Y=}_%{5G=p+JUG_$<2~~THJ0k1|MXotZUX~Ww`x&;_1EH za`v*EoFy-J@%W!@+qgyNMxDIGozA1XFLUXWX6+pToG0hZv24o~vxyqN_*}9&ucFX-LJz@Rp(EjWD>(`|ue)_w0YS^|z zeg=+@-jK4h)k7>MpHQTar_t(o}jn%o! zyTosAZP~rM*Ly;@Ez7(alMc&DI=%cXutz#8KIQYR-h~+(ig*&z*=K#L*{-)v$81^C zy%v~=78gpqI{Vsd!qWk*BfM=&a3gh5@zFl>9SWiht0`JA6wqkGo-TSh>55D zK9ehQsDN4Fj^mmm25FmwiuSM`Vqdd8+xWox&HrO>G>V%}nWDtWvTm0H+mpk4YOZE( zIoZC^Qdsz#(JLQ`Y4$Q}WT)M|wN5rL=JY3-FpIyn9vc+D6|gk&EEUXiEw2;Ei<|B? zhj*u={xkcI1BUxLx>@gCx&GelQ*hyqV3vK|((P&z)%%~Fdc)2<_5S}O9AVq!rc4Pl znV&x`%xrBMgTDEe~nKN z;Bz^7xB3Ow6M}dbYrow6d-mP6rTY~wZ~fWxU{!d4QwP(b$~b{9wdETx?|5?Y^vm5Z z_NTqu{h)T&gWXRo7ZvQ1*dgxnqi??r>!RD9j9n5c9QAg+JMI)R3%t3{%8q{5Litef8cjpa>_Q)_68 z6>O1uwn3#lwq9vxgj}$V^`gFc;SFY6?oK+wv5)VC@kV|pOWp5B?q@|Q?-j^&HO@L6 z{(8>*w)~hO8;AI6DGx8F7I@BQELf;BVuuI_s7oAZA! z4!ha*`|V7I7U4f`g56>s5ntv#Taw7d%*zrZ^FBtn%WpxX@vZ%tfejHX7d2M7Eqit6 zXkYfpiwivpTa5p;h*Wm*9TY9Tq&u^==77w0>sb%vR&>Pu%ww>docuxf;w#UmO_$n@ z`?_yTc(O|T;zJpqUOVr&4c-sAS3c<5KgZw|%hV(PB4q6*W$%{OUsw@+wlQeeFT>9t z8txmObrlMI`Ef1pgPpVH^BF$NJQjB1xXQ%5$2;@ATBUo}t(FZ8&5~I8EtBCA^XJ4hyVBIUwzytp6dPV{jX1~r!O=g!t-ll`_;XNB7u zD|DCth&D1^?)p=68I#lXV^$L@?#RuH{2ZaOzwgWv4XLvdc8k)ko(SA}cJeF*5s#G? zueyt}JZopHJH6Ov&z|p1Y)@u*DV@mB`n$+@%|~tLb81sJdi?l!eQiMoyCt{wu?~^y ziBp*EUTDkgPE%=%cyGI>d2ZrX8JjDbB4sO$BwwU9o?M!7Kg1;Ghk^0I7q$BpzPMGS z?)-V9-9HJCD;ApD#GFO{)VL{73OD;ToUGnh6>FWQf1<|%Q)^u)DUif&yzwk$0!BW5YRara! z7Y1fD*l*-i$##EacS`PPMx4j|&vO?ou}S}=V$~t4cc%9IJ>LlzAAKl)-Jh|RKmPpp zTZ^-H1)V!5&m^*Wk*Q{-!6Ro0DQ1-u{mZ2U0|Yp$O)S3MOPb4|vHybiD|5AVj_dt1 z626pAd%c&dGB0X1^Mp6*hZ3~dje56CHCFqzDs$U|tPM{$YrbMPVOsavL@cCI>G0e@ zyRO7M<5SCBo-LfWHE6EE%#URky7gW>oM7U8Ax^q(18c6YJjv?@ieof4%zYAM;gL{q_|Vr2=~a8-b@s82X>_R~!m2S);xrd0*ojgGW=W_HRs> zy=ud>Q0q&7a&qI%MDIVft?jh(uiGn-xoS(OWM^|su~I_EhL@pia+9Y=b(vZ5x;dO^*Qa|>|81T{lA zw5r5G&ACcPLq2!Of04&K&CYZ;1|?|;7W4$CUbrZ9@44W#Bf(L7!uGgS&snieWWLno zRCcZONfHSgSERqXQ{6tZ>f`T)E=gBb`L0b4I=D<_ZbNnS1(g=B+rs9WUX}fJFV|E) z3bx{nRky2L^HNMN?blZISc#-!&gqvppE?MwkX==NRJQ!0b@LXt&2#1}uU)0-axZC~ zq-bZq_r3VFex@d;Hz(xW6nR-tpjWwnb)Zl}mLj{(hXcg^^bs+p!) zr{ozPy;$1ty^}vy*e`#QK*+Lx4zqTC$dPLv?5OzbH=fIeL@?aUt}i+h>XpzpF;3&W!D7LGeKB%^B8ML8$t9?It+i))a!+dN zqpEe?A2&QI_P%V?6?p60r){7AW_WLYIrIDRgtp@ceif||{3D>__VY&J?+6=X#!h8mDf@MinNOC6D%n6}S19d6ifGQi(Wh^W&Jk z;_lT4H~BZ4ya{r?BhtDd(=^2{L@kkDMvm@ls;Tm z9XNI6EnWXCLGc!uQ0`WTayg+-JAJ)OOAo($?vWLuTK^_^%T|ro=g)7uu6VBeID7k^ z@Ywo)Gx!ZBXik>%eN>ShI9o4Ycm$}pZcs}d!S`U$sWeQhbbI0 z(@ItD-HWKpH=WFPI_Y7%l8TSo&PO+H|J?L@N^S?wwC6T6j>~JR$fd}i=`6E)@mpeB zky6mtaAx7uuBMoY*L2oe?wV=*$Y8hgW5&$e{WoLxdere94cc;}^Q`35IZHV{zF`QH zacq57682&Foe(C?&1K4KcN$&(#p7eZv$}Sxu>9rdduO6<+wQFS9l1L@J!bx(_YA`XgB`rPy)@Py+`Mh&ksCgHAN`&EQ)klj zJ(|b-PtPvR-xNGA>Rp1(?z*z(b=p!#*K7EHo2hlmyYxcZ=b(%WopnKJdlbFS?0vy5 zadTd!z>45wQpRR~+!sxV;ds^|Yg3`%YiUs1(p4ZgS$%8F(NgoLtOd?;pIscj@9z9? zOJ>LJtUf`_J)T`#=2oX?ZA)Dme6V9u$UP~&SL==~WAH60Y~A}Y@y*-y0%7d?Hh#3p z)b(=IWIVQ$g?Xm#)QvxP<^St<^Lcpm_Y}q%tIjzEJpcQs&1+)clFPIC1#Kjf(rqll zS1T^@et7-pl0RopoZ7L`I!SKMM3xY)6GF>lQcv+Dc&%QQJo&6Z?u)cDH?Gflm44jN zp>cK2`Fc4WkyR6y^yEBQd&WH4rQ`8#hCi$?1S7w$zqR7fGto5fKer`fO7+7Rylc)r zaNSwHK+MFODgPb&%P*1D2`h~3mjxZ#afprm_xjAf{Xc@P#=0#rJe>LG>bse3%Z~pE z_WZJud8%5`C5C_-nJ#?i+4pP|owkQ9*7KQo-k;o{8Wn5vw;h>(d{<})iTn<{({jpB z@U~8Y#^lS}3hhD)GL=dxvUStz``33jgh%tMJJw71_;zjT^z|2Bm_L1;?=qFy^7^*E zXWX+^FLZdn$oXU7f&AN3Ih+_5w=0IM&b~FFJhY6Vq=_YJMWWQ!t6y&I;B+qTX)i8V z^~tz?{uP6as(XeH0&2F2$1C?P$#bsSDJ|gm>Nj(%fl&Sd&ypoPXFMl06|HI%(fJ_6 zw}@eTdeoh!+1puy8u-@#DxBZ={q*Z&SC&n$dB*v*xM9@+)fg=quM@XUMQiQ4RquJj z($@0cdaL6z{+=;5-En)q=ljF#8~GDFE*$aqot694nLppHOJwuW$ZDelURU2=JbLED zFJZ@diz-E*$NXqsz3kJXXR>ko*IxPfV40ue8#DD!*@wRhe)=OA;MZH@qwQX;H?Foz68?B=25EpoUPHLmcmU*jI)vgRN{*?UfXPbZ2 z*Q2&}K4+EBJ{+iqKltg>8cJK@il2X-Oe7f!zKP~Tg_UsAK(E-bNs`5B=Jt?pBGcb`>?*3ol` zc)IJsf=S7ZC9|_XXr5E!xZ$!Hb+Be#? zDDK|H=MeQIL+tVGEeA}Z6Ep>u9QF<7@U7U*_9myh6XCJfkI@z6U6J=c?;eBbv zwhNCIPSp3dESgoOoZ;9YBFx(mb;thC1x`_}9Y0raZQwdp)H+>d?#bgpxjH95o!_ea z^^M>q*@$naUi+;6+Q85M?0UeYdKuAnrZw|R8}8f+d$ryA5vAvig(j_RSR9XlluE>A>?lFH5g{ZK`6` z%ey0T$T;?t&O52Y7Edp4ak=B&9~pgSTF}wf;5mP+)XMC4N2$BDS)4juVY?tZ|Blc; zhh;m`)eH9J-dU{ryYWbW?*2Lv=hKY3fAL)0@MK?loo%g3hPn2l zPu|f5JC)Me%Z&Z}%+j>%!fRI?;w@ce+xCEM$(k#V_U)0&aLMjy*)eJVst0TK{(k(o zpu}wAR2g%Flt-4ic4vJiKgztdJ;xy^W<*v40biukuNy`k24&^M>E%|tHr}t0MQ;#{` ze!gi}{mo$eqHYoO&+{+t>{4d8zWwz6y9QaCCpSbsZ8>}RL_-pD(AQ-4Th0aAzl*DO zzWpZYwx(x!vT4PXEAu~Pa$PCSs*7r<`FOhPSIx@c&E*@dHos4w%=1XUPcx4ry}aw# zuJ_a3x6OUuZuThr+5dZ6>i=?V{C{h=u*J!4j^ADOQtC~Y!~>Jnw=lfEIAN7T@Ws91 zQ*QMCN$pyHwyaJ<8+|wBXj+|Pwzywf8KrXuiX06hZ9<_RldIO zdz<(8)V$-9-lsnkZ(StMa-!j3kGulo$16*p`C3Qxb_lZWzG|xdIZ;wHa-K=BT-Orz z_GdfST`tX5?b%`V_r|pat$wbi3%(V$Dqc)@_w3WJT^9=L`j2MaXu2bJQ%J{3{NcXu zDG9%P#gYTgG#Eb)*88O-7xoo!wnDCbsJTt8y^+bkuDaBzHB4SHkCE0f!EP9y)Y=b zV?*wy33GKeajst7K1nZrk_A3ag`>fgGz&HHCAdea|zda>IX$sNXBOILmg?={m<-So7dlhN=*W8%-Udp4;F zDSD}QomaO+^i3~55_6z`=EMy-jdinc?)_49%qHKVY5K+dZt31Cw+U=3S|43{e42ah z=VQ~RbqjZC=r8x5sT}+0wM3 z{;GJX+Va!C4lbG9JM*ReDpiveIjkK!A{+GYt(#E0XICCHzf9vycur~Fgz0TGQm!n{fG;nCC1)ml5=sh8}yKkagg zYPql6EBW@1N!J%ve2sjYbMx^zTlUWiE5E6hE;oM~%lV02e}|&zdG(Wt(fZ3I-^csh zxUTfGa^u+*rtW@ccJk|g_&0CDPG^=?8{ZijzmtlISh%oXZTnsu*0l>hy`H*DZT(L7 z?`M4iE___oayMbxnF{qUDc9^A|IZb;;JeWMR9j~I*H1^ktY@q0^QsLw{W!XF!jJ0g z12%b6`~LFTC7*ch=hd@I;@F9w*+J@WEGkw_PUDX^`{p*aSg6d-BXUL89JYI%mHW=V zJoI2fMdbp+OWG>UdMcNz8N(0ryo_7KfAaWtwfdTbd>x)oB3tCnOt#K{x#LdSZ;wkA z+Q!UItU>RYEX6Kg-M>G@O!`cRL-B9Lx7{6@%V!FBTS|$8UUYD{8LpFir9b z^GUq6yKdWTkGD7OoII%{aZzgXnMFTz_#P&#?U^}QhFiJxNAa?l^r+>>J1#MA+T^%W zV4cLHM+{GR@;?4sw(HAc*LjvdPg@pxRV;kJ@LqR?$*M_93i+%zKYiDbSiX*{vT4TF z&sR?Wul{v=bKLw%r_WE4+CQ)SbIkk*k{f>S z44uAtW5}<%CGTCHu+|;=6z;P>B13yymEPk?;=7|*4yt%x6aO^-wr|h%S$A5V9eG`l zz4@x;Cx+hHo~bLfGd6vl&^Gf<|k%enAqku`7DYo?g~YQD#&eIoj4 z_UT1A(qAXt`F1fb^HAR>X?sS+79XE=$BXz4!|Y|wi+8=KT_ko?bi=*xPoG~n*>Uy{ zgTLk6gnI{$be_d7jNbk-nsn$&TL;k+rPVG|IQC)q?JYa9 zL!+#u7aDs^)#k!r>-Xi+;Os9qM|8Y(R}jTLm}d@KfLok9 zSFPA>zrm}y7gLqqUcUdv`k0fa)SCZyceY3$DqUQYX;kq;{O`{fzMXI9aQlCFl(j_f zQo-{RonNQ3$1lFs5wQEhlE(*jPFB6R>Qu#MDNW71M{5g>r2qNvKK`}BaW{*@W|e7O z7X{>hbxF;7c}bz|Td2Cby2Obt+0C828R75m&+&NaJWo5G*({0GUt4N}sq~!nZU@{` z=g$3p*L!|pWJ9@i@V{ky(%q-oIV3M}+5hAT>*fujqE-ThC)ca)i2l8iVZ%}TrrnEP z95k|@FqPwuHEH?cGYFQS;=gnRi?b_coL1LGODxsowb{GVfo{Khx$*}Z@wAf5_59OVV7+o z>vCrDt=O`^Z=z3~`MW7;x#i!syt~f$F*W&;@}tF-(~q$xnm*9KdGu?+vCeah61_`f zmU%BVl#Y8lbH#!qmlm>|y8O^BpRdx#{b8k_>mqiyHJc6p-d$GYeyHyImt_meA9-oY zRvyZkZSeU;nv3ZSKdU3#W2R5eSm|r_Qt=S`;m7-4Er^r0*{aU8;_hdMnjL03PvWe$ z?Yeov)AG_%vA6%s%uP3a(soR^GR@*d#}v^s+peXC_y=v-)Ohau_c>B)4^{bpo~Lv6 zuJ^WL=fdXIN(`?=ueoPCWj>pec5Oy)*d#aiw7qP%kNdRq{GE2^!_rQh_~q<7x9`Z( zXSwiXBEv%Un~GaPm@h|L-#XuKG&ftUrs2DRu1xAl!Rq+KeUsbx-^KsCrNN}|(@%YJ z@AOR(^V(;4R(9vS_@Bb+eSUr#n@jy?S^lS?e%Hem=$sbQtnzAo_BP?;;=4*g?`#%i zu8*l&-jlriRJOjn_4Dl53v1q7Roc0-Lt|Nqwsd}O{q%hgEFE@U?e=3*c_*{%0f(s1 z{Fj%eNO7&-d^LMkVdRe|F|D=PUtj<3JilqaLVfxF8UJSe+fb6zX0jw`jkWHxJGtxU z%nX<=(s9gStJR{{-P8XEhh8T+JN!n@p7N>oj>Un3^@`uk1m>p7PrnWO+H;BlBVp zGrkJrpLr{Lj--3|%k$IiHpkyQ6Z1_b%vkWB!@8`zuUOfA{ShCob6fl_mVTdg;QWVvOQTUtfN{;>JO4@!~TV{IV^t z|99If+_da}kG%HLnWDZK`_K2vU8s5PXQ#FF#hT>;zvH7!BrIm$)rpG!pVhX2@s#b! z-Gw3l>$$m(y(!Ak-`lM<^KYxpb-iu<8dc4|m_m2{lwZgm)ytB5?%d5Qawki3O&jKI zIcsh+Q9$$e`&~~w1ftgzM_s%AobN|=(K|k2o(ZOm&y7!>YMyaz(Xm@nJF~kMd|#jZ z$DOA`#9vN&>+hqvt(Wc1M9*Zh{LGp*!M86GtIO32n+%@o?K>LA_LPs^ zB6sea-(tz}TQ%QQTCM8Nc`{%9`!kpCerwa>qpwsil3W+NQZnp|m&NLN7hk73WbNvi z`*YQlT6Nv6Iq&D|H`%UKvcHqL*}rG)qujHGowtwGA4<(?6@A^9sbp9Xy|HWz*M zK8(@eq2Ismf6uCO?+ZPeeeFh%$BX(e5h9=Yxa1c0E?4SVGu3vNoYlOTEr~>)yooR$R^R*99KklA?JyJi$&<+*QE( z?$lD{mRoH9YJO>CzubL%)6!CHJ@599bJiyxxpMc>Pr2>O)8FvSJrcK?p~@^$?PzYH zg5`v7Ujr(fo}RZmsxJ2}ZdF`ksmt2O{X)5R+Z5+r775eJ^M3NDVaqe7`xAN&bv69a z^6leEIP$t>-ORA;?uuCT>-Nj`xlA};?^`2p`(vV>*JZuh?PitP$IG*iFkH6G)k@BP z=V!yUC?cYkS$uUh^RG__ji3DPD!Z24zii3r>YWGF%uMpLZoSMtd*Rf|`HPin9eM)) zu8rome-c$8vv)zosh-Jym~Qx~+Qm0B_PO0qePi;<>CJ-OzV|OzWwWuIJKz4x%UDye z=1}kc^UL{uY;AXU?MT>r@;ZO9SNx*Hjh69kZck&1uTM-kQ_;9=>ju>e(F@piT%T3q zxsb)?_`2Gr=!dT-7tCI|VFBC!-0i0yzdXiw@?CS@PcES^cI%UO9Phn;eb0Wmw+Am| zy*hsW_({{#4Xgd@uQm04`F56pXPsAL%Nd*On<91I=h9|}G;lOtj{dsAwe4Y^mWq?Y zp6QK;cPAvVtY{JY_+ry><=e#(&$j=c()na}uJ5iW#_yLFwwV12VVL*%N5hv-KfmpI z_B8VI&ijx0H}iKrT$u4f@%MI?*YCEz51g;}y=C?ZGl%Ve{#zgK=s*dpA_bUYX@s zIbS+2vE+{DXU^rH?ye|uaPEI|@iJr0lK#q@Nnv-|i_>o@hfGN8Ny=UteWW(H;>RWD zW~mRZ=Z|FGvwA6aDOref@13AW^H?X!dj1zX>;9)Ru<6-RTdC-%LoUypzVD7)&_2_9 zV?l|F(7N`yUyAPLynOjn=$t#RRN>_d5=Gk<^Yi-ux|Ze9wb=`P9MI^{bMyJfc(wP?v*+~|LAps+ z96KI-m&*~q|F^}p;?e0V@ogFXmaqN#8q-w%&y>)*^Tg`iEI;vI5%D1!uRd)_;c2X0 z-j}~o*o*biktx${^4#7;wtiG=50luxAS9>8WbU503KQ)zt^H>jLW<(jtrEX7Z&8r# zeZPCzN)E-m8#e_rT}I4fXr%5K`q!r3(*EeG~|*sfpI z$#;w6Z6kGuX8w=6s|`T7p=&-+gObDMGh=sC`Zp^g6M_rDHRE@0G4U-nb`l3Gke z`PCiq`?l)N{;Tv}XH&@e`~&i-d2{Mnp8fB)dcE;oY%_1}^sRQTF8kzLRP@VjMCaVz zqbz!T@g>oJ-{rjDE!VF(ng0BDL(sO^SnnfGPp(>fU~j|g#i6~oQr4~9;awtf`{#cz zPOqaU=N%KZbPSHskq!^2y!7<_vWGHd;U!&~HLaH78y`$&e5fq)Xp`q^;|BkK;zk)y zJ8zh;`zH4*>QVm;zx{nCPZijXKCgeovwFklbwUj%&R==Ud9&^J+H5A5fRjqmzO5Gz zeklp&(%6E_w1)lm6*^-k;0s ztW@^++&`UqN6>rus@jHirIR&(C(T;%(Jtfb4acg?>OF?W=Xjh%#7lk@bzPT9W;XKV zJ>&UFeA%M^3oO6;cE;8mxfVP3@9kO2rr-W$MxTFJ(ZAu{#IHQ1?n`fc%-7#5($W35 z_^g!9)VxLd&4H)6QAPxR?DycV!f&( z@T`jCl?kVp{+^uA+rIpF)SV*{0-qb|yXSAJ+b`Pq!S?&w9_K*0wU)201-?7Ob@ay( zN2`4Qh@B|W^l-e=7K4*})n1heBnN#j4;1g)Za2NuZpP=@2ipbZzcJ>WU0iGV zdb9sBmG4Pq`|odUW%Ikhw?U@v`~oK%ql_bUA9tO6aaAItc=NStU2En`{nj(5EBHBi zTW}@6JuYa#ES~BZD-WTR}F0VZ!k)-#z z;IG5v|I4zMGTpFgz5Hs97-K>0;SSe^DqHn;*Ze*z*EB9l-2RY1mEq&lLlb&6s8TICSggXiy~R3n&KXk! zqwjtJ9ARssq9nXOL>frMcfU?=xFU4w&x6;eBfm2*S?~X8y{)M0{7-Y|Sk0TSw?gjj zRy*byd<`+L)RV(mx<5ahB)%$6K`3~R*^|vykM^%zue3vCf04ueogy!mo#DMN`+?i3 zJYZV1_uAOKZ`@ALQ>g!Nd28zNcSl~f1Wo<1-;1lr`O&{6JuG|9FSMO~=Uq`&;Dv~cLRF z#QHsJYmU?$oYx&@$^LUgW9Y_I$1`f@>m0Afe2da5PBit-TfwpSbGPmG($G`C)j5|; zf1>m0_4fIXxf>_D-)T%`nr?ICPUGdk@45>D-+g4vC|faWqNJbyY>SL#zZK{GR`2te z99{kREyL53>)!2J-2Ecnna_8kNZ$0ese5Ezap&lNuzjNay-`K-Q{I7>wUv_JqU_gM zzvzf?>o_R+i|M3y=}K$I&DTY3O=Ug_rZq?3JiKC6O2>^kTZ|Uwsw>Q3FO!zlS!gL) z<{l{WVEsz%Z*D&|UYuQ`!O#2Mi#bu}OVD5ODTic2d}lfri{(GO9@rrt>>rn((w1Ho z@NDLq-_!Q_Dtz_)yXN!5gFSovts{RmOV72*zB7wSX4d(0u72IOdXJ=gt=zrD`|Yl{ zvzywV>rH#IuHZ47>XZ*n3jf_VZLvFWdCmG;ub#)KNB9ezV%{ zSE_#RYp`CuiT_Xjn`X7YmYs|L8`7G*YsITm3!8Ue5J-RPD*PwQ=Ahyxxku@58H=PI z|F}7^T|8TH$NIpSzfp|8?>5)BRlc%RJZJo7#;zM89I-qN(aujMRWB&sMblX?OkQhrdhgu8mDBDXnIY8vddlmD^V-T*O7*{&`5n68x9rm{X3OJ;i>l?r z1&#-&1@E1i_rWgL-l?ckJjAkb<28XU5y3Z?>Vh`g-j__R+Pp^1Q?0ai?Yx+fm%=`u z!bHD)^z>OKwTm-2dD9m8`%@Oleo(xSoHkQRJpbW*eoOs+2HvkX3_^6hZr%U#F(W7c zSH+q8zh0ytlAmea@uzEC)azFanpeKj@ue5V+Lp!gY zT=q#eRWkoy*~8iA{_5S6k9_^_+n#Xd*uH4}UHQ9W?Q;dyT75ZoZh3t4^RhoO&GXit zn18u+;{qS){VPI)RVF*l&ptY{Tjj&HxqtZfO}V*b$F+B}lL}rOv5>OQyOR4X^nB)p zN3u2PJKh;^80#3OF3Vqa%(*R|`O)k(3+(g$ocilfRB8V3-cSA5&~v{ewL@F_!)2eH zXTKWPw}R3F_`P=e!QqVU)9X5$j(@j%dq7L~8RMyVA?06vI+vDl|mr^4KvEWXdX zK1pujws%oZD%7dtH zZN(P*L*)Jkg&tD=@N;GVrh}$J{2R`H*qERhw4*M-@|0v@T#BOj`7^eb0+DT-rd1xR zT6OyE2^*fuJ?`-d2N%{0Un*vh;X4rP{N}=z4(1a%)268%HB|lD+PFSD{}AiC^=?l- zCiJoTofc|1fBw9d`HJhi8FHqdJf3~lU&zE+Yo`3x@AKorXJ(w+-TCIz@4v^?z1|(r zlT7>kPso1dt|w6!qb7IX$gL|{C#e+Faz{GXs`v2>7v_%F+IIvFsefFyF8z7=@+Ac} zhOYNkC1z+$_u`zg?`Qs@2=5xhz>E8`?zShHeG$GG*qUzss{H<}3vH174Ek66!dI??Gmi_;1 zN6ng$of@msnjf1XyJyK(L-C=9^5MT4} z=JpDKZ@+UhvmNw*M&wNk^54O7-qHW(mqS;)8~YB|>~Ju7rF!1(#_k?2-R1u8w7$wX z&px1&D8RJ#b*-m%nrLb96Y-Z^ujA9UeM~8Mx_PqUx{tXVGn5L{zPGJP`q{QMhuz{k z@3BAk&QGr4U9bLXbHU|V-`NVM%J1=X zF)fLU3oD#FS1|SY-}kW%L3?<9r7iGGU;3?grHs+k1)9@e$fZ@hf9_*(DpY2dV8yPV z6OXh!%e90d9%M-a4hiTczpR>^awJCq^=?d%6@Vl?NU)?Rc_v7%T zc@F2kuhdmJxV1%O@}z*wk7|!LuMoHsaP`Kw2yfe{&rf^#6)o5=d7lptU9u$h-J6fB zdmk%LIPh=@`;y$SX_Cc3&AYc})Eo9_=Uq-RUE;>{>bq9%rQ63g3q3rptG_tiXswfO zQe-RtUS+3iCOZD5-)>CqVON`*tDW^V$@Z&c+!xNYztJV-A2rUGt9d>P@}K|noA#d2 z!!ZxF&+=IEe%qpXLo59HPC0|KE8hL&<-AZllb=~QUFf3hS8=PW@+%p7Ch~3BKG&tC z=XiB+QCE2e*YS=Tp_T_{Y}xJ|zoj30z{_2gpV@y~>X%#Mi>>4eC1Y4#==R0;q(??s z>1~x4v}dX4-J9`S?BeBjHGf{#FsD@ z=Jdq3E;fS459CR%N#I))sh6o|VJG)%>bu=jrlh>vp)0Vo*S_kAX{BJK%&#Xo#>INY z<=Ook6~booJ+z+8YMAhgO>@O;>krq&j;UUGXEn*-j;F~6OZ(r?3T_F_m=P9XCg}c8 zi79P9?@va>4;^uge#Wi!stct4l(=rpTUEAv}KUhhhEnVVI#ZuRQ< zJ{nWHOM=h+ez{)2^2*_@lRek|>MsyhZ@o3kWV&=L>(VR!zUEu9534a5dvtH8{Q2Uv zQNdNGJfG8#7D}!T{JFezdga?IE;Dyta^0c$d0FGX{qi$T?AiZs^R|1(HN;a2fyzW3t>za6YPzQUk?&8gnef&3(!Dv7+b#4@#4q7k-lV)t^TtK1saX-+=Z=n%cYwYH>p3@ zTK46B$7Ok~U?$zeZA@Kf+NR!QzLsmJ_vY2cdy(rbj(%#jFc*{XS~I=CvW|s8UV-;( z#}bX#m$%%$c15$qecIjS|BkVp{jq-I#maM$n#=EVRqDL2az1v}C(E48~^m1 zC04I1l%1-)PPDI)|03hI8S<6_b@P9$t8~`a%X9nx^h9rQhy3K;VqTWLTe=cwnfl!I zka?lKV}rf!zpetmy|Fn*UfwzDb;Zth(TjFHb7SwHAM1E;6)#x0@}kVzKauB-Pma6u zf#ZONsN6o0IesRh+nquMjD$UdPDm@nM4r**?73OE>a=`7MT|npuY@b+tCoKFv7Ta zeM*yGU6!-F)V#qwnrGgPW2?IFFn-^~Bhj+RM-l`WXMg*{COxkWey;ag%=}i?>hCXVxzEp=9jD*)r_sJ5 zp*T|S_df|stxiR!BX{>N_AseWc&e4zP*`3h!rd{QF*;rKVvYEo^;49S9xeJ%)5WxJ z&C-Q7YA3a~8eW!r>fBVg=mnqb;}UQAyhfj2uWRoL%k2seP&u>tuF$p%{a2Oes;TbP z5xmN&b3-6(7R#S$!A%>Cedhg1irUw1Bgmv?bnb%vrxt$Mj+@bsUMyJRZ7P!3FIMv> zc+2gkJqqWtSXrm>|J?SM@9DQ=zYhK^*f~k=sp`4dv`eSgHE8VmJ$3r@$CD%93cPwg zi~W^};O6V|HM`SKYvH0wr)Xp?W1bnZ*#v_%XeDY{VZe=d$x4`_R#rz^U8NG zm@M?brh13ZHqkA?8(b=u`OD*hIZND~KMJU6) z)clCap(AY}93{8&_PjfMZo9(fmwSZYMYgi_Xg2?v@NenPsR0?HzBwDVb*f>VH(u z|NmFmj?M1+_m(r}$EIAho3XR^*v=E7S)ZK3LY^AMnTD^I1@}qRuXYz! zd7tm-#Q$05%WLsvj;cqrN;eiCWNfpYyYk{1E0c2b7n@GbIN(zhSLb{n5y%$q_&PFL@VQ+{p2MN}|64O^3&Y#FDrU3Bg?#vW zzN08jSxIKeZ*7lW%~c;xZwM-zqPeyF^NU4X7XlAVJR@kaaK)D=$qP=ftXtuoe*Tib zY5w1mWaEFH(IQ%YPhTH>)Otz&edn3iG29G(E~ysV|Mf@a?cL$c-dJ93ep@a5+o{0! zx4l*^oHDnFb-UiD$|&2q2QdMm7v@Orxp`kpFht~X%63=wLmgrFw+Wfv?R$JBm48Wd zXmFB`Uq{2+4+ZbS%{Fhie$(*^$3Ee#jtk!=>1q8gEsK6}VvTUyk0)YJY6V0;+^+IZ zxT~jJZS^h`ZtrFMh`Q)8<>`c0}Lo2}BZ^Gqj z;U?ETR`M;U0_DG5b)Lz5)=D7T@{RwR6@4F`cg&9XR(oPWd$`stlVcb80>wE`?F-q% zS|3yTdXX>J?w!1IoVa6G2skV0Kksa44tHwH|1Nct>B7>jQzX2a|JU72Qe9zipf%?A za<|iEbNks5jkpb~lRH9pEn=uP zmuO7MpW!k~E-%Yx!^+7?i>J@Gc*=XP=$ih#(<}D)^}>@{B-w2cizV|KiajX zl=ZXN$2BKDJ~lh@mv6DN*VXR~8!amTEarR1B`TPocXZADJvSa$-<=?OJU7?N=km7o z;-^lCy_e+i+Q*~P6#6E1Ufl7gWw##vv|70AzvZkyx&O4+{s_;i33Rxe(pnZU*&$)W z?KiP&PWis!)xNE#Co+N0ch}m!hk-9&v8ns{S7ls^6E|Mrb5%j6e{x#elDra|DJnaU ziF4XYhCRJztN%~5m#t=Y;h`^Cv*t~F>VALwq0ap)=DGQ^Z{o~0_e>03azIXI{pz(0 z84|2*&s)TQ8-|}b6(+=c>hc5M313wYS>{BpySSReKljGlHRTTK+tj{2tx^1#@m4u9 ze(mOOCl6!?+z#bdyZ3zKbypDv#vY9XOQS|#r69B2&%I;gEVlERUhxvP&C7V$)OV}0 z`PS99E ze_L*+f~3}qzd8+W%qDGYBCq>4&0F>6=F=lPJ|F49hFMBe}vPAwYXSKbgj(iw}!j#T-;E$Z$bWnUFX##FMni{nB=~E$#*U5gv}By z`#)|gS<#sB(Ds&H$M4w=E1VZ)FTEmcdG32+k$CxrQ*!dx>t5MM95&SQ?fJpCE#UCv ze=7>M%(|eo^Kq5q1Kv*;Z)GpIp>L+Y+k~C-)xG77n=Uf4E9B^WFz+}il4!6hxaxNJ zw{(^*lh|&w{?_Dr7uCa5yQ_&MYRy`eX&Mt)^LAf9s8qA`)72S_uD6!X3SM&L=s;5im%Ozw#4s-bwkhdu0t4!biqpcfDdY@RQ z+E2(6uw~?0vF+Gh%Xb=0JU_OCEIrQJ&VF$f&kg_b)D73f%EB@lDZOYiF}_%f^@YK+iTj0I=LJc! zt1yJ8)~>GD^?i$_chc|g&c!^tU$++R+$mHrQL5B@f{4|mv%=p6H#)R#7EpVk_B-eG zM|UR^@7Rvkb#ldWU7O{~YAm-^_-!auIrC1b@YI!+x>8eOw`*tr{iAVJENJ5D-_H|2 zxh>RTFqND4ws3z7TTX5HmIWRj;g7ERg^KTWVLmF59wT7jf4$wYM(eWq>hmV1@O zhX0>L@^1Oeel^wC!ra+9W0i2n@gUoS8zkIzo%M@9{G4Nf>bBh%oEl96)ZVXcI-~c` zNVDJmp=oo&jP?z)PCNUnBv!g+3s{?NSW>%$?Ly{$U6yx^FVvqDNczuhS$TH;&HW$Q zN*Nlb?C3}l5y`h$mHB0Us`8igrF)Mj_f7V=(9ki--iGt`trsaPW-UopP_vn3$f(A3 zO?^Y9h63v=uYO%Ww~g~>_{KC#-BV%EFl3Z=TK7^-!!sEvA&7bn~moH!KJL$VF@9EYX9}_m$YIbX;%6N3e)UQ;( zeaHTZ&?D*XSHuh+)alIkd7HN7Z}c;(td&AD7c4uw@cXtLCZ3itn+Sr7-vn(EoCy@ zwPiQo!~^;(g3cefy?0^6@^b~N?#+?h>*o+Z<#vuj)Ds5IUoKor86U7&8VGUCh~o1( z^)$LaET~45oh_l~<*QzKe@3Sb7msS+X}m3Wnz>j&RM;&a<` zOAdtHdb?fJAW-}5g$I3?>vSGBSOk0xXJhAEoR^YQSb6b)K&fe~mBg%^H!D3ml|APA zvGj)QKHhkl;ei~R@~5WRm0GN+7a4+jvIKt_PMgFb{)F$m(DzQx>8wscX^Q$UI1A-l ze|T|*s_Puub&>P-tA>jU-rlblI+k`S`BO*XN2X7lxl1bMCS+LDIvp3%Eb1)EW!M*S zSIp#^g5ft;UgtNBf_zIFw3rJtT^8Ij{Sw7c)yrZt<#Ou_ZsvPVLFcNH7I|za&p&c?aMOVMSQo7yI1Hi-MY89A?dUGUELiaF}Eh&%HVK{ndm7jzOA!kc0=%`e;J`c zYcdp$Uj3Fb@!JX8q>?XBt-@z-<~uOYVLE@_N3QJ?Wl#Ek5!w0FPU-N59osJKRn-WR zmsuaL>$2UmB~|&ecwT&!to6pHzwN4fKb=+oF8J_x?6*m8y-i}@XqgC{uF2(f)m#7j ztvBb~&)eJ<$GB8Qb0w{AO1bQVb6IKx`?zRe))pNnAi z%7^X?*pJE;M!XfhTz{g+QAjgsI<9ZZGg79>5FH}O8eQ;ze@Sfdo}MQ=d3#of_LUR z-|%3wnR3x_M?(3YzcUo~sLNOw>h533{CV=8hK7{W?wq2ttM_Nk7j8Nx^0LH<`~9hx z3+5#4+oe-j>a~D1`^`m8xmclXAL5Qyt!X_yv-GYPQ}}IHKXJvIr`@{+7>brndj9yS z@Wqy45^C~q|OoWRbrU*9Y zYUc;N(UxSKlK=JU`WXfe5nhL<@A`jz&-}ha8~@*N`(Nj2z@qCXrTO~otjQmo`7^Jq zDiNuFf1RTwTfgOO{`6^vMTuFN>U9cn`Y$_Urq4?adB51_=Om3-DTBG@t^yC_uB$Su ztY7lD!DMxdZi3g;3Wu!^JfwbxN~p$uGhy9k^s%+x)es>t=tUcjmrUS8p!Ux4f*|;XMC5-|nmK zyOuRe@txIr#LCBBqcAThjyd6aa#nY|5dV8< z*JkOhtdlzA+6)?=F2B8a-%7Xr1(_3+CmMIgD}G&BoFmP2uOq*rjO7N$x6?V@xvH_V z1oyg&EvfIG>%Z>e1mn-|zfKcz*rHe8(Z5RdzeDwUw%5DMuenW2&;Mwo$#DAp-K@Zl zg_G?L92L-Zx$?{4rB9MVS6kwnO@Fd>EHGR(%`%r!t>lJ!LT;}}a$K!O*T&7Edv<&_ za=mk&G0f+aR=hsz*?+I@Evs{G?kHU*_uAp;qR-P`Gqvqrx|G{I?U#(_fqD0jB%M$% zU!Qw>L*kR4(oAc0I@Uy+@Xd&qej|V4hOeET^d^1JV%yuw+ePJ!QuY{m+${YdBD#3% zh2w|Y*!}mcUwTy|Lql%zwf1Eb)l|PqxAP`TCDxc(ra0F~u*VzCpLKo4!RTw(vXh@) zOxhl6{IoveM9|*@0emVtTiBfKJl-bWo~wS`FfUx$^TJc@SJ$p3MH_C-sGpeNE1CH4 zpS{}BhW1bW76I8Wj&DxbH{JK{!QbBDmnLyH9IjlxN!sl!Tg3-|}?aEtzd-F1pJlj&eM)UbMRVzEC*@L&Pv;XyFu|svm)XYO?-ZK52 zt-T@Woon%Kd%0Uh+qEt}$lmxWCt>Ha@6Xe2vuRIO_y70v{2{(?*$3@s|DRb}mN&Ee zg?72;GW&%u*PG0E@u+I$gBO+$%vk{YU00W z$tbVL?}<{CY_G0O);GTYvi#@VR~K&nUcP3N;Ku1`C){o9b&eG8|5&f}T0-E%&zKo{ zcJIZCeJ^ec&eklJIv{UXvZ!)XI@9t5+4|edR$lI@+Ffbp=KinilU#I7*@l=(ZswFZ zCsY2#uGO9Jd{%JuO^ep3gyapXSb$e%;wMfXHQ3g~c<96xbK{~% zLJI>Q&)ByySVR8Ji>m@XVg>(w+Cwg>#qFJzw_-#1tJ4#*+PqrUgtX}|Jz1x}tY&8U z)1=wcX6XMnywjx1a%Ah*g%dx1%-?>@enE@x7lZm2N1y(#XZt7k^;%`v>t&bIsuJZF zAFtkaCQB^Uv9++jnlID%Xw}2wblIqww#S_;DHG?E#!Y&2kFQUckLUN-OK%R^b{#kU zdp0cWRcF&5~Q#PM|uK3EV zoMh`XZQr5tLl5^X+io}QNc!^m*An|5C@qjUd|^-igQCcv)(02vI{anXnWqA`)&y_y zG%(9{>yAoVs2XDCTzf$G=hue4Yp-l$*LixDucELslK+Mm^OeZARS$Z8YQ{gj@aE{{ z_IC|ed3LE4(6SDIG|9ba9s(^yV_BWoc%`W-}*RlOhKUJvs?#$jlqW2$6TCzFWE{jv?LA2(N{Z}oImHl%}ue@?e{*C=% zi&G7?lK15Pb=U8jGWD2I*UZ)HwVvh`$_FX^XN~&gyW_)@)OL@zs{R*m9IQ`>VDx>p zKg{QGJGUqNt@>>LO61=9Gt*!B&i%6CL`|qhgSm}nCHu+$*m#n z&8=Fls1v^{efdwd)4znDZdN|flzuMUc(2qJTO<2FTG~&~Z~87>dvNBRa!g`qI|Ki;^YMZ{&U} z*F8G+m?MIEmv^(PB57X7~D)mSbY zdE)iGcg=6(a%_Ice7LzcMIilhY+*n1m&(xGcU%Sa_X6vumEI4une|aM``;t`UtU`u zcUPPWT&1(ESee0$Yv=jqJ>PDD`Xk;$+RXDn5%Y{cU#6GWNDXYj~;Dg ze~{+Z0x3cAH!1^Qilt`+A?` z&uI6rU3r(?Cafw_MtiFq_uhhvUB8O1Sc-h>U#skP>d29r7IC8p&;KT0H1nUUYh`lO zS8`NoneX!Ii!o}gSte}~@}tzrp*#J^jFruQUcD-KpC|02?On~t-Yw`ksea|Qo8S2k z{{3Hg+e?RY=4@d>!KtUO?q>LJetzOh!PQl2|Lh7g8P3Y(>^aBt(EjI){i)Rs3oQzg zs?|-F7Cp*((6#bW;88b+s27KqsaNs5V}8K9N&RBVR>s*$wvj50&)>~-yTbQCK>5ty zWol0MuA0ZGC{)(iZ`d?1>(|@%ZIiB99$loJ&FQmv+nSK5vyX4wJG#t!N7|RoxtmX9 zu~&PRT-p@)SKem2MR5a1{I8<)jY+HK>g0v~ee15Zx#0|- z-<2bh`FEbV6-&21*!V)-Q?q`Dx5EbkbGuHjPgUD8`#-g^1R}vq!o9y7cbz|mAuQ@??TQ;XHI9>HPSp4XX+ohtW zkL|5|nkn=Z zteDwqedLVL=9hDWo~WAbiITrl^D=!&q5C4cj5>=|P2PeUo~IO_`#;-qVbPsgn=e*u z{VBNFyZ7;x$G6%{CnqK7&v#!|-##t!#bL*=bsM~y;$F^U=G_kMkdT%iq^K z^!(<}wa<5*Qa#@OHazyR=Fz+2yWe#3+epsYUVWOWm*byZS;8^v+69%%4!(XVv;D=U zvW{#Hd-s{iPDgfby;rjG*58_q*Z+0r-1Ag_>T}|NYp~)m*&R{Z-~D#)aphWh@b7__ zi(=Y~*=_U;i&o9QyUv^2GSlYA^UYuHa~O17oi$Ty-=J;? zo}Vu+xe@beqV&JxJI-&CZ^`-|dFb60v2Wr=hmFLax&7OC!p-Z@g_k!P=S*_6H)}9# z(w(vUo!E(y+b3HzL60^8(_v^907 zeY5^jV)DyeuA!IZXkXC(&lCNtJTE6pzPepBuQ`iP>;0kMf+urTBNx<1exAFvCREZ* zFr-i+FIefp(wClpy;ojpuDquyroO!?@$9FKn1?)rSGr04i)gPToLc-6loek-3u)q;5(D-WPW=Icnp!J#I0B*_F)u;y)`sO;fmeZsCiW9$Z$N zf9&(9zp**LW6x>UqxE8j_YZzL!_&23$$k;t4KJp!{M|ogeao^374z?1o3HWoc@lqT zuDJNr=0^t){Jgs0{Kb>if9_A$JH;I*AIIMuy3*faYVWEmE^ChL>8p5Pu-)NH0JC*% z%DKI2Q=Z7KOPt%m^4e_|Yjx>8#ZQ)ZPXylIK2tp8=BiV-{{7#z-u-~sLH@<}YmR+zAQL7 zh5h%fYW24-n!nU-;N;!$f5H*5efIy4HkLWdyy)KlHfvhNC!LR;zjwWza=^*$a?U}f zsn0&I^ETLBmbL45nf%>Lcg?0Vai*;8Ns0*m7TYO(J?-tpDXR5zgN3bLd8`TYG1T9B zr;<&}|Ka!B?akA7u({c#PF{Lv_S%Vp3%C9_w!0(SR>$`%!*gs#qaSrE*z-o|NW#KniM?B(`%kNSAM=k%Yq=BeZ_p7gFQ_jldg zD`R{nv$d}%w_x|~B}c1uG7dM-3{8HnG5SZ#c_8JzWsYb>iaRRTq{$K2jrk`{uXLo3lk65^C-xJ>{NRJmp8W z*jr86?eo9PJ@a{HvETCT3@e5F)K<4EOp7^qXU+1%ISnkS$96LbRxL@mpKZ=4*}A0D zz9vjv;pWMvzQVT+toNl$awOiTd)>WgKIy$pN@KCuLXG=>dTLgjykpQdW!8`87u!4g zpM3wg=;$ftgBM)oHG4i!_jtEot+Y1BaPHK&S^qxo&iek!q;koF@|YDn7Uy_gHwsvm zr(3^A-tbWP&1~$ z-toU%8It>~@a&ttZmaKkZ%Mb@?lCQtYmNJqD_IQo8m)qh8ubtEIlJTF_CL%2Z_&Fl zJ-2JpL2-o{)|Vb_&)VR1KFr#Uh5z;)(>8(nC35cNk9nG3HGes`=ajh8_2*4>CojBl zY5Y|2e_rLCv*}0E&K}&kHRke8|8HBSv_;M6FJB_ry}z2LLDBJx_~EY+#{+|t9!TH& z@Jox=^2q$hoaNKAUcZ?wDtLKzPn&OCpLoR4Bl8*$)Ua_Z?{eE4JTF5s=l2Q`&0a4< zGi9@c`-Mi&R9u(XT&|sPRZo`nQgzfT=i>_d1Oo&&DZT%*YQ>+@whyl|g6BN`yY7_a zbRMr6+m3%|-?incq4o0Kz8BF6JNMQeG)sNTKX3ZCsj|2C)d>Fe(oQbwZTm1g$m~Sn zwYJahl`D=O@1N#Y#olhvJ8efKhn?{6B>i49o4KpD>!w%xzr8GWp?e+Qm-a=eufJcr z_2tcPkEk{OjX(bIxjXxfOt@;h_mN8m+fOVx`u}kAod5Rb{U0Bj*$XGtSX^5FZ}zh3 zT2be<=0&yri$}d@YWLdewpEM_3{5Ny45H}wOr@t)80n>FriF%ZGB8JGn*@V!X$3a} zBg+eB1_m%u{JmuJ2A`0GfP@+64t$X3kd&Bo>{o`lhS)3r!!?57T zv<2b9MRn_xl5N%zj-me*d=c zZ)C9l%)MN(DVjgBy{A;veX0Atvxa-o`qylE;i+ZQJ8!O&-nM_zbYG=}V~?Lqja_xH z@TzrJu$9G`|KGznpD!=U>nIdMx#v+Pk}{k(=Z1+fI|dy|(!C z^Gm;HHyM5IzjJ5jk5g9PvePzI&i^W`9{$x)pZAHttK5A~Pw7)DI^Uu@HSL1)_g*RS$ z*R40UsWGnYY0;UsMRs#@2}yjrSaX=G#+!OQ@PcrFGIa9mXF z0-|A97(L=ax0M#_*v~!-525gq|@mFsx@~U{JwsSb$r6NNR3DYH>+o zyg8x!%3kw)D1QEQ(xaq=ga=>06mTXbBp9)8`e`wv@rm%v&EgUgGbEX6oMLQe+W!0V z|EK|%+rbV-FE6jm%*_9i|Ck#uFZaxJQ2Zx!y<^gYKU*e!II z{jl|StF{_{d;UAtb#i}fh57S)n>LgN?qv`6vH1SU`~J++hqTL&+3S{=M8vGxw{fRs z&a>MFd*^58>7>swUU@sF?pMv!ed_75p{KIy_WS;NHhZJ%gN{Fqmp#`ltl$3CeP7S| zb1QYL7Vdw1?n+SdHm-S3B-EE7~v$1zqxZF&(HMO2D z6IqaX&(HAV`ET0B*D`i?Klz`OSrsL*&DB`DwD|u=-mTYXmGZ9s|9*z)*F)Rg-dAh; zt&BImV|cvgDxbFXN7eQ5%Or1PW!Ky7{`Euo8r#jh9{xI`i!a9xS+5c>;4s!i-pKtk^ zYmHI)-QBB>_b+|1@oneXv$MtWtLEKax$tA{qgBGuRcB1^d!3S$`@8Dfqxolw56<2G zN%)Bt*Nu5sOuJJ&_oSRTyOzG%f7Nbn-M+qMX7}W|Sc~^Y*=pmgJj46xA<^K28t&m2Z=F(b5P3p z&C$9JjBO0_1;YK)`tASM8}>8>8YDGLniLcjb*sMZzr%wsnL$zk9s7@%E>f|uU%SL+ zqsG*Odo>K#9?Cel=z&gxS?BkXLY|WuHPV&Um$I1Wy|MrQe*Vnj>t#*H)n>A8|C{Fa zFVW&hVEOHk_WOdD*ZEez-&?P)eE*B7>uncVf!!KVSU%&%XAf(O=%o3t4x&r0U}5ey0BXvpnCoSYP{g z+}76rMd``vm)hosXY_Kf*&Z9Im$IZ*AuuXwFGv2PW$W$E$4YF8HChs%dv;!c%#AG$ znc4jRPu*PiaI1gWy>}lTz2PbOyj%PE-&;4fbXXn%=7N$7z1@K7Vz_)eWZt;_q)fS+&xU=lk(w zztwp$1$S0_n!onWrbPc>x70PyOw<-;dfCT!_@!ByexLf0hw(Ub;U&&*ZN5URcCYXK zxg9LOG4GPdx6Q1+dWB}o`SyQ4^>co4(3M{&cWwPV$<_0t&JK)r{78+=x6u}Xb- zIBeqH=cgrF>Tb=$xPG!&9vGDDFpJFfPzunXQr2XwqeP5gU=R;3+ zC}aM`jj6rvul1g@r`)@FPW6&vX86 zdVbmJ{1o+~-|OD&pZ9Z5^p0fq%lFn^zW#gjyIId4B&El^Us0lkAJxR^in@gU$nC2+d0#h?Mw^|;j9b{YJ}@&(|B^qmvhXUc3RG8T;e!q zo>D-A;sNy|S0~?meExqtxB)1!V9Amx)24l!|Il8*qIT94HjzjAg}oY_=lr!b{dK%j z3-rBwRvScZ(6H!kZ2Y);d3Umh+vD3Ox?S5vD|Y<#SQmQDFqIx}^m_#AF) z^KEiFCKUg=wl;q5^;K&wXT9#)fm7D;8d3WwE_$x@Yyo8RstT_?iCS zboUe~xi>T4Zq+QB`Mj(9^RxZGb|mLFt-pCs)YH2D-OQ@2t8JD-pkU*GZf zX^VbX_IxSnO!=rC|3eFInE5aD`*wBbo8T?UU3~trk;m2>e|CCP`7S>vt9rZon_Zh< z8%|#OaLrxA@_iCtuWrqlUhZpq`}&gyyB{Ao>Mve@XXliipMJh-zXr&~*J-&d8s_1sd=<9TmBS)X_!v1IT6cT=0C zyUMdqWnJ6zqHuoN(um*h&qvR@|9REvz47Pc3sd(_YW#OEKU{n1+to9tJbIe{{N~&< z;+?zy=KSnD-<2a|=H0!8zs`E?>AaciuK&8RQ2oY(JISkm&C2?Hz`K8qT;`d=IoHqM z_`kWXI{o=m{vOfOVudSamvJ=)^(ji24$SdJSaae zB{ANdtTg_MIpuSq0rN?b^lmdYwlr`h8ZUM~{=Z`osFx#vl*oOy2a7OpeVo3-Z3@ft zwy@9VReO=P z-fVZ-QpNA*7fVim7vk>k-@A4D|7&`=2jt}r+3s#Cedc=l3GeE6&wVT6rsnHd*j`&ZwS}%BZ>CqF}U-h9WKCg^-{^NLa%2woK=I79@Ti0Blp_bmZWA@w4`zKmv zI>igdpG(Tull^E}9$vO>{momEPcpw*d@{c8_VD&+*ZEVkw7$%lqqE|~*`?>R4qiPy zM??7K#KLb<*V`Yb#a5e3%qe(Yad7^ZFS*svHlKbT@#lSp@3uFISA^$iWv~C}@j1ah z{p`UhZ&;_jEq+#^X83nwNaWGEo6|Qw=s%j&b6%VO$NfF(3x1XL9Y1pWwTSFAi*WA` z=J)!q)a`oc74o@~^)%d2cEfi?8WEFyB+~`xJ@q_oFM0mpffv#{RlKU+|)Vs6g$7l5+SHQ?{DV!eKRZm|K9j+Ze2%ze`U$5nb&{LI?nq2ea?iN zrMExDOUEBt9@BRGx}Sf}uDc>t|7Sm(JMU)vjQ%q}6+g^<%Km+|OYa%&$f!x1b7xI| zyRlOK@4Ncx+wZA--N63$Vs^H6bI7_c7JvUQ+rNDN%U{oy#V=L&*30{{^}*lA|9(GT z|9#J+>e6gUtIArwzwtGA8!-dH4)qgC8vt} z#R?e)IIKtfzm)Tz2d4O?w}zP<%)4Ugp7Xmri8I z*Drs6|KYUX`QDA~J1@TbAb#+W_4bo?x3^|)zPZa&Tuj81a*bYybYv+kQ3w?N@DXuHM!6zVVWO^Z)$$zt-)^|1#fk-G@WF zO}}5=o9!2G`sZ@J`;7AGHuukjvfo*sQf_1X>d)tCnd$HD-pqe5wqgC7gQc z^Y5N^?l!f*{YzRe^Y_leY@yvp52Z#=|6?&dXX(4o$N%=7uo3s4%6ceUC{FUq$C`6I zCpMZ_>}xGN^it&R`J1if^*^V6x^JKR!Tyio`}C{RFG(%G($wp>;%-4u+ARGq6~`9d z2u`fM%IP%o_jL1Bx)J5!%Tqq<-1XATo3_;_F;)1I*enl2ouHYLanb@d&EG#qO}pQ| z#7<^jK%u5@NZN59zT4ZMEANYq{;qs{X;9;A@24)l>bq}mu3a1X_2-(oS%PirYf5E4 zbM5$|HgB?R$m2uB21{>0o9~$T(r4bxkFVD36%9J}k^A%B-fO>>ow<>IFwpw(>NDK2 zD<6mc^a_q{y}Rvq%iE9lOFw@;cxPvH&}$Lq+}m>1{<>Rq0&0(KzWw=%+%o<$CMK(^ z=~l8W*LAP0F?zdu$-g%%rmSfU{IvN|`#$x2E19!5Lkj+V^Ey`QW_`%0%*V5^>)fo^ zbCOq1=)M2`sOd+_izchfQn*Eb%zQk zr`fBn+;mNf^-Xmbmo=ZW+3t3_^lj^dE|-lDwB#L}w$0|v`E!q~p5EJQylslEcU^K$ zf^@>C8{c;PT0ZZy{rCF6hRfp~vA;h3-R-jeUd?%*A0BR%H8x*AN#K{!*ZYZ=f2T@6 zx|yRRuJdon_x!BYCY%lqS!J>6+}5pkrisZnA3U3q z^k6@8LuX^NV*_L2g#-mdiIr3B4)8XdXR>3lkTPJr@%8?L{}LbXKX`I;qu11zdlvck z%4wPPI;8cVcmR$l)n4NqLEzM|%LX z6ThI5V#`V=W&@X;{w&U~Gd7!l`WBR|?HS;r)X@8QN~FyTzr}iP+FZ|meSXZx-(D^% zantyx@Z?I{Lu$u29zJo_F|4xlan13I&%50&emHV!SL5Zq`I@=u>rT|#?b@=HGuiL6 zbV~Y8{q2UIzE15sypua>^ZL>ryU2_^CWSYXs;-xpU;i%UHfj5pvR&yb>@|IBAMe|~ zO0706B$)4c!lV z3-kWfmX-1Aqzg`(`E>n0uNjAV@Bg|z%VlPdhK|ebc>N_aXFGj9?%j6m&#PzlGmiF^ zL|HA^y#Cydshi*A1i2P&e!M9AdFHKsh0*J)t*x03Z!_WNxoUXL^+#W>^j_0C-L1!t z=TKBKN(xAbdkv2tUo|J`=c#ka$L^X-)TI#qq{toYjg$s3Jz9%@#W zcRu&te<1zzQv0Qq-Laqemb+fbzI5Abv-*39x3}-+7F;|hy?pxlZP8QLdHs91NU2V4 zzmJ%Iedy9+e%UEke7$pOm)I2Ezm;TCaMa=9uFlo<5qUQzy#MoedjCI}I|h5|+pcPs z{#x+JGp#bQXv+U@NB8{N(sFFWrLGB2cD;ENn09Dtk5VT`{@mRTOEUJ?7X193(_Fsl z`o~(aiK|u^e_g>+KUev4h5hzL@zZKIKA54E(EsYkn!i7b51F5}Qj7Tga;vXn_p(y2 zb1nDkXBVW^ZhU(5ZEWtlU;o4(T=-FOHsjcKx!e<5ZY|r`Fs09y$3kPru6}=N+`+e6vpK)M3d;X_p{?zTQ`>UZ z!*yGeK5ol$j)+>YeDZbG=+wy;Gv3X-CGzLq^Tppj{1AV$;)c2OhTepyz}If2JhOH%f9cO%_p|5MHUXI( zGo$}iewnx*t@7|@KiBb;nSo&m8v}zn_R0fgwj-XbuI58#@Nn%Dp8uttJUnN380{3- z%{wDk|L=d21nc62BMhplOSf#<@}K8_!AKWpzZ zosm12pmVG0_muYfNWSwuDa&Ku^ZwQUU$}3Ni|+e5f40p3u70w9&!? zN?N$icFVd)K`#!Px~aZBf9}^FAMQD6d56{HcE3qHX!pD{bnl$`*?n`~TK=DX|J7{8 z^;f1_P5qk2-($=#6SJY#Q@Og5L4EgE*}ZrFnfj=o{eCa&b$CU=n}=sF&l5L`@!Dtm z@NHx8s&2ERt8&xL<`!?TESWgr-doS_hxXiy@Xg$F&OSGI!N0ZT+%72=N7bWd{QsDB zCwx-f-?;~WnlJmjX!^;OclPLBPYFD``>?O^*34}O<=LxyE1#{2de6K}Zu@?n!|6$1 zmcKZ#LTH+Y4ev3)kc)y*{2U zz4PY%n|4LHR-c#t3d}z&mbs6=r|P^GH&@#94I9h1pSI3RJ2!FKvxN1ZZL&T@*gt=} z@R)XX&6#x^yIY?em3>(E;=}VxW^*&w|J9M2w=P~~{^h@(Ck`baJ?gDH^|_pev3x-w!A4-qxirQBt`!FV|$oFC}$f z8?BsIP0e!dI&Umye>**=w zF65mqZt`cP_|%;rV~?-@%-#5Ex{jbQ{YinMohI8FW5m){nQXVUL+}U+s=zF1AK~vxT>&<*QXY2dV+IByi zds`1y+uXSx;eRSO^7zpsp=S=9{pNJp_|>86X8W2dqu&+(bJPD-)#bgrZ^U+&Up-y_ zW=P(j(%>(bni?9OhFPuu>r=NRf9Kx(V~4)m{i@z!Z==^|Yg@W5@^jp?nyIcm{qHJl z*M&cwT&1MDd%w}U^WjV1M_P(Y&yt;evt<7Uzg-FmGw&C^6w&xyx$D=?HN{>TOlYOZ zAK_>1o-7Ou?Ckgkt6=jz#CXCtZmZg=N>xz(Wj`}qGq#l<+etf=k z_OjW(>AC;@@3+mL_I>`nt!J*~Fs`inKHbjf-cIA4X1_1R&ojTy>epEkr#JujwUXfX zsqP<6#@lV4_Ib&!+xL16E`=xd6_@Xm-1qN|sORkc;z4WU^f>u%CExu}xAB9}*S*Gn zmhFjN_55I6#+o z#dZGM)J-d9MQ>X9eNRrxQqRSou2|1xOTW85g7eMAcl)m_+`L9L?_Xx#Z-%q;e}~yy z>|1EC-L`t-vuzB~iY-`~1bXS{vBs^MAx zrd0=T%PqfKxAAep<405y3@u>`tqx( zw$IYp%)4u}qJOSm@Zp5yvkEi8y)ieR^{-q1#&y~iu36jnZ?dagygL8&_gvM=N8U_# z)lb>qJ0e%|z4qNnfKM_rGcbN@||?poWn#YU?QR|h$%IUUopPQClwY3P7ELwDw<~%6Xw+v%sVMCSPmX`erS4sR;00dFb|6v+G5_ zg#F%DPrq_H)5^E*wg1zrcV0hMy0SbcXjksRs)VEuvTI-7S(-Y1(z6KtnOBpSq+SWT zQk&{JZH>pYBa_yzjG8K3HTB+l&X+cVYku#Ux%B6Z!q$}@-4}2A3JQl>3dvdreV=C9 z`sB=hlVmRS>&GNB|47HPMwPqA7Vb~FSQ5JFe*V$<2DfkS_WANW`uW-HzlFBj0%~*L z9qD`}_DlHrbG_*GpKGt#zCB@3crI7_wBFK>Q)6F6E!`ee^`J!Z##hQ6DBY}b;5FO`=c_y5*#$V&bz=X}5HtS!>M{?B#h zPhNcL_oIKd=dJB#-&vOGZ!zWdQ}L<09-idedDOk4H@epM=qc;2cj?D<`$Vl{trKg1 zYcfx3sdeR^5^m+a=dR^WuZ+Xbb#7nTztcUZ=1|G0^!Uw!#p`Fr{$Bj&=;_+ROVx{= zUY)qdRYT)bH6h)AwcU@ZBf9 z|Iw0%DV6`cC;zS6`|r^Fl{*s;=eb>+zd+{Q%U91gozq;%iB?LvmhGw8$BK7W+Px?- zEy5_?C9x=*&|;yp!I=S*!$tOntV&p%CgPaA#!+xF+rd*CW@hDtiac&|5##0Y-lF3e zz}&Qt!8e#wN_IK}r!eEeHiu>nEf*f;4v(&tJ)w#x+H;r~oeH!$>YSMW<)!~x|NPu+ zOXK%*cILm^dA|5}nECe!v6poeh3%XZwE{Fmf_)CoS#rkn!Lp=B7IsHJtW0h?m~gvrsr|Qgi3}dJBn09B&nQe=oJrfoV{>bR_uTxS?_=02923@o5UHNwD zn!3{^f)39&&hOoPyLCd;!mC{uqPxs1OP`-GYxi7y@6Fql+Br`ju@>{c^C;&zA>`SA zqC9O^+n0{Zd17x)EmS=}=V|HbI{$zC;%jz?+O^sho!9>MQZ#AzT-V**v01ObyBd1e ztg2;R`tr)}me&5K(R_2tGj{&GdimxfS(o-}n;tXU-ruWtI(zqYqqTo3r>r*o@J@fP z_fuUn=Y`)Z&E`e(u9AMc-1r*bQti|CTCR5GUhmB|?sxsO^23+ngO9zfFRyzmG2^{~ z*y{RO+g4sr{n+@BG4^Sr`^!1~>u+!HI4&=J@zBEs)w51}PwHK~nAvvM>_E$@Q_K6e z|BZWW6_}S%;(4IUeY0$G$kg|%7e`Hg9+3L_@YnM})sxNZR!LOdd==pC)ivAHw&QwA z*axM;9gE8fxgNS^ZCH>HU(uf6_}|0&fA_}6Z~t7HIz@ZAmGJh~KQ;F@8LF(^8R7rT z^j_SA`e%2GyZ>y?J6xKZE;co56aVtNGvBLMJo4qV+oBph>AZhW@WzVs?537Zzj@1N zUEW@?BiZmV`(bC}w_f%o%iBJ^XHk7x@m*(n(YIaCz4(3g&wHro_{RJTJ}&(KUdGNy z2V?64u37SiLf;L1YWk*ccyZ*df9p2)%1_4(>`rb!^sQ_8#jUPo7f$O>kgosYvM<7D zyT*g0Gn!YsH0q8P+)vzDcxcmx3+8pp_CGq^ZuTic#PZs-@2j_puU1G+tB>zowQIe) z_Y}vMQ^O;!yL#nUd+t7GVhrqlX|k%s5Lvut(|qDl`mZFPjzbCH*VWqyY%eNna{lUIGtb4 zpB|XawfXM-6?${tnJ@F~4LqG>^y+n3_^kE6C2CVH9Delns--EPIo2*VN?JqyttL^EX=l_33KtcXZ)&6xxr@o8To91MF+!1wtPsxL=GiI(aG5ebK zVb1>#x<9LOIn;YZuRoX{6CogfrNqpwG<90yf}P6#*QCN{ypXDR-1zn4zR+78-mfOU z%KfbKx2~(KRHJ@t)_OyidDZuugFLfO6#e&=5c`oky__fQew_CIWh(aD_UHU(-aL8j zsdJ@vU*GAMzdwF#SLLxa)S1>~Z@G`bT^EUvYaKJI?cT_v9(DY2VG}*p`(qe(Z6Zr#RxjIqI4} zVX6Q6x0o0hma`Jo3pORM7c9sOUR3a8{{8>w3=Is7S$?$as4}Yl^YedqqDW7ZAoG+d zQ!ZV)^w0PYJJWLi$(I_O{-~}KR6Y1JQ}t=5>q?$?uAP~pZroz5>4pXdJF9nDw56Er z>)myu{05{ITUmEIyzqX&=a^SzUvIH1oAVvs=K0<$Z~eTY+W%ABmBjyb+3U>vs95p! zxbDMWqA}~6l7jWvJpWo2AHC&XICc4fO!r zS!7dbNu89dnEE?y%eoZ~AI?tt|5MhSpZjcZj@6rAR!2U(K0M{>y~Nwu|Mpzey_>W1 z_OZa?k7?@H-bT*%yFE46LbuTSopyBSk;a&{mHfKOPy0e^HOkHB{eKg*EBe}OPR=v_ z7Ih~)@?QQqa(975*|Cq;lxD9hzh{57E9ve1?5~^Gt+@IjF6R5;v}Id7i#9D@&}5o@ z|Mgs_IPUrCB^8BB;$MHen;5e9%%AI1o(E2oYPB|7J9&@RuD6RK*XMR+zgl&Y>5|Oy zN%3!HPg-B{-f8XTuEcxuW)|O`F*h~s*gk!eCnXs_WMtKEzxkJy@Be-NNuf`Z)2~lG zQRb#|=b&Wxn!1PUeLOy;9%ODhxvErLvSpQZYFu8@+fnR52$oxQmSd-OJ`Ki=*jLPoH?p*7OEY+tg-A* z_UBj4KhvkLFP^_;f62-2^On+2SgzmReSgNDsL$8mOX}{=T6^bq(mu~W+%tc@aCu>} z*e{R!{&GX{{AK6AUebRY|L1o0{NIM^-+8`2mcD=M^q$boZ?68={gs&&xFhcJ#Gm~> z>R#-#8I<3?|LZ(CWUuT$!x;N>yGs8ropW}9$P1K46=Ln}`&@}x7nm3rKv)U;0Fr4z zMM-8}B{4G)odJICyj)Ts<9R(jT!I)Fm?9Y%7|J6N`G?zn_hE&*oLlTDkPw+U$br_p`Pw zERUMC)4BZHZE4-pP51j|?NoJ1zLGqh%{f-OaLWV!{EajAe+s?5<9zY`#AxzUuVu=)Ih`}SH=Vpt zeZ>ET@xRHUd+w--G;f>K#j&`X^W?Xwt*+rwmQw?TXA6hw6*|oSz`OruSy7=Ri}!-I zmknQSR!y7Xwx(65JaDRS>6NJylUGM{NKaPbsY{y2#V)=n-ATTGecY zZ4$HBf(Km(HQ1e-{nHhkdG2%aKbm4&dPPT~U|q~k7NJH*&KL&ifDpCiJw2g5|K|pD zzUZs|aw#h5-locUX_DupRpOVPh3Xu+85mJe_#lz@#nVU2 zqe`Cc`m)Jczo7R5w~ay2(_bZe%bL5r3#K-o*3*md;!R!16!N61^>D;PgUHGGxu%Vi z7jQL+MKE70o-SJ@c=!$LzeVZw2fr)-Il6rRhO%|18%!^S?0vC1P9&z|6w`aVZxc;( z1OB%kEkD%zOs4SKjO{LUA=}&c-wDz>UMXUAK6&Nyz?B^d@*9~Se3Dr?Cr0&8tEKDV z_#KDhyBvQs?Y($7e*N=@OFw56{SMl*Z*%;yxw$qvA4H1$E-vS+sa5}XO#L&z-SOYL zX}f(ZpGob%{?tCxo^g8e<+Kx@&fI2TU|{fc^>bP0l+c7)&G=4PW@paCz`#x1(sENm z^L4K=mzHm0fz&ZtopZP;8)@a?=~)dLDN%~L?`H7LRQiL?zwhWs6pUsyEcKY@nGR_eQ`Fl#vr(Msx z`Q+x^r?=K_Y+Igx$od(-i+@Jc`@A4{aLFm_kG=vttobM?fI*}UTDIf}`C0$Jzp4IR+Rr=L+kd7wI zkt`+#1{+oe2370@IPwgDX*?OJ(uy^uxY&UC@OIT5Be_HedOk z*j9;x8Grtj|2sQ<&0h8|VmaDtje@t^FZpG#`{N18`;Xq7uUA=<_y5+9#Mu($>7VnPD`Bu9-N9lRhKKA$VPi$>} zY}%HUe(v&iCC-ojlOq1D(R(oeg@WpY7vB;dKGiqWoBu!OpGb7+_EXtx`BA^u{@u*K zFDh#0bCn5}{c@g_d8vxytUwujPta`QR}i!chAq7_BMZY@yEXSneQw0 z^oxobCZAst*~oTUUOp(jdiwt<2dm4!dKkXMfck{~WD<{?zoiez$#J=v=Jky@1GTZj``cKw5H%G8~OYP?ykavi!lXwm*M^t@qxq-F;mk&rjf=J^9k$kwd*HXS$?f4{ev9EMZyg#qz)c1RPpPjuwPg#C>&ipF} z&xeX#EK2P<6C?I{N9Oiwqp&yM{dDe~E;nC$M6sv#rDgA-8>+(JWlQWQZuTvn#gWaK z?f*P$d2ix$`c4pXL+E{XX)j# zsgqs@ZQXS#-0QFBkHqx+%SDDkTcXmJzd4wzw(8lLtCnYj%U49y-P@r1{pLKTpVj8B zQd>@6)2n`X-RNLPp=|!k{<~+&o4jXzIqfAUIwiI2*2(|>&dykO{=oav7jy4?{;9>S zzkXuev%4GrIIatrIy352r0%=Fv&Exqbbo9KOpJZkTzuWhul9=RWs_NvDt}5&otADt zeOhPry8XU;BTAoUUApoueZT2H_I#e-@2;fg?mf74rLOy1_RWtjO`Fah*J||F*Le3; zF=5e7u1_yFFSagCpE7^n`&rNHUViFY=VtgkbM0F_{q1MhZ1?xy)VuR$mFxSmw#-+5 z*PHila|wNW_pzb>u3YD-KUB_FZhFYtKmXsx|F%azX>R|LCf=XUK1bGJC9YIFC3$I1 zKMMnc1Kz0=*t$Q0h4I_Vf9-`i7><7|U1GX)9eZ5Yk#paSq~?Cwpyv0fV)5eBr#+r& zKKu0H(5oF$7G~Y2&l-ef^UI}qZ#tQKCT5`AzF+q@Y~1MS<8y`i%lydy*%>RYGc)kTADZr;!}y9( z-kf>r*`EEMdA8sFp|UruOk6Vhpx27>sc}bgFTCJ<6|u(uWZY>bl?nWIk!i1IISYQe z`A@V@{l(`4XI$k^O>FrVR-Ar2QHx1_7w9-jQNzW?Nm#l2gKRxxYLU79K zyEEk;<^6uaerVdxMxz3OzwUzdi8Ef!SyZ7Qv?688*>L^^x1z5;o?{UA#pAba@1MLo z2C`Ql3YlM7?C?QoR_ZlnE0SHeYrTmo4}=U_?J5ngbrYkXPpSR1TDOl!)p5m-r^iytc5Js?{--tmhmrD$dc%hPottNh+Y ztMGh0Yr5yz`@{e{SCbuQlwRtonTAc?AUKC7$YJgWHzmPhZkC|zQ;Oj(HlHFI?zZw( zX_U2E`7J**`_*2M4zm8t z>oX_jEr?I~VzjIBk6netrpPOsd6K>695SEtD*ouA(7%&kFDPE*BChh};cxj@GndBc zuTSk&o3QiNrsazn+f^@V?_9lid9QxD`CJ7PS=qR|U!$Y$Cti3v^^)&Qskau(pS_u7 z5?nXUUP@&{O#Uav*B5j5o?~{oS9^WS+x*rRHui;0Tm3GTJ?7cLoBMP3x8o0dg13J< zqPS{mwQG~!vy;mA(@zJTFMs*u`}*k#N2Z(*NSCy}acXYm ztA@@eMAot9^72DZ4J6^856e9KG4x9NpXZ1@gvD^A* z#`Awq@$|hjzb8_6)~Z$7%gS0Jrf6)~%p8z8W%6nFY97DBFBjq}>Kl{)C`XEj&Z_#H zxbU|AeJTI^#P_i^zB3FG-fmI(5&cH0w&KqEZ|VUb6ZBa=F8dL}neE?PFMmd)NTA@2 zJ!*eQ?FobB31$X{1AGh&3fP;T$@w|?MUat$i66gVj0!NK@A;gb-L*WYhnG`w5ld(&4fTfKVUuea0o z#^;5{H_Xp(Tc2>gT>ituhYugVd-v|!w{Op$J^S_R*Q-~rK7A5OpMQ1xVJ`l|CHH>4 z*{pOyD|zeTRY_aJ9YZ`LOGHna?%~+7L22_Mi}1jY<<~eSe_r=kNOINAmFlhKq5Nla z6wBB3uy8-p2%Zvq)Z5Fu(d3~_CEv{nZ7VX-%#o!uf2vqZxr9)g`;p&rhvg1` z|KwXEby(0@@b~=yg*Kh}O4(8z%;svVSpJ{-z1ZW(f|=!uPMzs2oO$!g{?&7Az0zW{ zW=QH6Rx9Zr*uK;9W|m{u0iHQuZ=cwfB_uGjZ_Bf4kIT3IeQ??}`?KvMaaPTD8zkDN zcq>UvTC|Bt_r>xPF=8i6nNCiteeveEyU&&_AJw#{FomA=c)o1%A-9KW-r@^xAK|e* zJGs!5_X&sc7HR*xOWw@e6S^tEXc6aCw#jePLXQ55sHnVpwtRUSYt*E_MNwfdR2o$~ zv@UPhvh3Z7ESI^Z9R+P??+}rC-1bBFZ6!B*lpDr z&jpbQDG`xB`-4laevcGYQQ8>cvU&-p3j55}?g7iMc)CV9wVex!aukhgzR15J-60iDjVpXqSxW6o^W`2?cv9_L~@>}s^)09Y<5p%IH|XCp@#3q zwGR(C@jaX;`y;MXsrtl$QP(2S1x6i-{-kRDKYeAiQaM zwqeMLN7D?YgHB)1{@>m;b=u+E_V=3m7EGP6G`X|py)&OZzuWA&S$sG4@JzORubPvY zTAe&^-h12RHwy0;ufDZQv0ZJxx$Zfo(&fQP)6DYcE_rUS(sJ9%bm=cKeWowlORB6^ zFBea<{8AP?Z)umhbAOgu_wUKIb8fubcy!wT^S8xve)gB2zMDIu;`5ob!Bzb1+7}Cw zwsL)1vT#y6N0|SmX-bbPCwZ!rt8dW=O6U{G)HA-VRB|A@=e?obqx7Erikl}G{!``p z_t%2!fAhzVkG#h?A6xhQ=|4QY2r^_J++uUsV`M$$o>EP zuWP;iukXK}KmYuh)Am0TY6)T7CH8naGXp~;8&RA6kT*g_Wt#+paA^g~84p;-OwO@@ zSEr>+{y*tD^4gMmLlQR=v#~9k59*wPHbUiz?+ttK@aI?i|99qWiZ^nHhTj{!zn?XNyIr*WSLX z@L9Zmh`Yg;FqWr-Et{qbRaTKB5&oBE; zzn;1u@?2hfLcGMrXN_J#oY|>;|7Ok42~U&%5^?U6sqw*tjj!J|^lQtRuREEx|Kyh5 z=M9?KQQy|Iu`K&v#QyHw|KoSpACkBtBeN|xYMIA0&ftzI&(6NeK4v_3>*0H^-<_%6 z>KmY4d+l6py2-h`M7tRZTYo9^Z~xMnv$glu=Y5`QU+z0ly{P)&>~HJeKg!?pZ;I*N zg)0vD8Q)xf^Lf$vIq`L|Z;h{p#Z2EaW1gjD?xyo^UE?h-ahdS1uL}6^yK?RMt!I7i zztKyVIBUH7^5U{5Q!cJa_d3l~{z2!|i$}Hj1>asA?YOSrGSg?#Jp0mW*}s=&|9*OO z$F8E)XQy8duN8UPBXmWm{_6WpXSVF=dir*&|GkNFXT!upruu1n>{wZUYt!Rp-WM;O zXzjVUdAUA!)unAcpZV_x%@*!!7ZYG zo&T{{BR4K^{86y*s@T%7-sM*}KZ~EfZ&|?mWtXOvT;FB?^L*FOIf3l5E?aNQ`B*Cd z{c~ID_SVV9WqS8_&dQzirM=Sq)w`n1P`}uuXCJq2Ijxmn_ z<)^kak+SJA?9y2c;d$RJtG4&9ou;&T@srYxmsrxi zX-}II>i>D|`VaX}v!8wVSzY}xUG}VH|Gypa`%ix{F4*_U@#)l?WpU~KNrM9Zz zljF}dhbJD}`#C~C`tEt3i_`9Wh~1@LQT6Pce%zt3y@&EAcT3#4&t3mbd(+-6|MS1D zsoej3N7nh>>RDQQ=Y>Bk-FteA^}E?2_g7ZDT6*VKMbMj1CUfWCvA?IfKWeu5%PN1VvTaM0>UCQhq$$F+GDJ&+OVCM%ul;C}p#%?D*i%KQ z(cu8&7Y2z2HV4)P3=^0*7zG&E8(0r8EMN>^^k86NkYV2|XTW136|mA_A;U_M7AFS| z3z>wC4F?&dcvpldOl&a7{84Xufbn{>9J3Fzl;{eP1rwS=IGk8Im}SH^NE}$e*vl0n zG=amwR9;C?d9rC=pO)2Ki*m!+bI&|I#>JATBp9rBe@%$h%B$O=*0%bY|E!Sds8W(t zw$74ysbv*>E~WeCos@M7VG3NrCubHtOo(_`;WZrf8TYd{uVed**)!!p4<7Bz*#P3y4T;ANjRTd)cxIp(>!>Bwq}=? zjYE^In1lJTRsmK;E2laRS49;EkDduk3!_@*DK2s5FlWp4={szwx3h5OT6bSxb+u)W zm}mSEHcs<%V9z|bZN;6aeJg(kMd=yt=*zdu-#YpA(g(j%x}Pd;f13YUN^ip2zDaI- zZ`__dE&8+z_cOUW6CXaPkJPYKyFK%%&>dy3ouM1F+ou_1Z+o7*+xDk@+@?2SRpM2r zZPwjN4e81$7kjH$wl4pU_(7eI`(6ucoLrE{RH1TPsNmwir)%@)ofCYkaBKUt`7$ql zKJ=}Oi}roArR%w%UfY3H@m14L#YOS9-gz8ZnR8V;f7|@iF~(CCYSc?d>2Hd&UU$+; z@Za(~hp$WaYrgf_xi2|k-`|KS?=nvvi+g^Q@i6nPR}JlwbNusfZ8*$lZ@RGcu%qcK zZEqo-#fzD3Z$%4QUcDNse!Fgc@yrz$%q@>69bJ5rZ{n#}{N>6~!e>@qDoxy#?zxv! z+Af@LZ`Rg)g`@80=gA$(Hq)#SG`|zL-(unirI!s065=DED>YVcoc#9BCDAFX)2$zG zWBp%qagCfZQqJ-pA^b^hb4NVSJ=N>5LfnH4ut z(mg_I`x~F*!u#(j8wvjx+qQr65xp9fUydtYFzJ_FT)F9d>$T&Ro0bLGom_tD*Q)k| zPnUjKusmPE{MnC{H4`iHCe}wiiG2ErqwZS zf6Tca{&niMCuuYFKJx6GVOTRWDtyMk_8VZZFJ-g>K@3Op|>iu<`&ssJulK-tLB6ftubh(?>`g7O#x0F2bj9$$B zIEE?z-gcXN+k=GXt&`fhJ9pm9_cN9CzKO06e`m^ay6FAR;8mIZ`n&&5lacySJ3U+_ z?RuR4?{zBntM=FYubq5(ZP&T2_j>czm%RtA)R^{ob@w`%*};UQ}{bBpsz%#ZVY+;w}B%rW~*mz9sZm$IrpPX5((_hXmdevJRS@TGT3W|kkYiYO1+X2$WdRQ>Hvh%s)VaG zl`$di*D|i|-M)Ka=B#_O)7~yyIJ-7`R@!|R2NzZs7nhXyDYb%y$9bnd(0kP8)@yjo zP%ZGW#N!O1#c3CF{3e~8arWdRmB}+tsz|!Oy#4;lTejYl=I?+1y%*2Fruy}~RaT*; z+pLza5=d;Bz#_-v6dCCntR{9x*IDDYJj2&h=jP04ZMq;GFp2-Z-OZnum(|z(dcXTY zwXxFBIj&=9$9uK+#7F zl@^#D-Kw;~#6#o)!{y?S{Q+KeE9@EemdoG$_|R3oMftA29K!_e`Ok_Y!WEo0e%u#W zclU^tk@efcI-}V>ZcX}vZ?x}~U)i?UhOP6=C(aOm+xA~S(yqAwXV0wY4q*N)xa#2P z0Qsl=O&aAPUipqzRg$y1%okSe;xc_K`+;xE-Nah~yqDYh5AB}0()sNNy~Zp2EBS-8 zm#}%v{xEsPT$L&#twrnsY_UzJUi1gp>}O&97^2aBv$<+!IOFxzAL1A?1z$b&ZGSJk zLVUja?wNWA{xTlm4$!~PeD8l-k+D{?+Tq6O|QsMpt2r5?cXw(-*oVU3PFhfbc> zvdifW`}`Lay-JacgZ`$c#~mtA{`jo_F6(JMK9 z*`@SZeyyvrc({3+`G?37iF>;hWD8$A&tCXXD^6rpwaLYoD^Bj@4gHW3@GpSLO5FLU z*fX0C&Ml|vwLh*q9P_`mOHwqe%HrYUZI>0=oxeC;@qFv($0IMwl*=wrf905joYx26 zd?#Cn`$@+**RtIDr^IOcYe$WimD_#C;}uROEx#|6coZv!I?r;qZRAo24N?!ZUUJjN z>XmyLuhPlW>sDHHW+;3=o1nW#)PqTYP1oIjVfw|$FG`y-MWf>17H$Y%ko}_Yi-{HM z1^bNDsB-HoWhcunmK`j+_wD!jd4Jw~NPpMh-&pt8dBZ0GdCmiM7Rri6j!I9uj-24F znxZ5*$yr-9NYS*&UFu1rO`^}e6YM{o)>}Pk|8hc}Re{-Pk;8_w2Q^q)7a553DFvu> zIbA%_k~Bf`s1kRV^G6Lv)kP{(dV&J9B4(9LX;fR_VkOTdQV-D3F&*bh%4me#jgHiXQh|PZFAvYqj>hi4<_~W zh21AY->6MI^@MAw*V}a;KYaQ0?c>!~f4=-<3$>NH%lWQ*BOf5e3JS=3<($isU?rg|B{w}uq z+gn-7f)5{^+xu-kKDn5DeEz??#_IFx-(AVP5*B;8VOLx9vxR+bTWYwo+*hnC&T05P zKQ`j3i_zz5fmgAc1Q!j4xW@OMf3ao$+y%>+0XvzO9e`d_zI%#}V~Yb9US3@fL-K6`z;Gv#-6**Wb$7T}{6 zd}dDKyH67HTArWpe*E+!->0pARQ`qiEB&{^L6Jjj3&%CCZCvL#?uphYCd?J_d+H}W z$F5k+I^3e%vfsk~`JZi{?OXhuvF)Q@GqttPiC*tC@8a){7ps4?tcbfT`sKEZZ?!v}9;s_i%bETs z^3?PykK0Symwr!qx5*)L%bSKbEpLo(elKdZ@!c1;FS5?--?~5NKjlBM*P7t8q#*o< z_9qe5E-Ba9Nu5b^lXgF9c(miunn%`0V^tSV(bzks@svbrTTw)1L}gHATxICbeOxPF zg~+Z-UB$af@v7rh&eAnj&bFbktJVdVuW-Mze)a!H?;h_vQ``J|!f(g#!tb8ni7&1X zUwpMC>ygRKSv9^h(_D&uio-t7dRBW@eOA7Sea5@W54I_CadQ9UK09!|&i#K#a*w&g z>^+VgqBXS^W|s{&F3XsD>0i+5DGXnYC3qtihiCt366$R{DZji`N_ftSkWWiKM)t~I z%Y1R!ty}fMz59oQ7XO)h$0=Buxus!$e_%joja|kH#t+P=T+TdPa&(45uOZ7HuCxQs zMHKJ#v`_Tc+%Vti-PwRQ^QSUgWcjGMRJLiR&z=MJ7j941PcvU(BT{r``5T6blVu%> zxh-Bfr`;31m$X4)--Z1l>Q6nterQR#R(Mk7=_H|jQ@)sfllWK0UY*ln+jH7O>d;Z^ z0_EMp=0R04C+10{e1GgUiLLMtb{oA#rzvi9fT)VY0@%`MW zxD9Lc^w-=Eo}DpI%&hk0pC8}92Nv(DnWScS`^xQu$4{$l|9m;Sb>^9k_aO}HQcWVDxZ6!WFe$xeP z^UU>y*R0TwI25v>NP#g+KBueC^ti;~M#-9ki;X_iYhO$ z*>>itNn%*g?GuZP{NHb@bqZjLG+F15wWoqKePSDWX| zjg8*<^2W`1s{Z?$>gBFHz4m@?Y*k5RT+YKa2M%4^nZ7$L*33}-^QT|0q|I|=Zf^To zeqK*PqUYtCd6OqxuHIu)|9Fl|`rmo)x|Yuh3prfj@NT2jleo4Cf36GJeX;NS?0l&^ zaKc-QeaFNPN3~b5No+Zj1GNyVo8@U)D+uWp}IAGk2Y=a*m7 zoa)uQ;=lU(6AAlwzjkRXO5Lz%Yoy?sDePUp{=XHMdHMBm)I>(Dmvc1!r3;l$)CyR+ zL-88>%cdjw+Ed-8YJ7Oy&*ZALIH)p~$6@ae-BzOj)uQPI+D}7#E=rnk$1zOm*VNbe z5|Sfz#PH4R<~Pw-L~|0?=ccSr2V73uC zwL>Q9?3-z8ZMLL%we)Y#|NEqaVPS`H=C{yYGmS19y%PG^{NzHu@z<78v(ilEaJL-I zm&bV(Pb*gi{@-v=r~ZbEQcm-YF1<(Af^*a^%>O6&YOUbD$#?4ncV26VIo2#twwXQGpP%yK67RY5 z@e{>8YBxx0-;X|Y@9*VZZ_RJq-`hR+|CXu^^$#1hbM^P!-c$H=U%2)8T8C%N{f8Lx zKKo7j!Sz~KZRNaEQa`uk$QM7mx3{KG%;4SbJ^TmC6ckqO*SysprgfyIaYh(ZW>Qdw zcNfDOsTT^*_$3T)&D^&^)BcdLg>GV3W|Mb8sH@i3dl}_Eb@|cTyjR6qsY=c*GTBl&xW0%$&8X}Oxw1+H|+6|-yveZ-MBI<^y#wP z;-5eF-un7%b$9mpl5`(asjg)+ZmiGKNp)A|lJ4X6do@#LM@e<`*<+HEFG+<@vA-U( zqp<6cYVNsLZ^9#Q>m6Dx#BqLaW1QZDnTMj1gI;w;JaW-FV72Sf(&^tK%LAUS`(3ut z`=i!9;l;828|PL`xLBX9yY2kq`H#PP<}Ljq{F%i~De=n;g`2+ZuBK_VD~)24LK^m8 znS3kAPjC?k2 zHMR5C?ytGbZq6`&%bngD%%e(w|$`ttnTc4 z#1UV*qVVkHH%B}(+26lxk(_(}irmkz*K7Jdct3f#viidYcZb^lEA!_1-`$k1vGe^_ zTg7E7tEc(aW=9u9IHh~1^%_r2o^Nf@*>hAc``m_(7iW5oR(<9<8ZmXxg zOC`(^JdnOAZfT>QeMH-igO~c(_!j-%!D?60Q}gf62hHx-?_J_T zZTz-vi%KWx$41`XoK|vOJ%a|1>u;uLWpX=Z1ulsg++nTDR z#r+Gv8vcs6yLU8H`}STNF0Jt7m%^*JB$`L{+@8(E{5$X4o>B$1l2^APKVEut_SlKP z^(rOzSc<27yx07Z{eRWcqkjrN^$E@qV^C#cS>^n;*8RcF9ltVb&iOrG@aNfDR`-3M zOT%1$E(w0~b8*l1d%M^D|H)bxSE}t7wV&C^y?v=p_Uz1E`*clI7A{s^I&-64yTYR^ zcIm0k@{=SK^Mr!rJ%4y;Z8`i^=1#+%77wKj)0yJCCd>*melNI>#UgpK@v={mZ2fVG znrBw6lv;J9>WCFn@#zDl57ve=PG>1Q?XjkaZLRFz9+f|j-E6Epe#EqiY}w8{Urr!t z&Hg6$$Y)&pmM_R!8T2}E_ucO8f4l8?_V6`Z@Eo+_D@oMRJU7RZasA14=R^uuA33wQ zPiyKP|EIFj7J+IZCzc9r?B3jPZ|{-_>*0R$iaq=+C(^pKW`~ z)8lHtk9yBZHQE`o^xLP8;X1MLyHw(ee_VdiwRh^&+d-yc$v$S%|G7W&Ci8B(`>48E z_DmCp0PBjMRl18BCmL<&=yCpGako(C-?NVo?ItkHipXPFArQFJ-KAM_UeQzgH{Wx1 zy8cpIS5YnNa`v_9qZ^A>8Js?J;KISo?sM5J;pTc45A_~&a`_gP>UCXXu74Brcl+{H zM;}&v3opKxkU4Kjby24A`L(u-SG-TV8)hT?nd|fYW5xGp8Gouf-?HT-^V7nQik`yd z<=MUcv3IY&6W0h-osy%~ZFIgiEw}D)=lf~Pm)D=Do8_sx%4G6$ote7fsn_+NKjV9K zx`wODTXEBri&k6v+EjU7uguMV^p|nX?Sqr2WLTgRv%Or(M3nWHB?g>80LRco$Zt`~X#N~D^2+pE2&cdwMX zwxWBE!28E*FR34Wy`phOYa~_NT2I&b2f3Mb7YjSDDNH>|2cN3LftDHE*)~&M5YdC}{0b@@EBG&uNX-Mv)uYVy2$(f-%hX(?|}HF?D>)j3gp z@aq>lZ?WW?@=4XGrT>ezw#7%DIwy&RgbJXni|Lb0Rc?JKa z@Nebk`gYo{e{rDq-`zKNPv`EL+ znPWZQKh3_8>;AYpynMR;n=?8ZFaG^)@6DB;o5efNWObe2i-eC)-p-yr<+#%E8O5^2 zTiPpQUR<|!dMhEh@m#xO^z`7`@1IsSUn>f#H@7(<LiPQ)XiglZ)WYk zP*&|rqucHk``_Glns)cM?U||-^-ti>dB|lUC(p$z01NqC!c0db1-u?US%+4T}^V~`|RxQtM86o3eDGv^VpR2 z>RHpXm(sf~eV%UrHKp+NpF{t?ZPD!Jlb;t@{r8tg>CJz|zOiRb*YDrAdr`^zn?FAv z`*OH*vHC^+$zfh?qD{R5IfiAcxw#e}fAxAt|9cs$TJNi0Cr*4FpSbjzX7basyw}|` z>_oDg)Rw(s_s`?!p0jhW@!?(bX1{)JqdsFbyEvz9%G{GN$+~XcR$~2<439dwuP~k4 z=3J7W@F{fDms7n*P1&>08azL>c5|}$@45PwYwJQpEUK?=y|-%l^bpn4chZ;0Y1+;+ zzZ3NNOVE#&mE~u&<=*(^*Sx!Y^sH&?YcU^=Pq%MuO*a1aNNxVD4VC->Df+*C6Z5}+ zTJmMdt%Gxor7lYFezKIR5RfWp6Sj#H&=p{E;@ISpw7~J_u|pXzcWPf>dG*Z~{sun# zgv;6PABs)xpPw^bbVthPz0o24rMB;%xQmznxp{oogcG3>A7VI4JeYQF?)iDOCfVZt z#wJdgebf2l-ySZvSdn;q%5!V>^_A^u>eHi^bu*u_ytvWoY5(&6{{kj!>~3A#8T(9B zcABhltniGmDYFFM?ELq*(f&`%=GyeWoOc|jygSUT*kY zu8;dRzg~Vvr9G=in0H_Qz841~b*foU*VR8*-G6ib&H47sa~~Ui>y>+}-_M5u-^N1YXWv5pEh2d_={`q+_ zwnrsp`&LM--6Xr<$e!vYdi`rSs#bOiZN6LaVEKHlA4{9R>pA39ON;$Bs?J&6d~fCR zHG#)hZvWx;e`ogl_51}LZ!E5)891cP-SYnV{ErSt74&mI*t_qr%AT=wi)2!QQ~KUO zhix;?JpbM|=kTe}GnZz+f0(4iZpOR$c3I1p#cioeTTcF{ny@BX)Q7)r=6dCg_RDya zqb0I-X5}1b3jeRLNONt_m@{Tp}BjybvJ@V=nV11IBEFK)W-V$=3qSFmxN=*@i# zR?pyh;L6c?;aJ(UBp$Z_w(14i20~{)uxY6muVX6w_F?X|<7TFzId``0NQ~IBr}~l7 z{*~GDtv-EZ5S?^Wp!&nz{uOH)U;X;m_-a?_-?M?D(%)Nun3~joy_WR4yjs(>$m_*d zb^bdgZ&GjNT{c(nD|W9tlDsK8W_K~?H?b4_Ds0DBY;cpC89F&=_jVndJvs5QUcO;7 zl4e+KeLb6*eV0|G`kL^=n=XGXmfL^lTGh{jR=eD!82d#N+nEJfs%og;HRyS1d$gVHxvKuEC(lecGj<6-TjE&dXZ-b9A%FKHF%h>% z3Y+9prRBm}{MUHu#zfD0BpSDEyVx>O&F%kE%hRtnGT;B;cSqYs+RV^*{~FY$+zF#seF4Xe93yP8JF#5Om0{_zwfi#h6C?*th8kAQ%x>x_3AWKEvZ|h zyI#HX{gf+nryH+`O|D8mc*=WfsCal-U&wI>hJ8=xE~}j%Dl@}g^<>cA1o7_Rce(TT zevVmtT18NOyZ6G&-z%2C7RUb-2H9 z_0+f8nML`?zkcsOYkDRRSJsr1Du#*bzuy`ebowqWHwt!SI=i4Wd5?MFHOrY*EoBP= zGUn8LIk)EA+2FMIt9^xXg!-qLz6oz>Y!Ufp?{hjad*0j`n_ek@7QXy?_oKA3{MgmM zO(Wy?)Hm<4^^00`e8KbQ2lI9`&uf;QVD*CIav$gN6R$c=4)k?eT6GOG)|0Gxf&vom>-^ecI-@Mo0a3+tu@lz$sxFBqd`>A<$YdyH!7W9SyhIblSff-`@-DiR*Sz+zI61kpPb@k-+C#zX_-okJ{{U!R#C-c`u_gL$@<^;Jo$gN zTzbBx#HTModu@HvqH_{Tm;TsZGdIim@q70*zfs1K2kSr8AC6ah z^(BA9bf?lIeT{Nn9df7M9_o7g&)H(zjm69c24#QObkDEfQh0dlsh!v5q<4hvjGldQ zmi0L0INH*XWq1qx%Jzr{5v<_?2}@S@xiiY z!9P3BPWiV!S55fqqs3~McTF!p{mMMg*z#^l%tHPA6qQ{k4TVdDto>x_yj7Ep!txFB z_wOn%`?0?CgV(0Y*zcdVpZhi~RIY06Q*+b)$J}38zi28}fBUvq@TElkiu0cr2c_wn zF(>nF7dJY%x<+i?>y7_fler&evVKr(Kk2Fx!IgfZQ$$knpwk?ysJD;b1nek$-haq^ zGFNu6)4DwUh)@a5TT<3@?!T2y>kI1$`WwWYRLZvW$Kkn$^`*A`G?{X>Omb83N8MI4 z#l2dEe+5LR&6a(zIU{OY{iOZtZ_Etrwh^hj_2ERy{;%iP=YF0wA=psaK)1)@lZ)Mo znmCT~GN+zpo}Sx+MDG;#9sKk7Sg*By{JV3fZtWB3d9t_q@3jr@p02IEkf(U&d8Jy{ zi50b~2k#{E7k;YIICu2(A7075^@kOgPTBtTo3k6oVy6i|wHx}+|J1vac9pg4H{+YW zTK5~iK386Z?PBHO4L29IkYg=%J#wCb|LEl3?O(6#ynXkL_-?(un?KL>-hJb|_{FD- z*%v-FwMzOTd&?;*IqBp}tBlu9C8t|0Dq^B{y}Mz*->Osi#_Hq$s-8UZ>f$;TsPPzRIvN7rpOMt{&O)|i{_t?-cx+)?83^gyBDA0UM#P8c*B}k zCx3RTr|DciZu{q9&C7SGo&D`| z|J^H(KDeyP{68qed5!APlZ&40QI7a@g3V?|(TNqIb6)2LwpmM_TsQY(z^t$(lLP#e z7EZ5TVHG#=Y1)?}Zq2FPPdp!b*6pk5ns}b8^s~{fR866fh412=bNG}=(wB~ zClS4TBS+2#<#+MBI(G;idCzkHOGmBTgEK3CFm0TCz^CN8&}<$?1-0KNCNv%t4puez zZEn_XUXd8YB-Eh`Nts!gqTo5F9pisRzXw$@+2+IHk$Z29%0 zt@Y=xmIkw%IVZSne%61EoAO1OZTe@w7!`w(LLI(YUU$>ZS=G26m)kwl`mdRdh3AG9 zCj~9ytm=Xjy0pakZ^YYOOVv&6@=s1FxXy2P;mn-b z`!lwkGpIec=Tg^<@VA8`$xr4wH>&U%%vLc9-g0N(@|L}t0v>j2AIpTyW4L#t==blb zv+ZYYkBqWAY3|tl`eyFBr$5%6QjVGX{?TGn2`15NE{TC`p;!8!Ki2!kTo-os)@D}k z<=_6#`^)#a^p@Ys=~qG@xUkk2vgcH5y<2#AhTI4DMRnQl@A2Qs-+WRo-oZ^$ns-{< z%I)rw6Atn`j+$$?b7J9Iuk+bQOn5TRk10pz0zo6vH8-+Wz7E= zeAtf4-EB55JQ-K^K(CtFeWQ8X$%PuFYv!NYvd`~m)cNoA7tYT+RQcDy{X%|8`}W%# z+xa6p7Y6yADl*Nmvmol)7bN7k-XT+w*zwD979O~u;s#b-5+drj~O@C$Dy_uZsSCpSSz2Twt+7EwDS>6_EPr1C+r);Tb3FoeNBVgxzC3WqFIRu-Z}#G$zEyX{G^UA$dM@gZ zY)^cC`~7m$hE};GzQebKJ06{=UC$o4*uTa?z~^-0 zMMeKvQg8NGZ2bSo`blM{W_td{`3&d3eA^y-y*${eYDQd^y|9|~jxQgqUbA&AEy>SS zGFvFQLU-|ORi;N17d-B`Gf~go-az$Cxd*S%uk-oX^xoywv)=b| z_Wxgx<&ZD2rc4q37VPKiA=tIo`L3wnpZ)ij**$+T z(d+)QZ$_Vwy<=VyRJ^8rM&;i*^IR_8UXgNdL+rOF|EJG3_P?YToIGjy?fKkgrqlDM zeSWah^IUq_X_aMPX08-kskvAs`QN#9kzTpNHntpl+c)&wJMej$#6*dw3GsdJe!f|L z=Z4nIr$3bJTi(=GB)vPumfn|PxAUfB%jS=}cJFU@I(vN5`=eQ{F2@p{<<40!*=r9= zO}Xjs&MU5K9(;_k+_(8|iR@j6vMA;qH`-XVQ?>{GI&k@r<@0^!3gu-lI^18yGgnBjTfFE^!HoMQ9~@sR z{(JtYbd9q64}QO?8OFJbmcEI-_RGe!ch{M;hs7$9{ekQEdy0wQJ1KkZe@=4h?HRLo zUYlcaS< zZ1p1x&#>NWcbFJZ^hikI!tMNw3A(&nkE#Tm483EyaDL!Z3rRDHxf>4_GAunbySBY} zy33C0Bj@6NgnV7(b^l?f^_h3`o^6`9e3kj^?&$PfE#GS^zFuCl{-L@0)C1v@+@8u# zDb09L_WIAE#rvhBCP>;AJ{P-o?M~>ACmVC;N`?!47L&CJxpK8?L)w<6ZBom0Yd>`^ zYBkNa*cro`d^dAC|C}=?-RFE@tZA9N|MUK)?*(71d-(qe?Kj`g-fbr42vtmFSEq$C@o28c{Tq<%F6i4Hz!{S z)_CW5tnmt7W#97Qt5x+u0gGB+&n~|+cFymTZ|qBW_F>(E93kU`<6TE2&EFMxFKS*e z>Gp(;x9vVWRA6Dc-g_s)RBFf4+4@JAYS*yaCH{Q*McDp_MQhqL5ees0*~`0Fb?oc! zozkX%b&XsKQe&2Ph@4ezHY4iGu*YXAR&&&LbHA@7J<%)NjoatJ-oIjU`?=knI zRhxzWwCF9osr&Mt+qQ#yW(0P`{1w)|Br@xo?w>@p!o+ok4;Ixq?OWOvoAUSgnyCsK zqB-84%8kF^TVtCp?We$%FvcjsI?vNp?X+04Jrq3?{&2Yl|?QF^|bYdzn2oiE3ERKMJwJuiRGt2{ID z8KxRq$QN%Vgicf9+=GKiK?MA2KXXpDU#q|4K-0))d=xNq>!LD^23^ zrcL{)B=5V&?7(fI)PT29d7U<2(kDj>yb_WA)N(LlInS4==aZ~AKi+>LsaNb`lXToyAwdODLp8aoA8RPE9 zTSu|Hzk0uDo5mH+LyMo!W!&TR+i%+AE8O4t`5*61R*z?Kv@HMSnsS!&*rxVy4$Gf6 zJWnm&{jA^3I>N}N=5ak=#SXr@Kl7XAxI~%u%0K_hlO1_${hw&VV^3a9o|W^)D#^J> z^^^#&oa}QK&K|J|3Gep!=Q<@?9i{i}{n`WJhZgU?Uc15U!0zJndu*@V)x5vu*Xu`Y zMk!tTH_OlSJ%6&lXKB*P{nb0V%~t%myTaGBR%&@}$hG9NE^!B5FOGja_tBS{2Bm#L zjOy{Z2J8EOxcSNTE7=|3mTz(|{B+}k#+>rL6N_JZTZ`B>@E82x4;JjdqW|>C7SZ{V z?cWzH&(u#ddoZz}{KKA$*I(!qY>{|1KdI^Q1j@W4taeUv9qS#hp2K^Gc#@Qi}g?D7t!Qh3(sq?>6le{~Z?M zere0smuFViMlTmjcYE)5HhPa~ep;CaL-n^aYvx^g^!NKV|9NG*w(MT;hQZpVRLlJM zRD*5PfB4C)J$G|o+s-K*@(13Una|$5lmD=!)9Mu*)?XOq;zZpi=hZxPtThvTmhpV5t7bO=i ztX+86-t+EjqqDrmXN1=C?v#C9p?)LT@tH*bYIg4|@9*#C%$LgxT>bH&WovHsBq{!L znkORnJ~fk)m(Jgrd`8~-SldOzQ?u>dWaYX!`!Am8T53*;=qBr{h!F zFZn6F7yrwYK0dWz{YxJ;zGt=Eh7Hp94ha_<9*9w6J^pDQi)Z2HyH6{NzOKqOv|y~| z*)Uz8_(%bF`lww!_*=T?x6L`njsuZg52pHXZEgB)dLaJLPMJTd zU60kHu z{J1&o>VD%l@$SLje_gkmXt48;NYJd?@1L&x`f|RJvC8I4*VUbLt?%4lf7!Ef(!Pp| zKjd%k?JT$cB=K>DpZh!~rmVfn{)-h}dArYZTvyVeeBN28YMb(Tcblq(%I|ybybyH1 z$9nRmz11frmGqRpJ=#LXGoP$imSp_$^yr_-r>zewwC$Ahlv7p=eSaeOf#`RuPbOMR zwpo1Q`Ly7!Or_kVOCS4el6&p+L(xISrFGwTb7 ztqHGpJ&0`HvVv<-wXT*Eugn^$ds_pXyVDk^RhSnE=yJ8Bi~rfSkVS-Xf9#6i3qKW9 zY+IBj!eUy@aP8>UlS~oZPfqS;zRDb@8*!{)!oK*&tBbF!m0mB+r=25f6RmKcbw=w4 zZ?~Hq1#c_<2AnW=S|{apnfJ5e&#DH~f}MKqnd(oh7VMF_*Bf)%Z=LGQVs-cCs2{nF zF}&fw8mwYJtbO{-*=;_*#i|ABM%lWjo;-^=`Bi}Lei_F?hi2x(OzgVVjQ7q?4Y6|j z+Tis>)~}|6Q+Dgr*sZ3wR>kE8I;V!0I_I{Rxdpo?mo}SiSh#w%uAtSg zn)d2`z14PXn%<8$Z(hAv_bw|Z_a)C&vyif^)mhomTTIvL-YM7>wKbM^>#aZURxLZ0 zm7A7boSN*tL(J%woJ8tdCW+Mi?Csl@3k4K9XT9NSzbSIC<@JN@;+yW4mVVG;NxD*; z6wK-3*t+%WUEiq_elI?(w{LhY@x#ha&rAEetB?G)kMFXr%*dzDJYPQeUW+e76c zArU1JB`Hf-|BAnPA--0CrM6|}Tt3E2MYR(P-3l#rLsq_isn-~{*6Ye2`oDeK|IJG#A8Jo!+_&5z(AIqJ$qQ%vls|1h5^UKwsm(W` zOm2$9jH5pc0?(wV&Gu|dw|RWfC*jhJ61Bcgx0XvTz8=rN{%1{ot6#9qF65Wxl(a`o z6=jSiRyLgbr21By{%3uxvQF*gcG*`~78%Z5%Nk*P+{|bZ``&9z*%yDrci#TCDC0}C z{q&usy}$nddHFWvh4q(St1df!Td`&s&(5!$1TEZo!2k$zhGD* z@Ru*vIb31idZwQ@d0gt5J4!|O_T?=wzZm_(Y8Ug8YW}^w_Z-hNc>ZtPw!nVT_lv$0 z&g5Ubf1%2R|Ae)C$32!FYX+Sxc1tyv_iSo946lENZxPUC+8fm~ZISAOdi%aVY!ec}CIJ9&-ALe9MGppDNSLrgmY2C)pP{e02*CBPnafR}`cP8Jt zGoQCqvA;8Z+UJ0kTod=7`O2Qj&!(yVDfi(MD^3-w%Zi7C9r8M_OzRDnh^qj2%Zv3v+e+T=W($g%{`hw7GEGsR zH@|dW{onJ_M;k1qmG@oc zyqS{s@6naTKYy$W-*e{Z@q^_N&DY$$W_hmTn^}z?$XjdMKMNeTTqyOP`pj_g(&$y6vZtQEUl=PCx+mk(m+YkLTFbvpQHi;xe|cWDzEj3w z_uCBxbElP`?meG&u4D4mm)w)~*FF0uFTY)C+2yPA)o0)Ty{Go^MM=R$&o0NUExkBn z#d90O(DY}m`*rnw#OD8J4Pv!WS;J0Po z4YQk$FW)gs@-}mF@*n-JEw;JqWlj8#te^=|8;>X1F3dC6zIhFyGs|uatUjWqUuxsdRl`b9`=J(R824Lx0YlPX67WS!tcFeJpEj z&)Uys=LM^m&G?f2w2L!owuJTm-`xLFXYG8sd+FZoe|A4U^!4)fwOW@={(sGG|I~K4 z``MrETRltdKE7%Dz1gAvyZN+L@lpSd|4?6ijkkPqIQw+=2BSulD_TKklQJ+kE~<6` z9rOspqUd|kij#{n3rdRh!Dp6$GAszAWm?oSp=HtPnrH?FhC&7g25nr%#g`P9#Jd+I zrevn(l{giZ7H8m-%#k+_h@)7ec>qf7h9KR}XUdFK{*B>w@>E#$ITow%4bpM1b2{KD^j*yk-g0u09U(wqKu zOF>MXXxm1`{57g!vaXxcX`fZJQ-i=K{!_S`v=ZO00(RwtQ= z#u(WvNnB&KIUu<2|CS${y28(QSJwQ`G~GYfKK6>$RV`-qPe$9k;@jQ3wwkwu8p?^Z zwyoZNfoH+rI{9hw0oNY9{P!(SRR4YY=X&{P|8LaKu$bPrH_eY_vDLFS*`oi)zWw>_ zFl(9WnS}=?Z%;Y4`@|FV%WdM;T+4zv4{nh)sO!>Z)mi1%Hg(&n4I0q_Pel3b9klwV zIDay^DZhEo_v=h;B6-_qEtBzM{AU-qGxh#*_qC3F+ut4R|EFvpyUg+6!iLPtb;h$! zH*au$bt^ycjkd+ls&%K0UGHtTxBX+$n;!DM`}g71k-H7LSnVBd28Ek>I6eKiJ?~0u zc}notJG>u5PV(OWmOtf|e1o-E$=M^{OI1%jPCWaC-$rlFJ&qNpTEAOGZqG8CB`4AH zNV&tR<)X?_Yt28r68BtESd>K{WPFiY7Rkh&s6AtT;K`QL%!}K;#CXTQH7dFkyR&E4 z2e-Vo+j)Q4K?NN4@=^*{0g;oLL`tEVmGiFo5*q`9ju-=jB3?7oOEU?TIBO&B=HE6G zsOO*X|KWq_k*n9JzTK7QdwF`I#J3B_?RaAyJ-7I}EaaKg^_cJG{e9MQo)m8P7DWB<^@u$9Wqm;;=uRdDl9(uPb))pAPhnvERNaT5P&_(DuOh>MvV_OVtmqZEfC~ zwe;x1mZg(oxi_<4Jqv`ILBxI#A9#0^mQk=MMoK|2%c5RnDlZ9|QN&qS>)6eBMd;9@+bMifD`s*#G+n*EqxpZY&Xxc> ztH*2emTY~|8}q8x#7ZbNeX>r2V6@G_%)OLXo`4x7`uVri*+`_>&lap{wUIm7Z8cfVz(Q|C`P zbHnYCnZUJ)8~9l6Sn7o8-pcWOdHIC!th38=%-r61ZSa$Df7u;bDJxWaQ+j@$%Q6|$ zO_TYZb}vy|W}kC$;f%FaJJv6CJh|-pxi7LB+`h|aS>Fs3;OR1|R&(w3G`3!4)O<`v z{^g(UE6SnA7B2F6zdgdl$DRM@{L+(xY11F=Oxye@O+WwW-b+FkEPD3ralf!}qHo@h zs7=Zja~GI7NlIVYT+N;F+i>#CANvf0EG*|QdtVXfwT5?{=cGBzUmwJ*KmFnNt`_T^ zhd+NhdCM;C%Gr>a=S#(!`U|#Bf4cY^TWICwV1<7vGxdK)UAc0=e*1#Z@&(7Ody*V1 z4V4o1HEch$sng=(p6`_gR?3>2*4;N?`u6Nz_-gL2X@ZSknRIVVKd9>Y(UUt_$s{&E z_1Wql;@Vakvp#J0koDPoa)E5#yT#49Pwt+r<9nAcdt~0Rpm1GNrSo=^8|Kv1+%o)b zleJ{d;wCpk6~4H>>TZJ@DJ!l<*o$0K+Rl1Cxx9131cgg)&5F)tR99PnPWo-|(sSx1 zvE3JCf(_FCi7e(6)ws0pxa)_)M}CJkDBcikel5J%-h5o>_H7$ZEYb347cmxLRJB$)3&Qw(FsHM;Dwe zedlSxbHwk;rtTDbPM-J6Pdwm!#&xfCRf%|~wynU?r9GB*b|v#I*cb0H*>SY_Sn`33 zu|Mv%-S1eRqtO4-BIDwtsvu^EE5*0}-IumYZFIle-uT@s>CWQA{;hjg@BT0Jtt9kQ zh&`talg&e=_VkHcy`F^jtlEE^t#0m*(nr64=RElA`#NQE59|BA$E5wa`;<2tdhI^! zV46|4G0VT8uj(; zcb23Mw)u=^+nN{8bX~-;=hBL0N7#K9zhjlFQodt#M}bMV>!{|k>!Ajm)*(+G83?&r zar3z+<<-upk~TPTDI>(^n|-*l#?tUk;WYIGzVm;5Zt94g7xnX+R{Uehmo$rsD`b{! z`FCQo`m^VoT~Aehe!%>wYTeGtxcErZ_O3S{u66HWvU_sPM{Bkz8>h>UpFC-)`)UkB z!yQ5=-r#-mv^wQ>zy958e5RgLeh8d*71)`n&Bf)b-I?Ft8~Sa*iSy2F*KLl~@f2MX zSM&W6!%?$?Q~&esQyudarT*2P6rVjae@$^(@Y$AZtw80sheI8IK3~4^(uYfNK7|&! ze(~ymTm|F9tpD>ak{4iA6ST~~Zu#_j^(pq;t6rCReRtP%Ki(8xy-DV=vSD(0*RqMy z;cYD);=C6h83*rU_^T|iNm+T_lR6#u+kEn#FO{BrIUeu>hm`$shL4K$b9UU76dfuRQ%8WodrP`0gC>0_Wv*|3vH*H+?SF`A`@j zJ$>uP>R+$gPZoX^zhu1hM#A;0n_gGXXZc{OU&9)H^)^%8hs|3Q(~hp+n0k4-&}$aE zTUtL<%D$LLuZiJnu}at|?U{RX*9E`7Ulkuc;#hHHZv6hr;2&bqp`yCN$G$|@l)YVF z^*1?CP4C*gd7tj5{qfVgJLSLLir z`reBCy=Cl4>+3cBJZ=ASgDPMV1_lNWaEIkuO)jT5BLl+@CM>6^!8$D99!79#Nl9j2 zdNH9IvviWLKa-(A+k4+%@@lrap3`++xbm`hI`UTpitrXi+(^95@OGIlcJe$8TC`o})uP#U zE^h+Ui#~Iva!cq7+u!Y%WZ%ywBP3VW!7f@=QMWeW6aTDv&c!n=1sCkM-RCu_?$Byk zy)6AxF&66uVh^UORy3dV6YJSNNnNzk-us<_dB?PmVUmY;9Wt4`Z)4B)dsZwT?(SOX zlIM`0Xu_1vCsEhSHSb*e2hYC!QvZx4`dxZmnw{?WGlhorK9WX_D*fX1tFssx7*;V8 ziYiA(x6GW9)FMJr)jHWe|B!*e(dSQs_pA*N3UQb#z#ME{@+K^FswdwDgN;uu1iF5_ zvwhyrqS`R^#iQrHf8Mk7lu6F(v2sXI-Yinp`BTPwrA*`t9yhgh8${X)d(4Xpva?K| ze42i!w#76pVq$j6`ftB3cU7qSO|EpkT74>~b!|b|v_xS^yEewY1KuqaB85jZS53+K z_UdYw<$24irgmG*3c|!!o3;e?9-b8PF5KR9`b~k=Im-TPO!{i`dmnxK))JEL&zC)M zX_sDAbjIvSYq!0q-1~9Y^;WOi&Ayy34m~y6n^LSS^s2gKrEb}wqVAo-*Z#g~(b8Z_ z&HO#X+UO0_;fDraZnB?~{i)n**k|x)slkV;$k)G%ZCCV92|80DbVY2x+x?n{H)qFm zqy*16mAO7;lDWl?3&$S_Nt83$&t)0^=cp-KxxDTE%K2ww%fEl%6Kk-ydU3W;ixYDTa#D-qjr2_P@pa}w zi3GdRYPcG|$VQXcxUN6+F=#yt1H)oo1_lG7&CgBE%`d7XlpME)<$~JU|Kt?@KXgcF zXgM|OZRvptKFr@1Rv$FmlEIea7%Vcy<)%xUp~trx{lqo$~C~hHXg-6)RU*#mt$1HjUwf^lgu$|I-43ofl5zTIHvCO)6v8Hlvtr z2MdyU`FAd}o+c5s%;C1whov0SPM54a*A^E1sFiJcw^Ja%=z^P87<2x@hfR*ItqG+D zY(K88tK406eg5xtOQpZX_9-^;T1oY2T5*|%uQ^n}UQqq+%X-WWUC>QT>(9fBVvRb4=QUcUe5lnO9y|`}P|9 z{%_AFcBmgM`C^^-zq>(R`QCAk?~$&~RlegSmmeR$tV%=9q!^@g)@>cd95)_D?dEw28yU}w>zDHZ0 z+rVqe`SX!}%G!RD*>gKuFLSSyZ7pg!RkMCaBInNinVwcTH*QwUe)~q^R?xaFy+NlF z>)&+kO3mP5;gmcsq48eQyX@slftz1S-2Wx_@HbEO-H_g*sT%5}b!*$Do+k@CG|pEG zRk_Pc{g16Gt<|mw%3L5?(L0?fpYPkH*t;m|@S%-cmwr<^neZ}9yVbny zKj(~T`o2M^~d#la#h$?M&4ZeNz}OPt+H)& z$`h?iPuBiD=(@%tdv3H0^HX~kiw6%9U*;^mwns!~TIr+3d-Od{vwHepU9x?~hc`|8 zU81)>m%1&v@fY{Sd6OUJW?tLm-1Y9mzH9IPvFdjf{}Eg}(S>=7p--=#(`#9yotot`jP3Z!*CKPXUL5Fk`sKXo=4YO? z?kyS~ee=!SQ@==fd^j|lDJ_1v`wRKdyMe*S*W2oDT(+@qL&k=lE!l3>ymO=;Ozz|S zoSkteMKb!BzsHa5f;$tV9+zh7pSw}LJ@eO;lX(W6JF6mm+1^=A+j(b`*@nr_kJOnb zO`Krssn7mRx+2~|r+40yXG%Vo#n&G6lREpi?p3|Qa=SINms@Km?zp?`qk8&-s}r7Y z?-2NU&USXb$D9jKbdMc8o72O1?5cHDuc5qJhrX7gsdwA051;zI70>+Is&+os+BsvVHJ zZDC5sv?&&|Z<)pO=FZ+$p1yyL zx}oC(28-tp_Bish9nYG%*Pzhss+-TV$cUqrYLhGsPF+bd{N&!>8vbmh*u+3@24Oex zPOj1`uX))1?)&lK*_WUL`#+b=$h=A^Hi#eLY zo#Do<){e_(gobY1zuWrqO8b?*F=0Dr{z{zp&aENnfW}*;2cD}QrNnR9^}lWMv#ToR zOXIUzDyu8^>9+(#E;|*(=n(f%Cx*X`(1kZxpNPyN9@17xp`-%^Ur^JJkxeZU#K$*zZ=(m;`5$M8&Tf>P?(g3Hz-;|wn}FNG)`1FqNAvf0^Bw%M z|LJiiu3tYFgirkux97~}Rx{OyXYI2OwfV53hrv72FRSa@S*njx8c+G3R-J5P7z0MW4J2s;l9!DLyKzwdR&(>U6{(?` z9qzY32{x__iCkg3b<(P72ff%z&!25PJp1QUd*7!AKPW_e{bwjI=V?Y+5&3w+bhR4KvW7FYPiSJpK>2G29;TB-L zcga+N*qNt7RbG4O@wspvQJTi25PnfH*CayrLH618Ul-WD5a{2dv)+cmN~S5bzu-^7 zjn{&gCj@doxxM)zW7E1truG}b>FNs?^%H93j zckFc7lF4RREc!M4qMz*7*DKr)YfC6!Nfd49G(P|C((A`QO)GVMc-1E~scYpQ&RM}W z_pS=#x2o0ia`qbjj&GE+R*yO3J8}B19F~;d4y6|Ce}Zx%8apW*YpiKW26RQdR8Dr}tL7girl;fXShLhWgG*N&l&a z_cAn&`>XEo_x&UHo|l!E**nq7)b_=cB%2y7`N#Y39pm^QT2)z4oZ_Qwv%`|9tk$MZ z=i~p$$7ehDSH9rv&EtFPdGM}HNxw$pM#joHC#sZAPu0oh{O5V@iula)+B45wo+muj zr)|j_b|srXyfzcADlo8mG9+Btu(dSGmrXTlx$OEjvD?ee$?o%7klZN8zwKyP{DXN( z;UB_sKXUQETl~;_-tuW|Ij5Xbwf`LL`Wk=1_1n|Erwld)32>M_a=ykVprbu^(a~87 zdJTUr+<*P{QIdnqmWSqgT~@Ke9<}@&GtIgU5=+)|MbGY8^yh!t&;J*6nCHK@UYsR4 z`v^0`N*}I3$pqciO7W+-rWbb!dZheFQWf7CBau+GWcjA3GMB0j8GC^be!A`}R!nRE zC#P`f!!Ln*Gq2x>`drmqKX1SJit61zBED9Ylt?`O|nP@s6P5 z`hK5RUpqH#yBBtP+atasfk9^+*dH%xk|>z{l#AW{%;zl%tQDP;^p6HcseD{=k3IIY z@$uhIT03W*tZIwPF}0R4nrXWI)z&-ZE*B^4p7k|+^W3Uy?U~O1?I(JfzH<8Ll7Uf0XckHv4xf=hW`r1S}N#>Q0<9o}G?v~c{JIIpG zuU$C#sdu4S_?&gRrYcDjjE;Pmk^WTXQ-j)RctE|I?8`I}iJaeD>es@#1UPo39La zSVJPt8GOCUwO3xJ(N?;QlTCWzFDb6ak1bqHUfrH?WqW~RNS52uyoF62SFYc0E2yny zKleQ;uiN;RkEsMxg7uQ zI>JinxW|)oFY=7o7uT1DNUu9_<#8744hg;^_fn;Ls$E-p4R3SulIzj8gqy%EG{}ar+2Z@*I8T!*`cuuj1)|5 z3pqYavu;Pr(~GaCL@j@@;(*RmbEdi6 zxoxG1cM9!%v#dJ>tg6i`in9Xu^7O_rF@1JoST0?YV7JEG^+j+MV>x$S>as4OzIuc1 z^7M}iCu=_*3~HSbcvFmBmur^6f!Ikl`wuR9&wJ#z$@%Z4BGD#0o7QKs+&S}Zf{p&9 z!YxXa%2-pTz<8z~eLPN;wuy+S0<}aM37!Wp>wwR=3hu7B_#@aD=g@ z@o3E7yvV~~ey;Qq^IgAqZk4lE#B@L3pBXPh<&Ug?Z`aj5d2#Z`$UT-jEq=Z`{{G0* z_Wt+&{YNi8eR_Pl{oHx`#nRoMueX=mYgd?29u>{Q7S^}8dh+v|HAbFWraQD;dctg& zQM&coQ+A6TX#&e4Ry?#`%OqgR>!G=1;|!tHbz0rQp0{%jmmXcGttPhNTJ6>!n`Dj6 zQm@;~we9OYeL+0^r-@tEebE;zF*3i}4+V5*E}UfC^I=_%YmBPl3SAC%j%{(GRxYn+ zrF-_C;(QgV*}?ie^3VC5+m?#&%3tIelG)l^ofqH8cw+h6V(+WHcCHL}X88FF)vSM7 zkTi>9`P2fxs?*ay?cAob<#@H7xby6eqtVCNrcL$Cp7iAF8s{T_zU_JQU>!$y;cc4_ z+^;WWXcrxm`1CAQvU&Ca8)NAyT32l!nD2<#$K%Yrc=M?vyPlllID7Q!h02p3W<|WT znc2iw*?RXn$0ON;YZ%N&Zaw*9}{qv)`UOPk#QNLz!+f&Tn3| zM4^ z=(*veF>S@PlSkux9&1j?oShWcoBG&XNVrt@rDV+iI*0DG3Df(m&V4WnPpB1J8-1DC zIyToQpJj?%?)-BucS{Q$8}DVhO=Dvg<$8GSs`CksLcu3TTpCmVS8aKG$gJzVMCrWl zsn?sQh2J=G?#3)j%_A3Ye_zD%ThRZ}gzA!6!D3S38gu~287}2TBrP)3SK4G|;gEg! zbI;5g(@BrB+tn|>cauALyoldKTCAM!vEVtiwe6XoE|yBmG@7?Gl&cCV^xU!1l@!?C zdf+7IU$$4A&v_RL@V;z!3GDuVB4dv)`!dTj273=x@uY{I$$k+0_|m@>9cx)#{(OHp z%lyAu*1d}>~?yFg*bf~y5-Qqjiq zer~=N=xHw5*fr;WKVo%S`G z?@V=5S(6Z*$)mX_YU$@ClhQPodrRs}wCxQo-NRh=G3$q?XW&Ox2a8D$C7yd1>nuNR zWbux}{O~DRo}{W~d~-YFAJ)3)*KzM4#-InsF1N2)l<0kI zL&y3_0>-tuA2l_N{}tBm{JvH9V0TPa0n2=$xt>pK&CEWn-SAK`@~NA41k-7^^HN_Q zvCV$2aem8X#i}ItVpqSIlv#I}BGx+Iza*Ha`X=$vuDR1x)49UlncYm2dw;X5`te?M zfl|Ke*8+hZw?95zTXHmz>m}3qyv#4=k~4MHI+j;(Z(`5>`B?qJo!iavi_@1dN9?w> z{a;d6#Mk})XtZ@ppRwjZ8_ zC1q&~w@<(KXwG*xEuB^|Ji=Q;n_|YD&8Nruk1~6vk@vubg5uD4@7SH>+B+n&gZhZm$p3hL$c9|DD89 zV|_f@@zint#yfki1SLEvikxY&#_Fs%quReIkEP}tNiv)h-eQsWIzaSZ(&uKo4;l9+ z?B`&f{8;x%MgIEd`<_0&8j-YYS5@Mpmus3P>q&-g`TrxOp-9YsmASmXj^yIy59D81 zH=8=1b?=@#?FD}-_oDw922s+7w*T0g7xOWcKZ1Yp;>wQF$oBRN5pjx@%9HlDX&q8< z-mvI!32%i^-6!KVh2mb;*K%wn2Mn6yB_6oMC1>qkKKpLtTfSR&&m1``z`pV2mi%zf zM-iu(rasuaes{lwLDOUx-;dm1zPmZ!+mvxRfA#03+Zv+C`d zo$ZNB?_PfQy?pI{k6%S|yMB8;xHCIy%I6PmvzfQ`Gq^Q&wV(i1B1IH8uOM}-uQ{Cnl{fu*3 zq?XBZ9m|TJ{z*&;5BfTU|7~*<`X6sl6xQIYvRv@RgpzcH>vPo3>b$eyU)`z~J4tQY zjbT>f5|@GZ9mL~F54Vua*lGakeYt0{8)=0 zgDu-n2a#Q051QOPcj|%r@)aN1<~}r0dh60!-;&H`tNKTZWA&HdH#4?bF}>l4ac_Tn zW^P)W&(Xfls!3}OpS!ZHN%qEs9F{JIb#2@e(()HI9G-2lW1gwdmCHxu?jP$5Yq^j) zp&|Lm74f5I-Lzv~D9Q`hUp(}?G|pq)eBs`+x*pdWo>XK^dH2)qUhfZ!C(T*voij8q zaPN{@V!K5$BjE9dMOsh)s&A@Qxcz)%t&G``MFPsL!2!XtPqf!}m%MR)lAyFt`rF^k z%T0H4BD3d8Fa?|W`db9w47vR(Jnm)f$GY4_aXB+II206ro!qcSdoAaY-|-%TN^?W9 z4oG#>Gq*hbw&vOCn=*Vy63)!&TzSz{GyCP|Hh0cxH=_uaw|EzX_L0j_aE|;8x_m_PxIA(SHzS+YxN1LPjS2FSP zD1M&F{|^7(^8M}ITf`IUVxFfQa-XcEc(PCal#F+o z(EE)->)-kqxv&1n=+WVFW;$b#(%Z*B-$d_U^~#M|MfGOonR_<_lZ0}<>|VWk^=r@Y zva=85lIwJ?B$q3xS1;mNyGc|qv`j#hZ{CHAzZs(0Sfys2Y_DU#HLc@8chl^rOwE;- z->ToL)EAnXyZh$!FnG^USArAFk1!H$!QOp9#a)5+W_~$RxN#G>ZB9g5&C-ppR(0Cor4~xrb`-=Uu0(~``7*X z$^Pbixwn%+iBIa}jZ0hBI%x%nhLl}u6`FQnUd{=QC#9@GN0b5$7DeyX(^FH+5ae2- z`>%n03d`yVX}>ixTECe-JzV`Fd9IPQrr?YzA;)Sq_gpYBa$l1>!8K>CM|-AKblNSo ze`VV^lN*$moVvZC_{FW7brwB*Z9aU8hrd)FS!1-De+T>A2i0?D>@S-AE@j!@TU$=Q z>PxquxHaO*6uqZkJ9vNQIa+PmczM6?!gVsQ?e14ra66SM9Dku%;bLkuvH#V6PQF$@ zCuPZZHG32}5A%O)-p=#4Js9G`i=YAa_x5wJASJ$rX&!QDdtkFJMz-_qO~7xT_c zuh4p3fs1-p+vJQq*C`9c#EP~^F@@~oR<-;xTRBWxxT)*>jY1aLaLa^sdvE>ubXwm! z-+Y^}`MumX1~VD9Eackj{o8I5k z?;p#mzf_tn&6)4{H9C03%z4{=vwDQvs;-$eFH|{Fb!|>{{oAbk+7-6p_1h1( zwihlwc)dJhLzs{LoV2^$Ic%Y&8{M)tN42an*zlq!^;X}5g~98uzpaa0x8%D*#XP^s z8jByD(Ve6BV!^W2uUM*QEzOaZIUCv%Et-Qi8KX-|+wa+RZtp<&q?H`30 zvZcf3Z}9#w_p5B)SFzP<(M!(hZtb3W^4B6=!3*tQRU9&>#9HXp9y+;JZW9N`rFA!g z?9XtwN57WOTUp=nt3Brb2LBiPV(RxStz$^pv-Mwv_g}+T{X75d@K^WTS+~2i^kP=@ zR_4qYaj8pB@sa=f~^SW9#%tGOe~-XmXjvi_fPRqocNT{GrynzT`OHFxRk&|4zixr+@9 zGJP^Dne@&q`7o>Vl*G12$L`floMO6rZta4~Uv_)=Mf~~q%6*y%7RwvfWq8NTu?>$T6-9q3^)`d7*+EV%D~lSU?^{719;lTZ>xp^BNzFrwn zHLtsOt=N=YjcHq17Y1FBiqYk^ddpUJh0EyGZ@tG#F)K3duSdwt*myJ7I=kzU^OaMx zzQ#%aa(7nMd+~NdXG;Vpk5`A~LY4ow3#-J7Kiu$bO3*aS4K^(*U!UkA=6V0unmNZV zd0z8KZd6&l@b5|E&zzGJZFyqNW&8hsi=8W9qBgIBA@|20^%ILbI}0RtRVwXRb;(3T z;|O2My(0k&US+r+(sa&OnRDRUJnObitlRe%{ry&O`}_KN*VmkTw{qr;eJ6Q)xcqCo z?!<0WYb^g;y7Iu8ufcPqdu;{ZM8rGpSm3;NTl9vG+qn`ZyCqt6zLq8%D?K8p{kSKf%w+WKr4ZQB{x1F zsP6k3>DO#vv!lG=!`HoslZ*rR?%VhK{Q0<&rt3=8+r#gAe7UjA=9FRZ%;bI3RDLSW z<%nK6gXv0@P7 zmbe8A&J+!@y>@w5(AF@sy(@F7+ZP8aUod<3^6#uyn|WAoXywaX>(kEnx}Edbf!V#D zQ#@c-!^!3c5?U*?-s-%_C=PACcUA4c zGV=p3x(*oqEmjol+3P8(ky-S2-dCPp*5whWVpKjls7S@1dfgUNT^4HTx`KE2jnq>1 zwfhY;s@o452^=my^&ot=;f4iE?|#(FxUu%&`#*mdzF)I1JhT18?oI#OHdRIcc)#?{ zHfHV@>+14$|7_6Hy%`-f(e~-vON;M_zUtrnP{?Znk9^R~irj>!`ZKn4G#3A4`Xp5B z_NC>{n~CPB+xs|U&pII2`9`k`)OS#I-=nI~UF z7+Y#RnQdd+s}&?;JwZc{Z<^H3kS`Ydc^hLs$Ss*?dysv{b>m#lb*)N0lYZ;Iu01{1 zWV*n6lUc>@?HZOSs17(d zXnvMx-ut75yPT;daLzXOlU>s^G`G1-T~olZOM!L9gj<>S=$?+yR+n3(>b#nr!TnFCM;Cw z*|cq**X_Oy?KX#nE0!g1obw>>*HrdvrV>jnd(NM1wmqfaU?hHr=S#28Kb!4)^*L<)$EW`)lk+cR z)KpIYdi%2SdHzEkZ|CXtx#jjK%#e?Llr_KjmG$3?dj!^}d{eKD*$}R`Lv_!RopUbN za~E@}*5A!oJ4N@{7kArS*?`wM`e7=qleW0}R+uY@H8gI{HD*y?MBJjYUd!^5$MS1?MC%Uj-*K^K?Za1=g`zgize}R;Xft$gd;gGqURY+5 zwzkloU1q;RRu!f9=jANe__DQF!kG2g?iu;gd51;jF~3zkJn5_OU75+D%+kB(*xZ>X zQ~b#qIsC+X9znzoYN-r=9B$WV(IKZ|2tT$0XL4z7^`LpFa8IFU8qDZSCJ@$h$xJ zTyjh+C!Y1Z9>?@eUpp;6w&&@{*hB(j7YmKUbSyQ_UTQxCn-G0yUblS_1eVF@^710YRuU6bk(mbH)rUY9lUE4ZE&af zoxR!ex1ZZ@+gm4yYi#>xpS=NB(;GknMRgX?Mb|2rkpQ#X~LziWHvd3>H`v~J~kjhFWyY@fd7 zP5Nt=qwgveg3RB5REx4lW+vn#gC3Kq{=^GVT0aI40}X4=ePB|bsk<&tZt=&0X%{0;gxM5Kvznj2S=75Wqv(dV;p%l!VUg>^ z+$Ve#d^O+qh5T(_Hve$`2QQg(-?y(hx^DvuL+U=C&#J56oKMPF`+QZ3-p}`PH~!Rw zJr+83&FEruwXcbu?BSlxU^tmE9fQ34N>L^qyPkX6`V zFRfo$@>6GrSBlie2MWG5+7Vw*UfZ};$n#?QG_fN~WM512UuI3e6yqTCC_Vdr(Nyt+ ze)A`JDgA#vRjcUCi7P*sbw~WacX{hRzO48F_jQbsk9EEn-71-Gp~-Sa_T2erAv69R z{h~iRxbm0y<^A5qFK2pY7z9mhI^k=bvr0(#?ccbUR_o>-u(j3Md%-X9_nGR(F|)tnURgh?uS+3_7Affp0}-6%v$29?XaS2pVo_2 zp2mI}-TSmMR(l%ztmxjS^D9d%ZT`&nHN3fI%~k7T8D@$KcARk(TA!FAtNydeZ^Pw` zi}I0SdWsIqENzQf>;hKBS@{N}G`D&evT&T#x_6YREa-IIq?@7KOLUlbi$+`#50?MY zT(;ri;mLb{UHNfhQJG`>r6#X7hF^0&X$Ks3>KA!>>08HaZeFb~%bO0DE}ziDcjbZ1 zmIrfQp6^PQSc zM%wZ-otLh^`Eg}u$K;#oT@$BP_Qo*X{^rGI>3Nd5>BWCzwIxT31Qt1oe|+xqV*k0T zCOM|(&T92vmTi2sz+Tj||11ylEQ#g4O-%9J`?Y>p#vi=1`j*1>1;4Ky5t}2b=lO3?cj0q$kFrT_oPLA# zpvo4DN-5RsMbc(7x3p%n=bLPIUmg9f{pM6tJ-r^aQ@`2d)&ErPN#@t|m@T+4jn}??aG*jHFwK?vBJo(eXI}_Uq^U|FN0T^@2K6=c*39jQ@uo zCOaPuuTd4=IrYxzkObB3#;*>(i3(?LJ@;y@!QmSB)Ks4f0Ww8z=4;;RH@m)ITVMDF z0db+#8?NYgI!v8*N!c~q_NQ%NaO2xMn;uS?aBurk+iPDB9^TJ2(NgOV*Dh}E8@UG> z3ReBT&vO4P+ncSj$B!pj`m@(FyxV-8v7)Q>LeLlMjTiUFU%tb8tKjbmzR)96_c@23 z+iFtn5)=5Azlq=S?RA#f@4Myd+a7fq&Ytn`$PwYDgZE~ixo})So`XZ+QF+JxhqHey zzP5auPRPRWtM0FLs>%`zU$yb<>dLI(Sbn}PF-3Xrmk+$E9};^m_1^CaKfoD;cW1K&pGf!lP|oV&N8%ChiYsPhRc6;+iDO5AQoC#r!60 z3+U(8Fzt)5@7itnFn#0Kt;s?+ttU?ZZe4RyOqsc!DRM%&`1bdVEdFth7iIXjPfv0$ zXMbz4^e|7=)8DeZn#Wf){x@3@rr@|CclTcD`*KX1?;btAx7apAf$=kwWPR%Umv4?n z`X#^Dvh=vQ-*wuK)ywxVfLUEmD zq3R?a``3Rz`Z(N(jS$xpHxvE7CHZ(+nElJGeus|5ap;{}{r~SL)4LviRU4&d&1?Ci z^2(D}FXa1MyWh3@k~Y87dba+0I zKU^$*Y3@mrxsIl}|7F-Om8$NNFKl`D5ri*&}9O zjIwpOpk=6k=F-QIc?E?mfqG$lNoC(oWQ$*1e4R7pf7Zoim-&c0K*-f|5)CRN2Xg>faf=0=oT)?75=-si5o z*(Ek1IFf1Y;d6g~e{a53x=1G8M)k_44%2kLpEKVwoO{P5diMPH8|gd!7VZ~!fBSRA z%DvefBDZ7i9|-V0utOtbK8OCzg8uevucmLKTZFDfP-UWI0<~=_!%a>hojktBc>P5!f z4?iWIOy;QTH28R2@b6YG@BhnVLY7W(sJH1o_S)vG;LLk0_gC@X-E+_2VCJqM@m;*D znfa&he_3#Xu3nI~yH@42MRoR^#d5JL4cAKx?thfN==H*>AH^;jvvx$&n9lPov_Hay>H<9wL?xsu=H=MC#CZCKLodb!ip zq#c{@?%uQ|+E#3i)7r2dtZb>#9x5`|UoQ<6ez1b&lKI&R_qK_}4uY~m-esZZQWyIg zEI+u3Lv-Ply&G3c{jPCSx8ZA$>-t)_TzSe3jaiplpFR6>bKjd2@68|exrwD+?hWQV ze8-S$`rCQWbv#$Cerxjg%pz^aNiHi@_8PeD3EnKm=iuj3yf}yDwz;Hi{SODR$=~12 z%1Pa{H8OCeX`pV2r5#tmhMT*+=N^cB$-VLQ-rd!UHmhoziOej0zd^y}M}nk~U_;G> z#xv_qh4OUX3EZo{PWkqV!$-qbsR&P14%OW2B|iI}t??0eANftPVFK^hL`_-fxi~Y` zx2Ns?nuWES^8(v{_{Qv+Shr@W>ylqg6~C*tem31BaqhC6)2mNU*X@hiYUGpAowjZL zZjo6VRa+Id?_3udy=cYM1!c3GK1c35bo^G#(&nQldRly2@*eUeS=H{IbfGxjvt!|s zXN%63EoATS+OzPc#O5!3vp>1pCb@XAoR`~wXl-U_LdBB)H@ux&S6|U~db)1makb** zB^3vz+9X>s>rb|O6xpB2Vp8CgryXb3yd$$ie&4kDN8K;v-$^QR+@5~#&AG6&ZDx@s z9@8z)>KQ*skav$gGTptCkE6Z4>DZT~5bY9&M>P}AJT*2^{%1HzzRxE@GHTbqQ(r9W z_RRdwv-j=wEGNdC$epuIYgTgKQ8}k8$LLd+%CO_;xnsPQ{4>|2v^XC1=-%@EeVL}C zo7Tz`7DbZTwUI$#zt-`^3)J5a{Aj8pb$90dS5rP6d$0a-#nLusRX5iZc=uLa_|Ru@ zDDL6OO>G@^qwxfvE4vDVKvJo|^q zt}7}hx7>ShH++BBC06%qtIMU`-NQoNI$GQL9$uaDYE#6y@WQfN-*$3xZR|8Py0^^o z`OD|O8!tEP|Ml!tkA>Aj7wfI%GqevslXrRcdMC$~nCST)5SY z2PaQk7yK<=`N?Zr#Kkpo$J25>Q#p&2rWAb4@qDKHPHo+t|5d+|L~riW5XhV9zwm0^>os}TH|BI#-%dJaU&5>EHCz7XgV*OH8#aHEn)7#C zY69DVe5R1Fb!*OL@Af_V;%}n9$$^LUQh$E!{W-TW;^P6$vr*^ba=8z)CR*)s*l_Jt zV#@Qa3zc|d+D=X5J~bz@$?!O5^*%Swy!F?-!uKrOt!3Ha7Jul{yGu89qj?u*WY%`S zRcchsa?I>p>wGt^^6Nf{siuDpzPOV5=U6#Q@maMZ??$m2*LP*_7ssAkWqv~2mHbtYknWIw z`|tMCIp)`oo&B@aR^q+L$E2UfQi9x6cJ4gDDm8gW=ew*&5gyJj?lo-P{vIv8LqJ`chl(TZhhPO7tBS zIJ)7y=-N#Oi|pDKrYqg;JvR5jm9w16iUw17cWbq)vEK>1Tz+_Nhv?ao9mWjm{*Du8 zHV3oV&p+VnyiYXlrkhY2`z3F)TZz}S{-=EBvk}m+Ie*mH`Qz_;r(t+ zgt$|ehlNAFOOyXP_ILYQrWA(0YdW3#hRI^@72`LaMMiD)Pv103T-?TebwY(~Oh;nu zJij2N?cB2?dLOsX$Ui1|pEqNY>-Kol7%NeBiErmWwJG0{=@x94p7?9!t;;D6+uOgL zEK-cg6f1jry5}%M#MhdqD+)Yx{H0GVO0k`<8lmZOqUWQ$$K!VmiBHvL{aU9Lu|k(; z?VdmHN~}t>>XyV-iLU+JRj3%VZnb5KeK%XwcE6>mp*kFIEdH?PKGScUZ!XeyB<+#@ z!K)f~3pW0UD0Ny96Mkcx&)yY`=~fL3JGcdBz1Q1w-)_RA({pbA6*sUsuI0}zpci#z zvE$s|6Lr)Z)4gP$-dwi&igIf;IEHGdU zU6N3)vuVqo7=4$uZC1J#JN$I3b6>SC%m2Hcf5#rvjSHmwSoW@ptFzsm#k)T0&C|W? z&)@z2eXN$@##Zy*D9s>~Gp9JWY?zthettW{=k~~He3deC5tlDLk?%djx%-{InuDp6 zo!8N(gHL%9Cp|hNE-27>NJ#OVif5^6?Q)?H(OdqU(vuWDC41XUfQ$S00gD8~yl~OB z5YgValL0#t+RkRV96xa850|KYpWNDoTxLG8>-I=wet2SEUUf2@MS;7@zjJcN(O3On zcoR}$J$5`dtCc($Y!*B%zP|gIR5kD87na9G*F3u$u60%HN%|SPgAEHaMb{pAaw=`{ z5-IlW_c;FdJUAbIc6a;T39(1xOxus@vou_b=M8+|oX+TfSI;{1`74u-C?@Wli?0;4 zW`$X$UzgspUo?4HPS5Fsi@8E|v)!Z8eM9F|^6h#OavxO( zW+-odvs{SCW?WHkN;FdHrF)ZRb&VA!T;qZ`d!+FPI9Wnh!txAu`^iKRFD zIZ3sL2fur^RY|63zW@7MX0extKW}UHamDS03q5wkS)ZSH;aFMsgV28Uy~j7ND?G7M zaN^>iL$SP{vVTjT{OelYdE#udQ_$9%ynEj@WFGGeTGUqGd#U2py5^5Ns}r~9FHpS7 zdpy8g#^i45uBa2Qce`G?!}>SD{BwKCtOh6)fTvoPh5M}wnej!9lQHIJuhbSgMekT1=5}W?)a}; zY5)08#odjYLq7kCJS4d$Yr~T66CsOkXFl0=^9oyXjrOVE2hK#rEsi@askF!I&-aIm zbKL$HJdWo4|NPt1r@23#Puy-AY<=+4DYo9UoVVXnUwsST&6_{@z>$Pdr|9)9jm^6z z9f<$pp!<Cv@x};t?*u(y#3G`r|aqSdFEM#KYe!R-!x6zMW^0Z z)HTXpURHBKL^(O@=3oWvjhbI43;FRAPsll0m1=X@q6r7!i^_?7Enq+hb_$3)BA z|8uf6mdehn{>|6<;4w#Sz^UVXRyl`npJYCpop)k01zoc2pE%vv7X z_#uH?T<(nR&4zB)!i<|!r}pl7+HiE)h7Crx#~p9Kn>ryg(?jm(%c+~vop#5*VpR0` z#VdO7tFhicnS(NAA&C>KCHdLyW=2f8Gv|c$7c~j>%MX)|EL6E0u`|Eqk>0eOY3uJ- z771-R`fys_#UeqSBj4;5SmT=_=7>b-_HrE2y0?;L@#Gg#XXbvl$Thtiaa2oGu;}e9 z-Sv^1x%y(Qd_tmf-aHCYbiH}tz~!bliSN?24hg(uEB$%b=)-x2U0&`#&-S09#m|>pTQWYxzX~<~Fhgxx z?B^QEt!vjt$4-4yIK6ekvzMtRZomFlT@~AUy>0agZibIj^Cu@CcHCihQ>O3VxhqLF zw)W|96O(WGOrOjiDpA#|P}SWKceJDPzLy-V8_@p;nK`Z-48T+=y~`hMJ%``)yvILABpxKTvgnHbK7A9wGce&2U{ z+Qp)>dz^J?@^XHC&ugBQ%{X3r&3NxQyUlU$Waljo+Of-V>E3VGU6&r8qOt1QoB#9f zuKlsK@*T(BGo0dUelT0FNiqJZP?5v^*W5O0uTSHlV$;c&h3xS*y9ir!0NfeMM!X6kM76lLvfKW&ipvHE2MG%gDHzUvqaJ#>)bJX zT^yyH_|zy?sz03}@^nA*`>D@eE_ctkm&|FE>noEfIW24B2fy~Dn_Kj?<^^uKUGOqz zx87I2$(n*^k_+#ivDDS*^1erCTJ=PyE$gSg8G(HKbqo^j0&+ zN#`G~HaVfbhdnm;&5EO$1_ghzSG8AaCrphpQ~LgoQL*6H`c(yo=A|ZOPd)frbxp0} z&$$O#nf4sp-&A~Rwz`ya()MLM2U;1c4+Q%4DzH6^?QWmlerGhwqUB)|e;f7xPdRD#h9_X-K_lrld5x2oMWxTJd^7Fyo&Aoh zHl8|bmF~^j=KIW@bIPq6mt2Wi63ugU#6r*5OwK=-CGjV>ZVR8ap0YyE@dLB=MG4!^ zNpuk5nouov<8I6I#U*jYp@P5EO7=hB{4XQM<=dvUJofGPKHJ%vXT^QKHe1Xh??t!t zsvxy@+XF6bn0;X`7iY!Md8;1C{XFWj_V6vo2)8Jf%~QXhG&H*Q_lPuPoXvd-r)grT8!;LtOJk#BvomIcP(K}df zZmO@$-5JZC%PxtW=Mn3Ba0_dw!{)bgX-msdoXaljIm@ft&qSx= zyT?B5%P|L@tNU(?TlhL^Ymu6?e8%QSSq0DCIr?1I)v%j~M7D_iUD5rv+`0T!eREHm z(62;+nk^p=ZTqsW|IVxlZ)F9IWLeAo{N)y8?dH`!vTf^}N81-({rB|SiZC9x^k*uv~@^5aF-LThe6@S3;Ws_*GEy%c6v<{2O78SOVTiQm3; z>%JwMF0GF+zm_X^?x3Qz^wPKCUv4-pVwIN{$YxbPTvTDsP@Ym|+_y z8~pO&TQC0Y)BEznt?q^GS|-QrYWVz6KzPO?y#&QGa@*72uxRa)DZAkqCs=zW&;Ruu zChHmR7)q`F@8X^L`DThAhn-*JH)+0Y-G2)fS3mHb@~iXq?d`>i0n29^I@cWev4ACT)nlqyq%4bi7wmpC!DjA^%cAe6Y@dEb;eC(j(kh*2N;QGH8jdQw zyRQh^ZF0GGh-Yijewl>d-vZ=hekbVMR|_vVKpEz%wGEeSK#j29KMUsQVZSGC!8?v+X= zqfU{>LX}Q!LQ2O}KY4K)+fTk}5qq_=EvIny3FEZx+b(f8BLwyazi`;Y6Lo>%;?W74 z&)Oz)cGxF7pEaIhbJ$C+@BhNcq?1D7n-Y|cUi{b2Zu4|meakVBY#n)BOuyfk|!@WVj^&D7k?3K9| zB;w~_m%ZeGmyAT{^b?C(yPaD9-!w3paQ5(4TkbaRn9?0?%W4;Xe7ADSCsB8uEz31q z))#0v&z-A&Q)AZis+&uzUnzMn2s{R4a==bn53pf9h>i8mK z%cxt_wsBR~#=nlzjQdOsUOe|#(c#T|8sxS&VS0#?f$O?czphz5d@ePW%koV}9M8$P zvj<$}i+#ME>7o#O^Nh>$m>gDb9?`O%2|7BSXSbTo*)F+HuJN!{&!&SBwo?PHJx!63 zyk2nk)EB8k-T{WJdWBXCIW9R@M;O?wUnT7r`)gDBR)Hh)KH08qdvdIoZ(`MA5t9c~ z@)xXWxU4e{_=3|8+;!e_qL`v+`|`YyZ>N5_=g~BLvzcd7|#N zo_Ln*bfMRytS);w=^0gziu0JVGtA4Di*{*k8clD}oX`5F)4hr>R$&VI~ zU3NK=|ouMVbN26;Wf?3u-^{``bM>oL zX)UK7T@f-B`tjD{)WZ3m>TbI>oQt%PVwBq~oRRCehGE|=k>#%h@(lh=EAYG5nXcWp zxO=AM%PTe~Pd(>$Idej|ljZBgu9GuYtG6p{ULgH{;H2a8*$OkC2`I)-xyxWwE;p-=d0O3z9_gFs6#gl5 z7M!lGT30)f_sWm;|2?Ms+doNT^lm9&pGMX#>jwgGqQEklXEb+PfY8W0T z#9UsxPJg1|f+eo2KYYF;6tO+cAh}rUu;yR+L&A{{S`TXa*PdN@UidtGKD%plRlC`#Qnh=c@ZtAHC-GICg)N-ObsTQZqIf*d3{Vwe-!i zf6w->-Thy1PMp5Q*?SdtlfnPo3u zwv9V(v-y1Gs=XVp)VHkvFSsvGxn}RuCtr(IR#_YT$`@Mg_b=e!sy&;;I)$bt9^T`T zBd5FYySsN1bNZqe=4aO5w*9j|ID-4c+o?ylN|z{YatOXJb=PYb#}!xS$c*Wk+1^hV zuC6&W)mx$EwtzvN-syAad9Cfz+1Tw49p>_VwC12#`kg|x86PCH-X76Gaz# zuYBZAKHnIsoNjF!K3k=AlE^LsEBOHtHrzYD#C_yfE#k%BEW$>!&K(wfo9! zn&+|J^owxvHJ+DSll=aCPMN;t=!e;P=5}+npX~g+uU?x`UEMJ5ou$ZniGAzWwf@N6 z@zKm?edTnSDfKEGc3ar`%sVtJCmYYyUiI_XwMUWn-%az|6;-#p{6d-n=X_3u~06NSV7PAU@#4bpBZ*02 z%$wzGcyvm+mvPDc+;q`cnD6>VuG_2Qoa@&d{x(amoIm>@S5?L@p^M8hBd^ai(;w-bRf9BoF zShx3kcAb9ct?$xtEZZ$lPMLG`<};&i@sIo5_{;vCulALS(at`kVJLBG{lY(8Ps8t| z^qbwjHuarXHp}+inKvI?{Am&WZ1ExS?K<){4?T|`yXGlbeEmwb#M1@!YbUWAK6mQL zT2Q}sweGqr$y-8yJbz^_SGD5rvc7+wwRb)!eVe)WkD}zecPmc#Nc@6=97I|&^+UyrJu_D9_YW~DzVW{ zcyMrG+?k-)r#j~U4O$hs-R)|K*TXwk&10Isr%k_oGRWNj^3?rh4o*|QzLvJTuXy0c zf%i9~s-#vd{Ib>I#LZ>r*nXD{h! zj=~Dk8DDh1)k++AzAW+Jy3dC^+!bP^{0dZ`8^r%J;q@u=C>Q=?tX&n8{w6C)S&*f= z``vW4>}Ko4O=%q`Gaf%zToy3z&q`Glzo*-O-P2v#yo1+k;rp<+XO5kWKE1eDmYI)z z;+-p&yp{2DvsyGyTu^4wSkS(2d3*V8&-9w#>St<7*Uj3kwz~3hPU5R>&dc%A#mBUt zFFWi0b?>w=r^UIMyxV73R!j|C|KY)Uo=J(*Hmr01z{SXO$>s;s9-%j%75v+b{7X9@ zOk*#1Dg5K-Y;*9hYR62a?y$^zV(hI;mwFz1Try8x@%^$6jtMn}<~Movl^wT8(Vb~z zdFYP9ycWk3D^Gk;o_u_n{OaXZk(W4JW-N`6JEW*|S>SWY`tPOUit{2SIIldL@IP-l zN2lf6+cwX9Dy`OTUzs{X-i3MA(tS(5r|+B}rw zygf(ycRv#;`1dGs^X(5e9JX}`EaqbG<=@H>>d$-dp`fmmijs;A3xaDDo!0UP1&-QCid&~U(fO(1b z+WG&I&du0a=O=H)C{e|HY>IrgeD;s~Z?}A!^o8&2b+tETz7k?nOZc|yoOve4dOzpj z_5P%pd!Ej`vGwNOWc&Q@JC`12TedWN;m@^U^I?B{{~_n+^Y&;c>Tw-C&9l^o$LxPm`R1l#_0CB-pEGs;sEUOCXEjaM zu6Fmoa63cjf$g0YE5DxOc^QAF>Uu@QTF;W!xI5N&!mit{dNcX8)!Hws|4RQVz4f|m zb*b$gt7!A9sXzOc-d@EpGg>7!{5Xs7{%4y6{zNa6$<&nTVw&cdvMNW<$K-Q z99&zLrQLnEb@{R%C;4+*UN~$&y6fWHy6yT?cQCk_mo15sPMyS}bJC4H@6_8b_nT~g za+x^IG-sHyLG(u5+S^UyzoZiXh`J}Vdc4*@sC^`V{mzafLB(6WW;UIzQjOI<{>qE_ zskG{I&cf8HgAT!!`PrObYje4OH-0K~|FQV}(J#sRg@@Gcwwm|H+ud%nTAO^+Np!Qw zf}c`Tv=&Y2KHz%a=hM;dj5B&4_W!pw{qFMd>ACNvg6x)@7W(79;?3n&&zt|mQyMn@Q>e3 zJ9&%$q4e30_i{4+<3G^Qb-}Dj|M$XkXILNF9lm(cLQTqPQD>iL!IK`dZ>pbG$rsIx z7V){pT)ShJLH4xsvptVVSw(Wr%3fuw82EDG=L1qr)l-zc!{6Gq7{3&m)oi-A>(C5N zm6PGcH~f6W<0GfGiUvH(a*b|Y_A+t9vGZSV{R{bfCy4h$SwQv0qyOG)*+HbLc~(w29# zj~{2QDs__Y?+-pz=p^6&vRS|K&7KE~Wkfpy-E_Z6MQ5acW9rc`=)O5e^P{JgM9<`e zyU(UhUaQ{N@LVnB`0**P_ zy+vq6`t5}N(hcg{C3OzZmVQ+{qa^g0=H>i$rMchTw6Y5x`7-l=NxA!ty{q=y?Dkbz z(*$giv#(xR+m@hpH|^d`VX?=*3U@M8Jz4i%!ezP8^>+*J?D@JqW4n=a>jC*YL0)+* z@oc|mmA{^SA?ru3pk@EmpAsT58+)&t+RrFY?GZazA#=6s&0ZzV{aX**^}Ms+H_?6i z<%6ticznvUCsuEEQg#3Qv*PVlp?w~|-^i41G7>UXFfNo*ymDj$>*-X{uv4ZRKbEVn z7W})QzIgIcwo^AYvK%rC`{5!wEAzaM^OY$xbJE(3g_R$@7V-AFU3%)5>lL}foLeJX zoR?cZkJ+<&c~b3ZMIDRnS%!=59he;azDMksW8D4;jhEJke(av8(!12>;@5DW^PJ4h zZjqI{_3lkGU+wSsw(EOHC=36aBP^*uzqutCvRx9n)v_z3?6cnmtF0H}!=La^p1LpM z=cjg2j<%Dld>2n^F;!o4+a$nq#+jMw2R|D}&Y$law(79T$AgLsXJ%jAy6Nb(SqGXf zeKmJKlp3{OzV}Ds)=i$PuP$CasXvq3_ByY8!PO01f%CX*Y!>?Goc80di}2fa>O-Mr zq)F+W79pOC8*aO*xXn#j{oSkc+K!F!ISU+4D6K8--f;9=*|n4e*0?0i^CA!VjKYfi z^`$F1w?#AEvzoFtwQZ@9srA0Km5+P(+-8}*&yS^eLW@s(z~j%kE^^n_=uPeyDqmpK zE}Xx%wMFA>cgCDznF#l&yJ6fX#rWe~1QL9Y_BTI&=};qW(3vT#onRlEDim{mSNFD~ ztQ<`#qQ1`_KXLrjLNaqsnavQ|B|@iQ$aCKVs6Vfj+*R#kkgJnLiV@_5~2*#VC} z3f$Rcx%}<7r*pRb`^K~SSxqa?>d$P)cN{r3&(7@KdwInqXvfO~eS!O;Z+SI7KIMHqFI;^6mRTCRroRgjo_XPoMw-;@GiOR{pKso? zIo0y`$)ir!Zgp_2`nz!(|Gh`o?wGzm^`vC=?Ahfk`qQ6vIUkkZDS7r*a+Ak|cRQkz z_nZ|~5ILUI!oJ{+DRj*zV^k!r10flR%*an*dxxmOv;%*?P2S>Q{yM$1`Mtb-<*zP=5)o55mWPgWcI{}is85%X znNpz5&b+@Vj7`i`aDH)4$fV|#liwfo%lCi#?WVWW`*r&cEow2mUH?b`QI`lzliINrqbV>*S9&ZOtjDW^#4!A`*+vP+!pb%_sPiL_|ShbbxNOV zh!p#!*KA)C#bOUt+?CoZq0glt(WhB`#o@!cW5;GTZr>xNq%7mgwpMhRK;SmB_cKo) zk(SA`w+Vjt-DzTw;e55FKI!jm7w6Akwl<}-^8B?rMn{7eobG2%W^^SJyGY+Nit<3ZR#W){!IK)w>o3h@5hnnV=iT@@K{;%;HBZ4GkBxKf}j7LebVXLED!oR3u= zry?fW@6Nh*fBR;)$MP%YY4O$?>|}h@7IX9im;3(tQD$VQ@37OE8KNwUg!2NlO@-bWH|O%uzeE0w#}*beq`bL z6>Gy7?=q=1ho1{O{HtZFqFFE7_qdM5Mod?}DEYF@eW2d^at?2%VCHYdX9Cd?N|*i= z`6XD%_Gq5oy5TDu!=K$u67km@+duNk@Yn23du+&P$F#RNaoszn-E#Ur)EQzqpR8J% z&$h#8$IqwC^{uO4&*qIf?0CA}IyfaKL~!bQfsDmbiY@x_{c9)d8=l@+cXrKton4~O zg(_Zl#qxcRwXk>KiTQl+W{hWO30Kw2RG0LA7uRaDwF@S#3QcqV-cxnTQ@^)3ZQks} zyrfQD^*3^bFP*;@L{0nrspY~);m`8|RceH1?o-?^|LE_AKl9>`|FJsuddH_*YfqO5 z^PV_0B{l!+n(ggr(Jz9HXRKoSuwhPShB5D7pF+#v9OI+2RxWGU&}e^jY30*ZB7eC4e=29IliZl`m|NK0a`gtuZ$*ougTCB)@T!3? zo;Rm1MLr^egL_FzoZNz6&nNV4c{ok^f!V2@Qwq`_)-+_9F62G7?iEk|X;u13pEH?WD`uY4_>-&d z^>2m++s;=$ow__AF5Wcop4JrS?n7DA_vbIN)0po3R?v=n*NVB%_S=Y-ng_lM>q)z1 zbh0hhV&G{)-Vrs%_ z=AtM@l|qJ$TEi0kYfr^DR)5_0hpC|a*w=1nk!!k}rZXJ9{m!}V{cp)j4wGXTf3rMV z?)UuM|C#^hYyRES?6LV#q1HyR#U&=qdp&>r^*cP%mHW;i?vCd46NMRlDIZ)tZab97 zM0Oq5^wTWLI#qW-fSO!F+9R58HVE(&YHhc0-9-?W@C6 z*UMX9>`D+ST_bALrM)EZqtWxsb3H6p8#cE%&f-{H^O4P*d70Aujq&F@lB2borZXRS z<-PRJ&Gfblvpu&|J=POdSg-S)MSbyxlnk~9TQ+gcnlza)$2<1hzmDwLZ{>=mrzQ8_ z-LN+ykU^#)^TX1w9ZFwCmG#{@(&W|37z_l24$P0e+G4Z);k*8p;-6+0A52@5^ySsj z$J6~ES|5F}W6HAcVbiDe9u#`MsnmDQlOp!*WoH|My|rgmw*JeC&RDo{=3AxM$n8;O zQ+KJhim-h-`Nl}`L}ZXR%W0EqnM!r>3z|NKuQSy(|I72L;Lf_>X^S75|IlA2@Pt<( z;G3`60_mhF-E6UIx2#-0cSo<~?>&*fkNn*6x93isS5x$vE-e*KnNtk=Id`!-Xg4RE zURL|-^y^=_=1IYfFkcT8$buUb~O>RF)Ib+&!EDZ<8cW>h?q$yus>*lxmspx!vy2ZvUhrD{?l#;1`)3Helh5C?*f(#> zy0h#G0mbwG*;TofymH?1M9078M#idNKX*NwwEpY&o9VvuZLfWKxPIBA?$g(eRSlNS zRrgzS)Mlcu-PNNNA(nx!V>|xm*vP)-jQU#||B-RR);8UMw7q`eOy3f2GQVHJY2E(n zf|QE1H?P(2?|hb@HP2p8vHZCC`<^o&{x=7Pgg^7UztGz1X)5o(Z$F-xaw{~ee_Ofi z-p;E|2SQSfY0myI+wj{lMhX4SPS(lUdb$0k1*BzqAUEk#`w%D^;y~Og{4l_kl^X6aMglddSc0~$@Ssd~0QPYb( zxzy}Of&I?<`77PNUubnszB$v&f5+d>%EdYVQr9ut2@Ke?IjzOLuPHRdD93qv)dj2sy*7Q$tv-4&91`p#?Qa{=U2y+cCXHU zv-0)Ahtqr%)442#KOKqw^rm=T?MdbG^}(}pMB6NzUoXg04(nCDC(5(F^OVmo?nEgo z?VPgwc|Pf<7w*VfuynHa`c=QIm;Wg3USlae;li=26^ld*0=dnsbHV^-d6$4|FPTZ=v>9}d%J z;oV)AHa%5T;_HG&@%h(hPrtq{!)1HdRNUFIBBW*DUow( zXO=!bU$N-a`e~{M^_2QqbRVyI)Z*^mWX^pkmtFgi((bCg*ALyixaRax55pZ_I`1vC z_LVX2ZM$kKmjCy_j3Ci~+=Cqty3Y2A-u0QjG$efK7 zx@{NEi;3O5k*#yVKK3B{Q|`Y}Cx3I#UF?4Ep~A&wdp0-im#=E)^grSpuMoZ2tdFCv z!8`S6(PS&3rYjvqR^blWH&2Nf_qW~?oYr_`&&i|Bsq_3U6;9z)y&dS!u|*>4U}bK* zjNkL*qOuA<`SOp2`P@IB$X72&)ZKgRjjYw`So^n)YtL%4s=MEGu{kyUfD|wDjEmc9 z?py1d?6zk&+F5D&e(I@jHgiuY83dkRzBjYG-S4L0J=4>Yu?bsj*O`hPTo)j0`Z{l- z(9+G1as}1^5Q;%xzKJ3g8P~f{( zw|uoqZ*R+zt(8x<2%Y=Iap%v@lF#yP7Wr<{2?jhmD_Bac;<~#P?M<4j*PQuTdF!Cv z+B$Bh-}WWn@|SG>->Z@4A!XN|vTn+5)3Y&}-}TjI{r6e*^SiQ9^?vJx8pgX@Ikzwt zmFxK>yK%wdfSSQ-IQ6_vu?9YZsmjn$BM7^Eo%z+$)WY~ zQ6Q_noc(f5yV`Hu?o*tq9c~)=id9aZBN8BHC&YPK`sA~nH_Mk7^{U_Fe%dnGap{#A zv-wx4ByJ72F^g@iTgqWqTIg-qn!}tvrSbZ<(-T{sEY3D-;)(tIIazU%Q*j%_YA?%K4nczA;xmK^MCnR|;xjt$Pof7_PeqwCc!d=Ywrp*1E?|13h z8Idm=^Nk}LB$(UWMe3%_`}VnPpPE*I&=vhF$CmCtqbEG$&YhY4i(e}3zx*S{_N`Xr z&pETIn9qHkoFRDCR`khA&rT^0o2|*aRl@W&ZM#d7FL!q+H%{H6csaIf^}4g+Cl}3A z=M z^!~V>PX~vGBCEAl$nIRPf*Yk9r>S(BDOa5?pSpAN-iFR?0zGT&5{`@ewtsaz?B`g^ z(0zAz>@AlsoT7ZMwzKm7n!igdXXE=LXB7jCtSz3Ze@yOq^espHe8UWpa}BOfn@kwp zIWpTlAF%rznKAox-!l7+_07pY*FV|T+4!~cfME8FGzG1O(zE`P zdpz>jJYwhYxiQJ*%j{!1T>6h*|2$y5Pfl&QTj=2p9$a02W^;)O#SkBCnd;CnUlTPNapPq(Np3R z|C?6lua8>zE&QyuQ^r}rL|N&c1LimM@9BToa$(M_^>1WqtK(kpHdtZ#HJh#TsMo?o z#WnV_38q&9{9iKp+6Vb8|GaGX=gZEkM6IH({$P-2IV{{!v*nfVft7ucEVXLoSG;e@ ze=3)reMfc*$N#y1DtbGAF%u^P$C&pO<^gKI?TOd~?nRwycdm)6t^7;Nqq{Tpp;{)p-MhPQ5O)6UAdm;C$hwY>hJbZ&y)F&CkjZ)Z|7^u)i| z+v+;KT|V;zuY~AK#w3y0Cjsl)QlBmmzqo%#!HQ+QJXL7|vm(!*aVo4{$+DM6@b0X0 zN7iXPj<|o!Sw^wFXz~sJ4WIY;xQJ<_eP>?w<-XeIRyW~ulh%J?c-Z=qX<3%lrLcVw zd`CX1?%Z*q;_&C(g>#Fy&5eAvZ@sJK*;3v&nR>sksfsP%nI_9wzJJbCVeiQ9sXEWU zUG`?}`l=`X;j%ZYOvsea)hB1g9u~iOb@3Oa{uQy8UrS2s*C-@CKk((uL-*hZ|M|;( zGv3Yo8zl8qanp+hQ`{yUt&8`5?=1c;5WAcaj%N*4?$VuuwSl z=-=OSihu9szB#x%+W5s?SKg?dw^L0dOIx3%+|ZaM*5JdqNJ@0(ytH!}3r@UfHEmK! zm=dS6@Bhn}*Q^2$hfVAMyf0Gb36F-Fg^tYKJ73>SJh;){*sS!-3yUv{cW1j4oO>>N zN8Bmc*_xqoPc+Y;WA#tnyhFyd3wXa#k{4} zGp%OvtGZ*|s<)*YPg*yWx2v2^ljP6gd>Wa5?{*KX#h2)FZr&vYhs8vX9p55m`1|KW z8-~3?Cxx%IR4=bBP`)!S+M1)MOSK^RVr~1%T~brb3UaSMb(fu4FoS)On#HMRHX)|0 zrrQlcrahA+^>%O5*&V!W&MW_!eG^u-`!*a;UA(~GEON;qtGzi9ceTH+FE`w_=HJJe z#^U=Vx;2I71wR!0*QMQmEL+U>OvlUB50uV+aux78B41U0vTufAa`gkN^8GDq-DV4a zFw@!lcIy3KdX))GkK7fe9X@l``z43Q%49ar=yFnsTpn=j4pQ~SfGb)o38!9qtax$e)7z~J>Um)BpNb!gGD4J$NrEWSN2 zYY&S4>-n(7ZTGE*vu4aZv*Bu#oNu78_GHOzv8r=pBQLyNGiRS;^`FltZZntdIJzdM=?g0;=zg`2pwc4sR@2G-8uTDH!5 z`2i{0eQ8hSw<_!~%+Ku>UwVzl&Ne;!<9n$bOZG2JJAW-xkJ})3QL3wZjr-zFo4#J* zS*|vZO`35{L(R;*Qwb|AS~Yt6{bMc^PVktw@QLK1sKW4h5uXkmuHB>E&mN|`WDfAC>ct{#cl&EED*_zkbyoxexzt-mQCBbntd| zOTTr?etW9p``>Hd{$BgGeOuYvJ9%5eX2!4AU9WokoLGL! zx!r%3K2?vKcJ6fP&pjgY2 znD^%t`~FnlnDRZt=Y#GNXGz^w?;V{r>K#9G&K!Muwy^6*c3@atc=AmTH*@=y zqIsw4k8I@<{cpkhs^;axVD>I)!95z*YxO2*uW2ut)3@{8x6PI9<&v*mFWV+q#%)-v zv{T4q`Nbpr#+eV_KZx4+RRf>%~)<#I0BT z>5N~sJGC@t=_Gl*JwoEyF~4p{KI>hwNoC#~j;Gh=hp&@i&q=$!Rj=VtlabGU&9Fl! zdL$*6Zj?2<)!6oV(cTkn&ze}1S?{m$ck%y|c69zz4VTrmo9~&gX5MUP&>Vl}!TT>W zFNd!SOgPf}Dl6|=@v_hh`7?TVzdOI|(ds>RTeoZOb*NjxDxabA;)`HSN|Id#3nRCf zrS1A9-;c8xyRY+8b~$ut>UWu3sQ@$gr5BPCp8W8wD))bE9_ck*?Pqb`_C>ju@_YYp z@tnV4mD#S+IZp*^?^$^FUbDLIzOWlFcrZ!+!)<8d~=V}6)<$NCOu;rFwDI3#)i)hy zRpa5+z^UGA^R=G3RIYnDFU*N|+VeB}7Fc<^MzBs?ul-cg{OQiCHzsTgh|s#?f9d1d z)NkvvJyzY&C@%1|juYH}=93VJ`|Tdw z_~Pr})P2m8KXLKSXYpTi?k|(S@nwUF9BqnE?*_S;mQVZ2CH@}ZAyQmrC?35$xx*|dH(@EAg#otzmM#dX9D!feDf8TWP z`rX&0xS2FRMDy`2RfrH?yhve2+0tJ*O{c@Tf0VFHV3T>cwxnp2JA3Awo$F2-G~H=` zG5>qQ%@3u?4%2H{=6YQHdQ9|MM9!w^l6!FO`U`fMz=tY7I~ z#9P-%KU?EQTcCJV1LHha!tcw1-H_V0^@ z7Ecq{I%l2gv_nUJwmi*!C$X_L|HiyEy-Lh}x2~&%*&TSxZc(sl-@;{EuWb3274<$l zXr-Fi*^du9*S!;8?!`1oVoI8TuGz|>17^z_c3qseMx^m|$rkl&&k5Rmn^(UUo>L#r z%V>}ob6wryotqi2!}=>ub2IhQ#e2+s^snqTQ{dn3oNg77_uz@ewGXG4Kij?h*^kTz zJ9D;|-!WS&xTEmFe~~>Y{}S|H%Y2=;0!&_e$Pw zwmfq7_`e(9BUPGMSPHE!xxDb2ptkEJuXx?%`8SzoT-~X|8Txk{0VWl>Wm%S##o>kRzCv2=+mi*mIp{IS#^hbG7`*%mRr84iS`19%O=E=|f zo4qCO1~dIDjOh(8-ga_1?_M1b86k+ENZ)FFjnqAwsG}`a(4Uo3=$JKeOPLB z%l}$`oRRj*PeF|D#kra(--=(xTx9-wBI1e^Zve;91o0PLQ+LIRB>m+-eu?AAyqC{Q zHb}g!)xY%jX6xlsJsA^wcO1OB+ge_yG$X*Fe)9>rLv>|Mv6LlkEMb zv+sBFiC+2L^PyFkA-^E|SH%L>u!Hd&kCQTkp2hGyUhzDfWBr7S6?R=$4(i8PpZs~y zxh}!<`r>}I2{kTOCDwE2S!KRhIjeI;?Zt-W9DN^4ww@3=alEbYc2$eO_ttH~4|(T$ zupNHF|E4L&`qox(4&=f&1N(M-5nR_1VTzOVSroI7RLORgMFjo1@^h5z+cNp1%A zQwED|@?9GHv+G`RdCst}V-@|#o$97y0;7ca!0shrHPttl`xQB`@xOups-z{|AQ?#rb0oue-Ku?)sOXE}Oo+r)c-C zFlhRM347Ol@HjpHF7H&6>ox}S3XZxo_mpodynXe`(BFP0x7rQOWgjKW?|R*7(v_dJb&31B_ZC5X z@(bhcC@npq^Y~7`Q7~`Yr46r^hw)$jd2RCN^;hKPzn>(ZX7+}2;cpU3wTe>wvX2XmF0Me^t3KQEkQSDTza;XR@C z|Iw7YN1r}6exvQ)&hUQ2wKkJS&zFQ>t%;qTf1qqW!@9JNc$svkI#Cmgq`+mYKhFx9 z7AeiRbt03wZgc(Bug)`jt)3PZu6_A4&>(8Xw6aJU(+_VOEu7r_wnSE|ih5@#hn(3c zx8&K>aO0$HvAkWgelBwU-F{s6c0}8`CgX)ZPsD_OuuYw}&1bu?T+`H6i?=0HGyW*& zoP0dXHsaITRXR66&SshW(3FGegz5F{YOy)d+4;L>ZN2wmcAlY0(|_-pg=$|Xc~?&m zPMQDloM==K-~I<4ejhhC7as{`|IHHNTo;rZ)cNGExRs6~hEPrub_T3t5ovX6HN~fPN zTA#LZN8a!EYHCyBP4s1I=cPBrzj@8=r*%J$<>7@R!V{#|?J4i8<*qc`_wD@Dx6gFf zXkB$Y@$P5Ll`ElVcV~8dc5YjCewR!|)tg(7c4Y(#UvJX+vO!~KUW!0jy4kn2DZi5a zHQc__Wru6)BM~h`$X4YC99$ZZ7pt79;k=)U;MU2CgFMRr!M8t zi+A_&H95QXimzB0C^IkE|CXtE{f^+LW+i9c=1iFQ@rV23y}N(+`idV9ubZc>->)9+ zuKr5OIY9rJ-ku5bFTPxBH(T#Z#MiAMM;%NzyequCb-)bN>4uxqf}Y<_DH6v))DZd3Ba2{+c7ivuZhqu!2|bvU8@3(i7`+Lmn9} zoa|^e`+e44Fta9e8FaM?UbpPU8e_r$MyqvRFvrNlp$u%>hr8n$D z${Oe7USd_V`L-_a-Jz__+^b*j+E5f5@p56`=8k8%|M%>4T64hC+F$9?f}PJUG=APt zu{A&b?6sm*JX=3F2L4zO^kacWO@N+E_QS)AJ|r&vkQn%5gNBa!{DMnL2IrN$^RH*! zE4#+KWX6rA(z7?c_f~!UbCcgco^`gK+siuN;6F?Xaq*>RcSQ?5<$iHG{P6yBPo`)u z&#`=ZTJtfhv(kad%4{&%;si>1Ie{HpRW^1$U z4&A<$OEG%wtEdaT|3v*CuTJ5Zt{klvRH9U3W%*2xUA@sbUQhB#&=iHmybIUVGlf2{ zn#6ae+N;_>^S$O<+h_9+e^Q)N8TC;`KiBI>*tZ>DuT-U4_}yD>(VsdsW6fUO=A$k9 z<4?~v-5*&Vojs3DOVF!xg7=rG)wQ1S-d3lZUcHXXKKrtz`l5GS$ce)Y)2*^D^e?h8 z<`tMEz}vcP-}{}9l#VnuTIX6Z+}^^HQ4=eWV9XR2{qVNmTpgaPH+gnuF>!2@xR!Y@ zXwLP^=XR`FAvT>scs_6KY_)|E<-L1z);d&v>iK@??6Sz~UQZ& zA`A=+91I{U)E}+dG>wsgVI~s;g99m61SMwXCFPgvx+E558#xtare~Ds<&-AkvpIKy zWB+9Xf!6mwMg476Lm!#AKE1GtgE96XV+&WcTi@d&*VM{Vtd~5zZtT|@(rJ6+(w_Hc zKUZ`;`aQkhe*XID%Ijig-#Vx9p>wx5OEa7qpOx^ykZU46)ESPC-Qy?bEj6z z$B1cOd~0Iod^@jutL*q*)#kN953Ac z`??pbeQ5jCfq#pcN!5g7lV2=8dF+|A*O}#8d-`=kR$ZR;aK#;Yz8gso91Yj|dQH>) z_9gO=Y@$$?taZw5=dJ2V(>Y#+ADlH~@#*k?|HU$9=-%6NH&xxMKh4psDncW%`t`eY zZ~BhCyx-?mJGr*%^u{LwH?6jt@ZP^V-`!u~|`rPxOZ3~t( zP8Lb=%Z|74{3H%aa)|U0IVJo~DkB3!G7|%XD=F#0r6{pHy(lxqzo;Z5KRrJ$F(=+L zFD12tP@-s^aIx#Qfq?7%zoO#ystU&oGn_JC?bCU)PbXFJExX3G8)C0L(p1*It*c$? z84sLo-(`ykRhMaI$XzDtb!Zd?8L_vI)5e)+7=T{?8>^=mR8 z-QFZM-HrXJw)vpuw3>H&_chQEU5W z)`}LNIXY?GvTJEP|8ky({(E1#u6W{k52l?zG_(qTD11|juTy8Acz@dZP`zy*-+Zes z?C9IoTDvy;eB&h^HRfA8jxN2|wQq$BYpU|DLzag$4_$dQS2^#E-O&~4Qem4TTsGTH z3e^12{-9{>(fCDI^?%u)6uIe-8plbYHR%nE3=GGa7#M6wiDUPi#NuN2qRbSx%$$%uYH!Jkiy){?vtXbvt(yoD-xyLK#$^548FRlGH-O9Nd zmvF53T+Q*aX$SMBTyx4_(c0(M&SvyuXqy<_ZO`E;haM zn|=3k{*8rB%I+24+9yi=aOKtNR&xnh9b%2s zXI*)6*HQoFtBz}@rFJ$G-Z&l?o=6>k4Xi8}UrKH}ckWnl*_}^EL}%ZBs=Xm&#^26=rV%DbO{GJlYky2CM~(H52C>gM znHU&uF*7h&lM?Geskw;-p1FzXsYXHWPJ|*oH^{qxwt>LD&)ROQv|5kt*>vmlvbPIY z`|4fI+In-|A{ic@1ks!nAI{!S_pSNPExxPN_~xhF=d&FOH*D-|?QIWeo9$^0OGyyf zvu?lP30D2XF*8naHP9n`8}#%(~)4AKlR0etE;Z;VYCvH60{1P(U=``XhqeD9W1?;rI(c6 z@-`V9NR`uk&DeX&)$mr7ez8}E7EAN4mky%KPyhPKz9w+dGt)g^GJQAKiA$d1TRSJX zJo=5+nZ{>ZyQZGqP$-$O^u!G5g-?X)7QTDIz^z^S@0?Bx?@GJfZ+Q+2OxwhtX&z`R zxa-C1Ol@hC4~Mc%OiuP}JC|8=W~0C)A&t&`&r?^0?P}I9uwXcHX0Q9RgHJ7W-o5|N ze`68zeP%wJxYzFeze0O+r)`*V)cwOAr_2*8CK>!NNKKsJu+HP^Ld(#!$O#)bZ>R0f z-L!kBPM&_bwY<%gpI5&oReJqAcfBp)W8{-c=H{*tRjFUTzUwy%?=O7jU#G0NQI*B) z&B^XFI-BNCc*wT#@jSa(Q+4Lr1kd~X=Jv|3Pj7YEUfXOdU0eThXK1D;6YuKL5cSemAzh zgz2gG?NL+TO&7yvc4h{K5;g_~D^gNlKxVR0W^sOQYDrOMGNHt`Hsoa99Rr@dzqKn~ z`y4-=6Kil;gtbXU;{u!GwBQNNx~I2A-8NFOlvDTEzjw)#$m+F<93uCHJ#7Q|nr6R$ z{+)ljxItD@szcgi(K8QsPZKrwGN_o>w)qHm(~|b+gIy6z3nGtLhBur$G$T#am3950 zHQ`RuD?d#*spa)}o!^ud6U7zz^;Shp(Y7e4U+lZ~_C$khDbFs(sXngPCa+%`Y_m+$LSmg(@2wk0uYP5Y`8aF!j+WVGnt@B?n?Bx} zt90zmlPj$LjIN7ir-vNA8^9dn#UmrF_}bK_c)gGL`|~c| zzy~WzSY&Iz+NgVLiu%0VvLYrrF-ckRp;?sB=KDJrO;MSkzNN*uqIT}DhU7AX6Q7?| zKiGHurlD02^PxNKKMi*s_{e{-_h{aq@Fwe{iU;RCIy-N(@JdYv|KBsiShx2Uv(2~3 zSKiFCHuJ~9*X+V`Z+&1pyYxE$wL8@}e|kKZ{_fylyyv`>wRf0CiSQH~V}mHAd@dLw$=qtWBNz@HDgPX0*&D;xKQ z`1B?TZzyyqXSk8=kjZ%~;A+@fhGd>^(;OU6zHFHrQM6zAMyINuOxE>nnMc~DFYdkH zA1m}GMp{exp1e*=)b4L>b^&$o&vF3ce{$!f6Uu-GcdY}jtWu}!%FzBZ@+4o>V(-J!3o;WY^t?R8cjp0b&#v|!ZG#z?{oK0l zDS2?mJk5Snf&_ z*ZPhETdEW$&sU7A^;p-W;Qi;1@`QWG?lSYd5aw?8+O@bWV3M>bYvikmE1fTGo%i_6 zqL_{o?E780`S-Ya&%KcKV2Z)Bhzm=fFAx>dy1dm))^pz;h9f!u-bXSVzwcdD`t^UC z_PMj4kKMVm|JwJGcWbilq;Ymf?rB%hc(Fn%2{O zgEv`6E?M4vI+lfT)t}I>8ZTq#y|fb6v76A8kPsla+QoZ*?_1uoPx@^amzeLmBb)H@ zOqH(C;&#W>SyS3OXQ-JJuSt(;dF(1>DB(9lkI!Br%*gPqX2rMN`RdunQ?=)BM+No# z9=_D9Ic8mPI5*7qTyN6SBq!N7+x{w^IUJafQjp`Xct$3u$WcbQ!ugA&jHTYQ3CCD_ zr>qGKblLZ({3+um941bivgrR_XRo}iyCYQ?lMaa4_J6)No4&1k zS2i@BkNGF$%2Tv9YsbTFK?T~Ygwro@20L|z8Yl6tT6XAT&DzR;b^NVCtgT#YbC?fi z-#Zx|b%M#XdHPH-jfbY&j){pybL8cehP>Z#rfmYF?SsRehw3}@Po+If+T3XGebH%g z=)y|gk~5}CTeQq&uS*h&ViD48{m0>=V#r?y3d-X<_zC;UmY0BQ& zeA0K)l~R(=I(|L)>2Ac7`7z2>YYwF9+`JSYziGKn(#8BY;oD^1u^p;VEDAWTVt8v& zv8Fh~&Z#R`H>w?LH+w3|^(wSKazYymb4J*P=FiWsxdfYB^RQFBa%YNo;bv?C5`L79{G|L-i8>hvkgsjob#bm9t2?UdIqf;SakZ*=&nB5;g$8gS>LmySt-c?$}e_ZkYU3o`UHNUI-_2P>wH~e1Y@-bnqJNv_{%n468 z+&P2IU7oL>r!Dny^OW5N!LPC=s(y|?l>FuOah}%OwLgNVy=^b=-IX$V<&Dqx5AvLy zGWS5F%xbaYdp53f|K#=|?q2zY`q~n+Jw>(i%-+}kyD6hK)%yNR`OkGf&!nEOHh6pX z&)y$sHPq>kvm$aB85qi#NX&bnK?hKO)RX82;)L^Ew;g!e-&b-aMiksAl#$*vCGD>F z>32(~w3f&xJev4c@!W}wv}cwZ{n#dyLR}%l}&c1bxe9V=FKw5I%a!DWZ^YFiQcc1 zs(Kg?vRyd$@#eP3bYZspsBCE60wnm{^bHN_<`$=X66DB^_Yk62aumACm%-A~u+bipH zKm442b;Yh#M-6URxwz%mC+@np{>750l~Zj)ukjknWO@mI{?02rRY$o~Yu=SG(WmNL zgFSt1UB%Q^+-jfXRTiQYSSYnW@o4MH9~e=`tJmuD129C zw@#ezmsRJpd{2!19W&9>TZQM|JpG%$>$pkmF_%fAua9p3v*gSr`)6P6uZaK6M=f7} zD1=5;GBPl%VPar#CZ!ePQj}N@iesdKB_g_^QzsnEn`0o*_TJ`bhp@-tO>1@qhIr{u zo#Y+rdg~h_4^Kkt){8gzcKF9vPtKhzqx99_+MoM3{#Pv1SdhN)(1}g$Ocgnb*4(#! z=gu>I&RBc7JKfSxjPG|AKmVb#Qhr5sLY{#K&U;ElMD**N6S&madEmvtbxkYT*2|VS zF$U}RrrxyjR?y|RI(^o|HPx0sIOe?SJm|+V?MIFSzj)#Q$KrP;D~TD~>?oTiTQgl& z(^O>ROvnF=a-O2AJpVDl+it6l-VDo+{B_YU*vGs> zP4iw-tNHv79V_d-^9-JftUj#!?qh+Co9({KZ>8s6@04+{H|tGxFLav9P;z$vzMD_` zEm>?@uKrHz4-QOZ-P`wOW?tjE#$zY{i7Dv(vihTBK5H|tZCPcl?&Mdm1>Udyn?3pZ zyQ}rl$36ZrAY$EVQMJpqa4!QNMg|6XCI$uzQexdLKd;0&Kd&sc2r;Z2oox~f!lf15 z42&!C$rMC!!TdCdj_uGc??_e3}*2RMnZoU|?LYWo$}^1qBt>>HTOJ}rJwSDSlT zW8$t4uYa7I`_bb3{iOyU%%nrFx@lQhRit$-ZV10}Y@3+r$6lPca`17M_-gS*Em6S!YHV)m--gD0S zpD;_7Bh%*DrU}YjCYPm{OwjhSRI%K!N*EB4T zgkKNS{1ShwxY4nz>FAN)o`ubsFJ@(Qf2hvnII}2Gq*asW(wo(kpLS89fJ(}HU(fE&1k3q`XJ9P1tOXm)Ap0+dD9ll0-s}U!&jpo#g zi*@haF}S)b@Y-U}>cZNLe~Vvwi7lJq@_))54QCO>0%^XtcV31amSBxARpeH@t>dJf zRd!G`-Dao4an4gh?-_TrUsLYVjX3*yqV;8&Uj515J3B5MUF%V**0Uw-7HjVZ!+jk+ zZ!0;2b1z?Ox4Nr^z2biRfv>A>M?1&($1D$3{a5`-|K9tRt4`J3{9XGt`avD% zjDw;E0tGkM{#QHXoAB`dfsHplmc6@~q!5-d>+E59iEi2IYqN!tPHV2^EI50Dd0VdF z&l$?LlMZ~Ec<51V+JEzJuJyt{4yUJg{M(^F>2B2D%|E}ce6C!1*jG58R z3cMVlZc7#}4hq}s9}&8U?XrTzmAecfy6w;N?H@>rW?ekgeKtDsKzQT=DS?*PuZ^9X zRiAuTs{eG?fBL%*F6TleJhfWQuQYQj?6iu{DJv*a?e8`G>nzgyc*p9gcPFk}{7pw< z(fQRA%_Do4O>f;O#r~6bGT;5ug2Sp1Ic*@NHtMI%~98_m}lb(T3}HQyo8DX4m=p`=Wfa-;A{Itu9s{PHH5+ z>3J{yXP$nOL0a7AUdiHZQ>DMjq*w3Tu(;W#ZPI~-#&iB1_+9^SsoBm)yQ6DX{`X*b zw|w2@*H2q=4UW!s-91;xF8;CQ!*`;tkB`5IGgP1bq#)s9eE9Tk^W$$tHvd0SqMi1p zwmu}aYIE3r@MI-q<_J{OE4@(jif3eC@MmIRuq7pZKodhqegI_ll2EG14LI%h+Cb#a zb8WZCtyeN<#eEb|%$bnTylw)Q`~x%fPS-5=x(Pq(Y|WMk#YEh&NkG|2to~tS|2WsB-$l9nNOQ)nT8Noo;3*NnE`#FzlNwbDy3c?%k=KE_*j=nw)80EmTxcwtkuGFXN+AmI^P@ zNey3<(%+)pzN?@VUok zvrpr<-R#gptG{Nh9-qG)cJ#TTzwD8YQTXL)KOgBtt*g-qPb}E_XO&9i^#608$f8yO z5)b?xrZF)vSg|sYI6n-ZH3-Q!PRc9^NX#J=v8BPW`QYKBaGA_mEV}ZZtKKb){eEfd z)Mcw?&3e1?m5Q{?1~xOJv?;!S-|se?;5KoVMne4j;&(gMC#c+hJ-dB2w@p{u){IoX z)rH5F_7>_--SIQZBYG*v_BDblRyO&WA*svtFxd-&n9?Vpl<=gG0>gX$+~U8za|-y9cop%#fe@ z=7LnL)U}3b*2*Vl+`HK*S=br){lv^BLDo{EN#Da9q6|V)Ze>D8k3^qL*mIcca>)hj z{X46FbXqTLNi^N}eb2Ilcd2?I>N0Z!%fsJj1vWf`jvgIYtCpCiIn(=(;4$|tg`m+R z?~SV0o?FgMl(-c1RWo(+RpAAv_pyAwaQ|1In}ed%+6*oIdAp2%ZK+zIxo(4(y{}@J zk7nTF)e(wTEua5#N&jK`yW3MSD%$m6v@OT1ecSR%>-usMRbF>oDUQv49PmHx?yaw! zWw#EL_iS`XUK99&p&Ew>Lcp=2+}EJoWS3U)l8^ zSQd6A?AjIo;O?^{i~Z!)mhMztXq8y2dFJGaOV560{;kO`SxdL z7wsvEU*x+cp(9XmwaBzM%iGcyPwrRhQQKR{wcM%c>uleu6*2D=F70`6If?I2tJ%XJ zg~CTA_-5$w)*BW|eqO1b{`395xoh5TUt1$s`a`Hcutf6AN@-V?tQs!kaIdGTD}v66 zzSFuB`opPsYTL~{v!WzKr)xdSx|sVr_0>}KV-mj~pL}~}CeQn|av%3xw>^4Puxk6l zg)BW?N^=hEmy&zX%)R&L1{H@&o)3*}b<-vYH^?(Rvpa44RUS1zWR@$PlVo9Fh~i>k zFe0Ut3(3qu8X5w%fIt|n6|^)AJTzqMy+5gH^Y!@GwqFF)Gn<#~p1zH9f{3ob6NT<6 zu4{Z&sfb4F-nxI!T;=b=TQ?W+Zg~B4(wv#!<>cGvoxQi}QhC^=>Z=~!ujj>au3ob2 z`lX+Fmp!MSPrLtqudbK>+_3$nlWewGty*()(t6dM+Z<}5b5yof2|wG`dMRbgoXh<- zk6eTLmgvqADSmU9zc&5Wy;Z(%U%o5bxktn2{Oxs>Cbyls|J}Y^@J>E{8O!_ZCpl|x z-bgzAQd^txct{<)i}ovD_tb?ay%x^do^`i!!G{(d?qth@*EmAI+FZ|M{Ka$Edv|Hd zst@N6``ce`zH;F1h1+>|S4^r4SbC*zXHerSo0nOd5mtRW(s|wsvF$SVh^a{Z(q-rQ z+F*e-pYPA$O_qC|uYA7s``gW=jkn)ElfHYl_pZ*Y9S3#ep0S@?kfviX`Q{SRyPGk$*6dVl_y%vH7G7M5W$__Iwy;~O7qWC;z zGONz^jSMN@67v2!?o$3ZMRUDX?50bJ*|WZ=NI!mr_xhj@9*^UzWl(hM)2VTrCpCF z{SZw$quuPDbSGY4?}$W~=`-c)GLsK-OMJf=zG~G2!?%aI`gU)gwQ5nJ(G&hdbDv1J zXf+yCY&ywbc(06uTPj(3_36Kh)};P?u}k;%I*T}t6padT8_Aq}o3*L0`Y*6Mi%0i5 zUr_eiRF&ac`tVim#d)$xUiKDSU#qvq2G0qbXE>`sf8UEENn-!z#FRc#IXLr+v#{J( zr;JJ6@3kTn@5%Uz=2~-_ju*WAsfvZq<(V z#jj3=_edKYKD=y=H1Dh4$@}IABG}IEz?%-`0t=K%g$$QVOoEojQ+WY{HOK`DJ^Mk|1HbIFLdYC zQjhC1^c{RET{J)RedlC7va8c1>7TZ&R9^Gvhb;o%`QKGA3B7k>x%M*KEonx)mcZ&w zT%CqV=C6YHOqu9qbN9`U3rh|q(OxcWL+4jsRdgT2BI~IDuf{I zZOFPXP`LxbXk`z`3PfuzxzkPjIuirKZx#jyQ&Ox5&d5wF@hBzOw$BaD_P=c)^7mbQ zVQb5j0CUgN$x^Xu3wztyq&kl8^WoUJZL)-F;fA?(EywcjZPHeo1@NrXqv0YB$?MG(OC_?G^c=M~^p~p}%#a&>Fov zlO!#hx4vuKEY>3uadJiFdle1#HKHrOSuVKfB$|Ex>)Hc+v8o3>FGpN(Wms3OtzBzz_|?2EQ$-p+|LPFFfB5VL<~bQYXXadb%OiFv!sfu0cD|qO zDV%o_u1r5T_i540DY^3(m}l-4yzxc5a`ug)#a8UzI_F#7$%yIqpa=8-T%Z>%fBA0x4pg_vwqRq@7|kTx9`h$i55xLOey)! zu)acU)8s|@JGTq1;kVvx-N&Q*a!%4SiGrs1$tmLNCMVur7Wu97-*pA1M4Ja&7WFPV z+r^cY=`O1KLb#O0!tCc8)A2xMR?I zf`9H=2hn-e2RGM$&t2f!RW)I)!Ue@SETJ!5HF&lB{h4k5d!#ECaj3^7#eecGVhVUF zXf;_bW$}xID{p<=1^?ShmVQtE-?8hW%DsDg`-26K-)1-FVV~OG*cFv69Qwk_VPbf) zJ!8qwB=uQ6xe4>xHUzW0h*P}RWf5RgAGct->_3^<1>Ff7;^QOkDr>L{th^`}_WjBq zdDFWAby`jG>tFNM9ln?NNHd0|X>!~==XuS>JFFAq?yoU>cr{gI+3y{8!U9s6H&`Ca zFD;3=ZXwgpoPXco?~dU2WoF+#UEsU-j|nvw?Y+~mdpaWnLm$z@U(k%|2_E@MO+g;% z1m#%}M$5Oc0pO97J+DQpdjca%Se{HWVZ3$7OiIOZ!j9)nO5q~ho!UB@-2ZB)ZJXrG z%JHZtEq&VNxc&bsZpraQSE#+deOdPppZk**v3uX_7e=g~Exf1la^|)TueUg#OPPMD zVs%Kn^VNAbj=Q|ka&F#K#mDK)rWUl5p zv8(<1%9nc^)$UWbh8=mFlM$U)k*Xp`RwY z=k%5DOXpV3(-vRmwJY$itH4#~kEM?@ZuE1ebzYx#>`vurlLOyYRC8)L9$sws$~Eo8 zqQtvun&CekUrj#7b47%%%1wlYfx&>2*yS(Kgy5D5nO!V$E=?j>rcMpb z&A)9X@NZpw;R(AlaVpV8kD0c?y$?OWAj_*3A|HWJ&&kdTA*>->*Bv}_a=Vw z7S=yFC1O!u`SIuTssjaL_Wv#@tgbd}+^NB35#D;~dFh$NwJt#it)yDw1diz5=}0|S z!t{AgY78@1adOz?hX&7|D&%fm(R1l$!pc*LhomI46$A4-stN*)0(~Ah{Na|osusFS zDr8PcU3|?P28PL#LPecfQ%`jLd1#h7XSL|ONl)3_5=HC|U4D7z*`lVYVKdWI9~fPo z-ZIAKE)tND&Y&C|W46hmW0b(hSD zNV&V~{F=PfoGM2T?L9mHi1HeIJSb%BA7`8Y@!#Eiaqbz8U!*?tc)QBEr5hSu4p^vg z(y;rY^|Y=)u2oK^N0dX_lucE%UZ?V@>QBw9^aV8I^lL?) zFJ0FhdUI=K_|rB0=Vs;^_MDF|@N~2f*y7=Lj;Tb%aS;cD)?M2og;EmM1ykogrfJ0tK)yql>eT4%`}?(a!~jOrr6N7Os&of zaU#s#73v>8OpUpd=`{JGZrOwruWnY%=j`8R=D&THiRzAIMV^K1dwm7I|Cc+c`Q?_v z>oEStWuf)iib3o}?lQ<6k#=Oz7u}H@aWCJmzpZo#&HjHDh{3uyQ_A@ZrR=U zg?&MalkGQdD1W(7E6d{d^jQ^b`FwhxJgxr+@YlMnd-MPE(r^D)w)0gL&*`>3&%0;t z+X+IO**DC7$#{u<|5x+)WwARSeeIYS%V|A%_ltY)!xrCtb#!dyBK^#?-u1f=eUbmMw|c>Nev}7MDzFo=2&UmpjM1+T&AmCGVWtvGJAd&F!CD z)&#!tD}4KF%hNmS;*BQrUvgTwQEpM}|A0xh6OV*l`d((*5_tP%=MS0N5*On|+C$8y zP$mooBOJnT34Rr~k-XV#8g2Je&|-`=lX&(tBOIMMFKe2?qr?m%Eh1y#nf=mXmvH%Vj^I!CH!tTuZsMYF_ujiVZ|=-F^x@y}yJz#t zo7s!PZpR8&PnSSd=ra;?C!TOXaj>(D99dmdrA}zw>T>~Aj{wXlIWR?4= za@A@L;k8~pAwAtpY>%d|lbj&V_c3YbkNz%3xy{;3TysnETv++|+c?7HW3+i|~vD z6^)V>Z(;1*!Z3T4$kch3a^2E86E~<{jCgv+b-HAFo`8L9kFxoJ>x$n@R-4cIA$#_h z?Ac$v&%S*B^4;EqH)pc(HTCmCX(79lq~?5Dt*~O&rOG2uRsChH4n3VR*P8d|_eaTm zVvXhpe`K@?T0LHzZsm|3@XvAWdNuj5pD*2iycgFwKWWXwiPQIrGkw1Kdak1UwI$IX zo7Odkh<%Cw&o=kgmHTIT=2tCCR9UREQ_s{h@`Od&{~dSc=RW#;_Gn$#0_8eZ)cWr8 zglMY?ObiUNtR&WV!Ko$AW+u=fVL}6jxsxyY-8K+ud;eKv{|(-&cg)HrZ)r8mGV%$Gf;?v&x~| zD9>aSzRD(_P%rbn3+~U)EeKC@T~!<-^3o~mLQ3M9R~Z&MPl^ogzu08xrO!4qitlqt z?D>*NVRIgiBQv7}H)!yi*vAt#LDTsS89G2{Cupgm#SMD^>EwV(A2iq zMw3gG-+r31==RBF6D&32cRxDx?%}=njN)BKR%(XU_N1?r-qpCld++_zY#~0K`unV2 zf34cE;x^;evRD7jSL$wKG>vKRkGjQ%2T6=FZ8bRnr1O`=-ub zc5^}_Te@P?J;Rwy^#Lh|Uazj@KEB8B!aJu2Tf8>gGnUn@?^IBlWi*eYz3{>B2V1h9 z+L=oVPgnV0(o_<)_H}KKyU0bWjzY2WbUlE<1pe!Nm> z_~OKuRg+@-VlK}}G%1T=y7OX+)%wGo9ff)`9ta=r)$Hcq^fc+vpMpCqKN89nZ%)!w zm9fs+wKQeBT8Q!vrk`wD?YTRrkH2|2(f+MX$KCde!Tpz} zmgeoAcj%{n#~VEv%lnUiCd}7d*C8x^d3u(9PR4)RocPF%n=e1rN6iDdS;ts5urn~6 z5n^DlB&Do%ttd#$O94%p6%m{_of@8Z&{XGKOo-+t8(m$!?Fy>K;8 zIm9i$WTme!|H%?LAGMeB?unn?Y9JZA-c^q`u`u`Tvm~?V(^SzgCw2qZyORC2|CB4boZqDUKuK`Ozv} zW2THVg=fv~Y%{yCwJjl$d#&C}$5~SRTN18?)oJH=ZGZ4ZyS8gnNl=k;>(s4F*<({eG`4emT@<|e$p^n_zFMBEQdef@=da-H z3|c*h;X&Knz5}s0nC@9k+vOfPWv5wdZ1|Scwcg7oo^tYRpQ_=#w>99rtKvOH;f?Df zmFAXNOK+Ugvww3|u+IC)#!0vP3R6p-e$%?U^KhMmQiE{TdlR?ds#vS0O*`5xeu*-Q zas7)7OH)zSU7kB>kNAY+3tiO=l1`jpR^yvg6(1_}b7RX@JxP~oS0@~qd0^7oH)l5A z+IUL#Q|Hr+9rs^nPWiNnF?_Gd(PK&XFYdRj_dNOY2b@r?aXB%%mZwg!SW)(C0`fD64&-FvN zZ%aIvdd~4lT|Z=g)LQZW*o9U>fzcb^ANaCz*TvGvB8uA5xgjV5{ZQ_4L-l)+riuloi$GF1ciCNBl3-oqF5#h4#4%&2KMGmiyN|wdv&b z4*kV5%Xu`4KFVBg(KDW&Yq+rc;@&CJ5q%-S0lQ|0?y&FJG%@yZRnTWaui$eFL^RJc zev3#kaIRXBEnl`Sp1(Mb&M4Dp%jUcGTPKgk|?(Wmk#sG3{a5>l)X-_TM^{p>z5wHqC&OUbAa^ z4jAzLXFm%raglh+)J=(K#&Q@JNeaQ%f` zvtHk?dNz{tPduz)y7uCc3g0{pv3-8G(ioS`+UFF_aQXD)8QUir-GuKWu53uvwo|@=N!;YPrw#pH!~}E($oYutQ<-b2eXrSf(4It#YO(zL#C9eAnLV*5!L|+j(@)zbl+~{>QsA-OpZAw)Q-q%Tu;;|Ic{ki!q{` z+0P~VYU8Jab$Md92#iNF&PQI>c`Lo!uE_}wmw3X7EFGT-1b2zi>@U6L* zFEToA(PDpaNby8_8c%qV@bf|`!JfpOF{#DnhRc}#9?@s1NS$VVnD5!2$$fiLp7|f# z+*rZ(UHw6B-fa=95OVHhQ1X?9YbrhnmSk5H=f0BhXuP@B@u&8Utp_?Y z12XfN_xrs1R=j=w=Q_K4<+oSf_N%nEz4cCc`MfTf<-x7b>|>`!&Ay;w9QL~@_g7oU zlg>|uf%gQTIxi~mnNsGG=`A92$nM+)>*-6bnOwRo<8=FYLgS?4 zSp3EB&E2ja&ei{j_#u36*Z$|f&;OtQ?Mmv$$DFs{Eo#-9TYk^>y7TY0EvaECW&0Uk z>Hht&>ig-^JI#}CpKgqoe_Xrgcgamto&H(ouU2^c;(InT(eI9(?yu#S@9)0%?AE{C z^N)*d?>#Cz|FGD5e`fJWk%#?4fs@?lYs3^CsEDPj6W^DTUY~7Na-)}zeKe!{xHv09Ot+P)^ikL5ysXg19m6x;QHH-7?+n*|z zeBEBgw|cU-mejf@^VcrPQ+-t z+WE*j zHWxnP=KNu={!sZI&pE*vcdl%>)_>{k^7fOL7lcn_J^WidXr-)*f~e7tYEk#c*E6zb z{+YGcRZMUn(-Ps!ssYwd{~|4X1$D>zi)voxGchn|voJ82lhQf=+j)B5^MIp z*Soakn3?AHC3CljsGi!EsmMNgve_ALR^f-Y%6wL2@ptFU`>T4i?C9l+lTTat|H+)_8fUmaq!Ne%`Z8kP{ za`zpSl~TERVB2}=wGSM%P57L5rhI4ECB^-q()noai-(nO81rrg8*JFClk@!M9+lgNs??>;Ivfv) z@0_gcdy`4@?0KL(=Yeox&3sqEInL8`e(n}_&~ZC6 z|CHq1@`(*yjjuRD*cH+h?3sQtDm>Br(J%0YWtI|;rp2S<>o-I-E|)uOCZ)*W<-K5s z9rwWkqhbx6!wh_TH}x)E+4Xl==Psu6$D#=rmDsx11!$iQ%#jNt~*q7gzJ zz|z3j?Arz+wcpoUY?z+X{kUe!!Y!v0q;um>ab$lB37YU$+B?D9aZ>i77xnL_+E3dM z)Vy?c^?BRxFEskh@5|?Hza4EeY5y@H`zgm?a7nM$N)+8$D02Lz;Qmmx*0Y7`u8v}J zrreWXH`yh~^sfBcqI)-zX3f+(>AE<0waMd29gROS`FJ#z98WTv|JVI!L&Ht4rv)39 zZCJ$AUhU12{%xP&w7dcnQ=^56n$JDMmTpzw5VY{~5f;7>wea7`C$3thx5f$C+&p#g z&F#Z~*W2$<_YIqJ<4WdABbyaHTNYo?tElp@^0fT1Z{cITjEXm=56&5E{BY`p^qvW& zG6{lF)&J(@oN^P|_wAjDud!~4ZEF6cP0TxIay6mU&NEYvZIXFB z$IIJk@tzikg>fFv*F#TjPhK%uN!{#J#Do(nH$v8~;5vD%t>QRTw`|9ss+1z_BVm`C?oXZDK7nYoI4-B1d z=Q4e|&DQrF&y&mE-Jh_3z2dV3F;?N64mF7d!uzW7l(w*m%3s-)^(%4e{ydk6{Rwr` zQh5FMyloP=ao+Jgi|hX7Z~MZx@GkkhBKolW)~wAR%!F%R&Ge(<7pw0>Tf5%|o_z)&d6z+ga3DVm(0lA4!VQkhs#@kOucPqVSG=v z`NNUS<=z4@ar%>E6}rS~UlM{;CX%E;v{h-#VRp zy8JxdE{g|`*1VNUSKQ9)U-|iys@{(KJJuiC@m;Co68C>4zJ34Z9`5}oy}#c2#OdkI z-?YmU?k?J3cVxK%_qm7X_y76J-IUO7AsC~V82Vr4xqhW!n*HNP)5YH{f9KEB-t+rw z_Sdh|w;fjfmmq7m``=rkwwLGQ4UeziUvU5U@7wRD#LqMD;J>qf*PmmB$@89Ds=RME zGx-{^Kyvn>cM|U|rC0SEs(pOA|I=yj3jXrzR!3~hj?Yn6HxfCe>AmHcmq}9n)Wz?< zIvX#av%GEs-=x$>Q~Yv#vzKmQ|1;@&uvg60lgg=UChb@*nanuXC94ch%Vp=Ysx%#&`)UMQZ@7Qv(x*$7Vw=~z^Ju=bJYS?KL_bKcE`7WQ=92^ zF~i3Hk)?mwyeO-#RM)bH88!1=;@-KhoMW**F|KscZl(O$)@QxdJ7yVO4RbRq{Ceg5 z*~&PpLk`hBS57YaX8L>U>B*^a<)_nU@0@YfJL-(6x32d2VAWO6iq^`RzFMXIwOQ+Y zxct3if+Yu+9N)RRYR{?Jse7};KA&u?;(xw1@Jq)-8^_)V z)W14uyPNOIU3qg_mD>-?w!P2HT9onm&F1*UcGKQya#T;c)aO#@$p7@xlHMyXoP2_o zecl%Id&m3N5w+{D&FlJk^5m|w-QL@_cIKQ`ufBECeDNjM*~#L@z7`W^=uQ6WlDaW; zxtp)w&Qp(8-qW*qR#&$x!LT=eDyKlW&h%;qdDj18v3?vU-j~Z z^hMi}8+-j^?Ot!%7_RR5*KU5++r{zg>yBH**3Ot*p}%7KnWwC}a_5#s#$1|dvit1Q zbvm1N)*o3FY!U2h?@}yPQB>-8b#Nfy*3ZjblC0p@n_$c* zlN!alM_YPv%+25``>c<>ce3Vg{`W$9^FP1i_xj|w{t|oq)793H9JF=G+AF(P-KKg=xc6p=6sks|xY}!-)v3i|hZk1j3s@kZR zNzayCOPR?heyil2)V+dV%T8>b`XNn!YNKm?UboCanH$9$QWSF+^Cl$^85)6ZA1HML3nJmS4kFa6r8joeZk zj9-(o@6M>J6Y-zBZ-Z;k;zt2J*9EWLT6#%++Y60vWi7Ff@9bR3JSW-koyVP?8&S6{ z(o$v@f8KLBxl(1#EW>A(%M>4peoCJwrlWS;;A2lyi06lS&n{N(aaxnT>A3mHyX$Y+ z95XpI&q!p?^UpOJ>u=~UxvDe!hs!1>lgS4kzcqZh>y$us*Bk#wi@N6|`Tks2qod`z zcD7^Pp=z~xQ+c1oK3O_bp!ez;i;&OnW-!H6zkfBgY~GOvhUMx%W&W1=>YtNWJ6mC` zwlRkUx_whVmxph9j+TT4hznx#A-X}PXZ))dej@22WVOuzB|GwF@@%$;y-wR?( zs=d~}IU2R`2zLc*ZQRL4?T*VW&TjqW*5RG_{C;j!#?;BJ>1(F9M_Mj+e{({0{nzf2 z1J{%2--VON`0CqxA^{!`l8zpgbq#F_jYG}!QEdmC5htOEpp(YKW%+wW^0 zz5R|a^us~+AAEHUj3=6JKd;zk%g0e^ASzI4kgo74;g!OtgiW7MG{0=B;CuFLCVyl8 zii^fxVSQ0-8&endB)$CNVY4uIc~}4+Yqa#+qd(MEX)v0XIz4yN3tg%!>CJoIHtSsB z!n{Q*stxD%3Ai>pUswERxM#oJZ7EFwHI1)Q`P08%iZtOmrIhcl6uRk5>&h#qGYsS3 zg|7c36?)(68rQ228m+9qbW}^NmoqPP$qa1Gofx~nZ^p5JBP9v4Gwp)A7_@dP-VR)M z*mm3LmmE*yqki1*+WKNo_V3&U_7S=3MMWNLlro$f_rIQ>xyD+_4i@)dq|gYVB1-=Nb^&wP@V-gq>e)iFIa@#|iliuzcwMekD&mg`hso-zOP#n0s_Emgt6IOoo(m!|OnkxB=7eZ1cR~glM`)gm9zAdGx z(c9F0X~#dEiF(=-g9?@%k+w0teE8Zc%e6^$*N;9ekNxsz{}tEwyY-x6KV{g)Eikz~ ze`)1MowJuYcGD8=Q;Ap z6z`R;7D_&1vWz=;;-!lp=iS=4sdW`E>wLGp?`r%0&#%04Mf%&6H)kvD{C%x8p1#Us z+nwrS;wbo0eM5g__+e)=qc@tDPh8!sw}mVF)rzxe&$+el7M{7c`OSpz=X1D`DrFYrC5UieGzuqmNEHkrBeEW$hVg4@`upL~Y;gMeHK8N|vf1&MMo8)bi zzuLdv>(Axeb28a&|6li46W{)C_E%t<)l&bN_sJCY-{;p`?%#CYD(3E!JKqA^#rc}k zDtlM2+i|!*>+|K{T&8#O^?WaupKqw!Qzd@oj{h6s^YZ(?Z)pCX%p;Z@Ao9jq!mpt8 z+}jCFxpP>rK0dy2|2sSTnYFwBXG*+_K2}>>+1XvT56A z&P7sDX>o==_#8aYYAp~(Td{@Ods)Nw*%s7Cp2|$*igJhrZkfdysg(qWe`14t^XC|d z?D?$yEGYBlr;XB@K~r<9GiLjShK5ebJvY^mZ8vLA&gM10U;pMYQFPq2A^q9jN;!|q z{`~#R*Z)|w=JGMkyLTU~ShMG=lGo)!j~xq7`gAT%*=nE=V0Hcelbs^DVU@;LuS#Ce zjoY+QyXTe1ba#~_>31hDn8p{r`|rC@Z6TJk{wsB=7H1!hy0Fd2>ARpE8@3sQSKG(jdHS>xHW&JAQxcu)fH7Sn3YH>tc(2 z+Im*fc^q!<7`FsXS@659D|yDlEoT}QFFU5=QhXp%!dp6~_0rP+mvjzyuDYlHvgh%P zt9K^^npGNe=lnCQ+O_ei+gCp2o125a_npyR9DQeAq%#|*#J-Kj(J3+0o20`mxy-|L zkGgjjChE?0uGr67em;KLHNW)I#g^Gt4~?RB&RqOI)c4}^q_Us?&n?N8cDXpi;SqDz zLoVZp%&YMmI~QxL+R~_=B>qF>H%s*tD<-DGnVp5M0-J5DHi$ow;MX?z@`>e?XoXtN zWh3>M;hSdn?pw0^jnzFrkM+~e`uv<8vgdB<`*r;5eax%(@a`7z-+RvRUPAqW)t+ff z=TG_9S|nz7`lr^MrjPc{_g8mkJlnY1E!#QnwxQp(hWn>1;(V|37dP+xGUfV#EDW8zYSk(&`P#KSIuE!EqGlI-xn5pd;CWT-WWuq{n|D9H`}W>_d)t~r zwqL9E9Fu*0bm}f;7g5W%>euEaZM`kZ{m%Dh*1Ce*ui7M-w%zN$9(gTj{xxpt=ep*Z znZMUu`W&!9vSqra;-hBS)(czYrvJ42@9o9W`1yuZ`^4PCyV`TI)tWYMoo{-Xv3qX7 zD@LEGDM`UT^Ac>n1f-f}EZ9DE<@5$$XI0T((;jqIvq#Ubd$-T-VIN!4-G{eBN|qfF z55Dw3qb2*KoWu1X)|cikciN=nwn-IayGB$ew=>V{oSRc1>16)bSLbN6%igYAEsb5%SRe2lbz-5YkR%j?=!@nYl4 z-L;P*JkOo1H+Zi;_21Vtsn@x;O2YC=6y~2gRk8J-d+jE>#ipl!&fd1~{eme{ol8Ud zrQdwE5n25zQ^Wang=|kovg#ZYPeJFXU;F%v{}}6VE!LQ8x_R=lFQv^ZuJ7}$HqMc* z?Fn1^ofXYNlUX%TX4-&pRw_<-9fpjp&UOpJ$gIeB4t`w z>qVKB-F=+XR7!%kEq$xw{=YD=XkGgAC(kda@||~743WHswhBpV$@2+k7#SD}m>C#| zT3ilEjvk3QX~ntu`6U^Il49>fN6;a3t?&PImHUXWGo8%b{&wNiP1P$_WnKQuXeM!6 z>%j>#)i2k})e^6+n64*u%(&+L*~2;8=f}tSpXaZb7At)>zxSkS_l@fLIcrj%vrW$3 zo^`By^;#a@zA!0S2jAJ3elFBl^X_vQpPrh$Pu%Z)8Ba`BIC#l+^*GdgOlRuxT~YS* zoxC>FjGu|IM=UFZQ}}OfbIf+Rzs!^EZ^zC46;B%$NY4_PBQ?3rdxCRt#W#od($~-3 zk#27jQd>Q-ZSp+uNV&&PtLNgU zi|emNioJgwr#5^0-0z8|qF1BtT%DG6C|bTiarWE;ExKNfT)pQH{QY@t`}bOfDTk&w zP2GNT>-!ULbXz8UJ^!($O#JRzy`;GH^6R_2W_Yc5wZF^vXZU9EH2o|8WP{C~&VHtF z#&N~r-OqGZt?px49gyVgS$Xqw(E%w|zVPJ34T%Q~5+n@1HzYY2E|3V|SyA1fS9j&e zMf(+Rbz=nFG`tS3KlfPoh0w+oENOACURT?iNZyb9hIC91XvU<}MB`)%BLjmm6Ol6} zkfZ}I$sEhl2_>G`38(WwCz5{u)wO$yfbE+S@$Io&8t%FVu#|mfoMIuw>9NFMiPGx$ z`H63savcQ}_|L`gEnl^7ZoIyI!7|UY{uUc=IW2c{T6eGGs)K7-=-alXBM3)u3PK40#(`s&u4xfQ-@O8b6Cwj6Y^dG~Gi|3xky=k$}A)4nmU z<}7+MljGp`!cZUfoI1zlGBdX9IkGKQ>7bj&a_RX-29>$LbvGW(d}$!%q%x1G=6|8( z-`S{Db?5;%TbHi>L6+aMKPjEAI=_SK{?v%T z#P}rsx5g^_?(Xn+%bD>N1>DPZ=SpFBbxvky%bL$;0Pw~*sDW4C2xFB|RIlqzq z|5-P@e6-4*i7oMpbS)H^KIhz}IE}Vp%G|1u~_9xASfr z@YI6lzsyu-KKA~7Er)rRw-wJ}0~76U5gJ0dtGD`wPkLMtZ-1(6cak`Bo94%u6OYe6 zyZiO*Kj9jKbCbWe&Eo!{*#F|ejH4@WfSugBefJKCnq{Q2-rwb% zDpF&}CEebrchfdzmyqd)eT^Hrjo&<%OmNrHakh%KSX3HwAacREUz;O%s?+w)yZrLE zo!%_HXE~Fyn07o_TXE}#W_A?6?QL)0wdtSl1o6uEZ%S(BP^p>bZh2TFGbHTUyu-de zXFnDuam{^P%<-OYD*vU;m5%csEmBfl%~pFRKWX`!{LhBJS=47A&yV@Fi%Ia<>9@># zB)?BCJsm1Fzdtzs)$VhZ87rUnR2Kj9=a)6hYM6fD#Hk;Cixa-By;8oI>HfJ=spaWT z7iy2Z&6s5Bd;2Hz+-cpmzcx&Zc47MWQ>V;7?53KxxZoW339gY+OaCv8vGe;P?z(21 z(-*-hHZG0-60F0mJ_}FRRxH|N&{FAKeVFBhgK%}rvCOP5=cN`~w;tmZda?bor3O!p z-uC^!PxHjJz7oB1X}aP6?W(-5H|Cw4l^l8ga+8$mslAX*7A{5 zhdCA$?g2B<Xmmxb z+_35~Pk-y0iY!gtQ!eRK!n>~>`FhIU%Enjfvdi|fe>A?l=(|5x_=jw-(yuAu&ouTJ z8a5?J^d0*5BJc1T`@R#$Ce}}8H*4d+GT-O-`E$#s+}JyZSuEn_i$}HV-+lfrKHt7( zk^2+=--{m_G-$>7N#_6C75+cywA-s}P8P}MUS_2%J%Gi zQL3)953TlCXLMHQ&4lE$?AiGo8(eFD2;{EVBd#{{^R(abGJE9?9{G{Ne%tm}`Tso+ zu6*7TbMa`jm9_HX=#!Blm2xY$d0CvD@PYfkmBYE&Vc{WM#{H-Ed^)bKzEHYjYP~F9 z^MffVQ=N(>FUj0Fzoc{KV_uJE$`cceijzXKGgmSj9-V8zwk~?%tkx{4Rh_eolBRxq z6)E9=_(y`$u@-l3ktxPrk3F8Q_73z&UeX_^xlX0+eZYEwPx_2G3A^WP*z<7WZQZw9 zcCOLAx1en8xzgA?6GPcUybI4Qu)3}gzh|lAbXKm@H+j0If7B5=C)jo9d{q$pycx#j zI}hv&?4Ng7Alo`W4Xd!@@_c4TKk>X**$sOTg1GJSAD#&MI>A3oyKgLu5(<+ zTlr3$z91kRBAI8X{%^WNH6kZuKhQGi0+vGpbc-nN@v%@v>Z2OwSIz8Wo7c;S_$lO-A zbJhF4-qSUT(K)9hBm53ulFOc6DVx1x8?)}_DGIzr&kWT+COLadd?B@CiN=b*H=^3b z$`18@Qm7H|HS}~0Yv6`yH#<@;9o?LKqPpWzg>u@vqnG_`?si#TtGLvuE?wyU zyy%+t^1YiD7pL#OBe=^r+V8t+&c-=8svi1m?H{k5I1zC4S{w7JV&jzZ+jrUWa%Sk% zy??dq=KGKblitRCV{_gYV_SMAHE5++%Ymz1l}9I7O*1`sOeWqh&)P@t!mjXhO%wJT z<=m}3+H)Yx+I(x`nHwBjhuzkEVUyaOpncBl$A${+UUP}JOL~IaTc39C6`c6rOLL|~ zl-H81s{)%2K_tUg*JI@yK{R{l+7B9(?cU`eu+$?a z1_o|om*9iV56(<2D#*+$&aQM$EGkGPyx}AGe)kmvfx7eYh6+yAWw+Pz+uhlvbYiZC zR{QdOClqg%+;Y3EqVjU<*AMmO%iea*IkCxC?ep37`tfDESDUZ5tNm9|$QN$p_Jysi zVC_Zg+(Z46Q@-#i-T)B%4$kdS#COJaM)o{954D zWxXFt;@`=C*_>#%)vDq1wvU_GZ(WlUY+CzR!&WX~8#8a(fn?XWRkcz|O?@F-wRE00 z+zZ<^?`MvIXs={6i_&ubgx5za{ysF`oNly!W1J9dx9WOj1ZT!Tg;NsebfIR~BYJ8`% z#S@o&+O$b8=;N*1a(a2G?yN==K7`#n#k(x0_0(yrOQ9mW)PHptwkl3I`=r)g)beZC zo{blu`KC{O!*guTzt;Gj|HJg}i0_!TGyb#LH(73%j$7WW?mKpC8~^%yD&uax_U-*G z7mnyD&f}ctcBMJ+4DXK6$tS0roq5`4S@42BJFc047-e-1s)6b}T91_uY6;(JR{i`Hz$INrul=JFb)ciB)d489V=k5E+ zpI}ui%)D&2NT0h#WI)2a;LB4*87@y`+}+N|u5iER$(!BnSNWb8U0GNe#N`moc_~LG zc73eozdyNxLAl;oyrcN*ru|g(rt_yx(*zReihF)VCVuxg7#Ay;B^TekS^T zo0G<#>LxmE*-gW>eINDND;adG)ie@p)|jQwIGM+~l(;6Klia8vRq#q@tgP<*X=?+Ollhxm|G)wSK>=yuBngS-Gl2 zpUPdn@{Pxgk}zw&TURn?zMY$&9i;Jw%XjX!+0$N~k(S^8Z$ba93~jAn+op!Dd{Mk| zOXk+ydIEPXZ#yk-`Myhfy5Hfi3mWyZ1-jR*IcxcMac(!S?wzZR^$N2unda@4-E{f; zUla4&nnlK|nHJ35o9y#))vHX`^?%nLcxNfSY5$_5-P3!v?wVY7TP*kI`aY%_pY%CQ za<>JGPp00yrlHX&__M4kJF?^qjlW-2l#8O}y+mz`20I9JQ=@7{gC zUOT50pDb)%tY7suiqUXYl%xErX@%Qkew3b7&HK%owL|zcZ}=VW2fXVK9+1{KW6$zx zo~5cuOo2ZSTbcLX7$c5jVjuG-MZ5jn5PwG~p}DY(dx~<~Ucp$y+*fv+9;?RpsPUKC z`NhduKKWsqWA>!%>;E%m3#?Nv&QxcV;;`zx=x{xA2HPhml}|gPfq?R@2Sk>huT(4fVHkSBn0f8aCIUa_QpOL*F^yS00@D zJ~4cz?TUv-@`G&5_S)Zi$PxZw_80%Yn9uo#KbSuC3%}U+-m&5x|K5Ec$}b#_5I%M; z{8<^Hx1Pl4!%Ub)6g zZl4l7`@#0qUhVRAH3gpUC!JGe7k9p`Ubl($JnQsF^H!={_+M8cY`16P`Q^nc;{Ry= zxXQiY{6CSsF^@va{ch+_Eu31Q`o2=5t6axVHvL>-zmSYquVGEucZ-&GqiXYK4?Z6G z`mykH&)@KA@Bi9Iorq4XFW-Dz;QpHpJ38${=5PEDo@hdxxbfwW+bTZLfGA1zHKb(m zP0UM4%}FZCN7UD#JP*QX`93$~cHa{df!g!oGFw}&h(F(Dd-_b;EOx!k4Pq^25uEcT zOtz49PFkM3{PM%s+vlV-#446vIbLeLE_iCo!|U(uZR-1<2Wfm{vo8$o+-7iVq1m32 zJx5JD-!&O5xxc-wU+mBSrX@|;ET;}iER^9gzM&Sisf+V{>dk`ShbteZCpsKEw)3B_ zjQOJOS0_DQZ?SY=`tDIz|0;u^z!;eTg?$%oS?5T%>v&E+@1@K0W9vk*y%*CDTMMk| z71*$=OxaxN_!9OhF$X)kX7uQ=sVm5?=#BU-^`b=e^~u|8S!d7ewMew$jy>PL-M;=n zbkK=__4|2TwY~RDR+%YkH&=MK`7O7Q1$DK@ChtG|xr*H;Q|rv!D_X}xCA=AC`p3Rr ze^kjP_}b%D=PddzM)C?~3UBvr=-tot@8ykYZr}KnFMjs=-ghE#+6u!u0Pnk-dj`gH|5$)EkCEp(X)%5!QKIPo4moM(TnzY?(N5{MyI+y+jp1*WF zDY5crztr`u98C+ZtThu;-($yiP?wRTE%Qrifp>aO%ZDp#Eha44>~3duq2BP0P*qUd z%H)W-L0_A-zvS+&jQZZY<%zTy!|eN$co#?6adQ~A^~j35@3OdbUUu%9y8Aj`?MweS zgsd zck9Ko^3>{N;p~}-vrfvch*+QdFWUiQOwPefd<#qR;OZZR! zt9tzDl()bCJ`H&C!vA`K%?BB$(9chM3Yr507$rRpOkAiqYjeTp?MF`SKU(I#E30|- z^7NAK3*OU&q?cA7-(oS#U&dQqKe@x*>?rTz+=Y7=@O~(I_knfV(zDMi_Gi!AJbim* z(F_T_&1(O${{7?t)$NEJ*e!Bd7IXysd{!c7$-pgUNDg$&%}h^BO3XnVatF$MAdH>? zgWnflwh;I`Z-3JMJ6HT<{x5pT&^X)DE4VE&Z^p9)A36h5ZeB`^cANBi#{PM+r+us4 zjXPD}-md-qEi!Wb{W~?c_BY##udU#$H(iy)9(H}g(U(bkkG+pR%*O4+FWGcKGFI{$L!P%XOGNChM#+t>f!_~Aa=VG#IJv_4 zJ&OkW8eJh@nF}wRrYax(wauZ`q*-{`#s#Ne7X1CLzQfI%XZ6G6`W2$>{9Lx1nodcU zEnhHo5yPD6T4hTT?Xw%^x+OiElDEA;z2_+JlMt)V=Ti*dY}!mHm5t0rHu zJE&H#=O-MU7xFyez_&FQ<{o~w^dfJ}-HlSxE(adi?oKY2y59PrZ7Sbc-;m~S3zK6a zy3>u`#~-|Vc=pOImkUF)&%FxUAyMD?@mjsM`fK5byYH;uSmMje{f9@;qk?y8!DZ78 zuaM-mY^G4ioB6JcF+u)$>>PKF#FC2I!oKb$u3L^K1t#6?*rK^{y<)dQ zvr{q`qdPxOKZ6TH?=8t=C(Ew<5RSL%Ks^OpZ{lYUxfsP>t-I@83Cna0m=^5vht zs&Q_?j6D0yBg?G6#U9waeaaT)eVv`z(k%P(U+lCt&9^c6C(boJvu5MXd2NS}OZl-_ z>zB_GmT&3dKcVwJi0hy1drevU$pY(_tl4VjDD`~yR6D)RCNZ{L>DsnIIxY4J{E3`D z)0)rUp4|W2@58<{H%nEuXMc~cKFxDeeNvljvkBLxug@md$9=WzvVI#Dx4!?ZwT$KI zPX*Qfv;MoyvOW0g(Gd{(bL7{Yh{Bc&ua{r1wdUVCYwB-P^&L(>J_jFo=-Dt~-FNZ* z!R~?V$2pF5xD=l(?Jb+NqKj|gd%yn-ztA@cr0nuvtii;nZ6#n5w$v+RSHEK_S%oz9Kfn_@W@{+X~RPsU`Y;-MpNr+##P^33!npPhW@ zX9X8iLkV7t*PtEqeMlY;)A)KqhWb;*Z+7;&8R{>bSyV_Uk0 zZ(3Vf_0@>F1V;Z$%PV%bKF{7@?#(hOOr~7xmeQYPGv+P!n|rBro4L8q8AaduMfFj4 zb&k*eV)@;8@#lm5cMdGOBRx&XG|5!zhaYFwk-6a^hO5L>3M9nc*~<@^*`^w#8+B~! zuAgEWxixC8_@R3$pZ+nT)(Ic)JIK@tFfj1xF)$bt-4io*K|jF&lpsMEEm6LWdLMNA z)TIA1wns&_zmwza&+$Ii(sFh!6OW9U%900v4lda=Wdm!*Mpf5I2g|xX`~2?s{d%5c zq|uBgbE@t1IFqhizI*xd<-3<{m9M}3a>xImhE7+&9ruUMGdl0zI(vQJhI%{evg0QW zWS%NX@Eu+#;_%n@q?_~Sf0{ja9gVzPW|s!&PDkFizPO7u}_+Mk#EoT^>K4W9mBSC zoNnrT5GTKPd7_-ypKAwi2ilxCq`+=JtD#!#tn<6u4)OXm`_^~c{r;{|dPGjs>7^pS z`@;ns?Mt+eiGMr3WWl)w0a2?ny;veO+5+eGHASvSt#`g8`)*gI6pzzEZKfZM*V*P= z%aDAh`6Ho7ly{od(WqozCZA*HZikC|8XenZaK$u0k>#+z+M4daH4JILFRu{zsnC6? zNqqTqR{jVhL(ldI*&B{+nrt6=pV{<%l8FtP)4K9`WSCj!+pTGvO}o~8x>m69#&iY~ z_sI!oH|k`6|FWWdOL0Zzx6dcvKbrf2dswzHHh-9r*)c3l~06 z>ujF5!B#+Jqe$+r>e{yv*7E&!9G`;|w*~9{44!p&^5@g{URFDAPR*!tEE9jm8aHL? zVYT*0QoXBFwBBrcUB0_Z!dQd-OO5NE(@nxZxsOz353vmfdbNn0xIYoA2sv zZflek434MQ#mTU|Ry!wf?9dD!uk~94=cs31dOKa>&r12zH`PvWUX)$!!0}Mpm$_9tF{qxJdbY^-p`-O)8 zxgT!+zVzvjZp8lwoA+mwiJk4$@4vku>Fd>*dSAZEygq))+KsWpr1j+gKd<-sKK|5U zGp&Vv%aOFry4P4OMOlsOy>}d1{po|Y%{itB{`Oz0VduCW`L+JIQSp)gQl5aWX3|or zFzp9ojB|OP?G`?MuJpFg;?nsiHYG$%T02iWBQe+i%b7WBo_Way>~jvj>6DXXzx{)2 z&i>HYFAL(k`1ce}EXrX2!?0a2Q|PE`pYN?VC04#lS1LPyc`M}!r!4j0Wt%LxRAttM zRTZ4oMyb-K;=hhmSbzLraY!ep;zESd;{|^XJ?wB0i1REf6ofC$?nGT)OdaOVEt@vb*OwfAl@G>ex;xUgd1_*{395 z&TlZ0XYE<4F6Hn){gutM7Y$2PJzE#G9PbTTRe@Ni% zHi`xhx1#7Xe2{37_!cG@%fHv*?jH&ib^ zv$I%iUdq7}m(=$)UX6Sx@2%%hJ$p^slMgf5D_4J8_Uc^Eldm!FzFz!z;nUI`xj(OM zDsR-B9(q9ZxwSn1(ifjUJK6gC+36I`ntQL_v+y1>S6#imrR}@ed9&T*Po)1o{=0gA zf{9nfw0|or^?Ne}qmvDiC3w;vZZTVP@1o?!mqktezLp(=t1laz4h}KAXe;i0u~Z~2 z=+DKae=PkRd~d&$xV=@P-EmI$R>8Ht%eSlPWWPUruCjE^>%gY7yQkgU-jaKH+M7S+ zyKfe*ShHFnxAE{r_rH%OM#vwY-QfCgNxW$5$=Kjf)<0s01&k*4H(%ta5A->3bLRpLFG>SxCk+@~16+l&;O6e@yW<|J8+ztZL%NJk5l{mYQ!0&ui^3J&_QMy-k*pI6{zToD%@Mh^(f%($|lJ;)p%?m9vo$!PGa1Cc{ zZqaUyM-vX#D%_g?`-${7^JR5Yrlf719UGZ)Lu;z!F1^A-pRTvx&hq}pZ@SOE=GNJ= zGi@JVzq}kLGBxP`B{4NG{nI}hmR#PfnRE83CDYMG5lrUV4-sOhqKpu!9_wXoQ7YYT$z5kZ%$>=v(u68ai=r2(lsA1kp8rCZI0Vn z$tnKLi4&h)VTpb>C;0iDl3iT=R-)qbcT_Zd4gEgnc3XwpU1NX4s0EWw@b+>Uon7Vp z*DgW4N+oal8nL@wHE98&<*(-b?g|xCI&!q>*}aLM`}#hK&gGvRbpNx8U!FNLSR72AEufLqSWwyVTU zgje)@w#G@}lndiOEHPz{toz8Jt%AUFzaIU?mN;h5S*py3!(#0hU z)lXF)Y~L)}cAmp-^`YlH^M9}T#x+NB(oc2-xc9w$z)z(W+ij|o7TC^XK~4PG3w5rX05ljI~p9+7FfIR z%!0<3Oq@a{BJ4fpKF79g-nVqxl7!0(Tk8b-m8w@hJAdcbAz2SS_9>CaCSUYOUDWcb z@ZZVyrjr&rc`tt$o_ai=>(q!9P+mbsp$nv?xjJc%^W&wj(dkEphWr zmCHxG?kN6r4-;HqBE6h7@WmBgpP8188416&C8sI>)2ygqN?y7@NvAIVXVzNrD=s;F zwQP$GPL#aMeEnAVw*vc?EKdi^Wt-PJ#VuWsuwm(=aMs=HH~jX#QQKO(v88t52K{Lp zBz2~&`;yCQx#-;b*X~BHalZ^$^+K0DX#Fn46u>z*h;#0u7PsR+)o=b+dEWA8xmneO zAi)K%We-0Mln)7YxqAG}jFs!wzZMF1j1!KW{?RSXvO>vJPWu0{7a_OxJNrVsb(Z}9 z*T3}Kg`3Z>nqJ_)6#44QT@kNkr??({aMbL3zyC!^*;TE{kG$tjT)E*lr=#ZjI1z8r zJ>N@|E*q%jul)3FUS9&w2L1WzG{Kp}(E?FwZ)pAY2r$5D97q-YhGGBh; zZhFD|M;jUKvt>gcYdrr^`+3ItS*zlX?6U3@!|}Os%LC)4^Bnse zD-1bTO>^87_0cm{!}5spO)e?s^-)RkGN)p>=3RL>UH0IXTN9;Tf5>!Vm{b30gTw@- zuPU3X?H27=x6wAaB5230A0Gayx36uTnG*>E;PY~QS;@HNvc*8V)9bZ)J{zHf_oZf{zv zlJ2s^V~%!^e$n^c&wqJ+3NB8KIc&6}MXImp$o)>sVz0%S7MD)+EbzVXq?^5+>D04l z?-Dih?AAvmy7M-?EUVyf&ekgObJVE1+1&O#KXBWl^4+&(dbO_p*n7mjR@wD)?5v9$ zH>sG(PzM_Sy?*3u_4ZdZQiJE^q3 zebq}JEe>anW~b2VlNlA2;+Mjjo|kb-UEZ!dy=KXpsME2VH@)V(8hW#I>8>Av)309& zI2F)7>DaV1mCG86NBYx_mA@#v9r@wN9PcTgF3h!$bFj)wTm2!2=i|G%|8HrYtqOdt zr8)oLy-!>J@dVHQXJ*0reS2%LK>wi@2~v%RU> zrQwzD+&I1BTLyEq1lt!yJzd+_v}E_0U7OFW_+9JvuDHicN3=7*;`u>ek9f0&#h+ao zXSeOYw&V4uy}I9wf=?9`T-f{6ckS9}srJ5FUcSqhZPz$uR>WTsbFr`dYW0I*=`p4} zKaTuU%N~E&S2`i3IUqXy>!chZ@rx_YU0itRlayge#?>hoW9NOFy=|UZebtf)+SfB` zqTlEo@ZQe;YF5t6e+MF7Tyls@RapPGL}izCZKg``XBF4m7k`S~PqbAj(VKAjxN}Wx zlj6zXLyGlZghlP2zB;VUwMpfj*3UnyYVK|R^iuoX{uTX88O`rYG%t>ooOY=Gg!rDf z&sl2j*74n6``|jK)xSxO;d-Gtmvd(9em2ejTK4bPzvjl=y|7bH^rXwNt47Dx2u}?! z_RBmr<+-F(o(}()mSdNud|kNDTkXhvne@t*_kM1>`}7v-ADO-F#Y$~E)lWB<|NT49 z)A~|}-l5wD@6{jPX$gsCXgstfgZDOv?pEg|&vO%!RVN?g_L;Ub$LjQP{bgU(U0$wB z`7}wR>8zKl&h2%%os6-yVP#+J@6B90cb`RU&T}?9=Li@6BR?O<&W_shSaIS4HGQ{& zskfioK98TUjPFghLfDM;+pkXR?7i`3hl#JQwBaA^Ni!pgmWVhAKM!`it)iMY^-|<= zlNH_(f4Q!0X)|4$P`Gam&#asCzF+u$ELFr&>2Y99aHh*(z<(jn~V2f4%%X zvn<-i_^Q{3=rt$r{p=QrT4mODTF_K&=Q-OqTVFUa}?o|iA-z%|Sw3KD~YTNa`e*;8ot50iPV0`;z@7H?Np^jOR*6!tu3=A@$NhqR+ zI^1$H3(zm_0S$D3Fxp_p+zDs%RvQSkez!Rq7}lBMln{C9Zp_NNF|nauzZv*=5~kib zVbA*gWj06V_p+@g%3kvE-znv)zPR^; zM&HL9T+MN--99TH+Ir2!VAVF}>r)PEw@>oUSk0htHpPXa1_2*=H>pvs2XT zS%qTmA=aBWD>vRul2_TjcI#i?Nj!%)OL#-#qSE+ zWOVz<^_svLW(jI^U`w&4!4#D`)1!U5CGkBJEdvvk7U^wspipKiqcWH z1U7l-W!=7sl02;tTiQZx2>M; zI_+h);*eMC4xYk-n}#>nJ-qr+o$FQY(zV`m70zt``&EizM$j3{HioyFT|X}Pc5vq! zc;BtCh<>`-{HxB4-ELL}Vb`aXHrzhN#poAamk^edaLKk{*?}&h(_1&a*vs(JFnea^ zqXxg}n`XUO6Rx`Lr8J|4|8s|M_s6e($*pS3KGTy(Tkd?lLny$c z>qa2&@1<-vGF8&zvbHuhZ{Ra8a9haz-)Y(*xy9$iJKGaIvac@JD7bcxVR|jkzp^(w zrXD-o@G^2`@9`&7ugb>AMRao}C46X=y}|T&m&lz>ryhr-RdW_?p(k;6Fyz+5b0NWzFxjJbT(cx90k#1{TLu$#z{E+oy&9WFGITs^eqo z?0S^>uhEKQRb1gE<})^(4<-CJc82OGAJ8iEcq5VU~M*c zb1GZ=&ORmsVYTY?0%JLI`%mo*ZElY$+7+Xg%YODf#U(Ch9=duf?{Z;d*NfH0wtv_S z=FOPM@YtCpI;X9T??+ZJ3Yn`auh-cFaklDua53_bg}qb0X5GA&9x zu&vTKJo&6=E9>K+2SR5hF7Gc%eWDR1!#*SFf$`Bmu@}5{ij9wTS`KYvOksU^V2S>k zg#L$GxAH!B%$sawbk0cc;uluPK2gNvp=JB3$(~FM4DrNXm;s)}2rekfEJ-cSNJUy{ z2P!#17_Ico4ff5S?I5y8`J?>27p$+2vW0J46eSZNy5v;p#zU-q*_$Ooq%Y_lSr+=Q z`hK0o%Bu47_xTC37_|F|72GUFjY;S2k1_E0KYE3vdpbd%MrGm`nT zCOMC5zANjc^hL0+#(MO|yPJJEncBsrKob)cQI$`d@H}_aXHyvEN@y~~2O-ky%V&yGK>t>yNFDW3j|B#QV2A^mRoB8<< zzM{vBwRXO1S)kL}wxP23;=Y}mCeMDhS=%vwbLR;qj-Q9`ak5-W`t+r1jqcNowvET{ z&+KGQUsJl*G-1NKRrbhxEZBd!x8^@L zYOR0wZltUUGXuj8Rt5$`qU!_KoSe*pVuF=GYsl@qJ7xm4&%=3w7EHT#W!;J^j<0$@ zKf2}ExQOG;6K0LhTdGz3vKDU3rzoxco!3~M@ zyq62#zm?#fdn`;ncuU%cDVgc*F(OChD~b(S4JNKzx2-m(NSS@F4oOZ_nJAY^J4)6<5e8{miTT`Q>}~uNJT7cP~G$ ze3$E7A2~&icXxJ5x`CXpw??zAT;$=;s~Y8OnO>*ty?xnSSjjA8<7=sU-fc_MD{3v4 zncRC<_WW~Yb;0tr{Oz&(C63&6SG=~W*?;?&CzoZWtyz3cW`c>4xM0J)$&x!|_ZLjN zXZ7WX4BO+NB{?4gSl{{P3Tf3&K3{raeTeYutK!n#3!nGMt5?57ME%j+)+of!FPk2q` ze%ZHvd-cC(WFE3!EM4_`-5tfNaRF=67iYwVDHvKrJgLqS+w<|GsosjujWR2OiriH+ zv-T={5>F7{s&1cXtm(3BMZA;p_hU~vf|NJab^c+>o)It7z98G|M!~-(<(vfqPmVnK z(%kamb!*OyEwZV7c0n^gKQY|8;JnS8H>Kq}7FQds6a9RMzfEtE=i=OF(#iX0zsZgC zvax*p;e(>~)A#SE{SRL->FU|De^$Jz)pJRxT&3f>V#CgZ`rmhnEIR!6plGaz;yL%* z(x*gf7ic{{$H}F2) z#Y9~j=baKd+T~lKeHqV~CUV7^o_?~Cbt_}d*+u3Jig|9UMc0OzoXv>3XtKDeKz7>x z?juGYg%mjQBAy*SqCWpZ;>XWPE2LM<7uT3DCqQU_p^(5DnSDQ=xOVjYXi5!NPLq83 z@aMcq?9Y#D&$<28T1xs(`t+yOcE;(s!LmL7*kyO@4u1WTlg+pAv*JvD&g*&$3*|Js z6L?ST+wdRl1U>fZ(z%-$85kC`Ffgd%%AWBh#U=46nTa|1=|+SWey*MJFzdE~!14Xk zfB4!LObD>vEWG?})R&d5x%?a0Cp_&=*7A0pcCBSX`T8X{@^+gf9Q)%q$M4ery7D>t zzK=D04<@8L~PD^TvoO_{)NIKJwO_vt1aXp+c zRfErZRyyaKm%BV3@C%Eryqz~CZ|1@$Tw<%cWZJ*qyKBErN-d&x?iAnVaer;x%dnLnGnD_=_2+J?uJ^vwSypXam6weiKMQWiRnd*P?sz(8 zKL51>dy%_ei}%HdJ{B(5$o|uGt1*mgiP3FAql9^9I5$*=^=$dcJ}LEEpVOiH#<7>C z|J%b5cPDk;-s=x-UMAIkwlA{#_43j4Lwo1jBwpKtG$Gx(sM;l2_JY_wW(I~eYzzzv z=m{b%Kd+=%-!UgSBQ-a(xI`~KGYxzY#jR|UU=T)YQWSqL*}TE$Ns>^?jB^Z(r~m)| zzdtKV{;-Awt1^$qzvpFqpNiQHdB5_6G>8Z@+jp33XP?NIF!KI8(l>^3i6^xwEJLKD&M8^G9EAEfU*s zBQje1+m&fkr%z|s`8MnI*3zq2uL{oI{BGW@UB7<)YB?Oc>E7*Yckaw7tPFkgGB-Ov zKRGFIMw0EryKnC%=FhZRa$5ZE?aCR#tqg)85|wes%Tn8~b{#jpFucb|#MS^W5ub#m(b zm&LDl+^`Ulx_MYfq_|?LiI|xY+un+ZBQKXsys}OIdQ#wWrQjcnw#m<2by+%f&#m;* zHH9`4uP7C-c~rRks#4g}gziewuDiFAw1ulf*R{HSyBl%qW5%XE0?(T}zvay=SNm9* zxui_JruO3sckS%wUo#p1>r6|_*<7>JL~Hijr;|B5kDE+4-LZDJqTSnvhYGf?G@V{| z>U>b|uAdv0KazR=_{R)`;G1c6)@D<;ElE}n5}OmYC1$2c>+79v>fI9IRX;;kKV7*r z?EbA#t@y%yRc88gUS9k3=EI)fSB? zuAM1;t$*ICw%$8cXuI3%#ifDy%cp$)d+v_>sc-7p{|~PY>OA^=b)Ea!TAR#oe+jgxXSc3>D!%%ue_GHmNw5(^+&0_y`0SxG;ilH# zTVL%ttM$A-w9H=3`rGM;XVPcp^B1amXWGZTJ~BPF;Lnv$=Kage&sY8W@$cq#t6<5z z*HL$}1yBEseEDLpzTGy%7gOCTZx`;ppT8~U{O`YI$3K_uzyJ2F^&;bd^V1HK zRLLdk>O7VzQ4gJ~Zrm^R`~P+C_v-WC>)t=Fe*eA3Zo7`IX=Ypg27QJz0c)o0<$W;q z)Ui1)2Wxus3C|=V*2T$&rY87oTPQl^Xd}AHvxt`pKX%nS!c`jw;#Q1 z;u|>SYSz{W9TrE0mMu|hqt+fX@KKuB;iA;&aNuc?Bm+M~wKcB;V+5lP0}BJw1*R2@ z1`M1H91aWzSQ8{ZR5awaFKb+MAd9t|m4iuuX|33mtOEuUJRDS*8X0y>X8pgOJ;KQL zL1AMz+bpJ2Tw&Z190~#ox*1m&9AlW=;KHKB$g$(Y9C^9(sv?(?3{|IY+B4g9R*;Oj zM6adVvDwXBz^z4!$vs#)uxYswpL0jXy)f`Q(X3Kg^_qd)@G+| zF;jP@YZRBpWpI>lar^aq>B4zo>o1DrB_DcJ8UM~&*{Vpd;-FdD>?#A+sjmGkJtj}y zy;zq!eeH=2&)eG^qyOq=aZCLW{nZ)LDHQ%r?`~Fl~TPM>jHT9^A{qlL)<;U;V zpWPH8uum)R@xfooDQ4F2#|HLaVcERcJ?F#qr%{5wW{-us5cF(hQ_Mun8Yv+7W zv0HNQ{=%A#k9>{mFPNXKoEcoNt5Le7IM~j$evO9T&Z#ebzU@xvd%>}mccI_iEcdWq z7aSUjtDpY+IK%baBW3nqranbZPt`9=Z}a2L|M%sh{V*?$wu+znih0xtX*+t7Fd@<8OI;wl9enE4+Qh zYWrbpRXeuTn_tgi*Nb27ZaF>3@5JT3yBFyQ8eVL@AAWwi$lLl)t8Mh|{`fU_a?q>Q z4_~x#cP_7Dy8h#CZMnX!UEiJVxFzja>U*~T{cRx=>nR0!=XQwwy!NYB_*KN= z+jNQ<)+J>k*@VEO(49A4hur(7i7qhOs5MkG1 zb>OP#290Y*`)-}O<0?C?GoZPzPc&zXLRRnGB!*z;<*b|`HGdBztXb!>?3}2^i6_Yy z_Z{84<9_s}dh74=W*48YJ-1i={N!pAOT%-gl@Bm8?Ah^gqb7r1ri;z}yR8xJTu!8<+*QCo{M)*fy{^a5gZgFfcL5F>p8VIj|}) zKCrm))?rI?VuDFi9KRH=#?%G@4;2LghJJP(u?sI9mNI2-d+`4&gX1#UH(?u+8YB;{ zVBgDT;uWCeAT)u);Q+H7cSOm8;6|^e?|&woytY80=b*u+n=J3MCa!SO(hbxo3f0=@ zC!TF!a5in$(MQ>v&zki!-}K|##Aax~cKgJ$*FTiDdPFIPPSFV2sU;hq-eEdpW*Ya| zq|aN=E@D)l{MOMijEy;Yb8pQ)Kb0WwrJ`J}onBMDU*s4ZnRV8uyESd|&qwv*45I8} zd`vO|d{Qz!77?A39S`_6WHZ{cRH!}3Inex%_g}y0f8M++erBt4d_|kHuB_KNz}M+> z>C3g4d431N)QzWZOw{O#a!^kXQoJdCqa}u;Rq=?MhU`M777>n>f|rz2oL0yyN;_F7 znl!9$nK*6l{;gY0ryPoPek1N>`SQ}0Ke3l;BV8>8!l!IqtrB#5h8Ek5-%ZleXZ`i% zeg7|dp>}xg{FI_+{|}wzoA>Y9y^!tc&X48fm#)6|{>P(Nms?Mremv#%+_zlrM@3Yx zE?&3q$KgAxx%R!k!2CTtFuO=;QLOcLwHU$oYvcvhFU8yz7Or?G|FuVK{fo0P(K9xj zU2eDF@u`0-XUz6gFU>bSzxvs~tlN*zhj+AVx)&c&&wu+)%qseJ+))vZ=U;TsOwO0D zxxF{^>xKP`zfF?Q&R=@jSK{l*#UGD)8=2?aIrpvn>zyy@(NoI~o?rOhZ|BprUF-k+ zjp$gOcI%(YN|U&V@4L=h?mTv0<^HMtQw#ea^VEfyUC{rsm2lovm;JeB zd*1_*#1E~0Q{Ox_QQh?8m|#}AZ|2U!x2r9ZcOII2SD~A`R%(0svBD*X9{!1oudI%o zaliQ*&o#ry(sQ=W(PC>Wrmpdtey_alv&Y=Si;d#eTy0;o`ic!13 zS2>?8TPEpwmU7Q0M*Fprn^wJ! zoaZOzSG@PsRvG^3y?slk^4n~`wnT438t-f|-C0v~7nioq<)1o#0{aZ7y+?Czy({$m z9q{@ohg*kt@q(nkjhlpJTaV7EaBcdMR%)Spq~`wfhpk5?D|37279ZQh`f5?dO}}f~ zoR=@xD7u`!oK62xYyV@mjMcg9t0(ND1QEQ(xaq=ga=>06mTXbBy_QE+G#PP@rfV*%PKau zv^IwM0@qJ3KW}XCCtZSdae_+YojZ3zSBL%m|KI-nqlKaq&c{EJ3KW_%KP+fo#FSGH z;-<_9OWcwWSRiI_U*>B`Ax~$*t%Uv3uf1LmS)3)qV>-*bo{5-4It;HMuVC|NK z-CqN>c0T+6`PLiG_WN6GtoI)M8hq`~-ltzTu20Xai~3mH9{TXgwWAl?pZ4j+p5K*O zeYpF)xZPRdSnERH1y9TWi&rYPpZayvZ^Qj<2E6OE{=E2{W$JBkdG)uyhx%{3Zr>?; zF2p+QjN$K$=Zl4HW(wc!*?Xqq$Gda)w;F$bB;2<6r7>&8Db`QIVt@Uoz1zR3VE4LT z8;zzv+v~oZB~o8g+&J@F){Lb=QlA1&TDU&vS)K8DYP#?x^`E-YZ!~xQKGW8+dUud% z-YfU`0MS<=er9tHSy#seyLsL{a)bX`PI}z2JDG+V(OValexI%Ic*dE?!b#e{w7RA` zPrd1<^J@Fl6ieB6XSWqEe>wk*wEt@>Jp=i>4=*K!M6Rgb9I9D5sdm*5_V&NhVdYtQ zm;S$c@cVt^B*E+2TUj`_sVo+*x%5eMv)K2Kb6<9@opn8E@5d{9p6Yh{bWhXL-x8;v zd-uSqHx;G6KbEb|du^$`rfI*&iER0f#5+&^)M>kyemu-ME$aG{Z>Njr%*c7YCC+`` z_jB7sZk{`vz4!3d@a3OR-q>;c$qd){=QH=@K3euo_)g8LZ~s}<^s4@=d89eso_TFP zf3ciV?6vo`TOPWuhfFY5lA!}n43L(|bKfXckh(6_jnG z=ZN$iV_{&p!pguPi@h=BoKcjYn@A|no(-<`2@V&rf3alIS}{$HD4+BT3-`P{9mbPn zzIxliSHc%U*G5QYIc|_$z1Zuj_M)h3l~m) z#B(lU%Q^lJ%Aei7zxsD?(%PRTlFg&(i_fJ$LXZvBDd5IFU zmd*8Bem8G>gbs(|T)*XEt2MhOd8n{BaP48wr#PH@N4+HN5mJQ4i3<3>&4!jPG z9t<1|iVWfm$sFyCzU_$(%MQL|*)6Lh=D<;66|lN-k%JOr6T?D*9TOY=UuVrRJS@QH zG=Z^=?G~q>^$pzw$A*#x!OgRnyqJWTI21W{e%NJKQx~9;2K7k?@h18c$8mx+%PFgKrIA#iLQhefaqC3FcNwLMi z+oZw4eVNItn`!G#E!i@$e_{NVT_Oozc67MKzSd5cXOn48S~*AfiA%qy|Cye|B!;%! zkQ2|eL#MyHy+u{`iAQj}Ox3fWC*JGdoGf9xoj>}Th`CMwtQtui2a(?RIlo z%U|2|yZUT%ZFXFEmAO@{-`e!X=2U$?V7aO;qf_f` z&Gj2M-a5BtUX4G_SF`J1;L)33CeOXPxuiRtckU$pQ)^!D`04h`>)%X?!p(*R3WgTp>r1t%rO{??jujKE4zV-LLm-px0v`T*S^wHDV?}Lo>&zzH8 zc|S$(gx~pTxuJh76%`jxJ+n4LSMSY^f5G3E+*q!im7{s@o?utrq*=SOZ!;$yHnN{S zeL`4+ewgfFz-GRbRHmEFsA9Rq*oWNmppeX`2?BPx#= z0_zs3?biGA=)=CZJL7GPcAgFHJ64dl-uJ!4=S{op-~IjZx_VLhjaxC7gG_&KULO&? zNt!!MX7?~3y4FWHj+*j0u4 zZr-ZCQ}U-@p$WqnDz9P?N$jbC3MM4kV6 z=wH*xXKd4VUsYWRI9pqvJx_f@L!wAe(?oW)_?iIzB|p4ll)aihU-mjB+#Mu&r(5W@7?FS7^u8SN}=<%Cvdf)bOx>20j<=Oix&_ zdi~Cvdz{uEbG@(V%g%jJGAUZ`>t3g0!r$&0JZ^R}-^TVnPh&&Z+?&5v+C;B-@^R6R zU;mTd@m&7R(_eMluD(}e&#co%2aPUrQQEMcVAuQxi>oZuKUmE5!$zBN5I~d zMjNY+e&=7^*A-To*>20V@2}=_x0Us$eqS-K{3R^<*I8_Rb+N&_)o!N051x!WlPz!c z{^$4WzrBt>6m@gWV$)sw_3G!eqnmDY_zGm&gse&3Z17d-^OxzR{OeV6|JAA=x{`nJ zh?w3*vCA8-slKiYQK{9NVV3M0bT((FQClYCLop{ko&Vw|SDt?|Z~3}4sm2qnCtY+& z3ZBp!7j?dGz1Y7?l6yY$mHWg!4~c!g{r?@ih5QpACOtQ566v<vecd+s7WdtA=Qf6K61=;mui5nR zB3Ie$$;lPlW6M*2&zbtJ_I&ZWE}4yjTQx4*T$yrg(Uu1fjz}xUhR+v`4e=Ms-_lW@ zb9ejG-JGl0j-NYk#@4z&=-cyod!@4rwXz;_zPr)+^4b~mOY5fSKPsTR*1=DUg4%!lbB%n%leJd-tVK`GdW$yyn?>q>DjhO@#LT?$Vea$yUuvH| z(ti;VA-aCnez$dLm$&M^s+}3`5-L*ke50Q5Zq4*J8{c~E>-fJoVd`V`op0}%tc{i} znSA(n*)#36|L*SpyKH&g^x9KuCjU>$pIsTf{dmi3&Rx|n&p%AvzpHD$=jVDKuN(XS zF5eZDw(jHRshU~Vw-5da{dsnZ|IzMw#`+I$X_x%o^!xgJYbICm&iU2Sdn(u8DLSp* z|3_A2-}<%PfxmNP4+NB~fBIMNvA_M>{%!hy&uZ4!t~&dqR5g6M*XlVuJEI@}R^0rZ zalgma%WLP~ij%8fdPe%l_BR(^@mwzDycyV7y}Tr+mzRG|+UILWuLh*ZGABQ%n!f9U z(6UqA-p}_&2L5P1{QJ`EBh9z(M?IPUWBZ$y!W^%O-Vt%S!jHw@u9?zd>-Jmz&i^@k z(%g@oR@wPsmP((d&m{dNPv&Q()Yw+7|9Rf4%>R1PIhmY6;&@ zI|P5dUUk}YGgK{`;V=RKAm#-ZG3jv zIf1yVpT6{VJv*JhO1taGn|H7FMi&*$UwXze|GN5TOPBalxf3S8+oe~$E@|8U&Bxt? z^0jRWPkj#C^7q60^ZqxF+E~u{pQl|_603VTF2roR;;E#rb19FXiMXEZtiGRrw@ztC z@5U!<4yS8&E|5H1`uthWMZ+(je$OykUHfqDB6r?(iGkOuHr)DX7kQm#SLz zNayoB&$`>v-|h!(&D*nL`lQ<9uKHzc!FOKuU)--|Y;M2h)Q@V{?|-(uFP^R!e=e?M zOTg!k%b!-SO_PnV{h0Xfd-|`=jpcsZmvz=9&G}LM{z&{A)`{uW-rrZHg>H0TXK~}` zoHI{y%ua8*Vtwgy>s)KaqR_11pzx!ct(r` z%;meeJLjz4_G6j<${7oUie3AEM$YP4@nLRd9j`m>E(k^+9{=X|{U&a?tG*bVceEps)*Sz;RK5wQ@ z=P=8^8XNTe|J(z&+RNq6iJy;sQe!`Fx96X&r>$pOyKOs_<9JldZ2DSb$#*|~F3*Xr zUAOnrmV+smbnmVAR^OmwEM{9^@^i-LMd3BaTkT$&ihfs#o_Z~Bc7@5c-vhmp4y@#&Xe=c+LpS4ov)AZc_`RAseUOjEi8}XT?sXrGTd3V%D{*ZW4^!mEe zWzRC5uXl5|er3JQ6=$1tch?H{m`H`o882%d`}fXY{)2O7v~6WYepzQgN_g+0yu_>- zd1qhx1)i0(pMG!q%s7#n3d!^5J#~V)5!*N zckhpmjPs}qi{G(we&(#4&r#{7)8D%a%9;L|?j)}NT`=tbgb$}IOs=2W|Kq^(MG>d( z7w*oU_J6~JOk3rA$(Yi@%4u$K>s)spUO%Ulefqk{|A&`6^x{8%T*bHl-IvwuN9rpK zRF>Ov&;knMVfWjv)Up?P+PIDnATH*S_-1j_a z55O~41_l}Ig{wz?aYiQfo0NjgMa9M8YoosY|6gCdPN+^{{{ADTi&QM^*DkTys4?~6 zUJb*whcXT>dZ5F`w#>|5{P={9Yugih9NT#-cKrVve`m)zZnPu*9I z$+-0S_?*rhS2jI&Wh3*Jskt*B6l#39t2cSa`BRh6{C{g<`15Gba`x2Z(Ac%&=gRjg zPN~-X7qGef?31NDYb$LO^Pjy7SzWx@^tzXkJZmya6b9s8GSM00L9P69seOvf3IDNbM&zW+;l{=Dc z{cpUoyZRw>H}kx?fA>ym-m3dKa#?Hr_v0`8k8QhH&-|`Pzp_v@;7@AcG+{cv`Q)6#sayC(Mx zp1(M^Y0=rpV!5s9ZCih=&8?g)y8gwMf~VTK7rlL@4o+9gwG!C7bJv@YTVG%KUtNFL zF0btDJ%Nv&9{-X-TRG3URN9z=R!HwKJGZhzlb7?w%@fDcI5}}y7dg(746k2+4H? z33s?|H2R)0cfo|f$?S*u(^CBtAFtL^6^QWJeuZ)N0%`Lc{%_x>z1csv`uy3Q&;Om< zslLBBzxG+9iT!*9d4><(_g9}_`Y_@1wga~($Irhce}%ciNzHK?lZ0Wy^2;ZG&-{AQ zKxIA8PQ4lOD#t1gACf-Ref#aRk21$M>SS+?I-6$fdl@{)6{5x2G~r}Q(8>@UG456; zo(F6XHWxGKG>9JHabQ+pkZllZV3@$@!FYthiJ|A*CP{dx~hmNehy^y9M-i_nfZo3O0W4K&ErG>O59%}CSZsDjubHhZOs z!AcJwJ&M>l=lNdOwPryfOAjtEo$1jQcq50ita`~|!3RZa#rqwfhTa zKGkl!DNTyxXpN-A&hYv^Rz$Gf8>?_ zNzcixzm{86Dv=(2!D8+6tSikSdF!VoO!+kJ3`>+?uh7w|l^&{XXBZ}Ye(R(mrD*B2 zljEhJk;0Xx38D)fTaF19DYpD{V{U10&o-HL?bs*};;+R|sMw;fnE^;Y?RjYW&@WeunP%CKCpWUM)t;}-^?I9s zU+9xHEHOK4?hD!Mv?*Max$4&s@88d4zumXF-q%*O{LG5I`*=^v|0=z{ZsMM`%dd)> z$1=H2Guv@M?S;+rntOqBBuol6m@U|oUbr$Px^(KbKWTrtt?!8bDS6&o@%HMj=r8lC zyEfd7(~Md0D$vXP>p9i>pY^~zy6i| zCjO3;d%_!yXS?Oa+LYYbU-|CG`New=N(%aR2QQQ6en0>Jhso1Ri{-1QlncgxJNc_j zsGhA_#%k*(fzJmDjqVuce#w!W`CcZic6#=`YdqKHW!B6oR7&|$wD;KR#Gv`Mxw~>T zs*diq`h90&cGcmVzOR~|a379dcVVBk*Ks57Npn`#8aA)L&tq8D*)DzS+^ZF#)j7Ej z57u5?#S{N;uS3-<#-m?FuAW36c7$JEN?YnI-WABvqOycUVvLTHz2pQ7Bs} zF!;?KXkX}SCN+`Gp2 zw?{8O6KAe(q9nrb?Bw;+MGQZnTyp*O)vT>f3nzFjRhrmw{&}&5 z49^4R1pjn~3KN8KQj;S7G@c<4Kok4FuZhJ&$g9GBxpjH!x45n z_IaNUKdowUa?@GH+4S`8qN~@WctqWj8*lmqO*!*&%8nSrJoEFf=jzHaUq3Ed)sp1q zbAiQkVpR9FfNX;>iLtIt!S121Ttsny|uD zO8d++rm*zo!Ox03@4S;(KfV3GAA=p6CYvc+%fYtBV-FI`+ZfB4w=u6{TEpnWAofrC zkG%0e={ei%t!PZ{`7ml3XWE+ zSyO-V_VeGuFSN6J%&TO=t?OnBojH?Z|Mlce!*{c@@BR7}(fvO!sB+cTb;m81Yy5v< z`v1K5^Sf_ky)V4oB_6AA^Vgm5nJbNN&Z^40p?1k_Yv0~Wk?U+q_C7THt8%2;e#fp= zJL4{|u@cqRx40`mD{yoCwlzhGZZYZcr%t~VuL$-O?mo0DUOMB=pHG_)FY0SuEcUkX zMR#lNpy|2s?$*eA-+$l9p7nRxg2j(l`>pxI`u|Gl{oq@(7x?Us`8)5y!E4rq zFF&rHtduRJ?DJdv(X-+5wX{8{=x#mh=Uz^siU>skbN2SmgGHI^U>M4)@+A#D z+gOnH_}2A&-SYb}&z|;vke?e9X=ifRZ0_{^mI(!4n^mXRpV{J@{;Yq~dyXfPH#dDN zIlB*|Onb8A@Ovf(hFz>UN0t0i^NDGNVHs5lf{v!|eQV0g!*hm*(N1yQbpQG32|vyo zaJe1yVA{EJ=jyPvzyANPpLf(*8+X?yVP7X~SiNrdn+=S|AI1Ow{eEt4K;;~v-L=2Z ztNxZUH(If-TIa{d`?JE!bHuJ5zg6{Sme78s*xS#NuRMR1S(AR>Znn+u>c_|W+i#w} zduh+vz12rq>q9tPHq~#i5&W_0+0(1WiPy!Bny#I#x8ci&``XhUF}*fXGsvCHHFHmA zY5tG24v-h#DzbdD`Lql%Pu0@~rp6Y#YDA+yu8SAE}=67cY6=x+KEIO_Be8puq zZocX#8(p}!a(&ego}c~N_Vx1o>|0KWd~>zC`PXd?nWPb_YrOU57X|OU@AJQk`q?bmA0{8aT(HS*p~-Br^3YisZB z&?s&y><@UbQReL;UrpDT;PAgQ;9+KC{W|OP^!jxR?A!mdF5C51@XhNr=_{7%O}RF`d~;Y|g*ny&I^|Hoz5a*b}z_y|<2;fx(0gXVV}! zF*Ca|-zg_CIh#<^083UXVgL`&KDj;bi63;O4RmHIOG4rw!%B9ZdOm|ckq17gH$LoV zJ}l45meUaOb#a0SPuz#Mwx2~6j^bW=6Y~)|bX&FC=jMdR#bNhO{{PS2H@nmLoU!Np z|F?1$2c2g*y7Ts{+Vv;@C;U7A+*tHXeRl0?`=e=68|Mc630*SbUE!S4!WX~J zO>u1%|E`s9v3&i9*NIV+ugsHm>;C5b_g3iDnrD>>Rm=RpeEh8|R=n@km#A-s`H!Y% zyzutl@U<%?aiXqW)xy6oS5BF7V%ojUF@>w+)+8pDStRT2{`Bg}i}F0ndz?vY3EIlD*JMudtX#HW!(Ez@BaJn|J!fwtjWK-=WP_=+V`@daFJ^X9NbIp~r?`!7u z75oIaP0O$yZUk&CYe_y5qy&?ypa(TW!2M_|fj~;r3=b z{>~~qm%Qoh8+J}xu9bqni+YpHxYj+oUvTclpPeUqWzMIm>AWoYazk~O>8pgvi3cma z1tYhfH{!qMGBskZWohcaxzjw0W|!COE&6%s6u;`k*DhM;wi%hkoX^`Cka6|;!);*? zCU1OpdTHdrslr_H^=T1bj+}~4JalE*g}wW~-SG1ET0S??^xTXaCugaq%@zI?6S(_f z;>k;vSI>()kMrODJt6Lp+1DlSwqCj+{Q3Uz;vIMDzwiAp_15kWlW%`-`SE7{*3GU3 zae;5XXii!k%wI8gwS}V8%6oOs8Z-X6tP`y}t9o)`{4P10ReX;umZ)!jc{z01@jbWs z)o*2}>zB@){UP+{s*I_>r?ji5$JJUre){bHeElWmZ)<;6yqtVoo^}2Ht?O@EJ^!`F z;Px?2^&3t5*Uh-Ib@T7eHjDPD@78ju@hczR|8S+=@g<*c*{W`xyuFD>*zVo$pDq1U z&zkedsJp1XW zyKsWk>f~oLLmGK}4D}atoI7V**en0~%f=PaZgcrJpIuo0X4Bh;@HIK#@7&+{{mJ*; zzfWI_T;^Y!r^Vp2eVth@!-)k`ExhNhT(dalYh8nnMskF4gFN#z70;8Og(p9cJX%?H zXoFEi&&SIg_N7NtBEvo`(%@hvN3zx!Z3`wk_1?Qt@n3Fp=VAo4`2b zwkrdp0+#^W0|tQx=>vQR7y=kn7#J5Y9*{_poKof@$ilcNkfXivF@s{k?t^*kZH!$^ zlUSM<&bl1@|C+JYM>2&|MbL$@MZ@K=z_SMDhC2_oHP2;iW9nj=#Nfp2|MOy&>fSgL z36@!575tVmb?dhud|u4jtaE;Ll3}t^-~_LimtJ;0Gt5X`8+S?Cg<1E4&Uq^*zV-KC zXMbRgb)5G!d0E7v86KibF75ilBDEn*`}NmJ2Nf=DIk0KZVZl#Tf9>L(4PFG5^d0r- zY%!dw<*~f<$9pCPg8+#)5&~@oY>drI=Gniy^t=}`_ig%VLue}@{|8yl|_wrLWKNLNA za%?Tbs>0QoqS5=xOD;EfS zSxl~;#Ic>{!N)zatHt#0+WmgG^kLQMKbpET)!R?x+Z9+;r!0H&`n%uPs}riNra$BH zw=+FiQyzY~W|dX+t|`H5W?qZ0u<$=8eObT%l~A{v(dU}{YdZO7ewNL?r?TswVa{reiL<8v_`U4UmV~-#|685>&Fl4}OE+w>f1JK}b;i@i zZ+9+S4BstP9zWB_C_lP2>#g0Zlj8l`zq9SDYMv*2=Hk5=nVW?+-m&JluGQ>Zbo=S9 z3m3mWS#)mOxq_t6_e%E6_Uc;Q{^zXui{kStrRpnIZ#7N%RQu@q<CT*ZG2XKRb7-DmJyQ`fS9$pZR_t3`-nJyneqFSXk?1V1 zH9OPK-v7I^tuW6ach{a*tBSnty1zrO_S5N)_wL(!r>u{evEOxlr2XPD_fNV{`x~zAIaji6 zOVN3>b-ry|8&zsq85kPb7#NhX4^2Qzsbpf7`hv$M!Uf`76&x;TJlG;2qU-N#>T-q2 zQK_ke<&d)2gpL&xo7%WcI9|=n(#Uw>;?g6OBO-8gf#w36!=>!ENB`xe|5{&tZr;t!zu#I~-#;gI+@<~YZL8Z%4YfyhU9e#2&N#G9F;YO? zS$U?4jKJY%ZHyg-2fkL>J`DHCZEf;i(PXV^v2lk*U;UO3{azg>Q z`e{`mPA3lqfe#fnX0y+x7-gDBP4!ZpeA1$Uv!NoEyMa-I@d<+v1B(K~1I7)EGZ;)5 zv=}5Ajvq{6S|qbp%z$T#*M!rKN{lTI3Jh}mH*yk;8r_(+L{9{B{$J0}VdR@|sX2~2 zipM}zu$g2876+B{me&Q3NP=zxV1#=*dwhSHInffVq(w4y)G~1TDM4bi|gCv z*LJ?{={u%r@<62P z_XI)3ITOX>^3(P4zJnVB<$5gdt~po>kgK&ppq*pEh5T zW70R?hg*-Y&Dm3~FJqFj@0rc7hw8lAS-bx4ns}_(^wENQyQ1~~CN-HvpZ><_*Ei89 zbP?aBr3{~5Cdip>JW{{#Sjk7rw==(9mY!IeI=y7=nNw=z)7LQ`KKSfe-0Q7}w{jlTW^!NbU76D-FXnn5kCln~KI7!4eqNixKfY74{%FSC3zBYQ= z)|0v}?_2xvI1lUjuD_1t8b)vJ46BY#)^ zf2UF_e&I#c{Dljr{CSr8^Uou5;Xg->f91zVT)e)|-2P_YE3@kKVGB{;tqYvK8LwP0_3}~eGis?8vZv!U?|plF?22^Y z-{M_TM}(Jc+kLT@{}hiXV?Mt~?CFVo;_j^9Vg%K`Ieh$l$F=9*uD#}0@5;rceGD&; zXMgfy&QfpQ+~esMopq`^7y19St9S3Wn3gv$eNErq(tg25``yKD*Lz&A%8uU^9&}=F ziu}i;7f<`m+oLSamv6tn{@EAP^kUYyz!2%19V<@V`s^2Va#hg0yLN$1Q~jRo&fIgk z_Cea`g{-Ts*Wb&JJumm*%^th!#}|Fs`}B^~w}1$r>lm>U7KVK5r)YT-N))%?L`^5~Hf*+#KMc+kdUCN?UhGx&4GZt$Jt7~N z_TISv*607%H}mFhPT#+|`q}R^e~!h6rs>7)lwg?V*77--AxAZ2PsT#st$a&%&tAd8 z!MaF*!IX2!&75VQe!MwSDEM?o#x;+u4v$GS!V~l77_GkQ^^mj4K!V3=uHWjbSte2~ z6JqqHdo5*ZY&iXN6KDw9bMZwF25p8?YsLhI3yc|zCJY=7dNLxK57@zxc|lT2c$$D%wjWUY+>ZFx{&F( znvs`Dg?*>U5+;Fy#?x$O!ZS=N4)f2=OWVl7cl^NPz&+xpQ?htYhpY_Z;&!z-m!I*$ zSSr?6t?j7MZ5z%K?YXIGg&ch64+uY0irmN(oV>~>G|@{@?~wElUN`&2C$FX?MxpGZ?U-C)C%!Zg7~A@V=l|KnZ%+03W(UK5GZTlKpuaJ$-E3#II1NnbUY zVoqs`{mT3ycVhm`bIa5X98WOFsfs(vaeNf$a@CMk6m>ev@lqhmZH2TVx08yh34`;w zi8T|}UVnX8R>>@|x>`p??Do`YJ+il!do&pw-S^}SZ>s3-AjW5BTs|~?Pf8t6P{Nn-rt|nw9isw)r<1SrO$QmJ%0DGFM4u&cU;`*i~Y~pzLb@8 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 utQMi1973EOs5_;R?J)d{)egkIX grafx2/src/version.c || exit 1 +} || exit 1 diff --git a/project/jni/application/grafx2/android.patch b/project/jni/application/grafx2/android.patch new file mode 100644 index 000000000..6181faf90 --- /dev/null +++ b/project/jni/application/grafx2/android.patch @@ -0,0 +1,111 @@ +Index: src/text.c +=================================================================== +--- src/text.c (revision 2067) ++++ src/text.c (working copy) +@@ -419,9 +419,9 @@ + + // Text rendering: creates a 8bit surface with its dedicated palette + if (antialias) +- text_surface=TTF_RenderText_Shaded(font, str, fg_color, bg_color ); ++ text_surface=TTF_RenderUTF8_Shaded(font, str, fg_color, bg_color ); + else +- text_surface=TTF_RenderText_Solid(font, str, fg_color); ++ text_surface=TTF_RenderUTF8_Solid(font, str, fg_color); + if (!text_surface) + { + TTF_CloseFont(font); +Index: src/mountlist.c +=================================================================== +--- src/mountlist.c (revision 2067) ++++ src/mountlist.c (working copy) +@@ -41,7 +41,7 @@ + #define MOUNTED_GETFSSTAT 1 + #define HAVE_SYS_MOUNT_H 1 + #include +-#elif defined(__SKYOS__) ++#elif defined(__SKYOS__)||defined(__ANDROID__) + #warning "Your platform is missing some specific code here ! please check and fix :)" + #else + #define MOUNTED_GETMNTENT1 +Index: src/io.c +=================================================================== +--- src/io.c (revision 2067) ++++ src/io.c (working copy) +@@ -455,7 +455,7 @@ + + byte Create_lock_file(const char *file_directory) + { +- #if defined (__amigaos__)||(__AROS__) ++ #if defined (__amigaos__)||(__AROS__)||(__ANDROID__) + #warning "Missing code for your platform, please check and correct!" + #else + char lock_filename[MAX_PATH_CHARACTERS]; +Index: src/setup.c +=================================================================== +--- src/setup.c (revision 2067) ++++ src/setup.c (working copy) +@@ -93,6 +93,8 @@ + // Append trailing slash + strcat(program_dir,PATH_SEPARATOR); + // Linux: argv[0] unreliable ++ #elif defined(__ANDROID__) ++ strcpy(program_dir, "./"); + #elif defined(__linux__) + if (argv0[0]!='/') + { +@@ -122,7 +124,7 @@ + #if defined(__macosx__) + strcat(data_dir,"Contents/Resources/"); + // On GP2X, executable is not in bin/ +- #elif defined (__GP2X__) || defined (__gp2x__) || defined (__WIZ__) || defined (__CAANOO__) ++ #elif defined (__GP2X__) || defined (__gp2x__) || defined (__WIZ__) || defined (__CAANOO__) || defined(__ANDROID__) + strcat(data_dir,"share/grafx2/"); + //on tos the same directory + #elif defined (__MINT__) +Index: src/sdlscreen.c +=================================================================== +--- src/sdlscreen.c (revision 2067) ++++ src/sdlscreen.c (working copy) +@@ -54,6 +54,8 @@ + #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE + #elif defined(__MINT__) + #define UPDATE_METHOD UPDATE_METHOD_CUMULATED ++ #elif defined(__ANDROID__) ++ #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE + #else + #define UPDATE_METHOD UPDATE_METHOD_CUMULATED + #endif +Index: src/readline.c +=================================================================== +--- src/readline.c (revision 2067) ++++ src/readline.c (working copy) +@@ -50,6 +50,9 @@ + #include + #include + #endif ++#if defined(__ANDROID__) ++#include ++#endif + + // Virtual keyboard is ON by default on these platforms: + #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) +@@ -400,6 +403,10 @@ + // Nothing. The caller should have initialized a valid hexa number. + } + ++#if defined(__ANDROID__) ++ SDL_ANDROID_GetScreenKeyboardTextInput(str, max_size); ++ input_key = SDLK_RETURN; ++#else + // Virtual keyboards + if (Config.Use_virtual_keyboard==1 || + (VIRT_KEY_DEFAULT_ON && Config.Use_virtual_keyboard==0)) +@@ -757,7 +764,7 @@ + Mouse_K=old_mouse_k; + Input_sticky_control=0; + } +- ++#endif // defined(__ANDROID__) + // 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); diff --git a/project/jni/application/grafx2/grafx2/src/SDLMain.h b/project/jni/application/grafx2/grafx2/src/SDLMain.h deleted file mode 100644 index 4683df57a..000000000 --- a/project/jni/application/grafx2/grafx2/src/SDLMain.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SDLMain.m - main entry point for our Cocoa-ized SDL app - Initial Version: Darrell Walisser - Non-NIB-Code & other changes: Max Horn - - Feel free to customize this file to suit your needs -*/ - -#import - -@interface SDLMain : NSObject -@end diff --git a/project/jni/application/grafx2/grafx2/src/SFont.c b/project/jni/application/grafx2/grafx2/src/SFont.c deleted file mode 100644 index 23de8ce0f..000000000 --- a/project/jni/application/grafx2/grafx2/src/SFont.c +++ /dev/null @@ -1,224 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* SFont: a simple font-library that uses special .pngs as fonts - Copyright (C) 2003 Karl Bartel - - License: GPL or LGPL (at your choice) - WWW: http://www.linux-games.com/sfont/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - Karl Bartel - Cecilienstr. 14 - 12307 Berlin - GERMANY - karlb@gmx.net -*/ -#include -#include - -#include -#include -#include "SFont.h" - -static Uint32 GetPixel(SDL_Surface *Surface, Sint32 X, Sint32 Y) -{ - Uint8 *bits; - Uint32 Bpp; - - assert(X>=0); - assert(Xw); - - Bpp = Surface->format->BytesPerPixel; - bits = ((Uint8 *)Surface->pixels)+Y*Surface->pitch+X*Bpp; - - // Get the pixel - switch(Bpp) { - case 1: - return *((Uint8 *)Surface->pixels + Y * Surface->pitch + X); - break; - case 2: - return *((Uint16 *)Surface->pixels + Y * Surface->pitch/2 + X); - break; - case 3: { // Format/endian independent - Uint8 r, g, b; - r = *((bits)+Surface->format->Rshift/8); - g = *((bits)+Surface->format->Gshift/8); - b = *((bits)+Surface->format->Bshift/8); - return SDL_MapRGB(Surface->format, r, g, b); - } - break; - case 4: - return *((Uint32 *)Surface->pixels + Y * Surface->pitch/4 + X); - break; - } - - return -1; -} - -SFont_Font* SFont_InitFont(SDL_Surface* Surface) -{ - int x = 0, i = 33; - Uint32 pixel; - SFont_Font* Font; - Uint32 pink; - - if (Surface == NULL) - return NULL; - - Font = (SFont_Font *) malloc(sizeof(SFont_Font)); - memset(Font, 0, sizeof(SFont_Font)); - - Font->Surface = Surface; - - SDL_LockSurface(Surface); - - pink = GetPixel(Surface, 0, 0); - while (x < Surface->w) { - if (GetPixel(Surface, x, 0) != pink) { - Font->CharBegin[i]=x; - while((x < Surface->w) && (GetPixel(Surface, x, 0)!= pink)) - x++; - Font->CharWidth[i]=x-Font->CharBegin[i]; - i++; - } - x++; - } - - // 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); - // No longer use SDL color keying - //SDL_SetColorKey(Surface, SDL_SRCCOLORKEY, pixel); - Font->Transparent=pixel; - - return Font; -} - -void SFont_FreeFont(SFont_Font* FontInfo) -{ - SDL_FreeSurface(FontInfo->Surface); - free(FontInfo); -} - -void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, - int x, int y, const char *text) -{ - const char* c; - SDL_Rect srcrect, dstrect; - - if(text == NULL) - return; - - // these values won't change in the loop - srcrect.y = 1; - dstrect.y = y; - srcrect.h = dstrect.h = Font->Surface->h - 1; - - for(c = text; *c != '\0' && x <= Surface->w ; c++) { - if (*c == '\n') { - dstrect.y += Font->Surface->h-1; - x=0; - continue; - } - // skip spaces and nonprintable characters - else if (*c == ' ' || Font->CharWidth[(int)*c]==0) { - x += Font->Space; - continue; - } - - srcrect.w = Font->CharWidth[(int)*c]; - dstrect.w = srcrect.w; - srcrect.x = Font->CharBegin[(int)*c]; - dstrect.x = x; - - SDL_BlitSurface(Font->Surface, &srcrect, Surface, &dstrect); - - x += Font->CharWidth[(int)*c]; - } -} - -int SFont_TextWidth(const SFont_Font *Font, const char *text) -{ - const char* c; - int width = 0; - int previous_width = 0; - - if(text == NULL) - return 0; - - for(c = text; *c != '\0'; c++) - { - if (*c == '\n') - { - if (previous_widthCharWidth[(int)*c]==0) - { - width += Font->Space; - continue; - } - - width += Font->CharWidth[(int)*c]; - } - - return previous_widthSurface->h - 1) * (nb_cr+1); -} - -/* -// Do not use: Doesn't implement carriage returns - -void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font *Font, - int y, const char *text) -{ - SFont_Write(Surface, Font, Surface->w/2 - SFont_TextWidth(Font, text)/2, - y, text); -} -*/ diff --git a/project/jni/application/grafx2/grafx2/src/SFont.h b/project/jni/application/grafx2/grafx2/src/SFont.h deleted file mode 100644 index 446acf4eb..000000000 --- a/project/jni/application/grafx2/grafx2/src/SFont.h +++ /dev/null @@ -1,100 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* SFont: a simple font-library that uses special bitmaps as fonts - Copyright (C) 2003 Karl Bartel - - License: GPL or LGPL (at your choice) - WWW: http://www.linux-games.com/sfont/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . - - Karl Bartel - Cecilienstr. 14 - 12307 Berlin - GERMANY - karlb@gmx.net -*/ - -/************************************************************************ -* SFONT - SDL Font Library by Karl Bartel * -* * -* All functions are explained below. For further information, take a * -* look at the example files, the links at the SFont web site, or * -* contact me, if you problem isn' addressed anywhere. * -* * -************************************************************************/ -////////////////////////////////////////////////////////////////////////////// -///@file SFont.h -/// Text rendering system, that uses bitmaps as fonts. -/// Not specific to Grafx2, it writes to SDL_Surface. -////////////////////////////////////////////////////////////////////////////// - - -#ifndef _SFONT_H_ -#define _SFONT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/// -/// Declare one variable of this type for each font you are using. -/// To load the fonts, load the font image into YourFont->Surface -/// and call InitFont( YourFont ); -typedef struct { - SDL_Surface *Surface; - int CharBegin[256]; - int CharWidth[256]; - int Space; - unsigned char Transparent; -} SFont_Font; - -/// -/// Initializes the font. -/// @param Font this contains the suface with the font. -/// The Surface must be loaded before calling this function -SFont_Font* SFont_InitFont (SDL_Surface *Font); - -/// -/// Frees the font. -/// @param Font The font to free -/// The font must be loaded before using this function. -void SFont_FreeFont(SFont_Font* Font); - -/// -/// Blits a string to a surface. -/// @param Surface The surface you want to blit to. -/// @param Font The font to use. -/// @param text A string containing the text you want to blit. -/// @param x Coordinates to start drawing. -/// @param y Coordinates to start drawing. -void SFont_Write(SDL_Surface *Surface, const SFont_Font *Font, int x, int y, - const char *text); - -/// Returns the width of "text" in pixels -int SFont_TextWidth(const SFont_Font* Font, const char *text); -/// Returns the height of "text" in pixels (which is always equal to Font->Surface->h) -int SFont_TextHeight(const SFont_Font* Font, const char *text); - -/// Blits a string to Surface with centered x position -void SFont_WriteCenter(SDL_Surface *Surface, const SFont_Font* Font, int y, - const char *text); - -#ifdef __cplusplus -} -#endif - -#endif /* SFONT_H */ diff --git a/project/jni/application/grafx2/grafx2/src/brush.c b/project/jni/application/grafx2/grafx2/src/brush.c deleted file mode 100644 index f30015058..000000000 --- a/project/jni/application/grafx2/grafx2/src/brush.c +++ /dev/null @@ -1,1944 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Franck Charlet - Copyright 2007-2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see - -******************************************************************************** - - Brush manipulation functions -*/ - -#include -#include -#include // memset() - -#include "global.h" -#include "graph.h" -#include "misc.h" -#include "errors.h" -#include "windows.h" -#include "sdlscreen.h" -#include "brush.h" - - -// Calcul de redimensionnement du pinceau pour éviter les débordements de -// l'écran et de l'image -void Compute_clipped_dimensions(short * x,short * y,short * width,short * height) -{ - if ((*x)(Limit_right+1)) - { - (*width)=(Limit_right-(*x))+1; - } - - if ((*y)(Limit_bottom+1)) - { - (*height)=(Limit_bottom-(*y))+1; - } -} - - // -- Calcul de redimensionnement du pinceau pour éviter les débordements - // de l'écran zoomé et de l'image -- - -void Compute_clipped_dimensions_zoom(short * x,short * y,short * width,short * height) -{ - if ((*x)(Limit_right_zoom+1)) - { - (*width)=(Limit_right_zoom-(*x))+1; - } - - if ((*y)(Limit_bottom_zoom+1)) - { - (*height)=(Limit_bottom_zoom-(*y))+1; - } -} - - - // -- Afficher le pinceau (de façon définitive ou non) -- - -void Display_paintbrush(short x,short y,byte color,byte is_preview) - // x,y: position du centre du pinceau - // color: couleur à appliquer au pinceau - // is_preview: "Il ne faut l'afficher qu'à l'écran" -{ - short start_x; // Position X (dans l'image) à partir de laquelle on - // affiche la brosse/pinceau - short start_y; // Position Y (dans l'image) à partir de laquelle on - // affiche la brosse/pinceau - short width; // width dans l'écran selon laquelle on affiche la - // brosse/pinceau - short height; // height dans l'écran selon laquelle on affiche la - // brosse/pinceau - short start_x_counter; // Position X (dans la brosse/pinceau) à partir - // de laquelle on affiche la brosse/pinceau - short start_y_counter; // Position Y (dans la brosse/pinceau) à partir - // de laquelle on affiche la brosse/pinceau - short x_pos; // Position X (dans l'image) en cours d'affichage - short y_pos; // Position Y (dans l'image) en cours d'affichage - short counter_x; // Position X (dans la brosse/pinceau) en cours - // d'affichage - short counter_y; // Position Y (dans la brosse/pinceau) en cours - // d'affichage - short end_counter_x; // Position X ou s'arrête l'affichade de la - // brosse/pinceau - short end_counter_y; // Position Y ou s'arrête l'affichade de la - // brosse/pinceau - byte temp_color; // color de la brosse en cours d'affichage - int position; - byte * temp; - - if (is_preview==0 || Mouse_K==0) // pas de curseur si on est en preview et - // en train de cliquer - switch (Paintbrush_shape) - { - case PAINTBRUSH_SHAPE_NONE : // No paintbrush. for colorpicker for example - break; - case PAINTBRUSH_SHAPE_POINT : // !!! TOUJOURS EN PREVIEW !!! - if ( (Paintbrush_X>=Limit_left) - && (Paintbrush_X<=Limit_right) - && (Paintbrush_Y>=Limit_top) - && (Paintbrush_Y<=Limit_bottom) ) - { - Pixel_preview(Paintbrush_X,Paintbrush_Y,color); - Update_part_of_screen(x,y,1,1); - } - break; - - case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur - - start_x=x-Brush_offset_X; - start_y=y-Brush_offset_Y; - width=Brush_width; - height=Brush_height; - Compute_clipped_dimensions(&start_x,&start_y,&width,&height); - if (width<=0 || height<=0) - break; - start_x_counter=start_x-(x-Brush_offset_X); - start_y_counter=start_y-(y-Brush_offset_Y); - end_counter_x=start_x_counter+width; - end_counter_y=start_y_counter+height; - - if (is_preview != 0) - { - if ( (width>0) && (height>0) ) - Display_brush_color( - start_x-Main_offset_X, - start_y-Main_offset_Y, - start_x_counter, - start_y_counter, - width, - height, - Back_color, - Brush_width - ); - - if (Main_magnifier_mode != 0) - { - Compute_clipped_dimensions_zoom(&start_x,&start_y,&width, - &height - ); - - start_x_counter=start_x-(x-Brush_offset_X); - start_y_counter=start_y-(y-Brush_offset_Y); - - if ( (width>0) && (height>0) ) - { - // Corrections dues au Zoom: - start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; - start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; - height=start_y+(height*Main_magnifier_factor); - if (height>Menu_Y) - height=Menu_Y; - - Display_brush_color_zoom(Main_X_zoom+start_x,start_y, - start_x_counter,start_y_counter, - width,height,Back_color, - Brush_width, - Horizontal_line_buffer); - } - } - - Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height); - - } - else - { - if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) - { - if (Smear_start != 0) - { - if ((width>0) && (height>0)) - { - Copy_part_of_image_to_another( - Main_screen, start_x, start_y, width, height, - Main_image_width, Smear_brush, - start_x_counter, start_y_counter, - Smear_brush_width - ); - - Update_part_of_screen(start_x,start_y,width,height); - } - Smear_start=0; - } - else - { - for (y_pos = start_y, counter_y = start_y_counter; - counter_y < end_counter_y; - y_pos++, counter_y++ - ) - for (x_pos = start_x, counter_x = start_x_counter; - counter_x < end_counter_x; - x_pos++, counter_x++ - ) - { - temp_color = Read_pixel_from_current_screen( - x_pos,y_pos - ); - position = (counter_y * Smear_brush_width)+ counter_x; - if ( (Read_pixel_from_brush(counter_x,counter_y) != Back_color) - && (counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) ) - Display_pixel(x_pos,y_pos,Smear_brush[position]); - Smear_brush[position]=temp_color; - } - - Update_part_of_screen(start_x,start_y,width,height); - } - - Smear_min_X=start_x_counter; - Smear_min_Y=start_y_counter; - Smear_max_X=end_counter_x; - Smear_max_Y=end_counter_y; - } - else - { - if (Shade_table==Shade_table_left) - for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0) ) - Display_brush_mono(start_x-Main_offset_X, - start_y-Main_offset_Y, - start_x_counter,start_y_counter, - width,height, - Back_color,Fore_color, - Brush_width); - - if (Main_magnifier_mode != 0) - { - Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); - start_x_counter=start_x-(x-Brush_offset_X); - start_y_counter=start_y-(y-Brush_offset_Y); - - if ( (width>0) && (height>0) ) - { - // Corrections dues au Zoom: - start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; - start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; - height=start_y+(height*Main_magnifier_factor); - if (height>Menu_Y) - height=Menu_Y; - - Display_brush_mono_zoom(Main_X_zoom+start_x,start_y, - start_x_counter,start_y_counter, - width,height, - Back_color,Fore_color, - Brush_width, - Horizontal_line_buffer); - - } - } - - Update_part_of_screen(x-Brush_offset_X,y-Brush_offset_Y,Brush_width,Brush_height); - } - else - { - if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) - { - if (Smear_start != 0) - { - if ((width>0) && (height>0)) - { - Copy_part_of_image_to_another(Main_screen, - start_x,start_y, - width,height, - Main_image_width, - Smear_brush, - start_x_counter, - start_y_counter, - Smear_brush_width); - Update_part_of_screen(start_x,start_y,width,height); - } - Smear_start=0; - } - else - { - for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) ) - Display_pixel(x_pos,y_pos,Smear_brush[position]); - Smear_brush[position]=temp_color; - } - - Update_part_of_screen(start_x,start_y,width,height); - - } - - Smear_min_X=start_x_counter; - Smear_min_Y=start_y_counter; - Smear_max_X=end_counter_x; - Smear_max_Y=end_counter_y; - } - else - { - for (y_pos=start_y,counter_y=start_y_counter;counter_y0) && (height>0) ) - Display_brush_mono(start_x-Main_offset_X, - start_y-Main_offset_Y, - start_x_counter,start_y_counter, - width,height, - 0,Fore_color, - MAX_PAINTBRUSH_SIZE); - - if (Main_magnifier_mode != 0) - { - Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); - start_x_counter=start_x-(x-Paintbrush_offset_X); - start_y_counter=start_y-(y-Paintbrush_offset_Y); - - if ( (width>0) && (height>0) ) - { - // Corrections dues au Zoom: - start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; - start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; - height=start_y+(height*Main_magnifier_factor); - if (height>Menu_Y) - height=Menu_Y; - - Display_brush_mono_zoom(Main_X_zoom+start_x,start_y, - start_x_counter,start_y_counter, - width,height, - 0,Fore_color, - MAX_PAINTBRUSH_SIZE, - Horizontal_line_buffer); - - } - } - - Brush=temp; - } - else - { - if ((Smear_mode != 0) && (Shade_table==Shade_table_left)) - { - if (Smear_start != 0) - { - if ((width>0) && (height>0)) - { - Copy_part_of_image_to_another(Main_screen, - start_x,start_y, - width,height, - Main_image_width, - Smear_brush, - start_x_counter, - start_y_counter, - Smear_brush_width); - Update_part_of_screen(start_x,start_y,width,height); - } - Smear_start=0; - } - else - { - for (y_pos=start_y,counter_y=start_y_counter;counter_y=Smear_min_Y) && (counter_x>=Smear_min_X) - // On clippe l'effet smear entre Smear_Min et Smear_Max - ) - Display_pixel(x_pos,y_pos,Smear_brush[position]); - Smear_brush[position]=temp_color; - } - Update_part_of_screen(start_x, start_y, width, height); - } - - - Smear_min_X=start_x_counter; - Smear_min_Y=start_y_counter; - Smear_max_X=end_counter_x; - Smear_max_Y=end_counter_y; - } - else - { - for (y_pos=start_y,counter_y=start_y_counter;counter_yMAX_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) ) - { - new_brush_remapped=(byte *)malloc(((long)new_brush_height)*new_brush_width); - if (new_brush_remapped == NULL) - { - Error(0); - 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; - - if (new_smear_brush) - { - free(Smear_brush); - Smear_brush=new_smear_brush; - } - 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; -} - - -// -- Effacer le pinceau -- // -// -void Hide_paintbrush(short x,short y) - // x,y: position du centre du pinceau -{ - short start_x; // Position X (dans l'image) à partir de laquelle on - // affiche la brosse/pinceau - short start_y; // Position Y (dans l'image) à partir de laquelle on - // affiche la brosse/pinceau - short width; // width dans l'écran selon laquelle on affiche la - // brosse/pinceau - short height; // height dans l'écran selon laquelle on affiche la - // brosse/pinceau - short start_x_counter; // Position X (dans la brosse/pinceau) à partir - // de laquelle on affiche la brosse/pinceau - short start_y_counter; // Position Y (dans la brosse/pinceau) à partir - // de laquelle on affiche la brosse/pinceau - //short x_pos; // Position X (dans l'image) en cours d'affichage - //short y_pos; // Position Y (dans l'image) en cours d'affichage - //short counter_x; // Position X (dans la brosse/pinceau) en cours - //d'affichage - //short counter_y; // Position Y (dans la brosse/pinceau) en cours d'affichage - short end_counter_x; // Position X ou s'arrête l'affichage de la brosse/pinceau - short end_counter_y; // Position Y ou s'arrête l'affichage de la brosse/pinceau - byte * temp; - - if (Mouse_K == 0) - switch (Paintbrush_shape) - { - case PAINTBRUSH_SHAPE_POINT : - if ( (Paintbrush_X>=Limit_left) - && (Paintbrush_X<=Limit_right) - && (Paintbrush_Y>=Limit_top) - && (Paintbrush_Y<=Limit_bottom) ) - { - Pixel_preview(Paintbrush_X,Paintbrush_Y,Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y)); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - } - break; - case PAINTBRUSH_SHAPE_COLOR_BRUSH : // Brush en couleur - case PAINTBRUSH_SHAPE_MONO_BRUSH : // Brush monochrome - start_x=x-Brush_offset_X; - start_y=y-Brush_offset_Y; - width=Brush_width; - height=Brush_height; - Compute_clipped_dimensions(&start_x,&start_y,&width,&height); - start_x_counter=start_x-(x-Brush_offset_X); - start_y_counter=start_y-(y-Brush_offset_Y); - end_counter_x=start_x_counter+width; - end_counter_y=start_y_counter+height; - - if ( (width>0) && (height>0) ) - Clear_brush(start_x-Main_offset_X, - start_y-Main_offset_Y, - start_x_counter,start_y_counter, - width,height,Back_color, - Main_image_width); - - if (Main_magnifier_mode != 0) - { - Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); - start_x_counter=start_x; - start_y_counter=start_y; - - if ( (width>0) && (height>0) ) - { - // Corrections dues au Zoom: - start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; - start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; - height=start_y+(height*Main_magnifier_factor); - if (height>Menu_Y) - height=Menu_Y; - - Clear_brush_scaled(Main_X_zoom+start_x,start_y, - start_x_counter,start_y_counter, - width,height,Back_color, - Main_image_width, - Horizontal_line_buffer); - } - } - break; - default: // Pinceau - start_x=x-Paintbrush_offset_X; - start_y=y-Paintbrush_offset_Y; - width=Paintbrush_width; - height=Paintbrush_height; - Compute_clipped_dimensions(&start_x,&start_y,&width,&height); - start_x_counter=start_x-(x-Paintbrush_offset_X); - start_y_counter=start_y-(y-Paintbrush_offset_Y); - end_counter_x=start_x_counter+width; - end_counter_y=start_y_counter+height; - - temp=Brush; - Brush=Paintbrush_sprite; - - if ( (width>0) && (height>0) ) - { - Clear_brush(start_x-Main_offset_X, - start_y-Main_offset_Y, - start_x_counter,start_y_counter, - width,height,0, - Main_image_width); - } - - if (Main_magnifier_mode != 0) - { - Compute_clipped_dimensions_zoom(&start_x,&start_y,&width,&height); - start_x_counter=start_x; - start_y_counter=start_y; - - if ( (width>0) && (height>0) ) - { - // Corrections dues au Zoom: - start_x=(start_x-Main_magnifier_offset_X)*Main_magnifier_factor; - start_y=(start_y-Main_magnifier_offset_Y)*Main_magnifier_factor; - height=start_y+(height*Main_magnifier_factor); - if (height>Menu_Y) - height=Menu_Y; - - Clear_brush_scaled(Main_X_zoom+start_x,start_y, - start_x_counter,start_y_counter, - width,height,0, - Main_image_width, - Horizontal_line_buffer); - } - } - - Brush=temp; - break; - } -} - - - -void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear) -{ - short temp; - short x_pos; - short y_pos; - word new_brush_width; - word new_brush_height; - - - // On commence par "redresser" les bornes: - if (start_x>end_x) - { - temp=start_x; - start_x =end_x; - end_x =temp; - } - if (start_y>end_y) - { - temp=start_y; - start_y =end_y; - end_y =temp; - } - - // On ne capture la nouvelle brosse que si elle est au moins partiellement - // dans l'image: - - if ((start_xMain_image_width) - new_brush_width=Main_image_width-start_x; - 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, 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); - - // On regarde s'il faut effacer quelque chose: - if (clear != 0) - { - for (y_pos=start_y;y_pos>1); - Brush_offset_Y=(Brush_height>>1); - } -} - - -void Rotate_90_deg(void) -{ - byte * old_brush; - - if (Realloc_brush(Brush_height, Brush_width, NULL, &old_brush)) - { - 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); -} - - -void Remap_brush(void) -{ - short x_pos; // Variable de balayage de la brosse - short y_pos; // Variable de balayage de la brosse - int color; - - - // On commence par initialiser le tableau de booléens à faux - for (color=0;color<=255;color++) - 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(old_brush); // Libération de l'ancienne brosse - -} - - -void Nibble_brush(void) -{ - long x_pos,y_pos; - byte state; - byte * old_brush; - word old_width; - word old_height; - int i; - - if ( (Brush_width>2) && (Brush_height>2) ) - { - 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)) - { - 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); - - // 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 (old_brush[((y_pos+1)*old_width)+x_pos+1]==Back_color) - Pixel_in_brush(x_pos-1,y_pos,Back_color); - } - - // 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); - - } -} - - - -void Capture_brush_with_lasso(int vertices, short * points,short clear) -{ - short start_x=Limit_right+1; - short start_y=Limit_bottom+1; - short end_x=Limit_left-1; - short end_y=Limit_top-1; - unsigned short temp; - short x_pos; - short y_pos; - word new_brush_width; - word new_brush_height; - - // On recherche les bornes de la brosse: - for (temp=0; temp<2*vertices; temp+=2) - { - x_pos=points[temp]; - y_pos=points[temp+1]; - if (x_posend_x) - end_x=x_pos; - if (y_posend_y) - end_y=y_pos; - } - - // On clippe ces bornes à l'écran: - if (start_xLimit_right) - end_x=Limit_right; - if (start_yLimit_bottom) - end_y=Limit_bottom; - - // On ne capture la nouvelle brosse que si elle est au moins partiellement - // dans l'image: - - if ((start_x>1); - Brush_offset_Y=(Brush_height>>1); - } -} - - - -//------------------------- Etirement de la brosse --------------------------- - -void Stretch_brush(short x1, short y1, short x2, short y2) -{ - byte * new_brush; - int new_brush_width; // Width de la nouvelle brosse - int new_brush_height; // Height de la nouvelle brosse - int x_flipped, y_flipped; - - // Compute new brush dimensions - if ((new_brush_width=x1-x2)<0) - { - x_flipped=1; - new_brush_width=-new_brush_width; - } - new_brush_width++; - - if ((new_brush_height=y1-y2)<0) - { - y_flipped=1; - new_brush_height=-new_brush_height; - } - new_brush_height++; - - new_brush=((byte *)malloc(new_brush_width*new_brush_height)); - if (!new_brush) - { - 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); - -} - - - -void Stretch_brush_preview(short x1, short y1, short x2, short y2) -{ - int src_x_pos,src_y_pos; - int initial_src_x_pos,initial_src_y_pos; - int delta_x,delta_y; - int dest_x_pos,dest_y_pos; - int initial_dest_x_pos,initial_dest_y_pos; - int final_dest_x_pos,final_dest_y_pos; - int dest_width,dest_height; - byte color; - - - // 1er calcul des positions destination extremes: - initial_dest_x_pos=Min(x1,x2); - initial_dest_y_pos=Min(y1,y2); - final_dest_x_pos =Max(x1,x2); - final_dest_y_pos =Max(y1,y2); - - // Calcul des dimensions de la destination: - dest_width=final_dest_x_pos-initial_dest_x_pos+1; - dest_height=final_dest_y_pos-initial_dest_y_pos+1; - - // Calcul des vecteurs d'incrémentation : - delta_x=(Brush_width<<16)/dest_width; - delta_y=(Brush_height<<16)/dest_height; - - // 1er calcul de la position X initiale dans la source: - initial_src_x_pos=(Brush_width<<16)* - (Max(initial_dest_x_pos,Limit_left)- - initial_dest_x_pos)/dest_width; - // Calcul du clip de la destination: - initial_dest_x_pos=Max(initial_dest_x_pos,Limit_left); - final_dest_x_pos =Min(final_dest_x_pos ,Limit_visible_right); - // On discute selon l'inversion en X - if (x1>x2) - { - // Inversion -> Inversion du signe de delta_x - delta_x=-delta_x; - initial_src_x_pos=(Brush_width<<16)-1-initial_src_x_pos; - } - - // 1er calcul de la position Y initiale dans la source: - initial_src_y_pos=(Brush_height<<16)* - (Max(initial_dest_y_pos,Limit_top)- - initial_dest_y_pos)/dest_height; - // Calcul du clip de la destination: - initial_dest_y_pos=Max(initial_dest_y_pos,Limit_top); - final_dest_y_pos =Min(final_dest_y_pos ,Limit_visible_bottom); - // On discute selon l'inversion en Y - if (y1>y2) - { - // Inversion -> Inversion du signe de delta_y - delta_y=-delta_y; - initial_src_y_pos=(Brush_height<<16)-1-initial_src_y_pos; - } - - // Pour chaque ligne : - src_y_pos=initial_src_y_pos; - for (dest_y_pos=initial_dest_y_pos;dest_y_pos<=final_dest_y_pos;dest_y_pos++) - { - // Pour chaque colonne: - src_x_pos=initial_src_x_pos; - for (dest_x_pos=initial_dest_x_pos;dest_x_pos<=final_dest_x_pos;dest_x_pos++) - { - color=Read_pixel_from_brush(src_x_pos>>16,src_y_pos>>16); - if (color!=Back_color) - Pixel_preview(dest_x_pos,dest_y_pos,color); - - src_x_pos+=delta_x; - } - - src_y_pos+=delta_y; - } - Update_part_of_screen(initial_dest_x_pos,initial_dest_y_pos,dest_width,dest_height); -} - -/// Returns the minimum of 4 integers. -int Min4(long int a, long int b, long int c, long int d) -{ - if (ab) - if (c>d) - return a>c?a:c; - else - return a>d?a:d; - else - if (c>d) - return b>c?b:c; - else - return b>d?b:d; -} - -// Recursive function for linear distortion. -void Draw_brush_linear_distort(unsigned long int tex_min_x, - unsigned long int tex_min_y, - unsigned long int tex_max_x, - unsigned long int tex_max_y, - long int x1, - long int y1, - long int x2, - long int y2, - long int x3, - long int y3, - long int x4, - long int y4) -{ - static byte color; - // bounding rectangle - static long int min_x, max_x, min_y, max_y; - - min_x=Min4(x1,x2,x3,x4); - max_x=Max4(x1,x2,x3,x4); - min_y=Min4(y1,y2,y3,y4); - max_y=Max4(y1,y2,y3,y4); - - if ((max_x>>16) - (min_x>>16) <= 1 && (max_y>>16) - (min_y>>16) <= 1) - //if (max_x - min_x <= 1<<16 && max_y - min_y <= 1<<16) - { - if ((min_x<(max_x&0x7FFF0000)) && (min_y<(max_y&0x7FFF0000))) - { - color=Read_pixel_from_brush((tex_min_x)>>16,(tex_min_y)>>16); - if (color!=Back_color) - Pixel_for_distort(min_x>>16,min_y>>16,color); - } - return; - } - // Cut in 4 quarters and repeat - // "top left" - Draw_brush_linear_distort(tex_min_x, - tex_min_y, - (tex_min_x+tex_max_x)>>1, - (tex_min_y+tex_max_y)>>1, - x1, - y1, - (x1+x2)>>1, - (y1+y2)>>1, - (x1+x2+x3+x4)>>2, - (y1+y2+y3+y4)>>2, - (x1+x4)>>1, - (y1+y4)>>1); - - // "top right" - Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1, - tex_min_y, - tex_max_x, - (tex_min_y+tex_max_y)>>1, - (x1+x2)>>1, - (y1+y2)>>1, - x2, - y2, - (x2+x3)>>1, - (y2+y3)>>1, - (x1+x2+x3+x4)>>2, - (y1+y2+y3+y4)>>2); - - // "bottom right" - Draw_brush_linear_distort((tex_min_x+tex_max_x)>>1, - (tex_min_y+tex_max_y)>>1, - tex_max_x, - tex_max_y, - (x1+x2+x3+x4)>>2, - (y1+y2+y3+y4)>>2, - (x2+x3)>>1, - (y2+y3)>>1, - x3, - y3, - (x3+x4)>>1, - (y3+y4)>>1); - - // "bottom left" - Draw_brush_linear_distort(tex_min_x, - (tex_min_y+tex_max_y)>>1, - (tex_min_x+tex_max_x)>>1, - tex_max_y, - (x1+x4)>>1, - (y1+y4)>>1, - (x1+x2+x3+x4)>>2, - (y1+y2+y3+y4)>>2, - (x3+x4)>>1, - (y3+y4)>>1, - x4, - y4); - - return; -} - -/// Draws a distorted version of the brush, mapped over the given quad (picture coordinates). -void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4) -{ - Pixel_for_distort=Pixel_figure_preview; - 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)); -} - -/// Modifies the current brush, mapping it over the given quad. -void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4) -{ - short min_x, max_x, min_y, max_y; - short width, height; - byte * new_brush; - - // Move all coordinates to start on (0,0) - min_x=Min4(x1,x2,x3,x4); - max_x=Max4(x1,x2,x3,x4); - min_y=Min4(y1,y2,y3,y4); - max_y=Max4(y1,y2,y3,y4); - - x1-=min_x; - x2-=min_x; - x3-=min_x; - x4-=min_x; - - y1-=min_y; - y2-=min_y; - y3-=min_y; - y4-=min_y; - - width=Max(max_x-min_x, 1); - height=Max(max_y-min_y, 1); - - new_brush=((byte *)malloc((long)width*height)); - if (!new_brush) - { - // Out of memory while allocating new brush - Error(0); - return; - } - - // Fill the new brush with backcolor, originally. - memset(new_brush,Back_color,((long)width)*height); - - // Call distort routine - Pixel_for_distort=Pixel_in_distort_buffer; - Distort_buffer=new_brush; - 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)); - - 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); - Brush_offset_Y=(Brush_height>>1); - -} - -//------------------------- Rotation de la brosse --------------------------- - -#ifndef NAN - #define NAN (-1.0e20F) - #define isnan(x) ((x)==NAN) -#endif -float * ScanY_Xt[2]; -float * ScanY_Yt[2]; -float * ScanY_X[2]; - - -void Interpolate_texture(int start_x,int start_y,int xt1,int yt1, - int end_x ,int end_y ,int xt2,int yt2,int height) -{ - int x_pos,y_pos; - int incr_x,incr_y; - int i,cumul; - int delta_x,delta_y; - int delta_xt=xt2-xt1; - int delta_yt=yt2-yt1; - int delta_x2=end_x-start_x; - int delta_y2=end_y-start_y; - float xt,yt; - - - x_pos=start_x; - y_pos=start_y; - - if (start_xdelta_y) - { - cumul=delta_x>>1; - for (i=0; i<=delta_x; i++) - { - if (cumul>=delta_x) - { - cumul-=delta_x; - y_pos+=incr_y; - } - - if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos]) - { - if (isnan(ScanY_X[1][y_pos]) // Droit non défini - || (x_pos>ScanY_X[1][y_pos])) - { - ScanY_X[1][y_pos]=(float)x_pos; - ScanY_Xt[1][y_pos]=xt; - ScanY_Yt[1][y_pos]=yt; - } - } - else - { - if (isnan(ScanY_X[1][y_pos])) // Droit non défini - { - ScanY_X[1][y_pos]=ScanY_X[0][y_pos]; - ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos]; - ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos]; - ScanY_X[0][y_pos]=(float)x_pos; - ScanY_Xt[0][y_pos]=xt; - ScanY_Yt[0][y_pos]=yt; - } - else - { - ScanY_X[0][y_pos]=(float)x_pos; - ScanY_Xt[0][y_pos]=xt; - ScanY_Yt[0][y_pos]=yt; - } - } - } - } - x_pos+=incr_x; - cumul+=delta_y; - } - } - else - { - cumul=delta_y>>1; - for (i=0; i<=delta_y; i++) - { - if (cumul>=delta_y) - { - cumul-=delta_y; - x_pos+=incr_x; - } - - if ((y_pos>=0) && (y_pos=ScanY_X[0][y_pos]) - { - if (isnan(ScanY_X[1][y_pos]) // Droit non défini - || (x_pos>ScanY_X[1][y_pos])) - { - ScanY_X[1][y_pos]=(float)x_pos; - ScanY_Xt[1][y_pos]=xt; - ScanY_Yt[1][y_pos]=yt; - } - } - else - { - if (isnan(ScanY_X[1][y_pos])) // Droit non défini - { - ScanY_X[1][y_pos]=ScanY_X[0][y_pos]; - ScanY_Xt[1][y_pos]=ScanY_Xt[0][y_pos]; - ScanY_Yt[1][y_pos]=ScanY_Yt[0][y_pos]; - ScanY_X[0][y_pos]=(float)x_pos; - ScanY_Xt[0][y_pos]=xt; - ScanY_Yt[0][y_pos]=yt; - } - else - { - ScanY_X[0][y_pos]=(float)x_pos; - ScanY_Xt[0][y_pos]=xt; - ScanY_Yt[0][y_pos]=yt; - } - } - } - } - y_pos+=incr_y; - cumul+=delta_x; - } - } -} - - - -void Compute_quad_texture(int x1,int y1,int xt1,int yt1, - int x2,int y2,int xt2,int yt2, - int x3,int y3,int xt3,int yt3, - int x4,int y4,int xt4,int yt4, - byte * buffer, int width, int height) -{ - int x_min,/*x_max,*/y_min/*,y_max*/; - int x,y,xt,yt; - int start_x,end_x,line_width; - float temp; - //byte color; - - x_min=Min(Min(x1,x2),Min(x3,x4)); - y_min=Min(Min(y1,y2),Min(y3,y4)); - - ScanY_Xt[0]=(float *)malloc(height*sizeof(float)); - ScanY_Xt[1]=(float *)malloc(height*sizeof(float)); - ScanY_Yt[0]=(float *)malloc(height*sizeof(float)); - ScanY_Yt[1]=(float *)malloc(height*sizeof(float)); - ScanY_X[0] =(float *)malloc(height*sizeof(float)); - ScanY_X[1] =(float *)malloc(height*sizeof(float)); - - // Fill_general avec des valeurs égales à NAN. - for (y=0; y=0 && yt>=0) - buffer[x+(y*width)]=*(Brush_original_pixels + yt * Brush_width + xt); - } - for (; x>1); - start_y=1-(Brush_height>>1); - end_x=start_x+Brush_width-1; - end_y=start_y+Brush_height-1; - - Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); - Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); - Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); - Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); - - // Calcul des nouvelles dimensions de la brosse: - x_min=Min(Min((int)x1,(int)x2),Min((int)x3,(int)x4)); - x_max=Max(Max((int)x1,(int)x2),Max((int)x3,(int)x4)); - y_min=Min(Min((int)y1,(int)y2),Min((int)y3,(int)y4)); - y_max=Max(Max((int)y1,(int)y2),Max((int)y3,(int)y4)); - - new_brush_width=x_max+1-x_min; - new_brush_height=y_max+1-y_min; - - new_brush=(byte *)malloc(new_brush_width*new_brush_height); - - if (!new_brush) - { - 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); - -} - - - -void Draw_quad_texture_preview(int x1,int y1,int xt1,int yt1, - int x2,int y2,int xt2,int yt2, - int x3,int y3,int xt3,int yt3, - int x4,int y4,int xt4,int yt4) -{ - int x_min,x_max,y_min,y_max; - int x,y,xt,yt; - int y_,y_min_; - int start_x,end_x,width,height; - float temp; - byte color; - - x_min=Min(Min(x1,x2),Min(x3,x4)); - x_max=Max(Max(x1,x2),Max(x3,x4)); - y_min=Min(Min(y1,y2),Min(y3,y4)); - y_max=Max(Max(y1,y2),Max(y3,y4)); - height=1+y_max-y_min; - - ScanY_Xt[0]=(float *)malloc(height*sizeof(float)); - ScanY_Xt[1]=(float *)malloc(height*sizeof(float)); - ScanY_Yt[0]=(float *)malloc(height*sizeof(float)); - ScanY_Yt[1]=(float *)malloc(height*sizeof(float)); - ScanY_X[0] =(float *)malloc(height*sizeof(float)); - ScanY_X[1] =(float *)malloc(height*sizeof(float)); - - // Fill_general avec des valeurs égales à NAN. - for (y=0; yLimit_bottom) y_max=Limit_bottom; - - for (y_=y_min; y_<=y_max; y_++) - { - y=y_-y_min_; - start_x=Round(ScanY_X[0][y]); - end_x =Round(ScanY_X[1][y]); - - width=1+end_x-start_x; - - if (start_xLimit_right) end_x=Limit_right; - - for (x=start_x; x<=end_x; x++) - { - temp=(float)(0.5+(float)x-ScanY_X[0][y])/(float)width; - 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) - { - color=Read_pixel_from_brush(xt,yt); - if (color!=Back_color) - Pixel_preview(x,y_,color); - } - } - } - - free(ScanY_Xt[0]); - free(ScanY_Xt[1]); - free(ScanY_Yt[0]); - free(ScanY_Yt[1]); - free(ScanY_X[0]); - free(ScanY_X[1]); - - ScanY_Xt[0] = ScanY_Xt[1] = ScanY_Yt[0] = ScanY_Yt[1] = ScanY_X[0] = ScanY_X[1] = NULL; -} - - -void Rotate_brush_preview(float angle) -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - int start_x,end_x,start_y,end_y; - float cos_a=cos(angle); - float sin_a=sin(angle); - - // Calcul des coordonnées des 4 coins: - // 1 2 - // 3 4 - - start_x=1-(Brush_width>>1); - start_y=1-(Brush_height>>1); - end_x=start_x+Brush_width-1; - end_y=start_y+Brush_height-1; - - Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); - Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); - Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); - Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); - - x1+=Brush_rotation_center_X; - y1+=Brush_rotation_center_Y; - x2+=Brush_rotation_center_X; - y2+=Brush_rotation_center_Y; - x3+=Brush_rotation_center_X; - y3+=Brush_rotation_center_Y; - x4+=Brush_rotation_center_X; - y4+=Brush_rotation_center_Y; - - // Et maintenant on dessine la brosse tournée. - Draw_quad_texture_preview(x1,y1, 0, 0, - x2,y2,Brush_width-1, 0, - x3,y3, 0,Brush_height-1, - x4,y4,Brush_width-1,Brush_height-1); - start_x=Min(Min(x1,x2),Min(x3,x4)); - end_x=Max(Max(x1,x2),Max(x3,x4)); - start_y=Min(Min(y1,y2),Min(y3,y4)); - 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/project/jni/application/grafx2/grafx2/src/brush.h b/project/jni/application/grafx2/grafx2/src/brush.h deleted file mode 100644 index 9682b1fed..000000000 --- a/project/jni/application/grafx2/grafx2/src/brush.h +++ /dev/null @@ -1,129 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007-2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file brush.h -/// Actions on the brush. -////////////////////////////////////////////////////////////////////////////// - -#ifndef __BRUSH_H_ -#define __BRUSH_H_ - -#include "struct.h" - -/*! - Gets the brush from the picture. - @param start_x left edge coordinate in the picture - @param start_y upper edge coordinate in the picture - @param end_x right edge coordinate in the picture - @param end_y bottom edge coordinate in the picture - @param clear If 1, the area is also cleared from the picture. -*/ -void Capture_brush(short start_x,short start_y,short end_x,short end_y,short clear); - -/*! - Rotates the brush to the right. -*/ -void Rotate_90_deg(void); - -/*! - Stretch the brush to fit the given rectangle. -*/ -void Stretch_brush(short x1, short y1, short x2, short y2); - -/*! - Stretch the brush to fit the given rectangle. - Uses fast approximation for the preview while drawing the rectangle on screen. -*/ -void Stretch_brush_preview(short x1, short y1, short x2, short y2); - -/*! - Rotates the brush to the right from the given angle. -*/ -void Rotate_brush(float angle); - -/*! - Stretch the brush to fit the given rectangle. - Uses fast approximation for the preview while changing the angle. -*/ -void Rotate_brush_preview(float angle); - -/*! - Remap the brush palette to the nearest color in the picture one. - Used when switching to the spare page. -*/ - -/*! - Distort the brush on the screen. -*/ -void Distort_brush_preview(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4); - -/*! - Replace the brush by a distorted version of itself. -*/ -void Distort_brush(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4); - - -void Remap_brush(void); - -/*! - Get color indexes used by the brush. -*/ -void Get_colors_from_brush(void); - -/*! - Outline the brush, add 1 foreground-colored pixel on the edges. - Edges are detected considering the backcolor as transparent. -*/ -void Outline_brush(void); - -/*! - Nibble the brush, remove 1 pixel on the edges and make it transparent (ie filled with back color). - Edges are detected considering the backcolor as transparent. -*/ -void Nibble_brush(void); - -/*! - Get brush from picture according to a freehand form. - @param vertices number of points in the freehand form - @param points array of points coordinates - @param clear If set to 1, the captured area is also cleared from the picture. -*/ -void Capture_brush_with_lasso(int vertices, short * points,short clear); - - -/// -/// 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/project/jni/application/grafx2/grafx2/src/brush_ops.c b/project/jni/application/grafx2/grafx2/src/brush_ops.c deleted file mode 100644 index 405ca7537..000000000 --- a/project/jni/application/grafx2/grafx2/src/brush_ops.c +++ /dev/null @@ -1,1392 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 2009 Franck Charlet - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -////////////////////////////////////////////////////////////////////////////// -///@file brush_ops.c -/// Code for operations about the brush (grabbing, rotating, ...) and magnifier -////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "brush.h" -#include "buttons.h" -#include "engine.h" -#include "global.h" -#include "graph.h" -#include "misc.h" -#include "operatio.h" -#include "pages.h" -#include "sdlscreen.h" -#include "windows.h" - -#if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) - #define M_PI 3.141592653589793238462643 -#endif - - -/// Simulates clicking the "Draw" button. -void Return_to_draw_mode(void) -{ - - // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au - // préalable: - Display_cursor(); - if (Mouse_K) - Wait_end_of_click(); - // !!! Efface la croix puis affiche le viseur !!! - Select_button(BUTTON_DRAW,LEFT_SIDE); // Désenclenche au passage le bouton brosse - if (Config.Auto_discontinuous) - { - // On se place en mode Dessin discontinu à la main - while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) - Select_button(BUTTON_DRAW,RIGHT_SIDE); - } - // Maintenant, il faut réeffacer le curseur parce qu'il sera raffiché en fin - // d'appel à cette action: - Hide_cursor(); - - // On passe en brosse couleur: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X: Y:",0); - Print_coordinates(); -} - -// ---------------------------------------------------------- OPERATION_MAGNIFY - - -void Magnifier_12_0(void) - -// Opération : 4 (item d'une Loupe) -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui - -{ - - // On passe en mode loupe - Main_magnifier_mode=1; - - // La fonction d'affichage dans la partie image est désormais un affichage - // spécial loupe. - Pixel_preview=Pixel_preview_magnifier; - - // On calcule l'origine de la loupe - Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); - Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); - - // Calcul des coordonnées absolues de ce coin DANS L'IMAGE - Main_magnifier_offset_X+=Main_offset_X; - Main_magnifier_offset_Y+=Main_offset_Y; - - Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); - - // On calcule les bornes visibles dans l'écran - Position_screen_according_to_zoom(); - Compute_limits(); - Display_all_screen(); - - // Repositionner le curseur en fonction des coordonnées visibles - Compute_paintbrush_coordinates(); - - // On fait de notre mieux pour restaurer l'ancienne opération: - Start_operation_stack(Operation_before_interrupt); - Display_cursor(); - Wait_end_of_click(); -} - - -/////////////////////////////////////////////////////////// OPERATION_COLORPICK - - -void Colorpicker_12_0(void) -// -// Opération : OPERATION_COLORPICK -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - - if (Mouse_K==LEFT_SIDE) - { - Set_fore_color(Colorpicker_color); - } - else - { - Set_back_color(Colorpicker_color); - } - Operation_push(Mouse_K); -} - - -void Colorpicker_1_1(void) -// -// Opération : OPERATION_COLORPICK -// Click Souris: 1 -// Taille_Pile : 1 -// -// Souris effacée: Non -// -{ - char str[4]; - - if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) - && (Paintbrush_X=0) && (Paintbrush_Y>=0) - && (Paintbrush_X=0) && (Paintbrush_Y>=0) - && (Paintbrush_X=Main_X_zoom) ) ) - Print_in_menu("X: Y: ",0); - - Print_coordinates(); - - Display_cursor(); -} - -////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH - - -void Brush_12_0(void) -// -// Opération : OPERATION_GRAB_BRUSH -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - if (Mouse_K==RIGHT_SIDE) // Besoin d'effacer la brosse après ? - { - Operation_push(1); - // Puisque la zone où on prend la brosse sera effacée, on fait un backup - Backup(); - } - else - Operation_push(0); - - // On laisse une trace du curseur pour que l'utilisateur puisse visualiser - // où demarre sa brosse: - Display_cursor(); - - Operation_push(Paintbrush_X); // Début X - Operation_push(Paintbrush_Y); // Début Y - Operation_push(Paintbrush_X); // Dernière position X - Operation_push(Paintbrush_Y); // Dernière position Y - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("\035: 1 \022: 1",0); -} - - -void Brush_12_5(void) -// -// Opération : OPERATION_GRAB_BRUSH -// Click Souris: 1 ou 2 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - char str[5]; - short start_x; - short start_y; - short old_x; - short old_y; - short width; - short height; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) - { - if (Config.Coords_rel) - { - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_push(start_x); - Operation_push(start_y); - - width=((start_x1) width--; - if (height>1) height--; - } - - Num2str(width,str,4); - Print_in_menu(str,2); - Num2str(height,str,4); - Print_in_menu(str,11); - } - else - Print_coordinates(); - } - - Display_all_screen(); - - x=Paintbrush_X; - y=Paintbrush_Y; - if (Snap_mode && Config.Adjust_brush_pick) - { - dx=Paintbrush_X-start_x; - dy=Paintbrush_Y-start_y; - if (dx<0) x++; else {if (dx>0) x--;} - if (dy<0) y++; else {if (dy>0) y--;} - Stretch_brush_preview(start_x,start_y,x,y); - } - else - Stretch_brush_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y); - - old_x=Paintbrush_X; - old_y=Paintbrush_Y; - Paintbrush_X=start_x; - Paintbrush_Y=start_y; - Display_cursor(); - Paintbrush_X=old_x; - Paintbrush_Y=old_y; - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(x); - Operation_push(y); - - Operation_push(start_x); - Operation_push(start_y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(2); -} - - - -void Stretch_brush_0_7(void) -// -// Opération : OPERATION_STRETCH_BRUSH -// Click Souris: 0 -// Taille_Pile : 7 -// -// Souris effacée: Non -// -{ - char str[5]; - short start_x; - short start_y; - short old_x; - short old_y; - short width=0; - short height=0; - byte size_change; - short prev_state; - - Operation_pop(&prev_state); - Operation_pop(&old_y); - Operation_pop(&old_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3)) - { - if (Menu_is_visible) - { - if (Config.Coords_rel) - { - width=((start_x1)?start_x+(Brush_width>>1)-1:1; - height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; - break; - case 'X': // Moitié X - width=(Brush_width>1)?start_x+(Brush_width>>1)-1:1; - height=start_y+Brush_height-1; - break; - case 'Y': // Moitié Y - width=start_x+Brush_width-1; - height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1; - break; - case 'n': // Normal - width=start_x+Brush_width-1; - height=start_y+Brush_height-1; - break; - default : - size_change=0; - } - Key_ANSI=0; - } - else - size_change=0; - - if (size_change) - { - // On efface la preview de la brosse (et la croix) - Display_all_screen(); - - old_x=Paintbrush_X; - old_y=Paintbrush_Y; - Paintbrush_X=start_x; - Paintbrush_Y=start_y; - Display_cursor(); - Paintbrush_X=old_x; - Paintbrush_Y=old_y; - - Stretch_brush_preview(start_x,start_y,width,height); - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(width); - Operation_push(height); - } - - Operation_push(start_x); - Operation_push(start_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(3); -} - - -void Stretch_brush_2_7(void) -// -// Opération : OPERATION_STRETCH_BRUSH -// Click Souris: 2 -// Taille_Pile : 7 -// -// Souris effacée: Oui -// -{ - short computed_x; - short computed_y; - short start_x; - short start_y; - - - Operation_stack_size-=3; - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&computed_y); - Operation_pop(&computed_x); - - // On efface la preview de la brosse (et la croix) - Display_all_screen(); - - // Et enfin on stocke pour de bon la nouvelle brosse étirée - Stretch_brush(start_x,start_y,computed_x,computed_y); - - Return_to_draw_mode(); -} - - -//////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH - - -void Rotate_brush_12_0(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - if (Mouse_K==LEFT_SIDE) - { - Brush_rotation_center_X=Paintbrush_X+(Brush_width>>1)-Brush_width; - Brush_rotation_center_Y=Paintbrush_Y; - Brush_rotation_center_is_defined=1; - Operation_push(Paintbrush_X); // Dernière position calculée X - Operation_push(Paintbrush_Y); // Dernière position calculée Y - Operation_push(Paintbrush_X); // Dernière position X - Operation_push(Paintbrush_Y); // Dernière position Y - Operation_push(1); // State précédent - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("Angle: 0° ",0); - } - else - { - Start_operation_stack(Operation_before_interrupt); - Wait_end_of_click(); // FIXME: celui-la il donne un résultat pas très chouette en visuel - } -} - - - -void Rotate_brush_1_5(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 1 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - char str[4]; - short old_x; - short old_y; - short prev_state; - float angle; - int dx,dy; - - Operation_pop(&prev_state); - Operation_pop(&old_y); - Operation_pop(&old_x); - - // 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) - && (Brush_rotation_center_Y==Paintbrush_Y) ) - angle=0.0; - else - { - dx=Paintbrush_X-Brush_rotation_center_X; - dy=Paintbrush_Y-Brush_rotation_center_Y; - angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); - if (dy>0) angle=M_2PI-angle; - } - - if (Menu_is_visible) - { - if (Config.Coords_rel) - { - Num2str((int)(angle*180.0/M_PI),str,3); - Print_in_menu(str,7); - } - else - Print_coordinates(); - } - - Display_all_screen(); - Rotate_brush_preview(angle); - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(2); -} - - - -void Rotate_brush_0_5(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - char str[4]; - short old_x; - short old_y; - short computed_x=0; - short computed_y=0; - byte angle_change; - short prev_state; - float angle=0.0; - int dx,dy; - - Operation_pop(&prev_state); - Operation_pop(&old_y); - Operation_pop(&old_x); - - // 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) - && (Brush_rotation_center_Y==Paintbrush_Y) ) - angle=0.0; - else - { - dx=Paintbrush_X-Brush_rotation_center_X; - dy=Paintbrush_Y-Brush_rotation_center_Y; - angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); - if (dy>0) angle=M_2PI-angle; - } - - if (Menu_is_visible) - { - if (Config.Coords_rel) - { - Num2str(Round(angle*180.0/M_PI),str,3); - Print_in_menu(str,7); - } - else - Print_coordinates(); - } - } - - // Utilise Key_ANSI au lieu de Key, car Get_input() met ce dernier - // à zero si une operation est en cours (Operation_stack_size!=0) - if (Key_ANSI) - { - angle_change=1; - computed_x=Brush_rotation_center_X; - computed_y=Brush_rotation_center_Y; - switch (Key_ANSI) - { - case '6': angle= 0.0 ; computed_x++; break; - case '9': angle=M_PI*0.25; computed_x++; computed_y--; break; - case '8': angle=M_PI*0.5 ; computed_y--; break; - case '7': angle=M_PI*0.75; computed_x--; computed_y--; break; - case '4': angle=M_PI ; computed_x--; break; - case '1': angle=M_PI*1.25; computed_x--; computed_y++; break; - case '2': angle=M_PI*1.5 ; computed_y++; break; - case '3': angle=M_PI*1.75; computed_x++; computed_y++; break; - default : - angle_change=0; - } - Key_ANSI=0; - } - else - angle_change=0; - - if (angle_change) - { - // On efface la preview de la brosse - Display_all_screen(); - Rotate_brush_preview(angle); - Display_cursor(); - - Operation_stack_size-=2; - Operation_push(computed_x); - Operation_push(computed_y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(3); -} - - -void Rotate_brush_2_5(void) -// -// Opération : OPERATION_ROTATE_BRUSH -// Click Souris: 2 -// Taille_Pile : 5 -// -// Souris effacée: Oui -// -{ - short computed_x; - short computed_y; - int dx,dy; - float angle; - - - // On efface la preview de la brosse - Display_all_screen(); - - Operation_stack_size-=3; - Operation_pop(&computed_y); - Operation_pop(&computed_x); - - // Calcul de l'angle par rapport à la dernière position calculée - if ( (Brush_rotation_center_X==computed_x) - && (Brush_rotation_center_Y==computed_y) ) - angle=0.0; - else - { - dx=computed_x-Brush_rotation_center_X; - dy=computed_y-Brush_rotation_center_Y; - angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy))); - if (dy>0) angle=M_2PI-angle; - } - - // Et enfin on stocke pour de bon la nouvelle brosse étirée - Rotate_brush(angle); - - Return_to_draw_mode(); -} - -///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH - -/// Draws a 2x2 XOR square at the specified picture coordinates, on the screen. -void Draw_stretch_spot(short x_pos, short y_pos) -{ - short x,y; - - for (y=y_pos-1;y=Limit_top && y<=Limit_visible_bottom) - for (x=x_pos-1;x=Limit_left && x<=Limit_visible_right) - Pixel_preview(x,y,~Read_pixel(x-Main_offset_X,y-Main_offset_Y)); - Update_part_of_screen(x_pos-1, y_pos-1, 2, 2); -} - -void Distort_brush_0_0(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 0 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - if ( Menu_is_visible ) - { - Print_in_menu("POSITION BRUSH TO START ",0); - } -} - -void Distort_brush_1_0(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - short x_pos, y_pos; - - Init_start_operation(); - Paintbrush_hidden=1; - Hide_cursor(); - - // Top left angle - x_pos=Paintbrush_X-Brush_offset_X; - y_pos=Paintbrush_Y-Brush_offset_Y; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - // Top right angle - x_pos+=Brush_width; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - // Bottom right angle - y_pos+=Brush_height; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - // Bottom left angle - x_pos-=Brush_width; - Draw_stretch_spot(x_pos,y_pos); - Operation_push(x_pos); - Operation_push(y_pos); - - Distort_brush_preview( - Operation_stack[1], - Operation_stack[2], - Operation_stack[3], - Operation_stack[4], - Operation_stack[5], - Operation_stack[6], - Operation_stack[7], - Operation_stack[8]); - Display_cursor(); - Update_part_of_screen(Paintbrush_X-Brush_offset_X, Paintbrush_Y-Brush_offset_Y, Brush_width, Brush_height); - Wait_end_of_click(); - // Erase the message in status bar - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - } -} - -void Distort_brush_1_8(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 1 -// Taille_Pile : 8 -// -// Souris effacée: No -// -{ - // How far (in pixels) you can catch a handle - #define REACH_DISTANCE 100 - short i; - short x[4]; - short y[4]; - long best_distance=REACH_DISTANCE; - short best_spot=-1; - - for (i=3;i>=0;i--) - { - long distance; - Operation_pop(&y[i]); - Operation_pop(&x[i]); - distance=Distance(Paintbrush_X,Paintbrush_Y,x[i],y[i]); - if (distance-1) - { - Operation_push(best_spot); - } - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - -void Distort_brush_1_9(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 1 -// Taille_Pile : 9 -// -// Souris effacée: No -// -{ - short i; - short x[4]; - short y[4]; - short selected_corner; - - // Pop all arguments - Operation_pop(&selected_corner); - for (i=3;i>=0;i--) - { - Operation_pop(&y[i]); - Operation_pop(&x[i]); - } - - if (Paintbrush_X!=x[selected_corner] || Paintbrush_Y!=y[selected_corner]) - { - Hide_cursor(); - - // Easiest refresh mode: make no assumptions on how the brush was - // displayed before. - Display_all_screen(); - - x[selected_corner]=Paintbrush_X; - y[selected_corner]=Paintbrush_Y; - - for (i=0;i<4;i++) - Draw_stretch_spot(x[i],y[i]); - - Distort_brush_preview(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); - - Display_cursor(); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - Update_rect(0,0,Screen_width,Menu_Y); - } - - // Push back all arguments - for (i=0;i<4;i++) - { - Operation_push(x[i]); - Operation_push(y[i]); - } - Operation_push(selected_corner); - -} -void Distort_brush_0_9(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 0 -// Taille_Pile : 9 -// -// Souris effacée: No -// -{ - short selected_corner; - Operation_pop(&selected_corner); - -} - -void Distort_brush_2_0(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Paintbrush_hidden=0; - Display_all_screen(); - // Erase the message in status bar - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - } - Return_to_draw_mode(); -} - -void Distort_brush_2_8(void) -// -// Opération : OPERATION_DISTORT_BRUSH -// Click Souris: 2 -// Taille_Pile : 8 -// -// Souris effacée: Oui -// -{ - short i; - short x[4]; - short y[4]; - - // Pop all arguments - for (i=3;i>=0;i--) - { - Operation_pop(&y[i]); - Operation_pop(&x[i]); - } - Distort_brush(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]); - - Paintbrush_hidden=0; - Display_all_screen(); - - Return_to_draw_mode(); -} - diff --git a/project/jni/application/grafx2/grafx2/src/buttons.c b/project/jni/application/grafx2/grafx2/src/buttons.c deleted file mode 100644 index 5499fa466..000000000 --- a/project/jni/application/grafx2/grafx2/src/buttons.c +++ /dev/null @@ -1,5478 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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) - - 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 -*/ - -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - #include - #include - #include -#elif defined(__WIN32__) - #include - #include -#else - #include -#endif - -#define _XOPEN_SOURCE 500 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "graph.h" -#include "engine.h" -#include "readline.h" -#include "filesel.h" -#include "loadsave.h" -#include "init.h" -#include "buttons.h" -#include "operatio.h" -#include "pages.h" -#include "palette.h" -#include "errors.h" -#include "readini.h" -#include "saveini.h" -#include "shade.h" -#include "io.h" -#include "help.h" -#include "text.h" -#include "sdlscreen.h" -#include "windows.h" -#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 -#elif defined(__MINT__) - #include - #include -#elif defined(__WIN32__) - #include - #include -#else - #include -#endif - -extern char Program_version[]; // generated in pversion.c - -extern short Old_MX; -extern short Old_MY; - - -//-- MODELE DE BOUTON DE MENU ------------------------------------------------ -/* -void Bouton_***(void) -{ - short clicked_button; - - Open_window(310,190,"***"); - - Window_set_normal_button(103,137,80,14,"OK",0,1,SDLK_RETURN); // 1 - Window_set_scroller_button(18,44,88,16,4,0); // 2 - - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - } - while (clicked_button!=1); - - Close_window(); - Unselect_button(BOUTON_***); - Display_cursor(); -} -*/ - -void Message_out_of_memory(void) -{ - short clicked_button; - - Open_window(216,76,"Not enough memory!"); - - Print_in_window(8,20,"Please consult the manual",MC_Black,MC_Light); - Print_in_window(24,28,"to know how to obtain",MC_Black,MC_Light); - Print_in_window(36,36,"more memory space.",MC_Black,MC_Light); - Window_set_normal_button(60,53,40,14,"OK",1,1,SDLK_RETURN); // 1 - Update_window_area(0,0,Window_width, Window_height); - Display_cursor(); - - do - clicked_button=Window_clicked_button(); - while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); - - if(clicked_button<=0) Key=0; - Close_window(); - Display_cursor(); -} - - -void Button_Message_initial(void) -{ - char str[30]; - int x_pos,offs_y,x,y; - - strcpy(str,"GrafX2 version "); - strcat(str,Program_version); - Open_window(260,172,str); - - Window_display_frame_in(10,20,239,62); - Block(Window_pos_X+(Menu_factor_X*11), - Window_pos_Y+(Menu_factor_Y*21), - Menu_factor_X*237,Menu_factor_Y*60,MC_Black); - for (y=23,offs_y=0; y<79; offs_y+=231,y++) - for (x=14,x_pos=0; x_pos<231; x_pos++,x++) - Pixel_in_window(x,y,Gfx->Logo_grafx2[offs_y+x_pos]); - - Print_in_window(130-4*26,88,"Copyright (c) 2007-2011 by",MC_Dark,MC_Light); - Print_in_window(130-4*23,96,"the Grafx2 project team",MC_Black,MC_Light); - Print_in_window(130-4*26,112,"Copyright (c) 1996-2001 by",MC_Dark,MC_Light); - Print_in_window(130-4*13,120,"Sunset Design",MC_Black,MC_Light); - //Print_in_window( 120-4*13,128,"(placeholder)",MC_Dark,MC_Light); - Print_in_window(130-4*28,136,"http://grafx2.googlecode.com",MC_Dark,MC_Light); - - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - while(!Mouse_K && !Key) - Get_input(20); - if (Mouse_K) - Wait_end_of_click(); - - Close_window(); - Display_cursor(); -} - - - -void Change_paintbrush_shape(byte shape) -{ - Paintbrush_shape=shape; - Display_paintbrush_in_menu(); - - switch (Current_operation) - { - case OPERATION_FILL : - Paintbrush_shape_before_fill=shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - break; - case OPERATION_COLORPICK : - Paintbrush_shape_before_colorpicker=shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_NONE; - break; - // Note: Il existe un Paintbrush_shape_before_lasso, mais comme le lasso aura - // été automatiquement désactivé avant d'arriver ici, y'a pas de problème. - } -} - - -//-------------------------------- UNDO/REDO --------------------------------- -void Button_Undo(void) -{ - Hide_cursor(); - Undo(); - - Set_palette(Main_palette); - Compute_optimal_menu_colors(Main_palette); - - Display_all_screen(); - Unselect_button(BUTTON_UNDO); - Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); - Display_menu(); - Display_cursor(); -} - -void Button_Redo(void) -{ - Hide_cursor(); - Redo(); - - Set_palette(Main_palette); - Compute_optimal_menu_colors(Main_palette); - - Display_all_screen(); - Unselect_button(BUTTON_UNDO); - Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); - Display_menu(); - Display_cursor(); -} - - -//---------------------------- SCROLL PALETTE LEFT --------------------------- -void Button_Pal_left(void) -{ - short cells; - cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y(); - - Hide_cursor(); - if (First_color_in_palette) - { - if (First_color_in_palette>=cells) - First_color_in_palette-=cells; - else - First_color_in_palette=0; - Display_menu_palette(); - } - Unselect_button(BUTTON_PAL_LEFT); - Display_cursor(); -} - -void Button_Pal_left_fast(void) -{ - short cells_x = Palette_cells_X(); - short cells_y = Palette_cells_Y(); - - Hide_cursor(); - if (First_color_in_palette) - { - if (First_color_in_palette>=cells_y*cells_x) - First_color_in_palette-=cells_y*cells_x; - else - First_color_in_palette=0; - Display_menu_palette(); - } - Unselect_button(BUTTON_PAL_LEFT); - Display_cursor(); -} - - -//--------------------------- SCROLL PALETTE RIGHT --------------------------- -void Button_Pal_right(void) -{ - short cells; - cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y(); - - Hide_cursor(); - if ((int)First_color_in_palette+Palette_cells_X()*Palette_cells_Y()<256) - { - First_color_in_palette+=cells; - Display_menu_palette(); - } - - Unselect_button(BUTTON_PAL_RIGHT); - Display_cursor(); -} - -void Button_Pal_right_fast(void) -{ - short cells_x = Palette_cells_X(); - short cells_y = Palette_cells_Y(); - - Hide_cursor(); - if ((int)First_color_in_palette+cells_y*cells_x<256) - { - if ((int)First_color_in_palette+(cells_y)*cells_x*2<256) - First_color_in_palette+=cells_x*cells_y; - else - First_color_in_palette=255/cells_y*cells_y-(cells_x-1)*cells_y; - Display_menu_palette(); - } - Unselect_button(BUTTON_PAL_RIGHT); - Display_cursor(); -} - -//-------------------- item de la forecolor dans le menu -------------------- -void Button_Select_forecolor(void) -{ - static long time_click = 0; - long time_previous; - int color; - - time_previous = time_click; - time_click = SDL_GetTicks(); - - color=Pick_color_in_palette(); - - if (color == Fore_color) - { - // Check if it's a double-click - if (time_click - time_previous < Config.Double_click_speed) - { - // Open palette window - Button_Palette(); - return; - } - } - - do - { - if (color != Fore_color && color!=-1) - { - Hide_cursor(); - Set_fore_color(color); - Display_cursor(); - } - // Wait loop after initial click - while(Mouse_K) - { - Get_input(20); - - if (Button_under_mouse()==BUTTON_CHOOSE_COL) - { - color=Pick_color_in_palette(); - if (color != Fore_color && color!=-1) - { - Hide_cursor(); - Status_print_palette_color(color); - Set_fore_color(color); - Display_cursor(); - } - } - } - } while(Mouse_K); -} - -//-------------------- item de la backcolor dans le menu -------------------- -void Button_Select_backcolor(void) -{ - int color; - - do - { - color=Pick_color_in_palette(); - - if (color!=-1 && color != Back_color) - { - Hide_cursor(); - Status_print_palette_color(color); - Set_back_color(color); - Display_cursor(); - } - // Wait loop after initial click - do - { - Get_input(20); - - if (Button_under_mouse()==BUTTON_CHOOSE_COL) - break; // This will repeat this button's action - - } while(Mouse_K); - } while(Mouse_K); -} - -void Button_Hide_menu(void) -{ - Hide_cursor(); - if (Menu_is_visible) - { - Menu_is_visible=0; - Menu_Y=Screen_height; - - if (Main_magnifier_mode) - { - Compute_magnifier_data(); - } - - // On repositionne le décalage de l'image pour qu'il n'y ait pas d'in- - // -cohérences lorsqu'on sortira du mode Loupe. - if (Main_offset_Y+Screen_height>Main_image_height) - { - if (Screen_height>Main_image_height) - Main_offset_Y=0; - else - Main_offset_Y=Main_image_height-Screen_height; - } - // On fait pareil pour le brouillon - if (Spare_offset_Y+Screen_height>Spare_image_height) - { - if (Screen_height>Spare_image_height) - Spare_offset_Y=0; - else - Spare_offset_Y=Spare_image_height-Screen_height; - } - - Compute_magnifier_data(); - if (Main_magnifier_mode) - Position_screen_according_to_zoom(); - Compute_limits(); - Compute_paintbrush_coordinates(); - Display_all_screen(); - } - else - { - byte current_menu; - Menu_is_visible=1; - Menu_Y=Screen_height; - for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) - if (Menu_bars[current_menu].Visible) - Menu_Y -= Menu_bars[current_menu].Height * Menu_factor_Y; - - Compute_magnifier_data(); - if (Main_magnifier_mode) - Position_screen_according_to_zoom(); - Compute_limits(); - Compute_paintbrush_coordinates(); - Display_menu(); - if (Main_magnifier_mode) - Display_all_screen(); - } - Unselect_button(BUTTON_HIDE); - Display_cursor(); -} - - -void Set_bar_visibility(word bar, byte visible) -{ - if (!visible && Menu_bars[bar].Visible) - { - // Hide it - Menu_bars[bar].Visible=0; - - Compute_menu_offsets(); - - if (Main_magnifier_mode) - { - Compute_magnifier_data(); - } - - // On repositionne le décalage de l'image pour qu'il n'y ait pas d'in- - // -cohérences lorsqu'on sortira du mode Loupe. - if (Main_offset_Y+Screen_height>Main_image_height) - { - if (Screen_height>Main_image_height) - Main_offset_Y=0; - else - Main_offset_Y=Main_image_height-Screen_height; - } - // On fait pareil pour le brouillon - if (Spare_offset_Y+Screen_height>Spare_image_height) - { - if (Screen_height>Spare_image_height) - Spare_offset_Y=0; - else - Spare_offset_Y=Spare_image_height-Screen_height; - } - - Compute_magnifier_data(); - if (Main_magnifier_mode) - Position_screen_according_to_zoom(); - Compute_limits(); - Compute_paintbrush_coordinates(); - Display_menu(); - Display_all_screen(); - } - else if (visible && !Menu_bars[bar].Visible) - { - // Show it - Menu_bars[bar].Visible = 1; - - Compute_menu_offsets(); - Compute_magnifier_data(); - if (Main_magnifier_mode) - Position_screen_according_to_zoom(); - Compute_limits(); - Compute_paintbrush_coordinates(); - Display_menu(); - if (Main_magnifier_mode) - Display_all_screen(); - } -} - -void Button_Toggle_toolbar(void) -{ - T_Dropdown_button dropdown; - T_Dropdown_choice *item; - static char menu_name[2][9]= { - " Tools", - " Layers" - }; - - menu_name[0][0] = Menu_bars[MENUBAR_TOOLS ].Visible ? 22 : ' '; - menu_name[1][0] = Menu_bars[MENUBAR_LAYERS].Visible ? 22 : ' '; - - Hide_cursor(); - - dropdown.Pos_X =Buttons_Pool[BUTTON_HIDE].X_offset; - dropdown.Pos_Y =Buttons_Pool[BUTTON_HIDE].Y_offset; - dropdown.Height =Buttons_Pool[BUTTON_HIDE].Height; - dropdown.Dropdown_width=70; - dropdown.First_item =NULL; - dropdown.Bottom_up =1; - - Window_dropdown_add_item(&dropdown, 0, menu_name[0]); - Window_dropdown_add_item(&dropdown, 1, menu_name[1]); - - item=Dropdown_activate(&dropdown,0,Menu_Y+Menu_bars[MENUBAR_STATUS].Top*Menu_factor_Y); - - if (item) - { - switch (item->Number) - { - case 0: - Set_bar_visibility(MENUBAR_TOOLS, !Menu_bars[MENUBAR_TOOLS].Visible); - break; - case 1: - Set_bar_visibility(MENUBAR_LAYERS, !Menu_bars[MENUBAR_LAYERS].Visible); - break; - } - } - - // Closing - Window_dropdown_clear_items(&dropdown); - - Unselect_button(BUTTON_HIDE); - Display_cursor(); -} - -void Button_Toggle_all_toolbars(void) -{ - // This is used to memorize the bars' visibility when temporarily hidden - static word Last_visibility = 0xFFFF; - int i; - word current_visibility; - - Hide_cursor(); - - // Check which bars are visible - current_visibility=0; - for (i=MENUBAR_STATUS+1;iPages->Filename, Main_backups->Pages->File_directory); - if ( (!File_exists(filename)) || Confirmation_box("Erase old file ?") ) - { - T_IO_Context save_context; - - Hide_cursor(); - old_cursor_shape=Cursor_shape; - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - - Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); - Save_image(&save_context); - Destroy_context(&save_context); - - Hide_cursor(); - Cursor_shape=old_cursor_shape; - Display_cursor(); - - if (!File_error) - // L'ayant sauvée avec succès, - return 1; // On peut quitter - else - // Il y a eu une erreur lors de la sauvegarde, - return 0; // On ne peut donc pas quitter - } - else - // L'utilisateur ne veut pas écraser l'ancien fichier, - return 0; // On doit donc rester - case 3 : return 1; // Quitter - } - return 0; -} - - -void Button_Quit(void) -{ - //short clicked_button; - - if (Button_Quit_local_function()) - { - if (Spare_image_is_modified) - { - Button_Page(); // On passe sur le brouillon - // Si l'utilisateur présente les derniers symptomes de l'abandon - if (Button_Quit_local_function()) - Quitting=1; - } - else - Quitting=1; - } - - if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) ) - Hide_cursor(); - - Unselect_button(BUTTON_QUIT); - - if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) ) - Display_cursor(); -} - - -//---------------------------- Effacer l'écran ------------------------------- -void Button_Clear(void) -{ - Hide_cursor(); - Backup(); - if (Stencil_mode && Config.Clear_with_stencil) - Clear_current_image_with_stencil(Main_backups->Pages->Transparent_color,Stencil); - else - Clear_current_image(Main_backups->Pages->Transparent_color); - Redraw_layered_image(); - End_of_modification(); - Display_all_screen(); - Unselect_button(BUTTON_CLEAR); - Display_cursor(); -} - -void Button_Clear_with_backcolor(void) -{ - Hide_cursor(); - Backup(); - if (Stencil_mode && Config.Clear_with_stencil) - Clear_current_image_with_stencil(Back_color,Stencil); - else - Clear_current_image(Back_color); - Redraw_layered_image(); - End_of_modification(); - Display_all_screen(); - Unselect_button(BUTTON_CLEAR); - Display_cursor(); -} - - -//------------------------------- Paramètres --------------------------------- - -#define SETTING_PER_PAGE 11 -#define SETTING_PAGES 5 - -#define SETTING_HEIGHT 12 - -typedef struct { - const char* Label; // Use NULL label to stop an array - int Code; -} T_Lookup; - -const T_Lookup Lookup_YesNo[] = { - {"NO",0}, - {"YES",1}, - {NULL,-1}, -}; - -const T_Lookup Lookup_FFF[] = { - {"All",0}, - {"Files",1}, - {"Dirs.",2}, - {NULL,-1}, -}; - -const T_Lookup Lookup_AutoRes[] = { - {"Internal",1}, - {"Real",2}, - {NULL,-1}, -}; - -const T_Lookup Lookup_Coords[] = { - {"Relative",1}, - {"Absolute",2}, - {NULL,-1}, -}; - -const T_Lookup Lookup_MenuRatio[] = { - {"None",0}, - {"x2",254}, // -2 - {"x3",253}, // -3 - {"x4",252}, // -4 - {"Moderate",2}, - {"Maximum",1}, - {NULL,-1}, -}; - -const T_Lookup Lookup_MouseSpeed[] = { - {"Normal",1}, - {"/2",2}, - {"/3",3}, - {"/4",4}, - {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) - void * Value; - int Min_value; - int Max_value; - int Digits; // Could be computed from Max_value...but don't bother. - const T_Lookup * Lookup; -} T_Setting; - -long int Get_setting_value(T_Setting *item) -{ - switch(item->Type) - { - case 1: - return *((byte *)(item->Value)); - break; - case 2: - return *((word *)(item->Value)); - break; - case 4: - default: - return *((long int *)(item->Value)); - break; - } -} - -void Set_setting_value(T_Setting *item, long int value) -{ - switch(item->Type) - { - case 1: - *((byte *)(item->Value)) = value; - break; - case 2: - *((word *)(item->Value)) = value; - break; - case 4: - default: - *((long int *)(item->Value)) = value; - break; - } -} - -// Fetch a label in a lookup table. Unknown values get label 0. -const char *Lookup_code(int code, const T_Lookup *lookup) -{ - int i; - - for(i=0; lookup[i].Label!=NULL; i++) - { - if (lookup[i].Code == code) - return lookup[i].Label; - } - return lookup[0].Label; -} - -/// Increase an enum to next-higher value (wrapping). -int Lookup_next(int code, const T_Lookup *lookup) -{ - int i; - - for(i=0; lookup[i].Label!=NULL; i++) - { - if (lookup[i].Code == code) - { - if (lookup[i+1].Label==NULL) - return lookup[0].Code; - return lookup[i+1].Code; - } - } - return 0; -} - -/// Decrease an enum to previous value (wrapping). -int Lookup_previous(int code, const T_Lookup *lookup) -{ - int count; - int current=-1; - - for(count=0; lookup[count].Label!=NULL; count++) - { - if (lookup[count].Code == code) - current=count; - } - - return lookup[(current + count - 1) % count].Code; -} - -void Settings_display_config(T_Setting *setting, T_Config * conf, T_Special_button *panel) -{ - int i; - - // A single button - Print_in_window(155,166,(conf->Auto_save)?"YES":" NO",MC_Black,MC_Light); - - // Clear all - Window_rectangle(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1, MC_Light); - for (i=0; iPos_X+3, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, setting[i].Label, i==0?MC_White:MC_Dark, MC_Light); - if(setting[i].Value) - { - - int value = Get_setting_value(&setting[i]); - - if (setting[i].Lookup) - { - // Use a lookup table to print a label - const char *str; - str = Lookup_code(value,setting[i].Lookup); - Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light); - } - else - { - // Print a number - char str[10]; - Num2str(value,str,setting[i].Digits); - Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light); - } - } - } - Update_window_area(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1); -} - -void Settings_save_config(T_Config * conf) -{ - if (Save_CFG()) - Error(0); - else - if (Save_INI(conf)) - Error(0); -} - -void Settings_load_config(T_Config * conf) -{ - if (Load_CFG(0)) - Error(0); - else - if (Load_INI(conf)) - Error(0); -} - -void Button_Settings(void) -{ - short clicked_button; - T_Config selected_config; - byte config_is_reloaded=0; - T_Special_button *panel; - byte need_redraw=1; - static byte current_page=0; - - // Definition of settings pages - // Label,Type (0 = label, 1+ = setting size in bytes), - // Value, min, max, digits, Lookup) - - T_Setting setting[SETTING_PER_PAGE*SETTING_PAGES] = { - - {" --- 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}, - {"Coordinates:",1,&(selected_config.Coords_rel),0,1,0,Lookup_Coords}, - {"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}, - {"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}, - {"Merge movement:",1,&(selected_config.Mouse_merge_movement),0,100,4,NULL}, - {"Double click speed:",2,&(selected_config.Double_click_speed),1,1999,4,NULL}, - {"Double key speed:",2,&(selected_config.Double_key_speed),1,1999,4,NULL}, - //{"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}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - - {" --- Editing ---",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}, - {"Fast zoom:",1,&(selected_config.Fast_zoom),0,1,0,Lookup_YesNo}, - {"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}, - {"Multi shortcuts:",1,&(selected_config.Allow_multi_shortcuts),0,1,0,Lookup_YesNo}, - {"",0,NULL,0,0,0,NULL}, - - {" --- File selector ---",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}, - {"Preview delay:",4,&(selected_config.Timer_delay), 1,256,3,NULL}, - {"Maximize preview:",1,&(selected_config.Maximize_preview), 0,1,0,Lookup_YesNo}, - {"Find file fast:",1,&(selected_config.Find_file_fast), 0,2,0,Lookup_FFF}, - {"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}, - {"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}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - {"",0,NULL,0,0,0,NULL}, - - - }; - - const char * help_section[SETTING_PAGES] = { - "GUI", - "INPUT", - "EDITING", - "FILE SELECTOR", - "FILE FORMAT OPTIONS", - }; - - selected_config=Config; - - Open_window(307,182,"Settings"); - - // Button Reload - Window_set_normal_button( 6,163, 51,14,"Reload" ,0,1,SDLK_LAST); // 1 - // Button Auto-save - Window_set_normal_button( 73,163,107,14,"Auto-save: ",0,1,SDLK_LAST); // 2 - // Button Save - Window_set_normal_button(183,163, 51,14,"Save" ,0,1,SDLK_LAST); // 3 - // Button Close - Window_set_normal_button(250,163, 51,14,"Close" ,0,1,KEY_ESC); // 4 - - panel=Window_set_special_button(10, 21, 272,SETTING_PER_PAGE*SETTING_HEIGHT); // 5 - Window_set_scroller_button(285,21,SETTING_PER_PAGE*SETTING_HEIGHT,SETTING_PAGES,1,current_page); // 6 - - Update_window_area(0,0,Window_width, Window_height); - Display_cursor(); - - do - { - if (need_redraw) - { - Hide_cursor(); - Settings_display_config(setting+current_page*SETTING_PER_PAGE, &selected_config, panel); - if (need_redraw & 2) - { - // Including slider position - Window_scroller_button_list->Position=current_page; - Window_draw_slider(Window_scroller_button_list); - } - - Display_cursor(); - - need_redraw=0; - } - - clicked_button=Window_clicked_button(); - - switch(clicked_button) - { - - case 1 : // Reload - Settings_load_config(&selected_config); - config_is_reloaded=1; - need_redraw=1; - break; - case 2 : // Auto-save - selected_config.Auto_save=!selected_config.Auto_save; - need_redraw=1; - break; - case 3 : // Save - Settings_save_config(&selected_config); - break; - // case 4: // Close - - case 5: // Panel area - { - T_Setting item; - - int num=(((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y - panel->Pos_Y)/SETTING_HEIGHT; - if (num >= 0 && num < SETTING_PER_PAGE) - { - item=setting[current_page*SETTING_PER_PAGE+num]; - if (item.Type!=0) - { - // Remember which button is clicked - byte old_mouse_k = Mouse_K; - - if (Window_normal_button_onclick(panel->Pos_X, panel->Pos_Y+num*SETTING_HEIGHT, panel->Width, SETTING_HEIGHT+1, 5)) - { - int value = Get_setting_value(&item); - - if (item.Lookup) - { - // Enum: toggle it - if (old_mouse_k & LEFT_SIDE) - value = Lookup_next(value, item.Lookup); - else - value = Lookup_previous(value, item.Lookup); - Set_setting_value(&item, value); - } - else - { - // Numeric: edit it - char str[10]; - 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,INPUT_TYPE_INTEGER)) - { - value=atoi(str); - if (valueitem.Max_value) - value = item.Max_value; - - Set_setting_value(&item, value); - } - Key=0; // Need to discard keys used during editing - } - } - } - } - } - need_redraw=1; - break; - case 6: // Scroller - current_page = Window_attribute2; - need_redraw=1; - break; - - } - - if (Key == KEY_MOUSEWHEELDOWN) - { - if (current_page < (SETTING_PAGES-1)) - { - current_page++; - need_redraw=2; - } - } - else if (Key == KEY_MOUSEWHEELUP) - { - if (current_page > 0) - { - current_page--; - need_redraw=2; - } - } - else if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(NB_BUTTONS+0, help_section[current_page]); - else if (Is_shortcut(Key,0x100+BUTTON_SETTINGS)) - clicked_button=4; - } - while ( (clicked_button!=4) && (Key!=SDLK_RETURN) ); - - // Checks on change - if (Config.Show_hidden_directories!=selected_config.Show_hidden_directories - ||Config.Show_hidden_files!=selected_config.Show_hidden_files) - { - // Reset fileselector offsets - // since different files are shown now - Main_fileselector_position=0; - Main_fileselector_offset=0; - Spare_fileselector_position=0; - Spare_fileselector_offset=0; - } - if(Config.Allow_multi_shortcuts && !selected_config.Allow_multi_shortcuts) - { - // User just disabled multi shortcuts: make them unique now. - Remove_duplicate_shortcuts(); - } - // Copy all - Config=selected_config; - - if (config_is_reloaded) - Compute_optimal_menu_colors(Main_palette); - - Close_window(); - Unselect_button(BUTTON_SETTINGS); - // Raffichage du menu pour que les inscriptions qui y figurent soient - // retracées avec la nouvelle fonte - Display_menu(); - Display_cursor(); - - // On vérifie qu'on peut bien allouer le nombre de pages Undo. - Set_number_of_backups(Config.Max_undo_pages); -} - -// Data for skin selector -T_Fileselector Skin_files_list; - - -// Data for font selector -T_Fileselector Font_files_list; - -// -char * Format_font_filename(const char * fname) -{ - static char result[12]; - int c; - int length; - - fname+=strlen(FONT_PREFIX); // Omit file prefix - length=strlen(fname) - 4; // assume .png extension - - for (c=0;c<11 && c11) - result[10] = ELLIPSIS_CHARACTER; - - return result; -} - -// Add a skin to the list -void Add_font_or_skin(const char *name) -{ - const char * fname; - int namelength; - - // Cut the long name to keep only filename (no directory) - fname = Find_last_slash(name); - if (fname) - fname++; - else - fname = name; - namelength = strlen(fname); - 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, fname, Format_filename(fname, 19, 0), 0, ICON_NONE); - - if (fname[0]=='\0') - return; - } - else if (namelength>=10 && !strncasecmp(fname, FONT_PREFIX, strlen(FONT_PREFIX)) - && (!strcasecmp(fname + namelength - 4, ".png"))) - { - Add_element_to_list(&Font_files_list, fname, Format_font_filename(fname), 0, ICON_NONE); - - if (fname[0]=='\0') - return; - } - -} - -// Callback to display a skin name in the list -void Draw_one_skin_name(word x, word y, word index, byte highlighted) -{ - T_Fileselector_item * current_item; - - if (Skin_files_list.Nb_elements) - { - current_item = Get_item_by_index(&Skin_files_list, index); - Print_in_window(x, y, current_item->Short_name, MC_Black, - (highlighted)?MC_Dark:MC_Light); - } -} - -/// Skin selector window -void Button_Skins(void) -{ - short clicked_button; - short temp; - char skinsdir[MAX_PATH_CHARACTERS]; - T_Dropdown_button * font_dropdown; - T_Dropdown_button * cursor_dropdown; - T_List_button * skin_list; - T_Scroller_button * file_scroller; - int selected_font = 0; - int selected_cursor = Config.Cursor; - 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" }; - T_Gui_skin * gfx = NULL; - - - #define FILESEL_Y 34 - - // --- Read the contents of skins/ directory ------------------ - - // Here we use the same data container as the fileselectors. - // Reinitialize the list - Free_fileselector_list(&Skin_files_list); - Free_fileselector_list(&Font_files_list); - // Browse the "skins" directory - strcpy(skinsdir, Data_directory); - strcat(skinsdir, SKINS_SUBDIRECTORY); - // Add each found file to the list - For_each_file(skinsdir, Add_font_or_skin); - // Sort it - Sort_list_of_files(&Skin_files_list); - Sort_list_of_files(&Font_files_list); - - selected_font = Find_file_in_fileselector(&Font_files_list, Config.Font_file); - - - // -------------------------------------------------------------- - - Open_window(290, 140, "Skins"); - - // Frames - Window_display_frame_in(6, FILESEL_Y - 2, 148, 84); // File selector - - // Texts - Print_in_window( 172, 33,"Font:" ,MC_Black,MC_Light); - Print_in_window( 172, 59,"Cursor:" ,MC_Black,MC_Light); - - // Ok button - Window_set_normal_button(6, 120, 51, 14, "OK", 0, 1, SDLK_RETURN); // 1 - - // List of skins - skin_list = Window_set_list_button( - // Fileselector - Window_set_special_button(8, FILESEL_Y + 1, 144, 80), // 2 - // Scroller for the fileselector - (file_scroller = Window_set_scroller_button(155, FILESEL_Y - 1, 82, - Skin_files_list.Nb_elements, 10, 0)), // 3 - Draw_one_skin_name, 2); // 4 - - skin_list->Cursor_position = Find_file_in_fileselector(&Skin_files_list, Config.Skin_file); - - // Buttons to choose a font - font_dropdown = Window_set_dropdown_button(172, 43, 104, 11, 0, Get_item_by_index(&Font_files_list,selected_font)->Short_name,1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 5 - for (temp=0; tempShort_name); - - // Cancel - Window_set_normal_button(61, 120, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 6 - - // Dropdown list to choose cursor type - cursor_dropdown = Window_set_dropdown_button(172, 69, 104, 11, 0, - cursors[selected_cursor], 1, 0, 1, RIGHT_SIDE|LEFT_SIDE,0); // 7 - for (temp = 0; temp<3; temp++) - Window_dropdown_add_item(cursor_dropdown, temp, cursors[temp]); - - Window_set_normal_button(172, 87, 14, 14, - (Config.Display_image_limits)?"X":" ", -1, 1, SDLK_LAST); // 8 - Print_in_window( 190, 85,"Draw picture", MC_Dark, MC_Light); - Print_in_window( 190, 94,"limits", MC_Dark, MC_Light); - - Window_set_normal_button(172, 111, 14, 14, - (Config.Separate_colors)?"X":" ", -1, 1, SDLK_LAST); // 9 - Print_in_window( 190, 109,"Separate", MC_Dark, MC_Light); - Print_in_window( 190, 118,"colors", MC_Dark, MC_Light); - - Window_redraw_list(skin_list); - - for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++) - for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++) - Pixel_in_window(x, y, Gfx->Preview[offs_y][x_pos]); - - Update_window_area(0, 0, Window_width, Window_height); - - Display_cursor(); - - 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"); - - switch(clicked_button) - { - case 1 : // OK - break; - case 2 : // double-click file: do nothing - break; - case 3 : // doesn't happen - break; - case 4 : // a file is selected - need_load=1; - break; - case 5 : // Font dropdown - selected_font = Window_attribute2; // Get the index of the chosen font. - break; - // 6: Cancel - case 7 : // Cursor - selected_cursor = Window_attribute2; - break; - case 8: // Display limits - showlimits = !showlimits; - Hide_cursor(); - Print_in_window(175, 90, (showlimits)?"X":" ", MC_Black, MC_Light); - Display_cursor(); - break; - case 9: // Separate colors - separatecolors = !separatecolors; - Hide_cursor(); - Print_in_window(175, 114, (separatecolors)?"X":" ", MC_Black, MC_Light); - Display_cursor(); - break; - } - } - while ( (clicked_button!=1) && (clicked_button !=6) && (Key != SDLK_ESCAPE)); - - if(clicked_button == 1) - { - byte * new_font; - - if (gfx != NULL) - { - Set_current_skin(skinsdir, gfx); - } - // (Re-)load the selected font - new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name); - if (new_font) - { - const char * fname; - - free(Menu_font); - Menu_font = new_font; - fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name; - free(Config.Font_file); - Config.Font_file = (char *)strdup(fname); - } - // Confirm the change of cursor shape - Config.Cursor = selected_cursor; - Config.Display_image_limits = showlimits; - Config.Separate_colors = separatecolors; - - // Now find the best colors for the new skin in the current palette - // and remap the skin - Compute_optimal_menu_colors(Main_palette); - - } - - // We don't want to keep the skin's palette, as this would corrupt the current picture's one. - Set_palette(Main_palette); - - Close_window(); - Unselect_button(BUTTON_SETTINGS); - - // Raffichage du menu pour que les inscriptions qui y figurent soient retracées avec la nouvelle fonte - Display_menu(); - // Redraw all buttons, to ensure all specific sprites are in place. - // This is necessary for multi-state buttons, for example Freehand. - for (button=0; buttonPages->Nb_layers; i++) - { - if (i == Spare_current_layer) - { - // Copy the current layer - memcpy(Spare_backups->Pages->Image[i],Main_backups->Pages->Image[Main_current_layer],Main_image_width*Main_image_height); - } - else - { - // Resize the original layer - Copy_part_of_image_to_another( - Spare_backups->Pages->Next->Image[i],0,0,Min(old_width,Spare_image_width), - Min(old_height,Spare_image_height),old_width, - Spare_backups->Pages->Image[i],0,0,Spare_image_width); - } - } - - // Copie des dimensions de l'image - /* - C'est inutile, le "Backuper et redimensionner brouillon" a déjà modifié - ces valeurs pour qu'elles soient correctes. - */ - /* - Spare_image_width=Main_image_width; - Spare_image_height=Main_image_height; - */ - - Copy_view_to_spare(); - - // Update the visible buffer of the spare. - // It's a bit complex because at the moment, to save memory, - // the spare doesn't have a full visible_buffer + depth_buffer, - // so I can't use exactly the same technique as for Main page. - // (It's the same reason that the "Page" function gets complex, - // it needs to rebuild a depth buffer only, trusting the - // depth buffer that was already available in Spare_.) - Update_spare_buffers(Spare_image_width,Spare_image_height); - Redraw_spare_image(); - - } - else - Message_out_of_memory(); -} - - -void Copy_some_colors(void) -{ - short index; - byte confirmation=0; - static byte mask_color_to_copy[256]; // static to use less stack - - memset(mask_color_to_copy,1,256); - Menu_tag_colors("Tag colors to copy",mask_color_to_copy,&confirmation,0, NULL, 0xFFFF); - - if (confirmation) - { - // Make a backup with the same pixel data as previous history steps - Backup_the_spare(0); - for (index=0; index<256; index++) - { - if (mask_color_to_copy[index]) - memcpy(Spare_palette+index,Main_palette+index, - sizeof(T_Components)); - } - } -} - - -void Button_Copy_page(void) -{ - short clicked_button; - - - Open_window(168,137,"Copy to spare page"); - - Window_set_normal_button(10, 20,148,14,"Pixels + palette" , 0,1,SDLK_RETURN); // 1 - Window_set_normal_button(10, 37,148,14,"Pixels only" , 3,1,SDLK_x); // 2 - Window_set_normal_button(10, 54,148,14,"Palette only" , 1,1,SDLK_p); // 3 - Window_set_normal_button(10, 71,148,14,"Some colors only" , 6,1,SDLK_c); // 4 - Window_set_normal_button(10, 88,148,14,"Palette and remap",13,1,SDLK_r); // 5 - Window_set_normal_button(44,114, 80,14,"Cancel" , 0,1,KEY_ESC); // 6 - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_PAGE, NULL); - else if (Is_shortcut(Key,0x200+BUTTON_PAGE)) - clicked_button=6; - } - while (clicked_button<=0); - - Close_window(); - Display_cursor(); - - switch (clicked_button) - { - case 1: // Pixels+palette - Backup_the_spare(-1); - Copy_image_only(); - // copie de la palette - memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); - // Equivalent of 'end_of_modifications' for spare. - Update_spare_buffers(Spare_image_width,Spare_image_height); - Redraw_spare_image(); - Spare_image_is_modified=1; - break; - - case 2: // Pixels only - Backup_the_spare(-1); - Copy_image_only(); - // Equivalent of 'end_of_modifications' for spare. - Update_spare_buffers(Spare_image_width,Spare_image_height); - Redraw_spare_image(); - Spare_image_is_modified=1; - break; - - case 3: // Palette only - Backup_the_spare(0); - // Copy palette - memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); - // Equivalent of 'end_of_modifications' for spare. - Update_spare_buffers(Spare_image_width,Spare_image_height); - Redraw_spare_image(); - Spare_image_is_modified=1; - break; - - case 4: // Some colors - // Will backup if needed - Copy_some_colors(); - break; - - case 5: // Palette and remap - Backup_the_spare(-1); - Remap_spare(); - // Copy palette - memcpy(Spare_palette,Main_palette,sizeof(T_Palette)); - // Equivalent of 'end_of_modifications' for spare. - Update_spare_buffers(Spare_image_width,Spare_image_height); - Redraw_spare_image(); - Spare_image_is_modified=1; - break; - } - - Hide_cursor(); - Unselect_button(BUTTON_PAGE); - Display_cursor(); -} - - -// -- Suppression d'une page ------------------------------------------------- -void Button_Kill(void) -{ - if ( (Main_backups->List_size==1) - || (!Confirmation_box("Delete the current page?")) ) - { - if (Main_backups->List_size==1) - Warning_message("You can't delete the last page."); - Hide_cursor(); - Unselect_button(BUTTON_KILL); - Display_cursor(); - } - else - { - Hide_cursor(); - Free_current_page(); - - Set_palette(Main_palette); - Compute_optimal_menu_colors(Main_palette); - - Display_all_screen(); - Unselect_button(BUTTON_KILL); - Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); - Display_menu(); - Display_cursor(); - } -} - - -//------------------------- Dimensions Image/Screen --------------------------- - -void Check_mode_button(short x_pos, short y_pos, byte state) -{ - byte color; - - switch (state & 0x7F) - { - case 0 : color=MC_White; break; - case 1 : color=MC_Light; break; - case 2 : color=MC_Dark; break; - default: color=MC_Black; - } - Block(Window_pos_X+Menu_factor_X*x_pos,Window_pos_Y+Menu_factor_Y*y_pos, - Menu_factor_X*9,Menu_factor_Y*3,color); - - Update_rect(Window_pos_X+Menu_factor_X*x_pos,Window_pos_Y+Menu_factor_Y*y_pos, - Menu_factor_X*9,Menu_factor_Y*3); -} - -/// Number of video modes to display in the resolution menu -#define MODELIST_LINES 10 - -void Display_modes_list(short list_start, short cursor_position) -{ - short index,current_mode; - short y_pos; - byte text_color,background_color; - char str[29]; - char *ratio; - - for (current_mode=list_start,index=0; indexPosition!=list_start) - { - Window_scroller_button_list->Position=list_start; - Window_draw_slider(Window_scroller_button_list); - } - Display_modes_list(list_start,cursor_position); - Display_cursor(); -} - -void Button_Resolution(void) -{ - short clicked_button; - int selected_mode; - word chosen_width; - word chosen_height; - byte chosen_pixel; - short list_start; - short cursor_position; - short temp; - char str[5]; - T_Special_button * input_width_button, * input_button_height; - T_Dropdown_button * pixel_button; - static const char *pixel_ratio_labels[PIXEL_MAX] ={ - "Normal (1x1)", - "Wide (2x1)", - "Tall (1x2)", - "Double (2x2)", - "Triple (3x3)", - "Wide2 (4x2)", - "Tall2 (2x4)", - "Quadruple (4x4)"}; - - Open_window(299,190,"Picture & screen sizes"); - - Print_in_window( 12, 21,"Picture size:" ,MC_Dark,MC_Light); - Window_display_frame ( 8,17,195, 33); - - Window_set_normal_button(223, 18,67,14,"OK" ,0,1,SDLK_RETURN); // 1 - Window_set_normal_button(223, 35,67,14,"Cancel" ,0,1,KEY_ESC); // 2 - - Print_in_window( 12, 37,"Width:" ,MC_Dark,MC_Light); - input_width_button=Window_set_input_button( 60, 35,4); // 3 - - Print_in_window(108, 37,"Height:" ,MC_Dark,MC_Light); - input_button_height=Window_set_input_button(164, 35,4); // 4 - - Window_display_frame ( 8,72,283,110); - Window_display_frame_in (37,84,228,84); - Window_rectangle (38,85,226,82,MC_Black); - Print_in_window( 16, 76,"OK" ,MC_Dark,MC_Light); - Print_in_window( 55, 76,"X Y" ,MC_Dark,MC_Light); - Print_in_window(120, 76,"Win / Full" ,MC_Dark,MC_Light); - Print_in_window(219, 76,"Ratio" ,MC_Dark,MC_Light); - Print_in_window( 30,170,"\03" ,MC_Dark,MC_Light); - Print_in_window( 62,170,"OK" ,MC_Dark,MC_Light); - Print_in_window(102,170,"Imperfect" ,MC_Dark,MC_Light); - Print_in_window(196,170,"Unsupported" ,MC_Dark,MC_Light); - Window_set_special_button(38,86,225,80); // 5 - - selected_mode=Current_resolution; - if (selected_mode>=MODELIST_LINES/2 && Nb_video_modes > MODELIST_LINES) - { - if (selected_mode>3; - if (temp0) - cursor_position--; - else - if (list_start>0) - list_start--; - Scroll_list_of_modes(list_start,cursor_position,&selected_mode); - Key=0; - break; - case SDLK_DOWN : // Bas - if (cursor_position<(MODELIST_LINES-1) && cursor_position<(Nb_video_modes-1)) - cursor_position++; - else - if (list_start0) - cursor_position=0; - else - { - if (list_start>(MODELIST_LINES-1)) - list_start-=(MODELIST_LINES-1); - else - list_start=0; - } - Scroll_list_of_modes(list_start,cursor_position,&selected_mode); - Key=0; - break; - case SDLK_PAGEDOWN : // PageDown - if (Nb_video_modesOPERATION_FILLED_CONTOUR) - Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; - - Hide_cursor(); - 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) *** - short clicked_button; - Open_popup(16,Menu_Y/Menu_factor_X-32,18,50); - Window_set_normal_button(1,1,16,16,"A",0,1,KEY_ESC); // 1 - Display_cursor(); - - Update_rect(16*Menu_factor_X,Menu_Y-32*Menu_factor_X,18*Menu_factor_X,50*Menu_factor_X); - - do - { - while(!Get_input())Wait_VBL(); - clicked_button = Window_get_clicked_button(); - - switch(clicked_button) - { - case 1: - Selected_freehand_mode++; - if (Selected_freehand_mode>OPERATION_FILLED_CONTOUR) - Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; - break; - } - } - while (Mouse_K); - - Close_popup(); - //Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode+2); - Start_operation_stack(Selected_freehand_mode); - Display_cursor(); -*/ -} - - -// -- Gestion des boutons de rectangle vide et plein ------------------------ - -void Button_Empty_rectangle(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_EMPTY_RECTANGLE); - Display_cursor(); -} - - -void Button_Filled_rectangle(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_FILLED_RECTANGLE); - Display_cursor(); -} - - -// -- Gestion des boutons de cercle (ellipse) vide et plein(e) -------------- - -void Button_Empty_circle(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_EMPTY_CIRCLE); - Display_cursor(); -} - - -void Button_Empty_ellipse(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_EMPTY_ELLIPSE); - Display_cursor(); -} - - -void Button_Filled_circle(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_FILLED_CIRCLE); - Display_cursor(); -} - - -void Button_Filled_ellipse(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_FILLED_ELLIPSE); - Display_cursor(); -} - - -// -- Gestion du menu des dégradés ------------------------------------------ -void Draw_button_gradient_style(short x_pos,short y_pos,int technique) -{ - short line; - - // On commence par afficher les 2 côtés qui constituent le dégradé de base: - // Côté gauche (noir) - Block(Window_pos_X+((x_pos+2)*Menu_factor_X), - Window_pos_Y+((y_pos+2)*Menu_factor_Y), - Menu_factor_X*6, - Menu_factor_Y*10,MC_Black); - // Côté droit (blanc) - Block(Window_pos_X+((x_pos+8)*Menu_factor_X), - Window_pos_Y+((y_pos+2)*Menu_factor_Y), - Menu_factor_X*5, - Menu_factor_Y*10,MC_White); - - switch(technique) - { - case 1 : // Dégradé de trames simples - // Au centre, on place 10 lignes tramées simplement - for (line=2;line<2+10;line++) - if (line&1) - { - // Lignes impaires - Pixel_in_window(x_pos+ 5,y_pos+line,MC_White); - Pixel_in_window(x_pos+ 7,y_pos+line,MC_White); - Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black); - } - else - { - // Lignes paires - Pixel_in_window(x_pos+ 6,y_pos+line,MC_White); - Pixel_in_window(x_pos+ 9,y_pos+line,MC_Black); - } - break; - case 2 : // Dégradé de trames étendues - // Au centre, on place 10 lignes tramées de façon compliquée - for (line=2;line<2+10;line++) - if (line&1) - { - // Lignes impaires - Pixel_in_window(x_pos+ 7,y_pos+line,MC_White); - Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black); - Pixel_in_window(x_pos+10,y_pos+line,MC_Black); - } - else - { - // Lignes paires - Pixel_in_window(x_pos+ 4,y_pos+line,MC_White); - Pixel_in_window(x_pos+ 6,y_pos+line,MC_White); - } - } - - Update_rect(Window_pos_X+((x_pos+2)*Menu_factor_X),Window_pos_Y+((y_pos+2)*Menu_factor_Y), - Menu_factor_X*10,Menu_factor_Y*10); -} - -void Load_gradient_data(int index) -{ - 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; - break; - case 1 : // Dégradé de trames simples - Gradient_function=Gradient_dithered; - break; - case 2 : // Dégradé de trames étendues - Gradient_function=Gradient_extra_dithered; - } -} - -void Draw_gradient_preview(short start_x,short start_y,short width,short height,int index) -{ - short x_pos; // Variables de balayage du block en bas de l'écran. - short y_pos; - short end_x; - short end_y; - - Load_gradient_data(index); - - start_x=Window_pos_X+(start_x*Menu_factor_X); - start_y=Window_pos_Y+(start_y*Menu_factor_Y); - - Gradient_total_range=width*Menu_factor_X; - - end_x=start_x+Gradient_total_range; - end_y=start_y+(height*Menu_factor_Y); - - for (y_pos=start_y;y_posPages->Gradients,sizeof(T_Gradient_array)); - - Open_window(235,146,"Gradation menu"); - - 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,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(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,127,110,16); - // On affiche la preview - Draw_gradient_preview(8,128,108,14,Current_gradient); - - 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(); - - do - { - 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) - { - case -1 : - case 1 : // Palette - if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) - { - Hide_cursor(); - temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); - - if (!old_mouse_k) - { - // On vient de clicker - - // On met à jour l'intervalle du dégradé - 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(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); - // Tracé de la preview: - Draw_gradient_preview(8,128,108,14,Current_gradient); - } - else - { - // On maintient le click, on va donc tester si le curseur bouge - if (temp_color!=last_color) - { - // On commence par ordonner la 1ère et dernière couleur du bloc - if (first_colorPages->Gradients->Range[Current_gradient].Start=first_color; - Main_backups->Pages->Gradients->Range[Current_gradient].End =temp_color; - } - else if (first_color>temp_color) - { - Main_backups->Pages->Gradients->Range[Current_gradient].Start=temp_color; - Main_backups->Pages->Gradients->Range[Current_gradient].End =first_color; - } - else - 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(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); - // Tracé de la preview: - Draw_gradient_preview(8,128,108,14,Current_gradient); - last_color=temp_color; - } - } - Display_cursor(); - } - break; - case 2 : // Nouvel indice de dégradé - // Nouvel indice dans Window_attribute2 - Current_gradient=Window_attribute2; - changed_gradient_index=1; - break; - case 3 : // Nouveau mélange de dégradé - Hide_cursor(); - // Nouvel mélange dans Window_attribute2 - Main_backups->Pages->Gradients->Range[Current_gradient].Mix=Window_attribute2; - // On affiche la nouvelle preview - 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) - 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,128,108,14,Current_gradient); - Display_cursor(); - break; - case 5 : // Changement de technique - Hide_cursor(); - // On change la technique par (+1)%3 - 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,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) - switch (Key) - { - case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu - case SDLK_COMMA : - Get_color_behind_window(&color,&click); - if (click) - { - Hide_cursor(); - temp_color=color; - - // On met à jour l'intervalle du dégradé - 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(Main_backups->Pages->Gradients->Range[Current_gradient].Start,Main_backups->Pages->Gradients->Range[Current_gradient].End); - // Tracé de la preview: - 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)) - { - Window_help(BUTTON_GRADRECT, NULL); - Key=0; - break; - } - 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 && clicked_button!=7); - - Close_window(); - // The Grad rect operation uses the same button as Grad menu. - if (Current_operation != OPERATION_GRAD_RECTANGLE) - Unselect_button(BUTTON_GRADRECT); - - Display_cursor(); - - Gradient_pixel=Display_pixel; - Cycling_mode=cycling_mode; - if (clicked_button==7) // Cancel - { - Current_gradient=old_current_gradient; - memcpy(Main_backups->Pages->Gradients,&backup_gradients,sizeof(T_Gradient_array)); - } -} - - -// -- Gestion des boutons de cercle / ellipse / rectangle dégradés -------------------- - -void Button_Grad_circle(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_GRAD_CIRCLE); - Display_cursor(); -} - - -void Button_Grad_ellipse(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_GRAD_ELLIPSE); - Display_cursor(); -} - - -void Button_Grad_rectangle(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_GRAD_RECTANGLE); - Display_cursor(); -} - - -// -- Gestion du bouton de remplissage --------------------------------------- - -void Button_Fill(void) -{ - if (Current_operation!=OPERATION_FILL) - { - Hide_cursor(); - - if (Current_operation!=OPERATION_REPLACE) - { - Paintbrush_shape_before_fill=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - } - else - if ( (Mouse_Y=Main_X_zoom) ) ) - Print_in_menu("X: Y: ",0); - Start_operation_stack(OPERATION_FILL); - Display_cursor(); - } -} - - -void Button_Replace(void) -{ - if (Current_operation!=OPERATION_REPLACE) - { - Hide_cursor(); - if (Current_operation!=OPERATION_FILL) - { - Paintbrush_shape_before_fill=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - } - if ( (Mouse_Y=Main_X_zoom) ) ) - Print_in_menu("X: Y: ( )",0); - Start_operation_stack(OPERATION_REPLACE); - Display_cursor(); - } -} - - -void Button_Unselect_fill(void) -{ - Paintbrush_shape=Paintbrush_shape_before_fill; - - if (Current_operation==OPERATION_REPLACE) - if ( (Mouse_Y=Main_X_zoom) ) ) - Print_in_menu("X: Y: ",0); -} - - -//---------------------------- 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+3)) - { - index = clicked_button-NB_PAINTBRUSH_SPRITES-3; - - if (Window_attribute2==1) // Set - { - // Store - - x_pos=13+((index+NB_PAINTBRUSH_SPRITES)%12)*24; - y_pos=27+((index+NB_PAINTBRUSH_SPRITES)/12)*25; - - Store_brush(index); - Hide_cursor(); - Display_stored_brush_in_window(x_pos+2, y_pos+2, index); - Display_cursor(); - } - else - { - // Restore and exit - - if (Restore_brush(index)) - { - Close_window(); - break; - } - } - - } - else if (clicked_button>=3) - // Standard paintbrushes - { - 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); - - Unselect_button(BUTTON_PAINTBRUSHES); - Display_cursor(); -} - - -void Button_Brush_monochrome(void) -{ - Hide_cursor(); - // On passe en brosse monochrome: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH); - - Unselect_button(BUTTON_PAINTBRUSHES); - - Display_cursor(); -} - -// -- Fonction renvoyant le mode vidéo le plus adapté à l'image chargée ----- -#define TOLERANCE_X 8 -#define TOLERANCE_Y 4 -int Best_video_mode(void) -{ - short best_width,best_height; - int best_mode; - short temp_x,temp_y; - int mode; - - // Si mode fenêtre, on reste dans ce mode. - if (Current_resolution == 0) - return 0; - - // On commence par borner les dimensions, ou du moins les rendre cohérentes - if ((Original_screen_X<=0) || (Config.Set_resolution_according_to==2)) - Original_screen_X=Main_image_width; - else - if (Original_screen_X<320) - Original_screen_X=320; - - if ((Original_screen_Y<=0) || (Config.Set_resolution_according_to==2)) - Original_screen_Y=Main_image_height; - else - if (Original_screen_Y<200) - Original_screen_Y=200; - - if ((Original_screen_X>1024) || (Original_screen_Y>768)) - { - Original_screen_X=1024; - Original_screen_Y=768; - } - - // Maintenant on peut chercher le mode qui correspond le mieux - best_mode=Current_resolution; - best_width=0; - best_height=0; - - - for (mode=1; mode On charge/sauve une image - // Image=0 => On charge/sauve une brosse -{ - byte confirm; - byte old_cursor_shape; - int new_mode; - T_IO_Context context; - static char filename [MAX_PATH_CHARACTERS]; - static char directory[MAX_PATH_CHARACTERS]; - - if (image) - { - strcpy(filename, Main_backups->Pages->Filename); - strcpy(directory, Main_backups->Pages->File_directory); - Init_context_layered_image(&context, filename, directory); - } - else - { - strcpy(filename, Brush_filename); - strcpy(directory, Main_current_directory); - Init_context_brush(&context, Brush_filename, Main_current_directory); - } - confirm=Button_Load_or_Save(1, &context); - - if (confirm) - { - if (image) - { - if (Main_image_is_modified) - confirm=Confirmation_box("Discard unsaved changes?"); - } - } - - // confirm is modified inside the first if, that's why we check it - // again here - if (confirm) - { - old_cursor_shape=Cursor_shape; - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - - if (image) - { - Original_screen_X=0; - Original_screen_Y=0; - } - - Load_image(&context); - - if (!image) - { - if (File_error==3) // Memory allocation error when loading brush - { - // 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; - - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - - Select_button(BUTTON_DRAW,LEFT_SIDE); - if (Config.Auto_discontinuous) - { - // On se place en mode Dessin discontinu à la main - while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) - Select_button(BUTTON_DRAW,RIGHT_SIDE); - } - Hide_cursor(); - // On passe en brosse couleur: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - } - else - { - Hide_cursor(); - Cursor_shape=old_cursor_shape; - } - - - if ( (File_error==1) || (Get_fileformat(Main_fileformat)->Palette_only) ) - { - if (File_error!=1) - Compute_optimal_menu_colors(Main_palette); - } - else - { - if (image) - { - if (Main_magnifier_mode) - { - Pixel_preview=Pixel_preview_normal; - Main_magnifier_mode=0; - Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); - } - - new_mode=Best_video_mode(); - if ((Config.Auto_set_res) && (new_mode!=Current_resolution)) - { - Init_mode_video( - Video_mode[new_mode].Width, - Video_mode[new_mode].Height, - Video_mode[new_mode].Fullscreen, - Pixel_ratio); - Display_menu(); - } - // In window mode, activate wide or tall pixels if the image says so. - else if (!Video_mode[Current_resolution].Fullscreen && - ((context.Ratio == PIXEL_WIDE && - Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || - (context.Ratio == PIXEL_TALL && - Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2))) - { - Init_mode_video( - Video_mode[Current_resolution].Width, - Video_mode[Current_resolution].Height, - Video_mode[Current_resolution].Fullscreen, - context.Ratio); - Display_menu(); - } - else - { - Main_offset_X=0; - Main_offset_Y=0; - Compute_limits(); - Compute_paintbrush_coordinates(); - } - } - - Compute_optimal_menu_colors(Main_palette); - Redraw_layered_image(); - End_of_modification(); - Display_all_screen(); - - if (image) - Main_image_is_modified=0; - } - - Destroy_context(&context); - - Display_menu(); - Display_cursor(); - } - - //if (!image) - // Swap_data_of_image_and_brush(); - Hide_cursor(); - Print_filename(); - Display_cursor(); - Set_palette(Main_palette); -} - - -void Button_Load(void) -{ - // On sauve l'état actuel des paramètres de l'image pour pouvoir les - // restituer en cas d'erreur n'affectant pas l'image - Upload_infos_page_main(Main_backups->Pages); - - Load_picture(1); -} - - -void Button_Reload(void) -{ - byte old_cursor_shape; - int new_mode; - - // On sauve l'état actuel des paramètres de l'image pour pouvoir les - // restituer en cas d'erreur n'affectant pas l'image - Upload_infos_page_main(Main_backups->Pages); - - if ( (!Main_image_is_modified) || Confirmation_box("Discard unsaved changes ?") ) - { - T_IO_Context context; - - Hide_cursor(); - old_cursor_shape=Cursor_shape; - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - - Original_screen_X=0; - Original_screen_Y=0; - - Init_context_layered_image(&context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); - Load_image(&context); - - Hide_cursor(); - Cursor_shape=old_cursor_shape; - - if (File_error!=1) - { - if (Main_magnifier_mode) - { - Pixel_preview=Pixel_preview_normal; - Main_magnifier_mode=0; - Draw_menu_button(BUTTON_MAGNIFIER,Main_magnifier_mode); - } - - new_mode=Best_video_mode(); - if ( ((Config.Auto_set_res) && (new_mode!=Current_resolution)) && - (!Resolution_in_command_line) ) - { - Init_mode_video( - Video_mode[new_mode].Width, - Video_mode[new_mode].Height, - Video_mode[new_mode].Fullscreen, - Pixel_ratio); - Display_menu(); - } - // In window mode, activate wide or tall pixels if the image says so. - else if (!Video_mode[Current_resolution].Fullscreen && - ((context.Ratio == PIXEL_WIDE && - Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) || - (context.Ratio == PIXEL_TALL && - Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2))) - { - Init_mode_video( - Video_mode[Current_resolution].Width, - Video_mode[Current_resolution].Height, - Video_mode[Current_resolution].Fullscreen, - context.Ratio); - Display_menu(); - } - else - { - Main_offset_X=0; - Main_offset_Y=0; - Compute_limits(); - Compute_paintbrush_coordinates(); - } - Redraw_layered_image(); - End_of_modification(); - Display_all_screen(); - - Main_image_is_modified=0; - } - Destroy_context(&context); - } - else - Hide_cursor(); - - Compute_optimal_menu_colors(Main_palette); - Display_menu(); - if (Config.Display_image_limits) - Display_image_limits(); - - Unselect_button(BUTTON_LOAD); - - Display_cursor(); -} - - -void Backup_filename(char * fname, char * backup_name) -{ - short i; - - strcpy(backup_name,fname); - for (i=strlen(fname)-strlen(Main_backups->Pages->Filename); backup_name[i]!='.'; i++); - backup_name[i+1]='\0'; - strcat(backup_name,"BAK"); -} - - -void Backup_existing_file(void) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - char new_filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier backup - - Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); - // Calcul du nom complet du fichier backup - Backup_filename(filename,new_filename); - - File_error=0; - - // On fait un backup si le nom du fichier n'est pas celui qu'on a choisi - // pour nommer les backups (c'est évident!). - if (strcmp(new_filename,filename)) - { - // S'il y avait déjà un fichier Backup, on l'efface - if ((File_exists(new_filename)) - && (remove(new_filename)!=0)) - File_error=1; - - if ((!File_error) - && (rename(filename,new_filename)!=0)) - File_error=1; - } -} - - -void Save_picture(byte image) - // image=1 => On charge/sauve une image - // image=0 => On charge/sauve une brosse -{ - byte confirm; - byte old_cursor_shape; - T_IO_Context save_context; - static char filename [MAX_PATH_CHARACTERS]; - static char directory[MAX_PATH_CHARACTERS]; - - if (image) - { - strcpy(filename, Main_backups->Pages->Filename); - strcpy(directory, Main_backups->Pages->File_directory); - Init_context_layered_image(&save_context, filename, directory); - save_context.Format = Main_fileformat; - } - else - { - strcpy(filename, Brush_filename); - strcpy(directory, Brush_file_directory); - Init_context_brush(&save_context, filename, directory); - save_context.Format = Main_fileformat; - } - - //if (!image) - // Swap_data_of_image_and_brush(); - - confirm=Button_Load_or_Save(0, &save_context); - - if (confirm && File_exists(save_context.File_name)) - { - confirm=Confirmation_box("Erase old file ?"); - if (confirm && (Config.Backup)) - { - Backup_existing_file(); - if (File_error) - { - confirm=0; - Error(0); - } - } - } - - if (confirm) - { - - old_cursor_shape=Cursor_shape; - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - - Save_image(&save_context); - - if (!File_error && image && !Get_fileformat(save_context.Format)->Palette_only) - { - Main_image_is_modified=0; - strcpy(Main_backups->Pages->Filename, save_context.File_name); - strcpy(Main_backups->Pages->File_directory, save_context.File_directory); - } - - Hide_cursor(); - Cursor_shape=old_cursor_shape; - Display_cursor(); - } - Destroy_context(&save_context); - - Print_filename(); - Set_palette(Main_palette); -} - - -void Button_Save(void) -{ - Save_picture(1); -} - - -void Button_Autosave(void) -{ - byte old_cursor_shape; - static char filename[MAX_PATH_CHARACTERS]; - byte file_already_exists; - - - Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); - file_already_exists=File_exists(filename); - - if ( (!file_already_exists) || Confirmation_box("Erase old file ?") ) - { - if ((file_already_exists) && (Config.Backup)) - Backup_existing_file(); - else - File_error=0; - - Hide_cursor(); - - if (!File_error) - { - T_IO_Context save_context; - - old_cursor_shape=Cursor_shape; - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - - Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory); - Save_image(&save_context); - if (!File_error) - { - Main_image_is_modified=0; - } - Destroy_context(&save_context); - - Hide_cursor(); - Cursor_shape=old_cursor_shape; - } - else - Error(0); - } - else - Hide_cursor(); - - Unselect_button(BUTTON_SAVE); - - Display_cursor(); -} - - -// -- Gestion des boutons de ligne ------------------------------------------ - -void Button_Lines(void) -{ - Hide_cursor(); - Start_operation_stack(Selected_line_mode); - Display_cursor(); -} - - -void Button_Lines_switch_mode(void) -{ - char icon; - - if (Selected_line_mode==OPERATION_LINE) - Selected_line_mode=OPERATION_K_LINE; - else - { - 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,icon); - Draw_menu_button(BUTTON_LINES,BUTTON_PRESSED); - Start_operation_stack(Selected_line_mode); - Display_cursor(); -} - - -// -- Button de brosse ------------------------------------------------------ - -void Button_Brush(void) -{ - Hide_cursor(); - - if (Current_operation!=OPERATION_GRAB_BRUSH) - Start_operation_stack(OPERATION_GRAB_BRUSH); - else - Unselect_button(BUTTON_BRUSH); - - Display_cursor(); -} - - -void Button_Unselect_brush(void) -{ - // On fait de notre mieux pour restaurer l'ancienne opération: - Start_operation_stack(Operation_before_interrupt); -} - - -void Button_Restore_brush(void) -{ - Hide_cursor(); - // On passe en brosse couleur: - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - - Unselect_button(BUTTON_BRUSH); - Unselect_button(BUTTON_POLYBRUSH); - - Display_cursor(); -} - - -// -- Button de prise de brosse au lasso ------------------------------------ - -void Button_Lasso(void) -{ - Hide_cursor(); - - if (Current_operation!=OPERATION_POLYBRUSH) - { - Paintbrush_shape_before_lasso=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - Start_operation_stack(OPERATION_POLYBRUSH); - } - else - Unselect_button(BUTTON_POLYBRUSH); - - Display_cursor(); -} - - -void Button_Unselect_lasso(void) -{ - // On fait de notre mieux pour restaurer l'ancienne opération: - Start_operation_stack(Operation_before_interrupt); - Paintbrush_shape=Paintbrush_shape_before_lasso; -} - - -// -- Button de pipette ----------------------------------------------------- - -void Button_Colorpicker(void) -{ - Hide_cursor(); - - if (Current_operation!=OPERATION_COLORPICK) - { - Colorpicker_color=-1; - Start_operation_stack(OPERATION_COLORPICK); - Paintbrush_shape_before_colorpicker=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_NONE; - if (Operation_before_interrupt!=OPERATION_REPLACE) - if ( (Mouse_Y=Main_X_zoom) ) ) - Print_in_menu("X: Y: ( )",0); - } - else - Unselect_button(BUTTON_COLORPICKER); - - Display_cursor(); -} - - -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) ) ) - Print_in_menu("X: Y: ",0); - - // On fait de notre mieux pour restaurer l'ancienne opération: - if (Current_operation==OPERATION_COLORPICK) - { - Start_operation_stack(Operation_before_interrupt); - Paintbrush_shape=Paintbrush_shape_before_colorpicker; - } -} - - - // -- Inversion de la couleur Fore et de la couleur Back -- -void Button_Invert_foreback(void) -{ - byte temp_color; - - temp_color=Fore_color; - Fore_color =Back_color; - Back_color =temp_color; - - Hide_cursor(); - Frame_menu_color(Back_color); - Frame_menu_color(Fore_color); - Reposition_palette(); - Display_foreback(); - Unselect_button(BUTTON_COLORPICKER); - Display_cursor(); -} - - -// -- Gestion du bouton Loupe ----------------------------------------------- - -byte Coming_from_zoom_factor_menu=0; - -void Button_Magnify(void) -{ - Hide_cursor(); - if ( (Current_operation==OPERATION_MAGNIFY) || (Main_magnifier_mode) ) - { - Unselect_button(BUTTON_MAGNIFIER); - } - else - { - Compute_magnifier_data(); - if ((!Config.Fast_zoom) || (Mouse_Y>=Menu_Y) || Coming_from_zoom_factor_menu) - { - Coming_from_zoom_factor_menu=0; - Start_operation_stack(OPERATION_MAGNIFY); - } - else - { /* Ceci est de la duplication de code de presque toute l'opération de */ - /* la loupe... Il serait peut-être plus propre de faire une procédure */ - /* qui s'en charge... */ - // On passe en mode loupe - Main_magnifier_mode=1; - - // La fonction d'affichage dans la partie image est désormais un affichage - // spécial loupe. - Pixel_preview=Pixel_preview_magnifier; - - // On calcule l'origine de la loupe - Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1); - Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1); - - // Calcul des coordonnées absolues de ce coin DANS L'IMAGE - Main_magnifier_offset_X+=Main_offset_X; - Main_magnifier_offset_Y+=Main_offset_Y; - - Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); - - // On calcule les bornes visibles dans l'écran - Position_screen_according_to_zoom(); - Compute_limits(); - Display_all_screen(); - - // Repositionner le curseur en fonction des coordonnées visibles - Compute_paintbrush_coordinates(); - } - } - Display_cursor(); - Update_rect(0,0,0,0); -} - -void Button_Magnify_menu(void) -{ - T_Dropdown_button dropdown; - T_Dropdown_choice *item; - int i; - const char text[NB_ZOOM_FACTORS][4] = - {"x2", "x3", "x4", "x5", "x6", "x8", "x10", "x12", "x14", "x16", "x18", "x20", - "x24", "x28", "x32"}; - - Hide_cursor(); - - dropdown.Pos_X =Buttons_Pool[BUTTON_MAGNIFIER].X_offset; - dropdown.Pos_Y =Buttons_Pool[BUTTON_MAGNIFIER].Y_offset; - dropdown.Height =Buttons_Pool[BUTTON_MAGNIFIER].Height; - dropdown.Dropdown_width=28; - dropdown.First_item =NULL; - dropdown.Bottom_up =1; - - for(i = 0; i < NB_ZOOM_FACTORS; i++) { - Window_dropdown_add_item(&dropdown, i, text[i]); - } - - item=Dropdown_activate(&dropdown,0,Menu_Y); - - if (item) - { - Change_magnifier_factor(item->Number,0); - } - - if ( (!item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Cancel - Unselect_button(BUTTON_MAGNIFIER); - - Display_all_screen(); - Display_cursor(); - Update_rect(Main_separator_position,0,Screen_width-Main_separator_position,Menu_Y); - - if ( (item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Passage en mode zoom - { - Coming_from_zoom_factor_menu=1; - Select_button(BUTTON_MAGNIFIER,LEFT_SIDE); - } - - Window_dropdown_clear_items(&dropdown); -} - -void Button_Unselect_magnifier(void) -{ - if (Main_magnifier_mode) - { - // 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 (Main_offset_X+Screen_width>Main_image_width) - Main_offset_X=Main_image_width-Screen_width; - if (Main_offset_X<0) - Main_offset_X=0; - - if (Main_offset_Y+Menu_Y>Main_image_height) - Main_offset_Y=Main_image_height-Menu_Y; - if (Main_offset_Y<0) - Main_offset_Y=0; - - // La fonction d'affichage dans l'image est désormais un affichage normal. - Pixel_preview=Pixel_preview_normal; - - // Calculer les bornes visibles dans l'écran - Compute_limits(); - Display_all_screen(); // <=> Display_screen(); - // Repositionner le curseur en fonction des coordonnées visibles - Compute_paintbrush_coordinates(); - - Old_MX = -1; - Old_MY = -1; - } - else // On fait de notre mieux pour restaurer l'ancienne opération: - Start_operation_stack(Operation_before_interrupt); -} - - -// ----------------------- Modifications de brosse --------------------------- - -void Button_Brush_FX(void) -{ - short clicked_button; - short index; - - Open_window(310,162,"Brush effects"); - - Window_display_frame( 6,19,298,61); - Window_display_frame( 6,83,122,53); - Window_display_frame(137,83,167,53); - - Window_set_normal_button(236,141, 67,14,"Cancel" ,0,1,KEY_ESC); // 1 - Window_set_normal_button( 19, 46, 27,14,"X\035" ,0,1,Config_Key[SPECIAL_FLIP_X][0]); // 2 - Window_set_normal_button( 19, 61, 27,14,"Y\022" ,0,1,Config_Key[SPECIAL_FLIP_Y][0]); // 3 - Window_set_normal_button( 58, 46, 37,14,"90°" ,0,1,Config_Key[SPECIAL_ROTATE_90][0]); // 4 - Window_set_normal_button( 96, 46, 37,14,"180°" ,0,1,Config_Key[SPECIAL_ROTATE_180][0]); // 5 - Window_set_normal_button( 58, 61, 75,14,"any angle" ,0,1,Config_Key[SPECIAL_ROTATE_ANY_ANGLE][0]); // 6 - Window_set_normal_button(145, 46, 67,14,"Stretch" ,0,1,Config_Key[SPECIAL_STRETCH][0]); // 7 - Window_set_normal_button(145, 61, 67,14,"Distort" ,0,1,Config_Key[SPECIAL_DISTORT][0]); // 8 - Window_set_normal_button(155, 99,131,14,"Recolorize" ,0,1,Config_Key[SPECIAL_RECOLORIZE_BRUSH][0]); // 9 - Window_set_normal_button(155,117,131,14,"Get brush colors",0,1,Config_Key[SPECIAL_GET_BRUSH_COLORS][0]); // 10 - - // Boutons représentant les coins du brush handle: (HG,HD,C,BG,BD) - Window_set_normal_button( 75, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_LEFT_ATTACHMENT][0]); // 11 - Window_set_normal_button(103, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_RIGHT_ATTACHMENT][0]); // 12 - Window_set_normal_button( 89,104,11,11,"",0,1,Config_Key[SPECIAL_CENTER_ATTACHMENT][0]); // 13 - Window_set_normal_button( 75,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_LEFT_ATTACHMENT][0]); // 14 - Window_set_normal_button(103,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_RIGHT_ATTACHMENT][0]); // 15 - - Window_set_normal_button(224,46,67,14,"Outline",0,1,Config_Key[SPECIAL_OUTLINE][0]); // 16 - Window_set_normal_button(224,61,67,14,"Nibble" ,0,1,Config_Key[SPECIAL_NIBBLE][0]); // 17 - - Window_set_normal_button( 7,141, 60,14,"Load",0,1,Config_Key[SPECIAL_LOAD_BRUSH][0]); // 18 - Window_set_normal_button( 70,141, 60,14,"Save",0,1,Config_Key[SPECIAL_SAVE_BRUSH][0]); // 19 - - Print_in_window( 80, 24,"Shape modifications",MC_Dark,MC_Light); - Print_in_window( 10, 36,"Mirror",MC_Dark,MC_Light); - Print_in_window( 72, 36,"Rotate",MC_Dark,MC_Light); - Print_in_window(155, 36,"Deform",MC_Dark,MC_Light); - Print_in_window(230, 36,"Borders",MC_Dark,MC_Light); - Print_in_window(141, 88,"Colors modifications",MC_Dark,MC_Light); - Print_in_window( 20,102,"Brush",MC_Dark,MC_Light); - Print_in_window( 16,110,"handle",MC_Dark,MC_Light); - - // Dessin des pointillés pour le "brush handle" - for (index=0; index<13; index+=2) - { - Pixel_in_window( 88+index, 92,MC_Dark); - Pixel_in_window( 88+index,126,MC_Dark); - Pixel_in_window( 77,103+index,MC_Dark); - Pixel_in_window(111,103+index,MC_Dark); - } - // Dessin des coins et du centre pour les boutons du "brush handle" - // Coin HG - Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X*7,Menu_factor_Y,MC_Black); - Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X,Menu_factor_Y*7,MC_Black); - // Coin HD - Block(Window_pos_X+(Menu_factor_X*105),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X*7,Menu_factor_Y,MC_Black); - Block(Window_pos_X+(Menu_factor_X*111),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X,Menu_factor_Y*7,MC_Black); - // Centre - Block(Window_pos_X+(Menu_factor_X* 91),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*7,Menu_factor_Y,MC_Black); - Block(Window_pos_X+(Menu_factor_X* 94),Window_pos_Y+(Menu_factor_Y*106),Menu_factor_X,Menu_factor_Y*7,MC_Black); - // Coin BG - Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y*126),Menu_factor_X*7,Menu_factor_Y,MC_Black); - Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y*120),Menu_factor_X,Menu_factor_Y*7,MC_Black); - // Coin BD - Block(Window_pos_X+(Menu_factor_X*105),Window_pos_Y+(Menu_factor_Y*126),Menu_factor_X*7,Menu_factor_Y,MC_Black); - Block(Window_pos_X+(Menu_factor_X*111),Window_pos_Y+(Menu_factor_Y*120),Menu_factor_X,Menu_factor_Y*7,MC_Black); - - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Key=0; - Window_help(BUTTON_BRUSH_EFFECTS, NULL); - } - else if (Is_shortcut(Key,0x100+BUTTON_BRUSH_EFFECTS)) - { - clicked_button=1; - } - } - while (clicked_button<=0); - - Close_window(); - Unselect_button(BUTTON_BRUSH_EFFECTS); - - // Gestion du bouton clické - switch (clicked_button) - { - case 2 : // Flip X - 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_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(); - break; - case 5 : // 180° Rotation - Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height); - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - break; - case 6 : // Any angle rotation - Start_operation_stack(OPERATION_ROTATE_BRUSH); - break; - case 7 : // Stretch - Start_operation_stack(OPERATION_STRETCH_BRUSH); - break; - case 8 : // Distort - Start_operation_stack(OPERATION_DISTORT_BRUSH); - break; - case 9 : // Recolorize - Remap_brush(); - break; - case 10 : // Get brush colors - Display_cursor(); - Get_colors_from_brush(); - Hide_cursor(); - break; - case 11 : // Brush Attachment: Top-Left - Brush_offset_X=0; - Brush_offset_Y=0; - break; - case 12 : // Brush Attachment: Top-Right - Brush_offset_X=(Brush_width-1); - Brush_offset_Y=0; - break; - case 13 : // Brush Attachment: Center - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - break; - case 14 : // Brush Attachment: Bottom-Left - Brush_offset_X=0; - Brush_offset_Y=(Brush_height-1); - break; - case 15 : // Brush Attachment: Bottom-Right - Brush_offset_X=(Brush_width-1); - Brush_offset_Y=(Brush_height-1); - break; - case 16 : // Outline - Outline_brush(); - break; - case 17 : // Nibble - Nibble_brush(); - break; - case 18 : // Load - Display_cursor(); - Load_picture(0); - Hide_cursor(); - break; - case 19 : // Save - Display_cursor(); - Save_picture(0); - Hide_cursor(); - break; - } - - Display_cursor(); -} - - -//---------------------------- Courbes de Bézier ---------------------------- - -void Button_Curves(void) -{ - Hide_cursor(); - Start_operation_stack(Selected_curve_mode); - Display_cursor(); -} - - -void Button_Curves_switch_mode(void) -{ - if (Selected_curve_mode==OPERATION_4_POINTS_CURVE) - Selected_curve_mode=OPERATION_3_POINTS_CURVE; - else - Selected_curve_mode=OPERATION_4_POINTS_CURVE; - - Hide_cursor(); - 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(); -} - - -//--------------------------------- Spray ----------------------------------- - -void Button_Airbrush(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_AIRBRUSH); - Display_cursor(); -} - - -void Refresh_airbrush_settings(byte selected_color, byte update_slider) -{ - char str[3]; - - if (update_slider) - { - Window_scroller_button_list->Position=49-Airbrush_multi_flow[selected_color]; - Window_draw_slider(Window_scroller_button_list); - } - Num2str(Airbrush_multi_flow[selected_color],str,2); - Print_in_window(196,130,str,MC_Black,MC_Light); - - Update_rect(Window_pos_X+(Menu_factor_X*(Window_palette_button_list->Pos_X+4+(selected_color >> 4)*10)), - Window_pos_Y+(Menu_factor_Y*(Window_palette_button_list->Pos_Y+3+(selected_color & 15)* 5)), - Menu_factor_X<<1,Menu_factor_Y*5); -} - - -void Button_Airbrush_menu(void) -{ - static byte spray_init=1; - short clicked_button; - char str[4]; - word index; - byte selected_color=Fore_color; - byte old_airbrush_mode =Airbrush_mode; - short old_airbrush_size =Airbrush_size; - byte old_airbrush_delay =Airbrush_delay; - byte old_airbrush_mono_flow=Airbrush_mono_flow; - byte old_airbrush_multi_flow[256]; - T_Special_button * input_size_button; - T_Special_button * input_delay_button; - T_Special_button * input_flow_button; - T_Special_button * input_init_button; - word old_mouse_x; - word old_mouse_y; - byte old_mouse_k; - byte color; - byte click; - - - memcpy(old_airbrush_multi_flow,Airbrush_multi_flow,256); - - - Open_window(226,170,"Spray"); - - Window_set_normal_button(110,148,51,14,"Cancel" ,0,1,KEY_ESC); // 1 - Window_set_normal_button(166,148,51,14,"OK" ,0,1,SDLK_RETURN); // 2 - - Window_set_scroller_button(178,62,74,50,1,49-Airbrush_multi_flow[selected_color]); // 3 - - Window_set_palette_button(7,56); // 4 - - Window_set_normal_button( 8,148,83,14,"Mode: ",0,1,SDLK_TAB); // 5 - if (Airbrush_mode) - Print_in_window(50,151," Mono",MC_Black,MC_Light); - else - Print_in_window(50,151,"Multi",MC_Black,MC_Light); - - Window_set_normal_button(194, 62,19,14,"+1" ,0,1,SDLK_KP_PLUS); // 6 - Window_set_normal_button(194, 79,19,14,"-1" ,0,1,SDLK_KP_MINUS); // 7 - Window_set_normal_button(194, 96,19,14,"x2" ,0,1,SDLK_KP_MULTIPLY); // 8 - Window_set_normal_button(194,113,19,14,"÷2" ,0,1,SDLK_KP_ENTER); // 9 - - Window_set_normal_button( 8, 37,43,14,"Clear" ,1,1,SDLK_c); // 10 - - Print_in_window(142,25,"Size:" ,MC_Dark,MC_Light); - input_size_button = Window_set_input_button(186,23,3); // 11 - Num2str(Airbrush_size,str,3); - Window_input_content(input_size_button,str); - - Print_in_window(142,39,"Delay:" ,MC_Dark,MC_Light); - input_delay_button = Window_set_input_button(194,37,2); // 12 - Num2str(Airbrush_delay,str,2); - Window_input_content(input_delay_button,str); - - Print_in_window( 27,24,"Mono-Flow:",MC_Dark,MC_Light); - input_flow_button = Window_set_input_button(111,22,2); // 13 - Num2str(Airbrush_mono_flow,str,2); - Window_input_content(input_flow_button,str); - - Print_in_window( 67,40,"Init:",MC_Dark,MC_Light); - input_init_button = Window_set_input_button(111,38,2); // 14 - Num2str(spray_init,str,2); - Window_input_content(input_init_button,str); - - Window_display_frame(173,56,45,86); - Window_display_frame(137,19,81,33); - - // On tagge toutes les couleurs utilisées - for (index=0; index<256; index++) - if (Airbrush_multi_flow[index]) - Stencil_tag_color(index,MC_Black); - // Et enfin, on tagge la couleur sélectionnée - Stencil_tag_color(selected_color,MC_White); - Refresh_airbrush_settings(selected_color,0); - - Update_window_area(0,0,Window_width, Window_height); - Display_cursor(); - Stencil_update_color(selected_color); - - - do - { - old_mouse_x=Mouse_X; - old_mouse_y=Mouse_Y; - old_mouse_k=Mouse_K; - - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case 0 : - case 2 : // OK - break; - - case 1 : // Cancel - Airbrush_mode =old_airbrush_mode; - Airbrush_size =old_airbrush_size; - Airbrush_delay =old_airbrush_delay; - Airbrush_mono_flow=old_airbrush_mono_flow; - memcpy(Airbrush_multi_flow,old_airbrush_multi_flow,256); - break; - - case 3 : // Scroller - Hide_cursor(); - Airbrush_multi_flow[selected_color]=49-Window_attribute2; - Refresh_airbrush_settings(selected_color,0); - Display_cursor(); - break; - - case -1 : - case 4 : // Palette - if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) - { - Hide_cursor(); - Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light); - Stencil_update_color(selected_color); - // Mettre la couleur sélectionnée à jour suivant le click - selected_color=(clicked_button==4) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); - if (Mouse_K==2) - Airbrush_multi_flow[selected_color]=0; - else - if (Airbrush_multi_flow[selected_color]==0) - Airbrush_multi_flow[selected_color]=spray_init; - - // Tagger la couleur sélectionnée en blanc - Stencil_tag_color(selected_color,MC_White); - Refresh_airbrush_settings(selected_color,1); - Display_cursor(); - Stencil_update_color(selected_color); - } - break; - - case 5 : // Toggle Mode - Airbrush_mode=(Airbrush_mode+1)&1; - Hide_cursor(); - if (Airbrush_mode) - Print_in_window(50,151," Mono",MC_Black,MC_Light); - else - Print_in_window(50,151,"Multi",MC_Black,MC_Light); - Update_rect(Window_pos_X+50*Menu_factor_X,Window_pos_Y+151*Menu_factor_Y,5*8*Menu_factor_X,8*Menu_factor_Y); - Display_cursor(); - break; - - case 6 : // +1 - for (index=0; index<256; index++) - { - if ( (Airbrush_multi_flow[index]) && (Airbrush_multi_flow[index]<49) ) - Airbrush_multi_flow[index]++; - } - Hide_cursor(); - Refresh_airbrush_settings(selected_color,1); - Display_cursor(); - break; - - case 7 : // -1 - for (index=0; index<256; index++) - { - if (Airbrush_multi_flow[index]>1) - Airbrush_multi_flow[index]--; - } - Hide_cursor(); - Refresh_airbrush_settings(selected_color,1); - Display_cursor(); - break; - - case 8 : // x2 - for (index=0; index<256; index++) - { - if (Airbrush_multi_flow[index]) - { - Airbrush_multi_flow[index]<<=1; - if (Airbrush_multi_flow[index]>49) - Airbrush_multi_flow[index]=49; - } - } - Hide_cursor(); - Refresh_airbrush_settings(selected_color,1); - Display_cursor(); - break; - - case 9 : // ÷2 - for (index=0; index<256; index++) - { - if (Airbrush_multi_flow[index]>1) - Airbrush_multi_flow[index]>>=1; - } - Hide_cursor(); - Refresh_airbrush_settings(selected_color,1); - Display_cursor(); - break; - - case 10 : // Clear - memset(Airbrush_multi_flow,0,256); - // On raffiche les infos de la couleur sélectionnée - Refresh_airbrush_settings(selected_color,1); - // On efface les anciens TAGs - Window_clear_tags(); - // Tagger la couleur sélectionnée en blanc - Stencil_tag_color(selected_color,MC_White); - Stencil_update_color(selected_color); - break; - - case 11 : // Size - Num2str(Airbrush_size,str,3); - Readline(188,25,str,3,INPUT_TYPE_INTEGER); - Airbrush_size=atoi(str); - // On corrige les dimensions - if (Airbrush_size>256) - { - Airbrush_size=256; - Num2str(Airbrush_size,str,3); - Window_input_content(input_size_button,str); - } - else if (!Airbrush_size) - { - Airbrush_size=1; - Num2str(Airbrush_size,str,3); - Window_input_content(input_size_button,str); - } - Display_cursor(); - break; - - case 12 : // Delay - Num2str(Airbrush_delay,str,2); - Readline(196,39,str,2,INPUT_TYPE_INTEGER); - Airbrush_delay=atoi(str); - // On corrige le delai - if (Airbrush_delay>99) - { - Airbrush_delay=99; - Num2str(Airbrush_delay,str,2); - Window_input_content(input_delay_button,str); - } - Display_cursor(); - break; - - case 13 : // Mono-Flow - Num2str(Airbrush_mono_flow,str,2); - Readline(113,24,str,2,INPUT_TYPE_INTEGER); - Airbrush_mono_flow=atoi(str); - // On corrige le flux - if (!Airbrush_mono_flow) - { - Airbrush_mono_flow=1; - Num2str(Airbrush_mono_flow,str,2); - Window_input_content(input_flow_button,str); - } - Display_cursor(); - break; - - case 14 : // Init - Num2str(spray_init,str,2); - Readline(113,40,str,2,INPUT_TYPE_INTEGER); - spray_init=atoi(str); - // On corrige la valeur - if (spray_init>=50) - { - spray_init=49; - Num2str(spray_init,str,2); - Window_input_content(input_init_button,str); - } - else if (spray_init<1) - { - spray_init=1; - Num2str(spray_init,str,2); - Window_input_content(input_init_button,str); - } - Display_cursor(); - break; - } - - if (!Mouse_K) - switch (Key) - { - case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu - case SDLK_COMMA : - Get_color_behind_window(&color,&click); - if (click) - { - Hide_cursor(); - Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light); - Stencil_update_color(selected_color); - // Mettre la couleur sélectionnée à jour suivant le click - selected_color=color; - if (click==2) - Airbrush_multi_flow[selected_color]=0; - else - if (Airbrush_multi_flow[selected_color]==0) - Airbrush_multi_flow[selected_color]=spray_init; - - // Tagger la couleur sélectionnée en blanc - Stencil_tag_color(selected_color,MC_White); - Refresh_airbrush_settings(selected_color,1); - Display_cursor(); - Stencil_update_color(selected_color); - Wait_end_of_click(); - } - Key=0; - break; - default: - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Window_help(BUTTON_AIRBRUSH, NULL); - Key=0; - break; - } - if (Is_shortcut(Key,0x200+BUTTON_AIRBRUSH)) - { - clicked_button=2; - break; - } - } - } - while ( (clicked_button!=1) && (clicked_button!=2) ); - - Close_window(); - -/* - // Tant que l'on aura pas résolu le problème du désenclenchement du mode - // de dessin précedent, il faudra laisser ça en remarque et donc passer en - // spray même si on a clické sur Cancel (idem pour OK (un peu plus bas)). - if (clicked_button==1) // Cancel - { - if (Current_operation!=OPERATION_AIRBRUSH) - Unselect_button(BUTTON_AIRBRUSH); - } -*/ - - Display_cursor(); - -/* - if (clicked_button==2) // OK -*/ - if (Current_operation!=OPERATION_AIRBRUSH) - Select_button(BUTTON_AIRBRUSH,LEFT_SIDE); -} - - -// -- Gestion des boutons de polygone vide et plein ------------------------- - -void Button_polygon(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_POLYGON); - Display_cursor(); -} - - -void Button_Polyform(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_POLYFORM); - Display_cursor(); -} - - -void Button_Polyfill(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_POLYFILL); - Display_cursor(); -} - - -void Button_Filled_polyform(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_FILLED_POLYFORM); - Display_cursor(); -} - - -// -- Boutons d'ajustement de l'image --------------------------------------- - -void Button_Adjust(void) -{ - Hide_cursor(); - Start_operation_stack(OPERATION_SCROLL); - Display_cursor(); -} - - -// -- Menu des effets (Shade, Stencil, etc...) ------------------------------ - -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),EFFECT_SPRITE_WIDTH*Menu_factor_X,EFFECT_SPRITE_HEIGHT*Menu_factor_Y); -} - - -void Display_effect_state(short x, short y, char * label, byte state) -{ - Block(Window_pos_X+(x*Menu_factor_X),Window_pos_Y+(y*Menu_factor_Y), - 12*Menu_factor_X,Menu_factor_Y<<3,MC_Light); - - Print_in_window(x,y,label,(state)?MC_White:MC_Black,MC_Light); - if (state) - Print_in_window(x+56,y,":ON ",MC_White,MC_Light); - else - Print_in_window(x+56,y,":OFF",MC_Black,MC_Light); -} - -void Display_effect_states(void) -{ - Display_effect_state( 30, 24,"Shade" ,Shade_mode); - Display_effect_state( 30, 43,"Q-shade",Quick_shade_mode); - Display_effect_state( 30, 62,"Transp.",Colorize_mode); - Display_effect_state( 30, 81,"Smooth" ,Smooth_mode); - Display_effect_state( 30,100,"Smear" ,Smear_mode); - Display_effect_state(176, 24,"Stencil",Stencil_mode); - Display_effect_state(176, 43,"Mask" ,Mask_mode); - Display_effect_state(176, 62,"Sieve" ,Sieve_mode); - Display_effect_state(176, 81,"Grid" ,Snap_mode); - Display_effect_state(176,100,"Tiling" ,Tiling_mode); -} - - -void Display_feedback_state(void) -{ - Print_in_window(159,134,(Config.FX_Feedback)?"YES":" NO",MC_Black,MC_Light); -} - - -void Button_Effects(void) -{ - short clicked_button; - byte exit_by_close_button=0; - - Open_window(270,152,"Drawing modes (effects)"); - - Window_set_normal_button( 7, 19, 16,16,"",0,1,Config_Key[SPECIAL_SHADE_MODE][0]); // 1 - Window_set_normal_button( 7, 38, 16,16,"",0,1,Config_Key[SPECIAL_QUICK_SHADE_MODE][0]); // 2 - Window_set_normal_button( 7, 57, 16,16,"",0,1,Config_Key[SPECIAL_COLORIZE_MODE][0]); // 3 - Window_set_normal_button( 7, 76, 16,16,"",0,1,Config_Key[SPECIAL_SMOOTH_MODE][0]); // 4 - Window_set_normal_button( 7, 95, 16,16,"",0,1,Config_Key[SPECIAL_SMEAR_MODE][0]); // 5 - Window_set_normal_button(153, 19, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6 - Window_set_normal_button(153, 38, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7 - Window_set_normal_button(153, 57, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8 - Window_set_normal_button(153, 76, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9 - Window_set_normal_button(153, 95, 16,16,"",0,1,Config_Key[SPECIAL_TILING_MODE][0]); // 10 - Window_set_normal_button(195,131, 68,14,"Close",0,1,SDLK_RETURN); // 11 - Window_set_normal_button( 7,131, 68,14,"All off",0,1,SDLK_DELETE); // 12 - Window_set_normal_button( 83,131,104,14,"Feedback: ",1,1,SDLK_f); // 13 - Display_feedback_state(); - Display_effect_sprite(0, 8,20); - Display_effect_sprite(0, 8,39); - Display_effect_sprite(1, 8,58); - Display_effect_sprite(2, 8,77); - Display_effect_sprite(8, 8,96); - Display_effect_sprite(4,154,20); - Display_effect_sprite(7,154,39); - Display_effect_sprite(5,154,58); - Display_effect_sprite(6,154,77); - Display_effect_sprite(3,154,96); - Display_effect_states(); - - Print_in_window(12,117,"click: Left:Switch / Right:Edit",MC_Dark,MC_Light); - - Update_window_area(0,0,Window_width, Window_height); - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - - if (Key==KEY_ESC || Is_shortcut(Key,0x100+BUTTON_EFFECTS)) - { - clicked_button=11; - Key=0; - } - else if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - // Aide contextuelle - switch(Window_get_clicked_button()) - { - case 1: - Window_help(BUTTON_EFFECTS, "SHADE"); - break; - case 2: - Window_help(BUTTON_EFFECTS, "QUICK SHADE"); - break; - case 3: - Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); - break; - case 4: - Window_help(BUTTON_EFFECTS, "SMOOTH"); - break; - case 5: - Window_help(BUTTON_EFFECTS, "SMEAR"); - break; - case 6: - Window_help(BUTTON_EFFECTS, "STENCIL"); - break; - case 7: - Window_help(BUTTON_EFFECTS, "MASK"); - break; - case 8: - Window_help(BUTTON_EFFECTS, "SIEVE"); - break; - case 9: - Window_help(BUTTON_EFFECTS, "GRID"); - break; - case 10: - Window_help(BUTTON_EFFECTS, "TILING"); - break; - default: - Window_help(BUTTON_EFFECTS, NULL); - } - // Hack because we have used Window_get_clicked_button() - Input_sticky_control=0; - // - } - - switch (clicked_button) - { - case 1 : // Shade - if (Window_attribute1==LEFT_SIDE) - { - Button_Shade_mode(); - Hide_cursor(); - Display_effect_states(); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Shade_menu(); - clicked_button=11; - } - break; - case 2 : // Quick-shade - if (Window_attribute1==LEFT_SIDE) - { - Button_Quick_shade_mode(); - Hide_cursor(); - Display_effect_states(); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Quick_shade_menu(); - clicked_button=11; - } - break; - case 3 : // Colorize / Transparency - if (Window_attribute1==LEFT_SIDE) - { - Button_Colorize_mode(); - Hide_cursor(); - Display_effect_states(); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Colorize_menu(); - clicked_button=11; - } - break; - case 4 : // Smooth - if (Window_attribute1==LEFT_SIDE) - { - Button_Smooth_mode(); - Hide_cursor(); - Display_effect_states(); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Smooth_menu(); - clicked_button=11; - } - break; - case 5 : // Smear - Button_Smear_mode(); - Hide_cursor(); - Display_effect_states(); - Display_cursor(); - break; - case 6 : // Stencil - if (Window_attribute1==LEFT_SIDE) - { - Button_Stencil_mode(); - Hide_cursor(); - Display_effect_state(176,24,"Stencil",Stencil_mode); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Stencil_menu(); - clicked_button=11; - } - break; - case 7 : // Mask - if (Window_attribute1==LEFT_SIDE) - { - Button_Mask_mode(); - Hide_cursor(); - Display_effect_state(176,43,"Mask",Mask_mode); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Mask_menu(); - clicked_button=11; - } - break; - case 8 : // Sieve - if (Window_attribute1==LEFT_SIDE) - { - Button_Sieve_mode(); - Hide_cursor(); - Display_effect_state(176,62,"Sieve",Sieve_mode); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Sieve_menu(); - clicked_button=11; - } - break; - case 9 : // Grid - if (Window_attribute1==LEFT_SIDE) - { - Button_Snap_mode(); - Hide_cursor(); - Display_effect_state(176,81,"Grid",Snap_mode); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Grid_menu(); - clicked_button=11; - } - break; - case 10 : // Tiling - if (Window_attribute1==LEFT_SIDE) - { - Button_Tiling_mode(); - Hide_cursor(); - Display_effect_states(); - Display_cursor(); - } - else - { - Close_window(); - Display_cursor(); - Button_Tiling_menu(); - clicked_button=11; - } - break; - case 11 : // Close - exit_by_close_button=1; - break; - case 12 : // All off - Effects_off(); - Hide_cursor(); - Display_effect_states(); - Display_cursor(); - break; - case 13 : // Feedback (pour Colorize et Shade) - Config.FX_Feedback = !Config.FX_Feedback; - Update_FX_feedback(Config.FX_Feedback); - Hide_cursor(); - Display_feedback_state(); - Display_cursor(); - break; - } - } - while (clicked_button!=11); - - if (exit_by_close_button) - Close_window(); - else - Hide_cursor(); - - if (!(Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode)) - Unselect_button(BUTTON_EFFECTS); - - Display_cursor(); -} - -// Callback to display a font name in the list -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) -{ - static char str[256]=""; - static int font_size=32; - static int antialias=1; - static short list_start=0; // index de le premiere fonte dans le selector - static short cursor_position=0; // index de la ligne active dans le selector - static short selected_font_index=0; - static short is_bold=0; - static short is_italic=0; - - 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[4]; - T_Special_button * input_size_button; - T_Special_button * input_text_button; - T_Special_button * preview_button; - T_Special_button * font_list_button; - T_Scroller_button * font_scroller; - T_List_button * font_list; - - byte redraw_is_needed=1; - byte preview_is_needed=1; - - Open_window(288,180,"Text"); - - // Texte saisi - Print_in_window(6,20,"Text:",MC_Dark,MC_Light); - input_text_button = Window_set_input_button(48,18,29); // 1 - - // TrueType options - Window_display_frame_in(182,34,100,68); - Print_in_window(199,31,"TrueType", MC_Dark, MC_Light); - // AA - Window_set_normal_button(188,58,13,11,antialias?"X":" ",0,1,SDLK_a); // 2 - Print_in_window(206,60,"AntiAlias", MC_Dark, MC_Light); - // Bold - Window_set_normal_button(188,72,13,11,is_bold?"X":" ",0,1,SDLK_b); // 3 - Print_in_window(206,75,"Bold", MC_Dark, MC_Light); - // Italic - Window_set_normal_button(188,86,13,11,is_italic?"X":" ",0,1,SDLK_i); // 4 - Print_in_window(206,89,"Italic", MC_Dark, MC_Light); - - // Scroller des fontes - font_scroller = Window_set_scroller_button(165,35,NB_FONTS*8,Nb_fonts,NB_FONTS,list_start); // 5 - // Liste des fontes disponibles - font_list_button = Window_set_special_button(8,35,152,NB_FONTS*8); // 6 - Window_display_frame_in(7, 33, 154, NB_FONTS*8+4); - - // Taille texte - input_size_button = Window_set_input_button(220,43,3); // 7 - Window_set_repeatable_button(202,43,13,11,"-",0,1,SDLK_LAST); // 8 - Window_set_repeatable_button(251,43,13,11,"+",0,1,SDLK_LAST); // 9 - - // Preview - preview_button = Window_set_special_button(8,106,273,50); // 10 - Window_display_frame_in(7, 105, 275, 52); - - Window_set_normal_button(8,160,40,14,"OK",0,1,SDLK_RETURN); // 11 - Window_set_normal_button(54,160,60,14,"Cancel",0,1,KEY_ESC); // 12 - - // List of fonts - font_list = Window_set_list_button(font_list_button, font_scroller, Draw_one_font_name, 2); // 13 - // Restore its settings from last passage in screen - font_list->List_start = list_start; - font_list->Cursor_position = cursor_position; - - Window_redraw_list(font_list); - - Update_window_area(0,0,Window_width, Window_height); - - // str texte - Window_input_content(input_text_button,str); - // Taille police - redraw_is_needed=1; - // -- - - while (1) - { - if (redraw_is_needed) - { - // Taille - Num2str(font_size,size_buffer,3); - Window_input_content(input_size_button,size_buffer); - } - if (preview_is_needed) - { - const char * preview_string = "AaBbCcDdEeFf012345"; - byte is_truetype; - - if (str[0]) - preview_string=str; - is_truetype=TrueType_font(selected_font_index); - free(new_brush); - new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height, text_palette); - // Background: - if (antialias&&is_truetype) - // Solid - Window_rectangle(8, 106, 273, 50,MC_Black); - else if (is_truetype) - { - long l = text_palette[Fore_color].R+text_palette[Fore_color].G+text_palette[Fore_color].B; - Window_rectangle(8, 106, 273, 50,l>128*3? MC_Black:MC_Light); - } - else - { - long l = text_palette[Back_color].R+text_palette[Back_color].G+text_palette[Back_color].B; - Window_rectangle(8, 106, 273, 50,l>128*3? MC_Light:MC_Black); - } - if (new_brush) - { - 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, - Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y, - preview_button->Width*Menu_factor_X, - preview_button->Height*Menu_factor_Y); - } - if (redraw_is_needed || preview_is_needed) - { - redraw_is_needed=0; - preview_is_needed=0; - Display_cursor(); - } - - clicked_button=Window_clicked_button(); - if (clicked_button==0) - { - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_TEXT, NULL); - else if (Is_shortcut(Key,0x100+BUTTON_TEXT)) - clicked_button=12; - } - switch(clicked_button) - { - case 1: // Texte saisi - Readline_ex(50,20,str,29,250,INPUT_TYPE_STRING,0); - preview_is_needed=1; - break; - - case 2: // AA - antialias = (antialias==0); - Hide_cursor(); - Print_in_window(191,60,antialias?"X":" ", MC_Black, MC_Light); - preview_is_needed=1; - break; - - case 3: // Bold - is_bold = (is_bold==0); - Hide_cursor(); - Print_in_window(191,74,is_bold?"X":" ", MC_Black, MC_Light); - preview_is_needed=1; - break; - - case 4: // Italic - is_italic = (is_italic==0); - Hide_cursor(); - Print_in_window(191,88,is_italic?"X":" ", MC_Black, MC_Light); - preview_is_needed=1; - break; - - case 5: // Scroller des fontes - /* Cannot happen, event is catched by the list control */ - break; - - case 13: // Font selection - selected_font_index = Window_attribute2; - Hide_cursor(); - preview_is_needed=1; - break; - - case 7: // Taille du texte (nombre) - Readline(222,45,size_buffer,3,INPUT_TYPE_INTEGER); - font_size=atoi(size_buffer); - // On corrige les dimensions - if (font_size < 1) - { - font_size = 1; - } - else if (font_size>500) - { - font_size = 500; - } - redraw_is_needed=1; - preview_is_needed=1; - break; - - case 8: // Taille - - if (font_size > 1) - { - font_size--; - Hide_cursor(); - redraw_is_needed=1; - preview_is_needed=1; - } - break; - - case 9: // Taille + - if (font_size < 255) - { - font_size++; - Hide_cursor(); - redraw_is_needed=1; - preview_is_needed=1; - } - break; - - - case 6: // Double-click font selector - case 11: // OK - // Save the selector settings - list_start = font_list->List_start; - cursor_position = font_list->Cursor_position; - - if (!new_brush) - { - // Si echec de rendu - Close_window(); - Unselect_button(BUTTON_TEXT); - Display_cursor(); - Error(0); - return; - } - 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_offset_X=Brush_width>>1; - Brush_offset_Y=Brush_height>>1; - - // Fermeture - Close_window(); - Unselect_button(BUTTON_TEXT); - - // On passe en brosse: - Display_cursor(); - if (antialias || !TrueType_font(selected_font_index)) - 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) - { - // On se place en mode Dessin discontinu à la main - while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW) - Select_button(BUTTON_DRAW,RIGHT_SIDE); - } - //Display_cursor(); - return; - - case 12: // Cancel - // Save the selector settings - list_start = font_list->List_start; - cursor_position = font_list->Cursor_position; - - free(new_brush); - new_brush = NULL; - Close_window(); - Unselect_button(BUTTON_TEXT); - Display_cursor(); - return; - } - } -} - -void Display_stored_brush_in_window(word x_pos,word y_pos,int index) -{ - if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX) - { - int x,y; - int offset_x=0, offset_y=0; - //int brush_offset_x=0, brush_offset_y=0; - - // Determine draw offset (small brushes are stacked on corner of their preview) - if (Brush_container[index].WidthBRUSH_CONTAINER_PREVIEW_WIDTH) - brush_offset_x = (Paintbrush_width-BRUSH_CONTAINER_PREVIEW_WIDTH)/2; - if (Paintbrush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) - brush_offset_y = (Paintbrush_height-BRUSH_CONTAINER_PREVIEW_HEIGHT)/2; - - for (y=0; yBRUSH_CONTAINER_PREVIEW_WIDTH || - Brush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT) - { - // Scale - 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_original_pixels, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH); - } - } - else - { - Error(0); - } - } -} - -/// 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; - Paintbrush_offset_Y=Paintbrush_height>>1; - } - else - { - // Recreate the brush pixels from its shape and dimensions - Set_paintbrush_size(Paintbrush_width,Paintbrush_height); - } - } - // Color brushes - if (shape == PAINTBRUSH_SHAPE_COLOR_BRUSH || - shape == PAINTBRUSH_SHAPE_MONO_BRUSH) - { - Paintbrush_shape=shape; - 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); - - return 1; -} - -void Button_Brush_container(void) -{ - short clicked_button; - short x_pos,y_pos; - byte index; - - Open_window(BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+8, - BRUSH_CONTAINER_ROWS*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+40, - "Brushes"); - - Window_set_normal_button( - (BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)-59)/2, - (BRUSH_CONTAINER_ROWS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18, - 67,14,"Cancel",0,1,KEY_ESC); // 1 - - index=0; - for (index=0; index < BRUSH_CONTAINER_ROWS*BRUSH_CONTAINER_COLUMNS; index++) - { - x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; - y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; - Window_set_normal_button( - x_pos, - y_pos, - BRUSH_CONTAINER_PREVIEW_WIDTH+2, - BRUSH_CONTAINER_PREVIEW_HEIGHT+2, - "",0,1,SDLK_LAST); - Display_stored_brush_in_window(x_pos+1, y_pos+1, index); - } - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - //if (Is_shortcut(Key,0x100+BUTTON_HELP)) - // Window_help(BUTTON_PAINTBRUSHES, NULL); - - if (clicked_button == 1) - break; - - if (clicked_button>1) - { - index = clicked_button-2; - - if (Window_attribute1==RIGHT_SIDE) - { - // Store - - x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7; - y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18; - - Store_brush(index); - Hide_cursor(); - Display_stored_brush_in_window(x_pos+1, y_pos+1, index); - Display_cursor(); - } - else - { - // Restore and exit - - if (Restore_brush(index)) - break; - } - } - } - while (1); - Close_window(); - - //Unselect_button(BUTTON_PAINTBRUSHES); - Display_cursor(); -} diff --git a/project/jni/application/grafx2/grafx2/src/buttons.h b/project/jni/application/grafx2/grafx2/src/buttons.h deleted file mode 100644 index eed881dcb..000000000 --- a/project/jni/application/grafx2/grafx2/src/buttons.h +++ /dev/null @@ -1,678 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -//////////////////////////////////////////////////////////////////////////// -///@file buttons.h -/// Almost all the editor actions that are called by the menu are here. -//////////////////////////////////////////////////////////////////////////// - -#ifndef __BOUTONS_H_ -#define __BOUTONS_H_ - -#include "struct.h" - -void Stencil_update_color(byte color); -void Stencil_tag_color(byte color, byte tag_color); - -/*! - Displays an error message when there is no more memory for the requested - operation. -*/ -void Message_out_of_memory(void); - -/*! - Displays the splash screen at program startup. -*/ -void Button_Message_initial(void); - -/*! - Changes brush shape. - This function saves the current brush shape and swith to the default one - (single pixel brush) for the filler and the color picker. - These functions don't need (and will not work with) a custom brush. -*/ -void Change_paintbrush_shape(byte shape); - -// Boutons relatifs aux couleurs - - -/*! - Callback for the palette scroller buttons left click. - Scrolls the menubar palette one column to the left. -*/ -void Button_Pal_left(void); - -/*! - Callback for the palette scroller buttons right click. - Scrolls the menubar palette faster to the left. -*/ -void Button_Pal_left_fast(void); - -/*! - Callback for the palette scroller buttons left click. - Scrolls the menubar palette one column to the right. -*/ -void Button_Pal_right(void); - -/*! - Callback for the palette scroller buttons right click. - Scrolls the menubar palette faster to the right. -*/ -void Button_Pal_right_fast(void); - -/*! - Callback for the palette color buttons left click. - Selects the foreground drawing color when clicking on the menubar palette. -*/ -void Button_Select_forecolor(void); - -/*! - Callback for the palette color buttons right click. - Selects the background drawing color when clicking on the menubar palette. -*/ -void Button_Select_backcolor(void); - -// Boutons relatifs au pinceaux - -/*! - Callback for the brush button left click. - Selects the monochrome brush mode when right clicking on the brush button. -*/ -void Button_Brush_monochrome(void); - -/*! - Callback for the brush button right click. - Displays the "Paintbrush menu". -*/ -void Button_Paintbrush_menu(void); - -// Boutons relatifs au mode de dessin à main levée - -/*! - Callback for the freehand draw button left click. - Selects freehand drawing mode, depending on the current state of the freehand button. -*/ -void Button_Draw(void); - -/*! - Callback for the freehand draw button right click. - Cycles the drawing modes for the freehand tool. -*/ -void Button_Draw_switch_mode(void); - -// Dessin par ligne - -/*! - Callback for the lines button left click. - Selects lines drawing mode, depending on the current state of the lines button. -*/ -void Button_Lines(void); - -/*! - Callback for the lines button right click. - Cycles the drawing modes for the lines tool. -*/ -void Button_Lines_switch_mode(void); - -// Button relatif au remplissage - -/*! - Callback for the fill button left click. - Start the filling operation. -*/ -void Button_Fill(void); - -/*! - Callback for the fill button right click. - Start the color replace operation. -*/ -void Button_Replace(void); - -/*! - Disable and release the fill button. - Restores the cursor (custom brushes are disabled for the fill operation). - Cleans the status bar if the color replacement tool put a preview color inside it. -*/ -void Button_Unselect_fill(void); - -// Spray - -/*! - Callback for the spray button left click. - Start the spray operation. -*/ -void Button_Airbrush(void); - -/*! - Callback for the spray button right click. - Opens the spray's setup menu. -*/ -void Button_Airbrush_menu(void); - -// Courbes de Bézier - -/*! - Callback for the curves button left click. - Start curve operation according to the selected mode. -*/ -void Button_Curves(void); - -/*! - Callback for the curves button right click. - Select the curve mode (1-point, 2-point) -*/ -void Button_Curves_switch_mode(void); - -// Boutons relatifs aux rectangles pleins et vides - -/*! - Callback for the empty rectangle button. - Start the rectangle operation. -*/ -void Button_Empty_rectangle(void); - -/*! - Callback for the filled rectangle button. - Start the filled rectangle operation. -*/ -void Button_Filled_rectangle(void); - -// Boutons relatifs au texte - -/*! - Callback for the text button. - Opens the text setup window. -*/ -void Button_Text(void); - -// Boutons relatifs aux dégradés - -/*! - Callback for the gradation button. - Opens the "Gradation menu". -*/ -void Button_Gradients(void); - -/*! - Gets the informations from the gradations table and set the global vars for the current gradation. - @param index index of the selected gradation -*/ -void Load_gradient_data(int index); - -// Boutons relatifs aux cercles (ellipses) dégradé(e)s - -/*! - Callback for the gradation circle button left click. - Starts drawing a gradation circle. -*/ -void Button_Grad_circle(void); - -/*! - Callback for the gradation circle right click. - Starts drawing a gradation ellipsis. -*/ -void Button_Grad_ellipse(void); - -/*! - Callback for the gradation rectangle button. - Starts the gradation rectangle drawing operation. -*/ -void Button_Grad_rectangle(void); - -// Boutons relatifs aux cercles (ellipses) plein(e)s et vides - -/*! - Callback for the circle button left click. - Starts drawing an empty circle -*/ -void Button_Empty_circle(void); - -/*! - Callback for the circle button left click. - Starts drawing an empty ellipsis -*/ -void Button_Empty_ellipse(void); - -/*! - Callback for the filled circle button ledt click. - Starts drawing a filled circle. -*/ -void Button_Filled_circle(void); - -/*! - Callback for the filled circle right click. - Starts drawing a filled ellipsis. -*/ -void Button_Filled_ellipse(void); - -// Boutons relatifs aux polygones vides et pleins - -/*! - Callback for the polyline button left click. - Starts drawing a polygon. -*/ -void Button_polygon(void); - -/*! - Callback for the polyline right click. - Starts drawing a polyform. -*/ -void Button_Polyform(void); - -/*! - Callback for the polyfill button left click. - Starts drawing a filled polygon. -*/ -void Button_Polyfill(void); - -/*! - Callback for the polyfill button right click. - Starts drawing a filled polyform. -*/ -void Button_Filled_polyform(void); - -// Boutons d'ajustement de l'image - -/*! - Callback for the adjust picture button. - Start the adjust picture operation. -*/ -void Button_Adjust(void); - -// Gestion du mode Shade - -/*! - Callback for the shade button (in the FX window). - Toogle the shade mode. -*/ -void Button_Shade_mode(void); - -/*! - Callback for the QSHade button (in the FX window). - Toogle the Quick Shade effect. -*/ -void Button_Quick_shade_mode(void); - -/*! - Callback for the Shade button (in the FX window) right click. - Displays the shade setup menu. -*/ -void Button_Shade_menu(void); - -// Gestion du Stencil - -/*! - Callback for the Stencil button (in the FX window) left click. - Toogle stencil mode. -*/ -void Button_Stencil_mode(void); - -/*! - Callback for the Stencil button (in the FX window) right click. - Displays the stencil setup menu. -*/ -void Button_Stencil_menu(void); - -// Gestion du Masque - -/*! - Callback for the Mask button (in the FX window) left click. - Toogles the mask mode/ -*/ -void Button_Mask_mode(void); - -/*! - Callback for the Mask button (in the FX window) right click. - Displays the mask setup menu. -*/ -void Button_Mask_menu(void); - -// Mode grille (Snap) - -/*! - Callback for the Grid button (in the FX window) left click. - Toogle the grid. -*/ - -void Button_Snap_mode(void); - -/*! - Callback for the Grid button (in the FX window) right click. - Displays the grid setup menu. -*/ -void Button_Grid_menu(void); - -/*! - Callback to toggle the grid visible in the magnified view. -*/ -void Button_Show_grid(void); - -// Mode trame (Sieve) - -/*! - In the sieve window, copy one of the presets patterns to the current one. - @param index Index of the pattern to copy -*/ -void Copy_preset_sieve(byte index); - -/*! - In the sieve window, swaps black and white in the current pattern. -*/ -void Invert_trame(void); - -/*! - Callback for the Sieve button (in the FX window) left click. - Toogle sieve mode. -*/ -void Button_Sieve_mode(void); - -/*! - Callback for the Sieve button (in the FX window) right click. - Displays the sieve setup menu. -*/ -void Button_Sieve_menu(void); - -// Mode Smooth - -/*! - Callback for the smooth button (in the FX window) left click. - Toogles smooth mode. -*/ -void Button_Smooth_mode(void); - -/*! - Callback for the Smooth button (in the FX window) right click. - Displays the smooth setup menu. -*/ -void Button_Smooth_mode(void); - -// Boutons relatifs au mode Colorize - -/*! - Computes the tables used by the transparency/colorize mode. - These tables are used to match the drawing color*picture color to the color that is painted on screen. -*/ -void Compute_colorize_table(void); - -/*! - Callback for the Tranparency button (in the FX window) left click. - Toogles transparent drawing mode. -*/ -void Button_Colorize_mode(void); - -/*! - Callback for the Transparency button (in the FX window) right click. - Displays the tranparency setup menu. -*/ -void Button_Colorize_menu(void); - -// Boutons relatifs au mode Tiling - -/*! - Callback for the Tiling button (in the FX window) left click. - Toogles tiling mode. -*/ -void Button_Tiling_mode(void); - -/*! - Callback for the Tiling button (in the FX window) right click. - Displays the tiling setup menu. -*/ -void Button_Tiling_menu(void); - -/*! - Callback for the command that turns off all drawaing effects. -*/ -void Effects_off(void); - -// Menu des effets - -/*! - Callback for the effects button click. - Displays the effect selection menu. -*/ -void Button_Effects(void); - -// Prise de brosse - -/*! - Callback for the brush button left click. - Start the brush picking operation. -*/ -void Button_Brush(void); - -/*! - Callback for the brush button right click. - Activates the last captured custom brush. -*/ -void Button_Restore_brush(void); - -/*! - Disables the custom brush and set back a regular one. -*/ -void Button_Unselect_brush(void); -// Prise de brosse au lasso - -/*! - Callback for the freehand brush pick button left click. - Starts freehand brush picking operation. -*/ -void Button_Lasso(void); - -/*! - Disables the custom freehand brush and set back a regular one. -*/ -void Button_Unselect_lasso(void); - -// Button relatifs à la pipette - -/*! - Starts the color picking operation. -*/ -void Button_Colorpicker(void); - -/*! - Disables the color picker button and get back to the previously selected drawing mode. -*/ -void Button_Unselect_colorpicker(void); - -/*! - Swap fore- and background colors. -*/ -void Button_Invert_foreback(void); - -// Mode loupe - -/*! - Enters magnify mode. -*/ -void Button_Magnify(void); - -/*! - Displays magnify menu. -*/ -void Button_Magnify_menu(void); - -/*! - Exit magnify mode. -*/ -void Button_Unselect_magnifier(void); - -// Les différents effets sur la brosse - -/*! - Display the Brush effects window. -*/ -void Button_Brush_FX(void); - -// Boutons relatifs aux différentes pages - -/*! - Swap main and spare drawing pages. -*/ -void Button_Page(void); - -/*! - Copy main page to spare page. -*/ -void Button_Copy_page(void); - -/*! - Copy only pixel data from main page to spare page (no palette copy). -*/ -void Copy_image_only(void); - -/*! - Kill (free from memory) the current page. -*/ -void Button_Kill(void); - -// Boutons relatifs aux changements de résolution et de taille d'image - -/*! - Display the screenmode menu. -*/ -void Button_Resolution(void); - -/*! - Set the screen to the "safe resolution" (320x200 pixel window). -*/ -void Button_Safety_resolution(void); - -// Boutons relatifs aux chargements et sauvegardes - -/*! - Opens the load file dialog. -*/ -void Button_Load(void); - -/*! - Reload current picture from disk. -*/ -void Button_Reload(void); - -/*! - Open the save file dialog. -*/ -void Button_Save(void); - -/*! - Saves the current file without asking for a new name. -*/ -void Button_Autosave(void); - -// Réglage des paramètres de l'utilisateur - -/*! - Display the setting menu. -*/ -void Button_Settings(void); - -/*! - Display the skin selector window. -*/ -void Button_Skins(void); - -// Annulation de la dernière modification - -/*! - Undo the last modification to the picture. -*/ -void Button_Undo(void); - -/*! - Redo an operation that has been undone. -*/ -void Button_Redo(void); - -// Boutons relatifs aux effacements d'images - -/*! - Clear the whole screen with black (color index 0). -*/ -void Button_Clear(void); - -/*! - Clear the screen with the selected backcolor. -*/ -void Button_Clear_with_backcolor(void); - -// Quitter le programme - -/*! - Quits the program. Display a requester to save the changes to the picture before exiting if the pic was modified since last save. -*/ -void Button_Quit(void); - -// Cacher le menu - -/*! - Hides the menubar. -*/ -void Button_Hide_menu(void); - -/*! - Shows a dropdown panel where you can choose which toolbars are visible -*/ -void Button_Toggle_toolbar(void); - -/*! - Hides all toolbars (except status) or shows them again -*/ -void Button_Toggle_all_toolbars(void); - - -/*! - Load picture from file. -*/ -void Load_picture(byte image); - -/*! - Save picture to file. -*/ -void Save_picture(byte image); - - -/*! - Generic color tagging menu, for various effects. -*/ -void Menu_tag_colors(char * window_title, byte * table, byte * mode, byte can_cancel, const char *help_section, word close_shortcut ); - - -/*! - Display the menu for the smooth effect. -*/ -void Button_Smooth_menu(void); - - -/*! - Toogles the smear mode. -*/ -void Button_Smear_mode(void); - -void Button_Brush_container(void); - -byte Store_paintbrush(int index); - -void Select_paintbrush(int index); - -#endif - diff --git a/project/jni/application/grafx2/grafx2/src/buttons_effects.c b/project/jni/application/grafx2/grafx2/src/buttons_effects.c deleted file mode 100644 index 6f621a638..000000000 --- a/project/jni/application/grafx2/grafx2/src/buttons_effects.c +++ /dev/null @@ -1,1259 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -//////////////////////////////////////////////////////////////////////////// -///@file buttons_effects.c -/// Handles all the effects buttons and setup windows in the effects menu. -//////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -#include "buttons.h" -#include "engine.h" -#include "global.h" -#include "graph.h" -#include "help.h" -#include "input.h" -#include "misc.h" -#include "readline.h" -#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) -{ - short clicked_button; - byte backup_table[256]; - word index; - word old_mouse_x; - word old_mouse_y; - byte old_mouse_k; - byte tagged_color; - byte color; - byte click; - - - Open_window(176,150,window_title); - - Window_set_palette_button(6,38); // 1 - Window_set_normal_button( 7, 19,78,14,"Clear" ,1,1,SDLK_c); // 2 - Window_set_normal_button(91, 19,78,14,"Invert",1,1,SDLK_i); // 3 - if (can_cancel) - { - Window_set_normal_button(91,129,78,14,"OK" ,0,1,SDLK_RETURN); // 4 - Window_set_normal_button( 7,129,78,14,"Cancel",0,1,KEY_ESC); // 5 - // On enregistre la table dans un backup au cas où on ferait Cancel - memcpy(backup_table,table,256); - } - else - Window_set_normal_button(49,129,78,14,"OK" ,0,1,SDLK_RETURN); // 4 - - // On affiche l'état actuel de la table - for (index=0; index<=255; index++) - Stencil_tag_color(index, (table[index])?MC_Black:MC_Light); - - Update_window_area(0,0,Window_width, Window_height); - Display_cursor(); - - do - { - old_mouse_x=Mouse_X; - old_mouse_y=Mouse_Y; - old_mouse_k=Mouse_K; - - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case 0 : - break; - case -1 : - case 1 : // Palette - if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) - { - Hide_cursor(); - tagged_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); - table[tagged_color]=(Mouse_K==LEFT_SIDE); - Stencil_tag_color(tagged_color,(Mouse_K==LEFT_SIDE)?MC_Black:MC_Light); - Display_cursor(); - Stencil_update_color(tagged_color); - } - break; - case 2 : // Clear - memset(table,0,256); - Hide_cursor(); - for (index=0; index<=255; index++) - Stencil_tag_color(index,MC_Light); - Display_cursor(); - Update_window_area(0,0,Window_width, Window_height); - break; - case 3 : // Invert - Hide_cursor(); - for (index=0; index<=255; index++) - Stencil_tag_color(index,(table[index]^=1)?MC_Black:MC_Light); - Display_cursor(); - Update_window_area(0,0,Window_width, Window_height); - } - - if (!Mouse_K) - switch (Key) - { - case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu - case SDLK_COMMA : - Get_color_behind_window(&color,&click); - if (click) - { - Hide_cursor(); - tagged_color=color; - table[tagged_color]=(click==LEFT_SIDE); - Stencil_tag_color(tagged_color,(click==LEFT_SIDE)?MC_Black:MC_Light); - Stencil_update_color(tagged_color); - Display_cursor(); - Wait_end_of_click(); - } - Key=0; - break; - default: - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Window_help(BUTTON_EFFECTS, help_section); - Key=0; - break; - } - else if (Is_shortcut(Key,close_shortcut)) - { - clicked_button=4; - } - } - } - while (clicked_button<4); - - Close_window(); - - if (clicked_button==5) // Cancel - memcpy(table,backup_table,256); - else // OK - *mode=1; - - Display_cursor(); -} - - -//--------------------------------- Stencil ---------------------------------- -void Button_Stencil_mode(void) -{ - Stencil_mode=!Stencil_mode; -} - - -void Stencil_tag_color(byte color, byte tag_color) -{ - Block(Window_pos_X+(Menu_factor_X*(Window_palette_button_list->Pos_X+4+(color >> 4)*10)), - Window_pos_Y+(Menu_factor_Y*(Window_palette_button_list->Pos_Y+3+(color & 15)* 5)), - Menu_factor_X<<1,Menu_factor_Y*5,tag_color); -} - -void Stencil_update_color(byte color) -{ - Update_rect(Window_pos_X+(Menu_factor_X*(Window_palette_button_list->Pos_X+4+(color >> 4)*10)), - Window_pos_Y+(Menu_factor_Y*(Window_palette_button_list->Pos_Y+3+(color & 15)* 5)), - Menu_factor_X<<1,Menu_factor_Y*5); -} - -void Button_Stencil_menu(void) -{ - Menu_tag_colors("Stencil",Stencil,&Stencil_mode,1, "STENCIL", SPECIAL_STENCIL_MENU); -} - - -//--------------------------------- Masque ----------------------------------- -void Button_Mask_mode(void) -{ - Mask_mode=!Mask_mode; -} - - -void Button_Mask_menu(void) -{ - Menu_tag_colors("Mask",Mask_table,&Mask_mode,1, "MASK", SPECIAL_MASK_MENU); -} - - -// -------------------------------- Grille ----------------------------------- - -void Button_Snap_mode(void) -{ - Hide_cursor(); - Snap_mode=!Snap_mode; - Compute_paintbrush_coordinates(); - Display_cursor(); -} - - -void Button_Grid_menu(void) -{ - short clicked_button; - word chosen_X =Snap_width; - word chosen_Y =Snap_height; - short dx_selected=Snap_offset_X; - short dy_selected=Snap_offset_Y; - - char showgrid = Show_grid; - // if grid is shown check if we snap - // if not snap by default (so the window work like before we introduced the "show" option) - char snapgrid = Show_grid?Snap_mode:1; - - T_Special_button * input_x_button; - T_Special_button * input_y_button; - T_Special_button * input_dx_button; - T_Special_button * input_dy_button; - - char str[3]; - - - Open_window(133,118,"Grid"); - - Window_set_normal_button(12,92,51,14,"Cancel",0,1,KEY_ESC); // 1 - Window_set_normal_button(70,92,51,14,"OK" ,0,1,SDLK_RETURN); // 2 - - Print_in_window(19,26, "X:",MC_Dark,MC_Light); - input_x_button = Window_set_input_button(37,24,2); // 3 - Num2str(chosen_X,str,2); - Window_input_content(input_x_button,str); - - Print_in_window(19,47, "Y:",MC_Dark,MC_Light); - input_y_button = Window_set_input_button(37,45,2); // 4 - Num2str(chosen_Y,str,2); - Window_input_content(input_y_button,str); - - Print_in_window(69,26,"dX:",MC_Dark,MC_Light); - input_dx_button = Window_set_input_button(95,24,2); // 5 - Num2str(dx_selected,str,2); - Window_input_content(input_dx_button,str); - - Print_in_window(69,47,"dY:",MC_Dark,MC_Light); - input_dy_button = Window_set_input_button(95,45,2); // 6 - Num2str(dy_selected,str,2); - - Window_set_normal_button(12, 62, 14, 14, " ", 0, 1, 0); // 7 - Window_set_normal_button(70, 62, 14, 14, " ", 0, 1, 0); // 8 - if (snapgrid) - Print_in_window(16, 65, "X", MC_Black, MC_Light); - if (Show_grid) - Print_in_window(74, 65, "X", MC_Black, MC_Light); - Print_in_window(32, 65,"Snap",MC_Dark,MC_Light); - Print_in_window(90, 65,"Show",MC_Dark,MC_Light); - - Window_input_content(input_dy_button,str); - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case 3 : - Num2str(chosen_X,str,2); - Readline(39,26,str,2,INPUT_TYPE_INTEGER); - chosen_X=atoi(str); - // On corrige les dimensions - if ((!chosen_X) || (chosen_X>80)) - { - if (!chosen_X) - chosen_X=1; - else - chosen_X=80; - Num2str(chosen_X,str,2); - Window_input_content(input_x_button,str); - } - if (dx_selected>=chosen_X) - { - dx_selected=chosen_X-1; - Num2str(dx_selected,str,2); - Window_input_content(input_dx_button,str); - } - Display_cursor(); - break; - case 4 : - Num2str(chosen_Y,str,2); - Readline(39,47,str,2,INPUT_TYPE_INTEGER); - chosen_Y=atoi(str); - // On corrige les dimensions - if ((!chosen_Y) || (chosen_Y>80)) - { - if (!chosen_Y) - chosen_Y=1; - else - chosen_Y=80; - Num2str(chosen_Y,str,2); - Window_input_content(input_y_button,str); - } - if (dy_selected>=chosen_Y) - { - dy_selected=chosen_Y-1; - Num2str(dy_selected,str,2); - Window_input_content(input_dy_button,str); - } - Display_cursor(); - break; - case 5 : - Num2str(dx_selected,str,2); - Readline(97,26,str,2,INPUT_TYPE_INTEGER); - dx_selected=atoi(str); - // On corrige les dimensions - if (dx_selected>79) - dx_selected=79; - if (dx_selected>=chosen_X) - dx_selected=chosen_X-1; - - Num2str(dx_selected,str,2); - Window_input_content(input_dx_button,str); - - Display_cursor(); - break; - case 6 : - Num2str(dy_selected,str,2); - Readline(97,47,str,2,INPUT_TYPE_INTEGER); - dy_selected=atoi(str); - // On corrige les dimensions - if (dy_selected>79) - dy_selected=79; - if (dy_selected>=chosen_Y) - dy_selected=chosen_Y-1; - - Num2str(dy_selected,str,2); - Window_input_content(input_dy_button,str); - - Display_cursor(); - - case 7: - snapgrid = !snapgrid; - Hide_cursor(); - Print_in_window(16, 65, snapgrid?"X":" ", MC_Black, MC_Light); - Display_cursor(); - break; - case 8: - showgrid = !showgrid; - Hide_cursor(); - Print_in_window(74, 65, showgrid?"X":" ", MC_Black, MC_Light); - Display_cursor(); - break; - - } - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_EFFECTS, "GRID"); - } - while ( (clicked_button!=1) && (clicked_button!=2) ); - - if (clicked_button==2) // OK - { - Snap_width=chosen_X; - Snap_height=chosen_Y; - Snap_offset_X=dx_selected; - Snap_offset_Y=dy_selected; - Snap_mode=snapgrid; - Show_grid=showgrid; - } - - Close_window(); - - Display_cursor(); -} - -void Button_Show_grid(void) -{ - Show_grid = !Show_grid; - Hide_cursor(); - Display_all_screen(); - Display_cursor(); -} - - -// -- Mode Smooth ----------------------------------------------------------- -void Button_Smooth_mode(void) -{ - if (Smooth_mode) - Effect_function=No_effect; - else - { - Effect_function=Effect_smooth; - Shade_mode=0; - Quick_shade_mode=0; - Colorize_mode=0; - Tiling_mode=0; - Smear_mode=0; - } - Smooth_mode=!Smooth_mode; -} - - -byte Smooth_default_matrices[4][3][3]= -{ - { {1,2,1}, {2,4,2}, {1,2,1} }, - { {1,3,1}, {3,9,3}, {1,3,1} }, - { {0,1,0}, {1,2,1}, {0,1,0} }, - { {2,3,2}, {3,1,3}, {2,3,2} } -}; - -void Button_Smooth_menu(void) -{ - short clicked_button; - word x,y,i,j; - byte chosen_matrix[3][3]; - T_Special_button * matrix_input[3][3]; - char str[3]; - - Open_window(142,109,"Smooth"); - - Window_set_normal_button(82,59,53,14,"Cancel",0,1,KEY_ESC); // 1 - Window_set_normal_button(82,88,53,14,"OK" ,0,1,SDLK_RETURN); // 2 - - Window_display_frame(6,17,130,37); - for (x=11,y=0; y<4; x+=31,y++) - { - Window_set_normal_button(x,22,27,27,"",0,1,SDLK_LAST); // 3,4,5,6 - for (j=0; j<3; j++) - for (i=0; i<3; i++) - Print_char_in_window(x+2+(i<<3),24+(j<<3),'0'+Smooth_default_matrices[y][i][j],MC_Black,MC_Light); - } - - Window_display_frame(6,58, 69,45); - for (j=0; j<3; j++) - for (i=0; i<3; i++) - { - matrix_input[i][j]=Window_set_input_button(10+(i*21),62+(j*13),2); // 7..15 - chosen_matrix[i][j] = Smooth_matrix[i][j] ; - Num2str(chosen_matrix[i][j], str, 2); - Window_input_content(matrix_input[i][j],str); - } - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - - if (clicked_button>2) - { - if (clicked_button<=6) - { - memcpy(chosen_matrix,Smooth_default_matrices[clicked_button-3],sizeof(chosen_matrix)); - Hide_cursor(); - for (j=0; j<3; j++) - for (i=0; i<3; i++) - { - Num2str(chosen_matrix[i][j],str,2); - Window_input_content(matrix_input[i][j],str); - } - Display_cursor(); - } - else - { - i=clicked_button-7; x=i%3; y=i/3; - Num2str(chosen_matrix[x][y],str,2); - Readline(matrix_input[x][y]->Pos_X+2, - matrix_input[x][y]->Pos_Y+2, - str,2,INPUT_TYPE_INTEGER); - chosen_matrix[x][y]=atoi(str); - Display_cursor(); - } - } - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_EFFECTS, "SMOOTH"); - else if (Is_shortcut(Key,SPECIAL_SMOOTH_MENU)) - clicked_button=2; - } - while ((clicked_button!=1) && (clicked_button!=2)); - - Close_window(); - - if (clicked_button==2) // OK - { - memcpy(Smooth_matrix,chosen_matrix,sizeof(Smooth_matrix)); - Smooth_mode=0; // On le met à 0 car la fonct° suivante va le passer à 1 - Button_Smooth_mode(); - } - - Display_cursor(); -} - - -// -- Mode Smear ------------------------------------------------------------ -void Button_Smear_mode(void) -{ - if (!Smear_mode) - { - if (!Colorize_mode) - Effect_function=No_effect; - Shade_mode=0; - Quick_shade_mode=0; - Smooth_mode=0; - Tiling_mode=0; - } - Smear_mode=!Smear_mode; -} - -// -- Mode Colorize --------------------------------------------------------- -void Compute_colorize_table(void) -{ - word index; - word factor_a; - word factor_b; - - factor_a=256*(100-Colorize_opacity)/100; - factor_b=256*( Colorize_opacity)/100; - - for (index=0;index<256;index++) - { - Factors_table[index]=index*factor_a; - Factors_inv_table[index]=index*factor_b; - } -} - - -void Button_Colorize_mode(void) -{ - if (Colorize_mode) - Effect_function=No_effect; - else - { - switch(Colorize_current_mode) - { - case 0 : - Effect_function=Effect_interpolated_colorize; - break; - case 1 : - Effect_function=Effect_additive_colorize; - break; - case 2 : - Effect_function=Effect_substractive_colorize; - break; - case 3 : - Effect_function=Effect_alpha_colorize; - } - Shade_mode=0; - Quick_shade_mode=0; - Smooth_mode=0; - Tiling_mode=0; - } - Colorize_mode=!Colorize_mode; -} - - -void Button_Colorize_display_selection(int mode) -{ - short y_pos=0; // Ligne où afficher les flèches de sélection - - // On commence par effacer les anciennes sélections: - // Partie gauche - 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) - { - case 0 : // Méthode interpolée - y_pos=37; - break; - case 1 : // Méthode additive - y_pos=57; - 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); -} - -void Button_Colorize_menu(void) -{ - short chosen_opacity; - short selected_mode; - short clicked_button; - char str[4]; - - Open_window(140,135,"Transparency"); - - Print_in_window(16,23,"Opacity:",MC_Dark,MC_Light); - Window_set_input_button(87,21,3); // 1 - Print_in_window(117,23,"%",MC_Dark,MC_Light); - Window_set_normal_button(16,34,108,14,"Interpolate",1,1,SDLK_i); // 2 - Window_display_frame(12,18,116,34); - - 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,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); - Button_Colorize_display_selection(Colorize_current_mode); - - chosen_opacity=Colorize_opacity; - selected_mode =Colorize_current_mode; - - Update_window_area(0,0,Window_width, Window_height); - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - - switch(clicked_button) - { - case 1: // Zone de saisie de l'opacité - Num2str(chosen_opacity,str,3); - Readline(89,23,str,3,INPUT_TYPE_INTEGER); - chosen_opacity=atoi(str); - // On corrige le pourcentage - if (chosen_opacity>100) - { - chosen_opacity=100; - Num2str(chosen_opacity,str,3); - Window_input_content(Window_special_button_list,str); - } - Display_cursor(); - break; - 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); - Display_cursor(); - } - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_EFFECTS, "TRANSPARENCY"); - else if (Is_shortcut(Key,SPECIAL_COLORIZE_MENU)) - clicked_button=7; - } - while (clicked_button<6); - - Close_window(); - - if (clicked_button==7) // OK - { - Colorize_opacity =chosen_opacity; - Colorize_current_mode=selected_mode; - Compute_colorize_table(); - Colorize_mode=0; // On le met à 0 car la fonct° suivante va le passer à 1 - Button_Colorize_mode(); - } - - Display_cursor(); -} - - -// -- Mode Tiling ----------------------------------------------------------- -void Button_Tiling_mode(void) -{ - if (Tiling_mode) - Effect_function=No_effect; - else - { - Effect_function=Effect_tiling; - Shade_mode=0; - Quick_shade_mode=0; - Colorize_mode=0; - Smooth_mode=0; - Smear_mode=0; - } - Tiling_mode=!Tiling_mode; -} - - -void Button_Tiling_menu(void) -{ - short clicked_button; - short chosen_offset_x=Tiling_offset_X; - short chosen_offset_y=Tiling_offset_Y; - char str[5]; - T_Special_button * input_offset_x_button; - T_Special_button * input_offset_y_button; - - Open_window(138,79,"Tiling"); - - Window_set_normal_button(13,55,51,14,"Cancel",0,1,KEY_ESC); // 1 - Window_set_normal_button(74,55,51,14,"OK" ,0,1,SDLK_RETURN); // 2 - input_offset_x_button = Window_set_input_button(91,21,4); // 3 - input_offset_y_button = Window_set_input_button(91,35,4); // 4 - Print_in_window(12,23,"Offset X:",MC_Dark,MC_Light); - Print_in_window(12,37,"Offset Y:",MC_Dark,MC_Light); - - Num2str(Tiling_offset_X,str,4); - Window_input_content(input_offset_x_button,str); - Num2str(Tiling_offset_Y,str,4); - Window_input_content(input_offset_y_button,str); - - Update_window_area(0,0,Window_width, Window_height); - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - - if (clicked_button==3) // Zone de saisie du décalage X - { - Num2str(chosen_offset_x,str,4); - 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) - { - chosen_offset_x=Brush_width-1; - Num2str(chosen_offset_x,str,4); - Window_input_content(input_offset_x_button,str); - } - Display_cursor(); - } - else - if (clicked_button==4) // Zone de saisie du décalage Y - { - Num2str(chosen_offset_y,str,4); - 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) - { - chosen_offset_y=Brush_height-1; - Num2str(chosen_offset_y,str,4); - Window_input_content(input_offset_y_button,str); - } - Display_cursor(); - } - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_EFFECTS, "TILING"); - } - while ( (clicked_button!=1) && (clicked_button!=2) ); - - Close_window(); - - if (clicked_button==2) // OK - { - Tiling_offset_X=chosen_offset_x; - Tiling_offset_Y=chosen_offset_y; - if (!Tiling_mode) - Button_Tiling_mode(); - } - - Display_cursor(); -} - -// -- All modes off --------------------------------------------------------- -void Effects_off(void) -{ - Effect_function=No_effect; - Shade_mode=0; - Quick_shade_mode=0; - Colorize_mode=0; - Smooth_mode=0; - Tiling_mode=0; - Smear_mode=0; - Stencil_mode=0; - Mask_mode=0; - Sieve_mode=0; - Snap_mode=0; -} - - -// -- Mode Sieve (Sieve) ---------------------------------------------------- - -void Button_Sieve_mode(void) -{ - Sieve_mode=!Sieve_mode; -} - - -void Draw_sieve_scaled(short origin_x, short origin_y) -{ - short x_pos; - short y_pos; - short x_size; - short y_size; - short start_x=Window_pos_X+(Menu_factor_X*230); - short start_y=Window_pos_Y+(Menu_factor_Y*78); - - x_size=Menu_factor_X*5; // |_ Taille d'une case - y_size=Menu_factor_Y*5; // | de la trame zoomée - - // On efface de contenu précédent - Block(origin_x,origin_y, - Menu_factor_X*Window_special_button_list->Width, - Menu_factor_Y*Window_special_button_list->Height,MC_Light); - - for (y_pos=0; y_posSieve_pattern[index][j&0xF]>>(15-(i&0xF)))&1)?MC_White:MC_Black); - - Update_rect(ToWinX(10),ToWinY(22),ToWinL(12*23+16),ToWinH(16)); -} - - -void Copy_preset_sieve(byte index) -{ - short i,j; - - for (j=0; j<16; j++) - for (i=0; i<16; i++) - Sieve[i][j]=(Gfx->Sieve_pattern[index][j]>>(15-i))&1; - Sieve_width=16; - Sieve_height=16; -} - - -void Invert_trame(void) -{ - byte x_pos,y_pos; - - for (y_pos=0; y_pos plus grande - short preview_y_end; // | rapidité. - - - memcpy(old_sieve,Sieve,256); - - Open_window(290,179,"Sieve"); - - preview_x_start=Window_pos_X+(Menu_factor_X*230); - preview_y_start=Window_pos_Y+(Menu_factor_Y*78); - preview_x_end=preview_x_start+(Menu_factor_X*51); - preview_y_end=preview_y_start+(Menu_factor_Y*71); - - Window_display_frame ( 7, 65,130,43); - Window_display_frame ( 7,110,130,43); - Window_display_frame_in(142, 68, 82,82); - Window_display_frame_in(229, 77, 53,73); - - Print_in_window(228, 68,"Preview",MC_Dark,MC_Light); - Print_in_window( 27, 83,"Scroll" ,MC_Dark,MC_Light); - Print_in_window( 23,120,"Width:" ,MC_Dark,MC_Light); - Print_in_window( 15,136,"Height:",MC_Dark,MC_Light); - - Window_set_special_button(143,69,80,80); // 1 - - Window_set_normal_button(175,157,51,14,"Cancel",0,1,KEY_ESC); // 2 - Window_set_normal_button(230,157,51,14,"OK" ,0,1,SDLK_RETURN); // 3 - - Window_set_normal_button( 8,157,51,14,"Clear" ,1,1,SDLK_c); // 4 - Window_set_normal_button( 63,157,51,14,"Invert",1,1,SDLK_i); // 5 - - Window_set_normal_button( 8,46,131,14,"Get from brush" ,1,1,SDLK_g); // 6 - Window_set_normal_button(142,46,139,14,"Transfer to brush",1,1,SDLK_t); // 7 - - Window_set_normal_button(109,114,11,11,"\030",0,1,SDLK_UP|MOD_SHIFT); // 8 - Window_set_normal_button(109,138,11,11,"\031",0,1,SDLK_DOWN|MOD_SHIFT); // 9 - Window_set_normal_button( 97,126,11,11,"\033",0,1,SDLK_LEFT|MOD_SHIFT); // 10 - Window_set_normal_button(121,126,11,11,"\032",0,1,SDLK_RIGHT|MOD_SHIFT); // 11 - button_bg_color = Window_set_normal_button(109,126,11,11,"" ,0,1,SDLK_INSERT); // 12 - Block(Window_pos_X+(Menu_factor_X*(button_bg_color->Pos_X+2)), - Window_pos_Y+(Menu_factor_Y*(button_bg_color->Pos_Y+2)), - Menu_factor_X*7, Menu_factor_Y*7, (default_bg_color)?MC_White:MC_Black); - - Window_set_repeatable_button(109, 69,11,11,"\030",0,1,SDLK_UP); // 13 - Window_set_repeatable_button(109, 93,11,11,"\031",0,1,SDLK_DOWN); // 14 - Window_set_repeatable_button( 97, 81,11,11,"\033",0,1,SDLK_LEFT); // 15 - Window_set_repeatable_button(121, 81,11,11,"\032",0,1,SDLK_RIGHT); // 16 - - for (index=0; index<12; index++) - Window_set_normal_button((index*23)+8,20,20,20,"",0,1,SDLK_F1+index); // 17 -> 28 - Draw_preset_sieve_patterns(); - - 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); - - Num2str(Sieve_width,str,2); - Print_in_window(71,120,str,MC_Black,MC_Light); - Num2str(Sieve_height,str,2); - Print_in_window(71,136,str,MC_Black,MC_Light); - Draw_sieve_scaled(origin_x,origin_y); - - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - 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); - - - switch (clicked_button) - { - case -1 : - case 0 : - break; - - case 1 : // Zone de dessin de la trame - /* // Version qui n'accepte pas les clicks sur la grille - x_pos=(Mouse_X-origin_x)/Menu_factor_X; - y_pos=(Mouse_Y-origin_y)/Menu_factor_Y; - if ( (x_pos%5<4) && (y_pos%5<4) ) - { - x_pos/=5; - y_pos/=5; - if ( (x_pos16)?16:Brush_width; - Sieve_height=(Brush_height>16)?16:Brush_height; - for (y_pos=0; y_pos>1); - Brush_offset_Y=(Brush_height>>1); - - Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH); - break; - - case 8 : // Réduire hauteur - if (Sieve_height>1) - { - Hide_cursor(); - Sieve_height--; - Num2str(Sieve_height,str,2); - Print_in_window(71,136,str,MC_Black,MC_Light); - Draw_sieve_scaled(origin_x,origin_y); - Display_cursor(); - Update_sieve_area(origin_x, origin_y); - } - break; - - case 9 : // Agrandir hauteur - if (Sieve_height<16) - { - Hide_cursor(); - for (index=0; index1) - { - Hide_cursor(); - Sieve_width--; - Num2str(Sieve_width,str,2); - Print_in_window(71,120,str,MC_Black,MC_Light); - Draw_sieve_scaled(origin_x,origin_y); - Display_cursor(); - Update_sieve_area(origin_x, origin_y); - } - break; - - case 11 : // Agrandir largeur - if (Sieve_width<16) - { - Hide_cursor(); - for (index=0; indexPos_X+2)), - Window_pos_Y+(Menu_factor_Y*(button_bg_color->Pos_Y+2)), - Menu_factor_X*7, Menu_factor_Y*7, (default_bg_color)?MC_White:MC_Black); - Display_cursor(); - Update_rect( - Window_pos_X+(Menu_factor_X*(button_bg_color->Pos_X+2)), - Window_pos_Y+(Menu_factor_Y*(button_bg_color->Pos_Y+2)), - Menu_factor_X*7, - Menu_factor_Y*7); - - break; - - case 13 : // Scroll vers le haut - Hide_cursor(); - for (x_pos=0; x_pos0; y_pos--) - Sieve[x_pos][y_pos]=Sieve[x_pos][y_pos-1]; - Sieve[x_pos][0]=temp; - } - Draw_sieve_scaled(origin_x,origin_y); - Display_cursor(); - Update_sieve_area(origin_x, origin_y); - break; - - case 15 : // Scroll vers la gauche - Hide_cursor(); - for (y_pos=0; y_pos0; x_pos--) - Sieve[x_pos][y_pos]=Sieve[x_pos-1][y_pos]; - Sieve[0][y_pos]=temp; - } - Draw_sieve_scaled(origin_x,origin_y); - Display_cursor(); - Update_sieve_area(origin_x, origin_y); - break; - - default : // Boutons de trames prédéfinies - Hide_cursor(); - Copy_preset_sieve(clicked_button-17); - Draw_sieve_scaled(origin_x,origin_y); - Num2str(Sieve_width,str,2); - Print_in_window(71,120,str,MC_Black,MC_Light); - Num2str(Sieve_height,str,2); - Print_in_window(71,136,str,MC_Black,MC_Light); - Draw_sieve_scaled(origin_x,origin_y); - Display_cursor(); - Update_sieve_area(origin_x, origin_y); - } - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Key=0; - Window_help(BUTTON_EFFECTS, "SIEVE"); - } - } - while ( (clicked_button!=2) && (clicked_button!=3) ); - - - Close_window(); - - if (clicked_button==2) // Cancel - { - Sieve_width=old_sieve_width; - Sieve_height=old_sieve_height; - memcpy(Sieve,old_sieve,256); - } - - if ( (clicked_button==3) && (!Sieve_mode) ) // OK - Button_Sieve_mode(); - - Display_cursor(); -} - - diff --git a/project/jni/application/grafx2/grafx2/src/const.h b/project/jni/application/grafx2/grafx2/src/const.h deleted file mode 100644 index 0c1bb43e5..000000000 --- a/project/jni/application/grafx2/grafx2/src/const.h +++ /dev/null @@ -1,529 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file const.h -/// Constants (preprocessor defines) and enumerations used anywhere. -////////////////////////////////////////////////////////////////////////////// - -#ifndef _CONST_H_ -#define _CONST_H_ - -#ifndef M_2PI -#define M_2PI 6.28318530717958647692528676656 ///< Hmm, pie... -#endif - -#define VERSION1 2 ///< Version number for gfx2.cfg (1/4) -#define VERSION2 0 ///< Version number for gfx2.cfg (2/4) -#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_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. -#define NB_CURSOR_SPRITES 8 ///< Number of available mouse cursor sprites. -#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 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 -#define PAINTBRUSH_HEIGHT 16 ///< Height of a preset paintbrush sprite -#define MAX_PAINTBRUSH_SIZE 127 ///< Max size for a resizable paintbrush -#define ICON_SPRITE_WIDTH 8 ///< Width of an icon in pixels -#define ICON_SPRITE_HEIGHT 8 ///< Height of an icon in pixels -#define NB_PAINTBRUSH_SPRITES 48 ///< Number of preset paintbrushes -#define NB_PRESET_SIEVE 12 ///< Number of preset sieve patterns -#define OPERATION_STACK_SIZE 16 ///< Max number of parameters in the operation stack. -#define MAX_DISPLAYABLE_PATH 37 ///< Max number of characters to display directory name, in Save/Load screens. -#define COMMENT_SIZE 32 ///< Max number of characters for a comment in PKM or PNG file. -#define NB_MAX_PAGES_UNDO 99 ///< Max number of undo pages -#define DEFAULT_ZOOM_FACTOR 4 ///< Initial zoom factor for the magnifier. -#define MAX_PATH_CHARACTERS 260 ///< Number of characters for a file+complete path. Adapt to your OS... -#define NB_BOOKMARKS 4 ///< Number of bookmark buttons in Save/Load screen. -// Character to show a right arrow, used when editing long strings. It's present in ::Gfx->System_font -#define RIGHT_TRIANGLE_CHARACTER 16 -// Character to show a left arrow, used when editing long strings. It's present in ::Gfx->System_font -#define LEFT_TRIANGLE_CHARACTER 17 -/// Character to display in menus for an ellipsis. -#define ELLIPSIS_CHARACTER '…' -#define NB_LAYERS 1 ///< Initial number of layers for a new image -#define MAX_NB_LAYERS 16 ///< Maximum number of layers that can be used in grafx2. Note that 32 is upper limit because of a few bit fields. -#define BRUSH_CONTAINER_PREVIEW_WIDTH 16 ///< Size for preview of a brush in Brush container -#define BRUSH_CONTAINER_PREVIEW_HEIGHT 16 ///< Size for preview of a brush in Brush container -#define BRUSH_CONTAINER_COLUMNS 4 ///< Number of columns in the Brush container -#define BRUSH_CONTAINER_ROWS 3 ///< Number of rows in the Brush container - -/// -/// We force the dynamic backup page allocation to leave a minimum of -/// 256Kb of free memory, to allow the rest of the program to work safely. -/// Note: This is a remainder of the DOS version. This system might not work -/// so well on other OSes, where the "available memory" changes due to external -/// factors. -#define MINIMAL_MEMORY_TO_RESERVE (256*1024) - -#define LEFT_SIDE 1 ///< Indicates a left side or left-click -#define RIGHT_SIDE 2 ///< Indicates a right side or right-click - -#define SEPARATOR_WIDTH 6 ///< Width of the separator between the normal and the zoomed view -#define INITIAL_SEPARATOR_PROPORTION 0.3 ///< Proportion of the normal view width, relative to the whole screen width. -#define NB_ZOOMED_PIXELS_MIN 4 ///< Minimal number of pixel shown (in width) by the zoomed view. (Note: below 4, you can't scroll!) - -#if defined(__MORPHOS__) || defined(__amigaos4__) || defined(__amigaos__) - #define PARENT_DIR "/" -#else - /// Filename that means "parent directory" for your operating system. - #define PARENT_DIR ".." -#endif - -/// List of file formats recognized by grafx2 -enum FILE_FORMATS -{ - FORMAT_ALL_IMAGES=0, ///< This is not really a file format, it's reserverd for a compilation of all file extensions - FORMAT_ALL_FILES=1, ///< This is not really a file format, it's reserverd for the "*.*" filter option. - FORMAT_PNG, - FORMAT_GIF, - FORMAT_BMP, - FORMAT_PCX, - FORMAT_PKM, - FORMAT_LBM, - FORMAT_IMG, - FORMAT_SCx, - FORMAT_PI1, - FORMAT_PC1, - FORMAT_CEL, - FORMAT_NEO, - FORMAT_C64, - FORMAT_KCF, - FORMAT_PAL, - FORMAT_SCR, - FORMAT_XPM, - FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image -}; - -/// Default format for 'save as' -#define DEFAULT_FILEFORMAT FORMAT_GIF - -/// Error codes for ::Error() -enum ERROR_CODES -{ - ERROR_WARNING=0, ///< Red flash on screen, non-fatal error - ERROR_GUI_MISSING, ///< The graphics file is missing - ERROR_GUI_CORRUPTED, ///< The graphics file cannot be parsed for GUI elements - ERROR_INI_MISSING, ///< File gfx2def.ini is missing - ERROR_CFG_MISSING, ///< File gfx2.cfg is missing (non-fatal) - ERROR_CFG_CORRUPTED, ///< File gfx2.cfg couldn't be parsed (non-fatal) - ERROR_CFG_OLD, ///< Unknown version of gfx2.cfg : either VERY old or wrong file (non-fatal) - ERROR_MEMORY, ///< Out of memory - ERROR_COMMAND_LINE, ///< Error in command-line arguments (syntax, or couldn't find the file to open) - ERROR_FORBIDDEN_MODE, ///< Graphics mode requested is not supported - ERROR_SAVING_CFG, ///< Error while writing gfx2.cfg - ERROR_MISSING_DIRECTORY, ///< Unable to return to the original "current directory" on program exit - ERROR_INI_CORRUPTED, ///< File gfx2.ini couldn't be parsed - ERROR_SAVING_INI, ///< Error while writing gfx2.ini - ERROR_SORRY_SORRY_SORRY ///< (Page allocation error that shouldn't ever happen, now) -}; - -/// Available pixel scalers -enum PIXEL_RATIO -{ - PIXEL_SIMPLE=0, ///< Use real pixels - PIXEL_WIDE, ///< Use wide pixels (2x1) like on Amstrad CPC mode 0 - PIXEL_TALL, ///< Use tall pixels (1x2) like on Amstrad CPC mode 2 - PIXEL_DOUBLE, ///< Use big pixels (2x2) if your LCD screen can't do lowres by itself - PIXEL_TRIPLE, ///< Use really big pixels (3x3) - PIXEL_WIDE2, ///< Use big wide pixels (4x2) - PIXEL_TALL2, ///< Use big tall pixels (2x4) - PIXEL_QUAD, ///< Use really giant pixels (4x4). You need to have a screen resolution at least 1280x800 to use this one - PIXEL_MAX ///< Number of elements in enum -}; - -/// Different kinds of menu button behavior. -enum FAMILY_OF_BUTTONS -{ - FAMILY_TOOL=1, ///< Drawing tools (example : Freehand draw) - FAMILY_INTERRUPTION, ///< Temporary operation (example : choosing paintbrush) > Interrupts the current operation to do something, then come back. - FAMILY_INSTANT, ///< Single-click action (example : choose a color in palette) > It will be over as soon as we exit the called function. - FAMILY_TOOLBAR, ///< Hide/show the menu - FAMILY_EFFECTS ///< Effects -}; - -/// The different kinds of buttons in menus or windows. -enum BUTTON_SHAPES -{ - BUTTON_SHAPE_NO_FRAME, ///< Ex: the palette - BUTTON_SHAPE_RECTANGLE, ///< Ex: Most buttons. - BUTTON_SHAPE_TRIANGLE_TOP_LEFT, ///< Ex: Empty rectangles. - BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT ///< Ex: Filled rectangles. -}; - -/// The different "mouse cursor" shapes -enum CURSOR_SHAPES -{ - CURSOR_SHAPE_ARROW, - CURSOR_SHAPE_TARGET, ///< This one uses the paintbrush - CURSOR_SHAPE_COLORPICKER, ///< This one uses the paintbrush - CURSOR_SHAPE_HOURGLASS, - CURSOR_SHAPE_MULTIDIRECTIONAL, - CURSOR_SHAPE_HORIZONTAL, - CURSOR_SHAPE_THIN_TARGET, ///< This one uses the paintbrush - CURSOR_SHAPE_THIN_COLORPICKER, ///< This one uses the paintbrush - CURSOR_SHAPE_XOR_TARGET, - CURSOR_SHAPE_XOR_RECTANGLE, - CURSOR_SHAPE_XOR_ROTATION -}; - -/// The different shapes that can be used as a paintbrush (paintbrush types go in the beginning) -enum PAINTBRUSH_SHAPES -{ - PAINTBRUSH_SHAPE_ROUND, - PAINTBRUSH_SHAPE_SQUARE, - PAINTBRUSH_SHAPE_HORIZONTAL_BAR, - PAINTBRUSH_SHAPE_VERTICAL_BAR, - PAINTBRUSH_SHAPE_SLASH, - PAINTBRUSH_SHAPE_ANTISLASH, - PAINTBRUSH_SHAPE_RANDOM, ///< Random pixels in a circle shape, like an airbrush. - PAINTBRUSH_SHAPE_CROSS, - PAINTBRUSH_SHAPE_PLUS, - 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_COLOR_BRUSH, ///< User's brush, in color mode - PAINTBRUSH_SHAPE_MONO_BRUSH, ///< User's brush, in mono mode - PAINTBRUSH_SHAPE_MAX ///< Upper limit. -}; - -/// Normal resting state for a menu button. -#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 -{ - SHADE_MODE_NORMAL, - SHADE_MODE_LOOP, - SHADE_MODE_NOSAT -}; - -/// Identifiers for the chunks (data blocks) of gfx2.cfg -enum CHUNKS_CFG -{ - CHUNK_KEYS = 0, ///< Shortcut keys definitions - CHUNK_VIDEO_MODES = 1, ///< List of video modes - CHUNK_SHADE = 2, ///< Shade settings - CHUNK_MASK = 3, ///< Mask settings - CHUNK_STENCIL = 4, ///< Stencil settings - CHUNK_GRADIENTS = 5, ///< Gradients - CHUNK_SMOOTH = 6, ///< Smooth effect settings - CHUNK_EXCLUDE_COLORS = 7, ///< List of excluded colors - CHUNK_QUICK_SHADE = 8, ///< QShade effect settings - CHUNK_GRID = 9, ///< Grid settings - CHUNK_BRUSH =10, ///< Paintbrushes - CHUNK_SCRIPTS =11, ///< Callable scripts - CHUNK_MAX -}; - -/// Identifiers for the 8x8 icons of ::Gfx->Icon_sprite (most are unused now) -enum ICON_TYPES -{ - ICON_FLOPPY_3_5=0, ///< 3.5 Floppy disk - ICON_FLOPPY_5_25, ///< 5.25 Floppy disk - ICON_HDD, ///< Hard disk drive - ICON_CDROM, ///< CD-ROM - ICON_NETWORK, ///< "Network" drive - ICON_STAR, ///< Star (favorite) - ICON_DROPDOWN, ///< Dropdown arrow - NB_ICON_SPRITES, ///< Number of 8x8 icons - ICON_NONE ///< None of the above -}; - -/// Identifiers for the buttons in the menu. -enum BUTTON_NUMBERS -{ - // Status bar - BUTTON_HIDE = 0, - - // Layer bar - BUTTON_LAYER_MENU, - BUTTON_LAYER_COLOR, - BUTTON_LAYER_MERGE, - BUTTON_LAYER_ADD, - BUTTON_LAYER_REMOVE, - BUTTON_LAYER_UP, - BUTTON_LAYER_DOWN, - BUTTON_LAYER_SELECT, - - // Main menu - BUTTON_PAINTBRUSHES, - BUTTON_ADJUST, - BUTTON_DRAW, - BUTTON_CURVES, - BUTTON_LINES, - BUTTON_AIRBRUSH, - BUTTON_FLOODFILL, - BUTTON_POLYGONS, - BUTTON_POLYFILL, - BUTTON_RECTANGLES, - BUTTON_FILLRECT, - BUTTON_CIRCLES, - BUTTON_FILLCIRC, - BUTTON_GRADRECT, - BUTTON_SPHERES, - BUTTON_BRUSH, - BUTTON_POLYBRUSH, - BUTTON_BRUSH_EFFECTS, - BUTTON_EFFECTS, - BUTTON_TEXT, - BUTTON_MAGNIFIER, - BUTTON_COLORPICKER, - BUTTON_RESOL, - BUTTON_PAGE, - BUTTON_SAVE, - BUTTON_LOAD, - BUTTON_SETTINGS, - BUTTON_CLEAR, - BUTTON_HELP, - BUTTON_UNDO, - BUTTON_KILL, - BUTTON_QUIT, - BUTTON_PALETTE, - BUTTON_PAL_LEFT, - BUTTON_PAL_RIGHT, - BUTTON_CHOOSE_COL, - 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, -/// so it requires a specific handling. -enum SPECIAL_ACTIONS -{ - SPECIAL_MOUSE_UP=0, - SPECIAL_MOUSE_DOWN, - SPECIAL_MOUSE_LEFT, - SPECIAL_MOUSE_RIGHT, - SPECIAL_CLICK_LEFT, - SPECIAL_CLICK_RIGHT, - SPECIAL_NEXT_FORECOLOR, - SPECIAL_PREVIOUS_FORECOLOR, - SPECIAL_NEXT_BACKCOLOR, - SPECIAL_PREVIOUS_BACKCOLOR, - SPECIAL_SMALLER_PAINTBRUSH, - SPECIAL_BIGGER_PAINTBRUSH, - SPECIAL_NEXT_USER_FORECOLOR, - SPECIAL_PREVIOUS_USER_FORECOLOR, - SPECIAL_NEXT_USER_BACKCOLOR, - SPECIAL_PREVIOUS_USER_BACKCOLOR, - SPECIAL_SCROLL_UP, - SPECIAL_SCROLL_DOWN, - SPECIAL_SCROLL_LEFT, - SPECIAL_SCROLL_RIGHT, - SPECIAL_SCROLL_UP_FAST, - SPECIAL_SCROLL_DOWN_FAST, - SPECIAL_SCROLL_LEFT_FAST, - SPECIAL_SCROLL_RIGHT_FAST, - SPECIAL_SCROLL_UP_SLOW, - SPECIAL_SCROLL_DOWN_SLOW, - SPECIAL_SCROLL_LEFT_SLOW, - SPECIAL_SCROLL_RIGHT_SLOW, - SPECIAL_SHOW_HIDE_CURSOR, - SPECIAL_DOT_PAINTBRUSH, - SPECIAL_CONTINUOUS_DRAW, - SPECIAL_FLIP_X, - SPECIAL_FLIP_Y, - SPECIAL_ROTATE_90, - SPECIAL_ROTATE_180, - SPECIAL_STRETCH, - SPECIAL_DISTORT, - SPECIAL_OUTLINE, - SPECIAL_NIBBLE, - 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, - SPECIAL_ZOOM_IN, - SPECIAL_ZOOM_OUT, - SPECIAL_CENTER_ATTACHMENT, - SPECIAL_TOP_LEFT_ATTACHMENT, - SPECIAL_TOP_RIGHT_ATTACHMENT, - SPECIAL_BOTTOM_LEFT_ATTACHMENT, - SPECIAL_BOTTOM_RIGHT_ATTACHMENT, - SPECIAL_EXCLUDE_COLORS_MENU, - SPECIAL_SHADE_MODE, - SPECIAL_SHADE_MENU, - SPECIAL_QUICK_SHADE_MODE, ///< This must be the first of the "effects" family - SPECIAL_QUICK_SHADE_MENU, - SPECIAL_STENCIL_MODE, - SPECIAL_STENCIL_MENU, - SPECIAL_MASK_MODE, - SPECIAL_MASK_MENU, - SPECIAL_GRID_MODE, - SPECIAL_GRID_MENU, - SPECIAL_SIEVE_MODE, - SPECIAL_SIEVE_MENU, - SPECIAL_COLORIZE_MODE, - SPECIAL_COLORIZE_MENU, - SPECIAL_SMOOTH_MODE, - SPECIAL_SMOOTH_MENU, - SPECIAL_SMEAR_MODE, - SPECIAL_EFFECTS_OFF, - SPECIAL_TILING_MODE, - SPECIAL_TRANSPARENCY_1, - SPECIAL_TRANSPARENCY_2, - SPECIAL_TRANSPARENCY_3, - SPECIAL_TRANSPARENCY_4, - SPECIAL_TRANSPARENCY_5, - SPECIAL_TRANSPARENCY_6, - SPECIAL_TRANSPARENCY_7, - SPECIAL_TRANSPARENCY_8, - SPECIAL_TRANSPARENCY_9, - SPECIAL_TRANSPARENCY_0, - SPECIAL_TILING_MENU, ///< This must be the last of the "effects" family - SPECIAL_ZOOM_1, - SPECIAL_ZOOM_2, - SPECIAL_ZOOM_3, - SPECIAL_ZOOM_4, - SPECIAL_ZOOM_5, - SPECIAL_ZOOM_6, - SPECIAL_ZOOM_8, - SPECIAL_ZOOM_10, - SPECIAL_ZOOM_12, - SPECIAL_ZOOM_14, - SPECIAL_ZOOM_16, - SPECIAL_ZOOM_18, - SPECIAL_ZOOM_20, - SPECIAL_SHOW_GRID, - SPECIAL_LAYER1_SELECT, - SPECIAL_LAYER1_TOGGLE, - SPECIAL_LAYER2_SELECT, - SPECIAL_LAYER2_TOGGLE, - SPECIAL_LAYER3_SELECT, - SPECIAL_LAYER3_TOGGLE, - SPECIAL_LAYER4_SELECT, - SPECIAL_LAYER4_TOGGLE, - SPECIAL_LAYER5_SELECT, - SPECIAL_LAYER5_TOGGLE, - SPECIAL_LAYER6_SELECT, - SPECIAL_LAYER6_TOGGLE, - SPECIAL_LAYER7_SELECT, - 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, - NB_SPECIAL_SHORTCUTS ///< Number of special shortcuts -}; - -/// Identifiers of the operations, ie tools you use on the image. -enum OPERATIONS -{ - OPERATION_CONTINUOUS_DRAW=0, ///< Freehand continuous draw - OPERATION_DISCONTINUOUS_DRAW,///< Freehand discontinuous draw - OPERATION_POINT_DRAW, ///< Freehand point-by-point draw - OPERATION_FILLED_CONTOUR, ///< Filled contour - OPERATION_LINE, ///< Lines - OPERATION_K_LINE, ///< Linked lines - OPERATION_CENTERED_LINES, ///< Centered lines - OPERATION_EMPTY_RECTANGLE, ///< Empty rectangle - OPERATION_FILLED_RECTANGLE, ///< Filled rectangle - OPERATION_EMPTY_CIRCLE, ///< Empty circle - OPERATION_FILLED_CIRCLE, ///< Filled circle - OPERATION_EMPTY_ELLIPSE, ///< Empty ellipse - OPERATION_FILLED_ELLIPSE, ///< Filled ellipse - OPERATION_FILL, ///< Fill - OPERATION_REPLACE, ///< Color replacer - OPERATION_GRAB_BRUSH, ///< Rectangular brush grabbing - OPERATION_POLYBRUSH, ///< Polygonal brush grabbing - OPERATION_COLORPICK, ///< Colorpicker - OPERATION_MAGNIFY, ///< Position the magnify window - OPERATION_3_POINTS_CURVE, ///< Curve with 3 control points - OPERATION_4_POINTS_CURVE, ///< Curve with 4 control points - OPERATION_AIRBRUSH, ///< Airbrush - OPERATION_POLYGON, ///< Polygon - OPERATION_POLYFORM, ///< Polyform - OPERATION_POLYFILL, ///< Filled polygon - OPERATION_FILLED_POLYFORM, ///< Filled polyform - OPERATION_SCROLL, ///< Scroll (pan) - OPERATION_GRAD_CIRCLE, ///< Gradient-filled circle - OPERATION_GRAD_ELLIPSE, ///< Gradient-filled ellipse - OPERATION_ROTATE_BRUSH, ///< Rotate brush - 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 -}; - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/engine.c b/project/jni/application/grafx2/grafx2/src/engine.c deleted file mode 100644 index 717232fd5..000000000 --- a/project/jni/application/grafx2/grafx2/src/engine.c +++ /dev/null @@ -1,3499 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -/// @file engine.c: Window engine and interface management -#include -#include -#include - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "graph.h" -#include "misc.h" -#include "special.h" -#include "buttons.h" -#include "operatio.h" -#include "shade.h" -#include "errors.h" -#include "sdlscreen.h" -#include "windows.h" -#include "brush.h" -#include "input.h" -#include "engine.h" -#include "pages.h" -#include "layers.h" -#include "factory.h" -#include "loadsave.h" -#include "io.h" - - - -// we need this as global -short Old_MX = -1; -short Old_MY = -1; - -//---------- Annuler les effets des modes de dessin (sauf la grille) --------- - -// Variables mémorisants les anciens effets - -byte Shade_mode_before_cancel; -byte Quick_shade_mode_before_cancel; -byte Stencil_mode_before_cancel; -byte Sieve_mode_before_cancel; -byte Colorize_mode_before_cancel; -byte Smooth_mode_before_cancel; -byte Tiling_mode_before_cancel; -Func_effect Effect_function_before_cancel; - -///This table holds pointers to the saved window backgrounds. We can have up to 8 windows open at a time. -byte* Window_background[8]; - - -///Table of tooltip texts for menu buttons -char * Menu_tooltip[NB_BUTTONS]= -{ - "Hide toolbars / Select ", - - "Layers manager ", - "Get/Set transparent col.", - "Merge layer ", - "Add layer ", - "Drop layer ", - "Raise layer ", - "Lower layer ", - "Layer select / toggle ", - "Paintbrush choice ", - "Adjust / Transform menu ", - "Freehand draw. / Toggle ", - "Splines / Toggle ", - "Lines / Toggle ", - "Spray / Menu ", - "Floodfill / Replace col.", - "Polylines / Polyforms ", - "Polyfill / Filled Pforms", - "Empty rectangles ", - "Filled rectangles ", - "Empty circles / ellipses", - "Filled circles / ellips.", - "Grad. rect / Grad. menu ", - "Grad. spheres / ellipses", - "Brush grab. / Restore ", - "Lasso / Restore brush ", -#ifdef __ENABLE_LUA__ - "Brush effects / factory ", -#else - "Brush effects ", -#endif - "Drawing modes (effects) ", - "Text ", - "Magnify mode / Menu ", - "Pipette / Invert colors ", - "Screen size / Safe. res.", - "Go / Copy to other page ", - "Save as / Save ", - "Load / Re-load ", - "Settings / Skins ", - "Clear / with backcolor ", - "Help / Statistics ", - "Undo / Redo ", - "Kill current page ", - "Quit ", - "Palette editor / setup ", - "Scroll pal. bkwd / Fast ", - "Scroll pal. fwd / Fast ", - "Color #" , -}; - -///Save a screen block (usually before erasing it with a new window or a dropdown menu) -void Save_background(byte **buffer, int x_pos, int y_pos, int width, int height) -{ - int index; - if(*buffer != NULL) DEBUG("WARNING : buffer already allocated !!!",0); - *buffer=(byte *) malloc(width*Menu_factor_X*height*Menu_factor_Y*Pixel_width); - if(*buffer==NULL) Error(0); - for (index=0; index<(height*Menu_factor_Y); index++) - Read_line(x_pos,y_pos+index,width*Menu_factor_X,(*buffer)+((int)index*width*Menu_factor_X*Pixel_width)); -} - -///Restores a screen block -void Restore_background(byte *buffer, int x_pos, int y_pos, int width, int height) -{ - int index; - for (index=0; index= Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top) && - Mouse_Y < Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top + Menu_bars[current_menu].Height)) - break; - } - } - if (current_menu==MENUBAR_COUNT) - return -1; - - y_pos=(Mouse_Y - Menu_Y)/Menu_factor_Y - Menu_bars[current_menu].Top; - - if (current_menu == 0) first_button = 0; - else first_button = Menu_bars[current_menu - 1].Last_button_index + 1; - - for (btn_number=first_button;btn_number<=Menu_bars[current_menu].Last_button_index;btn_number++) - { - switch(Buttons_Pool[btn_number].Shape) - { - case BUTTON_SHAPE_NO_FRAME : - case BUTTON_SHAPE_RECTANGLE : - - if ((x_pos>=Buttons_Pool[btn_number].X_offset) && - (y_pos>=Buttons_Pool[btn_number].Y_offset) && - (x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) && - (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height)) - return btn_number; - break; - - case BUTTON_SHAPE_TRIANGLE_TOP_LEFT: - if ((x_pos>=Buttons_Pool[btn_number].X_offset) && - (y_pos>=Buttons_Pool[btn_number].Y_offset) && - (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset<=Buttons_Pool[btn_number].Width)) - return btn_number; - break; - - case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT: - if ((x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) && - (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height) && - (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset>=Buttons_Pool[btn_number].Width)) - return btn_number; - break; - } - } - return -1; -} - - -///Draw a menu button, selected or not -void Draw_menu_button(byte btn_number,byte pressed) -{ - word start_x; - word start_y; - word width; - word height; - byte * bitmap; - word bitmap_width; - word x_pos; - word y_pos; - byte current_menu; - byte color; - signed char icon; - - // Find in which menu the button is - for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++) - { - // We found the right bar ! - if (Menu_bars[current_menu].Last_button_index >= btn_number && - (current_menu==0 || Menu_bars[current_menu -1].Last_button_index < btn_number)) - { - break; - } - } - - 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 (icon==-1) - { - // 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(0)) - { - action = 0; - - // Inhibit all keys if a drawing operation is in progress. - // We make an exception for the freehand operations, but these will - // only accept a very limited number of shortcuts. - if (Operation_stack_size!=0 && !Allow_color_change_during_operation) - Key=0; - - // Evenement de fermeture - if (Quit_is_required) - { - Quit_is_required=0; - Button_Quit(); - } - - if (Key) - { - effect_modified = 0; - - for (key_index=SPECIAL_CLICK_RIGHT+1;key_index>2)); - else - Scroll_screen(0,-(Screen_height>>3)); - action++; - break; - case SPECIAL_SCROLL_DOWN : // Scroll down - if (Main_magnifier_mode) - Scroll_magnifier(0,(Main_magnifier_height>>2)); - else - Scroll_screen(0,(Screen_height>>3)); - action++; - break; - case SPECIAL_SCROLL_LEFT : // Scroll left - if (Main_magnifier_mode) - Scroll_magnifier(-(Main_magnifier_width>>2),0); - else - Scroll_screen(-(Screen_width>>3),0); - action++; - break; - case SPECIAL_SCROLL_RIGHT : // Scroll right - if (Main_magnifier_mode) - Scroll_magnifier((Main_magnifier_width>>2),0); - else - Scroll_screen((Screen_width>>3),0); - action++; - break; - case SPECIAL_SCROLL_UP_FAST : // Scroll up faster - if (Main_magnifier_mode) - Scroll_magnifier(0,-(Main_magnifier_height>>1)); - else - Scroll_screen(0,-(Screen_height>>2)); - action++; - break; - case SPECIAL_SCROLL_DOWN_FAST : // Scroll down faster - if (Main_magnifier_mode) - Scroll_magnifier(0,(Main_magnifier_height>>1)); - else - Scroll_screen(0,(Screen_height>>2)); - action++; - break; - case SPECIAL_SCROLL_LEFT_FAST : // Scroll left faster - if (Main_magnifier_mode) - Scroll_magnifier(-(Main_magnifier_width>>1),0); - else - Scroll_screen(-(Screen_width>>2),0); - action++; - break; - case SPECIAL_SCROLL_RIGHT_FAST : // Scroll right faster - if (Main_magnifier_mode) - Scroll_magnifier((Main_magnifier_width>>1),0); - else - Scroll_screen((Screen_width>>2),0); - action++; - break; - case SPECIAL_SCROLL_UP_SLOW : // Scroll up slower - if (Main_magnifier_mode) - Scroll_magnifier(0,-1); - else - Scroll_screen(0,-1); - action++; - break; - case SPECIAL_SCROLL_DOWN_SLOW : // Scroll down slower - if (Main_magnifier_mode) - Scroll_magnifier(0,1); - else - Scroll_screen(0,1); - action++; - break; - case SPECIAL_SCROLL_LEFT_SLOW : // Scroll left slower - if (Main_magnifier_mode) - Scroll_magnifier(-1,0); - else - Scroll_screen(-1,0); - action++; - break; - case SPECIAL_SCROLL_RIGHT_SLOW : // Scroll right slower - if (Main_magnifier_mode) - Scroll_magnifier(1,0); - else - Scroll_screen(1,0); - action++; - break; - case SPECIAL_SHOW_HIDE_CURSOR : // Show / Hide cursor - Hide_cursor(); - Cursor_hidden=!Cursor_hidden; - Display_cursor(); - action++; - break; - case SPECIAL_DOT_PAINTBRUSH : // Paintbrush = "." - Hide_cursor(); - Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND; - Set_paintbrush_size(1,1); - Change_paintbrush_shape(PAINTBRUSH_SHAPE_ROUND); - Display_cursor(); - action++; - break; - case SPECIAL_CONTINUOUS_DRAW : // Continuous freehand drawing - Select_button(BUTTON_DRAW,LEFT_SIDE); - // ATTENTION CE TRUC EST MOCHE ET VA MERDER SI ON SE MET A UTILISER DES BOUTONS POPUPS - while (Current_operation!=OPERATION_CONTINUOUS_DRAW) - Select_button(BUTTON_DRAW,RIGHT_SIDE); - action++; - break; - case SPECIAL_FLIP_X : // Flip X - Hide_cursor(); - 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_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_ROTATE_90 : // 90° brush rotation - Hide_cursor(); - Rotate_90_deg(); - Display_cursor(); - action++; - break; - 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(); - action++; - break; - case SPECIAL_STRETCH : // Stretch brush - Hide_cursor(); - Start_operation_stack(OPERATION_STRETCH_BRUSH); - Display_cursor(); - action++; - break; - case SPECIAL_DISTORT : // Distort brush - Hide_cursor(); - Start_operation_stack(OPERATION_DISTORT_BRUSH); - Display_cursor(); - action++; - break; - case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle - Hide_cursor(); - Start_operation_stack(OPERATION_ROTATE_BRUSH); - 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(); - Display_cursor(); - action++; - break; - case SPECIAL_NIBBLE : // Nibble brush - Hide_cursor(); - Nibble_brush(); - Display_cursor(); - action++; - break; - case SPECIAL_GET_BRUSH_COLORS : // Get colors from brush - Get_colors_from_brush(); - action++; - break; - case SPECIAL_RECOLORIZE_BRUSH : // Recolorize brush - Hide_cursor(); - Remap_brush(); - Display_cursor(); - action++; - break; - case SPECIAL_LOAD_BRUSH : - Load_picture(0); - action++; - break; - case SPECIAL_SAVE_BRUSH : - Save_picture(0); - action++; - break; - case SPECIAL_ZOOM_IN : // Zoom in - Zoom(+1); - action++; - break; - case SPECIAL_ZOOM_OUT : // Zoom out - Zoom(-1); - action++; - break; - case SPECIAL_CENTER_ATTACHMENT : // Center brush attachment - Hide_cursor(); - Brush_offset_X=(Brush_width>>1); - Brush_offset_Y=(Brush_height>>1); - Display_cursor(); - action++; - break; - case SPECIAL_TOP_LEFT_ATTACHMENT : // Top-left brush attachment - Hide_cursor(); - Brush_offset_X=0; - Brush_offset_Y=0; - Display_cursor(); - action++; - break; - case SPECIAL_TOP_RIGHT_ATTACHMENT : // Top-right brush attachment - Hide_cursor(); - Brush_offset_X=(Brush_width-1); - Brush_offset_Y=0; - Display_cursor(); - action++; - break; - case SPECIAL_BOTTOM_LEFT_ATTACHMENT : // Bottom-left brush attachment - Hide_cursor(); - Brush_offset_X=0; - Brush_offset_Y=(Brush_height-1); - Display_cursor(); - action++; - break; - case SPECIAL_BOTTOM_RIGHT_ATTACHMENT : // Bottom right brush attachment - Hide_cursor(); - Brush_offset_X=(Brush_width-1); - Brush_offset_Y=(Brush_height-1); - Display_cursor(); - action++; - break; - case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu - Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); - action++; - break; - case SPECIAL_INVERT_SIEVE : - Invert_trame(); - action++; - break; - case SPECIAL_SHADE_MODE : - Button_Shade_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_SHADE_MENU : - Button_Shade_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_QUICK_SHADE_MODE : - Button_Quick_shade_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_QUICK_SHADE_MENU : - Button_Quick_shade_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_STENCIL_MODE : - Button_Stencil_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_STENCIL_MENU : - Button_Stencil_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_MASK_MODE : - Button_Mask_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_MASK_MENU : - Button_Mask_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_GRID_MODE : - Button_Snap_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_GRID_MENU : - Button_Grid_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_SHOW_GRID : - Button_Show_grid(); - effect_modified = 1; - action++; - break; - case SPECIAL_SIEVE_MODE : - Button_Sieve_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_SIEVE_MENU : - Button_Sieve_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_COLORIZE_MODE : - Button_Colorize_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_COLORIZE_MENU : - Button_Colorize_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_SMOOTH_MODE : - Button_Smooth_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_SMOOTH_MENU : - Button_Smooth_menu(); - effect_modified = 1; - action++; - break; - case SPECIAL_SMEAR_MODE : - Button_Smear_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_TILING_MODE : - Button_Tiling_mode(); - effect_modified = 1; - action++; - break; - case SPECIAL_TILING_MENU : - effect_modified = 1; - Button_Tiling_menu(); - action++; - break; - case SPECIAL_EFFECTS_OFF : - Effects_off(); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_1 : - Transparency_set(1); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_2 : - Transparency_set(2); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_3 : - Transparency_set(3); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_4 : - Transparency_set(4); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_5 : - Transparency_set(5); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_6 : - Transparency_set(6); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_7 : - Transparency_set(7); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_8 : - Transparency_set(8); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_9 : - Transparency_set(9); - effect_modified = 1; - action++; - break; - case SPECIAL_TRANSPARENCY_0 : - Transparency_set(0); - effect_modified = 1; - action++; - break; - case SPECIAL_ZOOM_1 : - Zoom_set(-1); - action++; - break; - case SPECIAL_ZOOM_2 : - Zoom_set(0); - action++; - break; - case SPECIAL_ZOOM_3 : - Zoom_set(1); - action++; - break; - case SPECIAL_ZOOM_4 : - Zoom_set(2); - action++; - break; - case SPECIAL_ZOOM_5 : - Zoom_set(3); - action++; - break; - case SPECIAL_ZOOM_6 : - Zoom_set(4); - action++; - break; - case SPECIAL_ZOOM_8 : - Zoom_set(5); - action++; - break; - case SPECIAL_ZOOM_10 : - Zoom_set(6); - action++; - break; - case SPECIAL_ZOOM_12 : - Zoom_set(7); - action++; - break; - case SPECIAL_ZOOM_14 : - Zoom_set(8); - action++; - break; - case SPECIAL_ZOOM_16 : - Zoom_set(9); - action++; - break; - case SPECIAL_ZOOM_18 : - Zoom_set(10); - action++; - break; - case SPECIAL_ZOOM_20 : - Zoom_set(11); - action++; - break; - case SPECIAL_LAYER1_SELECT: - case SPECIAL_LAYER2_SELECT: - case SPECIAL_LAYER3_SELECT: - case SPECIAL_LAYER4_SELECT: - case SPECIAL_LAYER5_SELECT: - case SPECIAL_LAYER6_SELECT: - case SPECIAL_LAYER7_SELECT: - case SPECIAL_LAYER8_SELECT: - Layer_activate((key_index-SPECIAL_LAYER1_SELECT)/2, LEFT_SIDE); - action++; - break; - case SPECIAL_LAYER1_TOGGLE: - case SPECIAL_LAYER2_TOGGLE: - case SPECIAL_LAYER3_TOGGLE: - case SPECIAL_LAYER4_TOGGLE: - case SPECIAL_LAYER5_TOGGLE: - case SPECIAL_LAYER6_TOGGLE: - case SPECIAL_LAYER7_TOGGLE: - case SPECIAL_LAYER8_TOGGLE: - Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE); - 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 - - - // Shortcut for clicks of Menu buttons. - // Disable all of them when an operation is in progress - if (Operation_stack_size==0) - { - // Some functions open windows that clear the Key variable, - // so we need to use a temporary replacement. - key_pressed = Key; - for (button_index=0;button_index=Menu_Y) || - ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) && - (Mouse_XHover_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(); - } - } - else - { - if ( (prev_button_number!=BUTTON_CHOOSE_COL) - || (temp_color!=First_color_in_palette) - || (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) ) - { - // Le curseur est sur un nouveau bouton - 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 - { // Le curseur est-il sur une couleur de la palette? - int color; - if ((color=Pick_color_in_palette())!=-1) - { - Hide_cursor(); - Status_print_palette_color(color); - Display_cursor(); - } - else - { - if ( (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) ) - { - Hide_cursor(); - 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,8*Menu_factor_Y); - Display_cursor(); - } - } - } - } - } - } - - prev_button_number=button_index; - - // Gestion des clicks - if (Mouse_K) - { - if (Mouse_Y>=Menu_Y) - { - if (button_index>=0) - { - Select_button(button_index,Mouse_K); - prev_button_number=-1; - } - } - else - if (Main_magnifier_mode) Move_separator(); - } - - } - - // we need to refresh that one as we may come from a sub window - Cursor_in_menu=(Mouse_Y>=Menu_Y) || - ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) && - (Mouse_XHover_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) - { - Cursor_in_menu_previous = 1; - } - else - { - blink=Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Hide_cursor; - - if (blink) Hide_cursor(); - - Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Action(); - - if (blink) Display_cursor(); - } - Old_MX=Mouse_X; - Old_MY=Mouse_Y; - } - while (!Quitting); -} - - - - - -////////////////////////////////////////////////////////////////////////////// -// différentes fonctions d'affichage utilisées dans les fenêtres // -////////////////////////////////////////////////////////////////////////////// - -//----------------------- Tracer une fenêtre d'options ----------------------- - -void Open_window(word width,word height, const char * title) -// Lors de l'appel à cette procédure, la souris doit être affichée. -// En sortie de cette procedure, la souris est effacée. -{ - //word i,j; - 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; - Window_height=height; - - // Positionnement de la fenêtre - 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_Window); - - // -- Frame de la fenêtre ----- --- -- - - - - // Frame noir puis en relief - Window_display_frame_mono(0,0,width,height,MC_Black); - Window_display_frame_out(1,1,width-2,height-2); - - // Barre sous le titre - Block(Window_pos_X+(Menu_factor_X<<3),Window_pos_Y+(11*Menu_factor_Y),(width-16)*Menu_factor_X,Menu_factor_Y,MC_Dark); - Block(Window_pos_X+(Menu_factor_X<<3),Window_pos_Y+(12*Menu_factor_Y),(width-16)*Menu_factor_X,Menu_factor_Y,MC_White); - - title_length = strlen(title); - if (title_length+2 > width/8) - title_length = width/8-2; - Print_in_window_limited((width-(title_length<<3))>>1,3,title,title_length,MC_Black,MC_Light); - - if (Windows_open == 1) - { - Menu_is_visible_before_window=Menu_is_visible; - Menu_is_visible=0; - Menu_Y_before_window=Menu_Y; - Menu_Y=Screen_height; - Cursor_shape_before_window=Cursor_shape; - 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 - Window_normal_button_list =NULL; - Window_palette_button_list =NULL; - Window_scroller_button_list=NULL; - Window_special_button_list =NULL; - Window_dropdown_button_list=NULL; - Window_nb_buttons =0; - -} - -//----------------------- Fermer une fenêtre d'options ----------------------- - -void Close_window(void) -// Lors de l'appel à cette procedure, la souris doit être affichée. -// En sortie de cette procedure, la souris est effacée. -{ - T_Normal_button * temp1; - T_Palette_button * temp2; - T_Scroller_button * temp3; - T_Special_button * temp4; - T_Dropdown_button * temp5; - T_List_button * temp6; - - Hide_cursor(); - - while (Window_normal_button_list) - { - temp1=Window_normal_button_list->Next; - free(Window_normal_button_list); - Window_normal_button_list=temp1; - } - while (Window_palette_button_list) - { - temp2=Window_palette_button_list->Next; - free(Window_palette_button_list); - Window_palette_button_list=temp2; - } - while (Window_scroller_button_list) - { - temp3=Window_scroller_button_list->Next; - free(Window_scroller_button_list); - Window_scroller_button_list=temp3; - } - while (Window_special_button_list) - { - temp4=Window_special_button_list->Next; - free(Window_special_button_list); - Window_special_button_list=temp4; - } - while (Window_dropdown_button_list) - { - temp5=Window_dropdown_button_list->Next; - Window_dropdown_clear_items(Window_dropdown_button_list); - free(Window_dropdown_button_list); - Window_dropdown_button_list=temp5; - } - while (Window_list_button_list) - { - temp6=Window_list_button_list->Next; - free(Window_list_button_list); - Window_list_button_list=temp6; - } - - if (Windows_open != 1) - { - // Restore de ce que la fenêtre cachait - Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); - Window_background[Windows_open-1]=NULL; - Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y); - Windows_open--; - } - else - { - free(Window_background[Windows_open-1]); - Window_background[Windows_open-1]=NULL; - Windows_open--; - - Paintbrush_hidden=Paintbrush_hidden_before_window; - - Compute_paintbrush_coordinates(); - - Menu_Y=Menu_Y_before_window; - Menu_is_visible=Menu_is_visible_before_window; - Cursor_shape=Cursor_shape_before_window; - - Display_all_screen(); - Display_menu(); - Allow_colorcycling=1; - Allow_drag_and_drop(1); - } - - Key=0; - Mouse_K=0; - - Old_MX = -1; - Old_MY = -1; - -} - - -//---------------- Dessiner un bouton normal dans une fenêtre ---------------- - -void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, - const char * title,byte undersc_letter,byte clickable) -{ - byte title_color; - word text_x_pos,text_y_pos; - - if (clickable) - { - Window_display_frame_out(x_pos,y_pos,width,height); - Window_display_frame_generic(x_pos-1,y_pos-1,width+2,height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark); - title_color=MC_Black; - } - else - { - Window_display_frame_out(x_pos,y_pos,width,height); - Window_display_frame_mono(x_pos-1,y_pos-1,width+2,height+2,MC_Light); - title_color=MC_Dark; - } - - text_x_pos=x_pos+( (width-(strlen(title)<<3)+1) >>1 ); - text_y_pos=y_pos+((height-7)>>1); - Print_in_window(text_x_pos,text_y_pos,title,title_color,MC_Light); - - if (undersc_letter) - Block(Window_pos_X+((text_x_pos+((undersc_letter-1)<<3))*Menu_factor_X), - Window_pos_Y+((text_y_pos+8)*Menu_factor_Y), - Menu_factor_X<<3,Menu_factor_Y,MC_Dark); -} - - -// -- Button normal enfoncé dans la fenêtre -- -void Window_select_normal_button(word x_pos,word y_pos,word width,word height) -{ - Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_Black,MC_Dark,MC_Dark,MC_Black); - Update_rect(Window_pos_X+x_pos*Menu_factor_X, Window_pos_Y+y_pos*Menu_factor_Y, width*Menu_factor_X, height*Menu_factor_Y); -} - -// -- Button normal désenfoncé dans la fenêtre -- -void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height) -{ - Window_display_frame_out(x_pos,y_pos,width,height); - Update_rect(Window_pos_X+x_pos*Menu_factor_X, Window_pos_Y+y_pos*Menu_factor_Y, width*Menu_factor_X, height*Menu_factor_Y); -} - - -//--------------- Dessiner un bouton palette dans une fenêtre ---------------- -void Window_draw_palette_bouton(word x_pos,word y_pos) -{ - word color; - - for (color=0; color<=255; color++) - Block( Window_pos_X+((((color >> 4)*10)+x_pos+6)*Menu_factor_X),Window_pos_Y+((((color & 15)*5)+y_pos+3)*Menu_factor_Y),Menu_factor_X*5,Menu_factor_Y*5,color); - - Window_display_frame(x_pos,y_pos,164,86); -} - - -// -------------------- Effacer les TAGs sur les palette --------------------- -// Cette fonct° ne sert plus que lorsqu'on efface les tags dans le menu Spray. -void Window_clear_tags(void) -{ - word origin_x; - word origin_y; - word x_pos; - word window_x_pos; - //word window_y_pos; - - origin_x=Window_pos_X+(Window_palette_button_list->Pos_X+3)*Menu_factor_X; - origin_y=Window_pos_Y+(Window_palette_button_list->Pos_Y+3)*Menu_factor_Y; - for (x_pos=0,window_x_pos=origin_x;x_pos<16;x_pos++,window_x_pos+=(Menu_factor_X*10)) - Block(window_x_pos,origin_y,Menu_factor_X*3,Menu_factor_Y*80,MC_Light); - Update_rect(origin_x,origin_y,ToWinL(160),ToWinH(80)); -} - - -// ---- Tracer les TAGs sur les palettes du menu Palette ou du menu Shade ---- -void Tag_color_range(byte start,byte end) -{ - word origin_x; - word origin_y; - //word x_pos; - word y_pos; - //word window_x_pos; - word window_y_pos; - word index; - - // On efface les anciens TAGs - for (index=0;index<=start;index++) - 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++) - 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; - origin_y=(Window_palette_button_list->Pos_Y+3)+(start&15)* 5; - for (y_pos=0,window_y_pos=origin_y ;y_pos<5;y_pos++,window_y_pos++) - Pixel_in_window(origin_x ,window_y_pos,MC_Black); - for (y_pos=0,window_y_pos=origin_y+1;y_pos<3;y_pos++,window_y_pos++) - Pixel_in_window(origin_x+1,window_y_pos,MC_Black); - Pixel_in_window(origin_x+2,origin_y+2,MC_Black); - - if (start!=end) - { - // On complète le 1er TAG - Pixel_in_window(origin_x+1,origin_y+4,MC_Black); - - // On affiche le 2ème TAG - origin_x=(Window_palette_button_list->Pos_X+3)+(end>>4)*10; - origin_y=(Window_palette_button_list->Pos_Y+3)+(end&15)* 5; - for (y_pos=0,window_y_pos=origin_y; y_pos<5; y_pos++,window_y_pos++) - Pixel_in_window(origin_x ,window_y_pos,MC_Black); - for (y_pos=0,window_y_pos=origin_y; y_pos<4; y_pos++,window_y_pos++) - Pixel_in_window(origin_x+1,window_y_pos,MC_Black); - Pixel_in_window(origin_x+2,origin_y+2,MC_Black); - - // On TAG toutes les couleurs intermédiaires - for (index=start+1;indexPos_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), - MC_Light); - } - - - } - - 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_length(T_Scroller_button * button) -{ - if (button->Nb_elements>button->Nb_visibles) - { - button->Cursor_length=(button->Nb_visibles*(button->Length-24))/button->Nb_elements; - if (!(button->Cursor_length)) - button->Cursor_length=1; - } - else - { - button->Cursor_length=button->Length-24; - } -} - -void Window_draw_slider(T_Scroller_button * button) -{ - word slider_position; - - 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_button(T_Scroller_button * button) -{ - 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); -} - - -//--------------- Dessiner une zone de saisie dans une fenêtre --------------- - -void Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters) -{ - Window_display_frame_in(x_pos,y_pos,(width_in_characters<<3)+3,11); -} - - -//------------ Modifier le contenu (caption) d'une zone de saisie ------------ - -void Window_input_content(T_Special_button * button, char * content) -{ - Print_in_window_limited(button->Pos_X+2,button->Pos_Y+2,content,button->Width/8,MC_Black,MC_Light); -} - -//------------ Effacer le contenu (caption) d'une zone de saisie ------------ - -void Window_clear_input_button(T_Special_button * button) -{ - Block((button->Pos_X+2)*Menu_factor_X+Window_pos_X,(button->Pos_Y+2)*Menu_factor_Y+Window_pos_Y,(button->Width/8)*8*Menu_factor_X,8*Menu_factor_Y,MC_Light); - Update_rect((button->Pos_X+2)*Menu_factor_X+Window_pos_X,(button->Pos_Y+2)*Menu_factor_Y+Window_pos_Y,button->Width/8*8*Menu_factor_X,8*Menu_factor_Y); -} - - -//------ Rajout d'un bouton à la liste de ceux présents dans la fenêtre ------ - -T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, - word width, word height, - const char * title, byte undersc_letter, - byte clickable, word shortcut) -{ - T_Normal_button * temp=NULL; - - Window_nb_buttons++; - - if (clickable) - { - temp=(T_Normal_button *)malloc(sizeof(T_Normal_button)); - temp->Number =Window_nb_buttons; - temp->Pos_X =x_pos; - temp->Pos_Y =y_pos; - temp->Width =width; - temp->Height =height; - temp->Clickable=clickable; - temp->Shortcut =shortcut; - temp->Repeatable=0; - - temp->Next=Window_normal_button_list; - Window_normal_button_list=temp; - } - - Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable); - return temp; -} -//------ Rajout d'un bouton à la liste de ceux présents dans la fenêtre ------ - -T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, - word width, word height, - const char * title, byte undersc_letter, - byte clickable, word shortcut) -{ - T_Normal_button * temp=NULL; - - Window_nb_buttons++; - - if (clickable) - { - temp=(T_Normal_button *)malloc(sizeof(T_Normal_button)); - temp->Number =Window_nb_buttons; - temp->Pos_X =x_pos; - temp->Pos_Y =y_pos; - temp->Width =width; - temp->Height =height; - temp->Shortcut=shortcut; - temp->Repeatable=1; - - temp->Next=Window_normal_button_list; - Window_normal_button_list=temp; - } - - Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable); - return temp; -} - -T_Palette_button * Window_set_palette_button(word x_pos, word y_pos) -{ - T_Palette_button * temp; - - temp=(T_Palette_button *)malloc(sizeof(T_Palette_button)); - temp->Number =++Window_nb_buttons; - temp->Pos_X =x_pos; - temp->Pos_Y =y_pos; - - temp->Next=Window_palette_button_list; - Window_palette_button_list=temp; - - Window_draw_palette_bouton(x_pos,y_pos); - return temp; -} - - -T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, - word height, - word nb_elements, - word nb_elements_visible, - word initial_position) -{ - T_Scroller_button * temp; - - 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->Length =height; - 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_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) -{ - T_Special_button * temp; - - temp=(T_Special_button *)malloc(sizeof(T_Special_button)); - temp->Number =++Window_nb_buttons; - temp->Pos_X =x_pos; - temp->Pos_Y =y_pos; - temp->Width =width; - temp->Height =height; - - temp->Next=Window_special_button_list; - Window_special_button_list=temp; - return temp; -} - - -T_Special_button * Window_set_input_button(word x_pos,word y_pos,word width_in_characters) -{ - T_Special_button *temp; - temp=Window_set_special_button(x_pos,y_pos,(width_in_characters<<3)+3,11); - Window_draw_input_bouton(x_pos,y_pos,width_in_characters); - return temp; -} - -T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width,word height,word dropdown_width,const char *label,byte display_choice,byte display_centered,byte display_arrow,byte active_button, byte bottom_up) -{ - T_Dropdown_button *temp; - - temp=(T_Dropdown_button *)malloc(sizeof(T_Dropdown_button)); - temp->Number =++Window_nb_buttons; - temp->Pos_X =x_pos; - temp->Pos_Y =y_pos; - temp->Width =width; - temp->Height =height; - temp->Display_choice =display_choice; - temp->First_item=NULL; - temp->Dropdown_width=dropdown_width?dropdown_width:width; - temp->Display_centered=display_centered; - temp->Display_arrow=display_arrow; - temp->Active_button=active_button; - temp->Bottom_up=bottom_up; - - temp->Next=Window_dropdown_button_list; - Window_dropdown_button_list=temp; - Window_draw_normal_bouton(x_pos,y_pos,width,height,"",-1,1); - if (label && label[0]) - Print_in_window(temp->Pos_X+2,temp->Pos_Y+(temp->Height-7)/2,label,MC_Black,MC_Light); - if (display_arrow) - Window_display_icon_sprite(temp->Pos_X+temp->Width-10,temp->Pos_Y+(temp->Height-7)/2,ICON_DROPDOWN); - - return temp; -} - -// Ajoute un choix à une dropdown. Le libellé est seulement référencé, -// il doit pointer sur une zone qui doit être encore valide à la fermeture -// de la fenêtre (comprise). -void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label) -{ - T_Dropdown_choice *temp; - T_Dropdown_choice *last; - - temp=(T_Dropdown_choice *)malloc(sizeof(T_Dropdown_choice)); - temp->Number =btn_number; - temp->Label=label; - temp->Next=NULL; - - last=dropdown->First_item; - if (last) - { - // On cherche le dernier élément - for (;last->Next;last=last->Next) - ; - last->Next=temp; - } - else - { - dropdown->First_item=temp; - } -} - -// ------------- Suppression de tous les choix d'une dropdown --------- -void Window_dropdown_clear_items(T_Dropdown_button * dropdown) -{ - T_Dropdown_choice * next_choice; - while (dropdown->First_item) - { - next_choice=dropdown->First_item->Next; - free(dropdown->First_item); - dropdown->First_item=next_choice; - } -} - -//----------------------- Create a List control ----------------------- -// These controls are special. They work over two controls previously created: -// - entry_button is the textual area where the list values will be printed. -// - scroller is a scroller button attached to it - -T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item, byte color_index) -{ - T_List_button *temp; - - temp=(T_List_button *)malloc(sizeof(T_List_button)); - temp->Number =++Window_nb_buttons; - temp->List_start = 0; - temp->Cursor_position = 0; - temp->Entry_button = entry_button; - temp->Scroller = scroller; - temp->Draw_list_item = draw_list_item; - temp->Color_index = color_index; - - temp->Next=Window_list_button_list; - Window_list_button_list=temp; - return temp; -} - -void Window_redraw_list(T_List_button * list) -{ - int i; - - for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--) - { - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + i * 8, - list->List_start + i, - i == list->Cursor_position); - } - // Remaining rectangle under list - i=list->Scroller->Nb_visibles-list->Scroller->Nb_elements; - if (i>0) - { - byte color; - color = list->Color_index == 0 ? MC_Black : - (list->Color_index == 1 ? MC_Dark : - (list->Color_index == 2 ? MC_Light : MC_White)); - - Window_rectangle( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y+list->Scroller->Nb_elements*8, - list->Entry_button->Width, - i*8, - color); - } -} - -//----------------------- Ouverture d'un pop-up ----------------------- - -void Open_popup(word x_pos, word y_pos, word width,word height) -// Lors de l'appel à cette procédure, la souris doit être affichée. -// En sortie de cette procedure, la souris est effacée. - -// Note : les pop-ups sont gérés comme s'ils étaient des sous-fenêtres, ils ont donc leur propre boucle d'évènements et tout, on peut ajouter des widgets dedans, ... -// Les différences sont surtout graphiques : - // -Possibilité de préciser la position XY - // -Pas de titre - // -Pas de cadre en relief mais seulement un plat, et il est blanc au lieu de noir. -{ - Windows_open++; - - Window_width=width; - 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); - -/* - // Fenêtre grise - Block(Window_pos_X+1*Menu_factor_X, - Window_pos_Y+1*Menu_factor_Y, - (width-2)*Menu_factor_X,(height-2)*Menu_factor_Y,MC_Light); - - // Frame noir puis en relief - Window_display_frame_mono(0,0,width,height,MC_White); -*/ - if (Windows_open == 1) - { - Menu_is_visible_before_window=Menu_is_visible; - Menu_is_visible=0; - Menu_Y_before_window=Menu_Y; - Menu_Y=Screen_height; - Cursor_shape_before_window=Cursor_shape; - Cursor_shape=CURSOR_SHAPE_ARROW; - Paintbrush_hidden_before_window=Paintbrush_hidden; - Paintbrush_hidden=1; - } - - // Initialisation des listes de boutons de la fenêtre - Window_normal_button_list =NULL; - Window_palette_button_list =NULL; - Window_scroller_button_list=NULL; - Window_special_button_list =NULL; - Window_dropdown_button_list =NULL; - Window_nb_buttons =0; - -} - -//----------------------- Fermer une fenêtre d'options ----------------------- - -void Close_popup(void) -// Lors de l'appel à cette procedure, la souris doit être affichée. -// En sortie de cette procedure, la souris est effacée. -{ - T_Normal_button * temp1; - T_Palette_button * temp2; - T_Scroller_button * temp3; - T_Special_button * temp4; - T_Dropdown_button * temp5; - T_List_button * temp6; - - Hide_cursor(); - - while (Window_normal_button_list) - { - temp1=Window_normal_button_list->Next; - free(Window_normal_button_list); - Window_normal_button_list=temp1; - } - while (Window_palette_button_list) - { - temp2=Window_palette_button_list->Next; - free(Window_palette_button_list); - Window_palette_button_list=temp2; - } - while (Window_scroller_button_list) - { - temp3=Window_scroller_button_list->Next; - free(Window_scroller_button_list); - Window_scroller_button_list=temp3; - } - while (Window_special_button_list) - { - temp4=Window_special_button_list->Next; - free(Window_special_button_list); - Window_special_button_list=temp4; - } - while (Window_dropdown_button_list) - { - Window_dropdown_clear_items(Window_dropdown_button_list); - temp5=Window_dropdown_button_list->Next; - free(Window_dropdown_button_list); - Window_dropdown_button_list=temp5; - } - while (Window_list_button_list) - { - temp6=Window_list_button_list->Next; - free(Window_list_button_list); - Window_list_button_list=temp6; - } - - if (Windows_open != 1) - { - // Restore de ce que la fenêtre cachait - Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); - Window_background[Windows_open-1]=NULL; - Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y); - Windows_open--; - } - else - { - free(Window_background[Windows_open-1]); - Window_background[Windows_open-1] = NULL; - Windows_open--; - - Paintbrush_hidden=Paintbrush_hidden_before_window; - - Compute_paintbrush_coordinates(); - - Menu_Y=Menu_Y_before_window; - Menu_is_visible=Menu_is_visible_before_window; - Cursor_shape=Cursor_shape_before_window; - - Display_all_screen(); - Display_menu(); - } - - Key=0; - Mouse_K=0; - - Old_MX = -1; - Old_MY = -1; - - -} -////////////////////////////////////////////////////////////////////////////// -// // -// Mini-MOTEUR utilisé dans les fenêtres (menus des boutons...) // -// // -////////////////////////////////////////////////////////////////////////////// - - -// -- Indique si on a cliqué dans une zone définie par deux points extremes -- -byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y) -{ - short x_pos,y_pos; - - x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X; - y_pos=((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y; - - return ((x_pos>=start_x) && - (y_pos>=start_y) && - (x_pos<=end_x) && - (y_pos<=end_y)); -} - - -// --- Attend que l'on clique dans la palette pour renvoyer la couleur choisie -// ou bien renvoie -1 si on a annulé l'action pas click-droit ou Escape ------ -short Wait_click_in_palette(T_Palette_button * button) -{ - short start_x=button->Pos_X+5; - short start_y=button->Pos_Y+3; - short end_x =button->Pos_X+160; - short end_y =button->Pos_Y+82; - byte selected_color; - byte old_hide_cursor; - byte old_main_magnifier_mode; - - Hide_cursor(); - old_hide_cursor=Cursor_hidden; - old_main_magnifier_mode=Main_magnifier_mode; - Main_magnifier_mode=0; - Cursor_hidden=0; - Cursor_shape=CURSOR_SHAPE_TARGET; - Display_cursor(); - - for (;;) - { - while (Get_input(20)) - ; - - if (Mouse_K==LEFT_SIDE) - { - if (Window_click_in_rectangle(start_x,start_y,end_x,end_y)) - { - Hide_cursor(); - selected_color=(((Mouse_X-Window_pos_X)/Menu_factor_X)-(button->Pos_X+2)) / 10 * 16 + - (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(button->Pos_Y+3)) / 5; - Cursor_shape=CURSOR_SHAPE_ARROW; - Cursor_hidden=old_hide_cursor; - Main_magnifier_mode=old_main_magnifier_mode; - Display_cursor(); - return selected_color; - } - if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) || - (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) ) - { - Hide_cursor(); - selected_color=Read_pixel(Mouse_X,Mouse_Y); - Cursor_shape=CURSOR_SHAPE_ARROW; - Cursor_hidden=old_hide_cursor; - Main_magnifier_mode=old_main_magnifier_mode; - Display_cursor(); - return selected_color; - } - } - - if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC)) - { - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_ARROW; - Cursor_hidden=old_hide_cursor; - Main_magnifier_mode=old_main_magnifier_mode; - Display_cursor(); - return -1; - } - } -} - - - -// -------------- Récupération d'une couleur derrière un menu ---------------- -void Get_color_behind_window(byte * color, byte * click) -{ - short old_x=-1; - short old_y=-1; - short index; - short a,b,c,d; // Variables temporaires et multitâches... - byte * buffer = NULL; - char str[25]; - byte cursor_was_hidden; - - - Hide_cursor(); - - cursor_was_hidden=Cursor_hidden; - Cursor_hidden=0; - - Save_background(&buffer,Window_pos_X,Window_pos_Y,Window_width,Window_height); - a=Menu_Y; - Menu_Y=Menu_Y_before_window; - b=Menu_is_visible; - Menu_is_visible=Menu_is_visible_before_window; - Display_all_screen(); - Display_menu(); - Menu_Y=a; - Menu_is_visible=b; - - Cursor_shape=CURSOR_SHAPE_COLORPICKER; - b=Paintbrush_hidden; - Paintbrush_hidden=1; - c=-1; // color pointée: au début aucune, comme ça on initialise tout - if (Menu_is_visible_before_window) - Print_in_menu(Menu_tooltip[BUTTON_CHOOSE_COL],0); - - Display_cursor(); - - do - { - Get_input(20); - - if ((Mouse_X!=old_x) || (Mouse_Y!=old_y)) - { - Hide_cursor(); - a=Read_pixel(Mouse_X,Mouse_Y); - if (a!=c) - { - c=a; // Mise à jour de la couleur pointée - if (Menu_is_visible_before_window) - { - sprintf(str,"%d",a); - d=strlen(str); - strcat(str," ("); - sprintf(str+strlen(str),"%d",Main_palette[a].R); - strcat(str,","); - sprintf(str+strlen(str),"%d",Main_palette[a].G); - strcat(str,","); - sprintf(str+strlen(str),"%d",Main_palette[a].B); - strcat(str,")"); - a=24-d; - for (index=strlen(str); indexScreen_width-width) - { - new_x=Screen_width-width; - dx = Mouse_X - new_x; - } - - new_y=Mouse_Y-dy; - - if (new_y<0) - { - new_y=0; - dy = Mouse_Y; - } - if (new_y>Screen_height-height) - { - new_y=Screen_height-height; - dy = Mouse_Y - new_y; - } - - if ((new_x!=old_x) || (new_y!=old_y)) - { - Hide_cursor(); - - Horizontal_XOR_line(old_x,old_y,width); - Vertical_XOR_line(old_x,old_y+1,height-2); - Vertical_XOR_line(old_x+width-1,old_y+1,height-2); - Horizontal_XOR_line(old_x,old_y+height-1,width); - - Horizontal_XOR_line(new_x,new_y,width); - Vertical_XOR_line(new_x,new_y+1,height-2); - Vertical_XOR_line(new_x+width-1,new_y+1,height-2); - Horizontal_XOR_line(new_x,new_y+height-1,width); - - Display_cursor(); - Update_rect(old_x,old_y,width,height); - Update_rect(new_x,new_y,width,height); - } - } - - Hide_cursor(); - Horizontal_XOR_line(new_x,new_y,width); - Vertical_XOR_line(new_x,new_y+1,height-2); - Vertical_XOR_line(new_x+width-1,new_y+1,height-2); - Horizontal_XOR_line(new_x,new_y+height-1,width); - - if ((new_x!=Window_pos_X) - || (new_y!=Window_pos_Y)) - { - a=Menu_Y; - Menu_Y=Menu_Y_before_window; - b=Menu_is_visible; - Menu_is_visible=Menu_is_visible_before_window; - //Display_all_screen(); - //Display_menu(); - Menu_Y=a; - Menu_is_visible=b; - - // Sauvegarde du contenu actuel de la fenêtre - Save_background(&buffer, Window_pos_X, Window_pos_Y, Window_width, Window_height); - - // Restore de ce que la fenêtre cachait - Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height); - Window_background[Windows_open-1] = NULL; - - // Sauvegarde de ce que la fenêtre remplace - Save_background(&(Window_background[Windows_open-1]), new_x, new_y, Window_width, Window_height); - - // Raffichage de la fenêtre - Restore_background(buffer, new_x, new_y, Window_width, Window_height); - buffer = NULL; - - // Mise à jour du rectangle englobant - Update_rect( - (new_x>Window_pos_X)?Window_pos_X:new_x, - (new_y>Window_pos_Y)?Window_pos_Y:new_y, - ((new_x>Window_pos_X)?(new_x-Window_pos_X):(Window_pos_X-new_x)) + Window_width*Menu_factor_X, - ((new_y>Window_pos_Y)?(new_y-Window_pos_Y):(Window_pos_Y-new_y)) + Window_height*Menu_factor_Y); - Window_pos_X=new_x; - Window_pos_Y=new_y; - - } - else - { - // Update pour effacer le rectangle XOR - Update_rect(Window_pos_X, Window_pos_Y, Window_width*Menu_factor_X, Window_height*Menu_factor_Y); - } - Cursor_shape=CURSOR_SHAPE_ARROW; - Display_cursor(); - -} - -/// -/// Displays a dropped-down menu and handles the UI logic until the user -/// releases a mouse button. -/// This function then clears the dropdown and returns the selected item, -/// or NULL if the user wasn't highlighting an item when he closed. -T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, short off_y) -{ - short nb_choices; - short choice_index; - short selected_index; - short old_selected_index; - short box_height; - T_Dropdown_choice *item; - - // Taille de l'ombre portée (en plus des dimensions normales) - #define SHADOW_RIGHT 3 - #define SHADOW_BOTTOM 4 - - - // Comptage des items pour calculer la taille - nb_choices=0; - for (item=button->First_item; item!=NULL; item=item->Next) - { - nb_choices++; - } - box_height=3+nb_choices*8+1; - - // Open a new stacked "window" to serve as drawing area. - Open_popup( - off_x+(button->Pos_X)*Menu_factor_X, - off_y+(button->Pos_Y+(button->Bottom_up?-box_height:button->Height))*Menu_factor_Y, - button->Dropdown_width+SHADOW_RIGHT, - box_height+SHADOW_BOTTOM); - - // Dessin de la boite - - // Bord gauche - Block(Window_pos_X,Window_pos_Y,Menu_factor_X,box_height*Menu_factor_Y,MC_Black); - // Frame fonce et blanc - Window_display_frame_out(1,0,button->Dropdown_width-1,box_height); - // Ombre portée - if (SHADOW_BOTTOM) - { - Block(Window_pos_X+SHADOW_RIGHT*Menu_factor_X, - Window_pos_Y+box_height*Menu_factor_Y, - button->Dropdown_width*Menu_factor_X, - SHADOW_BOTTOM*Menu_factor_Y, - MC_Black); - Block(Window_pos_X, - Window_pos_Y+box_height*Menu_factor_Y, - SHADOW_RIGHT*Menu_factor_X, - Menu_factor_Y, - MC_Black); - } - if (SHADOW_RIGHT) - { - Block(Window_pos_X+button->Dropdown_width*Menu_factor_X, - Window_pos_Y+SHADOW_BOTTOM*Menu_factor_Y, - SHADOW_RIGHT*Menu_factor_X, - (box_height-SHADOW_BOTTOM)*Menu_factor_Y, - MC_Black); - Block(Window_pos_X+button->Dropdown_width*Menu_factor_X, - Window_pos_Y, - Menu_factor_X, - SHADOW_BOTTOM*Menu_factor_Y, - MC_Black); - } - - selected_index=-1; - while (1) - { - old_selected_index = selected_index; - // Fenêtre grise - Block(Window_pos_X+2*Menu_factor_X, - Window_pos_Y+1*Menu_factor_Y, - (button->Dropdown_width-3)*Menu_factor_X,(box_height-2)*Menu_factor_Y,MC_Light); - // Affichage des items - for(item=button->First_item,choice_index=0; item!=NULL; item=item->Next,choice_index++) - { - byte color_1; - byte color_2; - if (choice_index==selected_index) - { - color_1=MC_White; - color_2=MC_Dark; - Block(Window_pos_X+3*Menu_factor_X, - Window_pos_Y+((2+choice_index*8)*Menu_factor_Y), - (button->Dropdown_width-5)*Menu_factor_X,(8)*Menu_factor_Y,MC_Dark); - } - else - { - color_1=MC_Black; - color_2=MC_Light; - } - Print_in_window(3,2+choice_index*8,item->Label,color_1,color_2); - } - Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y); - Display_cursor(); - - do - { - // Attente - 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; - - } while (Mouse_K && selected_index==old_selected_index); - - if (!Mouse_K) - break; - Hide_cursor(); - } - - Close_popup(); - - if (selected_index>=0 && selected_indexFirst_item; selected_index; item=item->Next,selected_index--) - ; - return item; - } - return NULL; -} - -// Gestion des dropdown -short Window_dropdown_on_click(T_Dropdown_button *button) -{ - T_Dropdown_choice * item; - - // Highlight the button - Hide_cursor(); - Window_select_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height); - - // Handle the dropdown's logic - item = Dropdown_activate(button, Window_pos_X, Window_pos_Y); - - // Unhighlight the button - Window_unselect_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height); - Display_cursor(); - - if (item == NULL) - { - Window_attribute2=-1; - return 0; - } - - if (button->Display_choice) - { - // Automatically update the label of the dropdown list. - int text_length = (button->Width-4-(button->Display_arrow?8:0))/8; - // Clear original label area - Window_rectangle(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,text_length*8,8,MC_Light); - Print_in_window_limited(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,item->Label,text_length ,MC_Black,MC_Light); - } - - Window_attribute2=item->Number; - return button->Number; - -} - -// --- Fonction de clic sur un bouton a peu près ordinaire: -// Attend que l'on relache le bouton, et renvoie le numero du bouton si on -// est resté dessus, 0 si on a annulé en sortant du bouton. -short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number) -{ - while(1) - { - Hide_cursor(); - Window_select_normal_button(x_pos,y_pos,width,height); - Display_cursor(); - while (Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1)) - { - Get_input(20); - if (!Mouse_K) - { - Hide_cursor(); - Window_unselect_normal_button(x_pos,y_pos,width,height); - Display_cursor(); - return btn_number; - } - } - Hide_cursor(); - Window_unselect_normal_button(x_pos,y_pos,width,height); - Display_cursor(); - while (!(Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1))) - { - Get_input(20); - if (!Mouse_K) - return 0; - } - } -} - -// --- Returns the number of the clicked button (-1:out of the window, 0:none) --- -short Window_get_clicked_button(void) -{ - T_Normal_button * temp1; - T_Palette_button * temp2; - T_Scroller_button * temp3; - T_Special_button * temp4; - T_Dropdown_button * temp5; - - Window_attribute1=Mouse_K; - - // Test click on normal buttons - for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next) - { - if ((Input_sticky_control == 0 || Input_sticky_control == temp1->Number) - && Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1)) - { - Input_sticky_control = temp1->Number; - if (temp1->Repeatable) - { - Hide_cursor(); - Window_select_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height); - Display_cursor(); - 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(); - return temp1->Number; - } - return Window_normal_button_onclick(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height,temp1->Number); - } - } - - // Test click on "Palette" buttons - for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next) - { - if ((Input_sticky_control == 0 || Input_sticky_control == temp2->Number) - && Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82)) - { - Input_sticky_control = temp2->Number; - // We store the clicked color in Attribute2 - Window_attribute2 = (((Mouse_X-Window_pos_X)/Menu_factor_X)-(temp2->Pos_X+2)) / 10 * 16 + - (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(temp2->Pos_Y+3)) / 5; - return temp2->Number; - } - } - - // Test click on slider/scroller bars - for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next) - { - // Button Up arrow - if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|1024)) - && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10)) - { - Input_sticky_control = temp3->Number | 1024; - Hide_cursor(); - Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11); - - if (temp3->Position) - { - temp3->Position--; - Window_attribute1=1; - Window_attribute2=temp3->Position; - Window_draw_slider(temp3); - } - else - Window_attribute1=0; - - Display_cursor(); - - 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); - Display_cursor(); - - return (Window_attribute1)? temp3->Number : 0; - } - - // Button Down arrow - if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|2048)) - && ((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(); - 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++; - Window_attribute1=2; - Window_attribute2=temp3->Position; - Window_draw_slider(temp3); - } - else - Window_attribute1=0; - - Display_cursor(); - - Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider); - - Hide_cursor(); - 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 && - ((!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: - long mouse_pos; - long origin; - - // Window_attribute2 receives the position of the cursor. - 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 if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements) - Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles; - - // If the cursor moved - - if (temp3->Position!=Window_attribute2) - { - temp3->Position=Window_attribute2; - Window_attribute1=3; - Hide_cursor(); - Window_draw_slider(temp3); - Display_cursor(); - } - else - // If the cursor moved - Window_attribute1=0; - } - else - // If there's not enough room to make the cursor move: - Window_attribute1=0; - - return (Window_attribute1)? temp3->Number : 0; - } - } - - // Test click on a special button - for (temp4=Window_special_button_list; temp4; temp4=temp4->Next) - { - if ((Input_sticky_control == 0 || Input_sticky_control == temp4->Number) - && Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1)) - { - Input_sticky_control = temp4->Number; - return temp4->Number; - } - } - - // Test click on a dropdown box - for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next) - { - if ((Input_sticky_control == 0 || Input_sticky_control == temp5->Number) - && Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1)) - { - Input_sticky_control = temp5->Number; - if (Mouse_K & temp5->Active_button) - return Window_dropdown_on_click(temp5); - else - { - Window_attribute2=-1; - return Window_normal_button_onclick(temp5->Pos_X,temp5->Pos_Y,temp5->Width,temp5->Height,temp5->Number); - } - } - } - - return 0; -} - - -short Window_get_button_shortcut(void) -{ - T_Normal_button * temp; - - if (Key & MOD_SHIFT) - Window_attribute1=RIGHT_SIDE; - else - Window_attribute1=LEFT_SIDE; - - // On fait une première recherche - temp=Window_normal_button_list; - while (temp!=NULL) - { - if (temp->Shortcut==Key) - { - Hide_cursor(); - Window_select_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height); - Display_cursor(); - - 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); - Display_cursor(); - - return temp->Number; - } - temp=temp->Next; - } - - // Si la recherche n'a pas été fructueuse ET que l'utilisateur appuyait sur - // , on regarde si un bouton ne pourrait pas réagir comme si - // n'était pas appuyé. - if (Window_attribute1==RIGHT_SIDE) - { - temp=Window_normal_button_list; - while (temp!=NULL) - { - if (temp->Shortcut==(Key&0x0FFF)) - return temp->Number; - temp=temp->Next; - } - } - - // Handle arrow keys, end/home, and mouse wheel that have - // a certain behavior if a list control is present. - if (Window_list_button_list) - { - T_List_button *list = Window_list_button_list; - // If there's more than one of such control, only capture - // events if the mouse cursor is over it. - if (list->Next) - { - // to do - } - - - - - - - } - return 0; -} - -short Window_clicked_button(void) -{ - short Button; - byte old_mouse_k; - - old_mouse_k=Mouse_K; - Get_input(20); - // Handle clicks - if (Mouse_K) - { - if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) - || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y))) - { - if (Input_sticky_control == 0 || Input_sticky_control == -1) - { - Input_sticky_control = -1; - return -1; - } - else - { - return 0; - } - } - - 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); - } - else - { - short clicked_button; - T_List_button * list; - static Uint32 time_last_click = 0; - static int last_list_number = -1; - Uint32 time_now; - - // Check which controls was clicked (by rectangular area) - clicked_button = Window_get_clicked_button(); - - // Check if it's part of a list control - for (list=Window_list_button_list; list!=NULL; list=list->Next) - { - if (list->Entry_button->Number == clicked_button) - { - // Click in the textual part of a list. - short clicked_line; - clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3; - if (clicked_line >= list->Scroller->Nb_elements) // Below last line - return 0; - time_now = SDL_GetTicks(); - if (clicked_line == list->Cursor_position) - { - // Double click check - if (old_mouse_k==0 && last_list_number==list->Number && time_now - time_last_click < Config.Double_click_speed) - { - time_last_click = time_now; - Input_sticky_control=0; - // Store the selected value as attribute2 - Window_attribute2=list->List_start + list->Cursor_position; - // Return the control ID of the "special button" that covers the list. - return list->Entry_button->Number; - } - time_last_click = time_now; - last_list_number=list->Number; - // Already selected : don't activate anything - return 0; - } - - Hide_cursor(); - // Redraw one item as disabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 0); - list->Cursor_position = clicked_line; - // Redraw one item as enabled - if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles) - list->Draw_list_item( - list->Entry_button->Pos_X, - list->Entry_button->Pos_Y + list->Cursor_position * 8, - list->List_start + list->Cursor_position, - 1); - Display_cursor(); - - // Store the selected value as attribute2 - Window_attribute2=list->List_start + list->Cursor_position; - // Return the control ID of the list. - return list->Number; - } - else if (list->Scroller->Number == clicked_button) - { - // Click in the scroller part of a list - if (list->List_start == list->Scroller->Position) - return 0; // Didn't actually move - // Update scroller indices - list->Cursor_position += list->List_start; - list->List_start = list->Scroller->Position; - list->Cursor_position -= list->List_start; - // Need to redraw all - Hide_cursor(); - Window_redraw_list(list); - Display_cursor(); - } - } - return clicked_button; - } - } - - // Intercept keys - if (Key) - { - T_List_button * list; - - Button=Window_get_button_shortcut(); - if (Button) - { - Key=0; - return Button; - } - // Check if there's a list control and the keys can control it - for (list=Window_list_button_list; list!=NULL; list=list->Next) - { - // FIXME: Make only one list have the keyboard focus. - if (1) - { - if (Key==SDLK_UP && (list->Cursor_position+list->List_start)>0) - { - Key=0; - Hide_cursor(); - list->Cursor_position--; - if (list->Cursor_position<0) - { - list->List_start=list->List_start+list->Cursor_position; - list->Cursor_position=0; - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - } - Window_redraw_list(list); - 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; - } - if (Key==SDLK_DOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) - { - Key=0; - Hide_cursor(); - list->Cursor_position++; - if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) - { - list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); - list->Cursor_position=(list->Scroller->Nb_visibles-1); - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - } - Window_redraw_list(list); - 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; - } - if (Key==SDLK_HOME && (list->Cursor_position!=0 || list->List_start!=0)) - { - Key=0; - Hide_cursor(); - list->Cursor_position=0; - list->List_start=0; - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - Window_redraw_list(list); - 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; - } - if (Key==SDLK_END && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) - { - Key=0; - Hide_cursor(); - list->Cursor_position=(list->Scroller->Nb_elements-1)-list->List_start; - if (list->Cursor_position>(list->Scroller->Nb_visibles-1)) - { - list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1); - list->Cursor_position=(list->Scroller->Nb_visibles-1); - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - } - Window_redraw_list(list); - 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; - } - if (Key==SDLK_PAGEDOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1)) - { - Key=0; - Hide_cursor(); - if (list->Scroller->Nb_elementsScroller->Nb_visibles) - { - list->Cursor_position=list->Scroller->Nb_elements-1; - } - else if(list->Cursor_position!=list->Scroller->Nb_visibles-1) - { - list->Cursor_position=list->Scroller->Nb_visibles-1; - } - else - { - list->List_start+=list->Scroller->Nb_visibles; - if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) - { - list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; - } - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - } - Window_redraw_list(list); - 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; - } - if (Key==SDLK_PAGEUP && (list->Cursor_position+list->List_start)>0) - { - Key=0; - Hide_cursor(); - if(list->Cursor_position!=0) - { - list->Cursor_position=0; - } - else - { - list->List_start-=list->Scroller->Nb_visibles; - if (list->List_start<0) - { - list->List_start=0; - } - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - } - Window_redraw_list(list); - 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; - } - if (Key == KEY_MOUSEWHEELUP && list->List_start>0) - { - list->Cursor_position+=list->List_start; - if (list->List_start>=3) - list->List_start-=3; - else - list->List_start=0; - list->Cursor_position-=list->List_start; - // On affiche à nouveau la liste - Hide_cursor(); - Window_redraw_list(list); - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - Display_cursor(); - } - if (Key==KEY_MOUSEWHEELDOWN && list->List_startScroller->Nb_elements-list->Scroller->Nb_visibles) - { - list->Cursor_position+=list->List_start; - list->List_start+=3; - if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements) - { - list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles; - } - list->Cursor_position-=list->List_start; - // On affiche à nouveau la liste - Hide_cursor(); - Window_redraw_list(list); - // Mise à jour du scroller - list->Scroller->Position=list->List_start; - Window_draw_slider(list->Scroller); - Display_cursor(); - } - - } - } - } - - return 0; -} - - -// Fonction qui sert à remapper les parties sauvegardées derriere les -// fenetres ouvertes. C'est utilisé par exemple par la fenetre de palette -// Qui remappe des couleurs, afin de propager les changements. -void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y) -{ - int window_index; - byte* EDI; - int dx,cx; - - for (window_index=0; window_indexMax_Y) - return; - if (dx+Window_stack[window_index].Pos_Y0;cx--) - { - *EDI = conversion_table[*EDI]; - EDI ++; - } - } - } -} - -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() -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file engine.h -/// Utility functions for the menu and all windows. -////////////////////////////////////////////////////////////////////////////// - -#ifndef __ENGINE_H__ -#define __ENGINE_H__ - -#include "struct.h" - -void Main_handler (void); -void Draw_menu_button (byte btn_number,byte pressed); -void Unselect_button (int btn_number); -void Select_button (int btn_number,byte click); -void Open_window (word width,word height, const char * title); -void Close_window (void); - -void Open_popup (word x_pos, word y_pos, word width, word height); -void Close_popup (void); - -void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height, - const char * title,byte undersc_letter,byte clickable); -void Window_select_normal_button(word x_pos,word y_pos,word width,word height); -void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height); -void Window_draw_palette_bouton(word x_pos,word y_pos); - -void Compute_slider_cursor_length(T_Scroller_button * button); -void Window_draw_slider(T_Scroller_button * button); -void Window_draw_scroller_button(T_Scroller_button * button); - -void Window_input_content(T_Special_button * button, char * content); -void Window_clear_input_button(T_Special_button * button); -void Window_draw_input_bouton(word x_pos, word y_pos, word width_in_characters); - -T_Normal_button * Window_set_normal_button(word x_pos, word y_pos, - word width, word height, const char * title, byte undersc_letter, - byte clickable, word shortcut); - -T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos, - word width, word height, const char * title, byte undersc_letter, - byte clickable, word shortcut); - -T_Palette_button * Window_set_palette_button(word x_pos, word y_pos); -void Window_clear_tags(void); -void Tag_color_range(byte start, byte end); - -T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos, - word height, word nb_elements, word nb_elements_visible, - word initial_position); - -T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos, - word height, word nb_elements, word nb_elements_visible, - word initial_position); - -T_Special_button * Window_set_special_button(word x_pos, word y_pos, word width, - word height); - -T_Special_button * Window_set_input_button(word x_pos, word y_pos, - word width_in_characters); - -T_Dropdown_button * Window_set_dropdown_button(word x_pos, word y_pos, - word width, word height, word dropdown_width, const char *label, - byte display_choice, byte display_centered, byte display_arrow, - byte active_button,byte bottom_up); - -/// Adds an item to a dropdown menu -void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, - const char *label); - -void Window_dropdown_clear_items(T_Dropdown_button * dropdown); - -/// -/// Displays a dropped-down menu and handles the UI logic until the user -/// releases a mouse button. -/// This function then clears the dropdown and returns the selected item, -/// or NULL if the user wasn't highlighting an item when he closed. -T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, short off_y); - -T_List_button * Window_set_list_button(T_Special_button * entry_button, - T_Scroller_button * scroller, Func_draw_list_item draw_list_item, byte color_index); -void Window_redraw_list(T_List_button * list); -byte Window_click_in_rectangle(short start_x, short start_y, short end_x, - short end_y); -short Wait_click_in_palette(T_Palette_button * button); -short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number); -void Get_color_behind_window(byte * color, byte * click); - -short Window_clicked_button(void); -int Button_under_mouse(void); -short Window_get_clicked_button(void); -void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y); -void Pixel_background(int x_pos, int y_pos, byte color); -/// -/// Updates the status bar line with a color number. -/// Used when hovering the menu palette. -void Status_print_palette_color(byte color); - -/// Puts the user in wait mode for the specified time ( in 1/100s), -/// though the mouse still works. -void Delay_with_active_mouse(int delay); - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/errors.h b/project/jni/application/grafx2/grafx2/src/errors.h deleted file mode 100644 index b9dd23c92..000000000 --- a/project/jni/application/grafx2/grafx2/src/errors.h +++ /dev/null @@ -1,54 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Adrien Destugues - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file errors.h -/// Functions and macros for tracing and error reporting. -////////////////////////////////////////////////////////////////////////////// - -#ifdef __VBCC__ - #define __func__ "stupid compiler !" -#endif - -/// Prints the source filename, line number, function name, a string and an integer. -#define DEBUG(y,z) printf("%s %d %s | %s : %d###\n",__FILE__,__LINE__,__func__,y,(unsigned int)z) - -/// Same as ::DEBUG but in hexadecimal -#define DEBUGX(y,z) printf("%s %d %s | %s : %X###\n",__FILE__,__LINE__,__func__,y,(unsigned int)z) - -/// Helper function used by the macro ::Error -void Error_function(int error_code, const char *filename, int line_number, const char *function_name); - -/// -/// Report a run-time error: It will print to standard output some information -/// about the calling function, and then: -/// - If the error code is 0, just do a red screen flash and resume. -/// - If the error code is non-zero, abort the program. -#define Error(n) Error_function(n, __FILE__,__LINE__,__func__) - -/// Helper function used by the macro ::Warning -void Warning_function(const char *message, const char *filename, int line_number, const char *function_name); - -/// -/// Report a run-time abnormal condition : It will print to standard output -/// some information about the calling function, and then resume silently. -/// This is most useful in debugger so you can put a breakpoint on -/// ::Warning_function and examine the stack trace. -#define Warning(msg) Warning_function(msg, __FILE__,__LINE__,__func__) diff --git a/project/jni/application/grafx2/grafx2/src/factory.c b/project/jni/application/grafx2/grafx2/src/factory.c deleted file mode 100644 index 03fe76748..000000000 --- a/project/jni/application/grafx2/grafx2/src/factory.c +++ /dev/null @@ -1,1882 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 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 factory.c - * \brief Brush factory - generates brush from lua scripts - * - * The brush factory allows you to generate brushes with Lua code. - */ - -#include - -#include "brush.h" -#include "buttons.h" -#include "engine.h" -#include "errors.h" -#include "filesel.h" // Get_item_by_index -#include "global.h" -#include "graph.h" -#include "io.h" // find_last_slash -#include "misc.h" -#include "pages.h" // Backup() -#include "readline.h" -#include "sdlscreen.h" -#include "windows.h" -#include "palette.h" -#include "input.h" // Is_shortcut() -#include "help.h" // Window_help() -#include "graph.h" -#include "filesel.h" // Read_list_of_drives() -#include "realpath.h" - - -/// Lua scripts bound to shortcut keys. -char * Bound_script[10]; - -#ifdef __ENABLE_LUA__ - -#include -#include -#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 - -// Work data that can be used during a script -static byte * Brush_backup = NULL; -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) -{ - if (value<0.0) - return 0; - else if (value>255.0) - return 255; - else return (byte)value; -} - -/// -/// This macro reads a Lua argument into a double or integral lvalue. -/// 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. -/// @param dest Destination lvalue. Can be a double, or any integral type. Conversion will "floor". -/// @param min_value Check for minimum value. Pass a double, or if you don't care, -DBL_MAX. -/// @param max_value Check for maximum value. Pass a double, or if you don't care, DBL_MAX. -#define LUA_ARG_NUMBER(index, func_name, dest, min_value, max_value) \ -do { \ - double value; \ - if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, (index)); \ - if (!lua_isnumber(L, (index))) return luaL_error(L, "%s: Argument %d is not a number.", func_name, (index)); \ - value = lua_tonumber(L, (index)); \ - if ((min_value) != -DBL_MAX && value<(min_value)) return luaL_error(L, "%s: Argument %d was too small, it had value of %f and minimum should be %f.", func_name, (index), value, (double)(min_value)); \ - if ((max_value) != DBL_MAX && value>(max_value)) return luaL_error(L, "%s: Argument %d was too big, it had value of %f and maximum should be %f.", func_name, (index), value, (double)(max_value)); \ - dest = value; \ -} while(0) - -/// -/// This macro reads a Lua argument into a string. -/// 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. -/// @param dest Destination string pointer, ideally a const char *. -#define LUA_ARG_STRING(index, func_name, dest) \ -do { \ - if (nb_args < (index)) return luaL_error(L, "%s: Argument %d is missing.", func_name, index); \ - if (!lua_isstring(L, (index))) return luaL_error(L, "%s: Argument %d is not a string.", func_name, index); \ - 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 { \ - if (nb_args != (num)) \ - 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; - } -} - -/// Paint a pixel in image without updating the screen -void Pixel_figure_no_screen(short x_pos,short y_pos,byte color) -{ - if (x_pos>0 && y_pos >0 && x_pos>1); - Brush_offset_Y=(Brush_height>>1); - return 0; -} - -int L_GetBrushSize(lua_State* L) -{ - lua_pushinteger(L, Brush_width); - lua_pushinteger(L, Brush_height); - return 2; -} - -int L_GetBrushTransparentColor(lua_State* L) -{ - lua_pushinteger(L, Back_color); - return 1; -} - -int L_PutBrushPixel(lua_State* L) -{ - int x; - int y; - uint8_t c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (3, "putbrushpixel"); - LUA_ARG_NUMBER(1, "putbrushpixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "putbrushpixel", y, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(3, "putbrushpixel", c, INT_MIN, INT_MAX); - - 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) - ; - else - { - Pixel_in_brush(x, y, c); - } - return 0; // no values returned for lua -} - -int L_GetBrushPixel(lua_State* L) -{ - int x; - int y; - uint8_t c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (2, "getbrushpixel"); - LUA_ARG_NUMBER(1, "getbrushpixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "getbrushpixel", y, INT_MIN, INT_MAX); - - if (x<0 || y<0 || x>=Brush_width || y>=Brush_height) - { - c = Back_color; // Return 'transparent' - } - else - { - c = Read_pixel_from_brush(x, y); - } - lua_pushinteger(L, c); - return 1; -} - -int L_GetBrushBackupPixel(lua_State* L) -{ - int x; - int y; - uint8_t c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (2, "getbrushbackuppixel"); - LUA_ARG_NUMBER(1, "getbrushbackuppixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "getbrushbackuppixel", y, INT_MIN, INT_MAX); - - if (x<0 || y<0 || x>=Brush_backup_width || y>=Brush_backup_height) - { - c = Back_color; // Return 'transparent' - } - else - { - c = *(Brush_backup + y * Brush_backup_width + x); - } - lua_pushinteger(L, c); - return 1; -} - -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); - - 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; -} - -int L_GetPictureSize(lua_State* L) -{ - lua_pushinteger(L, Main_image_width); - lua_pushinteger(L, Main_image_height); - return 2; -} - -int L_ClearPicture(lua_State* L) -{ - int c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (1, "clearpicture"); - LUA_ARG_NUMBER(1, "clearpicture", c, INT_MIN, INT_MAX); - - if (Stencil_mode && Config.Clear_with_stencil) - Clear_current_image_with_stencil(c,Stencil); - else - Clear_current_image(c); - Redraw_layered_image(); - - return 0; // no values returned for lua -} - -int L_PutPicturePixel(lua_State* L) -{ - int x; - int y; - int c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (3, "putpicturepixel"); - LUA_ARG_NUMBER(1, "putpicturepixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "putpicturepixel", y, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(3, "putpicturepixel", c, INT_MIN, INT_MAX); - - // Bound check - if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) - { - // Silently ignored - return 0; - } - Pixel_in_current_screen(x, y, c, 0); - return 0; // no values returned for lua -} - - -int L_DrawLine(lua_State* L) -{ - int x1, y1, x2, y2, c; - - int nb_args = lua_gettop(L); - - LUA_ARG_LIMIT(5, "drawline"); - LUA_ARG_NUMBER(1, "drawline", x1, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "drawline", y1, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(3, "drawline", x2, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(4, "drawline", y2, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(5, "drawline", c, INT_MIN, INT_MAX); - - Pixel_figure = (void (*) (word,word,byte))Pixel_figure_no_screen; - Draw_line_general(x1, y1, x2, y2, c); - - return 0; -} - - -int L_DrawFilledRect(lua_State* L) -{ - int x1, y1, x2, y2, c; - int min_x,min_y,max_x,max_y, x_pos, y_pos; - - int nb_args = lua_gettop(L); - - LUA_ARG_LIMIT(5, "drawfilledrect"); - LUA_ARG_NUMBER(1, "drawfilledrect", x1, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "drawfilledrect", y1, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(3, "drawfilledrect", x2, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(4, "drawfilledrect", y2, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(5, "drawfilledrect", c, INT_MIN, INT_MAX); - - // Put bounds in ascending order - if (x2>x1) - { - min_x=x1; - max_x=x2; - } - else - { - min_x=x2; - max_x=x1; - } - if (y2>y1) - { - min_y=y1; - max_y=y2; - } - else - { - min_y=y2; - max_y=y1; - } - - // Clipping limits - if (max_x>Main_image_width) - max_x=Main_image_width-1; - if (max_y>Main_image_height) - max_y=Main_image_height-1; - if (min_x<0) - min_x=0; - if (min_y<0) - min_y=0; - - // Perform drawing - for (y_pos=min_y; y_pos<=max_y;y_pos++) - for (x_pos=min_x; x_pos<=max_x;x_pos++) - Pixel_in_current_screen(x_pos,y_pos,c,0); - return 0; - -} - - -int L_DrawCircle(lua_State* L) -{ - int x1, y1, r, c; - - int nb_args = lua_gettop(L); - - LUA_ARG_LIMIT(4, "drawcircle"); - LUA_ARG_NUMBER(1, "drawcircle", x1, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "drawcircle", y1, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(3, "drawcircle", r, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(4, "drawcircle", c, INT_MIN, INT_MAX); - - Pixel_figure = (void (*) (word,word,byte))Pixel_figure_no_screen; - Circle_limit = r*r; - Draw_empty_circle_general(x1, y1, r, c); - - return 0; -} - - -int L_DrawDisk(lua_State* L) -{ - int center_x, center_y, r, c; - long circle_limit; - short x_pos,y_pos; - short min_x,max_x,min_y,max_y; - - int nb_args = lua_gettop(L); - - LUA_ARG_LIMIT(4, "drawdisk"); - LUA_ARG_NUMBER(1, "drawdisk", center_x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "drawdisk", center_y, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(3, "drawdisk", r, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(4, "drawdisk", c, INT_MIN, INT_MAX); - - circle_limit = r*r; - - // Compute clipping limits - min_x=center_x-r<0 ? 0 : center_x-r; - max_x=center_x+r>=Main_image_width? Main_image_width-1 : center_x+r; - min_y=center_y-r<0 ? 0 : center_y-r; - max_y=center_y+r>=Main_image_height? Main_image_height-1 : center_y+r; - - for (y_pos=min_y;y_pos<=max_y;y_pos++) - for (x_pos=min_x;x_pos<=max_x;x_pos++) - Pixel_in_current_screen(x_pos,y_pos,c,0); - - return 0; -} - - -int L_GetPicturePixel(lua_State* L) -{ - int x; - int y; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (2, "getpicturepixel"); - LUA_ARG_NUMBER(1, "getpicturepixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "getpicturepixel", y, INT_MIN, INT_MAX); - - // Bound check - if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) - { - // Silently return the image's transparent color - lua_pushinteger(L, Main_backups->Pages->Transparent_color); - return 1; - } - lua_pushinteger(L, Read_pixel_from_current_screen(x,y)); - return 1; -} - -int L_GetBackupPixel(lua_State* L) -{ - int x; - int y; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (2, "getbackuppixel"); - LUA_ARG_NUMBER(1, "getbackuppixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "getbackuppixel", y, INT_MIN, INT_MAX); - - // Bound check - 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->Next->Transparent_color); - return 1; - } - // 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; -} - -int L_GetLayerPixel(lua_State* L) -{ - int x; - int y; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (2, "getlayerpixel"); - LUA_ARG_NUMBER(1, "getlayerpixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "getlayerpixel", y, INT_MIN, INT_MAX); - - // Bound check - if (x<0 || y<0 || x>=Main_image_width || y>=Main_image_height) - { - // Silently return the image's transparent color - lua_pushinteger(L, Main_backups->Pages->Transparent_color); - return 1; - } - lua_pushinteger(L, Read_pixel_from_current_layer(x,y)); - return 1; -} - -// Spare - -int L_GetSparePictureSize(lua_State* L) -{ - lua_pushinteger(L, Spare_image_width); - lua_pushinteger(L, Spare_image_height); - return 2; -} - -int L_GetSpareLayerPixel(lua_State* L) -{ - int x; - int y; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (2, "getsparelayerpixel"); - LUA_ARG_NUMBER(1, "getsparelayerpixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "getsparelayerpixel", y, INT_MIN, INT_MAX); - - // Bound check - if (x<0 || y<0 || x>=Spare_image_width || y>=Spare_image_height) - { - // Silently return the image's transparent color - lua_pushinteger(L, Spare_backups->Pages->Transparent_color); - return 1; - } - lua_pushinteger(L, *(Spare_backups->Pages->Image[Spare_current_layer] + y*Spare_image_width + x)); - return 1; -} - -int L_GetSparePicturePixel(lua_State* L) -{ - int x; - int y; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (2, "getsparepicturepixel"); - LUA_ARG_NUMBER(1, "getsparepicturepixel", x, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "getsparepicturepixel", y, INT_MIN, INT_MAX); - - // Some bound checking is done by the function itself, here's the rest. - if (x<0 || y<0) - { - // Silently return the image's transparent color - lua_pushinteger(L, Spare_backups->Pages->Transparent_color); - return 1; - } - lua_pushinteger(L, Read_pixel_from_spare_screen(x,y)); - return 1; -} - -int L_GetSpareColor(lua_State* L) -{ - byte c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (1, "getsparecolor"); - LUA_ARG_NUMBER(1, "getsparecolor", c, INT_MIN, INT_MAX); - - lua_pushinteger(L, Spare_palette[c].R); - lua_pushinteger(L, Spare_palette[c].G); - lua_pushinteger(L, Spare_palette[c].B); - return 3; -} - -int L_GetSpareTransColor(lua_State* L) -{ - lua_pushinteger(L, Spare_backups->Pages->Transparent_color); - return 1; -} - - - -int L_SetColor(lua_State* L) -{ - byte c; - double r, g, b; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (4, "setcolor"); - LUA_ARG_NUMBER(1, "setcolor", c, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(2, "setcolor", r, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(3, "setcolor", g, INT_MIN, INT_MAX); - LUA_ARG_NUMBER(4, "setcolor", b, INT_MIN, INT_MAX); - - - Main_palette[c].R=Round_palette_component(clamp_byte(r)); - Main_palette[c].G=Round_palette_component(clamp_byte(g)); - Main_palette[c].B=Round_palette_component(clamp_byte(b)); - // Set_color(c, r, g, b); Not needed. Update screen when script is finished - Palette_has_changed=1; - return 0; -} - -int L_GetColor(lua_State* L) -{ - byte c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (1, "getcolor"); - LUA_ARG_NUMBER(1, "getcolor", c, INT_MIN, INT_MAX); - - lua_pushinteger(L, Main_palette[c].R); - lua_pushinteger(L, Main_palette[c].G); - lua_pushinteger(L, Main_palette[c].B); - return 3; -} - -int L_GetBackupColor(lua_State* L) -{ - byte c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (1, "getbackupcolor"); - LUA_ARG_NUMBER(1, "getbackupcolor", c, INT_MIN, INT_MAX); - - lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].R); - lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].G); - lua_pushinteger(L, Main_backups->Pages->Next->Palette[c].B); - return 3; -} - -int L_MatchColor(lua_State* L) -{ - double r, g, b; - int c; - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (3, "matchcolor"); - LUA_ARG_NUMBER(1, "matchcolor", r, -DBL_MAX, DBL_MAX); - LUA_ARG_NUMBER(2, "matchcolor", g, -DBL_MAX, DBL_MAX); - LUA_ARG_NUMBER(3, "matchcolor", b, -DBL_MAX, DBL_MAX); - - c = Best_color_nonexcluded(clamp_byte(r),clamp_byte(g),clamp_byte(b)); - lua_pushinteger(L, c); - return 1; -} - -int L_GetForeColor(lua_State* L) -{ - lua_pushinteger(L, Fore_color); - return 1; -} - -int L_GetBackColor(lua_State* L) -{ - lua_pushinteger(L, Back_color); - return 1; -} - -int L_GetTransColor(lua_State* L) -{ - lua_pushinteger(L, Main_backups->Pages->Transparent_color); - 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; - const int args_per_setting = 5; - double min_value[max_settings]; - double max_value[max_settings]; - double decimal_places[max_settings]; - double current_value[max_settings]; - const char * label[max_settings]; - unsigned short control[max_settings*3+1]; // Each value has at most 3 widgets. - enum CONTROL_TYPE { - CONTROL_OK = 0x0100, - CONTROL_CANCEL = 0x0200, - CONTROL_INPUT = 0x0300, - CONTROL_INPUT_MINUS = 0x0400, - CONTROL_INPUT_PLUS = 0x0500, - CONTROL_CHECKBOX = 0x0600, - CONTROL_VALUE_MASK = 0x00FF, - CONTROL_TYPE_MASK = 0xFF00 - }; - const char * window_caption; - int caption_length; - int nb_settings; - int nb_args; - unsigned int max_label_length; - int setting; - short clicked_button; - char str[40]; - short close_window = 0; - - nb_args = lua_gettop (L); - - - if (nb_args < 6) - { - return luaL_error(L, "inputbox: Less than 6 arguments"); - } - if ((nb_args - 1) % args_per_setting) - { - return luaL_error(L, "inputbox: Wrong number of arguments"); - } - nb_settings = (nb_args-1)/args_per_setting; - if (nb_settings > max_settings) - { - return luaL_error(L, "inputbox: Too many settings, limit reached"); - } - - max_label_length=4; // Minimum size to account for OK / Cancel buttons - - // First argument is window caption - LUA_ARG_STRING(1, "inputbox", window_caption); - caption_length = strlen(window_caption); - if ( caption_length > 14) - max_label_length = caption_length - 10; - - for (setting=0; setting max_label_length) - max_label_length = strlen(label[setting]); - - LUA_ARG_NUMBER(setting*args_per_setting+3, "inputbox", current_value[setting], -DBL_MAX, DBL_MAX); - LUA_ARG_NUMBER(setting*args_per_setting+4, "inputbox", min_value[setting], -DBL_MAX, DBL_MAX); - /*if (min_value[setting] < -999999999999999.0) - min_value[setting] = -999999999999999.0;*/ - LUA_ARG_NUMBER(setting*args_per_setting+5, "inputbox", max_value[setting], -DBL_MAX, DBL_MAX); - /*if (max_value[setting] > 999999999999999.0) - max_value[setting] = 999999999999999.0;*/ - 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 || max_value[setting]!=1) - if (decimal_places[setting]<0) - decimal_places[setting]=0; - // Keep current value in range - if (decimal_places[setting]>=0) - current_value[setting] = Fround(current_value[setting], decimal_places[setting]); - - if (current_value[setting] < min_value[setting]) - current_value[setting] = min_value[setting]; - else if (current_value[setting] > max_value[setting]) - current_value[setting] = max_value[setting]; - } - // 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(115+max_label_length*8,44+nb_settings*17,window_caption); - - // Normally this index is unused, but this initialization avoids - // any weird behavior if it was used by mistake. - control[0]=0; - - // OK - Window_set_normal_button( 7, 25 + 17 * nb_settings, 51,14,"OK" , 0,1,SDLK_RETURN); - control[Window_nb_buttons] = CONTROL_OK; - - // Cancel - Window_set_normal_button( 64, 25 + 17 * nb_settings, 51,14,"Cancel" , 0,1,KEY_ESC); - control[Window_nb_buttons] = CONTROL_CANCEL; - - for (setting=0; setting0) - { - setting = control[clicked_button] & (CONTROL_VALUE_MASK); - - switch (control[clicked_button] & CONTROL_TYPE_MASK) - { - case CONTROL_OK: - close_window = CONTROL_OK; - break; - - case CONTROL_CANCEL: - close_window = CONTROL_CANCEL; - break; - - 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,INPUT_TYPE_DECIMAL,decimal_places[setting]); - current_value[setting]=atof(str); - - if (current_value[setting] < min_value[setting]) - current_value[setting] = min_value[setting]; - else if (current_value[setting] > max_value[setting]) - current_value[setting] = max_value[setting]; - // Print editable value - Sprint_double(str,current_value[setting],decimal_places[setting],7); - Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); - // - Display_cursor(); - - break; - - case CONTROL_INPUT_MINUS: - if (current_value[setting] > min_value[setting]) - { - current_value[setting]--; - if (current_value[setting] < min_value[setting]) - current_value[setting] = min_value[setting]; - - Hide_cursor(); - // Print editable value - Sprint_double(str,current_value[setting],decimal_places[setting],7); - Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); - // - Display_cursor(); - } - break; - - case CONTROL_INPUT_PLUS: - if (current_value[setting] < max_value[setting]) - { - current_value[setting]++; - if (current_value[setting] > max_value[setting]) - current_value[setting] = max_value[setting]; - - Hide_cursor(); - // Print editable value - Sprint_double(str,current_value[setting],decimal_places[setting],7); - Print_in_window_limited(12+max_label_length*8+23, 22+setting*17, str, 7,MC_Black,MC_Light); - // - Display_cursor(); - } - break; - - case CONTROL_CHECKBOX: - if (decimal_places[setting]==0 || current_value[setting]==0.0) - { - current_value[setting] = (current_value[setting]==0.0); - Hide_cursor(); - Print_in_window(12+max_label_length*8+46, 22+setting*17, current_value[setting]?"X":" ",MC_Black,MC_Light); - // Uncheck other buttons of same family - if (decimal_places[setting]<0) - { - byte button; - for (button=3; button<=Window_nb_buttons; button++) - { - if (button != clicked_button && control[button] & CONTROL_CHECKBOX) - { - byte other_setting = control[button] & (CONTROL_VALUE_MASK); - if (decimal_places[other_setting] == decimal_places[setting]) - { - // Same family: unset and uncheck - current_value[other_setting]=0.0; - Print_in_window(12+max_label_length*8+46, 22+other_setting*17, " ",MC_Black,MC_Light); - } - } - } - } - Display_cursor(); - } - break; - } - } - } - - Close_window(); - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - - // Return values: - - // One boolean to tell if user pressed ok or cancel - lua_pushboolean(L, (close_window == CONTROL_OK)); - - // One value per control - for (setting=0; setting 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; button24) - msg2[24] = 0; // Cut off long messages - Print_in_menu(msg2,0); - free(msg2); - return 0; -} - - -int L_FinalizePicture(lua_State* L) -{ - int nb_args=lua_gettop(L); - - LUA_ARG_LIMIT (0, "finalizepicture"); - - Update_colors_during_script(); - End_of_modification(); - Backup(); - - return 0; -} - -// Handlers for window internals -T_Fileselector Scripts_selector; - -// Callback to display a skin name in the list -void Draw_script_name(word x, word y, word index, byte highlighted) -{ - T_Fileselector_item * current_item; - - if (Scripts_selector.Nb_elements) - { - byte fg, bg; - - current_item = Get_item_by_index(&Scripts_selector, index); - - if (current_item->Type==0) // Files - { - fg=(highlighted)?MC_White:MC_Light; - bg=(highlighted)?MC_Dark:MC_Black; - } - else if (current_item->Type==1) // Directories - { - fg=(highlighted)?MC_Light:MC_Dark; - bg=(highlighted)?MC_Dark:MC_Black; - } - else // Drives - { - fg=(highlighted)?MC_Light:MC_Dark; - bg=(highlighted)?MC_Dark:MC_Black; - - Window_display_icon_sprite(x,y,current_item->Icon); - x+=8; - } - - Print_in_window(x, y, current_item->Short_name, fg,bg); - - Update_window_area(x,y,NAME_WIDTH*8,8); - } -} - -/// -/// Displays first lines of comments from a lua script in the window. -void Draw_script_information(T_Fileselector_item * script_item, const char *full_directory) -{ - FILE *script_file; - char text_block[3][DESC_WIDTH+1]; - int x, y; - int i; - - // Blank the target area - Window_rectangle(7, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8, MC_Black); - - if (script_item && script_item->Type==0 && script_item->Full_name && script_item->Full_name[0]!='\0') - { - char full_name[MAX_PATH_CHARACTERS]; - strcpy(full_name, full_directory); - Append_path(full_name, script_item->Full_name, NULL); - - x=0; - y=0; - text_block[0][0] = text_block[1][0] = text_block[2][0] = '\0'; - // Start reading - script_file = fopen(full_name, "r"); - if (script_file != NULL) - { - int c; - c = fgetc(script_file); - while (c != EOF && y<3) - { - if (c == '\n') - { - if (x<2) - break; // Carriage return without comment: Stopping - y++; - x=0; - } - else if (x==0 || x==1) - { - if (c != '-') - break; // Non-comment line was encountered. Stopping. - x++; - } - else - { - if (x < DESC_WIDTH+2) - { - // Adding character - text_block[y][x-2] = (c<32 || c>255) ? ' ' : c; - text_block[y][x-1] = '\0'; - } - x++; - } - // Read next - c = fgetc(script_file); - } - fclose(script_file); - } - - 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], 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(8, FILESEL_Y + 89, DESC_WIDTH*6+2, 4*8); - -} - -// Add a script to the list -void Add_script(const char *name, byte is_file, byte is_directory, byte is_hidden) -{ - 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; - // Ignore parent directory entry - if (!strcmp(file_name, PARENT_DIR)) - 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_file) -{ - short index; - - index=Find_file_in_fileselector(selector, selected_file); - Locate_list_item(list, index); -} - -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 buf[MAX_PATH_CHARACTERS]; - - // Some scripts are slow - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - Flush_update(); - - if (script_subdirectory && script_subdirectory[0]!='\0') - { - strcpy(Last_run_script, script_subdirectory); - Append_path(Last_run_script, script_filename, NULL); - } - else - { - strcpy(Last_run_script, script_filename); - } - - // This chdir is for the script's sake. Grafx2 itself will (try to) - // not rely on what is the system's current directory. - Extract_path(buf,Last_run_script); - chdir(buf); - - L = lua_open(); - - strcpy(buf, "LUA_PATH="); - strcat(buf, Data_directory); - Append_path(buf+9, "scripts", NULL); - Append_path(buf+9, "libs", NULL); - Append_path(buf+9, "?.lua", NULL); - putenv(buf); - - // writing and reading pixels - lua_register(L,"putbrushpixel",L_PutBrushPixel); - lua_register(L,"putpicturepixel",L_PutPicturePixel); - lua_register(L, "drawline",L_DrawLine); - lua_register(L, "drawfilledrect",L_DrawFilledRect); - lua_register(L, "drawcircle",L_DrawCircle); - lua_register(L, "drawdisk",L_DrawDisk); - - lua_register(L,"getbrushpixel",L_GetBrushPixel); - lua_register(L,"getbrushbackuppixel",L_GetBrushBackupPixel); - lua_register(L,"getpicturepixel",L_GetPicturePixel); - lua_register(L,"getlayerpixel",L_GetLayerPixel); - lua_register(L,"getbackuppixel",L_GetBackupPixel); - lua_register(L,"getsparelayerpixel",L_GetSpareLayerPixel); - lua_register(L,"getsparepicturepixel",L_GetSparePicturePixel); - - - // resizing stuff - 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,"getsparepicturesize",L_GetSparePictureSize); - - // color and palette - lua_register(L,"setcolor",L_SetColor); - lua_register(L,"setforecolor",L_SetForeColor); - lua_register(L,"setbackcolor",L_SetBackColor); - - lua_register(L,"getcolor",L_GetColor); - lua_register(L,"getbackupcolor",L_GetBackupColor); - lua_register(L,"getbrushtransparentcolor",L_GetBrushTransparentColor); - lua_register(L,"getsparecolor",L_GetSpareColor); - lua_register(L,"getsparetranscolor",L_GetSpareTransColor); - lua_register(L,"getforecolor",L_GetForeColor); - lua_register(L,"getbackcolor",L_GetBackColor); - lua_register(L,"gettranscolor",L_GetTransColor); - - lua_register(L,"matchcolor",L_MatchColor); - - // ui - lua_register(L,"inputbox",L_InputBox); - lua_register(L,"messagebox",L_MessageBox); - lua_register(L,"statusmessage",L_StatusMessage); - lua_register(L,"selectbox",L_SelectBox); - - // misc. stuff - 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) - { - 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(); - Print_in_menu(" ",0); - - 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, const char *full_directory) -{ - int i; - char full_name[MAX_PATH_CHARACTERS]; - - if (script_item && script_item->Full_name && script_item->Full_name[0]!='\0') - { - strcpy(full_name, full_directory); - Append_path(full_name, script_item->Full_name, NULL); - - // Find if it already has a shortcut - for (i=0; i<10; i++) - if (Bound_script[i]!=NULL && !strcmp(Bound_script[i], full_name)) - break; - if (i<10) - { - // Existing shortcut - } - else - { - // 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(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, full_directory); - Display_cursor(); - } -} - -void Reload_scripts_list(void) -{ - // Reinitialize the list - Free_fileselector_list(&Scripts_selector); - if (Config.Scripts_directory[0]=='\0') - { - Read_list_of_drives(&Scripts_selector,NAME_WIDTH+1); - } - else - { - Add_element_to_list(&Scripts_selector, PARENT_DIR, Format_filename(PARENT_DIR, NAME_WIDTH+1, 1), 1, ICON_NONE); - // Add each found file to the list - For_each_directory_entry(Config.Scripts_directory, Add_script); - } - // Sort it - Sort_list_of_files(&Scripts_selector); - // -} - -void Button_Brush_Factory(void) -{ - static char selected_file[MAX_PATH_CHARACTERS]=""; - - short clicked_button; - T_List_button* scriptlist; - T_Scroller_button* scriptscroll; - T_Special_button* scriptarea; - T_Fileselector_item *item; - int last_selected_item=-1; - - Reload_scripts_list(); - - 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 - // Fileselector - scriptarea=Window_set_special_button(8, FILESEL_Y + 0, 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, 0); // 4 - - Window_set_normal_button(10, 149, 67, 14, "Run", 0, 1, SDLK_RETURN); // 5 - - 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 - - while (1) - { - // 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); - - Window_redraw_list(scriptlist); - Draw_script_information(Get_item_by_index(&Scripts_selector, - scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); - - Update_window_area(0, 0, Window_width, Window_height); - Display_cursor(); - // Wait for mouse release (needed for example after a double-click - // that navigates to a subdirectory) - while (last_selected_item==-1 && Mouse_K) - { - Get_input(20); - } - - Reset_quicksearch(); - - do - { - clicked_button = Window_clicked_button(); - if (Key==SDLK_BACKSPACE && Config.Scripts_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 2: // Double-click an entry in script list - clicked_button=5; - break; - case 4: // Select script - last_selected_item = scriptlist->List_start + scriptlist->Cursor_position; - Hide_cursor(); - Draw_script_information(Get_item_by_index(&Scripts_selector, - scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); - Display_cursor(); - break; - - case 6: - Set_script_shortcut(Get_item_by_index(&Scripts_selector, - scriptlist->List_start + scriptlist->Cursor_position), Config.Scripts_directory); - 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, item->Full_name); - break; - } - else if (item->Type==1 || item->Type==2) // Directory - { - if (item->Type==2) - { - // Selecting one drive root - strcpy(selected_file, PARENT_DIR); - strcat(Config.Scripts_directory, item->Full_name); - } - else - { - // Going down one or up by one directory - Append_path(Config.Scripts_directory, item->Full_name, selected_file); - } - - // No break: going back up to beginning of loop - - Reload_scripts_list(); - - scriptlist->Scroller->Nb_elements=Scripts_selector.Nb_elements; - Compute_slider_cursor_length(scriptlist->Scroller); - last_selected_item = -1; - Hide_cursor(); - } - } - - Close_window(); - Unselect_button(BUTTON_BRUSH_EFFECTS); - - if (clicked_button == 5) // Run the script - { - Run_script(Config.Scripts_directory, selected_file); - } - else - { - Display_cursor(); - } -} - -#else // NOLUA -void Button_Brush_Factory(void) -{ - Verbose_message("Error!", "The brush factory is not available in this build of GrafX2."); -} - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/factory.h b/project/jni/application/grafx2/grafx2/src/factory.h deleted file mode 100644 index 3a1a54f5e..000000000 --- a/project/jni/application/grafx2/grafx2/src/factory.h +++ /dev/null @@ -1,13 +0,0 @@ -/* 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/project/jni/application/grafx2/grafx2/src/fileformats.c b/project/jni/application/grafx2/grafx2/src/fileformats.c deleted file mode 100644 index 4f6b1d1b0..000000000 --- a/project/jni/application/grafx2/grafx2/src/fileformats.c +++ /dev/null @@ -1,4091 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -///@file fileformats.c -/// Saving and loading different picture formats. - -#ifndef __no_pnglib__ -#include -#if !defined(PNG_HAVE_PLTE) -#define PNG_HAVE_PLTE 0x02 -#endif -#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 - -#include "errors.h" -#include "global.h" -#include "loadsave.h" -#include "misc.h" -#include "struct.h" -#include "io.h" -#include "windows.h" // Best_color() -#include "pages.h" // Add_layer() - -//////////////////////////////////// IMG //////////////////////////////////// - -// -- Tester si un fichier est au format IMG -------------------------------- -void Test_IMG(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - T_IMG_Header IMG_header; - byte signature[6]={0x01,0x00,0x47,0x12,0x6D,0xB0}; - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=1; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - // Lecture et vérification de la signature - 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,118) - && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) - ) - { - if ( (!memcmp(IMG_header.Filler1,signature,6)) - && IMG_header.Width && IMG_header.Height) - File_error=0; - } - // Fermeture du fichier - fclose(file); - } -} - - -// -- Lire un fichier au format IMG ----------------------------------------- -void Load_IMG(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - byte * buffer; - FILE *file; - word x_pos,y_pos; - long width_read; - long file_size; - T_IMG_Header IMG_header; - - Get_full_filename(filename, context->File_name, context->File_directory); - File_error=0; - - if ((file=fopen(filename, "rb"))) - { - file_size=File_length_file(file); - - 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,118) - && Read_bytes(file,IMG_header.Palette,sizeof(T_Palette)) - ) - { - - buffer=(byte *)malloc(IMG_header.Width); - - Pre_load(context, IMG_header.Width,IMG_header.Height,file_size,FORMAT_IMG,PIXEL_SIMPLE,0); - if (File_error==0) - { - memcpy(context->Palette,IMG_header.Palette,sizeof(T_Palette)); - Palette_loaded(context); - - context->Width=IMG_header.Width; - context->Height=IMG_header.Height; - width_read=IMG_header.Width; - - for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) - { - if (Read_bytes(file,buffer,context->Width)) - { - for (x_pos=0; x_posWidth;x_pos++) - Set_pixel(context, x_pos,y_pos,buffer[x_pos]); - } - else - File_error=2; - } - } - - free(buffer); - buffer = NULL; - } - else - File_error=1; - - fclose(file); - } - else - File_error=1; -} - -// -- Sauver un fichier au format IMG --------------------------------------- -void Save_IMG(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - short x_pos,y_pos; - T_IMG_Header IMG_header; - byte signature[6]={0x01,0x00,0x47,0x12,0x6D,0xB0}; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - memcpy(IMG_header.Filler1,signature,6); - - IMG_header.Width=context->Width; - IMG_header.Height=context->Height; - - memset(IMG_header.Filler2,0,118); - IMG_header.Filler2[4]=0xFF; - IMG_header.Filler2[22]=64; // Lo(Longueur de la signature) - IMG_header.Filler2[23]=0; // Hi(Longueur de la signature) - memcpy(IMG_header.Filler2+23,"GRAFX2 by SunsetDesign (IMG format taken from PV (c)W.Wiedmann)",64); - - memcpy(IMG_header.Palette,context->Palette,sizeof(T_Palette)); - - 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,118) - && Write_bytes(file,IMG_header.Palette,sizeof(T_Palette)) - ) - - { - Init_write_buffer(); - - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - for (x_pos=0; x_posWidth; x_pos++) - Write_one_byte(file,Get_pixel(context, x_pos,y_pos)); - - End_write(file); - fclose(file); - - if (File_error) - remove(filename); - } - else // Error d'écriture (disque plein ou protégé) - { - fclose(file); - remove(filename); - File_error=1; - } - } - else - { - fclose(file); - remove(filename); - File_error=1; - } -} - - -//////////////////////////////////// LBM //////////////////////////////////// -typedef struct -{ - word Width; - word Height; - word X_org; // Inutile - word Y_org; // Inutile - byte BitPlanes; - byte Mask; - byte Compression; - byte Pad1; // Inutile - word Transp_col; - byte X_aspect; // Inutile - byte Y_aspect; // Inutile - word X_screen; - word Y_screen; -} T_LBM_Header; - -byte * LBM_buffer; -FILE *LBM_file; - -// -- Tester si un fichier est au format LBM -------------------------------- - -void Test_LBM(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - char format[4]; - char section[4]; - dword dummy; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((LBM_file=fopen(filename, "rb"))) - { - if (! Read_bytes(LBM_file,section,4)) - File_error=1; - else - if (memcmp(section,"FORM",4)) - File_error=1; - else - { - Read_dword_be(LBM_file, &dummy); - // On aurait pu vérifier que ce long est égal à la taille - // du fichier - 8, mais ça aurait interdit de charger des - // fichiers tronqués (et déjà que c'est chiant de perdre - // une partie du fichier il faut quand même pouvoir en - // garder un peu... Sinon, moi je pleure :'( !!! ) - if (! Read_bytes(LBM_file,format,4)) - File_error=1; - else - if ( (memcmp(format,"ILBM",4)) && (memcmp(format,"PBM ",4)) ) - File_error=1; - } - fclose(LBM_file); - } - else - File_error=1; -} - - -// -- Lire un fichier au format LBM ----------------------------------------- - - byte Image_HAM; - - // ---------------- Adapter la palette pour les images HAM ---------------- - void Adapt_palette_HAM(T_IO_Context * context) - { - short i,j,temp; - byte color; - - if (Image_HAM==6) - { - for (i=1; i<=14; i++) - { - // On recopie a palette de base - memcpy(context->Palette+(i<<4),context->Palette,48); - // On modifie les teintes de cette palette - for (j=0; j<16; j++) - { - color=(i<<4)+j; - if (i<=7) - { - if (i&1) - { - temp=context->Palette[j].R+16; - context->Palette[color].R=(temp<63)?temp:63; - } - if (i&2) - { - temp=context->Palette[j].G+16; - context->Palette[color].G=(temp<63)?temp:63; - } - if (i&4) - { - temp=context->Palette[j].B+16; - context->Palette[color].B=(temp<63)?temp:63; - } - } - else - { - if ((i-7)&1) - { - temp=context->Palette[j].R-16; - context->Palette[color].R=(temp>=0)?temp:0; - } - if ((i-7)&2) - { - temp=context->Palette[j].G-16; - context->Palette[color].G=(temp>=0)?temp:0; - } - if ((i-7)&4) - { - temp=context->Palette[j].B-16; - context->Palette[color].B=(temp>=0)?temp:0; - } - } - } - } - // Ici, il reste les 16 dernières couleurs à modifier - for (i=240,j=0; j<16; i++,j++) - { - temp=context->Palette[j].R+8; - context->Palette[i].R=(temp<63)?temp:63; - temp=context->Palette[j].G+8; - context->Palette[i].G=(temp<63)?temp:63; - temp=context->Palette[j].B+8; - context->Palette[i].B=(temp<63)?temp:63; - } - } - else if (Image_HAM==8) - { - for (i=1; i<=3; i++) - { - // On recopie la palette de base - memcpy(context->Palette+(i<<6),context->Palette,192); - // On modifie les teintes de cette palette - for (j=0; j<64; j++) - { - color=(i<<6)+j; - switch (i) - { - case 1 : - temp=context->Palette[j].R+16; - context->Palette[color].R=(temp<63)?temp:63; - break; - case 2 : - temp=context->Palette[j].G+16; - context->Palette[color].G=(temp<63)?temp:63; - break; - default: - temp=context->Palette[j].B+16; - context->Palette[color].B=(temp<63)?temp:63; - } - } - } - } - else // Image 64 couleurs sauvée en 32. - { - for (i=0; i<32; i++) - { - j=i+32; - context->Palette[j].R=context->Palette[i].R>>1; - context->Palette[j].G=context->Palette[i].G>>1; - context->Palette[j].B=context->Palette[i].B>>1; - } - } - } - -// 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; - } - return 1; -} - -// Les images ILBM sont stockés en bitplanes donc on doit trifouiller les bits pour -// en faire du chunky - -byte Color_ILBM_line(word x_pos, word real_line_size, byte HBPm1) -{ - // Renvoie la couleur du pixel (ILBM) en x_pos. - // CL sera le rang auquel on extrait les bits de la couleur - byte cl = 7 - (x_pos & 7); - int ax,bh,dx; - byte bl=0; - - for(dx=HBPm1;dx>=0;dx--) - { - //CIL_Loop - ax = (real_line_size * dx + x_pos) >> 3; - bh = (LBM_buffer[ax] >> cl) & 1; - - bl = (bl << 1) + bh; - } - - return bl; -} - -byte HBPm1; // header.BitPlanes-1 - - // ----------------------- Afficher une ligne ILBM ------------------------ - void Draw_ILBM_line(T_IO_Context *context, short y_pos, short real_line_size) - { - byte color; - byte red,green,blue; - byte temp; - short x_pos; - - if (Image_HAM<=1) // ILBM - { - for (x_pos=0; x_posWidth; x_pos++) - { - Set_pixel(context, x_pos,y_pos,Color_ILBM_line(x_pos,real_line_size, HBPm1)); - } - } - else - { - color=0; - red=context->Palette[0].R; - green =context->Palette[0].G; - blue =context->Palette[0].B; - if (Image_HAM==6) - for (x_pos=0; x_posWidth; x_pos++) // HAM6 - { - temp=Color_ILBM_line(x_pos,real_line_size, HBPm1); - switch (temp & 0xF0) - { - case 0x10: // blue - blue=(temp&0x0F)<<2; - color=Best_color(red,green,blue); - break; - case 0x20: // red - red=(temp&0x0F)<<2; - color=Best_color(red,green,blue); - break; - case 0x30: // green - green=(temp&0x0F)<<2; - color=Best_color(red,green,blue); - break; - default: // Nouvelle couleur - color=temp; - red=context->Palette[color].R; - green =context->Palette[color].G; - blue =context->Palette[color].B; - } - Set_pixel(context, x_pos,y_pos,color); - } - else - for (x_pos=0; x_posWidth; x_pos++) // HAM8 - { - temp=Color_ILBM_line(x_pos,real_line_size, HBPm1); - switch (temp & 0x03) - { - case 0x01: // blue - blue=temp>>2; - color=Best_color(red,green,blue); - break; - case 0x02: // red - red=temp>>2; - color=Best_color(red,green,blue); - break; - case 0x03: // green - green=temp>>2; - color=Best_color(red,green,blue); - break; - default: // Nouvelle couleur - color=temp; - red=context->Palette[color].R; - green =context->Palette[color].G; - blue =context->Palette[color].B; - } - Set_pixel(context, x_pos,y_pos,color); - } - } - } - - -void Load_LBM(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - T_LBM_Header header; - char format[4]; - char section[4]; - byte temp_byte; - short b256; - dword nb_colors; - dword section_size; - short x_pos; - short y_pos; - short counter; - short line_size; // Taille d'une ligne en octets - short real_line_size; // Taille d'une ligne en pixels - byte color; - long file_size; - dword dummy; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((LBM_file=fopen(filename, "rb"))) - { - file_size=File_length_file(LBM_file); - - // On avance dans le fichier (pas besoin de tester ce qui l'a déjà été) - Read_bytes(LBM_file,section,4); - Read_dword_be(LBM_file,&dummy); - Read_bytes(LBM_file,format,4); - if (!LBM_Wait_for((byte *)"BMHD")) - File_error=1; - Read_dword_be(LBM_file,&dummy); - - // Maintenant on lit le header pour pouvoir commencer le chargement de l'image - if ( (Read_word_be(LBM_file,&header.Width)) - && (Read_word_be(LBM_file,&header.Height)) - && (Read_word_be(LBM_file,&header.X_org)) - && (Read_word_be(LBM_file,&header.Y_org)) - && (Read_byte(LBM_file,&header.BitPlanes)) - && (Read_byte(LBM_file,&header.Mask)) - && (Read_byte(LBM_file,&header.Compression)) - && (Read_byte(LBM_file,&header.Pad1)) - && (Read_word_be(LBM_file,&header.Transp_col)) - && (Read_byte(LBM_file,&header.X_aspect)) - && (Read_byte(LBM_file,&header.Y_aspect)) - && (Read_word_be(LBM_file,&header.X_screen)) - && (Read_word_be(LBM_file,&header.Y_screen)) - && header.Width && header.Height) - { - if ( (header.BitPlanes) && (LBM_Wait_for((byte *)"CMAP")) ) - { - Read_dword_be(LBM_file,&nb_colors); - nb_colors/=3; - - if (((dword)1< il faut copier les 32 coul. - } // sur les 32 suivantes et assombrir ces dernières. - else - { - if ((header.BitPlanes==6) || (header.BitPlanes==8)) - Image_HAM=header.BitPlanes; - else - /* File_error=1;*/ /* C'est censé être incorrect mais j'ai */ - Image_HAM=0; /* trouvé un fichier comme ça, alors... */ - } - } - else - Image_HAM=0; - - if ( (!File_error) && (nb_colors>=2) && (nb_colors<=256) ) - { - HBPm1=header.BitPlanes-1; - if (header.Mask==1) - header.BitPlanes++; - - // Deluxe paint le fait... alors on le fait... - Back_color=header.Transp_col; - - // On commence par passer la palette en 256 comme ça, si la nouvelle - // palette a moins de 256 coul, la précédente ne souffrira pas d'un - // assombrissement préjudiciable. - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - else - Palette_64_to_256(context->Palette); - // On peut maintenant charger la nouvelle palette - if (Read_bytes(LBM_file,context->Palette,3*nb_colors)) - { - Palette_256_to_64(context->Palette); - if (Image_HAM) - Adapt_palette_HAM(context); - Palette_64_to_256(context->Palette); - Palette_loaded(context); - - // On lit l'octet de padding du CMAP si la taille est impaire - if (nb_colors&1) - if (Read_byte(LBM_file,&temp_byte)) - File_error=2; - - // Keep reading sections until we find the body - while (1) - { - 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; - - Original_screen_X = header.X_screen; - Original_screen_Y = header.Y_screen; - - Pre_load(context, context->Width,context->Height,file_size,FORMAT_LBM,PIXEL_SIMPLE,0); - if (File_error==0) - { - if (!memcmp(format,"ILBM",4)) // "ILBM": InterLeaved BitMap - { - // Calcul de la taille d'une ligne ILBM (pour les images ayant des dimensions exotiques) - if (context->Width & 15) - { - real_line_size=( (context->Width+16) >> 4 ) << 4; - line_size=( (context->Width+16) >> 4 )*(header.BitPlanes<<1); - } - else - { - real_line_size=context->Width; - line_size=(context->Width>>3)*header.BitPlanes; - } - - if (!header.Compression) - { // non compressé - LBM_buffer=(byte *)malloc(line_size); - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - if (Read_bytes(LBM_file,LBM_buffer,line_size)) - Draw_ILBM_line(context, y_pos,real_line_size); - else - File_error=2; - } - free(LBM_buffer); - LBM_buffer = NULL; - } - else - { // compressé - /*Init_lecture();*/ - - LBM_buffer=(byte *)malloc(line_size); - - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - for (x_pos=0; ((x_pos 127 alors il faut répéter 256-'temp_byte' fois la couleur de l'octet suivant - // Si temp_byte <= 127 alors il faut afficher directement les 'temp_byte' octets suivants - if (temp_byte>127) - { - if(Read_byte(LBM_file, &color)!=1) - { - File_error=2; - break; - } - b256=(short)(256-temp_byte); - for (counter=0; counter<=b256; counter++) - if (x_pos=line_size || Read_byte(LBM_file, &(LBM_buffer[x_pos++]))!=1) - File_error=2; - } - if (!File_error) - Draw_ILBM_line(context, y_pos,real_line_size); - } - - free(LBM_buffer); - LBM_buffer = NULL; - /*Close_lecture();*/ - } - } - else // "PBM ": Planar(?) BitMap - { - real_line_size=context->Width+(context->Width&1); - - if (!header.Compression) - { // non compressé - LBM_buffer=(byte *)malloc(real_line_size); - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - if (Read_bytes(LBM_file,LBM_buffer,real_line_size)) - for (x_pos=0; x_posWidth; x_pos++) - Set_pixel(context, x_pos,y_pos,LBM_buffer[x_pos]); - else - File_error=2; - } - free(LBM_buffer); - LBM_buffer = NULL; - } - else - { // compressé - /*Init_lecture();*/ - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - for (x_pos=0; ((x_pos127) - { - if(Read_byte(LBM_file, &color)!=1) - { - File_error=2; - break; - } - b256=256-temp_byte; - for (counter=0; counter<=b256; counter++) - Set_pixel(context, x_pos++,y_pos,color); - } - else - for (counter=0; counter<=temp_byte; counter++) - { - byte byte_read=0; - if(Read_byte(LBM_file, &byte_read)!=1) - { - File_error=2; - break; - } - Set_pixel(context, x_pos++,y_pos,byte_read); - } - } - } - /*Close_lecture();*/ - } - } - } - } - else - Set_file_error(2); - } - else - { - File_error=1; - } - } - else - Set_file_error(1); - } - else - File_error=1; - } - else - File_error=1; - - fclose(LBM_file); - } - else - File_error=1; -} - - -// -- Sauver un fichier au format LBM --------------------------------------- - - byte LBM_color_list[129]; - word LBM_list_size; - byte LBM_repetition_mode; - - // ------------- Ecrire les couleurs que l'on vient de traiter ------------ - void Transfer_colors(void) - { - byte index; - - if (LBM_list_size>0) - { - if (LBM_repetition_mode) - { - Write_one_byte(LBM_file,257-LBM_list_size); - Write_one_byte(LBM_file,LBM_color_list[0]); - } - else - { - Write_one_byte(LBM_file,LBM_list_size-1); - for (index=0; index et on a 3 couleurs qui se suivent - { - LBM_list_size-=2; - Transfer_colors(); - LBM_color_list[0]=color; - LBM_color_list[1]=color; - LBM_color_list[2]=color; - LBM_list_size=3; - LBM_repetition_mode=1; - } - } - else // La couleur n'est pas la même que la précédente - { - if (!LBM_repetition_mode) // On conserve le mode... - { - LBM_color_list[LBM_list_size++]=color; - if (LBM_list_size==128) - Transfer_colors(); - } - else // On change de mode... - { - Transfer_colors(); - LBM_color_list[LBM_list_size]=color; - LBM_list_size++; - } - } - } - } - - -void Save_LBM(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - T_LBM_Header header; - word x_pos; - word y_pos; - byte temp_byte; - word real_width; - int file_size; - int i; - - File_error=0; - Get_full_filename(filename, context->File_name, context->File_directory); - - // Ouverture du fichier - if ((LBM_file=fopen(filename,"wb"))) - { - Write_bytes(LBM_file,"FORM",4); - Write_dword_be(LBM_file,0); // On mettra la taille à jour à la fin - - Write_bytes(LBM_file,"PBM BMHD",8); - Write_dword_be(LBM_file,20); - - // On corrige la largeur de l'image pour qu'elle soit multiple de 2 - real_width=context->Width+(context->Width&1); - - header.Width=context->Width; - header.Height=context->Height; - header.X_org=0; - header.Y_org=0; - header.BitPlanes=8; - header.Mask=0; - header.Compression=1; - header.Pad1=0; - header.Transp_col=Back_color; - header.X_aspect=1; - header.Y_aspect=1; - header.X_screen = Screen_width; - header.Y_screen = Screen_height; - - Write_word_be(LBM_file,header.Width); - Write_word_be(LBM_file,header.Height); - Write_word_be(LBM_file,header.X_org); - Write_word_be(LBM_file,header.Y_org); - Write_bytes(LBM_file,&header.BitPlanes,1); - Write_bytes(LBM_file,&header.Mask,1); - Write_bytes(LBM_file,&header.Compression,1); - Write_bytes(LBM_file,&header.Pad1,1); - Write_word_be(LBM_file,header.Transp_col); - Write_bytes(LBM_file,&header.X_aspect,1); - Write_bytes(LBM_file,&header.Y_aspect,1); - Write_word_be(LBM_file,header.X_screen); - Write_word_be(LBM_file,header.Y_screen); - - Write_bytes(LBM_file,"CMAP",4); - 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 - - Init_write_buffer(); - - LBM_list_size=0; - - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - for (x_pos=0; ((x_posColor_cycles*16,SEEK_SET); - Write_dword_be(LBM_file,file_size-824-context->Color_cycles*16); - - if (!File_error) - { - fseek(LBM_file,4,SEEK_SET); - - // Si la taille de la section de l'image (taille fichier-8) est - // impaire, on rajoute un 0 (Padding) à la fin. - if ((file_size) & 1) - { - Write_dword_be(LBM_file,file_size-7); - fseek(LBM_file,0,SEEK_END); - temp_byte=0; - if (! Write_bytes(LBM_file,&temp_byte,1)) - File_error=1; - } - else - Write_dword_be(LBM_file,file_size-8); - - fclose(LBM_file); - - if (File_error) - remove(filename); - } - else - { - File_error=1; - fclose(LBM_file); - remove(filename); - } - } - else // Il y a eu une erreur lors du compactage => on efface le fichier - remove(filename); - } - else - File_error=1; -} - - - -//////////////////////////////////// BMP //////////////////////////////////// -typedef struct -{ - byte Signature[2]; // ='BM' = 0x4D42 - dword Size_1; // file size - word Reserved_1; // 0 - word Reserved_2; // 0 - dword Offset; // Offset of bitmap data start - - dword Size_2; // 40 - dword Width; - dword Height; - word Planes; // 1 - word Nb_bits; // 1,4,8 ou 24 - dword Compression; - dword Size_3; - dword XPM; - dword YPM; - dword Nb_Clr; - dword Clr_Imprt; -} T_BMP_Header; - -// -- Tester si un fichier est au format BMP -------------------------------- -void Test_BMP(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - T_BMP_Header header; - - File_error=1; - Get_full_filename(filename, context->File_name, context->File_directory); - - if ((file=fopen(filename, "rb"))) - { - if (Read_bytes(file,&(header.Signature),2) // "BM" - && Read_dword_le(file,&(header.Size_1)) - && Read_word_le(file,&(header.Reserved_1)) - && Read_word_le(file,&(header.Reserved_2)) - && Read_dword_le(file,&(header.Offset)) - && Read_dword_le(file,&(header.Size_2)) - && Read_dword_le(file,&(header.Width)) - && Read_dword_le(file,&(header.Height)) - && Read_word_le(file,&(header.Planes)) - && Read_word_le(file,&(header.Nb_bits)) - && Read_dword_le(file,&(header.Compression)) - && Read_dword_le(file,&(header.Size_3)) - && Read_dword_le(file,&(header.XPM)) - && Read_dword_le(file,&(header.YPM)) - && Read_dword_le(file,&(header.Nb_Clr)) - && Read_dword_le(file,&(header.Clr_Imprt)) - ) - { - - if ( header.Signature[0]=='B' && header.Signature[1]=='M' - && header.Size_2==40 - && header.Width && header.Height ) - File_error=0; - } - fclose(file); - } -} - -// Find the 8 important bits in a dword -byte Bitmap_mask(dword pixel, dword mask) -{ - byte result; - int i; - int bits_found; - - switch(mask) - { - // Shortcuts to quickly handle the common 24/32bit cases - case 0x000000FF: - return (pixel & 0x000000FF); - case 0x0000FF00: - return (pixel & 0x0000FF00)>>8; - case 0x00FF0000: - return (pixel & 0x00FF0000)>>16; - case 0xFF000000: - return (pixel & 0xFF000000)>>24; - } - // Uncommon : do it bit by bit. - bits_found=0; - result=0; - // Process the mask from low to high bit - for (i=0;i<32;i++) - { - // Found a bit in the mask - if (mask & (1<=8) - return result; - } - } - // Less than 8 bits in the mask: scale the result to 8 bits - return result << (8-bits_found); -} - -// -- Charger un fichier au format BMP -------------------------------------- -void Load_BMP(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - T_BMP_Header header; - byte * buffer; - word index; - byte local_palette[256][4]; // R,G,B,0 - word nb_colors = 0; - short x_pos; - short y_pos; - word line_size; - byte a,b,c=0; - long file_size; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((file=fopen(filename, "rb"))) - { - file_size=File_length_file(file); - - if (Read_bytes(file,header.Signature,2) - && Read_dword_le(file,&(header.Size_1)) - && Read_word_le(file,&(header.Reserved_1)) - && Read_word_le(file,&(header.Reserved_2)) - && Read_dword_le(file,&(header.Offset)) - && Read_dword_le(file,&(header.Size_2)) - && Read_dword_le(file,&(header.Width)) - && Read_dword_le(file,&(header.Height)) - && Read_word_le(file,&(header.Planes)) - && Read_word_le(file,&(header.Nb_bits)) - && Read_dword_le(file,&(header.Compression)) - && Read_dword_le(file,&(header.Size_3)) - && Read_dword_le(file,&(header.XPM)) - && Read_dword_le(file,&(header.YPM)) - && Read_dword_le(file,&(header.Nb_Clr)) - && Read_dword_le(file,&(header.Clr_Imprt)) - ) - { - switch (header.Nb_bits) - { - case 1 : - case 4 : - case 8 : - if (header.Nb_Clr) - nb_colors=header.Nb_Clr; - else - nb_colors=1<Palette,0,sizeof(T_Palette)); - // On peut maintenant transférer la nouvelle palette - for (index=0; indexPalette[index].R=local_palette[index][2]; - context->Palette[index].G=local_palette[index][1]; - context->Palette[index].B=local_palette[index][0]; - } - Palette_loaded(context); - - context->Width=header.Width; - context->Height=header.Height; - - switch (header.Compression) - { - case 0 : // Pas de compression - line_size=context->Width; - x_pos=(32/header.Nb_bits); // x_pos sert de variable temporaire - // On arrondit line_size au premier multiple de x_pos supérieur - if (line_size % x_pos) - line_size=((line_size/x_pos)*x_pos)+x_pos; - // On convertit cette taille en octets - line_size=(line_size*header.Nb_bits)>>3; - - buffer=(byte *)malloc(line_size); - for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) - { - if (Read_bytes(file,buffer,line_size)) - for (x_pos=0; x_posWidth; x_pos++) - switch (header.Nb_bits) - { - case 8 : - Set_pixel(context, x_pos,y_pos,buffer[x_pos]); - break; - case 4 : - if (x_pos & 1) - Set_pixel(context, x_pos,y_pos,buffer[x_pos>>1] & 0xF); - else - Set_pixel(context, x_pos,y_pos,buffer[x_pos>>1] >> 4 ); - break; - case 1 : - if ( buffer[x_pos>>3] & (0x80>>(x_pos&7)) ) - Set_pixel(context, x_pos,y_pos,1); - else - Set_pixel(context, x_pos,y_pos,0); - } - else - File_error=2; - } - free(buffer); - buffer = NULL; - break; - - case 1 : // Compression RLE 8 bits - x_pos=0; - y_pos=context->Height-1; - - /*Init_lecture();*/ - if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) - File_error=2; - while (!File_error) - { - if (a) // Encoded mode - for (index=1; index<=a; index++) - Set_pixel(context, x_pos++,y_pos,b); - else // Absolute mode - switch (b) - { - case 0 : // End of line - x_pos=0; - y_pos--; - break; - case 1 : // End of bitmap - break; - case 2 : // Delta - if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) - File_error=2; - x_pos+=a; - y_pos-=b; - break; - default: // Nouvelle série - while (b) - { - if(Read_byte(file, &a)!=1) - File_error=2; - //Read_one_byte(file, &c); - Set_pixel(context, x_pos++,y_pos,a); - //if (--c) - //{ - // Set_pixel(context, x_pos++,y_pos,c); - // b--; - //} - b--; - } - if (ftell(file) & 1) fseek(file, 1, SEEK_CUR); - } - if (a==0 && b==1) - break; - if(Read_byte(file, &a) !=1 || Read_byte(file, &b)!=1) - { - File_error=2; - } - } - /*Close_lecture();*/ - break; - - case 2 : // Compression RLE 4 bits - x_pos=0; - y_pos=context->Height-1; - - /*Init_lecture();*/ - if(Read_byte(file, &a)!=1 || Read_byte(file, &b) != 1) - File_error =2; - while ( (!File_error) && ((a)||(b!=1)) ) - { - if (a) // Encoded mode (A fois les 1/2 pixels de B) - for (index=1; index<=a; index++) - { - if (index & 1) - Set_pixel(context, x_pos,y_pos,b>>4); - else - Set_pixel(context, x_pos,y_pos,b&0xF); - x_pos++; - } - else // Absolute mode - switch (b) - { - case 0 : //End of line - x_pos=0; - y_pos--; - break; - case 1 : // End of bitmap - break; - case 2 : // Delta - if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) - File_error=2; - x_pos+=a; - y_pos-=b; - break; - default: // Nouvelle série (B 1/2 pixels bruts) - for (index=1; ((index<=b) && (!File_error)); index++,x_pos++) - { - if (index&1) - { - if(Read_byte(file, &c)!=1) File_error=2; - Set_pixel(context, x_pos,y_pos,c>>4); - } - else - Set_pixel(context, x_pos,y_pos,c&0xF); - } - // On lit l'octet rendant le nombre d'octets pair, si - // nécessaire. Encore un truc de crétin "made in MS". - if ( ((b&3)==1) || ((b&3)==2) ) - { - byte dummy; - if(Read_byte(file, &dummy)!=1) File_error=2; - } - } - if(Read_byte(file, &a)!=1 || Read_byte(file, &b)!=1) File_error=2; - } - /*Close_lecture();*/ - } - fclose(file); - } - else - { - fclose(file); - File_error=1; - } - } - } - else - { - // Image 16/24/32 bits - dword red_mask; - dword green_mask; - dword blue_mask; - if (header.Nb_bits == 16) - { - red_mask = 0x00007C00; - green_mask = 0x000003E0; - blue_mask = 0x0000001F; - } - else - { - red_mask = 0x00FF0000; - green_mask = 0x0000FF00; - blue_mask = 0x000000FF; - } - File_error=0; - - context->Width=header.Width; - context->Height=header.Height; - Pre_load(context,header.Width,header.Height,file_size,FORMAT_BMP,PIXEL_SIMPLE,1); - if (File_error==0) - { - switch (header.Compression) - { - case 3: // BI_BITFIELDS - if (!Read_dword_le(file,&red_mask) || - !Read_dword_le(file,&green_mask) || - !Read_dword_le(file,&blue_mask)) - File_error=2; - break; - default: - break; - } - if (fseek(file, header.Offset, SEEK_SET)) - File_error=2; - } - if (File_error==0) - { - switch (header.Nb_bits) - { - // 24bit bitmap - default: - case 24: - line_size=context->Width*3; - x_pos=(line_size % 4); // x_pos sert de variable temporaire - if (x_pos>0) - line_size+=(4-x_pos); - - buffer=(byte *)malloc(line_size); - for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) - { - if (Read_bytes(file,buffer,line_size)) - for (x_pos=0,index=0; x_posWidth; x_pos++,index+=3) - Set_pixel_24b(context, x_pos,y_pos,buffer[index+2],buffer[index+1],buffer[index+0]); - else - File_error=2; - } - break; - - // 32bit bitmap - case 32: - line_size=context->Width*4; - buffer=(byte *)malloc(line_size); - for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) - { - if (Read_bytes(file,buffer,line_size)) - for (x_pos=0; x_posWidth; x_pos++) - { - dword pixel=*(((dword *)buffer)+x_pos); - Set_pixel_24b(context, x_pos,y_pos,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask)); - } - else - File_error=2; - } - break; - - // 16bit bitmap - case 16: - line_size=(context->Width*2) + (context->Width&1)*2; - buffer=(byte *)malloc(line_size); - for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) - { - if (Read_bytes(file,buffer,line_size)) - for (x_pos=0; x_posWidth; x_pos++) - { - word pixel=*(((word *)buffer)+x_pos); - Set_pixel_24b(context, x_pos,y_pos,Bitmap_mask(pixel,red_mask),Bitmap_mask(pixel,green_mask),Bitmap_mask(pixel,blue_mask)); - } - else - File_error=2; - } - break; - - } - free(buffer); - buffer = NULL; - fclose(file); - } - } - } - else - { - fclose(file); - File_error=1; - } - } - else - File_error=1; -} - - -// -- Sauvegarder un fichier au format BMP ---------------------------------- -void Save_BMP(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - T_BMP_Header header; - short x_pos; - short y_pos; - long line_size; - word index; - byte local_palette[256][4]; // R,G,B,0 - - - File_error=0; - Get_full_filename(filename, context->File_name, context->File_directory); - - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - - // Image width must be a multiple of 4 bytes - line_size = context->Width; - if (line_size & 3) - line_size += (4 - (line_size & 3)); - - header.Signature[0] = 'B'; - header.Signature[1] = 'M'; - header.Size_1 =(line_size*context->Height)+1078; - header.Reserved_1 =0; - header.Reserved_2 =0; - header.Offset =1078; // Size of header data (including palette) - header.Size_2 =40; // Size of header - header.Width =context->Width; - header.Height =context->Height; - header.Planes =1; - header.Nb_bits =8; - header.Compression=0; - header.Size_3 =0; - header.XPM =0; - header.YPM =0; - header.Nb_Clr =0; - header.Clr_Imprt =0; - - if (Write_bytes(file,header.Signature,2) - && Write_dword_le(file,header.Size_1) - && Write_word_le(file,header.Reserved_1) - && Write_word_le(file,header.Reserved_2) - && Write_dword_le(file,header.Offset) - && Write_dword_le(file,header.Size_2) - && Write_dword_le(file,header.Width) - && Write_dword_le(file,header.Height) - && Write_word_le(file,header.Planes) - && Write_word_le(file,header.Nb_bits) - && Write_dword_le(file,header.Compression) - && Write_dword_le(file,header.Size_3) - && Write_dword_le(file,header.XPM) - && Write_dword_le(file,header.YPM) - && Write_dword_le(file,header.Nb_Clr) - && Write_dword_le(file,header.Clr_Imprt)) - { - // Chez Bill, ils ont dit: "On va mettre les couleur dans l'ordre - // inverse, et pour faire chier, on va les mettre sur une échelle de - // 0 à 255 parce que le standard VGA c'est de 0 à 63 (logique!). Et - // puis comme c'est pas assez débile, on va aussi y rajouter un octet - // toujours à 0 pour forcer les gens à s'acheter des gros disques - // durs... Comme ça, ça fera passer la pillule lorsqu'on sortira - // Windows 95." ... - for (index=0; index<256; index++) - { - local_palette[index][0]=context->Palette[index].B; - local_palette[index][1]=context->Palette[index].G; - local_palette[index][2]=context->Palette[index].R; - local_palette[index][3]=0; - } - - if (Write_bytes(file,local_palette,1024)) - { - Init_write_buffer(); - - // ... Et Bill, il a dit: "OK les gars! Mais seulement si vous rangez - // les pixels dans l'ordre inverse, mais que sur les Y quand-même - // parce que faut pas pousser." - for (y_pos=context->Height-1; ((y_pos>=0) && (!File_error)); y_pos--) - for (x_pos=0; x_posFile_name, context->File_directory); - - if ((file=fopen(filename, "rb"))) - { - if ( - (Read_bytes(file,signature,6)) && - ((!memcmp(signature,"GIF87a",6))||(!memcmp(signature,"GIF89a",6))) - ) - File_error=0; - - fclose(file); - } -} - - -// -- Lire un fichier au format GIF ----------------------------------------- -// -- Lire un fichier au format GIF ----------------------------------------- - -// Définition de quelques variables globales au chargement du GIF87a -word GIF_nb_bits; // Nb de bits composants un code complet -word GIF_remainder_bits; // Nb de bits encore dispos dans GIF_last_byte -byte GIF_remainder_byte; // Nb d'octets avant le prochain bloc de Raster Data -word GIF_current_code; // Code traité (qui vient d'être lu en général) -byte GIF_last_byte; // Octet de lecture des bits -word GIF_pos_X; // Coordonnées d'affichage de l'image -word GIF_pos_Y; -word GIF_interlaced; // L'image est entrelacée -word GIF_finished_interlaced_image; // L'image entrelacée est finie de charger -word GIF_pass; // index de passe de l'image entrelacée -FILE *GIF_file; // L'handle du fichier - -// -- Lit le code à GIF_nb_bits suivant -- - -word GIF_get_next_code(void) -{ - word nb_bits_to_process=GIF_nb_bits; - word nb_bits_processed =0; - word current_nb_bits; - - GIF_current_code=0; - - while (nb_bits_to_process) - { - if (GIF_remainder_bits==0) // Il ne reste plus de bits... - { - // Lire l'octet suivant: - - // Si on a atteint la fin du bloc de Raster Data - if (GIF_remainder_byte==0) - // Lire l'octet nous donnant la taille du bloc de Raster Data suivant - if(Read_byte(GIF_file, &GIF_remainder_byte)!=1) - File_error=2; - - if(Read_byte(GIF_file,&GIF_last_byte)!=1) - File_error = 2; - GIF_remainder_byte--; - GIF_remainder_bits=8; - } - - current_nb_bits=(nb_bits_to_process<=GIF_remainder_bits)?nb_bits_to_process:GIF_remainder_bits; - - GIF_current_code|=(GIF_last_byte & ((1<>=current_nb_bits; - nb_bits_processed +=current_nb_bits; - nb_bits_to_process-=current_nb_bits; - GIF_remainder_bits -=current_nb_bits; - } - - return GIF_current_code; -} - -// -- Affiche un nouveau pixel -- - -void GIF_new_pixel(T_IO_Context * context, T_GIF_IDB *idb, byte color) -{ - Set_pixel(context, idb->Pos_X+GIF_pos_X, idb->Pos_Y+GIF_pos_Y,color); - - GIF_pos_X++; - - if (GIF_pos_X>=idb->Image_width) - { - GIF_pos_X=0; - - if (!GIF_interlaced) - GIF_pos_Y++; - else - { - switch (GIF_pass) - { - case 0 : GIF_pos_Y+=8; - break; - case 1 : GIF_pos_Y+=8; - break; - case 2 : GIF_pos_Y+=4; - break; - default: GIF_pos_Y+=2; - } - - if (GIF_pos_Y>=idb->Image_height) - { - switch(++GIF_pass) - { - case 1 : GIF_pos_Y=4; - break; - case 2 : GIF_pos_Y=2; - break; - case 3 : GIF_pos_Y=1; - break; - case 4 : GIF_finished_interlaced_image=1; - } - } - } - } -} - - -void Load_GIF(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - char signature[6]; - - word * alphabet_stack; // Pile de décodage d'une chaîne - word * alphabet_prefix; // Table des préfixes des codes - word * alphabet_suffix; // Table des suffixes des codes - word alphabet_free; // Position libre dans l'alphabet - word alphabet_max; // Nombre d'entrées possibles dans l'alphabet - word alphabet_stack_pos; // Position dans la pile de décodage d'un chaîne - - T_GIF_LSDB LSDB; - T_GIF_IDB IDB; - T_GIF_GCE GCE; - - word nb_colors; // Nombre de couleurs dans l'image - 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 - 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 - word value_clr; // Valeur <=> Clear tables - word value_eof; // Valeur <=> End d'image - long file_size; - int number_LID; // Nombre d'images trouvées dans le fichier - short current_layer = 0; - - /////////////////////////////////////////////////// FIN DES DECLARATIONS // - - - number_LID=0; - - Get_full_filename(filename, context->File_name, context->File_directory); - - if ((GIF_file=fopen(filename, "rb"))) - { - file_size=File_length_file(GIF_file); - if ( (Read_bytes(GIF_file,signature,6)) && - ( (memcmp(signature,"GIF87a",6)==0) || - (memcmp(signature,"GIF89a",6)==0) ) ) - { - - // Allocation de mémoire pour les tables & piles de traitement: - alphabet_stack =(word *)malloc(4096*sizeof(word)); - alphabet_prefix=(word *)malloc(4096*sizeof(word)); - alphabet_suffix=(word *)malloc(4096*sizeof(word)); - - if (Read_word_le(GIF_file,&(LSDB.Width)) - && Read_word_le(GIF_file,&(LSDB.Height)) - && Read_byte(GIF_file,&(LSDB.Resol)) - && Read_byte(GIF_file,&(LSDB.Backcol)) - && Read_byte(GIF_file,&(LSDB.Aspect)) - ) - { - // Lecture du Logical Screen Descriptor Block réussie: - - Original_screen_X=LSDB.Width; - Original_screen_Y=LSDB.Height; - - Pre_load(context, LSDB.Width,LSDB.Height,file_size,FORMAT_GIF,PIXEL_SIMPLE,0); - context->Width=LSDB.Width; - context->Height=LSDB.Height; - - // Palette globale dispo = (LSDB.Resol and $80) - // Profondeur de couleur =((LSDB.Resol and $70) shr 4)+1 - // Nombre de bits/pixel = (LSDB.Resol and $07)+1 - // Ordre de Classement = (LSDB.Aspect and $80) - - nb_colors=(1 << ((LSDB.Resol & 0x07)+1)); - if (LSDB.Resol & 0x80) - { - // Palette globale dispo: - - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - - // 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)); - } - } - - // On lit un indicateur de block - Read_byte(GIF_file,&block_identifier); - while (block_identifier!=0x3B && !File_error) - { - switch (block_identifier) - { - case 0x21: // Bloc d'extension - { - byte function_code; - // Lecture du code de fonction: - Read_byte(GIF_file,&function_code); - // Lecture de la taille du bloc: - Read_byte(GIF_file,&size_to_read); - while (size_to_read!=0 && !File_error) - { - switch(function_code) - { - case 0xFE: // Comment Block Extension - // On récupère le premier commentaire non-vide, - // on jette les autres. - if (context->Comment[0]=='\0') - { - int nb_char_to_keep=Min(size_to_read,COMMENT_SIZE); - - Read_bytes(GIF_file,context->Comment,nb_char_to_keep); - context->Comment[nb_char_to_keep+1]='\0'; - // Si le commentaire etait trop long, on fait avance-rapide - // sur la suite. - if (size_to_read>nb_char_to_keep) - fseek(GIF_file,size_to_read-nb_char_to_keep,SEEK_CUR); - } - // Lecture de la taille du bloc suivant: - Read_byte(GIF_file,&size_to_read); - break; - case 0xF9: // Graphics Control Extension - // Prévu pour la transparence - if ( Read_byte(GIF_file,&(GCE.Packed_fields)) - && Read_word_le(GIF_file,&(GCE.Delay_time)) - && Read_byte(GIF_file,&(GCE.Transparent_color))) - { - if (GCE.Packed_fields & 1) - { - if (number_LID == 0) - context->Background_transparent = 1; - context->Transparent_color= GCE.Transparent_color; - } - else - { - if (number_LID == 0) - context->Background_transparent = 0; - context->Transparent_color = 0; // Reset transparent color - } - - } - else - File_error=2; - // Lecture de la taille du bloc suivant: - Read_byte(GIF_file,&size_to_read); - break; - - case 0xFF: // Application Extension - // Normally, always a 11-byte block - if (size_to_read == 0x0B) - { - char aeb[0x0B]; - Read_bytes(GIF_file,aeb, 0x0B); - if (File_error) - ; - else if (!memcmp(aeb,"NETSCAPE2.0",0x0B)) - { - // The well-known Netscape extension. - // Nothing to do, just skip sub-block - do - { - if (! Read_byte(GIF_file,&size_to_read)) - File_error=1; - fseek(GIF_file,size_to_read,SEEK_CUR); - } while (!File_error && size_to_read!=0); - } - else if (!memcmp(aeb,"GFX2PATH\x00\x00\x00",0x0B)) - { - // Original file path - if (context->Original_file_name && context->Original_file_directory) - { - Read_byte(GIF_file,&size_to_read); - if (!File_error && size_to_read) - { - Read_bytes(GIF_file,context->Original_file_directory, size_to_read); - Read_byte(GIF_file,&size_to_read); - if (!File_error && size_to_read) - { - Read_bytes(GIF_file,context->Original_file_name, size_to_read); - Read_byte(GIF_file,&size_to_read); // Normally 0 - } - } - } - else - { - // Nothing to do, just skip sub-block - 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 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 - { - fseek(GIF_file,size_to_read,SEEK_CUR); - // Lecture de la taille du bloc suivant: - Read_byte(GIF_file,&size_to_read); - } - break; - - default: - // On saute le bloc: - fseek(GIF_file,size_to_read,SEEK_CUR); - // Lecture de la taille du bloc suivant: - Read_byte(GIF_file,&size_to_read); - break; - } - } - } - break; - case 0x2C: // Local Image Descriptor - { - if (number_LID!=0) - { - // This a second layer/frame, or more. - // Attempt to add a layer to current image - current_layer++; - Set_layer(context, current_layer); - } - number_LID++; - - // lecture de 10 derniers octets - if ( Read_word_le(GIF_file,&(IDB.Pos_X)) - && Read_word_le(GIF_file,&(IDB.Pos_Y)) - && Read_word_le(GIF_file,&(IDB.Image_width)) - && Read_word_le(GIF_file,&(IDB.Image_height)) - && Read_byte(GIF_file,&(IDB.Indicator)) - && IDB.Image_width && IDB.Image_height) - { - - // Palette locale dispo = (IDB.Indicator and $80) - // Image entrelacée = (IDB.Indicator and $40) - // Ordre de classement = (IDB.Indicator and $20) - // Nombre de bits/pixel = (IDB.Indicator and $07)+1 (si palette locale dispo) - - if (IDB.Indicator & 0x80) - { - // Palette locale dispo - - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - - nb_colors=(1 << ((IDB.Indicator & 0x07)+1)); - // 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 =(1<value_clr) - { - alphabet_stack[alphabet_stack_pos++]=alphabet_suffix[GIF_current_code]; - GIF_current_code=alphabet_prefix[GIF_current_code]; - } - - special_case=alphabet_stack[alphabet_stack_pos++]=GIF_current_code; - - do - GIF_new_pixel(context, &IDB, alphabet_stack[--alphabet_stack_pos]); - while (alphabet_stack_pos!=0); - - alphabet_prefix[alphabet_free ]=old_code; - alphabet_suffix[alphabet_free++]=GIF_current_code; - old_code=byte_read; - - if (alphabet_free>alphabet_max) - { - if (GIF_nb_bits<12) - alphabet_max =((1 << (++GIF_nb_bits))-1); - } - } - else // Code Clear rencontré - { - GIF_nb_bits =initial_nb_bits + 1; - alphabet_max =((1 << GIF_nb_bits)-1); - alphabet_free =(1<=0) - if ( /* (GIF_pos_X!=0) || */ - ( ( (!GIF_interlaced) && (GIF_pos_Y!=IDB.Image_height) && (GIF_pos_X!=0)) || - ( (GIF_interlaced) && (!GIF_finished_interlaced_image) ) - ) ) - File_error=2; - } // Le fichier contenait un IDB - else - File_error=2; - } - default: - break; - } - // Lecture du code de fonction suivant: - if (!Read_byte(GIF_file,&block_identifier)) - File_error=2; - } - } // Le fichier contenait un LSDB - else - File_error=1; - - // Libération de la mémoire utilisée par les tables & piles de traitement: - free(alphabet_suffix); - free(alphabet_prefix); - free(alphabet_stack); - alphabet_suffix = alphabet_prefix = alphabet_stack = NULL; - } // Le fichier contenait au moins la signature GIF87a ou GIF89a - else - File_error=1; - - fclose(GIF_file); - - } // Le fichier était ouvrable - else - File_error=1; -} - - -// -- Sauver un fichier au format GIF --------------------------------------- - - int GIF_stop; // "On peut arrêter la sauvegarde du fichier" - byte GIF_buffer[256]; // buffer d'écriture de bloc de données compilées - - // -- Vider le buffer GIF dans le buffer KM -- - - void GIF_empty_buffer(void) - { - word index; - - if (GIF_remainder_byte) - { - GIF_buffer[0]=GIF_remainder_byte; - - for (index=0;index<=GIF_remainder_byte;index++) - Write_one_byte(GIF_file,GIF_buffer[index]); - - GIF_remainder_byte=0; - } - } - - // -- Ecrit un code à GIF_nb_bits -- - - void GIF_set_code(word Code) - { - word nb_bits_to_process=GIF_nb_bits; - word nb_bits_processed =0; - word current_nb_bits; - - while (nb_bits_to_process) - { - current_nb_bits=(nb_bits_to_process<=(8-GIF_remainder_bits))?nb_bits_to_process:(8-GIF_remainder_bits); - - GIF_last_byte|=(Code & ((1<>=current_nb_bits; - GIF_remainder_bits +=current_nb_bits; - nb_bits_processed +=current_nb_bits; - nb_bits_to_process-=current_nb_bits; - - if (GIF_remainder_bits==8) // Il ne reste plus de bits à coder sur l'octet courant - { - // Ecrire l'octet à balancer: - GIF_buffer[++GIF_remainder_byte]=GIF_last_byte; - - // Si on a atteint la fin du bloc de Raster Data - if (GIF_remainder_byte==255) - // On doit vider le buffer qui est maintenant plein - GIF_empty_buffer(); - - GIF_last_byte=0; - GIF_remainder_bits=0; - } - } - } - - - // -- Lire le pixel suivant -- - - byte GIF_next_pixel(T_IO_Context *context, T_GIF_IDB *idb) - { - byte temp; - - temp=Get_pixel(context, GIF_pos_X,GIF_pos_Y); - - if (++GIF_pos_X>=idb->Image_width) - { - GIF_pos_X=0; - if (++GIF_pos_Y>=idb->Image_height) - GIF_stop=1; - } - - return temp; - } - - - -void Save_GIF(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - - word * alphabet_prefix; // Table des préfixes des codes - word * alphabet_suffix; // Table des suffixes des codes - word * alphabet_daughter; // Table des chaînes filles (plus longues) - word * alphabet_sister; // Table des chaînes soeurs (même longueur) - word alphabet_free; // Position libre dans l'alphabet - word alphabet_max; // Nombre d'entrées possibles dans l'alphabet - word start; // Code précédent (sert au linkage des chaînes) - int descend; // Booléen "On vient de descendre" - - T_GIF_LSDB LSDB; - T_GIF_IDB IDB; - - - byte block_identifier; // Code indicateur du type de bloc en cours - word current_string; // Code de la chaîne en cours de traitement - byte current_char; // Caractère à coder - word index; // index de recherche de chaîne - short current_layer; - - /////////////////////////////////////////////////// FIN DES DECLARATIONS // - - File_error=0; - - Get_full_filename(filename, context->File_name, context->File_directory); - - if ((GIF_file=fopen(filename,"wb"))) - { - // On écrit la signature du fichier - if (Write_bytes(GIF_file,"GIF89a",6)) - { - // La signature du fichier a été correctement écrite. - - // Allocation de mémoire pour les tables - alphabet_prefix=(word *)malloc(4096*sizeof(word)); - alphabet_suffix=(word *)malloc(4096*sizeof(word)); - alphabet_daughter =(word *)malloc(4096*sizeof(word)); - alphabet_sister =(word *)malloc(4096*sizeof(word)); - - // On initialise le LSDB du fichier - if (Config.Screen_size_in_GIF) - { - LSDB.Width=Screen_width; - LSDB.Height=Screen_height; - } - else - { - LSDB.Width=context->Width; - LSDB.Height=context->Height; - } - LSDB.Resol =0x97; // Image en 256 couleurs, avec une palette - LSDB.Backcol=context->Transparent_color; - LSDB.Aspect =0; // Palette normale - - // On sauve le LSDB dans le fichier - - if (Write_word_le(GIF_file,LSDB.Width) && - Write_word_le(GIF_file,LSDB.Height) && - Write_byte(GIF_file,LSDB.Resol) && - Write_byte(GIF_file,LSDB.Backcol) && - Write_byte(GIF_file,LSDB.Aspect) ) - { - // Le LSDB a été correctement écrit. - int i; - // On sauve la palette - 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. - - // Ecriture de la transparence - //Write_bytes(GIF_file,"\x21\xF9\x04\x01\x00\x00\xNN\x00",8); - - // "Netscape" animation extension - // Write_bytes(GIF_file,"\x21\xFF\x0BNETSCAPE2.0\x03\xLL\xSS\xSS\x00",19); - // LL : 01 to loop - // SSSS : number of loops - - // Ecriture du commentaire - if (context->Comment[0]) - { - Write_bytes(GIF_file,"\x21\xFE",2); - 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; - current_layer < context->Nb_layers && !File_error; - current_layer++) - { - // Write a Graphic Control Extension - 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) - - if (current_layer > 0 || context->Background_transparent) - GCE_block[3] |= 1; // Transparent color flag - GCE_block[6] = context->Transparent_color; - - Set_layer(context, current_layer); - - if (current_layer == context->Nb_layers -1) - { - // "Infinite" delay for last frame - GCE_block[4] = 255; - GCE_block[5] = 255; - } - if (Write_bytes(GIF_file,GCE_block,8)) - { - - // On va écrire un block indicateur d'IDB et l'IDB du fichier - block_identifier=0x2C; - IDB.Pos_X=0; - IDB.Pos_Y=0; - IDB.Image_width=context->Width; - IDB.Image_height=context->Height; - IDB.Indicator=0x07; // Image non entrelacée, pas de palette locale. - IDB.Nb_bits_pixel=8; // Image 256 couleurs; - - if ( Write_byte(GIF_file,block_identifier) && - Write_word_le(GIF_file,IDB.Pos_X) && - Write_word_le(GIF_file,IDB.Pos_Y) && - Write_word_le(GIF_file,IDB.Image_width) && - Write_word_le(GIF_file,IDB.Image_height) && - Write_byte(GIF_file,IDB.Indicator) && - Write_byte(GIF_file,IDB.Nb_bits_pixel)) - { - // Le block indicateur d'IDB et l'IDB ont étés correctements - // écrits. - - Init_write_buffer(); - GIF_pos_X=0; - GIF_pos_Y=0; - GIF_last_byte=0; - GIF_remainder_bits=0; - GIF_remainder_byte=0; - - index=4096; - File_error=0; - GIF_stop=0; - - // Réintialisation de la table: - alphabet_free=258; - GIF_nb_bits =9; - alphabet_max =511; - GIF_set_code(256); - for (start=0;start<4096;start++) - { - alphabet_daughter[start]=4096; - alphabet_sister[start]=4096; - } - - ////////////////////////////////////////////// COMPRESSION LZW // - - start=current_string=GIF_next_pixel(context, &IDB); - descend=1; - - do - { - current_char=GIF_next_pixel(context, &IDB); - - // On regarde si dans la table on aurait pas une chaîne - // équivalente à current_string+Caractere - - while ( (index0xFFF) - { - // Réintialisation de la table: - GIF_set_code(256); - alphabet_free=258; - GIF_nb_bits =9; - alphabet_max =511; - for (start=0;start<4096;start++) - { - alphabet_daughter[start]=4096; - alphabet_sister[start]=4096; - } - } - else if (alphabet_free>alphabet_max+1) - { - // On augmente le nb de bits - - GIF_nb_bits++; - alphabet_max=(1< - // - // 00 - if (context->Original_file_name != NULL - && context->Original_file_directory != NULL) - { - long name_size = 1+strlen(context->Original_file_name); - long dir_size = 1+strlen(context->Original_file_directory); - if (name_size<256 && dir_size<256) - { - if (! Write_bytes(GIF_file,"\x21\xFF\x0BGFX2PATH\x00\x00\x00", 14) - || ! Write_byte(GIF_file,dir_size) - || ! Write_bytes(GIF_file, context->Original_file_directory, dir_size) - || ! Write_byte(GIF_file,name_size) - || ! Write_bytes(GIF_file, context->Original_file_name, name_size) - || ! Write_byte(GIF_file,0)) - File_error=1; - } - } - - // On écrit un GIF TERMINATOR, exigé par SVGA et SEA. - if (! Write_byte(GIF_file,'\x3B')) - File_error=1; - } - - } // On a pu écrire la palette - else - File_error=1; - - } // On a pu écrire le LSDB - else - File_error=1; - - // Libération de la mémoire utilisée par les tables - free(alphabet_sister); - free(alphabet_daughter); - free(alphabet_suffix); - free(alphabet_prefix); - - } // On a pu écrire la signature du fichier - else - File_error=1; - - fclose(GIF_file); - if (File_error) - remove(filename); - - } // On a pu ouvrir le fichier en écriture - else - File_error=1; - -} - - - -//////////////////////////////////// PCX //////////////////////////////////// -typedef struct - { - byte Manufacturer; // |_ Il font chier ces cons! Ils auraient pu - byte Version; // | mettre une vraie signature! - byte Compression; // L'image est-elle compressée? - byte Depth; // Nombre de bits pour coder un pixel (inutile puisqu'on se sert de Plane) - word X_min; // |_ Coin haut-gauche | - word Y_min; // | de l'image |_ (Crétin!) - word X_max; // |_ Coin bas-droit | - word Y_max; // | de l'image | - word X_dpi; // |_ Densité de |_ (Presque inutile parce que - word Y_dpi; // | l'image | aucun moniteur n'est pareil!) - byte Palette_16c[48]; // Palette 16 coul (inutile pour 256c) (débile!) - byte Reserved; // Ca me plait ça aussi! - byte Plane; // 4 => 16c , 1 => 256c , ... - word Bytes_per_plane_line;// Doit toujours être pair - word Palette_info; // 1 => color , 2 => Gris (ignoré à partir de la version 4) - word Screen_X; // |_ Dimensions de - word Screen_Y; // | l'écran d'origine - byte Filler[54]; // Ca... J'adore! - } T_PCX_Header; - -T_PCX_Header PCX_header; - -// -- Tester si un fichier est au format PCX -------------------------------- - -void Test_PCX(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - - File_error=0; - Get_full_filename(filename, context->File_name, context->File_directory); - - if ((file=fopen(filename, "rb"))) - { - if (Read_byte(file,&(PCX_header.Manufacturer)) && - Read_byte(file,&(PCX_header.Version)) && - Read_byte(file,&(PCX_header.Compression)) && - Read_byte(file,&(PCX_header.Depth)) && - Read_word_le(file,&(PCX_header.X_min)) && - Read_word_le(file,&(PCX_header.Y_min)) && - Read_word_le(file,&(PCX_header.X_max)) && - Read_word_le(file,&(PCX_header.Y_max)) && - Read_word_le(file,&(PCX_header.X_dpi)) && - Read_word_le(file,&(PCX_header.Y_dpi)) && - Read_bytes(file,&(PCX_header.Palette_16c),48) && - Read_byte(file,&(PCX_header.Reserved)) && - Read_byte(file,&(PCX_header.Plane)) && - Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && - Read_word_le(file,&(PCX_header.Palette_info)) && - Read_word_le(file,&(PCX_header.Screen_X)) && - Read_word_le(file,&(PCX_header.Screen_Y)) && - Read_bytes(file,&(PCX_header.Filler),54) ) - { - - // Vu que ce header a une signature de merde et peu significative, il - // va falloir que je teste différentes petites valeurs dont je connais - // l'intervalle. Grrr! - if ( (PCX_header.Manufacturer!=10) - || (PCX_header.Compression>1) - || ( (PCX_header.Depth!=1) && (PCX_header.Depth!=2) && (PCX_header.Depth!=4) && (PCX_header.Depth!=8) ) - || ( (PCX_header.Plane!=1) && (PCX_header.Plane!=2) && (PCX_header.Plane!=4) && (PCX_header.Plane!=8) && (PCX_header.Plane!=3) ) - || (PCX_header.X_maxWidth; x_pos++) - { - color=(LBM_buffer[x_pos/reduction]>>((reduction_minus_one-(x_pos%reduction))*depth)) & byte_mask; - Set_pixel(context, x_pos,y_pos,color); - } - } - -void Load_PCX(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - - short line_size; - short real_line_size; // width de l'image corrigée - short width_read; - short x_pos; - short y_pos; - byte byte1; - byte byte2; - byte index; - dword nb_colors; - long file_size; - byte palette_CGA[9]={ 84,252,252, 252, 84,252, 252,252,252}; - - long position; - long image_size; - byte * buffer; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((file=fopen(filename, "rb"))) - { - file_size=File_length_file(file); - if (Read_byte(file,&(PCX_header.Manufacturer)) && - Read_byte(file,&(PCX_header.Version)) && - Read_byte(file,&(PCX_header.Compression)) && - Read_byte(file,&(PCX_header.Depth)) && - Read_word_le(file,&(PCX_header.X_min)) && - Read_word_le(file,&(PCX_header.Y_min)) && - Read_word_le(file,&(PCX_header.X_max)) && - Read_word_le(file,&(PCX_header.Y_max)) && - Read_word_le(file,&(PCX_header.X_dpi)) && - Read_word_le(file,&(PCX_header.Y_dpi)) && - Read_bytes(file,&(PCX_header.Palette_16c),48) && - Read_byte(file,&(PCX_header.Reserved)) && - Read_byte(file,&(PCX_header.Plane)) && - Read_word_le(file,&(PCX_header.Bytes_per_plane_line)) && - Read_word_le(file,&(PCX_header.Palette_info)) && - Read_word_le(file,&(PCX_header.Screen_X)) && - Read_word_le(file,&(PCX_header.Screen_Y)) && - Read_bytes(file,&(PCX_header.Filler),54) ) - { - - context->Width=PCX_header.X_max-PCX_header.X_min+1; - context->Height=PCX_header.Y_max-PCX_header.Y_min+1; - - Original_screen_X=PCX_header.Screen_X; - Original_screen_Y=PCX_header.Screen_Y; - - if (PCX_header.Plane!=3) - { - Pre_load(context, context->Width,context->Height,file_size,FORMAT_PCX,PIXEL_SIMPLE,0); - if (File_error==0) - { - // On prépare la palette à accueillir les valeurs du fichier PCX - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - nb_colors=(dword)(1<4) - memcpy(context->Palette,PCX_header.Palette_16c,48); - else - { - context->Palette[1].R=0; - context->Palette[1].G=0; - context->Palette[1].B=0; - byte1=PCX_header.Palette_16c[3]>>5; - if (nb_colors==4) - { // Pal. CGA "alakon" (du Turc Allahkoum qui signifie "à la con" :)) - memcpy(context->Palette+1,palette_CGA,9); - if (!(byte1&2)) - { - context->Palette[1].B=84; - context->Palette[2].B=84; - context->Palette[3].B=84; - } - } // Palette monochrome (on va dire que c'est du N&B) - else - { - context->Palette[1].R=252; - context->Palette[1].G=252; - context->Palette[1].B=252; - } - } - - // On se positionne à la fin du fichier - 769 octets pour voir s'il y - // a une palette. - if ( (PCX_header.Depth==8) && (PCX_header.Version>=5) && (file_size>(256*3)) ) - { - fseek(file,file_size-((256*3)+1),SEEK_SET); - // On regarde s'il y a une palette après les données de l'image - if (Read_byte(file,&byte1)) - if (byte1==12) // Lire la palette si c'est une image en 256 couleurs - { - int index; - // On lit la palette 256c que ces crétins ont foutue à la fin du fichier - for(index=0;index<256;index++) - if ( ! Read_byte(file,&(context->Palette[index].R)) - || ! Read_byte(file,&(context->Palette[index].G)) - || ! Read_byte(file,&(context->Palette[index].B)) ) - { - File_error=2; - DEBUG("ERROR READING PCX PALETTE !",index); - break; - } - } - } - Palette_loaded(context); - - // Maintenant qu'on a lu la palette que ces crétins sont allés foutre - // à la fin, on retourne juste après le header pour lire l'image. - fseek(file,128,SEEK_SET); - if (!File_error) - { - line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; - real_line_size=(short)PCX_header.Bytes_per_plane_line<<3; - // On se sert de données LBM car le dessin de ligne en moins de 256 - // couleurs se fait comme avec la structure ILBM. - Image_HAM=0; - HBPm1=PCX_header.Plane-1; - LBM_buffer=(byte *)malloc(line_size); - - // Chargement de l'image - if (PCX_header.Compression) // Image compressée - { - /*Init_lecture();*/ - - image_size=(long)PCX_header.Bytes_per_plane_line*context->Height; - - if (PCX_header.Depth==8) // 256 couleurs (1 plan) - { - for (position=0; ((positionHeight) && (!File_error)); y_pos++) - { - for (x_pos=0; ((x_posHeight) && (!File_error);y_pos++) - { - if ((width_read=Read_bytes(file,LBM_buffer,line_size))) - { - if (PCX_header.Plane==1) - for (x_pos=0; x_posWidth;x_pos++) - Set_pixel(context, x_pos,y_pos,LBM_buffer[x_pos]); - else - { - if (PCX_header.Depth==1) - Draw_ILBM_line(context, y_pos,real_line_size); - else - Draw_PCX_line(context, y_pos,PCX_header.Depth); - } - } - else - File_error=2; - } - } - - free(LBM_buffer); - LBM_buffer = NULL; - } - } - } - else - { - // Image 24 bits!!! - - Pre_load(context,context->Width,context->Height,file_size,FORMAT_PCX,PIXEL_SIMPLE,1); - - if (File_error==0) - { - line_size=PCX_header.Bytes_per_plane_line*3; - buffer=(byte *)malloc(line_size); - - if (!PCX_header.Compression) - { - for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) - { - if (Read_bytes(file,buffer,line_size)) - { - for (x_pos=0; x_posWidth; x_pos++) - Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); - } - else - File_error=2; - } - } - else - { - /*Init_lecture();*/ - - for (y_pos=0,position=0;(y_posHeight) && (!File_error);) - { - // Lecture et décompression de la ligne - if(Read_byte(file,&byte1)!=1) File_error=2; - if (!File_error) - { - if ((byte1 & 0xC0)==0xC0) - { - byte1-=0xC0; // facteur de répétition - if(Read_byte(file,&byte2)!=1) File_error=2; // octet à répéter - if (!File_error) - { - for (index=0; (index=line_size) - { - for (x_pos=0; x_posWidth; x_pos++) - Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); - y_pos++; - position=0; - } - } - } - } - else - { - buffer[position++]=byte1; - if (position>=line_size) - { - for (x_pos=0; x_posWidth; x_pos++) - Set_pixel_24b(context, x_pos,y_pos,buffer[x_pos+(PCX_header.Bytes_per_plane_line*0)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*1)],buffer[x_pos+(PCX_header.Bytes_per_plane_line*2)]); - y_pos++; - position=0; - } - } - } - } - if (position!=0) - File_error=2; - - /*Close_lecture();*/ - } - free(buffer); - buffer = NULL; - } - } - } - else - { - File_error=1; - } - - fclose(file); - } - else - File_error=1; -} - - -// -- Ecrire un fichier au format PCX --------------------------------------- - -void Save_PCX(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - - short line_size; - short x_pos; - short y_pos; - byte counter; - byte last_pixel; - byte pixel_read; - - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((file=fopen(filename,"wb"))) - { - - PCX_header.Manufacturer=10; - PCX_header.Version=5; - PCX_header.Compression=1; - PCX_header.Depth=8; - PCX_header.X_min=0; - PCX_header.Y_min=0; - PCX_header.X_max=context->Width-1; - PCX_header.Y_max=context->Height-1; - PCX_header.X_dpi=0; - PCX_header.Y_dpi=0; - memcpy(PCX_header.Palette_16c,context->Palette,48); - PCX_header.Reserved=0; - PCX_header.Plane=1; - PCX_header.Bytes_per_plane_line=(context->Width&1)?context->Width+1:context->Width; - PCX_header.Palette_info=1; - PCX_header.Screen_X=Screen_width; - PCX_header.Screen_Y=Screen_height; - memset(PCX_header.Filler,0,54); - - if (Write_bytes(file,&(PCX_header.Manufacturer),1) && - Write_bytes(file,&(PCX_header.Version),1) && - Write_bytes(file,&(PCX_header.Compression),1) && - Write_bytes(file,&(PCX_header.Depth),1) && - Write_word_le(file,PCX_header.X_min) && - Write_word_le(file,PCX_header.Y_min) && - Write_word_le(file,PCX_header.X_max) && - 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),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),54) ) - { - line_size=PCX_header.Bytes_per_plane_line*PCX_header.Plane; - - Init_write_buffer(); - - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - { - pixel_read=Get_pixel(context, 0,y_pos); - - // Compression et écriture de la ligne - for (x_pos=0; ((x_pos1) || (last_pixel>=0xC0) ) - Write_one_byte(file,counter|0xC0); - Write_one_byte(file,last_pixel); - - } - } - - // Ecriture de l'octet (12) indiquant que la palette arrive - if (!File_error) - Write_one_byte(file,12); - - End_write(file); - - // Ecriture de la palette - if (!File_error) - { - if (! Write_bytes(file,context->Palette,sizeof(T_Palette))) - File_error=1; - } - } - else - File_error=1; - - fclose(file); - - if (File_error) - remove(filename); - - } - else - File_error=1; -} - - -//////////////////////////////////// SCx //////////////////////////////////// -typedef struct -{ - byte Filler1[4]; - word Width; - word Height; - byte Filler2; - byte Planes; -} T_SCx_Header; - -// -- Tester si un fichier est au format SCx -------------------------------- -void Test_SCx(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - //byte Signature[3]; - T_SCx_Header SCx_header; - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=1; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - // Lecture et vérification de la signature - 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)) - && Read_byte(file, &(SCx_header.Planes)) - ) - { - if ( (!memcmp(SCx_header.Filler1,"RIX",3)) - && SCx_header.Width && SCx_header.Height) - File_error=0; - } - // Fermeture du fichier - fclose(file); - } -} - - -// -- Lire un fichier au format SCx ----------------------------------------- -void Load_SCx(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - word x_pos,y_pos; - long size,real_size; - long file_size; - T_SCx_Header SCx_header; - T_Palette SCx_Palette; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((file=fopen(filename, "rb"))) - { - file_size=File_length_file(file); - - 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)) - && Read_byte(file, &(SCx_header.Planes)) - ) - { - Pre_load(context, SCx_header.Width,SCx_header.Height,file_size,FORMAT_SCx,PIXEL_SIMPLE,0); - if (File_error==0) - { - if (!SCx_header.Planes) - size=sizeof(T_Palette); - else - size=sizeof(T_Components)*(1<Palette,0,sizeof(T_Palette)); - - Palette_64_to_256(SCx_Palette); - memcpy(context->Palette,SCx_Palette,size); - Palette_loaded(context); - - context->Width=SCx_header.Width; - context->Height=SCx_header.Height; - - if (!SCx_header.Planes) - { // 256 couleurs (raw) - LBM_buffer=(byte *)malloc(context->Width); - - for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) - { - if (Read_bytes(file,LBM_buffer,context->Width)) - for (x_pos=0; x_posWidth;x_pos++) - Set_pixel(context, x_pos,y_pos,LBM_buffer[x_pos]); - else - File_error=2; - } - } - else - { // moins de 256 couleurs (planar) - size=((context->Width+7)>>3)*SCx_header.Planes; - real_size=(size/SCx_header.Planes)<<3; - LBM_buffer=(byte *)malloc(size); - HBPm1=SCx_header.Planes-1; - Image_HAM=0; - - for (y_pos=0;(y_posHeight) && (!File_error);y_pos++) - { - if (Read_bytes(file,LBM_buffer,size)) - Draw_ILBM_line(context, y_pos,real_size); - else - File_error=2; - } - } - free(LBM_buffer); - LBM_buffer = NULL; - } - else - File_error=1; - } - } - else - File_error=1; - - fclose(file); - } - else - File_error=1; -} - -// -- Sauver un fichier au format SCx --------------------------------------- -void Save_SCx(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - short x_pos,y_pos; - T_SCx_Header SCx_header; - byte last_char; - - last_char=strlen(context->File_name)-1; - if (context->File_name[last_char]=='?') - { - if (context->Width<=320) - context->File_name[last_char]='I'; - else - { - if (context->Width<=360) - context->File_name[last_char]='Q'; - else - { - if (context->Width<=640) - context->File_name[last_char]='F'; - else - { - if (context->Width<=800) - context->File_name[last_char]='N'; - else - context->File_name[last_char]='O'; - } - } - } - } - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - T_Palette palette_64; - memcpy(palette_64,context->Palette,sizeof(T_Palette)); - Palette_256_to_64(palette_64); - - memcpy(SCx_header.Filler1,"RIX3",4); - SCx_header.Width=context->Width; - SCx_header.Height=context->Height; - SCx_header.Filler2=0xAF; - SCx_header.Planes=0x00; - - 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) - && Write_byte(file, SCx_header.Planes) - && Write_bytes(file,&palette_64,sizeof(T_Palette)) - ) - { - Init_write_buffer(); - - for (y_pos=0; ((y_posHeight) && (!File_error)); y_pos++) - for (x_pos=0; x_posWidth; x_pos++) - Write_one_byte(file,Get_pixel(context, x_pos,y_pos)); - - End_write(file); - fclose(file); - - if (File_error) - remove(filename); - } - else // Error d'écriture (disque plein ou protégé) - { - fclose(file); - remove(filename); - File_error=1; - } - } - else - { - fclose(file); - remove(filename); - File_error=1; - } -} - -//////////////////////////////////// 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 //////////////////////////////////// - -#ifndef __no_pnglib__ - -// -- Tester si un fichier est au format PNG -------------------------------- -void Test_PNG(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - byte png_header[8]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=1; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - // Lecture du header du fichier - if (Read_bytes(file,png_header,8)) - { - if ( !png_sig_cmp(png_header, 0, 8)) - File_error=0; - } - 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) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - byte png_header[8]; - byte row_pointers_allocated; - png_bytep trans; - int num_trans; - png_color_16p trans_values; - - png_structp png_ptr; - png_infop info_ptr; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((file=fopen(filename, "rb"))) - { - // Load header (8 first bytes) - if (Read_bytes(file,png_header,8)) - { - // Do we recognize a png file signature ? - if ( !png_sig_cmp(png_header, 0, 8)) - { - // Prepare internal PNG loader - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr) - { - // Prepare internal PNG loader - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr) - { - png_byte color_type; - png_byte bit_depth; - png_voidp user_chunk_ptr; - - // Setup a return point. If a pnglib loading error occurs - // in this if(), the else will be executed. - if (!setjmp(png_jmpbuf(png_ptr))) - { - png_init_io(png_ptr, file); - // Inform pnglib we already loaded the header. - png_set_sig_bytes(png_ptr, 8); - - // 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 = 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 - // image format of libpng) - if (color_type == PNG_COLOR_TYPE_PALETTE - || color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA - || color_type == PNG_COLOR_TYPE_RGB - || color_type == PNG_COLOR_TYPE_RGB_ALPHA - ) - { - int num_text; - png_text *text_ptr; - - int unit_type; - png_uint_32 res_x; - png_uint_32 res_y; - - // Comment (tEXt) - context->Comment[0]='\0'; // Clear the previous comment - if ((num_text=png_get_text(png_ptr, info_ptr, &text_ptr, NULL))) - { - while (num_text--) - { - if (!strcmp(text_ptr[num_text].key,"Title")) - { - int size; - size = Min(text_ptr[num_text].text_length, COMMENT_SIZE); - strncpy(context->Comment, text_ptr[num_text].text, size); - context->Comment[size]='\0'; - break; // Skip all others tEXt chunks - } - } - } - // Pixel Ratio (pHYs) - if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) - { - // Ignore unit, and use the X/Y ratio as a hint for - // WIDE or TALL pixels - if (res_x>0 && res_y>0) - { - if (res_y/res_x>1) - { - context->Ratio=PIXEL_WIDE; - } - else if (res_x/res_y>1) - { - context->Ratio=PIXEL_TALL; - } - } - } - if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) - 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,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) - { - int x,y; - png_colorp palette; - int num_palette; - - // 16-bit images - if (bit_depth == 16) - { - // Reduce to 8-bit - png_set_strip_16(png_ptr); - } - else if (bit_depth < 8) - { - // Inform libpng we want one byte per pixel, - // even though the file was less than 8bpp - png_set_packing(png_ptr); - } - - // Images with alpha channel - if (color_type & PNG_COLOR_MASK_ALPHA) - { - // Tell libpng to ignore it - png_set_strip_alpha(png_ptr); - } - - // Greyscale images : - if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - // Map low bpp greyscales to full 8bit (0-255 range) - if (bit_depth < 8) - { - #if (PNG_LIBPNG_VER_MAJOR <= 1) && (PNG_LIBPNG_VER_MINOR < 4) - // Works well with png 1.2.8, but deprecated in 1.4 ... - png_set_gray_1_2_4_to_8(png_ptr); - #else - // ...where this seems to replace it: - png_set_expand_gray_1_2_4_to_8(png_ptr); - #endif - } - - // Create greyscale palette - for (x=0;x<256;x++) - { - context->Palette[x].R=x; - context->Palette[x].G=x; - context->Palette[x].B=x; - } - } - else if (color_type == PNG_COLOR_TYPE_PALETTE) // Palette images - { - - if (bit_depth < 8) - { - // Clear unused colors - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - } - // Load the palette - png_get_PLTE(png_ptr, info_ptr, &palette, - &num_palette); - for (x=0;xPalette[x].R=palette[x].red; - context->Palette[x].G=palette[x].green; - context->Palette[x].B=palette[x].blue; - } - free(palette); - palette = NULL; - } - if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) - { - Palette_loaded(context); - } - // Transparency (tRNS) - if (png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)) - { - if (color_type == PNG_COLOR_TYPE_PALETTE && trans!=NULL) - { - int i; - for (i=0; iTransparent_color = i; - context->Background_transparent = 1; - break; - } - } - } - else if ((color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_RGB) && trans_values!=NULL) - { - // In this case, num_trans is supposed to be "1", - // and trans_values[0] contains the reference color - // (RGB triplet) that counts as transparent. - - // Ideally, we should reserve this color in the palette, - // (so it's not merged and averaged with a neighbor one) - // and after creating the optimized palette, find its - // index and mark it transparent. - - // Current implementation: ignore. - } - } - - 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); - - // Allocate row pointers - Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height); - row_pointers_allocated = 0; - - /* read file */ - if (!setjmp(png_jmpbuf(png_ptr))) - { - if (color_type == PNG_COLOR_TYPE_GRAY - || color_type == PNG_COLOR_TYPE_GRAY_ALPHA - || color_type == PNG_COLOR_TYPE_PALETTE - ) - { - // 8bpp - - for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); - row_pointers_allocated = 1; - - png_read_image(png_ptr, Row_pointers); - - for (y=0; yHeight; y++) - for (x=0; xWidth; x++) - Set_pixel(context, x, y, Row_pointers[y][x]); - } - else - { - switch (context->Type) - { - case CONTEXT_PREVIEW: - // 24bpp - - // It's a preview - // Unfortunately we need to allocate loads of memory - for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr)); - row_pointers_allocated = 1; - - png_read_image(png_ptr, Row_pointers); - - for (y=0; yHeight; y++) - for (x=0; xWidth; x++) - Set_pixel_24b(context, x, y, Row_pointers[y][x*3],Row_pointers[y][x*3+1],Row_pointers[y][x*3+2]); - break; - case CONTEXT_MAIN_IMAGE: - case CONTEXT_BRUSH: - case CONTEXT_SURFACE: - // It's loading an actual image - // We'll save memory and time by writing directly into - // our pre-allocated 24bit buffer - for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*) (&(context->Buffer_image_24b[y * context->Width])); - png_read_image(png_ptr, Row_pointers); - break; - - } - } - } - else - File_error=2; - - /* cleanup heap allocation */ - if (row_pointers_allocated) - { - for (y=0; yHeight; y++) { - free(Row_pointers[y]); - Row_pointers[y] = NULL; - } - - } - free(Row_pointers); - Row_pointers = NULL; - } - else - File_error=2; - } - else - // Unsupported image type - File_error=1; - } - else - File_error=1; - } - else - File_error=1; - } - } - /*Close_lecture();*/ - } - else // Lecture header impossible: Error ne modifiant pas l'image - File_error=1; - - fclose(file); - } - else // Ouv. fichier impossible: Error ne modifiant pas l'image - File_error=1; -} - -void Save_PNG(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - int y; - 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; - Row_pointers = NULL; - - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - /* initialisation */ - if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) - && (info_ptr = png_create_info_struct(png_ptr))) - { - - if (!setjmp(png_jmpbuf(png_ptr))) - { - png_init_io(png_ptr, file); - - /* en-tete */ - if (!setjmp(png_jmpbuf(png_ptr))) - { - png_set_IHDR(png_ptr, info_ptr, context->Width, context->Height, - 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - png_set_PLTE(png_ptr, info_ptr, (png_colorp)context->Palette, 256); - { - // 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]) - { - text_ptr[1].text=context->Comment; - text_ptr[1].text_length=strlen(context->Comment); - nb_text_chunks=2; - } - png_set_text(png_ptr, info_ptr, text_ptr, nb_text_chunks); - } - if (context->Background_transparent) - { - // Transparency - byte opacity[256]; - // Need to fill a segment with '255', up to the transparent color - // which will have a 0. This piece of data (1 to 256 bytes) - // will be stored in the file. - memset(opacity, 255,context->Transparent_color); - opacity[context->Transparent_color]=0; - png_set_tRNS(png_ptr, info_ptr, opacity, (int)1 + context->Transparent_color,0); - } - switch(Pixel_ratio) - { - case PIXEL_WIDE: - case PIXEL_WIDE2: - png_set_pHYs(png_ptr, info_ptr, 3000, 6000, PNG_RESOLUTION_METER); - break; - case PIXEL_TALL: - case PIXEL_TALL2: - png_set_pHYs(png_ptr, info_ptr, 6000, 3000, PNG_RESOLUTION_METER); - break; - default: - 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 */ - Row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * context->Height); - pixel_ptr = context->Target_address; - for (y=0; yHeight; y++) - Row_pointers[y] = (png_byte*)(pixel_ptr+y*context->Pitch); - - if (!setjmp(png_jmpbuf(png_ptr))) - { - png_write_image(png_ptr, Row_pointers); - - /* cloture png */ - if (!setjmp(png_jmpbuf(png_ptr))) - { - png_write_end(png_ptr, NULL); - } - else - File_error=1; - } - else - File_error=1; - } - else - File_error=1; - } - else - { - File_error=1; - } - png_destroy_write_struct(&png_ptr, &info_ptr); - } - else - File_error=1; - // fermeture du fichier - fclose(file); - } - - // S'il y a eu une erreur de sauvegarde, on ne va tout de même pas laisser - // ce fichier pourri trainait... Ca fait pas propre. - if (File_error) - remove(filename); - - if (Row_pointers) - { - free(Row_pointers); - Row_pointers=NULL; - } -} -#endif // __no_pnglib__ - diff --git a/project/jni/application/grafx2/grafx2/src/filesel.c b/project/jni/application/grafx2/grafx2/src/filesel.c deleted file mode 100644 index f0eec93cf..000000000 --- a/project/jni/application/grafx2/grafx2/src/filesel.c +++ /dev/null @@ -1,2037 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include - -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - #include - #include - #include -#elif defined (__MINT__) - #include - #include -#elif defined(__WIN32__) - #include - #include - #include -#else - #include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "errors.h" -#include "io.h" -#include "windows.h" -#include "sdlscreen.h" -#include "loadsave.h" -#include "mountlist.h" -#include "engine.h" -#include "readline.h" -#include "input.h" -#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 - -// -- 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 - -T_Fileselector Filelist; - -/// Name of the current directory -//static char Selector_directory[1024]; -/// Filename (without directory) of the highlighted file -static char Selector_filename[256]; - -// Conventions: -// -// * Le fileselect modifie le répertoire courant. Ceci permet de n'avoir -// qu'un findfirst dans le répertoire courant à faire: - -void Recount_files(T_Fileselector *list) -{ - T_Fileselector_item *item; - - list->Nb_files=0; - list->Nb_directories=0; - list->Nb_elements=0; - - for (item = list->First; item != NULL; item = item->Next) - { - if (item->Type == 0) - list->Nb_files ++; - else - list->Nb_directories ++; - list->Nb_elements ++; - } - - if (list->Index) - { - free(list->Index); - list->Index = NULL; - } - - if (list->Nb_elements>0) - { - int i; - - list->Index = (T_Fileselector_item **) malloc(list->Nb_elements * sizeof(T_Fileselector_item **)); - if (list->Index) - { - // Fill the index - for (item = list->First, i=0; item != NULL; item = item->Next, i++) - { - list->Index[i] = item; - } - } - // If the malloc failed, we're probably in trouble, but I don't know - // how to recover from that..I'll just make the index bulletproof. - } -} - -// -- Destruction de la liste chaînée --------------------------------------- -void Free_fileselector_list(T_Fileselector *list) -// Cette procédure détruit la chaine des fichiers. Elle doit être appelée -// avant de rappeler la fonction Read_list_of_files, ainsi qu'en fin de -// programme. -{ - // Pointeur temporaire de destruction - T_Fileselector_item * temp_item; - - while (list->First!=NULL) - { - // On mémorise l'adresse du premier élément de la liste - temp_item =list->First; - // On fait avancer la tête de la liste - list->First=list->First->Next; - // Et on efface l'ancien premier élément de la liste - free(temp_item); - temp_item = NULL; - } - Recount_files(list); -} - -char * Format_filename(const char * fname, word max_length, int type) -{ - 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= max_length-1) - result[max_length-2]=ELLIPSIS_CHARACTER; - } - else - { - // Initialize as all spaces - for (c = 0; c max_length-6) - { - result[max_length-6]=ELLIPSIS_CHARACTER; - break; - } - result[c]=fname[c]; - } - - // 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=max_length-4;fname[c]!='\0' && other_cursor < max_length-1;c++,other_cursor++) - result[other_cursor]=fname[c]; - } - } - return result; -} - - -// -- Rajouter a la liste des elements de la liste un element --------------- -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. -{ - // Working element - T_Fileselector_item * temp_item; - - // Allocate enough room for one struct + the visible label - temp_item=(T_Fileselector_item *)malloc(sizeof(T_Fileselector_item)+strlen(short_name)); - - // 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; -} - -/// -/// Checks if a file has the requested file extension. -/// The extension string can end with a ';' (remainder is ignored) -/// This function allows wildcard '?', and '*' if it's the only character. -int Check_extension(const char *filename, const char * filter) -{ - int pos_last_dot = -1; - int c = 0; - - if (filter[0] == '*') - return 1; - // On recherche la position du dernier . dans le nom - for (c = 0; filename[c]!='\0'; c++) - if (filename[c]=='.') - pos_last_dot = c; - // Fichier sans extension (ca arrive) - if (pos_last_dot == -1) - return (filter[0] == '\0' || filter[0] == ';'); - - // Vérification caractère par caractère, case-insensitive. - c = 0; - while (1) - { - if (filter[c] == '\0' || filter[c] == ';') - return filename[pos_last_dot + 1 + c] == '\0'; - - if (filter[c] != '?' && - tolower(filter[c]) != tolower(filename[pos_last_dot + 1 + c])) - return 0; - - c++; - } -} - - -// -- Lecture d'une liste de fichiers --------------------------------------- -void Read_list_of_files(T_Fileselector *list, byte selected_format) -// Cette procédure charge dans la liste chainée les fichiers dont l'extension -// correspond au format demandé. -{ - DIR* current_directory; //Répertoire courant - struct dirent* entry; // Structure de lecture des éléments - char * filter = "*"; // Extension demandée - struct stat Infos_enreg; - char * current_path; - - // Tout d'abord, on déduit du format demandé un filtre à utiliser: - filter = Get_fileformat(selected_format)->Extensions; - - // Ensuite, on vide la liste actuelle: - Free_fileselector_list(list); - // 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 - if ( !strcmp(entry->d_name, ".")) - { - continue; - } - stat(entry->d_name,&Infos_enreg); - // et que l'élément trouvé est un répertoire - if( S_ISDIR(Infos_enreg.st_mode) && - // et que c'est ".." - (!strcmp(entry->d_name, PARENT_DIR) || - // ou qu'il n'est pas caché - Config.Show_hidden_directories || - !File_is_hidden(entry->d_name, entry->d_name))) - { - // On rajoute le répertoire à la liste - 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 - (Config.Show_hidden_files || //Il n'est pas caché - !File_is_hidden(entry->d_name, entry->d_name))) - { - const char * ext = filter; - while (ext!=NULL) - { - if (Check_extension(entry->d_name, ext)) - { - // On rajoute le fichier à la liste - 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; - } - else - { - ext = strchr(ext, ';'); - if (ext) - ext++; - } - } - } - } - -#if defined(__MORPHOS__) || defined(__AROS__) || defined (__amigaos4__) || defined(__amigaos__) - 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); -} - -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) -void bstrtostr( BSTR in, STRPTR out, TEXT max ) -{ - STRPTR iptr; - dword i; - - iptr = BADDR( in ); - - if( max > iptr[0] ) max = iptr[0]; - -#if defined(__AROS__) - for ( i=0 ; iNb_files=0; - list->Nb_directories=0; - - #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - { - struct DosList *dl; - char tmp[256]; - - dl = LockDosList( LDF_VOLUMES | LDF_READ ); - if( dl ) - { - while( ( dl = NextDosEntry( dl, LDF_VOLUMES | LDF_READ ) ) ) - { - bstrtostr( dl->dol_Name, tmp, 254 ); - strcat( tmp, ":" ); - Add_element_to_list(list, tmp, Format_filename(tmp, name_length, 2), 2, ICON_NONE ); - list->Nb_directories++; - } - UnLockDosList( LDF_VOLUMES | LDF_READ ); - } - } - #elif defined (__WIN32__) - { - char drive_name[]="A:\\"; - 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++) - { - if ( (1 << bit_index) & drive_bits ) - { - // On a ce lecteur, il faut maintenant déterminer son type "physique". - // pour profiter des jolies icones de X-man. - 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: - icon=ICON_CDROM; - break; - case DRIVE_REMOTE: - icon=ICON_NETWORK; - break; - case DRIVE_REMOVABLE: - icon=ICON_FLOPPY_3_5; - break; - case DRIVE_FIXED: - icon=ICON_HDD; - break; - default: - icon=ICON_NETWORK; - break; - } - drive_name[0]='A'+bit_index; - Add_element_to_list(list, drive_name, Format_filename(drive_name,name_length-1,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,name_length,2),2,ICON_NONE); - list->Nb_directories++; - drive_index++; - } - } - - #else - { - //Sous les différents unix, on va mettre - // un disque dur qui pointera vers la racine, - // et un autre vers le home directory de l'utilisateur. - - // Ensuite on utilise read_file_system_list pour compléter - - struct mount_entry* mount_points_list; - struct mount_entry* next; - - #if defined(__BEOS__) || defined(__HAIKU__) - char * home_dir = getenv("$HOME"); - #else - char * home_dir = getenv("HOME"); - #endif - Add_element_to_list(list, "/", Format_filename("/",name_length,2), 2, ICON_NONE); - list->Nb_directories++; - if(home_dir) - { - Add_element_to_list(list, home_dir, Format_filename(home_dir, name_length, 2), 2, ICON_NONE); - list->Nb_directories++; - } - - mount_points_list = read_file_system_list(0); - - while(mount_points_list != NULL) - { - 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, Format_filename(mount_points_list->me_mountdir, name_length, 2), 2, ICON_NONE); - list->Nb_directories++; - } - next = mount_points_list -> me_next; - #if !(defined(__macosx__) || defined(__FreeBSD__)) - free(mount_points_list -> me_type); - #endif - free(mount_points_list -> me_devname); - free(mount_points_list -> me_mountdir); - free(mount_points_list); - mount_points_list = next; - } - - } - #endif - - 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) -// Tri la liste chainée existante dans l'ordre suivant: -// -// * Les répertoires d'abord, dans l'ordre alphabétique de leur nom -// * Les fichiers ensuite, dans l'ordre alphabétique de leur nom -{ - byte list_is_sorted; // Booléen "La liste est triée" - byte need_swap; // Booléen "Il faut inverser les éléments" - T_Fileselector_item * prev_item; - T_Fileselector_item * current_item; - T_Fileselector_item * next_item; - T_Fileselector_item * next_to_next_item; - - // Check there are at least two elements before sorting - if (list->First && list->First->Next) - { - do - { - // Par défaut, on considère que la liste est triée - list_is_sorted=1; - - current_item=list->First; - next_item=current_item->Next; - - while ( (current_item!=NULL) && (next_item!=NULL) ) - { - // On commence par supposer qu'il n'y pas pas besoin d'inversion - need_swap=0; - - // Ensuite, on vérifie si les deux éléments sont bien dans l'ordre ou - // non: - - // Si l'élément courant est un fichier est que le suivant est - // un répertoire -> need_swap - if ( current_item->Type < next_item->Type ) - need_swap=1; - // 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) && - (FILENAME_COMPARE(current_item->Full_name,next_item->Full_name)>0) ) - need_swap=1; - - - if (need_swap) - { - // Si les deux éléments nécessitent d'être inversé: - - // On les inverses: - - // On note avant tout les éléments qui encapsulent nos deux amis - prev_item =current_item->Previous; - next_to_next_item=next_item->Next; - - // On permute le chaînage des deux éléments entree eux - current_item->Next =next_to_next_item; - current_item->Previous=next_item; - next_item->Next =current_item; - next_item->Previous=prev_item; - - // On tente un chaînage des éléments encapsulant les compères: - if (prev_item!=NULL) - prev_item->Next=next_item; - if (next_to_next_item!=NULL) - next_to_next_item->Previous=current_item; - - // On fait bien attention à modifier la tête de liste en cas de besoin - if (current_item==list->First) - list->First=next_item; - - // Ensuite, on se prépare à étudier les éléments précédents: - current_item=prev_item; - - // Et on constate que la liste n'était pas encore génialement triée - list_is_sorted=0; - } - else - { - // Si les deux éléments sont dans l'ordre: - - // On passe aux suivants - current_item=current_item->Next; - next_item=next_item->Next; - } - } - } - while (!list_is_sorted); - } - // Force a recount / re-index - Recount_files(list); -} - -T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index) -{ - // Safety - if (index >= list->Nb_elements) - index=list->Nb_elements-1; - - if (list->Index) - { - return list->Index[index]; - } - else - { - // Index not available. - // Can only happen in case of malloc error. - // Fall back anyway on iterative search - - T_Fileselector_item * item = list->First; - for (;index>0;index--) - item = item->Next; - - return item; - } - -} - - -// -- Affichage des éléments de la liste de fichier / répertoire ------------ -void Display_file_list(T_Fileselector *list, short offset_first,short selector_offset) -// -// offset_first = Décalage entre le premier fichier visible dans le -// sélecteur et le premier fichier de la liste -// -// selector_offset = Décalage entre le premier fichier visible dans le -// sélecteur et le fichier sélectionné dans la liste -// -{ - T_Fileselector_item * current_item; - byte index; // index du fichier qu'on affiche (0 -> 9) - byte text_color; - byte background_color; - - - // On vérifie s'il y a au moins 1 fichier dans la liste: - if (list->Nb_elements>0) - { - // On commence par chercher à pointer sur le premier fichier visible: - current_item = Get_item_by_index(list, offset_first); - - // Pour chacun des 10 éléments inscriptibles à l'écran - for (index=0;index<10;index++) - { - // S'il est sélectionné: - if (!selector_offset) - { - // Si c'est un fichier - if (current_item->Type==0) - text_color=SELECTED_FILE_COLOR; - else - text_color=SELECTED_DIRECTORY_COLOR; - - background_color=SELECTED_BACKGROUND_COLOR; - } - else - { - // Si c'est un fichier - if (current_item->Type==0) - text_color=NORMAL_FILE_COLOR; - else - text_color=NORMAL_DIRECTORY_COLOR; - - background_color=NORMAL_BACKGROUND_COLOR; - } - - // On affiche l'élément - 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--; - current_item=current_item->Next; - if (!current_item) - break; - } // End de la boucle d'affichage - - } // End du test d'existence de fichiers -} - - -// -- Récupérer le libellé d'un élément de la liste ------------------------- -void Get_selected_item(T_Fileselector *list, short offset_first,short selector_offset,char * label,int *type) -// -// offset_first = Décalage entre le premier fichier visible dans le -// sélecteur et le premier fichier de la liste -// -// selector_offset = Décalage entre le premier fichier visible dans le -// sélecteur et le fichier à récupérer -// -// label = str de réception du libellé de l'élément -// -// type = Récupération du type: 0 fichier, 1 repertoire, 2 lecteur. -// Passer NULL si pas interessé. -{ - T_Fileselector_item * current_item; - - // On vérifie s'il y a au moins 1 fichier dans la liste: - if (list->Nb_elements>0) - { - // On commence par chercher à pointer sur le premier fichier visible: - // Ensuite, on saute autant d'éléments que le décalage demandé: - current_item = Get_item_by_index(list, offset_first + selector_offset); - - // On recopie la chaîne - strcpy(label, current_item->Full_name); - - if (type != NULL) - *type=current_item->Type; - } // End du test d'existence de fichiers -} - - -// ----------------- Déplacements dans la liste de fichiers ----------------- - -void Selector_scroll_down(short * offset_first,short * selector_offset) -// Fait scroller vers le bas le sélecteur de fichier... (si possible) -{ - if ( ((*selector_offset)<9) - && ( (*selector_offset)+1 < Filelist.Nb_elements ) ) - // Si la sélection peut descendre - Display_file_list(&Filelist, *offset_first,++(*selector_offset)); - else // Sinon, descendre la fenêtre (si possible) - if ((*offset_first)+100) - // Si la sélection peut monter - Display_file_list(&Filelist, *offset_first,--(*selector_offset)); - else // Sinon, monter la fenêtre (si possible) - if ((*offset_first)>0) - Display_file_list(&Filelist, --(*offset_first),*selector_offset); -} - - -void Selector_page_down(short * offset_first,short * selector_offset, short lines) -{ - if (Filelist.Nb_elements-1>*offset_first+*selector_offset) - { - if (*selector_offset<9) - { - if (Filelist.Nb_elements<10) - { - *offset_first=0; - *selector_offset=Filelist.Nb_elements-1; - } - else *selector_offset=9; - } - else - { - if (Filelist.Nb_elements>*offset_first+18) - *offset_first+=lines; - else - { - *offset_first=Filelist.Nb_elements-10; - *selector_offset=9; - } - } - } - Display_file_list(&Filelist, *offset_first,*selector_offset); -} - - -void Selector_page_up(short * offset_first,short * selector_offset, short lines) -{ - if (*offset_first+*selector_offset>0) - { - if (*selector_offset>0) - *selector_offset=0; - else - { - if (*offset_first>lines) - *offset_first-=lines; - else - *offset_first=0; - } - } - Display_file_list(&Filelist, *offset_first,*selector_offset); -} - - -void Selector_end(short * offset_first,short * selector_offset) -{ - if (Filelist.Nb_elements<10) - { - *offset_first=0; - *selector_offset=Filelist.Nb_elements-1; - } - else - { - *offset_first=Filelist.Nb_elements-10; - *selector_offset=9; - } - Display_file_list(&Filelist, *offset_first,*selector_offset); -} - - -void Selector_home(short * offset_first,short * selector_offset) -{ - Display_file_list(&Filelist, (*offset_first)=0,(*selector_offset)=0); -} - - - -short Compute_click_offset_in_fileselector(void) -/* - Renvoie le décalage dans le sélecteur de fichier sur lequel on a clické. - Renvoie le décalage du dernier fichier si on a clické au delà. - Renvoie -1 si le sélecteur est vide. -*/ -{ - short computed_offset; - - computed_offset=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-95)>>3; - if (computed_offset>=Filelist.Nb_elements) - computed_offset=Filelist.Nb_elements-1; - - return computed_offset; -} - -void Display_bookmark(T_Dropdown_button * Button, int bookmark_number) -{ - if (Config.Bookmark_directory[bookmark_number]) - { - int label_size; - // Libellé - Print_in_window_limited(Button->Pos_X+3+10,Button->Pos_Y+2,Config.Bookmark_label[bookmark_number],8,MC_Black,MC_Light); - label_size=strlen(Config.Bookmark_label[bookmark_number]); - if (label_size<8) - Window_rectangle(Button->Pos_X+3+10+label_size*8,Button->Pos_Y+2,(8-label_size)*8,8,MC_Light); - // Menu apparait sur clic droit - Button->Active_button=RIGHT_SIDE; - // item actifs - Window_dropdown_clear_items(Button); - Window_dropdown_add_item(Button,0,"Set"); - Window_dropdown_add_item(Button,1,"Rename"); - Window_dropdown_add_item(Button,2,"Clear"); - } - else - { - // Libellé - Print_in_window(Button->Pos_X+3+10,Button->Pos_Y+2,"--------",MC_Dark,MC_Light); - // Menu apparait sur clic droit ou gauche - Button->Active_button=RIGHT_SIDE|LEFT_SIDE; - // item actifs - Window_dropdown_clear_items(Button); - Window_dropdown_add_item(Button,0,"Set"); - } -} - -//------------------------ Chargements et sauvegardes ------------------------ - -void Print_current_directory(void) -// -// Affiche Main_current_directory sur 37 caractères -// -{ - char temp_name[MAX_DISPLAYABLE_PATH+1]; // Nom tronqué - int length; // length du répertoire courant - int index; // index de parcours de la chaine complète - - Window_rectangle(10,84,37*8,8,MC_Light); - - length=strlen(Main_current_directory); - if (length>MAX_DISPLAYABLE_PATH) - { // Doh! il va falloir tronquer le répertoire (bouh !) - - // On commence par copier bêtement les 3 premiers caractères (e.g. "C:\") - for (index=0;index<3;index++) - temp_name[index]=Main_current_directory[index]; - - // On y rajoute 3 petits points: - strcpy(temp_name+3,"..."); - - // Ensuite, on cherche un endroit à partir duquel on pourrait loger tout - // le reste de la chaine (Ouaaaaaah!!! Vachement fort le mec!!) - for (index++;indexNb_elements=Filelist.Nb_elements; - button->Position=Position; - 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); - // On affiche les nouveaux: - Display_file_list(&Filelist, Position,offset); - - Update_window_area(8-1,95-1,144+2,80+2); - - // On récupère le nom du schmilblick à "accéder" - Get_selected_item(&Filelist, Position,offset,Selector_filename,&Selected_type); - // On affiche le nouveau nom de fichier - Print_filename_in_fileselector(); - // On affiche le nom du répertoire courant - Print_current_directory(); -} - - -void Reload_list_of_files(byte filter, T_Scroller_button * button) -{ - Read_list_of_files(&Filelist, filter); - Sort_list_of_files(&Filelist); - // - // Check and fix the fileselector positions, because - // the directory content may have changed. - // - // Make the offset absolute - Main_fileselector_offset += Main_fileselector_position; - // Ensure it's within limits - if (Main_fileselector_offset >= Filelist.Nb_elements) - { - Main_fileselector_offset = Filelist.Nb_elements-1; - } - // Ensure the position doesn't show "too many files" - if (Main_fileselector_position!=0 && Main_fileselector_position>(Filelist.Nb_elements-10)) - { - if (Filelist.Nb_elements<10) - { - Main_fileselector_position=0; - } - else - { - Main_fileselector_position=Filelist.Nb_elements-10; - } - } - // Restore the offset as relative to the position. - Main_fileselector_offset -= Main_fileselector_position; - - Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,button); -} - -void Scroll_fileselector(T_Scroller_button * file_scroller) -{ - char old_filename[MAX_PATH_CHARACTERS]; - - strcpy(old_filename,Selector_filename); - - // On regarde si la liste a bougé - if (file_scroller->Position!=Main_fileselector_position) - { - // Si c'est le cas, il faut mettre à jour la jauge - file_scroller->Position=Main_fileselector_position; - Window_draw_slider(file_scroller); - } - // On récupére le nom du schmilblick à "accéder" - Get_selected_item(&Filelist, Main_fileselector_position,Main_fileselector_offset,Selector_filename,&Selected_type); - if (strcmp(old_filename,Selector_filename)) - New_preview_is_needed=1; - - // On affiche le nouveau nom de fichier - Print_filename_in_fileselector(); - Display_cursor(); -} - - -short Find_file_in_fileselector(T_Fileselector *list, const char * fname) -{ - T_Fileselector_item * item; - short index; - short close_match=0; - - index=0; - for (item=list->First; item!=NULL; item=item->Next) - { - if (strcmp(item->Full_name,fname)==0) - return index; - if (strcasecmp(item->Full_name,fname)==0) - close_match=index; - - index++; - } - - return close_match; -} - -void Highlight_file(short index) -{ - - if ((Filelist.Nb_elements<=10) || (index<5)) - { - Main_fileselector_position=0; - Main_fileselector_offset=index; - } - else - { - if (index>=Filelist.Nb_elements-5) - { - Main_fileselector_position=Filelist.Nb_elements-10; - Main_fileselector_offset=index-Main_fileselector_position; - } - else - { - Main_fileselector_position=index-4; - Main_fileselector_offset=4; - } - } -} - - -short Find_filename_match(T_Fileselector *list, char * fname) -{ - short best_match; - T_Fileselector_item * current_item; - 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) - || (Config.Find_file_fast==(current_item->Type+1)) ) - { - // On compare et si c'est mieux, on stocke dans Meilleur_nom - for (counter=0; fname[counter]!='\0' && tolower(current_item->Full_name[counter])==tolower(fname[counter]); counter++); - if (counter>matching_letters) - { - matching_letters=counter; - best_match=item_number; - } - } - item_number++; - } - - 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, 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, 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) - // load=1 => On affiche le menu du bouton LOAD - // load=0 => On affiche le menu du bouton SAVE -{ - short clicked_button; - T_Scroller_button * file_scroller; - 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 save_filename[MAX_PATH_CHARACTERS]; - char initial_comment[COMMENT_SIZE+1]; - 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); - else - window_shortcut = load?SPECIAL_LOAD_BRUSH:SPECIAL_SAVE_BRUSH; - - // Backup data that needs be restored on "cancel" - initial_back_color=Back_color; - strcpy(initial_comment,context->Comment); - - if (load) - { - if (context->Type == CONTEXT_MAIN_IMAGE) - Open_window(310,200,"Load picture"); - else - Open_window(310,200,"Load brush"); - Window_set_normal_button(198,180,51,14,"Load",0,1,SDLK_RETURN); // 1 - } - else - { - if (context->Type == CONTEXT_MAIN_IMAGE) - Open_window(310,200,"Save picture"); - else - Open_window(310,200,"Save brush"); - Window_set_normal_button(198,180,51,14,"Save",0,1,SDLK_RETURN); // 1 - if (Main_format<=FORMAT_ALL_FILES) // Correction du *.* - { - Main_format=Main_fileformat; - Main_fileselector_position=0; - Main_fileselector_offset=0; - } - - if (Get_fileformat(Main_format)->Save == NULL) // Correction d'un format insauvable - { - Main_format=DEFAULT_FILEFORMAT; - Main_fileselector_position=0; - Main_fileselector_offset=0; - } - // Affichage du commentaire - if (Get_fileformat(Main_format)->Comment) - 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 - Window_set_normal_button(7,180,51,14,"Delete",0,1,SDLK_DELETE); // 3 - - // Frame autour des infos sur le fichier de dessin - Window_display_frame_in(6, 44,299, 37); - // Frame autour de la preview - Window_display_frame_in(181,93,124,84); - // Frame autour du fileselector - Window_display_frame_in(6,93,148,84); - - // Fileselector - Window_set_special_button(9,95,144,80); // 4 - - // Scroller du fileselector - file_scroller = Window_set_scroller_button(160,94,82,1,10,0); // 5 - - // Dropdown pour les formats de fichier - formats_dropdown= - Window_set_dropdown_button(68,28,52,11,0, - Get_fileformat(Main_format)->Label, - 1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 6 - - for (format=0; format < Nb_known_formats(); format++) - { - 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); - - // Texte de commentaire des dessins - Print_in_window(9,70,"Txt:",MC_Dark,MC_Light); - Window_set_input_button(43,68,COMMENT_SIZE); // 7 - - // Saisie du nom de fichier - Window_set_input_button(80,46,27); // 8 - - Print_in_window(9,47,"Filename",MC_Dark,MC_Light); - Print_in_window(9,59,"Image:",MC_Dark,MC_Light); - Print_in_window(101,59,"Size:",MC_Dark,MC_Light); - Print_in_window(228,59,"(",MC_Dark,MC_Light); - Print_in_window(292,59,")",MC_Dark,MC_Light); - - // Selecteur de Lecteur / Volume - Window_set_normal_button(7,18,53,23,"",0,1,SDLK_LAST); // 9 - Print_in_window(10,22,"Select",MC_Black,MC_Light); - Print_in_window(14,30,"drive",MC_Black,MC_Light); - - // Bookmarks - for (temp=0;tempPos_X+3,bookmark_dropdown[temp]->Pos_Y+2,ICON_STAR); - Display_bookmark(bookmark_dropdown[temp],temp); - } - // 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__) - static char path[1024]={0}; - chdir(context->File_directory); - Dgetpath(path,0); - strcat(path,PATH_SEPARATOR); - strcpy(Main_current_directory,path); - #else - chdir(context->File_directory); - getcwd(Main_current_directory,256); - #endif - - - } - - // Affichage des premiers fichiers visibles: - Reload_list_of_files(Main_format,file_scroller); - - if (!load) - { - // On initialise le nom de fichier à celui en cours et non pas celui sous - // la barre de sélection - strcpy(Selector_filename,context->File_name); - // On affiche le nouveau nom de fichier - Print_filename_in_fileselector(); - - Highlight_file(Find_file_in_fileselector(&Filelist, context->File_name)); - Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); - } - - New_preview_is_needed=1; - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case -1 : - case 0 : - break; - - case 1 : // Load ou Save - if(load) - { - // Determine the type - if(File_exists(Selector_filename)) - { - Selected_type = 0; - if(Directory_exists(Selector_filename)) Selected_type = 1; - } - else - { - Selected_type = 1; - } - } - else - { - if(Directory_exists(Selector_filename)) Selected_type = 1; - else Selected_type = 0; - } - has_clicked_ok=1; - break; - - case 2 : // Cancel - break; - - case 3 : // Delete - if (Filelist.Nb_elements && (*Selector_filename!='.') && Selected_type!=2) - { - char * message; - Hide_cursor(); - // On affiche une demande de confirmation - if (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) - { - message="Delete file ?"; - } - else - { - message="Remove directory ?"; - } - if (Confirmation_box(message)) - { - // Si c'est un fichier - if (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) - // On efface le fichier (si on peut) - temp=(!remove(Selector_filename)); - else // Si c'est un repertoire - // On efface le repertoire (si on peut) - temp=(!rmdir(Selector_filename)); - - if (temp) // temp indique si l'effacement s'est bien passé - { - // On remonte si c'était le dernier élément de la liste - if (Main_fileselector_position+Main_fileselector_offset==Filelist.Nb_elements-1) - { - if (Main_fileselector_position) - Main_fileselector_position--; - else - if (Main_fileselector_offset) - Main_fileselector_offset--; - } - else // Si ce n'était pas le dernier, il faut faire gaffe à ce - { // que ses copains d'en dessous ne remontent pas trop. - if ( (Main_fileselector_position) - && (Main_fileselector_position+10==Filelist.Nb_elements) ) - { - Main_fileselector_position--; - Main_fileselector_offset++; - } - } - // On relit les informations - Reload_list_of_files(Main_format,file_scroller); - // On demande la preview du nouveau fichier sur lequel on se trouve - New_preview_is_needed=1; - } - else - Error(0); - - // On place la barre de sélection du brouillon au début s'il a le - // même répertoire que l'image principale. - if (!strcmp(Main_current_directory,Spare_current_directory)) - { - Spare_fileselector_position=0; - Spare_fileselector_offset=0; - } - } - } - break; - - case 4 : // Zone d'affichage de la liste de fichiers - Hide_cursor(); - - temp=Compute_click_offset_in_fileselector(); - if (temp>=0) - { - if (temp!=Main_fileselector_offset) - { - // On met à jour le décalage - Main_fileselector_offset=temp; - - // On récupére le nom du schmilblick à "accéder" - Get_selected_item(&Filelist, Main_fileselector_position,Main_fileselector_offset,Selector_filename,&Selected_type); - // On affiche le nouveau nom de fichier - Print_filename_in_fileselector(); - // On affiche à nouveau la liste - Display_file_list(&Filelist, Main_fileselector_position,Main_fileselector_offset); - - // On vient de changer de nom de fichier, donc on doit s'appreter - // a rafficher une preview - New_preview_is_needed=1; - Reset_quicksearch(); - - } - else - { - // En sauvegarde, si on a double-clické sur un répertoire, il - // faut mettre le nom de fichier au nom du répertoire. Sinon, dans - // certains cas, on risque de sauvegarder avec le nom du fichier - // actuel au lieu de changer de répertoire. - if (Main_fileselector_position+Main_fileselector_offsetDefault_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, INPUT_TYPE_STRING); - Display_cursor(); - } - break; - case 8 : // Saisie du nom de fichier - - // Save the filename - strcpy(save_filename, Selector_filename); - - 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. - for(temp=0,dummy=0; ((Selector_filename[temp]) && (!dummy)); temp++) - if (Selector_filename[temp]=='.') - dummy=1; - if (!dummy) - { - if (Get_fileformat(Main_format)->Default_extension) - { - if(!Directory_exists(Selector_filename)) - { - strcat(Selector_filename, "."); - strcat(Selector_filename, Get_fileformat(Main_format)->Default_extension); - } - } - else - { - // put default extension - // (but maybe we should browse through all available ones until we find - // something suitable ?) - if(!Directory_exists(Selector_filename)) - { - strcat(Selector_filename, ".pkm"); - } - } - } - if(load) - { - // Determine the type - if(File_exists(Selector_filename)) - { - Selected_type = 0; - if(Directory_exists(Selector_filename)) Selected_type = 1; - } - else - { - Selected_type = 1; - } - } - else - { - if(Directory_exists(Selector_filename)) Selected_type = 1; - else Selected_type = 0; - } - - // Now load immediately, but only if the user exited readline by pressing ENTER - if (Mouse_K == 0) has_clicked_ok = 1; - } - else - { - // Restore the old filename - strcpy(Selector_filename, save_filename); - Print_filename_in_fileselector(); - } - Display_cursor(); - break; - case 9 : // Volume Select - Hide_cursor(); - // Comme on tombe sur un disque qu'on connait pas, on se place en - // début de liste: - Main_fileselector_position=0; - Main_fileselector_offset=0; - // Affichage des premiers fichiers visibles: - Read_list_of_drives(&Filelist,19); - Sort_list_of_files(&Filelist); - Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); - Display_cursor(); - New_preview_is_needed=1; - Reset_quicksearch(); - break; - default: - if (clicked_button>=10 && clicked_button<10+NB_BOOKMARKS) - { - // Bookmark - char * directory_name; - - switch(Window_attribute2) - { - case -1: // bouton lui-même: aller au répertoire mémorisé - if (Config.Bookmark_directory[clicked_button-10]) - { - strcpy(Selector_filename,Config.Bookmark_directory[clicked_button-10]); - Selected_type=1; - has_clicked_ok=1; - Reset_quicksearch(); - } - break; - - case 0: // Set - free(Config.Bookmark_directory[clicked_button-10]); - Config.Bookmark_directory[clicked_button-10] = NULL; - Config.Bookmark_label[clicked_button-10][0]='\0'; - temp=strlen(Main_current_directory); - Config.Bookmark_directory[clicked_button-10]=malloc(temp+1); - strcpy(Config.Bookmark_directory[clicked_button-10],Main_current_directory); - - directory_name=Find_last_slash(Main_current_directory); - if (directory_name && directory_name[1]!='\0') - directory_name++; - else - directory_name=Main_current_directory; - temp=strlen(directory_name); - strncpy(Config.Bookmark_label[clicked_button-10],directory_name,8); - if (temp>8) - { - Config.Bookmark_label[clicked_button-10][7]=ELLIPSIS_CHARACTER; - Config.Bookmark_label[clicked_button-10][8]='\0'; - } - Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); - break; - - case 1: // Rename - if (Config.Bookmark_directory[clicked_button-10]) - { - // On enlève les "..." avant l'édition - char bookmark_label[8+1]; - 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,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(); - } - break; - - case 2: // Clear - if (Config.Bookmark_directory[clicked_button-10] && Confirmation_box("Erase bookmark ?")) - { - free(Config.Bookmark_directory[clicked_button-10]); - Config.Bookmark_directory[clicked_button-10]=NULL; - Config.Bookmark_label[clicked_button-10][0]='\0'; - Display_bookmark(bookmark_dropdown[clicked_button-10],clicked_button-10); - } - break; - } - } - break; - } - - switch (Key) - { - case SDLK_UNKNOWN : break; - case SDLK_DOWN : // Bas - Reset_quicksearch(); - Hide_cursor(); - Selector_scroll_down(&Main_fileselector_position,&Main_fileselector_offset); - Scroll_fileselector(file_scroller); - Key=0; - break; - case SDLK_UP : // Haut - Reset_quicksearch(); - Hide_cursor(); - Selector_scroll_up(&Main_fileselector_position,&Main_fileselector_offset); - Scroll_fileselector(file_scroller); - Key=0; - break; - case SDLK_PAGEDOWN : // PageDown - 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 - 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 - Reset_quicksearch(); - Hide_cursor(); - Selector_end(&Main_fileselector_position,&Main_fileselector_offset); - Scroll_fileselector(file_scroller); - Key=0; - break; - case SDLK_HOME : // Home - Reset_quicksearch(); - Hide_cursor(); - Selector_home(&Main_fileselector_position,&Main_fileselector_offset); - Scroll_fileselector(file_scroller); - Key=0; - break; - case KEY_MOUSEWHEELDOWN : - Reset_quicksearch(); - Hide_cursor(); - Selector_page_down(&Main_fileselector_position,&Main_fileselector_offset,3); - Scroll_fileselector(file_scroller); - Key=0; - break; - case KEY_MOUSEWHEELUP : - 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 - Reset_quicksearch(); - // Si le choix ".." est bien en tête des propositions... - if (!strcmp(Filelist.First->Full_name,PARENT_DIR)) - { - // On va dans le répertoire parent. - strcpy(Selector_filename,PARENT_DIR); - Selected_type=1; - has_clicked_ok=1; - } - Key=0; - break; - default: - if (clicked_button<=0) - { - short selected_item; - - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Window_help(load?BUTTON_LOAD:BUTTON_SAVE, NULL); - break; - } - if (Is_shortcut(Key,window_shortcut)) - { - clicked_button=2; - break; - } - - selected_item=Quicksearch(&Filelist); - if (selected_item>=0) - { - temp=Main_fileselector_position+Main_fileselector_offset; - Hide_cursor(); - 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; - } - // Key=0; ? - } - else - Reset_quicksearch(); - } - - if (has_clicked_ok) - { - // Si c'est un répertoire, on annule "has_clicked_ok" et on passe - // dedans. - if (Selected_type!=0) - { - Hide_cursor(); - has_clicked_ok=0; - - // On mémorise le répertoire dans lequel on était - if (strcmp(Selector_filename,PARENT_DIR)) - { - strcpy(previous_directory,PARENT_DIR); - } - else - { - Extract_filename(previous_directory, Main_current_directory); - } - - // 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(Find_file_in_fileselector(&Filelist, previous_directory)); - } - else - Error(0); - // Affichage des premiers fichiers visibles: - Prepare_and_display_filelist(Main_fileselector_position,Main_fileselector_offset,file_scroller); - Display_cursor(); - New_preview_is_needed=1; - - // On est dans un nouveau répertoire, donc on remet le quicksearch à 0 - Reset_quicksearch(); - } - else // Sinon on essaye de charger ou sauver le fichier - { - strcpy(context->File_directory,Main_current_directory); - if (!load && !Get_fileformat(Main_format)->Palette_only) - Main_fileformat=Main_format; - save_or_load_image=1; - } - } - - // Gestion du chrono et des previews - if (New_preview_is_needed) - { - // On efface les infos de la preview précédente s'il y en a une - // d'affichée - if (Timer_state==2) - { - Hide_cursor(); - // 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,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 - Window_rectangle(236,59,56,8,MC_Light); - // On efface le format du fichier - Window_rectangle(59,59,5*8,8,MC_Light); - // Affichage du commentaire - if ( (!load) && (Get_fileformat(Main_format)->Comment) ) - { - Print_in_window(45,70,context->Comment,MC_Black,MC_Light); - } - Display_cursor(); - // 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,PREVIEW_WIDTH,PREVIEW_HEIGHT); - } - - New_preview_is_needed=0; - Timer_state=0; // State du chrono = Attente d'un Xème de seconde - // On lit le temps de départ du chrono - Init_chrono(Config.Timer_delay); - } - - if (!Timer_state) // Prendre une nouvelle mesure du chrono et regarder - Check_timer(); // s'il ne faut pas afficher la preview - - if (Timer_state==1) // Il faut afficher la preview - { - if ( (Main_fileselector_position+Main_fileselector_offset>=Filelist.Nb_directories) && (Filelist.Nb_elements) ) - { - T_IO_Context preview_context; - - Init_context_preview(&preview_context, Selector_filename, Main_current_directory); - Hide_cursor(); - - Load_image(&preview_context); - Destroy_context(&preview_context); - - Update_window_area(0,0,Window_width,Window_height); - Display_cursor(); - - } - - Timer_state=2; // On arrête le chrono - } - } - while ( (!has_clicked_ok) && (clicked_button!=2) ); - - if (has_clicked_ok) - { - strcpy(context->File_name, Selector_filename); - strcpy(context->File_directory, Main_current_directory); - if (!load) - context->Format = Main_format; - } - else - { - // Data to restore - strcpy(context->Comment, initial_comment); - } - - - // On restaure les données de l'image qui ont certainement été modifiées - // par la preview. - Set_palette(Main_palette); - Back_color=initial_back_color; - - Compute_optimal_menu_colors(Main_palette); - temp=(Window_pos_Y+(Window_height*Menu_factor_Y) -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file filesel.h -/// Fileselector window, used for loading and saving images and brushes. -////////////////////////////////////////////////////////////////////////////// -#ifndef __FILESEL_H__ -#define __FILESEL_H__ - -#include "struct.h" -#include "loadsave.h" - -byte Button_Load_or_Save(byte load, T_IO_Context *context); - -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 maximum 40 characters -/// including the '\\0'. -char * Format_filename(const char * fname, word max_length, int type); - -void Free_fileselector_list(T_Fileselector *list); - -void Sort_list_of_files(T_Fileselector *list); - -void Recount_files(T_Fileselector *list); - -T_Fileselector_item * Get_item_by_index(T_Fileselector *list, short index); - -void Read_list_of_drives(T_Fileselector *list, byte name_length); - -short Find_file_in_fileselector(T_Fileselector *list, const char * fname); - -void Locate_list_item(T_List_button * list, short selected_item); - -int Quicksearch_list(T_List_button * list, T_Fileselector * selector); - -void Reset_quicksearch(void); - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/global.h b/project/jni/application/grafx2/grafx2/src/global.h deleted file mode 100644 index 979783aad..000000000 --- a/project/jni/application/grafx2/grafx2/src/global.h +++ /dev/null @@ -1,1037 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Franck Charlet - Copyright 2009 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file global.h -/// This file contains all global variables. -/// They are prefixed by ::GFX2_GLOBAL so they are extern when needed. -////////////////////////////////////////////////////////////////////////////// -#ifndef _GLOBAL_H_ -#define _GLOBAL_H_ - -#include -#include "struct.h" - -// MAIN declares the variables, -// other files only have an extern definition. -#ifdef GLOBAL_VARIABLES - /// Magic prefix to make all declarations extern, except when included by main.c. - #define GFX2_GLOBAL -#else - #define GFX2_GLOBAL extern -#endif - -// -- CONFIGURATION variables - -/// Current configuration. -GFX2_GLOBAL T_Config Config; - -/// Array of special keys. -GFX2_GLOBAL word Config_Key[NB_SPECIAL_SHORTCUTS][2]; - -/// A video mode (resolution) usable by Grafx2. -typedef struct -{ - short Width; ///< Screen width - short Height; ///< Screen height - byte Mode; ///< Unused (used to be Mode-X, SVGA, etc) - word Fullscreen; ///< 0 for window, 1 for fullscreen - byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. -} T_Video_mode; - -/// Array of all video modes supported by your platform. Actually filled up to ::Nb_video_modes, excluded. -GFX2_GLOBAL T_Video_mode Video_mode[MAX_VIDEO_MODES]; - -/// Actual number of video modes in ::Video_mode. -GFX2_GLOBAL int Nb_video_modes; - -// -- Menu colors - -GFX2_GLOBAL byte MC_Black; ///< Index of color to use as "black" in the GUI menus. -GFX2_GLOBAL byte MC_Dark; ///< Index of color to use as "dark grey" in the GUI menus. -GFX2_GLOBAL byte MC_Light; ///< Index of color to use as "light grey" in the GUI menus. -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. -GFX2_GLOBAL byte Mouse_K; ///< Current mouse buttons state. Bitfield: 1 for RMB, 2 for LMB. -GFX2_GLOBAL byte Keyboard_click_allowed; ///< Set to 0 when you edit a textfield so you can use space without exiting it - -/// Helper macro to take only one button when both are pressed (LMB has priority) -#define Mouse_K_unique (Mouse_K==0?0:(Mouse_K&1?1:(Mouse_K&2?2:0))) - -/// Last key pressed, 0 if none. Set by the latest call to ::Get_input() -GFX2_GLOBAL dword Key; - -/// -/// Last character typed, converted to ANSI character set (Windows-1252). -/// This is mostly used when the user enters text (filename, etc). -GFX2_GLOBAL dword Key_ANSI; - -// Keyboard modifiers -// (Name conflict with windows.h) -#ifdef MOD_SHIFT - #undef MOD_SHIFT -#endif -#ifdef MOD_CTRL - #undef MOD_CTRL -#endif -#ifdef MOD_ALT - #undef MOD_ALT -#endif - -/// Key modifier for SHIFT key. Used as mask in ::Key, for example. -#define MOD_SHIFT 0x1000 -/// Key modifier for CONTROL key. Used as mask in ::Key, for example. -#define MOD_CTRL 0x2000 -/// Key modifier for ALT key. Used as mask in ::Key, for example. -#define MOD_ALT 0x4000 -/// Key modifier for META key. Used as mask in ::Key, for example. -#define MOD_META 0x8000 - -/// Boolean set to true when the OS/window manager requests the application to close. ie: [X] button -GFX2_GLOBAL byte Quit_is_required; - -/// -/// This boolean is true when the current operation allows changing the -/// foreground or background color. -GFX2_GLOBAL byte Allow_color_change_during_operation; - -// -- Mouse cursor data - -/// Current mouse cursor. Value is in enum ::CURSOR_SHAPES -GFX2_GLOBAL byte Cursor_shape; -/// Backup of ::Cursor_shape, used while a window is open (and needs a different cursor) -GFX2_GLOBAL byte Cursor_shape_before_window; -/// Boolean, means the cursor should not be drawn. It's togglable by the user. -GFX2_GLOBAL byte Cursor_hidden; -/// Boolean, means the cursor is currently hovering over a menu GUI element. -GFX2_GLOBAL byte Cursor_in_menu; -/// Boolean, means the cursor was hovering over a menu GUI element. -GFX2_GLOBAL byte Cursor_in_menu_previous; -/// Storage for the graphics under the mouse cursor. Used by ::Hide_cursor and ::Display_cursor -GFX2_GLOBAL byte Cursor_background[CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; - -// -- Paintbrush data - -/// Active paintbrush. It's an index in enum ::PAINTBRUSH_SHAPES -GFX2_GLOBAL byte Paintbrush_shape; -/// Backup of ::Paintbrush_shape, before fill operation -GFX2_GLOBAL byte Paintbrush_shape_before_fill; -/// Backup of ::Paintbrush_shape, before color picker operation -GFX2_GLOBAL byte Paintbrush_shape_before_colorpicker; -/// Backup of ::Paintbrush_shaper, before lasso operation -GFX2_GLOBAL byte Paintbrush_shape_before_lasso; -/// Boolean, true when the preview paintbrush shouldn't be drawn. -GFX2_GLOBAL byte Paintbrush_hidden; -/// Cordinate of the preview paintbrush in image space. -GFX2_GLOBAL short Paintbrush_X; -/// Cordinate of the preview paintbrush in image space. -GFX2_GLOBAL short Paintbrush_Y; -/// Pixel data of the current brush -GFX2_GLOBAL byte * Paintbrush_sprite; -/// Current paintbrush's width -GFX2_GLOBAL short Paintbrush_width; -/// Current paintbrush's height -GFX2_GLOBAL short Paintbrush_height; -/// Position of current paintbrush's handle -GFX2_GLOBAL short Paintbrush_offset_X; -/// Position of current paintbrush's handle -GFX2_GLOBAL short Paintbrush_offset_Y; - -// -- Graphic commands - -/// On the screen, draw a point. -GFX2_GLOBAL Func_pixel Pixel; -/// Test a pixel color from screen. -GFX2_GLOBAL Func_read Read_pixel; -/// Redraw all screen, without overwriting the menu. -GFX2_GLOBAL Func_display Display_screen; -/// Draw a rectangle on screen. -GFX2_GLOBAL Func_block Block; -/// Draw a point from the image to screen (no zoom). -GFX2_GLOBAL Func_pixel Pixel_preview_normal; -/// Draw a point from the image to screen (magnified part). -GFX2_GLOBAL Func_pixel Pixel_preview_magnifier; -/// Draw a point from the image to screen (zoomed if needed). -GFX2_GLOBAL Func_pixel Pixel_preview; -/// Draw a horizontal XOR line on screen. -GFX2_GLOBAL Func_line_XOR Horizontal_XOR_line; -/// Draw a vertical XOR line on screen. -GFX2_GLOBAL Func_line_XOR Vertical_XOR_line; -/// Display part of the brush on screen, color mode. -GFX2_GLOBAL Func_display_brush_color Display_brush_color; -/// Display part of the brush on screen, monochrome mode. -GFX2_GLOBAL Func_display_brush_mono Display_brush_mono; -/// Clear the brush currently displayed on screen, redrawing the image instead. -GFX2_GLOBAL Func_display_brush_color Clear_brush; -/// Remap part of the screen after the menu colors have changed. -GFX2_GLOBAL Func_remap Remap_screen; -/// Draw a line on screen. -GFX2_GLOBAL Func_procsline Display_line; -/// Draw a line on screen, without doubling it if using wide pixels. (to be used when the line is already doubled in the input buffer) -GFX2_GLOBAL Func_procsline Display_line_fast; -/// Read a line of pixels from screen. -GFX2_GLOBAL Func_procsline Read_line; -/// Redraw all magnified part on screen, without overwriting the menu. -GFX2_GLOBAL Func_display_zoom Display_zoomed_screen; -/// Display part of the brush on the magnified part of screen, color mode. -GFX2_GLOBAL Func_display_brush_color_zoom Display_brush_color_zoom; -/// Display part of the brush on the magnified part of screen, monochrome mode. -GFX2_GLOBAL Func_display_brush_mono_zoom Display_brush_mono_zoom; -/// Clear the brush currently displayed on the magnified part of screen, redrawing the image instead. -GFX2_GLOBAL Func_display_brush_color_zoom Clear_brush_scaled; -/// Draw an arbitrary brush on screen (not the current brush) -GFX2_GLOBAL Func_draw_brush Display_brush; - -// -- Screen data - -/// Requested window width. This is set when the user resizes the window. -GFX2_GLOBAL int Resize_width; -/// Requested window height. This is set when the user resizes the window. -GFX2_GLOBAL int Resize_height; -/// Current video mode. Index in ::Video_mode -GFX2_GLOBAL int Current_resolution; -/// After loading an image, this holds the "original screen width", if the file format supported it. -GFX2_GLOBAL short Original_screen_X; -/// After loading an image, this holds the "original screen height", if the file format supported it. -GFX2_GLOBAL short Original_screen_Y; -/// -/// Current screen (or window) width, in pixels. -/// Note that this takes ::Pixel_ratio into account. -GFX2_GLOBAL short Screen_width; -/// -/// Current screen (or window) height, in pixels. -/// Note that this takes ::Pixel_ratio into account. -GFX2_GLOBAL short Screen_height; -/// Coordinate (in image space) of the topmost visible pixel. -GFX2_GLOBAL short Limit_top; -/// -/// Coordinate (in image space) of the lowest visible pixel. -/// This can be larger than the image height, if the screen is bigger than image. -GFX2_GLOBAL short Limit_bottom; -/// Coordinate (in image space) of the leftmost visible pixel. -GFX2_GLOBAL short Limit_left; -/// -/// Coordinate (in image space) of the rightmost visible pixel. -/// This can be larger than the image width, if the screen is bigger than image. -GFX2_GLOBAL short Limit_right; -/// -/// Coordinate (in image space) of the lowest visible pixel, limited by the -/// image height. Compare with ::Limit_bottom, which is not clipped. -GFX2_GLOBAL short Limit_visible_bottom; -/// -/// Coordinate (in image space) of the rightmost visible pixel, limited by the -/// image width. Compare with ::Limit_right, which is not clipped. -GFX2_GLOBAL short Limit_visible_right; - -/// Coordinate (in image space) of the pixel at the top of the magnified view. -GFX2_GLOBAL short Limit_top_zoom; -/// -/// Coordinate (in image space) of the pixel at the bottom of the magnified view. -/// This can be larger than the image height, if the screen is bigger than image. -GFX2_GLOBAL short Limit_bottom_zoom; -/// Coordinate (in image space) of the pixel at the left of the magnified view. -GFX2_GLOBAL short Limit_left_zoom; -/// -/// Coordinate (in image space) of the pixel at the right of the magnified view. -/// This can be larger than the image width, if the screen is bigger than image. -GFX2_GLOBAL short Limit_right_zoom; -/// -/// Coordinate (in image space) of the lowest visible pixel, limited by the -/// image height. Compare with ::Limit_bottom, which is not clipped. -GFX2_GLOBAL short Limit_visible_bottom_zoom; -/// Coordinate (in image space) of the rightmost visible pixel. -/// This can be larger than the image width, if the screen is bigger than image. -GFX2_GLOBAL short Limit_visible_right_zoom; - -/// Buffer of pixels, used when drawing something to screen. -GFX2_GLOBAL byte * Horizontal_line_buffer; - -/// Current pixel ratio. Index in enum ::PIXEL_RATIO -GFX2_GLOBAL int Pixel_ratio; -/// Current width of pixels, according to ::Pixel_ratio -GFX2_GLOBAL int Pixel_width; -/// Current height of pixels, according to ::Pixel_ratio -GFX2_GLOBAL int Pixel_height; - - -// -- Current image data - -/// Pointer to the pixel data of the main image -GFX2_GLOBAL byte * Main_screen; -/// Palette of the main image -GFX2_GLOBAL T_Palette Main_palette; -/// Boolean, means the image has been modified since last save. -GFX2_GLOBAL byte Main_image_is_modified; -/// Width in pixels of the main image. -GFX2_GLOBAL short Main_image_width; -/// Height in pixels of the main image. -GFX2_GLOBAL short Main_image_height; -/// X position (in image space) of the pixel to display in the top left corner of screen. -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; -/// 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. -GFX2_GLOBAL char Main_filename[256]; -/// File format of the image currently edited. It's a value of enum ::FILE_FORMATS -GFX2_GLOBAL byte Main_fileformat; -/// -/// Fileselector "filter" format, for the current image. -/// (The spare page has its own separate settings) -/// It's 0 for "*.*", or a value of enum ::FILE_FORMATS -GFX2_GLOBAL byte Main_format; -/// Index of the first file/entry to display in the fileselector. -GFX2_GLOBAL short Main_fileselector_position; -/// -/// Position of the "highlight" bar in the fileselector. 10 Files can be visible, -/// So it's a number in the [0-9] range. -GFX2_GLOBAL short Main_fileselector_offset; -/// Current directory for the fileselector. -GFX2_GLOBAL char Main_current_directory[1024]; -/// Main image's file comment (some image formats support text strings). -GFX2_GLOBAL char Main_comment[COMMENT_SIZE+1]; -/// X position (in screen coordinates) of the separator between normal and magnified views. -GFX2_GLOBAL short Main_separator_position; -/// X position (in screen coordinates) of the first pixel of the magnified view. -GFX2_GLOBAL short Main_X_zoom; -/// Proportion of the non-magnified part of the screen. -GFX2_GLOBAL float Main_separator_proportion; -/// Boolean, true if the main image has the magnifier active. -GFX2_GLOBAL byte Main_magnifier_mode; -/// Zoom factor used in the magnifier (main image). -GFX2_GLOBAL word Main_magnifier_factor; -/// Height of the magnified view for the main image. -GFX2_GLOBAL word Main_magnifier_height; -/// Width of the magnified view for the main image. -GFX2_GLOBAL word Main_magnifier_width; -/// X position (in image space) of the pixel to display in the top left corner of the magnified view. -GFX2_GLOBAL short Main_magnifier_offset_X; -/// Y position (in image space) of the pixel to display in the top left corner of the magnified view. -GFX2_GLOBAL short Main_magnifier_offset_Y; -/// Index of layer currently being edited -GFX2_GLOBAL byte Main_current_layer; -/// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. -GFX2_GLOBAL dword Main_layers_visible; -/// Index to use next time, when creating incremental backups, to make unique filename. -GFX2_GLOBAL long Main_safety_number; -/// Number of edit actions since the last safety backup -GFX2_GLOBAL long Main_edits_since_safety_backup; -/// SDL Time of the previous safety backup -GFX2_GLOBAL Uint32 Main_time_of_safety_backup; -/// Letter prefix for the filenames of safety backups. a or b -GFX2_GLOBAL byte Main_safety_backup_prefix; - -// -- Spare page data - -/// Palette of the spare page -GFX2_GLOBAL T_Palette Spare_palette; -/// Boolean, means the spare page has been modified since last save. -GFX2_GLOBAL byte Spare_image_is_modified; -/// Width in pixels of the spare image. -GFX2_GLOBAL short Spare_image_width; -/// Height in pixels of the spare image. -GFX2_GLOBAL short Spare_image_height; -/// X position (in image space) of the pixel to display in the top left corner of screen. -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; -/// 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. -GFX2_GLOBAL char Spare_filename[MAX_PATH_CHARACTERS]; -/// File format of the image currently edited as spare page. It's a value of enum ::FILE_FORMATS -GFX2_GLOBAL byte Spare_fileformat; -/// -/// Fileselector "filter" format, for the spare page. -/// (The main image has its own separate settings) -/// It's 0 for "*.*", or a value of enum ::FILE_FORMAT -GFX2_GLOBAL byte Spare_format; -/// Index of the first file/entry to display in the fileselector. -GFX2_GLOBAL short Spare_fileselector_position; -/// -/// Position of the "highlight" bar in the fileselector. 10 Files can be visible, -/// So it's a number in the [0-9] range. -GFX2_GLOBAL short Spare_fileselector_offset; -/// Current directory for the fileselector. -GFX2_GLOBAL char Spare_current_directory[MAX_PATH_CHARACTERS]; -/// Spare page's file comment (some image formats support text strings). -GFX2_GLOBAL char Spare_comment[COMMENT_SIZE+1]; -/// X position (in screen coordinates) of the separator between normal and magnified views. -GFX2_GLOBAL short Spare_separator_position; -/// X position (in screen coordinates) of the first pixel of the magnified view. -GFX2_GLOBAL short Spare_X_zoom; -/// Proportion of the non-magnified part of the screen. -GFX2_GLOBAL float Spare_separator_proportion; -/// Boolean, true if the main image has the magnifier active. -GFX2_GLOBAL byte Spare_magnifier_mode; -/// Zoom factor used in the magnifier (spare page). -GFX2_GLOBAL word Spare_magnifier_factor; -/// Width of the magnified view for the spare page. -GFX2_GLOBAL word Spare_magnifier_height; -/// Height of the magnified view for the spare page. -GFX2_GLOBAL word Spare_magnifier_width; -/// X position (in image space) of the pixel to display in the top left corner of the magnified view. -GFX2_GLOBAL short Spare_magnifier_offset_X; -/// Y position (in image space) of the pixel to display in the top left corner of the magnified view. -GFX2_GLOBAL short Spare_magnifier_offset_Y; -/// Index of layer currently being edited -GFX2_GLOBAL byte Spare_current_layer; -/// Bitfield that records which layers are visible. 2^0 for 0, 2^1 for 1, 2^2 for 2, etc. -GFX2_GLOBAL dword Spare_layers_visible; -/// Index to use next time, when creating incremental backups, to make unique filename. -GFX2_GLOBAL long Spare_safety_number; -/// Number of edit actions since the last safety backup -GFX2_GLOBAL long Spare_edits_since_safety_backup; -/// SDL Time of the previous safety backup -GFX2_GLOBAL Uint32 Spare_time_of_safety_backup; -/// Letter prefix for the filenames of safety backups. a or b -GFX2_GLOBAL byte Spare_safety_backup_prefix; - -// -- Image backups - -/// Backup of the current screen, used during drawing when FX feedback is OFF. -GFX2_GLOBAL byte * Screen_backup; -/// List of backup pages for the main image. -GFX2_GLOBAL T_List_of_pages * Main_backups; -/// List of backup pages for the spare page. -GFX2_GLOBAL T_List_of_pages * Spare_backups; - - -// -- Brush data - -/// 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 -GFX2_GLOBAL word Brush_offset_Y; -/// Width of the current brush. -GFX2_GLOBAL word Brush_width; -/// Height of the current brush. -GFX2_GLOBAL word Brush_height; -/// Name of the directory that holds the brush fil (after loading or saving it). -GFX2_GLOBAL char Brush_file_directory[MAX_PATH_CHARACTERS]; -/// Filename (without directory) of the brush (after loading or saving it). -GFX2_GLOBAL char Brush_filename[MAX_PATH_CHARACTERS]; -/// File format of the brush. It's a value of enum ::FILE_FORMATS -GFX2_GLOBAL byte Brush_fileformat; -/// -/// Fileselector "filter" format, for the brush. -/// It's 0 for "*.*", or a value of enum ::FILE_FORMATS -GFX2_GLOBAL byte Brush_format; -/// Index of the first file/entry to display in the brush's fileselector. -GFX2_GLOBAL short Brush_fileselector_position; -/// -/// Position of the "highlight" bar in the brush's fileselector. 10 Files can -/// be visible, so it's a number in the [0-9] range. -GFX2_GLOBAL short Brush_fileselector_offset; -/// Current directory for the brush's fileselector. -GFX2_GLOBAL char Brush_current_directory[256]; -/// File comment in the brush's fileselector (some image formats support text strings). -GFX2_GLOBAL char Brush_comment[COMMENT_SIZE+1]; -/// Indicator used for the "Rotate brush" operation. -GFX2_GLOBAL byte Brush_rotation_center_is_defined; -/// Position of the brush's rotation center, in screen coordinates. -GFX2_GLOBAL short Brush_rotation_center_X; -/// Position of the brush's rotation center, in screen coordinates. -GFX2_GLOBAL short Brush_rotation_center_Y; - -// -- Menu data (toolbox) - -/// Boolean, true if the menu has to be displayed. -GFX2_GLOBAL byte Menu_is_visible; -/// Height of the menu, when it's displayed -GFX2_GLOBAL word Menu_height; -/// -/// Y position (in screen coordinates) where the menu begins. -/// This is always either ::Screen_height (when menu is hidden) or (::Screen_height - ::Menu_height) -/// As a result, the drawing algoritm always draws the image from 0 to ::Menu_Y-1 -GFX2_GLOBAL word Menu_Y; -/// Y position of the status bar (in screen coordinates) -GFX2_GLOBAL word Menu_status_Y; -/// Scaling factor for the menu and all GUI elements -GFX2_GLOBAL byte Menu_factor_X; -/// Scaling factor for the menu and all GUI elements -GFX2_GLOBAL byte Menu_factor_Y; -/// Size of a color cell in the menu's palette. -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,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 - ; - - -// -- Window data - -/// Number of stacked windows currently displayed. 0 when no window is present. -GFX2_GLOBAL byte Windows_open; -/// Backup of ::Menu_is_visible, used to store it while a window is open. -GFX2_GLOBAL byte Menu_is_visible_before_window; -/// Backup of ::Menu_Y, used to store it while a window is open. -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; - -/// 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[Windows_open-1].Pos_X - -/// Position of the top border of the topmost window (in screen coordinates) -#define Window_pos_Y Window_stack[Windows_open-1].Pos_Y - -/// -/// Width of the topmost window, in "window pixels" -/// (multiply by ::Menu_factor_X to get screen pixels) -#define Window_width Window_stack[Windows_open-1].Width - -/// -/// Height of the topmost window, in "window pixels" -/// (multiply by ::Menu_factor_Y to get screen pixels) -#define Window_height Window_stack[Windows_open-1].Height - -/// Total number of buttons/controls in the topmost window. -#define Window_nb_buttons Window_stack[Windows_open-1].Nb_buttons - -/// List of normal buttons in the topmost window. -#define Window_normal_button_list Window_stack[Windows_open-1].Normal_button_list - -/// List of "palette" buttons in the topmost window. -#define Window_palette_button_list Window_stack[Windows_open-1].Palette_button_list - -/// List of sliders (scrollers) in the topmost window. -#define Window_scroller_button_list Window_stack[Windows_open-1].Scroller_button_list - -/// List of special buttons in the topmost window. -#define Window_special_button_list Window_stack[Windows_open-1].Special_button_list - -/// List of dropdown buttons in the topmost window. -#define Window_dropdown_button_list Window_stack[Windows_open-1].Dropdown_button_list - -/// List of list buttons in the topmost window. -#define Window_list_button_list Window_stack[Windows_open-1].List_button_list - -/// -/// 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[Windows_open-1].Attribute1 - -/// -/// 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[Windows_open-1].Attribute2 - -#define Window_draggable Window_stack[Windows_open-1].Draggable - - -/// Definition of the menu (toolbox) -GFX2_GLOBAL struct -{ - // Button aspect - word X_offset; ///< Position relative to menu's left - word Y_offset; ///< Position relative to menu's top - word Width; ///< Button's active width - word Height; ///< Button's active heigth - byte Pressed; ///< Button is currently pressed - byte Shape; ///< Shape, listed in enum ::BUTTON_SHAPES - signed 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 - Func_action Right_action; ///< Action triggered by a right mouseclick on the button - word Left_shortcut[2]; ///< Keyboard shortcut for a left mouseclick - word Right_shortcut[2];///< Keyboard shortcut for a right mouseclick - byte Left_instant; ///< Will not wait for mouse release before triggering action - byte Right_instant; ///< Will not wait for mouse release before triggering action - - // Data used when the button is unselected - Func_action Unselect_action; ///< Action triggered by unselecting the button - byte Family; ///< enum ::FAMILY_OF_BUTTONS. - -} Buttons_Pool[NB_BUTTONS]; - - - -// -- Information about the different drawing modes (effects) - -/// Current effecting function. When no effect is selected this is ::No_effect() -GFX2_GLOBAL Func_effect Effect_function; - -/// -/// Array of booleans, indicates which colors should never be picked by -/// ::Best_color() -GFX2_GLOBAL byte Exclude_color[256]; - -// -- Smear mode - -/// Smear mode is activated -GFX2_GLOBAL byte Smear_mode; -/// Boolean, indicates that a smear is in progress. -GFX2_GLOBAL byte Smear_start; -/// Pointer to the sprite to use for smear; it contains pixels from the image. -GFX2_GLOBAL byte * Smear_brush; -/// Width of the ::Smear_brush -GFX2_GLOBAL word Smear_brush_width; -/// Height of the ::Smear_brush -GFX2_GLOBAL word Smear_brush_height; -/// Limits of the smear. -GFX2_GLOBAL short Smear_min_X; -/// Limits of the smear. -GFX2_GLOBAL short Smear_max_X; -/// Limits of the smear. -GFX2_GLOBAL short Smear_min_Y; -/// Limits of the smear. -GFX2_GLOBAL short Smear_max_Y; - -// -- Shade mode -/// List of the shade tables -GFX2_GLOBAL T_Shade Shade_list[8]; -/// Shade currently selected (index in ::Shade_list) -GFX2_GLOBAL byte Shade_current; -/// Conversion table in use -GFX2_GLOBAL byte * Shade_table; -/// Conversion table for a left click -GFX2_GLOBAL byte Shade_table_left[256]; -/// Conversion table for a right click -GFX2_GLOBAL byte Shade_table_right[256]; -/// Boolean, true when the shade mode is active. -GFX2_GLOBAL byte Shade_mode; - -/// Boolean, true when the quick-shade mode is active. -GFX2_GLOBAL byte Quick_shade_mode; -/// Size of the step, in Quick-shade mode. It's the number of colors to "jump". -GFX2_GLOBAL byte Quick_shade_step; -/// Determines how colors should loop in Quick-shade more. Value in enum ::SHADE_MODES -GFX2_GLOBAL byte Quick_shade_loop; - -// -- Stencil mode - -/// Boolean, true when stencil mode is active. -GFX2_GLOBAL byte Stencil_mode; -/// Array of the protected colors by Stencil mode. -GFX2_GLOBAL byte Stencil[256]; - -// -- Grid mode - -/// Boolean, true when the Grid mode is active. -GFX2_GLOBAL byte Snap_mode; -/// Boolean, true when the Grid is displayed in zoomed view. -GFX2_GLOBAL byte Show_grid; -/// Width of the grid in Grid mode. -GFX2_GLOBAL word Snap_width; -/// Height of the grid in Grid mode. -GFX2_GLOBAL word Snap_height; -/// Position of the starting pixel, in Grid mode. -GFX2_GLOBAL word Snap_offset_X; -/// Position of the starting pixel, in Grid mode. -GFX2_GLOBAL word Snap_offset_Y; - -// -- Sieve mode - -/// Boolean, true when the Sieve mode is active -GFX2_GLOBAL byte Sieve_mode; -/// Sprite of the sieve pattern. It's actually an array of booleans. -GFX2_GLOBAL byte Sieve[16][16]; -/// Width of the sieve pattern, in Sieve mode. -GFX2_GLOBAL short Sieve_width; -/// Height of the sieve pattern, in Sieve mode. -GFX2_GLOBAL short Sieve_height; - -// -- Colorize mode - -/// Boolean, true when the Colorize mode is active. -GFX2_GLOBAL byte Colorize_mode; -/// % of opacity of Colorize mode (for translucency) -GFX2_GLOBAL byte Colorize_opacity; -/// Sets the colorization mode: 0 transparency, 1 additive, 2 substractive -GFX2_GLOBAL byte Colorize_current_mode; -/// -/// Table of precomputed factors used by Colorize mode. It hold 0 to 255 when -/// opacity is 100%, 0 to 128 when opacity is 50%, etc. -// FIXME: This only caches a multiplication and a division. Maybe we should scrap it -GFX2_GLOBAL word Factors_table[256]; -/// -/// Table of precomputed factors used by Colorize mode. It hold 255 to 0 when -/// opacity is 100%, 128 to 0 when opacity is 50%, etc. -// FIXME: This only caches a multiplication, a division, a substraction. Maybe we should scrap it -GFX2_GLOBAL word Factors_inv_table[256]; - -// -- Smooth mode - -/// Boolean, true when the Smooth mode is active -GFX2_GLOBAL byte Smooth_mode; -/// Matrix of "weights" used by the Smooth mode. -GFX2_GLOBAL byte Smooth_matrix[3][3]; - -// -- Tiling mode - -/// Boolean, true when the Tiling mode is active -GFX2_GLOBAL byte Tiling_mode; -/// Position of the starting pixel in Tiling mode. -GFX2_GLOBAL short Tiling_offset_X; -/// Position of the starting pixel in Tiling mode. -GFX2_GLOBAL short Tiling_offset_Y; - -// -- Mask mode - -/// Boolean, true when the Tiling mode is active -GFX2_GLOBAL byte Mask_mode; -/// Array of booleans. True if the indexed color is protected by the mask. -GFX2_GLOBAL byte Mask_table[256]; - -// -- Magnifier data - -#ifdef GLOBAL_VARIABLES - word ZOOM_FACTOR[NB_ZOOM_FACTORS]={2,3,4,5,6,8,10,12,14,16,18,20, 24, 28, 32}; -#else -/// Successive zoom factors, used by the Magnifier. - extern word ZOOM_FACTOR[NB_ZOOM_FACTORS]; -#endif - -// -- Data for ellipses and circles -// FIXME: move most of these to graph.c -GFX2_GLOBAL long Ellipse_cursor_X; -GFX2_GLOBAL long Ellipse_cursor_Y; -GFX2_GLOBAL long Ellipse_vertical_radius_squared; -GFX2_GLOBAL long Ellipse_horizontal_radius_squared; -GFX2_GLOBAL qword Ellipse_limit; -GFX2_GLOBAL long Circle_cursor_X; -GFX2_GLOBAL long Circle_cursor_Y; -GFX2_GLOBAL long Circle_limit; - -// -- Data for gradients - -/// First color of the gradient. -GFX2_GLOBAL short Gradient_lower_bound; -/// Last color of the gradient -GFX2_GLOBAL short Gradient_upper_bound; -/// Boolean, true if the gradient should use colors in descending order -GFX2_GLOBAL int Gradient_is_inverted; -/// Number of colors in the range ::Gradient_lower_bound to ::Gradient_upper_bound (included) -GFX2_GLOBAL long Gradient_bounds_range; -/// Maximum value passed to the gradient function. The pixels assigned this value should use last gradient color. -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; -/// -/// Pointer to the pixel-drawing function that gradients should use: -/// 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; -/// 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 - -/// Mode to use in airbrush: 0 for multicolor, 1 for mono. -GFX2_GLOBAL byte Airbrush_mode; -/// Diameter of the airbrush, in pixels. -GFX2_GLOBAL short Airbrush_size; -/// Delay between two airbrush "shots", in 1/100s -GFX2_GLOBAL byte Airbrush_delay; -/// Number of pixels that are emitted by the airbrush, in mono mode. -GFX2_GLOBAL byte Airbrush_mono_flow; -/// Number of pixels that are emitted by the airbrush for each color (multi mode) -GFX2_GLOBAL byte Airbrush_multi_flow[256]; - -/// -- Misc data about the program - -/// Boolean, set to true to exit the program. -GFX2_GLOBAL byte Quitting; -/// Name of the directory that was current when the program was run. -GFX2_GLOBAL char Initial_directory[256]; -/// Name of the directory that holds the program's (read-only) data: skins, icon, etc. -GFX2_GLOBAL char Data_directory[256]; -/// Name of the directory where grafx2 reads and writes configuration (gfx2.ini, gfx2.cfg) -GFX2_GLOBAL char Config_directory[256]; -/// Current foreground color for drawing. -GFX2_GLOBAL byte Fore_color; -/// Current background color for drawing. -GFX2_GLOBAL byte Back_color; -/// For the "Freehand draw" tool, this determines which variant is selected, from ::OPERATION_CONTINUOUS_DRAW to ::OPERATION_FILLED_CONTOUR -GFX2_GLOBAL byte Selected_freehand_mode; -/// For the Curve tool, this determines which variant is selected, either ::OPERATION_3_POINTS_CURVE or ::OPERATION_4_POINTS_CURVE -GFX2_GLOBAL byte Selected_curve_mode; -/// For the Line tool, this determines which variant is selected, either ::OPERATION_LINE, ::OPERATION_K_LIGNE or ::OPERATION_CENTERED_LINES -GFX2_GLOBAL byte Selected_line_mode; -/// Determines which color appears in the first cell of the menu palette. Change this value to "scroll" the palette. -GFX2_GLOBAL byte First_color_in_palette; -/// Boolean, true if Grafx2 was run with a command-line argument to set a resolution on startup (overrides config) -GFX2_GLOBAL byte Resolution_in_command_line; - -// - Graphic - -/// Pointer to the font selected for menus. -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. -GFX2_GLOBAL byte Current_help_section; -/// Line number of the help viewer, in current ::Help_section. 0 for top, increase value to scroll down. -GFX2_GLOBAL word Help_position; - -// -- Operation data - -/// Index of the operation which was selected (ex: drawing rectangle) before the current interruption (ex: colorpicking). -GFX2_GLOBAL word Operation_before_interrupt; -/// Index of the current operation. This is the active "tool". -GFX2_GLOBAL word Current_operation; -/// -/// This stack is used to memorize all parameters needed during the course of -/// an operation. For example when drawing a rectangle: color, starting -/// coordinates, ending coordinates. -GFX2_GLOBAL word Operation_stack[OPERATION_STACK_SIZE]; -/// Number of parameters stored in ::Operation_stack (0=empty) -GFX2_GLOBAL byte Operation_stack_size; -/// Boolean, true if the operation (drawing) started in the magnified area. -GFX2_GLOBAL byte Operation_in_magnifier; -/// Last color hovered by the colorpicker. -1 if it wasn't over the image. -GFX2_GLOBAL short Colorpicker_color; -/// Position of the colorpicker tool, in image coordinates. -GFX2_GLOBAL short Colorpicker_X; -/// Position of the colorpicker tool, in image coordinates. -GFX2_GLOBAL short Colorpicker_Y; - -GFX2_GLOBAL short * Polyfill_table_of_points; -GFX2_GLOBAL int Polyfill_number_of_points; - -/// Brush container -GFX2_GLOBAL T_Brush_template Brush_container[BRUSH_CONTAINER_COLUMNS*BRUSH_CONTAINER_ROWS]; - -#ifdef GLOBAL_VARIABLES - byte CURSOR_FOR_OPERATION[NB_OPERATIONS]= - { - CURSOR_SHAPE_TARGET , // Freehand continuous draw - CURSOR_SHAPE_TARGET , // Freehand discontinuous draw - CURSOR_SHAPE_TARGET , // Freehand point-by-point draw - CURSOR_SHAPE_TARGET , // Filled contour - CURSOR_SHAPE_TARGET , // Lines - CURSOR_SHAPE_TARGET , // Linked lines - CURSOR_SHAPE_TARGET , // Centered lines - CURSOR_SHAPE_XOR_TARGET , // Empty rectangle - CURSOR_SHAPE_XOR_TARGET , // Filled rectangle - CURSOR_SHAPE_TARGET , // Empty circle - CURSOR_SHAPE_TARGET , // Filled circle - CURSOR_SHAPE_TARGET , // Empty ellipse - CURSOR_SHAPE_TARGET , // Filled ellipse - CURSOR_SHAPE_TARGET , // Fill - CURSOR_SHAPE_TARGET , // Color replacer - CURSOR_SHAPE_XOR_TARGET , // Rectangular brush grabbing - CURSOR_SHAPE_TARGET , // Polygonal brush grabbing - CURSOR_SHAPE_COLORPICKER , // Colorpicker - CURSOR_SHAPE_XOR_RECTANGLE , // Position the magnify window - CURSOR_SHAPE_TARGET , // Curve with 3 control points - CURSOR_SHAPE_TARGET , // Curve with 4 control points - CURSOR_SHAPE_TARGET , // Airbrush - CURSOR_SHAPE_TARGET , // Polygon - CURSOR_SHAPE_TARGET , // Polyform - CURSOR_SHAPE_TARGET , // Filled polygon - CURSOR_SHAPE_TARGET , // Filled polyform - CURSOR_SHAPE_MULTIDIRECTIONAL , // Scroll (pan) - CURSOR_SHAPE_TARGET , // Gradient-filled circle - CURSOR_SHAPE_TARGET , // Gradient-filled ellipse - CURSOR_SHAPE_XOR_ROTATION , // Rotate brush - 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. - extern byte CURSOR_FOR_OPERATION[NB_OPERATIONS]; -#endif - -/// -/// Procedures to call for each state (determined by ::Operation_stack_size) of -/// each operation, and for each mouse state (no button,left button,right button) -GFX2_GLOBAL struct -{ - Func_action Action; ///< Function to call - byte Hide_cursor; ///< Boolean: Need to hide/unhide cursor during this step - byte Fast_mouse; ///< Operation should take shortcuts with mouse movements -} Operation[NB_OPERATIONS][3][OPERATION_STACK_SIZE]; - -// -- misc - -/// -/// Indicator of error in previous file operations. -/// - 0: OK -/// - 1: Error when beginning operation. Existing data should be ok. -/// - 2: Error while operation was in progress. Data is modified. -/// - -1: Interruption of a preview. -GFX2_GLOBAL signed char File_error; -/// Current line number when reading/writing gfx2.ini -GFX2_GLOBAL int Line_number_in_INI_file; - -// -- Specific to SDL - -/// Pointer to the program's screen. -GFX2_GLOBAL SDL_Surface * Screen_SDL; -#ifdef ANDROID -GFX2_GLOBAL SDL_Surface * Screen_SDL_Hardware; -#endif -/// Pointer to the current joystick controller. -GFX2_GLOBAL SDL_Joystick* Joystick; - -/// Indicates "no keyboard shortcut". -#define KEY_NONE 0 -/// -/// This is the "key identifier" for the mouse 3rd button. -/// It was chosen to not conflict with any SDL key number. -#define KEY_MOUSEMIDDLE (SDLK_LAST+1) -/// -/// This is the "key identifier" for the mouse wheelup. -/// It was chosen to not conflict with any SDL key number. -#define KEY_MOUSEWHEELUP (SDLK_LAST+2) -/// -/// This is the "key identifier" for the mouse wheeldown. -/// It was chosen to not conflict with any SDL key number. -#define KEY_MOUSEWHEELDOWN (SDLK_LAST+3) -/// -/// This is the "key identifier" for joystick button number 0. -/// All numbers starting with this one are reserved for joystick buttons -/// (since their is an unknown number of them, and for example 18 on GP2X) -/// It was chosen to not conflict with any SDL key number. -#define KEY_JOYBUTTON (SDLK_LAST+4) - -/// 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 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 console ports can get a joybutton equivalent of it. - #define KEY_ESC SDLK_ESCAPE -#endif - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/graph.c b/project/jni/application/grafx2/grafx2/src/graph.c deleted file mode 100644 index 06c99716a..000000000 --- a/project/jni/application/grafx2/grafx2/src/graph.c +++ /dev/null @@ -1,2994 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see - -******************************************************************************** - - Drawing functions and effects. - -*/ - -#include -#include -#include - -#include "global.h" -#include "struct.h" -#include "engine.h" -#include "buttons.h" -#include "pages.h" -#include "errors.h" -#include "sdlscreen.h" -#include "graph.h" -#include "misc.h" -#include "pxsimple.h" -#include "pxtall.h" -#include "pxwide.h" -#include "pxdouble.h" -#include "pxtriple.h" -#include "pxwide2.h" -#include "pxtall2.h" -#include "pxquad.h" -#include "windows.h" -#include "input.h" -#include "brush.h" - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -#if defined(__VBCC__) || defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) - #define M_PI 3.141592653589793238462643 -#endif - -// Generic pixel-drawing function. -Func_pixel Pixel_figure; - -// Fonction qui met à jour la zone de l'image donnée en paramètre sur l'écran. -// Tient compte du décalage X et Y et du zoom, et fait tous les controles nécessaires -void Update_part_of_screen(short x, short y, short width, short height) -{ - short effective_w, effective_h; - short effective_X; - short effective_Y; - short diff; - - // Première étape, si L ou H est négatif, on doit remettre la zone à l'endroit - if (width < 0) - { - x += width; - width = - width; - } - - if (height < 0) - { - y += height; - height = - height; - } - - // D'abord on met à jour dans la zone écran normale - diff = x-Main_offset_X; - if (diff<0) - { - effective_w = width + diff; - effective_X = 0; - } - else - { - effective_w = width; - effective_X = diff; - } - diff = y-Main_offset_Y; - if (diff<0) - { - effective_h = height + diff; - effective_Y = 0; - } - else - { - effective_h = height; - effective_Y = diff; - } - - // Normalement il ne faudrait pas updater au delà du split quand on est en mode loupe, - // mais personne ne devrait demander d'update en dehors de cette limite, même le fill est contraint - // a rester dans la zone visible de l'image - // ...Sauf l'affichage de brosse en preview - yr - if(Main_magnifier_mode && effective_X + effective_w > Main_separator_position) - effective_w = Main_separator_position - effective_X; - else if(effective_X + effective_w > Screen_width) - effective_w = Screen_width - effective_X; - - if(effective_Y + effective_h > Menu_Y) - effective_h = Menu_Y - effective_Y; - - /* - SDL_Rect r; - r.x=effective_X; - r.y=effective_Y; - r.h=effective_h; - r.w=effective_w; - SDL_FillRect(Screen_SDL,&r,3); - */ - Update_rect(effective_X,effective_Y,effective_w,effective_h); - - // Et ensuite dans la partie zoomée - if(Main_magnifier_mode) - { - // Clipping en X - effective_X = (x-Main_magnifier_offset_X)*Main_magnifier_factor; - effective_Y = (y-Main_magnifier_offset_Y)*Main_magnifier_factor; - effective_w = width * Main_magnifier_factor; - effective_h = height * Main_magnifier_factor; - - if (effective_X < 0) - { - effective_w+=effective_X; - if (effective_w<0) - return; - - effective_X = Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X; - } - else - effective_X += Main_separator_position + SEPARATOR_WIDTH*Menu_factor_X; - diff = effective_X+effective_w-Min(Screen_width, Main_X_zoom+(Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); - if (diff>0) - { - effective_w -=diff; - if (effective_w<0) - return; - } - - - // Clipping en Y - if (effective_Y < 0) - { - effective_h+=effective_Y; - if (effective_h<0) - return; - effective_Y = 0; - } - diff = effective_Y+effective_h-Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); - if (diff>0) - { - effective_h -=diff; - if (effective_h<0) - return; - } - - - // Très utile pour le debug :) - /*SDL_Rect r; - r.x=effective_X; - r.y=effective_Y; - r.h=effective_h; - r.w=effective_w; - SDL_FillRect(Screen_SDL,&r,3);*/ - - Redraw_grid(effective_X,effective_Y,effective_w,effective_h); - Update_rect(effective_X,effective_Y,effective_w,effective_h); - } -} - - - -void Transform_point(short x, short y, float cos_a, float sin_a, - short * rx, short * ry) -{ - *rx=Round(((float)x*cos_a)+((float)y*sin_a)); - *ry=Round(((float)y*cos_a)-((float)x*sin_a)); -} - - -//--------------------- Initialisation d'un mode vidéo ----------------------- - -int Init_mode_video(int width, int height, int fullscreen, int pix_ratio) -{ - int index; - int factor; - int pix_width; - int pix_height; - byte screen_changed; - byte pixels_changed; - int absolute_mouse_x=Mouse_X*Pixel_width; - int absolute_mouse_y=Mouse_Y*Pixel_height; - static int Wrong_resize; - -try_again: - - switch (pix_ratio) - { - default: - case PIXEL_SIMPLE: - pix_width=1; - pix_height=1; - break; - case PIXEL_TALL: - pix_width=1; - pix_height=2; - break; - case PIXEL_WIDE: - pix_width=2; - pix_height=1; - break; - case PIXEL_DOUBLE: - pix_width=2; - pix_height=2; - break; - case PIXEL_TRIPLE: - pix_width=3; - pix_height=3; - break; - case PIXEL_WIDE2: - pix_width=4; - pix_height=2; - break; - case PIXEL_TALL2: - pix_width=2; - pix_height=4; - break; - case PIXEL_QUAD: - pix_width=4; - pix_height=4; - break; - } - - screen_changed = (Screen_width*Pixel_width!=width || - Screen_height*Pixel_height!=height || - Video_mode[Current_resolution].Fullscreen != fullscreen); - - // Valeurs raisonnables: minimum 320x200 - if (!fullscreen) - { - if (Wrong_resize>20 && (width < 320*pix_width || height < 200*pix_height)) - { - if(pix_ratio != PIXEL_SIMPLE) { - pix_ratio = PIXEL_SIMPLE; - Verbose_message("Error!", "Your WM is forcing GrafX2 to resize to something " - "smaller than the minimal resolution.\n" - "GrafX2 switched to a smaller\npixel scaler to avoid problems "); - goto try_again; - } - } - - if (width > 320*pix_width && height > 200*pix_height) - Wrong_resize = 0; - - if (width < 320*pix_width) - { - width = 320*pix_width; - screen_changed=1; - Wrong_resize++; - } - if (height < 200*pix_height) - { - height = 200*pix_height; - screen_changed=1; - Wrong_resize++; - } - Video_mode[0].Width = width; - Video_mode[0].Height = height; - - } - else - { - if (width < 320*pix_width || height < 200*pix_height) - return 1; - } - // La largeur doit être un multiple de 4 - #ifdef __amigaos4__ - // On AmigaOS the systems adds some more constraints on that ... - width = (width + 15) & 0xFFFFFFF0; - #else - //width = (width + 3 ) & 0xFFFFFFFC; - #endif - - pixels_changed = (Pixel_ratio!=pix_ratio); - - if (!screen_changed && !pixels_changed) - return 0; - if (screen_changed) - { - Set_mode_SDL(&width, &height,fullscreen); - } - - if (screen_changed || pixels_changed) - { - Pixel_ratio=pix_ratio; - Pixel_width=pix_width; - Pixel_height=pix_height; - switch (Pixel_ratio) - { - default: - case PIXEL_SIMPLE: - Pixel = Pixel_simple ; - Read_pixel= Read_pixel_simple ; - Display_screen = Display_part_of_screen_simple ; - Block = Block_simple ; - Pixel_preview_normal = Pixel_preview_normal_simple ; - Pixel_preview_magnifier = Pixel_preview_magnifier_simple ; - Horizontal_XOR_line = Horizontal_XOR_line_simple ; - Vertical_XOR_line = Vertical_XOR_line_simple ; - Display_brush_color = Display_brush_color_simple ; - Display_brush_mono = Display_brush_mono_simple ; - Clear_brush = Clear_brush_simple ; - Remap_screen = Remap_screen_simple ; - Display_line = Display_line_on_screen_simple ; - Display_line_fast = Display_line_on_screen_simple ; - Read_line = Read_line_screen_simple ; - Display_zoomed_screen = Display_part_of_screen_scaled_simple ; - Display_brush_color_zoom = Display_brush_color_zoom_simple ; - Display_brush_mono_zoom = Display_brush_mono_zoom_simple ; - Clear_brush_scaled = Clear_brush_scaled_simple ; - Display_brush = Display_brush_simple ; - break; - case PIXEL_TALL: - Pixel = Pixel_tall; - Read_pixel= Read_pixel_tall; - Display_screen = Display_part_of_screen_tall; - Block = Block_tall; - Pixel_preview_normal = Pixel_preview_normal_tall; - Pixel_preview_magnifier = Pixel_preview_magnifier_tall; - Horizontal_XOR_line = Horizontal_XOR_line_tall; - Vertical_XOR_line = Vertical_XOR_line_tall; - Display_brush_color = Display_brush_color_tall; - Display_brush_mono = Display_brush_mono_tall; - Clear_brush = Clear_brush_tall; - Remap_screen = Remap_screen_tall; - Display_line = Display_line_on_screen_tall; - Display_line_fast = Display_line_on_screen_tall; - Read_line = Read_line_screen_tall; - Display_zoomed_screen = Display_part_of_screen_scaled_tall; - Display_brush_color_zoom = Display_brush_color_zoom_tall; - Display_brush_mono_zoom = Display_brush_mono_zoom_tall; - Clear_brush_scaled = Clear_brush_scaled_tall; - Display_brush = Display_brush_tall; - break; - case PIXEL_WIDE: - Pixel = Pixel_wide ; - Read_pixel= Read_pixel_wide ; - Display_screen = Display_part_of_screen_wide ; - Block = Block_wide ; - Pixel_preview_normal = Pixel_preview_normal_wide ; - Pixel_preview_magnifier = Pixel_preview_magnifier_wide ; - Horizontal_XOR_line = Horizontal_XOR_line_wide ; - Vertical_XOR_line = Vertical_XOR_line_wide ; - Display_brush_color = Display_brush_color_wide ; - Display_brush_mono = Display_brush_mono_wide ; - Clear_brush = Clear_brush_wide ; - Remap_screen = Remap_screen_wide ; - Display_line = Display_line_on_screen_wide ; - Display_line_fast = Display_line_on_screen_fast_wide ; - Read_line = Read_line_screen_wide ; - Display_zoomed_screen = Display_part_of_screen_scaled_wide ; - Display_brush_color_zoom = Display_brush_color_zoom_wide ; - Display_brush_mono_zoom = Display_brush_mono_zoom_wide ; - Clear_brush_scaled = Clear_brush_scaled_wide ; - Display_brush = Display_brush_wide ; - break; - case PIXEL_DOUBLE: - Pixel = Pixel_double ; - Read_pixel= Read_pixel_double ; - Display_screen = Display_part_of_screen_double ; - Block = Block_double ; - Pixel_preview_normal = Pixel_preview_normal_double ; - Pixel_preview_magnifier = Pixel_preview_magnifier_double ; - Horizontal_XOR_line = Horizontal_XOR_line_double ; - Vertical_XOR_line = Vertical_XOR_line_double ; - Display_brush_color = Display_brush_color_double ; - Display_brush_mono = Display_brush_mono_double ; - Clear_brush = Clear_brush_double ; - Remap_screen = Remap_screen_double ; - Display_line = Display_line_on_screen_double ; - Display_line_fast = Display_line_on_screen_fast_double ; - Read_line = Read_line_screen_double ; - Display_zoomed_screen = Display_part_of_screen_scaled_double ; - Display_brush_color_zoom = Display_brush_color_zoom_double ; - Display_brush_mono_zoom = Display_brush_mono_zoom_double ; - Clear_brush_scaled = Clear_brush_scaled_double ; - Display_brush = Display_brush_double ; - break; - case PIXEL_TRIPLE: - Pixel = Pixel_triple ; - Read_pixel= Read_pixel_triple ; - Display_screen = Display_part_of_screen_triple ; - Block = Block_triple ; - Pixel_preview_normal = Pixel_preview_normal_triple ; - Pixel_preview_magnifier = Pixel_preview_magnifier_triple ; - Horizontal_XOR_line = Horizontal_XOR_line_triple ; - Vertical_XOR_line = Vertical_XOR_line_triple ; - Display_brush_color = Display_brush_color_triple ; - Display_brush_mono = Display_brush_mono_triple ; - Clear_brush = Clear_brush_triple ; - Remap_screen = Remap_screen_triple ; - Display_line = Display_line_on_screen_triple ; - Display_line_fast = Display_line_on_screen_fast_triple ; - Read_line = Read_line_screen_triple ; - Display_zoomed_screen = Display_part_of_screen_scaled_triple ; - Display_brush_color_zoom = Display_brush_color_zoom_triple ; - Display_brush_mono_zoom = Display_brush_mono_zoom_triple ; - Clear_brush_scaled = Clear_brush_scaled_triple ; - Display_brush = Display_brush_triple ; - break; - case PIXEL_WIDE2: - Pixel = Pixel_wide2 ; - Read_pixel= Read_pixel_wide2 ; - Display_screen = Display_part_of_screen_wide2 ; - Block = Block_wide2 ; - Pixel_preview_normal = Pixel_preview_normal_wide2 ; - Pixel_preview_magnifier = Pixel_preview_magnifier_wide2 ; - Horizontal_XOR_line = Horizontal_XOR_line_wide2 ; - Vertical_XOR_line = Vertical_XOR_line_wide2 ; - Display_brush_color = Display_brush_color_wide2 ; - Display_brush_mono = Display_brush_mono_wide2 ; - Clear_brush = Clear_brush_wide2 ; - Remap_screen = Remap_screen_wide2 ; - Display_line = Display_line_on_screen_wide2 ; - Display_line_fast = Display_line_on_screen_fast_wide2 ; - Read_line = Read_line_screen_wide2 ; - Display_zoomed_screen = Display_part_of_screen_scaled_wide2 ; - Display_brush_color_zoom = Display_brush_color_zoom_wide2 ; - Display_brush_mono_zoom = Display_brush_mono_zoom_wide2 ; - Clear_brush_scaled = Clear_brush_scaled_wide2 ; - Display_brush = Display_brush_wide2 ; - break; - case PIXEL_TALL2: - Pixel = Pixel_tall2 ; - Read_pixel= Read_pixel_tall2 ; - Display_screen = Display_part_of_screen_tall2 ; - Block = Block_tall2 ; - Pixel_preview_normal = Pixel_preview_normal_tall2 ; - Pixel_preview_magnifier = Pixel_preview_magnifier_tall2 ; - Horizontal_XOR_line = Horizontal_XOR_line_tall2 ; - Vertical_XOR_line = Vertical_XOR_line_tall2 ; - Display_brush_color = Display_brush_color_tall2 ; - Display_brush_mono = Display_brush_mono_tall2 ; - Clear_brush = Clear_brush_tall2 ; - Remap_screen = Remap_screen_tall2 ; - Display_line = Display_line_on_screen_tall2 ; - Display_line_fast = Display_line_on_screen_fast_tall2 ; - Read_line = Read_line_screen_tall2 ; - Display_zoomed_screen = Display_part_of_screen_scaled_tall2 ; - Display_brush_color_zoom = Display_brush_color_zoom_tall2 ; - Display_brush_mono_zoom = Display_brush_mono_zoom_tall2 ; - Clear_brush_scaled = Clear_brush_scaled_tall2 ; - Display_brush = Display_brush_tall2 ; - break; - case PIXEL_QUAD: - Pixel = Pixel_quad ; - Read_pixel= Read_pixel_quad ; - Display_screen = Display_part_of_screen_quad ; - Block = Block_quad ; - Pixel_preview_normal = Pixel_preview_normal_quad ; - Pixel_preview_magnifier = Pixel_preview_magnifier_quad ; - Horizontal_XOR_line = Horizontal_XOR_line_quad ; - Vertical_XOR_line = Vertical_XOR_line_quad ; - Display_brush_color = Display_brush_color_quad ; - Display_brush_mono = Display_brush_mono_quad ; - Clear_brush = Clear_brush_quad ; - Remap_screen = Remap_screen_quad ; - Display_line = Display_line_on_screen_quad ; - Display_line_fast = Display_line_on_screen_fast_quad ; - Read_line = Read_line_screen_quad ; - Display_zoomed_screen = Display_part_of_screen_scaled_quad ; - Display_brush_color_zoom = Display_brush_color_zoom_quad ; - Display_brush_mono_zoom = Display_brush_mono_zoom_quad ; - Clear_brush_scaled = Clear_brush_scaled_quad ; - Display_brush = Display_brush_quad ; - break; - } - } - Screen_width = width/Pixel_width; - Screen_height = height/Pixel_height; - - Clear_border(MC_Black); // Requires up-to-date Screen_* and Pixel_* - - // Set menu size (software zoom) - if (Screen_width/320 > Screen_height/200) - factor=Screen_height/200; - else - factor=Screen_width/320; - - switch (Config.Ratio) - { - case 1: // Always the biggest possible - Menu_factor_X=factor; - Menu_factor_Y=factor; - break; - case 2: // Only keep the aspect ratio - Menu_factor_X=factor-1; - if (Menu_factor_X<1) Menu_factor_X=1; - Menu_factor_Y=factor-1; - if (Menu_factor_Y<1) Menu_factor_Y=1; - break; - case 0: // Always smallest possible - Menu_factor_X=1; - 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)); - } - if (Pixel_height>Pixel_width && Screen_width>=Menu_factor_X*2*320) - Menu_factor_X*=2; - else if (Pixel_width>Pixel_height && Screen_height>=Menu_factor_Y*2*200) - Menu_factor_Y*=2; - - free(Horizontal_line_buffer); - Horizontal_line_buffer=(byte *)malloc(Pixel_width * - ((Screen_width>Main_image_width)?Screen_width:Main_image_width)); - - Set_palette(Main_palette); - - Current_resolution=0; - if (fullscreen) - { - for (index=1; index=Screen_width) - Mouse_X=Screen_width-1; - Mouse_Y=absolute_mouse_y/Pixel_height; - if (Mouse_Y>=Screen_height) - Mouse_Y=Screen_height-1; - if (fullscreen) - Set_mouse_position(); - - Spare_offset_X=0; // | Il faut penser à éviter les incohérences - Spare_offset_Y=0; // |- de décalage du brouillon par rapport à - Spare_magnifier_mode=0; // | la résolution. - - if (Main_magnifier_mode) - { - Pixel_preview=Pixel_preview_magnifier; - } - else - { - Pixel_preview=Pixel_preview_normal; - // Recaler la vue (meme clipping que dans Scroll_screen()) - if (Main_offset_X+Screen_width>Main_image_width) - Main_offset_X=Main_image_width-Screen_width; - if (Main_offset_X<0) - Main_offset_X=0; - if (Main_offset_Y+Menu_Y>Main_image_height) - Main_offset_Y=Main_image_height-Menu_Y; - if (Main_offset_Y<0) - Main_offset_Y=0; - } - - Compute_magnifier_data(); - if (Main_magnifier_mode) - Position_screen_according_to_zoom(); - Compute_limits(); - Compute_paintbrush_coordinates(); - - Resize_width=0; - Resize_height=0; - return 0; -} - - - - // -- Redimentionner l'image (nettoie l'écran virtuel) -- - -void Resize_image(word chosen_width,word chosen_height) -{ - word old_width=Main_image_width; - word old_height=Main_image_height; - int i; - - // +-+-+ - // |C| | A+B+C = Ancienne image - // +-+A| - // |B| | C = Nouvelle image - // +-+-+ - - 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. - - Main_image_is_modified=1; - - // On copie donc maintenant la partie C dans la nouvelle image. - for (i=0; iPages->Nb_layers; i++) - { - Copy_part_of_image_to_another( - Main_backups->Pages->Next->Image[i],0,0,Min(old_width,Main_image_width), - Min(old_height,Main_image_height),old_width, - Main_backups->Pages->Image[i],0,0,Main_image_width); - } - Redraw_layered_image(); - } - else - { - // Afficher un message d'erreur - Display_cursor(); - Message_out_of_memory(); - Hide_cursor(); - } -} - - - -void Remap_spare(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; - byte layer; - - // On commence par initialiser le tableau de booléens à faux - for (color=0;color<=255;color++) - used[color]=0; - - // On calcule la table d'utilisation des couleurs - for (layer=0; layerPages->Nb_layers; layer++) - for (y_pos=0;y_posPages->Image[layer]+(y_pos*Spare_image_width+x_pos))]=1; - - // On va maintenant se servir de la table "used" comme table de - // conversion: pour chaque indice, la table donne une couleur de - // remplacement. - // Note : Seules les couleurs utilisées on besoin d'êtres recalculées: les - // autres ne seront jamais consultées dans la nouvelle table de - // conversion puisque elles n'existent pas dans l'image, donc elles - // ne seront pas utilisées par Remap_general_lowlevel. - for (color=0;color<=255;color++) - if (used[color]) - 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_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]; -} - - - -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 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 ?")) - - // 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_posLimit_left) && - (Read_pixel_from_current_layer(start_x-1,line)==2)) || - // Test de la présence d'un point à droite du segment - ((end_x-1Limit_top)) - for (x_pos=start_x;x_pos*right_reached) - *right_reached=end_x; - // On remplit le segment de start_x à end_x-1. - for (x_pos=start_x;x_posLimit_top) - current_limit_top--; - - for (line=current_limit_bottom;line>=current_limit_top;line--) - { - line_is_modified=0; - // On va traiter le cas de la ligne n° line. - - // On commence le traitement à la gauche de l'écran - start_x=Limit_left; - - // Pour chaque segment de couleur 1 que peut contenir la ligne - while (start_x<=Limit_right) - { - // On cherche son début - for (;(start_x<=Limit_right) && - (Read_pixel_from_current_layer(start_x,line)!=1);start_x++); - - if (start_x<=Limit_right) - { - // Un segment de couleur 1 existe et commence à la position start_x. - // On va donc en chercher la fin. - for (end_x=start_x+1;(end_x<=Limit_right) && - (Read_pixel_from_current_layer(end_x,line)==1);end_x++); - - // On sait qu'il existe un segment de couleur 1 qui commence en - // start_x et qui se termine en end_x-1. - - // On va maintenant regarder si une couleur sur la périphérie - // permet de colorier ce segment avec la couleur 2. - - can_propagate=( - // Test de la présence d'un point à gauche du segment - ((start_x>Limit_left) && - (Read_pixel_from_current_layer(start_x-1,line)==2)) || - // Test de la présence d'un point à droite du segment - ((end_x-1*right_reached) - *right_reached=end_x; - // On remplit le segment de start_x à end_x-1. - for (x_pos=start_x;x_posLimit_top) ) - current_limit_top--; // On monte cette limite vers le haut - } - } - - *top_reached=current_limit_top; - *bottom_reached =current_limit_bottom; - (*right_reached)--; -} // end de la routine de remplissage "Fill" - -byte Read_pixel_from_backup_layer(word x,word y) -{ - return *((y)*Main_image_width+(x)+Main_backups->Pages->Next->Image[Main_current_layer]); -} - -void Fill_general(byte fill_color) -// -// Cette fonction fait un remplissage qui gère tous les effets. Elle fait -// appel à "Fill()". -// -{ - byte cursor_shape_before_fill; - short x_pos,y_pos; - short top_reached ,bottom_reached; - short left_reached,right_reached; - byte replace_table[256]; - - - // Avant toute chose, on vérifie que l'on n'est pas en train de remplir - // en dehors de l'image: - - if ( (Paintbrush_X>=Limit_left) && - (Paintbrush_X<=Limit_right) && - (Paintbrush_Y>=Limit_top) && - (Paintbrush_Y<=Limit_bottom) ) - { - // On suppose que le curseur est déjà caché. - // Hide_cursor(); - - // On va faire patienter l'utilisateur en lui affichant un joli petit - // sablier: - cursor_shape_before_fill=Cursor_shape; - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - - // On commence par effectuer un backup de l'image. - Backup(); - - // On fait attention au Feedback qui DOIT se faire avec le backup. - Update_FX_feedback(0); - - // On va maintenant "épurer" la zone visible de l'image: - memset(replace_table,0,256); - replace_table[Read_pixel_from_backup_layer(Paintbrush_X,Paintbrush_Y)]=1; - Replace_colors_within_limits(replace_table); - - // On fait maintenant un remplissage classique de la couleur 1 avec la 2 - Fill(&top_reached ,&bottom_reached, - &left_reached,&right_reached); - - // On s'apprête à faire des opérations qui nécessitent un affichage. Il - // faut donc retirer de l'écran le curseur: - Hide_cursor(); - Cursor_shape=cursor_shape_before_fill; - - // Il va maintenant falloir qu'on "turn" ce gros caca "into" un truc qui - // ressemble un peu plus à ce à quoi l'utilisateur peut s'attendre. - if (top_reached>Limit_top) - Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer], // source - Limit_left,Limit_top, // Pos X et Y dans source - (Limit_right-Limit_left)+1, // width copie - top_reached-Limit_top,// height copie - Main_image_width, // width de la source - Main_backups->Pages->Image[Main_current_layer], // Destination - Limit_left,Limit_top, // Pos X et Y destination - Main_image_width); // width destination - if (bottom_reachedPages->Next->Image[Main_current_layer], - Limit_left,bottom_reached+1, - (Limit_right-Limit_left)+1, - Limit_bottom-bottom_reached, - Main_image_width,Main_backups->Pages->Image[Main_current_layer], - Limit_left,bottom_reached+1,Main_image_width); - if (left_reached>Limit_left) - Copy_part_of_image_to_another(Main_backups->Pages->Next->Image[Main_current_layer], - Limit_left,top_reached, - left_reached-Limit_left, - (bottom_reached-top_reached)+1, - Main_image_width,Main_backups->Pages->Image[Main_current_layer], - Limit_left,top_reached,Main_image_width); - if (right_reachedPages->Next->Image[Main_current_layer], - right_reached+1,top_reached, - Limit_right-right_reached, - (bottom_reached-top_reached)+1, - Main_image_width,Main_backups->Pages->Image[Main_current_layer], - right_reached+1,top_reached,Main_image_width); - - for (y_pos=top_reached;y_pos<=bottom_reached;y_pos++) - for (x_pos=left_reached;x_pos<=right_reached;x_pos++) - if (Read_pixel_from_current_layer(x_pos,y_pos)==2) - { - // Si le pixel en cours de traitement a été touché par le Fill() - // on se doit d'afficher le pixel modifié par la couleur de - // remplissage: - - // Ceci se fait en commençant par restaurer la couleur qu'il y avait - // précédemment (c'est important pour que les effets ne s'emmèlent - // pas le pinceaux) - Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0); - - // Enfin, on peut afficher le pixel, en le soumettant aux effets en - // cours: - Display_pixel(x_pos,y_pos,fill_color); - } - else - Pixel_in_current_screen(x_pos,y_pos,Read_pixel_from_backup_layer(x_pos,y_pos),0); - - // Restore original feedback value - Update_FX_feedback(Config.FX_Feedback); - - // A la fin, on n'a pas besoin de réafficher le curseur puisque c'est - // l'appelant qui s'en charge, et on n'a pas besoin de rafficher l'image - // puisque les seuls points qui ont changé dans l'image ont été raffichés - // par l'utilisation de "Display_pixel()", et que les autres... eh bein - // on n'y a jamais touché à l'écran les autres: ils sont donc corrects. - if(Main_magnifier_mode) - { - short w,h; - - w=Min(Screen_width-Main_X_zoom, (Main_image_width-Main_magnifier_offset_X)*Main_magnifier_factor); - h=Min(Menu_Y, (Main_image_height-Main_magnifier_offset_Y)*Main_magnifier_factor); - - Redraw_grid(Main_X_zoom,0,w,h); - } - - Update_rect(0,0,0,0); - End_of_modification(); - } -} - - - -////////////////////////////////////////////////////////////////////////////// -////////////////// TRACéS DE FIGURES GéOMéTRIQUES STANDARDS ////////////////// -////////////////////////// avec gestion de previews ////////////////////////// -////////////////////////////////////////////////////////////////////////////// - - // Data used by ::Init_permanent_draw() and ::Pixel_figure_permanent() - static Uint32 Permanent_draw_next_refresh=0; - static int Permanent_draw_count=0; - - void Init_permanent_draw(void) - { - Permanent_draw_count = 0; - Permanent_draw_next_refresh = SDL_GetTicks() + 100; - } - - // Affichage d'un point de façon définitive (utilisation du pinceau) - void Pixel_figure_permanent(word x_pos,word y_pos,byte color) - { - Display_paintbrush(x_pos,y_pos,color,0); - Permanent_draw_count ++; - - // Check every 8 pixels - if (! (Permanent_draw_count&7)) - { - Uint32 now = SDL_GetTicks(); - SDL_PumpEvents(); - if (now>= Permanent_draw_next_refresh) - { - Permanent_draw_next_refresh = now+100; - Flush_update(); - } - } - } - - // Affichage d'un point de façon définitive - void Pixel_clipped(word x_pos,word y_pos,byte color) - { - if ( (x_pos>=Limit_left) && - (x_pos<=Limit_right) && - (y_pos>=Limit_top) && - (y_pos<=Limit_bottom) ) - Display_pixel(x_pos,y_pos,color); - } - - // Affichage d'un point pour une preview - void Pixel_figure_preview(word x_pos,word y_pos,byte color) - { - if ( (x_pos>=Limit_left) && - (x_pos<=Limit_right) && - (y_pos>=Limit_top) && - (y_pos<=Limit_bottom) ) - Pixel_preview(x_pos,y_pos,color); - } - // Affichage d'un point pour une preview, avec sa propre couleur - void Pixel_figure_preview_auto(word x_pos,word y_pos) - { - if ( (x_pos>=Limit_left) && - (x_pos<=Limit_right) && - (y_pos>=Limit_top) && - (y_pos<=Limit_bottom) ) - Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos)); - } - - // Affichage d'un point pour une preview en xor - void Pixel_figure_preview_xor(word x_pos,word y_pos,__attribute__((unused)) byte color) - { - if ( (x_pos>=Limit_left) && - (x_pos<=Limit_right) && - (y_pos>=Limit_top) && - (y_pos<=Limit_bottom) ) - Pixel_preview(x_pos,y_pos,~Read_pixel(x_pos-Main_offset_X, - y_pos-Main_offset_Y)); - } - - // Affichage d'un point pour une preview en xor additif - // (Il lit la couleur depuis la page backup) - void Pixel_figure_preview_xorback(word x_pos,word y_pos,__attribute__((unused)) byte color) - { - if ( (x_pos>=Limit_left) && - (x_pos<=Limit_right) && - (y_pos>=Limit_top) && - (y_pos<=Limit_bottom) ) - Pixel_preview(x_pos,y_pos,~Screen_backup[x_pos+y_pos*Main_image_width]); - } - - - // Effacement d'un point de preview - void Pixel_figure_clear_preview(word x_pos,word y_pos,__attribute__((unused)) byte color) - { - if ( (x_pos>=Limit_left) && - (x_pos<=Limit_right) && - (y_pos>=Limit_top) && - (y_pos<=Limit_bottom) ) - Pixel_preview(x_pos,y_pos,Read_pixel_from_current_screen(x_pos,y_pos)); - } - - // Affichage d'un point dans la brosse - void Pixel_figure_in_brush(word x_pos,word y_pos,byte color) - { - x_pos-=Brush_offset_X; - y_pos-=Brush_offset_Y; - if ( (x_posLimit_bottom) - end_y=Limit_bottom; - if (start_xLimit_right) - end_x=Limit_right; - - // Affichage du cercle - for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++) - for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++) - if (Pixel_in_circle()) - Display_pixel(x_pos,y_pos,color); - - Update_part_of_screen(start_x,start_y,end_x+1-start_x,end_y+1-start_y); -} - - - // -- Tracer général d'une ellipse vide ----------------------------------- - -void Draw_empty_ellipse_general(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color) -{ - short start_x; - short start_y; - short x_pos; - short y_pos; - - start_x=center_x-horizontal_radius; - start_y=center_y-vertical_radius; - - // Calcul des limites de l'ellipse - Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1); - - // Affichage des extremitées de l'ellipse sur chaque quart de l'ellipse: - for (y_pos=start_y,Ellipse_cursor_Y=-vertical_radius;y_posLimit_bottom) - end_y=Limit_bottom; - if (start_xLimit_right) - end_x=Limit_right; - - // Affichage de l'ellipse - for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++) - for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++) - if (Pixel_in_ellipse()) - Display_pixel(x_pos,y_pos,color); - Update_part_of_screen(center_x-horizontal_radius,center_y-vertical_radius,2*horizontal_radius+1,2*vertical_radius+1); -} - -/****************** -* TRACÉ DE LIGNES * -******************/ - -/// Alters bx and by so the (AX,AY)-(BX,BY) segment becomes either horizontal, -/// vertical, 45degrees, or isometrical for pixelart (ie 2:1 ratio) -void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by) -{ - int dx, dy; - float angle; - - dx = *bx-ax; - dy = *by-ay; - - // No mouse move: no need to clamp anything - if (dx==0 || dy == 0) return; - - // Determine angle (heading) - angle = atan2(dx, dy); - - // Get absolute values, useful from now on: - //dx=abs(dx); - //dy=abs(dy); - - // Negative Y - if (angle < M_PI*(-15.0/16.0) || angle > M_PI*(15.0/16.0)) - { - *bx=ax; - *by=ay + dy; - } - // Iso close to negative Y - else if (angle < M_PI*(-13.0/16.0)) - { - dy=dy | 1; // Round up to next odd number - *bx=ax + dy/2; - *by=ay + dy; - } - // 45deg - else if (angle < M_PI*(-11.0/16.0)) - { - *by = (*by + ay + dx)/2; - *bx = ax - ay + *by; - } - // Iso close to negative X - else if (angle < M_PI*(-9.0/16.0)) - { - dx=dx | 1; // Round up to next odd number - *bx=ax + dx; - *by=ay + dx/2; - } - // Negative X - else if (angle < M_PI*(-7.0/16.0)) - { - *bx=ax + dx; - *by=ay; - } - // Iso close to negative X - else if (angle < M_PI*(-5.0/16.0)) - { - dx=dx | 1; // Round up to next odd number - *bx=ax + dx; - *by=ay - dx/2; - } - // 45 degrees - else if (angle < M_PI*(-3.0/16.0)) - { - *by = (*by + ay - dx)/2; - *bx = ax + ay - *by; - } - // Iso close to positive Y - else if (angle < M_PI*(-1.0/16.0)) - { - dy=dy | 1; // Round up to next odd number - *bx=ax - dy/2; - *by=ay + dy; - } - // Positive Y - else if (angle < M_PI*(1.0/16.0)) - { - *bx=ax; - *by=ay + dy; - } - // Iso close to positive Y - else if (angle < M_PI*(3.0/16.0)) - { - dy=dy | 1; // Round up to next odd number - *bx=ax + dy/2; - *by=ay + dy; - } - // 45 degrees - else if (angle < M_PI*(5.0/16.0)) - { - *by = (*by + ay + dx)/2; - *bx = ax - ay + *by; - } - // Iso close to positive X - else if (angle < M_PI*(7.0/16.0)) - { - dx=dx | 1; // Round up to next odd number - *bx=ax + dx; - *by=ay + dx/2; - } - // Positive X - else if (angle < M_PI*(9.0/16.0)) - { - *bx=ax + dx; - *by=ay; - } - // Iso close to positive X - else if (angle < M_PI*(11.0/16.0)) - { - dx=dx | 1; // Round up to next odd number - *bx=ax + dx; - *by=ay - dx/2; - } - // 45 degrees - else if (angle < M_PI*(13.0/16.0)) - { - *by = (*by + ay - dx)/2; - *bx = ax + ay - *by; - } - // Iso close to negative Y - else //if (angle < M_PI*(15.0/16.0)) - { - dy=dy | 1; // Round up to next odd number - *bx=ax - dy/2; - *by=ay + dy; - } - - return; -} - - // -- Tracer général d'une ligne ------------------------------------------ - -void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color) -{ - short x_pos,y_pos; - short incr_x,incr_y; - short i,cumul; - short delta_x,delta_y; - - x_pos=start_x; - y_pos=start_y; - - if (start_xdelta_x) - { - cumul=delta_y>>1; - for (i=1; i=delta_y) - { - cumul-=delta_y; - x_pos+=incr_x; - } - Pixel_figure(x_pos,y_pos,color); - } - } - else - { - cumul=delta_x>>1; - for (i=1; i=delta_x) - { - cumul-=delta_x; - y_pos+=incr_y; - } - Pixel_figure(x_pos,y_pos,color); - } - } - - if ( (start_x!=end_x) || (start_y!=end_y) ) - Pixel_figure(end_x,end_y,color); - -} - - // -- Tracer définitif d'une ligne -- - -void Draw_line_permanent(short start_x,short start_y,short end_x,short end_y, byte color) -{ - - int w = end_x-start_x, h = end_y - start_y; - Pixel_figure=Pixel_figure_permanent; - Init_permanent_draw(); - Draw_line_general(start_x,start_y,end_x,end_y,color); - Update_part_of_screen((start_xend_x) - { - temp=start_x; - start_x=end_x; - end_x=temp; - } - if (start_y>end_y) - { - temp=start_y; - start_y=end_y; - end_y=temp; - } - - // On trace le rectangle: - Init_permanent_draw(); - - for (x_pos=start_x;x_pos<=end_x;x_pos++) - { - Pixel_figure_permanent(x_pos,start_y,color); - Pixel_figure_permanent(x_pos, end_y,color); - } - - for (y_pos=start_y+1;y_posend_x) - { - temp=start_x; - start_x=end_x; - end_x=temp; - } - if (start_y>end_y) - { - temp=start_y; - start_y=end_y; - end_y=temp; - } - - // Correction en cas de dépassement des limites de l'image - if (end_x>Limit_right) - end_x=Limit_right; - if (end_y>Limit_bottom) - end_y=Limit_bottom; - - // On trace le rectangle: - for (y_pos=start_y;y_pos<=end_y;y_pos++) - for (x_pos=start_x;x_pos<=end_x;x_pos++) - // Display_pixel traite chaque pixel avec tous les effets ! (smear, ...) - // Donc on ne peut pas otimiser en traçant ligne par ligne avec memset :( - Display_pixel(x_pos,y_pos,color); - Update_part_of_screen(start_x,start_y,end_x-start_x,end_y-start_y); - -} - - - - - // -- Tracer une courbe de Bézier -- - -void Draw_curve_general(short x1, short y1, - short x2, short y2, - short x3, short y3, - short x4, short y4, - byte color) -{ - float delta,t,t2,t3; - short x,y,old_x,old_y; - word i; - int cx[4]; - int cy[4]; - - // Calcul des vecteurs de coefficients - cx[0]= - x1 + 3*x2 - 3*x3 + x4; - cx[1]= + 3*x1 - 6*x2 + 3*x3; - cx[2]= - 3*x1 + 3*x2; - cx[3]= + x1; - cy[0]= - y1 + 3*y2 - 3*y3 + y4; - cy[1]= + 3*y1 - 6*y2 + 3*y3; - cy[2]= - 3*y1 + 3*y2; - cy[3]= + y1; - - // Traçage de la courbe - old_x=x1; - old_y=y1; - Pixel_figure(old_x,old_y,color); - delta=0.05; // 1.0/20 - t=0; - for (i=1; i<=20; i++) - { - t=t+delta; t2=t*t; t3=t2*t; - x=Round(t3*cx[0] + t2*cx[1] + t*cx[2] + cx[3]); - y=Round(t3*cy[0] + t2*cy[1] + t*cy[2] + cy[3]); - Draw_line_general(old_x,old_y,x,y,color); - old_x=x; - old_y=y; - } - - x = Min(Min(x1,x2),Min(x3,x4)); - y = Min(Min(y1,y2),Min(y3,y4)); - old_x = Max(Max(x1,x2),Max(x3,x4)) - x; - old_y = Max(Max(y1,y2),Max(y3,y4)) - y; - Update_part_of_screen(x,y,old_x+1,old_y+1); -} - - // -- Tracer une courbe de Bézier définitivement -- - -void Draw_curve_permanent(short x1, short y1, - short x2, short y2, - short x3, short y3, - short x4, short y4, - byte color) -{ - Pixel_figure=Pixel_figure_permanent; - Init_permanent_draw(); - Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); -} - - // -- Tracer la preview d'une courbe de Bézier -- - -void Draw_curve_preview(short x1, short y1, - short x2, short y2, - short x3, short y3, - short x4, short y4, - byte color) -{ - Pixel_figure=Pixel_figure_preview; - Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); -} - - // -- Effacer la preview d'une courbe de Bézier -- - -void Hide_curve_preview(short x1, short y1, - short x2, short y2, - short x3, short y3, - short x4, short y4, - byte color) -{ - Pixel_figure=Pixel_figure_clear_preview; - Draw_curve_general(x1,y1,x2,y2,x3,y3,x4,y4,color); -} - - - - - // -- Spray : un petit coup de Pschiitt! -- - -void Airbrush(short clicked_button) -{ - short x_pos,y_pos; - short radius=Airbrush_size>>1; - long radius_squared=(long)radius*radius; - short index,count; - byte color_index; - byte direction; - - - Hide_cursor(); - - if (Airbrush_mode) - { - for (count=1; count<=Airbrush_mono_flow; count++) - { - x_pos=(rand()%Airbrush_size)-radius; - y_pos=(rand()%Airbrush_size)-radius; - if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared ) - { - x_pos+=Paintbrush_X; - y_pos+=Paintbrush_Y; - if (clicked_button==1) - Display_paintbrush(x_pos,y_pos,Fore_color,0); - else - Display_paintbrush(x_pos,y_pos,Back_color,0); - } - } - } - else - { - // On essaye de se balader dans la table des flux de façon à ce que ce - // ne soit pas toujours la dernière couleur qui soit affichée en dernier - // Pour ça, on part d'une couleur au pif dans une direction aléatoire. - direction=rand()&1; - for (index=0,color_index=rand()/*%256*/; index<256; index++) - { - for (count=1; count<=Airbrush_multi_flow[color_index]; count++) - { - x_pos=(rand()%Airbrush_size)-radius; - y_pos=(rand()%Airbrush_size)-radius; - if ( (x_pos*x_pos)+(y_pos*y_pos) <= radius_squared ) - { - x_pos+=Paintbrush_X; - y_pos+=Paintbrush_Y; - if (clicked_button==LEFT_SIDE) - Display_paintbrush(x_pos,y_pos,color_index,0); - else - Display_paintbrush(x_pos,y_pos,Back_color,0); - } - } - if (direction) - color_index++; - else - color_index--; - } - } - - Display_cursor(); -} - - - - ////////////////////////////////////////////////////////////////////////// - ////////////////////////// GESTION DES DEGRADES ////////////////////////// - ////////////////////////////////////////////////////////////////////////// - - - // -- Gestion d'un dégradé de base (le plus moche) -- - -void Gradient_basic(long index,short x_pos,short y_pos) -{ - long position; - - // On fait un premier calcul partiel - position=(index*Gradient_bounds_range); - - // On gère un déplacement au hasard - position+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; - position-=(Gradient_total_range*Gradient_random_factor) >>7; - - position/=Gradient_total_range; - - // On va vérifier que nos petites idioties n'ont pas éjecté la valeur hors - // des valeurs autorisées par le dégradé défini par l'utilisateur. - - if (position<0) - position=0; - else if (position>=Gradient_bounds_range) - position=Gradient_bounds_range-1; - - // On ramène ensuite la position dans le dégradé vers un numéro de couleur - if (Gradient_is_inverted) - Gradient_pixel(x_pos,y_pos,Gradient_upper_bound-position); - else - Gradient_pixel(x_pos,y_pos,Gradient_lower_bound+position); -} - - - // -- Gestion d'un dégradé par trames simples -- - -void Gradient_dithered(long index,short x_pos,short y_pos) -{ - long position_in_gradient; - long position_in_segment; - - // - // But de l'opération: en plus de calculer la position de base (désignée - // dans cette procédure par "position_in_gradient", on calcule la position - // de l'indice dans le schéma suivant: - // - // | Les indices qui traînent de ce côté du segment se voient subir - // | une incrémentation conditionnelle à leur position dans l'écran. - // v - // |---|---|---|---- - - - - // ^ - // |_ Les indices qui traînent de ce côté du segment se voient subir une - // décrémentation conditionnelle à leur position dans l'écran. - - // On fait d'abord un premier calcul partiel - position_in_gradient=(index*Gradient_bounds_range); - - // On gère un déplacement au hasard... - position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; - position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7; - - if (position_in_gradient<0) - position_in_gradient=0; - - // ... qui nous permet de calculer la position dans le segment - position_in_segment=((position_in_gradient<<2)/Gradient_total_range)&3; - - // On peut ensuite terminer le calcul de l'indice dans le dégradé - position_in_gradient/=Gradient_total_range; - - // On va pouvoir discuter de la valeur de position_in_gradient en fonction - // de la position dans l'écran et de la position_in_segment. - - switch (position_in_segment) - { - case 0 : // On est sur la gauche du segment - if (((x_pos+y_pos)&1)==0) - position_in_gradient--; - break; - - // On n'a pas à traiter les cas 1 et 2 car ils représentent des valeurs - // suffisament au centre du segment pour ne pas avoir à subir la trame - - case 3 : // On est sur la droite du segment - if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 côtés de la trame. - position_in_gradient++; - } - - // On va vérifier que nos petites idioties n'ont pas éjecté la valeur hors - // des valeurs autorisées par le dégradé défini par l'utilisateur. - - if (position_in_gradient<0) - position_in_gradient=0; - else if (position_in_gradient>=Gradient_bounds_range) - position_in_gradient=Gradient_bounds_range-1; - - // On ramène ensuite la position dans le dégradé vers un numéro de couleur - if (Gradient_is_inverted) - position_in_gradient=Gradient_upper_bound-position_in_gradient; - else - position_in_gradient=Gradient_lower_bound+position_in_gradient; - - Gradient_pixel(x_pos,y_pos,position_in_gradient); -} - - - // -- Gestion d'un dégradé par trames étendues -- - -void Gradient_extra_dithered(long index,short x_pos,short y_pos) -{ - long position_in_gradient; - long position_in_segment; - -// - // But de l'opération: en plus de calculer la position de base (désignée - // dans cette procédure par "position_in_gradient", on calcule la position - // de l'indice dans le schéma suivant: - // - // | Les indices qui traînent de ce côté du segment se voient subir - // | une incrémentation conditionnelle à leur position dans l'écran. - // v - // |---|---|---|---- - - - - // ^ - // |_ Les indices qui traînent de ce côté du segment se voient subir une - // décrémentation conditionnelle à leur position dans l'écran. - - // On fait d'abord un premier calcul partiel - position_in_gradient=(index*Gradient_bounds_range); - - // On gère un déplacement au hasard - position_in_gradient+=(Gradient_total_range*(rand()%Gradient_random_factor)) >>6; - position_in_gradient-=(Gradient_total_range*Gradient_random_factor) >>7; - - if (position_in_gradient<0) - position_in_gradient=0; - - // Qui nous permet de calculer la position dans le segment - position_in_segment=((position_in_gradient<<3)/Gradient_total_range)&7; - - // On peut ensuite terminer le calcul de l'indice dans le dégradé - position_in_gradient/=Gradient_total_range; - - // On va pouvoir discuter de la valeur de position_in_gradient en fonction - // de la position dans l'écran et de la position_in_segment. - - switch (position_in_segment) - { - case 0 : // On est sur l'extrême gauche du segment - if (((x_pos+y_pos)&1)==0) - position_in_gradient--; - break; - - case 1 : // On est sur la gauche du segment - case 2 : // On est sur la gauche du segment - if (((x_pos & 1)==0) && ((y_pos & 1)==0)) - position_in_gradient--; - break; - - // On n'a pas à traiter les cas 3 et 4 car ils représentent des valeurs - // suffisament au centre du segment pour ne pas avoir à subir la trame - - case 5 : // On est sur la droite du segment - case 6 : // On est sur la droite du segment - if (((x_pos & 1)==0) && ((y_pos & 1)!=0)) - position_in_gradient++; - break; - - case 7 : // On est sur l'extreme droite du segment - if (((x_pos+y_pos)&1)!=0) // Note: on doit faire le test inverse au cas gauche pour synchroniser les 2 côtés de la trame. - position_in_gradient++; - } - - // On va vérifier que nos petites idioties n'ont pas éjecté la valeur hors - // des valeurs autorisées par le dégradé défini par l'utilisateur. - - if (position_in_gradient<0) - position_in_gradient=0; - else if (position_in_gradient>=Gradient_bounds_range) - position_in_gradient=Gradient_bounds_range-1; - - // On ramène ensuite la position dans le dégradé vers un numéro de couleur - if (Gradient_is_inverted) - position_in_gradient=Gradient_upper_bound-position_in_gradient; - else - position_in_gradient=Gradient_lower_bound+position_in_gradient; - - Gradient_pixel(x_pos,y_pos,position_in_gradient); -} - - - - // -- Tracer un cercle degradé (une sphère) -- - -void Draw_grad_circle(short center_x,short center_y,short radius,short spot_x,short spot_y) -{ - long start_x; - long start_y; - long x_pos; - long y_pos; - long end_x; - long end_y; - long distance_x; // Distance (au carré) sur les X du point en cours au centre d'éclairage - long distance_y; // Distance (au carré) sur les Y du point en cours au centre d'éclairage - - start_x=center_x-radius; - start_y=center_y-radius; - end_x=center_x+radius; - end_y=center_y+radius; - - // Correction des bornes d'après les limites - if (start_yLimit_bottom) - end_y=Limit_bottom; - if (start_xLimit_right) - end_x=Limit_right; - - Gradient_total_range=Circle_limit+ - ((center_x-spot_x)*(center_x-spot_x))+ - ((center_y-spot_y)*(center_y-spot_y))+ - (2L*radius*sqrt( - ((center_x-spot_x)*(center_x-spot_x))+ - ((center_y-spot_y)*(center_y-spot_y)))); - - if (Gradient_total_range==0) - Gradient_total_range=1; - - // Affichage du cercle - for (y_pos=start_y,Circle_cursor_Y=(long)start_y-center_y;y_pos<=end_y;y_pos++,Circle_cursor_Y++) - { - distance_y =(y_pos-spot_y); - distance_y*=distance_y; - for (x_pos=start_x,Circle_cursor_X=(long)start_x-center_x;x_pos<=end_x;x_pos++,Circle_cursor_X++) - if (Pixel_in_circle()) - { - distance_x =(x_pos-spot_x); - distance_x*=distance_x; - Gradient_function(distance_x+distance_y,x_pos,y_pos); - } - } - - Update_part_of_screen(center_x-radius,center_y-radius,2*radius+1,2*radius+1); -} - - - // -- Tracer une ellipse degradée -- - -void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y) -{ - long start_x; - long start_y; - long x_pos; - long y_pos; - long end_x; - long end_y; - long distance_x; // Distance (au carré) sur les X du point en cours au centre d'éclairage - long distance_y; // Distance (au carré) sur les Y du point en cours au centre d'éclairage - - - start_x=center_x-horizontal_radius; - start_y=center_y-vertical_radius; - end_x=center_x+horizontal_radius; - end_y=center_y+vertical_radius; - - // Calcul des limites de l'ellipse - Ellipse_compute_limites(horizontal_radius+1,vertical_radius+1); - - // On calcule la distance maximale: - Gradient_total_range=(horizontal_radius*horizontal_radius)+ - (vertical_radius*vertical_radius)+ - ((center_x-spot_x)*(center_x-spot_x))+ - ((center_y-spot_y)*(center_y-spot_y))+ - (2L - *sqrt( - (horizontal_radius*horizontal_radius)+ - (vertical_radius *vertical_radius )) - *sqrt( - ((center_x-spot_x)*(center_x-spot_x))+ - ((center_y-spot_y)*(center_y-spot_y)))); - - if (Gradient_total_range==0) - Gradient_total_range=1; - - // Correction des bornes d'après les limites - if (start_yLimit_bottom) - end_y=Limit_bottom; - if (start_xLimit_right) - end_x=Limit_right; - - // Affichage de l'ellipse - for (y_pos=start_y,Ellipse_cursor_Y=start_y-center_y;y_pos<=end_y;y_pos++,Ellipse_cursor_Y++) - { - distance_y =(y_pos-spot_y); - distance_y*=distance_y; - for (x_pos=start_x,Ellipse_cursor_X=start_x-center_x;x_pos<=end_x;x_pos++,Ellipse_cursor_X++) - if (Pixel_in_ellipse()) - { - distance_x =(x_pos-spot_x); - distance_x*=distance_x; - Gradient_function(distance_x+distance_y,x_pos,y_pos); - } - } - - Update_part_of_screen(start_x,start_y,end_x-start_x+1,end_y-start_y+1); -} - - -// Tracé d'un rectangle (rax ray - rbx rby) dégradé selon le vecteur (vax vay - vbx - vby) -void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short vay, short vbx, short vby) -{ - short y_pos, x_pos; - - // On commence par s'assurer que le rectangle est à l'endroit - if(rbx < rax) - { - x_pos = rbx; - rbx = rax; - rax = x_pos; - } - - if(rby < ray) - { - y_pos = rby; - rby = ray; - ray = y_pos; - } - - // Correction des bornes d'après les limites - if (rayLimit_bottom) - rby=Limit_bottom; - if (raxLimit_right) - rbx=Limit_right; - - if(vbx == vax) - { - // Le vecteur est vertical, donc on évite la partie en dessous qui foirerait avec une division par 0... - if (vby == vay) return; // L'utilisateur fait n'importe quoi - Gradient_total_range = abs(vby - vay); - for(y_pos=ray;y_pos<=rby;y_pos++) - for(x_pos=rax;x_pos<=rbx;x_pos++) - Gradient_function(abs(vby - y_pos),x_pos,y_pos); - - } - else - { - float a; - float b; - float distance_x, distance_y; - - Gradient_total_range = sqrt(pow(vby - vay,2)+pow(vbx - vax,2)); - a = (float)(vby - vay)/(float)(vbx - vax); - b = vay - a*vax; - - for (y_pos=ray;y_pos<=rby;y_pos++) - for (x_pos = rax;x_pos<=rbx;x_pos++) - { - // On calcule ou on en est dans le dégradé - distance_x = pow((y_pos - vay),2)+pow((x_pos - vax),2); - distance_y = pow((-a * x_pos + y_pos - b),2)/(a*a+1); - - Gradient_function((int)sqrt(distance_x - distance_y),x_pos,y_pos); - } - } - Update_part_of_screen(rax,ray,rbx,rby); -} - - - - -// -- Tracer un polygône plein -- - -typedef struct T_Polygon_edge /* an active edge */ -{ - short top; /* top y position */ - short bottom; /* bottom y position */ - float x, dx; /* floating point x position and gradient */ - float w; /* width of line segment */ - struct T_Polygon_edge *prev; /* doubly linked list */ - struct T_Polygon_edge *next; -} T_Polygon_edge; - - - -/* Fill_edge_structure: - * Polygon helper function: initialises an edge structure for the 2d - * rasteriser. - */ -void Fill_edge_structure(T_Polygon_edge *edge, short *i1, short *i2) -{ - short *it; - - if (i2[1] < i1[1]) - { - it = i1; - i1 = i2; - i2 = it; - } - - edge->top = i1[1]; - edge->bottom = i2[1] - 1; - edge->dx = ((float) i2[0] - (float) i1[0]) / ((float) i2[1] - (float) i1[1]); - edge->x = i1[0] + 0.4999999; - edge->prev = NULL; - edge->next = NULL; - - if (edge->dx+1 < 0.0) - edge->x += edge->dx+1; - - if (edge->dx >= 0.0) - edge->w = edge->dx; - else - edge->w = -(edge->dx); - - if (edge->w-1.0<0.0) - edge->w = 0.0; - else - edge->w = edge->w-1; -} - - - -/* Add_edge: - * Adds an edge structure to a linked list, returning the new head pointer. - */ -T_Polygon_edge * Add_edge(T_Polygon_edge *list, T_Polygon_edge *edge, int sort_by_x) -{ - T_Polygon_edge *pos = list; - T_Polygon_edge *prev = NULL; - - if (sort_by_x) - { - while ( (pos) && ((pos->x+((pos->w+pos->dx)/2)) < (edge->x+((edge->w+edge->dx)/2))) ) - { - prev = pos; - pos = pos->next; - } - } - else - { - while ((pos) && (pos->top < edge->top)) - { - prev = pos; - pos = pos->next; - } - } - - edge->next = pos; - edge->prev = prev; - - if (pos) - pos->prev = edge; - - if (prev) - { - prev->next = edge; - return list; - } - else - return edge; -} - - - -/* Remove_edge: - * Removes an edge structure from a list, returning the new head pointer. - */ -T_Polygon_edge * Remove_edge(T_Polygon_edge *list, T_Polygon_edge *edge) -{ - if (edge->next) - edge->next->prev = edge->prev; - - if (edge->prev) - { - edge->prev->next = edge->next; - return list; - } - else - return edge->next; -} - - - -/* polygon: - * Draws a filled polygon with an arbitrary number of corners. Pass the - * number of vertices, then an array containing a series of x, y points - * (a total of vertices*2 values). - */ -void Polyfill_general(int vertices, short * points, int color) -{ - short c; - short top = 0x7FFF; - short bottom = 0; - short *i1, *i2; - short x_pos,end_x; - T_Polygon_edge *edge, *next_edge, *initial_edge; - T_Polygon_edge *active_edges = NULL; - T_Polygon_edge *inactive_edges = NULL; - - /* allocate some space and fill the edge table */ - initial_edge=edge=(T_Polygon_edge *) malloc(sizeof(T_Polygon_edge) * vertices); - - i1 = points; - i2 = points + ((vertices-1)<<1); - - for (c=0; cbottom >= edge->top) - { - if (edge->top < top) - top = edge->top; - - if (edge->bottom > bottom) - bottom = edge->bottom; - - inactive_edges = Add_edge(inactive_edges, edge, 0); - edge++; - } - } - i2 = i1; - i1 += 2; - } - - /* for each scanline in the polygon... */ - for (c=top; c<=bottom; c++) - { - /* check for newly active edges */ - edge = inactive_edges; - while ((edge) && (edge->top == c)) - { - next_edge = edge->next; - inactive_edges = Remove_edge(inactive_edges, edge); - active_edges = Add_edge(active_edges, edge, 1); - edge = next_edge; - } - - /* draw horizontal line segments */ - if ((c>=Limit_top) && (c<=Limit_bottom)) - { - edge = active_edges; - while ((edge) && (edge->next)) - { - x_pos=/*Round*/(edge->x); - end_x=/*Round*/(edge->next->x+edge->next->w); - if (x_posLimit_right) - end_x=Limit_right; - for (; x_pos<=end_x; x_pos++) - Pixel_figure(x_pos,c,color); - edge = edge->next->next; - } - } - - /* update edges, sorting and removing dead ones */ - edge = active_edges; - while (edge) - { - next_edge = edge->next; - if (c >= edge->bottom) - active_edges = Remove_edge(active_edges, edge); - else - { - edge->x += edge->dx; - while ((edge->prev) && ( (edge->x+(edge->w/2)) < (edge->prev->x+(edge->prev->w/2))) ) - { - if (edge->next) - edge->next->prev = edge->prev; - edge->prev->next = edge->next; - edge->next = edge->prev; - edge->prev = edge->prev->prev; - edge->next->prev = edge; - if (edge->prev) - edge->prev->next = edge; - else - active_edges = edge; - } - } - edge = next_edge; - } - } - - free(initial_edge); - initial_edge = NULL; - - // On ne connait pas simplement les xmin et xmax ici, mais de toutes façon ce n'est pas utilisé en preview - Update_part_of_screen(0,top,Main_image_width,bottom-top+1); -} - - -void Polyfill(int vertices, short * points, int color) -{ - int index; - - Pixel_clipped(points[0],points[1],color); - if (vertices==1) - { - Update_part_of_screen(points[0],points[1],1,1); - return; - } - - // Comme pour le Fill, cette operation fait un peu d'"overdraw" - // (pixels dessinés plus d'une fois) alors on force le FX Feedback à OFF - Update_FX_feedback(0); - - Pixel_figure=Pixel_clipped; - Polyfill_general(vertices,points,color); - - // Remarque: pour dessiner la bordure avec la brosse en cours au lieu - // d'un pixel de couleur premier-plan, il suffit de mettre ici: - // Pixel_figure=Pixel_figure_permanent; - - // Dessin du contour - for (index=0; index255)) - index++; - - // On note la position de la première case de la séquence - first=index; - - // On recherche la position de la dernière case de la séquence - for (last=first;list[last+1]<256;last++); - - // Pour toutes les cases non vides (et non inhibées) qui suivent - switch (mode) - { - case SHADE_MODE_NORMAL : - for (;(index<512) && (list[index]<256);index++) - { // On met à jour les tables de conversion - color=list[index]; - table_inc[color]=list[(index+step<=last)?index+step:last]; - table_dec[color]=list[(index-step>=first)?index-step:first]; - } - break; - case SHADE_MODE_LOOP : - temp=1+last-first; - for (;(index<512) && (list[index]<256);index++) - { // On met à jour les tables de conversion - color=list[index]; - table_inc[color]=list[first+((step+index-first)%temp)]; - table_dec[color]=list[first+(((temp-step)+index-first)%temp)]; - } - break; - default : // SHADE_MODE_NOSAT - for (;(index<512) && (list[index]<256);index++) - { // On met à jour les tables de conversion - color=list[index]; - if (index+step<=last) - table_inc[color]=list[index+step]; - if (index-step>=first) - table_dec[color]=list[index-step]; - } - } - } -} - - - -// -- Interface avec l'image, affectée par le facteur de grossissement ------- - - // fonction d'affichage "Pixel" utilisée pour les opérations définitivement - // Ne doit à aucune condition être appelée en dehors de la partie visible - // de l'image dans l'écran (ça pourrait être grave) -void Display_pixel(word x,word y,byte color) - // x & y sont la position d'un point dans l'IMAGE - // color est la couleur du point - // Le Stencil est géré. - // Les effets sont gérés par appel à Effect_function(). - // La Loupe est gérée par appel à Pixel_preview(). -{ - if ( ( (!Sieve_mode) || (Effect_sieve(x,y)) ) - && (!((Stencil_mode) && (Stencil[Read_pixel_from_current_layer(x,y)]))) - && (!((Mask_mode) && (Mask_table[Read_pixel_from_spare_screen(x,y)]))) ) - { - color=Effect_function(x,y,color); - Pixel_in_current_screen(x,y,color,1); - } -} - - - -// -- Calcul des différents effets ------------------------------------------- - - // -- Aucun effet en cours -- - -byte No_effect(__attribute__((unused)) word x,__attribute__((unused)) word y,byte color) -{ - return color; -} - - // -- Effet de Shading -- - -byte Effect_shade(word x,word y,__attribute__((unused)) byte color) -{ - return Shade_table[Read_pixel_from_feedback_screen(x,y)]; -} - -byte Effect_quick_shade(word x,word y,byte color) -{ - int c=color=Read_pixel_from_feedback_screen(x,y); - int direction=(Fore_color<=Back_color); - byte start,end; - int width; - - if (direction) - { - start=Fore_color; - end =Back_color; - } - else - { - start=Back_color; - end =Fore_color; - } - - if ((c>=start) && (c<=end) && (start!=end)) - { - width=1+end-start; - - if ( ((Shade_table==Shade_table_left) && direction) || ((Shade_table==Shade_table_right) && (!direction)) ) - c-=Quick_shade_step%width; - else - c+=Quick_shade_step%width; - - if (cend) - switch (Quick_shade_loop) - { - case SHADE_MODE_NORMAL : return end; - case SHADE_MODE_LOOP : return (c-width); - default : return color; - } - } - - return c; -} - - // -- Effet de Tiling -- - -byte Effect_tiling(word x,word y,__attribute__((unused)) byte color) -{ - return Read_pixel_from_brush((x+Brush_width-Tiling_offset_X)%Brush_width, - (y+Brush_height-Tiling_offset_Y)%Brush_height); -} - - // -- Effet de Smooth -- - -byte Effect_smooth(word x,word y,__attribute__((unused)) byte color) -{ - int r,g,b; - byte c; - int weight,total_weight; - byte x2=((x+1)Pages->Transparent_color) // transparent color - return color; - - depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); - return *(Main_backups->Pages->Image[depth] + x+y*Main_image_width); - #else - return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); - #endif -} - -void Pixel_in_current_screen (word x,word y,byte color,int with_preview) -{ - #ifndef NOLAYERS - byte depth = *(Main_visible_image_depth_buffer.Image+x+y*Main_image_width); - *(Main_backups->Pages->Image[Main_current_layer] + x+y*Main_image_width)=color; - if ( depth <= Main_current_layer) - { - if (color == Main_backups->Pages->Transparent_color) // transparent color - // fetch pixel color from the topmost visible layer - color=*(Main_backups->Pages->Image[depth] + x+y*Main_image_width); - - *(x+y*Main_image_width+Main_screen)=color; - - if (with_preview) - Pixel_preview(x,y,color); - } - #else - *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; - if (with_preview) - Pixel_preview(x,y,color); - #endif -} - -void Pixel_in_current_layer(word x,word y, byte color) -{ - *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer])=color; -} - -byte Read_pixel_from_current_layer(word x,word y) -{ - return *((y)*Main_image_width+(x)+Main_backups->Pages->Image[Main_current_layer]); -} diff --git a/project/jni/application/grafx2/grafx2/src/graph.h b/project/jni/application/grafx2/grafx2/src/graph.h deleted file mode 100644 index 70c49d3c3..000000000 --- a/project/jni/application/grafx2/grafx2/src/graph.h +++ /dev/null @@ -1,123 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007-2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file graph.h -/// Graphic functions that target the screen and/or image. -////////////////////////////////////////////////////////////////////////////// - -void Shade_list_to_lookup_tables(word * list, short step, byte mode, byte * table_inc, - byte * table_dec -); - -void Transform_point(short x, short y, - float cos_a, float sin_a, short * rx, short * ry); - -int Init_mode_video(int width, int height, int fullscreen,int pixel_ratio); - -byte No_effect(word x,word y,byte color); -byte Effect_shade(word x,word y,byte color); -byte Effect_quick_shade(word x,word y,byte color); -byte Effect_tiling(word x,word y,byte color); -byte Effect_smooth(word x,word y,byte color); - -void Display_foreback(void); - - -void Display_pixel(word x,word y,byte color); - -void Display_paintbrush(short x,short y,byte color,byte is_preview); -void Hide_paintbrush(short x,short y); - -void Resize_image(word chosen_width,word chosen_height); - -void Fill_general(byte fill_color); -void Replace(byte New_color); - -void Pixel_figure_preview (word x_pos,word y_pos,byte color); -void Pixel_figure_preview_auto(word x_pos,word y_pos); -void Pixel_figure_preview_xor(word x_pos,word y_pos,byte color); -void Pixel_figure_preview_xorback(word x_pos,word y_pos,byte color); -void Pixel_figure_in_brush(word x_pos,word y_pos,byte color); - -void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color); - -void Draw_empty_circle_permanent(short center_x,short center_y,short radius,byte color); -void Draw_empty_circle_preview (short center_x,short center_y,short radius,byte color); -void Hide_empty_circle_preview (short center_x,short center_y,short radius); -void Draw_empty_circle_general(short center_x,short center_y,short radius,byte color); -void Draw_filled_circle (short center_x,short center_y,short radius,byte color); - -void Draw_empty_ellipse_permanent(short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); -void Draw_empty_ellipse_preview (short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); -void Hide_empty_ellipse_preview (short center_x,short center_y,short horizontal_radius,short vertical_radius); -void Draw_filled_ellipse (short center_x,short center_y,short horizontal_radius,short vertical_radius,byte color); - -void Clamp_coordinates_regular_angle(short ax, short ay, short* bx, short* by); -void Draw_line_general(short start_x,short start_y,short end_x,short end_y, byte color); -void Draw_line_permanent (short start_x,short start_y,short end_x,short end_y,byte color); -void Draw_line_preview (short start_x,short start_y,short end_x,short end_y,byte color); -void Draw_line_preview_xor(short start_x,short start_y,short end_x,short end_y,byte color); -void Draw_line_preview_xorback(short start_x,short start_y,short end_x,short end_y,byte color); -void Hide_line_preview (short start_x,short start_y,short end_x,short end_y); - -void Draw_empty_rectangle(short start_x,short start_y,short end_x,short end_y,byte color); -void Draw_filled_rectangle(short start_x,short start_y,short end_x,short end_y,byte color); - -void Draw_curve_permanent(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); -void Draw_curve_preview (short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); -void Hide_curve_preview (short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, byte color); - -void Airbrush(short clicked_button); - -void Gradient_basic (long index,short x_pos,short y_pos); -void Gradient_dithered (long index,short x_pos,short y_pos); -void Gradient_extra_dithered(long index,short x_pos,short y_pos); -void Degrade_aleatoire (long index,short x_pos,short y_pos); - -void Draw_grad_circle (short center_x,short center_y,short radius,short spot_x,short spot_y); -void Draw_grad_ellipse(short center_x,short center_y,short horizontal_radius,short vertical_radius,short spot_x,short spot_y); -void Draw_grad_rectangle(short rax,short ray,short rbx,short rby,short vax,short vay, short vbx, short vby); - -void Polyfill_general(int vertices, short * points, int color); -void Polyfill(int vertices, short * points, int color); - -/// Remap the spare page according to the main page's palette -void Remap_spare(void); - -/// -/// All the figure-drawing functions work by calling this function for each -/// pixel to draw. Before calling these functions, you should assign -/// ::Pixel_figure depending on what you where you want to draw: -/// - ::Pixel_figure_preview : On screen. -/// - ::Pixel_figure_preview_xor : On screen, XORing the color. -/// - ::Pixel_figure_permanent : On screen and in the image. -/// - ::Pixel_figure_clear_preview : On screen, reverting to the image's pixels. -extern Func_pixel Pixel_figure; - -void Update_part_of_screen(short x, short y, short width, short height); - -void Redraw_grid(short x, short y, unsigned short w, unsigned short h); - -void Pixel_in_current_screen (word x,word y,byte color,int with_preview); -void Pixel_in_current_layer(word x,word y, byte color); -byte Read_pixel_from_current_screen (word x,word y); -byte Read_pixel_from_current_layer(word x,word y); diff --git a/project/jni/application/grafx2/grafx2/src/haiku.h b/project/jni/application/grafx2/grafx2/src/haiku.h deleted file mode 100644 index 4d5068de0..000000000 --- a/project/jni/application/grafx2/grafx2/src/haiku.h +++ /dev/null @@ -1,8 +0,0 @@ -#include "struct.h" - -#ifndef __HAIKU_H -#define __HAIKU_H - -qword haiku_get_free_space(char* path); - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/help.c b/project/jni/application/grafx2/grafx2/src/help.c deleted file mode 100644 index 34eec25c4..000000000 --- a/project/jni/application/grafx2/grafx2/src/help.c +++ /dev/null @@ -1,863 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include - -#if defined(__WIN32__) - #include -#elif defined(__macosx__) || defined(__FreeBSD__) - #include - #include -#elif defined (__linux__) - #include -#elif defined(__HAIKU__) - #include "haiku.h" -#elif defined (__MINT__) - #include - #include - #include -#endif - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "engine.h" -#include "helpfile.h" -#include "help.h" -#include "sdlscreen.h" -#include "text.h" -#include "keyboard.h" -#include "windows.h" -#include "input.h" -#include "hotkeys.h" -#include "errors.h" -#include "pages.h" - -extern char Program_version[]; // generated in pversion.c -extern char SVN_revision[]; // generated in pversion.c - -// Recherche un raccourci clavier: -word * Shortcut(word shortcut_number) -{ - if (shortcut_number & 0x100) - return &(Buttons_Pool[shortcut_number & 0xFF].Left_shortcut[0]); - if (shortcut_number & 0x200) - return &(Buttons_Pool[shortcut_number & 0xFF].Right_shortcut[0]); - return &(Config_Key[shortcut_number & 0xFF][0]); -} - -// 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) -{ - static char shortcuts_name[80]; - word * pointer = Shortcut(shortcut_number); - if (pointer == NULL) - return "(Problem)"; - else - { - if (pointer[0] == 0 && pointer[1] == 0) - return "None"; - if (pointer[0] != 0 && pointer[1] == 0) - return Key_name(pointer[0]); - if (pointer[0] == 0 && pointer[1] != 0) - return Key_name(pointer[1]); - - strcpy(shortcuts_name, Key_name(pointer[0])); - strcat(shortcuts_name, " or "); - strcat(shortcuts_name, Key_name(pointer[1])); - return shortcuts_name; - } -} -void Redefine_control(word *shortcut, int x_pos, int y_pos) -{ - Hide_cursor(); - Print_in_window(x_pos,y_pos,"*PRESS KEY OR BUTTON*",MC_Black,MC_Light); - Display_cursor(); - while (1) - { - Get_input(20); - if (Key==KEY_ESC) - return; - if (Key!=0) - { - *shortcut=Key; - return; - } - } -} - -void Window_set_shortcut(int action_id) -{ - short clicked_button; - short order_index; - short config_index; - short redraw_controls=1; - word * shortcut_ptr=NULL; - word backup_shortcut[2]; - - shortcut_ptr=Shortcut(action_id); - - backup_shortcut[0]=shortcut_ptr[0]; - backup_shortcut[1]=shortcut_ptr[1]; - - // Recherche dans hotkeys - order_index=0; - while (Ordering[order_index]!=action_id) - { - order_index++; - if (order_index>=NB_SHORTCUTS) - { - Error(0); - return; - } - } - /* - config_index=0; - while (ConfigKey[config_index].Number!=order_index) - { - config_index++; - if (config_index>=NB_SHORTCUTS) - { - Error(0); - return; - } - } - */ - config_index=order_index; // Comprends pas... ça devrait pas marcher - - Open_window(302,131,"Keyboard shortcut"); - Window_set_normal_button(181,111,55,14,"Cancel",0,1,KEY_ESC); // 1 - Window_set_normal_button(241,111,55,14,"OK",0,1,SDLK_RETURN); // 2 - - Window_set_normal_button(6,111,111,14,"Reset default",0,1,KEY_NONE); // 3 - - // Titre - Block(Window_pos_X+(Menu_factor_X*5), - Window_pos_Y+(Menu_factor_Y*16), - Menu_factor_X*292,Menu_factor_Y*11,MC_Black); - Print_in_window(7,18,ConfigKey[config_index].Label,MC_White,MC_Black); - - // Zone de description - Window_display_frame_in(5,68,292,37); - Print_in_window(8,70,ConfigKey[config_index].Explanation1,MC_Black,MC_Light); - Print_in_window(8,78,ConfigKey[config_index].Explanation2,MC_Black,MC_Light); - Print_in_window(8,86,ConfigKey[config_index].Explanation3,MC_Black,MC_Light); - - // Shortcut 0 - Window_set_normal_button(27,30,177,14,"",0,1,KEY_NONE); // 4 - Window_set_normal_button(209,30,56,14,"Remove",0,1,KEY_NONE); // 5 - - // Shortcut 1 - Window_set_normal_button(27,49,177,14,"",0,1,KEY_NONE); // 6 - Window_set_normal_button(209,49,56,14,"Remove",0,1,KEY_NONE); // 7 - - Display_cursor(); - do - { - if (redraw_controls) - { - Hide_cursor(); - Block(Window_pos_X+(Menu_factor_X*32), - Window_pos_Y+(Menu_factor_Y*33), - Menu_factor_X*21*8,Menu_factor_Y*8,MC_Light); - Print_in_window_limited(32,33,Key_name(shortcut_ptr[0]),21,MC_Black,MC_Light); - Block(Window_pos_X+(Menu_factor_X*32), - Window_pos_Y+(Menu_factor_Y*52), - Menu_factor_X*21*8,Menu_factor_Y*8,MC_Light); - Print_in_window_limited(32,52,Key_name(shortcut_ptr[1]),21,MC_Black,MC_Light); - - Update_rect(Window_pos_X,Window_pos_Y,302*Menu_factor_X,131*Menu_factor_Y); - - Display_cursor(); - redraw_controls=0; - } - - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case -1: - case 0: - break; - case 4: // Change 0 - Redefine_control(&shortcut_ptr[0], 32, 33); - redraw_controls=1; - break; - case 6: // Change 1 - Redefine_control(&shortcut_ptr[1], 32, 52); - redraw_controls=1; - break; - case 5: // Remove 0 - shortcut_ptr[0]=0; - redraw_controls=1; - break; - case 7: // Remove 1 - shortcut_ptr[1]=0; - redraw_controls=1; - break; - case 3: // Defaults - shortcut_ptr[0]=ConfigKey[config_index].Key; - shortcut_ptr[1]=ConfigKey[config_index].Key2; - redraw_controls=1; - break; - case 1: // Cancel - shortcut_ptr[0]=backup_shortcut[0]; - shortcut_ptr[1]=backup_shortcut[1]; - case 2: // OK - // Replace twice by single - if (shortcut_ptr[0]==shortcut_ptr[1]) - shortcut_ptr[1]=0; - // Remove all other shortcuts that use same keys - if (!Config.Allow_multi_shortcuts) - { - int n; - for (n=0; n<2; n++) - { - if (shortcut_ptr[n]!=0) - { - int i; - for(i=0; i'_' || 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) - { - 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) - (16 - line_index)*8, - MC_Black); - break; - } - // On affiche la ligne - line = Help_section[Current_help_section].Help_table[start_line + line_index].Text; - line_type = Help_section[Current_help_section].Help_table[start_line + line_index].Line_type; - // Si c'est une sous-ligne de titre, on utilise le texte de la ligne précédente - if (line_type == '-' && (start_line + line_index > 0)) - line = Help_section[Current_help_section].Help_table[start_line + line_index - 1].Text; - else if (line_type == 'K') - { - const char *hyperlink; - const char * escaped_percent_pos; - // Determine link position: - link_position = strstr(line,"%s") - line; - // Adjust for any escaped %% that would precede it. - escaped_percent_pos = line; - do - { - escaped_percent_pos = strstr(escaped_percent_pos,"%%"); - if (escaped_percent_pos && escaped_percent_pos - line < link_position) - { - link_position--; - escaped_percent_pos+=2; - } - } while (escaped_percent_pos); - // - hyperlink=Keyboard_shortcut_value(Help_section[Current_help_section].Help_table[start_line + line_index].Line_parameter); - link_size=strlen(hyperlink); - snprintf(buffer, 44, line, hyperlink); - if (strlen(line)+link_size-2>44) - { - buffer[43]=ELLIPSIS_CHARACTER; - buffer[44]='\0'; - } - line = buffer; - } - - width=Print_help(x_pos, y_pos+(line_index<<3), line, line_type, link_position, link_size); - // On efface la fin de la ligne: - if (width<44) - Window_rectangle (x_pos+width*6, - y_pos+(line_index<<3), - (44-width)*6, - 8, - MC_Black); - } - Update_window_area(x_pos,y_pos,44*6,16*8); -} - - -void Scroll_help(T_Scroller_button * scroller) -{ - Hide_cursor(); - scroller->Position=Help_position; - Compute_slider_cursor_length(scroller); - Window_draw_slider(scroller); - Display_help(); - Display_cursor(); -} - - -void Button_Help(void) -{ - short btn_number; - - // Aide contextuelle - if (Key!=0) - { - btn_number = Button_under_mouse(); - if (btn_number != -1) - { - Window_help(btn_number, NULL); - return; - } - } - Window_help(-1, NULL); -} -// Ouvre l'ecran d'aide. Passer -1 pour la section par défaut (ou derniere,) -// Ou un nombre de l'enumération BUTTON_NUMBERS pour l'aide contextuelle. -void Window_help(int section, const char *sub_section) -{ - short clicked_button; - short nb_lines; - T_Scroller_button * scroller; - - if (section!=-1) - { - Current_help_section = 4 + section; - Help_position = 0; - } - nb_lines=Help_section[Current_help_section].Length; - if (section!=-1 && sub_section!=NULL) - { - int index=0; - for (index=0; index2) - { - Current_help_section=clicked_button-3; - Help_position=0; - nb_lines=Help_section[Current_help_section].Length; - scroller->Position=0; - scroller->Nb_elements=nb_lines; - Compute_slider_cursor_length(scroller); - Window_draw_slider(scroller); - } - else - Help_position=Window_attribute2; - - Display_help(); - Display_cursor(); - } - - - // Gestion des touches de déplacement dans la liste - switch (Key) - { - case SDLK_UP : // Haut - if (Help_position>0) - Help_position--; - Scroll_help(scroller); - Key=0; - break; - case SDLK_DOWN : // Bas - if (Help_position15) - Help_position-=15; - else - Help_position=0; - Scroll_help(scroller); - Key=0; - break; - case (KEY_MOUSEWHEELUP) : // WheelUp - if (Help_position>3) - Help_position-=3; - else - Help_position=0; - Scroll_help(scroller); - Key=0; - break; - case SDLK_PAGEDOWN : // PageDown - if (nb_lines>16) - { - if (Help_position16) - { - if (Help_position16) - { - Help_position=nb_lines-16; - Scroll_help(scroller); - Key=0; - } - break; - } - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - clicked_button=1; - } - while ((clicked_button!=1) && (Key!=SDLK_RETURN)); - - Key=0; - Close_window(); - Unselect_button(BUTTON_HELP); - Display_cursor(); -} - - -#define STATS_TITLE_COLOR MC_White -#define STATS_DATA_COLOR MC_Light -void Button_Stats(void) -{ - short clicked_button; - char buffer[37]; - dword color_usage[256]; - unsigned long long freeRam; - qword mem_size = 0; - - Open_window(310,174,"Statistics"); - - // Dessin de la fenetre ou va s'afficher le texte - Window_display_frame_in(8,17,294,132); - Block(Window_pos_X+(Menu_factor_X*9), - Window_pos_Y+(Menu_factor_Y*18), - Menu_factor_X*292,Menu_factor_Y*130,MC_Black); - - Window_set_normal_button(120,153,70,14,"OK",0,1,KEY_ESC); // 1 - - // Affichage du numéro de version - Print_in_window(10,19,"Program version:",STATS_TITLE_COLOR,MC_Black); - sprintf(buffer,"%s.%s",Program_version, SVN_revision); - Print_in_window(146,19,buffer,STATS_DATA_COLOR,MC_Black); - 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); - - freeRam = Memory_free(); - - if(freeRam > (100ULL*1024*1024*1024)) - sprintf(buffer,"%u Gigabytes",(unsigned int)(freeRam/(1024*1024*1024))); - else if(freeRam > (100*1024*1024)) - sprintf(buffer,"%u Megabytes",(unsigned int)(freeRam/(1024*1024))); - else if(freeRam > 100*1024) - 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)) - sprintf(buffer,"%ld (%lld Gb)",Stats_pages_number, Stats_pages_memory/(1024*1024*1024)); - else if(Stats_pages_memory > (100*1024*1024)) - sprintf(buffer,"%ld (%lld Mb)",Stats_pages_number, Stats_pages_memory/(1024*1024)); - else - sprintf(buffer,"%ld (%lld Kb)",Stats_pages_number, Stats_pages_memory/1024); - Print_in_window(162,59,buffer,STATS_DATA_COLOR,MC_Black); - - // Affichage de l'espace disque libre - sprintf(buffer,"Free space on %c:",Main_current_directory[0]); - Print_in_window(10,67,buffer,STATS_TITLE_COLOR,MC_Black); - -#if defined(__WIN32__) - { - ULARGE_INTEGER tailleU; - GetDiskFreeSpaceEx(Main_current_directory,&tailleU,NULL,NULL); - mem_size = tailleU.QuadPart; - } -#elif defined(__linux__) || defined(__macosx__) || defined(__FreeBSD__) - // Note: under MacOSX, both macros are defined anyway. - { - struct statfs disk_info; - statfs(Main_current_directory,&disk_info); - mem_size=(qword) disk_info.f_bfree * (qword) disk_info.f_bsize; - } -#elif defined(__HAIKU__) - mem_size = haiku_get_free_space(Main_current_directory); -#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 :)" - mem_size=0; -#endif - - if(mem_size > (100ULL*1024*1024*1024)) - sprintf(buffer,"%u Gigabytes",(unsigned int)(mem_size/(1024*1024*1024))); - else if(mem_size > (100*1024*1024)) - sprintf(buffer,"%u Megabytes",(unsigned int)(mem_size/(1024*1024))); - else if(mem_size > (100*1024)) - sprintf(buffer,"%u Kilobytes",(unsigned int)(mem_size/1024)); - else - sprintf(buffer,"%u bytes",(unsigned int)mem_size); - Print_in_window(146,67,buffer,STATS_DATA_COLOR,MC_Black); - - // Affichage des informations sur l'image - Print_in_window(10,83,"Picture info.:",STATS_TITLE_COLOR,MC_Black); - - // Affichage des dimensions de l'image - Print_in_window(18,91,"Dimensions :",STATS_TITLE_COLOR,MC_Black); - sprintf(buffer,"%dx%d",Main_image_width,Main_image_height); - Print_in_window(122,91,buffer,STATS_DATA_COLOR,MC_Black); - - // Affichage du nombre de couleur utilisé - Print_in_window(18,99,"Colors used:",STATS_TITLE_COLOR,MC_Black); - memset(color_usage,0,sizeof(color_usage)); - sprintf(buffer,"%d",Count_used_colors(color_usage)); - Print_in_window(122,99,buffer,STATS_DATA_COLOR,MC_Black); - - // Affichage des dimensions de l'écran - Print_in_window(10,115,"Resolution:",STATS_TITLE_COLOR,MC_Black); - sprintf(buffer,"%dx%d",Screen_width,Screen_height); - Print_in_window(106,115,buffer,STATS_DATA_COLOR,MC_Black); - - Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*310,Menu_factor_Y*174); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - if (Is_shortcut(Key,0x200+BUTTON_HELP)) - clicked_button=1; - } - while ( (clicked_button!=1) && (Key!=SDLK_RETURN) ); - - if(Key==SDLK_RETURN)Key=0; - - Close_window(); - Unselect_button(BUTTON_HELP); - Display_cursor(); -} - diff --git a/project/jni/application/grafx2/grafx2/src/help.h b/project/jni/application/grafx2/grafx2/src/help.h deleted file mode 100644 index 42cd7627b..000000000 --- a/project/jni/application/grafx2/grafx2/src/help.h +++ /dev/null @@ -1,66 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file help.h -/// Functions related to the help browser. The help data is in helpfile.h -////////////////////////////////////////////////////////////////////////////// - -#ifndef __HELP_H_ -#define __HELP_H_ - -/*! - Called to open the help window with the keyboard shortcut. - If the mouse is over a button, its contextual help will be displayed. - Else, the default helpscreen will be shown. -*/ -void Button_Help(void); - -/*! - Displays and runs the "Statistics" window -*/ -void Button_Stats(void); - -/*! - Displays and runs the "Help / About..." window - @param section Number of the help section page to display (equals the button number the mouse was hovering for the contextual help), -1 for the main help page. - @param sub_section Help sub-section title (the page will be scrolled so this title is at the top). -*/ -void Window_help(int section, const char * sub_section); - -/// 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); - -/// -/// Browse the complete list of shortcuts and ensure that a key only triggers -/// one of them. -void Remove_duplicate_shortcuts(void); - -#endif - diff --git a/project/jni/application/grafx2/grafx2/src/helpfile.h b/project/jni/application/grafx2/grafx2/src/helpfile.h deleted file mode 100644 index 6ed351bc5..000000000 --- a/project/jni/application/grafx2/grafx2/src/helpfile.h +++ /dev/null @@ -1,2966 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2009 Franck Charlet - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file helpfile.h -/// This is all the text that appears in contextual help and credits. -/// -/// Note: The source code is kept on a public website, so keep this in mind -/// if you're thinking of putting an e-mail address in there. At least, use -/// "\100" instead of @, to help against the most basic email address harvesters. -////////////////////////////////////////////////////////////////////////////// - -#include "const.h" // Uses enumerations BUTTON_NUMBERS and SPECIAL_ACTIONS - -// Some magic formulas: - -#define HELP_TEXT(x) {'N', x, 0}, -// Generates a 'N' line (Normal) - -#define HELP_LINK(x,y) {'K', x, y}, -// Generates a 'K' line (Key) - -#define HELP_BOLD(x) {'S', x, 0}, -// Generates a 'S' line (BOLD) - -#define HELP_TITLE(x) {'T', x, 0}, {'-', x, 0}, -// Generates a 'T' line (Title, upper half) -// and a second '-' line (Title, lower half), with the same text. - -static const T_Help_table helptable_about[] = -/* - Do not exceed 44 characters for normal lines: - HELP_TEXT ("--------------------------------------------") - Do not exceed 22 characters for title lines: - HELP_TITLE("======================") -*/ -{ - HELP_TEXT ("") // Leave enough room for a hard-coded logo, eventually. - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" GRAFX 2 ") - HELP_BOLD (" \"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-2011, the Grafx2 project team") - HELP_TEXT (" Copyright 1996-2001, SUNSET DESIGN") -}; -static const T_Help_table helptable_licence[] = -{ - HELP_TITLE(" LICENSE") - HELP_TEXT ("") - HELP_TEXT ("Grafx2 is FREE SOFTWARE, you can") - HELP_TEXT ("redistribute it and/or modify it under the") - HELP_TEXT ("terms of the GNU General Public License as") - HELP_TEXT ("published by the Free Software Foundation;") - HELP_TEXT ("version 2 of the License.") - HELP_TEXT ("") - HELP_TEXT ("Grafx2 is distributed in the hope that it") - HELP_TEXT ("will be useful, but WITHOUT ANY WARRANTY;") - HELP_TEXT ("without even the implied warranty of") - HELP_TEXT ("MERCHANTABILITY or FITNESS FOR A PARTICULAR") - HELP_TEXT ("PURPOSE. See the GNU General Public License") - HELP_TEXT ("for more details.") - HELP_TEXT ("") - HELP_TEXT ("You should have received a copy of the GNU") - HELP_TEXT ("General Public License along with Grafx2;") - HELP_TEXT ("if not, see http://www.gnu.org/licenses/ or") - HELP_TEXT ("write to the Free Software Foundation, Inc.") - HELP_TEXT (" 59 Temple Place - Suite 330, Boston,") - HELP_TEXT (" MA 02111-1307, USA.") - -}; -static const T_Help_table helptable_help[] = -{ - HELP_TITLE(" HELP") - HELP_TEXT ("") - HELP_TEXT (" Contextual help is available by pressing") - HELP_LINK (" the %s key",0x100+BUTTON_HELP) - HELP_TEXT (" You can do it while hovering a menu icon,") - HELP_TEXT (" or while a window is open.") - HELP_TEXT (" When a keyboard shortcut is displayed it's") - HELP_TEXT (" your current configuration and you can") - HELP_TEXT (" change it by clicking it.") - HELP_TEXT ("") - HELP_TITLE(" KEYBOARD SHORTCUTS") - HELP_TEXT ("") - HELP_TEXT ("Scroll visible area") - HELP_LINK (" up: %s", SPECIAL_SCROLL_UP) - HELP_LINK (" down: %s", SPECIAL_SCROLL_DOWN) - HELP_LINK (" left: %s", SPECIAL_SCROLL_LEFT) - HELP_LINK (" right: %s", SPECIAL_SCROLL_RIGHT) - HELP_LINK (" up faster: %s", SPECIAL_SCROLL_UP_FAST) - HELP_LINK (" down faster: %s", SPECIAL_SCROLL_DOWN_FAST) - HELP_LINK (" left faster: %s", SPECIAL_SCROLL_LEFT_FAST) - HELP_LINK (" right faster: %s", SPECIAL_SCROLL_RIGHT_FAST) - HELP_LINK (" up slower: %s", SPECIAL_SCROLL_UP_SLOW) - HELP_LINK (" down slower: %s", SPECIAL_SCROLL_DOWN_SLOW) - HELP_LINK (" left slower: %s", SPECIAL_SCROLL_LEFT_SLOW) - HELP_LINK (" right slower: %s", SPECIAL_SCROLL_RIGHT_SLOW) - HELP_TEXT ("Emulate mouse") - HELP_LINK (" Up: %s", SPECIAL_MOUSE_UP) - HELP_LINK (" Down: %s", SPECIAL_MOUSE_DOWN) - HELP_LINK (" Left: %s", SPECIAL_MOUSE_LEFT) - HELP_LINK (" Right: %s", SPECIAL_MOUSE_RIGHT) - HELP_LINK (" Left click: %s", SPECIAL_CLICK_LEFT) - HELP_LINK (" Right click: %s", SPECIAL_CLICK_RIGHT) - HELP_LINK ("Show / Hide menu: %s", 0x100+BUTTON_HIDE) - HELP_LINK ("Show / Hide cursor: %s", SPECIAL_SHOW_HIDE_CURSOR) - HELP_LINK ("Paintbrush = \".\": %s", SPECIAL_DOT_PAINTBRUSH) - HELP_LINK ("Paintbrush choice: %s", 0x100+BUTTON_PAINTBRUSHES) - HELP_LINK ("Monochrome brush: %s", 0x200+BUTTON_PAINTBRUSHES) - HELP_LINK ("Freehand drawing: %s", 0x100+BUTTON_DRAW) - HELP_TEXT ("Switch freehand") - HELP_LINK (" drawing mode: %s", 0x200+BUTTON_DRAW) - HELP_TEXT ("Continuous freehand") - HELP_LINK (" drawing: %s", SPECIAL_CONTINUOUS_DRAW) - HELP_LINK ("Line: %s", 0x100+BUTTON_LINES) - HELP_LINK ("Knotted lines: %s", 0x200+BUTTON_LINES) - HELP_LINK ("Spray: %s", 0x100+BUTTON_AIRBRUSH) - HELP_LINK ("Spray menu: %s", 0x200+BUTTON_AIRBRUSH) - HELP_LINK ("Floodfill: %s", 0x100+BUTTON_FLOODFILL) - HELP_LINK ("Replace color: %s", 0x200+BUTTON_FLOODFILL) - HELP_LINK ("Bezier's curves: %s", 0x100+BUTTON_CURVES) - HELP_TEXT ("Bezier's curve with") - HELP_LINK (" 3 or 4 points %s", 0x200+BUTTON_CURVES) - HELP_LINK ("Empty rectangle: %s", 0x100+BUTTON_RECTANGLES) - HELP_LINK ("Filled rectangle: %s", 0x100+BUTTON_FILLRECT) - HELP_LINK ("Empty circle: %s", 0x100+BUTTON_CIRCLES) - HELP_LINK ("Empty ellipse: %s", 0x200+BUTTON_CIRCLES) - HELP_LINK ("Filled circle: %s", 0x100+BUTTON_FILLCIRC) - HELP_LINK ("Filled ellipse: %s", 0x200+BUTTON_FILLCIRC) - HELP_LINK ("Empty polygon: %s", 0x100+BUTTON_POLYGONS) - HELP_LINK ("Empty polyform: %s", 0x200+BUTTON_POLYGONS) - HELP_LINK ("Polyfill: %s", 0x100+BUTTON_POLYFILL) - HELP_LINK ("Filled polyform: %s", 0x200+BUTTON_POLYFILL) - HELP_LINK ("Gradient rectangle: %s", 0x100+BUTTON_GRADRECT) - HELP_LINK ("Gradation menu: %s", 0x200+BUTTON_GRADRECT) - HELP_LINK ("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) - HELP_LINK ("Flip picture menu: %s", 0x200+BUTTON_ADJUST) - HELP_LINK ("Effects menu: %s", 0x100+BUTTON_EFFECTS) - HELP_LINK ("Effects all off %s", SPECIAL_EFFECTS_OFF) - HELP_LINK ("Shade mode: %s", SPECIAL_SHADE_MODE) - HELP_LINK ("Shade menu: %s", SPECIAL_SHADE_MENU) - HELP_LINK ("Quick-shade mode: %s", SPECIAL_QUICK_SHADE_MODE) - HELP_LINK ("Quick-shade menu: %s", SPECIAL_QUICK_SHADE_MENU) - HELP_LINK ("Stencil mode: %s", SPECIAL_STENCIL_MODE) - HELP_LINK ("Stencil menu: %s", SPECIAL_STENCIL_MENU) - HELP_LINK ("Mask mode: %s", SPECIAL_MASK_MODE) - HELP_LINK ("Mask menu: %s", SPECIAL_MASK_MENU) - HELP_LINK ("Grid mode: %s", SPECIAL_GRID_MODE) - HELP_LINK ("Grid menu: %s", SPECIAL_GRID_MENU) - HELP_LINK ("Grid view: %s", SPECIAL_SHOW_GRID) - HELP_LINK ("Sieve mode: %s", SPECIAL_SIEVE_MODE) - HELP_LINK ("Sieve menu: %s", SPECIAL_SIEVE_MENU) - HELP_LINK ("Invert Sieve: %s", SPECIAL_INVERT_SIEVE) - HELP_LINK ("Colorize mode: %s", SPECIAL_COLORIZE_MODE) - HELP_LINK (" At opacity 10%%: %s", SPECIAL_TRANSPARENCY_1) - HELP_LINK (" At opacity 20%%: %s", SPECIAL_TRANSPARENCY_2) - HELP_LINK (" At opacity 30%%: %s", SPECIAL_TRANSPARENCY_3) - HELP_LINK (" At opacity 40%%: %s", SPECIAL_TRANSPARENCY_4) - HELP_LINK (" At opacity 50%%: %s", SPECIAL_TRANSPARENCY_5) - HELP_LINK (" At opacity 60%%: %s", SPECIAL_TRANSPARENCY_6) - HELP_LINK (" At opacity 70%%: %s", SPECIAL_TRANSPARENCY_7) - HELP_LINK (" At opacity 80%%: %s", SPECIAL_TRANSPARENCY_8) - HELP_LINK (" At opacity 90%%: %s", SPECIAL_TRANSPARENCY_9) - HELP_LINK (" At opacity 100%%: %s", SPECIAL_TRANSPARENCY_0) - HELP_LINK ("Colorize menu: %s", SPECIAL_COLORIZE_MENU) - HELP_LINK ("Smooth mode: %s", SPECIAL_SMOOTH_MODE) - HELP_LINK ("Smooth menu: %s", SPECIAL_SMOOTH_MENU) - HELP_LINK ("Smear mode: %s", SPECIAL_SMEAR_MODE) - HELP_LINK ("Tiling mode: %s", SPECIAL_TILING_MODE) - HELP_LINK ("Tiling menu: %s", SPECIAL_TILING_MENU) - HELP_LINK ("Pick brush: %s", 0x100+BUTTON_BRUSH) - HELP_LINK ("Pick polyform brush: %s", 0x100+BUTTON_POLYBRUSH) - HELP_LINK ("Restore brush: %s", 0x200+BUTTON_BRUSH) - HELP_LINK ("Flip brush X: %s", SPECIAL_FLIP_X) - HELP_LINK ("Flip brush Y: %s", SPECIAL_FLIP_Y) - HELP_LINK ("90° brush rotation: %s", SPECIAL_ROTATE_90) - HELP_LINK ("180° brush rotation: %s", SPECIAL_ROTATE_180) - HELP_LINK ("Stretch brush: %s", SPECIAL_STRETCH) - HELP_LINK ("Distort brush: %s", SPECIAL_DISTORT) - HELP_LINK ("Outline brush: %s", SPECIAL_OUTLINE) - HELP_LINK ("Nibble brush: %s", SPECIAL_NIBBLE) - HELP_LINK ("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) - HELP_LINK ("Pipette: %s", 0x100+BUTTON_COLORPICKER) - HELP_LINK ("Swap fore/back color:%s", 0x200+BUTTON_COLORPICKER) - HELP_TEXT ("Magnifier mode") - HELP_LINK (" Toggle: %s", 0x100+BUTTON_MAGNIFIER) - HELP_LINK (" Zoom factor menu: %s", 0x200+BUTTON_MAGNIFIER) - HELP_LINK (" Zoom in: %s", SPECIAL_ZOOM_IN) - HELP_LINK (" Zoom out: %s", SPECIAL_ZOOM_OUT) - HELP_LINK (" 1:1 (off) %s", SPECIAL_ZOOM_1) - HELP_LINK (" 2:1 %s", SPECIAL_ZOOM_2) - HELP_LINK (" 3:1 %s", SPECIAL_ZOOM_3) - HELP_LINK (" 4:1 %s", SPECIAL_ZOOM_4) - HELP_LINK (" 5:1 %s", SPECIAL_ZOOM_5) - HELP_LINK (" 6:1 %s", SPECIAL_ZOOM_6) - HELP_LINK (" 8:1 %s", SPECIAL_ZOOM_8) - HELP_LINK (" 10:1 %s", SPECIAL_ZOOM_10) - HELP_LINK (" 12:1 %s", SPECIAL_ZOOM_12) - HELP_LINK (" 14:1 %s", SPECIAL_ZOOM_14) - HELP_LINK (" 16:1 %s", SPECIAL_ZOOM_16) - HELP_LINK (" 18:1 %s", SPECIAL_ZOOM_18) - HELP_LINK (" 20:1 %s", SPECIAL_ZOOM_20) - HELP_LINK ("Brush effects menu: %s", 0x100+BUTTON_BRUSH_EFFECTS) - HELP_LINK ("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) - HELP_LINK ("Help: %s", 0x100+BUTTON_HELP) - HELP_LINK ("Statistics: %s", 0x200+BUTTON_HELP) - HELP_LINK ("Go to spare page: %s", 0x100+BUTTON_PAGE) - HELP_LINK ("Copy to spare page: %s", 0x200+BUTTON_PAGE) - HELP_LINK ("Save as: %s", 0x100+BUTTON_SAVE) - HELP_LINK ("Save: %s", 0x200+BUTTON_SAVE) - HELP_LINK ("Load: %s", 0x100+BUTTON_LOAD) - HELP_LINK ("Re-load: %s", 0x200+BUTTON_LOAD) - HELP_LINK ("Save brush: %s", SPECIAL_SAVE_BRUSH) - HELP_LINK ("Load brush: %s", SPECIAL_LOAD_BRUSH) - HELP_LINK ("Larger brush size: %s", SPECIAL_BIGGER_PAINTBRUSH) - HELP_LINK ("Smaller brush size: %s", SPECIAL_SMALLER_PAINTBRUSH) - HELP_LINK ("Settings: %s", 0x100+BUTTON_SETTINGS) - HELP_LINK ("Undo: %s", 0x100+BUTTON_UNDO) - HELP_LINK ("Redo: %s", 0x200+BUTTON_UNDO) - HELP_LINK ("Kill page: %s", 0x100+BUTTON_KILL) - HELP_LINK ("Clear: %s", 0x100+BUTTON_CLEAR) - HELP_LINK ("Clear with BG color: %s", 0x200+BUTTON_CLEAR) - HELP_LINK ("Quit: %s", 0x100+BUTTON_QUIT) - HELP_LINK ("Palette menu: %s", 0x100+BUTTON_PALETTE) - HELP_LINK ("2nd Palette menu: %s", 0x200+BUTTON_PALETTE) - HELP_LINK ("Exclude colors menu: %s", SPECIAL_EXCLUDE_COLORS_MENU) - HELP_TEXT ("") - HELP_TEXT ("Scroll palette") - HELP_LINK (" Back: %s", 0x100+BUTTON_PAL_LEFT) - HELP_LINK (" Forward: %s", 0x100+BUTTON_PAL_RIGHT) - HELP_LINK (" Back faster: %s", 0x200+BUTTON_PAL_LEFT) - HELP_LINK (" Forward faster: %s", 0x200+BUTTON_PAL_RIGHT) - HELP_TEXT ("") - HELP_TEXT ("Change brush attachement") - HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) - HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) - HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) - HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) - HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) - HELP_TEXT ("") - HELP_TEXT ("Select foreground color") - HELP_TEXT ("") - HELP_LINK (" Next : %s", SPECIAL_NEXT_FORECOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_FORECOLOR) - HELP_TEXT ("") - HELP_TEXT ("Select background color") - HELP_LINK (" Next : %s", SPECIAL_NEXT_BACKCOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_BACKCOLOR) - HELP_TEXT ("") - HELP_TEXT ("Select user-defined foreground color") - HELP_TEXT ("") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) - HELP_TEXT ("") - HELP_TEXT ("Select user-defined background color") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) - HELP_TEXT ("") - HELP_TEXT ("LAYERS") - HELP_TEXT ("") - HELP_LINK (" Menu : %s", 0x100+BUTTON_LAYER_MENU) - HELP_LINK (" Add new : %s", 0x100+BUTTON_LAYER_ADD) - HELP_LINK (" Delete : %s", 0x100+BUTTON_LAYER_REMOVE) - HELP_LINK (" Merge : %s", 0x100+BUTTON_LAYER_MERGE) - HELP_LINK (" Move up : %s", 0x100+BUTTON_LAYER_UP) - HELP_LINK (" Move down : %s", 0x100+BUTTON_LAYER_DOWN) - //HELP_LINK (" Set transp: %s", 0x100+BUTTON_LAYER_COLOR) - HELP_TEXT (" Select :") - HELP_LINK (" 1 : %s", SPECIAL_LAYER1_SELECT) - HELP_LINK (" 2 : %s", SPECIAL_LAYER2_SELECT) - HELP_LINK (" 3 : %s", SPECIAL_LAYER3_SELECT) - HELP_LINK (" 4 : %s", SPECIAL_LAYER4_SELECT) - HELP_LINK (" 5 : %s", SPECIAL_LAYER5_SELECT) - HELP_LINK (" 6 : %s", SPECIAL_LAYER6_SELECT) - HELP_LINK (" 7 : %s", SPECIAL_LAYER7_SELECT) - HELP_LINK (" 8 : %s", SPECIAL_LAYER8_SELECT) - HELP_TEXT (" Toggle :") - HELP_LINK (" 1 : %s", SPECIAL_LAYER1_TOGGLE) - HELP_LINK (" 2 : %s", SPECIAL_LAYER2_TOGGLE) - HELP_LINK (" 3 : %s", SPECIAL_LAYER3_TOGGLE) - HELP_LINK (" 4 : %s", SPECIAL_LAYER4_TOGGLE) - HELP_LINK (" 5 : %s", SPECIAL_LAYER5_TOGGLE) - HELP_LINK (" 6 : %s", SPECIAL_LAYER6_TOGGLE) - HELP_LINK (" 7 : %s", SPECIAL_LAYER7_TOGGLE) - HELP_LINK (" 8 : %s", SPECIAL_LAYER8_TOGGLE) -}; -static const T_Help_table helptable_credits[] = -{ -//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TITLE(" GRAFX2 IS CREATED BY") - HELP_TEXT ("") - HELP_BOLD (" THE GRAFX2 PROJECT TEAM") - HELP_TEXT ("") - HELP_TEXT (" Adrien Destugues (pulkomandy)") - HELP_TEXT (" Yves Rizoud (yrizoud)") - HELP_TEXT ("") - HELP_TEXT (" Got the source back to life in 2006") - HELP_TEXT ("") - HELP_BOLD (" SUNSET DESIGN") - HELP_BOLD (" AUTHORS OF GRAFX2.0 BETA 96.5%") - HELP_TEXT ("") - HELP_TEXT (" Guillaume Dorme alias \"Robinson\" (code)") - HELP_TEXT (" Karl Maritaud alias \"X-Man\" (code&gfx)") -//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT ("") - HELP_TEXT (" Re-licensed GrafX2 under the GPL in 2001") - HELP_TEXT (" Huge thanks to them for their work !") - HELP_TEXT ("") - HELP_BOLD (" OTHER CODE CONTRIBUTORS") - HELP_TEXT ("") - HELP_TEXT (" Karl Bartel") - HELP_TEXT (" SFont: bitmap fonts rendering") - HELP_TEXT ("") - HELP_TEXT (" Petter Lindquist") - HELP_TEXT (" C64 file and image formats") - HELP_TEXT ("") - HELP_TEXT (" Pasi Kallinen") - HELP_TEXT (" Better command-line handling") - HELP_TEXT ("") - HELP_TEXT (" DawnBringer") - HELP_TEXT (" Lua scripts, image effects") - HELP_TEXT ("") - HELP_TEXT (" Nitrofurano") - HELP_TEXT (" Lua scripts") - HELP_TEXT ("") - HELP_TITLE(" ART") - HELP_TEXT ("") - HELP_TEXT (" Made (www.m4de.com)") - HELP_TEXT (" Logo (classic)") - HELP_TEXT ("") - HELP_TEXT (" X-Man") - HELP_TEXT (" Buttons and fonts (classic)") - HELP_TEXT ("") - HELP_TEXT (" iLKke (ilkke.blogspot.com)") - HELP_TEXT (" Buttons and logo (modern, scenish)") - HELP_TEXT (" Several fonts") - HELP_TEXT ("") - HELP_TEXT (" Jamon") - HELP_TEXT (" Buttons, logo and font (DPaint tribute)") - HELP_TEXT ("") - HELP_TEXT (" Hatch") - HELP_TEXT (" Vectorized icon") - HELP_TEXT ("") - HELP_TEXT (" ...Pixelled all the graphics") - HELP_TEXT ("") - HELP_TITLE(" OTHER MACHINES PORTS") - HELP_TEXT ("") - HELP_BOLD (" AMIGA OS 3 PORT") - HELP_TEXT ("") - HELP_TEXT (" Artur Jarosik") - HELP_TEXT ("") - HELP_BOLD (" AMIGA OS 4 PORT") - HELP_TEXT ("") - HELP_TEXT (" Peter Gordon (www.petergordon.org.uk)") - HELP_TEXT ("") - HELP_BOLD (" AROS PORT") - HELP_TEXT ("") - HELP_TEXT (" Fernando Mastandrea (masta.uy)") - HELP_TEXT (" Markus Weiss") - HELP_TEXT ("") - HELP_BOLD (" FREEBSD PORT") - HELP_TEXT ("") - HELP_TEXT (" Jean-Baptiste Berlioz (Tobe)") - HELP_TEXT ("") - HELP_BOLD (" HAIKU OS AND BEOS PORT") - HELP_TEXT ("") - HELP_TEXT (" Luc Schrijvers (Begasus)") - HELP_TEXT ("") - HELP_BOLD (" LINUX BINARIES") - HELP_TEXT ("") - HELP_TEXT (" Gentoo : Matteo 'Peach' Pescarin") - HELP_TEXT (" Debian : Gürkan Sengün") - HELP_TEXT ("") - HELP_BOLD (" MAC OS X PORT") - HELP_TEXT ("") - HELP_TEXT (" Franck Charlet (hitchhikr)") - HELP_TEXT (" Per Olofsson (MagerValp)") - HELP_TEXT ("") - HELP_BOLD (" MORPHOS PORT") - HELP_TEXT ("") - HELP_TEXT (" Rusback") - HELP_TEXT (" OffseT") - HELP_TEXT ("") - HELP_BOLD (" NETBSD PORT") - HELP_TEXT ("") - HELP_TEXT (" Jeff Read") - HELP_TEXT ("") - HELP_BOLD (" SKYOS PORT") - 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 ("") - HELP_TITLE(" BUGFINDERS") - HELP_TEXT ("") -//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT (" anibiqme blumunkee BDCIron ") - HELP_TEXT (" Ced DarkDefende DawnBringer ") - HELP_TEXT (" El Topo falenblood fanickbux ") - HELP_TEXT (" fano fogbot121 Frost ") - HELP_TEXT (" Grimmy Gürkan Sengün Hatch ") - HELP_TEXT (" HoraK-FDF iLKke Iw2evk ") - HELP_TEXT (" jackfrost128 Jamon keito ") - HELP_TEXT (" kusma Lord Graga Lorenzo Gatti ") - HELP_TEXT (" MagerValp maymunbeyin mind ") - HELP_TEXT (" MooZ Pasi Kallinen the Peach ") - HELP_TEXT (" petter PheeL Ravey1138 ") - HELP_TEXT (" richienyhus sm4tik spratek ") - HELP_TEXT (" Surt tape.yrm TeeEmCee ") - HELP_TEXT (" tempest Timo Kurrpa titus^Rab ") - HELP_TEXT (" Tobé yakumo2975 00ai99") - HELP_TEXT ("") - HELP_TEXT (" ... posted the annoying bug reports.") - HELP_TEXT ("") - HELP_TITLE(" FILE FORMATS CREDITS") - HELP_TEXT ("") - HELP_TEXT (" BMP : Microsoft") - HELP_TEXT (" CEL,KCF : K.O.S. (KISekae Set system)") - HELP_TEXT (" GIF : Compuserve") - HELP_TEXT (" IMG : Bivas (W. Wiedmann?)") - HELP_TEXT (" LBM : Electronic Arts") - HELP_TEXT (" PAL : ermmh... nobody (?)") - HELP_TEXT (" PCX : Z-Soft") - HELP_TEXT (" PI1,PC1 : Degas Elite") - HELP_TEXT (" PKM : Sunset Design") - HELP_TEXT (" PNG : W3C") - HELP_TEXT (" SCx : Colorix (?)") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" OUR HOMEPAGE") - HELP_TEXT ("") - HELP_BOLD (" http://grafx2.googlecode.com") - HELP_TEXT ("") - HELP_TEXT (" Please report any bug you may find there") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE(" GREETINGS") - HELP_TEXT ("") - HELP_BOLD ("Pulkomandy:") - HELP_TEXT ("") - HELP_TEXT (" To the Pouet.net BBS posters, the #CPC") - HELP_TEXT (" trolls and the bitfellas") - HELP_TEXT (" To every people who makes the scene alive!") - HELP_TEXT (" To all guys making nice pixelled pictures") - HELP_TEXT (" (with or without GrafX2)") - HELP_TEXT ("") - HELP_BOLD ("Sunset Designs:") - HELP_TEXT ("") - HELP_TEXT (" We send our best regards to...") - HELP_TEXT ("") - HELP_TEXT (" Access Filter Pink") - HELP_TEXT (" Ace Fiver Pixel") - HELP_TEXT (" AcidJam Flan Profil") - HELP_TEXT (" Acryl Fred Prowler") - HELP_TEXT (" Alexel FreddyV Puznik") - HELP_TEXT (" Alias Frost Quick") - HELP_TEXT (" Amiral Gaël(GDC) Ra") - HELP_TEXT (" Arrakis GainX Raster") - HELP_TEXT (" Avocado Gandalf Ravian") - HELP_TEXT (" Baloo Goblin RedBug") - HELP_TEXT (" Barti Greenpix7 Rem") - HELP_TEXT (" Bat Grid Rez") - HELP_TEXT (" Biro GrosQuick Roudoudou") - HELP_TEXT (" Bisounours HackerCroll Sacrilege") - HELP_TEXT (" BlackAxe Haplo Sam") - HELP_TEXT (" Bonnie Hof SandMan") - HELP_TEXT (" Boo Hornet Scape") - HELP_TEXT (" Boz Hulud Sébastien") - HELP_TEXT (" Carine Java Shodan") - HELP_TEXT (" Chandra JBT Skal") - HELP_TEXT (" Cheetah Jérôme Skyfire") - HELP_TEXT (" Chill Julien(JCA) Sphair") - HELP_TEXT (" Cougar KalMinDo Sprocket") - HELP_TEXT (" Cremax KaneWood Stef") - HELP_TEXT (" Cyclone Karma Stony") - HELP_TEXT (" Dake Keith303 Sumaleth") - HELP_TEXT (" Danny Lazur Sunday") - HELP_TEXT (" Danube LightShow Suny") - HELP_TEXT (" Darjul Lluvia Sybaris") - HELP_TEXT (" Darwin Louie TBF") - HELP_TEXT (" DarkAngel Luk Tempest") - HELP_TEXT (" Das Made Thor") - HELP_TEXT (" Decker Mamos TMK") - HELP_TEXT (" DerPiipo Mandrixx TwoFace") - HELP_TEXT (" Destop Mangue Underking") - HELP_TEXT (" Diabolo Mars Unreal") - HELP_TEXT (" DineS Mephisto VaeVictis") - HELP_TEXT (" Drac Mercure Vastator") - HELP_TEXT (" DrYes Mirec Vatin") - HELP_TEXT (" Edyx Moa Veckman") - HELP_TEXT (" Eller Moxica Wain") - HELP_TEXT (" Ellyn MRK Wally") - HELP_TEXT (" EOF Nitch WillBe") - HELP_TEXT (" Fall Noal Xoomie") - HELP_TEXT (" Fame Nytrik Xtrm") - HELP_TEXT (" Fantom Optic YannSulu") - HELP_TEXT (" Fear Orome Z") - HELP_TEXT (" Feather Pahladin Zeb") - HELP_TEXT (" Fennec Phar Zebig") - HELP_TEXT ("") - HELP_TEXT (" and all #pixel, #demofr and #coders.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT (" Some information taken from several docs") - HELP_TEXT (" (PCGPE, Intervue, PC Interdit...)") - HELP_TEXT (" gave us an invaluable help.") - HELP_TEXT ("") - HELP_TEXT (" Thanks to Shawn Hargreaves for his filled") - HELP_TEXT (" polygon routine from Allegro v2.2.") - HELP_TEXT ("") - HELP_TEXT (" Thanks to Carlos \"Made\" Pardo for his") - HELP_TEXT (" great GrafX2 logo.") - HELP_TEXT ("") - HELP_TEXT (" This is our very first program compiled") - HELP_TEXT (" with the Gnu C Compiler.") - HELP_TEXT (" A thousand thanks to the authors of") - HELP_TEXT (" this compiler.") - HELP_TEXT ("") - HELP_TEXT (" We also would like to thank all the") - HELP_TEXT (" people who gave us ideas to improve") - HELP_TEXT (" GrafX2.") - HELP_TEXT ("") - HELP_TITLE (" SNAIL MAIL") - HELP_TEXT ("") -//HELP_TEXT ("0----5----0----5----0----5----0----5----0--X") - HELP_TEXT (" ADRIEN DESTUGUES (PulkoMandy)") - HELP_TEXT (" 3, rue Lapouble") - HELP_TEXT (" 64000 PAU") - HELP_TEXT (" (Send emails! Welcome in 21th century!)") - HELP_TEXT ("") - HELP_TEXT (" GUILLAUME DORME (Robinson)") - HELP_TEXT (" 15, rue de l'observatoire") - HELP_TEXT (" 87000 LIMOGES (FRANCE)") - HELP_TEXT (" (May take some years to get an answer)") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT (" KARL MARITAUD (X-Man)") - HELP_TEXT (" 10, rue de la Brasserie") - HELP_TEXT (" 87000 LIMOGES (FRANCE)") - HELP_TEXT (" (From 2001, current status: unknown)") - HELP_TEXT ("") - HELP_TEXT ("") -}; -static const T_Help_table helptable_paintbrush[] = -{ - HELP_TITLE("PAINTBRUSHES") - HELP_TEXT ("") - HELP_BOLD (" LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_PAINTBRUSHES) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can choose the") - HELP_TEXT ("shape of your paintbrush.") - HELP_TEXT ("") - HELP_TEXT ("Paintbrushes are sorted by family. You can") - HELP_TEXT ("see some paintbrushes of the same family but") - HELP_TEXT ("with different sizes. There is at least one") - HELP_TEXT ("paint-brush from each family displayed in") - HELP_TEXT ("this menu.") - HELP_TEXT ("Here is the list of all the different") - HELP_TEXT ("paintbrush families:") - HELP_TEXT ("") - HELP_TEXT ("******* *** * * * * * * ") - HELP_TEXT ("******* ***** * * * * * * ") - HELP_TEXT ("******* ******* * * * * * * * * ") - HELP_TEXT ("******* ******* * * * * * * ") - HELP_TEXT ("******* ******* * * * * * * * * ") - HELP_TEXT ("******* ***** * * * * * * ") - HELP_TEXT ("******* *** * * * * * * ") - HELP_TEXT ("") - HELP_TEXT ("Square Disc Sieve Sieve ") - HELP_TEXT (" square disc ") - HELP_TEXT (" ") - HELP_TEXT (" * * * ") - HELP_TEXT (" *** * * * ") - HELP_TEXT (" ***** * * ") - HELP_TEXT ("******* ******* * ") - HELP_TEXT (" ***** * * * * ") - HELP_TEXT (" *** * ") - HELP_TEXT (" * * * * ") - HELP_TEXT (" ") - HELP_TEXT ("Diamond Random Horiz. Vertical") - HELP_TEXT (" bar bar ") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * *******") - HELP_TEXT (" * * * * *") - HELP_TEXT (" * * * * *") - HELP_TEXT ("* * * * *") - HELP_TEXT ("") - HELP_TEXT (" Slash Back- Cross X Cross +") - HELP_TEXT (" slash") - HELP_TEXT ("") - HELP_TEXT ("When using one of these, you can change the") - HELP_TEXT ("brush size by using the keys:") - HELP_LINK ("Reduce : %s", SPECIAL_SMALLER_PAINTBRUSH) - HELP_LINK ("Increase : %s", SPECIAL_BIGGER_PAINTBRUSH) - HELP_TEXT ("") - 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 ("") - HELP_TEXT ("The bottom row, initially showing empty") - HELP_TEXT ("buttons, is the brush container. You can") - HELP_TEXT ("right-click a button to store the current") - HELP_TEXT ("brush in it, and then whenever you need the") - HELP_TEXT ("brush back, open this menu again and") - HELP_TEXT ("left-click the button.") - HELP_TEXT ("The container can memorize resizable brushes") - HELP_TEXT ("as well as brushes grabbed from the image.") - HELP_TEXT ("Brushes are lost when you exit the program.") - HELP_TEXT ("") - HELP_BOLD (" RIGHT CLICK ") - HELP_LINK ("(Key:%s)",0x200+BUTTON_PAINTBRUSHES) - HELP_TEXT ("") - HELP_TEXT ("Transforms your current user-defined brush") - HELP_TEXT ("into a paintbrush. This is actually a") - HELP_TEXT ("\"monochromisation\" of your user-defined") - HELP_TEXT ("brush. This means that every color of the") - HELP_TEXT ("brush that aren't the Back-color will be") - HELP_TEXT ("set to the Fore-color. But this option") - HELP_TEXT ("doesn't alter the brush: you'll just have") - HELP_TEXT ("to right-click on the \"Get brush\" buttons") - HELP_TEXT ("to get your brush back.") - HELP_TEXT ("") - HELP_TEXT ("Note: When you press (not in the menu) the") - HELP_LINK ("key %s, the current",SPECIAL_DOT_PAINTBRUSH) - HELP_TEXT ("paintbrush becomes the smallest member of") - HELP_TEXT ("the \"Disc\" family: i.e one pixel.") - -}; -static const T_Help_table helptable_adjust[] = -{ - HELP_TITLE("ADJUST OR TRANSFORM") - HELP_TITLE(" PICTURE") - HELP_TEXT ("") - HELP_BOLD (" LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_ADJUST) - HELP_TEXT ("") - HELP_TEXT ("Allows you to scroll the picture to") - HELP_TEXT ("re-center your graph for example.") - HELP_TEXT ("") - HELP_TEXT ("Any part of the picture that goes out of") - HELP_TEXT ("the image by a side comes back by the") - HELP_TEXT ("opposite one.") - HELP_TEXT ("") - HELP_TEXT ("Left clicking the picture will scroll only") - HELP_TEXT ("the active layer. Right-clicking will scroll") - HELP_TEXT ("all of them.") - HELP_TEXT ("") - HELP_TEXT ("It is assimilated to the drawing tools") - HELP_TEXT ("family.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_BOLD (" RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_ADJUST) - HELP_TEXT ("") - HELP_TEXT ("Opens the Picture Transform menu.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("PICTURE TRANSFORM") - HELP_TEXT ("") - HELP_BOLD ("RESCALE") - HELP_TEXT ("") - HELP_TEXT ("Allows you to change the image's size,") - HELP_TEXT ("rescaling it accordingly. Enter new size") - HELP_TEXT ("and press RESIZE to confirm.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("When 'Lock proportions' is checked and you") - HELP_TEXT ("change one dimension, the other one is") - HELP_TEXT ("automatically adjusted to preserve the") - HELP_TEXT ("proportions of the original image.") - HELP_TEXT ("") - HELP_TEXT ("You can use the dropdown button to choose") - HELP_TEXT ("between three ways to enter the dimensions:") - HELP_TEXT ("") - HELP_TEXT ("In 'Pixels' mode, the column 'old' shows") - HELP_TEXT ("the original dimensions, and you can set") - HELP_TEXT ("the new size in pixels.") - HELP_TEXT ("") - HELP_TEXT ("In 'Percent' mode, you set a percentage") - HELP_TEXT ("compared to the original image.") - HELP_TEXT ("") - HELP_TEXT ("In 'Ratio' mode, you can set 2 numbers for") - HELP_TEXT ("each dimension, and the resizing factor will") - HELP_TEXT ("be of 'new'÷'old'. For example you can use") - HELP_TEXT ("1:3 to divide the image by three, 2:1 to") - HELP_TEXT ("double it, and any fraction like 15:16.") - HELP_TEXT ("") - HELP_TEXT ("Be careful that moving from one mode to the") - HELP_TEXT ("next can lose precision, if the selected") - HELP_TEXT ("dimensions cannot be represented exactly in") - HELP_TEXT ("the new mode.") - HELP_TEXT ("") - HELP_BOLD ("MIRROR") - HELP_TEXT ("") - HELP_TEXT ("- X: Flip the picture horizontally.") - HELP_TEXT ("") - HELP_TEXT ("- Y: Flip the picture vertically.") - HELP_TEXT ("") - HELP_BOLD ("ROTATE") - HELP_TEXT ("") - HELP_TEXT ("-90°: Rotates the image by 90°") - HELP_TEXT (" clockwise.") - HELP_TEXT ("") - HELP_TEXT ("+90°: Rotates the image by 90°") - HELP_TEXT (" counter-clockwise.") - HELP_TEXT ("180°: Rotates the image by 180°") - HELP_TEXT ("") - HELP_TEXT ("") -}; -static const T_Help_table helptable_draw[] = -{ - HELP_TITLE("HAND-DRAWING") - HELP_TEXT ("") - HELP_BOLD (" LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_DRAW) - HELP_TEXT ("") - HELP_TEXT ("Selects the current hand-drawing mode as the") - HELP_TEXT ("active drawing tool. There are 4") - HELP_TEXT ("hand-drawing modes:") - HELP_TEXT ("") - HELP_TEXT ("Continuous hand-drawing: as you move the") - HELP_TEXT ("mouse, the paintbrush is regularily pasted") - HELP_TEXT ("on the picture. This drawing tool allows to") - HELP_TEXT ("change the fore and back colors when being") - HELP_TEXT ("in use.") - HELP_TEXT ("") - HELP_TEXT ("Discontinuous hand-drawing: as you move the") - HELP_TEXT ("mouse, the paintbrush is pasted on the") - HELP_TEXT ("picture every time a delay is passed") - HELP_TEXT ("(actually, the delay is 1 VBL") - HELP_TEXT ("(vertical blanking)). This drawing tool") - HELP_TEXT ("allows to change the fore and back colors") - HELP_TEXT ("when being in use.") - HELP_TEXT ("") - HELP_TEXT ("Dot by dot hand-drawing: the paintbrush is") - HELP_TEXT ("only pasted at the position where you first") - HELP_TEXT ("clicked.") - HELP_TEXT ("") - HELP_TEXT ("Contour fill: Draws pixels like continuous") - HELP_TEXT ("mode, but when you release the button Grafx2") - HELP_TEXT ("draws a line back to your starting position,") - HELP_TEXT ("and fills the area. This tool doesn't use") - HELP_TEXT ("the current brush, but single pixels.") - HELP_TEXT ("") - HELP_BOLD (" RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_DRAW) - HELP_TEXT ("") - HELP_TEXT ("Toggles the different hand-drawing modes") - HELP_TEXT ("and activates, at the same time, the") - HELP_TEXT ("hand-drawing tool.") -}; -static const T_Help_table helptable_curves[] = -{ - HELP_TITLE("SPLINES") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_CURVES) - HELP_TEXT ("") - HELP_TEXT ("Selects the current curve-drawing mode as") - HELP_TEXT ("the active drawing tool. There are 2") - HELP_TEXT ("different curve-drawing modes:") - HELP_TEXT ("") - HELP_TEXT ("* 4 control points curves: define the basic") - HELP_TEXT ("line like a classical line, then move, with") - HELP_TEXT ("the left mouse button, the inner control") - HELP_TEXT ("points to choose the shape of your curve.") - HELP_TEXT ("When the curve has the shape you want, click") - HELP_TEXT ("with the right mouse button to draw it") - HELP_TEXT ("definitively.") - HELP_TEXT ("") - HELP_TEXT ("* 3 control points curves: the same as") - HELP_TEXT ("above, but you'll have only one inner") - HELP_TEXT ("control point to place. Moreover, the spline") - HELP_TEXT ("will be traced just after placing this") - HELP_TEXT ("point.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_CURVES) - HELP_TEXT ("") - HELP_TEXT ("Toggles the different curve-drawing modes") - HELP_TEXT ("and activates, at the same time, the") - HELP_TEXT ("curve-drawing tool.") -}; -static const T_Help_table helptable_lines[] = -{ - HELP_TITLE("LINES") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LINES) - HELP_TEXT ("") - HELP_TEXT ("Selects the current line-drawing mode as the") - HELP_TEXT ("active drawing tool. There are 3") - HELP_TEXT ("line-drawing modes:") - HELP_TEXT ("") - HELP_TEXT ("* Classical lines: when first clicking on") - HELP_TEXT ("the picture, you'll define the start of the") - HELP_TEXT ("line. Maintain your click to choose the end") - HELP_TEXT ("of the line and release the mouse button to") - HELP_TEXT ("set it.") - HELP_TEXT ("If you hold SHIFT when drawing, the line") - HELP_TEXT ("will be constrained to horizonal, vertical") - HELP_TEXT ("or diagonal.") - HELP_TEXT ("") - HELP_TEXT ("* Knotted lines: works like classical lines,") - HELP_TEXT ("but the end of your line will automatically") - HELP_TEXT ("become the start of the next one. When you") - HELP_TEXT ("want to stop chaining lines, use the") - HELP_TEXT ("opposite mouse button. \"The opposite button\"") - HELP_TEXT ("means that if you started to draw lignes") - HELP_TEXT ("with the left button (Fore-color), you'll") - HELP_TEXT ("have to stop the procedure with the right") - HELP_TEXT ("button; and conversely.") - HELP_TEXT ("") - HELP_TEXT ("* Concentric lines: when first clicking on") - HELP_TEXT ("the picture, you'll define center of the") - HELP_TEXT ("lines. In fact, the center is defined by the") - HELP_TEXT ("the position of the mouse when you release") - HELP_TEXT ("the mouse button. Then you can draw lines") - HELP_TEXT ("from the center to the current mouse") - HELP_TEXT ("position by clicking. To stop drawing") - HELP_TEXT ("concentric lines, use the opposite mouse") - HELP_TEXT ("button. This drawing tool allows to change") - HELP_TEXT ("the fore and back colors when being in use.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_LINES) - HELP_TEXT ("") - HELP_TEXT ("Toggles the different line-drawing modes and") - HELP_TEXT ("activates, at the same time, the") - HELP_TEXT ("line-drawing tool.") - -}; -static const T_Help_table helptable_airbrush[] = -{ - HELP_TITLE("SPRAY") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_AIRBRUSH) - HELP_TEXT ("") - HELP_TEXT ("Selects the spray as the active drawing") - HELP_TEXT ("tool. This drawing tool allows to change the") - HELP_TEXT ("fore and back colors when being in use.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_AIRBRUSH) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can configure the") - HELP_TEXT ("spray:") - HELP_TEXT ("") - HELP_TEXT ("- Size: Defines the diameter of the circle") - HELP_TEXT ("in which will effectively fit the spray.") - HELP_TEXT ("") - HELP_TEXT ("- Delay: Defines the number of VBLs that") - HELP_TEXT ("will be waited for between two flows of") - HELP_TEXT ("spray.") - HELP_TEXT ("") - HELP_TEXT ("- Mode: Defines whether you want to use a") - HELP_TEXT ("monochrome spray or a multi- colored one.") - HELP_TEXT ("") - HELP_TEXT ("- Mono-flow: Defines the number of") - HELP_TEXT ("paintbrushes that will be pasted in the") - HELP_TEXT ("circle of the spray at each cycle.") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Left-click on a color of the") - HELP_TEXT ("palette to see how much it will be used in") - HELP_TEXT ("the multicolored flow, and modify it by") - HELP_TEXT ("using the gauge on the right. If the flow of") - HELP_TEXT ("this color was equal to 0, then the \"Init\"") - HELP_TEXT ("value will be applied. Or set the flow of a") - HELP_TEXT ("color to 0 by clicking on it with the right") - HELP_TEXT ("mouse button.") - HELP_TEXT ("") - HELP_TEXT ("- Clear: Removes all the colors from the") - HELP_TEXT ("multicolored flow. Actually, this puts a 0") - HELP_TEXT ("value in the use of each color.") - HELP_TEXT ("") - HELP_TEXT ("- Init: Allows you to define a value that") - HELP_TEXT ("will be set to the color you click on in the") - HELP_TEXT ("palette if its value is equal to 0. This") - HELP_TEXT ("permits to tag a set of colors more quickly.") - HELP_TEXT ("") - HELP_TEXT ("- +1,-1,x2,/2: Modify the values of all the") - HELP_TEXT ("tagged colors (and only them).") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("Tip: If you often use the Shade mode, and") - HELP_TEXT ("are bored to click many times on a color to") - HELP_TEXT ("reach the color you want, you can define a") - HELP_TEXT ("spray with \"Size\"=1, \"Mono-flow\"=1, and") - HELP_TEXT ("\"Delay\"=2 (or more, according to your") - HELP_TEXT ("reflexes). And then, you'll just have to") - HELP_TEXT ("click a few hundredths of second to modify a") - HELP_TEXT ("color.") -}; -static const T_Help_table helptable_floodfill[] = -{ - HELP_TITLE("FLOODFILL") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_FLOODFILL) - HELP_TEXT ("") - HELP_TEXT ("Selects the filler as the active drawing") - HELP_TEXT ("tool. The filler, as any drawing tool, will") - HELP_TEXT ("be affected by all the effects!") - HELP_TEXT ("") - HELP_TEXT ("Note that only the visible part of the") - HELP_TEXT ("picture will be filled (as every other") - HELP_TEXT ("drawing tools, the floodfill only alters the") - HELP_TEXT ("visible part of the picture; this avoids") - HELP_TEXT ("unwanted effects that wouldn't be controlled") - HELP_TEXT ("by the user).") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_FLOODFILL) - HELP_TEXT ("") - HELP_TEXT ("Selects the color replacement as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Any rule has its exceptions and this one") - HELP_TEXT ("doesn't depart from that. Indeed, this tool") - HELP_TEXT ("is the only one to be affected by no effect") - HELP_TEXT ("(except Stencil) and to be able to modify") - HELP_TEXT ("non visible parts of the picture.") - HELP_TEXT ("The function of this tool being replacing") - HELP_TEXT ("all the occurences of a color in the picture") - HELP_TEXT ("by another, if would have been a shame to") - HELP_TEXT ("limit modifications only to the visible part") - HELP_TEXT ("of the picture.") -}; -static const T_Help_table helptable_polygons[] = -{ - HELP_TITLE("POLYGONS") - HELP_TITLE("POLYFORMS") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYGONS) - HELP_TEXT ("") - HELP_TEXT ("Selects the polygons as the active drawing") - HELP_TEXT ("tool.") - HELP_TEXT ("") - HELP_TEXT ("This works just like knotted-lines but loops") - HELP_TEXT ("the extremities when you're finished.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYGONS) - HELP_TEXT ("") - HELP_TEXT ("Selects the polyforms as the active drawing") - HELP_TEXT ("tool.") - HELP_TEXT ("") - HELP_TEXT ("This works like a combination of free-hand") - HELP_TEXT ("drawing and knotted-lines. If you keep the") - HELP_TEXT ("mouse button pressed, you'll draw as if you") - HELP_TEXT ("were in free-hand drawing mode. And, if you") - HELP_TEXT ("release the mouse button, it will work like") - HELP_TEXT ("knotted lines.") - HELP_TEXT ("") - HELP_TEXT ("Click on the opposite mouse button (i.e.:") - HELP_TEXT ("click right if you started to draw with the") - HELP_TEXT ("left mouse button, and vice versa) to") - HELP_TEXT ("terminate the operation. The two extremities") - HELP_TEXT ("will be linked automatically.") -}; -static const T_Help_table helptable_polyfill[] = -{ - HELP_TITLE("FILLED POLY") - HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYFILL) - HELP_LINK ("(Key:%s)",0x200+BUTTON_POLYFILL) - HELP_TEXT (" Work exactly the same way as the polygons") - HELP_TEXT ("et polyforms above, but fill in the interior") - HELP_TEXT ("of the drawn shapes.") -}; -static const T_Help_table helptable_rectangles[] = -{ - HELP_TITLE("RECTANGLES") - HELP_LINK ("(Key:%s)",0x100+BUTTON_RECTANGLES) - HELP_TEXT ("") - HELP_TEXT ("Selects the empty rectangles as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Set a corner of a rectangle. Maintain the") - HELP_TEXT ("click to move the opposite corner and") - HELP_TEXT ("release the mouse button to set it") - HELP_TEXT ("definitively.") -}; -static const T_Help_table helptable_filled_rectangles[] = -{ - HELP_TITLE("FILLED RECT") - HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLRECT) - HELP_TEXT ("") - HELP_TEXT ("Selects the filled rectangles as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Works like an empty rectangle.") -}; -static const T_Help_table helptable_circles[] = -{ - HELP_TITLE("CIRCLES") - HELP_TITLE("ELLIPSES") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_CIRCLES) - HELP_TEXT ("") - HELP_TEXT ("Selects the empty circles as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Position the center of the cercle and") - HELP_TEXT ("maintain the mouse button to select its") - HELP_TEXT ("radius.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_CIRCLES) - HELP_TEXT ("") - HELP_TEXT ("Selects the empty ellipses as the active") - HELP_TEXT ("drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Position the center of the cercle and") - HELP_TEXT ("maintain the mouse button to select its") - HELP_TEXT ("dimensions.") -}; -static const T_Help_table helptable_filled_circles[] = -{ - HELP_TITLE("FILLED CIRCLES") - HELP_TITLE(" AND ELLIPSES") - HELP_TEXT ("") - HELP_BOLD ("FILLED CIRCLES") - HELP_LINK ("(Key:%s)",0x100+BUTTON_FILLCIRC) - HELP_TEXT ("") - HELP_TEXT ("Works like empty circles.") - HELP_TEXT ("") - HELP_BOLD ("FILLED ELLIPSES") - HELP_LINK ("(Key:%s)",0x200+BUTTON_FILLCIRC) - HELP_TEXT ("") - HELP_TEXT ("Works like empty ellipses.") -}; -static const T_Help_table helptable_grad_rect[] = -{ - HELP_TITLE("GRAD RECTANGLE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_GRADRECT) - HELP_TEXT ("") - HELP_TEXT ("Selects the rectangle with gradations as") - HELP_TEXT ("the active drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Set a corner of a rectangle. Maintain the") - HELP_TEXT ("click to move the opposite corner and") - HELP_TEXT ("release the mouse button to set it") - HELP_TEXT ("definitively.") - HELP_TEXT ("") - HELP_TEXT ("If you don't like what you have done and") - HELP_TEXT ("want to restart, you can use the right") - HELP_TEXT ("click to cancel everything at this point.") - HELP_TEXT (" If you think it's nice, then click and hold") - HELP_TEXT ("the mouse in a point you want to have the") - HELP_TEXT ("starting color, drag to a point where you") - HELP_TEXT ("want the ending color, and release the") - HELP_TEXT ("button. You can press SHIFT to enforce your") - HELP_TEXT ("line to be vertical, horizontal, or") - HELP_TEXT ("diagonal.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_GRADRECT) - HELP_TEXT ("") - HELP_TEXT ("Opens a window where you can define the way") - HELP_TEXT ("gradations are processed. The different") - HELP_TEXT ("sections of this menu are:") - HELP_TEXT ("") - HELP_TEXT ("- Direction (arrow): Switches the direction") - HELP_TEXT ("of the gradation.") - HELP_TEXT ("") - HELP_TEXT ("- Dithering method: Toggles the 3 following") - HELP_TEXT ("methods:") - HELP_TEXT (" - No dithering") - HELP_TEXT (" - Basical dithering") - HELP_TEXT (" - Enhanced dithering") - HELP_TEXT ("") - HELP_TEXT ("- Mix: Mixes the gradation with a more or") - HELP_TEXT ("less random factor.") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Select a color range to build a") - HELP_TEXT ("gradation.") - HELP_TEXT ("") - HELP_TEXT ("- Index scroller: Defines the current") - HELP_TEXT ("gradation among a set of 16 that will be") - HELP_TEXT ("memorised.") - 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[] = -{ - HELP_TITLE("GRAD SPHERE") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_SPHERES) - HELP_TEXT ("") - HELP_TEXT ("Selects the spheres as the active drawing") - HELP_TEXT ("tool.") - HELP_TEXT ("") - HELP_TEXT ("Position the center of the sphere and") - HELP_TEXT ("maintain the mouse button to select its") - HELP_TEXT ("radius. Then place the spot-light.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_SPHERES) - HELP_TEXT ("") - HELP_TEXT ("Selects the ellipses with gradation as the") - HELP_TEXT ("active drawing tool.") - HELP_TEXT ("") - HELP_TEXT ("Draw the shape like a normal ellipse, and") - HELP_TEXT ("then position the spot-light and click the") - HELP_TEXT ("left mouse button to finish the shape.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("If you trace a sphere or an ellipse with") - HELP_TEXT ("gradation with the right mouse button, the") - HELP_TEXT ("result will be the same figure filled with") - HELP_TEXT ("the Back-color.") -}; -static const T_Help_table helptable_brush[] = -{ - HELP_TITLE("GRAB BRUSH") - HELP_BOLD (" OR RESTORE BRUSH") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH) - HELP_TEXT ("") - HELP_TEXT ("Engages a brush grabbing.") - HELP_TEXT ("") - HELP_TEXT ("Click on a corner of the rectangle") - HELP_TEXT ("containing the brush then maintain the click") - HELP_TEXT ("to define the opposite corner of the") - HELP_TEXT ("rectangle. Release the mouse button to grab") - HELP_TEXT ("the brush. Performing this operation with") - HELP_TEXT ("the right mouse button will erase the area") - HELP_TEXT ("where the brush was grabbed with the") - HELP_TEXT ("Back-color.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) - HELP_TEXT ("") - HELP_TEXT ("Restores the old brush.") -}; -static const T_Help_table helptable_polybrush[] = -{ - HELP_TITLE("POLY GRAB") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_POLYBRUSH) - HELP_TEXT ("") - HELP_TEXT ("Grabs a brush of any shape by defining a") - HELP_TEXT ("polyform (please refer to section 8 for more") - HELP_TEXT ("explanations).") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_BRUSH) - HELP_TEXT ("") - HELP_TEXT ("Restores the old brush (same as above).") -}; -static const T_Help_table helptable_brush_fx[] = -{ - HELP_TITLE("BRUSH FX") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_BRUSH_EFFECTS) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where the following options") - HELP_TEXT ("are available:") - HELP_TEXT ("") - HELP_LINK ("- X: (Key:%s)",SPECIAL_FLIP_X) - HELP_TEXT ("Flip horizontally.") - HELP_TEXT ("") - HELP_LINK ("- Y: (Key:%s)",SPECIAL_FLIP_Y) - HELP_TEXT ("Flip vertically.") - HELP_TEXT ("") - HELP_LINK ("- Rotate by 90°: (Key:%s)",SPECIAL_ROTATE_90) - HELP_TEXT ("Rotates the brush by an angle of 90 degrees.") - HELP_TEXT ("") - HELP_LINK ("- Rotate by 180°: (Key:%s)",SPECIAL_ROTATE_180) - HELP_TEXT ("Rotates the brush by an angle of 180") - HELP_TEXT ("degrees.") - HELP_TEXT ("") - HELP_TEXT ("- Rotate by any angle:") - HELP_LINK ("(Key:%s)",SPECIAL_ROTATE_ANY_ANGLE) - HELP_TEXT ("Triggers an interactive operation that") - HELP_TEXT ("allows you to rotate the brush. For this,") - HELP_TEXT ("start by placing the center or rotation with") - HELP_TEXT ("the left mouse button (if, at this moment,") - HELP_TEXT ("you press the right button, the operation") - HELP_TEXT ("with be cancelled). After that, you can") - HELP_TEXT ("define the angle of rotation as many times") - HELP_TEXT ("as you want by moving the mouse and") - HELP_TEXT ("left-clicking. Then validate with the right") - HELP_TEXT ("button when you are satisfied. Meanwhile,") - HELP_TEXT ("you can press on the 8 outer digits of the") - HELP_TEXT ("numeric pad for defining angles multiple of") - HELP_TEXT ("45 degrees:") - HELP_TEXT ("") - HELP_TEXT (" 135 90 45") - HELP_TEXT (" \\ | /") - HELP_TEXT (" '7' '8' '9'") - HELP_TEXT (" 180 -'4' '6'- 0") - HELP_TEXT (" '1' '2' '3'") - HELP_TEXT (" / | \\") - HELP_TEXT (" 225 270 315") - HELP_TEXT ("") - HELP_LINK ("- Stretch: (Key:%s)",SPECIAL_STRETCH) - HELP_TEXT ("Triggers an interactive operation") - HELP_TEXT ("that enables you to stretch the brush. For") - HELP_TEXT ("this, start by placing the upper-left") - HELP_TEXT ("cornerof the brush with the left mouse") - HELP_TEXT ("button (if, at this moment, you press the") - HELP_TEXT ("right button, the operation will be") - HELP_TEXT ("cancelled). after that, you can place the") - HELP_TEXT ("opposite corner as many times as you need,") - HELP_TEXT ("then validate with the right mouse button") - HELP_TEXT ("when you are satisfied. If you place this") - HELP_TEXT ("point at coordinates inferior to the ones of") - HELP_TEXT ("the first point, the brush will be inverted.") - HELP_TEXT ("Meanwhile, you can press the following keys") - HELP_TEXT ("whose effects are:") - 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") - HELP_TEXT ("that allows you to distort your brush.") - HELP_TEXT ("Start by placing the brush somewhere on the") - HELP_TEXT ("screen and left-click. The brush will") - HELP_TEXT ("appear, with a little peg at each corner.") - HELP_TEXT ("Use the left mouse button to displace the") - HELP_TEXT ("corners, which will deform the brush.") - HELP_TEXT ("When you're done, click the right mouse") - HELP_TEXT ("button.") - HELP_TEXT ("") - HELP_LINK ("- Outline: (Key:%s)",SPECIAL_OUTLINE) - HELP_TEXT ("This option permits to draw the") - HELP_TEXT ("outlines of the brush with the Fore- color.") - HELP_TEXT ("") - HELP_LINK ("- Nibble: (Key:%s)",SPECIAL_NIBBLE) - HELP_TEXT ("This option \"nibbles\" the outlines") - HELP_TEXT ("of the brush. It's in some way the opposite") - HELP_TEXT ("effect of the Outline option.") - HELP_TEXT ("") - HELP_LINK ("- Recolorize: (Key:%s)",SPECIAL_RECOLORIZE_BRUSH) - HELP_TEXT ("Remaps the brush so that it") - HELP_TEXT ("looks like it would in the spare page, using") - HELP_TEXT ("the current palette.") - HELP_TEXT ("") - HELP_LINK ("- Get brush colors: (Key:%s)",SPECIAL_GET_BRUSH_COLORS) - HELP_TEXT ("Transfers the spare") - HELP_TEXT ("page's colors used by the brush to the") - HELP_TEXT ("current palette.") - HELP_TEXT ("") - HELP_TEXT ("- Brush handle:") - HELP_TEXT ("Allows you to choose where to place the") - HELP_TEXT ("handle of the brush. Shortcuts are :") - HELP_LINK (" Center : %s", SPECIAL_CENTER_ATTACHMENT) - HELP_LINK (" Top-left : %s", SPECIAL_TOP_LEFT_ATTACHMENT) - HELP_LINK (" Top-right : %s", SPECIAL_TOP_RIGHT_ATTACHMENT) - HELP_LINK (" Bottom-left : %s", SPECIAL_BOTTOM_LEFT_ATTACHMENT) - HELP_LINK (" Bottom-right: %s", SPECIAL_BOTTOM_RIGHT_ATTACHMENT) - HELP_TEXT ("") - HELP_LINK ("- Load : (Key:%s)",SPECIAL_LOAD_BRUSH) - HELP_TEXT ("Load a brush from disk.") - HELP_TEXT ("") - HELP_LINK ("- Save : (Key:%s)",SPECIAL_SAVE_BRUSH) - HELP_TEXT ("Save a brush to disk.") - HELP_TEXT ("") - HELP_TEXT ("") - 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") - HELP_TEXT ("'Brush factory'), or even modify the image") - HELP_TEXT ("or palette, like a Photoshop filter. See") - HELP_TEXT ("the online documentation for more help") - HELP_TEXT ("on scripting.") - HELP_TEXT ("") - HELP_TEXT ("You can select a script with the selector,") - HELP_TEXT ("the bottom panel shows a short description") - HELP_TEXT ("of what it does, and you can click Run to") - HELP_TEXT ("launch it.") - HELP_TEXT ("") - HELP_TEXT ("The scripts are located in the application's") - HELP_TEXT ("data folder, under the '/scripts'") - HELP_TEXT ("subdirectory. The list is refreshed each") - 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[] = -{ - HELP_TITLE("DRAW MODES") - HELP_LINK ("(Key:%s)",0x100+BUTTON_EFFECTS) - HELP_TEXT ("") - HELP_TEXT (" This button opens a menu where you can") - HELP_TEXT ("switch on or off the different drawing") - HELP_TEXT ("modes.") - HELP_TEXT (" In this menu, the \"All off\" button switches") - HELP_TEXT ("all the drawing modes off. The [Del] key") - HELP_TEXT ("is the keyboard shortcut for this button.") - HELP_TEXT (" The \"Feedback\" button is only used in") - HELP_TEXT ("\"Shade\", \"Quick-shade, \"Transparency\"") - HELP_TEXT ("and \"Smooth\" modes. When it is set, it means") - HELP_TEXT ("that the _current_ state of the picture") - HELP_TEXT ("has to be taken into account for the effect") - HELP_TEXT ("instead of the state in which the image") - HELP_TEXT ("was when you started to click for drawing.") - HELP_TEXT ("The best, as often, is that you try by") - HELP_TEXT ("yourself with and without Feedback to see") - HELP_TEXT ("the difference.") - HELP_TEXT (" The other buttons are the following:") - HELP_TEXT ("") - HELP_TITLE("SHADE") - HELP_TEXT (" It consists in increasing or decreasing the") - HELP_TEXT ("color number within a user-defined range.") - HELP_TEXT ("This shows its real dimension when used with") - HELP_TEXT ("a range of colors that shade off. Then,") - HELP_TEXT ("you can work on a part of your picture where") - HELP_TEXT ("colors belong to the same range without") - HELP_TEXT ("having to change your brush color all the") - HELP_TEXT ("time. You can choose the incrementation or") - HELP_TEXT ("decrementation of the color by pressing") - HELP_TEXT ("the left or right mouse button while") - HELP_TEXT ("drawing. If you click on a color that does") - HELP_TEXT ("not belong to the range, it will remain") - HELP_TEXT ("unchanged.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key : %s)", SPECIAL_SHADE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Shade mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SHADE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define one table") - HELP_TEXT ("of shades within a range of 8 memorised by") - HELP_TEXT ("the program. The different sections of this") - HELP_TEXT ("menu are:") - HELP_TEXT ("") - HELP_TEXT ("- Palette: You can define in it the color") - HELP_TEXT ("blocks that will be inserted") - HELP_TEXT ("into the table of shades.") - HELP_TEXT ("") - HELP_TEXT ("- Scroller: Used to change flick through the") - HELP_TEXT ("tables of shades.") - HELP_TEXT ("") - HELP_TEXT ("- Table of shades definition area: The 512") - HELP_TEXT ("squares should be widely") - HELP_TEXT ("sufficient to define the different shades") - HELP_TEXT ("since every 256 colors of") - HELP_TEXT ("the palette cannot be present more than once") - HELP_TEXT ("in each table.") - HELP_TEXT ("") - HELP_TEXT ("- A window (on the top-right side) permits") - HELP_TEXT ("to visualize the different") - HELP_TEXT ("shades defined in he current table.") - HELP_TEXT ("") - HELP_TEXT ("- Copy: Copy the contents of the table in a") - HELP_TEXT ("buffer.") - HELP_TEXT ("(Each time you open this menu, the current") - HELP_TEXT ("table is automatically") - HELP_TEXT ("transfered into this buffer).") - HELP_TEXT ("") - HELP_TEXT ("- Paste: Copy the contents of the buffer") - HELP_TEXT ("above in the current table.") - HELP_TEXT ("") - HELP_TEXT ("- Clear: Reset the \"shades\" table.") - HELP_TEXT ("") - HELP_TEXT ("- Insert: Used to insert the block selected") - HELP_TEXT ("in the palette at the") - HELP_TEXT ("cursor's position in the table of shades.") - HELP_TEXT ("IF you click with the left mouse button on") - HELP_TEXT ("this button THEN IF a block of more than one") - HELP_TEXT ("color is selected in the table THEN It is") - HELP_TEXT ("deleted and the block defined in the palette") - HELP_TEXT ("is inserted. ELSE The block defined in the") - HELP_TEXT ("palette is inserted at the postion just") - HELP_TEXT ("before the selected square. END IF") - HELP_TEXT ("ELSE The block defined in the palette is") - HELP_TEXT ("inserted by erasing the colors following the") - HELP_TEXT ("beginning of the bloc selected in the table.") - HELP_TEXT ("END IF") - HELP_TEXT ("") - HELP_TEXT ("- Delete: Delete the block selected in the") - HELP_TEXT ("table.") - HELP_TEXT ("") - HELP_TEXT ("- Blank: Follows this algorithm:") - HELP_TEXT ("IF you click with the left mouse button on") - HELP_TEXT ("this button THEN Replace the block selected") - HELP_TEXT ("in the table by blank squares.") - HELP_TEXT ("ELSE IF a block of more than one color is") - HELP_TEXT ("selected in the table THEN Insert blank") - HELP_TEXT ("squares to the left and to the right of the") - HELP_TEXT ("block. (this is useful for isolating a") - HELP_TEXT ("shade quickly) ELSE Insert blank squares") - HELP_TEXT ("to the left of the selected square. END IF") - HELP_TEXT ("END IF") - HELP_TEXT ("") - HELP_TEXT ("- Invert: Invert the order of the block") - HELP_TEXT ("selected in the table.") - HELP_TEXT ("") - HELP_TEXT ("- Swap: Allows you you move a block (this") - HELP_TEXT ("exchanges it with what is") - HELP_TEXT ("where you want to move it).") - HELP_TEXT ("") - HELP_TEXT ("- Undo: Cancel the last modification of the") - HELP_TEXT ("table.") - HELP_TEXT ("") - HELP_TEXT ("- The 2 numbers displayed on the right of") - HELP_TEXT ("these buttons are: (above) - the number of") - HELP_TEXT ("the color selected in the palette if only") - HELP_TEXT ("one color is selected. (below) - the number") - HELP_TEXT ("of the color contained in a square in the") - HELP_TEXT ("shades table if this square is the only one") - HELP_TEXT ("selected.") - HELP_TEXT ("") - HELP_TEXT ("- The \"mode\" button displays 3 different") - HELP_TEXT ("modes:") - HELP_TEXT ("\"Normal\": Shades in the range and saturates") - HELP_TEXT ("to its boundaries.") - HELP_TEXT ("\"Loop\": Shades in the range and loops if") - HELP_TEXT ("boundaries are passed.") - HELP_TEXT ("\"No saturation\": Shades in the range and") - HELP_TEXT ("doesn't saturate if boundaries are passed.") - HELP_TEXT ("If the Step (see below) is set to 1, this") - HELP_TEXT ("option does exactly the same as the Normal") - HELP_TEXT ("mode.") - HELP_TEXT ("") - HELP_TEXT ("- Set/Disable: If you want to define several") - HELP_TEXT ("shades in the same table") - HELP_TEXT ("but you'd like these shades not to be") - HELP_TEXT ("effective at the same time, you") - HELP_TEXT ("can mask (disable) some parts of the table") - HELP_TEXT ("so that they will be") - HELP_TEXT ("interpreted a blank squares.") - HELP_TEXT ("To do that, select a block in the table of") - HELP_TEXT ("shades and click on \"Set\".") - HELP_TEXT ("The block will be underlined with a white") - HELP_TEXT ("line; this means that it is") - HELP_TEXT ("disabled.") - HELP_TEXT ("") - HELP_TEXT ("- Clear/Enable: This does exactly the") - HELP_TEXT ("opposite as the button above.") - HELP_TEXT ("") - HELP_TEXT ("- Step: Defines the step of incrementation") - HELP_TEXT ("of the shade. The bigger,") - HELP_TEXT ("the faster you run through the colors of the") - HELP_TEXT ("shade.") - HELP_TEXT ("For example: if the step is 2 and that you") - HELP_TEXT ("have defined a shade with") - HELP_TEXT ("the colors 0,1,4,5,9 and that you click on a") - HELP_TEXT ("pixel of color 1, it will") - HELP_TEXT ("take the value 5 which is 2 positions next") - HELP_TEXT ("in the la table.") - HELP_TEXT ("") - HELP_TEXT ("(We are sorry for these technical") - HELP_TEXT ("considerations quite far from a purely") - HELP_TEXT ("artistic point of view; but know that this") - HELP_TEXT ("effect is really very useful and it is") - HELP_TEXT ("preferable that you understand its whole") - HELP_TEXT ("functionment if you want to fully take") - HELP_TEXT ("advantage of it).") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("QUICK SHADE") - HELP_TEXT (" This drawing mode has about the same effect") - HELP_TEXT ("as Shade mode's except that it is faster") - HELP_TEXT ("to configurate but a little bit less") - HELP_TEXT ("powerful. When you draw on a color of the") - HELP_TEXT ("image which is between the fore- and the") - HELP_TEXT ("back-color in the palette, the color tends") - HELP_TEXT ("towards the fore-color (according to the") - HELP_TEXT ("step defined) if you draw with the left") - HELP_TEXT ("mouse button, or it tends towards the") - HELP_TEXT ("back-color if you are using the right mouse") - HELP_TEXT ("button.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Quick-shade mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_QUICK_SHADE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu with a few parameters that mean") - HELP_TEXT ("exactly the same as in the menu of Shade") - HELP_TEXT ("mode. These parameters are the step and the") - HELP_TEXT ("loop/satu- ration mode (normal, loop, no") - HELP_TEXT ("saturation).") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("STENCIL") - HELP_TEXT (" It is used to prevent some colors from") - HELP_TEXT ("being modified if you draw on them. The") - HELP_TEXT ("main application of the stencil is when you") - HELP_TEXT ("want to change one color or more into") - HELP_TEXT ("another.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Stencil mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_STENCIL_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define a stencil.") - HELP_TEXT ("The different sections of this menu are:") - HELP_TEXT ("") - HELP_TEXT ("- Clear: No color is protected.") - HELP_TEXT ("") - HELP_TEXT ("- Invert: Colors that were protected are") - HELP_TEXT ("unprotected and vice versa.") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Select colors that should be") - HELP_TEXT ("protected with the left mouse button or") - HELP_TEXT ("unprotect colors with the right mouse") - HELP_TEXT ("button.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("MASK") - HELP_TEXT (" This effect could have been called \"True") - HELP_TEXT ("stencil\" because it protects some parts of") - HELP_TEXT ("the picture instead of some colors. The") - HELP_TEXT ("colors you tag represent the pixels in the") - HELP_TEXT ("spare page, corresponding to the pixels in") - HELP_TEXT ("the current page, that you don't want to") - HELP_TEXT ("alter. For example, draw a simple white") - HELP_TEXT ("figure on a black background in the spare") - HELP_TEXT ("page. Then, tag the black color in the menu") - HELP_TEXT ("of the Mask mode. When you'll draw in the") - HELP_TEXT ("current page, only the pixels corresponding") - HELP_TEXT ("to the white (non-black) ones in the spare") - HELP_TEXT ("page will be modified.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_MASK_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Mask mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_MASK_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can set the colors of") - HELP_TEXT ("the Mask.") - HELP_TEXT ("This menu works the same way as the one of") - HELP_TEXT ("the Stencil, so please refer to the Stencil") - HELP_TEXT ("paragraph to know how to use it.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("GRID") - HELP_TEXT (" This is useful to snap the cursor to the") - HELP_TEXT ("cross-points of a grid. It's generally") - HELP_TEXT ("used to draw a grid before drawing sprites") - HELP_TEXT ("of the same size such as a font or tiles,") - HELP_TEXT ("or for drawing figures or grabbing brushes") - HELP_TEXT ("with their dimensions multiple of the step") - HELP_TEXT ("of the grid.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_GRID_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Snap-to-grid mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_GRID_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the grid") - HELP_TEXT ("parameters. These parameters are:") - HELP_TEXT ("") - HELP_TEXT ("- X,Y: Steps of the grid.") - HELP_TEXT ("") - HELP_TEXT ("- dX,dY: Offsets of the grid.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("The following shortcut hides or shows the") - HELP_TEXT ("grid in the magnified view:") - HELP_LINK ("%s", SPECIAL_SHOW_GRID) - HELP_TEXT ("The grid size will be according to your") - HELP_TEXT ("snap-to-grid settings.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("SIEVE") - HELP_TEXT (" This effect allows you, by defining a") - HELP_TEXT ("pattern, to draw only on particular points") - HELP_TEXT ("of the picture. If you are a Manga drawer,") - HELP_TEXT ("you might find this useful to make patterned") - HELP_TEXT ("shades or color transitions.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Sieve mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SIEVE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the Sieve") - HELP_TEXT ("parameters. This menu consists in:") - HELP_TEXT ("") - HELP_TEXT ("- 16x16 drawing area: You can define a") - HELP_TEXT ("pattern in it (left click => white pixel /") - HELP_TEXT ("right click => black pixel). All the white") - HELP_TEXT ("pixels indicate that, when you'll draw,") - HELP_TEXT ("pixels will be applied on the picture at the") - HELP_TEXT ("corresponding positions whereas black pixels") - HELP_TEXT ("won't modify the picture: whites pixels are") - HELP_TEXT ("the \"holes of the sieve\".") - HELP_TEXT ("") - HELP_TEXT ("- 12 default patterns: They can be copied to") - HELP_TEXT ("the drawing area.") - HELP_TEXT ("") - HELP_TEXT ("- \"Transfer to brush\": Copies the pattern to") - HELP_TEXT ("the brush (white pixels => Fore-color /") - HELP_TEXT ("black pixels => Back-color).") - HELP_TEXT ("") - HELP_TEXT ("- \"Get from brush\": Puts the brush into the") - HELP_TEXT ("drawing area (back-color => black pixels /") - HELP_TEXT ("others => white pixels).") - HELP_TEXT ("") - HELP_TEXT ("- Scrolling 4-arrows pad: Scrolls the") - HELP_TEXT ("pattern in the drawing area.") - HELP_TEXT ("") - HELP_TEXT ("- Resizing 4-arrows pad: Defines the") - HELP_TEXT ("dimensions of the pattern.") - HELP_TEXT ("") - HELP_TEXT ("- Default-value (black or white square):") - HELP_TEXT ("Indicates which value must be inserted when") - HELP_TEXT ("you increase the dimensions of the pattern.") - HELP_TEXT ("") - HELP_TEXT ("- \"Clear\": Sets the whole pattern with the") - HELP_TEXT ("default value (see above).") - HELP_TEXT ("") - HELP_TEXT ("- \"Invert\": It... inverts :) ... black and") - HELP_TEXT ("white pixels.") - HELP_LINK ("(Key: %s)", SPECIAL_INVERT_SIEVE) - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("TRANSPARENCY") - HELP_TEXT (" This allows to mix the color(s) of the") - HELP_TEXT ("paintbrush with the colors of the picture.") - HELP_TEXT ("It's used to make transparency effects like") - HELP_TEXT ("with watercolors.") - HELP_TEXT ("") - HELP_TEXT ("You can also use the following shortcuts to") - HELP_TEXT ("activate transparency mode and assign an") - HELP_TEXT ("amount of opacity:") - HELP_LINK (" 10%% : %s", SPECIAL_TRANSPARENCY_1) - HELP_LINK (" 20%% : %s", SPECIAL_TRANSPARENCY_2) - HELP_LINK (" 30%% : %s", SPECIAL_TRANSPARENCY_3) - HELP_LINK (" 40%% : %s", SPECIAL_TRANSPARENCY_4) - HELP_LINK (" 50%% : %s", SPECIAL_TRANSPARENCY_5) - HELP_LINK (" 60%% : %s", SPECIAL_TRANSPARENCY_6) - HELP_LINK (" 70%% : %s", SPECIAL_TRANSPARENCY_7) - HELP_LINK (" 80%% : %s", SPECIAL_TRANSPARENCY_8) - HELP_LINK (" 90%% : %s", SPECIAL_TRANSPARENCY_9) - HELP_LINK (" 100%% : %s", SPECIAL_TRANSPARENCY_0) - HELP_TEXT ("If you use two of these shortcuts quickly,") - HELP_TEXT ("the second will set the units for finer") - HELP_TEXT ("control. Ie: 4 5 makes 45%, 0 9 makes 9%.") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Transparency mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_COLORIZE_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the") - HELP_TEXT ("Transparency parameters. These parameters") - HELP_TEXT ("are:") - HELP_TEXT ("") - HELP_TEXT ("- Interpolation rate: Indicates the") - HELP_TEXT ("percentage of the applied color that will be") - HELP_TEXT ("considered upon the replaced color.") - HELP_TEXT ("") - HELP_TEXT ("- Interpolation method: Uses an") - HELP_TEXT ("interpolation algorithm to compute the") - HELP_TEXT ("color, according to the interpolation rate.") - HELP_TEXT ("") - HELP_TEXT ("- Additive method: Uses the lightest colors") - HELP_TEXT ("to choose the color to apply. For example:") - HELP_TEXT ("if you want to apply a color RGB:30,20,40 on") - HELP_TEXT ("a color RGB:10,50,20, the color applied will") - HELP_TEXT ("be the one, in the palette, that is the") - HELP_TEXT ("closest to the theoretic color RGB:30,50,40.") - HELP_TEXT ("") - HELP_TEXT ("- Subtractive method: uses the darkest") - HELP_TEXT ("colors to choose the color to apply. For") - HELP_TEXT ("example: if you want to apply a color") - HELP_TEXT ("RGB:30,20,40 on a color RGB:10,50,20, the") - HELP_TEXT ("color applied will be the one, in the") - HELP_TEXT ("palette, that is the closest to the") - HELP_TEXT ("theoretic color RGB:10,20,20.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("SMOOTH") - HELP_TEXT (" It provides an easy but not as efficient") - HELP_TEXT ("anti-aliasing as any artist's touch.") - HELP_TEXT ("Anyway this effect finds a better use in") - HELP_TEXT ("making a blurry aspect.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Smooth mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_SMOOTH_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the Smooth") - HELP_TEXT ("matrix or choose one among the 4 ones") - HELP_TEXT ("predefined.") - HELP_TEXT ("The middle square represents the pixel on") - HELP_TEXT ("which you draw and the 8 others represent") - HELP_TEXT ("the neighbour pixels. Then, the point on") - HELP_TEXT ("which one draw will be replaced by the") - HELP_TEXT ("weighted average (according to values of") - HELP_TEXT ("each squares) of the 9 defined points.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("SMEAR") - HELP_TEXT (" It smears pixels in the direction you are") - HELP_TEXT ("moving your paintbrush, just as if you") - HELP_TEXT ("wanted to spread fresh paint with your") - HELP_TEXT ("fingers. You can combine this effect with") - HELP_TEXT ("the transparency effect.") - HELP_TEXT ("") - HELP_LINK ("(Key: %s)", SPECIAL_SMEAR_MODE) - HELP_TEXT ("Switches the Smear mode.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("TILING") - HELP_TEXT (" It consists in displaying parts of the") - HELP_TEXT ("brush that are adjusted on a tiling when") - HELP_TEXT ("you are drawing. It's mainly used for") - HELP_TEXT ("quickly drawing a background with a") - HELP_TEXT ("pattern, but there is a great number of") - HELP_TEXT ("other possibilities.") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_TILING_MODE) - HELP_TEXT ("") - HELP_TEXT ("Switches the Tiling mode.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key: %s)", SPECIAL_TILING_MENU) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can define the Tiling") - HELP_TEXT ("parameters. These parameters are the offsets") - HELP_TEXT ("of the tiling.") -}; -static const T_Help_table helptable_text[] = -{ - HELP_TITLE("TEXT") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_TEXT) - HELP_TEXT ("") - HELP_TEXT ("The text menu allows you to enter some text") - HELP_TEXT ("and render it as a brush.") - HELP_TEXT ("The current background and foreground colors") - HELP_TEXT ("are very important, they determine the text") - HELP_TEXT ("color, the transparent color, and also the") - HELP_TEXT ("color range to use for antialiasing.") - HELP_TEXT ("GrafX2 can use 'bitmap' fonts as long as") - HELP_TEXT ("they are in the special layout supported ") - HELP_TEXT ("by SFont.") - HELP_TEXT ("TrueType fonts can also be used if this") - HELP_TEXT ("version of GrafX2 was compiled with") - HELP_TEXT ("TrueType support.") - HELP_TEXT ("") - HELP_TEXT ("- Txt: Click and enter your text here, a") - HELP_TEXT ("line of up to 250 characters.") - HELP_TEXT ("") - HELP_TEXT ("- Clear txt: Empties the current text.") - HELP_TEXT ("When the text is empty, a standard string") - HELP_TEXT ("is shown instead in the preview area.") - HELP_TEXT ("") - HELP_TEXT ("- Antialias: Click to enable or disable") - HELP_TEXT ("Antialiasing. Only affects TrueType fonts.") - HELP_TEXT ("") - HELP_TEXT ("- Size: Determine the font height. Only") - HELP_TEXT ("affects TrueType fonts.") - HELP_TEXT ("") - HELP_TEXT ("- Font selector: Choose a font. You can") - HELP_TEXT ("use the arrow keys (up and down) to quickly") - HELP_TEXT ("browse your fonts.") - HELP_TEXT ("TrueType fonts are indicated by 'TT'.") - HELP_TEXT ("") - HELP_TEXT ("- Preview area: Shows what the brush will") - HELP_TEXT ("look like.") -}; -static const T_Help_table helptable_magnifier[] = -{ - HELP_TITLE("MAGNIFIER") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_MAGNIFIER) - HELP_TEXT ("") - HELP_TEXT ("Engages/Disengages the choice of the zoomed") - HELP_TEXT ("window. If you're already in magnifier mode,") - HELP_TEXT ("you'll return to normal mode.") - HELP_LINK ("Zoom in : %s",SPECIAL_ZOOM_IN) - HELP_LINK ("Zoom out: %s",SPECIAL_ZOOM_OUT) - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_MAGNIFIER) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can choose the") - HELP_TEXT ("magnifying factor.") - HELP_TEXT ("") - HELP_TEXT (" Note: When you are in Zoom mode, you can") - HELP_TEXT ("move the \"split\" bar by clicking on it and") - HELP_TEXT ("moving your mouse left or right while") - HELP_TEXT ("holding the mouse button down.") -}; -static const T_Help_table helptable_colorpicker[] = -{ - HELP_TITLE("PIPETTE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_COLORPICKER) - HELP_TEXT ("") - HELP_TEXT ("Engages a color grabbing.") - HELP_TEXT ("") - HELP_TEXT ("Click on the picture to get the color of the") - HELP_TEXT ("pixel you're on. You can either get a new") - HELP_TEXT ("Fore-color or Back-color with respectively") - HELP_TEXT ("left or right mouse button.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_COLORPICKER) - HELP_TEXT ("") - HELP_TEXT ("Swap Fore-color and Back-color.") - HELP_TEXT ("") - HELP_TEXT (" The color currently pointed will be") - HELP_TEXT ("displayed in the tool-bar right after the") - HELP_TEXT ("coordinates. If you click outside the") - HELP_TEXT ("picture, the color 0 will be returned.") -}; -static const T_Help_table helptable_resolution[] = -{ - HELP_TITLE("RESOLUTION AND") - HELP_TITLE(" IMAGE SIZE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_RESOL) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can define the") - HELP_TEXT ("size of your picture and choose the") - HELP_TEXT ("screen resolution.") - HELP_TEXT ("") - HELP_TEXT ("- Image size") - HELP_TEXT ("Click in the boxes named \"Width\" and") - HELP_TEXT ("\"Height\" to change the size of the image") - HELP_TEXT ("you're editing, up to 9999x9999.") - HELP_TEXT ("You can also right-click a video mode to") - HELP_TEXT ("copy its dimensions to the image's.") - HELP_TEXT ("") - HELP_TEXT ("- Pixel size") - HELP_TEXT ("If you choose any Pixel size other than") - HELP_TEXT ("Normal, Grafx2 will emulate a lower") - HELP_TEXT ("resolution by scaling up everything it") - HELP_TEXT ("displays, including the menus and mouse") - HELP_TEXT ("cursor. In Double, Triple and Quadruple") - HELP_TEXT ("mode, the image will appear zoomed x2, x3 or") - HELP_TEXT ("x4, keeping the original proportions. The") - HELP_TEXT ("scaling is done in software, with no linear") - HELP_TEXT ("interpolation, so it can't cause blur. This") - HELP_TEXT ("setting is especially useful if your") - HELP_TEXT ("hardware or drivers don't support the low") - HELP_TEXT ("resolutions you need, but it also allows you") - HELP_TEXT ("to draw in low-resolution while staying in") - HELP_TEXT ("window mode.") - HELP_TEXT ("If you choose one of the scalers called") - HELP_TEXT ("Wide, Tall, Wide2 and Tall2, this will") - HELP_TEXT ("emulate a video mode which has rectangular") - HELP_TEXT ("pixels (longer horizontally or vertically),") - HELP_TEXT ("like some video modes of the C64, Amstrad") - HELP_TEXT ("CPC, and Commodore Amiga.") - HELP_TEXT ("") - HELP_TEXT ("- Video mode") - HELP_TEXT ("Click on a video mode to select it.") - HELP_TEXT ("Grafx2 only lists modes that are detected") - HELP_TEXT ("as available on your computer. Depending on") - HELP_TEXT ("your video card and drivers, there can be") - HELP_TEXT ("a huge difference in the number of modes") - HELP_TEXT ("it can propose.") - HELP_TEXT ("The small buttons on the left-hand side of") - HELP_TEXT ("the lines in the list of modes have been") - HELP_TEXT ("designed to allow you to disable some modes") - HELP_TEXT ("that are not supported by your card. So, the") - HELP_TEXT ("modes that you will disable won't be used") - HELP_TEXT ("when loading pictures with \"Auto-set") - HELP_TEXT ("resolution\" ON.") - HELP_TEXT ("") - HELP_TEXT ("When you click on one of these buttons, its") - HELP_TEXT ("color changes to one of the 4 following. The") - HELP_TEXT ("signification for each color of these") - HELP_TEXT ("buttons is:") - HELP_TEXT ("") - HELP_TEXT ("- Light gray: The video mode is OK. It can") - HELP_TEXT ("be used by the auto-set resolution option") - HELP_TEXT ("when you load picture, and you can select it") - HELP_TEXT ("in the menu of resolutions.") - HELP_TEXT ("") - HELP_TEXT ("- White: It works exactly the same as above.") - HELP_TEXT ("Moreover, it allows you to tag your") - HELP_TEXT ("favourite modes. Indeed, the huge number of") - HELP_TEXT ("video modes makes it more difficult to find") - HELP_TEXT ("the mode your want in the list; so you can") - HELP_TEXT ("tag your favoutite ones in white, so that it") - HELP_TEXT ("will be easier to locate them. (Note: you") - HELP_TEXT ("cannot disable the standard windowed mode)") - HELP_TEXT ("") - HELP_TEXT ("- Dark gray: It allows you to indicate which") - HELP_TEXT ("modes are not really perfect (flickering,") - HELP_TEXT ("not centered, etc...) but which can be used") - HELP_TEXT ("even so. The difference with the light grey") - HELP_TEXT ("button is that these modes won't be used by") - HELP_TEXT ("the auto-set resolution option.") - HELP_TEXT ("") - HELP_TEXT ("- Black: Use it for totally unsupported") - HELP_TEXT ("modes. Thus, these modes won't be selected") - HELP_TEXT ("the \"auto-set res.\" and the program will") - HELP_TEXT ("not let you select them from the list of") - HELP_TEXT ("resolutions.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_RESOL) - HELP_TEXT ("") - HELP_TEXT (" Automatically switches to the 640x400 window") - HELP_TEXT ("mode.") -}; -static const T_Help_table helptable_page[] = -{ - HELP_TITLE("SPARE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_PAGE) - HELP_TEXT ("") - HELP_TEXT ("Jumps to spare page. The current page is") - HELP_TEXT ("then considered as the new spare page, and") - HELP_TEXT ("the spare page considered as the new current") - HELP_TEXT ("page.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_PAGE) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu where you can choose whether") - HELP_TEXT ("you want to copy the whole picture (keyboard") - HELP_TEXT ("short-cut in this menu is [Return]), only") - HELP_TEXT ("the pixels, only the palette, or only some") - HELP_TEXT ("colors.") - HELP_TEXT ("In this last case, a second menu") - HELP_TEXT ("(stencil-like) will propose you to tag the") - HELP_TEXT ("colors you want to copy (they are all") - HELP_TEXT ("selected by default).") - HELP_TEXT ("Please refer to section \"Stencil\" to know") - HELP_TEXT ("how to use this last menu.") - HELP_TEXT ("The last option the menu (\"Copy palette and") - HELP_TEXT ("remap\"), remaps the spare page with the") - HELP_TEXT ("current palette and replicates this palette") - HELP_TEXT ("to the spare page. This option is useful to") - HELP_TEXT ("quickly remap a picture with the palette of") - HELP_TEXT ("another.") -}; -static const T_Help_table helptable_save[] = -{ - HELP_TITLE("SAVE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_SAVE) - HELP_TEXT ("") - HELP_TEXT ("Displays a fileselector where the following") - HELP_TEXT ("options are available:") - HELP_TEXT ("") - HELP_TEXT ("- Select drive: Allow you to change the") - HELP_TEXT ("current drive.or volume (depending on your") - HELP_TEXT ("operating system") - HELP_TEXT ("") - HELP_TEXT ("- Format: Allows you to choose the file") - HELP_TEXT ("format you want. (PAL and KCF file formats") - HELP_TEXT ("are \"palette\" files).") - HELP_TEXT ("") - HELP_TEXT ("- Filename: Allows you to give a new name to") - HELP_TEXT ("the picture. If no extension is given, the") - HELP_TEXT ("default (according to the format) will be") - HELP_TEXT ("used.") - HELP_TEXT ("") - HELP_TEXT ("- Bookmarks: The four dropdown buttons allow") - HELP_TEXT ("you to bookmark frequently used directories.") - HELP_TEXT ("Use right-click to open a contextual menu") - HELP_TEXT ("to Set it (memorize current directory),") - HELP_TEXT ("Rename it to change its label, and Clear it") - HELP_TEXT ("if you no longer need it. Use left-click to") - HELP_TEXT ("change to the memorized directory.") - HELP_TEXT ("") - HELP_TEXT ("- File-list: Allows you to flick through the") - HELP_TEXT ("disk tree or to overwrite an existing file.") - HELP_TEXT ("") - HELP_TEXT ("- Delete: Allows you to delete the item") - HELP_TEXT ("under the selection bar. If the item is a") - HELP_TEXT ("directory, it must be empty to be removed.") - HELP_TEXT ("") - HELP_TEXT ("- Save: Saves the picture with the current") - HELP_TEXT ("filename, with the chosen format. If the ") - HELP_TEXT ("current filename represents a directory,") - HELP_TEXT ("you'll enter it.") - HELP_TEXT ("") - HELP_TEXT ("- Comment (Txt): If you're using the PKM") - HELP_TEXT ("or PNG format, you can type in a comment on") - HELP_TEXT ("your picture. It will be memorized in the") - HELP_TEXT ("image.") - HELP_TEXT ("") - HELP_TEXT ("Note: The Backspace key brings you directly") - HELP_TEXT ("to the parent directory. You can also type") - HELP_TEXT ("the first letters of a filename you are") - HELP_TEXT ("looking for, to access it faster.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_SAVE) - HELP_TEXT ("") - HELP_TEXT ("Save the current picture with its current") - HELP_TEXT ("filename, format and comment.") - HELP_TEXT ("") - HELP_TEXT ("If the file already exists, a confirmation") - HELP_TEXT ("box will appear.") -}; -static const T_Help_table helptable_load[] = -{ - - HELP_TITLE("LOAD") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LOAD) - HELP_TEXT ("") - HELP_TEXT ("This works the same way as Save.") - HELP_TEXT ("") - HELP_TEXT ("You'll have access in the format selector to") - HELP_TEXT ("a \"*.*\" filter. And of course, you won't be") - HELP_TEXT ("able to type in any comment.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_LOAD) - HELP_TEXT ("") - HELP_TEXT ("Reloads the picture.") - HELP_TEXT ("") - HELP_TEXT ("If you want to load a picture and that you") - HELP_TEXT ("haven't saved the last modifications of the") - HELP_TEXT ("current picture, a confirmation box will") - HELP_TEXT ("appear.") -}; -static const T_Help_table helptable_settings[] = -{ - HELP_TITLE("SETTINGS") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_SETTINGS) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where you can configure some") - HELP_TEXT ("miscellaneous elements of the program.") - HELP_TEXT ("Detailed description of each setting is") - HELP_TEXT ("available when this screen is open (Use the") - HELP_LINK ("%s key.",0x100+BUTTON_HELP) - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("SKINS") - HELP_TEXT ("") - HELP_TEXT ("This window allow you to change the look and") - HELP_TEXT ("feel of the program.") - HELP_TEXT ("") - HELP_TEXT ("- Font: determines whether you want to use") - HELP_TEXT ("GrafX2 with a classical font, or another one") - HELP_TEXT ("a bit funnier.") - HELP_TEXT ("") - HELP_TEXT ("- Cursor: Allows you to choose the graphic") - HELP_TEXT ("mouse cursor: Solid and Thin are solid black") - HELP_TEXT ("and white cursors defined by the skin file,") - HELP_TEXT (" Transparent is a 1-pixel wide XOR cross.") - HELP_TEXT ("") - HELP_TEXT ("- Graphic file: you can change the whole") - HELP_TEXT ("interface by selecting where the sprites for") - HELP_TEXT ("all buttons are. Look at the files in the") - HELP_TEXT ("\"skin\" directory if you want to create your") - HELP_TEXT ("own. There are two skins available, the") - HELP_TEXT ("default for 2.1 is called modern. Classic is") - HELP_TEXT ("for nostalgics who wish to remember the old") - HELP_TEXT ("days of Sunset Design. If you create a good") - HELP_TEXT ("skin, feel free to share it with us! We may") - HELP_TEXT ("include it in a future release...") - HELP_TEXT ("") - HELP_TEXT ("- Separate colors: Draws a squaring around") - HELP_TEXT ("the colors of the tool-bar.") - HELP_TEXT ("") - HELP_TEXT ("- Show/Hide picture limits: Indicates if the") - HELP_TEXT ("picture boundaries must be displayed when") - HELP_TEXT ("you are in a resolution bigger than the") - HELP_TEXT ("picture.") - HELP_TEXT ("") -}; - -static const T_Help_table helptable_settings_details[] = -{ - HELP_TITLE("DETAILED SETTINGS") - HELP_TEXT ("") - HELP_TITLE("FILE SELECTOR") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_BOLD (" Show hidden files") - HELP_TEXT ("Hidden files appear.") - HELP_TEXT ("") - HELP_BOLD (" Show hidden directories") - HELP_TEXT ("Hidden directories appear.") - HELP_TEXT ("") - HELP_BOLD (" Preview delay") - HELP_TEXT ("Delay before displaying a preview in file-") - HELP_TEXT ("selectors (in 18.2th of second). Possible") - HELP_TEXT ("values range from 1 to 256.") - HELP_TEXT ("") - HELP_BOLD (" Maximize preview") - HELP_TEXT ("Maximize the preview of the pictures so that") - HELP_TEXT ("it is as big as possible. If you're not in") - HELP_TEXT ("the same resolution as the picture's one, it") - HELP_TEXT ("can try to correct the aspect ratio, but if") - HELP_TEXT ("the picture does not fill the whole screen,") - HELP_TEXT ("it can be worse.") - HELP_TEXT ("") - HELP_BOLD (" Find file fast") - HELP_TEXT ("This option is used to place the selection") - HELP_TEXT ("bar on a filename by typing its first") - HELP_TEXT ("letters. For example, if you want to find") - HELP_TEXT ("the 'PICTURE.PKM' in a directory that also") - HELP_TEXT ("contains 'PALETTE.PAL', you'll just have to") - HELP_TEXT ("type P and I. The different values of 'FFF'") - HELP_TEXT ("indicate if you want to find the name in") - HELP_TEXT ("both files and directories or just in only") - HELP_TEXT ("one of these:") - HELP_TEXT ("0: files and directories") - HELP_TEXT ("1: files only") - HELP_TEXT ("2: directories only") - HELP_TEXT ("") - HELP_BOLD (" Auto set resolution") - HELP_TEXT ("Automatically set the resolution when") - HELP_TEXT ("loading a picture. You should set this value") - HELP_TEXT ("to 'yes' after disabling the video modes") - HELP_TEXT ("that are notsupported by your video card or") - HELP_TEXT ("monitor.") - HELP_TEXT ("") - HELP_BOLD (" Set resolution according to") - HELP_TEXT ("If the variable above is set to 'yes', this") - HELP_TEXT ("one tells if you want to set the resolution") - HELP_TEXT ("according to:") - HELP_TEXT ("1: the internal 'original screen' dimensions") - HELP_TEXT (" of the picture") - HELP_TEXT ("2: the actual dimensions of the picture") - HELP_TEXT (" ") - HELP_BOLD (" Backup") - HELP_TEXT ("Create a backup file when saving.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("FILE FORMAT OPTIONS") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_BOLD (" Save screen size in GIF") - HELP_TEXT ("Save the screen dimensions in GIF files. If") - HELP_TEXT ("you want to read these files with Photoshop") - HELP_TEXT ("or Alchemy, and maybe some other programs,") - HELP_TEXT ("you must set this option to 'no'.") - HELP_TEXT ("") - HELP_BOLD (" Clear palette") - HELP_TEXT ("If you load a picture with a palette of less") - HELP_TEXT ("than 256 colors, this option defines if you") - HELP_TEXT ("want to clear the palette or to keep the") - HELP_TEXT ("colors of the previous picture that are over") - HELP_TEXT ("the number of colors of the new picture.") - HELP_TEXT ("For example, if you load a 32-color picture,") - HELP_TEXT ("the colors 32 to 255 will be set to black if") - HELP_TEXT ("this option is set to 'yes', or they will be") - HELP_TEXT ("kept unchanged if this option is set to 'no'") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TITLE("GUI") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_BOLD (" Opening message") - HELP_TEXT ("Display a message at startup telling the") - HELP_TEXT ("version number of the program.") - HELP_TEXT ("") - HELP_BOLD (" Menu ratio") - HELP_TEXT ("Aspect ratio and size of the menus and the") - HELP_TEXT ("tool-bar.") - HELP_TEXT ("Possible values:") - HELP_TEXT ("0: Do not adapt (pixels are not stretched)") - HELP_TEXT ("1: Adapt the menus and the tool-bar") - HELP_TEXT (" according to the resolution") - HELP_TEXT ("2: Slightly adapt the ratio of the menus and") - HELP_TEXT (" tool-bar") - HELP_TEXT ("-1:Do not adapt (like 0)") - HELP_TEXT ("-2:Stretch by x2 maximum") - HELP_TEXT ("-3:Stretch by x3 maximum") - HELP_TEXT ("-4:Stretch by x4 maximum") - HELP_TEXT ("") - HELP_BOLD (" Draw limits") - HELP_TEXT ("Draw the limits of the picture.") - HELP_TEXT ("") - HELP_BOLD (" Coordinates") - HELP_TEXT ("Coordinates:") - HELP_TEXT ("1: Relative") - HELP_TEXT ("2: Absolute") - HELP_TEXT ("") - HELP_BOLD (" Separate colors") - HELP_TEXT ("Separate the colors in the tool-bar by a") - HELP_TEXT ("black squaring.") - HELP_TEXT ("") - HELP_BOLD (" Safety colors") - HELP_TEXT ("When you reduce the palette or 'zap' some") - HELP_TEXT ("colors out of it, it is possible that there") - HELP_TEXT ("are not enough colors left to draw the") - HELP_TEXT ("menus. Switching the following variable on") - HELP_TEXT ("will bring back the colors of the menu if") - HELP_TEXT ("there are less than 4 colors left after") - HELP_TEXT ("'reducing' or 'zapping'.") - HELP_TEXT ("") - HELP_BOLD (" Grid XOR color") - HELP_TEXT ("This determines the color value for the") - HELP_TEXT ("grid. Each pixel of the grid will be") - HELP_TEXT ("displayed by XOR-ing the original color with") - HELP_TEXT ("the value of this setting.") - HELP_TEXT ("For example, if you always paint 16-color") - HELP_TEXT ("images, you can set it to 16 so the color of") - HELP_TEXT ("the grid are 16 for 0, 17 for 1, etc. Then") - HELP_TEXT ("you can set colors 16-31 as lighter/darker") - 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 ("") - HELP_TEXT ("") - HELP_BOLD (" Gauges scrolling speed Left") - HELP_TEXT ("Speed of the scroll-bars (in VBLs waited)") - HELP_TEXT ("while clicking with the left or right button") - HELP_TEXT ("of the mouse.") - HELP_TEXT ("Values can be between 1 and 255. The bigger") - HELP_TEXT ("values, the slower.") - HELP_TEXT ("") - HELP_BOLD (" Gauges scrolling speed Right") - HELP_TEXT ("Speed of the scroll-bars (in VBLs waited)") - HELP_TEXT ("while clicking with the left or right button") - HELP_TEXT ("of the mouse.") - HELP_TEXT ("Values can be between 1 and 255. The bigger") - HELP_TEXT ("values, the slower.") - HELP_TEXT ("") - HELP_BOLD (" Merge movement") - HELP_TEXT ("This setting allows you merge successive") - HELP_TEXT ("mouse movements into a single mouse") - HELP_TEXT ("movement. You should only use it if you are") - HELP_TEXT ("using a mouse which reports at 200Hz or") - HELP_TEXT ("more, and you experience lag when using") - HELP_TEXT ("discontinuous hand-drawing with large") - HELP_TEXT ("brushes (this tool tries to paste the brush") - HELP_TEXT ("and update the screen on each new mouse") - HELP_TEXT ("position) In this case, set this to 2 or") - HELP_TEXT ("more, to ignore some intermediate mouse") - HELP_TEXT ("reports when a more recent one is present.") - HELP_TEXT ("Note that with a value superior to 1, you") - HELP_TEXT ("lose precision with continuous hand-drawing,") - HELP_TEXT ("as intermediate mouse positions are skipped.") - HELP_TEXT ("") - HELP_BOLD (" Double click speed") - HELP_TEXT ("This is the time (in milliseconds) between") - HELP_TEXT ("two clicks for Grafx2 to recognize a") - HELP_TEXT ("double-click. Double-click is used mostly in") - HELP_TEXT ("the palette area of the menu: double-click a") - HELP_TEXT ("color to open the palette.") - HELP_TEXT ("") - HELP_BOLD (" Double key speed") - HELP_TEXT ("When you press two digit keys in rapid") - HELP_TEXT ("succession (ex: 3 8), Grafx2 sets") - HELP_TEXT ("transparency to 38% (instead of 30% then") - HELP_TEXT ("80%). This setting allows you to set the") - HELP_TEXT ("maximum delay between two keypresses for") - 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 ("") - HELP_BOLD (" Adjust brush pick") - HELP_TEXT ("Adjust the brush grabbing in 'grid' mode.") - HELP_TEXT ("") - HELP_BOLD (" Undo pages") - HELP_TEXT ("Number of pages stored in memory for") - HELP_TEXT ("'undoing'.") - HELP_TEXT ("Values are between 1 and 99.") - HELP_TEXT ("") - HELP_BOLD (" Vertices per polygon") - HELP_TEXT ("Maximum number of vertices used in filled") - HELP_TEXT ("polygons and polyforms, and lasso. Possible") - HELP_TEXT ("values range from 2 to 16384.") - HELP_TEXT ("") - HELP_BOLD (" Fast zoom") - HELP_TEXT ("Automatically zoom into the pointed area") - HELP_TEXT ("when you press the short-key of the") - HELP_TEXT ("Magnifier button while being above the") - HELP_TEXT ("picture.") - HELP_TEXT ("") - HELP_BOLD (" Clear with stencil") - HELP_TEXT ("Take the Stencil into account when clearing") - HELP_TEXT ("the image.") - HELP_TEXT ("") - HELP_BOLD (" Auto discontinuous") - HELP_TEXT ("Directly set the discontinuous freehand") - HELP_TEXT ("drawing mode after brush grabbing.") - HELP_TEXT ("") - HELP_BOLD (" Auto nb colors used") - HELP_TEXT ("Automaticaly count the number of different") - HELP_TEXT ("colors used when opening the palette editor") - HELP_TEXT ("window. (Set it to 'no' if you have a slow") - HELP_TEXT ("computer or if you edit huge pictures)") - 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.") - HELP_TEXT ("") - HELP_TEXT (" Multi shortcuts") - HELP_TEXT ("When this setting is disabled, and you") - HELP_TEXT ("create a shortcut with a key that is already") - HELP_TEXT ("associated to another shortcut, Grafx2 will") - HELP_TEXT ("unset the latter. If you enable this mode,") - HELP_TEXT ("Grafx2 will not make such check, so you can") - HELP_TEXT ("design shortcuts that trigger several") - HELP_TEXT ("actions at once.") - HELP_TEXT ("") -}; - -static const T_Help_table helptable_clear[] = -{ - - HELP_TITLE("CLEAR") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_CLEAR) - HELP_TEXT ("") - HELP_TEXT ("Clears the picture with the color number 0,") - HELP_TEXT ("or the transparent color of the picture.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_CLEAR) - HELP_TEXT ("") - HELP_TEXT ("Clears the picture with the Back-color.") -}; -static const T_Help_table helptable_general[] = -{ - - HELP_TITLE("HELP STATS") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_HELP) - HELP_TEXT ("") - HELP_TEXT ("Displays an info window where you'll find") - HELP_TEXT ("some credits, help about the credits,") - HELP_TEXT ("different effects, greetings, registering...") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_HELP) - HELP_TEXT ("") - HELP_TEXT ("Displays a window where you'll find") - HELP_TEXT ("miscellaneous information about the system.") - HELP_TEXT (" Note: you should take care to keep more") - HELP_TEXT ("than 128 Kb in order to let the program") - HELP_TEXT ("run in a proper way.") -}; -static const T_Help_table helptable_undo[] = -{ - - HELP_TITLE("OOPS") - HELP_TEXT ("(UNDO/REDO)") - HELP_TEXT ("LEFT CLICK Allows you to undo the last") - HELP_TEXT ("modification on the picture.") - HELP_LINK ("(Key:%s)",0x100+BUTTON_UNDO) - HELP_TEXT ("") - HELP_TEXT ("RIGHT CLICK Allows you to redo the last") - HELP_TEXT ("modification undone on the picture.") - HELP_TEXT ("The maximum number of UNDO that you can") - HELP_TEXT ("perform can be defined in the settings") - HELP_TEXT ("menu.") - HELP_TEXT ("Undo/Redo aren't effective after page") - HELP_TEXT ("switching, picture loading and picture") - HELP_TEXT ("size modifications.") - HELP_LINK ("(Key:%s)",0x200+BUTTON_UNDO) -}; -static const T_Help_table helptable_kill[] = -{ - - HELP_TITLE("KILL") - HELP_TEXT ("KILL CURRENT PAGE") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_KILL) - HELP_TEXT ("") - HELP_TEXT ("Removes the current page from the list of") - HELP_TEXT ("\"Undo\" pages. This allows you to free some") - HELP_TEXT ("memory if you need it. For instance, this") - HELP_TEXT ("will allow you to delete the start-up page") - HELP_TEXT ("after having loaded an image. A message will") - HELP_TEXT ("appear if you've already erased all the") - HELP_TEXT ("pages except the last one.") - HELP_TEXT (" Note: Another way to free some memory is to") - HELP_TEXT ("decrease the number of \"Undo\" pages. Or") - HELP_TEXT ("else, if you have recentlt grabbed a very") - HELP_TEXT ("big brush that you don't use any more, you") - HELP_TEXT ("can grab a new smaller one. The memory") - HELP_TEXT ("allocated by the big brush will be thus") - HELP_TEXT ("freed.") -}; -static const T_Help_table helptable_quit[] = -{ - - HELP_TITLE("QUIT") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_QUIT) - HELP_TEXT ("") - HELP_TEXT ("Allows you to leave GrafX2. If there are") - HELP_TEXT ("unsaved modifications in the current or") - HELP_TEXT ("spare page, a confirmation box will ask you") - HELP_TEXT ("if you really want to quit GrafX2, if you") - HELP_TEXT ("want to save (Auto-save, no fileselector) or") - HELP_TEXT ("if you want to stay in GrafX2.") -}; -static const T_Help_table helptable_palette[] = -{ - - HELP_TITLE("PAL MENU") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_PALETTE) - HELP_TEXT ("") - HELP_TEXT ("Displays a menu where the following options") - HELP_TEXT ("are available:") - HELP_TEXT ("") - HELP_TEXT ("- Palette: Allows you to choose a") - HELP_TEXT ("color-block to edit. If you click with the") - HELP_TEXT ("right mouse button, you'll choose a new") - HELP_TEXT ("Back-color.") - HELP_TEXT ("") - HELP_TEXT ("- Gauges: Allow you to modify the") - HELP_TEXT ("current selection.") - HELP_TEXT ("") - HELP_TEXT ("- 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 ("- 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 ("- Neg: Transforms the current selection") - HELP_TEXT ("into its reverse video equivalent.") - HELP_TEXT ("") - HELP_TEXT ("- Invert: Swaps the colors of the current") - HELP_TEXT ("selection so that the first colors become") - HELP_TEXT ("the last ones.") - HELP_TEXT ("") - HELP_TEXT ("- X-Invert: Works as above but modifies the") - HELP_TEXT ("picture so that it looks the same.") - HELP_TEXT ("") - HELP_TEXT ("- Swap: Swaps the current selection with") - HELP_TEXT ("another color-block. Click on the beginning") - HELP_TEXT ("of the new color-block.") - HELP_TEXT ("") - HELP_TEXT ("- X-Swap: Works as above but modifies the") - HELP_TEXT ("picture so that it looks the same. This may") - HELP_TEXT ("be useful if you want to sort your palette.") - HELP_TEXT ("") - HELP_TEXT ("- Copy: Copies the current selection to") - HELP_TEXT ("another color-block. Click on the beginning") - HELP_TEXT ("of the new color-block.") - HELP_TEXT ("") - HELP_TEXT ("- Spread: Computes a gradation between two") - HELP_TEXT ("colors. If your selection is only made up of") - HELP_TEXT ("one color, select the second color in the") - HELP_TEXT ("palette. Otherwise, the two colors used will") - HELP_TEXT ("be its extremities.") - HELP_TEXT ("") - HELP_TEXT ("- Sort: sorts the palette by color ranges.") - HELP_TEXT ("If you click with the left mouse button, it") - HELP_TEXT ("will sort by H S L; and if you click with") - HELP_TEXT ("the right mouse button, it will sort by L") - HELP_TEXT ("only. Note that you can choose a range of") - HELP_TEXT ("colors before sorting, and instead of the") - HELP_TEXT ("whole palette it will sort this range.") - HELP_TEXT ("") - HELP_TEXT ("- Used: Indicates the number of colors used") - HELP_TEXT ("in the picture 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 ("- Reduce: Allows you to reduce the palette") - HELP_TEXT ("to the number of colors you want (and") - HELP_TEXT ("modifies the picture).") - HELP_TEXT ("") - HELP_TEXT ("- Undo: Allows you to recover the last") - HELP_TEXT ("modifications made on the palette. Note that") - HELP_TEXT ("it can't undo the changes that affect the") - HELP_TEXT ("pixels (remapping), you'll need to Cancel") - HELP_TEXT ("them.") - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("If you press , the program will") - HELP_TEXT ("replace, as well as possible, some unused") - HELP_TEXT ("colors by the four default colors of the") - HELP_TEXT ("menu. The image won't look altered because") - HELP_TEXT ("the modified colors (in the case they were") - HELP_TEXT ("used on a few points) will be replaced by") - HELP_TEXT ("the closest colors in the rest of the") - HELP_TEXT ("palette. This option is really useful when") - HELP_TEXT ("you modify the palette so that there are no") - HELP_TEXT ("colors that fit for the menu (eg: \"Zap") - HELP_TEXT ("unused\" while very little colors are used in") - HELP_TEXT ("the picture; or \"Reduce\" with a very small") - HELP_TEXT ("number of colors).") - HELP_TEXT ("") - HELP_TEXT ("If you press the key below or <,>") - HELP_TEXT ("(QWERTY), the menu will disappear and you") - HELP_TEXT ("will be able to pick up a color from the") - HELP_TEXT ("picture easily. Press to cancel.") - HELP_TEXT ("") - HELP_TEXT ("If only one color is selected (not a block),") - HELP_TEXT ("the <[> and <]> keys can be used to select") - HELP_TEXT ("the previous or next Forecolor (Backcolor if") - HELP_TEXT ("you press at the same time).") - HELP_TEXT ("") - HELP_TEXT ("Warning! If you press Undo after an action") - HELP_TEXT ("that modifies the picture (X-Swap, X-Invert") - HELP_TEXT ("and Reduce colors), the picture won't be") - HELP_TEXT ("remapped as it was just before this action.") - HELP_TEXT ("Only Cancel will.") - HELP_TEXT ("") - HELP_TITLE("PALETTE OPTIONS") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_LINK ("(Key:%s)",0x200+BUTTON_PALETTE) - HELP_TEXT ("") - HELP_TEXT ("Opens a menu from where you have the") - HELP_TEXT ("following options:") - HELP_TEXT ("") - HELP_TEXT ("- Colors for best match:") - HELP_TEXT ("A menu in which you can select the colors") - HELP_TEXT ("that have not to be used for smoothing, for") - HELP_TEXT ("the transparency mode, and for remapping.") - HELP_TEXT ("") - HELP_TEXT ("- User's color series:") - HELP_TEXT ("A menu in which you can define color series") - HELP_TEXT ("for next/previous user color shortcuts.") - HELP_TEXT ("It's the same settings than the shade mode.") - HELP_TEXT ("After you have some color ranges defined in") - HELP_TEXT ("this screen, you can use those shortcuts to") - HELP_TEXT ("move to the next or previous color according") - HELP_TEXT ("to your ranges:") - HELP_TEXT ("") - HELP_TEXT ("Foreground color") - HELP_TEXT ("") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_FORECOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_FORECOLOR) - HELP_TEXT ("") - HELP_TEXT ("Background color") - HELP_LINK (" Next : %s", SPECIAL_NEXT_USER_BACKCOLOR) - HELP_LINK (" Previous: %s", SPECIAL_PREVIOUS_USER_BACKCOLOR) - HELP_TEXT ("") - HELP_TEXT ("") - HELP_TEXT ("- Palette layout:") - HELP_TEXT ("Lets you customize the palette that appears") - HELP_TEXT ("on the right of the menu. You can choose the") - HELP_TEXT ("number of lines and columns.") - HELP_TEXT ("If you want the colors to run top to bottom,") - HELP_TEXT ("check the 'Vertical' button, otherwise the") - HELP_TEXT ("colors runs left to right.") - HELP_TEXT ("") - HELP_TEXT ("- RGB Scale:") - HELP_TEXT ("Lets you set the scale of the R G B sliders") - HELP_TEXT ("in the palette screen. You should normally") - HELP_TEXT ("leave it at 256 to get the full 0-255 range,") - HELP_TEXT ("but if you want to constrain the palette") - HELP_TEXT ("to the capabilities of some specific") - HELP_TEXT ("computers and consoles, you can choose eg:") - HELP_TEXT (" 64 : VGA") - HELP_TEXT (" 16 : Amiga") - HELP_TEXT (" 4 : MSX2") - HELP_TEXT (" 2 : Amstrad CPC") - }; -static const T_Help_table helptable_pal_scroll[] = -{ - - HELP_TITLE("SCROLL PAL") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Scrolls the palette window in the right of") - HELP_TEXT ("the menu.") - HELP_LINK ("Key for back: %s", 0x100+BUTTON_PAL_LEFT) - HELP_LINK ("Key for forward: %s", 0x100+BUTTON_PAL_RIGHT) - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Same as above, but faster.") - HELP_LINK ("Key for back: %s", 0x200+BUTTON_PAL_LEFT) - HELP_LINK ("Key for forward: %s", 0x200+BUTTON_PAL_RIGHT) - HELP_TEXT ("") -}; -static const T_Help_table helptable_color_select[] = -{ - - HELP_TITLE("PALETTE") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Defines the Fore-color.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Defines the Back-color.") -}; -static const T_Help_table helptable_hide[] = -{ - - HELP_TITLE("HIDE MENU") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_LINK ("(Key:%s)",0x100+BUTTON_HIDE) - HELP_TEXT ("") - HELP_TEXT ("Allows you to hide all toolbars, leaving") - HELP_TEXT ("only the status bar.") - HELP_TEXT ("Click again to show them again.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Opens a drop-down menu where you can choose") - HELP_TEXT ("Which toolbars are going to be visible in") - HELP_TEXT ("the menu.") - -}; - -static const T_Help_table helptable_layermenu[] = -{ - - HELP_TITLE("LAYERS MENU") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_MENU) - HELP_TEXT ("") - HELP_TEXT ("In this menu you can set the following") - HELP_TEXT ("options:") - HELP_TEXT ("") - HELP_TEXT ("* Transparent color : This determines which") - HELP_TEXT ("color index is considered transparent when") - HELP_TEXT ("using layers. Click the button and then") - HELP_TEXT ("click on the image to pick the right color,") - HELP_TEXT ("or use ESC to cancel.") - HELP_TEXT ("") - HELP_TEXT ("* Transparent background : When this option") - HELP_TEXT ("is checked, all pixels of the transparent") - HELP_TEXT ("color on layer 1 (background layer) will") - HELP_TEXT ("be tagged as transparent in the final image.") - HELP_TEXT ("Check this option if you want to make a") - HELP_TEXT ("transparent GIF or PNG. These are the only") - HELP_TEXT ("file formats that support this option.") - -}; -static const T_Help_table helptable_layertrans[] = -{ - - HELP_TITLE("LAYERS TRANSPARENCY") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Sets the transparent color as background pen") - HELP_TEXT ("color.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_TEXT ("") - HELP_TEXT ("The current Background color becomes the") - HELP_TEXT ("color considered transparent for the layers.") - -}; -static const T_Help_table helptable_layermerge[] = -{ - - HELP_TITLE("LAYERS MERGE") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_MERGE) - HELP_TEXT ("") - HELP_TEXT ("Merges the current layer with the one below") - HELP_TEXT ("it, and sets the resulting layer as current") - HELP_TEXT ("one for editing.") - HELP_TEXT ("This function has no effect if you're") - HELP_TEXT ("editing the lowest layer.") -}; -static const T_Help_table helptable_layeradd[] = -{ - - HELP_TITLE("ADD LAYER") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_ADD) - HELP_TEXT ("") - HELP_TEXT ("Add a new layer above the current one,") - HELP_TEXT ("and selects this new (empty) layer for") - HELP_TEXT ("editing.") - -}; -static const T_Help_table helptable_layerdel[] = -{ - - HELP_TITLE("DROP LAYER") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_REMOVE) - HELP_TEXT ("") - HELP_TEXT ("Deletes the current layer.") - -}; -static const T_Help_table helptable_layerup[] = -{ - - HELP_TITLE("MOVE LAYER UP") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_UP) - HELP_TEXT ("") - HELP_TEXT ("Swaps the current layer with the one") - HELP_TEXT ("above it. This has no effect if this") - HELP_TEXT ("layer is already on top.") - -}; -static const T_Help_table helptable_layerdown[] = -{ - - HELP_TITLE("MOVE LAYER DOWN") - HELP_TEXT ("") - HELP_LINK ("(Key:%s)",0x100+BUTTON_LAYER_DOWN) - HELP_TEXT ("") - HELP_TEXT ("Swaps the current layer with the one") - HELP_TEXT ("below it. This has no effect if this") - HELP_TEXT ("layer is already on the bottom.") -}; -static const T_Help_table helptable_layerselect[] = -{ - - HELP_TITLE("LAYER SELECTION") - HELP_TEXT ("") - HELP_BOLD ("LEFT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Choose a layer as the current one for") - HELP_TEXT ("drawing.") - HELP_TEXT ("") - HELP_BOLD ("RIGHT CLICK") - HELP_TEXT ("") - HELP_TEXT ("Makes a layer visible or invisible.") - HELP_TEXT ("If you click the current layer, this toggles") - HELP_TEXT ("the visibility of all other layers instead.") -}; -#define HELP_TABLE_DECLARATION(x) {x, sizeof(x)/sizeof(const T_Help_table)}, - -T_Help_section Help_section[] = -{ - HELP_TABLE_DECLARATION(helptable_about) - HELP_TABLE_DECLARATION(helptable_licence) - HELP_TABLE_DECLARATION(helptable_help) - HELP_TABLE_DECLARATION(helptable_credits) - - // Attention, keep the same order as BUTTON_NUMBERS: - HELP_TABLE_DECLARATION(helptable_hide) - HELP_TABLE_DECLARATION(helptable_layermenu) - HELP_TABLE_DECLARATION(helptable_layertrans) - HELP_TABLE_DECLARATION(helptable_layermerge) - HELP_TABLE_DECLARATION(helptable_layeradd) - HELP_TABLE_DECLARATION(helptable_layerdel) - HELP_TABLE_DECLARATION(helptable_layerup) - HELP_TABLE_DECLARATION(helptable_layerdown) - HELP_TABLE_DECLARATION(helptable_layerselect) - HELP_TABLE_DECLARATION(helptable_paintbrush) - HELP_TABLE_DECLARATION(helptable_adjust) - HELP_TABLE_DECLARATION(helptable_draw) - HELP_TABLE_DECLARATION(helptable_curves) - HELP_TABLE_DECLARATION(helptable_lines) - HELP_TABLE_DECLARATION(helptable_airbrush) - HELP_TABLE_DECLARATION(helptable_floodfill) - HELP_TABLE_DECLARATION(helptable_polygons) - HELP_TABLE_DECLARATION(helptable_polyfill) - HELP_TABLE_DECLARATION(helptable_rectangles) - HELP_TABLE_DECLARATION(helptable_filled_rectangles) - HELP_TABLE_DECLARATION(helptable_circles) - HELP_TABLE_DECLARATION(helptable_filled_circles) - HELP_TABLE_DECLARATION(helptable_grad_rect) - HELP_TABLE_DECLARATION(helptable_spheres) - HELP_TABLE_DECLARATION(helptable_brush) - HELP_TABLE_DECLARATION(helptable_polybrush) - HELP_TABLE_DECLARATION(helptable_brush_fx) - HELP_TABLE_DECLARATION(helptable_effects) - HELP_TABLE_DECLARATION(helptable_text) - HELP_TABLE_DECLARATION(helptable_magnifier) - HELP_TABLE_DECLARATION(helptable_colorpicker) - HELP_TABLE_DECLARATION(helptable_resolution) - HELP_TABLE_DECLARATION(helptable_page) - HELP_TABLE_DECLARATION(helptable_save) - HELP_TABLE_DECLARATION(helptable_load) - HELP_TABLE_DECLARATION(helptable_settings) - HELP_TABLE_DECLARATION(helptable_clear) - HELP_TABLE_DECLARATION(helptable_general) - HELP_TABLE_DECLARATION(helptable_undo) - HELP_TABLE_DECLARATION(helptable_kill) - HELP_TABLE_DECLARATION(helptable_quit) - HELP_TABLE_DECLARATION(helptable_palette) - HELP_TABLE_DECLARATION(helptable_pal_scroll) - HELP_TABLE_DECLARATION(helptable_pal_scroll) - HELP_TABLE_DECLARATION(helptable_color_select) - // End of buttons list - - // NB_BUTTONS+0 - HELP_TABLE_DECLARATION(helptable_settings_details) - // NB_BUTTONS+1 - // HELP_TABLE_DECLARATION() - // NB_BUTTONS+2 - // HELP_TABLE_DECLARATION() - // ... - -}; diff --git a/project/jni/application/grafx2/grafx2/src/hotkeys.c b/project/jni/application/grafx2/grafx2/src/hotkeys.c deleted file mode 100644 index bdf65ba4e..000000000 --- a/project/jni/application/grafx2/grafx2/src/hotkeys.c +++ /dev/null @@ -1,1846 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include "struct.h" -#include "global.h" -#include "hotkeys.h" - -#ifdef __VBCC__ - #define false 0 - #define true 1 -#endif - -T_Key_config ConfigKey[NB_SHORTCUTS] = { - {0, - "Scroll up", - "Scrolls the picture up, both in", - "magnify and normal mode.", - "", - false, - SDLK_UP, // HAUT - 0}, - {1, - "Scroll down", - "Scrolls the picture down, both in", - "magnify and normal mode.", - "", - false, - SDLK_DOWN, // BAS - 0}, - {2, - "Scroll left", - "Scrolls the picture to the left,", - "both in magnify and normal mode.", - "", - false, - SDLK_LEFT, // GAUCHE - 0}, - {3, - "Scroll right", - "Scrolls the picture to the right,", - "both in magnify and normal mode.", - "", - false, - SDLK_RIGHT, // DROITE - 0}, - {4, - "Faster scroll up", - "Used to scroll upwards in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_UP|MOD_SHIFT, // Shift + Haut - 0}, - {5, - "Faster scroll down", - "Used to scroll downwards in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_DOWN|MOD_SHIFT, // Shift + Bas - 0}, - {6, - "Faster scroll left", - "Used to scroll to the left in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_LEFT|MOD_SHIFT, // Shift + Gauche - 0}, - {7, - "Faster scroll right", - "Used to scroll to the right in the", - "picture fast, either in magnify and", - "normal mode.", - true, - SDLK_RIGHT|MOD_SHIFT, // Shift + Droite - 0}, - {8, - "Slower scroll up", - "Used to scroll upwards in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_UP|MOD_ALT, // Alt + Haut - 0}, - {9, - "Slower scroll down", - "Used to scroll downwards in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_DOWN|MOD_ALT, // Alt + Bas - 0}, - {10, - "Slower scroll left", - "Used to scroll to the left in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_LEFT|MOD_ALT, // Alt + Gauche - 0}, - {11, - "Slower scroll right", - "Used to scroll to the right in the", - "picture pixel by pixel, either in", - "magnify and normal mode.", - true, - SDLK_RIGHT|MOD_ALT, // Alt + Droite - 0}, - {12, - "Move mouse cursor 1 pixel up", - "Used to simulate a very small mouse", - "deplacement up.It's very useful", - "when you want ultra-high precision.", - true, - SDLK_UP|MOD_CTRL, // Ctrl + Haut - 0}, - {13, - "Move mouse cursor 1 pixel down", - "Used to simulate a very small mouse", - "deplacement down.It's very useful", - "when you want ultra-high precision.", - true, - SDLK_DOWN|MOD_CTRL, // Ctrl + Bas - 0}, - {14, - "Move mouse cursor 1 pixel left", - "Used to simulate a very small mouse", - "deplacement left.It's very useful", - "when you want ultra-high precision.", - true, - SDLK_LEFT|MOD_CTRL, // Ctrl + Gauche - 0}, - {15, - "Move mouse cursor 1 pixel right", - "Used to simulate a very small mouse", - "deplacement right.It's very useful", - "when you want ultra-high precision.", - true, - SDLK_RIGHT|MOD_CTRL, // Ctrl + Droite - 0}, - {16, - "Simulate left mouse click", - "Used to simulate a click with the", - "left mouse button. It's useful", - "when you want ultra-high precision.", - true, - SDLK_SPACE, // Space - 0}, - {17, - "Simulate right mouse click", - "Used to simulate a click with the", - "right mouse button.. It's useful", - "when you want ultra-high precision.", - true, - SDLK_SPACE|MOD_SHIFT, // Shift + Space - 0}, - {18, - "Show/hide menu toolbars", - "Hides all toolbar menus, or shows", - "them back.", - "", - false, - SDLK_F10, // F10 - 0}, - {19, - "Show/hide cursor", - "Switch the cursor display on/off.", - "This only works on the \"small cross\"", - "and \"hand\" cursors.", - true, - SDLK_F9, // F9 - 0}, - {20, - "Set paintbrush to 1 pixel", - "Useful when you want to use a", - "\"single-pixel-brush\".", - "", - true, - SDLK_DELETE, // Del - 0}, - {21, - "Paintbrush choice", - "Opens a menu where you can choose a", - "paintbrush out of 24 predefined", - "ones.", - true, - SDLK_F4, // F4 - 0}, - {22, - "Monochrome brush", - "Turn your current user-defined brush", - "into a single colored one. All non-", - "transparent colors are set to FG.", - true, - SDLK_F4|MOD_SHIFT, // Shift + F4 - 0}, - {23, - "Freehand drawing", - "Set the drawing mode to the", - "classical freehand one.", - "", - true, - SDLK_d, // D - 0}, - {24, - "Switch freehand drawing mode", - "Alternates between: continuous,", - "discontinuous, point by point,", - "and contour fill", - true, - SDLK_d|MOD_SHIFT, // Shift + D - 0}, - {25, - "Continuous freehand drawing", - "Switch directly to continuous", - "freehand drawing mode.", - "", - true, - SDLK_d|MOD_CTRL, // Ctrl + D - 0}, - {26, - "Line", - "Allows you to draw lines.", - "", - "", - true, - SDLK_l, // L - 0}, - {27, - "Knotted lines", - "Allows you to draw linked lines.", - "This mode can also be called", - "\"Polyline\".", - true, - SDLK_l|MOD_SHIFT, // Shift + L - 0}, - {28, - "Spray", - "Allows you to spray brushes", - "randomly in the picture.", - "", - true, - SDLK_a, // A (Q en AZERTY) - 0}, - {29, - "Spray menu", - "Opens a menu in which you can", - "configure the spray flow and size.", - "", - true, - SDLK_a|MOD_SHIFT, // Shift + A - 0}, - {30, - "Flood-fill", - "Allows you to fill an area of the", - "picture made of pixels of the same", - "color.", - true, - SDLK_f, // F - 0}, - {124, - "Replace color", - "This tool replaces all the pixels of", - "the clicked color to the fore-color", - "or the back-color.", - true, - SDLK_f|MOD_SHIFT, // Shift + F - 0}, - {31, - "Bezier's curves", - "Allows you to draw Bezier's curves.", - "", - "", - true, - SDLK_i, // I - 0}, - {32, - "Bezier's curve with 3 or 4 points", - "Allows you to choose whether you", - "want to draw Bezier's curves with", - "3 or 4 points.", - true, - SDLK_i|MOD_SHIFT, // Shift + I - 0}, - {33, - "Empty rectangle", - "Allows you to draw a rectangle using", - "the brush.", - "", - true, - SDLK_r, // R - 0}, - {34, - "Filled rectangle", - "Allows you to draw a filled", - "rectangle.", - "", - true, - SDLK_r|MOD_SHIFT, // Shift + R - 0}, - {35, - "Empty circle", - "Allows you to draw a circle using", - "the brush.", - "", - true, - SDLK_c, // C - 0}, - {36, - "Empty ellipse", - "Allows you to draw an ellipse using", - "the brush.", - "", - true, - SDLK_c|MOD_CTRL, // Ctrl + C - 0}, - {37, - "Filled circle", - "Allows you to draw a filled circle.", - "", - "", - true, - SDLK_c|MOD_SHIFT, // Shift + C - 0}, - {38, - "Filled ellipse", - "Allows you to draw a filled ellipse.", - "", - "", - true, - SDLK_c|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + C - 0}, - {39, - "Empty polygon", - "Allows you to draw a polygon using", - "the brush.", - "", - true, - SDLK_n, // N - 0}, - {40, - "Empty \"polyform\"", - "Allows you to draw a freehand", - "polygon using the brush.", - "", - true, - SDLK_n|MOD_CTRL, // Ctrl + N - 0}, - {41, - "Filled polygon", - "Allows you to draw a filled polygon.", - "", - "", - true, - SDLK_n|MOD_SHIFT, // Shift + N - 0}, - {42, - "Filled \"polyform\"", - "Allows you to draw a filled freehand", - "polygon.", - "", - true, - SDLK_n|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + N - 0}, - {43, - "Rectangle with gradation", - "Allows you to draw a rectangle with", - "a color gradation.", - "", - true, - SDLK_r|MOD_ALT, // Alt + R - 0}, - {44, - "Gradation menu", - "Allows you to configure the way", - "color gradations are calculated.", - "", - true, - SDLK_g|MOD_ALT, // Alt + G - 0}, - {45, - "Sphere with gradation", - "Allows you to draw a rectangle with", - "a color gradation.", - "", - true, - SDLK_c|MOD_ALT, // Alt + C - 0}, - {46, - "Ellipse with gradation", - "Allows you to draw an ellipse filled", - "with a color gradation.", - "", - true, - SDLK_c|MOD_SHIFT|MOD_ALT, // Shift + Alt + C - 0}, - {47, - "Adjust picture", - "Allows you to move the whole picture", - "Around. What gets out from a side", - "reappears on the other.", - true, - SDLK_KP5, // Kpad5 - 0}, - {48, - "Picture effects", - "Opens the 'Picture effects' window.", - "", - "", - true, - SDLK_KP5|MOD_SHIFT, // Shift + Kpad5 - 0}, - {49, - "Drawing effects", - "Opens a menu where you can enable/", - "disable and configure the drawing", - "effects.", - true, - SDLK_e, // E - 0}, - {50, - "Shade mode", - "Enables or disables Shade mode", - "", - "", - true, - SDLK_F5, // F5 - 0}, - {51, - "Shade menu", - "Opens a the menu for Shade settings.", - "", - "", - true, - SDLK_F5|MOD_SHIFT, // Shift + F5 - 0}, - {131, - "Quick-shade mode", - "Enables or disables Quick-shade", - "mode.", - "", - true, - SDLK_F5|MOD_CTRL, // Ctrl + F5 - 0}, - {132, - "Quick-shade menu", - "Opens a the menu for Quick-shade", - "settings.", - "", - true, - SDLK_F5|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + F5 - 0}, - {52, - "Stencil mode", - "Enables or disables Stencil mode.", - "", - "", - true, - SDLK_F6, // F6 - 0}, - {53, - "Stencil menu", - "Opens a the menu for Stencil", - "settings.", - "", - true, - SDLK_F6|MOD_SHIFT, // Shift + F6 - 0}, - {54, - "Mask mode", - "Enables or disables Mask mode.", - "", - "", - true, - SDLK_F6|MOD_ALT, // Alt + F6 - 0}, - {55, - "Mask menu", - "Opens a the menu for Mask settings.", - "", - "", - true, - SDLK_F6|MOD_SHIFT|MOD_ALT, // Shift + Alt + F6 - 0}, - {56, - "Grid mode", - "Enables or disables the Grid mode.", - "", - "", - true, - SDLK_g, // G - 0}, - {57, - "Grid menu", - "Open a menu where you can configure", - "the grid used by Grid mode.", - "", - true, - SDLK_g|MOD_SHIFT, // Shift + G - 0}, - {58, - "Sieve mode", - "Enables or disables the Sieve mode.", - "", - "", - true, - SDLK_g|MOD_CTRL, // Ctrl + G - 0}, - {59, - "Sieve menu", - "Opens a menu where you can configure", - "the sieve.", - "", - true, - SDLK_g|MOD_SHIFT|MOD_CTRL, // Shift + Ctrl + G - 0}, - {60, - "Invert sieve", - "Inverts the pattern defined in the", - "Sieve menu.", - "", - true, - SDLK_g|MOD_CTRL|MOD_ALT, // Ctrl + Alt + G - 0}, - {61, - "Colorize mode", - "Enables or disables the Colorize", - "mode.", - "", - true, - SDLK_F7, // F7 - 0}, - {62, - "Colorize menu", - "Opens a menu where you can give the", - "opacity percentage for Colorize", - "mode.", - true, - SDLK_F7|MOD_SHIFT, // Shift + F7 - 0}, - {63, - "Smooth mode", - "Enables or disables the Smooth", - "mode.", - "", - true, - SDLK_F8, // F8 - 0}, - {123, - "Smooth menu", - "Opens a menu where you can define", - "the Smooth matrix.", - "", - true, - SDLK_F8|MOD_SHIFT, // Shift + F8 - 0}, - {64, - "Smear mode", - "Enables or disables the Smear mode.", - "", - "", - true, - SDLK_F8|MOD_ALT, // Alt + F8 - 0}, - {65, - "Tiling mode", - "Enables or disables the Tiling", - "mode.", - "", - true, - SDLK_b|MOD_ALT, // Alt + B - 0}, - {66, - "Tiling menu", - "Opens a menu where you can configure", - "the origin of the tiling.", - "", - true, - SDLK_b|MOD_SHIFT|MOD_ALT, // Shift + Alt + B - 0}, - {67, - "Classical brush grabbing", - "Allows you to pick a brush defined", - "within a rectangle.", - "", - true, - SDLK_b, // B - 0}, - {68, - "\"Lasso\" brush grabbing", - "Allows you to pick a brush defined", - "within a freehand polygon.", - "", - true, - SDLK_b|MOD_CTRL, // Ctrl + B - 0}, - {69, - "Get previous brush back", - "Restore the last user-defined brush.", - "", - "", - true, - SDLK_b|MOD_SHIFT, // Shift + B - 0}, - {70, - "Horizontal brush flipping", - "Reverse brush horizontally.", - "", - "", - true, - SDLK_x, // X - 0}, - {71, - "Vertical brush flipping", - "Reverse brush vertically.", - "", - "", - true, - SDLK_y, // Y - 0}, - {72, - "90° brush rotation", - "Rotate the user-defined brush by 90°", - "(counter-clockwise).", - "", - true, - SDLK_z, // Z (W en AZERTY) - 0}, - {73, - "180° brush rotation", - "Rotate the user-defined brush by", - "180°.", - "", - true, - SDLK_z|MOD_SHIFT, // Shift + Z - 0}, - {74, - "Strech brush", - "Allows you to resize the", - "user-defined brush.", - "", - true, - SDLK_s, // S - 0}, - {75, - "Distort brush", - "Allows you to distort the", - "user-defined brush.", - "", - true, - SDLK_s|MOD_SHIFT, // Shift + S - 0}, - {76, - "Outline brush", - "Outlines the user-defined brush", - "with the fore color.", - "", - true, - SDLK_o, // O - 0}, - {77, - "Nibble brush", - "Deletes the borders of the", - "user-defined brush.This does the", - "opposite of the Outline option.", - true, - SDLK_o|MOD_SHIFT, // Shift + O - 0}, - {78, - "Get colors from brush", - "Copy colors of the spare page that", - "are used in the brush.", - "", - true, - SDLK_F11, // F11 - 0}, - {79, - "Recolorize brush", - "Recolorize the user-defined brush in", - "order to get a brush which looks as", - "if it was grabbed in the spare page.", - true, - SDLK_F12, // F12 - 0}, - {80, - "Rotate by any angle", - "Rotate the brush by an angle that", - "you can define.", - "", - true, - SDLK_w, // W (Z en AZERTY) - 0}, - {81, - "Pipette", - "Allows you to copy the color of a", - "pixel in the picture into the", - "foreground or background color.", - true, - SDLK_BACKQUOTE, // `~ (Key sous le Esc - ² en AZERTY) - 0}, - {82, - "Swap foreground/background colors", - "Invert foreground and background", - "colors.", - "", - true, - SDLK_BACKQUOTE|MOD_SHIFT, // Shift + `~ - 0}, - {83, - "Magnifier mode", - "Allows you to zoom into the picture.", - "", - "", - true, - SDLK_m, // M (, ? sur AZERTY) - KEY_MOUSEMIDDLE}, - {84, - "Zoom factor menu", - "Opens a menu where you can choose a", - "magnifying factor.", - "", - true, - SDLK_m|MOD_SHIFT, // Shift + M - 0}, - {85, - "Zoom in", - "Increase magnifying factor.", - "", - "", - true, - SDLK_KP_PLUS, // Grey + - KEY_MOUSEWHEELUP}, - {86, - "Zoom out", - "Decrease magnifying factor.", - "", - "", - true, - SDLK_KP_MINUS, // Grey - - KEY_MOUSEWHEELDOWN}, - {87, - "Brush effects menu", - "Opens a menu which proposes", - "different effects on the", - "user-defined brush.", - true, - SDLK_b|MOD_CTRL|MOD_ALT, // Ctrl + Alt + B - 0}, - {88, - "Text", - "Opens a menu which permits you to", - "type in a character string and", - "render it as a brush.", - true, - SDLK_t, // T - 0}, - {89, - "Screen resolution menu", - "Opens a menu where you can choose", - "the screen resolution and image", - "dimensions.", - true, - SDLK_RETURN, // Enter - 0}, - {90, - "\"Safety\" resolution", - "Resets the resolution to a 'safe'", - "mode that should work everywhere:", - "usually a 640x400 window.", - false, - SDLK_RETURN|MOD_SHIFT, // Shift + Enter - 0}, - {91, - "Help and credits", - "Opens a window where you can get", - "information about the program,", - "or contextual help.", - true, - SDLK_F1, // F1 - 0}, - {92, - "Statistics", - "Displays miscellaneous more or less", - "useful information.", - "", - true, - SDLK_F1|MOD_SHIFT, // Shift + F1 - 0}, - {93, - "Jump to spare page", - "Swap current page and spare page.", - "", - "", - true, - SDLK_TAB, // Tab - 0}, - {94, - "Copy current page to spare page", - "Copy current page to spare page.", - "", - "", - true, - SDLK_TAB|MOD_SHIFT, // Shift + Tab - 0}, - {95, - "Save picture as...", - "Opens a file-selector that allows", - "you to save your picture with a new", - "path-name.", - true, - SDLK_F2, // F2 - 0}, - {96, - "Save picture", - "Saves your picture with the last", - "name you gave it.", - "", - true, - SDLK_F2|MOD_SHIFT, // Shift + F2 - 0}, - {97, - "Load picture", - "Opens a file-selector that allows", - "you to load a new picture.", - "", - true, - SDLK_F3, // F3 - 0}, - {98, - "Re-load picture", - "Re-load the current picture. This", - "allows you to cancel modifications", - "made since last saving.", - true, - SDLK_F3|MOD_SHIFT, // Shift + F3 - 0}, - {99, - "Save brush", - "Opens a file-selector that allows", - "you to save your current", - "user-defined brush.", - true, - SDLK_F2|MOD_CTRL, // Ctrl + F2 - 0}, - {100, - "Load brush", - "Opens a file-selector that allows", - "you to load a brush.", - "", - true, - SDLK_F3|MOD_CTRL, // Ctrl + F3 - 0}, - {101, - "Settings", - "Opens a menu which permits you to", - "modify some parameters of the", - "program.", - true, - SDLK_F10|MOD_SHIFT, // Shift + F10 - 0}, - {102, - "Undo (Oops!)", - "Cancel the last action which", - "modified the picture.", - "", - true, - SDLK_u, // U - // 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.", - "", - "", - true, - SDLK_u|MOD_SHIFT, // Shift + U - // 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", - "removes the current page from the", - "list of \"Undo\" pages.", - true, - SDLK_DELETE|MOD_SHIFT, // Shift + Suppr - 0}, - {104, - "Clear page", - "Clears the picture with color 0,", - "or the transparent color if it's", - "a layered image.", - true, - SDLK_BACKSPACE, // BackSpace - 0}, - {105, - "Clear page with backcolor", - "Clears the picture with the", - "current backcolor.", - "", - true, - SDLK_BACKSPACE|MOD_SHIFT, // Shift + BackSpace - 0}, - {106, - "Quit program", - "Allows you to leave the program.", - "If modifications were not saved,", - "confirmation is asked.", - false, - SDLK_q, // Q (A en AZERTY) - // 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", - "modify the current palette.", - "", - true, - SDLK_p, // P - 0}, - {125, - "Secondary palette menu", - "Opens a menu which allows you to", - "define color series and some tagged", - "colors.", - true, - SDLK_p|MOD_SHIFT, // Shift + P - 0}, - {130, - "Exclude colors menu", - "Opens a menu which allows you to", - "define the colors you don't want to", - "use in Smooth and Transparency", - true, - SDLK_p|MOD_CTRL, // Ctrl + P - 0}, - {108, - "Scroll palette to the left", - "Scroll palette in the tool bar to", - "the left, column by column.", - "", - true, - SDLK_PAGEUP, // PgUp - 0}, - {109, - "Scroll palette to the right", - "Scroll palette in the tool bar to", - "the right, column by column.", - "", - true, - SDLK_PAGEDOWN, // PgDn - 0}, - {110, - "Scroll palette to the left faster", - "Scroll palette in the tool bar to", - "the left, 8 columns by 8 columns.", - "", - true, - SDLK_PAGEUP|MOD_SHIFT, // Shift + PgUp - 0}, - {111, - "Scroll palette to the right faster", - "Scroll palette in the tool bar to", - "the right, 8 columns by 8 columns.", - "", - true, - SDLK_PAGEDOWN|MOD_SHIFT, // Shift + PgDn - 0}, - {112, - "Center brush attachment point", - "Set the attachement of the", - "user-defined brush to its center.", - "", - true, - SDLK_KP5|MOD_CTRL, // Ctrl + 5 (pavé numérique) - 0}, - {113, - "Top-left brush attachment point", - "Set the attachement of the", - "user-defined brush to its top-left", - "corner.", - true, - SDLK_HOME|MOD_CTRL, // Ctrl + 7 - 0}, - {114, - "Top-right brush attachment point", - "Set the attachement of the", - "user-defined brush to its top-right", - "corner.", - true, - SDLK_PAGEUP|MOD_CTRL, // Ctrl + 9 - 0}, - {115, - "Bottom-left brush attachment point", - "Set the attachement of the", - "user-defined brush to its", - "bottom-left corner.", - true, - SDLK_END|MOD_CTRL, // Ctrl + 1 - 0}, - {116, - "Bottom-right brush attachment point", - "Set the attachement of the", - "user-defined brush to its", - "bottom-right corner.", - true, - SDLK_PAGEDOWN|MOD_CTRL, // Ctrl + 3 - 0}, - {117, - "Next foreground color", - "Set the foreground color to the next", - "in the palette.", - "", - true, - SDLK_RIGHTBRACKET, // ] (0x en AZERTY) - 0}, - {118, - "Previous foreground color", - "Set the foreground color to the", - "previous in the palette.", - "", - true, - SDLK_LEFTBRACKET, // [ (^ en AZERTY) - 0}, - {119, - "Next background color", - "Set the background color to the next", - "in the palette.", - "", - true, - SDLK_RIGHTBRACKET|MOD_SHIFT, // Shift + ] - 0}, - {120, - "Previous background color", - "Set the background color to the", - "previous in the palette.", - "", - true, - SDLK_LEFTBRACKET|MOD_SHIFT, // Shift + [ - 0}, - {126, - "Next user-defined forecolor", - "Set the foreground color to the next", - "in the user-defined color series.", - "", - true, - SDLK_EQUALS, // "=+" - 0}, - {127, - "Previous user-defined forecolor", - "Set the foreground color to the", - "previous in the user-defined color", - "series.", - true, - SDLK_MINUS, // "-_" (")°" en AZERTY - 0}, - {128, - "Next user-defined backcolor", - "Set the background color to the next", - "in the user-defined color series.", - "", - true, - SDLK_EQUALS|MOD_SHIFT, // Shift + "=+" - 0}, - {129, - "Previous user-defined backcolor", - "Set the background color to the", - "previous in the user-defined color", - "series.", - true, - SDLK_MINUS|MOD_SHIFT, // Shift + "-_" (")°" en AZERTY - 0}, - {121, - "Shrink paintbrush", - "Decrease the width of the paintbrush", - "if it is special circle or square.", - "", - true, - SDLK_COMMA, // , < (;. en AZERTY) - 0}, - {122, - "Enlarge paintbrush", - "Increase the width of the paintbrush", - "if it is special circle or square.", - "", - true, - SDLK_PERIOD, // .> (:/ en AZERTY) - 0}, - {134, - "Effects off", - "Turns off all drawing effects. This", - "is the same as the 'All off' button", - "in the Effects screen", - true, - SDLK_e|MOD_SHIFT, // Shift-E - 0}, - {135, - "Transparency 10%", - "Turns transparency on and sets its", - "opacity at 10%.", - "", - true, - SDLK_1, // 1 - 0}, - {136, - "Transparency 20%", - "Turns transparency on and sets its", - "opacity at 20%.", - "", - true, - SDLK_2, // 2 - 0}, - {137, - "Transparency 30%", - "Turns transparency on and sets its", - "opacity at 30%.", - "", - true, - SDLK_3, // 3 - 0}, - {138, - "Transparency 40%", - "Turns transparency on and sets its", - "opacity at 40%.", - "", - true, - SDLK_4, // 4 - 0}, - {139, - "Transparency 50%", - "Turns transparency on and sets its", - "opacity at 50%.", - "", - true, - SDLK_5, // 5 - 0}, - {140, - "Transparency 60%", - "Turns transparency on and sets its", - "opacity at 60%.", - "", - true, - SDLK_6, // 6 - 0}, - {141, - "Transparency 70%", - "Turns transparency on and sets its", - "opacity at 70%.", - "", - true, - SDLK_7, // 7 - 0}, - {142, - "Transparency 80%", - "Turns transparency on and sets its", - "opacity at 80%.", - "", - true, - SDLK_8, // 8 - 0}, - {143, - "Transparency 90%", - "Turns transparency on and sets its", - "opacity at 90%.", - "", - true, - SDLK_9, // 9 - 0}, - {144, - "Transparency 0%", - "Turns transparency on and sets its", - "opacity at 0%.", - "", - true, - SDLK_0, // 0 - 0}, - {145, - "Zoom 1:1", - "Turns magnifier mode off.", - "", - "", - true, - SDLK_1|MOD_CTRL, /* Ctrl + 1 */ - 0}, - {146, - "Zoom 2:1", - "Turns magnifier mode on and set its", - "factor to 2:1", - "", - true, - SDLK_2|MOD_CTRL, /* Ctrl + 2 */ - 0}, - {147, - "Zoom 3:1", - "Turns magnifier mode on and set its", - "factor to 3:1", - "", - true, - SDLK_3|MOD_CTRL, /* Ctrl + 3 */ - 0}, - {148, - "Zoom 4:1", - "Turns magnifier mode on and set its", - "factor to 4:1", - "", - true, - SDLK_4|MOD_CTRL, /* Ctrl + 4 */ - 0}, - {149, - "Zoom 5:1", - "Turns magnifier mode on and set its", - "factor to 5:1", - "", - true, - SDLK_5|MOD_CTRL, /* Ctrl + 5 */ - 0}, - {150, - "Zoom 6:1", - "Turns magnifier mode on and set its", - "factor to 6:1", - "", - true, - SDLK_6|MOD_CTRL, /* Ctrl + 6 */ - 0}, - {151, - "Zoom 8:1", - "Turns magnifier mode on and set its", - "factor to 8:1", - "", - true, - SDLK_7|MOD_CTRL, /* Ctrl + 7 */ - 0}, - {152, - "Zoom 10:1", - "Turns magnifier mode on and set its", - "factor to 10:1", - "", - true, - SDLK_8|MOD_CTRL, /* Ctrl + 8 */ - 0}, - {153, - "Zoom 12:1", - "Turns magnifier mode on and set its", - "factor to 12:1", - "", - true, - 0, - 0}, - {154, - "Zoom 14:1", - "Turns magnifier mode on and set its", - "factor to 14:1", - "", - true, - 0, - 0}, - {155, - "Zoom 16:1", - "Turns magnifier mode on and set its", - "factor to 16:1", - "", - true, - 0, - 0}, - {156, - "Zoom 18:1", - "Turns magnifier mode on and set its", - "factor to 18:1", - "", - true, - 0, - 0}, - {157, - "Zoom 20:1", - "Turns magnifier mode on and set its", - "factor to 20:1", - "", - true, - 0, - 0}, - {158, - "Show/Hide Grid", - "Turns on or off the visible grid in ", - "the magnified view. Grid cells match", - "the size ", - true, - SDLK_g|MOD_SHIFT|MOD_ALT, // Shift + Alt + G, - 0}, - {159, - "Select layer 1", - "Makes the layer 1 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {160, - "Toggle layer 1", - "Makes layer 1 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {161, - "Select layer 2", - "Makes the layer 2 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {162, - "Toggle layer 2", - "Makes layer 2 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {163, - "Select layer 3", - "Makes the layer 3 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {164, - "Toggle layer 3", - "Makes layer 3 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {165, - "Select layer 4", - "Makes the layer 4 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {166, - "Toggle layer 4", - "Makes layer 4 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {167, - "Select layer 5", - "Makes the layer 5 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {168, - "Toggle layer 5", - "Makes layer 5 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {169, - "Select layer 6", - "Makes the layer 6 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {170, - "Toggle layer 6", - "Makes layer 6 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {171, - "Select layer 7", - "Makes the layer 7 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {172, - "Toggle layer 7", - "Makes layer 7 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {173, - "Select layer 8", - "Makes the layer 8 visible and", - "set it as the active one, where", - "you can draw.", - true, - 0, - 0}, - {174, - "Toggle layer 8", - "Makes layer 8 visible or invisible.", - "If it's the current active layer,", - "toggle all other layers instead.", - true, - 0, - 0}, - {175, - "Add a layer", - "Adds a new layer on top of the", - "active one. The new layer is filled", - "with transparent color.", - true, - SDLK_INSERT|MOD_ALT, // Alt + Insert - 0}, - {176, - "Delete a layer", - "Delete the current layer.", - "You can't delete the last", - "layer.", - true, - SDLK_DELETE|MOD_ALT, // Alt + Delete - 0}, - {177, - "Merge a layer", - "Merges the current layer with", - "the one directly below it.", - "", - true, - SDLK_END|MOD_ALT, // Alt + End - 0}, - {178, - "Swap layer (up)", - "Moves the current layer one position", - "up the stack. No effect if already", - "on top.", - true, - SDLK_PAGEUP|MOD_ALT, // Alt + PageUp - 0}, - {179, - "Swap layer (down)", - "Moves the current layer one position", - "down the stack. No effect if already", - "on bottom.", - true, - SDLK_PAGEDOWN|MOD_ALT, // Alt + PageDown - 0}, - {180, - "Layers menu", - "Opens a window with options related", - "to layers and image transparency.", - "", - true, - 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}, -}; - -word Ordering[NB_SHORTCUTS]= -{ - SPECIAL_SCROLL_UP, // Scroll up - SPECIAL_SCROLL_DOWN, // Scroll down - SPECIAL_SCROLL_LEFT, // Scroll left - SPECIAL_SCROLL_RIGHT, // Scroll right - SPECIAL_SCROLL_UP_FAST, // Scroll up faster - SPECIAL_SCROLL_DOWN_FAST, // Scroll down faster - SPECIAL_SCROLL_LEFT_FAST, // Scroll left faster - SPECIAL_SCROLL_RIGHT_FAST, // Scroll right faster - SPECIAL_SCROLL_UP_SLOW, // Scroll up slower - SPECIAL_SCROLL_DOWN_SLOW, // Scroll down slower - SPECIAL_SCROLL_LEFT_SLOW, // Scroll left slower - SPECIAL_SCROLL_RIGHT_SLOW, // Scroll right slower - SPECIAL_MOUSE_UP, // Emulate mouse up - SPECIAL_MOUSE_DOWN, // Emulate mouse down - SPECIAL_MOUSE_LEFT, // Emulate mouse left - SPECIAL_MOUSE_RIGHT, // Emulate mouse right - SPECIAL_CLICK_LEFT, // Emulate mouse click left - SPECIAL_CLICK_RIGHT, // Emulate mouse click right - 0x100+BUTTON_HIDE, // Show / Hide menus - SPECIAL_SHOW_HIDE_CURSOR, // Show / Hide cursor - SPECIAL_DOT_PAINTBRUSH, // Paintbrush = "." - 0x100+BUTTON_PAINTBRUSHES, // Paintbrush choice - 0x200+BUTTON_PAINTBRUSHES, // Monochrome brush - 0x100+BUTTON_DRAW, // Freehand drawing - 0x200+BUTTON_DRAW, // Switch freehand drawing mode - SPECIAL_CONTINUOUS_DRAW, // Continuous freehand drawing - 0x100+BUTTON_LINES, // Line - 0x200+BUTTON_LINES, // Knotted lines - 0x100+BUTTON_AIRBRUSH, // Spray - 0x200+BUTTON_AIRBRUSH, // Spray menu - 0x100+BUTTON_FLOODFILL, // Floodfill - 0x200+BUTTON_FLOODFILL, // Replace color - 0x100+BUTTON_CURVES, // Bézier's curves - 0x200+BUTTON_CURVES, // Bézier's curve with 3 or 4 points - 0x100+BUTTON_RECTANGLES, // Empty rectangle - 0x100+BUTTON_FILLRECT, // Filled rectangle - 0x100+BUTTON_CIRCLES, // Empty circle - 0x200+BUTTON_CIRCLES, // Empty ellipse - 0x100+BUTTON_FILLCIRC, // Filled circle - 0x200+BUTTON_FILLCIRC, // Filled ellipse - 0x100+BUTTON_POLYGONS, // Empty polygon - 0x200+BUTTON_POLYGONS, // Empty polyform - 0x100+BUTTON_POLYFILL, // Polyfill - 0x200+BUTTON_POLYFILL, // Filled polyform - 0x100+BUTTON_GRADRECT, // Gradient rectangle - 0x200+BUTTON_GRADRECT, // Gradation menu - 0x100+BUTTON_SPHERES, // Spheres - 0x200+BUTTON_SPHERES, // Gradient ellipses - 0x100+BUTTON_ADJUST, // Adjust picture - 0x200+BUTTON_ADJUST, // Flip picture menu - 0x100+BUTTON_EFFECTS, // Menu des effets - SPECIAL_SHADE_MODE, // Shade mode - SPECIAL_SHADE_MENU, // Shade menu - SPECIAL_QUICK_SHADE_MODE, // Quick-shade mode - SPECIAL_QUICK_SHADE_MENU, // Quick-shade menu - SPECIAL_STENCIL_MODE, // Stencil mode - SPECIAL_STENCIL_MENU, // Stencil menu - SPECIAL_MASK_MODE, // Mask mode - SPECIAL_MASK_MENU, // Mask menu - SPECIAL_GRID_MODE, // Grid mode - SPECIAL_GRID_MENU, // Grid menu - SPECIAL_SIEVE_MODE, // Sieve mode - SPECIAL_SIEVE_MENU, // Sieve menu - SPECIAL_INVERT_SIEVE, // Inverser la trame du mode Sieve - SPECIAL_COLORIZE_MODE, // Colorize mode - SPECIAL_COLORIZE_MENU, // Colorize menu - SPECIAL_SMOOTH_MODE, // Smooth mode - SPECIAL_SMOOTH_MENU, // Smooth menu - SPECIAL_SMEAR_MODE, // Smear mode - SPECIAL_TILING_MODE, // Tiling mode - SPECIAL_TILING_MENU, // Tiling menu - 0x100+BUTTON_BRUSH, // Pick brush - 0x100+BUTTON_POLYBRUSH, // Pick polyform brush - 0x200+BUTTON_BRUSH, // Restore brush - SPECIAL_FLIP_X, // Flip X - SPECIAL_FLIP_Y, // Flip Y - SPECIAL_ROTATE_90, // 90° brush rotation - SPECIAL_ROTATE_180, // 180° brush rotation - SPECIAL_STRETCH, // Stretch brush - SPECIAL_DISTORT, // Distort brush - SPECIAL_OUTLINE, // Outline brush - SPECIAL_NIBBLE, // Nibble brush - SPECIAL_GET_BRUSH_COLORS, // Get colors from brush - SPECIAL_RECOLORIZE_BRUSH, // Recolorize brush - SPECIAL_ROTATE_ANY_ANGLE, // Rotate brush by any angle - 0x100+BUTTON_COLORPICKER, // Pipette - 0x200+BUTTON_COLORPICKER, // Swap fore/back color - 0x100+BUTTON_MAGNIFIER, // Magnifier mode - 0x200+BUTTON_MAGNIFIER, // Zoom factor menu - SPECIAL_ZOOM_IN, // Zoom in - SPECIAL_ZOOM_OUT, // Zoom out - 0x100+BUTTON_BRUSH_EFFECTS, // Brush effects menu - 0x100+BUTTON_TEXT, // Text - 0x100+BUTTON_RESOL, // Resolution menu - 0x200+BUTTON_RESOL, // Safety resolution - 0x100+BUTTON_HELP, // Help & credits - 0x200+BUTTON_HELP, // Statistics - 0x100+BUTTON_PAGE, // Go to spare page - 0x200+BUTTON_PAGE, // Copy to spare page - 0x100+BUTTON_SAVE, // Save as - 0x200+BUTTON_SAVE, // Save - 0x100+BUTTON_LOAD, // Load - 0x200+BUTTON_LOAD, // Re-load - SPECIAL_SAVE_BRUSH, // Save brush - SPECIAL_LOAD_BRUSH, // Load brush - 0x100+BUTTON_SETTINGS, // Settings - 0x100+BUTTON_UNDO, // Undo - 0x200+BUTTON_UNDO, // Redo - 0x100+BUTTON_KILL, // Kill - 0x100+BUTTON_CLEAR, // Clear - 0x200+BUTTON_CLEAR, // Clear with backcolor - 0x100+BUTTON_QUIT, // Quit - 0x100+BUTTON_PALETTE, // Palette menu - 0x200+BUTTON_PALETTE, // Palette menu secondaire - SPECIAL_EXCLUDE_COLORS_MENU, // Exclude colors menu - 0x100+BUTTON_PAL_LEFT, // Scroll palette left - 0x100+BUTTON_PAL_RIGHT, // Scroll palette right - 0x200+BUTTON_PAL_LEFT, // Scroll palette left faster - 0x200+BUTTON_PAL_RIGHT, // Scroll palette right faster - SPECIAL_CENTER_ATTACHMENT, // Center brush attachement - SPECIAL_TOP_LEFT_ATTACHMENT, // Top-left brush attachement - SPECIAL_TOP_RIGHT_ATTACHMENT, // Top-right brush attachement - SPECIAL_BOTTOM_LEFT_ATTACHMENT, // Bottom-left brush attachement - SPECIAL_BOTTOM_RIGHT_ATTACHMENT, // Bottom right brush attachement - SPECIAL_NEXT_FORECOLOR, // Next foreground color - SPECIAL_PREVIOUS_FORECOLOR, // Previous foreground color - SPECIAL_NEXT_BACKCOLOR, // Next background color - SPECIAL_PREVIOUS_BACKCOLOR, // Previous background color - SPECIAL_NEXT_USER_FORECOLOR, // Next user-defined foreground color - SPECIAL_PREVIOUS_USER_FORECOLOR, // Previous user-defined foreground color - SPECIAL_NEXT_USER_BACKCOLOR, // Next user-defined background color - SPECIAL_PREVIOUS_USER_BACKCOLOR, // Previous user-defined background color - SPECIAL_SMALLER_PAINTBRUSH, // Sets paintbrush size: smaller - SPECIAL_BIGGER_PAINTBRUSH, // Sets paintbrush size: bigger - SPECIAL_EFFECTS_OFF, // Turns off all effects - SPECIAL_TRANSPARENCY_1, // Sets transparency level 10% - SPECIAL_TRANSPARENCY_2, // Sets transparency level 20% - SPECIAL_TRANSPARENCY_3, // Sets transparency level 30% - SPECIAL_TRANSPARENCY_4, // Sets transparency level 40% - SPECIAL_TRANSPARENCY_5, // Sets transparency level 50% - SPECIAL_TRANSPARENCY_6, // Sets transparency level 60% - SPECIAL_TRANSPARENCY_7, // Sets transparency level 70% - SPECIAL_TRANSPARENCY_8, // Sets transparency level 80% - SPECIAL_TRANSPARENCY_9, // Sets transparency level 90% - SPECIAL_TRANSPARENCY_0, // Sets transparency level 00% - SPECIAL_ZOOM_1, /**< Sets zoom factor to 1:1 (no magnification) */ - SPECIAL_ZOOM_2, /**< Sets zoom factor to 2:1 */ - SPECIAL_ZOOM_3, /**< Sets zoom factor to 3:1 */ - SPECIAL_ZOOM_4, /**< Sets zoom factor to 4:1 */ - SPECIAL_ZOOM_5, /**< Sets zoom factor to 5:1 */ - SPECIAL_ZOOM_6, /**< Sets zoom factor to 6:1 */ - SPECIAL_ZOOM_8, /**< Sets zoom factor to 8:1 */ - SPECIAL_ZOOM_10, /**< Sets zoom factor to 10:1 */ - SPECIAL_ZOOM_12, /**< Sets zoom factor to 12:1 */ - SPECIAL_ZOOM_14, /**< Sets zoom factor to 14:1 */ - SPECIAL_ZOOM_16, /**< Sets zoom factor to 16:1 */ - SPECIAL_ZOOM_18, /**< Sets zoom factor to 18:1 */ - SPECIAL_ZOOM_20, /**< Sets zoom factor to 20:1 */ - SPECIAL_SHOW_GRID, - SPECIAL_LAYER1_SELECT, - SPECIAL_LAYER1_TOGGLE, - SPECIAL_LAYER2_SELECT, - SPECIAL_LAYER2_TOGGLE, - SPECIAL_LAYER3_SELECT, - SPECIAL_LAYER3_TOGGLE, - SPECIAL_LAYER4_SELECT, - SPECIAL_LAYER4_TOGGLE, - SPECIAL_LAYER5_SELECT, - SPECIAL_LAYER5_TOGGLE, - SPECIAL_LAYER6_SELECT, - SPECIAL_LAYER6_TOGGLE, - SPECIAL_LAYER7_SELECT, - SPECIAL_LAYER7_TOGGLE, - SPECIAL_LAYER8_SELECT, - SPECIAL_LAYER8_TOGGLE, - 0x100+BUTTON_LAYER_ADD, - 0x100+BUTTON_LAYER_REMOVE, - 0x100+BUTTON_LAYER_MERGE, - 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, -}; diff --git a/project/jni/application/grafx2/grafx2/src/hotkeys.h b/project/jni/application/grafx2/grafx2/src/hotkeys.h deleted file mode 100644 index 38006841e..000000000 --- a/project/jni/application/grafx2/grafx2/src/hotkeys.h +++ /dev/null @@ -1,60 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file hotkeys.h -/// Definition of the tables used by the keyboard shortcuts. -/// The actual data is in hotkeys.c -////////////////////////////////////////////////////////////////////////////// - -#if !defined(__VBCC__) - #include -#else - #define bool char -#endif -#include - -#define NB_SHORTCUTS 198 ///< Number of actions that can have a key combination associated to it. - -/*** Types definitions and structs ***/ - -typedef struct -{ - word Number; ///< Identifier for shortcut. This is a number starting from 0, which matches ::T_Config_shortcut_info.Number - char Label[36]; ///< Text to show in the screen where you can edit the shortcut. - char Explanation1[37]; ///< Explanation text (1/3) to show in the screen where you can edit the shortcut. - char Explanation2[37]; ///< Explanation text (2/3) to show in the screen where you can edit the shortcut. - char Explanation3[37]; ///< Explanation text (3/3) to show in the screen where you can edit the shortcut. - bool Suppr; ///< Boolean, true if the shortcut can be removed. - word Key; ///< Primary shortcut. Value is a keycode, see keyboard.h - word Key2; ///< Secondary shortcut. Value is a keycode, see keyboard.h -} T_Key_config; - -/// Table with all the configurable shortcuts, whether they are for a menu button or a special action. -extern T_Key_config ConfigKey[NB_SHORTCUTS]; -/// -/// Translation table from a shortcut index to a shortcut identifier. -/// The value is either: -/// - 0x000 + special shortcut number -/// - 0x100 + button number (left click) -/// - 0x200 + button number (right click) -extern word Ordering[NB_SHORTCUTS]; diff --git a/project/jni/application/grafx2/grafx2/src/init.c b/project/jni/application/grafx2/grafx2/src/init.c deleted file mode 100644 index 8be7e423b..000000000 --- a/project/jni/application/grafx2/grafx2/src/init.c +++ /dev/null @@ -1,2976 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#define _XOPEN_SOURCE 500 - -// Signal handler: I activate it for the two platforms who certainly -// support them. Feel free to check with others. -#if defined(__WIN32__) || defined(__linux__) - #define GRAFX2_CATCHES_SIGNALS -#endif - -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - #include - #include -#endif - -#include -//#include -#include - -#ifndef __VBCC__ - #include -#endif - -#include -#include -#include -#include -#if defined(__WIN32__) - #include // GetLogicalDrives(), GetDriveType(), DRIVE_* -#endif -#ifndef __GP2X__ - #include -#endif -#if defined (__MINT__) - #include -#endif -#ifdef GRAFX2_CATCHES_SIGNALS - #include -#endif - -#include "buttons.h" -#include "const.h" -#include "errors.h" -#include "global.h" -#include "graph.h" -#include "init.h" -#include "io.h" -#include "factory.h" -#include "help.h" -#include "hotkeys.h" -#include "keyboard.h" -#include "loadsave.h" // Image_emergency_backup -#include "misc.h" -#include "mountlist.h" // read_file_system_list -#include "operatio.h" -#include "palette.h" -#include "sdlscreen.h" -#include "setup.h" -#include "struct.h" -#include "transform.h" -#include "windows.h" -#include "layers.h" -#include "special.h" -#include "buttons.h" - -char Gui_loading_error_message[512]; - -// Rechercher la liste et le type des lecteurs de la machine - -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) -void bstrtostr( BSTR in, STRPTR out, TEXT max ); -#endif - -// Fonctions de lecture dans la skin de l'interface graphique -byte GUI_seek_down(SDL_Surface *gui, int *start_x, int *start_y, byte neutral_color,char * section) -{ - byte color; - int y; - y=*start_y; - *start_x=0; - do - { - color=Get_SDL_pixel_8(gui,*start_x,y); - if (color!=neutral_color) - { - *start_y=y; - return 0; - } - y++; - } while (yh); - - sprintf(Gui_loading_error_message, "Error in skin file: Was looking down from %d,%d for a '%s', and reached the end of the image\n", - *start_x, *start_y, section); - return 1; -} - -byte GUI_seek_right(SDL_Surface *gui, int *start_x, int start_y, byte neutral_color, char * section) -{ - byte color; - int x; - x=*start_x; - - do - { - color=Get_SDL_pixel_8(gui,x,start_y); - if (color!=neutral_color) - { - *start_x=x; - return 0; - } - x++; - } while (xw); - - sprintf(Gui_loading_error_message, "Error in skin file: Was looking right from %d,%d for a '%s', and reached the edege of the image\n", - *start_x, start_y, section); - return 1; -} - -byte Read_GUI_block(T_Gui_skin *gfx, SDL_Surface *gui, int start_x, int start_y, void *dest, int width, int height, char * section, int type) -{ - // type: 0 = normal GUI element, only 4 colors allowed - // type: 1 = mouse cursor, 4 colors allowed + transparent - // type: 2 = brush icon or sieve pattern (only gui->Color[3] and gui->Color_trans) - // type: 3 = raw bitmap (splash screen) - - byte * dest_ptr=dest; - int x,y; - byte color; - - // Verification taille - if (start_y+height>=gui->h || start_x+width>=gui->w) - { - sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but it doesn't fit the image.\n", - start_x, start_y, height, width, section); - return 1; - } - - for (y=start_y; yColor[0] && color != gfx->Color[1] && color != gfx->Color[2] && color != gfx->Color[3])) - { - sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the GUI colors (which were detected as %d,%d,%d,%d.\n", - start_x, start_y, height, width, section, x, y, color, gfx->Color[0], gfx->Color[1], gfx->Color[2], gfx->Color[3]); - return 1; - } - if (type==1 && (color != gfx->Color[0] && color != gfx->Color[1] && color != gfx->Color[2] && color != gfx->Color[3] && color != gfx->Color_trans)) - { - sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the mouse colors (which were detected as %d,%d,%d,%d,%d.\n", - start_x, start_y, height, width, section, x, y, color, gfx->Color[0], gfx->Color[1], gfx->Color[2], gfx->Color[3], gfx->Color_trans); - return 1; - } - if (type==2) - { - if (color != gfx->Color[3] && color != gfx->Color_trans) - { - sprintf(Gui_loading_error_message, "Error in skin file: Was looking at %d,%d for a %d*%d object (%s) but at %d,%d a pixel was found with color %d which isn't one of the brush colors (which were detected as %d on %d.\n", - start_x, start_y, height, width, section, x, y, color, gfx->Color[3], gfx->Color_trans); - return 1; - } - // Conversion en 0/1 pour les brosses monochromes internes - color = (color != gfx->Color_trans); - } - *dest_ptr=color; - dest_ptr++; - } - } - return 0; -} - -byte Read_GUI_pattern(T_Gui_skin *gfx, SDL_Surface *gui, int start_x, int start_y, word *dest, char * section) -{ - byte buffer[256]; - int x,y; - - if (Read_GUI_block(gfx, gui, start_x, start_y, buffer, 16, 16, section, 2)) - return 1; - - for (y=0; y<16; y++) - { - *dest=0; - for (x=0; x<16; x++) - { - *dest=*dest | buffer[y*16+x]<Color_trans) - { - found=1; - break; - } - } - if (found) - break; - } - // Locate first non-empty line - found=0; - for (start_y=0;start_y<14;start_y++) - { - for (x=0;x<29;x++) - { - if (cursor_buffer[start_y*29+x]!=gfx->Color_trans) - { - found=1; - break; - } - } - if (found) - break; - } - gfx->Cursor_offset_X[cursor_number]=14-start_x; - gfx->Cursor_offset_Y[cursor_number]=14-start_y; - - for (y=0;yCursor_sprite[cursor_number][y][x]=cursor_buffer[(start_y+y)*29+start_x+x]; -} - -byte Parse_skin(SDL_Surface * gui, T_Gui_skin *gfx) -{ - int i,j; - int cursor_x=0,cursor_y=0; - byte color; - byte neutral_color; // color neutre utilisée pour délimiter les éléments GUI - int char_1=0; // Indices utilisés pour les 4 "fontes" qui composent les - int char_2=0; // grands titres de l'aide. Chaque indice avance dans - int char_3=0; // l'une des fontes dans l'ordre : 1 2 - int char_4=0; // 3 4 - byte mouse_cursor_area[29][29]; - SDL_Palette * SDLPal; - - // Default palette - if (!gui->format || gui->format->BitsPerPixel != 8) - { - sprintf(Gui_loading_error_message, "Not a 8-bit image"); - return 1; - } - SDLPal=gui->format->palette; - if (!SDLPal || SDLPal->ncolors!=256) - { - sprintf(Gui_loading_error_message, "Not a 256-color palette"); - return 1; - } - - // Read the default palette - Get_SDL_Palette(SDLPal, gfx->Default_palette); - - // Carré "noir" - gfx->Color[0] = Get_SDL_pixel_8(gui,cursor_x,cursor_y); - do - { - if (++cursor_x>=gui->w) - { - sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - return 1; - } - color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); - } while(color==gfx->Color[0]); - // Carré "foncé" - gfx->Color[1] = color; - do - { - if (++cursor_x>=gui->w) - { - sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - return 1; - } - color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); - } while(color==gfx->Color[1]); - // Carré "clair" - gfx->Color[2] = color; - do - { - if (++cursor_x>gui->w) - { - sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - return 1; - } - color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); - } while(color==gfx->Color[2]); - // Carré "blanc" - gfx->Color[3] = color; - do - { - if (++cursor_x>=gui->w) - { - sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - return 1; - } - color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); - } while(color==gfx->Color[3]); - // Carré "transparent" - gfx->Color_trans=color; - do - { - if (++cursor_x>=gui->w) - { - sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - return 1; - } - color=Get_SDL_pixel_8(gui,cursor_x,cursor_y); - } while(color==gfx->Color_trans); - // Reste : couleur neutre - neutral_color=color; - - - cursor_x=0; - cursor_y=1; - while ((color=Get_SDL_pixel_8(gui,cursor_x,cursor_y))==gfx->Color[0]) - { - cursor_y++; - if (cursor_y>=gui->h) - { - sprintf(Gui_loading_error_message, "Error in GUI skin file: should start with 5 consecutive squares for black, dark, light, white, transparent, then a neutral color\n"); - return 1; - } - } - - // Menu - 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[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, "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[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[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], EFFECT_SPRITE_WIDTH, EFFECT_SPRITE_HEIGHT, "effect sprite",0)) - return 1; - cursor_x+=EFFECT_SPRITE_WIDTH; - } - cursor_y+=EFFECT_SPRITE_HEIGHT; - - // Layer sprite - for (j=0; j<3; j++) - { - for (i=0; i<16; i++) - { - if (i==0) - { - if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "layer sprite")) - return 1; - } - else - { - if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "layer sprite")) - return 1; - } - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Layer_sprite[j][i], LAYER_SPRITE_WIDTH, LAYER_SPRITE_HEIGHT, "layer sprite",1)) - return 1; - cursor_x+=LAYER_SPRITE_WIDTH; - } - cursor_y+=LAYER_SPRITE_HEIGHT; - } - - - // Mouse cursors - for (i=0; iMenu_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; - - // Drive sprites - for (i=0; iIcon_sprite[i], ICON_SPRITE_WIDTH, ICON_SPRITE_HEIGHT, "sprite drive",1)) - return 1; - cursor_x+=ICON_SPRITE_WIDTH; - } - cursor_y+=ICON_SPRITE_HEIGHT; - - // Logo splash screen - - if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "logo menu")) - return 1; - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, gfx->Logo_grafx2, 231, 56, "logo menu",3)) - return 1; - cursor_y+=56; - - // Trames - for (i=0; iSieve_pattern[i],"sieve pattern")) - return 1; - cursor_x+=16; - } - cursor_y+=16; - - // Help font: Normal - for (i=0; i<256; i++) - { - // Each line holds 32 symbols - if ((i%32)==0) - { - if (i!=0) - cursor_y+=8; - if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (norm)")) - return 1; - } - else - { - if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (norm)")) - return 1; - } - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, &(gfx->Help_font_norm[i][0][0]), 6, 8, "help font (norm)",0)) - return 1; - cursor_x+=6; - } - cursor_y+=8; - - // Help font: Bold - for (i=0; i<256; i++) - { - // Each line holds 32 symbols - if ((i%32)==0) - { - if (i!=0) - cursor_y+=8; - if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (bold)")) - return 1; - } - else - { - if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (bold)")) - return 1; - } - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, &(gfx->Bold_font[i][0][0]), 6, 8, "help font (bold)",0)) - return 1; - cursor_x+=6; - } - cursor_y+=8; - - // Help font: Title - for (i=0; i<256; i++) - { - byte * dest; - // Each line holds 64 symbols - if ((i%64)==0) - { - if (i!=0) - cursor_y+=8; - if (GUI_seek_down(gui, &cursor_x, &cursor_y, neutral_color, "help font (title)")) - return 1; - } - else - { - if (GUI_seek_right(gui, &cursor_x, cursor_y, neutral_color, "help font (title)")) - return 1; - } - - if (i&1) - if (i&64) - dest=&(gfx->Help_font_t4[char_4++][0][0]); - else - dest=&(gfx->Help_font_t2[char_2++][0][0]); - else - if (i&64) - dest=&(gfx->Help_font_t3[char_3++][0][0]); - else - dest=&(gfx->Help_font_t1[char_1++][0][0]); - - if (Read_GUI_block(gfx, gui, cursor_x, cursor_y, dest, 6, 8, "help font (title)",0)) - return 1; - cursor_x+=6; - } - cursor_y+=8; - - // 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_Gradient_array *gradients) -{ - T_Gui_skin * gfx; - char filename[MAX_PATH_CHARACTERS]; - SDL_Surface * gui; - - gfx = (T_Gui_skin *)malloc(sizeof(T_Gui_skin)); - if (gfx == NULL) - { - sprintf(Gui_loading_error_message, "Not enough memory to read skin file\n"); - return NULL; - } - - // Read the "skin" file - strcpy(filename,Data_directory); - strcat(filename,SKINS_SUBDIRECTORY PATH_SEPARATOR); - strcat(filename,skin_file); - - gui=Load_surface(filename, gradients); - if (!gui) - { - sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); - free(gfx); - gfx = NULL; - return NULL; - } - if (Parse_skin(gui, gfx)) - { - SDL_FreeSurface(gui); - free(gfx); - gfx = NULL; - return NULL; - } - SDL_FreeSurface(gui); - return gfx; -} - -// ---- font loading ----- - -byte Parse_font(SDL_Surface * image, byte * font) -{ - int character; - byte color; - int x, y; - int chars_per_line; - - // Check image size - if (image->w % 8) - { - sprintf(Gui_loading_error_message, "Error in font file: Image width is not a multiple of 8.\n"); - return 1; - } - if (image->w * image->h < 8*8*256) - { - sprintf(Gui_loading_error_message, "Error in font file: Image is too small to be a 256-character 8x8 font.\n"); - return 1; - } - chars_per_line = image->w/8; - - for (character=0; character < 256; character++) - { - for (y=0; y<8; y++) - { - for (x=0;x<8; x++) - { - // Pick pixel - color = Get_SDL_pixel_8(image, (character % chars_per_line)*8+x, (character / chars_per_line)*8+y); - if (color > 1) - { - sprintf(Gui_loading_error_message, "Error in font file: Only colors 0 and 1 can be used for the font.\n"); - return 1; - } - // Put it in font. 0 = BG, 1 = FG. - font[character*64 + y*8 + x]=color; - } - } - } - return 0; -} - -byte * Load_font(const char * font_name) -{ - byte * font; - char filename[MAX_PATH_CHARACTERS]; - SDL_Surface * image; - - font = (byte *)malloc(8*8*256); - if (font == NULL) - { - sprintf(Gui_loading_error_message, "Not enough memory to read font file\n"); - return NULL; - } - - // Read the file containing the image - sprintf(filename,"%s" SKINS_SUBDIRECTORY "%s%s", Data_directory, PATH_SEPARATOR, font_name); - - image=Load_surface(filename, NULL); - if (!image) - { - sprintf(Gui_loading_error_message, "Unable to load the skin image (missing? not an image file?)\n"); - free(font); - return NULL; - } - if (Parse_font(image, font)) - { - SDL_FreeSurface(image); - free(font); - return NULL; - } - SDL_FreeSurface(image); - return font; -} - - -// Initialisation des boutons: - - // Action factice: - -void Do_nothing(void) -{} - - // Initialiseur d'un bouton: - -void Init_button(byte btn_number, - word x_offset , word y_offset, - word width , word height, - byte shape, - Func_action left_action, - Func_action right_action, - byte left_instant, - byte right_instant, - Func_action unselect_action, - byte family) -{ - Buttons_Pool[btn_number].X_offset =x_offset; - Buttons_Pool[btn_number].Y_offset =y_offset; - 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; - Buttons_Pool[btn_number].Left_instant =left_instant; - Buttons_Pool[btn_number].Right_instant =right_instant; - Buttons_Pool[btn_number].Unselect_action =unselect_action; - Buttons_Pool[btn_number].Family =family; -} - - - // Initiliseur de tous les boutons: - -void Init_buttons(void) -{ - byte button_index; - - for (button_index=0;button_index= MAX_VIDEO_MODES-1) - { - DEBUG("Error! Attempt to create too many videomodes. Maximum is:", MAX_VIDEO_MODES); - return; - } - if (!fullscreen) - supported = 128; // Prefere, non modifiable - else if (SDL_VideoModeOK(width, height, 8, SDL_FULLSCREEN)) - supported = 1; // supported - else - { - // Non supporte : on ne le prend pas - return; - } - - Video_mode[Nb_video_modes].Width = width; - Video_mode[Nb_video_modes].Height = height; - Video_mode[Nb_video_modes].Mode = mode; - Video_mode[Nb_video_modes].Fullscreen = fullscreen; - Video_mode[Nb_video_modes].State = supported; - Nb_video_modes ++; -} - -// Utilisé pour trier les modes retournés par SDL -int Compare_video_modes(const void *p1, const void *p2) -{ - const T_Video_mode *mode1 = (const T_Video_mode *)p1; - const T_Video_mode *mode2 = (const T_Video_mode *)p2; - - // Tris par largeur - if(mode1->Width - mode2->Width) - return mode1->Width - mode2->Width; - - // Tri par hauteur - return mode1->Height - mode2->Height; -} - - -// Initializes the list of available video modes -void Set_all_video_modes(void) -{ - SDL_Rect** Modes; - Nb_video_modes=0; - - // 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__) || defined(__WIZ__) || defined(__CAANOO__) - // Native GP2X resolution - Set_video_mode( 320,240,0, 1); - #else - // Window mode, with default size of 640x480 - Set_video_mode( 640,480,0, 0); - #endif - - Set_video_mode( 320,200,0, 1); - Set_video_mode( 320,224,0, 1); - #if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) - // For the GP2X, this one is already declared above. - Set_video_mode( 320,240,0, 1); - #endif - Set_video_mode( 320,256,0, 1); - Set_video_mode( 320,270,0, 1); - Set_video_mode( 320,282,0, 1); - Set_video_mode( 320,300,0, 1); - Set_video_mode( 320,360,0, 1); - Set_video_mode( 320,400,0, 1); - Set_video_mode( 320,448,0, 1); - Set_video_mode( 320,480,0, 1); - Set_video_mode( 320,512,0, 1); - Set_video_mode( 320,540,0, 1); - Set_video_mode( 320,564,0, 1); - Set_video_mode( 320,600,0, 1); - Set_video_mode( 360,200,0, 1); - Set_video_mode( 360,224,0, 1); - Set_video_mode( 360,240,0, 1); - Set_video_mode( 360,256,0, 1); - Set_video_mode( 360,270,0, 1); - Set_video_mode( 360,282,0, 1); - Set_video_mode( 360,300,0, 1); - Set_video_mode( 360,360,0, 1); - Set_video_mode( 360,400,0, 1); - Set_video_mode( 360,448,0, 1); - Set_video_mode( 360,480,0, 1); - Set_video_mode( 360,512,0, 1); - Set_video_mode( 360,540,0, 1); - Set_video_mode( 360,564,0, 1); - Set_video_mode( 360,600,0, 1); - Set_video_mode( 400,200,0, 1); - Set_video_mode( 400,224,0, 1); - Set_video_mode( 400,240,0, 1); - Set_video_mode( 400,256,0, 1); - Set_video_mode( 400,270,0, 1); - Set_video_mode( 400,282,0, 1); - Set_video_mode( 400,300,0, 1); - Set_video_mode( 400,360,0, 1); - Set_video_mode( 400,400,0, 1); - Set_video_mode( 400,448,0, 1); - Set_video_mode( 400,480,0, 1); - Set_video_mode( 400,512,0, 1); - Set_video_mode( 400,540,0, 1); - Set_video_mode( 400,564,0, 1); - Set_video_mode( 400,600,0, 1); - Set_video_mode( 640,224,0, 1); - Set_video_mode( 640,240,0, 1); - Set_video_mode( 640,256,0, 1); - Set_video_mode( 640,270,0, 1); - Set_video_mode( 640,300,0, 1); - Set_video_mode( 640,350,0, 1); - Set_video_mode( 640,400,0, 1); - Set_video_mode( 640,448,0, 1); - Set_video_mode( 640,480,0, 1); - Set_video_mode( 640,512,0, 1); - Set_video_mode( 640,540,0, 1); - Set_video_mode( 640,564,0, 1); - Set_video_mode( 640,600,0, 1); - Set_video_mode( 800,600,0, 1); - Set_video_mode(1024,768,0, 1); - - Modes = SDL_ListModes(NULL, SDL_FULLSCREEN); - if ((Modes != (SDL_Rect**)0) && (Modes!=(SDL_Rect**)-1)) - { - int index; - for (index=0; Modes[index]; index++) - { - int index2; -#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 - index2=1; -#endif - for (/**/; index2 < Nb_video_modes; index2++) - if (Modes[index]->w == Video_mode[index2].Width && - Modes[index]->h == Video_mode[index2].Height) - { - // Was already in the hard-coded list: ok, don't add. - break; - } - if (index2 >= Nb_video_modes && Modes[index]->w>=320 && Modes[index]->h>=200) - { - // New mode to add to the list - Set_video_mode(Modes[index]->w,Modes[index]->h,0, 1); - } - } - // Sort the modes : those found by SDL were listed at the end. - // Note that we voluntarily omit the first entry: the default mode. - qsort(&Video_mode[1], Nb_video_modes - 1, sizeof(T_Video_mode), Compare_video_modes); - } -} - -//--------------------------------------------------------------------------- - -int Load_CFG(int reload_all) -{ - FILE* Handle; - char filename[MAX_PATH_CHARACTERS]; - long file_size; - int index,index2; - T_Config_header cfg_header; - T_Config_chunk Chunk; - T_Config_shortcut_info cfg_shortcut_info; - T_Config_video_mode cfg_video_mode; - int key_conversion = 0; - - strcpy(filename,Config_directory); - strcat(filename,"gfx2.cfg"); - - file_size=File_length(filename); - - if ((Handle=fopen(filename,"rb"))==NULL) - return ERROR_CFG_MISSING; - - if ( (file_size<7) - || (!Read_bytes(Handle, &cfg_header.Signature, 3)) - || memcmp(cfg_header.Signature,"CFG",3) - || (!Read_byte(Handle, &cfg_header.Version1)) - || (!Read_byte(Handle, &cfg_header.Version2)) - || (!Read_byte(Handle, &cfg_header.Beta1)) - || (!Read_byte(Handle, &cfg_header.Beta2)) ) - goto Erreur_lecture_config; - - // Version DOS de Robinson et X-Man - if ( (cfg_header.Version1== 2) - && (cfg_header.Version2== 0) - && (cfg_header.Beta1== 96)) - { - // Les touches (scancodes) sont à convertir) - key_conversion = 1; - } - // Version SDL jusqu'a 98% - else if ( (cfg_header.Version1== 2) - && (cfg_header.Version2== 0) - && (cfg_header.Beta1== 97)) - { - // Les touches 00FF (pas de touche) sont a comprendre comme 0x0000 - key_conversion = 2; - } - // Version SDL - else if ( (cfg_header.Version1!=VERSION1) - || (cfg_header.Version2!=VERSION2) - || (cfg_header.Beta1!=BETA1) - || (cfg_header.Beta2!=BETA2) ) - goto Erreur_config_ancienne; - - // - Lecture des infos contenues dans le fichier de config - - while (Read_byte(Handle, &Chunk.Number)) - { - Read_word_le(Handle, &Chunk.Size); - switch (Chunk.Number) - { - case CHUNK_KEYS: // Touches - if (reload_all) - { - 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) || - !Read_word_le(Handle, &cfg_shortcut_info.Key2) ) - goto Erreur_lecture_config; - else - { - if (key_conversion==1) - { - cfg_shortcut_info.Key = Key_for_scancode(cfg_shortcut_info.Key); - } - else if (key_conversion==2) - { - if (cfg_shortcut_info.Key == 0x00FF) - cfg_shortcut_info.Key = 0x0000; - if (cfg_shortcut_info.Key2 == 0x00FF) - cfg_shortcut_info.Key2 = 0x0000; - } - - for (index2=0; - ((index2>8) - { - case 0 : - Config_Key[Ordering[index2]&0xFF][0]=cfg_shortcut_info.Key; - Config_Key[Ordering[index2]&0xFF][1]=cfg_shortcut_info.Key2; - break; - case 1 : - Buttons_Pool[Ordering[index2]&0xFF].Left_shortcut[0] = cfg_shortcut_info.Key; - Buttons_Pool[Ordering[index2]&0xFF].Left_shortcut[1] = cfg_shortcut_info.Key2; - break; - case 2 : - Buttons_Pool[Ordering[index2]&0xFF].Right_shortcut[0] = cfg_shortcut_info.Key; - Buttons_Pool[Ordering[index2]&0xFF].Right_shortcut[1] = cfg_shortcut_info.Key2; - break; - } - } - else - goto Erreur_lecture_config; - } - } - } - else - { - if (fseek(Handle,Chunk.Size,SEEK_CUR)==-1) - goto Erreur_lecture_config; - } - break; - case CHUNK_VIDEO_MODES: // Modes vidéo - 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__) || defined(__WIZ__) || defined(__CAANOO__) - index2=0; -#else - index2=1; -#endif - for (/**/; index2> (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; - } - } - - if (fclose(Handle)) - return ERROR_CFG_CORRUPTED; - - return 0; - -Erreur_lecture_config: - fclose(Handle); - return ERROR_CFG_CORRUPTED; -Erreur_config_ancienne: - fclose(Handle); - return ERROR_CFG_OLD; -} - - -int Save_CFG(void) -{ - FILE* Handle; - int index; - int index2; - int modes_to_save; - char filename[MAX_PATH_CHARACTERS]; - T_Config_header cfg_header; - T_Config_chunk Chunk; - T_Config_shortcut_info cfg_shortcut_info={0,0,0}; - T_Config_video_mode cfg_video_mode={0,0,0}; - - strcpy(filename,Config_directory); - strcat(filename,CONFIG_FILENAME); - - if ((Handle=fopen(filename,"wb"))==NULL) - return ERROR_SAVING_CFG; - - // Ecriture du header - memcpy(cfg_header.Signature,"CFG",3); - cfg_header.Version1=VERSION1; - cfg_header.Version2=VERSION2; - cfg_header.Beta1 =BETA1; - cfg_header.Beta2 =BETA2; - if (!Write_bytes(Handle, &cfg_header.Signature,3) || - !Write_byte(Handle, cfg_header.Version1) || - !Write_byte(Handle, cfg_header.Version2) || - !Write_byte(Handle, cfg_header.Beta1) || - !Write_byte(Handle, cfg_header.Beta2) ) - goto Erreur_sauvegarde_config; - - // Enregistrement des touches - Chunk.Number=CHUNK_KEYS; - Chunk.Size=NB_SHORTCUTS*6; - - if (!Write_byte(Handle, Chunk.Number) || - !Write_word_le(Handle, Chunk.Size) ) - goto Erreur_sauvegarde_config; - for (index=0; index>8) - { - case 0 : - cfg_shortcut_info.Key =Config_Key[Ordering[index]&0xFF][0]; - cfg_shortcut_info.Key2=Config_Key[Ordering[index]&0xFF][1]; - break; - case 1 : - cfg_shortcut_info.Key =Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[0]; - cfg_shortcut_info.Key2=Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[1]; - break; - case 2 : - cfg_shortcut_info.Key =Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[0]; - cfg_shortcut_info.Key2=Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[1]; - break; - } - if (!Write_word_le(Handle, cfg_shortcut_info.Number) || - !Write_word_le(Handle, cfg_shortcut_info.Key) || - !Write_word_le(Handle, cfg_shortcut_info.Key2) ) - goto Erreur_sauvegarde_config; - } - - // D'abord compter les modes pour lesquels l'utilisateur a mis une préférence - modes_to_save=0; -#if defined(__GP2X__) || defined (__WIZ__) || defined (__CAANOO__) - index = 0; -#else - index = 1; -#endif - for (/**/; 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; - - return 0; - -Erreur_sauvegarde_config: - fclose(Handle); - return ERROR_SAVING_CFG; -} - -// (Ré)assigne toutes les valeurs de configuration par défaut -void Set_config_defaults(void) -{ - int index, index2; - - // Keyboard shortcuts - for (index=0; index>8) - { - case 0 : - Config_Key[Ordering[index]&0xFF][0]=ConfigKey[index].Key; - Config_Key[Ordering[index]&0xFF][1]=ConfigKey[index].Key2; - break; - case 1 : - Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[0] = ConfigKey[index].Key; - Buttons_Pool[Ordering[index]&0xFF].Left_shortcut[1] = ConfigKey[index].Key2; - break; - case 2 : - Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[0] = ConfigKey[index].Key; - Buttons_Pool[Ordering[index]&0xFF].Right_shortcut[1] = ConfigKey[index].Key2; - break; - } - } - // Shade - Shade_current=0; - for (index=0; index<8; index++) - { - Shade_list[index].Step=1; - Shade_list[index].Mode=0; - for (index2=0; index2<512; index2++) - Shade_list[index].List[index2]=256; - } - // Shade par défaut pour la palette standard - for (index=0; index<7; index++) - for (index2=0; index2<16; index2++) - Shade_list[0].List[index*17+index2]=index*16+index2+16; - - Shade_list_to_lookup_tables(Shade_list[Shade_current].List, - Shade_list[Shade_current].Step, - Shade_list[Shade_current].Mode, - Shade_table_left,Shade_table_right); - - // Mask - for (index=0; index<256; index++) - Mask_table[index]=0; - - // Stencil - for (index=0; index<256; index++) - Stencil[index]=1; - - // Smooth - Smooth_matrix[0][0]=1; - Smooth_matrix[0][1]=2; - Smooth_matrix[0][2]=1; - Smooth_matrix[1][0]=2; - Smooth_matrix[1][1]=4; - Smooth_matrix[1][2]=2; - Smooth_matrix[2][0]=1; - Smooth_matrix[2][1]=2; - Smooth_matrix[2][2]=1; - - // Exclude colors - for (index=0; index<256; index++) - Exclude_color[index]=0; - - // Quick shade - Quick_shade_step=1; - Quick_shade_loop=0; - - // Grid - Snap_width=Snap_height=8; - Snap_offset_X=Snap_offset_Y=0; - -} - -#ifdef GRAFX2_CATCHES_SIGNALS - -#if defined(__WIN32__) - #define SIGHANDLER_T __p_sig_fn_t -#elif defined(__macosx__) - typedef void (*sig_t) (int); - #define SIGHANDLER_T sig_t -#else - #define SIGHANDLER_T __sighandler_t -#endif - -// Memorize the signal handlers of SDL -SIGHANDLER_T Handler_TERM=SIG_DFL; -SIGHANDLER_T Handler_INT=SIG_DFL; -SIGHANDLER_T Handler_ABRT=SIG_DFL; -SIGHANDLER_T Handler_SEGV=SIG_DFL; -SIGHANDLER_T Handler_FPE=SIG_DFL; - -void Sig_handler(int sig) -{ - // Restore default behaviour - signal(SIGTERM, Handler_TERM); - signal(SIGINT, Handler_INT); - signal(SIGABRT, Handler_ABRT); - signal(SIGSEGV, Handler_SEGV); - signal(SIGFPE, Handler_FPE); - - switch(sig) - { - case SIGTERM: - case SIGINT: - case SIGABRT: - case SIGSEGV: - Image_emergency_backup(); - default: - break; - } -} -#endif - -void Init_sighandler(void) -{ -#ifdef GRAFX2_CATCHES_SIGNALS - Handler_TERM=signal(SIGTERM,Sig_handler); - Handler_INT =signal(SIGINT,Sig_handler); - Handler_ABRT=signal(SIGABRT,Sig_handler); - Handler_SEGV=signal(SIGSEGV,Sig_handler); - Handler_FPE =signal(SIGFPE,Sig_handler); -#endif -} - -void Init_brush_container(void) -{ - int i; - - for (i=0; iDefault_palette[gfx->Color[0]]; - //Config.Fav_menu_colors[1] = gfx->Default_palette[gfx->Color[1]]; - //Config.Fav_menu_colors[2] = gfx->Default_palette[gfx->Color[2]]; - //Config.Fav_menu_colors[3] = gfx->Default_palette[gfx->Color[3]]; - - // Reassign GUI color indices - MC_Black = gfx->Color[0]; - MC_Dark = gfx->Color[1]; - MC_Light = gfx->Color[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 - 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]); - } -} - -/// -/// Based on which toolbars are visible, updates their offsets and -/// computes ::Menu_height and ::Menu_Y -void Compute_menu_offsets(void) -{ - int i; - int offset; - - // Recompute all offsets - offset=0; - Menu_height=0; - for (i = MENUBAR_COUNT-1; i >=0; i--) - { - Menu_bars[i].Top = offset; - if(Menu_bars[i].Visible) - { - offset += Menu_bars[i].Height; - Menu_height += Menu_bars[i].Height; - } - } - // Update global menu coordinates - 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/project/jni/application/grafx2/grafx2/src/init.h b/project/jni/application/grafx2/grafx2/src/init.h deleted file mode 100644 index 3f64ae7a5..000000000 --- a/project/jni/application/grafx2/grafx2/src/init.h +++ /dev/null @@ -1,56 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file init.h -/// Initialization (and some de-initialization) functions. -////////////////////////////////////////////////////////////////////////////// - -T_Gui_skin *Load_graphics(const char * skin_file, T_Gradient_array *gradients); -void Set_current_skin(const char *skinfile, T_Gui_skin *gfx); -void Init_buttons(void); -void Init_operations(void); -void Init_brush_container(void); -int Load_CFG(int reload_all); -int Save_CFG(void); -void Set_all_video_modes(void); -void Set_config_defaults(void); -void Init_sighandler(void); -void Init_paintbrushes(void); - -/// Set application icon(s) -void Define_icon(void); - -extern char Gui_loading_error_message[512]; - -/// -/// Loads a 8x8 monochrome font, the kind used in all menus and screens. -/// This function allocates the memory, and returns a pointer to it when -/// successful. -/// If an error is encountered, it frees what needs it, prints an error message -/// in ::Gui_loading_error_message, and returns NULL. -byte * Load_font(const char * font_name); - -/// -/// Based on which toolbars are visible, updates their offsets and -/// computes ::Menu_height and ::Menu_Y -void Compute_menu_offsets(void); - diff --git a/project/jni/application/grafx2/grafx2/src/input.c b/project/jni/application/grafx2/grafx2/src/input.c deleted file mode 100644 index d9e5273d0..000000000 --- a/project/jni/application/grafx2/grafx2/src/input.c +++ /dev/null @@ -1,1103 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include - -#ifdef __WIN32__ - #include - #include -#endif - -#include "global.h" -#include "keyboard.h" -#include "sdlscreen.h" -#include "windows.h" -#include "errors.h" -#include "misc.h" -#include "buttons.h" -#include "input.h" -#include "loadsave.h" - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -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) - -int Input_sticky_control = 0; -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; -byte Directional_down_right; -byte Directional_down; -byte Directional_down_left; -byte Directional_left; -byte Directional_up_left; -byte Directional_click; - -// 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; -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. - -// 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) - return 0; - - if (function & 0x100) - { - if (Buttons_Pool[function&0xFF].Left_shortcut[0]==key) - return 1; - if (Buttons_Pool[function&0xFF].Left_shortcut[1]==key) - return 1; - return 0; - } - if (function & 0x200) - { - if (Buttons_Pool[function&0xFF].Right_shortcut[0]==key) - return 1; - if (Buttons_Pool[function&0xFF].Right_shortcut[1]==key) - return 1; - return 0; - } - if(key == Config_Key[function][0]) - return 1; - if(key == Config_Key[function][1]) - return 1; - return 0; -} - -// Called each time there is a cursor move, either triggered by mouse or keyboard shortcuts -int Move_cursor_with_constraints() -{ - int feedback=0; - int mouse_blocked=0; ///< Boolean, Set to true if mouse movement was clipped. - - - // Clip mouse to the editing area. There can be a border when using big - // pixels, if the SDL screen dimensions are not factors of the pixel size. - if (Input_new_mouse_Y>=Screen_height) - { - Input_new_mouse_Y=Screen_height-1; - mouse_blocked=1; - } - if (Input_new_mouse_X>=Screen_width) - { - Input_new_mouse_X=Screen_width-1; - mouse_blocked=1; - } - //Gestion "avancée" du curseur: interdire la descente du curseur dans le - //menu lorsqu'on est en train de travailler dans l'image - if (Operation_stack_size != 0) - { - - - //Si le curseur ne se trouve plus dans l'image - if(Menu_Y<=Input_new_mouse_Y) - { - //On bloque le curseur en fin d'image - mouse_blocked=1; - Input_new_mouse_Y=Menu_Y-1; //La ligne !!au-dessus!! du menu - } - - if(Main_magnifier_mode) - { - if(Operation_in_magnifier==0) - { - if(Input_new_mouse_X>=Main_separator_position) - { - mouse_blocked=1; - Input_new_mouse_X=Main_separator_position-1; - } - } - else - { - if(Input_new_mouse_X Config.Mouse_merge_movement - && !Operation[Current_operation][Mouse_K_unique] - [Operation_stack_size].Fast_mouse) - feedback=1; - } - if (mouse_blocked) - Set_mouse_position(); - return feedback; -} - -// WM events management - -void Handle_window_resize(SDL_ResizeEvent event) -{ - Resize_width = event.w; - Resize_height = event.h; -} - -void Handle_window_exit(__attribute__((unused)) SDL_QuitEvent event) -{ - Quit_is_required = 1; -} - -// Mouse events management - -int Handle_mouse_move(SDL_MouseMotionEvent event) -{ - Input_new_mouse_X = event.x/Pixel_width; - Input_new_mouse_Y = event.y/Pixel_height; - - return Move_cursor_with_constraints(); -} - -int Handle_mouse_click(SDL_MouseButtonEvent event) -{ - switch(event.button) - { - case SDL_BUTTON_LEFT: - if (Button_inverter) - Input_new_mouse_K |= 2; - else - Input_new_mouse_K |= 1; - break; - break; - - case SDL_BUTTON_RIGHT: - if (Button_inverter) - Input_new_mouse_K |= 1; - else - Input_new_mouse_K |= 2; - break; - break; - - case SDL_BUTTON_MIDDLE: - Key = KEY_MOUSEMIDDLE|Key_modifiers(SDL_GetModState()); - // TODO: repeat system maybe? - return 0; - - case SDL_BUTTON_WHEELUP: - Key = KEY_MOUSEWHEELUP|Key_modifiers(SDL_GetModState()); - return 0; - - case SDL_BUTTON_WHEELDOWN: - Key = KEY_MOUSEWHEELDOWN|Key_modifiers(SDL_GetModState()); - return 0; - default: - return 0; - } - return Move_cursor_with_constraints(); -} - -int Handle_mouse_release(SDL_MouseButtonEvent event) -{ - switch(event.button) - { - case SDL_BUTTON_LEFT: - if (Button_inverter) - Input_new_mouse_K &= ~2; - else - Input_new_mouse_K &= ~1; - break; - - case SDL_BUTTON_RIGHT: - if (Button_inverter) - Input_new_mouse_K &= ~1; - else - Input_new_mouse_K &= ~2; - break; - } - - return Move_cursor_with_constraints(); -} - -// Keyboard management - -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_emulated_up=1; - return 0; - } - else if(Is_shortcut(Key,SPECIAL_MOUSE_DOWN)) - { - Directional_emulated_down=1; - return 0; - } - else if(Is_shortcut(Key,SPECIAL_MOUSE_LEFT)) - { - Directional_emulated_left=1; - return 0; - } - else if(Is_shortcut(Key,SPECIAL_MOUSE_RIGHT)) - { - Directional_emulated_right=1; - return 0; - } - else if(Is_shortcut(Key,SPECIAL_CLICK_LEFT) && Keyboard_click_allowed > 0) - { - Input_new_mouse_K=1; - Directional_click=1; - return Move_cursor_with_constraints(); - } - else if(Is_shortcut(Key,SPECIAL_CLICK_RIGHT) && Keyboard_click_allowed > 0) - { - Input_new_mouse_K=2; - Directional_click=2; - return Move_cursor_with_constraints(); - } - - return 0; -} - -int Release_control(int key_code, int modifier) -{ - int need_feedback = 0; - - if (modifier == MOD_SHIFT) - { - // Disable "snap axis" mode - Snap_axis = 0; - need_feedback = 1; - } - if (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_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_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_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_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)) - { - if (Directional_click & 1) - { - Directional_click &= ~1; - Input_new_mouse_K &= ~1; - return Move_cursor_with_constraints() || need_feedback; - } - } - if((key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][0]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][0]&modifier) || - (key_code && key_code == (Config_Key[SPECIAL_CLICK_RIGHT][1]&0x0FFF)) || (Config_Key[SPECIAL_CLICK_RIGHT][1]&modifier)) - { - if (Directional_click & 2) - { - Directional_click &= ~2; - Input_new_mouse_K &= ~2; - return Move_cursor_with_constraints() || need_feedback; - } - } - - // Other keys don't need to be released : they are handled as "events" and procesed only once. - // These clicks are apart because they need to be continuous (ie move while key pressed) - // We are relying on "hardware" keyrepeat to achieve that. - return need_feedback; -} - - -int Handle_key_release(SDL_KeyboardEvent event) -{ - int modifier; - int released_key = Keysym_to_keycode(event.keysym) & 0x0FFF; - - 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; - } - return Release_control(released_key, modifier); -} - - -// Joystick management - -int Handle_joystick_press(SDL_JoyButtonEvent event) -{ - if (event.button == Joybutton_shift) - { - SDL_SetModState(SDL_GetModState() | KMOD_SHIFT); - return 0; - } - 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 = Button_inverter ? 2 : 1; - return Move_cursor_with_constraints(); - } - if (event.button == Joybutton_right_click) - { - Input_new_mouse_K = Button_inverter ? 1 : 2; - return Move_cursor_with_constraints(); - } - switch(event.button) - { - #ifdef JOY_BUTTON_UP - case JOY_BUTTON_UP: - Directional_up=1; - break; - #endif - #ifdef JOY_BUTTON_UPRIGHT - case JOY_BUTTON_UPRIGHT: - Directional_up_right=1; - break; - #endif - #ifdef JOY_BUTTON_RIGHT - case JOY_BUTTON_RIGHT: - Directional_right=1; - break; - #endif - #ifdef JOY_BUTTON_DOWNRIGHT - case JOY_BUTTON_DOWNRIGHT: - Directional_down_right=1; - break; - #endif - #ifdef JOY_BUTTON_DOWN - case JOY_BUTTON_DOWN: - Directional_down=1; - break; - #endif - #ifdef JOY_BUTTON_DOWNLEFT - case JOY_BUTTON_DOWNLEFT: - Directional_down_left=1; - break; - #endif - #ifdef JOY_BUTTON_LEFT - case JOY_BUTTON_LEFT: - Directional_left=1; - break; - #endif - #ifdef JOY_BUTTON_UPLEFT - case JOY_BUTTON_UPLEFT: - Directional_up_left=1; - break; - #endif - - default: - break; - } - - Key = (KEY_JOYBUTTON+event.button)|Key_modifiers(SDL_GetModState()); - // TODO: systeme de répétition - - return Move_cursor_with_constraints(); -} - -int Handle_joystick_release(SDL_JoyButtonEvent event) -{ - if (event.button == Joybutton_shift) - { - SDL_SetModState(SDL_GetModState() & ~KMOD_SHIFT); - return Release_control(0,MOD_SHIFT); - } - if (event.button == Joybutton_control) - { - SDL_SetModState(SDL_GetModState() & ~KMOD_CTRL); - return Release_control(0,MOD_CTRL); - } - if (event.button == Joybutton_alt) - { - SDL_SetModState(SDL_GetModState() & ~(KMOD_ALT|KMOD_META)); - return Release_control(0,MOD_ALT); - } - if (event.button == Joybutton_left_click) - { - Input_new_mouse_K &= ~1; - return Move_cursor_with_constraints(); - } - if (event.button == Joybutton_right_click) - { - Input_new_mouse_K &= ~2; - return Move_cursor_with_constraints(); - } - - switch(event.button) - { - #ifdef JOY_BUTTON_UP - case JOY_BUTTON_UP: - Directional_up=1; - break; - #endif - #ifdef JOY_BUTTON_UPRIGHT - case JOY_BUTTON_UPRIGHT: - Directional_up_right=1; - break; - #endif - #ifdef JOY_BUTTON_RIGHT - case JOY_BUTTON_RIGHT: - Directional_right=1; - break; - #endif - #ifdef JOY_BUTTON_DOWNRIGHT - case JOY_BUTTON_DOWNRIGHT: - Directional_down_right=1; - break; - #endif - #ifdef JOY_BUTTON_DOWN - case JOY_BUTTON_DOWN: - Directional_down=1; - break; - #endif - #ifdef JOY_BUTTON_DOWNLEFT - case JOY_BUTTON_DOWNLEFT: - Directional_down_left=1; - break; - #endif - #ifdef JOY_BUTTON_LEFT - case JOY_BUTTON_LEFT: - Directional_left=1; - break; - #endif - #ifdef JOY_BUTTON_UPLEFT - case JOY_BUTTON_UPLEFT: - Directional_up_left=1; - break; - #endif - - default: - break; - } - return Move_cursor_with_constraints(); -} - -void Handle_joystick_movement(SDL_JoyAxisEvent event) -{ - if (event.axis==JOYSTICK_AXIS_X) - { - Directional_right=Directional_left=0; - if (event.value<-JOYSTICK_THRESHOLD) - { - Directional_left=1; - } - else if (event.value>JOYSTICK_THRESHOLD) - Directional_right=1; - } - else if (event.axis==JOYSTICK_AXIS_Y) - { - Directional_up=Directional_down=0; - if (event.value<-JOYSTICK_THRESHOLD) - { - Directional_up=1; - } - else if (event.value>JOYSTICK_THRESHOLD) - Directional_down=1; - } -} - -// Attempts to move the mouse cursor by the given deltas (may be more than 1 pixel at a time) -int Cursor_displace(short delta_x, short delta_y) -{ - short x=Input_new_mouse_X; - short y=Input_new_mouse_Y; - - if(Main_magnifier_mode && Input_new_mouse_Y < Menu_Y && Input_new_mouse_X > Main_separator_position) - { - // Cursor in zoomed area - - if (delta_x<0) - Input_new_mouse_X = Max(Main_separator_position, x-Main_magnifier_factor); - else if (delta_x>0) - Input_new_mouse_X = Min(Screen_width-1, x+Main_magnifier_factor); - if (delta_y<0) - Input_new_mouse_Y = Max(0, y-Main_magnifier_factor); - else if (delta_y>0) - Input_new_mouse_Y = Min(Screen_height-1, y+Main_magnifier_factor); - } - else - { - if (delta_x<0) - Input_new_mouse_X = Max(0, x+delta_x); - else if (delta_x>0) - Input_new_mouse_X = Min(Screen_width-1, x+delta_x); - if (delta_y<0) - Input_new_mouse_Y = Max(0, y+delta_y); - else if (delta_y>0) - Input_new_mouse_Y = Min(Screen_height-1, y+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_emulated_up|| - Directional_emulated_right||Directional_emulated_down|| - Directional_emulated_left)) - { - Directional_first_move=0; - } - else - { - long time_now; - int step=0; - - time_now=SDL_GetTicks(); - - 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) - { - // Directional controller UP - 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, -step); - } - // Directional controller RIGHT - 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(step,0); - } - // Directional controller DOWN - 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, step); - } - // Directional controller LEFT - 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(-step,0); - } - } - } - // If the cursor was moved since last update, - // it was erased, so we need to redraw it (with the preview brush) - if (Mouse_moved) - { - Compute_paintbrush_coordinates(); - Display_cursor(); - return 1; - } - if (user_feedback_required) - return 1; - - // Nothing significant happened - if (sleep_time) - SDL_Delay(sleep_time); - return 0; -} - -void Adjust_mouse_sensitivity(word fullscreen) -{ - // Deprecated - (void)fullscreen; -} - -void Set_mouse_position(void) -{ - SDL_WarpMouse(Mouse_X*Pixel_width, 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/project/jni/application/grafx2/grafx2/src/input.h b/project/jni/application/grafx2/grafx2/src/input.h deleted file mode 100644 index 9ee0d7e76..000000000 --- a/project/jni/application/grafx2/grafx2/src/input.h +++ /dev/null @@ -1,66 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file input.h -/// Functions for mouse, keyboard and joystick input. -/// Joystick input is used to emulate mouse on platforms that don't have a -/// pointing device, ie: the GP2X. -////////////////////////////////////////////////////////////////////////////// - -/// -/// This is the keyboard/mouse/joystick input polling function. -/// Returns 1 if a significant changed occurred, such as a mouse button pressed -/// or depressed, or a new keypress was in the keyboard buffer. -/// 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(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); - -void Set_mouse_position(void); - -/// -/// This holds the ID of the GUI control that the mouse -/// is manipulating. The input system will reset it to zero -/// when mouse button is released, but it's the engine -/// that will record and retrieve a real control ID. -extern int Input_sticky_control; - -/// Allows locking movement to X or Y axis: 0=normal, 1=lock on next move, 2=locked horizontally, 3=locked vertically. -extern int Snap_axis; -/// For the :Snap_axis mode, sets the origin's point (in image coordinates) -extern int Snap_axis_origin_X; -/// For the :Snap_axis mode, sets the origin's point (in image coordinates) -extern int Snap_axis_origin_Y; - -/// -/// 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/project/jni/application/grafx2/grafx2/src/io.c b/project/jni/application/grafx2/grafx2/src/io.c deleted file mode 100644 index bda37459d..000000000 --- a/project/jni/application/grafx2/grafx2/src/io.c +++ /dev/null @@ -1,498 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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) - - 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 -*/ - -// Fonctions de lecture/ecriture file, gèrent les systèmes big-endian et -// little-endian. - -#define _XOPEN_SOURCE 500 - -#include -#include -#include -#include -#include -#include - -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - #include - #include - #include -#elif defined(__WIN32__) - #include - #include - //#include -#elif defined(__MINT__) - #include - #include - #include -#else - #include -#endif - -#include "struct.h" -#include "io.h" -#include "realpath.h" - -// Lit un octet -// Renvoie -1 si OK, 0 en cas d'erreur -int Read_byte(FILE *file, byte *dest) -{ - return fread(dest, 1, 1, file) == 1; -} -// Ecrit un octet -// Renvoie -1 si OK, 0 en cas d'erreur -int Write_byte(FILE *file, byte b) -{ - return fwrite(&b, 1, 1, file) == 1; -} -// Lit des octets -// Renvoie -1 si OK, 0 en cas d'erreur -int Read_bytes(FILE *file, void *dest, size_t size) -{ - return fread(dest, 1, size, file) == size; -} -// Ecrit des octets -// Renvoie -1 si OK, 0 en cas d'erreur -int Write_bytes(FILE *file, void *src, size_t size) -{ - return fwrite(src, 1, size, file) == size; -} - -// Lit un word (little-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Read_word_le(FILE *file, word *dest) -{ - if (fread(dest, 1, sizeof(word), file) != sizeof(word)) - return 0; - #if SDL_BYTEORDER != SDL_LIL_ENDIAN - *dest = SDL_Swap16(*dest); - #endif - return -1; -} -// Ecrit un word (little-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Write_word_le(FILE *file, word w) -{ - #if SDL_BYTEORDER != SDL_LIL_ENDIAN - w = SDL_Swap16(w); - #endif - return fwrite(&w, 1, sizeof(word), file) == sizeof(word); -} -// Lit un word (big-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Read_word_be(FILE *file, word *dest) -{ - if (fread(dest, 1, sizeof(word), file) != sizeof(word)) - return 0; - #if SDL_BYTEORDER != SDL_BIG_ENDIAN - *dest = SDL_Swap16(*dest); - #endif - return -1; -} -// Ecrit un word (big-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Write_word_be(FILE *file, word w) -{ - #if SDL_BYTEORDER != SDL_BIG_ENDIAN - w = SDL_Swap16(w); - #endif - return fwrite(&w, 1, sizeof(word), file) == sizeof(word); -} -// Lit un dword (little-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Read_dword_le(FILE *file, dword *dest) -{ - if (fread(dest, 1, sizeof(dword), file) != sizeof(dword)) - return 0; - #if SDL_BYTEORDER != SDL_LIL_ENDIAN - *dest = SDL_Swap32(*dest); - #endif - return -1; -} -// Ecrit un dword (little-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Write_dword_le(FILE *file, dword dw) -{ - #if SDL_BYTEORDER != SDL_LIL_ENDIAN - dw = SDL_Swap32(dw); - #endif - return fwrite(&dw, 1, sizeof(dword), file) == sizeof(dword); -} - -// Lit un dword (big-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Read_dword_be(FILE *file, dword *dest) -{ - if (fread(dest, 1, sizeof(dword), file) != sizeof(dword)) - return 0; - #if SDL_BYTEORDER != SDL_BIG_ENDIAN - *dest = SDL_Swap32(*dest); - #endif - return -1; -} -// Ecrit un dword (big-endian) -// Renvoie -1 si OK, 0 en cas d'erreur -int Write_dword_be(FILE *file, dword dw) -{ - #if SDL_BYTEORDER != SDL_BIG_ENDIAN - dw = SDL_Swap32(dw); - #endif - return fwrite(&dw, 1, sizeof(dword), file) == sizeof(dword); -} - -// Détermine la position du dernier '/' ou '\\' dans une chaine, -// typiquement pour séparer le nom de file d'un chemin. -// Attention, sous Windows, il faut s'attendre aux deux car -// par exemple un programme lancé sous GDB aura comme argv[0]: -// d:\Data\C\GFX2\grafx2/grafx2.exe -char * Find_last_slash(const char * str) -{ - const char * position = NULL; - for (; *str != '\0'; str++) - if (*str == PATH_SEPARATOR[0] -#ifdef __WIN32__ - || *str == '/' -#endif - ) - position = str; - return (char *)position; -} -// Récupère la partie "nom de file seul" d'un chemin -void Extract_filename(char *dest, const char *source) -{ - const char * position = Find_last_slash(source); - - if (position) - strcpy(dest,position+1); - else - strcpy(dest,source); -} -// Récupère la partie "répertoire+/" d'un chemin. -void Extract_path(char *dest, const char *source) -{ - char * position=NULL; - - Realpath(source,dest); - position = Find_last_slash(dest); - if (position) - *(position+1) = '\0'; - else - strcat(dest, PATH_SEPARATOR); -} - -/// -/// Appends a file or directory name to an existing directory name. -/// As a special case, when the new item is equal to PARENT_DIR, this -/// will remove the rightmost directory name. -/// reverse_path is optional, if it's non-null, the function will -/// write there : -/// - if filename is ".." : The name of eliminated directory/file -/// - else: ".." -void Append_path(char *path, const char *filename, char *reverse_path) -{ - // Parent - if (!strcmp(filename, PARENT_DIR)) - { - // Going up one directory - long len; - char * slash_pos; - - // Remove trailing slash - len=strlen(path); - if (len && (!strcmp(path+len-1,PATH_SEPARATOR) - #ifdef __WIN32__ - || path[len-1]=='/' - #endif - )) - path[len-1]='\0'; - - slash_pos=Find_last_slash(path); - if (slash_pos) - { - if (reverse_path) - strcpy(reverse_path, slash_pos+1); - *slash_pos='\0'; - } - else - { - if (reverse_path) - strcpy(reverse_path, path); - path[0]='\0'; - } - #if defined(__WIN32__) - // Roots of drives need a pending antislash - if (path[0]!='\0' && path[1]==':' && path[2]=='\0') - { - strcat(path, PATH_SEPARATOR); - } - #endif - } - else - // Sub-directory - { - long len; - // Add trailing slash if needed - len=strlen(path); - if (len && (strcmp(path+len-1,PATH_SEPARATOR) - #ifdef __WIN32__ - && path[len-1]!='/' - #endif - )) - { - strcpy(path+len, PATH_SEPARATOR); - len+=strlen(PATH_SEPARATOR); - } - strcat(path, filename); - - if (reverse_path) - strcpy(reverse_path, PARENT_DIR); - } -} - -int File_exists(char * fname) -// Détermine si un file passé en paramètre existe ou non dans le -// répertoire courant. -{ - struct stat buf; - int result; - - result=stat(fname,&buf); - if (result!=0) - return(errno!=ENOENT); - else - return 1; - -} -int Directory_exists(char * directory) -// Détermine si un répertoire passé en paramètre existe ou non dans le -// répertoire courant. -{ - DIR* entry; // Structure de lecture des éléments - - if (strcmp(directory,PARENT_DIR)==0) - return 1; - else - { - // On va chercher si le répertoire existe à l'aide d'un Opendir. S'il - // renvoie NULL c'est que le répertoire n'est pas accessible... - - entry=opendir(directory); - if (entry==NULL) - return 0; - else - { - closedir(entry); - return 1; - } - } -} - -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) || defined(__MINT__) - #define FILE_IS_HIDDEN_ATTRIBUTE __attribute__((unused)) -#else - #define FILE_IS_HIDDEN_ATTRIBUTE -#endif -/// Check if a file or directory is hidden. -int File_is_hidden(FILE_IS_HIDDEN_ATTRIBUTE const char *fname, const char *full_name) -{ -#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) || defined(__MINT__) - // False (unable to determine, or irrrelevent for platform) - return 0; -#elif defined(__WIN32__) - unsigned long att; - if (full_name!=NULL) - att = GetFileAttributesA(full_name); - else - att = GetFileAttributesA(fname); - if (att==INVALID_FILE_ATTRIBUTES) - return 0; - return (att&FILE_ATTRIBUTE_HIDDEN)?1:0; -#else - return fname[0]=='.'; -#endif - - -} -// Taille de fichier, en octets -int File_length(const char * fname) -{ - struct stat infos_fichier; - if (stat(fname,&infos_fichier)) - return 0; - return infos_fichier.st_size; -} -int File_length_file(FILE * file) -{ - struct stat infos_fichier; - if (fstat(fileno(file),&infos_fichier)) - return 0; - return infos_fichier.st_size; -} - -void For_each_file(const char * directory_name, void Callback(const char *)) -{ - // 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); - if (S_ISREG(Infos_enreg.st_mode)) - { - Callback(full_filename); - } - } - 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(full_filename); - 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), - File_is_hidden(entry->d_name, full_filename)); - } - closedir(current_directory); -} - - -void Get_full_filename(char * output_name, char * file_name, char * directory_name) -{ - strcpy(output_name,directory_name); - if (output_name[0] != '\0') - { - // Append a separator at the end of path, if there isn't one already. - // This handles the case of directory variables which contain one, - // as well as directories like "/" on Unix. - if (output_name[strlen(output_name)-1]!=PATH_SEPARATOR[0]) - strcat(output_name,PATH_SEPARATOR); - } - strcat(output_name,file_name); -} - -/// Lock file used to prevent several instances of grafx2 from harming each others' backups -#ifdef __WIN32__ -HANDLE Lock_file_handle = INVALID_HANDLE_VALUE; -#else -int Lock_file_handle = -1; -#endif - -byte Create_lock_file(const char *file_directory) -{ - #if defined (__amigaos__)||(__AROS__)||(ANDROID) - #warning "Missing code for your platform, please check and correct!" - #else - char lock_filename[MAX_PATH_CHARACTERS]; - - strcpy(lock_filename,file_directory); - strcat(lock_filename,"gfx2.lck"); - - #ifdef __WIN32__ - // Windowzy method for creating a lock file - Lock_file_handle = CreateFile( - lock_filename, - GENERIC_WRITE, - 0, // No sharing - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (Lock_file_handle == INVALID_HANDLE_VALUE) - { - return -1; - } - #else - // Unixy method for lock file - Lock_file_handle = open(lock_filename,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); - if (Lock_file_handle == -1) - { - // Usually write-protected media - return -1; - } - if (lockf(Lock_file_handle, F_TLOCK, 0)==-1) - { - close(Lock_file_handle); - // Usually write-protected media - return -1; - } - #endif - #endif // __amigaos__ or __AROS__ - return 0; -} - -void Release_lock_file(const char *file_directory) -{ - char lock_filename[MAX_PATH_CHARACTERS]; - - #ifdef __WIN32__ - if (Lock_file_handle != INVALID_HANDLE_VALUE) - { - CloseHandle(Lock_file_handle); - } - #else - if (Lock_file_handle != -1) - { - close(Lock_file_handle); - Lock_file_handle = -1; - } - #endif - - // Actual deletion - strcpy(lock_filename,file_directory); - strcat(lock_filename,"gfx2.lck"); - remove(lock_filename); -} diff --git a/project/jni/application/grafx2/grafx2/src/io.h b/project/jni/application/grafx2/grafx2/src/io.h deleted file mode 100644 index 042ef3379..000000000 --- a/project/jni/application/grafx2/grafx2/src/io.h +++ /dev/null @@ -1,125 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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) - - 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 io.h -/// Low-level endian-neutral file operations, and also some filesystem operations. -/// Many of these may seem trivial, but the wrappers eliminate the need for a -/// forest of preprocessor defines in each file. -/// You MUST use the functions in this file instead of: -/// - fread() and fwrite() -/// - stat() -/// - fstat() -/// - opendir() -/// - readdir() -/// - Also, don't assume "/" or "\\", use PATH_SEPARATOR -/// If you don't, you break another platform. -////////////////////////////////////////////////////////////////////////////// - -/// Reads a single byte from an open file. Returns true if OK, false if a file i/o error occurred. -int Read_byte(FILE *file, byte *dest); -/// Writes a single byte to an open file. Returns true if OK, false if a file i/o error occurred. -int Write_byte(FILE *file, byte b); - -/// Reads several bytes from an open file. Returns true if OK, false if a file i/o error occurred. -int Read_bytes(FILE *file, void *dest, size_t size); -/// Writes several bytes to an open file. Returns true if OK, false if a file i/o error occurred. -int Write_bytes(FILE *file, void *dest, size_t size); - -/// Reads a 16-bit Low-Endian word from an open file. Returns true if OK, false if a file i/o error occurred. -int Read_word_le(FILE *file, word *dest); -/// Writes a 16-bit Low-Endian word to an open file. Returns true if OK, false if a file i/o error occurred. -int Write_word_le(FILE *file, word w); -/// Reads a 32-bit Low-Endian dword from an open file. Returns true if OK, false if a file i/o error occurred. -int Read_dword_le(FILE *file, dword *dest); -/// Writes a 32-bit Low-Endian dword to an open file. Returns true if OK, false if a file i/o error occurred. -int Write_dword_le(FILE *file, dword dw); - -/// Reads a 16-bit Big-Endian word from an open file. Returns true if OK, false if a file i/o error occurred. -int Read_word_be(FILE *file, word *dest); -/// Writes a 16-bit Big-Endian word to an open file. Returns true if OK, false if a file i/o error occurred. -int Write_word_be(FILE *file, word w); -/// Reads a 32-bit Big-Endian dword from an open file. Returns true if OK, false if a file i/o error occurred. -int Read_dword_be(FILE *file, dword *dest); -/// Writes a 32-bit Big-Endian dword to an open file. Returns true if OK, false if a file i/o error occurred. -int Write_dword_be(FILE *file, dword dw); - -/// Extracts the filename part from a full file name. -void Extract_filename(char *dest, const char *source); -/// Extracts the directory from a full file name. -void Extract_path(char *dest, const char *source); - -/// Finds the rightmost path separator in a full filename. Used to separate directory from file. -char * Find_last_slash(const char * str); - -#if defined(__WIN32__) - #define PATH_SEPARATOR "\\" -#elif defined(__MINT__) - #define PATH_SEPARATOR "\\" -#else - #define PATH_SEPARATOR "/" -#endif - -/// Size of a file, in bytes. Returns 0 in case of error. -int File_length(const char *fname); - -/// Size of a file, in bytes. Takes an open file as argument, returns 0 in case of error. -int File_length_file(FILE * file); - -/// Returns true if a file passed as a parameter exists in the current directory. -int File_exists(char * fname); - -/// Returns true if a directory passed as a parameter exists in the current directory. -int Directory_exists(char * directory); - -/// Check if a file or directory is hidden. Full name (with directories) is optional. -int File_is_hidden(const char *fname, const char *full_name); - -/// 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. -void Get_full_filename(char * output_name, char * file_name, char * directory_name); - -/// -/// Appends a file or directory name to an existing directory name. -/// As a special case, when the new item is equal to PARENT_DIR, this -/// will remove the rightmost directory name. -/// reverse_path is optional, if it's non-null, the function will -/// write there : -/// - if filename is ".." : The name of eliminated directory/file -/// - else: ".." -void Append_path(char *path, const char *filename, char *reverse_path); - -/// -/// Creates a lock file, to check if an other instance of Grafx2 is running. -/// @return 0 on success (first instance), -1 on failure (others are running) -byte Create_lock_file(const char *file_directory); - -/// -/// Release a lock file created by ::Create_Lock_file -void Release_lock_file(const char *file_directory); - diff --git a/project/jni/application/grafx2/grafx2/src/keyboard.c b/project/jni/application/grafx2/grafx2/src/keyboard.c deleted file mode 100644 index 584d20fb7..000000000 --- a/project/jni/application/grafx2/grafx2/src/keyboard.c +++ /dev/null @@ -1,713 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include -#include "global.h" -#include "keyboard.h" - -// Table de correspondance des scancode de clavier IBM PC AT vers -// les symboles de touches SDL (sym). -// La correspondance est bonne si le clavier est QWERTY US, ou si -// l'utilisateur est sous Windows. -// Dans l'ordre des colonnes: Normal, +Shift, +Control, +Alt -const word Scancode_to_sym[256][4] = -{ -/* 00 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 01 Esc */ { SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE ,SDLK_ESCAPE }, -/* 02 1 ! */ { SDLK_1 ,SDLK_1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 03 2 @ */ { SDLK_2 ,SDLK_2 ,SDLK_2 ,SDLK_UNKNOWN }, -/* 04 3 # */ { SDLK_3 ,SDLK_3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 05 4 $ */ { SDLK_4 ,SDLK_4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 06 5 % */ { SDLK_5 ,SDLK_5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 07 6 ^ */ { SDLK_6 ,SDLK_6 ,SDLK_6 ,SDLK_UNKNOWN }, -/* 08 7 & */ { SDLK_7 ,SDLK_7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 09 8 * */ { SDLK_8 ,SDLK_8 ,SDLK_8 ,SDLK_UNKNOWN }, -/* 0A 9 ( */ { SDLK_9 ,SDLK_9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 0B 0 ) */ { SDLK_0 ,SDLK_0 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 0C - _ */ { SDLK_MINUS ,SDLK_MINUS ,SDLK_MINUS ,SDLK_UNKNOWN }, -/* 0D = + */ { SDLK_EQUALS ,SDLK_EQUALS ,SDLK_EQUALS ,SDLK_UNKNOWN }, -/* 0E BkSpc */ { SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE ,SDLK_BACKSPACE }, -/* 0F Tab */ { SDLK_TAB ,SDLK_TAB ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 10 Q */ { SDLK_q ,SDLK_q ,SDLK_q ,SDLK_q }, -/* 11 W */ { SDLK_w ,SDLK_w ,SDLK_w ,SDLK_w }, -/* 12 E */ { SDLK_e ,SDLK_e ,SDLK_e ,SDLK_e }, -/* 13 R */ { SDLK_r ,SDLK_r ,SDLK_r ,SDLK_r }, -/* 14 T */ { SDLK_t ,SDLK_t ,SDLK_t ,SDLK_t }, -/* 15 Y */ { SDLK_y ,SDLK_y ,SDLK_y ,SDLK_y }, -/* 16 U */ { SDLK_u ,SDLK_u ,SDLK_u ,SDLK_u }, -/* 17 I */ { SDLK_i ,SDLK_i ,SDLK_i ,SDLK_i }, -/* 18 O */ { SDLK_o ,SDLK_o ,SDLK_o ,SDLK_o }, -/* 19 P */ { SDLK_p ,SDLK_p ,SDLK_p ,SDLK_p }, -/* 1A [ */ { SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET ,SDLK_LEFTBRACKET }, -/* 1B ] */ { SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET,SDLK_RIGHTBRACKET}, -/* 1C Retrn */ { SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN ,SDLK_RETURN }, -/* 1D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 1E A */ { SDLK_a ,SDLK_a ,SDLK_a ,SDLK_a }, -/* 1F S */ { SDLK_s ,SDLK_s ,SDLK_s ,SDLK_s }, -/* 20 D */ { SDLK_d ,SDLK_d ,SDLK_d ,SDLK_d }, -/* 21 F */ { SDLK_f ,SDLK_f ,SDLK_f ,SDLK_f }, -/* 22 G */ { SDLK_g ,SDLK_g ,SDLK_g ,SDLK_g }, -/* 23 H */ { SDLK_h ,SDLK_h ,SDLK_h ,SDLK_h }, -/* 24 J */ { SDLK_j ,SDLK_j ,SDLK_j ,SDLK_j }, -/* 25 K */ { SDLK_k ,SDLK_k ,SDLK_k ,SDLK_k }, -/* 26 L */ { SDLK_l ,SDLK_l ,SDLK_l ,SDLK_l }, -/* 27 ; : */ { SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON ,SDLK_SEMICOLON }, -/* 28 ' */ { SDLK_QUOTE ,SDLK_QUOTE ,SDLK_UNKNOWN ,SDLK_QUOTE }, -/* 29 ` ~ */ { SDLK_BACKQUOTE ,SDLK_BACKQUOTE ,SDLK_UNKNOWN ,SDLK_BACKQUOTE }, -/* 2A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 2B \\ */ { SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH ,SDLK_BACKSLASH }, -/* 2C Z */ { SDLK_z ,SDLK_z ,SDLK_z ,SDLK_z }, -/* 2D X */ { SDLK_x ,SDLK_x ,SDLK_x ,SDLK_x }, -/* 2E C */ { SDLK_c ,SDLK_c ,SDLK_c ,SDLK_c }, -/* 2F V */ { SDLK_v ,SDLK_v ,SDLK_v ,SDLK_v }, -/* 30 B */ { SDLK_b ,SDLK_b ,SDLK_b ,SDLK_b }, -/* 31 N */ { SDLK_n ,SDLK_n ,SDLK_n ,SDLK_n }, -/* 32 M */ { SDLK_m ,SDLK_m ,SDLK_m ,SDLK_m }, -/* 33 , < */ { SDLK_COMMA ,SDLK_COMMA ,SDLK_UNKNOWN ,SDLK_COMMA }, -/* 34 . > */ { SDLK_PERIOD ,SDLK_PERIOD ,SDLK_UNKNOWN ,SDLK_PERIOD }, -/* 35 / ? */ { SDLK_SLASH ,SDLK_SLASH ,SDLK_UNKNOWN ,SDLK_SLASH }, -/* 36 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 37 Grey* */ { SDLK_KP_MULTIPLY ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY }, -/* 38 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 39 Space */ { SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE ,SDLK_SPACE }, -/* 3A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3B F1 */ { SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3C F2 */ { SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3D F3 */ { SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3E F4 */ { SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 3F F5 */ { SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 40 F6 */ { SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 41 F7 */ { SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 42 F8 */ { SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 43 F9 */ { SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 44 F10 */ { SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 45 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 46 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 47 Home */ { SDLK_HOME ,SDLK_HOME ,SDLK_UNKNOWN ,SDLK_HOME }, -/* 48 Up */ { SDLK_UP ,SDLK_UP ,SDLK_UNKNOWN ,SDLK_UP }, -/* 49 PgUp */ { SDLK_PAGEUP ,SDLK_PAGEUP ,SDLK_UNKNOWN ,SDLK_PAGEUP }, -/* 4A Grey- */ { SDLK_KP_MINUS ,SDLK_KP_MINUS ,SDLK_UNKNOWN ,SDLK_KP_MINUS }, -/* 4B Left */ { SDLK_LEFT ,SDLK_LEFT ,SDLK_UNKNOWN ,SDLK_LEFT }, -/* 4C Kpad5 */ { SDLK_KP5 ,SDLK_KP5 ,SDLK_UNKNOWN ,SDLK_KP5 }, -/* 4D Right */ { SDLK_RIGHT ,SDLK_RIGHT ,SDLK_UNKNOWN ,SDLK_RIGHT }, -/* 4E Grey+ */ { SDLK_KP_PLUS ,SDLK_KP_PLUS ,SDLK_UNKNOWN ,SDLK_KP_PLUS }, -/* 4F End */ { SDLK_END ,SDLK_END ,SDLK_UNKNOWN ,SDLK_END }, -/* 50 Down */ { SDLK_DOWN ,SDLK_DOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, -/* 51 PgDn */ { SDLK_PAGEDOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN }, -/* 52 Ins */ { SDLK_INSERT ,SDLK_INSERT ,SDLK_UNKNOWN ,SDLK_INSERT }, -/* 53 Del */ { SDLK_DELETE ,SDLK_DELETE ,SDLK_UNKNOWN ,SDLK_DELETE }, -/* 54 ??? */ { SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 55 ??? */ { SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 56 Lft| */ { SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 57 ??? */ { SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 58 ??? */ { SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 59 ??? */ { SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5A ??? */ { SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5B ??? */ { SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5C ??? */ { SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5D ??? */ { SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 5E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 ,SDLK_UNKNOWN }, -/* 5F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 ,SDLK_UNKNOWN }, -/* 60 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 ,SDLK_UNKNOWN }, -/* 61 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 ,SDLK_UNKNOWN }, -/* 62 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 ,SDLK_UNKNOWN }, -/* 63 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 ,SDLK_UNKNOWN }, -/* 64 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 ,SDLK_UNKNOWN }, -/* 65 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 ,SDLK_UNKNOWN }, -/* 66 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 ,SDLK_UNKNOWN }, -/* 67 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 ,SDLK_UNKNOWN }, -/* 68 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F1 }, -/* 69 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F2 }, -/* 6A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F3 }, -/* 6B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F4 }, -/* 6C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F5 }, -/* 6D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F6 }, -/* 6E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F7 }, -/* 6F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F8 }, -/* 70 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F9 }, -/* 71 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F10 }, -/* 72 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 73 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT ,SDLK_UNKNOWN }, -/* 74 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT ,SDLK_UNKNOWN }, -/* 75 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END ,SDLK_UNKNOWN }, -/* 76 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEDOWN ,SDLK_UNKNOWN }, -/* 77 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME ,SDLK_UNKNOWN }, -/* 78 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_1 }, -/* 79 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_2 }, -/* 7A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_3 }, -/* 7B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_4 }, -/* 7C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_5 }, -/* 7D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_6 }, -/* 7E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_7 }, -/* 7F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_8 }, -/* 80 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_9 }, -/* 81 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_0 }, -/* 82 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MINUS }, -/* 83 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_EQUALS }, -/* 84 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP ,SDLK_UNKNOWN }, -/* 85 F11 */ { SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 86 F12 */ { SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 87 ??? */ { SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 88 ??? */ { SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 89 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 ,SDLK_UNKNOWN }, -/* 8A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 ,SDLK_UNKNOWN }, -/* 8B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F11 }, -/* 8C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_F12 }, -/* 8D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP ,SDLK_UNKNOWN }, -/* 8E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MINUS ,SDLK_UNKNOWN }, -/* 8F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP5 ,SDLK_UNKNOWN }, -/* 90 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_PLUS ,SDLK_UNKNOWN }, -/* 91 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN ,SDLK_UNKNOWN }, -/* 92 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT ,SDLK_UNKNOWN }, -/* 93 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE ,SDLK_UNKNOWN }, -/* 94 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB ,SDLK_UNKNOWN }, -/* 95 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE ,SDLK_UNKNOWN }, -/* 96 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_MULTIPLY ,SDLK_UNKNOWN }, -/* 97 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_HOME }, -/* 98 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UP }, -/* 99 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, -/* 9A ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 9B ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LEFT }, -/* 9C ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 9D ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RIGHT }, -/* 9E ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* 9F ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_END }, -/* A0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DOWN }, -/* A1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_PAGEUP }, -/* A2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_INSERT }, -/* A3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_DELETE }, -/* A4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_DIVIDE }, -/* A5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_TAB }, -/* A6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_KP_ENTER }, -/* A7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* A8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* A9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* AF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B6 Win L */ { SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B7 Win R */ { SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B8 Win M */ { SDLK_MENU ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* B9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* BF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C2 ??? */ { SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C3 ??? */ { SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* C9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* CE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER ,SDLK_UNKNOWN }, -/* CF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER ,SDLK_UNKNOWN }, -/* D0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU ,SDLK_UNKNOWN }, -/* D1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* D9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* DA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_LSUPER }, -/* DB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_RSUPER }, -/* DC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_MENU }, -/* DD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* DE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* DF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E0 Enter */ { SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_KP_ENTER ,SDLK_UNKNOWN }, -/* E1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* E9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* ED ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* EF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F0 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F1 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F2 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F3 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F4 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F5 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F6 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F7 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F8 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* F9 ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FA ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FB ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FC ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FD ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FE ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -/* FF ??? */ { SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN ,SDLK_UNKNOWN }, -}; - -// Conversion de l'ancien codage des touches: -// 0x00FF le scancode (maintenant code sym sur 0x0FFF) -// 0x0100 shift (maintenant 0x1000) -// 0x0200 control (maintenant 0x2000) -// 0x0400 alt (maintenant 0x4000) -word Key_for_scancode(word scancode) -{ - if (scancode & 0x0400) - return Scancode_to_sym[scancode & 0xFF][3] | - (scancode & 0x0700) << 4; - else if (scancode & 0x0200) - return Scancode_to_sym[scancode & 0xFF][2] | - (scancode & 0x0700) << 4; - else if (scancode & 0x0100) - return Scancode_to_sym[scancode & 0xFF][1] | - (scancode & 0x0700) << 4; - else - return Scancode_to_sym[scancode & 0xFF][0]; -} - -// Convertit des modificateurs de touches SDL en modificateurs GrafX2 -word Key_modifiers(SDLMod mod) -{ - word modifiers=0; - - if (mod & KMOD_CTRL ) - modifiers|=MOD_CTRL; - if (mod & KMOD_SHIFT ) - modifiers|=MOD_SHIFT; - if (mod & (KMOD_ALT|KMOD_MODE)) - modifiers|=MOD_ALT; - if (mod & (KMOD_META)) - modifiers|=MOD_META; - - return modifiers; -} - -word Keysym_to_keycode(SDL_keysym keysym) -{ - word key_code = 0; - word mod; - - // On ignore shift, alt et control isolés. - if (keysym.sym == SDLK_RSHIFT || keysym.sym == SDLK_LSHIFT || - keysym.sym == SDLK_RCTRL || keysym.sym == SDLK_LCTRL || - keysym.sym == SDLK_RALT || keysym.sym == SDLK_LALT || - keysym.sym == SDLK_RMETA || keysym.sym == SDLK_LMETA || - keysym.sym == SDLK_MODE) // AltGr - return 0; - - // Les touches qui n'ont qu'une valeur unicode (très rares) - // seront codées sur 11 bits, le 12e bit est mis à 1 (0x0800) - if (keysym.sym != 0) - key_code = keysym.sym; - else if (keysym.scancode != 0) - { - key_code = (keysym.scancode & 0x07FF) | 0x0800; - } - - // Normally I should test keysym.mod here, but on windows the implementation - // is buggy: if you release a modifier key, the following keys (when they repeat) - // still name the original modifiers. - mod=Key_modifiers(SDL_GetModState()); - - // SDL_GetModState() seems to get the right up-to-date info. - key_code |= mod; - return key_code; -} - -const char * Key_name(word key) -{ - typedef struct - { - word keysym; - char *Key_name; - } T_key_label; - T_key_label key_labels[] = - { - { SDLK_BACKSPACE , "Backspace" }, - { SDLK_TAB , "Tab" }, - { SDLK_CLEAR , "Clear" }, - { SDLK_RETURN , "Return" }, - { SDLK_PAUSE , "Pause" }, - { SDLK_ESCAPE , "Esc" }, - { SDLK_DELETE , "Del" }, - { SDLK_KP0 , "KP 0" }, - { SDLK_KP1 , "KP 1" }, - { SDLK_KP2 , "KP 2" }, - { SDLK_KP3 , "KP 3" }, - { SDLK_KP4 , "KP 4" }, - { SDLK_KP5 , "KP 5" }, - { SDLK_KP6 , "KP 6" }, - { SDLK_KP7 , "KP 7" }, - { SDLK_KP8 , "KP 8" }, - { SDLK_KP9 , "KP 9" }, - { SDLK_KP_PERIOD , "KP ." }, - { SDLK_KP_DIVIDE , "KP /" }, - { SDLK_KP_MULTIPLY, "KP *" }, - { SDLK_KP_MINUS , "KP -" }, - { SDLK_KP_PLUS , "KP +" }, - { SDLK_KP_ENTER , "KP Enter" }, - { SDLK_KP_EQUALS , "KP =" }, - { SDLK_UP , "Up" }, - { SDLK_DOWN , "Down" }, - { SDLK_RIGHT , "Right" }, - { SDLK_LEFT , "Left" }, - { SDLK_INSERT , "Ins" }, - { SDLK_HOME , "Home" }, - { SDLK_END , "End" }, - { SDLK_PAGEUP , "PgUp" }, - { SDLK_PAGEDOWN , "PgDn" }, - { SDLK_F1 , "F1" }, - { SDLK_F2 , "F2" }, - { SDLK_F3 , "F3" }, - { SDLK_F4 , "F4" }, - { SDLK_F5 , "F5" }, - { SDLK_F6 , "F6" }, - { SDLK_F7 , "F7" }, - { SDLK_F8 , "F8" }, - { SDLK_F9 , "F9" }, - { SDLK_F10 , "F10" }, - { SDLK_F11 , "F11" }, - { SDLK_F12 , "F12" }, - { SDLK_F13 , "F13" }, - { SDLK_F14 , "F14" }, - { SDLK_F15 , "F15" }, - { SDLK_NUMLOCK , "NumLock" }, - { SDLK_CAPSLOCK , "CapsLck" }, - { SDLK_SCROLLOCK , "ScrlLock" }, - { SDLK_RSHIFT , "RShift" }, - { SDLK_LSHIFT , "LShift" }, - { SDLK_RCTRL , "RCtrl" }, - { SDLK_LCTRL , "LCtrl" }, - { SDLK_RALT , "RAlt" }, - { SDLK_LALT , "LAlt" }, - { SDLK_RMETA , "RMeta" }, - { SDLK_LMETA , "LMeta" }, - { SDLK_LSUPER , "LWin" }, - { SDLK_RSUPER , "RWin" }, - { SDLK_MODE , "AltGr" }, - { SDLK_COMPOSE , "Comp" }, - { SDLK_HELP , "Help" }, - { SDLK_PRINT , "Print" }, - { SDLK_SYSREQ , "SysReq" }, - { SDLK_BREAK , "Break" }, - { SDLK_MENU , "Menu" }, - { SDLK_POWER , "Power" }, - { SDLK_EURO , "Euro" }, - { SDLK_UNDO , "Undo" }, - { KEY_MOUSEMIDDLE, "Mouse3" }, - { KEY_MOUSEWHEELUP, "WheelUp" }, - { KEY_MOUSEWHEELDOWN, "WheelDown" } - }; - - int index; - static char buffer[41]; - buffer[0] = '\0'; - - if (key == SDLK_UNKNOWN) - return "None"; - - if (key & MOD_CTRL) - strcat(buffer, "Ctrl+"); - if (key & MOD_ALT) - strcat(buffer, "Alt+"); - if (key & MOD_SHIFT) - strcat(buffer, "Shift+"); - if (key & MOD_META) - strcat(buffer, "\201"); - // Note: Apple's "command" character is not present in the ANSI table, so we - // recycled an ANSI value that doesn't have any displayable character - // associated. - - - key=key & ~(MOD_CTRL|MOD_ALT|MOD_SHIFT); - - // 99 is only a sanity check - if (key>=KEY_JOYBUTTON && key<=KEY_JOYBUTTON+99) - { - - char *button_name; - switch(key-KEY_JOYBUTTON) - { - #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); - - return buffer; - } - - if (key & 0x800) - { - sprintf(buffer+strlen(buffer), "[%d]", key & 0x7FF); - return buffer; - } - key = key & 0x7FF; - // Touches ASCII - if (key>=' ' && key < 127) - { - sprintf(buffer+strlen(buffer), "'%c'", toupper(key)); - return buffer; - } - // Touches 'World' - if (key>=SDLK_WORLD_0 && key <= SDLK_WORLD_95) - { - sprintf(buffer+strlen(buffer), "w%d", key - SDLK_WORLD_0); - return buffer; - } - - // Touches au libellé connu - for (index=0; index < (long)sizeof(key_labels)/(long)sizeof(T_key_label);index++) - { - if (key == key_labels[index].keysym) - { - sprintf(buffer+strlen(buffer), "%s", key_labels[index].Key_name); - return buffer; - } - } - // Autres touches inconnues - sprintf(buffer+strlen(buffer), "0x%X", key & 0x7FF); - return buffer; - -} - -// Obtient le caractère ANSI tapé, à partir d'un keysym. -// (Valeur 32 à 255) -// Renvoie 0 s'il n'y a pas de caractère associé (shift, backspace, etc) -word Keysym_to_ANSI(SDL_keysym keysym) -{ - // This part was removed from the MacOSX port, but I put it back for others - // as on Linux and Windows, it's what allows editing a text line with the keys - // SDLK_LEFT, SDLK_RIGHT, SDLK_HOME, SDLK_END etc. - #if !(defined(__macosx__) || defined(__FreeBSD__)) - if ( keysym.unicode == 0) - { - - switch(keysym.sym) - { - case SDLK_DELETE: - case SDLK_LEFT: - case SDLK_RIGHT: - case SDLK_HOME: - case SDLK_END: - case SDLK_BACKSPACE: - case KEY_ESC: - return keysym.sym; - case SDLK_RETURN: - // Case alt-enter - if (SDL_GetModState() & (KMOD_ALT|KMOD_META)) - return '\n'; - return keysym.sym; - default: - return 0; - } - } - #endif - // - if ( keysym.unicode > 32 && keysym.unicode < 127) - { - return keysym.unicode; // Pas de souci, on est en ASCII standard - } - - // Quelques conversions Unicode-ANSI - switch(keysym.unicode) - { - case 0x8100: - return 'ü'; // ü - case 0x1A20: - return 'é'; // é - case 0x201A: - return 'è'; // è - case 0x9201: - return 'â'; // â - case 0x1E20: - return 'ä'; // ä - case 0x2620: - return 'à'; // à - case 0x2020: - return 'å'; // å - case 0x2120: - return 'ç'; // ç - case 0xC602: - return 'ê'; // ê - case 0x3020: - return 'ë'; // ë - case 0x6001: - return 'è'; // è - case 0x3920: - return 'ï'; // ï - case 0x5201: - return 'î'; // î - case 0x8D00: - return 'ì'; // ì - case 0x1C20: - return 'ô'; // ô - case 0x1D20: - return 'ö'; // ö - case 0x2220: - return 'ò'; // ò - case 0x1320: - return 'û'; // û - case 0x1420: - return 'ù'; // ù - case 0xDC02: - return 'ÿ'; // ÿ - case 0x5301: - return '£'; // £ - case 0xA000: - return 'á'; // á - case 0xA100: - return 'í'; // í - case 0xA200: - return 'ó'; // ó - case 0xA300: - return 'ú'; // ú - case 0xA400: - return 'ñ'; // ñ - case 0xA700: - return 'º'; // º - case 0xC600: - return 'ã'; // ã - } - - // Key entre 127 et 255 - if (keysym.unicode<256) - { -#if defined(__macosx__) || defined(__FreeBSD__) - // fc: Looks like there's a mismatch with delete & backspace - // i don't why SDLK_DELETE was returned instead of SDLK_BACKSPACE - if(keysym.unicode == 127) - { - return(SDLK_BACKSPACE); - } - // We don't make any difference between return & enter in the app context. - if(keysym.unicode == 3) - { - return(SDLK_RETURN); - } -#endif - return keysym.unicode; - } - - // Sinon c'est une touche spéciale, on retourne son scancode - return keysym.sym; -} diff --git a/project/jni/application/grafx2/grafx2/src/keyboard.h b/project/jni/application/grafx2/grafx2/src/keyboard.h deleted file mode 100644 index c2dec3f51..000000000 --- a/project/jni/application/grafx2/grafx2/src/keyboard.h +++ /dev/null @@ -1,77 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file keyboard.h -/// Functions to convert bewteen the SDL key formats and the keycode we use -/// in grafx2. -/// The keycode we're using is generalized to handle mouse and joystick shortcuts -/// as well. The format can be broken down as: -/// - 0x0000 + a number between 0 and SDLK_LAST (about 324) : the SDL "sym" key number. -/// - 0x0000 + SDLK_LAST+1: Mouse middle button. -/// - 0x0000 + SDLK_LAST+2: Mouse wheel up. -/// - 0x0000 + SDLK_LAST+3: Mouse wheel down. -/// - 0x0000 + SDLK_LAST+4+B : Joystick button number "B", starting at B=0. -/// - 0x0800 + a number between 0 and 0x7FF: The scancode key number, for keys which have no "sym", such as keys from multimedia keyboards, and "fn" and "Thinkpad" key for a laptop. -/// Add 0x1000 for the Shift modifier MOD_SHIFT -/// Add 0x2000 for the Control modifier ::MOD_CONTROL -/// Add 0x4000 for the Alt modifier ::MOD_ALT -/// Add 0x8000 for the "Meta" modifier ::MOD_META (On MacOS X it's the CMD key) -////////////////////////////////////////////////////////////////////////////// - -/*! - Convert an SDL keysym to an ANSI/ASCII character. - This is used to type text and numeric values in input boxes. - @param keysym SDL symbol to convert -*/ -word Keysym_to_ANSI(SDL_keysym keysym); - -/*! - Convert an SDL keysym to an internal keycode number. - This is needed because SDL tends to split the information across the unicode sym, the regular sym, and the raw keycode. - We also need to differenciate 1 (keypad) and 1 (regular keyboard), and some other things. - See the notice at the beginning of keyboard.h for the format of a keycode. - @param keysym SDL symbol to convert -*/ -word Keysym_to_keycode(SDL_keysym keysym); - -/*! - Helper function to convert between SDL system and the old coding for PC keycodes. - This is only used to convert configuration files from the DOS version of - Grafx2, where keyboard codes are in in the IBM PC AT form. - @param scancode Scancode to convert -*/ -word Key_for_scancode(word scancode); - -/*! - Returns key name in a string. Used to display them in the helpscreens and in the keymapper window. - @param Key keycode of the key to translate, including modifiers -*/ -const char * Key_name(word key); - -/*! - Gets the modifiers in our format from the SDL_Mod information. - Returns a combination of ::MOD_SHIFT, ::MOD_ALT, ::MOD_CONTROL - @param mod SDL modifiers state -*/ -word Key_modifiers(SDLMod mod); - diff --git a/project/jni/application/grafx2/grafx2/src/layers.c b/project/jni/application/grafx2/grafx2/src/layers.c deleted file mode 100644 index 6b8abfb92..000000000 --- a/project/jni/application/grafx2/grafx2/src/layers.c +++ /dev/null @@ -1,391 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include "const.h" -#include "struct.h" -#include "global.h" -#include "windows.h" -#include "engine.h" -#include "pages.h" -#include "sdlscreen.h" -#include "input.h" -#include "help.h" -#include "misc.h" - -void Layer_activate(byte layer, short side) -{ - word old_layers; - - if (layer >= Main_backups->Pages->Nb_layers) - return; - - // Keep a copy of which layers were visible - old_layers = Main_layers_visible; - - #ifndef NOLAYERS - - if (side == RIGHT_SIDE) - { - // Right-click on current layer - if (Main_current_layer == layer) - { - if (Main_layers_visible == (dword)(1<Pages); - //Update_FX_feedback(Config.FX_Feedback); - Display_all_screen(); - Display_layerbar(); - Display_cursor(); -} - -void Button_Layer_add(void) -{ - Hide_cursor(); - - if (Main_backups->Pages->Nb_layers < MAX_NB_LAYERS) - { - // Backup with unchanged layers - Backup_layers(0); - if (!Add_layer(Main_backups,Main_current_layer+1)) - { - Update_depth_buffer(); - Display_all_screen(); - Display_layerbar(); - End_of_modification(); - } - } - - Unselect_button(BUTTON_LAYER_ADD); - Display_cursor(); -} - -void Button_Layer_remove(void) -{ - Hide_cursor(); - - if (Main_backups->Pages->Nb_layers > 1) - { - // Backup with unchanged layers - Backup_layers(0); - if (!Delete_layer(Main_backups,Main_current_layer)) - { - Update_screen_targets(); - Redraw_layered_image(); - - Display_all_screen(); - Display_layerbar(); - End_of_modification(); - } - } - Unselect_button(BUTTON_LAYER_REMOVE); - Display_cursor(); -} - -void Button_Layer_select(void) -{ - short layer; - // Determine which button is clicked according to mouse position - layer = (Mouse_X/Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width) - / Layer_button_width; - - // Safety required because the mouse cursor can have slided outside button. - if (layer < 0) - layer=0; - else if (layer > Main_backups->Pages->Nb_layers-1) - layer=Main_backups->Pages->Nb_layers-1; - - Layer_activate(layer, LEFT_SIDE); -} - -void Button_Layer_toggle(void) -{ - short layer; - // Determine which button is clicked according to mouse position - layer = (Mouse_X/Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width) - / Layer_button_width; - - // Safety required because the mouse cursor can have slided outside button. - if (layer < 0) - layer=0; - else if (layer > Main_backups->Pages->Nb_layers-1) - layer=Main_backups->Pages->Nb_layers-1; - - Layer_activate(layer, RIGHT_SIDE); -} - -static void Draw_transparent_color(byte color) -{ - char buf[4]; - Num2str(color, buf, 3); - Print_in_window(63,39,buf,MC_Black,MC_Light); - Window_rectangle(90,39,13,7,color); -} - -static void Draw_transparent_background(byte background) -{ - Print_in_window(99,57,background?"X":" ",MC_Black,MC_Light); -} - - -void Button_Layer_menu(void) -{ - byte transparent_color = Main_backups->Pages->Transparent_color; - byte transparent_background = Main_backups->Pages->Background_transparent; - short clicked_button; - byte color; - byte click; - - Open_window(122,100,"Layers"); - - Window_display_frame_in( 6, 21,110, 52); - Print_in_window(14,18,"Transparency",MC_Dark,MC_Light); - - Print_in_window(11,38,"Color",MC_Black,MC_Light); - Window_set_normal_button(54, 36, 56,13,"" , 0,1,KEY_NONE); // 1 - Draw_transparent_color(transparent_color); - - Print_in_window(11,57,"Background",MC_Black,MC_Light); - Window_set_normal_button(95, 54, 15,13,"" , 0,1,KEY_NONE); // 2 - Draw_transparent_background(transparent_background); - - Window_set_normal_button( 7, 78, 51,14,"OK" , 0,1,SDLK_RETURN); // 3 - Window_set_normal_button(63, 78, 51,14,"Cancel", 0,1,KEY_ESC); // 4 - - Update_window_area(0,0,Window_width, Window_height); - - do - { - - clicked_button=Window_clicked_button(); - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_LAYER_MENU, NULL); - switch(clicked_button) - { - case 1: // color - Get_color_behind_window(&color,&click); - if (click && transparent_color!=color) - { - transparent_color=color; - Hide_cursor(); - Draw_transparent_color(transparent_color); - Display_cursor(); - Wait_end_of_click(); - } - break; - - case 2: // background - transparent_background = !transparent_background; - Hide_cursor(); - Draw_transparent_background(transparent_background); - Display_cursor(); - break; - } - } - while (clicked_button<3); - - // On exit - Hide_cursor(); - Close_window(); - if (clicked_button==3) - { - // Accept changes - if (Main_backups->Pages->Transparent_color != transparent_color || - Main_backups->Pages->Background_transparent != transparent_background) - { - Backup_layers(-1); - Main_backups->Pages->Transparent_color = transparent_color; - Main_backups->Pages->Background_transparent = transparent_background; - Redraw_layered_image(); - Display_all_screen(); - End_of_modification(); - } - } - Unselect_button(BUTTON_LAYER_MENU); - Display_cursor(); -} - -void Button_Layer_set_transparent(void) -{ - Hide_cursor(); - - if (Main_backups->Pages->Transparent_color != Back_color) - { - Backup_layers(-1); - Main_backups->Pages->Transparent_color = Back_color; - - Redraw_layered_image(); - Display_all_screen(); - End_of_modification(); - } - - Unselect_button(BUTTON_LAYER_COLOR); - Display_cursor(); -} - -void Button_Layer_get_transparent(void) -{ - Hide_cursor(); - - if (Main_backups->Pages->Transparent_color != Back_color) - { - Set_back_color(Main_backups->Pages->Transparent_color); - } - - Unselect_button(BUTTON_LAYER_COLOR); - Display_cursor(); -} - -void Button_Layer_merge(void) -{ - Hide_cursor(); - - if (Main_current_layer>0) - { - // Backup layer below the current - Backup_layers(1<<(Main_current_layer-1)); - - Merge_layer(); - - Update_screen_targets(); - Redraw_layered_image(); - Display_all_screen(); - Display_layerbar(); - End_of_modification(); - } - - Unselect_button(BUTTON_LAYER_MERGE); - Display_cursor(); -} - -void Button_Layer_up(void) -{ - Hide_cursor(); - - if (Main_current_layer < (Main_backups->Pages->Nb_layers-1)) - { - byte * tmp; - dword layer_flags; - - // Backup with unchanged layers - Backup_layers(0); - - // swap - tmp = Main_backups->Pages->Image[Main_current_layer]; - Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer+1]; - Main_backups->Pages->Image[Main_current_layer+1] = tmp; - - // Swap visibility indicators - layer_flags = (Main_layers_visible >> Main_current_layer) & 3; - // Only needed if they are different. - if (layer_flags == 1 || layer_flags == 2) - { - // One is on, the other is off. Negating them will - // perform the swap. - Main_layers_visible ^= (3 << Main_current_layer); - } - Main_current_layer++; - - Update_screen_targets(); - Redraw_layered_image(); - Display_all_screen(); - Display_layerbar(); - End_of_modification(); - } - - Unselect_button(BUTTON_LAYER_UP); - Display_cursor(); -} - -void Button_Layer_down(void) -{ - Hide_cursor(); - - if (Main_current_layer > 0) - { - byte * tmp; - dword layer_flags; - - // Backup with unchanged layers - Backup_layers(0); - - // swap - tmp = Main_backups->Pages->Image[Main_current_layer]; - Main_backups->Pages->Image[Main_current_layer] = Main_backups->Pages->Image[Main_current_layer-1]; - Main_backups->Pages->Image[Main_current_layer-1] = tmp; - - // Swap visibility indicators - layer_flags = (Main_layers_visible >> (Main_current_layer-1)) & 3; - // Only needed if they are different. - if (layer_flags == 1 || layer_flags == 2) - { - // Only needed if they are different. - // One is on, the other is off. Negating them will - // perform the swap. - Main_layers_visible ^= (3 << (Main_current_layer-1)); - } - Main_current_layer--; - Update_screen_targets(); - Redraw_layered_image(); - Display_layerbar(); - Display_all_screen(); - End_of_modification(); - } - - Unselect_button(BUTTON_LAYER_DOWN); - Display_cursor(); -} diff --git a/project/jni/application/grafx2/grafx2/src/layers.h b/project/jni/application/grafx2/grafx2/src/layers.h deleted file mode 100644 index 9bf83f491..000000000 --- a/project/jni/application/grafx2/grafx2/src/layers.h +++ /dev/null @@ -1,35 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -void Button_Layer_add(void); -void Button_Layer_remove(void); -void Button_Layer_menu(void); -void Button_Layer_set_transparent(void); -void Button_Layer_get_transparent(void); -void Button_Layer_merge(void); -void Button_Layer_up(void); -void Button_Layer_down(void); -void Button_Layer_select(void); -void Button_Layer_toggle(void); -void Layer_activate(byte layer, short side); - - diff --git a/project/jni/application/grafx2/grafx2/src/libraw2crtc.c b/project/jni/application/grafx2/grafx2/src/libraw2crtc.c deleted file mode 100644 index 4dd868306..000000000 --- a/project/jni/application/grafx2/grafx2/src/libraw2crtc.c +++ /dev/null @@ -1,190 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* GFX2CRTC - libraw2crtc.c - * CloudStrife - 20080921 - * Diffusé sous licence libre CeCILL v2 - * Voire LICENCE - */ - -#include -#include -#include - -#include "const.h" -#include "global.h" -#include "struct.h" -#include "loadsave.h" - -unsigned short addrCalc(unsigned char vcc, unsigned char rcc, unsigned char hcc, unsigned char cclk, unsigned char r1, unsigned char r12, unsigned char r13) -{ - unsigned short MA; - unsigned short addr; - - //MA = vcc*r1 + hcc + (0x0C)*256; - MA = vcc*r1 + hcc + r12*256 + r13; - addr = cclk | ((MA & 0x03FF) << 1); - addr = addr | ((rcc & 0x07) << 11); - addr = addr | ((MA & 0x3000) << 2); - - return addr; -} - -unsigned char mode0interlace(T_IO_Context * context, unsigned char x, unsigned char y) -{ - unsigned char mode0pixel[] = {0, 64, 4, 68, 16, 80, 20, 84, 1, 65, 5, 69, 17, 81, 21, 85}; - return mode0pixel[Get_pixel(context,x,y)] << 1 | mode0pixel[Get_pixel(context,x+1,y)]; -} - -unsigned char mode1interlace(T_IO_Context * context, unsigned char x, unsigned char y) -{ - unsigned char mode1pixel[] = {0, 16, 1, 17}; - return mode1pixel[Get_pixel(context,x,y)] << 3 | mode1pixel[Get_pixel(context,x+1,y)] << 2 | mode1pixel[Get_pixel(context,x+2,y)] << 1 | mode1pixel[Get_pixel(context,x+3,y)]; -} - -unsigned char mode2interlace(T_IO_Context * context, unsigned char x, unsigned char y) -{ - unsigned char out = 0; - int i; - for(i = 0; i < 8; i++) out += ((Get_pixel(context,x+7-i,y)&1) << i); - return out; -} - -unsigned char mode3interlace(T_IO_Context * context, unsigned char x, unsigned char y) -{ - unsigned char mode3pixel[] = {0, 16, 1, 17}; - return mode3pixel[Get_pixel(context, x,y)] << 3 | mode3pixel[Get_pixel(context,x+1,y)] << 2; -} - -unsigned char (*ptrMode)(T_IO_Context * context, unsigned char x, unsigned char y); - -unsigned char *raw2crtc(T_IO_Context *context, unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13) -{ - unsigned char *outBuffer; - unsigned char *tmpBuffer; - unsigned char *allocationBuffer; - unsigned short minAddr = 0; - unsigned char minAddrIsDefined = 0; - unsigned short maxAddr = 0; - - unsigned char nbPixPerByte; - int y,x; - unsigned char r6; - unsigned short i; - unsigned char *ptrTmp; - unsigned char *ptrOut; - unsigned char vcc; - unsigned char rcc; - unsigned char hcc; - unsigned char cclk; - - switch(mode) - { - case 0: - { - *r1 = (width+3)/4; - nbPixPerByte = 2; - ptrMode = mode0interlace; - break; - } - case 1: - { - *r1 = (width+7)/8; - nbPixPerByte = 4; - ptrMode = mode1interlace; - break; - } - case 2: - { - *r1 = (width+15)/16; - nbPixPerByte = 8; - ptrMode = mode2interlace; - break; - } - case 3: - { - *r1 = (width+3)/4; - nbPixPerByte = 2; - ptrMode = mode3interlace; - break; - } - default: - { - exit(4); - } - } - - tmpBuffer = (unsigned char*)malloc(0xFFFF); - if (tmpBuffer == NULL) - { - printf("Allocation tmpBuffer raté\n"); - exit(4); - } - - allocationBuffer = (unsigned char*)malloc(0xFFFF); - if(allocationBuffer == NULL) - { - printf("Allocation allocationBuffer raté\n"); - exit(4); - } - memset(allocationBuffer, 0, 0xFFFF); - - r6 = height/(r9+1); - - for(vcc = 0; vcc < r6; vcc++) - { - for(rcc = 0; rcc < (r9+1); rcc++) - { - for(hcc = 0; hcc < *r1; hcc++) - { - for(cclk = 0; cclk < 2; cclk++) - { - x = (hcc << 1 | cclk); - y = vcc*(r9+1) + rcc; - *(tmpBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) = (*ptrMode)(context,x,y); - *(allocationBuffer + addrCalc(vcc, rcc, hcc, cclk, *r1, r12, r13)) += 1; - } - } - } - } - - for(i = 0; i < 0xFFFF; i++) - { - if(*(allocationBuffer + i) > 1) - { - printf("Attention : Ecriture multiple a l'adresse mémoire %d\n",i); - } - if(*(allocationBuffer + i) > 0) - { - maxAddr = i; - } - if((*(allocationBuffer + i) == 1) && (minAddrIsDefined == 0)) - { - minAddr = i; - minAddrIsDefined = 1; - } - } - - *outSize = (maxAddr + 1) - minAddr; - - outBuffer = (unsigned char*)malloc((*outSize)); - if (outBuffer == NULL) - { - printf("Allocation outBuffer raté\n"); - exit(4); - } - - ptrTmp = tmpBuffer + minAddr; - ptrOut = outBuffer; - - for(i = minAddr; i <= maxAddr; i++) - { - *(ptrOut++) = *(ptrTmp++); - } - - free(tmpBuffer); - tmpBuffer = NULL; - free(allocationBuffer); - allocationBuffer = NULL; - - return outBuffer; -} diff --git a/project/jni/application/grafx2/grafx2/src/libraw2crtc.h b/project/jni/application/grafx2/grafx2/src/libraw2crtc.h deleted file mode 100644 index f689043c4..000000000 --- a/project/jni/application/grafx2/grafx2/src/libraw2crtc.h +++ /dev/null @@ -1,14 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* GFX2CRTC - libraw2crtc.h - * CloudStrife - 20080921 - * Diffusé sous licence libre CeCILL v2 - * Voire LICENCE - */ - -#ifndef LIBRAW2CRTC_H -#define LIBRAW2CRTC_H 1 - -unsigned char * raw2crtc(unsigned short width, unsigned short height, unsigned char mode, unsigned char r9, unsigned long *outSize, unsigned char *r1, unsigned char r12, unsigned char r13); - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/loadsave.c b/project/jni/application/grafx2/grafx2/src/loadsave.c deleted file mode 100644 index d2a06de42..000000000 --- a/project/jni/application/grafx2/grafx2/src/loadsave.c +++ /dev/null @@ -1,1587 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#define _XOPEN_SOURCE 500 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "buttons.h" -#include "const.h" -#include "errors.h" -#include "global.h" -#include "io.h" -#include "loadsave.h" -#include "misc.h" -#include "graph.h" -#include "op_c.h" -#include "pages.h" -#include "palette.h" -#include "sdlscreen.h" -#include "struct.h" -#include "windows.h" -#include "engine.h" -#include "brush.h" -#include "setup.h" - -// -- PKM ------------------------------------------------------------------- -void Test_PKM(T_IO_Context *); -void Load_PKM(T_IO_Context *); -void Save_PKM(T_IO_Context *); - -// -- LBM ------------------------------------------------------------------- -void Test_LBM(T_IO_Context *); -void Load_LBM(T_IO_Context *); -void Save_LBM(T_IO_Context *); - -// -- GIF ------------------------------------------------------------------- -void Test_GIF(T_IO_Context *); -void Load_GIF(T_IO_Context *); -void Save_GIF(T_IO_Context *); - -// -- PCX ------------------------------------------------------------------- -void Test_PCX(T_IO_Context *); -void Load_PCX(T_IO_Context *); -void Save_PCX(T_IO_Context *); - -// -- BMP ------------------------------------------------------------------- -void Test_BMP(T_IO_Context *); -void Load_BMP(T_IO_Context *); -void Save_BMP(T_IO_Context *); - -// -- IMG ------------------------------------------------------------------- -void Test_IMG(T_IO_Context *); -void Load_IMG(T_IO_Context *); -void Save_IMG(T_IO_Context *); - -// -- SCx ------------------------------------------------------------------- -void Test_SCx(T_IO_Context *); -void Load_SCx(T_IO_Context *); -void Save_SCx(T_IO_Context *); - -// -- CEL ------------------------------------------------------------------- -void Test_CEL(T_IO_Context *); -void Load_CEL(T_IO_Context *); -void Save_CEL(T_IO_Context *); - -// -- KCF ------------------------------------------------------------------- -void Test_KCF(T_IO_Context *); -void Load_KCF(T_IO_Context *); -void Save_KCF(T_IO_Context *); - -// -- PAL ------------------------------------------------------------------- -void Test_PAL(T_IO_Context *); -void Load_PAL(T_IO_Context *); -void Save_PAL(T_IO_Context *); - -// -- PI1 ------------------------------------------------------------------- -void Test_PI1(T_IO_Context *); -void Load_PI1(T_IO_Context *); -void Save_PI1(T_IO_Context *); - -// -- PC1 ------------------------------------------------------------------- -void Test_PC1(T_IO_Context *); -void Load_PC1(T_IO_Context *); -void Save_PC1(T_IO_Context *); - -// -- NEO ------------------------------------------------------------------- -void Test_NEO(T_IO_Context *); -void Load_NEO(T_IO_Context *); -void Save_NEO(T_IO_Context *); - -// -- C64 ------------------------------------------------------------------- -void Test_C64(T_IO_Context *); -void Load_C64(T_IO_Context *); -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 *); -void Load_PNG(T_IO_Context *); -void Save_PNG(T_IO_Context *); -#endif - -// -- SDL_Image ------------------------------------------------------------- -// (TGA, BMP, PNM, XPM, XCF, PCX, GIF, JPG, TIF, LBM, PNG, ICO) -void Load_SDL_Image(T_IO_Context *); - -// ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts -T_Format File_formats[] = { - {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;pcx;pkm;lbm;ilbm;iff;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;kcf;pal;c64;koa;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico"}, - {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, - {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, -#ifndef __no_pnglib__ - {FORMAT_PNG, " png", Test_PNG, Load_PNG, Save_PNG, 0, 1, 0, "png", "png"}, -#endif - {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;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"}, - {FORMAT_PC1, " pc1", Test_PC1, Load_PC1, Save_PC1, 0, 0, 0, "pc1", "pc1"}, - {FORMAT_CEL, " cel", Test_CEL, Load_CEL, Save_CEL, 0, 0, 0, "cel", "cel"}, - {FORMAT_NEO, " neo", Test_NEO, Load_NEO, Save_NEO, 0, 0, 0, "neo", "neo"}, - {FORMAT_KCF, " kcf", Test_KCF, Load_KCF, Save_KCF, 1, 0, 0, "kcf", "kcf"}, - {FORMAT_PAL, " pal", Test_PAL, Load_PAL, Save_PAL, 1, 0, 0, "pal", "pal"}, - {FORMAT_C64, " c64", Test_C64, Load_C64, Save_C64, 0, 1, 0, "c64", "c64;koa"}, - {FORMAT_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) -{ - // Clipping - if ((x_pos>=context->Width) || (y_pos>=context->Height)) - return; - - switch (context->Type) - { - // Chargement des pixels dans l'écran principal - case CONTEXT_MAIN_IMAGE: - Pixel_in_current_screen(x_pos,y_pos,color,0); - break; - - // Chargement des pixels dans la brosse - case CONTEXT_BRUSH: - //Pixel_in_brush(x_pos,y_pos,color); - *(context->Buffer_image + y_pos * context->Pitch + x_pos)=color; - break; - - // Chargement des pixels dans la preview - case CONTEXT_PREVIEW: - // Skip pixels of transparent index if : - // 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) - { - 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) - { - 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 - context->Preview_bitmap[x_pos/context->Preview_factor_X + (y_pos/context->Preview_factor_Y)*PREVIEW_WIDTH*Menu_factor_X]=color; - } - - break; - - // Load pixels in a SDL_Surface - case CONTEXT_SURFACE: - if (x_pos>=0 && y_pos>=0 && x_posSurface->w && y_posSurface->h) - *(((byte *)(context->Surface->pixels)) + context->Surface->pitch * y_pos + x_pos) = color; - break; - - } - -} - - -void Palette_loaded(T_IO_Context *context) -{ - // Update the current screen to the loaded palette - switch (context->Type) - { - case CONTEXT_MAIN_IMAGE: - case CONTEXT_PREVIEW: - case CONTEXT_BRUSH: - case CONTEXT_SURFACE: - break; - } - - switch (context->Type) - { - case CONTEXT_PREVIEW: - case CONTEXT_MAIN_IMAGE: - case CONTEXT_BRUSH: - case CONTEXT_SURFACE: - break; - } -} - -// Chargement des pixels dans le buffer 24b -void Set_pixel_24b(T_IO_Context *context, short x_pos, short y_pos, byte r, byte g, byte b) -{ - byte color; - - // Clipping - if (x_pos<0 || y_pos<0 || x_pos>=context->Width || y_pos>=context->Height) - return; - - switch(context->Type) - { - case CONTEXT_MAIN_IMAGE: - case CONTEXT_BRUSH: - case CONTEXT_SURFACE: - { - int index; - - index=(y_pos*context->Width)+x_pos; - context->Buffer_image_24b[index].R=r; - context->Buffer_image_24b[index].G=g; - context->Buffer_image_24b[index].B=b; - } - 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)); - - // 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; - } -} - - - -// Création d'une palette fake -void Set_palette_fake_24b(T_Palette palette) -{ - int color; - - // Génération de la palette - for (color=0;color<256;color++) - { - palette[color].R=((color & 0xE0)>>5)<<5; - palette[color].G=((color & 0x1C)>>2)<<5; - palette[color].B=((color & 0x03)>>0)<<6; - } -} - -/// -/// Generic allocation and similar stuff, done at beginning of image load, -/// as soon as size is known. -void Pre_load(T_IO_Context *context, short width, short height, long file_size, int format, enum PIXEL_RATIO ratio, byte truecolor) -{ - char str[10]; - - context->Pitch = width; // default - context->Width = width; - context->Height = height; - context->Ratio = ratio; - context->Nb_layers = 1; - context->Transparent_color=0; - context->Background_transparent=0; - - switch(context->Type) - { - // 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)) - { - Num2str(width,str,4); - Num2str(height,str+5,4); - str[4]='x'; - Print_in_window(143,59,str,MC_Black,MC_Light); - } - else - { - Print_in_window(143,59,"VERY BIG!",MC_Black,MC_Light); - } - - // Affichage de la taille du fichier - if (file_size<1048576) - { - // Le fichier fait moins d'un Mega, on affiche sa taille direct - Num2str(file_size,str,7); - Print_in_window(236,59,str,MC_Black,MC_Light); - } - else if ((file_size/1024)<100000) - { - // Le fichier fait plus d'un Mega, on peut afficher sa taille en Ko - Num2str(file_size/1024,str,5); - strcpy(str+5,"Kb"); - Print_in_window(236,59,str,MC_Black,MC_Light); - } - else - { - // Le fichier fait plus de 100 Mega octets (cas très rare :)) - Print_in_window(236,59,"LARGE!!",MC_Black,MC_Light); - } - - // Affichage du vrai format - if (format!=Main_format) - { - 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); - - // Calcul des données nécessaires à l'affichage de la preview: - if (ratio == PIXEL_WIDE && - Pixel_ratio != PIXEL_WIDE && - Pixel_ratio != PIXEL_WIDE2) - width*=2; - else if (ratio == PIXEL_TALL && - Pixel_ratio != PIXEL_TALL && - Pixel_ratio != PIXEL_TALL2) - height*=2; - - 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) ) - { - if (context->Preview_factor_X>context->Preview_factor_Y) - context->Preview_factor_Y=context->Preview_factor_X; - else - context->Preview_factor_X=context->Preview_factor_Y; - } - - context->Preview_pos_X=Window_pos_X+183*Menu_factor_X; - 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,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,PREVIEW_WIDTH,PREVIEW_HEIGHT); - break; - - // Other loading - case CONTEXT_MAIN_IMAGE: - 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. - // Normalement tout va bien, tout est sous contrôle... - - // Load into layer 0, by default. - context->Nb_layers=1; - Main_current_layer=0; - Main_layers_visible=1<<0; - Set_layer(context,0); - - // Remove previous comment, unless we load just a palette - if (! Get_fileformat(context->Format)->Palette_only) - context->Comment[0]='\0'; - } - else - { - // Afficher un message d'erreur - // Pour être sûr que ce soit lisible. - Compute_optimal_menu_colors(context->Palette); - Message_out_of_memory(); - File_error=1; // 1 => On n'a pas perdu l'image courante - } - break; - - case CONTEXT_BRUSH: - context->Buffer_image = (byte *)malloc(width*height); - if (! context->Buffer_image) - { - File_error=3; - return; - } - context->Target_address=context->Buffer_image; - - break; - - case CONTEXT_SURFACE: - context->Surface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCCOLORKEY, width, height, 8, 0, 0, 0, 0); - if (! context->Surface) - { - File_error=1; - return; - } - //context->Pitch = context->Surface->pitch; - //context->Target_address = context->Surface->pixels; - break; - } - - if (File_error) - return; - - // Extra process for truecolor images - if (truecolor) - { - //context->Is_truecolor = 1; - - switch(context->Type) - { - case CONTEXT_MAIN_IMAGE: - case CONTEXT_BRUSH: - case CONTEXT_SURFACE: - // Allocate 24bit buffer - context->Buffer_image_24b= - (T_Components *)malloc(width*height*sizeof(T_Components)); - if (!context->Buffer_image_24b) - { - // Print an error message - // The following is to be sure the message is readable - Compute_optimal_menu_colors(context->Palette); - Message_out_of_memory(); - File_error=1; - } - break; - - case CONTEXT_PREVIEW: - // Load palette - Set_palette_fake_24b(context->Palette); - Palette_loaded(context); - break; - } - } -} - -///////////////////////////////////////////////////////////////////////////// -// Gestion des lectures et écritures // -///////////////////////////////////////////////////////////////////////////// - -byte * Write_buffer; -word Write_buffer_index; - -void Init_write_buffer(void) -{ - Write_buffer=(byte *)malloc(64000); - Write_buffer_index=0; -} - -void Write_one_byte(FILE *file, byte b) -{ - Write_buffer[Write_buffer_index++]=b; - if (Write_buffer_index>=64000) - { - if (! Write_bytes(file,Write_buffer,64000)) - File_error=1; - Write_buffer_index=0; - } -} - -void End_write(FILE *file) -{ - if (Write_buffer_index) - if (! Write_bytes(file,Write_buffer,Write_buffer_index)) - File_error=1; - free(Write_buffer); - Write_buffer = NULL; -} - - -///////////////////////////////////////////////////////////////////////////// - -// -------- Modifier la valeur du code d'erreur d'accès à un fichier -------- -// On n'est pas obligé d'utiliser cette fonction à chaque fois mais il est -// important de l'utiliser dans les cas du type: -// if (!File_error) *** else File_error=***; -// En fait, dans le cas où l'on modifie File_error alors qu'elle contient -// dèjà un code d'erreur. -void Set_file_error(int value) -{ - if (File_error>=0) - File_error=value; -} - - -// -- Charger n'importe connu quel type de fichier d'image (ou palette) ----- -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: - File_error=1; - - if (context->Format>FORMAT_ALL_FILES) - { - format = Get_fileformat(context->Format); - if (format->Test) - format->Test(context); - } - - if (File_error) - { - // 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++) - { - format = Get_fileformat(index); - // Loadable format - if (format->Test == NULL) - continue; - - // On appelle le testeur du format: - format->Test(context); - // On s'arrête si le fichier est au bon format: - if (File_error==0) - break; - } - } - - if (File_error) - { - context->Format = DEFAULT_FILEFORMAT; - // Last try: with SDL_image - Load_SDL_Image(context); - - if (File_error) - { - // Sinon, l'appelant sera au courant de l'échec grace à File_error; - // et si on s'apprêtait à faire un chargement définitif de l'image (pas - // une preview), alors on flash l'utilisateur. - //if (Pixel_load_function!=Pixel_load_in_preview) - // Error(0); - return; - } - } - else - // Si on a su déterminer avec succès le format du fichier: - { - context->Format = format->Identifier; - // On peut charger le fichier: - // Dans certains cas il est possible que le chargement plante - // après avoir modifié la palette. TODO - format->Load(context); - } - - if (File_error>0) - { - fprintf(stderr,"Unable to load file %s!\n",context->File_name); - if (context->Type!=CONTEXT_SURFACE) - Error(0); - } - - // Post-load - - if (context->Buffer_image_24b) - { - // On vient de charger une image 24b - if (!File_error) - { - switch(context->Type) - { - case CONTEXT_MAIN_IMAGE: - // Cas d'un chargement dans l'image - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - Flush_update(); - if (Convert_24b_bitmap_to_256(Main_backups->Pages->Image[0],context->Buffer_image_24b,context->Width,context->Height,context->Palette)) - File_error=2; - else - { - Palette_loaded(context); - } - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_ARROW; - Display_cursor(); - break; - - case CONTEXT_BRUSH: - // Cas d'un chargement dans la brosse - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_HOURGLASS; - Display_cursor(); - Flush_update(); - if (Convert_24b_bitmap_to_256(Brush,context->Buffer_image_24b,context->Width,context->Height,context->Palette)) - File_error=2; - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_ARROW; - Display_cursor(); - break; - - case CONTEXT_PREVIEW: - // nothing to do - break; - - 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; - break; - - } - } - 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; - // From white to black - for (gui_index=3; gui_index>=0; gui_index--) - { - int c; - T_Components gui_color; - - gui_color=*Favorite_GUI_color(gui_index); - // Try find a very close match (ignore last 2 bits) - for (c=255; c>=0; c--) - { - if ((context->Palette[c].R|3) == (gui_color.R|3) - && (context->Palette[c].G|3) == (gui_color.G|3) - && (context->Palette[c].B|3) == (gui_color.B|3) ) - break; - } - if (c<0) // Not found - { - // Find an unused slot at end of palette - for (c=255; c>=0; c--) - { - if (color_usage[c]==0) - { - context->Palette[c]=gui_color; - // Tag as a used color - color_usage[c]=1; - break; - } - } - } - } - } - } - } - - if (context->Type == CONTEXT_MAIN_IMAGE) - { - if ( File_error!=1) - { - Set_palette(context->Palette); - if (format->Palette_only) - { - // Make a backup step - Backup_layers(0); - } - // Copy the loaded palette - memcpy(Main_palette, context->Palette, sizeof(T_Palette)); - memcpy(Main_backups->Pages->Palette, context->Palette, sizeof(T_Palette)); - - // For formats that handle more than just the palette: - // Transfer the data to main image. - if (!format->Palette_only) - { - if (context->Original_file_name && context->Original_file_name[0] - && context->Original_file_directory && context->Original_file_directory[0]) - { - strcpy(Main_backups->Pages->Filename,context->Original_file_name); - strcpy(Main_backups->Pages->File_directory,context->Original_file_directory); - } - else - { - strcpy(Main_backups->Pages->Filename,context->File_name); - strcpy(Main_backups->Pages->File_directory,context->File_directory); - } - - // On considère que l'image chargée n'est plus modifiée - Main_image_is_modified=0; - // Et on documente la variable Main_fileformat avec la valeur: - Main_fileformat=format->Identifier; - - // already done initially on Backup_with_new_dimensions - //Main_image_width= context->Width; - //Main_image_height= context->Height; - - Main_current_layer = context->Nb_layers - 1; - Main_layers_visible = (2<Pages->Transparent_color = context->Transparent_color; - Main_backups->Pages->Background_transparent = context->Background_transparent; - - // Correction des dimensions - if (Main_image_width<1) - 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) - { - // On considère que l'image chargée est encore modifiée - Main_image_is_modified=1; - // Et on documente la variable Main_fileformat avec la valeur: - Main_fileformat=format->Identifier; - } - else - { - // Dans ce cas, on sait que l'image n'a pas changé, mais ses - // paramètres (dimension, palette, ...) si. Donc on les restaures. - Download_infos_page_main(Main_backups->Pages); - } - } - else if (context->Type == CONTEXT_BRUSH && File_error==0) - { - - 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) - { - if (File_error == 0) - { - // Copy the palette - SDL_Color colors[256]; - int i; - - for (i=0; i<256; i++) - { - colors[i].r=context->Palette[i].R; - colors[i].g=context->Palette[i].G; - colors[i].b=context->Palette[i].B; - } - 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); - - } - -} - - -// -- Sauver n'importe quel type connu de fichier d'image (ou palette) ------ -void Save_image(T_IO_Context *context) -{ - T_Format *format; - - // On place par défaut File_error à vrai au cas où on ne sache pas - // sauver le format du fichier: (Est-ce vraiment utile??? Je ne crois pas!) - File_error=1; - - switch (context->Type) - { - case CONTEXT_MAIN_IMAGE: - if (!File_formats[context->Format-1].Supports_layers - && Main_backups->Pages->Nb_layers > 1) - { - if (! Confirmation_box("This format doesn't support layers\nand will save a flattened copy of\nyour image. Proceed?")) - { - // File_error is already set to 1. - return; - } - } - break; - - case CONTEXT_BRUSH: - break; - - case CONTEXT_PREVIEW: - break; - - case CONTEXT_SURFACE: - break; - } - - format = Get_fileformat(context->Format); - if (format->Save) - format->Save(context); - - if (File_error) - { - Error(0); - return; - } -} - - -void Load_SDL_Image(T_IO_Context *context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - word x_pos,y_pos; - // long file_size; - dword pixel; - long file_size; - SDL_Surface * surface; - - - Get_full_filename(filename, context->File_name, context->File_directory); - File_error=0; - - surface = IMG_Load(filename); - - if (!surface) - { - File_error=1; - return; - } - - file_size=File_length(filename); - - if (surface->format->BytesPerPixel == 1) - { - // 8bpp image - - Pre_load(context, surface->w, surface->h, file_size ,FORMAT_MISC, PIXEL_SIMPLE, 0); - - // Read palette - if (surface->format->palette) - { - Get_SDL_Palette(surface->format->palette, context->Palette); - } - - for (y_pos=0; y_posHeight; y_pos++) - { - for (x_pos=0; x_posWidth; x_pos++) - { - Set_pixel(context, x_pos, y_pos, Get_SDL_pixel_8(surface, x_pos, y_pos)); - } - } - - } - else - { - { - // 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++) - { - for (x_pos=0; x_posWidth; x_pos++) - { - pixel = Get_SDL_pixel_hicolor(surface, x_pos, y_pos); - Set_pixel_24b( - context, - x_pos, - y_pos, - ((pixel & surface->format->Rmask) >> surface->format->Rshift) << surface->format->Rloss, - ((pixel & surface->format->Gmask) >> surface->format->Gshift) << surface->format->Gloss, - ((pixel & surface->format->Bmask) >> surface->format->Bshift) << surface->format->Bloss); - } - } - } - - SDL_FreeSurface(surface); -} - -/// -/// Load an arbitrary SDL_Surface. -/// @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; - - Init_context_surface(&context, 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; -} - - -/// Saves an image. -/// This routine will only be called when all hope is lost, memory thrashed, etc -/// It's the last chance to save anything, but the code has to be extremely -/// careful, anything could happen. -/// The chosen format is IMG since it's extremely simple, difficult to make it -/// create an unusable image. -void Emergency_backup(const char *fname, byte *source, int width, int height, T_Palette *palette) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - short x_pos,y_pos; - T_IMG_Header IMG_header; - - if (width == 0 || height == 0 || source == NULL) - return; - - strcpy(filename,Config_directory); - strcat(filename,fname); - - // Ouverture du fichier - file=fopen(filename,"wb"); - if (!file) - return; - - memcpy(IMG_header.Filler1,"\x01\x00\x47\x12\x6D\xB0",6); - memset(IMG_header.Filler2,0,118); - IMG_header.Filler2[4]=0xFF; - IMG_header.Filler2[22]=64; // Lo(Longueur de la signature) - IMG_header.Filler2[23]=0; // Hi(Longueur de la signature) - memcpy(IMG_header.Filler2+23,"GRAFX2 by SunsetDesign (IMG format taken from PV (c)W.Wiedmann)",64); - - if (!Write_bytes(file,IMG_header.Filler1,6) || - !Write_word_le(file,width) || - !Write_word_le(file,height) || - !Write_bytes(file,IMG_header.Filler2,118) || - !Write_bytes(file,palette,sizeof(T_Palette))) - { - fclose(file); - return; - } - - for (y_pos=0; ((y_posPages && Main_backups->Pages->Nb_layers == 1) - 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(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) -{ - unsigned int i; - T_Format * safe_default = File_formats; - - for (i=0; i < Nb_known_formats(); i++) - { - if (File_formats[i].Identifier == format) - return &(File_formats[i]); - - if (File_formats[i].Identifier == FORMAT_GIF) - safe_default=&(File_formats[i]); - } - // Normally impossible to reach this point, unless called with an invalid - // enum.... - return safe_default; -} - -/// Query the color of a pixel (to save) -byte Get_pixel(T_IO_Context *context, short x, short y) -{ - return *(context->Target_address + y*context->Pitch + x); -} - -/// 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)); -} - -/// Setup for loading a preview in fileselector -void Init_context_preview(T_IO_Context * context, char *file_name, char *file_directory) -{ - memset(context, 0, sizeof(T_IO_Context)); - - context->Type = CONTEXT_PREVIEW; - context->File_name = file_name; - context->File_directory = file_directory; - context->Format = Main_fileformat; // FIXME ? -} - -// Setup for loading/saving an intermediate backup -void Init_context_backup_image(T_IO_Context * context, char *file_name, char *file_directory) -{ - Init_context_layered_image(context, file_name, file_directory); -} - -/// 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; - context->File_name = file_name; - context->File_directory = file_directory; - context->Format = Main_fileformat; - memcpy(context->Palette, Main_palette, sizeof(T_Palette)); - context->Width = Main_image_width; - context->Height = Main_image_height; - context->Nb_layers = Main_backups->Pages->Nb_layers; - strcpy(context->Comment, Main_comment); - context->Transparent_color=Main_backups->Pages->Transparent_color; - context->Background_transparent=Main_backups->Pages->Background_transparent; - if (Pixel_ratio == PIXEL_WIDE || Pixel_ratio == PIXEL_WIDE2) - context->Ratio=PIXEL_WIDE; - else if (Pixel_ratio == PIXEL_TALL || Pixel_ratio == PIXEL_TALL2) - context->Ratio=PIXEL_TALL; - else - context->Ratio=PIXEL_SIMPLE; - 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 -//void Init_context_flat_image(T_IO_Context * context, char *file_name, char *file_directory) -//{ - -//} - -/// Setup for loading/saving the user's brush -void Init_context_brush(T_IO_Context * context, char *file_name, char *file_directory) -{ - memset(context, 0, sizeof(T_IO_Context)); - - context->Type = CONTEXT_BRUSH; - context->File_name = file_name; - context->File_directory = file_directory; - context->Format = Brush_fileformat; - // Use main screen's palette - memcpy(context->Palette, Main_palette, sizeof(T_Palette)); - context->Width = Brush_width; - context->Height = Brush_height; - context->Nb_layers = 1; - // Solid save... could use BG color maybe - context->Transparent_color=0; - context->Background_transparent=0; - context->Ratio=PIXEL_SIMPLE; - context->Target_address=Brush; - context->Pitch=Brush_width; - -} - -// Setup for loading an image into a new SDL surface. -void Init_context_surface(T_IO_Context * context, char *file_name, char *file_directory) -{ - memset(context, 0, sizeof(T_IO_Context)); - - context->Type = CONTEXT_SURFACE; - context->File_name = file_name; - context->File_directory = file_directory; - context->Format = DEFAULT_FILEFORMAT; - // context->Palette - // context->Width - // context->Height - context->Nb_layers = 1; - context->Transparent_color=0; - context->Background_transparent=0; - context->Ratio=PIXEL_SIMPLE; - //context->Target_address - //context->Pitch - -} -/// Function to call when need to switch layers. -void Set_layer(T_IO_Context *context, byte layer) -{ - context->Current_layer = layer; - - if (context->Type == CONTEXT_MAIN_IMAGE) - { - // This awful thing is the part that happens on load - while (layer > (context->Nb_layers-1)) - { - if (Add_layer(Main_backups, layer)) - { - // Failure to add a layer on load: - // Position on last layer - layer = context->Nb_layers-1; - break; - } - context->Nb_layers = Main_backups->Pages->Nb_layers; - Main_current_layer = layer; - Main_layers_visible = (2<Target_address=Main_backups->Pages->Image[layer]; - } -} - -// ============================================ -// Safety backups -// ============================================ - - -typedef struct T_String_list -{ - char * String; - struct T_String_list * Next; -} T_String_list; - -/// A list of files, used for scanning a directory -T_String_list *Backups_main = NULL; -/// A list of files, used for scanning a directory -T_String_list *Backups_spare = NULL; - - -// Settings for safety backup (frequency, numbers, etc) - -const int Rotation_safety_backup = 8; - -const int Min_interval_for_safety_backup = 30000; -const int Min_edits_for_safety_backup = 10; - -const int Max_interval_for_safety_backup = 60000; -const int Max_edits_for_safety_backup = 30; - -/// -/// Adds a file to Backups_main or Backups_spare lists, if it's a backup. -/// -void Add_backup_file(const char *name) -{ - T_String_list ** list; - T_String_list * elem; - int i; - char file_name[MAX_PATH_CHARACTERS]; - - // Only files names of the form a0000000.* and b0000000.* are expected - - Extract_filename(file_name, name); - - // Check first character - if (file_name[0]==Main_safety_backup_prefix) - list = &Backups_main; - else if (file_name[0]==Spare_safety_backup_prefix) - list = &Backups_spare; - else { - // Not a good file - return; - } - - // Check next characters till file extension - i = 1; - while (file_name[i]!='\0' && file_name[i]!='.') - { - if (file_name[i]< '0' || file_name[i] > '9') - { - // Not a good file - return; - } - i++; - } - - // Add to list (top insertion) - elem = (T_String_list *)malloc(sizeof(T_String_list)); - elem->String=strdup(file_name); - elem->Next=*list; - *list=elem; -} - - -/// String comparer for sorting -int String_compare (const void * a, const void * b) -{ - return strcmp(*(char**)a,*(char**)b); -} - -/// -/// Reload safety backups, by loading several files in the right order. -/// -byte Process_backups(T_String_list **list) -{ - int nb_files; - int i; - char ** files_vector; - T_String_list *element; - byte backup_max_undo_pages; - - if (*list == NULL) - return 0; - - // Save the maximum number of pages - // (It's used in Create_new_page() which gets called on each Load_image) - backup_max_undo_pages = Config.Max_undo_pages; - Config.Max_undo_pages = 99; - - // Count files - nb_files=0; - element=*list; - while (element != NULL) - { - nb_files++; - element = element->Next; - } - // Allocate a vector - files_vector = (char **)malloc(sizeof(char *) * nb_files); - // Copy from list to vector - for (i=0;iString; - next = (*list)->Next; - free(*list); - *list = next; - } - - // Sort the vector - qsort (files_vector, nb_files , sizeof(char **), String_compare); - - for (i=0; i < nb_files; i++) - { - // Load this file - T_IO_Context context; - char file_name[MAX_PATH_CHARACTERS]=""; - char file_directory[MAX_PATH_CHARACTERS]=""; - - Init_context_backup_image(&context, files_vector[i], Config_directory); - // Provide buffers to read original location - context.Original_file_name = file_name; - context.Original_file_directory = file_directory; - Load_image(&context); - Main_image_is_modified=1; - Destroy_context(&context); - Redraw_layered_image(); - Display_all_screen(); - } - - // Done with the vector - for (i=0; i < nb_files; i++) - { - free(files_vector[i]); - } - free(files_vector); - files_vector = NULL; - - // Restore the maximum number of pages - Config.Max_undo_pages = backup_max_undo_pages; - - return nb_files; -} - - -/// Global indicator that tells if the safety backup system is active -byte Safety_backup_active = 0; - -/// -/// Checks if there are any pending safety backups, and then opens them. -/// @return 0 if no problem, -1 if the backup system cannot be activated, >=1 if some backups are restored -int Check_recovery(void) -{ - int restored_spare; - int restored_main; - - // First check if can write backups -#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; - - Backups_main = NULL; - Backups_spare = NULL; - For_each_file(Config_directory, Add_backup_file); - - // Do the processing twice: once for possible backups of the main page, - // once for possible backups of the spare. - - restored_spare = Process_backups(&Backups_spare); - if (restored_spare) - { - Main_offset_X=0; - Main_offset_Y=0; - Compute_limits(); - Compute_paintbrush_coordinates(); - if (Backups_main) - Button_Page(); - } - restored_main = Process_backups(&Backups_main); - - if (restored_main) - { - Main_offset_X=0; - Main_offset_Y=0; - Compute_limits(); - Compute_paintbrush_coordinates(); - } - return restored_main + restored_spare; -} - -void Rotate_safety_backups(void) -{ - Uint32 now; - T_IO_Context context; - char file_name[12+1]; - char deleted_file[MAX_PATH_CHARACTERS]; - - if (!Safety_backup_active) - return; - - now = SDL_GetTicks(); - // It's time to save if either: - // - Many edits have taken place - // - A minimum number of edits have taken place AND a minimum time has passed - // - At least one edit was done, and a maximum time has passed - if ((Main_edits_since_safety_backup > Max_edits_for_safety_backup) || - (Main_edits_since_safety_backup > Min_edits_for_safety_backup && - now > Main_time_of_safety_backup + Min_interval_for_safety_backup) || - (Main_edits_since_safety_backup > 1 && - now > Main_time_of_safety_backup + Max_interval_for_safety_backup)) - { - - // Clear a previous save (rotating saves) - 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); - remove(deleted_file); // no matter if fail - - // Reset counters - Main_edits_since_safety_backup=0; - Main_time_of_safety_backup=now; - - // Create a new file name and save - 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); - context.Format=FORMAT_GIF; - // Provide original file data, to store as a GIF Application Extension - context.Original_file_name = Main_backups->Pages->Filename; - context.Original_file_directory = Main_backups->Pages->File_directory; - - Save_image(&context); - Destroy_context(&context); - - Main_safety_number++; - } -} - -/// Remove safety backups. Need to call on normal program exit. -void Delete_safety_backups(void) -{ - T_String_list *element; - - if (!Safety_backup_active) - return; - - Backups_main = NULL; - Backups_spare = NULL; - - For_each_file(Config_directory, Add_backup_file); - - chdir(Config_directory); - for (element=Backups_main; element!=NULL; element=element->Next) - { - if(remove(element->String)) - printf("Failed to delete %s\n",element->String); - } - for (element=Backups_spare; element!=NULL; element=element->Next) - { - if(remove(element->String)) - printf("Failed to delete %s\n",element->String); - } - - // Release lock file -#if defined (__MINT__) - //TODO: release file lock under Freemint only -#else - Release_lock_file(Config_directory); -#endif - -} diff --git a/project/jni/application/grafx2/grafx2/src/loadsave.h b/project/jni/application/grafx2/grafx2/src/loadsave.h deleted file mode 100644 index 8fcd6376d..000000000 --- a/project/jni/application/grafx2/grafx2/src/loadsave.h +++ /dev/null @@ -1,259 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -////////////////////////////////////////////////////////////////////////////// -///@file loadsave.h -/// Saving and loading different picture formats. -/// Also handles showing the preview in fileselectors. -////////////////////////////////////////////////////////////////////////////// - -#ifndef __LOADSAVE_H__ -#define __LOADSAVE_H__ - -#include -#include - -enum CONTEXT_TYPE { - CONTEXT_MAIN_IMAGE, - CONTEXT_BRUSH, - CONTEXT_PREVIEW, - 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 -{ - /// Kind of context. Internally used to differentiate the "sub-classes" - enum CONTEXT_TYPE Type; - - // File properties - - char * File_name; - char * File_directory; - byte Format; - - // Image properties - - T_Palette Palette; - short Width; - short Height; - byte Nb_layers; - char Comment[COMMENT_SIZE+1]; - byte Background_transparent; - byte Transparent_color; - /// Pixel ratio of the image - enum PIXEL_RATIO Ratio; - - /// Load/save address of first pixel - byte *Target_address; - /// Pitch: Difference of addresses between one pixel and the one just "below" it - long Pitch; - - /// Original file name, stored in GIF file - char * Original_file_name; - /// 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; - - /// Internal: Used to mark truecolor images on loading. Only used by preview. - //byte Is_truecolor; - /// Internal: Temporary RGB buffer when loading 24bit images - T_Components *Buffer_image_24b; - - /// Internal: Temporary buffer when saving the flattened copy of something - byte *Buffer_image; - - // Internal: working data for preview case - short Preview_factor_X; - 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 *); - -/* -void Pixel_load_in_current_screen (word x_pos, word y_pos, byte color); -void Pixel_load_in_preview (word x_pos, word y_pos, byte color); -void Pixel_load_in_brush (word x_pos, word y_pos, byte color); -*/ - -// Setup for loading a preview in fileselector -void Init_context_preview(T_IO_Context * context, char *file_name, char *file_directory); -// Setup for loading/saving the current main image -void Init_context_layered_image(T_IO_Context * context, char *file_name, char *file_directory); -// Setup for loading/saving an intermediate backup -void Init_context_backup_image(T_IO_Context * context, char *file_name, char *file_directory); -// Setup for loading/saving the flattened version of current main image -void Init_context_flat_image(T_IO_Context * context, char *file_name, char *file_directory); -// Setup for loading/saving the user's brush -void Init_context_brush(T_IO_Context * context, char *file_name, char *file_directory); -// Setup for saving an arbitrary undo/redo step, from either the main or spare page. -void Init_context_history_step(T_IO_Context * context, T_Page *page); -// Setup for loading an image into a new SDL surface. -void Init_context_surface(T_IO_Context * context, char *file_name, char *file_directory); - -// Cleans up resources (currently: the 24bit buffer) -void Destroy_context(T_IO_Context *context); - -/// -/// High-level picture loading function. -void Load_image(T_IO_Context *context); - -/// -/// High-level picture saving function. -void Save_image(T_IO_Context *context); - -/// -/// Checks if there are any pending safety backups, and then opens them. -/// Returns 0 if there were none -/// Returns non-zero if some backups were loaded. -int Check_recovery(void); - -/// Makes a safety backup periodically. -void Rotate_safety_backups(void); - -/// Remove safety backups. Need to call on normal program exit. -void Delete_safety_backups(void); - -/// Data for an image file format. -typedef struct { - byte Identifier; ///< Identifier for this format in enum :FILE_FORMATS - char *Label; ///< Five-letter label - Func_IO Test; ///< Function which tests if the file is of this format - Func_IO Load; ///< Function which loads an image of this format - Func_IO Save; ///< Function which saves an image of this format - byte Palette_only; ///< Boolean, true if this format saves/loads only the palette. - byte Comment; ///< This file format allows a text comment - byte Supports_layers; ///< Boolean, true if this format preserves layers on saving - char *Default_extension; ///< Default file extension - char *Extensions; ///< List of semicolon-separated file extensions -} T_Format; - -/// Array of the known file formats -extern T_Format File_formats[]; - -/// -/// Function which attempts to save backups of the images (main and spare), -/// called in case of SIGSEGV. -/// It will save an image only if it has just one layer... otherwise, -/// the risk of flattening a layered image (or saving just one detail layer) -/// is too high. -void Image_emergency_backup(void); - -/// -/// Load an arbitrary SDL_Surface. -/// @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); - - -/* -/// Pixel ratio of last loaded image: one of :PIXEL_SIMPLE, :PIXEL_WIDE or :PIXEL_TALL -extern enum PIXEL_RATIO Ratio_of_loaded_image; -*/ - -T_Format * Get_fileformat(byte format); - -// -- File formats - -/// Total number of known file formats -unsigned int Nb_known_formats(void); - -// Internal use - -/// Generic allocation and similar stuff, done at beginning of image load, as soon as size is known. -void Pre_load(T_IO_Context *context, short width, short height, long file_size, int format, enum PIXEL_RATIO ratio, byte truecolor); -/// Remaps the window. To call after palette (last) changes. -void Palette_loaded(T_IO_Context *context); -/// Generic cleanup done on end of loading (ex: color-conversion from the temporary 24b buffer) -//void Post_load(T_IO_Context *context); - -/// Query the color of a pixel (to save) -byte Get_pixel(T_IO_Context *context, short x, short y); -/// Set the color of a pixel (on load) -void Set_pixel(T_IO_Context *context, short x, short y, byte c); -/// Set the color of a 24bit pixel (on load) -void Set_pixel_24b(T_IO_Context *context, short x, short y, byte r, byte g, byte b); -/// Function to call when need to switch layers. -void Set_layer(T_IO_Context *context, byte layer); - - -// ================================================================= -// What follows here are the definitions of functions and data -// useful for fileformats.c, miscfileformats.c etc. -// ================================================================= - -// This is here and not in fileformats.c because the emergency save uses it... -typedef struct -{ - byte Filler1[6]; - word Width; - word Height; - byte Filler2[118]; - T_Palette Palette; -} T_IMG_Header; - -// Data for 24bit loading - -/* -typedef void (* Func_24b_display) (short,short,byte,byte,byte); - -extern int Image_24b; -extern T_Components * Buffer_image_24b; -extern Func_24b_display Pixel_load_24b; - -void Init_preview_24b(short width,short height,long size,int format); -void Pixel_load_in_24b_preview(short x_pos,short y_pos,byte r,byte g,byte b); -*/ -// - -void Set_file_error(int value); - -/* -void Init_preview(short width,short height,long size,int format,enum PIXEL_RATIO ratio); -*/ -void Init_write_buffer(void); -void Write_one_byte(FILE *file, byte b); -void End_write(FILE *file); - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/main.c b/project/jni/application/grafx2/grafx2/src/main.c deleted file mode 100644 index 08685850f..000000000 --- a/project/jni/application/grafx2/grafx2/src/main.c +++ /dev/null @@ -1,966 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#define GLOBAL_VARIABLES - -// time.h defines timeval which conflicts with the one in amiga SDK -#ifdef __amigaos__ - #include -#else - #include -#endif - -#include -#include -#include -#include -#include -#include -#include - - -// There is no WM on the GP2X... -#if !defined(__GP2X__) && !defined(__WIZ__) && !defined(__CAANOO__) - #include -#endif - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "graph.h" -#include "misc.h" -#include "init.h" -#include "buttons.h" -#include "engine.h" -#include "pages.h" -#include "loadsave.h" -#include "sdlscreen.h" -#include "errors.h" -#include "readini.h" -#include "saveini.h" -#include "io.h" -#include "text.h" -#include "setup.h" -#include "windows.h" -#include "brush.h" -#include "palette.h" -#include "realpath.h" -#include "input.h" -#include "help.h" - -#if defined(__WIN32__) - #include - #include - #define chdir(dir) SetCurrentDirectory(dir) -#elif defined (__MINT__) - #include -#elif defined(__macosx__) - #import - #import -#elif defined(__FreeBSD__) - #import -#endif - - -#if defined (__WIN32__) - // On Windows, SDL_putenv is not present in any compilable header. - // It can be linked anyway, this declaration only avoids - // a compilation warning. - 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) -{ - int mode_index; - printf("Syntax: grafx2 [] [] []\n\n"); - printf(" can be:]\n"); - printf("\t-? -h -H -help for this help screen\n"); - printf("\t-wide to emulate a video mode with wide pixels (2x1)\n"); - printf("\t-tall to emulate a video mode with tall pixels (1x2)\n"); - printf("\t-double to emulate a video mode with double pixels (2x2)\n"); - printf("\t-wide2 to emulate a video mode with double wide pixels (4x2)\n"); - printf("\t-tall2 to emulate a video mode with double tall pixels (2x4)\n"); - printf("\t-triple to emulate a video mode with triple pixels (3x3)\n"); - printf("\t-quadruple to emulate a video mode with quadruple pixels (4x4)\n"); - printf("\t-rgb n to reduce RGB precision from 256 to n levels\n"); - printf("\t-skin to use an alternate file with the menu graphics\n"); - printf("\t-mode to set a video mode\n"); - printf("Arguments can be prefixed either by / - or --\n"); - printf("They can also be abbreviated.\n\n"); - printf("Available video modes:\n\n"); - for (mode_index = 0; mode_index < Nb_video_modes; mode_index += 12) - { - int k; - for (k = 0; k < 6; k++) - { - if (mode_index + k >= Nb_video_modes) break; - printf("%12s",Mode_label(mode_index + k)); - } - puts(""); - } -} - -// ---------------------------- Sortie impromptue ---------------------------- -void Warning_function(const char *message, const char *filename, int line_number, const char *function_name) -{ - printf("Warning in file %s, line %d, function %s : %s\n", filename, line_number, function_name, message); -} - - -// ---------------------------- Sortie impromptue ---------------------------- -void Error_function(int error_code, const char *filename, int line_number, const char *function_name) -{ - T_Palette temp_palette; - int index; - printf("Error number %d occured in file %s, line %d, function %s.\n", error_code, filename,line_number,function_name); - - if (error_code==0) - { - // L'erreur 0 n'est pas une vraie erreur, elle fait seulement un flash rouge de l'écran pour dire qu'il y a un problème. - // Toutes les autres erreurs déclenchent toujours une sortie en catastrophe du programme ! - memcpy(temp_palette,Main_palette,sizeof(T_Palette)); - for (index=0;index<=255;index++) - temp_palette[index].R=255; - Set_palette(temp_palette); - Delay_with_active_mouse(50); // Half a second of red flash - Set_palette(Main_palette); - } - else - { - switch (error_code) - { - case ERROR_GUI_MISSING : printf("Error: File containing the GUI graphics is missing!\n"); - printf("This program cannot run without this file.\n"); - break; - case ERROR_GUI_CORRUPTED : printf("Error: File containing the GUI graphics couldn't be parsed!\n"); - printf("This program cannot run without a correct version of this file.\n"); - break; - case ERROR_INI_MISSING : printf("Error: File gfx2def.ini is missing!\n"); - printf("This program cannot run without this file.\n"); - break; - case ERROR_MEMORY : printf("Error: Not enough memory!\n\n"); - printf("You should try exiting other programs to free some bytes for Grafx2.\n\n"); - break; - case ERROR_FORBIDDEN_MODE : printf("Error: The requested video mode has been disabled from the resolution menu!\n"); - printf("If you want to run the program in this mode, you'll have to start it with an\n"); - printf("enabled mode, then enter the resolution menu and enable the mode you want.\n"); - printf("Check also if the 'Default_video_mode' parameter in gfx2.ini is correct.\n"); - break; - case ERROR_COMMAND_LINE : printf("Error: Invalid parameter or file not found.\n\n"); - Display_syntax(); - break; - case ERROR_SAVING_CFG : printf("Error: Write error while saving settings!\n"); - printf("Settings have not been saved correctly, and the gfx2.cfg file may have been\n"); - printf("corrupt. If so, please delete it and Grafx2 will restore default settings.\n"); - break; - case ERROR_MISSING_DIRECTORY : printf("Error: Directory you ran the program from not found!\n"); - break; - case ERROR_INI_CORRUPTED : printf("Error: File gfx2.ini is corrupt!\n"); - printf("It contains bad values at line %d.\n",Line_number_in_INI_file); - printf("You can re-generate it by deleting the file and running GrafX2 again.\n"); - break; - case ERROR_SAVING_INI : printf("Error: Cannot rewrite file gfx2.ini!\n"); - break; - case ERROR_SORRY_SORRY_SORRY : printf("Error: Sorry! Sorry! Sorry! Please forgive me!\n"); - break; - } - - SDL_Quit(); - exit(error_code); - } -} - -enum CMD_PARAMS -{ - CMDPARAM_HELP, - CMDPARAM_MODE, - CMDPARAM_PIXELRATIO_TALL, - CMDPARAM_PIXELRATIO_WIDE, - CMDPARAM_PIXELRATIO_DOUBLE, - CMDPARAM_PIXELRATIO_TRIPLE, - CMDPARAM_PIXELRATIO_QUAD, - CMDPARAM_PIXELRATIO_TALL2, - CMDPARAM_PIXELRATIO_WIDE2, - CMDPARAM_RGB, - CMDPARAM_SKIN -}; - -struct { - const char *param; - int id; -} cmdparams[] = { - {"?", CMDPARAM_HELP}, - {"h", CMDPARAM_HELP}, - {"H", CMDPARAM_HELP}, - {"help", CMDPARAM_HELP}, - {"mode", CMDPARAM_MODE}, - {"tall", CMDPARAM_PIXELRATIO_TALL}, - {"wide", CMDPARAM_PIXELRATIO_WIDE}, - {"double", CMDPARAM_PIXELRATIO_DOUBLE}, - {"triple", CMDPARAM_PIXELRATIO_TRIPLE}, - {"quadruple", CMDPARAM_PIXELRATIO_QUAD}, - {"tall2", CMDPARAM_PIXELRATIO_TALL2}, - {"wide2", CMDPARAM_PIXELRATIO_WIDE2}, - {"rgb", CMDPARAM_RGB}, - {"skin", CMDPARAM_SKIN} -}; - -#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof(x[0])) - -// --------------------- Analyse de la ligne de commande --------------------- -int Analyze_command_line(int argc, char * argv[], char *main_filename, char *main_directory, char *spare_filename, char *spare_directory) -{ - char *buffer ; - int index; - int file_in_command_line; - - file_in_command_line = 0; - Resolution_in_command_line = 0; - - Current_resolution = Config.Default_resolution; - - for (index = 1; index 256) - { - Error(ERROR_COMMAND_LINE); - Display_syntax(); - exit(0); - } - Set_palette_RGB_scale(scale); - } - else - { - Error(ERROR_COMMAND_LINE); - Display_syntax(); - exit(0); - } - break; - case CMDPARAM_SKIN: - // GUI skin file - index++; - if (index 1) - { - // Il y a déjà 2 noms de fichiers et on vient d'en trouver un 3ème - Error(ERROR_COMMAND_LINE); - Display_syntax(); - exit(0); - } - else if (File_exists(argv[index])) - { - file_in_command_line ++; - buffer = Realpath(argv[index], NULL); - - if (file_in_command_line == 1) - { - // Separate path from filename - Extract_path(main_directory, buffer); - Extract_filename(main_filename, buffer); - } - else - { - // Separate path from filename - Extract_path(spare_directory, buffer); - Extract_filename(spare_filename, buffer); - } - free(buffer); - buffer = NULL; - } - else - { - Error(ERROR_COMMAND_LINE); - Display_syntax(); - exit(0); - } - break; - } - } - 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 à - // l'initialisation du programme. - Main_backups=(T_List_of_pages *)malloc(sizeof(T_List_of_pages)); - Spare_backups=(T_List_of_pages *)malloc(sizeof(T_List_of_pages)); - Init_list_of_pages(Main_backups); - Init_list_of_pages(Spare_backups); - - // Determine the executable directory - Set_program_directory(argv[0],program_directory); - // Choose directory for data (read only) - Set_data_directory(program_directory,Data_directory); - // Choose directory for settings (read/write) - Set_config_directory(program_directory,Config_directory); -#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); - - // On initialise les données sur le nom de fichier de l'image de brouillon: - strcpy(Spare_current_directory,Main_current_directory); - - Main_fileformat=DEFAULT_FILEFORMAT; - Spare_fileformat =Main_fileformat; - - strcpy(Brush_current_directory,Main_current_directory); - strcpy(Brush_file_directory,Main_current_directory); - strcpy(Brush_filename ,"NO_NAME.GIF"); - Brush_fileformat =Main_fileformat; - - // On initialise ce qu'il faut pour que les fileselects ne plantent pas: - - Main_fileselector_position=0; // Au début, le fileselect est en haut de la liste des fichiers - Main_fileselector_offset=0; // Au début, le fileselect est en haut de la liste des fichiers - Main_format=FORMAT_ALL_IMAGES; - Main_current_layer=0; - Main_layers_visible=0xFFFFFFFF; - Spare_current_layer=0; - Spare_layers_visible=0xFFFFFFFF; - - Spare_fileselector_position=0; - Spare_fileselector_offset=0; - Spare_format=FORMAT_ALL_IMAGES; - Brush_fileselector_position=0; - Brush_fileselector_offset=0; - Brush_format=FORMAT_ALL_IMAGES; - - // On initialise les commentaires des images à des chaînes vides - Main_comment[0]='\0'; - Brush_comment[0]='\0'; - - // On initialise d'ot' trucs - Main_offset_X=0; - Main_offset_Y=0; - Main_separator_position=0; - Main_X_zoom=0; - Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; - Main_magnifier_mode=0; - Main_magnifier_factor=DEFAULT_ZOOM_FACTOR; - Main_magnifier_height=0; - Main_magnifier_width=0; - Main_magnifier_offset_X=0; - Main_magnifier_offset_Y=0; - Spare_offset_X=0; - Spare_offset_Y=0; - Spare_separator_position=0; - Spare_X_zoom=0; - Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; - Spare_magnifier_mode=0; - Spare_magnifier_factor=DEFAULT_ZOOM_FACTOR; - Spare_magnifier_height=0; - Spare_magnifier_width=0; - Spare_magnifier_offset_X=0; - Spare_magnifier_offset_Y=0; - Keyboard_click_allowed = 1; - - 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_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"); - Define_icon(); - - // Texte - Init_text(); - - // On initialise tous les modes vidéo - Set_all_video_modes(); - Pixel_ratio=PIXEL_SIMPLE; - // On initialise les données sur l'état du programme: - // Donnée sur la sortie du programme: - Quit_is_required=0; - Quitting=0; - // Données sur l'état du menu: - Menu_is_visible=1; - // Données sur les couleurs et la palette: - First_color_in_palette=0; - // Données sur le curseur: - Cursor_shape=CURSOR_SHAPE_TARGET; - Cursor_hidden=0; - // Données sur le pinceau: - Paintbrush_X=0; - Paintbrush_Y=0; - Paintbrush_hidden=0; - - // On initialise tout ce qui concerne les opérations et les effets - Operation_stack_size=0; - Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW; - Selected_line_mode =OPERATION_LINE; - Selected_curve_mode =OPERATION_3_POINTS_CURVE; - Effect_function=No_effect; - // On initialise les infos de la loupe: - Main_magnifier_mode=0; - Main_magnifier_factor=DEFAULT_ZOOM_FACTOR; - Main_separator_proportion=INITIAL_SEPARATOR_PROPORTION; - Spare_separator_proportion=INITIAL_SEPARATOR_PROPORTION; - // On initialise les infos du mode smear: - Smear_mode=0; - Smear_brush_width=PAINTBRUSH_WIDTH; - Smear_brush_height=PAINTBRUSH_HEIGHT; - // On initialise les infos du mode smooth: - Smooth_mode=0; - // On initialise les infos du mode shade: - Shade_mode=0; // Les autres infos du Shade sont chargées avec la config - Quick_shade_mode=0; // idem - // On initialise les infos sur les dégradés: - Gradient_pixel =Display_pixel; // Les autres infos sont chargées avec la config - // On initialise les infos de la grille: - Snap_mode=0; - Snap_width=8; - Snap_height=8; - Snap_offset_X=0; - Snap_offset_Y=0; - // On initialise les infos du mode Colorize: - Colorize_mode=0; // Mode colorize inactif par défaut - Colorize_opacity=50; // Une interpolation de 50% par défaut - Colorize_current_mode=0; // Par défaut, la méthode par interpolation - Compute_colorize_table(); - // On initialise les infos du mode Tiling: - Tiling_mode=0; // Pas besoin d'initialiser les décalages car ça se fait - // en prenant une brosse (toujours mis à 0). - // On initialise les infos du mode Mask: - Mask_mode=0; - - // Infos du Spray - Airbrush_mode=1; // Mode Mono - Airbrush_size=31; - Airbrush_delay=1; - Airbrush_mono_flow=10; - memset(Airbrush_multi_flow,0,256); - srand(time(NULL)); // On randomize un peu tout ça... - - // Initialisation des boutons - Init_buttons(); - // Initialisation des opérations - Init_operations(); - - // Initialize the brush container - Init_brush_container(); - - 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(); - - switch(Load_CFG(1)) - { - case ERROR_CFG_MISSING: - // Pas un problème, on a les valeurs par défaut. - break; - case ERROR_CFG_CORRUPTED: - DEBUG("Corrupted CFG file.",0); - break; - case ERROR_CFG_OLD: - DEBUG("Unknown CFG file version, not loaded.",0); - break; - } - // Charger la configuration du .INI - temp=Load_INI(&Config); - if (temp) - Error(temp); - - if(!Config.Allow_multi_shortcuts) - { - Remove_duplicate_shortcuts(); - } - - Compute_menu_offsets(); - - file_in_command_line=Analyze_command_line(argc, argv, main_filename, main_directory, spare_filename, spare_directory); - - Current_help_section=0; - Help_position=0; - - // Load sprites, palette etc. - gfx = Load_graphics(Config.Skin_file, &initial_gradients); - if (gfx == NULL) - { - gfx = Load_graphics(DEFAULT_SKIN_FILENAME, &initial_gradients); - if (gfx == NULL) - { - printf("%s", Gui_loading_error_message); - Error(ERROR_GUI_MISSING); - } - } - Set_current_skin(Config.Skin_file, gfx); - // Override colors - // Gfx->Default_palette[MC_Black]=Config.Fav_menu_colors[0]; - // 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]; - - // 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; - Copy_preset_sieve(0); - - // Font - if (!(Menu_font=Load_font(Config.Font_file))) - if (!(Menu_font=Load_font(DEFAULT_FONT_FILENAME))) - { - printf("Unable to open the default font file: %s\n", DEFAULT_FONT_FILENAME); - Error(ERROR_GUI_MISSING); - } - - memcpy(Main_palette, Gfx->Default_palette, sizeof(T_Palette)); - - Fore_color=Best_color_nonexcluded(255,255,255); - Back_color=Best_color_nonexcluded(0,0,0); - - // Allocation de mémoire pour la brosse - if (!(Brush =(byte *)malloc( 1* 1))) Error(ERROR_MEMORY); - if (!(Smear_brush =(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE))) Error(ERROR_MEMORY); - - - starting_videomode=Current_resolution; - Horizontal_line_buffer=NULL; - Screen_width=Screen_height=Current_resolution=0; - - Init_mode_video( - Video_mode[starting_videomode].Width, - Video_mode[starting_videomode].Height, - Video_mode[starting_videomode].Fullscreen, - Pixel_ratio); - - // Windows only: move back the window to its original position. - #if defined(__WIN32__) - if (!Video_mode[starting_videomode].Fullscreen) - { - if (Config.Window_pos_x != 9999 && Config.Window_pos_y != 9999) - { - //RECT r; - static SDL_SysWMinfo pInfo; - SDL_VERSION(&pInfo.version); - SDL_GetWMInfo(&pInfo); - //GetWindowRect(pInfo.window, &r); - 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; - Main_image_height=Screen_height/Pixel_height; - Spare_image_width=Screen_width/Pixel_width; - Spare_image_height=Screen_height/Pixel_height; - - // Allocation de mémoire pour les différents écrans virtuels (et brosse) - if (Init_all_backup_lists(Screen_width,Screen_height)==0) - Error(ERROR_MEMORY); - - // 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_paintbrush_in_menu(); - 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(); - - Spare_image_is_modified=0; - Main_image_is_modified=0; - - // Gestionnaire de signaux, quand il ne reste plus aucun espoir - Init_sighandler(); - - // Le programme débute en mode de dessin à la main - Select_button(BUTTON_DRAW,LEFT_SIDE); - - // 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()) - { - T_IO_Context context; - - default: - // Some files were loaded from last crash-exit. - // Do not load files from command-line, nor show splash screen. - Compute_optimal_menu_colors(Main_palette); - Display_all_screen(); - Display_menu(); - Display_cursor(); - Verbose_message("Images recovered", - "Grafx2 has recovered images from\n" - "last session, before a crash or\n" - "shutdown. Browse the history using\n" - "the Undo/Redo button, and when\n" - "you find a state that you want to\n" - "save, use the 'Save as' button to\n" - "save the image.\n" - "Some backups can be present in\n" - "the spare page too.\n"); - break; - - case -1: // Unable to write lock file - Verbose_message("Warning", - "Safety backups (every minute) are\n" - "disabled because Grafx2 is running\n" - "from a read-only device, or other\n" - "instances are running."); - break; - - case 0: - - switch (file_in_command_line) - { - case 0: - if (Config.Opening_message) - Button_Message_initial(); - break; - - case 2: - // Load this file - Init_context_layered_image(&context, spare_filename, spare_directory); - Load_image(&context); - Destroy_context(&context); - Redraw_layered_image(); - End_of_modification(); - - Button_Page(); - // no break ! proceed with the other file now - case 1: - Init_context_layered_image(&context, main_filename, main_directory); - Load_image(&context); - Destroy_context(&context); - Redraw_layered_image(); - End_of_modification(); - - Hide_cursor(); - Compute_optimal_menu_colors(Main_palette); - Display_all_screen(); - Display_menu(); - Display_cursor(); - Resolution_in_command_line = 0; - break; - - default: - break; - } - } - - Allow_drag_and_drop(1); - - return(1); -} - -// ------------------------- Fermeture du programme -------------------------- -void Program_shutdown(void) -{ - int return_code; - - // Windows only: Recover the window position. - #if defined(__WIN32__) - { - RECT r; - static SDL_SysWMinfo pInfo; - - SDL_GetWMInfo(&pInfo); - GetWindowRect(pInfo.window, &r); - - Config.Window_pos_x = r.left; - Config.Window_pos_y = r.top; - } - #else - // All other targets: irrelevant dimensions. - // Do not attempt to force them back on next program run. - Config.Window_pos_x = 9999; - Config.Window_pos_y = 9999; - #endif - - // Remove the safety backups, this is normal exit - Delete_safety_backups(); - - // On libère le buffer de gestion de lignes - free(Horizontal_line_buffer); - Horizontal_line_buffer = NULL; - - // On libère le pinceau spécial - free(Paintbrush_sprite); - Paintbrush_sprite = NULL; - - // On libère les différents écrans virtuels et brosse: - free(Brush); - Brush = NULL; - Set_number_of_backups(0); - - // Free the skin (Gui graphics) data - free(Gfx); - Gfx=NULL; - - // On prend bien soin de passer dans le répertoire initial: - if (chdir(Initial_directory)!=-1) - { - // On sauvegarde les données dans le .CFG et dans le .INI - if (Config.Auto_save) - { - return_code=Save_CFG(); - if (return_code) - Error(return_code); - return_code=Save_INI(&Config); - if (return_code) - Error(return_code); - } - } - else - 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 - -} - - -// -------------------------- Procédure principale --------------------------- -int main(int argc,char * argv[]) -{ - - if(!Init_program(argc,argv)) - { - Program_shutdown(); - return 0; - } - - Main_handler(); - - Program_shutdown(); - return 0; -} diff --git a/project/jni/application/grafx2/grafx2/src/misc.c b/project/jni/application/grafx2/grafx2/src/misc.c deleted file mode 100644 index f69531615..000000000 --- a/project/jni/application/grafx2/grafx2/src/misc.c +++ /dev/null @@ -1,880 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include -#include -#include -#include -#include "struct.h" -#include "sdlscreen.h" -#include "global.h" -#include "errors.h" -#include "buttons.h" -#include "engine.h" -#include "misc.h" -#include "keyboard.h" -#include "sdlscreen.h" -#include "windows.h" -#include "palette.h" -#include "input.h" -#include "graph.h" -#include "pages.h" - -///Count used palette indexes in the whole picture -///Return the total number of different colors -///Fill in "usage" with the count for each color -word Count_used_colors(dword* usage) -{ - int nb_pixels = 0; - Uint8* current_pixel; - Uint8 color; - word nb_colors = 0; - int i; - int layer; - - for (i = 0; i < 256; i++) usage[i]=0; - - // Compute total number of pixels in the picture - nb_pixels = Main_image_height * Main_image_width; - - // For each layer - for (layer = 0; layer < Main_backups->Pages->Nb_layers; layer++) - { - current_pixel = Main_backups->Pages->Image[layer]; - // For each pixel in picture - for (i = 0; i < nb_pixels; i++) - { - color=*current_pixel; // get color in picture for this pixel - - usage[color]++; // add it to the counter - - // go to next pixel - current_pixel++; - } - } - - // count the total number of unique used colors - for (i = 0; i < 256; i++) - { - if (usage[i]!=0) - nb_colors++; - } - - return nb_colors; -} - -/// Same as ::Count_used_colors, but use a block screen memory instead of -/// picture data. Used to count colors in the loading screen. -word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, - word width, word height) -{ - Uint8 color; - word x, y; - word nb_colors = 0; - int i; - - // Init usage table - for (i = 0; i < 256; i++) usage[i]=0; - - // For each pixel in screen area - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - // Get color in screen memory - color=*(Screen_pixels+((start_x + x)+(start_y + y) * Screen_width - * Pixel_height) * Pixel_width); - usage[color]++; //Un point de plus pour cette couleur - } - } - //On va maintenant compter dans la table les couleurs utilisées: - for (i = 0; i < 256; i++) - { - if (usage[i]!=0) - nb_colors++; - } - return nb_colors; -} - - -/// Same as ::Count_used_colors, but for a given rectangle in the picture only. -/// Used bu the C64 block constraint checker. -word Count_used_colors_area(dword* usage, word start_x, word start_y, - word width, word height) -{ - Uint8 color; - word x, y; - word nb_colors = 0; - int i; - - // Init usage table - for (i = 0; i < 256; i++) usage[i]=0; - - // On parcourt l'écran courant pour compter les utilisations des couleurs - for (y = 0; y < height; y++) - { - for (x = 0; x < width; x++) - { - // Get color from picture - color=*(Main_screen+((start_x + x)+(start_y + y)*Main_image_width)); - usage[color]++; //Un point de plus pour cette couleur - } - } - - //On va maintenant compter dans la table les couleurs utilisées: - for (i = 0; i < 256; i++) - { - if (usage[i]!=0) - nb_colors++; - } - return nb_colors; -} - - -void Set_palette(T_Palette palette) -{ - register int i; - SDL_Color PaletteSDL[256]; - for(i=0;i<256;i++) - { - PaletteSDL[i].r=(palette[i].R=Round_palette_component(palette[i].R)); - PaletteSDL[i].g=(palette[i].G=Round_palette_component(palette[i].G)); - PaletteSDL[i].b=(palette[i].B=Round_palette_component(palette[i].B)); - } - SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, PaletteSDL,0,256); -} - -void Set_color(byte color, byte red, byte green, byte blue) -{ - SDL_Color comp; - comp.r=red; - comp.g=green; - comp.b=blue; - SDL_SetPalette(Screen_SDL, SDL_PHYSPAL | SDL_LOGPAL, &comp, color, 1); -} - -void Wait_end_of_click(void) -{ - // On désactive tous les raccourcis clavier - - while(Mouse_K) - Get_input(20); -} - -void Clear_current_image_with_stencil(byte color, byte * stencil) - //Effacer l'image courante avec une certaine couleur en mode Stencil -{ - int nb_pixels=0; //ECX - //al=color - //edi=Screen_pixels - byte* pixel=Main_backups->Pages->Image[Main_current_layer]; - int i; - - nb_pixels=Main_image_height*Main_image_width; - - for(i=0;iPages->Image[Main_current_layer], - color , - Main_image_width * Main_image_height - ); -} - -void Init_chrono(dword delay) - // Démarrer le chrono -{ - Timer_delay = delay; - Timer_start = SDL_GetTicks()/55; - return; -} - -void Pixel_in_brush (word x, word y, byte color) -{ - *(Brush + y * Brush_width + x)=color; -} - -byte Read_pixel_from_brush (word x, word y) -{ - return *(Brush + y * Brush_width + x); -} - -void Replace_a_color(byte old_color, byte new_color) -{ - word x; - word y; - - // Update all pixels - for (y=0; y=Spare_image_width || y>=Spare_image_height) - return Spare_backups->Pages->Transparent_color; -#ifndef NOLAYERS - return *(Spare_visible_image.Image + y*Spare_image_width + x); -#else - return *(Spare_backups->Pages->Image[Spare_current_layer] + y*Spare_image_width + x); -#endif - -} - -void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height) -{ - word x,y; - - for(y=0;y0;dx--) - { - // Pour chaque pixel - for(cx=width;cx>0;cx--) - { - *out_buffer = conversion_table[*in_buffer]; - in_buffer++; - out_buffer++; - } - 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_original_pixels; //Adr dest brosse (EDI) - int dx; - - for (dx=Brush_height;dx!=0;dx--) - //Pour chaque ligne - { - - // On fait une copie de la ligne - memcpy(dest,src,Brush_width); - - // On passe à la ligne suivante - src+=image_width; - dest+=Brush_width; - } - -} - -byte Read_pixel_from_feedback_screen (word x,word y) -{ - return *(FX_feedback_screen+y*Main_image_width+x); -} - -dword Round_div(dword numerator,dword divisor) -{ - return numerator/divisor; -} - -byte Effect_sieve(word x,word y) -{ - return Sieve[x % Sieve_width][y % Sieve_height]; -} - -void Replace_colors_within_limits(byte * replace_table) -{ - int y; - int x; - byte* pixel; - - // Pour chaque ligne : - for(y = Limit_top;y <= Limit_bottom; y++) - { - // Pour chaque pixel sur la ligne : - for (x = Limit_left;x <= Limit_right;x ++) - { - pixel = Main_backups->Pages->Image[Main_current_layer]+y*Main_image_width+x; - *pixel = replace_table[*pixel]; - } - } -} - -byte Read_pixel_from_backup_screen (word x,word y) -{ - return *(Screen_backup + x + Main_image_width * y); -} - -void Palette_256_to_64(T_Palette palette) -{ - int i; - for(i=0;i<256;i++) - { - palette[i].R = palette[i].R >> 2; - palette[i].G = palette[i].G >> 2; - palette[i].B = palette[i].B >> 2; - } -} - -void Palette_64_to_256(T_Palette palette) -{ - int i; - for(i=0;i<256;i++) - { - palette[i].R = (palette[i].R << 2)|(palette[i].R >> 4); - palette[i].G = (palette[i].G << 2)|(palette[i].G >> 4); - palette[i].B = (palette[i].B << 2)|(palette[i].B >> 4); - } -} - -byte Effect_interpolated_colorize (word x,word y,byte color) -{ - // factor_a = 256*(100-Colorize_opacity)/100 - // factor_b = 256*( Colorize_opacity)/100 - // - // (Couleur_dessous*factor_a+color*facteur_B)/256 - // - - // On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la - // palette des teintes) et dans EDI, 3*color. - byte color_under = Read_pixel_from_feedback_screen(x,y); - byte blue_under=Main_palette[color_under].B; - byte blue=Main_palette[color].B; - byte green_under=Main_palette[color_under].G; - byte green=Main_palette[color].G; - byte red_under=Main_palette[color_under].R; - byte red=Main_palette[color].R; - - // On récupère les 3 composantes RVB - - // blue - blue = (Factors_inv_table[blue] - + Factors_table[blue_under]) / 256; - green = (Factors_inv_table[green] - + Factors_table[green_under]) / 256; - red = (Factors_inv_table[red] - + Factors_table[red_under]) / 256; - return Best_color(red,green,blue); - -} - -byte Effect_additive_colorize (word x,word y,byte color) -{ - byte color_under = Read_pixel_from_feedback_screen(x,y); - byte blue_under=Main_palette[color_under].B; - byte green_under=Main_palette[color_under].G; - byte red_under=Main_palette[color_under].R; - byte blue=Main_palette[color].B; - byte green=Main_palette[color].G; - byte red=Main_palette[color].R; - - return Best_color( - red>red_under?red:red_under, - green>green_under?green:green_under, - blue>blue_under?blue:blue_under); -} - -byte Effect_substractive_colorize(word x,word y,byte color) -{ - byte color_under = Read_pixel_from_feedback_screen(x,y); - byte blue_under=Main_palette[color_under].B; - byte green_under=Main_palette[color_under].G; - byte red_under=Main_palette[color_under].R; - byte blue=Main_palette[color].B; - byte green=Main_palette[color].G; - byte red=Main_palette[color].R; - - return Best_color( - redTimer_start) Timer_state=1; -} - -void Flip_Y_lowlevel(byte *src, short width, short height) -{ - // ESI pointe sur la partie haute de la brosse - // EDI sur la partie basse - byte* ESI = src ; - byte* EDI = src + (height - 1) *width; - byte tmp; - word cx; - - while(ESI < EDI) - { - // Il faut inverser les lignes pointées par ESI et - // EDI ("Brush_width" octets en tout) - - for(cx = width;cx>0;cx--) - { - tmp = *ESI; - *ESI = *EDI; - *EDI = tmp; - ESI++; - EDI++; - } - - // On change de ligne : - // ESI pointe déjà sur le début de la ligne suivante - // EDI pointe sur la fin de la ligne en cours, il - // doit pointer sur le début de la précédente... - EDI -= 2 * width; // On recule de 2 lignes - } -} - -void Flip_X_lowlevel(byte *src, short width, short height) -{ - // ESI pointe sur la partie gauche et EDI sur la partie - // droite - byte* ESI = src; - byte* EDI = src + width - 1; - - byte* line_start; - byte* line_end; - byte tmp; - word cx; - - while(ESI0;cx--) - { - tmp=*ESI; - *ESI=*EDI; - *EDI=tmp; - EDI+=width; - ESI+=width; - } - - // On change de colonne - // ESI > colonne suivante - // EDI > colonne précédente - ESI = line_start + 1; - EDI = line_end - 1; - } -} - -// Rotate a pixel buffer 180º on itself. -void Rotate_180_deg_lowlevel(byte *src, short width, short height) -{ - // ESI pointe sur la partie supérieure de la brosse - // EDI pointe sur la partie basse - byte* ESI = src; - byte* EDI = src + height*width - 1; - // EDI pointe sur le dernier pixel de la derniere ligne - byte tmp; - word cx; - - // In case of odd height, the algorithm in this function would - // miss the middle line, so we do it this way: - if (height & 1) - { - Flip_X_lowlevel(src, width, height); - Flip_Y_lowlevel(src, width, height); - return; - } - - - while(ESI < EDI) - { - // On échange les deux lignes pointées par EDI et - // ESI (Brush_width octets) - // En même temps, on échange les pixels, donc EDI - // pointe sur la FIN de sa ligne - - for(cx=width;cx>0;cx--) - { - tmp = *ESI; - *ESI = *EDI; - *EDI = tmp; - - EDI--; // Attention ici on recule ! - ESI++; - } - } -} - -void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped) -{ - int offset,line,column; - - int x_pos_in_brush; // Position courante dans l'ancienne brosse - int y_pos_in_brush; - int delta_x_in_brush; // "Vecteur incrémental" du point précédent - int delta_y_in_brush; - int initial_x_pos; // Position X de début de parcours de ligne - - // Calcul du "vecteur incrémental": - delta_x_in_brush=(src_width<<16) * (x_flipped?-1:1) / (dst_width); - delta_y_in_brush=(src_height<<16) * (y_flipped?-1:1) / (dst_height); - - offset=0; - - // Calcul de la valeur initiale de y_pos: - if (y_flipped) - y_pos_in_brush=(src_height<<16)-1; // Inversion en Y de la brosse - else - y_pos_in_brush=0; // Pas d'inversion en Y de la brosse - - // Calcul de la valeur initiale de x_pos pour chaque ligne: - if (x_flipped) - initial_x_pos = (src_width<<16)-1; // Inversion en X de la brosse - else - initial_x_pos = 0; // Pas d'inversion en X de la brosse - - // Pour chaque ligne - for (line=0;line>16) + (y_pos_in_brush>>16)*src_width); - // On passe à la colonne de brosse suivante: - x_pos_in_brush+=delta_x_in_brush; - // On passe au pixel suivant de la nouvelle brosse: - offset++; - } - // On passe à la ligne de brosse suivante: - y_pos_in_brush+=delta_y_in_brush; - } -} - - -void Scroll_picture(byte * main_src, byte * main_dest, short x_offset,short y_offset) -{ - byte* src = main_src; //source de la copie - byte* dest = main_dest + y_offset * Main_image_width + x_offset; - const word length = Main_image_width - x_offset; // Nombre de pixels à copier à droite - word y; - for(y = Main_image_height - y_offset;y>0;y--) - { - // Pour chaque ligne - memcpy(dest,src,length); - memcpy(dest - x_offset,src+length,x_offset); - - // On passe à la ligne suivante - dest += Main_image_width; - src += Main_image_width; - } - - // On vient de faire le traitement pour otutes les lignes au-dessous de y_offset - // Maintenant on traite celles au dessus - dest = x_offset + main_dest; - for(y = y_offset;y>0;y--) - { - memcpy(dest,src,length); - memcpy(dest - x_offset,src+length,x_offset); - - dest += Main_image_width; - src += Main_image_width; - } - - Update_rect(0,0,0,0); -} - -void Zoom_a_line(byte* original_line, byte* zoomed_line, - word factor, word width - ) -{ - byte color; - word x; - - // Pour chaque pixel - for(x=0;x -#elif defined(__macosx__) || defined(__FreeBSD__) || defined(__NetBSD__) - #include -#elif defined(__BEOS__) || defined(__HAIKU__) - // sysinfo not implemented -#elif defined(__AROS__) || defined(__amigaos4__) || defined(__MORPHOS__) || defined(__amigaos__) - #include -#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) -{ - // Memory is no longer relevant. If there is ANY problem or doubt here, - // you can simply return 10*1024*1024 (10Mb), to make the "Pages"something - // memory allocation functions happy. - - // However, it is still a good idea to make a proper function if you can... - // If Grafx2 thinks the memory is full, weird things may happen. And if memory - // ever becomes full and you're still saying there are 10MB free here, the - // program will crash without saving any picture backup ! You've been warned... -#if defined(__WIN32__) - MEMORYSTATUS mstt; - mstt.dwLength = sizeof(MEMORYSTATUS); - GlobalMemoryStatus(&mstt); - return mstt.dwAvailPhys; -#elif defined(__macosx__) || defined(__FreeBSD__) || defined(__NetBSD__) - int mib[2]; - int maxmem; - size_t len; - - mib[0] = CTL_HW; - mib[1] = HW_USERMEM; - len = sizeof(maxmem); - sysctl(mib,2,&maxmem,&len,NULL,0); - return maxmem; -#elif defined(__BEOS__) || defined(__HAIKU__) || defined(__SKYOS__) || defined(__amigaos4__) || defined(__TRU64__) || defined(ANDROID) - // No on BeOS or Haiku - // AvailMem is misleading on os4 (os4 caches stuff in memory that you can still allocate) -#warning "There is missing code there for your platform ! please check and correct :)" - return 10*1024*1024; -#elif defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - return AvailMem(MEMF_ANY); -#else - struct sysinfo info; - sysinfo(&info); - return info.freeram*info.mem_unit; -#endif -} -#endif - - - -// Arrondir un nombre réel à la valeur entière la plus proche -// TODO : this should probably be replaced with round() from C99... -short Round(float value) -{ - short temp=value; - - if (value>=0) - { if ((value-temp)>= 0.5) temp++; } - else - { if ((value-temp)<=-0.5) temp--; } - - return temp; -} - - -// Arrondir le résultat d'une division à la valeur entière supérieure -short Round_div_max(short numerator,short divisor) -{ - if (!(numerator % divisor)) - return (numerator/divisor); - else - return (numerator/divisor)+1; -} - - -// Retourne le minimum entre deux nombres -int Min(int a,int b) -{ - return (ab)?a:b; -} - -/* Round number n to d decimal points */ -double Fround(double n, unsigned d) -{ - double exp; - exp = pow(10.0, d); - return floor(n * exp + 0.5) / exp; -} - - -// Fonction retournant le libellé d'une mode (ex: " 320x200") -char * Mode_label(int mode) -{ - static char str[24]; - if (! Video_mode[mode].Fullscreen) - return "window"; - sprintf(str, "%dx%d", Video_mode[mode].Width, Video_mode[mode].Height); - - return str; -} - - -// Trouve un mode video à partir d'une chaine: soit "window", -// soit de la forme "320x200" -// Renvoie -1 si la chaine n'est pas convertible -int Convert_videomode_arg(const char *argument) -{ - // Je suis paresseux alors je vais juste tester les libellés - int mode_index; - for (mode_index=0; mode_index -*/ -////////////////////////////////////////////////////////////////////////////// -///@file misc.h -/// Miscellanous unsorted functions. -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - -#define SWAP_BYTES(a,b) { byte c=a; a=b; b=c;} -#define SWAP_WORDS(a,b) { word c=a; a=b; b=c;} -#define SWAP_DWORDS(a,b) { dword c=a; a=b; b=c;} -#define SWAP_SHORTS(a,b) { short c=a; a=b; b=c;} -#define SWAP_FLOATS(a,b) { float c=a; a=b; b=c;} -#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 * 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); -void Set_palette(T_Palette palette); -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); -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); -word Count_used_colors_screen_area(dword* usage, word start_x, word start_y, word width, word height); -void Pixel_in_brush (word x,word y,byte color); -byte Read_pixel_from_spare_screen(word x,word y); -byte Read_pixel_from_backup_screen (word x,word y); -byte Read_pixel_from_feedback_screen (word x,word y); -byte Read_pixel_from_brush (word x,word y); - -void Ellipse_compute_limites(short horizontal_radius,short vertical_radius); -// Calcule les valeurs suivantes en fonction des deux paramètres: -// -// Ellipse_vertical_radius_squared -// Ellipse_horizontal_radius_squared -// Ellipse_Limit_High -// Ellipse_Limit_Low - - -byte Pixel_in_ellipse(void); -// Indique si le pixel se trouvant à Ellipse_cursor_X pixels -// (Ellipse_cursor_X>0 = à droite, Ellipse_cursor_X<0 = à gauche) et à -// Ellipse_cursor_Y pixels (Ellipse_cursor_Y>0 = en bas, -// Ellipse_cursor_Y<0 = en haut) du centre se trouve dans l'ellipse en -// cours. - -byte Pixel_in_circle(void); -// Indique si le pixel se trouvant à Circle_cursor_X pixels -// (Circle_cursor_X>0 = à droite, Circle_cursor_X<0 = à gauche) et à -// Circle_cursor_Y pixels (Circle_cursor_Y>0 = en bas, -// Circle_cursor_Y<0 = en haut) du centre se trouve dans le cercle en -// cours. - -// Gestion du chrono dans les fileselects -void Init_chrono(dword delay); -void Check_timer(void); - -void Replace_a_color(byte old_color, byte New_color); -void Replace_colors_within_limits(byte * replace_table); - -byte Effect_interpolated_colorize (word x,word y,byte color); -byte Effect_additive_colorize (word x,word y,byte color); -byte Effect_substractive_colorize(word x,word y,byte color); -byte Effect_alpha_colorize(word x,word y,byte color); -byte Effect_sieve(word x,word y); - -/// -/// Inverts a pixel buffer, according to a horizontal axis. -/// @param src Pointer to the pixel buffer to process. -/// @param width Width of the buffer. -/// @param height Height of the buffer. -void Flip_Y_lowlevel(byte *src, short width, short height); - -/// -/// Inverts a pixel buffer, according to a vertical axis. -/// @param src Pointer to the pixel buffer to process. -/// @param width Width of the buffer. -/// @param height Height of the buffer. -void Flip_X_lowlevel(byte *src, short width, short height); -/// -/// Rotate a pixel buffer by 90 degrees, clockwise. -/// @param source Source pixel buffer. -/// @param dest Destination pixel buffer. -/// @param width Width of the original buffer (height of the destination one). -/// @param height Height of the original buffer (width of the destination one). -void Rotate_90_deg_lowlevel(byte * source, byte * dest, short width, short height); -/// -/// Rotate a pixel buffer by 90 degrees, counter-clockwise. -/// @param source Source pixel buffer. -/// @param dest Destination pixel buffer. -/// @param width Width of the original buffer (height of the destination one). -/// @param height Height of the original buffer (width of the destination one). -void Rotate_270_deg_lowlevel(byte * source, byte * dest, short width, short height); -/// -/// Rotate a pixel buffer by 180 degrees. -/// @param src The pixel buffer (source and destination). -/// @param width Width of the buffer. -/// @param height Height of the buffer. -void Rotate_180_deg_lowlevel(byte *src, short width, short height); - -/// -/// Copies an image to another, rescaling it and optionally flipping it. -/// @param src_buffer Original image (address of first byte) -/// @param src_width Original image's width in pixels -/// @param src_height Original image's height in pixels -/// @param dst_buffer Destination image (address of first byte) -/// @param dst_width Destination image's width in pixels -/// @param dst_height Destination image's height in pixels -/// @param x_flipped Boolean, true to flip the image horizontally -/// @param y_flipped Boolean, true to flip the image vertically -void Rescale(byte *src_buffer, short src_width, short src_height, byte *dst_buffer, short dst_width, short dst_height, short x_flipped, short y_flipped); - -void Zoom_a_line(byte * original_line,byte * zoomed_line,word factor,word width); -void Copy_part_of_image_to_another(byte * source,word source_x,word source_y,word width,word height,word source_width,byte * dest,word dest_x,word dest_y,word destination_width); - -// -- Gestion du chrono -- -byte Timer_state; // State du chrono: 0=Attente d'un Xème de seconde - // 1=Il faut afficher la preview - // 2=Plus de chrono à gerer pour l'instant -dword Timer_delay; // Nombre de 18.2ème de secondes demandés -dword Timer_start; // Heure de départ du chrono -byte New_preview_is_needed; // Booléen "Il faut relancer le chrono de preview" - - -unsigned long Memory_free(void); - -#define Num2str(a,b,c) sprintf(b,"%*lu",c,(long)(a)) - -#define Dec2str(a,b,c) sprintf(b,"%.*f",c,(double)(a)) - -short Round(float value); -short Round_div_max(short numerator,short divisor); - -/* round number n to d decimal points */ -double Fround(double n, unsigned d); - - - -int Min(int a,int b); -int Max(int a,int b); - -char* Mode_label(int mode); -int Convert_videomode_arg(const char *argument); diff --git a/project/jni/application/grafx2/grafx2/src/miscfileformats.c b/project/jni/application/grafx2/grafx2/src/miscfileformats.c deleted file mode 100644 index 7715cea19..000000000 --- a/project/jni/application/grafx2/grafx2/src/miscfileformats.c +++ /dev/null @@ -1,2701 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -///@file miscfileformats.c -/// Formats that aren't fully saving, either because of palette restrictions or other things - -#include -#include - -#include "engine.h" -#include "errors.h" -#include "global.h" -#include "io.h" -#include "libraw2crtc.h" -#include "limits.h" -#include "loadsave.h" -#include "misc.h" -#include "sdlscreen.h" -#include "struct.h" -#include "windows.h" - -//////////////////////////////////// PAL //////////////////////////////////// -// - -// -- Tester si un fichier est au format PAL -------------------------------- -void Test_PAL(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - long file_size; // Taille du fichier - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error = 1; - - // Ouverture du fichier - if ((file = fopen(filename, "rb"))) - { - // Lecture de la taille du fichier - file_size = File_length_file(file); - // Le fichier ne peut être au format PAL que si sa taille vaut 768 octets - if (file_size == sizeof(T_Palette)) - File_error = 0; - else { - // Sinon c'est peut être un fichier palette ASCII "Jasc" - fread(filename, 1, 8, file); - if (strncmp(filename,"JASC-PAL",8) == 0) - { - File_error = 0; - } - } - fclose(file); - } -} - - -// -- Lire un fichier au format PAL ----------------------------------------- -void Load_PAL(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - //long file_size; // Taille du fichier - - - Get_full_filename(filename, context->File_name, context->File_directory); - File_error=0; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - long file_size = File_length_file(file); - // Le fichier ne peut être au format PAL que si sa taille vaut 768 octets - if (file_size == sizeof(T_Palette)) - { - T_Palette palette_64; - // Pre_load(context, ?); // Pas possible... pas d'image... - - // Lecture du fichier dans context->Palette - if (Read_bytes(file, palette_64, sizeof(T_Palette))) - { - Palette_64_to_256(palette_64); - memcpy(context->Palette, palette_64, sizeof(T_Palette)); - Palette_loaded(context); - } - else - File_error = 2; - } else { - fread(filename, 1, 8, file); - if (strncmp(filename,"JASC-PAL",8) == 0) - { - int i, n, r, g, b; - fscanf(file, "%d",&n); - if(n != 100) - { - File_error = 2; - fclose(file); - return; - } - // Read color count - fscanf(file, "%d",&n); - for (i = 0; i < n; i++) - { - fscanf(file, "%d %d %d",&r, &g, &b); - context->Palette[i].R = r; - context->Palette[i].G = g; - context->Palette[i].B = b; - } - Palette_loaded(context); - } else File_error = 2; - - } - - // Fermeture du fichier - fclose(file); - } - else - // Si on n'a pas réussi à ouvrir le fichier, alors il y a eu une erreur - File_error=1; -} - - -// -- Sauver un fichier au format PAL --------------------------------------- -void Save_PAL(T_IO_Context * context) -{ - FILE *file; - char filename[MAX_PATH_CHARACTERS]; ///< full filename - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - // Open output file - if ((file=fopen(filename,"w"))) - { - int i; - if (fputs("JASC-PAL\n0100\n256\n", file)==EOF) - File_error=1; - for (i = 0; i < 256 && File_error==0; i++) - { - if (fprintf(file,"%d %d %d\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0) - File_error=1; - } - - fclose(file); - - if (File_error) - remove(filename); - } - else - { - // unable to open output file, nothing saved. - File_error=1; - } -} - - -//////////////////////////////////// PKM //////////////////////////////////// -typedef struct -{ - char Ident[3]; // String "PKM" } - byte Method; // Compression method - // 0 = per-line compression (c)KM - // others = unknown at the moment - byte Recog1; // Recognition byte 1 - byte Recog2; // Recognition byte 2 - word Width; // Image width - word Height; // Image height - T_Palette Palette;// RGB Palette 256*3, on a 1-64 scale for each component - word Jump; // Size of the jump between header and image: - // Used to insert a comment -} T_PKM_Header; - -// -- Tester si un fichier est au format PKM -------------------------------- -void Test_PKM(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - T_PKM_Header header; - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=1; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - // Lecture du header du fichier - if (Read_bytes(file,&header.Ident,3) && - Read_byte(file,&header.Method) && - Read_byte(file,&header.Recog1) && - Read_byte(file,&header.Recog2) && - Read_word_le(file,&header.Width) && - Read_word_le(file,&header.Height) && - Read_bytes(file,&header.Palette,sizeof(T_Palette)) && - Read_word_le(file,&header.Jump)) - { - // On regarde s'il y a la signature PKM suivie de la méthode 0. - // La constante "PKM" étant un chaîne, elle se termine toujours par 0. - // Donc pas la peine de s'emm...er à regarder si la méthode est à 0. - if ( (!memcmp(&header,"PKM",4)) && header.Width && header.Height) - File_error=0; - } - fclose(file); - } -} - - -// -- Lire un fichier au format PKM ----------------------------------------- -void Load_PKM(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - T_PKM_Header header; - byte color; - byte temp_byte; - word len; - word index; - dword Compteur_de_pixels; - dword Compteur_de_donnees_packees; - dword image_size; - dword Taille_pack; - long file_size; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - if ((file=fopen(filename, "rb"))) - { - file_size=File_length_file(file); - - if (Read_bytes(file,&header.Ident,3) && - Read_byte(file,&header.Method) && - Read_byte(file,&header.Recog1) && - Read_byte(file,&header.Recog2) && - Read_word_le(file,&header.Width) && - Read_word_le(file,&header.Height) && - Read_bytes(file,&header.Palette,sizeof(T_Palette)) && - Read_word_le(file,&header.Jump)) - { - context->Comment[0]='\0'; // On efface le commentaire - if (header.Jump) - { - index=0; - while ( (indexCOMMENT_SIZE) - { - color=temp_byte; // On se sert de color comme - temp_byte=COMMENT_SIZE; // variable temporaire - color-=COMMENT_SIZE; - } - else - color=0; - - if (Read_bytes(file,context->Comment,temp_byte)) - { - index+=temp_byte; - context->Comment[temp_byte]='\0'; - if (color) - if (fseek(file,color,SEEK_CUR)) - File_error=2; - } - else - File_error=2; - } - else - File_error=2; - break; - - case 1 : // Dimensions de l'écran d'origine - if (Read_byte(file,&temp_byte)) - { - if (temp_byte==4) - { - index+=4; - if ( ! Read_word_le(file,(word *) &Original_screen_X) - || !Read_word_le(file,(word *) &Original_screen_Y) ) - File_error=2; - } - else - File_error=2; - } - else - File_error=2; - break; - - case 2 : // color de transparence - if (Read_byte(file,&temp_byte)) - { - if (temp_byte==1) - { - index++; - if (! Read_byte(file,&Back_color)) - File_error=2; - } - else - File_error=2; - } - else - File_error=2; - break; - - default: - if (Read_byte(file,&temp_byte)) - { - index+=temp_byte; - if (fseek(file,temp_byte,SEEK_CUR)) - File_error=2; - } - else - File_error=2; - } - } - else - File_error=2; - } - if ( (!File_error) && (index!=header.Jump) ) - File_error=2; - } - - /*Init_lecture();*/ - - if (!File_error) - { - Pre_load(context, header.Width,header.Height,file_size,FORMAT_PKM,PIXEL_SIMPLE,0); - if (File_error==0) - { - - context->Width=header.Width; - context->Height=header.Height; - image_size=(dword)(context->Width*context->Height); - // Palette lue en 64 - memcpy(context->Palette,header.Palette,sizeof(T_Palette)); - Palette_64_to_256(context->Palette); - Palette_loaded(context); - - Compteur_de_donnees_packees=0; - Compteur_de_pixels=0; - // Header size is 780 - Taille_pack=(file_size)-780-header.Jump; - - // Boucle de décompression: - while ( (Compteur_de_pixelsWidth, - Compteur_de_pixels / context->Width, - temp_byte); - Compteur_de_donnees_packees++; - Compteur_de_pixels++; - } - else // Sinon, On regarde si on va décompacter un... - { // ... nombre de pixels tenant sur un byte - if (temp_byte==header.Recog1) - { - if(Read_byte(file, &color)!=1) - { - File_error=2; - break; - } - if(Read_byte(file, &temp_byte)!=1) - { - File_error=2; - break; - } - for (index=0; indexWidth, - (Compteur_de_pixels+index) / context->Width, - color); - Compteur_de_pixels+=temp_byte; - Compteur_de_donnees_packees+=3; - } - else // ... nombre de pixels tenant sur un word - { - if(Read_byte(file, &color)!=1) - { - File_error=2; - break; - } - Read_word_be(file, &len); - for (index=0; indexWidth, - (Compteur_de_pixels+index) / context->Width, - color); - Compteur_de_pixels+=len; - Compteur_de_donnees_packees+=4; - } - } - } - } - } - /*Close_lecture();*/ - } - else // Lecture header impossible: Error ne modifiant pas l'image - File_error=1; - - fclose(file); - } - else // Ouv. fichier impossible: Error ne modifiant pas l'image - File_error=1; -} - - -// -- Sauver un fichier au format PKM --------------------------------------- - - // Trouver quels sont les octets de reconnaissance - void Find_recog(byte * recog1, byte * recog2) - { - dword Find_recon[256]; // Table d'utilisation de couleurs - byte best; // Meilleure couleur pour recon (recon1 puis recon2) - dword NBest; // Nombre d'occurences de cette couleur - word index; - - - // On commence par compter l'utilisation de chaque couleurs - Count_used_colors(Find_recon); - - // Ensuite recog1 devient celle la moins utilisée de celles-ci - *recog1=0; - best=1; - NBest=INT_MAX; // Une même couleur ne pourra jamais être utilisée 1M de fois. - for (index=1;index<=255;index++) - if (Find_recon[index]Width; - header.Height=context->Height; - memcpy(header.Palette,context->Palette,sizeof(T_Palette)); - Palette_256_to_64(header.Palette); - - // Calcul de la taille du Post-header - header.Jump=9; // 6 pour les dimensions de l'ecran + 3 pour la back-color - comment_size=strlen(context->Comment); - if (comment_size) - header.Jump+=comment_size+2; - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - // Ecriture du header - if (Write_bytes(file,&header.Ident,3) && - Write_byte(file,header.Method) && - Write_byte(file,header.Recog1) && - Write_byte(file,header.Recog2) && - Write_word_le(file,header.Width) && - Write_word_le(file,header.Height) && - Write_bytes(file,&header.Palette,sizeof(T_Palette)) && - Write_word_le(file,header.Jump)) - { - Init_write_buffer(); - - // Ecriture du commentaire - // (Compteur_de_pixels est utilisé ici comme simple index de comptage) - if (comment_size) - { - Write_one_byte(file,0); - Write_one_byte(file,comment_size); - for (Compteur_de_pixels=0; Compteur_de_pixelsComment[Compteur_de_pixels]); - } - // Ecriture des dimensions de l'écran - Write_one_byte(file,1); - Write_one_byte(file,4); - Write_one_byte(file,Screen_width&0xFF); - Write_one_byte(file,Screen_width>>8); - Write_one_byte(file,Screen_height&0xFF); - Write_one_byte(file,Screen_height>>8); - // Ecriture de la back-color - Write_one_byte(file,2); - Write_one_byte(file,1); - Write_one_byte(file,Back_color); - - // Routine de compression PKM de l'image - image_size=(dword)(context->Width*context->Height); - Compteur_de_pixels=0; - pixel_value=Get_pixel(context, 0,0); - - while ( (Compteur_de_pixelsWidth,Compteur_de_pixels / context->Width); - } - while ( (pixel_value==last_color) - && (Compteur_de_pixels=image_size) break; - pixel_value=Get_pixel(context, Compteur_de_pixels % context->Width,Compteur_de_pixels / context->Width); - } - - if ( (last_color!=header.Recog1) && (last_color!=header.Recog2) ) - { - if (repetitions==1) - Write_one_byte(file,last_color); - else - if (repetitions==2) - { - Write_one_byte(file,last_color); - Write_one_byte(file,last_color); - } - else - if ( (repetitions>2) && (repetitions<256) ) - { // RECON1/couleur/nombre - Write_one_byte(file,header.Recog1); - Write_one_byte(file,last_color); - Write_one_byte(file,repetitions&0xFF); - } - else - if (repetitions>=256) - { // RECON2/couleur/hi(nombre)/lo(nombre) - Write_one_byte(file,header.Recog2); - Write_one_byte(file,last_color); - Write_one_byte(file,repetitions>>8); - Write_one_byte(file,repetitions&0xFF); - } - } - else - { - if (repetitions<256) - { - Write_one_byte(file,header.Recog1); - Write_one_byte(file,last_color); - Write_one_byte(file,repetitions&0xFF); - } - else - { - Write_one_byte(file,header.Recog2); - Write_one_byte(file,last_color); - Write_one_byte(file,repetitions>>8); - Write_one_byte(file,repetitions&0xFF); - } - } - } - - End_write(file); - } - else - File_error=1; - fclose(file); - } - else - { - File_error=1; - fclose(file); - } - // S'il y a eu une erreur de sauvegarde, on ne va tout de même pas laisser - // ce fichier pourri traîner... Ca fait pas propre. - if (File_error) - remove(filename); -} - - -//////////////////////////////////// CEL //////////////////////////////////// -typedef struct -{ - word Width; // width de l'image - word Height; // height de l'image -} T_CEL_Header1; - -typedef struct -{ - byte Signature[4]; // Signature du format - byte Kind; // Type de fichier ($10=PALette $20=BitMaP) - byte Nb_bits; // Nombre de bits - word Filler1; // ??? - word Width; // width de l'image - word Height; // height de l'image - word X_offset; // Offset en X de l'image - word Y_offset; // Offset en Y de l'image - byte Filler2[16]; // ??? -} T_CEL_Header2; - -// -- Tester si un fichier est au format CEL -------------------------------- - -void Test_CEL(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - int size; - FILE *file; - T_CEL_Header1 header1; - T_CEL_Header2 header2; - int file_size; - - File_error=0; - Get_full_filename(filename, context->File_name, context->File_directory); - file_size=File_length(filename); - if (file_size==0) - { - File_error = 1; // Si on ne peut pas faire de stat il vaut mieux laisser tomber - return; - } - - if (! (file=fopen(filename, "rb"))) - { - File_error = 1; - return; - } - if (Read_word_le(file,&header1.Width) && - Read_word_le(file,&header1.Height) ) - { - // Vu que ce header n'a pas de signature, il va falloir tester la - // cohérence de la dimension de l'image avec celle du fichier. - - size=file_size-4; - if ( (!size) || ( (((header1.Width+1)>>1)*header1.Height)!=size ) ) - { - // Tentative de reconnaissance de la signature des nouveaux fichiers - - fseek(file,0,SEEK_SET); - if (Read_bytes(file,&header2.Signature,4) && - !memcmp(header2.Signature,"KiSS",4) && - Read_byte(file,&header2.Kind) && - (header2.Kind==0x20) && - Read_byte(file,&header2.Nb_bits) && - Read_word_le(file,&header2.Filler1) && - Read_word_le(file,&header2.Width) && - 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,16)) - { - // ok - } - else - File_error=1; - } - else - File_error=1; - } - else - { - File_error=1; - } - fclose(file); -} - - -// -- Lire un fichier au format CEL ----------------------------------------- - -void Load_CEL(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - T_CEL_Header1 header1; - T_CEL_Header2 header2; - short x_pos; - short y_pos; - byte last_byte=0; - long file_size; - const long int header_size = 4; - - File_error=0; - Get_full_filename(filename, context->File_name, context->File_directory); - if ((file=fopen(filename, "rb"))) - { - if (Read_word_le(file,&(header1.Width)) - && Read_word_le(file,&(header1.Height))) - { - file_size=File_length_file(file); - if ( (file_size>header_size) - && ( (((header1.Width+1)>>1)*header1.Height)==(file_size-header_size) ) ) - { - // Chargement d'un fichier CEL sans signature (vieux fichiers) - context->Width=header1.Width; - context->Height=header1.Height; - Original_screen_X=context->Width; - Original_screen_Y=context->Height; - Pre_load(context, context->Width,context->Height,file_size,FORMAT_CEL,PIXEL_SIMPLE,0); - if (File_error==0) - { - // Chargement de l'image - /*Init_lecture();*/ - for (y_pos=0;((y_posHeight) && (!File_error));y_pos++) - for (x_pos=0;((x_posWidth) && (!File_error));x_pos++) - if ((x_pos & 1)==0) - { - if(Read_byte(file,&last_byte)!=1) File_error = 2; - Set_pixel(context, x_pos,y_pos,(last_byte >> 4)); - } - else - Set_pixel(context, x_pos,y_pos,(last_byte & 15)); - /*Close_lecture();*/ - } - } - else - { - // On réessaye avec le nouveau format - - fseek(file,0,SEEK_SET); - if (Read_bytes(file,header2.Signature,4) - && Read_byte(file,&(header2.Kind)) - && Read_byte(file,&(header2.Nb_bits)) - && Read_word_le(file,&(header2.Filler1)) - && Read_word_le(file,&(header2.Width)) - && 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,16) - ) - { - // Chargement d'un fichier CEL avec signature (nouveaux fichiers) - - context->Width=header2.Width+header2.X_offset; - context->Height=header2.Height+header2.Y_offset; - Original_screen_X=context->Width; - Original_screen_Y=context->Height; - Pre_load(context, context->Width,context->Height,file_size,FORMAT_CEL,PIXEL_SIMPLE,0); - if (File_error==0) - { - // Chargement de l'image - /*Init_lecture();*/ - - if (!File_error) - { - // Effacement du décalage - for (y_pos=0;y_posWidth;x_pos++) - Set_pixel(context, x_pos,y_pos,0); - for (y_pos=header2.Y_offset;y_posHeight;y_pos++) - for (x_pos=0;x_pos> 4)); - } - else - Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte & 15)); - break; - - case 8: - for (y_pos=0;((y_posFile_name, context->File_directory); - if ((file=fopen(filename,"wb"))) - { - // On regarde si des couleurs >16 sont utilisées dans l'image - for (x_pos=16;((x_pos<256) && (!Utilisation[x_pos]));x_pos++); - - if (x_pos==256) - { - // Cas d'une image 16 couleurs (écriture à l'ancien format) - - header1.Width =context->Width; - header1.Height=context->Height; - - if (Write_word_le(file,header1.Width) - && Write_word_le(file,header1.Height) - ) - { - // Sauvegarde de l'image - Init_write_buffer(); - for (y_pos=0;((y_posHeight) && (!File_error));y_pos++) - { - for (x_pos=0;((x_posWidth) && (!File_error));x_pos++) - if ((x_pos & 1)==0) - last_byte=(Get_pixel(context, x_pos,y_pos) << 4); - else - { - last_byte=last_byte | (Get_pixel(context, x_pos,y_pos) & 15); - Write_one_byte(file,last_byte); - } - - if ((x_pos & 1)==1) - Write_one_byte(file,last_byte); - } - End_write(file); - } - else - File_error=1; - fclose(file); - } - else - { - // Cas d'une image 256 couleurs (écriture au nouveau format) - - // Recherche du décalage - for (y_pos=0;y_posHeight;y_pos++) - { - for (x_pos=0;x_posWidth;x_pos++) - if (Get_pixel(context, x_pos,y_pos)!=0) - break; - if (Get_pixel(context, x_pos,y_pos)!=0) - break; - } - header2.Y_offset=y_pos; - for (x_pos=0;x_posWidth;x_pos++) - { - for (y_pos=0;y_posHeight;y_pos++) - if (Get_pixel(context, x_pos,y_pos)!=0) - break; - if (Get_pixel(context, x_pos,y_pos)!=0) - break; - } - header2.X_offset=x_pos; - - memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature - header2.Kind=0x20; // Initialisation du type (BitMaP) - header2.Nb_bits=8; // Initialisation du nombre de bits - header2.Filler1=0; // Initialisation du filler 1 (?) - header2.Width=context->Width-header2.X_offset; // Initialisation de la largeur - header2.Height=context->Height-header2.Y_offset; // Initialisation de la hauteur - for (x_pos=0;x_pos<16;x_pos++) // Initialisation du filler 2 (?) - header2.Filler2[x_pos]=0; - - if (Write_bytes(file,header2.Signature,4) - && Write_byte(file,header2.Kind) - && Write_byte(file,header2.Nb_bits) - && Write_word_le(file,header2.Filler1) - && Write_word_le(file,header2.Width) - && 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,14) - ) - { - // Sauvegarde de l'image - Init_write_buffer(); - for (y_pos=0;((y_posFile_name, context->File_directory); - if ((file=fopen(filename, "rb"))) - { - if (File_length_file(file)==320) - { - 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 ((header1.Palette[pal_index].color[color_index].Byte2>>4)!=0) - File_error=1; - } - else - { - if (Read_bytes(file,header2.Signature,4) - && Read_byte(file,&(header2.Kind)) - && Read_byte(file,&(header2.Nb_bits)) - && Read_word_le(file,&(header2.Filler1)) - && Read_word_le(file,&(header2.Width)) - && 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,14) - ) - { - if (memcmp(header2.Signature,"KiSS",4)==0) - { - if (header2.Kind!=0x10) - File_error=1; - } - else - File_error=1; - } - else - File_error=1; - } - fclose(file); - } - else - File_error=1; -} - - -// -- Lire un fichier au format KCF ----------------------------------------- - -void Load_KCF(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - T_KCF_Header header1; - T_CEL_Header2 header2; - byte bytes[3]; - int pal_index; - int color_index; - int index; - long file_size; - - - File_error=0; - Get_full_filename(filename, context->File_name, context->File_directory); - if ((file=fopen(filename, "rb"))) - { - file_size=File_length_file(file); - 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 (!File_error) - { - // Pre_load(context, ?); // Pas possible... pas d'image... - - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - - // Chargement de la palette - for (pal_index=0;pal_index<10;pal_index++) - for (color_index=0;color_index<16;color_index++) - { - index=16+(pal_index*16)+color_index; - 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++) - { - context->Palette[index].R=context->Palette[index+16].R; - context->Palette[index].G=context->Palette[index+16].G; - context->Palette[index].B=context->Palette[index+16].B; - } - - Palette_loaded(context); - } - else - File_error=1; - } - else - { - // Fichier KCF au nouveau format - - if (Read_bytes(file,header2.Signature,4) - && Read_byte(file,&(header2.Kind)) - && Read_byte(file,&(header2.Nb_bits)) - && Read_word_le(file,&(header2.Filler1)) - && Read_word_le(file,&(header2.Width)) - && 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,14) - ) - { - // Pre_load(context, ?); // Pas possible... pas d'image... - - index=(header2.Nb_bits==12)?16:0; - for (pal_index=0;pal_indexPalette[index].R=(bytes[0] >> 4) << 4; - context->Palette[index].B=(bytes[0] & 15) << 4; - context->Palette[index].G=(bytes[1] & 15) << 4; - break; - - case 24: // RRRR RRRR | VVVV VVVV | BBBB BBBB - Read_bytes(file,bytes,3); - context->Palette[index].R=bytes[0]; - context->Palette[index].G=bytes[1]; - context->Palette[index].B=bytes[2]; - } - - index++; - } - } - - if (header2.Nb_bits==12) - for (index=0;index<16;index++) - { - context->Palette[index].R=context->Palette[index+16].R; - context->Palette[index].G=context->Palette[index+16].G; - context->Palette[index].B=context->Palette[index+16].B; - } - - Palette_loaded(context); - } - else - File_error=1; - } - fclose(file); - } - else - File_error=1; -} - - -// -- Ecrire un fichier au format KCF --------------------------------------- - -void Save_KCF(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - FILE *file; - T_KCF_Header header1; - T_CEL_Header2 header2; - byte bytes[3]; - int pal_index; - int color_index; - int index; - dword Utilisation[256]; // Table d'utilisation de couleurs - - // On commence par compter l'utilisation de chaque couleurs - Count_used_colors(Utilisation); - - File_error=0; - Get_full_filename(filename, context->File_name, context->File_directory); - if ((file=fopen(filename,"wb"))) - { - // Sauvegarde de la palette - - // On regarde si des couleurs >16 sont utilisées dans l'image - for (index=16;((index<256) && (!Utilisation[index]));index++); - - if (index==256) - { - // Cas d'une image 16 couleurs (écriture à l'ancien format) - - for (pal_index=0;pal_index<10;pal_index++) - for (color_index=0;color_index<16;color_index++) - { - index=16+(pal_index*16)+color_index; - 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; - } - - // 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 - { - // Cas d'une image 256 couleurs (écriture au nouveau format) - - memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature - header2.Kind=0x10; // Initialisation du type (PALette) - header2.Nb_bits=24; // Initialisation du nombre de bits - header2.Filler1=0; // Initialisation du filler 1 (?) - header2.Width=256; // Initialisation du nombre de couleurs - header2.Height=1; // Initialisation du nombre de palettes - header2.X_offset=0; // Initialisation du décalage X - header2.Y_offset=0; // Initialisation du décalage Y - for (index=0;index<16;index++) // Initialisation du filler 2 (?) - header2.Filler2[index]=0; - - if (!Write_bytes(file,header2.Signature,4) - || !Write_byte(file,header2.Kind) - || !Write_byte(file,header2.Nb_bits) - || !Write_word_le(file,header2.Filler1) - || !Write_word_le(file,header2.Width) - || !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,14) - ) - File_error=1; - - for (index=0;(index<256) && (!File_error);index++) - { - bytes[0]=context->Palette[index].R; - bytes[1]=context->Palette[index].G; - bytes[2]=context->Palette[index].B; - if (! Write_bytes(file,bytes,3)) - File_error=1; - } - } - - fclose(file); - - if (File_error) - remove(filename); - } - else - File_error=1; -} - - -//////////////////////////////////// PI1 //////////////////////////////////// - -//// DECODAGE d'une partie d'IMAGE //// - -void PI1_8b_to_16p(byte * src,byte * dest) -{ - int i; // index du pixel à calculer - word byte_mask; // Masque de decodage - word w0,w1,w2,w3; // Les 4 words bien ordonnés de la source - - byte_mask=0x8000; - w0=(((word)src[0])<<8) | src[1]; - w1=(((word)src[2])<<8) | src[3]; - w2=(((word)src[4])<<8) | src[5]; - w3=(((word)src[6])<<8) | src[7]; - for (i=0;i<16;i++) - { - // Pour décoder le pixel n°i, il faut traiter les 4 words sur leur bit - // correspondant à celui du masque - - dest[i]=((w0 & byte_mask)?0x01:0x00) | - ((w1 & byte_mask)?0x02:0x00) | - ((w2 & byte_mask)?0x04:0x00) | - ((w3 & byte_mask)?0x08:0x00); - byte_mask>>=1; - } -} - -//// CODAGE d'une partie d'IMAGE //// - -void PI1_16p_to_8b(byte * src,byte * dest) -{ - int i; // index du pixel à calculer - word byte_mask; // Masque de codage - word w0,w1,w2,w3; // Les 4 words bien ordonnés de la destination - - byte_mask=0x8000; - w0=w1=w2=w3=0; - for (i=0;i<16;i++) - { - // Pour coder le pixel n°i, il faut modifier les 4 words sur leur bit - // correspondant à celui du masque - - w0|=(src[i] & 0x01)?byte_mask:0x00; - w1|=(src[i] & 0x02)?byte_mask:0x00; - w2|=(src[i] & 0x04)?byte_mask:0x00; - w3|=(src[i] & 0x08)?byte_mask:0x00; - byte_mask>>=1; - } - dest[0]=w0 >> 8; - dest[1]=w0 & 0x00FF; - dest[2]=w1 >> 8; - dest[3]=w1 & 0x00FF; - dest[4]=w2 >> 8; - dest[5]=w2 & 0x00FF; - dest[6]=w3 >> 8; - dest[7]=w3 & 0x00FF; -} - -//// DECODAGE de la PALETTE //// - -void PI1_decode_palette(byte * src,byte * palette) -{ - int i; // Numéro de la couleur traitée - int ip; // index dans la palette - word w; // Word contenant le code - - // Schéma d'un word = - // - // Low High - // VVVV RRRR | 0000 BBBB - // 0321 0321 | 0321 - - ip=0; - for (i=0;i<16;i++) - { - #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 //// - -void PI1_code_palette(byte * palette,byte * dest) -{ - int i; // Numéro de la couleur traitée - int ip; // index dans la palette - word w; // Word contenant le code - - // Schéma d'un word = - // - // 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 - } -} - - -// -- Tester si un fichier est au format PI1 -------------------------------- -void Test_PI1(T_IO_Context * context) -{ - FILE * file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - int size; // Taille du fichier - word resolution; // Résolution de l'image - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=1; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - // Vérification de la taille - size=File_length_file(file); - if ((size==32034) || (size==32066)) - { - // Lecture et vérification de la résolution - if (Read_word_le(file,&resolution)) - { - if (resolution==0x0000) - File_error=0; - } - } - // Fermeture du fichier - fclose(file); - } -} - - -// -- Lire un fichier au format PI1 ----------------------------------------- -void Load_PI1(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - word x_pos,y_pos; - byte * buffer; - byte * ptr; - byte pixels[320]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - if ((file=fopen(filename, "rb"))) - { - // allocation d'un buffer mémoire - buffer=(byte *)malloc(32034); - if (buffer!=NULL) - { - // Lecture du fichier dans le buffer - if (Read_bytes(file,buffer,32034)) - { - // Initialisation de la preview - Pre_load(context, 320,200,File_length_file(file),FORMAT_PI1,PIXEL_SIMPLE,0); - if (File_error==0) - { - // Initialisation de la palette - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - PI1_decode_palette(buffer+2,(byte *)context->Palette); - Palette_loaded(context); - - context->Width=320; - context->Height=200; - - // Chargement/décompression de l'image - ptr=buffer+34; - for (y_pos=0;y_pos<200;y_pos++) - { - for (x_pos=0;x_pos<(320>>4);x_pos++) - { - PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); - ptr+=8; - } - for (x_pos=0;x_pos<320;x_pos++) - Set_pixel(context, x_pos,y_pos,pixels[x_pos]); - } - } - } - else - File_error=1; - free(buffer); - buffer = NULL; - } - else - File_error=1; - fclose(file); - } - else - File_error=1; -} - - -// -- Sauver un fichier au format PI1 --------------------------------------- -void Save_PI1(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - short x_pos,y_pos; - byte * buffer; - byte * ptr; - byte pixels[320]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - // allocation d'un buffer mémoire - buffer=(byte *)malloc(32066); - // Codage de la résolution - buffer[0]=0x00; - buffer[1]=0x00; - // Codage de la palette - PI1_code_palette((byte *)context->Palette,buffer+2); - // Codage de l'image - ptr=buffer+34; - for (y_pos=0;y_pos<200;y_pos++) - { - // Codage de la ligne - memset(pixels,0,320); - if (y_posHeight) - { - for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) - pixels[x_pos]=Get_pixel(context, x_pos,y_pos); - } - - for (x_pos=0;x_pos<(320>>4);x_pos++) - { - PI1_16p_to_8b(pixels+(x_pos<<4),ptr); - ptr+=8; - } - } - - memset(buffer+32034,0,32); // 32 extra NULL bytes at the end of the file to make ST Deluxe Paint happy - - if (Write_bytes(file,buffer,32066)) - { - fclose(file); - } - else // Error d'écriture (disque plein ou protégé) - { - fclose(file); - remove(filename); - File_error=1; - } - // Libération du buffer mémoire - free(buffer); - buffer = NULL; - } - else - { - fclose(file); - remove(filename); - File_error=1; - } -} - - -//////////////////////////////////// PC1 //////////////////////////////////// - -//// DECOMPRESSION d'un buffer selon la méthode PACKBITS //// - -void PC1_uncompress_packbits(byte * src,byte * dest) -{ - int is,id; // Les indices de parcour des buffers - int n; // Octet de contrôle - - for (is=id=0;id<32000;) - { - n=src[is++]; - - if (n & 0x80) - { - // Recopier src[is] -n+1 fois - n=257-n; - for (;(n>0) && (id<32000);n--) - dest[id++]=src[is]; - is++; - } - else - { - // Recopier n+1 octets littéralement - n=n+1; - for (;(n>0) && (id<32000);n--) - dest[id++]=src[is++]; - } - - // Contrôle des erreurs - if (n>0) - File_error=1; - } -} - -//// COMPRESSION d'un buffer selon la méthode PACKBITS //// - -void PC1_compress_packbits(byte * src,byte * dest,int source_size,int * dest_size) -{ - int is; // index dans la source - int id; // index dans la destination - int ir; // index de la répétition - int n; // Taille des séquences - int repet; // "Il y a répétition" - - for (is=id=0;is0;n--) - dest[id++]=src[is++]; - } - - // On code la partie sans répétitions - if (repet) - { - // On compte la quantité de fois qu'il faut répéter la valeur - for (ir+=3;ir>=1; - } - } -} - -//// CODAGE d'une partie d'IMAGE //// - -// Transformation d'1 ligne de pixels en 4 plans de bits - -void PC1_1line_to_4bp(byte * src,byte * dst0,byte * dst1,byte * dst2,byte * dst3) -{ - int i,j; // Compteurs - int ip; // index du pixel à calculer - byte byte_mask; // Masque de decodage - byte b0,b1,b2,b3; // Les 4 octets des plans bits sources - - ip=0; - // Pour chacun des 40 octets des plans de bits - for (i=0;i<40;i++) - { - // Pour chacun des 8 bits des octets - byte_mask=0x80; - b0=b1=b2=b3=0; - for (j=0;j<8;j++) - { - b0|=(src[ip] & 0x01)?byte_mask:0x00; - b1|=(src[ip] & 0x02)?byte_mask:0x00; - b2|=(src[ip] & 0x04)?byte_mask:0x00; - b3|=(src[ip] & 0x08)?byte_mask:0x00; - ip++; - byte_mask>>=1; - } - dst0[i]=b0; - dst1[i]=b1; - dst2[i]=b2; - dst3[i]=b3; - } -} - - -// -- Tester si un fichier est au format PC1 -------------------------------- -void Test_PC1(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - int size; // Taille du fichier - word resolution; // Résolution de l'image - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=1; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - // Vérification de la taille - size=File_length_file(file); - if ((size<=32066)) - { - // Lecture et vérification de la résolution - if (Read_word_le(file,&resolution)) - { - if (resolution==0x0080) - File_error=0; - } - } - // Fermeture du fichier - fclose(file); - } -} - - -// -- Lire un fichier au format PC1 ----------------------------------------- -void Load_PC1(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - int size; - word x_pos,y_pos; - byte * buffercomp; - byte * bufferdecomp; - byte * ptr; - byte pixels[320]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - if ((file=fopen(filename, "rb"))) - { - size=File_length_file(file); - // allocation des buffers mémoire - buffercomp=(byte *)malloc(size); - bufferdecomp=(byte *)malloc(32000); - if ( (buffercomp!=NULL) && (bufferdecomp!=NULL) ) - { - // Lecture du fichier dans le buffer - if (Read_bytes(file,buffercomp,size)) - { - // Initialisation de la preview - Pre_load(context, 320,200,File_length_file(file),FORMAT_PC1,PIXEL_SIMPLE,0); - if (File_error==0) - { - // Initialisation de la palette - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - PI1_decode_palette(buffercomp+2,(byte *)context->Palette); - Palette_loaded(context); - - context->Width=320; - context->Height=200; - - // Décompression du buffer - PC1_uncompress_packbits(buffercomp+34,bufferdecomp); - - // Décodage de l'image - ptr=bufferdecomp; - for (y_pos=0;y_pos<200;y_pos++) - { - // Décodage de la scanline - PC1_4bp_to_1line(ptr,ptr+40,ptr+80,ptr+120,pixels); - ptr+=160; - // Chargement de la ligne - for (x_pos=0;x_pos<320;x_pos++) - Set_pixel(context, x_pos,y_pos,pixels[x_pos]); - } - } - } - else - File_error=1; - free(bufferdecomp); - free(buffercomp); - buffercomp = bufferdecomp = NULL; - } - else - { - File_error=1; - free(bufferdecomp); - free(buffercomp); - buffercomp = bufferdecomp = NULL; - } - fclose(file); - } - else - File_error=1; -} - - -// -- Sauver un fichier au format PC1 --------------------------------------- -void Save_PC1(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - int size; - short x_pos,y_pos; - byte * buffercomp; - byte * bufferdecomp; - byte * ptr; - byte pixels[320]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - // Allocation des buffers mémoire - bufferdecomp=(byte *)malloc(32000); - buffercomp =(byte *)malloc(64066); - // Codage de la résolution - buffercomp[0]=0x80; - buffercomp[1]=0x00; - // Codage de la palette - PI1_code_palette((byte *)context->Palette,buffercomp+2); - // Codage de l'image - ptr=bufferdecomp; - for (y_pos=0;y_pos<200;y_pos++) - { - // Codage de la ligne - memset(pixels,0,320); - if (y_posHeight) - { - for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) - pixels[x_pos]=Get_pixel(context, x_pos,y_pos); - } - - // Encodage de la scanline - PC1_1line_to_4bp(pixels,ptr,ptr+40,ptr+80,ptr+120); - ptr+=160; - } - - // Compression du buffer - PC1_compress_packbits(bufferdecomp,buffercomp+34,32000,&size); - size+=34; - for (x_pos=0;x_pos<16;x_pos++) - buffercomp[size++]=0; - - if (Write_bytes(file,buffercomp,size)) - { - fclose(file); - } - else // Error d'écriture (disque plein ou protégé) - { - fclose(file); - remove(filename); - File_error=1; - } - // Libération des buffers mémoire - free(bufferdecomp); - free(buffercomp); - buffercomp = bufferdecomp = NULL; - } - else - { - fclose(file); - remove(filename); - File_error=1; - } -} - - -//////////////////////////////////// NEO //////////////////////////////////// - -void Test_NEO(T_IO_Context * context) -{ - FILE *file; // Fichier du fichier - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - int size; // Taille du fichier - word resolution; // Résolution de l'image - - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=1; - - // Ouverture du fichier - if ((file=fopen(filename, "rb"))) - { - // Vérification de la taille - size=File_length_file(file); - if ((size==32128)) - { - // Flag word : toujours 0 - if (Read_word_le(file,&resolution)) - { - if (resolution == 0) - File_error = 0; - } - - // Lecture et vérification de la résolution - if (Read_word_le(file,&resolution)) - { - if (resolution==0 || resolution==1 || resolution==2) - File_error |= 0; - } - } - // Fermeture du fichier - fclose(file); - } - -} - -void Load_NEO(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - word x_pos,y_pos; - byte * buffer; - byte * ptr; - byte pixels[320]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - if ((file=fopen(filename, "rb"))) - { - // allocation d'un buffer mémoire - buffer=(byte *)malloc(32128); - if (buffer!=NULL) - { - // Lecture du fichier dans le buffer - if (Read_bytes(file,buffer,32128)) - { - // Initialisation de la preview - Pre_load(context, 320,200,File_length_file(file),FORMAT_NEO,PIXEL_SIMPLE,0); - if (File_error==0) - { - // Initialisation de la palette - if (Config.Clear_palette) - memset(context->Palette,0,sizeof(T_Palette)); - // on saute la résolution et le flag, chacun 2 bits - PI1_decode_palette(buffer+4,(byte *)context->Palette); - Palette_loaded(context); - - context->Width=320; - context->Height=200; - - // Chargement/décompression de l'image - ptr=buffer+128; - for (y_pos=0;y_pos<200;y_pos++) - { - for (x_pos=0;x_pos<(320>>4);x_pos++) - { - PI1_8b_to_16p(ptr,pixels+(x_pos<<4)); - ptr+=8; - } - for (x_pos=0;x_pos<320;x_pos++) - Set_pixel(context, x_pos,y_pos,pixels[x_pos]); - } - } - } - else - File_error=1; - free(buffer); - buffer = NULL; - } - else - File_error=1; - fclose(file); - } - else - File_error=1; -} - -void Save_NEO(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier - FILE *file; - short x_pos,y_pos; - byte * buffer; - byte * ptr; - byte pixels[320]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - File_error=0; - // Ouverture du fichier - if ((file=fopen(filename,"wb"))) - { - // allocation d'un buffer mémoire - buffer=(byte *)malloc(32128); - // Codage de la résolution - buffer[0]=0x00; - buffer[1]=0x00; - buffer[2]=0x00; - buffer[3]=0x00; - // Codage de la palette - PI1_code_palette((byte *)context->Palette,buffer+4); - // Codage de l'image - ptr=buffer+128; - for (y_pos=0;y_pos<200;y_pos++) - { - // Codage de la ligne - memset(pixels,0,320); - if (y_posHeight) - { - for (x_pos=0;(x_pos<320) && (x_posWidth);x_pos++) - pixels[x_pos]=Get_pixel(context, x_pos,y_pos); - } - - for (x_pos=0;x_pos<(320>>4);x_pos++) - { - PI1_16p_to_8b(pixels+(x_pos<<4),ptr); - ptr+=8; - } - } - - if (Write_bytes(file,buffer,32128)) - { - fclose(file); - } - else // Error d'écriture (disque plein ou protégé) - { - fclose(file); - remove(filename); - File_error=1; - } - // Libération du buffer mémoire - free(buffer); - buffer = NULL; - } - else - { - fclose(file); - remove(filename); - File_error=1; - } -} - -//////////////////////////////////// C64 //////////////////////////////////// -void Test_C64(T_IO_Context * context) -{ - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - long file_size; - - Get_full_filename(filename, context->File_name, context->File_directory); - - file = fopen(filename,"rb"); - - if (file) - { - file_size = File_length_file(file); - switch (file_size) - { - case 1000: // screen or color - case 1002: // (screen or color) + loadaddr - case 8000: // raw bitmap - case 8002: // raw bitmap with loadaddr - case 9000: // bitmap + screen - case 9002: // bitmap + screen + loadaddr - case 10001: // multicolor - case 10003: // multicolor + loadaddr - File_error = 0; - break; - default: // then we don't know for now. - File_error = 1; - } - fclose (file); - } - else - { - File_error = 1; - } -} - -void Load_C64_hires(T_IO_Context *context, byte *bitmap, byte *colors) -{ - int cx,cy,x,y,c[4],pixel,color; - - for(cy=0; cy<25; cy++) - { - for(cx=0; cx<40; cx++) - { - c[0]=colors[cy*40+cx]&15; - c[1]=colors[cy*40+cx]>>4; - for(y=0; y<8; y++) - { - pixel=bitmap[cy*320+cx*8+y]; - for(x=0; x<8; x++) - { - color=c[pixel&(1<<(7-x))?1:0]; - Set_pixel(context, cx*8+x,cy*8+y,color); - } - } - } - } -} - -void Load_C64_multi(T_IO_Context *context, byte *bitmap, byte *colors, byte *nybble, byte background) -{ - int cx,cy,x,y,c[4],pixel,color; - c[0]=background&15; - for(cy=0; cy<25; cy++) - { - for(cx=0; cx<40; cx++) - { - c[1]=colors[cy*40+cx]>>4; - c[2]=colors[cy*40+cx]&15; - c[3]=nybble[cy*40+cx]&15; - - for(y=0; y<8; y++) - { - pixel=bitmap[cy*320+cx*8+y]; - for(x=0; x<4; x++) - { - color=c[(pixel&3)]; - pixel>>=2; - Set_pixel(context, cx*4+(3-x),cy*8+y,color); - } - } - } - } -} - -void Load_C64(T_IO_Context * context) -{ - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - long file_size; - int i; - byte background,hasLoadAddr=0; - int loadFormat=0; - enum c64_format {F_hires,F_multi,F_bitmap,F_screen,F_color}; - const char *c64_format_names[]={"hires","multicolor","bitmap","screen","color"}; - - // Palette from http://www.pepto.de/projects/colorvic/ - byte pal[48]={ - 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, - 0x68, 0x37, 0x2B, - 0x70, 0xA4, 0xB2, - 0x6F, 0x3D, 0x86, - 0x58, 0x8D, 0x43, - 0x35, 0x28, 0x79, - 0xB8, 0xC7, 0x6F, - 0x6F, 0x4F, 0x25, - 0x43, 0x39, 0x00, - 0x9A, 0x67, 0x59, - 0x44, 0x44, 0x44, - 0x6C, 0x6C, 0x6C, - 0x9A, 0xD2, 0x84, - 0x6C, 0x5E, 0xB5, - 0x95, 0x95, 0x95}; - - byte bitmap[8000],colors[1000],nybble[1000]; - word width=320, height=200; - - Get_full_filename(filename, context->File_name, context->File_directory); - file = fopen(filename,"rb"); - - if (file) - { - File_error=0; - file_size = File_length_file(file); - - switch (file_size) - { - case 1000: // screen or color - hasLoadAddr=0; - loadFormat=F_screen; - break; - - case 1002: // (screen or color) + loadaddr - hasLoadAddr=1; - loadFormat=F_screen; - break; - - case 8000: // raw bitmap - hasLoadAddr=0; - loadFormat=F_bitmap; - break; - - case 8002: // raw bitmap with loadaddr - hasLoadAddr=1; - loadFormat=F_bitmap; - break; - - case 9000: // bitmap + screen - hasLoadAddr=0; - loadFormat=F_hires; - break; - - case 9002: // bitmap + screen + loadaddr - hasLoadAddr=1; - loadFormat=F_hires; - break; - - case 10001: // multicolor - hasLoadAddr=0; - loadFormat=F_multi; - break; - - case 10003: // multicolor + loadaddr - hasLoadAddr=1; - loadFormat=F_multi; - break; - - default: // then we don't know what it is. - File_error = 1; - - } - - memcpy(context->Palette,pal,48); // this set the software palette for grafx2 - Palette_loaded(context); // Always call it if you change the palette - - if (file_size>9002) - width=160; - - if (hasLoadAddr) - { - // get load address - Read_byte(file,&background); - Read_byte(file,&background); - sprintf(filename,"load at $%02x00",background); - } - else - { - sprintf(filename,"no addr"); - } - - if(file_size>9002) - { - context->Ratio = PIXEL_WIDE; - } - sprintf(context->Comment,"C64 %s, %s", - c64_format_names[loadFormat],filename); - Pre_load(context, width, height, file_size, FORMAT_C64, context->Ratio,0); // Do this as soon as you can - - context->Width = width ; - context->Height = height; - - Read_bytes(file,bitmap,8000); - - if (file_size>8002) - Read_bytes(file,colors,1000); - else - { - for(i=0;i<1000;i++) - { - colors[i]=1; - } - } - - if(width==160) - { - Read_bytes(file,nybble,1000); - Read_byte(file,&background); - Load_C64_multi(context,bitmap,colors,nybble,background); - } - else - { - Load_C64_hires(context,bitmap,colors); - } - - File_error = 0; - fclose(file); - } - else - File_error = 1; -} - -int Save_C64_window(byte *saveWhat, byte *loadAddr) -{ - int button; - unsigned int i; - T_Dropdown_button *what, *addr; - char * what_label[] = { - "All", - "Bitmap", - "Screen", - "Color" - }; - char * address_label[] = { - "None", - "$2000", - "$4000", - "$6000", - "$8000", - "$A000", - "$C000", - "$E000" - }; - - Open_window(200,120,"c64 settings"); - Window_set_normal_button(110,100,80,15,"Save",1,1,SDLK_RETURN); - Window_set_normal_button(10,100,80,15,"Cancel",1,1,SDLK_ESCAPE); - - 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); - Window_dropdown_clear_items(what); - for (i=0; i2) - { - Warning_message("More than 2 colors in 8x8 pixels"); - // TODO here we should hilite the offending block - printf("\nerror at %dx%d (%d colors)\n",cx*8,cy*8,numcolors); - return 1; - } - c1 = 0; c2 = 0; - for(i=0;i<16;i++) - { - if(cusage[i]) - { - c2=i; - break; - } - } - c1=c2+1; - for(i=c2;i<16;i++) - { - if(cusage[i]) - { - c1=i; - } - } - colors[cx+cy*40]=(c2<<4)|c1; - - for(y=0; y<8; y++) - { - bits=0; - for(x=0; x<8; x++) - { - pixel=Get_pixel(context, x+cx*8,y+cy*8); - if(pixel>15) - { - Warning_message("Color above 15 used"); - // TODO hilite offending block here too? - // or make it smarter with color allocation? - // However, the palette is fixed to the 16 first colors - return 1; - } - bits=bits<<1; - if (pixel==c2) bits|=1; - } - bitmap[pos++]=bits; - //Write_byte(file,bits&255); - } - } - } - - file = fopen(filename,"wb"); - - if(!file) - { - Warning_message("File open failed"); - File_error = 1; - return 1; - } - - if (loadAddr) - { - Write_byte(file,0); - Write_byte(file,loadAddr); - } - if (saveWhat==0 || saveWhat==1) - Write_bytes(file,bitmap,8000); - if (saveWhat==0 || saveWhat==2) - Write_bytes(file,colors,1000); - - fclose(file); - return 0; -} - -int Save_C64_multi(T_IO_Context *context, char *filename, byte saveWhat, byte loadAddr) -{ - /* - BITS COLOR INFORMATION COMES FROM - 00 Background color #0 (screen color) - 01 Upper 4 bits of screen memory - 10 Lower 4 bits of screen memory - 11 Color nybble (nybble = 1/2 byte = 4 bits) - */ - - int cx,cy,x,y,c[4]={0,0,0,0},color,lut[16],bits,pixel,pos=0; - byte bitmap[8000],screen[1000],nybble[1000]; - word numcolors,count; - dword cusage[256]; - byte i,background=0; - FILE *file; - - numcolors=Count_used_colors(cusage); - - count=0; - for(x=0;x<16;x++) - { - //printf("color %d, pixels %d\n",x,cusage[x]); - if(cusage[x]>count) - { - count=cusage[x]; - background=x; - } - } - - for(cy=0; cy<25; cy++) - { - //printf("\ny:%2d ",cy); - for(cx=0; cx<40; cx++) - { - numcolors=Count_used_colors_area(cusage,cx*4,cy*8,4,8); - if(numcolors>4) - { - Warning_message("More than 4 colors in 4x8"); - // TODO hilite offending block - return 1; - } - color=1; - c[0]=background; - for(i=0; i<16; i++) - { - lut[i]=0; - if(cusage[i]) - { - if(i!=background) - { - lut[i]=color; - c[color]=i; - color++; - } - else - { - lut[i]=0; - } - } - } - // add to screen and nybble - screen[cx+cy*40]=c[1]<<4|c[2]; - nybble[cx+cy*40]=c[3]; - //printf("%x%x%x ",c[1],c[2],c[3]); - for(y=0;y<8;y++) - { - bits=0; - for(x=0;x<4;x++) - { - pixel=Get_pixel(context, cx*4+x,cy*8+y); - if(pixel>15) - { - Warning_message("Color above 15 used"); - // TODO hilite as in hires, you should stay to - // the fixed 16 color palette - return 1; - } - bits=bits<<2; - bits|=lut[pixel]; - - } - //Write_byte(file,bits&255); - bitmap[pos++]=bits; - } - } - } - - file = fopen(filename,"wb"); - - if(!file) - { - Warning_message("File open failed"); - File_error = 1; - return 1; - } - - if (loadAddr) - { - Write_byte(file,0); - Write_byte(file,loadAddr); - } - - if (saveWhat==0 || saveWhat==1) - Write_bytes(file,bitmap,8000); - - if (saveWhat==0 || saveWhat==2) - Write_bytes(file,screen,1000); - - if (saveWhat==0 || saveWhat==3) - Write_bytes(file,nybble,1000); - - if (saveWhat==0) - Write_byte(file,background); - - fclose(file); - //printf("\nbg:%d\n",background); - return 0; -} - -void Save_C64(T_IO_Context * context) -{ - char filename[MAX_PATH_CHARACTERS]; - static byte saveWhat=0, loadAddr=0; - dword numcolors,cusage[256]; - numcolors=Count_used_colors(cusage); - - Get_full_filename(filename, context->File_name, context->File_directory); - - if (numcolors>16) - { - Warning_message("Error: Max 16 colors"); - File_error = 1; - return; - } - if (((context->Width!=320) && (context->Width!=160)) || context->Height!=200) - { - Warning_message("must be 320x200 or 160x200"); - File_error = 1; - return; - } - - if(!Save_C64_window(&saveWhat,&loadAddr)) - { - File_error = 1; - return; - } - //printf("saveWhat=%d, loadAddr=%d\n",saveWhat,loadAddr); - - if (context->Width==320) - File_error = Save_C64_hires(context,filename,saveWhat,loadAddr); - else - File_error = Save_C64_multi(context,filename,saveWhat,loadAddr); -} - - -// SCR (Amstrad CPC) - -void Test_SCR(__attribute__((unused)) T_IO_Context * context) -{ - // Mmh... not sure what we could test. Any idea ? - // The palette file can be tested, if it exists and have the right size it's - // ok. But if it's not there the pixel data may still be valid. And we can't - // use the filesize as this depends on the screen format. - - // An AMSDOS header would be a good indication but in some cases it may not - // be there -} - -void Load_SCR(__attribute__((unused)) T_IO_Context * context) -{ - // The Amstrad CPC screen memory is mapped in a weird mode, somewhere - // between bitmap and textmode. Basically the only way to decode this is to - // emulate the video chip and read the bytes as needed... - // Moreover, the hardware allows the screen to have any size from 8x1 to - // 800x273 pixels, and there is no indication of that in the file besides - // its size. It can also use any of the 3 screen modes. Fortunately this - // last bit of information is stored in the palette file. - // Oh, and BTW, the picture can be offset, and it's even usual to do it, - // because letting 128 pixels unused at the beginning of the file make it a - // lot easier to handle screens using more than 16K of VRam. - // The pixel encoding change with the video mode so we have to know that - // before attempting to load anything... - // As if this wasn't enough, Advanced OCP Art Studio, the reference tool on - // Amstrad, can use RLE packing when saving files, meaning we also have to - // handle that. - - // All this mess enforces us to load (and unpack if needed) the file to a - // temporary 32k buffer before actually decoding it. - - // 1) Seek for a palette - // 2) If palette found get screenmode from there, else ask user - // 3) ask user for screen size (or register values) - // 4) Load color data from palette (if found) - // 5) Close palette - // 6) Open the file - // 7) Run around the screen to untangle the pixeldata - // 8) Close the file -} - -void Save_SCR(T_IO_Context * context) -{ - // TODO : Add possibility to set R9, R12, R13 values - // TODO : Add OCP packing support - // TODO : Add possibility to include AMSDOS header, with proper loading - // address guessed from r12/r13 values. - - unsigned char* output; - unsigned long outsize; - unsigned char r1; - int cpc_mode; - FILE* file; - char filename[MAX_PATH_CHARACTERS]; - - Get_full_filename(filename, context->File_name, context->File_directory); - - - switch(Pixel_ratio) - { - case PIXEL_WIDE: - case PIXEL_WIDE2: - cpc_mode = 0; - break; - case PIXEL_TALL: - case PIXEL_TALL2: - cpc_mode = 2; - break; - default: - cpc_mode = 1; - break; - } - - output = raw2crtc(context->Width,context->Height,cpc_mode,7,&outsize,&r1,0,0); - - file = fopen(filename,"wb"); - Write_bytes(file, output, outsize); - fclose(file); - - free (output); - output = NULL; - - File_error = 0; -} diff --git a/project/jni/application/grafx2/grafx2/src/mountlist.c b/project/jni/application/grafx2/grafx2/src/mountlist.c deleted file mode 100644 index 0fee330bf..000000000 --- a/project/jni/application/grafx2/grafx2/src/mountlist.c +++ /dev/null @@ -1,934 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* mountlist.c -- return a list of mounted file systems - - Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001, 2002, 2003, - 2004, 2005, 2006, 2007 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . -*/ - -// This file is not used on some platforms, so don't do anything for them -#if(!defined(__WIN32__))&&(!defined(__amigaos4__))&&(!defined(__AROS__))&&(!defined(__MORPHOS__))&&(!defined(__amigaos__)) - -// We don't use autoconf and all that in grafx2, so let's do the config here ... -#if defined(__macosx__) || defined(__FreeBSD__) // MacOS X is POSIX compliant - #define MOUNTED_GETMNTINFO -#if defined(__macosx__) - #include -#endif -#elif defined(__NetBSD__) - #define MOUNTED_GETMNTINFO2 -#elif defined(__BEOS__) || defined(__HAIKU__) - #define MOUNTED_FS_STAT_DEV -#elif defined(__TRU64__) - #define MOUNTED_GETFSSTAT 1 - #define HAVE_SYS_MOUNT_H 1 - #include -#elif defined(__SKYOS__)||defined(ANDROID) - #warning "Your platform is missing some specific code here ! please check and fix :)" -#else - #define MOUNTED_GETMNTENT1 -#endif - -#define _XOPEN_SOURCE 500 -// --- END GRAFX2 CUSTOM CONFIG --- - -#include "mountlist.h" - -#include -#include -#include -#include - -#include - -#include - -#include - -#if HAVE_SYS_PARAM_H -# include -#endif - -#if defined MOUNTED_GETFSSTAT /* OSF_1 and Darwin1.3.x */ -# if HAVE_SYS_UCRED_H -# include /* needed on OSF V4.0 for definition of NGROUPS, - NGROUPS is used as an array dimension in ucred.h */ -# include /* needed by powerpc-apple-darwin1.3.7 */ -# endif -# if HAVE_SYS_MOUNT_H -# include -# endif -# if HAVE_SYS_FS_TYPES_H -# include /* needed by powerpc-apple-darwin1.3.7 */ -# endif -# if HAVE_STRUCT_FSSTAT_F_FSTYPENAME -# define FS_TYPE(Ent) ((Ent).f_fstypename) -# else -# define FS_TYPE(Ent) mnt_names[(Ent).f_type] -# endif -#endif /* MOUNTED_GETFSSTAT */ - -#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ -# include -# if !defined MOUNTED -# if defined _PATH_MOUNTED /* GNU libc */ -# define MOUNTED _PATH_MOUNTED -# endif -# if defined MNT_MNTTAB /* HP-UX. */ -# define MOUNTED MNT_MNTTAB -# endif -# if defined MNTTABNAME /* Dynix. */ -# define MOUNTED MNTTABNAME -# endif -# endif -#endif - -#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ -# include -#endif - -#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ -# include -#endif - -#ifdef MOUNTED_GETMNT /* Ultrix. */ -# include -# include -#endif - -#ifdef MOUNTED_FS_STAT_DEV /* BeOS. */ -# include -# include -#endif - -#ifdef MOUNTED_FREAD /* SVR2. */ -# include -#endif - -#ifdef MOUNTED_FREAD_FSTYP /* SVR3. */ -# include -# include -# include -#endif - -#ifdef MOUNTED_LISTMNTENT -# include -#endif - -#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ -# include -#endif - -#ifdef MOUNTED_VMOUNT /* AIX. */ -# include -# include -#endif - -#ifdef DOLPHIN -/* So special that it's not worth putting this in autoconf. */ -# undef MOUNTED_FREAD_FSTYP -# define MOUNTED_GETMNTTBL -#endif - -#if HAVE_SYS_MNTENT_H -/* This is to get MNTOPT_IGNORE on e.g. SVR4. */ -# include -#endif - -#undef MNT_IGNORE -#if defined MNTOPT_IGNORE && defined HAVE_HASMNTOPT -# define MNT_IGNORE(M) hasmntopt ((M), MNTOPT_IGNORE) -#else -# define MNT_IGNORE(M) 0 -#endif - -#if USE_UNLOCKED_IO -# include "unlocked-io.h" -#endif - -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) -#endif - -/* The results of open() in this file are not used with fchdir, - therefore save some unnecessary work in fchdir.c. */ -#undef open -#undef close - -/* The results of opendir() in this file are not used with dirfd and fchdir, - therefore save some unnecessary work in fchdir.c. */ -#undef opendir -#undef closedir - -// gcc2 under haiku and beos don't like these macros for some reason. -// As they are not used there anyways, we remove them and everyone is happy. -#if !defined(__HAIKU__) && !defined(__BEOS__) -#ifndef ME_DUMMY -# define ME_DUMMY(Fs_name, Fs_type) \ - (strcmp (Fs_type, "autofs") == 0 \ - || strcmp (Fs_type, "none") == 0 \ - || strcmp (Fs_type, "proc") == 0 \ - || strcmp (Fs_type, "subfs") == 0 \ - || strcmp (Fs_type, "sysfs") == 0 \ - || strcmp (Fs_type, "usbfs") == 0 \ - || strcmp (Fs_type, "devpts") == 0 \ - || strcmp (Fs_type, "tmpfs") == 0 \ - /* for NetBSD 3.0 */ \ - || strcmp (Fs_type, "kernfs") == 0 \ - /* for Irix 6.5 */ \ - || strcmp (Fs_type, "ignore") == 0 \ - /* for MacOSX */ \ - || strcmp (Fs_type, "devfs") == 0 \ - || strcmp (Fs_type, "fdesc") == 0 \ - || strcmp (Fs_type, "nfs") == 0 \ - || strcmp (Fs_type, "volfs") == 0) -#endif - -#ifndef ME_REMOTE -/* A file system is `remote' if its Fs_name contains a `:' - or if (it is of type (smbfs or cifs) and its Fs_name starts with `//'). */ -# define ME_REMOTE(Fs_name, Fs_type) \ - (strchr (Fs_name, ':') != NULL \ - || ((Fs_name)[0] == '/' \ - && (Fs_name)[1] == '/' \ - && (strcmp (Fs_type, "smbfs") == 0 \ - || strcmp (Fs_type, "cifs") == 0))) -#endif -#endif // HAIKU / BEOS - -#ifdef MOUNTED_GETMNTINFO - -# if ! HAVE_STRUCT_STATFS_F_FSTYPENAME -static char * -fstype_to_string (short int t) -{ - switch (t) - { -# ifdef MOUNT_PC - case MOUNT_PC: - return "pc"; -# endif -# ifdef MOUNT_MFS - case MOUNT_MFS: - return "mfs"; -# endif -# ifdef MOUNT_LO - case MOUNT_LO: - return "lo"; -# endif -# ifdef MOUNT_TFS - case MOUNT_TFS: - return "tfs"; -# endif -# ifdef MOUNT_TMP - case MOUNT_TMP: - return "tmp"; -# endif -# ifdef MOUNT_UFS - case MOUNT_UFS: - return "ufs" ; -# endif -# ifdef MOUNT_NFS - case MOUNT_NFS: - return "nfs" ; -# endif -# ifdef MOUNT_MSDOS - case MOUNT_MSDOS: - return "msdos" ; -# endif -# ifdef MOUNT_LFS - case MOUNT_LFS: - return "lfs" ; -# endif -# ifdef MOUNT_LOFS - case MOUNT_LOFS: - return "lofs" ; -# endif -# ifdef MOUNT_FDESC - case MOUNT_FDESC: - return "fdesc" ; -# endif -# ifdef MOUNT_PORTAL - case MOUNT_PORTAL: - return "portal" ; -# endif -# ifdef MOUNT_NULL - case MOUNT_NULL: - return "null" ; -# endif -# ifdef MOUNT_UMAP - case MOUNT_UMAP: - return "umap" ; -# endif -# ifdef MOUNT_KERNFS - case MOUNT_KERNFS: - return "kernfs" ; -# endif -# ifdef MOUNT_PROCFS - case MOUNT_PROCFS: - return "procfs" ; -# endif -# ifdef MOUNT_AFS - case MOUNT_AFS: - return "afs" ; -# endif -# ifdef MOUNT_CD9660 - case MOUNT_CD9660: - return "cd9660" ; -# endif -# ifdef MOUNT_UNION - case MOUNT_UNION: - return "union" ; -# endif -# ifdef MOUNT_DEVFS - case MOUNT_DEVFS: - return "devfs" ; -# endif -# ifdef MOUNT_EXT2FS - case MOUNT_EXT2FS: - return "ext2fs" ; -# endif - default: - return "?"; - } -} -# endif - -static char * -fsp_to_string (const struct statfs *fsp) -{ -# if HAVE_STRUCT_STATFS_F_FSTYPENAME - return (char *) (fsp->f_fstypename); -# else - return fstype_to_string (fsp->f_type); -# endif -} - -#endif /* MOUNTED_GETMNTINFO */ - -#ifdef MOUNTED_VMOUNT /* AIX. */ -static char * -fstype_to_string (int t) -{ - struct vfs_ent *e; - - e = getvfsbytype (t); - if (!e || !e->vfsent_name) - return "none"; - else - return e->vfsent_name; -} -#endif /* MOUNTED_VMOUNT */ - -#ifdef __linux__ - #define BROKEN __attribute__((unused)) -#else - #define BROKEN -#endif - - -#if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2 - -/* Return the device number from MOUNT_OPTIONS, if possible. - Otherwise return (dev_t) -1. */ - -static dev_t -dev_from_mount_options (BROKEN char const *mount_options) -{ - /* GNU/Linux allows file system implementations to define their own - meaning for "dev=" mount options, so don't trust the meaning - here. */ -# ifndef __linux__ - - static char const dev_pattern[] = ",dev="; - char const *devopt = strstr (mount_options, dev_pattern); - - if (devopt) - { - char const *optval = devopt + sizeof dev_pattern - 1; - char *optvalend; - unsigned long int dev; - errno = 0; - dev = strtoul (optval, &optvalend, 16); - if (optval != optvalend - && (*optvalend == '\0' || *optvalend == ',') - && ! (dev == ULONG_MAX && errno == ERANGE) - && dev == (dev_t) dev) - return dev; - } - -# endif - - return -1; -} - -#endif - -/* Return a list of the currently mounted file systems, or NULL on error. - Add each entry to the tail of the list so that they stay in order. - If NEED_FS_TYPE is true, ensure that the file system type fields in - the returned list are valid. Otherwise, they might not be. */ - -struct mount_entry * -read_file_system_list (BROKEN bool need_fs_type) -{ - struct mount_entry *mount_list; - struct mount_entry *me; - struct mount_entry **mtail = &mount_list; - -#ifdef MOUNTED_LISTMNTENT - { - struct tabmntent *mntlist, *p; - struct mntent *mnt; - struct mount_entry *me; - - /* the third and fourth arguments could be used to filter mounts, - but Crays doesn't seem to have any mounts that we want to - remove. Specifically, automount create normal NFS mounts. - */ - - if (listmntent (&mntlist, KMTAB, NULL, NULL) < 0) - return NULL; - for (p = mntlist; p; p = p->next) { - mnt = p->ment; - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (mnt->mnt_fsname); - me->me_mountdir = xstrdup (mnt->mnt_dir); - me->me_type = xstrdup (mnt->mnt_type); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = -1; - *mtail = me; - mtail = &me->me_next; - } - freemntlist (mntlist); - } -#endif - -#ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */ - { - struct mntent *mnt; - char *table = MOUNTED; - FILE *fp; - - fp = setmntent (table, "r"); - if (fp == NULL) - return NULL; - - while ((mnt = getmntent (fp))) - { - me = malloc (sizeof *me); - me->me_devname = strdup (mnt->mnt_fsname); - me->me_mountdir = strdup (mnt->mnt_dir); - me->me_type = strdup (mnt->mnt_type); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = dev_from_mount_options (mnt->mnt_opts); - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - if (endmntent (fp) == 0) - goto free_then_fail; - } -#endif /* MOUNTED_GETMNTENT1. */ - -#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */ - { - struct statfs *fsp; - int entries; - - entries = getmntinfo (&fsp, MNT_NOWAIT); - if (entries < 0) - return NULL; - for (; entries-- > 0; fsp++) - { - me = malloc (sizeof *me); - me->me_devname = strdup (fsp->f_mntfromname); - me->me_mountdir = strdup (fsp->f_mntonname); -#if defined(__macosx__) - me->me_type = fsp->f_fstypename; -#else - me->me_type = fsp->fs_typename; -#endif - me->me_type_malloced = 0; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - } -#endif /* MOUNTED_GETMNTINFO */ - -#ifdef MOUNTED_GETMNTINFO2 /* NetBSD 3.0. */ - { - struct statvfs *fsp; - int entries; - - entries = getmntinfo (&fsp, MNT_NOWAIT); - if (entries < 0) - return NULL; - for (; entries-- > 0; fsp++) - { - me = malloc (sizeof *me); - me->me_devname = strdup (fsp->f_mntfromname); - me->me_mountdir = strdup (fsp->f_mntonname); - me->me_type = strdup (fsp->f_fstypename); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - } -#endif /* MOUNTED_GETMNTINFO2 */ - -#ifdef MOUNTED_GETMNT /* Ultrix. */ - { - int offset = 0; - int val; - struct fs_data fsd; - - while (errno = 0, - 0 < (val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY, - (char *) 0))) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (fsd.fd_req.devname); - me->me_mountdir = xstrdup (fsd.fd_req.path); - me->me_type = gt_names[fsd.fd_req.fstype]; - me->me_type_malloced = 0; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = fsd.fd_req.dev; - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - if (val < 0) - goto free_then_fail; - } -#endif /* MOUNTED_GETMNT. */ - -#if defined MOUNTED_FS_STAT_DEV /* BeOS */ - { - /* The next_dev() and fs_stat_dev() system calls give the list of - all file systems, including the information returned by statvfs() - (fs type, total blocks, free blocks etc.), but without the mount - point. But on BeOS all file systems except / are mounted in the - rootfs, directly under /. - The directory name of the mount point is often, but not always, - identical to the volume name of the device. - We therefore get the list of subdirectories of /, and the list - of all file systems, and match the two lists. */ - - DIR *dirp; - struct rootdir_entry - { - char *name; - dev_t dev; - ino_t ino; - struct rootdir_entry *next; - }; - struct rootdir_entry *rootdir_list; - struct rootdir_entry **rootdir_tail; - int32 pos; - dev_t dev; - fs_info fi; - - /* All volumes are mounted in the rootfs, directly under /. */ - rootdir_list = NULL; - rootdir_tail = &rootdir_list; - dirp = opendir ("/"); - if (dirp) - { - struct dirent *d; - - while ((d = readdir (dirp)) != NULL) - { - char *name; - struct stat statbuf; - - if (strcmp (d->d_name, "..") == 0) - continue; - - if (strcmp (d->d_name, ".") == 0) - name = strdup ("/"); - else - { - name = malloc (1 + strlen (d->d_name) + 1); - name[0] = '/'; - strcpy (name + 1, d->d_name); - } - - if (lstat (name, &statbuf) >= 0 && S_ISDIR (statbuf.st_mode)) - { - struct rootdir_entry *re = malloc (sizeof *re); - re->name = name; - re->dev = statbuf.st_dev; - re->ino = statbuf.st_ino; - - /* Add to the linked list. */ - *rootdir_tail = re; - rootdir_tail = &re->next; - } - else - free (name); - } - closedir (dirp); - } - *rootdir_tail = NULL; - - for (pos = 0; (dev = next_dev (&pos)) >= 0; ) - if (fs_stat_dev (dev, &fi) >= 0) - { - /* Note: fi.dev == dev. */ - struct rootdir_entry *re; - - for (re = rootdir_list; re; re = re->next) - if (re->dev == fi.dev && re->ino == fi.root) - break; - - me = malloc (sizeof *me); - me->me_devname = strdup (fi.device_name[0] != '\0' ? fi.device_name : fi.fsh_name); - me->me_mountdir = strdup (re != NULL ? re->name : fi.fsh_name); - me->me_type = strdup (fi.fsh_name); - me->me_type_malloced = 1; - me->me_dev = fi.dev; - me->me_dummy = 0; - me->me_remote = (fi.flags & B_FS_IS_SHARED) != 0; - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - *mtail = NULL; - - while (rootdir_list != NULL) - { - struct rootdir_entry *re = rootdir_list; - rootdir_list = re->next; - free (re->name); - free (re); - } - } -#endif /* MOUNTED_FS_STAT_DEV */ - -#if defined MOUNTED_GETFSSTAT /* __alpha running OSF_1 */ - { - int numsys, counter; - size_t bufsize; - struct statfs *stats; - - numsys = getfsstat ((struct statfs *)0, 0L, MNT_NOWAIT); - if (numsys < 0) - return (NULL); - /* - if (SIZE_MAX / sizeof *stats <= numsys) - xalloc_die ();*/ - - bufsize = (1 + numsys) * sizeof *stats; - stats = malloc (bufsize); - numsys = getfsstat (stats, bufsize, MNT_NOWAIT); - - if (numsys < 0) - { - free (stats); - return (NULL); - } - - for (counter = 0; counter < numsys; counter++) - { - me = malloc (sizeof *me); - me->me_devname = strdup (stats[counter].f_mntfromname); - me->me_mountdir = strdup (stats[counter].f_mntonname); - //me->me_type = strdup (FS_TYPE (stats[counter])); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - free (stats); - } -#endif /* MOUNTED_GETFSSTAT */ - -#if defined MOUNTED_FREAD || defined MOUNTED_FREAD_FSTYP /* SVR[23]. */ - { - struct mnttab mnt; - char *table = "/etc/mnttab"; - FILE *fp; - - fp = fopen (table, "r"); - if (fp == NULL) - return NULL; - - while (fread (&mnt, sizeof mnt, 1, fp) > 0) - { - me = xmalloc (sizeof *me); -# ifdef GETFSTYP /* SVR3. */ - me->me_devname = xstrdup (mnt.mt_dev); -# else - me->me_devname = xmalloc (strlen (mnt.mt_dev) + 6); - strcpy (me->me_devname, "/dev/"); - strcpy (me->me_devname + 5, mnt.mt_dev); -# endif - me->me_mountdir = xstrdup (mnt.mt_filsys); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - me->me_type = ""; - me->me_type_malloced = 0; -# ifdef GETFSTYP /* SVR3. */ - if (need_fs_type) - { - struct statfs fsd; - char typebuf[FSTYPSZ]; - - if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1 - && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1) - { - me->me_type = xstrdup (typebuf); - me->me_type_malloced = 1; - } - } -# endif - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - if (ferror (fp)) - { - /* The last fread() call must have failed. */ - int saved_errno = errno; - fclose (fp); - errno = saved_errno; - goto free_then_fail; - } - - if (fclose (fp) == EOF) - goto free_then_fail; - } -#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */ - -#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */ - { - struct mntent **mnttbl = getmnttbl (), **ent; - for (ent=mnttbl;*ent;ent++) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup ( (*ent)->mt_resource); - me->me_mountdir = xstrdup ( (*ent)->mt_directory); - me->me_type = xstrdup ((*ent)->mt_fstype); - me->me_type_malloced = 1; - me->me_dummy = ME_DUMMY (me->me_devname, me->me_type); - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = (dev_t) -1; /* Magic; means not known yet. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - endmnttbl (); - } -#endif - -#ifdef MOUNTED_GETMNTENT2 /* SVR4. */ - { - struct mnttab mnt; - char *table = MNTTAB; - FILE *fp; - int ret; - int lockfd = -1; - -# if defined F_RDLCK && defined F_SETLKW - /* MNTTAB_LOCK is a macro name of our own invention; it's not present in - e.g. Solaris 2.6. If the SVR4 folks ever define a macro - for this file name, we should use their macro name instead. - (Why not just lock MNTTAB directly? We don't know.) */ -# ifndef MNTTAB_LOCK -# define MNTTAB_LOCK "/etc/.mnttab.lock" -# endif - lockfd = open (MNTTAB_LOCK, O_RDONLY); - if (0 <= lockfd) - { - struct flock flock; - flock.l_type = F_RDLCK; - flock.l_whence = SEEK_SET; - flock.l_start = 0; - flock.l_len = 0; - while (fcntl (lockfd, F_SETLKW, &flock) == -1) - if (errno != EINTR) - { - int saved_errno = errno; - close (lockfd); - errno = saved_errno; - return NULL; - } - } - else if (errno != ENOENT) - return NULL; -# endif - - errno = 0; - fp = fopen (table, "r"); - if (fp == NULL) - ret = errno; - else - { - while ((ret = getmntent (fp, &mnt)) == 0) - { - me = xmalloc (sizeof *me); - me->me_devname = xstrdup (mnt.mnt_special); - me->me_mountdir = xstrdup (mnt.mnt_mountp); - me->me_type = xstrdup (mnt.mnt_fstype); - me->me_type_malloced = 1; - me->me_dummy = MNT_IGNORE (&mnt) != 0; - me->me_remote = ME_REMOTE (me->me_devname, me->me_type); - me->me_dev = dev_from_mount_options (mnt.mnt_mntopts); - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - - ret = fclose (fp) == EOF ? errno : 0 < ret ? 0 : -1; - } - - if (0 <= lockfd && close (lockfd) != 0) - ret = errno; - - if (0 <= ret) - { - errno = ret; - goto free_then_fail; - } - } -#endif /* MOUNTED_GETMNTENT2. */ - -#ifdef MOUNTED_VMOUNT /* AIX. */ - { - int bufsize; - char *entries, *thisent; - struct vmount *vmp; - int n_entries; - int i; - - /* Ask how many bytes to allocate for the mounted file system info. */ - if (mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize) != 0) - return NULL; - entries = xmalloc (bufsize); - - /* Get the list of mounted file systems. */ - n_entries = mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries); - if (n_entries < 0) - { - int saved_errno = errno; - free (entries); - errno = saved_errno; - return NULL; - } - - for (i = 0, thisent = entries; - i < n_entries; - i++, thisent += vmp->vmt_length) - { - char *options, *ignore; - - vmp = (struct vmount *) thisent; - me = xmalloc (sizeof *me); - if (vmp->vmt_flags & MNT_REMOTE) - { - char *host, *dir; - - me->me_remote = 1; - /* Prepend the remote dirname. */ - host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off; - dir = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off; - me->me_devname = xmalloc (strlen (host) + strlen (dir) + 2); - strcpy (me->me_devname, host); - strcat (me->me_devname, ":"); - strcat (me->me_devname, dir); - } - else - { - me->me_remote = 0; - me->me_devname = xstrdup (thisent + - vmp->vmt_data[VMT_OBJECT].vmt_off); - } - me->me_mountdir = xstrdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off); - me->me_type = xstrdup (fstype_to_string (vmp->vmt_gfstype)); - me->me_type_malloced = 1; - options = thisent + vmp->vmt_data[VMT_ARGS].vmt_off; - ignore = strstr (options, "ignore"); - me->me_dummy = (ignore - && (ignore == options || ignore[-1] == ',') - && (ignore[sizeof "ignore" - 1] == ',' - || ignore[sizeof "ignore" - 1] == '\0')); - me->me_dev = (dev_t) -1; /* vmt_fsid might be the info we want. */ - - /* Add to the linked list. */ - *mtail = me; - mtail = &me->me_next; - } - free (entries); - } -#endif /* MOUNTED_VMOUNT. */ - - *mtail = NULL; - return mount_list; - - - free_then_fail: - { - int saved_errno = errno; - *mtail = NULL; - - while (mount_list) - { - me = mount_list->me_next; - free (mount_list->me_devname); - free (mount_list->me_mountdir); - if (mount_list->me_type_malloced) - free (mount_list->me_type); - free (mount_list); - mount_list = me; - } - - errno = saved_errno; - return NULL; - } -} - -#endif - diff --git a/project/jni/application/grafx2/grafx2/src/mountlist.h b/project/jni/application/grafx2/grafx2/src/mountlist.h deleted file mode 100644 index ae0c29448..000000000 --- a/project/jni/application/grafx2/grafx2/src/mountlist.h +++ /dev/null @@ -1,54 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* mountlist.h -- declarations for list of mounted file systems - - Copyright (C) 1991, 1992, 1998, 2000, 2001, 2002, 2003, 2004, 2005 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file mountlist.h -/// A function to enumerate the mounting points in the filesystem. -/// Used to display them in fileselectors. -////////////////////////////////////////////////////////////////////////////// - -#ifndef MOUNTLIST_H_ -# define MOUNTLIST_H_ - -#if !defined(__VBCC__) - # include -#else - #define bool char -#endif - -#include - -/* A mount table entry. */ -struct mount_entry -{ - char *me_devname; /* Device node name, including "/dev/". */ - char *me_mountdir; /* Mount point directory name. */ - char *me_type; /* "nfs", "4.2", etc. */ - dev_t me_dev; /* Device number of me_mountdir. */ - unsigned int me_dummy : 1; /* Nonzero for dummy file systems. */ - unsigned int me_remote : 1; /* Nonzero for remote fileystems. */ - unsigned int me_type_malloced : 1; /* Nonzero if me_type was malloced. */ - struct mount_entry *me_next; -}; - -struct mount_entry *read_file_system_list (bool need_fs_type); - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/op_c.c b/project/jni/application/grafx2/grafx2/src/op_c.c deleted file mode 100644 index 1838d5d7c..000000000 --- a/project/jni/application/grafx2/grafx2/src/op_c.c +++ /dev/null @@ -1,1415 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2010 Alexander Filyanov - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "op_c.h" -#include "errors.h" - -int Convert_24b_bitmap_to_256_fast(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette); - -/// Convert RGB to HSL. -/// Both input and output are in the 0..255 range to use in the palette screen -void RGB_to_HSL(int r,int g,int b,byte * hr,byte * sr,byte* lr) -{ - double rd,gd,bd,h,s,l,max,min; - - // convert RGB to HSV - rd = r / 255.0; // rd,gd,bd range 0-1 instead of 0-255 - gd = g / 255.0; - bd = b / 255.0; - - // compute maximum of rd,gd,bd - if (rd>=gd) - { - if (rd>=bd) - max = rd; - else - max = bd; - } - else - { - if (gd>=bd) - max = gd; - else - max = bd; - } - - // compute minimum of rd,gd,bd - if (rd<=gd) - { - if (rd<=bd) - min = rd; - else - min = bd; - } - else - { - if (gd<=bd) - min = gd; - else - min = bd; - } - - l = (max + min) / 2.0; - - if(max==min) - s = h = 0; - else - { - if (l<=0.5) - s = (max - min) / (max + min); - else - s = (max - min) / (2 - (max + min)); - - if (max == rd) - h = 42.5 * (gd-bd)/(max-min); - else if (max == gd) - h = 42.5 * (bd-rd)/(max-min)+85; - else - h = 42.5 * (rd-gd)/(max-min)+170; - if (h<0) h+=255; - } - - *hr = h; - *lr = (l*255.0); - *sr = (s*255.0); -} - -/// Convert HSL back to RGB -/// Input and output are all in range 0..255 -void HSL_to_RGB(byte h,byte s,byte l, byte* r, byte* g, byte* b) -{ - float rf =0 ,gf = 0,bf = 0; - float hf,lf,sf; - float p,q; - - if(s==0) - { - *r=*g=*b=l; - return; - } - - hf = h / 255.0; - lf = l / 255.0; - sf = s / 255.0; - - if (lf<=0.5) - q = lf*(1+sf); - else - q = lf+sf-lf*sf; - p = 2*lf-q; - - rf = hf + (1 / 3.0); - gf = hf; - bf = hf - (1 / 3.0); - - if (rf < 0) rf+=1; - if (rf > 1) rf-=1; - if (gf < 0) gf+=1; - if (gf > 1) gf-=1; - if (bf < 0) bf+=1; - if (bf > 1) bf-=1; - - if (rf < 1/6.0) - rf = p + ((q-p)*6*rf); - else if(rf < 0.5) - rf = q; - else if(rf < 2/3.0) - rf = p + ((q-p)*6*(2/3.0-rf)); - else - rf = p; - - if (gf < 1/6.0) - gf = p + ((q-p)*6*gf); - else if(gf < 0.5) - gf = q; - else if(gf < 2/3.0) - gf = p + ((q-p)*6*(2/3.0-gf)); - else - gf = p; - - if (bf < 1/6.0) - bf = p + ((q-p)*6*bf); - else if(bf < 0.5) - bf = q; - else if(bf < 2/3.0) - bf = p + ((q-p)*6*(2/3.0-bf)); - else - bf = p; - - *r = rf * (255); - *g = gf * (255); - *b = bf * (255); -} - -/// -/// Returns a value that is high when color is near white, -/// and low when it's darker. Used for sorting. -long Perceptual_lightness(T_Components *color) -{ - return 26*color->R*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 -// creating the whole table and only create parts of it when they are actually -// needed. This may or may not be faster - -/// Creates a new conversion table -/// params: bumber of bits for R, G, B (precision) -T_Conversion_table * CT_new(int nbb_r,int nbb_g,int nbb_b) -{ - T_Conversion_table * n; - int size; - - n=(T_Conversion_table *)malloc(sizeof(T_Conversion_table)); - if (n!=NULL) - { - // Copy the passed parameters - n->nbb_r=nbb_r; - n->nbb_g=nbb_g; - n->nbb_b=nbb_b; - - // Calculate the others - - // Value ranges (max value actually) - n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; - n->dec_g=nbb_b; - n->dec_b=0; - - // Reductions (how many bits are lost) - n->red_r=8-nbb_r; - n->red_g=8-nbb_g; - n->red_b=8-nbb_b; - - // Allocate the table - size=(n->rng_r)*(n->rng_g)*(n->rng_b); - n->table=(byte *)calloc(size, 1); - if (n->table == NULL) - { - // Not enough memory - free(n); - n=NULL; - } - } - - return n; -} - - -/// Delete a conversion table and release its memory -void CT_delete(T_Conversion_table * t) -{ - free(t->table); - free(t); - t = NULL; -} - - -/// Get the best palette index for an (R, G, B) color -byte CT_get(T_Conversion_table * t,int r,int g,int b) -{ - int index; - - // Reduce the number of bits to the table precision - r=(r>>t->red_r); - g=(g>>t->red_g); - b=(b>>t->red_b); - - // Find the nearest color - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - - return t->table[index]; -} - - -/// Set an entry of the table, index (RGB), value i -void CT_set(T_Conversion_table * t,int r,int g,int b,byte i) -{ - int index; - - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - t->table[index]=i; -} - - -// Handlers for the occurences tables -// This table is used to count the occurence of an (RGB) pixel value in the -// source 24bit image. These count are then used by the median cut algorithm to -// decide which cluster to split. - -/// Initialize an occurence table -void OT_init(T_Occurrence_table * t) -{ - int size; - - size=(t->rng_r)*(t->rng_g)*(t->rng_b)*sizeof(int); - memset(t->table,0,size); // Set it to 0 -} - -/// Allocate an occurence table for given number of bits -T_Occurrence_table * OT_new(int nbb_r,int nbb_g,int nbb_b) -{ - T_Occurrence_table * n; - int size; - - n=(T_Occurrence_table *)malloc(sizeof(T_Occurrence_table)); - if (n!=0) - { - // Copy passed parameters - n->nbb_r=nbb_r; - n->nbb_g=nbb_g; - n->nbb_b=nbb_b; - - // Compute others - n->rng_r=(1<rng_g=(1<rng_b=(1<dec_r=nbb_g+nbb_b; - n->dec_g=nbb_b; - n->dec_b=0; - n->red_r=8-nbb_r; - n->red_g=8-nbb_g; - n->red_b=8-nbb_b; - - // Allocate the table - size=(n->rng_r)*(n->rng_g)*(n->rng_b)*sizeof(int); - n->table=(int *)calloc(size, 1); - if (n->table == NULL) - { - // Not enough memory ! - free(n); - n=NULL; - } - } - - return n; -} - - -/// Delete a table and free the memory -void OT_delete(T_Occurrence_table * t) -{ - free(t->table); - free(t); - t = NULL; -} - - -/// Get number of occurences for a given color -int OT_get(T_Occurrence_table * t, int r, int g, int b) -{ - int index; - - // Drop bits as needed - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - return t->table[index]; -} - - -/// Add 1 to the count for a color -void OT_inc(T_Occurrence_table * t,int r,int g,int b) -{ - int index; - - // Drop bits as needed - r=(r>>t->red_r); - g=(g>>t->red_g); - b=(b>>t->red_b); - // Compute the address - index=(r<dec_r) | (g<dec_g) | (b<dec_b); - t->table[index]++; -} - - -/// Count the use of each color in a 24bit picture and fill in the table -void OT_count_occurrences(T_Occurrence_table* t, T_Bitmap24B image, int size) -{ - T_Bitmap24B ptr; - int index; - - for (index = size, ptr = image; index > 0; index--, ptr++) - OT_inc(t, ptr->R, ptr->G, ptr->B); -} - - -/// Count the total number of pixels in an occurence table -int OT_count_colors(T_Occurrence_table * t) -{ - int val; // Computed return value - int nb; // Number of colors to test - int i; // Loop index - - val = 0; - nb=(t->rng_r)*(t->rng_g)*(t->rng_b); - for (i = 0; i < nb; i++) - if (t->table[i]>0) - val++; - - return val; -} - - -// Cluster management -// Clusters are boxes in the RGB spaces, defined by 6 corner coordinates : -// Rmax, Rmin, Vmax (or Gmax), Vmin, Rmax, Rmin -// The median cut algorithm start with a single cluster covering the whole -// colorspace then split it in two smaller clusters on the longest axis until -// there are 256 non-empty clusters (with some tricks if the original image -// actually has less than 256 colors) -// Each cluster also store the number of pixels that are inside and the -// rmin, rmax, vmin, vmax, bmin, bmax values are the first/last values that -// actually are used by a pixel in the cluster -// When you split a big cluster there may be some space between the splitting -// plane and the first pixel actually in a cluster - - -/// Pack a cluster, ie compute its {r,v,b}{min,max} values -void Cluster_pack(T_Cluster * c,T_Occurrence_table * to) -{ - int rmin,rmax,vmin,vmax,bmin,bmax; - int r,g,b; - - // Find min. and max. values actually used for each component in this cluster - - // Pre-shift everything to avoid using OT_Get and be faster. This will only - // work if the occurence table actually has full precision, that is a - // 256^3*sizeof(int) = 64MB table. If your computer has less free ram and - // malloc fails, this will not work at all ! - // GIMP use only 6 bits for G and B components in this table. - rmin=c->rmax <<16; rmax=c->rmin << 16; - vmin=c->vmax << 8; vmax=c->vmin << 8; - bmin=c->bmax; bmax=c->bmin; - c->occurences=0; - - // Unoptimized code kept here for documentation purpose because the optimized - // one is unreadable : run over the whole cluster and find the min and max, - // and count the occurences at the same time. - /* - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for (b=c->bmin;b<=c->bmax;b++) - { - nbocc=to->table[r + g + b]; // OT_get - if (nbocc) - { - if (rrmax) rmax=r; - if (gvmax) vmax=g; - if (bbmax) bmax=b; - c->occurences+=nbocc; - } - } - */ - - // Optimized version : find the extremums one at a time, so we can reduce the - // area to seek for the next one. Start at the edges of the cluster and go to - // the center until we find a pixel. - - for(r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - rmin=r; - goto RMAX; - } - } -RMAX: - for(r=c->rmax<<16;r>=rmin;r-=1<<16) - for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - rmax=r; - goto VMIN; - } - } -VMIN: - for(g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - for(r=rmin;r<=rmax;r+=1<<16) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - vmin=g; - goto VMAX; - } - } -VMAX: - for(g=c->vmax<<8;g>=vmin;g-=1<<8) - for(r=rmin;r<=rmax;r+=1<<16) - for(b=c->bmin;b<=c->bmax;b++) - { - if(to->table[r + g + b]) // OT_get - { - vmax=g; - goto BMIN; - } - } -BMIN: - for(b=c->bmin;b<=c->bmax;b++) - for(r=rmin;r<=rmax;r+=1<<16) - for(g=vmin;g<=vmax;g+=1<<8) - { - if(to->table[r + g + b]) // OT_get - { - bmin=b; - goto BMAX; - } - } -BMAX: - for(b=c->bmax;b>=bmin;b--) - for(r=rmin;r<=rmax;r+=1<<16) - for(g=vmin;g<=vmax;g+=1<<8) - { - if(to->table[r + g + b]) // OT_get - { - bmax=b; - goto ENDCRUSH; - } - } -ENDCRUSH: - // We still need to seek the internal part of the cluster to count pixels - // inside it - for(r=rmin;r<=rmax;r+=1<<16) - for(g=vmin;g<=vmax;g+=1<<8) - for(b=bmin;b<=bmax;b++) - { - c->occurences+=to->table[r + g + b]; // OT_get - } - - // Unshift the values and put them in the cluster info - c->rmin=rmin>>16; c->rmax=rmax>>16; - c->vmin=vmin>>8; c->vmax=vmax>>8; - c->bmin=bmin; c->bmax=bmax; - - // Find the longest axis to know which way to split the cluster - // This multiplications are supposed to improve the result, but may or may not - // work, actually. - r=(c->rmax-c->rmin)*299; - g=(c->vmax-c->vmin)*587; - b=(c->bmax-c->bmin)*114; - - if (g>=r) - { - // G>=R - if (g>=b) - { - // G>=R et G>=B - c->plus_large=1; - } - else - { - // G>=R et Gplus_large=2; - } - } - else - { - // R>G - if (r>=b) - { - // R>G et R>=B - c->plus_large=0; - } - else - { - // R>G et Rplus_large=2; - } - } -} - - -/// Split a cluster on its longest axis. -/// c = source cluster, c1, c2 = output after split -void Cluster_split(T_Cluster * c, T_Cluster * c1, T_Cluster * c2, int hue, - T_Occurrence_table * to) -{ - int limit; - int cumul; - int r, g, b; - - // Split criterion: each of the cluster will have the same number of pixels - limit = c->occurences / 2; - cumul = 0; - if (hue == 0) // split on red - { - // Run over the cluster until we reach the requested number of pixels - for (r = c->rmin<<16; r<=c->rmax<<16; r+=1<<16) - { - for (g = c->vmin<<8; g<=c->vmax<<8; g+=1<<8) - { - for (b = c->bmin; b<=c->bmax; b++) - { - cumul+=to->table[r + g + b]; - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - - r>>=16; - g>>=8; - - // We tried to split on red, but found half of the pixels with r = rmin - // so we enforce some split to happen anyway, instead of creating an empty - // c2 and c1 == c - if (r==c->rmin) - r++; - - c1->Rmin=c->Rmin; c1->Rmax=r-1; - c1->rmin=c->rmin; c1->rmax=r-1; - c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; - c1->vmin=c->vmin; c1->vmax=c->vmax; - c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; - c1->bmin=c->bmin; c1->bmax=c->bmax; - - c2->Rmin=r; c2->Rmax=c->Rmax; - c2->rmin=r; c2->rmax=c->rmax; - c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; - c2->vmin=c->vmin; c2->vmax=c->vmax; - c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; - c2->bmin=c->bmin; c2->bmax=c->bmax; - } - else - if (hue==1) // split on green - { - - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - { - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - { - for (b=c->bmin;b<=c->bmax;b++) - { - cumul+=to->table[r + g + b]; - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - - r>>=16; g>>=8; - - if (g==c->vmin) - g++; - - c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; - c1->rmin=c->rmin; c1->rmax=c->rmax; - c1->Gmin=c->Gmin; c1->Vmax=g-1; - c1->vmin=c->vmin; c1->vmax=g-1; - c1->Bmin=c->Bmin; c1->Bmax=c->Bmax; - c1->bmin=c->bmin; c1->bmax=c->bmax; - - c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; - c2->rmin=c->rmin; c2->rmax=c->rmax; - c2->Gmin=g; c2->Vmax=c->Vmax; - c2->vmin=g; c2->vmax=c->vmax; - c2->Bmin=c->Bmin; c2->Bmax=c->Bmax; - c2->bmin=c->bmin; c2->bmax=c->bmax; - } - else // split on blue - { - - for (b=c->bmin;b<=c->bmax;b++) - { - for (g=c->vmin<<8;g<=c->vmax<<8;g+=1<<8) - { - for (r=c->rmin<<16;r<=c->rmax<<16;r+=1<<16) - { - cumul+=to->table[r + g + b]; - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - if (cumul>=limit) - break; - } - - r>>=16; g>>=8; - - if (b==c->bmin) - b++; - - c1->Rmin=c->Rmin; c1->Rmax=c->Rmax; - c1->rmin=c->rmin; c1->rmax=c->rmax; - c1->Gmin=c->Gmin; c1->Vmax=c->Vmax; - c1->vmin=c->vmin; c1->vmax=c->vmax; - c1->Bmin=c->Bmin; c1->Bmax=b-1; - c1->bmin=c->bmin; c1->bmax=b-1; - - c2->Rmin=c->Rmin; c2->Rmax=c->Rmax; - c2->rmin=c->rmin; c2->rmax=c->rmax; - c2->Gmin=c->Gmin; c2->Vmax=c->Vmax; - c2->vmin=c->vmin; c2->vmax=c->vmax; - c2->Bmin=b; c2->Bmax=c->Bmax; - c2->bmin=b; c2->bmax=c->bmax; - } -} - - -/// Compute the mean R, G, B (for palette generation) and H, L (for palette sorting) -void Cluster_compute_hue(T_Cluster * c,T_Occurrence_table * to) -{ - int cumul_r,cumul_g,cumul_b; - int r,g,b; - int nbocc; - - byte s=0; - - cumul_r=cumul_g=cumul_b=0; - for (r=c->rmin;r<=c->rmax;r++) - for (g=c->vmin;g<=c->vmax;g++) - for (b=c->bmin;b<=c->bmax;b++) - { - nbocc=OT_get(to,r,g,b); - if (nbocc) - { - cumul_r+=r*nbocc; - cumul_g+=g*nbocc; - cumul_b+=b*nbocc; - } - } - - c->r=(cumul_r<red_r)/c->occurences; - c->g=(cumul_g<red_g)/c->occurences; - c->b=(cumul_b<red_b)/c->occurences; - RGB_to_HSL(c->r, c->g, c->b, &c->h, &s, &c->l); -} - - -// Cluster set management -// A set of clusters in handled as a list, the median cut algorithm pops a -// cluster from the list, split it, and pushes back the two splitted clusters -// until the lit grows to 256 items - - -// Debug helper : check if a cluster set has the right count value -/* -void CS_Check(T_Cluster_set* cs) -{ - int i; - T_Cluster* c = cs->clusters; - for (i = cs->nb; i > 0; i--) - { - assert( c != NULL); - c = c->next; - } - - assert(c == NULL); -} -*/ - -/// Setup the first cluster before we start the operations -/// This one covers the full palette range -void CS_Init(T_Cluster_set * cs, T_Occurrence_table * to) -{ - cs->clusters->Rmin = cs->clusters->rmin = 0; - cs->clusters->Gmin = cs->clusters->vmin = 0; - cs->clusters->Bmin = cs->clusters->bmin = 0; - cs->clusters->Rmax = cs->clusters->rmax = to->rng_r - 1; - cs->clusters->Vmax = cs->clusters->vmax = to->rng_g - 1; - cs->clusters->Bmax = cs->clusters->bmax = to->rng_b - 1; - cs->clusters->next = NULL; - Cluster_pack(cs->clusters, to); - cs->nb = 1; -} - -/// Allocate a new cluster set -T_Cluster_set * CS_New(int nbmax, T_Occurrence_table * to) -{ - T_Cluster_set * n; - - n=(T_Cluster_set *)malloc(sizeof(T_Cluster_set)); - if (n != NULL) - { - // Copy requested params - n->nb_max = OT_count_colors(to); - - // If the number of colors asked is > 256, we ceil it because we know we - // don't want more - if (n->nb_max > nbmax) - { - n->nb_max = nbmax; - } - - // Allocate the first cluster - n->clusters=(T_Cluster *)malloc(sizeof(T_Cluster)); - if (n->clusters != NULL) - CS_Init(n, to); - else - { - // No memory free ! Sorry ! - free(n); - n = NULL; - } - } - - return n; -} - -/// Free a cluster set -void CS_Delete(T_Cluster_set * cs) -{ - T_Cluster* nxt; - while (cs->clusters != NULL) - { - nxt = cs->clusters->next; - free(cs->clusters); - cs->clusters = nxt; - } - free(cs); - cs = NULL; -} - - -/// Pop a cluster from the cluster list -void CS_Get(T_Cluster_set * cs, T_Cluster * c) -{ - T_Cluster* current = cs->clusters; - T_Cluster* prev = NULL; - - // Search a cluster with at least 2 distinct colors so we can split it - // Clusters are sorted by number of occurences, so a cluster may end up - // with a lot of pixelsand on top of the list, but only one color. We can't - // split it in that case. It should probably be stored on a list of unsplittable - // clusters to avoid running on it again on each iteration. - do - { - if ( (current->rmin < current->rmax) || - (current->vmin < current->vmax) || - (current->bmin < current->bmax) ) - break; - - prev = current; - - } while((current = current -> next)); - - // copy it to c - *c = *current; - - // remove it from the list - cs->nb--; - - if(prev) - prev->next = current->next; - else - cs->clusters = current->next; - free(current); - current = NULL; -} - - -/// Push a cluster in the list -void CS_Set(T_Cluster_set * cs,T_Cluster * c) -{ - T_Cluster* current = cs->clusters; - T_Cluster* prev = NULL; - - // Search the first cluster that is smaller than ours (less pixels) - while (current && current->occurences > c->occurences) - { - prev = current; - current = current->next; - } - - // Now insert our cluster just before the one we found - c -> next = current; - - current = malloc(sizeof(T_Cluster)); - *current = *c ; - - if (prev) prev->next = current; - else cs->clusters = current; - - cs->nb++; -} - -/// This is the main median cut algorithm and the function actually called to -/// reduce the palette. We get the number of pixels for each collor in the -/// occurence table and generate the cluster set from it. -// 1) RGB space is a big box -// 2) We seek the pixels with extreme values -// 3) We split the box in 2 parts on its longest axis -// 4) We pack the 2 resulting boxes again to leave no empty space between the box border and the first pixel -// 5) We take the box with the biggest number of pixels inside and we split it again -// 6) Iterate until there are 256 boxes. Associate each of them to its middle color -void CS_Generate(T_Cluster_set * cs, T_Occurrence_table * to) -{ - T_Cluster current; - T_Cluster Nouveau1; - T_Cluster Nouveau2; - - // There are less than 256 boxes - while (cs->nbnb_max) - { - // Get the biggest one - CS_Get(cs,¤t); - - // Split it - Cluster_split(¤t, &Nouveau1, &Nouveau2, current.plus_large, to); - - // Pack the 2 new clusters (the split may leave some empty space between the - // box border and the first actual pixel) - Cluster_pack(&Nouveau1, to); - Cluster_pack(&Nouveau2, to); - - // Put them back in the list - CS_Set(cs,&Nouveau1); - CS_Set(cs,&Nouveau2); - - } -} - - -/// Compute the color associated to each box in the list -void CS_Compute_colors(T_Cluster_set * cs, T_Occurrence_table * to) -{ - T_Cluster * c; - - for (c=cs->clusters;c!=NULL;c=c->next) - Cluster_compute_hue(c,to); -} - - -// We sort the clusters on two criterions to get a somewhat coherent palette. -// TODO : It would be better to do this in one single pass. - -/// Sort the clusters by chrominance value -void CS_Sort_by_chrominance(T_Cluster_set * cs) -{ - T_Cluster* nc; - T_Cluster* prev = NULL; - T_Cluster* place; - T_Cluster* newlist = NULL; - - while (cs->clusters) - { - // Remove the first cluster from the original list - nc = cs->clusters; - cs->clusters = cs->clusters->next; - - // Find his position in the new list - for (place = newlist; place != NULL; place = place->next) - { - if (place->h > nc->h) break; - prev = place; - } - - // Chain it there - nc->next = place; - if (prev) prev->next = nc; - else newlist = nc; - - prev = NULL; - } - - // Put the new list back in place - cs->clusters = newlist; -} - - -/// Sort the clusters by luminance value -void CS_Sort_by_luminance(T_Cluster_set * cs) -{ - T_Cluster* nc; - T_Cluster* prev = NULL; - T_Cluster* place; - T_Cluster* newlist = NULL; - - while (cs->clusters) - { - // Remove the first cluster from the original list - nc = cs->clusters; - cs->clusters = cs->clusters->next; - - // Find its position in the new list - for (place = newlist; place != NULL; place = place->next) - { - if (place->l > nc->l) break; - prev = place; - } - - // Chain it there - nc->next = place; - if (prev) prev->next = nc; - else newlist = nc; - - // reset prev pointer - prev = NULL; - } - - // Put the new list back in place - cs->clusters = newlist; -} - - -/// Generates the palette from the clusters, then the conversion table to map (RGB) to a palette index -void CS_Generate_color_table_and_palette(T_Cluster_set * cs,T_Conversion_table * tc,T_Components * palette) -{ - int index; - int r,g,b; - T_Cluster* current = cs->clusters; - - for (index=0;indexnb;index++) - { - palette[index].R=current->r; - palette[index].G=current->g; - palette[index].B=current->b; - - for (r=current->Rmin; r<=current->Rmax; r++) - for (g=current->Gmin;g<=current->Vmax;g++) - for (b=current->Bmin;b<=current->Bmax;b++) - CT_set(tc,r,g,b,index); - current = current->next; - } -} - -///////////////////////////////////////////////////////////////////////////// -///////////////////////////////////////// Méthodes de gestion des dégradés // -///////////////////////////////////////////////////////////////////////////// - -void GS_Init(T_Gradient_set * ds,T_Cluster_set * cs) -{ - ds->gradients[0].nb_colors=1; - ds->gradients[0].min=cs->clusters->h; - ds->gradients[0].max=cs->clusters->h; - ds->gradients[0].hue=cs->clusters->h; - // Et hop : le 1er ensemble de d‚grad‚s est initialis‚ - ds->nb=1; -} - -T_Gradient_set * GS_New(T_Cluster_set * cs) -{ - T_Gradient_set * n; - - n=(T_Gradient_set *)malloc(sizeof(T_Gradient_set)); - if (n!=NULL) - { - // On recopie les paramètres demandés - n->nb_max=cs->nb_max; - - // On tente d'allouer la table - n->gradients=(T_Gradient *)malloc((n->nb_max)*sizeof(T_Gradient)); - if (n->gradients!=0) - // C'est bon! On initialise - GS_Init(n,cs); - else - { - // Table impossible à allouer - free(n); - n=NULL; - } - } - - return n; -} - -void GS_Delete(T_Gradient_set * ds) -{ - free(ds->gradients); - free(ds); -} - -void GS_Generate(T_Gradient_set * ds,T_Cluster_set * cs) -{ - int id; // Les indexs de parcours des ensembles - int best_gradient; // Meilleur d‚grad‚ - int best_diff; // Meilleure diff‚rence de chrominance - int diff; // difference de chrominance courante - T_Cluster * current = cs->clusters; - - // Pour chacun des clusters … traiter - do - { - // On recherche le d‚grad‚ le plus proche de la chrominance du cluster - best_gradient=-1; - best_diff=99999999; - for (id=0;idnb;id++) - { - diff=abs(current->h - ds->gradients[id].hue); - if ((best_diff>diff) && (diff<16)) - { - best_gradient=id; - best_diff=diff; - } - } - - // Si on a trouv‚ un d‚grad‚ dans lequel inclure le cluster - if (best_gradient!=-1) - { - // On met … jour le d‚grad‚ - if (current->h < ds->gradients[best_gradient].min) - ds->gradients[best_gradient].min=current->h; - if (current->h > ds->gradients[best_gradient].max) - ds->gradients[best_gradient].max=current->h; - ds->gradients[best_gradient].hue=((ds->gradients[best_gradient].hue* - ds->gradients[best_gradient].nb_colors) - +current->h) - /(ds->gradients[best_gradient].nb_colors+1); - ds->gradients[best_gradient].nb_colors++; - } - else - { - // On cr‚e un nouveau d‚grad‚ - best_gradient=ds->nb; - ds->gradients[best_gradient].nb_colors=1; - ds->gradients[best_gradient].min=current->h; - ds->gradients[best_gradient].max=current->h; - ds->gradients[best_gradient].hue=current->h; - ds->nb++; - } - current->h=best_gradient; - } while((current = current->next)); - - // On redistribue les valeurs dans les clusters - current = cs -> clusters; - do - current->h=ds->gradients[current->h].hue; - while((current = current ->next)); -} - - -/// Compute best palette for given picture. -T_Conversion_table * Optimize_palette(T_Bitmap24B image, int size, - T_Components * palette, int r, int g, int b) -{ - T_Occurrence_table * to; - T_Conversion_table * tc; - T_Cluster_set * cs; - T_Gradient_set * ds; - - // Allocate all the elements - to = 0; tc = 0; cs = 0; ds = 0; - - to = OT_new(r, g, b); - if (to == NULL) - return 0; - - tc = CT_new(r, g, b); - if (tc == NULL) - { - OT_delete(to); - return 0; - } - - // Count pixels for each color - OT_count_occurrences(to, image, size); - - cs = CS_New(256, to); - if (cs == NULL) - { - CT_delete(tc); - OT_delete(to); - return 0; - } - //CS_Check(cs); - // Ok, everything was allocated - - // Generate the cluster set with median cut algorithm - CS_Generate(cs, to); - //CS_Check(cs); - - // Compute the color data for each cluster (palette entry + HL) - CS_Compute_colors(cs, to); - //CS_Check(cs); - - ds = GS_New(cs); - if (ds!= NULL) - { - GS_Generate(ds, cs); - GS_Delete(ds); - } - // Sort the clusters on L and H to get a nice palette - CS_Sort_by_luminance(cs); - //CS_Check(cs); - CS_Sort_by_chrominance(cs); - //CS_Check(cs); - - // And finally generate the conversion table to map RGB > pal. index - CS_Generate_color_table_and_palette(cs, tc, palette); - //CS_Check(cs); - - CS_Delete(cs); - OT_delete(to); - return tc; -} - - -/// Change a value with proper ceiling and flooring -int Modified_value(int value,int modif) -{ - value+=modif; - if (value<0) - { - value=0; - } - else if (value>255) - { - value=255; - } - return value; -} - - -/// Convert a 24b image to 256 colors (with a given palette and conversion table) -/// This destroys the 24b picture ! -/// Uses floyd steinberg dithering. -void Convert_24b_bitmap_to_256_Floyd_Steinberg(T_Bitmap256 dest,T_Bitmap24B source,int width,int height,T_Components * palette,T_Conversion_table * tc) -{ - T_Bitmap24B current; - T_Bitmap24B c_plus1; - T_Bitmap24B u_minus1; - T_Bitmap24B next; - T_Bitmap24B u_plus1; - T_Bitmap256 d; - int x_pos,y_pos; - int red,green,blue; - float e_red,e_green,e_blue; - - // On initialise les variables de parcours: - current =source; // Le pixel dont on s'occupe - next =current+width; // Le pixel en dessous - c_plus1 =current+1; // Le pixel à droite - u_minus1=next-1; // Le pixel en bas à gauche - u_plus1 =next+1; // Le pixel en bas à droite - d =dest; - - // On parcours chaque pixel: - for (y_pos=0;y_posR; - green =current->G; - blue =current->B; - // Cherche la couleur correspondant dans la palette et la range dans l'image de destination - *d=CT_get(tc,red,green,blue); - - // Puis on calcule pour chaque composante l'erreur dûe à l'approximation - red-=palette[*d].R; - green -=palette[*d].G; - blue -=palette[*d].B; - - // Et dans chaque pixel voisin on propage l'erreur - // A droite: - e_red=(red*7)/16.0; - e_green =(green *7)/16.0; - e_blue =(blue *7)/16.0; - if (x_pos+1R=Modified_value(c_plus1->R,e_red); - c_plus1->G=Modified_value(c_plus1->G,e_green ); - c_plus1->B=Modified_value(c_plus1->B,e_blue ); - } - // En bas à gauche: - if (y_pos+10) - { - u_minus1->R=Modified_value(u_minus1->R,e_red); - u_minus1->G=Modified_value(u_minus1->G,e_green ); - u_minus1->B=Modified_value(u_minus1->B,e_blue ); - } - // En bas: - e_red=(red*5/16.0); - e_green =(green*5 /16.0); - e_blue =(blue*5 /16.0); - next->R=Modified_value(next->R,e_red); - next->G=Modified_value(next->G,e_green ); - next->B=Modified_value(next->B,e_blue ); - // En bas à droite: - if (x_pos+1R=Modified_value(u_plus1->R,e_red); - u_plus1->G=Modified_value(u_plus1->G,e_green ); - u_plus1->B=Modified_value(u_plus1->B,e_blue ); - } - } - - // On passe au pixel suivant : - current++; - c_plus1++; - u_minus1++; - next++; - u_plus1++; - d++; - } - } -} - - -/// Converts from 24b to 256c without dithering, using given conversion table -void Convert_24b_bitmap_to_256_nearest_neighbor(T_Bitmap256 dest, - T_Bitmap24B source, int width, int height, __attribute__((unused)) T_Components * palette, - T_Conversion_table * tc) -{ - T_Bitmap24B current; - T_Bitmap256 d; - int x_pos, y_pos; - int red, green, blue; - - // On initialise les variables de parcours: - current =source; // Le pixel dont on s'occupe - - d =dest; - - // On parcours chaque pixel: - for (y_pos = 0; y_pos < height; y_pos++) - { - for (x_pos = 0 ;x_pos < width; x_pos++) - { - // On prends la meilleure couleur de la palette qui traduit la couleur - // 24 bits de la source: - red = current->R; - green = current->G; - blue = current->B; - // Cherche la couleur correspondant dans la palette et la range dans - // l'image de destination - *d = CT_get(tc, red, green, blue); - - // On passe au pixel suivant : - current++; - d++; - } - } -} - - -// These are the allowed precisions for all the tables. -// For some of them only the first one may work because of ugly optimizations -static const byte precision_24b[]= -{ - 8,8,8, - 6,6,6, - 6,6,5, - 5,6,5, - 5,5,5, - 5,5,4, - 4,5,4, - 4,4,4, - 4,4,3, - 3,4,3, - 3,3,3, - 3,3,2}; - - -// 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 - - // On essaye d'obtenir une table de conversion qui loge en mémoire, avec la - // meilleure précision possible - for (ip=0;ip<(10*3);ip+=3) - { - table=Optimize_palette(source,width*height,palette,precision_24b[ip+0], - precision_24b[ip+1],precision_24b[ip+2]); - if (table!=0) - break; - } - if (table!=0) - { - //Convert_24b_bitmap_to_256_Floyd_Steinberg(dest,source,width,height,palette,table); - Convert_24b_bitmap_to_256_nearest_neighbor(dest,source,width,height,palette,table); - CT_delete(table); - return 0; - } - 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/project/jni/application/grafx2/grafx2/src/op_c.h b/project/jni/application/grafx2/grafx2/src/op_c.h deleted file mode 100644 index 76b544a2a..000000000 --- a/project/jni/application/grafx2/grafx2/src/op_c.h +++ /dev/null @@ -1,218 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file op_c.h -/// Color reduction and color conversion (24b->8b, RGB<->HSL). -/// This is called op_c because half of the process was originally -/// coded in op_asm, in assembler. -////////////////////////////////////////////////////////////////////////////// - -#ifndef _OP_C_H_ -#define _OP_C_H_ - -#include "struct.h" - -//////////////////////////////////////////////// Définition des types de base - -typedef T_Components * T_Bitmap24B; -typedef byte * T_Bitmap256; - - - -//////////////////////////////////////// Définition d'une table de conversion - -typedef struct -{ - int nbb_r; // Nb de bits de précision sur les rouges - int nbb_g; // Nb de bits de précision sur les verts - int nbb_b; // Nb de bits de précision sur les bleu - - int rng_r; // Nb de valeurs sur les rouges (= 1< -*/ -#include -#include -#include - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "engine.h" -#include "graph.h" -#include "operatio.h" -#include "buttons.h" -#include "pages.h" -#include "errors.h" -#include "sdlscreen.h" -#include "brush.h" -#include "windows.h" -#include "input.h" - -// PI is NOT part of math.h according to C standards... -#if defined(__GP2X__) || defined(__VBCC__) - #define M_PI 3.14159265358979323846 -#endif - -/// Time (in SDL ticks) when the next airbrush drawing should be done. Also used -/// for discontinuous freehand drawing. -Uint32 Airbrush_next_time; - -void Start_operation_stack(word new_operation) -{ - Brush_rotation_center_is_defined=0; - - // On mémorise l'opération précédente si on démarre une interruption - switch(new_operation) - { - case OPERATION_MAGNIFY: - case OPERATION_COLORPICK: - case OPERATION_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 - Current_operation=new_operation; - break; - default : - // On passe à l'operation demandée - Current_operation=new_operation; - Operation_before_interrupt=Current_operation; - } - - // On spécifie si l'opération autorise le changement de couleur au clavier - switch(new_operation) - { - case OPERATION_CONTINUOUS_DRAW: - case OPERATION_DISCONTINUOUS_DRAW: - case OPERATION_AIRBRUSH: - case OPERATION_CENTERED_LINES: - Allow_color_change_during_operation=1; - break; - default : - Allow_color_change_during_operation=0; - } - - // Et on passe au curseur qui va avec - Cursor_shape=CURSOR_FOR_OPERATION[new_operation]; - Operation_stack_size=0; -} - - -void Init_start_operation(void) -{ - Operation_in_magnifier=(Mouse_X>=Main_X_zoom); - Smear_start=1; -} - - -void Operation_push(short value) -{ - Operation_stack[++Operation_stack_size]=value; -} - - -void Operation_pop(short * value) -{ - *value=Operation_stack[Operation_stack_size--]; -} - - -byte Paintbrush_shape_before_operation; -byte Paintbrush_hidden_before_scroll; - - - -short Distance(short x1, short y1, short x2, short y2) -{ - short x2_moins_x1=x2-x1; - short y2_minus_y1=y2-y1; - - return Round( sqrt( (x2_moins_x1*x2_moins_x1) + (y2_minus_y1*y2_minus_y1) ) ); -} - - -void Display_coords_rel_or_abs(short start_x, short start_y) -{ - char str[6]; - - if (Config.Coords_rel) - { - if (Menu_is_visible) - { - if (Paintbrush_X>start_x) - { - Num2str(Paintbrush_X-start_x,str,5); - str[0]='+'; - } - else if (Paintbrush_Xstart_y) - { - Num2str(Paintbrush_Y-start_y,str,5); - str[0]='+'; - } - else if (Paintbrush_YAirbrush_next_time) - { - Airbrush_next_time+=Airbrush_delay*10; - Hide_cursor(); - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); - Display_cursor(); - } - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -// ---------- - -void Freehand_mode2_2_0(void) -// Opération : OPERATION_DISCONTINUOUS_DRAW -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Print_coordinates(); - Airbrush_next_time = SDL_GetTicks() + Airbrush_delay*10; - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); -} - - -void Freehand_mode2_2_2(void) -// Opération : OPERATION_DISCONTINUOUS_DRAW -// Click Souris: 2 -// Taille_Pile : 2 -// -// Souris effacée: Non -{ - short start_x; - short start_y; - - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ( (start_x!=Paintbrush_X) || (start_y!=Paintbrush_Y) ) - { - Print_coordinates(); - if (SDL_GetTicks()>Airbrush_next_time) - { - Airbrush_next_time+=Airbrush_delay*10; - Hide_cursor(); - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); - Display_cursor(); - } - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -////////////////////////////////////////////////////// OPERATION_POINT_DRAW - -void Freehand_mode3_1_0(void) -// Opération : OPERATION_POINT_DRAW -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_left; - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,0); - Operation_push(0); // On change simplement l'état de la pile... -} - - -void Freehand_Mode3_2_0(void) -// Opération : OPERATION_POINT_DRAW -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - // On affiche définitivement le pinceau - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Back_color,0); - Operation_push(0); // On change simplement l'état de la pile... -} - - -void Freehand_mode3_0_1(void) -// Opération : OPERATION_POINT_DRAW -// Click Souris: 0 -// Taille_Pile : 1 -// -// Souris effacée: Non -{ - End_of_modification(); - Operation_stack_size--; -} - - -///////////////////////////////////////////////////////////// OPERATION_LINE - -void Line_12_0(void) -// Opération : OPERATION_LINE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui - -// Début du tracé d'une ligne (premier clic) -{ - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - if (Mouse_K==LEFT_SIDE) - { - Shade_table=Shade_table_left; - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - Operation_push(Fore_color); - } - else - { - Shade_table=Shade_table_right; - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - Operation_push(Back_color); - } - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Line_12_5(void) -// Opération : OPERATION_LINE -// Click Souris: 1 -// Taille_Pile : 5 -// -// Souris effacée: Non - -// Poursuite du tracé d'une ligne (déplacement de la souris en gardant le -// curseur appuyé) -{ - short start_x; - short start_y; - short end_x; - short end_y; - - short cursor_x; - short cursor_y; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - - cursor_x = Paintbrush_X; - cursor_y = Paintbrush_Y; - - // On corrige les coordonnées de la ligne si la touche shift est appuyée... - if(SDL_GetModState() & KMOD_SHIFT) - Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); - - // On vient de bouger - if ((cursor_x!=end_x) || (cursor_y!=end_y)) - { - Hide_cursor(); - - Display_coords_rel_or_abs(start_x,start_y); - - Hide_line_preview(start_x,start_y,end_x,end_y); - if (Mouse_K==LEFT_SIDE) - { - Pixel_figure_preview (start_x,start_y,Fore_color); - Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Fore_color); - } - else - { - Pixel_figure_preview (start_x,start_y,Back_color); - Draw_line_preview (start_x,start_y,cursor_x,cursor_y,Back_color); - } - - Operation_push(start_x); - Operation_push(start_y); - Operation_push(cursor_x); - Operation_push(cursor_y); - - Display_cursor(); - } - else - { - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - } -} - - -void Line_0_5(void) -// Opération : OPERATION_LINE -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Oui - -// End du tracé d'une ligne (relachage du bouton) -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - Display_paintbrush (start_x,start_y,color,0); - Draw_line_permanent(start_x,start_y,end_x,end_y,color); - - End_of_modification(); - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -/////////////////////////////////////////////////////////// OPERATION_K_LINE - - -void K_line_12_0(void) -// Opération : OPERATION_K_LINE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - // On place temporairement le début de la ligne qui ne s'afficherait pas sinon - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Mouse_K | 0x80); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 6 : phase d'appui, non interruptible -} - - -void K_line_12_6(void) -// Opération : OPERATION_K_LINE -// Click Souris: 1 ou 2 | 0 -// Taille_Pile : 6 | 7 -// -// Souris effacée: Non -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - - Operation_pop(&end_y); - Operation_pop(&end_x); - - if ((Paintbrush_X!=end_x) || (Paintbrush_Y!=end_y)) - { - Hide_cursor(); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - - Display_coords_rel_or_abs(start_x,start_y); - - Hide_line_preview(start_x,start_y,end_x,end_y); - Pixel_figure_preview (start_x,start_y,color); - Draw_line_preview (start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Operation_push(color); - Operation_push(start_x); - Operation_push(start_y); - Display_cursor(); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void K_line_0_6(void) -// Opération : OPERATION_K_LINE -// Click Souris: 0 -// Taille_Pile : 6 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - /* Doesn't work if fast moving - Pixel_figure_preview_xor (start_x,start_y, 0); - Draw_line_preview_xor (start_x,start_y,end_x,end_y,0); - */ - Paintbrush_shape=Paintbrush_shape_before_operation; - if (direction & 0x80) - { - Display_paintbrush(start_x,start_y,color,0); - direction=(direction & 0x7F); - } - Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - Operation_push(direction); - Operation_push(direction); // Valeur bidon servant de nouvel état de pile - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 7 : phase de "repos", interruptible (comme Elliot Ness :)) -} - - -void K_line_12_7(void) -// Opération : OPERATION_K_LINE -// Click Souris: 1 ou 2 -// Taille_Pile : 7 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - Operation_pop(&direction); - - if (direction==Mouse_K) - { - Operation_push(direction); - Operation_push(color); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - // Taille de pile 6 : phase d'appui, non interruptible - } - else - { - // La série de ligne est terminée, il faut donc effacer la dernière - // preview de ligne - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - - Display_cursor(); - Wait_end_of_click(); - Hide_cursor(); - Paintbrush_shape=Paintbrush_shape_before_operation; - - End_of_modification(); - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - } -} - -/////////////////////////////////////////////////// OPERATION_RECTANGLE_????? - -void Rectangle_12_0(void) -// Opération : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("\035: 1 \022: 1",0); - // On laisse une trace du curseur à l'écran - Display_cursor(); - - if (Mouse_K==LEFT_SIDE) - { - Shade_table=Shade_table_left; - Operation_push(Fore_color); - } - else - { - Shade_table=Shade_table_right; - Operation_push(Back_color); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Rectangle_12_5(void) -// Opération : OPERATION_EMPTY_RECTANGLE / OPERATION_FILLED_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 5 -// -// Souris effacée: Non -{ - short start_x; - short start_y; - short old_x; - short old_y; - char str[5]; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) - { - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Num2str(((start_xcenter_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x - :center_x-Paintbrush_X; - vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y - :center_y-Paintbrush_Y; - Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); - - Display_cursor(); - } - - Operation_push(color); - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Empty_ellipse_0_5(void) -// -// Opération : OPERATION_EMPTY_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Draw_empty_ellipse_permanent(center_x,center_y,horizontal_radius,vertical_radius,color); - - End_of_modification(); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -void Filled_ellipse_0_5(void) -// -// Opération : OPERATION_FILLED_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 5 (color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,color); - - End_of_modification(); - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -////////////////////////////////////////////////////////////// OPERATION_FILL - - -void Fill_1_0(void) -// -// Opération : OPERATION_FILL -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Hide_cursor(); - // Pas besoin d'initialiser le début d'opération car le Smear n'affecte pas - // le Fill, et on se fout de savoir si on est dans la partie gauche ou - // droite de la loupe. - // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. - Shade_table=Shade_table_left; - Fill_general(Fore_color); - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); -} - - -void Fill_2_0(void) -// -// Opération : OPERATION_FILL -// Click Souris: 2 -// Taille_Pile : 0 -// -// 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 - // droite de la loupe. - // On ne s'occupe pas de faire un Backup: c'est "Fill_general" qui s'en charge. - Shade_table=Shade_table_right; - Fill_general(Back_color); - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); -} - - -///////////////////////////////////////////////////////// OPERATION_REPLACE - - -void Replace_1_0(void) -// -// Opération : OPERATION_REPLACE -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - Hide_cursor(); - // Pas besoin d'initialiser le début d'opération car le Smear n'affecte pas - // le Replace, et on se fout de savoir si on est dans la partie gauche ou - // droite de la loupe. - Backup(); -// Shade_table=Shade_table_left; - Replace(Fore_color); - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); -} - - -void Replace_2_0(void) -// -// Opération : OPERATION_REPLACE -// Click Souris: 2 -// Taille_Pile : 0 -// -// 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 - // droite de la loupe. - Backup(); -// Shade_table=Shade_table_right; - Replace(Back_color); - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); -} - - -/////////////////////////////////////////////////// OPERATION_4_POINTS_CURVE - - -void Draw_curve_cross(short x_pos, short y_pos) -{ - short start_x,end_x; - short start_y,end_y; - short i,temp; - //byte temp2; - - if (x_pos>=Limit_left+3) - start_x=0; - else - start_x=3-(x_pos-Limit_left); - - if (y_pos>=Limit_top+3) - start_y=0; - else - start_y=3-(y_pos-Limit_top); - - if (x_pos<=Limit_visible_right-3) - end_x=6; - else - end_x=3+(Limit_visible_right-x_pos); - - if (y_pos<=Limit_visible_bottom-3) - end_y=6; - else - end_y=3+(Limit_visible_bottom-y_pos); - - if (start_x<=end_x && start_y<=end_y) - { - for (i=start_x; i<=end_x; i++) - { - temp=x_pos+i-3; - Pixel_preview(temp,y_pos,~Read_pixel(temp -Main_offset_X, - y_pos-Main_offset_Y)); - } - for (i=start_y; i<=end_y; i++) - { - temp=y_pos+i-3; - Pixel_preview(x_pos,temp,~Read_pixel(x_pos-Main_offset_X, - temp -Main_offset_Y)); - } - Update_part_of_screen(x_pos+start_x-3,y_pos+start_y-3,end_x-start_x+1,end_y-start_y+1); - } -} - - -void Curve_34_points_1_0(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_left; - - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Fore_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Fore_color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Curve_34_points_2_0(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -// -{ - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,Back_color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Back_color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Curve_34_points_1_5(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 1 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - short x1,x2,y1,y2; - - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - - if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) - { - Hide_cursor(); - Display_coords_rel_or_abs(x1,y1); - - Hide_line_preview(x1,y1,x2,y2); - Pixel_figure_preview (x1,y1,Fore_color); - Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Fore_color); - - Display_cursor(); - } - - Operation_push(x1); - Operation_push(y1); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Curve_34_points_2_5(void) -// -// Opération : OPERATION_COURBE_?_POINTS -// Click Souris: 2 -// Taille_Pile : 5 -// -// Souris effacée: Non -// -{ - short x1,x2,y1,y2; - - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - - if ( (y2!=Paintbrush_Y) || (x2!=Paintbrush_X) ) - { - Hide_cursor(); - Display_coords_rel_or_abs(x1,y1); - - Hide_line_preview(x1,y1,x2,y2); - Pixel_figure_preview (x1,y1,Back_color); - Draw_line_preview (x1,y1,Paintbrush_X,Paintbrush_Y,Back_color); - - Display_cursor(); - } - - Operation_push(x1); - Operation_push(y1); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -byte Cursor_hidden_before_curve; - -void Curve_4_points_0_5(void) -// -// Opération : OPERATION_4_POINTS_CURVE -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Oui -// -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short third_x,third_y; - short color; - - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - third_x=Round_div(abs(x4-x1),3); - third_y=Round_div(abs(y4-y1),3); - - if (x1B=(8/3) * C->P - *x3=Round((bx+x4)/2.0); // · _/·· P3 P2=middle of [P1,B] - *y3=Round((by+y4)/2.0); // P4*-- P3=middle of [P4,B] -} - - -void Curve_3_points_0_5(void) -// -// Opération : OPERATION_3_POINTS_CURVE -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Oui -// -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short color; - - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); - - 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) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - - Operation_push(color); - Operation_push(x1); - Operation_push(y1); - Operation_push(x2); - Operation_push(y2); - Operation_push(x3); - Operation_push(y3); - Operation_push(x4); - Operation_push(y4); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - - if (Config.Stylus_mode) - { - Display_cursor(); - while(!Mouse_K) - Get_input(20); - Hide_cursor(); - - Hide_line_preview(x1,y1,x4,y4); - } -} - -void Curve_drag(void) -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short old_x,old_y; - short color; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) ) - { - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y3); - Operation_pop(&x3); - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - Hide_cursor(); - Print_coordinates(); - - Hide_curve_preview(x1,y1,x2,y2,x3,y3,x4,y4,color); - Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); - Draw_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); - Display_cursor(); - - Operation_push(color); - Operation_push(x1); - Operation_push(y1); - Operation_push(x2); - Operation_push(y2); - Operation_push(x3); - Operation_push(y3); - Operation_push(x4); - Operation_push(y4); - } - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} -void Curve_finalize(void) -{ - short x1,y1,x2,y2,x3,y3,x4,y4; - short old_x,old_y; - short color; - - Operation_pop(&old_y); - Operation_pop(&old_x); - Operation_pop(&y4); - Operation_pop(&x4); - Operation_pop(&y3); - Operation_pop(&x3); - Operation_pop(&y2); - Operation_pop(&x2); - Operation_pop(&y1); - Operation_pop(&x1); - Operation_pop(&color); - - Paintbrush_hidden=0; - - Hide_cursor(); - - Hide_curve_preview (x1,y1,x2,y2,x3,y3,x4,y4,color); - Compute_3_point_curve(x1,y1,x4,y4,&x2,&y2,&x3,&y3); - Draw_curve_permanent(x1,y1,x2,y2,x3,y3,x4,y4,color); - - End_of_modification(); - Display_cursor(); - 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 - -void Airbrush_1_0(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 1 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - Init_start_operation(); - Backup(); - Shade_table=Shade_table_left; - - 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); -} - -void Airbrush_2_0(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 2 -// Taille_Pile : 0 -// -// Souris effacée: Non -// -{ - if (Rightclick_colorpick(1)) - return; - - Init_start_operation(); - Backup(); - Shade_table=Shade_table_right; - 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); -} - -void Airbrush_12_2(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 1 ou 2 -// Taille_Pile : 2 -// -// Souris effacée: Non -// -{ - short old_x,old_y; - Uint32 now; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) ) - { - Hide_cursor(); - Print_coordinates(); - Display_cursor(); - } - - now=SDL_GetTicks(); - if (now>Airbrush_next_time) - { - //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); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Airbrush_0_2(void) -// -// Opération : OPERATION_AIRBRUSH -// Click Souris: 0 -// Taille_Pile : 2 -// -// Souris effacée: Non -// -{ - Operation_stack_size-=2; - End_of_modification(); -} - - -////////////////////////////////////////////////////////// OPERATION_POLYGON - - -void Polygon_12_0(void) -// Opération : OPERATION_POLYGON -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - // On place temporairement le début de la ligne qui ne s'afficherait pas sinon - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Mouse_K | 0x80); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 8 : phase d'appui, non interruptible -} - - - -void Polygon_12_9(void) -// Opération : OPERATION_POLYGON -// Click Souris: 1 ou 2 -// Taille_Pile : 9 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - Operation_pop(&direction); - - if (direction==Mouse_K) - { - Operation_push(direction); - Operation_push(color); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - // Taille de pile 8 : phase d'appui, non interruptible - } - else - { - // La série de ligne est terminée, il faut donc effacer la dernière - // preview de ligne et relier le dernier point avec le premier - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,end_x,end_y); - Operation_pop(&end_y); - Operation_pop(&end_x); - Paintbrush_shape=Paintbrush_shape_before_operation; - // Le pied aurait été de ne pas repasser sur le 1er point de la 1ère ligne - // mais c'est pas possible :( - Draw_line_permanent(start_x,start_y,end_x,end_y,color); - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); - Hide_cursor(); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - - Paintbrush_shape=Paintbrush_shape_before_operation; - } -} - - -////////////////////////////////////////////////////////// OPERATION_POLYFILL - -void Polyfill_12_0(void) -// Opération : OPERATION_POLYFILL -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - Paintbrush_hidden=1; - - color=(Mouse_K==LEFT_SIDE)?Fore_color:Back_color; - - Polyfill_table_of_points=(short *) malloc((Config.Nb_max_vertices_per_polygon<<1)*sizeof(short)); - Polyfill_table_of_points[0]=Paintbrush_X; - Polyfill_table_of_points[1]=Paintbrush_Y; - Polyfill_number_of_points=1; - - // On place temporairement le début de la ligne qui ne s'afficherait pas sinon - Pixel_figure_preview_xor(Paintbrush_X,Paintbrush_Y,0); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Mouse_K | 0x80); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - // Taille de pile 8 : phase d'appui, non interruptible -} - - -void Polyfill_0_8(void) -// Opération : OPERATION_POLYFILL -// Click Souris: 0 -// Taille_Pile : 8 -// -// Souris effacée: Oui -{ - short start_x; - short start_y; - short end_x; - short end_y; - short color; - short direction; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&color); - Operation_pop(&direction); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); - - if (direction & 0x80) - direction=(direction & 0x7F); - - Operation_push(direction); // Valeur bidon servant de nouvel état de pile - Operation_push(direction); - Operation_push(color); - - Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0); - - if (Polyfill_number_of_points=center_x) - x_offset=(Paintbrush_X-center_x)%Main_image_width; - else - x_offset=Main_image_width-((center_x-Paintbrush_X)%Main_image_width); - - if (Paintbrush_Y>=center_y) - y_offset=(Paintbrush_Y-center_y)%Main_image_height; - else - y_offset=Main_image_height-((center_y-Paintbrush_Y)%Main_image_height); - - Display_coords_rel_or_abs(center_x,center_y); - - if (side == RIGHT_SIDE) - { - // All layers at once - Scroll_picture(Screen_backup, Main_screen, x_offset,y_offset); - } - else - { - // One layer at once - Scroll_picture(Main_backups->Pages->Next->Image[Main_current_layer], Main_backups->Pages->Image[Main_current_layer], x_offset, y_offset); - Redraw_current_layer(); - } - - Display_all_screen(); - } - - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(side); -} - -void Scroll_0_5(void) -// -// Opération : OPERATION_SCROLL -// Click Souris: 0 -// Taille_Pile : 5 -// -// Souris effacée: Oui -// -{ - // All layers at once - short center_x; - short center_y; - short x_pos; - short y_pos; - short x_offset; - short y_offset; - short side; - int i; - - - Operation_pop(&side); - Operation_pop(&y_pos); - Operation_pop(&x_pos); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - - if (side == RIGHT_SIDE) - { - // All layers at once - if (x_pos>=center_x) - x_offset=(x_pos-center_x)%Main_image_width; - else - x_offset=Main_image_width-((center_x-x_pos)%Main_image_width); - - if (y_pos>=center_y) - y_offset=(y_pos-center_y)%Main_image_height; - else - y_offset=Main_image_height-((center_y-y_pos)%Main_image_height); - - - // Do the actual scroll operation on all layers. - for (i=0; iPages->Nb_layers; i++) - //if ((1<Pages->Next->Image[i], Main_backups->Pages->Image[i], x_offset, y_offset); - // Update the depth buffer too ... - // It would be faster to scroll it, but we don't have method - // for in-place scrolling. - Update_depth_buffer(); - } - else - { - // One layer : everything was done while dragging the mouse - } - - Cursor_hidden=Cursor_hidden_before_scroll; - - End_of_modification(); - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -//////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE - - -void Grad_circle_12_0(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - Init_start_operation(); - Backup(); - 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; - - Paintbrush_hidden_before_scroll=Paintbrush_hidden; - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("Radius: 0 ",0); - - Operation_push(Mouse_K); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_circle_12_6(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 1 ou 2 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Non -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short radius; - char str[5]; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) - { - Hide_cursor(); - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Num2str(Distance(center_x,center_y,Paintbrush_X,Paintbrush_Y),str,4); - Print_in_menu(str,7); - } - else - Print_coordinates(); - - Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ - ((tangent_y-center_y)*(tangent_y-center_y)); - radius=sqrt(Circle_limit); - Hide_empty_circle_preview(center_x,center_y,radius); - - Circle_limit=((Paintbrush_X-center_x)*(Paintbrush_X-center_x))+ - ((Paintbrush_Y-center_y)*(Paintbrush_Y-center_y)); - radius=sqrt(Circle_limit); - Draw_empty_circle_preview(center_x,center_y,radius,color); - - Display_cursor(); - } - - Operation_push(color); - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_circle_0_6(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 0 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short click; - short radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - - Operation_pop(&color); - Operation_pop(&click); - - if (click==LEFT_SIDE) - { - Operation_push(click); - Operation_push(color); - - Operation_push(center_x); - Operation_push(center_y); - Operation_push(tangent_x); - Operation_push(tangent_y); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - - // On change la forme du curseur - Cursor_shape=CURSOR_SHAPE_XOR_TARGET; - - // On affiche une croix XOR au centre du cercle - Draw_curve_cross(center_x,center_y); - - if (Menu_is_visible) - { - if (Config.Coords_rel) - Print_in_menu("X: Y:",0); - else - Print_in_menu("X: Y: ",0); - Display_coords_rel_or_abs(center_x,center_y); - } - } - else - { - Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ - ((tangent_y-center_y)*(tangent_y-center_y)); - radius=sqrt(Circle_limit); - Hide_empty_circle_preview(center_x,center_y,radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - Draw_filled_circle(center_x,center_y,radius,Back_color); - - End_of_modification(); - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - } -} - - -void Grad_circle_12_8(void) -// -// Opération : OPERATION_GRAD_CIRCLE -// Click Souris: 0 -// Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short old_mouse_k; - - short radius; - - Operation_stack_size-=2; // On fait sauter les 2 derniers élts de la pile - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - Operation_pop(&old_mouse_k); - - Hide_cursor(); - // On efface la croix XOR au centre du cercle - Draw_curve_cross(center_x,center_y); - - Circle_limit=((tangent_x-center_x)*(tangent_x-center_x))+ - ((tangent_y-center_y)*(tangent_y-center_y)); - radius=sqrt(Circle_limit); - Hide_empty_circle_preview(center_x,center_y,radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - if (Mouse_K==old_mouse_k) - Draw_grad_circle(center_x,center_y,radius,Paintbrush_X,Paintbrush_Y); - - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - - -void Grad_circle_or_ellipse_0_8(void) -// -// Opération : OPERATION_{CERCLE|ELLIPSE}_DEGRADE -// Click Souris: 0 -// Taille_Pile : 8 -// -// Souris effacée: Non -// -{ - short start_x; - short start_y; - short tangent_x; - short tangent_y; - short old_x; - short old_y; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) - { - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Display_coords_rel_or_abs(start_x,start_y); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(tangent_x); - Operation_push(tangent_y); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE - - -void Grad_ellipse_12_0(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui -{ - byte color; - - Init_start_operation(); - Backup(); - 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; - - Paintbrush_hidden_before_scroll=Paintbrush_hidden; - Paintbrush_hidden=1; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Update_part_of_screen(Paintbrush_X,Paintbrush_Y,1,1); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Mouse_K); - Operation_push(color); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_ellipse_12_6(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 1 ou 2 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Non -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - - if ( (tangent_x!=Paintbrush_X) || (tangent_y!=Paintbrush_Y) ) - { - Hide_cursor(); - Display_coords_rel_or_abs(center_x,center_y); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - horizontal_radius=(Paintbrush_X>center_x)?Paintbrush_X-center_x - :center_x-Paintbrush_X; - vertical_radius =(Paintbrush_Y>center_y)?Paintbrush_Y-center_y - :center_y-Paintbrush_Y; - Draw_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius,color); - - Display_cursor(); - } - - Operation_push(color); - Operation_push(center_x); - Operation_push(center_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_ellipse_0_6(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 6 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short click; - //short radius; - short horizontal_radius; - short vertical_radius; - - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - - Operation_pop(&color); - Operation_pop(&click); - - if (click==LEFT_SIDE) - { - Operation_push(click); - Operation_push(color); - - Operation_push(center_x); - Operation_push(center_y); - Operation_push(tangent_x); - Operation_push(tangent_y); - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - - // On change la forme du curseur - Cursor_shape=CURSOR_SHAPE_XOR_TARGET; - - // On affiche une croix XOR au centre du cercle - Draw_curve_cross(center_x,center_y); - - if (Menu_is_visible) - { - if (Config.Coords_rel) - Print_in_menu("X: Y:",0); - else - Print_in_menu("X: Y: ",0); - Display_coords_rel_or_abs(center_x,center_y); - } - } - else - { - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - Draw_filled_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Back_color); - - End_of_modification(); - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - } -} - - -void Grad_ellipse_12_8(void) -// -// Opération : OPERATION_GRAD_ELLIPSE -// Click Souris: 0 -// Taille_Pile : 8 (Mouse_K, color, X_Centre, Y_Centre, X_Tangente, Y_Tangente, old_x, old_y) -// -// Souris effacée: Oui -// -{ - short tangent_x; - short tangent_y; - short center_x; - short center_y; - short color; - short horizontal_radius; - short vertical_radius; - short old_mouse_k; - - Operation_stack_size-=2; // On fait sauter les 2 derniers élts de la pile - Operation_pop(&tangent_y); - Operation_pop(&tangent_x); - Operation_pop(¢er_y); - Operation_pop(¢er_x); - Operation_pop(&color); - Operation_pop(&old_mouse_k); - - Hide_cursor(); - // On efface la croix XOR au centre de l'ellipse - Draw_curve_cross(center_x,center_y); - - horizontal_radius=(tangent_x>center_x)?tangent_x-center_x - :center_x-tangent_x; - vertical_radius =(tangent_y>center_y)?tangent_y-center_y - :center_y-tangent_y; - Hide_empty_ellipse_preview(center_x,center_y,horizontal_radius,vertical_radius); - - Paintbrush_hidden=Paintbrush_hidden_before_scroll; - Cursor_shape=CURSOR_SHAPE_TARGET; - - if (Mouse_K==old_mouse_k) - Draw_grad_ellipse(center_x,center_y,horizontal_radius,vertical_radius,Paintbrush_X,Paintbrush_Y); - - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} - -/****************************** -* Operation_Rectangle_Degrade * -******************************/ - -// 1) tracé d'un rectangle classique avec les lignes XOR -// 2) tracé d'une ligne vecteur de dégradé, comme une ligne normale -// 3) dessin du dégradé - - -void Grad_rectangle_12_0(void) -// Opération : OPERATION_GRAD_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 0 -// -// Souris effacée: Oui - -// Initialisation de l'étape 1, on commence à dessiner le rectangle -{ - Init_start_operation(); - Backup(); - Load_gradient_data(Current_gradient); - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("\035: 1 \022: 1",0); - // On laisse une trace du curseur à l'écran - Display_cursor(); - - if (Mouse_K==LEFT_SIDE) - { - Shade_table=Shade_table_left; - Operation_push(Mouse_K); - } - else - { - Shade_table=Shade_table_right; - Operation_push(Mouse_K); - } - - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Grad_rectangle_12_5(void) -// Opération : OPERATION_GRAD_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 5 -// -// Souris effacée: Non - -// Modification de la taille du rectangle -{ - short start_x; - short start_y; - short old_x; - short old_y; - char str[5]; - - Operation_pop(&old_y); - Operation_pop(&old_x); - - if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) - { - Operation_pop(&start_y); - Operation_pop(&start_x); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Num2str(((start_x Min(Main_image_width, - Main_magnifier_mode?Main_separator_position:Screen_width)) - { - offset_width = end_x - Min(Main_image_width, - Main_magnifier_mode?Main_separator_position:Screen_width); - } - - if (end_y-Main_offset_Y > Min(Main_image_height, Menu_Y)) - offset_height = end_y - Min(Main_image_height, Menu_Y); - - if (width == 0) - { - // Single line - Vertical_XOR_line(start_x-Main_offset_X, start_y - - Main_offset_Y, height - offset_height + 1); - } - else if (height == 0) - { - // Single line - Horizontal_XOR_line(start_x-Main_offset_X, - start_y - Main_offset_Y, width - offset_width + 1); - } - else - { - // Dessin dans la zone de dessin normale - Horizontal_XOR_line(start_x-Main_offset_X, - start_y - Main_offset_Y, width - offset_width + 1); - - // If not, this line is out of the picture so there is no need to draw it - if (offset_height == 0 || end_y - 1 > Menu_Y + Main_offset_Y) - { - Horizontal_XOR_line(start_x - Main_offset_X, end_y - - Main_offset_Y, width - offset_width + 1); - } - - if (height > offset_height + 2) - { - Vertical_XOR_line(start_x-Main_offset_X, start_y - - Main_offset_Y + 1, height - offset_height - 1); - - if (offset_width == 0) - { - Vertical_XOR_line(end_x - Main_offset_X, start_y - - Main_offset_Y + 1, height - offset_height - 1); - } - } - } - - Update_rect(start_x - Main_offset_X, start_y - Main_offset_Y, - width + 1 - offset_width, height + 1 - offset_height); - - // Dessin dans la zone zoomée - if (Main_magnifier_mode && start_x <= Limit_right_zoom - && end_x > Limit_left_zoom - && start_y <= Limit_bottom_zoom - && end_y > Limit_top_zoom ) - { - offset_width = 0; - offset_height = 0; - - if (start_xLimit_right_zoom) // On dépasse du zoom à droite - offset_width += end_x - Limit_right_zoom; - - if(start_yLimit_bottom_zoom) // On dépasse du zoom en bas - offset_height += end_y - Limit_bottom_zoom; - - if(width > offset_width) - { - if(offset_top==0) // La ligne du haut est visible - Horizontal_XOR_line_zoom(offset_left>0?offset_left:start_x,start_y,width-offset_width+1); - - if(height!=0 && end_y<=Limit_bottom_zoom) // La ligne du bas est visible - Horizontal_XOR_line_zoom(offset_left>0?offset_left:start_x,end_y,width-offset_width+1); - } - if (width==0 && height!=0 && height > offset_height && offset_left==0) - { - // Single vertical line - Vertical_XOR_line_zoom(start_x,offset_top!=0?offset_top:start_y,height-offset_height); - } - else - { - if(height > offset_height + 2) - { - if(offset_left==0) // La ligne de gauche est visible - Vertical_XOR_line_zoom(start_x,offset_top!=0?offset_top:(start_y+1),height-offset_height-(offset_top==0)+(end_y>Limit_bottom_zoom)); - - if(end_x<=Limit_right_zoom) // La ligne de droite est visible - Vertical_XOR_line_zoom(end_x,offset_top!=0?offset_top:(start_y+1),height-offset_height-(offset_top==0)+(end_y>Limit_bottom_zoom)); - } - } - } -} -void Grad_rectangle_0_5(void) -// OPERATION_GRAD_RECTANGLE -// click souris 0 -// Taile pile : 5 -// -// Souris effacée : non - -// Le rectangle est en place, maintenant il faut tracer le vecteur de dégradé, -// on doit donc attendre que l'utilisateur clique quelque part -// On stocke tout de suite les coordonnées du pinceau comme ça on change d'état et on passe à la suite -{ - // !!! Cette fonction remet start_x start_y end_x end_y dans la pile à la fin donc il ne faut pas les modifier ! (sauf éventuellement un tri) - short start_x; - short start_y; - short end_x; - short end_y; - short width,height; - - - // Tracé propre du rectangle - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - - // This trick will erase the large crosshair at original position, - // in normal and zoomed views. - Paintbrush_X = start_x; - Paintbrush_Y = start_y; - - if (start_x>end_x) - SWAP_SHORTS(start_x, end_x) - - if (start_y>end_y) - SWAP_SHORTS(start_y, end_y) - - Hide_cursor(); - - width = end_x - start_x; - height = end_y - start_y; - - // Check if the rectangle is not fully outside the picture - if (start_x > Main_image_width // Rectangle at right of picture - || start_y > Main_image_height // Rectangle below picture - || start_y - 1 - Main_offset_Y > Menu_Y ) // Rectangle below viewport - { - Operation_pop(&end_y); // reset the stack - return; // cancel the operation - } - Draw_xor_rect(start_x, start_y, end_x, end_y); - - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - - // On ajoute des trucs dans la pile pour forcer le passage à l'étape suivante - Operation_push(end_x); - Operation_push(end_y); -} - -void Grad_rectangle_0_7(void) -// OPERATION_GRAD_RECTANGLE -// click souris 0 -// Taile pile : 5 -// -// Souris effacée : non - -// On continue à attendre que l'utilisateur clique en gardant les coords à jour -{ - Operation_stack_size -= 2; - Print_coordinates(); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - -void Grad_rectangle_12_7(void) -// Opération : OPERATION_GRAD_RECTANGLE -// Click Souris: 1 ou 2 -// Taille_Pile : 7 -// -// Souris effacée: Oui - -// Début du tracé du vecteur (premier clic) -// On garde les anciennes coordonnées dans la pile, et on ajoute les nouvelles par dessus - -// Si l'utilisateur utilise le mauvais bouton, on annule le tracé. Mais ça nous oblige à vider toute la pile pour vérifier :( -{ - short start_x,end_x,start_y,end_y,vax,vay,click; - - Operation_pop(&vay); - Operation_pop(&vax); - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&click); - - - if(click==Mouse_K) - { - Operation_push(click); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(end_x); - Operation_push(end_y); - Operation_push(vax); - Operation_push(vay); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - - } - else - { - // Mauvais bouton > anulation de l'opération. - // On a déjà vidé la pile, il reste à effacer le rectangle XOR - Draw_xor_rect(start_x, start_y, end_x, end_y); - } -} - -void Grad_rectangle_12_9(void) - // Opération : OPERATION_GRAD_RECTANGLE - // Click Souris: 1 - // Taille_Pile : 9 - // - // Souris effacée: Oui - - // Poursuite du tracé du vecteur (déplacement de la souris en gardant le curseur appuyé) -{ - short start_x; - short start_y; - short end_x; - short end_y; - short cursor_x; - short cursor_y; - - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - - cursor_x = Paintbrush_X; - cursor_y = Paintbrush_Y; - // On corrige les coordonnées de la ligne si la touche shift est appuyée... - if(SDL_GetModState() & KMOD_SHIFT) - Clamp_coordinates_regular_angle(start_x,start_y,&cursor_x,&cursor_y); - - if ((cursor_x!=end_x) || (cursor_y!=end_y)) - { - Display_coords_rel_or_abs(start_x,start_y); - - Draw_line_preview_xor(start_x,start_y,end_x,end_y,0); - Draw_line_preview_xor(start_x,start_y,cursor_x,cursor_y,0); - - } - - - Operation_push(start_x); - Operation_push(start_y); - Operation_push(cursor_x); - Operation_push(cursor_y); -} - -void Grad_rectangle_0_9(void) - // Opération : OPERATION_GRAD_RECTANGLE - // Click Souris: 0 - // Taille_Pile : 9 - // - // Souris effacée: Oui - - // Ouf, fini ! on dessine enfin le rectangle avec son dégradé -{ - short rect_start_x; - short rect_start_y; - short rect_end_x; - short rect_end_y; - - short vector_start_x; - short vector_start_y; - short vector_end_x; - short vector_end_y; - - Operation_pop(&vector_end_y); - Operation_pop(&vector_end_x); - Operation_pop(&vector_start_y); - Operation_pop(&vector_start_x); - Operation_pop(&rect_end_y); - Operation_pop(&rect_end_x); - Operation_pop(&rect_start_y); - Operation_pop(&rect_start_x); - Operation_stack_size--; - - Hide_cursor(); - // Maintenant on efface tout le bazar temporaire : rectangle et ligne XOR - Draw_xor_rect(rect_start_x, rect_start_y, rect_end_x, rect_end_y); - Hide_line_preview(vector_start_x,vector_start_y,vector_end_x,vector_end_y); - - // Et enfin on trace le rectangle avec le dégradé dedans ! - if (vector_end_x==vector_start_x && vector_end_y==vector_start_y) - { - // Vecteur nul > pas de rectangle tracé - } - else - { - Draw_grad_rectangle(rect_start_x,rect_start_y,rect_end_x,rect_end_y,vector_start_x,vector_start_y,vector_end_x,vector_end_y); - } - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); - - if ((Config.Coords_rel) && (Menu_is_visible)) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } -} -/////////////////////////////////////////////////// OPERATION_CENTERED_LINES - - -void Centered_lines_12_0(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 1 ou 2 - // Taille_Pile : 0 - // - // Souris effacée: Oui -{ - if (Rightclick_colorpick(0)) - return; - - Init_start_operation(); - Backup(); - Shade_table=(Mouse_K==LEFT_SIDE)?Shade_table_left:Shade_table_right; - - if ((Config.Coords_rel) && (Menu_is_visible)) - Print_in_menu("X:± 0 Y:± 0",0); - - Operation_push(Mouse_K); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Centered_lines_12_3(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 1 ou 2 - // Taille_Pile : 3 - // - // Souris effacée: Non -{ - short start_x; - short start_y; - - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - - -void Centered_lines_0_3(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 0 - // Taille_Pile : 3 - // - // Souris effacée: Oui -{ - short start_x; - short start_y; - short Button; - short color; - - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&Button); - - color=(Button==LEFT_SIDE)?Fore_color:Back_color; - - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Paintbrush_shape_before_operation=Paintbrush_shape; - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - - Operation_push(Button); - Operation_push(Paintbrush_X); // Nouveau début X - Operation_push(Paintbrush_Y); // Nouveau début Y - Operation_push(Paintbrush_X); // Nouvelle dernière fin X - Operation_push(Paintbrush_Y); // Nouvelle dernière fin Y - Operation_push(Paintbrush_X); // Nouvelle dernière position X - Operation_push(Paintbrush_Y); // Nouvelle dernière position Y -} - - -void Centered_lines_12_7(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 1 ou 2 - // Taille_Pile : 7 - // - // Souris effacée: Non -{ - short Button; - short start_x; - short start_y; - short end_x; - short end_y; - short last_x; - short last_y; - short color; - - Operation_pop(&last_y); - Operation_pop(&last_x); - Operation_pop(&end_y); - Operation_pop(&end_x); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&Button); - - if (Mouse_K==Button) - { - if ( (end_x!=Paintbrush_X) || (end_y!=Paintbrush_Y) || - (last_x!=Paintbrush_X) || (last_y!=Paintbrush_Y) ) - { - Hide_cursor(); - - color=(Button==LEFT_SIDE)?Fore_color:Back_color; - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,last_x,last_y); - - Smear_start=1; - Display_paintbrush (start_x,start_y,color,0); - Draw_line_permanent(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Paintbrush_shape=PAINTBRUSH_SHAPE_POINT; - Pixel_figure_preview(Paintbrush_X,Paintbrush_Y,color); - Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Display_cursor(); - } - - Operation_push(Button); - Operation_push(start_x); - Operation_push(start_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); - } - else - { - Hide_cursor(); - - Paintbrush_shape=Paintbrush_shape_before_operation; - - Pixel_figure_preview_auto (start_x,start_y); - Hide_line_preview (start_x,start_y,last_x,last_y); - - if ( (Config.Coords_rel) && (Menu_is_visible) ) - { - Print_in_menu("X: Y: ",0); - Print_coordinates(); - } - - Display_cursor(); - End_of_modification(); - Wait_end_of_click(); - } -} - - -void Centered_lines_0_7(void) - // Opération : OPERATION_CENTERED_LINES - // Click Souris: 0 - // Taille_Pile : 7 - // - // Souris effacée: Non -{ - short Button; - short start_x; - short start_y; - short end_x; - short end_y; - short last_x; - short last_y; - short color; - - Operation_pop(&last_y); - Operation_pop(&last_x); - Operation_pop(&end_y); - Operation_pop(&end_x); - - if ((Paintbrush_X!=last_x) || (Paintbrush_Y!=last_y)) - { - Hide_cursor(); - Operation_pop(&start_y); - Operation_pop(&start_x); - Operation_pop(&Button); - - color=(Button==LEFT_SIDE)?Fore_color:Back_color; - - Display_coords_rel_or_abs(start_x,start_y); - - Hide_line_preview(start_x,start_y,last_x,last_y); - - Pixel_figure_preview(start_x,start_y,color); - Draw_line_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y,color); - - Operation_push(Button); - Operation_push(start_x); - Operation_push(start_y); - Display_cursor(); - } - - Operation_push(end_x); - Operation_push(end_y); - Operation_push(Paintbrush_X); - Operation_push(Paintbrush_Y); -} - diff --git a/project/jni/application/grafx2/grafx2/src/operatio.h b/project/jni/application/grafx2/grafx2/src/operatio.h deleted file mode 100644 index 62002a59f..000000000 --- a/project/jni/application/grafx2/grafx2/src/operatio.h +++ /dev/null @@ -1,232 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file operatio.h -/// Code for the drawing tools operations. -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - -// General operation handling functions. These may be moved to ops_handler.h when operatio.c grows over 5000 lines again... - -/// Do some housekeeping before starting work on a operation. -void Start_operation_stack(word new_operation); -/// Put a value on ::Operation_stack -void Operation_push(short value); -/// Take a value off ::Operation_stack -void Operation_pop(short * value); -void Init_start_operation(void); -short Distance(short x1, short y1, short x2, short y2); - -//////////////////////////////////////////////////// OPERATION_CONTINUOUS_DRAW -void Freehand_mode1_1_0(void); -void Freehand_mode1_1_2(void); -void Freehand_mode12_0_2(void); -void Freehand_mode1_2_0(void); -void Freehand_mode1_2_2(void); - -///////////////////////////////////////////////// OPERATION_DISCONTINUOUS_DRAW -void Freehand_mode2_1_0(void); -void Freehand_mode2_1_2(void); -void Freehand_mode2_2_0(void); -void Freehand_mode2_2_2(void); - -////////////////////////////////////////////////////// OPERATION_POINT_DRAW -void Freehand_mode3_1_0(void); -void Freehand_Mode3_2_0(void); -void Freehand_mode3_0_1(void); - -///////////////////////////////////////////////////////////// OPERATION_LINE - -void Line_12_0(void); -void Line_12_5(void); -void Line_0_5(void); - -///////////////////////////////////////////////////////////// OPERATION_MAGNIFY - -void Magnifier_12_0(void); - -/////////////////////////////////////////////////// OPERATION_RECTANGLE_????? - -void Rectangle_12_0(void); -void Rectangle_12_5(void); -void Empty_rectangle_0_5(void); -void Filled_rectangle_0_5(void); - -////////////////////////////////////////////////////// OPERATION_CERCLE_????? - -void Circle_12_0(void); -void Circle_12_5(void); -void Empty_circle_0_5(void); -void Filled_circle_0_5(void); - -///////////////////////////////////////////////////// OPERATION_ELLIPSE_????? - -void Ellipse_12_0(void); -void Ellipse_12_5(void); -void Empty_ellipse_0_5(void); -void Filled_ellipse_0_5(void); - -////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH - -void Brush_12_0(void); -void Brush_12_5(void); -void Brush_0_5(void); - -///////////////////////////////////////////////////// OPERATION_STRETCH_BRUSH - -void Stretch_brush_12_0(void); -void Stretch_brush_1_7(void); -void Stretch_brush_0_7(void); -void Stretch_brush_2_7(void); - -//////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH - -void Rotate_brush_12_0(void); -void Rotate_brush_1_5(void); -void Rotate_brush_0_5(void); -void Rotate_brush_2_5(void); - -///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH - -void Distort_brush_0_0(void); -void Distort_brush_1_0(void); -void Distort_brush_2_0(void); -void Distort_brush_1_8(void); -void Distort_brush_2_8(void); -void Distort_brush_1_9(void); -void Distort_brush_0_9(void); - -//////////////////////////////////////////////////////// OPERATION_POLYBRUSH - -void Polybrush_12_8(void); - -////////////////////////////////////////////////////////////// OPERATION_FILL - -void Fill_1_0(void); -void Fill_2_0(void); - -///////////////////////////////////////////////////////// OPERATION_REPLACE - -void Replace_1_0(void); -void Replace_2_0(void); - -/////////////////////////////////////////////////////////// OPERATION_COLORPICK - -void Pipette_0_0(void); -void Colorpicker_12_0(void); -void Colorpicker_1_1(void); -void Colorpicker_2_1(void); -void Colorpicker_0_1(void); - -/////////////////////////////////////////////////////////// OPERATION_K_LIGNE - -void K_line_12_0(void); -void K_line_12_6(void); -void K_line_0_6(void); -void K_line_12_7(void); - -/////////////////////////////////////////////////// OPERATION_COURBE_?_POINTS - -void Curve_34_points_1_0(void); -void Curve_34_points_2_0(void); -void Curve_34_points_1_5(void); -void Curve_34_points_2_5(void); - -void Curve_4_points_0_5(void); -void Curve_4_points_1_9(void); -void Curve_4_points_2_9(void); - -void Curve_3_points_0_5(void); -void Curve_3_points_0_11(void); -void Curve_3_points_12_11(void); - -///////////////////////////////////////////////////////////// OPERATION_AIRBRUSH - -void Airbrush_1_0(void); -void Airbrush_2_0(void); -void Airbrush_12_2(void); -void Airbrush_0_2(void); - -//////////////////////////////////////////////////////////// OPERATION_*POLY* - -void Polygon_12_0(void); -void Polygon_12_9(void); - -void Polyfill_12_0(void); -void Polyfill_0_8(void); -void Polyfill_12_8(void); -void Polyfill_12_9(void); - -void Polyform_12_0(void); -void Polyform_12_8(void); -void Polyform_0_8(void); - -void Filled_polyform_12_0(void); -void Filled_polyform_12_8(void); -void Filled_polyform_0_8(void); -void Filled_contour_0_8(void); - -//////////////////////////////////////////////////////////// OPERATION_SCROLL - -void Scroll_12_0(void); -void Scroll_12_5(void); -void Scroll_0_5(void); - -//////////////////////////////////////////////////// OPERATION_GRAD_CIRCLE - -void Grad_circle_12_0(void); -void Grad_circle_12_6(void); -void Grad_circle_0_6(void); -void Grad_circle_12_8(void); -void Grad_circle_or_ellipse_0_8(void); - -////////////////////////////////////////////////// OPERATION_GRAD_ELLIPSE - -void Grad_ellipse_12_0(void); -void Grad_ellipse_12_6(void); -void Grad_ellipse_0_6(void); -void Grad_ellipse_12_8(void); - -///////////////////////////////////////////////// OPERATION_GRAD_RECTANGLE - -void Grad_rectangle_12_0(void); -void Grad_rectangle_12_5(void); -void Grad_rectangle_0_5(void); -void Grad_rectangle_0_7(void); -void Grad_rectangle_12_7(void); -void Grad_rectangle_12_9(void); -void Grad_rectangle_0_9(void); - -/////////////////////////////////////////////////// OPERATION_CENTERED_LINES - -void Centered_lines_12_0(void); -void Centered_lines_12_3(void); -void Centered_lines_0_3(void); -void Centered_lines_12_7(void); -void Centered_lines_0_7(void); - -/////////////////////////////////////////////////// OPERATION_RMB_COLORPICK - -byte Rightclick_colorpick(byte cursor_visible); -void Rightclick_colorpick_2_1(void); -void Rightclick_colorpick_0_1(void); diff --git a/project/jni/application/grafx2/grafx2/src/pages.c b/project/jni/application/grafx2/grafx2/src/pages.c deleted file mode 100644 index 066eaa923..000000000 --- a/project/jni/application/grafx2/grafx2/src/pages.c +++ /dev/null @@ -1,1418 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -////////////////////////////////////////////////////////////////////////// -/////////////////////////// GESTION DU BACKUP //////////////////////////// -////////////////////////////////////////////////////////////////////////// - -#include -#include -#include - -#include "global.h" -#include "pages.h" -#include "errors.h" -#include "loadsave.h" -#include "misc.h" -#include "windows.h" - -// -- Layers data - -/// Array of two images, that contains the "flattened" version of the visible layers. -#ifndef NOLAYERS -T_Bitmap Main_visible_image; -T_Bitmap Main_visible_image_backup; -T_Bitmap Main_visible_image_depth_buffer; -T_Bitmap Spare_visible_image; -#endif - - /// - /// GESTION DES PAGES - /// - -/// Bitfield which records which layers are backed up in Page 0. -static dword Last_backed_up_layers=0; - -/// Total number of unique bitmaps (layers, animation frames, backups) -long Stats_pages_number=0; -/// Total memory used by bitmaps (layers, animation frames, backups) -long long Stats_pages_memory=0; - -/// Allocate and initialize a new page. -T_Page * New_page(byte nb_layers) -{ - T_Page * page; - - page = (T_Page *)malloc(sizeof(T_Page)+nb_layers*sizeof(byte *)); - if (page!=NULL) - { - int i; - for (i=0; iImage[i]=NULL; - page->Width=0; - page->Height=0; - memset(page->Palette,0,sizeof(T_Palette)); - page->Comment[0]='\0'; - page->File_directory[0]='\0'; - 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; - } - return page; -} - -// ============================================================== -// Layers allocation functions. -// -// Layers are made of a "number of users" (short), followed by -// the actual pixel data (a large number of bytes). -// Every time a layer is 'duplicated' as a reference, the number -// of users is incremented. -// Every time a layer is freed, the number of users is decreased, -// and only when it reaches zero the pixel data is freed. -// ============================================================== - -/// Allocate a new layer -byte * New_layer(long pixel_size) -{ - short * ptr = malloc(sizeof(short)+pixel_size); - if (ptr==NULL) - return NULL; - - // Stats - Stats_pages_number++; - Stats_pages_memory+=pixel_size; - - *ptr = 1; - return (byte *)(ptr+1); -} - -/// Free a layer -void Free_layer(T_Page * page, byte layer) -{ - short * ptr; - if (page->Image[layer]==NULL) - return; - - ptr = (short *)(page->Image[layer]); - if (-- (*(ptr-1))) // Users-- - return; - else { - free(ptr-1); - } - - // Stats - Stats_pages_number--; - Stats_pages_memory-=page->Width * page->Height; -} - -/// Duplicate a layer (new reference) -byte * Dup_layer(byte * layer) -{ - short * ptr = (short *)(layer); - - if (layer==NULL) - return NULL; - - (*(ptr-1)) ++; // Users ++ - return 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 -{ - //int factor_index; - int size_is_modified; - - if (page!=NULL) - { - size_is_modified=(Main_image_width!=page->Width) || - (Main_image_height!=page->Height); - - Main_image_width=page->Width; - Main_image_height=page->Height; - memcpy(Main_palette,page->Palette,sizeof(T_Palette)); - strcpy(Main_comment,page->Comment); - Main_fileformat=page->File_format; - - if (size_is_modified) - { - Main_magnifier_mode=0; - Main_offset_X=0; - Main_offset_Y=0; - Pixel_preview=Pixel_preview_normal; - Compute_limits(); - Compute_paintbrush_coordinates(); - } - - } - //Update_buffers( page->Width, page->Height); - //memcpy(Main_screen, page->Image[Main_current_layer], page->Width*page->Height); - -} - -void Redraw_layered_image(void) -{ - #ifndef NOLAYERS - // Re-construct the image with the visible layers - byte layer; - // First layer - for (layer=0; layerPages->Nb_layers; layer++) - { - if ((1<Pages->Image[layer], - Main_image_width*Main_image_height); - - // Initialize the depth buffer - memset(Main_visible_image_depth_buffer.Image, - layer, - Main_image_width*Main_image_height); - - // skip all other layers - layer++; - break; - } - } - // subsequent layer(s) - for (; layerPages->Nb_layers; layer++) - { - if ((1<Pages->Image[layer]+i); - if (color != Main_backups->Pages->Transparent_color) // transparent color - { - *(Main_visible_image.Image+i) = color; - if (layer != Main_current_layer) - *(Main_visible_image_depth_buffer.Image+i) = layer; - } - } - } - } - #else - Update_screen_targets(); - #endif - Update_FX_feedback(Config.FX_Feedback); -} - -void Update_depth_buffer(void) -{ - #ifndef NOLAYERS - // Re-construct the depth buffer with the visible layers. - // This function doesn't touch the visible buffer, it assumes - // that it was already up-to-date. (Ex. user only changed active layer) - - int layer; - // First layer - for (layer=0; layerPages->Nb_layers; layer++) - { - if ((1<Pages->Nb_layers; layer++) - { - // skip the current layer, whenever we reach it - if (layer == Main_current_layer) - continue; - - if ((1<Pages->Image[layer]+i); - if (color != Main_backups->Pages->Transparent_color) // transparent color - { - *(Main_visible_image_depth_buffer.Image+i) = layer; - } - } - } - } - #endif - Update_FX_feedback(Config.FX_Feedback); -} - -void Redraw_spare_image(void) -{ - #ifndef NOLAYERS - // Re-construct the image with the visible layers - byte layer; - // First layer - for (layer=0; layerPages->Nb_layers; layer++) - { - if ((1<Pages->Image[layer], - Spare_image_width*Spare_image_height); - - // No depth buffer in the spare - //memset(Spare_visible_image_depth_buffer.Image, - // layer, - // Spare_image_width*Spare_image_height); - - // skip all other layers - layer++; - break; - } - } - // subsequent layer(s) - for (; layerPages->Nb_layers; layer++) - { - if ((1<Pages->Image[layer]+i); - if (color != Spare_backups->Pages->Transparent_color) // transparent color - { - *(Spare_visible_image.Image+i) = color; - //if (layer != Spare_current_layer) - // *(Spare_visible_image_depth_buffer.Image+i) = layer; - } - } - } - } - #endif -} - -void Redraw_current_layer(void) -{ -#ifndef NOLAYERS - int i; - for (i=0; iPages->Image[Main_current_layer]+i); - if (color != Main_backups->Pages->Transparent_color) // transparent color - { - *(Main_visible_image.Image+i) = color; - } - else - { - *(Main_visible_image.Image+i) = *(Main_backups->Pages->Image[depth]+i); - } - } - } -#endif -} - -void Upload_infos_page_main(T_Page * page) -// Sauve l'écran courant dans la page -{ - if (page!=NULL) - { - //page->Image[Main_current_layer]=Main_screen; - page->Width=Main_image_width; - page->Height=Main_image_height; - memcpy(page->Palette,Main_palette,sizeof(T_Palette)); - strcpy(page->Comment,Main_comment); - page->File_format=Main_fileformat; - } -} - -void Download_infos_page_spare(T_Page * page) -{ - if (page!=NULL) - { - Spare_image_width=page->Width; - Spare_image_height=page->Height; - memcpy(Spare_palette,page->Palette,sizeof(T_Palette)); - Spare_fileformat=page->File_format; - } -} - -void Upload_infos_page_spare(T_Page * page) -{ - if (page!=NULL) - { - //page->Image[Spare_current_layer]=Spare_screen; - page->Width=Spare_image_width; - page->Height=Spare_image_height; - memcpy(page->Palette,Spare_palette,sizeof(T_Palette)); - page->File_format=Spare_fileformat; - } -} - -byte * FX_feedback_screen; - -void Update_FX_feedback(byte with_feedback) -{ - - if (with_feedback) - FX_feedback_screen=Main_backups->Pages->Image[Main_current_layer]; - else - FX_feedback_screen=Main_backups->Pages->Next->Image[Main_current_layer]; -} - -void Clear_page(T_Page * page) -{ - // On peut appeler cette fonction sur une page non allouée. - int i; - for (i=0; iNb_layers; i++) - { - 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. -} - -void Copy_S_page(T_Page * dest,T_Page * source) -{ - *dest=*source; - dest->Gradients=NULL; -} - - - /// - /// GESTION DES LISTES DE PAGES - /// - -void Init_list_of_pages(T_List_of_pages * list) -{ - // Important: appeler cette fonction sur toute nouvelle structure - // T_List_of_pages! - - list->List_size=0; - list->Pages=NULL; -} - -int Allocate_list_of_pages(T_List_of_pages * list) -{ - // Important: la T_List_of_pages ne doit pas déjà désigner une liste de - // pages allouée auquel cas celle-ci serait perdue. - T_Page * page; - - // On initialise chacune des nouvelles pages - page=New_page(NB_LAYERS); - if (!page) - return 0; - - // Set as first page of the list - page->Next = page; - page->Prev = page; - list->Pages = page; - - list->List_size=1; - - page->Gradients=Dup_gradient(NULL); - if (!page->Gradients) - return 0; - - return 1; // Succès -} - - -void Backward_in_list_of_pages(T_List_of_pages * list) -{ - // Cette fonction fait l'équivalent d'un "Undo" dans la liste de pages. - // Elle effectue une sorte de ROL (Rotation Left) sur la liste: - // +---+-+-+-+-+-+-+-+-+-+ | - // ¦0¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦ | - // +---+-+-+-+-+-+-+-+-+-+ | 0=page courante - // ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ |_ A=page la plus ancienne - // v v v v v v v v v v v | 1=DerniÞre page (1er backup) - // +---+-+-+-+-+-+-+-+-+-+ | - // ¦1¦2¦3¦4¦5¦6¦7¦8¦9¦A¦0¦ | - // +---+-+-+-+-+-+-+-+-+-+ | - - // Pour simuler un véritable Undo, l'appelant doit mettre la structure - // de page courante à jour avant l'appel, puis en réextraire les infos en - // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère - // page de la liste). - - if (Last_backed_up_layers) - { - // First page contains a ready-made backup of its ->Next. - // We have swap the first two pages, so the original page 0 - // will end up in position 0 again, and then overwrite it with a backup - // of the 'new' page1. - T_Page * page0; - T_Page * page1; - - page0 = list->Pages; - page1 = list->Pages->Next; - - page0->Next = page1->Next; - page1->Prev = page0->Prev; - page0->Prev = page1; - page1->Next = page0; - list->Pages = page0; - return; - } - list->Pages = list->Pages->Next; -} - -void Advance_in_list_of_pages(T_List_of_pages * list) -{ - // Cette fonction fait l'équivalent d'un "Redo" dans la liste de pages. - // Elle effectue une sorte de ROR (Rotation Right) sur la liste: - // +-+-+-+-+-+-+-+-+-+-+-+ | - // |0|1|2|3|4|5|6|7|8|9|A| | - // +-+-+-+-+-+-+-+-+-+-+-+ | 0=page courante - // | | | | | | | | | | | |_ A=page la plus ancienne - // v v v v v v v v v v v | 1=Dernière page (1er backup) - // +-+-+-+-+-+-+-+-+-+-+-+ | - // |A|0|1|2|3|4|5|6|7|8|9| | - // +-+-+-+-+-+-+-+-+-+-+-+ | - - // Pour simuler un véritable Redo, l'appelant doit mettre la structure - // de page courante à jour avant l'appel, puis en réextraire les infos en - // sortie, ainsi que celles relatives à la plus récente page d'undo (1ère - // page de la liste). - if (Last_backed_up_layers) - { - // First page contains a ready-made backup of its ->Next. - // We have swap the first two pages, so the original page 0 - // will end up in position -1 again, and then overwrite it with a backup - // of the 'new' page1. - T_Page * page0; - T_Page * page1; - - page0 = list->Pages; - page1 = list->Pages->Prev; - - page0->Prev = page1->Prev; - page1->Next = page0->Next; - page0->Next = page1; - page1->Prev = page0; - list->Pages = page1; - return; - } - list->Pages = list->Pages->Prev; -} - -void Free_last_page_of_list(T_List_of_pages * list) -{ - if (list!=NULL) - { - if (list->List_size>0) - { - T_Page * page; - // The last page is the one before first - page = list->Pages->Prev; - - page->Next->Prev = page->Prev; - page->Prev->Next = page->Next; - Clear_page(page); - free(page); - page = NULL; - list->List_size--; - } - } -} - -// layer_mask tells which layers have to be fresh copies instead of references -int Create_new_page(T_Page * new_page, T_List_of_pages * list, dword layer_mask) -{ - -// This function fills the "Image" field of a new Page, -// based on the pages's attributes (width,height,...) -// then pushes it on front of a Page list. - - if (list->List_size >= (Config.Max_undo_pages+1)) - { - // List is full. - // If some other memory-limit was to be implemented, here would - // be the right place to do it. - // For example, we could rely on Stats_pages_memory, - // because it's the sum of all bitmaps in use (in bytes). - - // Destroy the latest page - Free_last_page_of_list(list); - } - { - int i; - for (i=0; iNb_layers; i++) - { - if ((1<Image[i]=New_layer(new_page->Height*new_page->Width); - else - new_page->Image[i]=Dup_layer(list->Pages->Image[i]); - } - } - - - // Insert as first - new_page->Next = list->Pages; - new_page->Prev = list->Pages->Prev; - list->Pages->Prev->Next = new_page; - list->Pages->Prev = new_page; - list->Pages = new_page; - list->List_size++; - - return 1; -} - -void Change_page_number_of_list(T_List_of_pages * list,int number) -{ - // Truncate the list if larger than requested - while(list->List_size > number) - { - Free_last_page_of_list(list); - } -} - -void Free_page_of_a_list(T_List_of_pages * list) -{ - // On ne peut pas détruire la page courante de la liste si après - // destruction il ne reste pas encore au moins une page. - if (list->List_size>1) - { - // On fait faire un undo à la liste, comme ça, la nouvelle page courante - // est la page précédente - Backward_in_list_of_pages(Main_backups); - - // Puis on détruit la dernière page, qui est l'ancienne page courante - Free_last_page_of_list(list); - } -} - -void Update_screen_targets(void) -{ - #ifndef NOLAYERS - Main_screen=Main_visible_image.Image; - Screen_backup=Main_visible_image_backup.Image; - #else - Main_screen=Main_backups->Pages->Image[Main_current_layer]; - Screen_backup=Main_backups->Pages->Next->Image[Main_current_layer]; - #endif -} - -/// Update all the special image buffers, if necessary. -int Update_buffers(int width, int height) -{ -#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_backup.Width*Main_visible_image_backup.Height != width*height) - { - // Previous image - free(Main_visible_image_backup.Image); - Main_visible_image_backup.Image = (byte *)malloc(width * height); - if (Main_visible_image_backup.Image == NULL) - return 0; - } - Main_visible_image_backup.Width = width; - Main_visible_image_backup.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; -} -/// Update all the special image buffers of the spare page, if necessary. -int Update_spare_buffers(int width, int height) -{ -#ifndef NOLAYERS - // At least one dimension is different - if (Spare_visible_image.Width*Spare_visible_image.Height != width*height) - { - // Current image - free(Spare_visible_image.Image); - Spare_visible_image.Image = (byte *)malloc(width * height); - if (Spare_visible_image.Image == NULL) - return 0; - } - Spare_visible_image.Width = width; - Spare_visible_image.Height = height; - -#endif - return 1; -} - -/// -/// GESTION DES BACKUPS -/// - -int Init_all_backup_lists(int width,int height) -{ - // width et height correspondent à la dimension des images de départ. - int i; - - if (! Allocate_list_of_pages(Main_backups) || - ! Allocate_list_of_pages(Spare_backups)) - return 0; - // On a réussi à allouer deux listes de pages dont la taille correspond à - // celle demandée par l'utilisateur. - - // On crée un descripteur de page correspondant à la page principale - Upload_infos_page_main(Main_backups->Pages); - // On y met les infos sur la dimension de démarrage - Main_backups->Pages->Width=width; - Main_backups->Pages->Height=height; - strcpy(Main_backups->Pages->File_directory,Main_current_directory); - strcpy(Main_backups->Pages->Filename,"NO_NAME.GIF"); - - - for (i=0; iPages->Nb_layers; i++) - { - Main_backups->Pages->Image[i]=New_layer(width*height); - if (! Main_backups->Pages->Image[i]) - return 0; - memset(Main_backups->Pages->Image[i], 0, width*height); - } -#ifndef NOLAYERS - Main_visible_image.Width = 0; - Main_visible_image.Height = 0; - Main_visible_image.Image = NULL; - Main_visible_image_backup.Image = NULL; - Main_visible_image_depth_buffer.Image = NULL; - Spare_visible_image.Width = 0; - Spare_visible_image.Height = 0; - Spare_visible_image.Image = NULL; - -#endif - if (!Update_buffers(width, height)) - return 0; - if (!Update_spare_buffers(width, height)) - return 0; - -#ifndef NOLAYERS - // For speed, instead of Redraw_layered_image() we'll directly set the buffers. - memset(Main_visible_image.Image, 0, width*height); - memset(Main_visible_image_backup.Image, 0, width*height); - memset(Main_visible_image_depth_buffer.Image, 0, width*height); - memset(Spare_visible_image.Image, 0, width*height); - -#endif - Download_infos_page_main(Main_backups->Pages); - Update_FX_feedback(Config.FX_Feedback); - - // Default values for spare page - Spare_backups->Pages->Width = width; - Spare_backups->Pages->Height = height; - memcpy(Spare_backups->Pages->Palette,Main_palette,sizeof(T_Palette)); - strcpy(Spare_backups->Pages->Comment,""); - strcpy(Spare_backups->Pages->File_directory,Main_current_directory); - strcpy(Spare_backups->Pages->Filename,"NO_NAME2.GIF"); - Spare_backups->Pages->File_format=DEFAULT_FILEFORMAT; - // Copy this informations in the global Spare_ variables - Download_infos_page_spare(Spare_backups->Pages); - - // Clear the initial Visible buffer - //memset(Main_screen,0,Main_image_width*Main_image_height); - - // Spare - for (i=0; iPages->Image[i]=New_layer(width*height); - if (! Spare_backups->Pages->Image[i]) - return 0; - memset(Spare_backups->Pages->Image[i], 0, width*height); - - } - //memset(Spare_screen,0,Spare_image_width*Spare_image_height); - - End_of_modification(); - return 1; -} - -void Set_number_of_backups(int nb_backups) -{ - Change_page_number_of_list(Main_backups,nb_backups+1); - Change_page_number_of_list(Spare_backups,nb_backups+1); - - // Le +1 vient du fait que dans chaque liste, en 1ère position on retrouve - // les infos de la page courante sur le brouillon et la page principale. - // (nb_backups = Nombre de backups, sans compter les pages courantes) -} - -int Backup_new_image(byte layers,int width,int height) -{ - // 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); - if (!new_page) - { - Error(0); - return 0; - } - new_page->Width=width; - new_page->Height=height; - new_page->Transparent_color=0; - new_page->Gradients=Dup_gradient(NULL); - if (!Create_new_page(new_page,Main_backups,0xFFFFFFFF)) - { - Error(0); - return 0; - } - - 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) -{ - // Retourne 1 si la page de dimension souhaitee est disponible en brouillon - // et 0 sinon. - - T_Page * new_page; - int return_code=0; - byte nb_layers; - - nb_layers=Spare_backups->Pages->Nb_layers; - // On crée un descripteur pour la nouvelle page de brouillon - new_page=New_page(nb_layers); - if (!new_page) - { - Error(0); - return 0; - } - - // 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; - if (Create_new_page(new_page,Spare_backups,0xFFFFFFFF)) - { - byte i; - - for (i=0; iPages->Image[i], Spare_backups->Pages->Transparent_color, width*height); - } - - // Update_buffers(width, height); // Not for spare - - Download_infos_page_spare(Spare_backups->Pages); - - // Light up the 'has unsaved changes' indicator - Spare_image_is_modified=1; - - return_code=1; - } - return return_code; -} - -void Backup(void) -// Sauve la page courante comme première page de backup et crée une nouvelle page -// pur continuer à dessiner. Utilisé par exemple pour le fill -{ - Backup_layers(1<Pages); - - // Create a fresh Page descriptor - new_page=New_page(Main_backups->Pages->Nb_layers); - if (!new_page) - { - Error(0); - return; - } - - // 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); - - Update_FX_feedback(Config.FX_Feedback); - - // Copy the actual pixels from the backup to the latest page - for (i=0; iPages->Nb_layers;i++) - { - if ((1<Pages->Image[i], - Main_backups->Pages->Next->Image[i], - Main_image_width*Main_image_height); - } - // Light up the 'has unsaved changes' indicator - Main_image_is_modified=1; - - /* - Last_backed_up_layers = 1<Pages->Nb_layers); - if (!new_page) - { - Error(0); - return; - } - - // 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 - for (i=0; iPages->Nb_layers;i++) - { - if ((1<Pages->Image[i], - Spare_backups->Pages->Next->Image[i], - Spare_image_width*Spare_image_height); - } - // Light up the 'has unsaved changes' indicator - Spare_image_is_modified=1; - -} - -void Check_layers_limits() -{ - if (Main_current_layer > Main_backups->Pages->Nb_layers-1) - { - Main_current_layer = Main_backups->Pages->Nb_layers-1; - Main_layers_visible |= 1<Pages); - // On fait faire un undo à la liste des backups de la page principale - Backward_in_list_of_pages(Main_backups); - - Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); - - // On extrait ensuite les infos sur la nouvelle page courante - Download_infos_page_main(Main_backups->Pages); - // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même - // palette que la page courante. Mais en temps normal, le backup - // n'est pas utilisé à la suite d'un Undo. Donc ça ne devrait pas - // poser de problèmes. - - Check_layers_limits(); - Redraw_layered_image(); - End_of_modification(); - -} - -void Redo(void) -{ - if (Last_backed_up_layers) - { - Free_page_of_a_list(Main_backups); - Last_backed_up_layers=0; - } - // On remet à jour l'état des infos de la page courante (pour pouvoir les - // retrouver plus tard) - Upload_infos_page_main(Main_backups->Pages); - // On fait faire un redo à la liste des backups de la page principale - Advance_in_list_of_pages(Main_backups); - - Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); - - // On extrait ensuite les infos sur la nouvelle page courante - Download_infos_page_main(Main_backups->Pages); - // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même - // palette que la page courante. Mais en temps normal, le backup - // n'est pas utilisé à la suite d'un Redo. Donc ça ne devrait pas - // poser de problèmes. - - Check_layers_limits(); - Redraw_layered_image(); - End_of_modification(); - -} - -void Free_current_page(void) -{ - // On détruit la page courante de la liste principale - Free_page_of_a_list(Main_backups); - - // On extrait ensuite les infos sur la nouvelle page courante - Download_infos_page_main(Main_backups->Pages); - // Note: le backup n'a pas obligatoirement les mêmes dimensions ni la même - // palette que la page courante. Mais en temps normal, le backup - // n'est pas utilisé à la suite d'une destruction de page. Donc ça ne - // devrait pas poser de problèmes. - - Update_buffers(Main_backups->Pages->Width, Main_backups->Pages->Height); - Check_layers_limits(); - Redraw_layered_image(); - End_of_modification(); -} - -void Exchange_main_and_spare(void) -{ - T_List_of_pages * temp_list; - - // On commence par mettre à jour dans les descripteurs les infos sur les - // pages qu'on s'apprête à échanger, pour qu'on se retrouve pas avec de - // vieilles valeurs qui datent de mathuzalem. - Upload_infos_page_main(Main_backups->Pages); - Upload_infos_page_spare(Spare_backups->Pages); - - // On inverse les listes de pages - temp_list=Main_backups; - Main_backups=Spare_backups; - Spare_backups=temp_list; - - // On extrait ensuite les infos sur les nouvelles pages courante, brouillon - // et backup. - - /* SECTION GROS CACA PROUT PROUT */ - // Auparavant on ruse en mettant déjà à jour les dimensions de la - // nouvelle page courante. Si on ne le fait pas, le "Download" va détecter - // un changement de dimensions et va bêtement sortir du mode loupe, alors - // que lors d'un changement de page, on veut bien conserver l'état du mode - // loupe du brouillon. - Main_image_width=Main_backups->Pages->Width; - Main_image_height=Main_backups->Pages->Height; - - Download_infos_page_main(Main_backups->Pages); - Download_infos_page_spare(Spare_backups->Pages); -} - -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); -#else - Update_screen_targets(); -#endif - - Update_FX_feedback(Config.FX_Feedback); -/* - Last_backed_up_layers = 0; - Backup(); - */ - // - // Processing safety backups - // - Main_edits_since_safety_backup++; - Rotate_safety_backups(); -} - -/// Add a new layer to latest page of a list. Returns 0 on success. -byte Add_layer(T_List_of_pages *list, byte layer) -{ - T_Page * source_page; - T_Page * new_page; - byte * new_image; - int i; - - source_page = list->Pages; - - if (list->Pages->Nb_layers == MAX_NB_LAYERS) - return 1; - - // Keep the position reasonable - if (layer > list->Pages->Nb_layers) - layer = list->Pages->Nb_layers; - - // Allocate the pixel data - new_image = New_layer(list->Pages->Height*list->Pages->Width); - if (! new_image) - { - Error(0); - return 1; - } - // Re-allocate the page itself, with room for one more pointer - new_page = realloc(source_page, sizeof(T_Page)+(list->Pages->Nb_layers+1)*sizeof(byte *)); - if (!new_page) - { - Error(0); - return 1; - } - if (new_page != source_page) - { - // Need some housekeeping because the page moved in memory. - // Update all pointers that pointed to it: - new_page->Prev->Next = new_page; - new_page->Next->Prev = new_page; - list->Pages = new_page; - } - list->Pages->Nb_layers++; - // Move around the pointers. This part is going to be tricky when we - // have 'animations x layers' in this vector. - for (i=list->Pages->Nb_layers-1; i>layer ; i--) - { - new_page->Image[i]=new_page->Image[i-1]; - } - new_page->Image[layer]=new_image; - // Fill with transparency, initially - memset(new_image, Main_backups->Pages->Transparent_color, list->Pages->Height*list->Pages->Width); // transparent color - - // Done. Note that the visible buffer is already ok since we - // only inserted a transparent "slide" somewhere. - // The depth buffer is all wrong though. - - // Update the flags of visible layers. - { - dword layers_before; - dword layers_after; - dword *visible_layers_flag; - - // Determine if we're modifying the spare or the main page. - if (list == Main_backups) - { - visible_layers_flag = &Main_layers_visible; - Main_current_layer = layer; - } - else - { - visible_layers_flag = &Spare_layers_visible; - Spare_current_layer = layer; - } - - // Fun with binary! - layers_before = ((1<Pages; - - // Keep the position reasonable - if (layer >= list->Pages->Nb_layers) - layer = list->Pages->Nb_layers - 1; - if (list->Pages->Nb_layers == 1) - return 1; - - // For simplicity, we won't actually shrink the page in terms of allocation. - // It would only save the size of a pointer, and anyway, as the user draws, - // this page is going to fall off the end of the Undo-list - // and so it will be cleared anyway. - - // Smart freeing of the pixel data - Free_layer(list->Pages, layer); - - list->Pages->Nb_layers--; - // Move around the pointers. This part is going to be tricky when we - // have 'animations x layers' in this vector. - for (i=layer; i < list->Pages->Nb_layers; i++) - { - list->Pages->Image[i]=list->Pages->Image[i+1]; - } - - // Done. At this point the visible buffer and the depth buffer are - // all wrong. - - // Update the flags of visible layers. - { - dword layers_before; - dword layers_after; - dword *visible_layers_flag; - byte new_current_layer; - - // Determine if we're modifying the spare or the main page. - if (list == Main_backups) - { - visible_layers_flag = &Main_layers_visible; - if (Main_current_layer>=layer && Main_current_layer>0) - Main_current_layer--; - new_current_layer = Main_current_layer; - } - else - { - visible_layers_flag = &Spare_layers_visible; - if (Spare_current_layer>=layer && Spare_current_layer>0) - Spare_current_layer--; - new_current_layer = Spare_current_layer; - } - - // Fun with binary! - layers_before = ((1<>1; - *visible_layers_flag = layers_before | layers_after; - // Ensure the current layer is part what is shown. - *visible_layers_flag |= 1<Pages->Image[Main_current_layer]+i); - if (color != Main_backups->Pages->Transparent_color) // transparent color - *(Main_backups->Pages->Image[Main_current_layer-1]+i) = color; - } - return Delete_layer(Main_backups,Main_current_layer); -} diff --git a/project/jni/application/grafx2/grafx2/src/pages.h b/project/jni/application/grafx2/grafx2/src/pages.h deleted file mode 100644 index 31a514c58..000000000 --- a/project/jni/application/grafx2/grafx2/src/pages.h +++ /dev/null @@ -1,141 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pages.h -/// Handler for the Undo/Redo system. -////////////////////////////////////////////////////////////////////////////// - -#ifndef _PAGES_H_ -#define _PAGES_H_ - -/// -/// Pointer to the image to read, while drawing. It's either the last history -/// layer page when FX feedback is on, or the history page before it -/// when FX feedback is off. -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; - -/// -/// INDIVIDUAL PAGES -/// - -void Download_infos_page_main(T_Page * page); -void Upload_infos_page_main(T_Page * page); -/// Add a new layer to latest page of a list. Returns 0 on success. -byte Add_layer(T_List_of_pages *list, byte layer); -/// Delete a layer from the latest page of a list. Returns 0 on success. -byte Delete_layer(T_List_of_pages *list, byte layer); -/// Merges the current layer onto the one below it. -byte Merge_layer(); - -// private -T_Page * New_page(byte nb_layers); -void Download_infos_page_spare(T_Page * page); -void Upload_infos_page_spare(T_Page * page); -void Clear_page(T_Page * page); -void Copy_S_page(T_Page * dest,T_Page * source); - - - -/// -/// LISTS OF PAGES -/// - -void Init_list_of_pages(T_List_of_pages * list); -// private -int Allocate_list_of_pages(T_List_of_pages * list); -void Backward_in_list_of_pages(T_List_of_pages * list); -void Advance_in_list_of_pages(T_List_of_pages * list); -void Free_last_page_of_list(T_List_of_pages * list); -int Create_new_page(T_Page * new_page,T_List_of_pages * current_list, dword layer_mask); -void Change_page_number_of_list(T_List_of_pages * list,int number); -void Free_page_of_a_list(T_List_of_pages * list); - - - -/// -/// BACKUP HIGH-LEVEL FUNCTIONS -/// - -int Init_all_backup_lists(int width,int height); -void Set_number_of_backups(int nb_backups); -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); -/// Backup with a new copy for the working layer, and references for all others. -void Backup(void); -/// Backup with a new copy of some layers (the others are references). -void Backup_layers(dword layer_mask); -void Undo(void); -void Redo(void); -void Free_current_page(void); // 'Kill' button -void Exchange_main_and_spare(void); -void End_of_modification(void); - -void Update_depth_buffer(void); -void Redraw_layered_image(void); -void Redraw_current_layer(void); - -void Update_screen_targets(void); -/// Update all the special image buffers, if necessary. -int Update_buffers(int width, int height); -int Update_spare_buffers(int width, int height); -void Redraw_spare_image(void); -/// -/// Must be called after changing the head of Main_backups list, or -/// Main_current_layer -void Update_FX_feedback(byte with_feedback); - -/// -/// STATISTICS -/// - -/// Total number of unique bitmaps (layers, animation frames, backups) -extern long Stats_pages_number; -/// Total memory used by bitmaps (layers, animation frames, backups) -extern long long Stats_pages_memory; - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/palette.c b/project/jni/application/grafx2/grafx2/src/palette.c deleted file mode 100644 index 3ca1f7d34..000000000 --- a/project/jni/application/grafx2/grafx2/src/palette.c +++ /dev/null @@ -1,2992 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include -#include -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "engine.h" -#include "readline.h" -#include "buttons.h" -#include "pages.h" -#include "help.h" -#include "sdlscreen.h" -#include "errors.h" -#include "op_c.h" -#include "windows.h" -#include "input.h" -#include "palette.h" -#include "shade.h" - -byte Palette_view_is_RGB = 1; // Indique si on est en HSL ou en RGB - -// 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 -//int RGB_scale = 64; // VGA -//int RGB_scale = 16; // Amiga -//int RGB_scale = 4; // MSX2 -//int RGB_scale = 3; // Amstrad CPC - -// Nombre de graduations pour une composante dans le mode actuel -int Color_count=256; -// Les composantes vont de 0 à (Color_count-1) -int Color_max=255; -// Le demi-pas est une quantité que l'on ajoute à une composante -// avant de faire un arrondi par division. -int Color_halfstep=0; - - -void Set_palette_RGB_scale(int scale) -{ - if (scale>= 2 && scale <= 256) - RGB_scale = scale; -} - -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 Component_unit(int count) -{ - Color_count = count; - Color_max = count-1; - Color_halfstep = 256/count/2; -} - -void Set_HSL(T_Palette start_palette, T_Palette end_palette, byte color, short diff_h, short diff_s, short diff_l) -{ - byte h, s, l; - RGB_to_HSL(start_palette[color].R,start_palette[color].G,start_palette[color].B,&h,&s,&l); - // La teinte (Hue) est cyclique - h=(diff_h+256+h); - // Pour les autres (Saturation, Lightness), au lieu d'additionner, - // on va faire un ratio, cela utilise mieux la plage de valeurs 0-255 - if (diff_s<0) - s=(255+diff_s)*s/255; - else if (diff_s>0) - s=255-(255-diff_s)*(255-s)/255; - if (diff_l<0) - l=(255+diff_l)*l/255; - else if (diff_l>0) - l=255-(255-diff_l)*(255-l)/255; - HSL_to_RGB(h,s,l,&end_palette[color].R,&end_palette[color].G,&end_palette[color].B); -} - -void Set_red(byte color, short new_color, T_Palette palette) -{ - if (new_color< 0) - new_color= 0; - if (new_color>255) - new_color=255; - // Arrondi - new_color=Round_palette_component(new_color); - - palette[color].R=new_color; -} - - -void Set_green(byte color, short new_color, T_Palette palette) -{ - if (new_color< 0) - new_color= 0; - if (new_color>255) - new_color=255; - // Arrondi - new_color=Round_palette_component(new_color); - - palette[color].G=new_color; -} - - -void Set_blue(byte color, short new_color, T_Palette palette) -{ - if (new_color< 0) - new_color= 0; - if (new_color>255) - new_color=255; - // Arrondi - new_color=Round_palette_component(new_color); - - palette[color].B=new_color; -} - -void Format_component(byte value, char *str) -// Formate une chaine de 4 caractères+\0 : "nnn " -{ - Num2str(value,str,3); - str[3]=' '; - str[4]='\0'; -} - -void Spread_colors(short start,short end,T_Palette palette) -// Modifie la palette pour obtenir un dégradé de couleur entre les deux bornes -// passées en paramètre -{ - short start_red; - short start_green; - short start_blue; - short end_red; - short end_green; - short end_blue; - short index; - - // On vérifie qu'il y ait assez de couleurs entre le début et la fin pour - // pouvoir faire un dégradé: - if ( (start!=end) && (start+1!=end) ) - { - start_red=palette[start].R; - start_green =palette[start].G; - start_blue =palette[start].B; - - end_red =palette[end ].R; - end_green =palette[end ].G; - end_blue =palette[end ].B; - - for (index=start+1;index=Window_pos_Y) && (y_pos=Window_pos_X) && (x_posPages->Nb_layers; layer++) - 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 = - conversion_table[Main_backups->Pages->Transparent_color]; - - // On calcule les limites à l'écran de l'image - if (Main_image_height>=Menu_Y_before_window) - end_y=Menu_Y_before_window; - else - end_y=Main_image_height; - - if (!Main_magnifier_mode) - { - if (Main_image_width>=Screen_width) - end_x=Screen_width; - else - end_x=Main_image_width; - - } - else - { - if (Main_image_width>=Main_separator_position) - end_x=Main_separator_position; - else - end_x=Main_image_width; - - if ((Main_X_zoom+(Main_image_width*Main_magnifier_factor))>=Screen_width) - end_x_mag=Screen_width; - else - end_x_mag=(Main_X_zoom+(Main_image_width*Main_magnifier_factor)); - - if (Main_image_height*Main_magnifier_factor>=Menu_Y_before_window) - end_y_mag=Menu_Y_before_window; - else - end_y_mag=Main_image_height*Main_magnifier_factor; - } - - // On doit maintenant faire la traduction à l'écran - Remap_zone_highlevel(0,0,end_x,end_y,conversion_table); - - if (Main_magnifier_mode) - { - Remap_zone_highlevel(Main_separator_position,0,end_x_mag,end_y_mag,conversion_table); - // Il peut encore rester le bas de la barre de split à remapper si la - // partie zoomée ne descend pas jusqu'en bas... - Remap_zone_highlevel(Main_separator_position,end_y_mag, - (Main_separator_position+(SEPARATOR_WIDTH*Menu_factor_X)), - Menu_Y_before_window,conversion_table); - } - // Remappe tous les fonds de fenetre (qui doivent contenir un bout d'écran) - Remap_window_backgrounds(conversion_table, 0, Menu_Y_before_window); -} - - -void Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette, dword * color_usage) -{ - short pos_1; - short pos_2; - short end_1; - short end_2; - byte conversion_table[256]; - - T_Components temp_palette[256]; - dword temp_usage[256]; - - // On fait une copie de la palette - memcpy(temp_palette, palette, sizeof(T_Palette)); - - // 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 - // fera aucune conversion. - for (pos_1=0;pos_1<=255;pos_1++) - conversion_table[pos_1]=pos_1; - - // On calcul les dernières couleurs de chaque bloc. - end_1=block_1_start+block_size-1; - end_2=block_2_start+block_size-1; - - if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) - { - // Le bloc destination commence dans le bloc source. - - for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) - { - // Il faut transformer la couleur pos_1 en pos_2: - - conversion_table[pos_2]=pos_1; - color_usage[pos_1]=temp_usage[pos_2]; - palette[pos_1].R=temp_palette[pos_2].R; - palette[pos_1].G=temp_palette[pos_2].G; - palette[pos_1].B=temp_palette[pos_2].B; - - // On gère la mise à jour de pos_2 - if (pos_2==end_2) - pos_2=block_1_start; - else - pos_2++; - } - } - else - if ((block_2_start=block_1_start)) - { - // Le bloc destination déborde dans le bloc source. - - for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) - { - // Il faut transformer la couleur pos_1 en pos_2: - - conversion_table[pos_2]=pos_1; - color_usage[pos_1]=temp_usage[pos_2]; - palette[pos_1].R=temp_palette[pos_2].R; - palette[pos_1].G=temp_palette[pos_2].G; - palette[pos_1].B=temp_palette[pos_2].B; - - // On gère la mise à jour de pos_2 - if (pos_2==end_1) - pos_2=block_2_start; - else - pos_2++; - } - } - else - { - // Le bloc source et le bloc destination sont distincts. - - for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) - { - // Il va falloir permutter la couleur pos_1 avec la couleur pos_2 - conversion_table[pos_1]=pos_2; - conversion_table[pos_2]=pos_1; - - // On intervertit le nombre d'used des couleurs pour garder une - // cohérence lors d'un éventuel "Zap unused". - SWAP_DWORDS(color_usage[pos_1], color_usage[pos_2]) - - // On fait un changement de teinte: - SWAP_BYTES(palette[pos_1].R, palette[pos_2].R) - SWAP_BYTES(palette[pos_1].G, palette[pos_2].G) - SWAP_BYTES(palette[pos_1].B, palette[pos_2].B) - } - } - - if (with_remap) - { - Remap_image_highlevel(conversion_table); - } - else - { - // Restore color usage. Shouldn't have reordered it in the first place. - memcpy(color_usage, temp_usage, sizeof(dword) * 256); - } -} - - - -void Set_nice_menu_colors(dword * color_usage,int not_picture) -{ - short index,index2; - byte color; - byte replace_table[256]; - T_Components rgb[4]; - short new_colors[4]={255,254,253,252}; - - // On initialise la table de remplacement - for (index=0; index<256; index++) - replace_table[index]=index; - - // On recherche les 4 couleurs les moins utilisées dans l'image pour pouvoir - // les remplacer par les nouvelles couleurs. - for (index2=0; index2<4; index2++) - for (index=255; index>=0; index--) - { - if ((index!=new_colors[0]) && (index!=new_colors[1]) - && (index!=new_colors[2]) && (index!=new_colors[3]) - && (color_usage[index]new_colors[index+1]) - { - index2 =new_colors[index]; - new_colors[index] =new_colors[index+1]; - new_colors[index+1]=index2; - color=1; - } - } - } while (color); - - // On sauvegarde dans rgb les teintes qu'on va remplacer et on met les - // couleurs du menu par défaut - for (index=0; index<4; index++) - { - 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; - 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 - // sont les couleurs qui peuvent remplacer les anciennes - Hide_cursor(); - for (index=0; index<4; index++) - replace_table[new_colors[index]]=Best_color_nonexcluded - (rgb[index].R,rgb[index].G,rgb[index].B); - - if (not_picture) - { - // Remap caused by preview. Only remap screen - Remap_zone_highlevel(0,0,Screen_width,Screen_height,replace_table); - } - else - { - // On fait un changement des couleurs visibles à l'écran et dans l'image - Remap_image_highlevel(replace_table); - } - Display_cursor(); -} - - - -void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage) -{ - char str[5]; // buffer d'affichage du compteur - byte conversion_table[256]; // Table de conversion - int color_1; // |_ Variables de balayages - int color_2; // | de la palette - int best_color_1=0; - int best_color_2=0; - int difference; - int best_difference; - dword used; - dword best_used; - - // On commence par initialiser la table de conversion dans un état où - // aucune conversion ne sera effectuée. - for (color_1=0; color_1<=255; color_1++) - conversion_table[color_1]=color_1; - - // Si on ne connait pas encore le nombre de couleurs utilisées, on le - // calcule! (!!! La fonction appelée Efface puis Affiche le curseur !!!) - if ((*used_colors)<0) - Update_color_count(used_colors,color_usage); - - Hide_cursor(); - - // On tasse la palette vers le début parce qu'elle doit ressembler à - // du Gruyère (et comme Papouille il aime pas le fromage...) - - // Pour cela, on va scruter la couleur color_1 et se servir de l'indice - // color_2 comme position de destination. - for (color_1=color_2=0;color_1<=255;color_1++) - { - if (color_usage[color_1]) - { - // On commence par s'occuper des teintes de la palette - palette[color_2].R=palette[color_1].R; - palette[color_2].G=palette[color_1].G; - palette[color_2].B=palette[color_1].B; - - // Ensuite, on met à jour le tableau d'occupation des couleurs. - color_usage[color_2]=color_usage[color_1]; - - // On va maintenant s'occuper de la table de conversion: - conversion_table[color_1]=color_2; - - // Maintenant, la place désignée par color_2 est occupée, alors on - // doit passer à un indice de destination suivant. - color_2++; - } - } - - // On met toutes les couleurs inutilisées en noir - for (;color_2<256;color_2++) - { - palette[color_2].R=0; - palette[color_2].G=0; - palette[color_2].B=0; - color_usage[color_2]=0; - } - - // Maintenant qu'on a une palette clean, on va boucler en réduisant - // le nombre de couleurs jusqu'à ce qu'on atteigne le nombre désiré. - // (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 - // une seule couleur qui est la moyenne pondérée de ces 2 couleurs - // en fonction de leur utilisation dans l'image. - - best_difference =0x7FFF; - 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++) - if (color_1!=color_2) - { - difference =abs((short)palette[color_1].R-palette[color_2].R)+ - abs((short)palette[color_1].G-palette[color_2].G)+ - abs((short)palette[color_1].B-palette[color_2].B); - - if (difference<=best_difference) - { - used=color_usage[color_1]+color_usage[color_2]; - if ((differencebest_color_2) - { - // La color_1 va scroller en arrière. - - // Donc on transfère son utilisation dans l'utilisation de la - // couleur qui la précède. - color_usage[color_1-1]=color_usage[color_1]; - - // Et on transfère ses teintes dans les teintes de la couleur qui - // la précède. - palette[color_1-1].R=palette[color_1].R; - palette[color_1-1].G=palette[color_1].G; - palette[color_1-1].B=palette[color_1].B; - } - - // Une fois la palette et la table d'utilisation gérées, on peut - // s'occuper de notre table de conversion. - if (conversion_table[color_1]>best_color_2) - // La color_1 avait l'intention de se faire remplacer par une - // couleur que l'on va (ou que l'on a déjà) bouger en arrière. - conversion_table[color_1]--; - } - - // On vient d'éjecter une couleur, donc on peut mettre à jour le nombre - // de couleurs utilisées. - (*used_colors)--; - - // A la fin, on doit passer (dans la palette) les teintes du dernier - // élément de notre ensemble en noir. - palette[*used_colors].R=0; - palette[*used_colors].G=0; - palette[*used_colors].B=0; - - // Au passage, on va s'assurer que l'on a pas oublié de la mettre à une - // utilisation nulle. - color_usage[*used_colors]=0; - - // Après avoir éjecté une couleur, on le fait savoir à l'utilisateur par - // l'intermédiaire du compteur de nombre utilisées. - Num2str(*used_colors,str,3); - Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light); - } - - // Maintenant, tous ces calculs doivent êtres pris en compte dans la - // palette, l'image et à l'écran. - Remap_image_highlevel(conversion_table); // Et voila pour l'image et l'écran - Display_cursor(); -} - - -// Position of the numeric values of the R G B sliders -static const int NUMERIC_R_X = 176; -static const int NUMERIC_G_X = 203; -static const int NUMERIC_B_X = 230; -static const int NUMERIC_Y = 171; -// Position of the whole button -static const int NUMERIC_BOX_X = 175; -static const int NUMERIC_BOX_Y = 169; -static const int NUMERIC_BOX_W = 81; -static const int NUMERIC_BOX_H = 12; - -void Set_palette_slider(T_Scroller_button * slider, - word nb_elements, word position, - char * value, short x_pos) -{ - slider->Nb_elements=nb_elements; - slider->Position=position; - Compute_slider_cursor_length(slider); - Window_draw_slider(slider); - Print_counter(x_pos,NUMERIC_Y,value,MC_Black,MC_Light); -} - - - -void Display_sliders(T_Scroller_button * red_slider, - T_Scroller_button * green_slider, - T_Scroller_button * blue_slider, - byte block_is_selected, T_Components * palette) -{ - char str[5]; - - if (block_is_selected) - { - Set_palette_slider(red_slider,Color_max*2+1,Color_max,"± 0",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 - { - byte j1, j2, j3; - j1= palette[Fore_color].R; - j2= palette[Fore_color].G; - j3= palette[Fore_color].B; - if (!Palette_view_is_RGB) - { - RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); - } - - Format_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, - T_Palette palette,byte start,byte end) -{ - char str[5]; - - Hide_cursor(); - // Réaffichage des jauges: - if (start!=end) - { - // Dans le cas d'un bloc, tout à 0. - red_slider->Position =Color_max; - Window_draw_slider(red_slider); - Print_counter(NUMERIC_R_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); - - green_slider->Position =Color_max; - Window_draw_slider(green_slider); - Print_counter(NUMERIC_G_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); - - blue_slider->Position =Color_max; - Window_draw_slider(blue_slider); - Print_counter(NUMERIC_B_X,NUMERIC_Y,"± 0",MC_Black,MC_Light); - } - else - { - // Dans le cas d'une seule couleur, composantes. - byte j1, j2, j3; - j1= palette[start].R; - j2= palette[start].G; - j3= palette[start].B; - if (!Palette_view_is_RGB) - { - RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3); - } - DEBUG("j1",j1); - Format_component(j1*Color_count/256,str); - red_slider->Position=Color_max-Expand_component(j1); - Window_draw_slider(red_slider); - Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); - - Format_component(j2*Color_count/256,str); - green_slider->Position=Color_max-Expand_component(j2); - Window_draw_slider(green_slider); - Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); - - Format_component(j3*Color_count/256,str); - blue_slider->Position=Color_max-Expand_component(j3); - Window_draw_slider(blue_slider); - Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); - } - Display_cursor(); -} - - -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 */ - - if (block_start == block_end) { - // only one color selected: auto-detect the range - for (block_start=0; block_start!=255; block_start++) - if (color_usage[block_start]) - break; - for (block_end=255; block_end!=0; block_end--) - if (color_usage[block_end]) - break; - } - - // Normalize the histogram towards the most used color - // Step 1 : find the most used color in the range - for(i=block_start; i<= block_end; i++) { - if(color_usage[i] > max_count) max_count = color_usage[i]; - } - - if (max_count == 0) - { - Warning_message("All these colors are unused!"); - Hide_cursor(); - return -1; - } - - Open_window(263, 150, "Histogram"); - Window_set_normal_button(120, 130, 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; - // Don't draw anything if the color is unused - if (color_usage[i]!=0) - { - // Draw at least one pixel if the color is used - if (height==0) - height=1; - - Window_rectangle( - 3+j*bar_width, - 127-height, - bar_width, - height, i); - - //if (i == MC_Light) { - Window_rectangle( - 3+j*bar_width, - 126-height, - bar_width, - 1,MC_Black); - //} - } - // vertical outline - if (height>old_height) - Window_rectangle( - 2+j*bar_width, - 126-height, - 1, - height-old_height+1,MC_Black); - else if (old_height>height) - Window_rectangle( - 3+j*bar_width, - 126-old_height, - 1, - old_height-height+1,MC_Black); - - old_height=height; - j++; - } - // Last vertical outline - if (old_height!=0) - Window_rectangle( - 3+j*(256/(block_end-block_start+1)), - 126-old_height, - 1, - old_height+1,MC_Black); - - histo = Window_set_special_button(3, 27, j*bar_width, 100); // 2 - - 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; - byte color,click; // Variables pouvant reservir pour différents calculs intermédiaires - short clicked_button; - word old_mouse_x; - word old_mouse_y; - byte old_mouse_k; - byte block_start; - byte block_end; - byte first_color; - byte last_color; - char str[10]; - word i; - T_Normal_button * button_used; - T_Scroller_button * red_slider; - 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; - - dword color_usage[256]; - short used_colors = -1; // -1 <=> Inconnu - byte conversion_table[256]; - - //T_Components * backup_palette; - //T_Components * temp_palette; - //T_Components * working_palette; - - 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)); - - Component_unit(RGB_scale); - - Open_window(299, 188,"Palette"); - - memcpy(working_palette, Main_palette, sizeof(T_Palette)); - Palette_edit_step(); - - Window_set_palette_button(5, 79); // 1 - - Window_display_frame (172, 63, 122, 121); - - // Graduation des jauges de couleur - 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(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_RGB_or_HSL(0); - Component_unit(RGB_scale); - } else { - 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(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(7, 69, "Color number:", MC_Dark, MC_Light); - Num2str(Fore_color, str, 3); - Print_in_window(COLOR_X, COLOR_Y, str, MC_Black, MC_Light); - - 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(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 - - 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_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 - - // 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); - - 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(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); - - Update_window_area(0,0,299,188); - - do - { - old_mouse_x=Mouse_X; - old_mouse_y=Mouse_Y; - old_mouse_k=Mouse_K; - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case 0 : // Nulle part - break; - case -1 : // Hors de la fenêtre - case 1 : // palette - if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) - { - Hide_cursor(); - temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); - if (Mouse_K==RIGHT_SIDE) - { - // 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 - Palette_edit_step(); - - 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(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 - { - if (!old_mouse_k) - { - // On vient de clicker sur une couleur (et une seule) - if ( (Fore_color!=temp_color) || (block_start!=block_end) ) - { - // La couleur en question est nouvelle ou elle annule un - // ancien bloc. Il faut donc sélectionner cette couleur comme - // unique couleur choisie. - - Fore_color=first_color=last_color=block_start=block_end=temp_color; - Tag_color_range(block_start,block_end); - - // Affichage du n° de la couleur sélectionnée - 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); - - Palette_edit_select_range(); - } - } - else - { - // On maintient le click, on va donc tester si le curseur bouge - if (temp_color!=last_color) - { - // On commence par ordonner la 1ère et dernière couleur du bloc - if (first_colortemp_color) - { - block_start=temp_color; - block_end=first_color; - - // Affichage du n° de la couleur sélectionnée - Num2str(block_start,str ,3); - Num2str(block_end ,str+4,3); - str[3]=26; // Flèche vers la droite - Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - - // Affichage des jauges - Display_sliders(red_slider,green_slider,blue_slider,1,NULL); - - // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); - } - else - { - block_start=block_end=first_color; - Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light); - - // Affichage du n° de la couleur sélectionnée - 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(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - - // Affichage des jauges - Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); - - // Affichage dans le block de visu de la couleur en cours - 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) - Tag_color_range(block_start,block_end); - } - - last_color=temp_color; - } - Display_cursor(); - } - - } - break; - case 2 : // Jauge rouge - Hide_cursor(); - Palette_edit_alter_channel(); - if (block_start==block_end) - { - if(Palette_view_is_RGB) - { - 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 - { - HSL_to_RGB( - 255-red_slider->Position, - 255-green_slider->Position, - 255-blue_slider->Position, - &working_palette[Fore_color].R, - &working_palette[Fore_color].G, - &working_palette[Fore_color].B); - Format_component((int)255-red_slider->Position,str); - } - 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+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, - 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) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-red_slider->Position),str,4); - str[0]='-'; - } - else if (red_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); - - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - case 3 : // Jauge verte - Hide_cursor(); - Palette_edit_alter_channel(); - if (block_start==block_end) - { - if(Palette_view_is_RGB) - { - 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 - { - HSL_to_RGB( - 255-red_slider->Position, - 255-green_slider->Position, - 255-blue_slider->Position, - &working_palette[Fore_color].R, - &working_palette[Fore_color].G, - &working_palette[Fore_color].B); - Format_component((int)255-green_slider->Position,str); - } - 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+Reduce_component(Color_max-green_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, - 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) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-green_slider->Position),str,4); - str[0]='-'; - } - else if (green_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - - case 4 : // Jauge bleue - Hide_cursor(); - Palette_edit_alter_channel(); - if (block_start==block_end) - { - if(Palette_view_is_RGB) - { - 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 - { - HSL_to_RGB( - 255-red_slider->Position, - 255-green_slider->Position, - 255-blue_slider->Position, - &working_palette[Fore_color].R, - &working_palette[Fore_color].G, - &working_palette[Fore_color].B); - Format_component((int)255-blue_slider->Position,str); - } - 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+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, - 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) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-blue_slider->Position),str,4); - str[0]='-'; - } - else if (blue_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - - case 5 : // Merge - if (block_start!=block_end) - { - dword sum_r=0, sum_g=0, sum_b=0, used=0; - - Palette_edit_step(); - // 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; - Palette_edit_step(); - - // 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 - // Backup - Palette_edit_step(); - // Grey Scale - for (i=block_start;i<=block_end;i++) - { - temp_color=(dword)( ((dword)working_palette[i].R*30) + ((dword)working_palette[i].G*59) + ((dword)working_palette[i].B*11) )/100; - Set_red(i,temp_color,working_palette); - Set_green (i,temp_color,working_palette); - Set_blue (i,temp_color,working_palette); - } - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - // On prépare la "modifiabilité" des nouvelles couleurs - Set_palette(working_palette); - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - - need_to_remap=1; - break; - - case 7 : // Swap - case 8 : // X-Swap - temp_color=Wait_click_in_palette(Window_palette_button_list); - if ((temp_color>=0) - && (temp_color!=block_start)) - { - Hide_cursor(); - Palette_edit_step(); - - // On calcule le nombre de couleurs a swapper sans risquer de sortir - // de la palette (La var. first_color est utilisée pour économiser 1 var; c'est tout) - first_color=(temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color; - - if (clicked_button==8) // On ne fait de backup de l'image que si on - // est en mode X-SWAP. - if (!image_is_backed_up) - { - Backup_layers(-1); - image_is_backed_up=1; - } - - Swap(clicked_button==8,block_start,temp_color,first_color,working_palette,color_usage); - - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - - // On déplace le bloc vers les modifs: - last_color=block_end=temp_color+first_color-1; - Fore_color=first_color=block_start=temp_color; - // On raffiche le n° des bornes du bloc: - if (block_start!=block_end) - { - // Cas d'un bloc multi-couleur - Num2str(block_start,str ,3); - Num2str(block_end ,str+4,3); - str[3]=26; // Flèche vers la droite - // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); - } - else - { - // Cas d'une seule couleur - Num2str(Fore_color,str,3); - Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); - // 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); - } - 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); - - need_to_remap=1; - - Set_palette(working_palette); - - Display_cursor(); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - - // En cas de X-Swap, tout l'ecran a pu changer de couleur. - if (clicked_button==8) - { - Palette_edit_step(); // Disable Undo - Update_rect(0, 0, Screen_width, Menu_Y_before_window); - End_of_modification(); - } - Wait_end_of_click(); - } - break; - - case 9 : // Copy (to other slot) - temp_color=Wait_click_in_palette(Window_palette_button_list); - if ((temp_color>=0) && (temp_color!=block_start)) - { - Hide_cursor(); - Palette_edit_step(); - memcpy(working_palette+temp_color,backup_palette+block_start, - ((temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color)*3); - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - Set_palette(working_palette); - // On déplace le bloc vers les modifs: - last_color=block_end=((temp_color+block_end-block_start<=255)?(temp_color+block_end-block_start):255); - Fore_color=first_color=block_start=temp_color; - // On raffiche le n° des bornes du bloc: - if (block_start!=block_end) - { - // Cas d'un bloc multi-couleur - Num2str(block_start,str ,3); - Num2str(block_end ,str+4,3); - str[3]=26; // Flèche vers la droite - // Affichage dans le block de visu du bloc (dégradé) en cours - Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,block_start,block_end); - } - else - { - // Cas d'une seule couleur - Num2str(Fore_color,str,3); - Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light); - // 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); - } - 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); - - need_to_remap=1; - - Display_cursor(); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Wait_end_of_click(); - } - break; - - case 10 : // Spread - if (block_start!=block_end) - { - Palette_edit_step(); - Spread_colors(block_start,block_end,working_palette); - } - else - { - temp_color=Wait_click_in_palette(Window_palette_button_list); - if (temp_color>=0) - { - Palette_edit_step(); - if (temp_color 256) - break; // Cancel - - reduce_colors_number = choice; - } - 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) - { - Backup_layers(-1); - image_is_backed_up = 1; - } - - Reduce_palette(&used_colors, reduce_colors_number, working_palette, - color_usage); - - if ((Config.Safety_colors) && (used_colors<4)) - { - memcpy(temp_palette, Main_palette, sizeof(T_Palette)); - memcpy(Main_palette, working_palette, sizeof(T_Palette)); - Set_nice_menu_colors(color_usage, 0); - memcpy(working_palette, Main_palette, sizeof(T_Palette)); - memcpy(Main_palette, temp_palette, sizeof(T_Palette)); - } - - Set_palette(working_palette); // On définit la nouvelle palette - Draw_all_palette_sliders(red_slider, green_slider, blue_slider, - working_palette, block_start, block_end); - memcpy(temp_palette, working_palette, sizeof(T_Palette)); - Palette_edit_step(); // Disable Undo - End_of_modification(); - need_to_remap = 1; - } - break; - - case 12: // Undo - Palette_edit_undo_redo(); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Set_palette(working_palette); - - need_to_remap=1; - break; - - 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 - Palette_edit_step(); - if (used_colors==-1) - Update_color_count(&used_colors,color_usage); - for (i=0; i<256; i++) - { - if (!color_usage[i]) - { - temp_color=block_start+(i % (block_end+1-block_start)); - working_palette[i].R=backup_palette[temp_color].R; - working_palette[i].G=backup_palette[temp_color].G; - working_palette[i].B=backup_palette[temp_color].B; - } - } - - if ((Config.Safety_colors) && (used_colors<4) && (block_end==block_start)) - { - memcpy(temp_palette,Main_palette,sizeof(T_Palette)); - memcpy(Main_palette,working_palette,sizeof(T_Palette)); - Set_nice_menu_colors(color_usage,0); - memcpy(working_palette,Main_palette,sizeof(T_Palette)); - memcpy(Main_palette,temp_palette,sizeof(T_Palette)); - } - - Set_palette(working_palette); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - - need_to_remap=1; - break; - - case 17 : // [+] - if (!Palette_view_is_RGB) - break; - Hide_cursor(); - Palette_edit_alter_channel(); - if (block_start==block_end) - { - if (red_slider->Position) - { - (red_slider->Position)--; - Window_draw_slider(red_slider); - 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,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,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 - { - if (red_slider->Position) - { - (red_slider->Position)--; - Window_draw_slider(red_slider); - } - if (green_slider->Position) - { - (green_slider->Position)--; - Window_draw_slider(green_slider); - } - if (blue_slider->Position) - { - (blue_slider->Position)--; - Window_draw_slider(blue_slider); - } - - for (i=block_start; i<=block_end; i++) - { - Set_red(i,temp_palette[i].R+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 -- - if (red_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-red_slider->Position),str,4); - str[0]='-'; - } - else if (red_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); - - - // -- green -- - if (green_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-green_slider->Position),str,4); - str[0]='-'; - } - else if (green_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); - - - // -- blue -- - if (blue_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-blue_slider->Position),str,4); - str[0]='-'; - } - else if (blue_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - - case 18 : // [-] - if (!Palette_view_is_RGB) - break; - Hide_cursor(); - Palette_edit_alter_channel(); - if (block_start==block_end) - { - if (red_slider->PositionPosition)++; - Window_draw_slider(red_slider); - 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,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,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 - { - if (red_slider->Position<(Color_max*2)) - { - (red_slider->Position)++; - Window_draw_slider(red_slider); - } - if (green_slider->Position<(Color_max*2)) - { - (green_slider->Position)++; - Window_draw_slider(green_slider); - } - if (blue_slider->Position<(Color_max*2)) - { - (blue_slider->Position)++; - Window_draw_slider(blue_slider); - } - - for (i=block_start; i<=block_end; i++) - { - Set_red(i,temp_palette[i].R+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 -- - if (red_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-red_slider->Position),str,4); - str[0]='-'; - } - else if (red_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light); - - - // -- green -- - if (green_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-green_slider->Position),str,4); - str[0]='-'; - } - else if (green_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light); - - - // -- blue -- - if (blue_slider->Position>Color_max) - { - // Jauge dans les négatifs: - Num2str(-(Color_max-blue_slider->Position),str,4); - str[0]='-'; - } - else if (blue_slider->PositionPosition ,str,4); - str[0]='+'; - } - else - { - // Jauge nulle: - strcpy(str,"± 0"); - } - Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light); - } - - need_to_remap=1; - - Display_cursor(); - Set_palette(working_palette); - break; - - case 19 : // Negative - // Backup - Palette_edit_step(); - // Negative - for (i=block_start;i<=block_end;i++) - { - Set_red(i,255-working_palette[i].R,working_palette); - Set_green (i,255-working_palette[i].G,working_palette); - Set_blue (i,255-working_palette[i].B,working_palette); - } - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Set_palette(working_palette); - // On prépare la "modifiabilité" des nouvelles couleurs - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - - need_to_remap=1; - break; - - case 20 : // Inversion - case 21 : // X-Inversion - // Backup - Palette_edit_step(); // Not undoable if X-Invert - // On initialise la table de conversion - for (i=0; i<=255; i++) - conversion_table[i]=i; - // Inversion - for (i=block_start; i < block_start + (block_end-block_start+1)/2;i++) - { - temp_color=block_end-(i-block_start); - - Set_red (i,backup_palette[temp_color].R,working_palette); - Set_green (i,backup_palette[temp_color].G,working_palette); - Set_blue (i,backup_palette[temp_color].B,working_palette); - Set_red (temp_color,backup_palette[i].R,working_palette); - Set_green (temp_color,backup_palette[i].G,working_palette); - Set_blue (temp_color,backup_palette[i].B,working_palette); - - if (clicked_button==21) - { - conversion_table[i]=temp_color; - conversion_table[temp_color]=i; - - temp=color_usage[i]; - color_usage[i]=color_usage[temp_color]; - color_usage[temp_color]=temp; - } - } - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - // Si on est en X-Invert, on remap l'image (=> on fait aussi 1 backup) - if (clicked_button==21) - { - if (!image_is_backed_up) - { - Backup_layers(-1); - image_is_backed_up=1; - } - Hide_cursor(); - Remap_image_highlevel(conversion_table); - Display_cursor(); - End_of_modification(); - Palette_edit_step(); // Disable Undo - } - // 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 22 : // HSL <> RGB - - // Acte les changements en cours sur une ou plusieurs couleurs - Palette_edit_select_range(); - - Hide_cursor(); - - Palette_view_is_RGB = !Palette_view_is_RGB; - if(! Palette_view_is_RGB) - { - // On passe en HSL - Print_RGB_or_HSL(1); - Component_unit(256); - - // Display the + and - button as disabled - 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_RGB_or_HSL(0); - Component_unit(RGB_scale); - - // Display the + and - button as enabled - 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); - - 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 - { - byte h = 0, l = 0, s=0; - byte oh=0,ol=0,os=0; // Valeur pour la couleur précédente - int swap=1; - byte remap_table[256]; - byte inverted_table[256]; - byte begin, end; - long lightness; - long old_lightness; - - - if(block_start==block_end) - { - begin = 0; - end = 255; - } - else - { - begin = block_start; - end = block_end; - } - - // Init remap table - for (i=0;i<256;i++) - remap_table[i]=i; - // Make a backup because remapping is an undoable modification - if (!image_is_backed_up) - { - Backup_layers(-1); - image_is_backed_up=1; - } - - if(Window_attribute2==0) - // Sort by Hue (H) and Lightness (L) - while(swap==1) - { - swap=0; - h=0;l=255;s=0; - for(temp_color=begin;temp_color<=end;temp_color++) - { - oh=h; ol=l; os=s; - RGB_to_HSL(working_palette[temp_color].R, - working_palette[temp_color].G, - working_palette[temp_color].B,&h,&s,&l); - - if( - ((s==0) && (os>0)) // A grey is before a saturated color - || ((s>0 && os > 0) && (hol))) // 2 saturated colors: sort by H, then by L - || ((os==0 && s==0) && l>ol)) // Two greys: sort by L only - { - // Swap color with the previous one - SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) - SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) - SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) - - SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) - - SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) - - swap=1; - } - } - } - - else // Sort only on perceived lightness - while(swap==1) - { - swap=0; - lightness=Perceptual_lightness(working_palette+begin); - for(temp_color=begin+1;temp_color<=end;temp_color++) - { - old_lightness=lightness; - lightness=Perceptual_lightness(working_palette+temp_color); - - if(lightness>old_lightness) - { - // Swap color with the previous one - SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R) - SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G) - SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B) - - SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1]) - - SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1]) - - swap=1; - } - } - } - - for (i=0;i<256;i++) - inverted_table[remap_table[i]]=i; - Remap_image_highlevel(inverted_table); - // Maintenant, tous ces calculs doivent êtres pris en compte dans la - // palette, l'image et à l'écran. - Set_palette(working_palette); - Palette_edit_step(); // Disable Undo - - End_of_modification(); - 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 - Palette_edit_step(); - // 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); - - Palette_edit_select_range(); - - } - Display_cursor(); - Input_sticky_control=0; - Wait_end_of_click(); - break; - } - } - - - if (!Mouse_K) - { - if (Key) - { - if (Is_shortcut(Key,SPECIAL_PREVIOUS_FORECOLOR)) // Décaler Forecolor vers la gauche - { - if (block_start==block_end) - { - Fore_color--; - first_color--; - last_color--; - block_start--; - block_end--; - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Hide_cursor(); - Tag_color_range(block_start,block_end); - // Affichage du n° de la couleur sélectionnée - Num2str(Fore_color,str,3); - Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // 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); - Display_cursor(); - } - Key=0; - } - else if (Is_shortcut(Key,SPECIAL_NEXT_FORECOLOR)) // Décaler Forecolor vers la droite - { - if (block_start==block_end) - { - Fore_color++; - first_color++; - last_color++; - block_start++; - block_end++; - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Hide_cursor(); - Tag_color_range(block_start,block_end); - // Affichage du n° de la couleur sélectionnée - Num2str(Fore_color,str,3); - Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - // 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); - Display_cursor(); - } - Key=0; - } - else if (Is_shortcut(Key,SPECIAL_PREVIOUS_BACKCOLOR)) - { - Back_color--; - Hide_cursor(); - 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; - } - else if (Is_shortcut(Key,SPECIAL_NEXT_BACKCOLOR)) - { - Back_color++; - Hide_cursor(); - 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; - } - else if (Key == SDLK_BACKSPACE) - // Remise des couleurs du menu à l'état normal en essayant - // de ne pas trop modifier l'image. - { - if (!image_is_backed_up) - { - Backup_layers(-1); - image_is_backed_up=1; - } - if (used_colors==-1) - Update_color_count(&used_colors, color_usage); - - Palette_edit_step(); - memcpy(temp_palette,Main_palette,sizeof(T_Palette)); - memcpy(Main_palette,working_palette,sizeof(T_Palette)); - Set_nice_menu_colors(color_usage,0); - memcpy(working_palette,Main_palette,sizeof(T_Palette)); - memcpy(Main_palette,temp_palette,sizeof(T_Palette)); - Set_palette(working_palette); - memcpy(temp_palette,working_palette,sizeof(T_Palette)); - Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end); - Update_color_count(&used_colors,color_usage); - // End_of_modification(); - // Not really needed, the change was in palette entries - need_to_remap=1; - Key=0; - } - else if (Is_shortcut(Key,0x100+BUTTON_COLORPICKER)) - { - // Récupération d'une couleur derrière le menu - Get_color_behind_window(&color,&click); - if (click) - { - Hide_cursor(); - if (click==RIGHT_SIDE) - { - if (Back_color!=color) - { - Back_color=color; - // 4 blocks de back_color entourant la fore_color - 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 - { - Fore_color=first_color=last_color=block_start=block_end=color; - Tag_color_range(block_start,block_end); - - // Affichage du n° de la couleur sélectionnée - 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(COLOR_X,COLOR_Y,str,MC_Black,MC_Light); - - // Affichage des jauges - Display_sliders(red_slider,green_slider,blue_slider,0,working_palette); - - // Affichage dans le block de visu de la couleur en cours - 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); - - Palette_edit_select_range(); - } - Display_cursor(); - Wait_end_of_click(); - } - Key=0; - } - else if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Key=0; - Window_help(BUTTON_PALETTE, NULL); - } - else if (Is_shortcut(Key,0x100+BUTTON_PALETTE)) - { - // 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 - Palette_edit_step(); - - 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) - { - Hide_cursor(); - Compute_optimal_menu_colors(working_palette); - - // On remappe brutalement - Remap_screen_after_menu_colors_change(); - // Puis on remet les trucs qui ne devaient pas changer - Window_draw_palette_bouton(5,79); - 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); - - Display_cursor(); - need_to_remap=0; - } - } - } - while ((clicked_button!=13) && (clicked_button!=14)); - - if (clicked_button==14) // Sortie par OK - { - if ( (!image_is_backed_up) - && memcmp(Main_palette,working_palette,sizeof(T_Palette)) ) - Backup_layers(-1); - memcpy(Main_palette,working_palette,sizeof(T_Palette)); - End_of_modification(); - // Not really needed, the change was in palette entries - } - - Compute_optimal_menu_colors(Main_palette); - - // La variable employée ici n'a pas vraiment de rapport avec son nom... - need_to_remap=(Window_pos_Y+(Window_height*Menu_factor_Y)Position = rgb_scale_slider->Position>128?rgb_scale_slider->Position*2-256:0; - Num2str(256-rgb_scale_slider->Position,str,3); - Print_in_window(157,78,str,MC_Black,MC_Light); - Window_draw_slider(rgb_scale_slider); - break; - - case 10: - // /2 RGB scale - rgb_scale_slider->Position = rgb_scale_slider->Position>253?254:(rgb_scale_slider->Position)/2+128; - Num2str(256-rgb_scale_slider->Position,str,3); - Print_in_window(157,78,str,MC_Black,MC_Light); - Window_draw_slider(rgb_scale_slider); - } - } - while (clicked_button!=1 && clicked_button!=2 && clicked_button!=3 && clicked_button!=4); - - // We need to get the sliders positions before closing the window, because they will be freed. - palette_cols=256-columns_slider->Position; - palette_lines=16-lines_slider->Position; - rgb_scale=256-rgb_scale_slider->Position; - - Close_window(); - Unselect_button(BUTTON_PALETTE); - Display_cursor(); - - if (clicked_button==4) // Cancel - return; - - if (palette_vertical != Config.Palette_vertical) - { - Config.Palette_vertical=palette_vertical; - palette_needs_redraw=1; - } - if (palette_cols!=Config.Palette_cells_X || - palette_lines!=Config.Palette_cells_Y) - { - Config.Palette_cells_X = palette_cols; - Config.Palette_cells_Y = palette_lines; - palette_needs_redraw=1; - } - if (rgb_scale!=RGB_scale) - { - Set_palette_RGB_scale(rgb_scale); - Set_palette(Main_palette); - Compute_optimal_menu_colors(Main_palette); - } - - if (clicked_button==1) - { - Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU); - } - else if (clicked_button==2) - { - // Open the menu with Shade settings. Same as the shortcut, except - // that this will not activate shade mode on exit. - Shade_settings_menu(); - } - - if (palette_needs_redraw) - { - Change_palette_cells(); - Display_menu(); - Display_sprite_in_menu(BUTTON_PAL_LEFT,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/project/jni/application/grafx2/grafx2/src/palette.h b/project/jni/application/grafx2/grafx2/src/palette.h deleted file mode 100644 index 5b68e1d42..000000000 --- a/project/jni/application/grafx2/grafx2/src/palette.h +++ /dev/null @@ -1,60 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -////////////////////////////////////////////////////////////////////////////// -///@file palette.h -/// Palette screen, and some palette-related high-level functions. -////////////////////////////////////////////////////////////////////////////// - -/// Open the palette menu and handles everything inside it. -void Button_Palette(void); -/// Open the secondary palette menu and handles it. -void Button_Secondary_palette(void); - -/// Choose the number of graduations for RGB components, from 2 to 256. -void Set_palette_RGB_scale(int); - -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. -byte Round_palette_component(byte comp); - -/*! - Adds 4 menu colors in the current palette. - @param color_usage An up-to-date color usage table (byte[256]) (read only) - @param not_picture 0 if the caller is the palette screen, 1 if it's a preview in the file selector. -*/ -void Set_nice_menu_colors(dword * color_usage,int not_picture); - -/// 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/project/jni/application/grafx2/grafx2/src/pversion.c b/project/jni/application/grafx2/grafx2/src/pversion.c deleted file mode 100644 index b60e3b671..000000000 --- a/project/jni/application/grafx2/grafx2/src/pversion.c +++ /dev/null @@ -1,2 +0,0 @@ -char Program_version[]="2.3"; - diff --git a/project/jni/application/grafx2/grafx2/src/pxdouble.c b/project/jni/application/grafx2/grafx2/src/pxdouble.c deleted file mode 100644 index 99a63f556..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxdouble.c +++ /dev/null @@ -1,510 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxdouble.h" -#include "pxwide.h" // for Display_transparent_line_on_screen_wide() - -#define ZOOMX 2 -#define ZOOMY 2 - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -void Pixel_double (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1)* VIDEO_LINE_WIDTH + 1)=color; -} - -byte Read_pixel_double (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_double (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_double (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_double (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_double (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_double(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_double( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_double(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *dest=*(dest+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=~*dest; - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_double(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_double(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_double(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_double(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_double(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_double(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_double( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_double(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_double(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_double( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_double(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_fast_double(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - diff --git a/project/jni/application/grafx2/grafx2/src/pxdouble.h b/project/jni/application/grafx2/grafx2/src/pxdouble.h deleted file mode 100644 index 14810f86b..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxdouble.h +++ /dev/null @@ -1,50 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxdouble.h -/// Renderer for double pixels (2x2). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_double (word x,word y,byte color); - byte Read_pixel_double (word x,word y); - void Block_double (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_double (word x,word y,byte color); - void Pixel_preview_magnifier_double (word x,word y,byte color); - void Horizontal_XOR_line_double (word x_pos,word y_pos,word width); - void Vertical_XOR_line_double (word x_pos,word y_pos,word height); - void Display_brush_color_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_double (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_double (word width,word height,word image_width); - void Display_line_on_screen_double (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_double (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_double(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_double (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_double (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_double (word x_pos,word y_pos,word width,byte * line); diff --git a/project/jni/application/grafx2/grafx2/src/pxquad.c b/project/jni/application/grafx2/grafx2/src/pxquad.c deleted file mode 100644 index 476093201..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxquad.c +++ /dev/null @@ -1,545 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxquad.h" - -#define ZOOMX 4 -#define ZOOMY 4 - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -void Pixel_quad (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 3)=color; -} - -byte Read_pixel_quad (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_quad (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_quad (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la triple - memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la quadruple - memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_quad (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_quad (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_quad(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_quad( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_quad(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+3) = *(dest+3*VIDEO_LINE_WIDTH+2) = *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+3) = *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_quad(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_quad(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_quad(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_quad(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_quad(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_quad(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+3)=*(dest+3*VIDEO_LINE_WIDTH+2)=*(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+3)=*(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_quad( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_quad(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Triple the line - memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Quadruple it - memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_quad(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_quad( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_quad(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_quad(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - diff --git a/project/jni/application/grafx2/grafx2/src/pxquad.h b/project/jni/application/grafx2/grafx2/src/pxquad.h deleted file mode 100644 index 04f219501..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxquad.h +++ /dev/null @@ -1,50 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxquad.h -/// Renderer for quadruple pixels (4x4). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_quad (word x,word y,byte color); - byte Read_pixel_quad (word x,word y); - void Block_quad (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_quad (word x,word y,byte color); - void Pixel_preview_magnifier_quad (word x,word y,byte color); - void Horizontal_XOR_line_quad (word x_pos,word y_pos,word width); - void Vertical_XOR_line_quad (word x_pos,word y_pos,word height); - void Display_brush_color_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_quad (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_quad (word width,word height,word image_width); - void Display_line_on_screen_quad (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_quad (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_quad(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_quad (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_quad (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_quad (word x_pos,word y_pos,word width,byte * line); diff --git a/project/jni/application/grafx2/grafx2/src/pxsimple.c b/project/jni/application/grafx2/grafx2/src/pxsimple.c deleted file mode 100644 index 9cfaff3f7..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxsimple.c +++ /dev/null @@ -1,481 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxsimple.h" - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -void Pixel_simple (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x + y * VIDEO_LINE_WIDTH)=color; -} - -byte Read_pixel_simple (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * VIDEO_LINE_WIDTH + x ); -} - -void Block_simple (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x; - rectangle.y=start_y; - rectangle.w=width; - rectangle.h=height; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_simple (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_simple (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_simple (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_simple(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_simple( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_simple(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; - - int x; - - for (x=0;x 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH - width; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_simple(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *dest=color; - - // On passe au pixel suivant - src++; - dest++; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH-width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_simple(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_simple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH - width; - src = src + brush_width - width; - } -} - -void Remap_screen_simple(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *dest = conversion_table[*dest]; - dest ++; - } - - dest = dest + VIDEO_LINE_WIDTH - width; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_simple(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels. Utilisé pour les textes. */ -{ - memcpy(Screen_pixels+x_pos+y_pos*VIDEO_LINE_WIDTH,line,width); -} - -void Display_transparent_mono_line_on_screen_simple( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos * VIDEO_LINE_WIDTH + x_pos; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color) -{ - byte* src = line; - byte* dest = Screen_pixels + y_pos * VIDEO_LINE_WIDTH + x_pos; - - word x; - - // Pour chaque pixel de la ligne - for(x = width;x > 0;x--) - { - if(*src!=transp_color) - *dest = *src; - src++; - dest++; - } -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_simple(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_simple(x_pos,y,width*Main_magnifier_factor,buffer,transp_color); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_simple(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_simple( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_simple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_simple(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} diff --git a/project/jni/application/grafx2/grafx2/src/pxsimple.h b/project/jni/application/grafx2/grafx2/src/pxsimple.h deleted file mode 100644 index 175d1a653..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxsimple.h +++ /dev/null @@ -1,53 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxsimple.h -/// Renderer for simple pixels (1x1). This is the normal one. -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_simple (word x,word y,byte color); - byte Read_pixel_simple (word x,word y); - void Block_simple (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_simple (word x,word y,byte color); - void Pixel_preview_magnifier_simple (word x,word y,byte color); - void Horizontal_XOR_line_simple (word x_pos,word y_pos,word width); - void Vertical_XOR_line_simple (word x_pos,word y_pos,word height); - void Display_brush_color_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_simple (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_simple (word width,word height,word image_width); - void Display_line_on_screen_simple (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_simple (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_simple(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_simple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_simple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - -void Display_transparent_mono_line_on_screen_simple( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color); -void Display_transparent_line_on_screen_simple(word x_pos,word y_pos,word width,byte* line,byte transp_color); diff --git a/project/jni/application/grafx2/grafx2/src/pxtall.c b/project/jni/application/grafx2/grafx2/src/pxtall.c deleted file mode 100644 index b62a39865..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxtall.c +++ /dev/null @@ -1,466 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxtall.h" -#include "pxsimple.h" - -#define ZOOMX 1 -#define ZOOMY 2 - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -void Pixel_tall (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x + y*ZOOMY*VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x + (y*ZOOMY+1)*VIDEO_LINE_WIDTH)=color; -} - -byte Read_pixel_tall (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x ); -} - -void Block_tall (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x; - rectangle.y=start_y*ZOOMY; - rectangle.w=width; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_tall (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - dest+=VIDEO_LINE_WIDTH; - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_tall (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_tall (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_tall(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_tall( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_tall(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; - - int x; - - for (x=0;x 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - *(dest+VIDEO_LINE_WIDTH) = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + ZOOMY*VIDEO_LINE_WIDTH - width; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_tall(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos+Screen_pixels; // dest = adr Destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - { - *dest=color; - *(dest+VIDEO_LINE_WIDTH)=color; - } - - // On passe au pixel suivant - src++; - dest++; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=ZOOMY*VIDEO_LINE_WIDTH-width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_tall(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - memcpy(dest,src,width); - dest+=VIDEO_LINE_WIDTH; - memcpy(dest,src,width); - - // On passe à la ligne suivante - src+=image_width; - dest+=VIDEO_LINE_WIDTH; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_tall(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *dest = *src; - *(dest+VIDEO_LINE_WIDTH) = *src; - } - - // Pixel suivant - src++; dest++; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width; - src = src + brush_width - width; - } -} - -void Remap_screen_tall(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos*ZOOMY*VIDEO_LINE_WIDTH + x_pos; - int x,y; - - // Pour chaque ligne - for(y=height*ZOOMY;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *dest = conversion_table[*dest]; - dest ++; - } - - dest = dest + VIDEO_LINE_WIDTH - width; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_tall(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels. Utilisé pour les textes. */ -{ - memcpy(Screen_pixels+x_pos+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width); - memcpy(Screen_pixels+x_pos+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width); -} - -void Read_line_screen_tall(word x_pos,word y_pos,word width,byte * line) -{ - memcpy(line,VIDEO_LINE_WIDTH*ZOOMY*y_pos + x_pos + Screen_pixels,width); -} - -void Display_part_of_screen_scaled_tall( - word width, // width non zoomée - word height, // height zoomée - word image_width,byte * buffer) -{ - byte* src = Main_screen + Main_magnifier_offset_Y * image_width - + Main_magnifier_offset_X; - int y = 0; // Ligne en cours de traitement - - // Pour chaque ligne à zoomer - while(1) - { - int x; - - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On l'affiche Facteur fois, sur des lignes consécutives - x = Main_magnifier_factor*ZOOMY; - // Pour chaque ligne - do{ - // On affiche la ligne zoomée - Display_line_on_screen_simple( - Main_X_zoom, y, width*Main_magnifier_factor, - buffer - ); - // On passe à la suivante - y++; - if(y==height*ZOOMY) - { - Redraw_grid(Main_X_zoom,0, - width*Main_magnifier_factor,height); - Update_rect(Main_X_zoom,0, - width*Main_magnifier_factor,height); - return; - } - x--; - }while (x > 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_tall(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_simple(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); - memcpy(Screen_pixels + (y*ZOOMY +1) * VIDEO_LINE_WIDTH + x_pos, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos, width*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_tall(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_simple( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_tall(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_tall(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} diff --git a/project/jni/application/grafx2/grafx2/src/pxtall.h b/project/jni/application/grafx2/grafx2/src/pxtall.h deleted file mode 100644 index 424ec7747..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxtall.h +++ /dev/null @@ -1,48 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxtall.h -/// Renderer for tall pixels (1x2). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_tall (word x,word y,byte color); - byte Read_pixel_tall (word x,word y); - void Block_tall (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_tall (word x,word y,byte color); - void Pixel_preview_magnifier_tall (word x,word y,byte color); - void Horizontal_XOR_line_tall (word x_pos,word y_pos,word width); - void Vertical_XOR_line_tall (word x_pos,word y_pos,word height); - void Display_brush_color_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_tall (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_tall (word width,word height,word image_width); - void Display_line_on_screen_tall (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_tall (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_tall(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_tall (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_tall (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); diff --git a/project/jni/application/grafx2/grafx2/src/pxtall2.c b/project/jni/application/grafx2/grafx2/src/pxtall2.c deleted file mode 100644 index 1e45b972b..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxtall2.c +++ /dev/null @@ -1,537 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxtall2.h" - -#define ZOOMX 2 -#define ZOOMY 4 - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -void Pixel_tall2 (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+3) * VIDEO_LINE_WIDTH + 1)=color; -} - -byte Read_pixel_tall2 (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_tall2 (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_tall2 (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la triple - memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la quadruple - memcpy(dest-width*ZOOMX+3*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_tall2 (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_tall2 (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_tall2(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_tall2( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_tall2(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=~*(dest); - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+1) = *(dest+3*VIDEO_LINE_WIDTH) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_tall2(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_tall2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_tall2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_tall2(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_tall2(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+3)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_tall2(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+3*VIDEO_LINE_WIDTH+1)=*(dest+3*VIDEO_LINE_WIDTH)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+1)=*(dest)=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_tall2( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_tall2(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Triple the line - memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Quadruple it - memcpy(Screen_pixels + (y*ZOOMY+3)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_tall2(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_tall2( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_tall2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_tall2(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - diff --git a/project/jni/application/grafx2/grafx2/src/pxtall2.h b/project/jni/application/grafx2/grafx2/src/pxtall2.h deleted file mode 100644 index 478edf9f5..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxtall2.h +++ /dev/null @@ -1,50 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxtall2.h -/// Renderer for double-tall pixels (2x4). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_tall2 (word x,word y,byte color); - byte Read_pixel_tall2 (word x,word y); - void Block_tall2 (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_tall2 (word x,word y,byte color); - void Pixel_preview_magnifier_tall2 (word x,word y,byte color); - void Horizontal_XOR_line_tall2 (word x_pos,word y_pos,word width); - void Vertical_XOR_line_tall2 (word x_pos,word y_pos,word height); - void Display_brush_color_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_tall2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_tall2 (word width,word height,word image_width); - void Display_line_on_screen_tall2 (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_tall2 (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_tall2(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_tall2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_tall2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_tall2 (word x_pos,word y_pos,word width,byte * line); diff --git a/project/jni/application/grafx2/grafx2/src/pxtriple.c b/project/jni/application/grafx2/grafx2/src/pxtriple.c deleted file mode 100644 index 39fb7189e..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxtriple.c +++ /dev/null @@ -1,533 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxtriple.h" - -#define ZOOMX 3 -#define ZOOMY 3 - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -void Pixel_triple (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+2) * VIDEO_LINE_WIDTH + 2)=color; -} - -byte Read_pixel_triple (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_triple (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_triple (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+2)=*(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - // On la triple - memcpy(dest-width*ZOOMX+2*VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_triple (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_triple (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_triple(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_triple( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_triple(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=~*dest; - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+2*VIDEO_LINE_WIDTH+2) = *(dest+2*VIDEO_LINE_WIDTH+1) = *(dest+2*VIDEO_LINE_WIDTH) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+2) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_triple(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_triple(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_triple(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_triple(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_triple(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+2)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_triple(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+2*VIDEO_LINE_WIDTH+2)=*(dest+2*VIDEO_LINE_WIDTH+1)=*(dest+2*VIDEO_LINE_WIDTH)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+2)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_triple( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_triple(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+2)=*(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - // Triple the line - memcpy(Screen_pixels + (y*ZOOMY+2)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_triple(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_triple( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_triple(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_triple(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - diff --git a/project/jni/application/grafx2/grafx2/src/pxtriple.h b/project/jni/application/grafx2/grafx2/src/pxtriple.h deleted file mode 100644 index 29719cdd6..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxtriple.h +++ /dev/null @@ -1,50 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxtriple.h -/// Renderer for triple pixels (3x3). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_triple (word x,word y,byte color); - byte Read_pixel_triple (word x,word y); - void Block_triple (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_triple (word x,word y,byte color); - void Pixel_preview_magnifier_triple (word x,word y,byte color); - void Horizontal_XOR_line_triple (word x_pos,word y_pos,word width); - void Vertical_XOR_line_triple (word x_pos,word y_pos,word height); - void Display_brush_color_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_triple (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_triple (word width,word height,word image_width); - void Display_line_on_screen_triple (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_triple (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_triple(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_triple (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_triple (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_triple (word x_pos,word y_pos,word width,byte * line); diff --git a/project/jni/application/grafx2/grafx2/src/pxwide.c b/project/jni/application/grafx2/grafx2/src/pxwide.c deleted file mode 100644 index e1aa80552..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxwide.c +++ /dev/null @@ -1,519 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxwide.h" - -#define ZOOMX 2 -#define ZOOMY 1 - -#ifdef __VBCC__ - #define __attribute__(x) -#endif - -void Pixel_wide (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; -} - -byte Read_pixel_wide (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_wide (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_wide (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_wide (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_wide (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_wide(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_wide( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_wide(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *dest=*(dest+1)=~*dest; - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_wide(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_wide(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_wide(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_wide(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+1) = *dest = conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_wide(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_wide(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_wide( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color) -{ - byte* src = line; - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - word x; - - // Pour chaque pixel de la ligne - for(x = width;x > 0;x--) - { - if(*src!=transp_color) - { - *(dest+1) = *dest = *src; - } - src++; - dest+=ZOOMX; - } -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_wide(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - Display_transparent_line_on_screen_wide(x_pos,y*ZOOMY,width*Main_magnifier_factor,buffer,transp_color); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_wide(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_wide( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_wide(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - Display_line_on_screen_fast_wide(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - diff --git a/project/jni/application/grafx2/grafx2/src/pxwide.h b/project/jni/application/grafx2/grafx2/src/pxwide.h deleted file mode 100644 index 7ffaf24d3..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxwide.h +++ /dev/null @@ -1,51 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxwide.h -/// Renderer for wide pixels (2x1). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_wide (word x,word y,byte color); - byte Read_pixel_wide (word x,word y); - void Block_wide (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_wide (word x,word y,byte color); - void Pixel_preview_magnifier_wide (word x,word y,byte color); - void Horizontal_XOR_line_wide (word x_pos,word y_pos,word width); - void Vertical_XOR_line_wide (word x_pos,word y_pos,word height); - void Display_brush_color_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_wide (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_wide (word width,word height,word image_width); - void Display_line_on_screen_wide (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_wide (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_wide(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_wide (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_wide (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_wide (word x_pos,word y_pos,word width,byte * line); - void Display_transparent_line_on_screen_wide(word x_pos,word y_pos,word width,byte* line,byte transp_color); diff --git a/project/jni/application/grafx2/grafx2/src/pxwide2.c b/project/jni/application/grafx2/grafx2/src/pxwide2.c deleted file mode 100644 index 0fcd81041..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxwide2.c +++ /dev/null @@ -1,527 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Franck Charlet - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include "global.h" -#include "sdlscreen.h" -#include "misc.h" -#include "graph.h" -#include "pxwide2.h" - -#define ZOOMX 4 -#define ZOOMY 2 - -#ifdef __VBCC__ - #define __attribute__(w) -#endif - -void Pixel_wide2 (word x,word y,byte color) -/* Affiche un pixel de la color aux coords x;y à l'écran */ -{ - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + y*ZOOMY * VIDEO_LINE_WIDTH + 3)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 1)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 2)=color; - *(Screen_pixels + x * ZOOMX + (y*ZOOMY+1) * VIDEO_LINE_WIDTH + 3)=color; -} - -byte Read_pixel_wide2 (word x,word y) -/* On retourne la couleur du pixel aux coords données */ -{ - return *( Screen_pixels + y * ZOOMY * VIDEO_LINE_WIDTH + x * ZOOMX); -} - -void Block_wide2 (word start_x,word start_y,word width,word height,byte color) -/* On affiche un rectangle de la couleur donnée */ -{ - SDL_Rect rectangle; - rectangle.x=start_x*ZOOMX; - rectangle.y=start_y*ZOOMY; - rectangle.w=width*ZOOMX; - rectangle.h=height*ZOOMY; - SDL_FillRect(Screen_SDL,&rectangle,color); -} - -void Display_part_of_screen_wide2 (word width,word height,word image_width) -/* Afficher une partie de l'image telle quelle sur l'écran */ -{ - byte* dest=Screen_pixels; //On va se mettre en 0,0 dans l'écran (dest) - byte* src=Main_offset_Y*image_width+Main_offset_X+Main_screen; //Coords de départ ds la source (src) - int y; - int dy; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - // On fait une copie de la ligne - for (dy=width;dy>0;dy--) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - src++; - dest+=ZOOMX; - } - // On double la ligne qu'on vient de copier - memcpy(dest-width*ZOOMX+VIDEO_LINE_WIDTH,dest-width*ZOOMX,width*ZOOMX); - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - //Update_rect(0,0,width,height); -} - -void Pixel_preview_normal_wide2 (word x,word y,byte color) -/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image - * dans l'écran, en mode normal (pas en mode loupe) - * Note: si on modifie cette procédure, il faudra penser à faire également - * la modif dans la procédure Pixel_Preview_Loupe_SDL. */ -{ -// if(x-Main_offset_X >= 0 && y - Main_offset_Y >= 0) - Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); -} - -void Pixel_preview_magnifier_wide2 (word x,word y,byte color) -{ - // Affiche le pixel dans la partie non zoomée - Pixel_wide2(x-Main_offset_X,y-Main_offset_Y,color); - - // Regarde si on doit aussi l'afficher dans la partie zoomée - if (y >= Limit_top_zoom && y <= Limit_visible_bottom_zoom - && x >= Limit_left_zoom && x <= Limit_visible_right_zoom) - { - // On est dedans - int height; - int y_zoom = Main_magnifier_factor * (y-Main_magnifier_offset_Y); - - if (Menu_Y - y_zoom < Main_magnifier_factor) - // On ne doit dessiner qu'un morceau du pixel - // sinon on dépasse sur le menu - height = Menu_Y - y_zoom; - else - height = Main_magnifier_factor; - - Block_wide2( - Main_magnifier_factor * (x-Main_magnifier_offset_X) + Main_X_zoom, - y_zoom, Main_magnifier_factor, height, color - ); - } -} - -void Horizontal_XOR_line_wide2(word x_pos,word y_pos,word width) -{ - //On calcule la valeur initiale de dest: - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; - - int x; - - for (x=0;x0;i--) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*(dest)=~*(dest); - dest+=VIDEO_LINE_WIDTH*ZOOMY; - } -} - -void Display_brush_color_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = Brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+3) = *(dest+VIDEO_LINE_WIDTH+2) = *(dest+VIDEO_LINE_WIDTH+1) = *(dest+VIDEO_LINE_WIDTH) = *(dest+3) = *(dest+2) = *(dest+1) = *dest = *src; - } - - // Pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Display_brush_mono_wide2(word x_pos, word y_pos, - word x_offset, word y_offset, word width, word height, - byte transp_color, byte color, word brush_width) -/* On affiche la brosse en monochrome */ -{ - byte* dest=y_pos*ZOOMY*VIDEO_LINE_WIDTH+x_pos*ZOOMX+Screen_pixels; // dest = adr destination à - // l'écran - byte* src=brush_width*y_offset+x_offset+Brush; // src = adr ds - // la brosse - int x,y; - - for(y=height;y!=0;y--) - //Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - if (*src!=transp_color) - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=color; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=brush_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -void Clear_brush_wide2(word x_pos,word y_pos,__attribute__((unused)) word x_offset,__attribute__((unused)) word y_offset,word width,word height,__attribute__((unused))byte transp_color,word image_width) -{ - byte* dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; //On va se mettre en 0,0 dans l'écran (dest) - byte* src = ( y_pos + Main_offset_Y ) * image_width + x_pos + Main_offset_X + Main_screen; //Coords de départ ds la source (src) - int y; - int x; - - for(y=height;y!=0;y--) - // Pour chaque ligne - { - for(x=width;x!=0;x--) - //Pour chaque pixel - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - - // On passe au pixel suivant - src++; - dest+=ZOOMX; - } - - // On passe à la ligne suivante - src+=image_width-width; - dest+=VIDEO_LINE_WIDTH*ZOOMY-width*ZOOMX; - } - Update_rect(x_pos,y_pos,width,height); -} - -// Affiche une brosse (arbitraire) à l'écran -void Display_brush_wide2(byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width) -{ - // dest = Position à l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - // src = Position dans la brosse - byte* src = brush + y_offset * brush_width + x_offset; - - word x,y; - - // Pour chaque ligne - for(y = height;y > 0; y--) - { - // Pour chaque pixel - for(x = width;x > 0; x--) - { - // On vérifie que ce n'est pas la transparence - if(*src != transp_color) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*src; - } - - // Pixel suivant - src++; dest+=ZOOMX; - } - - // On passe à la ligne suivante - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - src = src + brush_width - width; - } -} - -void Remap_screen_wide2(word x_pos,word y_pos,word width,word height,byte * conversion_table) -{ - // dest = coords a l'écran - byte* dest = Screen_pixels + y_pos * ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - int x,y; - - // Pour chaque ligne - for(y=height;y>0;y--) - { - // Pour chaque pixel - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest= - conversion_table[*dest]; - dest +=ZOOMX; - } - - dest = dest + VIDEO_LINE_WIDTH*ZOOMY - width*ZOOMX; - } - - Update_rect(x_pos,y_pos,width,height); -} - -void Display_line_on_screen_fast_wide2(word x_pos,word y_pos,word width,byte * line) -/* On affiche toute une ligne de pixels telle quelle. */ -/* Utilisée si le buffer contient déja des pixel doublés. */ -{ - memcpy(Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH,line,width*ZOOMX); - memcpy(Screen_pixels+x_pos*ZOOMX+(y_pos*ZOOMY+1)*VIDEO_LINE_WIDTH,line,width*ZOOMX); -} - -void Display_line_on_screen_wide2(word x_pos,word y_pos,word width,byte * line) -/* On affiche une ligne de pixels en les doublant. */ -{ - int x; - byte *dest; - dest=Screen_pixels+x_pos*ZOOMX+y_pos*ZOOMY*VIDEO_LINE_WIDTH; - for(x=width;x>0;x--) - { - *(dest+VIDEO_LINE_WIDTH+3)=*(dest+VIDEO_LINE_WIDTH+2)=*(dest+VIDEO_LINE_WIDTH+1)=*(dest+VIDEO_LINE_WIDTH)=*(dest+3)=*(dest+2)=*(dest+1)=*dest=*line; - dest+=ZOOMX; - line++; - } -} -void Display_transparent_mono_line_on_screen_wide2( - word x_pos, word y_pos, word width, byte* line, - byte transp_color, byte color) -// Affiche une ligne à l'écran avec une couleur + transparence. -// Utilisé par les brosses en mode zoom -{ - byte* dest = Screen_pixels+ y_pos*VIDEO_LINE_WIDTH + x_pos*ZOOMX; - int x; - // Pour chaque pixel - for(x=0;x 0); - src += image_width; - } -// ATTENTION on n'arrive jamais ici ! -} - -// Affiche une partie de la brosse couleur zoomée -void Display_brush_color_zoom_wide2(word x_pos,word y_pos, - word x_offset,word y_offset, - word width, // width non zoomée - word end_y_pos,byte transp_color, - word brush_width, // width réelle de la brosse - byte * buffer) -{ - byte* src = Brush+y_offset*brush_width + x_offset; - word y = y_pos; - byte bx; - - // Pour chaque ligne - while(1) - { - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - // On affiche facteur fois la ligne zoomée - for(bx=Main_magnifier_factor;bx>0;bx--) - { - byte* line_src = buffer; - byte* dest = Screen_pixels + y*ZOOMY * VIDEO_LINE_WIDTH + x_pos * ZOOMX; - word x; - // Pour chaque pixel de la ligne - for(x = width*Main_magnifier_factor;x > 0;x--) - { - if(*line_src!=transp_color) - { - *(dest+3)=*(dest+2)=*(dest+1)=*dest = *line_src; - } - line_src++; - dest+=ZOOMX; - } - // Double the line - memcpy(Screen_pixels + (y*ZOOMY+1)*VIDEO_LINE_WIDTH + x_pos*ZOOMX, Screen_pixels + y*ZOOMY*VIDEO_LINE_WIDTH + x_pos*ZOOMX, width*ZOOMX*Main_magnifier_factor); - y++; - if(y==end_y_pos) - { - return; - } - } - src += brush_width; - } - // ATTENTION zone jamais atteinte -} - -void Display_brush_mono_zoom_wide2(word x_pos, word y_pos, - word x_offset, word y_offset, - word width, // width non zoomée - word end_y_pos, - byte transp_color, byte color, - word brush_width, // width réelle de la brosse - byte * buffer -) - -{ - byte* src = Brush + y_offset * brush_width + x_offset; - int y=y_pos*ZOOMY; - - //Pour chaque ligne à zoomer : - while(1) - { - int bx; - // src = Ligne originale - // On éclate la ligne - Zoom_a_line(src,buffer,Main_magnifier_factor,width); - - // On affiche la ligne Facteur fois à l'écran (sur des - // lignes consécutives) - bx = Main_magnifier_factor*ZOOMY; - - // Pour chaque ligne écran - do - { - // On affiche la ligne zoomée - Display_transparent_mono_line_on_screen_wide2( - x_pos, y, width * Main_magnifier_factor, - buffer, transp_color, color - ); - // On passe à la ligne suivante - y++; - // On vérifie qu'on est pas à la ligne finale - if(y == end_y_pos*ZOOMY) - { - Redraw_grid( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - Update_rect( x_pos, y_pos, - width * Main_magnifier_factor, end_y_pos - y_pos ); - return; - } - bx --; - } - while (bx > 0); - - // Passage à la ligne suivante dans la brosse aussi - src+=brush_width; - } -} - -void Clear_brush_scaled_wide2(word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,__attribute__((unused)) byte transp_color,word image_width,byte * buffer) -{ - - // En fait on va recopier l'image non zoomée dans la partie zoomée ! - byte* src = Main_screen + y_offset * image_width + x_offset; - int y = y_pos; - int bx; - - // Pour chaque ligne à zoomer - while(1){ - Zoom_a_line(src,buffer,Main_magnifier_factor*ZOOMX,width); - - bx=Main_magnifier_factor; - - // Pour chaque ligne - do{ - // TODO a verifier - Display_line_on_screen_fast_wide2(x_pos,y, - width * Main_magnifier_factor,buffer); - - // Ligne suivante - y++; - if(y==end_y_pos) - { - Redraw_grid(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - Update_rect(x_pos,y_pos, - width*Main_magnifier_factor,end_y_pos-y_pos); - return; - } - bx--; - }while(bx!=0); - - src+= image_width; - } -} - - diff --git a/project/jni/application/grafx2/grafx2/src/pxwide2.h b/project/jni/application/grafx2/grafx2/src/pxwide2.h deleted file mode 100644 index d6409e971..000000000 --- a/project/jni/application/grafx2/grafx2/src/pxwide2.h +++ /dev/null @@ -1,50 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file pxwide2.h -/// Renderer for double-wide pixels (4x2). -////////////////////////////////////////////////////////////////////////////// - -#include "struct.h" - - void Pixel_wide2 (word x,word y,byte color); - byte Read_pixel_wide2 (word x,word y); - void Block_wide2 (word start_x,word start_y,word width,word height,byte color); - void Pixel_preview_normal_wide2 (word x,word y,byte color); - void Pixel_preview_magnifier_wide2 (word x,word y,byte color); - void Horizontal_XOR_line_wide2 (word x_pos,word y_pos,word width); - void Vertical_XOR_line_wide2 (word x_pos,word y_pos,word height); - void Display_brush_color_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - void Display_brush_mono_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,byte color,word brush_width); - void Clear_brush_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word image_width); - void Remap_screen_wide2 (word x_pos,word y_pos,word width,word height,byte * conversion_table); - void Display_part_of_screen_wide2 (word width,word height,word image_width); - void Display_line_on_screen_wide2 (word x_pos,word y_pos,word width,byte * line); - void Read_line_screen_wide2 (word x_pos,word y_pos,word width,byte * line); - void Display_part_of_screen_scaled_wide2(word width,word height,word image_width,byte * buffer); - void Display_brush_color_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word brush_width,byte * buffer); - void Display_brush_mono_zoom_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,byte color,word brush_width,byte * buffer); - void Clear_brush_scaled_wide2 (word x_pos,word y_pos,word x_offset,word y_offset,word width,word end_y_pos,byte transp_color,word image_width,byte * buffer); - void Display_brush_wide2 (byte * brush, word x_pos,word y_pos,word x_offset,word y_offset,word width,word height,byte transp_color,word brush_width); - - void Display_line_on_screen_fast_wide2 (word x_pos,word y_pos,word width,byte * line); diff --git a/project/jni/application/grafx2/grafx2/src/readini.c b/project/jni/application/grafx2/grafx2/src/readini.c deleted file mode 100644 index 21827b6cf..000000000 --- a/project/jni/application/grafx2/grafx2/src/readini.c +++ /dev/null @@ -1,980 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#define _XOPEN_SOURCE 500 - -#include -#include -#include -#include - -#include "const.h" -#include "errors.h" -#include "global.h" -#include "misc.h" -#include "readini.h" -#include "setup.h" -#include "realpath.h" -#include "io.h" - -void Load_INI_clear_string(char * str, byte keep_comments) -{ - int index; - int equal_found=0; - - for (index=0;str[index]!='\0';) - { - if ((str[index]=='=')) - { - equal_found=1; - index++; - // On enleve les espaces après le '=' - while (str[index]==' ' || str[index]=='\t') - memmove(str+index,str+index+1,strlen(str+index)); - } - else if ((str[index]==' ' && !equal_found) || (str[index]=='\t')) - { - // Suppression d'un espace ou d'un tab: - memmove(str+index,str+index+1,strlen(str+index)); - } - else - if (!keep_comments && ((str[index]==';') || (str[index]=='#'))) - { - // Comment - str[index]='\0'; - } - else if ((str[index]=='\r') || (str[index]=='\n')) - { - // Line break - str[index]='\0'; - } - else - { - if (!equal_found) - { - // Passage en majuscule d'un caractère: - - str[index]=toupper((int)str[index]); - } - index++; - } - } - // On enlève les espaces avant la fin de chaine - while (index>0 && (str[index-1]==' ' || str[index-1]=='\t')) - { - index--; - str[index]='\0'; - } -} - - - -int Load_INI_seek_pattern(char * buffer,char * pattern) -{ - int buffer_index; - int pattern_index; - - // A partir de chaque lettre de la chaîne buffer - for (buffer_index=0;buffer[buffer_index]!='\0';buffer_index++) - { - // On regarde si la chaîne pattern est équivalente à la position courante - // de la chaîne buffer: - for (pattern_index=0;(pattern[pattern_index]!='\0') && (buffer[buffer_index+pattern_index]==pattern[pattern_index]);pattern_index++); - - // Si on a trouvé la chaîne pattern dans la chaîne buffer, on renvoie la - // position à laquelle on l'a trouvée (+1 pour que si on la trouve au - // début ça ne renvoie pas la même chose que si on ne l'avait pas - // trouvée): - if (pattern[pattern_index]=='\0') - return (buffer_index+1); - } - - // Si on ne l'a pas trouvée, on renvoie 0: - return 0; -} - - - -int Load_INI_reach_group(FILE * file,char * buffer,char * group) -{ - int stop_seek; - char * group_upper; - char * upper_buffer; - - // On alloue les zones de mémoire: - group_upper=(char *)malloc(1024); - upper_buffer=(char *)malloc(1024); - - // On commence par se faire une version majuscule du groupe à rechercher: - strcpy(group_upper,group); - Load_INI_clear_string(group_upper, 0); - - stop_seek=0; - do - { - // On lit une ligne dans le fichier: - if (fgets(buffer,1024,file)==0) - { - free(upper_buffer); - free(group_upper); - return ERROR_INI_CORRUPTED; - } - - Line_number_in_INI_file++; - - // On s'en fait une version en majuscule: - strcpy(upper_buffer,buffer); - Load_INI_clear_string(upper_buffer, 0); - - // On compare la chaîne avec le groupe recherché: - stop_seek=Load_INI_seek_pattern(upper_buffer,group_upper); - } - while (!stop_seek); - - free(upper_buffer); - free(group_upper); - - return 0; -} - -/// -/// Find the next string in the .INI file. -/// @param file INI file currently opened -/// @param buffer Current text buffer, preserved from one call to the next -/// @param option_name string to search -/// @param return_code the found value will be copied there. (must be allocaed) -/// @param raw_text Boolean: true to return the raw value (up to end-of-line), false to strip comments. -int Load_INI_get_string(FILE * file,char * buffer,char * option_name,char * return_code, byte raw_text) -{ - int stop_seek; - char * option_upper; - char * upper_buffer; - int buffer_index; - - // On alloue les zones de mémoire: - option_upper=(char *)malloc(1024); - upper_buffer=(char *)malloc(1024); - - // On commence par se faire une version majuscule de l'option à rechercher: - strcpy(option_upper,option_name); - Load_INI_clear_string(option_upper, 0); - - stop_seek=0; - do - { - // On lit une ligne dans le fichier: - if (fgets(buffer,1024,file)==NULL) - { - free(upper_buffer); - free(option_upper); - return ERROR_INI_CORRUPTED; - } - - Line_number_in_INI_file++; - - // On s'en fait une version en majuscule: - strcpy(upper_buffer,buffer); - Load_INI_clear_string(upper_buffer, raw_text); - - // On compare la chaîne avec l'option recherchée: - stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); - - // Si on l'a trouvée: - if (stop_seek) - { - // On se positionne juste après la chaîne "=" - buffer_index=Load_INI_seek_pattern(upper_buffer,"="); - - strcpy(return_code, upper_buffer + buffer_index); - } - } - while (!stop_seek); - - free(upper_buffer); - free(option_upper); - - return 0; -} - -int Load_INI_get_value(char * str,int * index,int * value) -{ - int negative = 0; - - // On teste si la valeur actuelle est YES (ou Y): - - if (Load_INI_seek_pattern(str+(*index),"yes,")==1) - { - (*value)=1; - (*index)+=4; - return 0; - } - if (strcmp(str+(*index),"yes")==0) - { - (*value)=1; - (*index)+=3; - return 0; - } - if (Load_INI_seek_pattern(str+(*index),"y,")==1) - { - (*value)=1; - (*index)+=2; - return 0; - } - if (strcmp(str+(*index),"y")==0) - { - (*value)=1; - (*index)+=1; - return 0; - } - - // On teste si la valeur actuelle est NO (ou N): - - if (Load_INI_seek_pattern(str+(*index),"no,")==1) - { - (*value)=0; - (*index)+=3; - return 0; - } - if (strcmp(str+(*index),"no")==0) - { - (*value)=0; - (*index)+=2; - return 0; - } - if (Load_INI_seek_pattern(str+(*index),"n,")==1) - { - (*value)=0; - (*index)+=2; - return 0; - } - if (strcmp(str+(*index),"n")==0) - { - (*value)=0; - (*index)+=1; - return 0; - } - if (str[*index]=='$') - { - (*value)=0; - - for (;;) - { - (*index)++; - - if ((str[*index]>='0') && (str[*index]<='9')) - (*value)=((*value)*16)+str[*index]-'0'; - else - if ((str[*index]>='A') && (str[*index]<='F')) - (*value)=((*value)*16)+str[*index]-'A'+10; - else - if (str[*index]==',') - { - (*index)++; - return 0; - } - else - if (str[*index]=='\0') - return 0; - else - return ERROR_INI_CORRUPTED; - } - } - if (str[*index]=='-') - { - negative = 1; - // next character - (*index)++; - // Fall thru - } - if ((str[*index]>='0') && (str[*index]<='9')) - { - (*value)=0; - - for (;;) - { - if ((str[*index]>='0') && (str[*index]<='9')) - { - (*value)=((*value)*10)+str[*index]-'0'; - if (negative) - { - (*value)*= -1; - // This is to do it once per number. - negative = 0; - } - } - else - if (str[*index]==',') - { - (*index)++; - return 0; - } - else - if (str[*index]=='\0') - return 0; - else - return ERROR_INI_CORRUPTED; - - (*index)++; - } - } - else - return ERROR_INI_CORRUPTED; -} - - - -int Load_INI_get_values(FILE * file,char * buffer,char * option_name,int nb_expected_values,int * values) -{ - int stop_seek; - char * option_upper; - char * upper_buffer; - int buffer_index; - int nb_values; - - // On alloue les zones de mémoire: - option_upper=(char *)malloc(1024); - upper_buffer=(char *)malloc(1024); - - // On commence par se faire une version majuscule de l'option à rechercher: - strcpy(option_upper,option_name); - Load_INI_clear_string(option_upper, 0); - - stop_seek=0; - do - { - // On lit une ligne dans le fichier: - if (fgets(buffer,1024,file)==0) - { - free(upper_buffer); - free(option_upper); - return ERROR_INI_CORRUPTED; - } - - Line_number_in_INI_file++; - - // On s'en fait une version en majuscule: - strcpy(upper_buffer,buffer); - Load_INI_clear_string(upper_buffer, 0); - - // On compare la chaîne avec l'option recherchée: - stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); - - // Si on l'a trouvée: - if (stop_seek) - { - nb_values=0; - - // On se positionne juste après la chaîne "=" - buffer_index=Load_INI_seek_pattern(upper_buffer,"="); - - // Tant qu'on a pas atteint la fin de la ligne - while (upper_buffer[buffer_index]!='\0') - { - if (Load_INI_get_value(upper_buffer,&buffer_index,values+nb_values)) - { - free(upper_buffer); - free(option_upper); - return ERROR_INI_CORRUPTED; - } - - if ( ((++nb_values) == nb_expected_values) && - (upper_buffer[buffer_index]!='\0') ) - { - // Too many values ! - free(upper_buffer); - free(option_upper); - return ERROR_INI_CORRUPTED; - } - } - - if (nb_valuesStylus_mode = 1; -#else - conf->Stylus_mode = 0; -#endif - - - // On alloue les zones de mémoire: - buffer=(char *)malloc(1024); - filename=(char *)malloc(256); - - // On calcule le nom du fichier qu'on manipule: - strcpy(filename,Config_directory); - 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,INIDEF_FILENAME); - file=fopen(filename,"r"); - if (file == 0) - { - free(filename); - free(buffer); - return ERROR_INI_MISSING; - } - } - - if ((return_code=Load_INI_reach_group(file,buffer,"[MOUSE]"))) - goto Erreur_Retour; - - if ((return_code=Load_INI_get_values (file,buffer,"X_sensitivity",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>4)) - conf->Mouse_sensitivity_index_x=1; - else - conf->Mouse_sensitivity_index_x=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Y_sensitivity",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>4)) - conf->Mouse_sensitivity_index_y=1; - else - conf->Mouse_sensitivity_index_y=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"X_correction_factor",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>4)) - goto Erreur_ERREUR_INI_CORROMPU; - // Deprecated setting, unused - - if ((return_code=Load_INI_get_values (file,buffer,"Y_correction_factor",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>4)) - goto Erreur_ERREUR_INI_CORROMPU; - // Deprecated setting, unused - - if ((return_code=Load_INI_get_values (file,buffer,"Cursor_aspect",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>3)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Cursor=values[0]-1; - - if ((return_code=Load_INI_reach_group(file,buffer,"[MENU]"))) - goto Erreur_Retour; - - conf->Fav_menu_colors[0].R=0; - conf->Fav_menu_colors[0].G=0; - conf->Fav_menu_colors[0].B=0; - conf->Fav_menu_colors[3].R=255; - conf->Fav_menu_colors[3].G=255; - conf->Fav_menu_colors[3].B=255; - - if ((return_code=Load_INI_get_values (file,buffer,"Light_color",3,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>63)) - goto Erreur_ERREUR_INI_CORROMPU; - if ((values[1]<0) || (values[1]>63)) - goto Erreur_ERREUR_INI_CORROMPU; - if ((values[2]<0) || (values[2]>63)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Fav_menu_colors[2].R=(values[0]<<2)|(values[0]>>4); - conf->Fav_menu_colors[2].G=(values[1]<<2)|(values[1]>>4); - conf->Fav_menu_colors[2].B=(values[2]<<2)|(values[2]>>4); - - if ((return_code=Load_INI_get_values (file,buffer,"Dark_color",3,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>63)) - goto Erreur_ERREUR_INI_CORROMPU; - if ((values[1]<0) || (values[1]>63)) - goto Erreur_ERREUR_INI_CORROMPU; - if ((values[2]<0) || (values[2]>63)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Fav_menu_colors[1].R=(values[0]<<2)|(values[0]>>4); - conf->Fav_menu_colors[1].G=(values[1]<<2)|(values[1]>>4); - conf->Fav_menu_colors[1].B=(values[2]<<2)|(values[2]>>4); - - if ((return_code=Load_INI_get_values (file,buffer,"Menu_ratio",1,values))) - goto Erreur_Retour; - if ((values[0]<-4) || (values[0]>2)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Ratio=values[0]; - - if ((return_code=Load_INI_reach_group(file,buffer,"[FILE_SELECTOR]"))) - goto Erreur_Retour; - - if ((return_code=Load_INI_get_values (file,buffer,"Show_hidden_files",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Show_hidden_files=values[0]?1:0; - - if ((return_code=Load_INI_get_values (file,buffer,"Show_hidden_directories",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Show_hidden_directories=values[0]?1:0; - -/* if ((return_code=Load_INI_get_values (file,buffer,"Show_system_directories",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Show_system_directories=values[0]?1:0; -*/ - if ((return_code=Load_INI_get_values (file,buffer,"Preview_delay",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>256)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Timer_delay=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Maximize_preview",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Maximize_preview=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Find_file_fast",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>2)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Find_file_fast=values[0]; - - - if ((return_code=Load_INI_reach_group(file,buffer,"[LOADING]"))) - goto Erreur_Retour; - - if ((return_code=Load_INI_get_values (file,buffer,"Auto_set_resolution",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Auto_set_res=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Set_resolution_according_to",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>2)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Set_resolution_according_to=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Clear_palette",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Clear_palette=values[0]; - - - if ((return_code=Load_INI_reach_group(file,buffer,"[MISCELLANEOUS]"))) - goto Erreur_Retour; - - if ((return_code=Load_INI_get_values (file,buffer,"Draw_limits",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Display_image_limits=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Adjust_brush_pick",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Adjust_brush_pick=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Coordinates",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>2)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Coords_rel=2-values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Backup",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Backup=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Undo_pages",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>99)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Max_undo_pages=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Gauges_scrolling_speed_Left",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>255)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Delay_left_click_on_slider=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Gauges_scrolling_speed_Right",1,values))) - goto Erreur_Retour; - if ((values[0]<1) || (values[0]>255)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Delay_right_click_on_slider=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Auto_save",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Auto_save=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Vertices_per_polygon",1,values))) - goto Erreur_Retour; - if ((values[0]<2) || (values[0]>16384)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Nb_max_vertices_per_polygon=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Fast_zoom",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Fast_zoom=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Separate_colors",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Separate_colors=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"FX_feedback",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->FX_Feedback=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Safety_colors",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Safety_colors=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Opening_message",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Opening_message=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Clear_with_stencil",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Clear_with_stencil=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Auto_discontinuous",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Auto_discontinuous=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Save_screen_size_in_GIF",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Screen_size_in_GIF=values[0]; - - if ((return_code=Load_INI_get_values (file,buffer,"Auto_nb_colors_used",1,values))) - goto Erreur_Retour; - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Auto_nb_used=values[0]; - - // Optionnel, le mode video par défaut (à partir de beta 97.0%) - conf->Default_resolution=0; - if (!Load_INI_get_string (file,buffer,"Default_video_mode",value_label, 0)) - { - int mode = Convert_videomode_arg(value_label); - if (mode>=0) - conf->Default_resolution=mode; - } - - // Optionnel, les dimensions de la fenêtre (à partir de beta 97.0%) - // Do that only if the first mode is actually windowed (not the case on gp2x for example) - if(Video_mode[0].Fullscreen==0) - { - Video_mode[0].Width = 640; - Video_mode[0].Height = 480; - if (!Load_INI_get_values (file,buffer,"Default_window_size",2,values)) - { - if ((values[0]>=320)) - Video_mode[0].Width = values[0]; - if ((values[1]>=200)) - Video_mode[0].Height = values[1]; - } - } - - conf->Mouse_merge_movement=100; - // Optionnel, paramètre pour grouper les mouvements souris (>98.0%) - if (!Load_INI_get_values (file,buffer,"Merge_movement",1,values)) - { - if ((values[0]<0) || (values[0]>1000)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Mouse_merge_movement=values[0]; - } - - conf->Palette_cells_X=8; - // Optionnel, nombre de colonnes dans la palette (>98.0%) - if (!Load_INI_get_values (file,buffer,"Palette_cells_X",1,values)) - { - if ((values[0]<1) || (values[0]>256)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Palette_cells_X=values[0]; - } - conf->Palette_cells_Y=8; - // Optionnel, nombre de lignes dans la palette (>98.0%) - if (!Load_INI_get_values (file,buffer,"Palette_cells_Y",1,values)) - { - if (values[0]<1 || values[0]>16) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Palette_cells_Y=values[0]; - } - // Optionnel, bookmarks (>98.0%) - for (index=0;indexBookmark_directory[index]=NULL; - conf->Bookmark_label[index][0]='\0'; - } - for (index=0;index8) - { - value_label[7]=ELLIPSIS_CHARACTER; - value_label[8]='\0'; - } - strcpy(conf->Bookmark_label[index],value_label); - } - } - else - break; - if (!Load_INI_get_string (file,buffer,"Bookmark_directory",value_label, 1)) - { - int size=strlen(value_label); - if (size!=0) - { - conf->Bookmark_directory[index]=(char *)malloc(size+1); - strcpy(conf->Bookmark_directory[index],value_label); - } - } - else - break; - } - conf->Palette_vertical=0; - // Optional, vertical palette option (>98.0%) - if (!Load_INI_get_values (file,buffer,"Palette_vertical",1,values)) - { - if ((values[0]<0) || (values[0]>1)) - goto Erreur_ERREUR_INI_CORROMPU; - conf->Palette_vertical=values[0]; - } - - // Optional, the window position (>98.0%) - conf->Window_pos_x=9999; - conf->Window_pos_y=9999; - if (!Load_INI_get_values (file,buffer,"Window_position",2,values)) - { - conf->Window_pos_x = values[0]; - conf->Window_pos_y = values[1]; - } - - conf->Double_click_speed=500; - // Optional, speed of double-click (>2.0) - if (!Load_INI_get_values (file,buffer,"Double_click_speed",1,values)) - { - if ((values[0]>0) || (values[0]<=2000)) - conf->Double_click_speed=values[0]; - } - - conf->Double_key_speed=500; - // Optional, speed of double-keypress (>2.0) - if (!Load_INI_get_values (file,buffer,"Double_key_speed",1,values)) - { - if ((values[0]>0) || (values[0]<=2000)) - conf->Double_key_speed=values[0]; - } - - // Optional, name of skin file. (>2.0) - if(!Load_INI_get_string(file,buffer,"Skin_file",value_label,1)) - { - conf->Skin_file = strdup(value_label); - } - else - conf->Skin_file = strdup("skin_DPaint.png"); - - // Optional, name of font file. (>2.0) - if(!Load_INI_get_string(file,buffer,"Font_file",value_label,1)) - conf->Font_file = strdup(value_label); - else - conf->Font_file = strdup("font_Dpaint.png"); - - conf->Grid_XOR_color=255; - // Optional, XOR color for grid overlay (>2.0) - if (!Load_INI_get_values (file,buffer,"Grid_XOR_color",1,values)) - { - if ((values[0]>0) && (values[0]<=255)) - conf->Grid_XOR_color=values[0]; - } - - // Optional, "fake hardware zoom" factor (>2.1) - if (!Load_INI_get_values (file, buffer,"Pixel_ratio",1,values)) - { - Pixel_ratio = values[0]; - switch(Pixel_ratio) { - case PIXEL_WIDE: - if(Video_mode[0].Width < 640) - Pixel_ratio = PIXEL_SIMPLE; - break; - case PIXEL_TALL: - if(Video_mode[0].Height < 400) - Pixel_ratio = PIXEL_SIMPLE; - break; - case PIXEL_DOUBLE: - if(Video_mode[0].Width < 640 || Video_mode[0].Height < 400) - Pixel_ratio = PIXEL_SIMPLE; - break; - case PIXEL_TRIPLE: - if(Video_mode[0].Width < 3*320 || Video_mode[0].Height < 3*200) - Pixel_ratio = PIXEL_SIMPLE; - break; - case PIXEL_WIDE2: - if(Video_mode[0].Width < 4*320 || Video_mode[0].Height < 2*200) - Pixel_ratio = PIXEL_SIMPLE; - break; - case PIXEL_TALL2: - if(Video_mode[0].Width < 2*320 || Video_mode[0].Height < 4*200) - Pixel_ratio = PIXEL_SIMPLE; - break; - case PIXEL_QUAD: - if(Video_mode[0].Width < 4*320 || Video_mode[0].Height < 4*200) - Pixel_ratio = PIXEL_SIMPLE; - break; - default: - // Convert back unknown values to PIXEL_SIMPLE - Pixel_ratio = PIXEL_SIMPLE; - break; - } - } - - // Optional, Menu bars visibility (> 2.1) - if (!Load_INI_get_values (file, buffer,"Menubars_visible",1,values)) - { - int index; - for (index=MENUBAR_STATUS+1; indexRight_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; - } - } - - // Optional, Location of last directory used for Lua scripts browsing (>=2.3) - conf->Scripts_directory[0]='\0'; - if (!Load_INI_get_string (file,buffer,"Scripts_directory",value_label, 1)) - { - strcpy(conf->Scripts_directory,value_label); - } - if (conf->Scripts_directory[0]=='\0') - { - // Default when empty: - Realpath(Data_directory, conf->Scripts_directory); - Append_path(conf->Scripts_directory, "scripts", NULL); - } - - conf->Allow_multi_shortcuts=0; - // Optional, allow or disallow multiple shortcuts on same key (>=2.3) - if (!Load_INI_get_values (file,buffer,"Allow_multi_shortcuts",1,values)) - { - conf->Allow_multi_shortcuts=(values[0]!=0); - } - - // Insert new values here - - fclose(file); - - free(filename); - free(buffer); - return 0; - - // Gestion des erreurs: - - Erreur_Retour: - fclose(file); - free(filename); - free(buffer); - return return_code; - - Erreur_ERREUR_INI_CORROMPU: - - fclose(file); - free(filename); - free(buffer); - return ERROR_INI_CORRUPTED; -} diff --git a/project/jni/application/grafx2/grafx2/src/readini.h b/project/jni/application/grafx2/grafx2/src/readini.h deleted file mode 100644 index e55152f36..000000000 --- a/project/jni/application/grafx2/grafx2/src/readini.h +++ /dev/null @@ -1,29 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file readini.h -/// Reading settings in gfx2.ini -////////////////////////////////////////////////////////////////////////////// - -int Load_INI(T_Config * conf); -int Load_INI_seek_pattern(char * buffer,char * pattern); -void Load_INI_clear_string(char * str, byte keep_comments); diff --git a/project/jni/application/grafx2/grafx2/src/readline.c b/project/jni/application/grafx2/grafx2/src/readline.c deleted file mode 100644 index cc7900beb..000000000 --- a/project/jni/application/grafx2/grafx2/src/readline.c +++ /dev/null @@ -1,675 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -/************************************************************************ -* * -* READLINE (procédure permettant de saisir une chaîne de caractères) * -* * -************************************************************************/ - -#include -#include -#include - -#include "const.h" -#include "struct.h" -#include "global.h" -#include "misc.h" -#include "errors.h" -#include "const.h" -#include "sdlscreen.h" -#include "readline.h" -#include "windows.h" -#include "input.h" -#include "engine.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 -#define CURSOR_BACKGROUND_COLOR MC_Dark - -// Suppresion d'un caractère à une certaine POSITION dans une CHAINE. -void Remove_character(char * str, byte position) -{ - for (;str[position]!='\0';position++) - str[position]=str[position+1]; -} - - -void Insert_character(char * str, char letter, byte position) -// Insertion d'une LETTRE à une certaine POSITION -// dans une CHAINE d'une certaine TAILLE. -{ - char temp_char; - - for (;letter!='\0';position++) - { - // On mémorise le caractère qui se trouve en "position" - temp_char=str[position]; - // On splotch la lettre à insérer - str[position]=letter; - // On place le caractère mémorisé dans "letter" comme nouvelle lettre à insérer - letter=temp_char; - } - // On termine la chaine - str[position]='\0'; -} - -int Valid_character(int c) -{ - // Sous Linux: Seul le / est strictement interdit, mais beaucoup - // d'autres poseront des problèmes au shell, alors on évite. - // Sous Windows : c'est moins grave car le fopen() échouerait de toutes façons. - // AmigaOS4: Pas de ':' car utilisé pour les volumes. - #if defined(__WIN32__) - char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':', '\\'}; - #elif defined (__amigaos4__) - char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':'}; - #else - char forbidden_char[] = {'/', '|', '?', '*', '<', '>'}; - #endif - int position; - - if (c < ' ' || c > 255) - return 0; - - for (position=0; position<(long)sizeof(forbidden_char); position++) - if (c == forbidden_char[position]) - return 0; - return 1; -} - -void Display_whole_string(word x_pos,word y_pos,char * str,byte position) -{ - 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); - } -} - -/**************************************************************************** -* Enhanced super scanf deluxe pro plus giga mieux :-) * -****************************************************************************/ -byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type) -// Paramètres: -// x_pos, y_pos : Coordonnées de la saisie dans la fenêtre -// str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) -// max_size : Nombre de caractères logeant dans la zone de saisie -// input_type : 0=Chaîne, 1=Nombre, 2=Nom de fichier -// Sortie: -// 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) -{ - byte max_size; - // Grosse astuce pour les noms de fichiers: La taille affichée est différente - // de la taille maximum gérée. - if (input_type == 2) - max_size = 255; - else - max_size = visible_size; - return Readline_ex(x_pos,y_pos,str,visible_size,max_size,input_type,0); -} - -/**************************************************************************** -* Enhanced super scanf deluxe pro plus giga mieux :-) * -****************************************************************************/ -byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places) -// Paramètres: -// x_pos, y_pos : Coordonnées de la saisie dans la fenêtre -// str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) -// max_size : Nombre de caractères logeant dans la zone de saisie -// input_type : 0=String, 1=Unsigned int, 2=Filename 3=Signed Double -// decimal_places: Number of decimal places for a double -// Sortie: -// 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) -{ - char initial_string[256]; - char display_string[256]; - byte position; - byte size; - word input_key=0; - byte is_authorized; - 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==INPUT_TYPE_INTEGER && str[0]!='\0') - snprintf(str,10,"%d",atoi(str)); // On tasse la chaine à gauche - 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; - - 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_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_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 - strcpy(initial_string,str); - - size=strlen(str); - position=(size=visible_size) - offset=position-visible_size+1; - // Formatage d'une partie de la chaine (si trop longue pour tenir) - strncpy(display_string, str + offset, visible_size); - display_string[visible_size]='\0'; - if (offset>0) - display_string[0]=LEFT_TRIANGLE_CHARACTER; - if (visible_size + offset + 1 < size ) - display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; - - Display_whole_string(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(); - if (Mouse_K) - { - Display_cursor(); - Wait_end_of_click(); - Hide_cursor(); - } - - while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) - { - Display_cursor(); -#ifdef VIRT_KEY - if (use_virtual_keyboard) - { - int clicked_button; - - clicked_button=Window_clicked_button(); - input_key=Key_ANSI; - - 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) - { - case SDLK_DELETE : // Suppr. - if (position0) - { - // Effacement de la chaîne - if (position==size) - 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))) - offset--; - goto affichage; - } - break; - case SDLK_RIGHT : // Droite - if ((position visible_size + offset - 2) - //if (offset + visible_size < max_size && (position == size || (position > visible_size + offset - 2))) - if (display_string[position-offset]==RIGHT_TRIANGLE_CHARACTER || position-offset>=visible_size) - offset++; - goto affichage; - } - break; - case SDLK_HOME : // Home - if (position) - { - // Effacement de la chaîne - if (position==size) - Block(window_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; - goto affichage; - } - break; - case SDLK_END : // End - if ((position=visible_size) - offset=position-visible_size+1; - goto affichage; - } - break; - case SDLK_BACKSPACE : // Backspace : combinaison de gauche + suppr - - if (position) - { - position--; - if (offset > 0 && (position == 0 || position < (offset + 1))) - offset--; - Remove_character(str,position); - size--; - // Effacement de la chaîne - Block(window_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; - - case KEY_ESC : - // On restaure la chaine initiale - strcpy(str,initial_string); - size=strlen(str); - break; - default : - if (size=' ' && input_key<= 255)||input_key=='\n') - is_authorized=1; - break; - case INPUT_TYPE_INTEGER : - if ( (input_key>='0') && (input_key<='9') ) - is_authorized=1; - break; - case INPUT_TYPE_DECIMAL: - if ( (input_key>='0') && (input_key<='9') ) - is_authorized=1; - else if (input_key=='-' && position==0 && str[0]!='-') - is_authorized=1; - else if (input_key=='.') - is_authorized=1; - break; - 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... - if (is_authorized) - { - // ... alors on l'insère ... - Insert_character(str,input_key,position/*,size*/); - // ce qui augmente la taille de la chaine - size++; - // et qui risque de déplacer le curseur vers la droite - if (size=visible_size) - offset++; - } - // Enfin, on raffiche la chaine - goto affichage; - } // End du test d'autorisation de touche - } // End du test de place libre - break; - -affichage: - size=strlen(str); - // Formatage d'une partie de la chaine (si trop longue pour tenir) - strncpy(display_string, str + offset, visible_size); - display_string[visible_size]='\0'; - if (offset>0) - display_string[0]=LEFT_TRIANGLE_CHARACTER; - if (visible_size + offset + 0 < size ) - display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; - - Display_whole_string(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_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==INPUT_TYPE_INTEGER) - { - if (str[0]=='\0') - { - strcpy(str,"0"); - size=1; - } - Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); - } - else if (input_type==INPUT_TYPE_DECIMAL) - { - double value; - // Discard extra digits - value = Fround(atof(str), decimal_places); - Sprint_double(str,value,decimal_places,visible_size); - // Recompute updated size - size = strlen(str); - - if (size<=visible_size) - Print_in_window(x_pos+((visible_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); - else - Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); - } - else - { - Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); - } - 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); -} - -void Sprint_double(char *str, double value, byte decimal_places, byte min_positions) -{ - int i; - int length; - - sprintf(str,"%.*f",decimal_places, value); - length=strlen(str); - - for (i=0; i= 0 && decimals[j]=='0'; j--) - { - decimals[j] = '\0'; - } - // If all decimals were removed, remove the dot too - if (str[i+1]=='\0') - str[i]='\0'; - - // Update string length - length=strlen(str); - - // Ends the parent loop - break; - } - } - - // Now try add spaces at beginning - if (length -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file readline.h -/// 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 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); - -/// -/// Lets the user input a line of text, exit by Esc or Return. -/// @param x_pos Coordinates of input, in window coordinates before scaling. -/// @param y_pos Coordinates of input, in window coordinates before scaling. -/// @param str The original string value (will be modified, unless user cancels. -/// @param visible_size Number of characters visible. -/// @param max_size Number of characters editable. -/// @param input_type 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); - -/// -/// Converts a double to string. -/// @param str Target string, should be pre-allocated and at least 40 characters, to be safe. -/// @param value The number to convert -/// @param decimal_places Number of decimal places to keep. 15 seems the maximum. -/// @param min_positions Minimum number of characters: Will pad spaces on the left to meet this minimum. -void Sprint_double(char *str, double value, byte decimal_places, byte min_positions); diff --git a/project/jni/application/grafx2/grafx2/src/realpath.c b/project/jni/application/grafx2/grafx2/src/realpath.c deleted file mode 100644 index 1a916e72c..000000000 --- a/project/jni/application/grafx2/grafx2/src/realpath.c +++ /dev/null @@ -1,121 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -#define _XOPEN_SOURCE 500 -#include -#include -#include -#include -#include -#if defined(__AROS__) -#include -#endif - -#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 -// -// When tested on Debian, this piece of code doesn't resolve -// symbolic link in the filename itself, only on the directories in -// the path. So this implementation is limited, it's really better to -// use realpath() if your platform has it. - - #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__amigaos__) - // This is a random default value ... - #define PATH_MAX 32768 - #endif - - static char *sep(char *path) - { - char *tmp, c; - - tmp = strrchr(path, '/'); - if(tmp) { - c = tmp[1]; - tmp[1] = 0; - if (chdir(path)) { - return NULL; - } - tmp[1] = c; - - return tmp + 1; - } - return path; - } - - char *Realpath(const char *_path, char *resolved_path) - { - int fd = open(".", O_RDONLY), l; - char current_dir_path[PATH_MAX]; - char path[PATH_MAX], lnk[PATH_MAX], *tmp = (char *)""; - - if (fd < 0) { - return NULL; - } - getcwd(current_dir_path,PATH_MAX); - strncpy(path, _path, PATH_MAX); - - if (chdir(path)) { - if (errno == ENOTDIR) { - #if defined(__WIN32__) || defined(__MORPHOS__) || defined(__amigaos__) - // No symbolic links and no readlink() - l = -1; - #else - l = readlink(path, lnk, PATH_MAX); - #endif - if (!(tmp = sep(path))) { - resolved_path = NULL; - goto abort; - } - if (l < 0) { - if (errno != EINVAL) { - resolved_path = NULL; - goto abort; - } - } else { - lnk[l] = 0; - if (!(tmp = sep(lnk))) { - resolved_path = NULL; - goto abort; - } - } - } else { - resolved_path = NULL; - goto abort; - } - } - - if(resolved_path==NULL) // if we called realpath with null as a 2nd arg - resolved_path = (char*) malloc( PATH_MAX ); - - if (!getcwd(resolved_path, PATH_MAX)) { - resolved_path = NULL; - goto abort; - } - - if(strcmp(resolved_path, "/") && *tmp) { - strcat(resolved_path, "/"); - } - - strcat(resolved_path, tmp); - abort: - chdir(current_dir_path); - close(fd); - return resolved_path; - } - -#elif defined (__WIN32__) -// Mingw has a working equivalent. It only has reversed arguments. - char *Realpath(const char *_path, char *resolved_path) - { - return _fullpath(resolved_path,_path,260); - } -#else -// Use the stdlib function. - char *Realpath(const char *_path, char *resolved_path) - { - return realpath(_path, resolved_path); - } -#endif - - diff --git a/project/jni/application/grafx2/grafx2/src/realpath.h b/project/jni/application/grafx2/grafx2/src/realpath.h deleted file mode 100644 index 35f625bcd..000000000 --- a/project/jni/application/grafx2/grafx2/src/realpath.h +++ /dev/null @@ -1,36 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Adrien Destugues - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file realpath.h -/// Implementation of realpath() that is portable on all our platforms. -////////////////////////////////////////////////////////////////////////////// - -#ifndef _REALPATH_H -#define _REALPATH_H - -/// -/// Makes an absolute filename, resolving symbolic links etc. -/// @param _path Input path -/// @param resolved_path Output path, allocated by caller -/// @return (points to resolved_path) -char *Realpath(const char *_path, char *resolved_path); - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/saveini.c b/project/jni/application/grafx2/grafx2/src/saveini.c deleted file mode 100644 index b691965f3..000000000 --- a/project/jni/application/grafx2/grafx2/src/saveini.c +++ /dev/null @@ -1,735 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include -#include -#include "const.h" -#include "global.h" -#include "readini.h" -#include "io.h" -#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) -{ - int stop_seek; - char * group_upper; - char * upper_buffer; - - // On alloue les zones de mémoire: - group_upper =(char *)malloc(1024); - upper_buffer=(char *)malloc(1024); - - // On commence par se faire une version majuscule du groupe à rechercher: - strcpy(group_upper,group); - Load_INI_clear_string(group_upper, 0); - - stop_seek=0; - do - { - // On lit une ligne dans le fichier: - if (fgets(buffer,1024,old_file)==0) - { - free(upper_buffer); - free(group_upper); - return ERROR_INI_CORRUPTED; - } - - // On s'en fait une version en majuscule: - strcpy(upper_buffer,buffer); - Load_INI_clear_string(upper_buffer, 0); - - // On compare la chaîne avec le groupe recherché: - stop_seek=Load_INI_seek_pattern(upper_buffer,group_upper); - if (fprintf(new_file,"%s",buffer)<0) - { - free(upper_buffer); - free(group_upper); - return ERROR_SAVING_INI; - } - } - while (stop_seek==0); - - free(upper_buffer); - free(group_upper); - - return 0; -} - - - -int Save_INI_char_in_value_alphabet(char c) -{ - if ( - ( // Digit - (c>='0') && - (c<='9') - ) || - ( // Uppercase letter - (c>='A') && - (c<='Z') - ) || - ( // Lowerchase letter - (c>='a') && - (c<='z') - ) || - (c == '$') || // Hexa prefix - (c == '-') || // Minus sign - (c== '.') // Dot (in filenames) - ) - return 1; - else - return 0; -} - - - -void Save_INI_set_value(char * dest,char * source,int nb_values_to_set,int * values,int litteral) -{ - int dest_index; - int source_index; - int value_index; - - // On commence par recopier tout jusqu'au symbole '=': - for (source_index=0;source[source_index]!='=';source_index++) - dest[source_index]=source[source_index]; - - // Puis on recopie le symbole '=': - dest[source_index]=source[source_index]; - source_index++; - - // Puis on recopie tous les espaces qui suivent: - for (;source[source_index]==' ';source_index++) - dest[source_index]=source[source_index]; - - // Pour l'instant, la source et la destination en sont au même point: - dest_index=source_index; - - // Puis pour chaque valeur à recopier: - for (value_index=0;value_index Yes - - memcpy(dest+dest_index,"yes",3); - dest_index+=3; - } - else - { - // La valeur <=> No - - memcpy(dest+dest_index,"no",2); - dest_index+=2; - } - } - else - { - // La valeur doit être écrite sous forme numérique - - if (source[source_index]=='$') - { - // On va écrire la valeur sous forme hexadécimale: - - // On commence par inscrire le symbole '$': - dest[dest_index]='$'; - - // Puis on y concatène la valeur: - sprintf(dest+dest_index+1,"%x",values[value_index]); - dest_index+=strlen(dest+dest_index); - } - else - { - // On va écrire la valeur sous forme décimale: - - sprintf(dest+dest_index,"%d",values[value_index]); - dest_index+=strlen(dest+dest_index); - } - } - - // Dans la source, on saute la valeur: - for (;Save_INI_char_in_value_alphabet(source[source_index]) && (source[source_index]!='\0');source_index++); - - if (value_index!=(nb_values_to_set-1)) - { - // Il reste d'autres valeurs à écrire - - // On recopie tous les caractères de la source jusqu'au suivant qui - // désigne une valeur: - for (;(!Save_INI_char_in_value_alphabet(source[source_index])) && (source[source_index]!='\0');source_index++,dest_index++) - dest[dest_index]=source[source_index]; - } - else - { - // C'est la dernière valeur à initialiser - - // On recopie toute la fin de la ligne: - for (;source[source_index]!='\0';source_index++,dest_index++) - dest[dest_index]=source[source_index]; - - // Et on n'oublie pas d'y mettre l''\0': - dest[dest_index]='\0'; - } - } -} - -void Save_INI_set_string(char * dest,char * source,char * value) -{ - int dest_index; - int source_index; - - // On commence par recopier tout jusqu'au symbole '=': - for (source_index=0;source[source_index]!='=';source_index++) - dest[source_index]=source[source_index]; - - // Puis on recopie le symbole '=': - dest[source_index]=source[source_index]; - source_index++; - - // Puis on recopie tous les espaces qui suivent: - for (;source[source_index]==' ';source_index++) - dest[source_index]=source[source_index]; - - // Pour l'instant, la source et la destination en sont au même point: - dest_index=source_index; - - // Dans la destination, on écrit la valeur: - strcpy(dest+dest_index,value); - dest_index+=strlen(value); - - // Dans la source, on saute la valeur: - for (;Save_INI_char_in_value_alphabet(source[source_index]) && (source[source_index]!='\0');source_index++); - - // On recopie toute la fin de la ligne: - for (;source[source_index]!='\0';source_index++,dest_index++) - dest[dest_index]=source[source_index]; - - // Et on n'oublie pas d'y mettre l''\0': - dest[dest_index]='\0'; -} - -int Save_INI_set_strings(FILE * old_file,FILE * new_file,char * buffer,char * option_name,char * value) -{ - int stop_seek; - char * option_upper; - char * upper_buffer; - char * result_buffer; - //int buffer_index; - - // On alloue les zones de mémoire: - option_upper=(char *)malloc(1024); - upper_buffer=(char *)malloc(1024); - result_buffer=(char *)malloc(1024); - - // On convertit un eventuel argument NULL en chaine vide. - if (value == NULL) - value=""; - - // On commence par se faire une version majuscule de l'option à rechercher: - strcpy(option_upper,option_name); - Load_INI_clear_string(option_upper, 0); - - stop_seek=0; - do - { - // On lit une ligne dans le fichier: - if (fgets(buffer,1024,old_file)==0) - { - free(result_buffer); - free(upper_buffer); - free(option_upper); - return ERROR_INI_CORRUPTED; - } - - // On s'en fait une version en majuscule: - strcpy(upper_buffer,buffer); - Load_INI_clear_string(upper_buffer, 0); - - // On compare la chaîne avec l'option recherchée: - stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); - - if (stop_seek) - { - // On l'a trouvée: - - Save_INI_set_string(result_buffer,buffer,value); - if (fprintf(new_file,"%s",result_buffer)<0) - { - free(result_buffer); - free(upper_buffer); - free(option_upper); - return ERROR_SAVING_INI; - } - } - else - { - // On l'a pas trouvée: - - if (fprintf(new_file,"%s",buffer)<0) - { - free(result_buffer); - free(upper_buffer); - free(option_upper); - return ERROR_SAVING_INI; - } - } - } - while (stop_seek==0); - - free(result_buffer); - free(upper_buffer); - free(option_upper); - - return 0; -} - -int Save_INI_set_values(FILE * old_file,FILE * new_file,char * buffer,char * option_name,int nb_values_to_set,int * values,int litteral) -{ - int stop_seek; - char * option_upper; - char * upper_buffer; - char * result_buffer; - //int buffer_index; - - // On alloue les zones de mémoire: - option_upper=(char *)malloc(1024); - upper_buffer=(char *)malloc(1024); - result_buffer=(char *)malloc(1024); - - // On commence par se faire une version majuscule de l'option à rechercher: - strcpy(option_upper,option_name); - Load_INI_clear_string(option_upper, 0); - - stop_seek=0; - do - { - // On lit une ligne dans le fichier: - if (fgets(buffer,1024,old_file)==0) - { - free(result_buffer); - free(upper_buffer); - free(option_upper); - DEBUG("END OF FILE",0); - return ERROR_INI_CORRUPTED; - } - - // On s'en fait une version en majuscule: - strcpy(upper_buffer,buffer); - Load_INI_clear_string(upper_buffer, 0); - - // On compare la chaîne avec l'option recherchée: - stop_seek=Load_INI_seek_pattern(upper_buffer,option_upper); - - if (stop_seek) - { - // On l'a trouvée: - - Save_INI_set_value(result_buffer,buffer,nb_values_to_set,values,litteral); - if (fprintf(new_file,"%s",result_buffer)<0) - { - free(result_buffer); - free(upper_buffer); - free(option_upper); - return ERROR_SAVING_INI; - } - } - else - { - // On l'a pas trouvée: - - if (fprintf(new_file,"%s",buffer)<0) - { - free(result_buffer); - free(upper_buffer); - free(option_upper); - return ERROR_SAVING_INI; - } - } - } - while (stop_seek==0); - - free(result_buffer); - free(upper_buffer); - free(option_upper); - - return 0; -} - - - -void Save_INI_flush(FILE * old_file,FILE * new_file,char * buffer) -{ - while (fgets(buffer,1024,old_file)!=0) - fprintf(new_file,"%s",buffer); -} - - - -int Save_INI(T_Config * conf) -{ - FILE * old_file; - FILE * new_file; - char * buffer; - int values[3]; - char filename[MAX_PATH_CHARACTERS]; - char temp_filename[MAX_PATH_CHARACTERS]; - int return_code; - char ref_ini_file[MAX_PATH_CHARACTERS]; - int ini_file_exists; - int index; - - // On alloue les zones de mémoire: - buffer=(char *)malloc(1024); - - // On calcule les noms des fichiers qu'on manipule: - strcpy(filename,Config_directory); - 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,INISAVE_FILENAME); - - // Delete gfx2.$$$ - remove(temp_filename); - // Rename current config file as gfx2.$$$ - if (rename(filename,temp_filename)!=0) - { - goto Erreur_ERREUR_SAUVEGARDE_INI; - } - } - // On récupère un fichier INI "propre" à partir de gfx2def.ini - strcpy(ref_ini_file,Data_directory); - strcat(ref_ini_file,INIDEF_FILENAME); - old_file=fopen(ref_ini_file,"rb"); - if (old_file==0) - { - fclose(old_file); - free(buffer); - return ERROR_INI_MISSING; - } - new_file=fopen(filename,"wb"); - if (new_file==0) - { - free(buffer); - return ERROR_SAVING_INI; - } - 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 (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 (old_file,new_file,buffer,"Y_sensitivity",1,values,0))) - goto Erreur_Retour; - - values[0]=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 (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 (old_file,new_file,buffer,"Cursor_aspect",1,values,0))) - goto Erreur_Retour; - - 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 (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 (old_file,new_file,buffer,"Dark_color",3,values,0))) - goto Erreur_Retour; - - values[0]=conf->Ratio; - 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(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 (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 (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 (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 (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 (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 (old_file,new_file,buffer,"Find_file_fast",1,values,0))) - goto Erreur_Retour; - - - 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 (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 (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 (old_file,new_file,buffer,"Clear_palette",1,values,1))) - goto Erreur_Retour; - - - 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 (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 (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 (old_file,new_file,buffer,"Coordinates",1,values,0))) - goto Erreur_Retour; - - values[0]=conf->Backup; - 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (old_file,new_file,buffer,"Auto_nb_colors_used",1,values,1))) - goto Erreur_Retour; - - 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 (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 (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 (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 (old_file,new_file,buffer,"Palette_cells_Y",1,values,0))) - goto Erreur_Retour; - - for (index=0;indexBookmark_label[index]))) - goto Erreur_Retour; - 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 (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 (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 (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 (old_file,new_file,buffer,"Double_key_speed",1,values,0))) - goto Erreur_Retour; - - 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 (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 (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 (old_file,new_file,buffer,"Pixel_ratio",1,values,0))) { - DEBUG("saving pixel ratio",return_code); - goto Erreur_Retour; - } - - values[0]=0; - for (index=0; indexRight_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; - - if ((return_code=Save_INI_set_strings (old_file,new_file,buffer,"Scripts_directory",conf->Scripts_directory))) - goto Erreur_Retour; - - values[0]=(conf->Allow_multi_shortcuts); - if ((return_code=Save_INI_set_values (old_file,new_file,buffer,"Allow_multi_shortcuts",1,values,1))) - goto Erreur_Retour; - - // Insert new values here - - Save_INI_flush(old_file,new_file,buffer); - - fclose(new_file); - fclose(old_file); - - // On efface le fichier temporaire <=> Ancienne version du .INI - if (ini_file_exists) - remove(temp_filename); - free(buffer); - return 0; - - // Gestion des erreurs: - - Erreur_Retour: - - fclose(new_file); - fclose(old_file); - free(buffer); - return return_code; - - Erreur_ERREUR_SAUVEGARDE_INI: - - free(buffer); - return ERROR_SAVING_INI; -} diff --git a/project/jni/application/grafx2/grafx2/src/saveini.h b/project/jni/application/grafx2/grafx2/src/saveini.h deleted file mode 100644 index c45b38f5e..000000000 --- a/project/jni/application/grafx2/grafx2/src/saveini.h +++ /dev/null @@ -1,27 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file saveini.h -/// Saving settings in gfx2.ini -////////////////////////////////////////////////////////////////////////////// - -int Save_INI(T_Config * conf); diff --git a/project/jni/application/grafx2/grafx2/src/sdlscreen.c b/project/jni/application/grafx2/grafx2/src/sdlscreen.c deleted file mode 100644 index cdb0634e0..000000000 --- a/project/jni/application/grafx2/grafx2/src/sdlscreen.c +++ /dev/null @@ -1,373 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include -#include -#include -#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" -#include "misc.h" - -// Update method that does a large number of small rectangles, aiming -// for a minimum number of total pixels updated. -#define UPDATE_METHOD_MULTI_RECTANGLE 1 -// Intermediate update method, does only one update with the smallest -// rectangle that includes all modified pixels. -#define UPDATE_METHOD_CUMULATED 2 -// Total screen update, for platforms that impose a Vsync on each SDL update. -#define UPDATE_METHOD_FULL_PAGE 3 - -// UPDATE_METHOD can be set from makefile, otherwise it's selected here -// depending on the platform : -#ifndef UPDATE_METHOD - #if defined(__macosx__) - #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE - #elif defined(__MINT__) - #define UPDATE_METHOD UPDATE_METHOD_CUMULATED - #elif defined(ANDROID) - #define UPDATE_METHOD UPDATE_METHOD_FULL_PAGE - #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; - -#ifdef ANDROID - Screen_SDL_Hardware=SDL_SetVideoMode(*width,*height,16,(fullscreen?SDL_FULLSCREEN:0)); - Screen_SDL=SDL_CreateRGBSurface(SDL_SWSURFACE, *width, *height, 8, 0, 0, 0, 0); - if(Screen_SDL_Hardware != NULL) -#else - Screen_SDL=SDL_SetVideoMode(*width,*height,8,(fullscreen?SDL_FULLSCREEN:0)|SDL_RESIZABLE); - if(Screen_SDL != NULL) -#endif - { - // Check the mode we got, in case it was different from the one we requested. - if (Screen_SDL->w != *width || Screen_SDL->h != *height) - { - DEBUG("Error: Got a different video mode than the requested one!",0); - *width = Screen_SDL->w; - *height = Screen_SDL->h; - } - Screen_pixels=Screen_SDL->pixels; - } - else - { - DEBUG("Error: Unable to change video mode!",0); - } - - // 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) -short Min_X=0; -short Min_Y=0; -short Max_X=10000; -short Max_Y=10000; -short Status_line_dirty_begin=0; -short Status_line_dirty_end=0; -#endif - -#if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) - int update_is_required=0; -#endif - -void Flush_update(void) -{ -#if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) - // Do a full screen update - if (update_is_required) - { -#ifdef ANDROID - SDL_BlitSurface(Screen_SDL, NULL, Screen_SDL_Hardware, NULL); - SDL_UpdateRect(Screen_SDL_Hardware, 0, 0, 0, 0); -#else - SDL_UpdateRect(Screen_SDL, 0, 0, 0, 0); -#endif - update_is_required=0; - } -#endif - #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) - if (Min_X>=Max_X || Min_Y>=Max_Y) - { - ; // Nothing to do - } - else - { - if (Min_X<0) - Min_X=0; - if (Min_Y<0) - Min_Y=0; - SDL_UpdateRect(Screen_SDL, Min_X*Pixel_width, Min_Y*Pixel_height, Min(Screen_width-Min_X, Max_X-Min_X)*Pixel_width, Min(Screen_height-Min_Y, Max_Y-Min_Y)*Pixel_height); - - Min_X=Min_Y=10000; - Max_X=Max_Y=0; - } - if (Status_line_dirty_end) - { - SDL_UpdateRect(Screen_SDL, (18+(Status_line_dirty_begin*8))*Menu_factor_X*Pixel_width,Menu_status_Y*Pixel_height,(Status_line_dirty_end-Status_line_dirty_begin)*8*Menu_factor_X*Pixel_width,8*Menu_factor_Y*Pixel_height); - } - Status_line_dirty_begin=25; - Status_line_dirty_end=0; - - #endif - -} - -void Update_rect(short x, short y, unsigned short width, unsigned short height) -{ - #if (UPDATE_METHOD == UPDATE_METHOD_MULTI_RECTANGLE) - SDL_UpdateRect(Screen_SDL, x*Pixel_width, y*Pixel_height, width*Pixel_width, height*Pixel_height); - #endif - - #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) - if (width==0 || height==0) - { - Min_X=Min_Y=0; - Max_X=Max_Y=10000; - } - else - { - if (x < Min_X) - Min_X = x; - if (y < Min_Y) - Min_Y = y; - if (x+width>Max_X) - Max_X=x+width; - if (y+height>Max_Y) - Max_Y=y+height; - } - #endif - - #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) - update_is_required=1; - #endif - -} - -void Update_status_line(short char_pos, short width) -{ - #if (UPDATE_METHOD == UPDATE_METHOD_MULTI_RECTANGLE) - SDL_UpdateRect(Screen_SDL, (18+char_pos*8)*Menu_factor_X*Pixel_width,Menu_status_Y*Pixel_height,width*8*Menu_factor_X*Pixel_width,8*Menu_factor_Y*Pixel_height); - #endif - - #if (UPDATE_METHOD == UPDATE_METHOD_CUMULATED) - // Merge the ranges - if (Status_line_dirty_end < char_pos+width) - Status_line_dirty_end=char_pos+width; - if (Status_line_dirty_begin > char_pos) - Status_line_dirty_begin=char_pos; - #endif - - #if (UPDATE_METHOD == UPDATE_METHOD_FULL_PAGE) - (void)char_pos; // unused parameter - (void)width; // unused parameter - update_is_required=1; - #endif - -} - -/// -/// Converts a SDL_Surface (indexed colors or RGB) into an array of bytes -/// (indexed colors). -/// If dest is NULL, it's allocated by malloc(). Otherwise, be sure to -/// pass a buffer of the right dimensions. -byte * Surface_to_bytefield(SDL_Surface *source, byte * dest) -{ - byte *src; - byte *dest_ptr; - int y; - int remainder; - - // Support seulement des images 256 couleurs - if (source->format->BytesPerPixel != 1) - return NULL; - - if (source->w & 3) - remainder=4-(source->w&3); - else - remainder=0; - - if (dest==NULL) - dest=(byte *)malloc(source->w*source->h); - - dest_ptr=dest; - src=(byte *)(source->pixels); - for(y=0; y < source->h; y++) - { - memcpy(dest_ptr, src,source->w); - dest_ptr += source->w; - src += source->w + remainder; - } - return dest; - -} - -/// Gets the RGB 24-bit color currently associated with a palette index. -SDL_Color Color_to_SDL_color(byte index) -{ - SDL_Color color; - color.r = Main_palette[index].R; - color.g = Main_palette[index].G; - color.b = Main_palette[index].B; - color.unused = 255; - return color; -} - -/// Reads a pixel in a 8-bit SDL surface. -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: - // 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))); - } -} - -/// Convert a SDL Palette to a grafx2 palette -void Get_SDL_Palette(const SDL_Palette * sdl_palette, T_Palette palette) -{ - int i; - - for (i=0; i<256; i++) - { - palette[i].R=sdl_palette->colors[i].r; - palette[i].G=sdl_palette->colors[i].g; - palette[i].B=sdl_palette->colors[i].b; - } - -} - -void Clear_border(byte color) -{ - int width; - int height; - - // This function can be called before the graphics mode is set. - // Nothing to do then. - if (!Screen_SDL) - return; - - width = Screen_SDL->w - Screen_width*Pixel_width; - height = Screen_SDL->h - Screen_height*Pixel_height; - if (width) - { - SDL_Rect r; - r.x=Screen_SDL->w - width; - r.y=0; - r.h=Screen_SDL->h; - r.w=width; - SDL_FillRect(Screen_SDL,&r,color); -#ifdef ANDROID - SDL_BlitSurface(Screen_SDL, NULL, Screen_SDL_Hardware, NULL); - SDL_UpdateRect(Screen_SDL_Hardware, r.x, r.y, r.w, r.h); -#else - SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h); -#endif - } - if (height) - { - SDL_Rect r; - r.x=0; - r.y=Screen_SDL->h - height; - r.h=height; - r.w=Screen_SDL->w - height; - SDL_FillRect(Screen_SDL,&r,color); -#ifdef ANDROID - SDL_BlitSurface(Screen_SDL, NULL, Screen_SDL_Hardware, NULL); - SDL_UpdateRect(Screen_SDL_Hardware, r.x, r.y, r.w, r.h); -#else - SDL_UpdateRect(Screen_SDL, r.x, r.y, r.w, r.h); -#endif - } -} - -/// 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/project/jni/application/grafx2/grafx2/src/sdlscreen.h b/project/jni/application/grafx2/grafx2/src/sdlscreen.h deleted file mode 100644 index 8c58a1412..000000000 --- a/project/jni/application/grafx2/grafx2/src/sdlscreen.h +++ /dev/null @@ -1,77 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file sdlscreen.h -/// Screen update (refresh) system, and some SDL-specific graphic functions. -////////////////////////////////////////////////////////////////////////////// - -#ifndef SDLSCREEN_H_INCLUDED -#define SDLSCREEN_H_INCLUDED - -#include -#include "struct.h" - -/// -/// This is the number of bytes in a video line for the current mode. -/// On many platforms it will be the video mode's width (in pixels), rounded up -/// to be a multiple of 4. -#define VIDEO_LINE_WIDTH (Screen_SDL->pitch) - -void Set_mode_SDL(int *,int *,int); - -SDL_Rect ** List_SDL_video_modes; -byte* Screen_pixels; - -void Update_rect(short x, short y, unsigned short width, unsigned short height); -void Flush_update(void); -void Update_status_line(short char_pos, short width); - -/// -/// Converts a SDL_Surface (indexed colors or RGB) into an array of bytes -/// (indexed colors). -/// If dest is NULL, it's allocated by malloc(). Otherwise, be sure to -/// pass a buffer of the right dimensions. -byte * Surface_to_bytefield(SDL_Surface *source, byte * dest); -/// Gets the RGB 24-bit color currently associated with a palette index. -SDL_Color Color_to_SDL_color(byte); -/// Reads a pixel in a 8-bit SDL surface. -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); - -/// -/// Clears the parts of screen that are outside of the editing area. -/// There is such area only if the screen mode is not a multiple of the pixel -/// 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/project/jni/application/grafx2/grafx2/src/setup.c b/project/jni/application/grafx2/grafx2/src/setup.c deleted file mode 100644 index b0a62f8ae..000000000 --- a/project/jni/application/grafx2/grafx2/src/setup.c +++ /dev/null @@ -1,240 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -#include -#include -#include -#include -#include -#if defined(__WIN32__) - #include - #include // Mingw's _mkdir() -#elif defined(__macosx__) - #import - #import -#elif defined(__FreeBSD__) - #import -#elif defined(__MINT__) - #include - #include -#elif defined(__linux__) - #include - #include -#endif - -#include "struct.h" -#include "io.h" -#include "setup.h" - -#if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) - // This is a random default value ... - #define PATH_MAX 32768 -#endif - -int Create_ConfigDirectory(char * config_dir) -{ - #ifdef __WIN32__ - // Mingw's mkdir has a weird name and only one argument - return _mkdir(config_dir); - #else - return mkdir(config_dir,S_IRUSR|S_IWUSR|S_IXUSR); - #endif -} - -#if defined(__macosx__) || defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) && !defined(__VBCC__) - #define ARG_UNUSED __attribute__((unused)) -#else - #define ARG_UNUSED -#endif -// Determine which directory contains the executable. -// IN: Main's argv[0], some platforms need it, some don't. -// OUT: Write into program_dir. Trailing / or \ is kept. -// Note : in fact this is only used to check for the datafiles and fonts in -// this same directory. -void Set_program_directory(ARG_UNUSED const char * argv0,char * program_dir) -{ - #undef ARG_UNUSED - - // MacOSX - #if defined(__macosx__) - CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFURLGetFileSystemRepresentation(url,true,(UInt8*)program_dir,MAXPATHLEN); - CFRelease(url); - // Append trailing slash - strcat(program_dir ,"/"); - - // AmigaOS and alike: hard-coded volume name. - #elif defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__) - strcpy(program_dir,"PROGDIR:"); - #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(ANDROID) - strcpy(program_dir, "./"); - #elif defined(__linux__) - if (argv0[0]!='/') - { - char path[PATH_MAX]; - readlink("/proc/self/exe", path, sizeof(path)); - Extract_path(program_dir, path); - return; - } - Extract_path(program_dir, argv0); - - // Others: The part of argv[0] before the executable name. - // Keep the last \ or /. - // On Windows, Mingw32 already provides the full path in all cases. - #else - Extract_path(program_dir, argv0); - #endif -} - -// Determine which directory contains the read-only data. -// IN: The directory containing the executable -// OUT: Write into data_dir. Trailing / or \ is kept. -void Set_data_directory(const char * program_dir, char * data_dir) -{ - // On all platforms, data is relative to the executable's directory - strcpy(data_dir,program_dir); - // On MacOSX, it is stored in a special folder: - #if defined(__macosx__) - strcat(data_dir,"Contents/Resources/"); - // On GP2X, executable is not in bin/ - #elif defined (__GP2X__) || defined (__gp2x__) || defined (__WIZ__) || defined (__CAANOO__) || defined(ANDROID) - 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 -} - -// Determine which directory should store the user's configuration. -// -// For most Unix and Windows platforms: -// If a config file already exists in program_dir, it will return it in priority -// (Useful for development, and possibly for upgrading from DOS version) -// If the standard directory doesn't exist yet, this function will attempt -// to create it ($(HOME)/.grafx2, or %APPDATA%\GrafX2) -// If it cannot be created, this function will return the executable's -// own directory. -// IN: The directory containing the executable -// OUT: Write into config_dir. Trailing / or \ is kept. -void Set_config_directory(const char * program_dir, char * config_dir) -{ - // AmigaOS4 - #if defined(__amigaos4__) || defined(__AROS__) - strcpy(config_dir,"PROGDIR:"); - // GP2X - #elif defined(__GP2X__) || 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 the remaining targets except OSX, the executable is in ./bin - #if !defined(__macosx__) - strcat(config_dir, "../"); - #endif - strcpy(filename, config_dir); - strcat(filename, CONFIG_FILENAME); - - if (!File_exists(filename)) - { - char *config_parent_dir; - #if defined(__WIN32__) - // "%APPDATA%\GrafX2" - const char* Config_SubDir = "GrafX2"; - config_parent_dir = getenv("APPDATA"); - #elif defined(__BEOS__) || defined(__HAIKU__) - // "~/.grafx2", the BeOS way - const char* Config_SubDir = ".grafx2"; - config_parent_dir = getenv("$HOME"); - #elif defined(__macosx__) - // "~/Library/Preferences/com.googlecode.grafx2" - const char* Config_SubDir = "Library/Preferences/com.googlecode.grafx2"; - config_parent_dir = getenv("HOME"); - #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"; - config_parent_dir = getenv("HOME"); - #endif - - if (config_parent_dir && config_parent_dir[0]!='\0') - { - int size = strlen(config_parent_dir); - strcpy(config_dir, config_parent_dir); - if (config_parent_dir[size-1] != '\\' && config_parent_dir[size-1] != '/') - { - strcat(config_dir,PATH_SEPARATOR); - } - strcat(config_dir,Config_SubDir); - if (Directory_exists(config_dir)) - { - // Répertoire trouvé, ok - strcat(config_dir,PATH_SEPARATOR); - } - else - { - // Tentative de création - if (!Create_ConfigDirectory(config_dir)) - { - // Réussi - strcat(config_dir,PATH_SEPARATOR); - } - else - { - // Echec: on se rabat sur le repertoire de l'executable. - strcpy(config_dir,program_dir); - #if defined(__macosx__) - strcat(config_dir, "../"); - #endif - } - } - } - } - #endif -} diff --git a/project/jni/application/grafx2/grafx2/src/setup.h b/project/jni/application/grafx2/grafx2/src/setup.h deleted file mode 100644 index 678695128..000000000 --- a/project/jni/application/grafx2/grafx2/src/setup.h +++ /dev/null @@ -1,157 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file setup.h -/// Functions that determine where grafx2 is running, finds its data, and -/// reads and writes configuration files. -////////////////////////////////////////////////////////////////////////////// - -/// -/// Determine which directory contains the executable. -/// - IN: Main's argv[0], some platforms need it, some don't. -/// - OUT: Write into program_dir. Trailing / or \ is kept. -/// Note : in fact this is only used to check for the datafiles and fonts in this same directory. -void Set_program_directory(const char * argv0,char * program_dir); - -/// -/// Determine which directory contains the read-only data. -/// IN: The directory containing the executable -/// OUT: Write into data_dir. Trailing / or \ is kept. -void Set_data_directory(const char * program_dir, char * data_dir); - -/// -/// Determine which directory should store the user's configuration. -/// For most Unix and Windows platforms: -/// If a config file already exists in program_dir, it will return it in priority -/// (Useful for development, and possibly for upgrading from DOS version) -/// If the standard directory doesn't exist yet, this function will attempt -/// to create it ($(HOME)/.grafx2, or %APPDATA%\\GrafX2) -/// If it cannot be created, this function will return the executable's -/// own directory. -/// IN: The directory containing the executable -/// OUT: Write into config_dir. Trailing / or \ is kept. -void Set_config_directory(const char * program_dir, char * config_dir); - - -/// 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/project/jni/application/grafx2/grafx2/src/shade.c b/project/jni/application/grafx2/grafx2/src/shade.c deleted file mode 100644 index bab856dbc..000000000 --- a/project/jni/application/grafx2/grafx2/src/shade.c +++ /dev/null @@ -1,1132 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include - -#include "global.h" -#include "graph.h" -#include "engine.h" -#include "errors.h" -#include "misc.h" -#include "readline.h" -#include "help.h" -#include "sdlscreen.h" -#include "windows.h" -#include "input.h" -#include "shade.h" - -void Button_Shade_mode(void) -{ - if (Shade_mode) - Effect_function=No_effect; - else - { - Effect_function=Effect_shade; - Quick_shade_mode=0; - Colorize_mode=0; - Smooth_mode=0; - Tiling_mode=0; - Smear_mode=0; - } - Shade_mode=!Shade_mode; -} - - -void Button_Quick_shade_mode(void) -{ - if (Quick_shade_mode) - Effect_function=No_effect; - else - { - Effect_function=Effect_quick_shade; - Shade_mode=0; - Colorize_mode=0; - Smooth_mode=0; - Tiling_mode=0; - Smear_mode=0; - } - Quick_shade_mode=!Quick_shade_mode; -} - - -void Shade_draw_grad_ranges(void) -{ - word cursor=0; - word nb_shades=0; - short shade_processed,shade_processed_old; - word shade_size=0; - word start_shade=0; - short x_pos,y_pos; - short x_size,y_size; - short start_x,start_y,end_x,end_y; - - // On commence par compter le nombre de shades - while (cursor<512) - { - while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00)) - cursor++; - - if (cursor<512) - { - nb_shades++; - while ( (cursor<512) - && (!(Shade_list[Shade_current].List[cursor]&0xFF00)) ) - cursor++; - } - } - - // Maintenant qu'on sait combien il y en a, on les affiche: - if (nb_shades) - { - x_size=Menu_factor_X<<6; - y_size=Menu_factor_Y*48; - start_x=Window_pos_X+(Menu_factor_X*224); - start_y=Window_pos_Y+(Menu_factor_Y*35); - end_x=start_x+x_size; - end_y=start_y+y_size; - - cursor=0; - shade_processed_old=-1; - - for (y_pos=start_y;y_posshade_processed_old) - { - // On commence par sauter tous les vides jusqu'au prochain shade - while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00)) - cursor++; - start_shade=cursor; - // puis regarde sa taille - while ((cursor<512) && (!(Shade_list[Shade_current].List[cursor]&0xFF00))) - cursor++; - shade_size=cursor-start_shade; - shade_processed_old=shade_processed; - } - - for (x_pos=start_x;x_pos=selection_start) && (position<=selection_end)) - { - Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y,MC_White); - Block(x_pos,y_pos+Menu_factor_Y,Menu_factor_X<<2,Menu_factor_Y,MC_Black); - } - else - Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_White); - } - else // "enablée" - { - if ((position>=selection_start) && (position<=selection_end)) - Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Black); - else - Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Light); - } - } - Update_rect(Window_pos_X+8*Menu_factor_X,Window_pos_Y+131*Menu_factor_Y,Menu_factor_X*64<<2,Menu_factor_Y*8<<3); -} - - -void Display_selected_cell_color(word selection_start,word selection_end) -{ - char str[4]; - - if ((selection_start!=selection_end) - || (Shade_list[Shade_current].List[selection_start]&0x0100)) - strcpy(str," "); - else - Num2str(Shade_list[Shade_current].List[selection_start]&0xFF,str,3); - - Print_in_window(213,115,str,MC_Black,MC_Light); -} - - -void Display_selected_color(word selection_start,word selection_end) -{ - char str[4]; - - if (selection_start!=selection_end) - strcpy(str," "); - else - Num2str(selection_start,str,3); - - Print_in_window(213,106,str,MC_Black,MC_Light); -} - - -void Display_shade_mode(short x,short y,byte mode) -{ - char str[7]; - - switch (mode) - { - case SHADE_MODE_NORMAL : - strcpy(str,"Normal"); - break; - case SHADE_MODE_LOOP : - strcpy(str," Loop "); - break; - default : // SHADE_MODE_NOSAT - strcpy(str,"No sat"); - } - Print_in_window(x,y,str,MC_Black,MC_Light); -} - - -void Display_all_shade(word selection_start1,word selection_end1, - word selection_start2,word selection_end2) -{ - word line, column; - word position; - - for (line=0; line<8; line++) - for (column=0; column<64; column++) - { - position=(line<<6)+column; - // On regarde si c'est une couleur ou un bloc vide - if (Shade_list[Shade_current].List[position]&0x0100) // Vide - { - Window_display_frame_out((column<<2)+8,(line*7)+127,4,4); - Block(Window_pos_X+(Menu_factor_X*((column<<2)+9)), - Window_pos_Y+(Menu_factor_Y*((line*7)+128)), - Menu_factor_X<<1,Menu_factor_Y<<1,MC_Light); - } - else // color - Block(Window_pos_X+(Menu_factor_X*((column<<2)+8)), - Window_pos_Y+(Menu_factor_Y*((line*7)+127)), - Menu_factor_X<<2,Menu_factor_Y<<2, - Shade_list[Shade_current].List[position]&0xFF); - } - Update_rect(Window_pos_X+7*Menu_factor_X,Window_pos_Y+126*Menu_factor_Y,Menu_factor_X*((64<<2)+2),Menu_factor_Y*((8<<2)+2)); - Tag_shades(selection_start2,selection_end2); - Shade_draw_grad_ranges(); - Display_selected_cell_color(selection_start2,selection_end2); - Display_selected_color(selection_start1,selection_end1); - Display_shade_mode(250,110,Shade_list[Shade_current].Mode); -} - - -void Remove_shade(word selection_start,word selection_end) -{ - word temp; - - if (selection_end=512) - temp=512-selection_start; - - for (cursor=511;cursor>=limit;cursor--) - Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-temp]; - - for (cursor=selection_start+temp;selection_start=512) return; - - for (cursor=511;cursor>position;cursor--) - Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-1]; - - Shade_list[Shade_current].List[position]=0x0100; -} - - -short Wait_click_in_shade_table() -{ - short selected_cell=-1; - byte old_hide_cursor; - - - Hide_cursor(); - old_hide_cursor=Cursor_hidden; - Cursor_hidden=0; - Cursor_shape=CURSOR_SHAPE_TARGET; - Display_cursor(); - - while (selected_cell<0) - { - 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) ) - || ( (Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) - || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) ) ) - ) - selected_cell=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+ - ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2); - - if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC)) - selected_cell=512; // valeur indiquant que l'on n'a rien choisi - } - - Hide_cursor(); - Cursor_shape=CURSOR_SHAPE_ARROW; - Cursor_hidden=old_hide_cursor; - Display_cursor(); - return selected_cell; -} - - -void Swap_shade(short block_1_start,short block_2_start,short block_size) -{ - short pos_1; - short pos_2; - short end_1; - short end_2; - word temp; - word * temp_shade; - - // On fait une copie de la liste - temp_shade=(word *)malloc(512*sizeof(word)); - memcpy(temp_shade,Shade_list[Shade_current].List,512*sizeof(word)); - - // On calcul les dernières couleurs de chaque bloc. - end_1=block_1_start+block_size-1; - end_2=block_2_start+block_size-1; - - if ((block_2_start>=block_1_start) && (block_2_start<=end_1)) - { - // Le bloc destination commence dans le bloc source. - for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++) - { - // Il faut transformer la case pos_1 en pos_2: - Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2]; - // On gère la mise à jour de pos_2 - if (pos_2==end_2) - pos_2=block_1_start; - else - pos_2++; - } - } - else - if ((block_2_start=block_1_start)) - { - // Le bloc destination déborde dans le bloc source. - for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++) - { - // Il faut transformer la couleur pos_1 en pos_2: - Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2]; - // On gère la mise à jour de pos_2 - if (pos_2==end_1) - pos_2=block_2_start; - else - pos_2++; - } - } - else - { - // Le bloc source et le bloc destination sont distincts. - for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++) - { - // On échange les cases - temp =Shade_list[Shade_current].List[pos_1]; - Shade_list[Shade_current].List[pos_1]=Shade_list[Shade_current].List[pos_2]; - Shade_list[Shade_current].List[pos_2]=temp; - } - } - - free(temp_shade); -} - - -int Menu_shade(void) -{ - short clicked_button; // Numéro du bouton sur lequel l'utilisateur a clické - char str[4]; // str d'affichage du n° de shade actif et du Pas - word old_mouse_x, old_mouse_x2; // Mémo. de l'ancienne pos. du curseur - word old_mouse_y, old_mouse_y2; - byte old_mouse_k, old_mouse_k2; - byte temp_color; // Variables de gestion des clicks dans la palette - byte first_color = Fore_color; - byte last_color = Fore_color; - word selection_start = 0; - word selection_end = 0; - T_Special_button * input_button; - short temp, temp2; - word temp_cell; - word * buffer; // buffer du Copy/Paste - word * undo_buffer; // buffer du Undo - word * temp_ptr; - byte color; - byte click; - - - buffer =(word *)malloc(512*sizeof(word)); - undo_buffer =(word *)malloc(512*sizeof(word)); - temp_ptr=(word *)malloc(512*sizeof(word)); - - // Ouverture de la fenêtre du menu - Open_window(310,190,"Shade"); - - // Déclaration & tracé du bouton de palette - Window_set_palette_button(5,16); // 1 - - // Déclaration & tracé du scroller de sélection du n° de dégradé - Window_set_scroller_button(192,17,84,8,1,Shade_current); // 2 - - // Déclaration & tracé de la zone de définition des dégradés - Window_set_special_button(8,127,256,53); // 3 - - // Déclaration & tracé des boutons de sortie - Window_set_normal_button(207,17,51,14,"Cancel",0,1,KEY_ESC); // 4 - Window_set_normal_button(261,17,43,14,"OK" ,0,1,SDLK_RETURN); // 5 - - // Déclaration & tracé des boutons de copie de shade - Window_set_normal_button(206,87,27,14,"Cpy" ,1,1,SDLK_c); // 6 - Window_set_normal_button(234,87,43,14,"Paste" ,1,1,SDLK_p); // 7 - - // On tagge le bloc - Tag_color_range(Fore_color,Fore_color); - - // Tracé d'un cadre creux autour du bloc dégradé - Window_display_frame_in(171,26,18,66); - Block(Window_pos_X+(Menu_factor_X*172),Window_pos_Y+(Menu_factor_Y*27), - Menu_factor_X<<4,Menu_factor_Y<<6,MC_Black); - // Tracé d'un cadre creux autour de tous les dégradés - Window_display_frame_in(223,34,66,50); - Shade_draw_grad_ranges(); - // Tracé d'un cadre autour de la zone de définition de dégradés - Window_display_frame(5,124,262,61); - Display_all_shade(first_color,last_color,selection_start,selection_end); - - // Déclaration & tracé des boutons d'édition de shade - Window_set_normal_button( 6,107,27,14,"Ins" ,0,1,SDLK_INSERT); // 8 - Window_set_normal_button( 38,107,27,14,"Del" ,0,1,SDLK_DELETE); // 9 - Window_set_normal_button( 66,107,43,14,"Blank",1,1,SDLK_b); // 10 - Window_set_normal_button(110,107,27,14,"Inv" ,1,1,SDLK_i); // 11 - Window_set_normal_button(138,107,27,14,"Swp" ,1,1,SDLK_s); // 12 - - // Déclaration & tracé des boutons de taggage - Print_in_window(268,123,"Disbl"/*"Dsabl"*/,MC_Dark,MC_Light); - Window_set_normal_button(274,133,27,14,"Set" ,0,1,SDLK_F1); // 13 - Window_set_normal_button(274,148,27,14,"Clr" ,0,1,SDLK_F2); // 14 - - // Déclaration & tracé de la zone de saisie du pas - Print_in_window(272,165,"Step",MC_Dark,MC_Light); - input_button = Window_set_input_button(274,174,3); // 15 - Num2str(Shade_list[Shade_current].Step,str,3); - Window_input_content(input_button,str); - - // Button Undo - Window_set_normal_button(170,107,35,14,"Undo",1,1,SDLK_u); // 16 - // Button Clear - Window_set_normal_button(278,87,27,14,"Clr",0,1,SDLK_BACKSPACE); // 17 - - // Button Mode - Window_set_normal_button(244,107,60,14,"",0,1,SDLK_TAB); // 18 - - // Affichage du n° de shade actif - Num2str(Shade_current+1,str,1); - Print_in_window(210,55,str,MC_Black,MC_Light); - - memcpy(buffer ,Shade_list[Shade_current].List,512*sizeof(word)); - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - - Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*310,Menu_factor_Y*190); - - Display_cursor(); - - do - { - old_mouse_x=old_mouse_x2=Mouse_X; - old_mouse_y=old_mouse_y2=Mouse_Y; - old_mouse_k=old_mouse_k2=Mouse_K; - - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case 0 : - break; - case -1 : - case 1 : // Gestion de la palette - if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) ) - { - Hide_cursor(); - temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y); - - if (!old_mouse_k) - { // On vient de clicker - - // On met à jour l'intervalle du Shade - first_color=last_color=temp_color; - // On tagge le bloc - Tag_color_range(first_color,last_color); - // Tracé du bloc dégradé: - Display_grad_block_in_window(172,27,first_color,last_color); - } - else - { // On maintient le click, on va donc tester si le curseur bouge - if (temp_color!=last_color) - { - last_color=temp_color; - - // On tagge le bloc - if (first_color<=temp_color) - { - Tag_color_range(first_color,last_color); - Display_grad_block_in_window(172,27,first_color,last_color); - } - else - { - Tag_color_range(last_color,first_color); - Display_grad_block_in_window(172,27,last_color,first_color); - } - } - } - - // On affiche le numéro de la couleur sélectionnée - Display_selected_color(first_color,last_color); - - Display_cursor(); - } - break; - - case 2 : // Gestion du changement de Shade (scroller) - Hide_cursor(); - Shade_current=Window_attribute2; - // Affichade du n° de shade actif - Num2str(Shade_current+1,str,1); - Print_in_window(210,55,str,MC_Black,MC_Light); - // Affichade du Pas - Num2str(Shade_list[Shade_current].Step,str,3); - Print_in_window(276,176,str,MC_Black,MC_Light); - // Tracé du bloc dégradé: - Display_all_shade(first_color,last_color,selection_start,selection_end); - Display_cursor(); - // On place le nouveau shade dans le buffer du Undo - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - break; - - case 3 : // Gestion de la zone de définition de shades - if (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) - if ( (Mouse_X!=old_mouse_x2) || (Mouse_Y!=old_mouse_y2) || (Mouse_K!=old_mouse_k2) ) - { - Hide_cursor(); - selection_end=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+ - ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2); - if (!old_mouse_k2) // On vient de clicker - selection_start=selection_end; - Tag_shades(selection_start,selection_end); - Display_selected_cell_color(selection_start,selection_end); - Display_cursor(); - } - break; - - case 5: // Ok - if (selection_start == selection_end && Shade_list[Shade_current].List[selection_start] > 0) - Set_fore_color(Shade_list[Shade_current].List[selection_start]); - else if (first_color == last_color) - Set_fore_color(first_color); - break; - - case 6 : // Copy - memcpy(buffer,Shade_list[Shade_current].List,512*sizeof(word)); - break; - - case 7 : // Paste - // On place le shade dans le buffer du Undo - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - // Et on le modifie - memcpy(Shade_list[Shade_current].List,buffer,512*sizeof(word)); - Hide_cursor(); - Display_all_shade(first_color,last_color,selection_start,selection_end); - Display_cursor(); - break; - - case 8 : // Insert - // On place le shade dans le buffer du Undo - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - // Et on le modifie - if (first_color<=last_color) - temp=last_color-first_color; - else - temp=first_color-last_color; - - if (selection_start==selection_end) // Une couleur sélectionnée - { - if (Window_attribute1==2) - Remove_shade(selection_start,selection_start+temp); - } - else // Un bloc sélectionné - { - Remove_shade(selection_start,selection_end); - - if (first_color<=last_color) - temp=last_color-first_color; - else - temp=first_color-last_color; - - if (selection_start=512) - selection_start=511; - selection_end=selection_start; - - Hide_cursor(); - Display_all_shade(first_color,last_color,selection_start,selection_end); - Display_cursor(); - break; - - case 9 : // Delete - // On place le shade dans le buffer du Undo - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - // Et on le modifie - Remove_shade(selection_start,selection_end); - if (selection_start<=selection_end) - selection_end=selection_start; - else - selection_start=selection_end; - Hide_cursor(); - Display_all_shade(first_color,last_color,selection_start,selection_end); - Display_cursor(); - break; - - case 10 : // Blank - // On place le shade dans le buffer du Undo - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - // Et on le modifie - if (Window_attribute1==RIGHT_SIDE) // Click droit - { - if (selection_start!=selection_end) - { - if (selection_start<=selection_end) - { - Insert_empty_cell_in_shade(selection_start); - Insert_empty_cell_in_shade(selection_end+2); - } - else - { - Insert_empty_cell_in_shade(selection_end); - Insert_empty_cell_in_shade(selection_start+2); - } - } - else - Insert_empty_cell_in_shade(selection_start); - - if (selection_start<511) selection_start++; - if (selection_end<511) selection_end++; - } - else // Click gauche - { - if (selection_start<=selection_end) - { - temp=selection_start; - temp2=selection_end; - } - else - { - temp=selection_end; - temp2=selection_start; - } - while (temp<=temp2) - Shade_list[Shade_current].List[temp++]=0x0100; - } - - Hide_cursor(); - Display_all_shade(first_color,last_color,selection_start,selection_end); - Display_cursor(); - break; - - case 11 : // Invert - // On place le shade dans le buffer du Undo - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - // Et on le modifie - if (selection_start<=selection_end) - { - temp=selection_start; - temp2=selection_end; - } - else - { - temp=selection_end; - temp2=selection_start; - } - - for (;temp255) - { - temp=255; - Num2str(temp,str,3); - Window_input_content(input_button,str); - } - Shade_list[Shade_current].Step=temp; - Display_cursor(); - break; - - case 16 : // Undo - memcpy(temp_ptr,undo_buffer,512*sizeof(word)); - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - memcpy(Shade_list[Shade_current].List,temp_ptr,512*sizeof(word)); - - Hide_cursor(); - Display_all_shade(first_color,last_color,selection_start,selection_end); - Display_cursor(); - break; - - case 17 : // Clear - memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word)); - for (temp=0;temp<512;temp++) - Shade_list[Shade_current].List[temp]=0x0100; - Hide_cursor(); - Display_all_shade(first_color,last_color,selection_start,selection_end); - Display_cursor(); - break; - - case 18 : // Mode - Shade_list[Shade_current].Mode=(Shade_list[Shade_current].Mode+1)%3; - Hide_cursor(); - Display_shade_mode(250,110,Shade_list[Shade_current].Mode); - Display_cursor(); - } - - if (!Mouse_K) - switch (Key) - { - case SDLK_LEFTBRACKET : // Décaler couleur dans palette vers la gauche - case SDLK_RIGHTBRACKET : // Décaler couleur dans palette vers la droite - if (first_color==last_color) - { - if (Key==SDLK_LEFTBRACKET) - { - first_color--; - last_color--; - } - else - { - first_color++; - last_color++; - } - Hide_cursor(); - Tag_color_range(first_color,first_color); - Block(Window_pos_X+(Menu_factor_X*172), - Window_pos_Y+(Menu_factor_Y*27), - Menu_factor_X<<4,Menu_factor_Y*64,first_color); - // On affiche le numéro de la couleur sélectionnée - Display_selected_color(first_color,last_color); - Display_cursor(); - } - Key=0; - break; - - case SDLK_UP : // Select Haut - case SDLK_DOWN : // Select Bas - case SDLK_LEFT : // Select Gauche - case SDLK_RIGHT : // Select Droite - if (selection_start==selection_end) - { - switch (Key) - { - case SDLK_UP : // Select Haut - if (selection_start>=64) - { - selection_start-=64; - selection_end-=64; - } - else - selection_start=selection_end=0; - break; - case SDLK_DOWN : // Select Bas - if (selection_start<448) - { - selection_start+=64; - selection_end+=64; - } - else - selection_start=selection_end=511; - break; - case SDLK_LEFT : // Select Gauche - if (selection_start>0) - { - selection_start--; - selection_end--; - } - break; - default : // Select Droite - if (selection_start<511) - { - selection_start++; - selection_end++; - } - } - Hide_cursor(); - Tag_shades(selection_start,selection_start); - Display_selected_cell_color(selection_start,selection_start); - Display_cursor(); - } - Key=0; - break; - - case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu - case SDLK_COMMA : - Get_color_behind_window(&color,&click); - if (click) - { - Hide_cursor(); - temp_color=color; - - // On met à jour l'intervalle du Shade - first_color=last_color=temp_color; - // On tagge le bloc - Tag_color_range(first_color,last_color); - // Tracé du bloc dégradé: - Display_grad_block_in_window(172,27,first_color,last_color); - - // On affiche le numéro de la couleur sélectionnée - Display_selected_color(first_color,last_color); - - Display_cursor(); - Wait_end_of_click(); - } - Key=0; - break; - default: - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Key=0; - Window_help(BUTTON_EFFECTS, "SHADE"); - } - else if (Is_shortcut(Key,SPECIAL_SHADE_MENU)) - clicked_button=5; - } - } - while ((clicked_button!=4) && (clicked_button!=5)); - - Close_window(); - free(undo_buffer); - free(buffer); - free(temp_ptr); - - return (clicked_button==5); -} - -/// Handles the screen with Shade settings. -/// @return true if user clicked ok, false if he cancelled -int Shade_settings_menu(void) -{ - T_Shade * initial_shade_list; // Anciennes données des shades - byte old_shade; // old n° de shade actif - int return_code; - - // Backup des anciennes données - initial_shade_list=(T_Shade *)malloc(sizeof(Shade_list)); - memcpy(initial_shade_list,Shade_list,sizeof(Shade_list)); - old_shade=Shade_current; - - return_code = Menu_shade(); - if (!return_code) // Cancel - { - memcpy(Shade_list,initial_shade_list,sizeof(Shade_list)); - Shade_current=old_shade; - } - else // OK - { - Shade_list_to_lookup_tables(Shade_list[Shade_current].List, - Shade_list[Shade_current].Step, - Shade_list[Shade_current].Mode, - Shade_table_left,Shade_table_right); - } - - free(initial_shade_list); - - Display_cursor(); - - return return_code; -} - - -void Button_Shade_menu(void) -{ - if (Shade_settings_menu()) - { - // If user clicked OK while in the menu, activate Shade mode. - if (!Shade_mode) - Button_Shade_mode(); - } -} - - -void Button_Quick_shade_menu(void) -{ - short clicked_button; - int temp; - char str[4]; - byte step_backup=Quick_shade_step; // Backup des - byte loop_backup=Quick_shade_loop; // anciennes données - T_Special_button * step_button; - - Open_window(142,56,"Quick-shade"); - - Window_set_normal_button(76,36,60,14,"OK",0,1,SDLK_RETURN); // 1 - Window_set_normal_button( 6,36,60,14,"Cancel",0,1,KEY_ESC); // 2 - Window_set_normal_button(76,18,60,14,"",0,1,SDLK_TAB); // 3 - Display_shade_mode(83,21,Quick_shade_loop); - - // Déclaration & tracé de la zone de saisie du pas - Print_in_window(5,21,"Step",MC_Dark,MC_Light); - step_button = Window_set_input_button(40,19,3); // 4 - Num2str(Quick_shade_step,str,3); - Window_input_content(step_button,str); - - Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*142,Menu_factor_Y*56); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - - switch (clicked_button) - { - case 3 : // Mode - Quick_shade_loop=(Quick_shade_loop+1)%3; - Hide_cursor(); - Display_shade_mode(83,21,Quick_shade_loop); - Display_cursor(); - break; - - case 4 : // Saisie du pas - Num2str(Quick_shade_step,str,3); - Readline(42,21,str,3,INPUT_TYPE_INTEGER); - temp=atoi(str); - // On corrige le pas - if (!temp) - { - temp=1; - Num2str(temp,str,3); - Window_input_content(step_button,str); - } - else if (temp>255) - { - temp=255; - Num2str(temp,str,3); - Window_input_content(step_button,str); - } - Quick_shade_step=temp; - Display_cursor(); - } - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - Window_help(BUTTON_EFFECTS, "QUICK SHADE"); - else if (Is_shortcut(Key,SPECIAL_QUICK_SHADE_MENU)) - clicked_button=1; - } - while ((clicked_button!=1) && (clicked_button!=2)); - - Close_window(); - - if (clicked_button==2) // Cancel - { - Quick_shade_step=step_backup; - Quick_shade_loop=loop_backup; - } - else // OK - { - // Si avant de rentrer dans le menu on n'était pas en mode Quick-Shade - if (!Quick_shade_mode) - Button_Quick_shade_mode(); // => On y passe (cool!) - } - - Display_cursor(); -} diff --git a/project/jni/application/grafx2/grafx2/src/shade.h b/project/jni/application/grafx2/grafx2/src/shade.h deleted file mode 100644 index 94278e55c..000000000 --- a/project/jni/application/grafx2/grafx2/src/shade.h +++ /dev/null @@ -1,34 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -////////////////////////////////////////////////////////////////////////////// -///@file shade.h -/// Screens for Shade and Quick-shade settings. -////////////////////////////////////////////////////////////////////////////// - - -#ifndef SHADE_H_INCLUDED -#define SHADE_H_INCLUDED - -void Button_Quick_shade_menu(void); - -int Shade_settings_menu(void); - -#endif // SHADE_H_INCLUDED diff --git a/project/jni/application/grafx2/grafx2/src/special.c b/project/jni/application/grafx2/grafx2/src/special.c deleted file mode 100644 index 6e3dc579f..000000000 --- a/project/jni/application/grafx2/grafx2/src/special.c +++ /dev/null @@ -1,468 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include -#include "const.h" -#include "struct.h" -#include "global.h" -#include "graph.h" -#include "engine.h" -#include "windows.h" -#include "special.h" -#include "pages.h" -#include "misc.h" -#include "buttons.h" - - - - - -//---------------------- Modifier le pinceau spécial ------------------------- - -int Circle_squared_diameter(int diameter) -{ - int result = diameter*diameter; - // Trick to make some circles rounder, even though - // mathematically incorrect. - if (diameter==3 || diameter==9) - return result-2; - if (diameter==11) - return result-6; - if (diameter==14) - return result-4; - - return result; -} - -void Set_paintbrush_size(int width, int height) -{ - int x_pos,y_pos; - int x,y; - int radius2; - - if (width<1) width=1; - if (height<1) height=1; - if (width>MAX_PAINTBRUSH_SIZE) width=MAX_PAINTBRUSH_SIZE; - if (height>MAX_PAINTBRUSH_SIZE) height=MAX_PAINTBRUSH_SIZE; - Paintbrush_width=width; - Paintbrush_height=height; - Paintbrush_offset_X=Paintbrush_width>>1; - Paintbrush_offset_Y=Paintbrush_height>>1; - switch (Paintbrush_shape) - { - case PAINTBRUSH_SHAPE_ROUND : - radius2=Circle_squared_diameter(Paintbrush_width); - - for (y_pos=0, y=1-Paintbrush_height; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos>1; - for (y_pos=0; y_pos0) - Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos-1]=0; - if (y_pos>0) - Paintbrush_sprite[((y_pos-1)*MAX_PAINTBRUSH_SIZE)+x_pos]=0; - } - } - } -} - -void Smaller_paintbrush(void) -{ - if ( (Paintbrush_shape1) - || (Paintbrush_height>1) ) ) - { - Hide_cursor(); - switch (Paintbrush_shape) - { - case PAINTBRUSH_SHAPE_CROSS: - case PAINTBRUSH_SHAPE_PLUS: - case PAINTBRUSH_SHAPE_DIAMOND: - if (Paintbrush_width&1) - Set_paintbrush_size(Paintbrush_width-2,Paintbrush_height-2); - else - Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); - break; - case PAINTBRUSH_SHAPE_SQUARE: - case PAINTBRUSH_SHAPE_SLASH: - case PAINTBRUSH_SHAPE_ANTISLASH: - case PAINTBRUSH_SHAPE_SIEVE_SQUARE: - case PAINTBRUSH_SHAPE_ROUND: - case PAINTBRUSH_SHAPE_SIEVE_ROUND: - case PAINTBRUSH_SHAPE_RANDOM: - Set_paintbrush_size(Paintbrush_width-1,Paintbrush_height-1); - break; - case PAINTBRUSH_SHAPE_HORIZONTAL_BAR: - Set_paintbrush_size(Paintbrush_width-1,1); - break; - case PAINTBRUSH_SHAPE_VERTICAL_BAR: - Set_paintbrush_size(1,Paintbrush_height-1); - } - Display_paintbrush_in_menu(); - Display_cursor(); - } -} - -void Bigger_paintbrush(void) -{ - if ( (Paintbrush_shapeMain_image_width) - temp_x_offset=Main_image_width-Screen_width; - if (temp_y_offset+Menu_Y>Main_image_height) - temp_y_offset=Main_image_height-Menu_Y; - if (temp_x_offset<0) - temp_x_offset=0; - if (temp_y_offset<0) - temp_y_offset=0; - - if ( (Main_offset_X!=temp_x_offset) || - (Main_offset_Y!=temp_y_offset) ) - { - Hide_cursor(); - Main_offset_X=temp_x_offset; - Main_offset_Y=temp_y_offset; - - Compute_limits(); - Compute_paintbrush_coordinates(); - - Display_all_screen(); // <=> Display_screen + Display_image_limits - Display_cursor(); - } -} - - -// ---------------------- Scroller la fenêtre de la loupe -------------------- -void Scroll_magnifier(short delta_x,short delta_y) -{ - short temp_x_offset; - short temp_y_offset; - - temp_x_offset=Main_magnifier_offset_X+delta_x; - temp_y_offset=Main_magnifier_offset_Y+delta_y; - - Clip_magnifier_offsets(&temp_x_offset, &temp_y_offset); - - if ( (Main_magnifier_offset_X!=temp_x_offset) || - (Main_magnifier_offset_Y!=temp_y_offset) ) - { - Hide_cursor(); - Main_magnifier_offset_X=temp_x_offset; - Main_magnifier_offset_Y=temp_y_offset; - - Position_screen_according_to_zoom(); - - Compute_limits(); - Compute_paintbrush_coordinates(); - - Display_all_screen(); - Display_cursor(); - } -} - - -// -------------- Changer le Zoom (grâce aux touches [+] et [-]) ------------- -void Zoom(short delta) -{ - short index; - for (index=0; ZOOM_FACTOR[index]!=Main_magnifier_factor; index++); - index+=delta; - - if ( (index>=0) && (index -*/ - -#include "struct.h" - -////////////////////////////////////////////////////////////////////////////// -///@file special.h -/// Editor functions that can be hooked to a keyboard shortcut, but don't have -/// a menu button associated to them. -////////////////////////////////////////////////////////////////////////////// - -void Set_paintbrush_size(int width, int height); -void Smaller_paintbrush(void); -void Bigger_paintbrush(void); - -void Special_next_forecolor(void); -void Special_previous_forecolor(void); -void Special_next_backcolor(void); -void Special_previous_backcolor(void); - -void Special_next_user_forecolor(void); -void Special_previous_user_forecolor(void); -void Special_next_user_backcolor(void); -void Special_previous_user_backcolor(void); - -void Scroll_screen(short delta_x,short delta_y); -void Scroll_magnifier(short delta_x,short delta_y); - -void Zoom(short delta); -void Zoom_set(int index); - -void Display_stored_brush_in_window(word x,word y,int number); -void Store_brush(int index); -byte Restore_brush(int index); - -/*! - Command that sets the transparency level. -*/ -void Transparency_set(byte amount); - diff --git a/project/jni/application/grafx2/grafx2/src/struct.h b/project/jni/application/grafx2/grafx2/src/struct.h deleted file mode 100644 index 75e610f22..000000000 --- a/project/jni/application/grafx2/grafx2/src/struct.h +++ /dev/null @@ -1,539 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file struct.h -/// Structures that can be used in the whole program. -////////////////////////////////////////////////////////////////////////////// -#ifndef _STRUCT_H_ -#define _STRUCT_H_ - -#if defined(__BEOS__) || defined(__TRU64__) - #include -#else - #include -#endif - -#include "const.h" - - -// POSIX calls it strcasecmp, Windows uses stricmp... no ANSI standard. -#ifdef WIN32 - #define strcasecmp stricmp -#endif - -// Definition of the base data types -/// 8bit unsigned integer -#define byte uint8_t -/// 16bit unsigned integer -#define word uint16_t -/// 32bit unsigned integer -#define dword uint32_t -/// 64bit unsigned integer -#define qword uint64_t - -// Named function prototypes -// GrafX2 use a lot of function pointer to do the drawing depending in the "fake hardware zoom" and the magnifier status. -typedef void (* Func_action) (void); ///< An action. Used when you click a menu button or trigger a keyboard shortcut. -typedef void (* Func_pixel) (word,word,byte); ///< Set pixel at position (x,y) to color c. Used in load screen to write the data to brush, picture, or preview area. -typedef byte (* Func_read) (word,word); ///< Read a pixel at position (x,y) on something. Used for example in save to tell if the data is a brush or a picture -typedef void (* Func_clear) (byte); -typedef void (* Func_display) (word,word,word); -typedef byte (* Func_effect) (word,word,byte); ///< Called by all drawing tools to draw with a special effect (smooth, transparency, shade, ...) -typedef void (* Func_block) (word,word,word,word,byte); -typedef void (* Func_line_XOR) (word,word,word); ///< Draw an XOR line on the picture view of the screen. Use a different function when in magnify mode. -typedef void (* Func_display_brush_color) (word,word,word,word,word,word,byte,word); -typedef void (* Func_display_brush_mono) (word,word,word,word,word,word,byte,byte,word); -typedef void (* Func_gradient) (long,short,short); -typedef void (* Func_remap) (word,word,word,word,byte *); -typedef void (* Func_procsline) (word,word,word,byte *); -typedef void (* Func_display_zoom) (word,word,word,byte *); -typedef void (* Func_display_brush_color_zoom) (word,word,word,word,word,word,byte,word,byte *); -typedef void (* Func_display_brush_mono_zoom) (word,word,word,word,word,word,byte,byte,word,byte *); -typedef void (* Func_draw_brush) (byte *,word,word,word,word,word,word,byte,word); -typedef void (* Func_draw_list_item) (word,word,word,byte); ///< 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). -#pragma pack() -#endif - -/// A normal rectangular button in windows and menus. -typedef struct T_Normal_button -{ - short Number; ///< Unique identifier for all controls - word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. - word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. - word Width; ///< Width before scaling - word Height; ///< Height before scaling - byte Clickable; ///< Boolean, unused. - byte Repeatable; ///< Boolean, true if the button activates repeatedly until you release the mouse button. Used for "+" buttons, for example. - word Shortcut; ///< Keyboard shortcut that will emulate a click on this button. - struct T_Normal_button * Next;///< Pointer to the next normal button of current window. -} T_Normal_button; - -/// A window control that shows a complete 256-color palette -typedef struct T_Palette_button -{ - short Number; ///< Unique identifier for all controls - word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. - word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. - struct T_Palette_button * Next;///< Pointer to the next palette of current window. -} T_Palette_button; - -/// A window control that represents a 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 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_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; - -/// Special invisible button -/// A window control that only has a rectangular "active" area which catches mouse clicks, -// but no visible shape. It's used for custom controls where the drawing is done on -// a case by case basis. -typedef struct T_Special_button -{ - short Number; ///< Unique identifier for all controls - word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. - word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. - word Width; ///< Width before scaling - word Height; ///< Height before scaling - struct T_Special_button * Next;///< Pointer to the next special button of current window. -} T_Special_button; - -/// Data for a dropdown item, ie. one proposed choice. -typedef struct T_Dropdown_choice -{ - short Number; ///< Value that identifies the choice (for this dropdown only) - const char * Label; ///< String to display in the dropdown panel - struct T_Dropdown_choice * Next;///< Pointer to the next choice for this dropdown. -} T_Dropdown_choice; - -/// A window control that behaves like a dropdown button. -typedef struct T_Dropdown_button -{ - short Number; ///< Unique identifier for all controls - word Pos_X; ///< Coordinate for top of button, relative to the window, before scaling. - word Pos_Y; ///< Coordinate for left of button, relative to the window, before scaling. - word Width; ///< Width before scaling - word Height; ///< Height before scaling - byte Display_choice; ///< Boolean, true if the engine should print the selected item's label in the dropdown area when the user chooses it. - byte Display_centered; ///< Boolean, true to center the labels (otherwise, align left) - byte Display_arrow; ///< Boolean, true to display a "down" arrow box in top right - byte Bottom_up; ///< Boolean, true to make the dropdown panel go above its button instead of below it - byte Active_button; ///< Determines which mouse button(s) cause the dropdown panel to open: LEFT_SIDE || RIGHT_SIDE || (LEFT_SIDE|RIGHT_SIDE) - word Dropdown_width; ///< Width of the dropdown panel when it's open. Use 0 for "same as the dropdown button" - T_Dropdown_choice * First_item; ///< Linked list with the choices available for this dropdown. - struct T_Dropdown_button * Next;///< Pointer to the next dropdown button of current window. -} T_Dropdown_button; - -/// Data for one item (file, directory) in a fileselector. -typedef struct T_Fileselector_item -{ - char 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 -typedef struct T_Fileselector -{ - /// Number of elements in the current fileselector's ::Filelist - short Nb_elements; - /// Number of files in the current fileselector's ::Filelist - short Nb_files; - /// Number of directories in the current fileselector's ::Filelist - short Nb_directories; - /// Head of the linked list for the fileselector. - T_Fileselector_item * First; - /// Index for direct access to element number N - T_Fileselector_item ** Index; -} T_Fileselector; - -/// "List" button as used in the font selection, skin selection, and brush factory screens. It's like a limited filelist. -/// The screenmode selection and load/save screen were written before this existed so they use their own code. It would be nice if they were updated to use this one. -typedef struct T_List_button -{ - short Number; ///< Unique identifier for all controls - short List_start; ///< Index of the font to appear as first line - short Cursor_position; ///< Index of the selected line (0=top) - - T_Special_button * Entry_button; ///< Pointer to the associated selection control. - T_Scroller_button * Scroller; ///< Pointer to the associated scroller - - Func_draw_list_item Draw_list_item; ///< Function to call for each item to draw its line - byte Color_index; ///< Background color: From 0->MC_Black to 3->MC_White - - 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. - char * Text; ///< Displayed string. - int Line_parameter; ///< Generic parameter depending on line type. For 'K' lines: a shortcut identifier. For others: unused. -} T_Help_table; - -/// Data for one section of the "Help" screens, ie a page. -typedef struct -{ - const T_Help_table* Help_table; ///< Pointer to the array of ::T_Help_table that contains the lines - word Length; ///< Size of the array of lines -} T_Help_section; - -/// Data for one setting of gradients. Warning, this one is saved/loaded as binary. -typedef struct -{ - byte Start; ///< First color - byte End; ///< Last color - dword Inverse; ///< Boolean, true if the gradient goes in descending order - dword Mix; ///< Amount of randomness to add to the mix (0-255) - dword Technique;///< Gradient technique: 0 (no pattern) 1 (dithering), or 2 (big dithering) - 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 -{ - word List[512]; ///< List of entries, each one is either a color (0-255) or -1 for empty. - byte Step; ///< Step to increment/decrement on left-clicks. - byte Mode; ///< Shade mode: Normal, Loop, or No-saturation see ::SHADE_MODES -} T_Shade; - -/// Data for one fullscreen video mode in configuration file. Warning, this one is saved/loaded as binary. -typedef struct -{ - byte State; ///< How good is the mode supported. 0:Good (white) 1:OK (light) 2:So-so (dark) 4:User-disabled (black); +128 => System doesn't support it at all. - word Width; ///< Videomode width in pixels. - word Height;///< Videomode height in pixels. -} T_Config_video_mode; - -/// Header for gfx2.cfg -typedef struct -{ - char Signature[3]; ///< Signature for the file format. "CFG". - byte Version1; ///< Major version number (ex: 2) - byte Version2; ///< Minor version number (ex: 0) - byte Beta1; ///< Major beta version number (ex: 96) - byte Beta2; ///< Major beta version number (ex: 5) -} T_Config_header; - -/// 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; - - -/// 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; - - -/// This structure holds all the settings saved and loaded as gfx2.ini. -typedef struct -{ - char *Font_file; ///< Name of the font used in the menus. Matches file skins/font_*.png (Case-sensitive on some filesystems) - char *Skin_file; ///< String, name of the file where all the graphic data is stored - int Show_hidden_files; ///< Boolean, true to show hidden files in fileselectors. - int Show_hidden_directories; ///< Boolean, true to show hidden directories in fileselectors. -// int Show_system_directories; ///< (removed when converted from DOS) - byte Display_image_limits; ///< Boolean, true to display a dotted line at the borders of the image if it's smaller than screen. - byte Cursor; ///< Mouse cursor aspect: 1 Solid, 2 Transparent, 3 Thin - byte Maximize_preview; ///< Boolean, true to make previews in fileselector fit the whole rectangle. - byte Auto_set_res; ///< Boolean, true to make grafx2 switch to a new resolution whenever you load an image. - byte Coords_rel; ///< Boolean, true to display coordinates as relative (instead of absolute) - byte Backup; ///< Boolean, true to backup the original file whenever you save an image. - byte Adjust_brush_pick; ///< Boolean, true to omit the right and bottom edges when grabbing a brush in Grid mode. - byte Auto_save; ///< Boolean, true to save configuration when exiting program. - byte Max_undo_pages; ///< Number of steps to memorize for Undo/Redo. - byte Mouse_sensitivity_index_x; ///< Mouse sensitivity in X axis - byte Mouse_sensitivity_index_y; ///< Mouse sensitivity in Y axis - byte Mouse_merge_movement; ///< Number of SDL mouse events that are merged into a single change of mouse coordinates. - byte Delay_left_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. - byte Delay_right_click_on_slider; ///< Delay (in 1/100s) between two activations of a repeatable button when you hold left-click. - long Timer_delay; ///< Delay (in 1/55s) before showing a preview in a fileselector. - T_Components Fav_menu_colors[4]; ///< Favorite colors to use for the menu. - int Nb_max_vertices_per_polygon; ///< Limit for the number of vertices in polygon tools. - byte Clear_palette; ///< Boolean, true to reset the palette (to black) before loading an image. - byte Set_resolution_according_to; ///< When Auto_set_res is on, this determines if the mode should be chosen according to the "original screen" information in the file (1) or the picture dimensons (2) - int8_t Ratio; ///< Determines the scaling of menu and windows: 0 no scaling, 1 scaling, 2 slight scaling, negative= opposite of max scaling - byte Fast_zoom; ///< Boolean, true if the magnifier shortcut should automatically view the mouse area. - byte Find_file_fast; ///< In fileselectors, this determines which entries should be sought when typing letters: 0 all, 1 files only, 2 directories only. - byte Separate_colors; ///< Boolean, true if the menu palette should separate color cells with a black outline. - word Palette_cells_X; ///< Number of colors to show in a row of the menu palette. - word Palette_cells_Y; ///< Number of colors to show in a column of the menu palette. - byte Palette_vertical; ///< Boolean, true if the menu palette should go top to bottom instead of left to right - byte FX_Feedback; ///< Boolean, true if drawing effects should read the image being modified (instead of the image before clicking) - byte Safety_colors; ///< Boolean, true to make the palette automatically re-create menu colors if needed after a "Zap" or color reduction. - byte Opening_message; ///< Boolean, true to display the splash screen on strtup. - byte Clear_with_stencil; ///< Boolean, true to take the stencil into effect (if active) when using the Clear function. - byte Auto_discontinuous; ///< Boolean, true to automatically switch to the discontinuous freehand draw after grabbing a brush. - byte Screen_size_in_GIF; ///< Boolean, true to store current resolution in GIF files. - byte Auto_nb_used; ///< Boolean, true to count colors in Palette screen. - byte Default_resolution; ///< Default video mode to use on startup. Index in ::Video_mode. - char *Bookmark_directory[NB_BOOKMARKS];///< Bookmarked directories in fileselectors: This is the full directory name. - char Bookmark_label[NB_BOOKMARKS][8+1];///< Bookmarked directories in fileselectors: This is the displayed name. - int Window_pos_x; ///< Last window x position (9999 if unsupportd/irrelevant for the platform) - int Window_pos_y; ///< Last window y position (9999 if unsupportd/irrelevant for the platform) - word Double_click_speed; ///< Maximum delay for double-click, in ms. - word Double_key_speed; ///< Maximum delay for double-keypress, in ms. - 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. - char Scripts_directory[MAX_PATH_CHARACTERS];///< Full pathname of directory for Lua scripts - byte Allow_multi_shortcuts; ///< Boolean, true if the same key combination can trigger multiple shortcuts. -} T_Config; - -// Structures utilisées pour les descriptions de pages et de liste de pages. -// Lorsqu'on gérera les animations, il faudra aussi des listes de listes de -// pages. - -// Ces structures sont manipulées à travers des fonctions de gestion du -// backup dans "graph.c". - -/// This is the data for one step of Undo/Redo, for one image. -/// This structure is resized dynamically to hold pointers to all of the layers in the picture. -/// The pointed layers are just byte* holding the raw pixel data. But at Image[0]-1 you will find a short that is used as a reference counter for each layer. -/// This way we can use the same pixel data in many undo pages when the user edit only one of the layers (which is what they usually do). -typedef struct T_Page -{ - int Width; ///< Image width in pixels. - int Height; ///< Image height in pixels. - T_Palette Palette; ///< Image palette. - - char Comment[COMMENT_SIZE+1]; ///< Comment to store in the image file. - - char File_directory[MAX_PATH_CHARACTERS];///< Directory that contains the file. - char Filename[MAX_PATH_CHARACTERS]; ///< Filename without directory. - byte File_format; ///< File format, in enum ::FILE_FORMATS - 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 -#if __GNUC__ < 3 - byte * Image[0]; -#else - byte * Image[]; ///< Pixel data for the (first layer of) image. -#endif - // Define as Image[0] if you have an old gcc which is not C99. - // No field after Image[] ! Dynamic layer allocation for Image[1], [2] etc. -} T_Page; - -/// Collection of undo/redo steps. -typedef struct -{ - int List_size; ///< Number of ::T_Page in the vector "Pages". - T_Page * Pages; ///< Head of a linked list of pages, each one being a undo/redo step. -} T_List_of_pages; - -/// A single image bitmap -/// This struct is used to store a flattened view of the current picture. -typedef struct -{ - int Width; ///< Image width in pixels. - int Height; ///< Image height in pixels. - byte * Image; ///< Pixel data for the image. -} T_Bitmap; - -/// A single memorized brush from the Brush Container -typedef struct -{ - byte Paintbrush_shape; ///< Kind of brush - byte Thumbnail[BRUSH_CONTAINER_PREVIEW_WIDTH][BRUSH_CONTAINER_PREVIEW_HEIGHT]; - // Data for color brush - word Width; - word Height; - byte * Brush; /// < Color brush (if any) - T_Palette Palette; - byte Colormap[256]; - byte Transp_color; -} T_Brush_template; - -/// GUI skin data -typedef struct -{ - // Mouse - - /// X coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_WIDTH - word Cursor_offset_X[NB_CURSOR_SPRITES]; - /// Y coordinate of the mouse cursor's "hot spot". It is < ::CURSOR_SPRITE_HEIGHT - word Cursor_offset_Y[NB_CURSOR_SPRITES]; - /// Graphic resources for the mouse cursor. - byte Cursor_sprite[NB_CURSOR_SPRITES][CURSOR_SPRITE_HEIGHT][CURSOR_SPRITE_WIDTH]; - - // Sieve patterns - - /// Preset sieve patterns, stored as binary (one word per line) - word Sieve_pattern[12][16]; - - // Menu and other graphics - - /// Bitmap data for the menu, a single rectangle. - byte Menu_block[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[2][NB_MENU_SPRITES][MENU_SPRITE_HEIGHT][MENU_SPRITE_WIDTH]; - /// Bitmap data for the different "effects" icons. - 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. - byte Logo_grafx2[231*56]; - /// Bitmap data for the 6x8 font used in help screens. - byte Help_font_norm [256][6][8]; - /// Bitmap data for the 6x8 font used in help screens ("bold" verstion). - byte Bold_font [256][6][8]; - // 12 - // 34 - /// Bitmap data for the title font used in help screens. Top-left quarter. - byte Help_font_t1 [64][6][8]; - /// Bitmap data for the title font used in help screens. Top-right quarter. - byte Help_font_t2 [64][6][8]; - /// Bitmap data for the title font used in help screens. Bottom-left quarter. - byte Help_font_t3 [64][6][8]; - /// Bitmap data for the title font used in help screens. Bottom-right quarter. - byte Help_font_t4 [64][6][8]; - /// Bitmap data for the small 8x8 icons. - byte Icon_sprite[NB_ICON_SPRITES][ICON_SPRITE_HEIGHT][ICON_SPRITE_WIDTH]; - - /// A default 256-color palette. - T_Palette Default_palette; - - /// Preview for displaying in the skin dialog - byte Preview[16][173]; - - /// GUI color indices in skin palette: black, dark, light, white. - byte Color[4]; - /// 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[3]; ///< [0] has normal buttons, [1] has selected buttons, [2] is current. - word Skin_width; - byte Last_button_index; -} T_Menu_Bar; - -typedef enum { - MENUBAR_STATUS = 0, // MUST be 0 - MENUBAR_LAYERS, - MENUBAR_TOOLS, - MENUBAR_COUNT -} T_Menubars; - -#endif diff --git a/project/jni/application/grafx2/grafx2/src/text.c b/project/jni/application/grafx2/grafx2/src/text.c deleted file mode 100644 index f240a4398..000000000 --- a/project/jni/application/grafx2/grafx2/src/text.c +++ /dev/null @@ -1,667 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* 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 - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -// Pour désactiver le support TrueType, définir NOTTF -// To disable TrueType support, define NOTTF - -#include -#include -#include // tolower() - -// TrueType -#ifndef NOTTF -#if defined(__macosx__) - #include -#else - #include -#endif - -#if defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__) || defined(ANDROID) -// No X11 -#elif defined(__linux__) - #include -#endif -#endif - -#if defined(__macosx__) - #include - #import - #import -#endif - -#include -#include "SFont.h" - -#include "struct.h" -#include "global.h" -#include "sdlscreen.h" -#include "io.h" -#include "errors.h" -#include "windows.h" -#include "misc.h" -#include "setup.h" - -typedef struct T_Font -{ - char * Name; - int Is_truetype; - int Is_bitmap; - char Label[22]; - - // Liste chainée simple - struct T_Font * Next; - struct T_Font * Previous; -} T_Font; -// Liste chainée des polices de texte -T_Font * font_list_start; -int Nb_fonts; - -// Inspiré par Allegro -#define EXTID(a,b,c) ((((a)&255)<<16) | (((b)&255)<<8) | (((c)&255))) -#define EXTID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255))) - -int Compare_fonts(T_Font * font_1, T_Font * font_2) -{ - if (font_1->Is_bitmap && !font_2->Is_bitmap) - return -1; - if (font_2->Is_bitmap && !font_1->Is_bitmap) - return 1; - return strcmp(font_1->Label, font_2->Label); -} - -// Ajout d'une fonte à la liste. -void Add_font(const char *name) -{ - char * font_name; - T_Font * font; - int size=strlen(name)+1; - int index; - - // Détermination du type: - -#if defined(__macosx__) - - if (size < 6) return; - - char strFontName[512]; - CFStringRef CFSFontName;// = CFSTR(name); - - CFSFontName = CFStringCreateWithBytes(NULL, (UInt8 *) name, size - 1, kCFStringEncodingASCII, false); - // Fix some funny names - CFStringGetCString(CFSFontName, strFontName, 512, kCFStringEncodingASCII); - - // Now we have a printable font name, use it - name = strFontName; - -#else - if (size<5 || - name[size-5]!='.') - return; -#endif - - font = (T_Font *)malloc(sizeof(T_Font)); - - switch (EXTID(tolower(name[size-4]), tolower(name[size-3]), tolower(name[size-2]))) - { - case EXTID('t','t','f'): - case EXTID('f','o','n'): - case EXTID('o','t','f'): - case EXTID('p','f','b'): - font->Is_truetype = 1; - font->Is_bitmap = 0; - break; - case EXTID('b','m','p'): - case EXTID('g','i','f'): - case EXTID('j','p','g'): - case EXTID('l','b','m'): - case EXTID('p','c','x'): - case EXTID('p','n','g'): - case EXTID('t','g','a'): - case EXTID('t','i','f'): - case EXTID('x','c','f'): - case EXTID('x','p','m'): - case EXTID('.','x','v'): - font->Is_truetype = 0; - font->Is_bitmap = 1; - break; - default: - #if defined(__macosx__) - if(strcasecmp(&name[size-6], "dfont") == 0) - { - font->Is_truetype = 1; - font->Is_bitmap = 0; - } - else - { - free(font); - return; - } - #else - free(font); - return; - #endif - } - - font->Name = (char *)malloc(size); - strcpy(font->Name, name); - // Label - strcpy(font->Label, " "); - if (font->Is_truetype) - font->Label[17]=font->Label[18]='T'; // Logo TT - font_name=Find_last_slash(font->Name); - if (font_name==NULL) - font_name=font->Name; - else - font_name++; - for (index=0; index < 17 && font_name[index]!='\0' && font_name[index]!='.'; index++) - font->Label[index]=font_name[index]; - - // Gestion Liste - font->Next = NULL; - font->Previous = NULL; - if (font_list_start==NULL) - { - // Premiere (liste vide) - font_list_start = font; - Nb_fonts++; - } - else - { - int compare; - compare = Compare_fonts(font, font_list_start); - if (compare<=0) - { - if (compare==0 && !strcmp(font->Name, font_list_start->Name)) - { - // Doublon - free(font->Name); - free(font); - return; - } - // Avant la premiere - font->Next=font_list_start; - font_list_start=font; - Nb_fonts++; - } - else - { - T_Font *searched_font; - searched_font=font_list_start; - while (searched_font->Next && (compare=Compare_fonts(font, searched_font->Next))>0) - searched_font=searched_font->Next; - // Après searched_font - if (compare==0 && strcmp(font->Name, searched_font->Next->Name)==0) - { - // Doublon - free(font->Name); - free(font); - return; - } - font->Next=searched_font->Next; - searched_font->Next=font; - Nb_fonts++; - } - } -} - - -// Trouve le nom d'une fonte par son numéro -char * Font_name(int index) -{ - T_Font *font = font_list_start; - if (index<0 ||index>=Nb_fonts) - return ""; - while (index--) - font = font->Next; - return font->Name; -} - - -// Trouve le libellé d'affichage d'une fonte par son numéro -// Renvoie un pointeur sur un buffer statique de 20 caracteres. -char * Font_label(int index) -{ - T_Font *font; - static char label[20]; - - strcpy(label, " "); - - // Recherche de la fonte - font = font_list_start; - if (index<0 ||index>=Nb_fonts) - return label; - while (index--) - font = font->Next; - - // Libellé - strcpy(label, font->Label); - return label; -} - - -// Vérifie si une fonte donnée est TrueType -int TrueType_font(int index) -{ - T_Font *font = font_list_start; - if (index<0 ||index>=Nb_fonts) - return 0; - while (index--) - font = font->Next; - return font->Is_truetype; -} - - - -// Initialisation à faire une fois au début du programme -void Init_text(void) -{ - char directory_name[MAX_PATH_CHARACTERS]; - #ifndef NOTTF - // Initialisation de TTF - TTF_Init(); - #endif - - // Initialisation des fontes - font_list_start = NULL; - Nb_fonts=0; - // Parcours du répertoire "fonts" - strcpy(directory_name, Data_directory); - strcat(directory_name, FONTS_SUBDIRECTORY); - For_each_file(directory_name, Add_font); - - #if defined(__WIN32__) - // Parcours du répertoire systeme windows "fonts" - #ifndef NOTTF - { - char * WindowsPath=getenv("windir"); - if (WindowsPath) - { - sprintf(directory_name, "%s\\FONTS", WindowsPath); - For_each_file(directory_name, Add_font); - } - } - #endif - #elif defined(__macosx__) - // Récupération de la liste des fonts avec fontconfig - #ifndef NOTTF - - - int i,number; - char home_dir[MAXPATHLEN]; - char *font_path_list[3] = { - "/System/Library/Fonts", - "/Library/Fonts" - }; - number = 3; - // Make sure we also search into the user's fonts directory - CFURLRef url = (CFURLRef) CFCopyHomeDirectoryURLForUser(NULL); - CFURLGetFileSystemRepresentation(url, true, (UInt8 *) home_dir, MAXPATHLEN); - strcat(home_dir, "/Library/Fonts"); - font_path_list[2] = home_dir; - - for(i=0;iformat->palette, palette); - - if (antialias) - { - 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 (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; - } - } - 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) - { - new_fore=Best_color_perceptual_except(Main_palette[Back_color].R, Main_palette[Back_color].G, Main_palette[Back_color].B, Back_color); - } - - 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, T_Palette palette) -{ - SFont_Font *font; - SDL_Surface * text_surface; - SDL_Surface *font_surface; - byte * new_brush; - SDL_Rect rectangle; - - // Chargement de la fonte - font_surface=IMG_Load(Font_name(font_number)); - if (!font_surface) - { - Verbose_message("Warning","Error loading font.\nThe file may be corrupt."); - return NULL; - } - // 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; - } - - // Calcul des dimensions - *height=SFont_TextHeight(font, str); - *width=SFont_TextWidth(font, str); - // Allocation d'une surface SDL - 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 transparent color - rectangle.x=0; - rectangle.y=0; - rectangle.w=*width; - rectangle.h=*height; - SDL_FillRect(text_surface, &rectangle, font->Transparent); - // Rendu du texte - SFont_Write(text_surface, font, 0, 0, str); - if (!text_surface) - { - DEBUG("Rendering failed",2); - SFont_FreeFont(font); - return NULL; - } - - new_brush=Surface_to_bytefield(text_surface, NULL); - if (!new_brush) - { - DEBUG("Converting failed",3); - SDL_FreeSurface(text_surface); - SFont_FreeFont(font); - return NULL; - } - - Get_SDL_Palette(font_surface->format->palette, palette); - - // Swap current BG color with font's transparent color - if (font->Transparent != Back_color) - { - int c; - byte colmap[256]; - // Swap palette entries - - SWAP_BYTES(palette[font->Transparent].R, palette[Back_color].R) - SWAP_BYTES(palette[font->Transparent].G, palette[Back_color].G) - SWAP_BYTES(palette[font->Transparent].B, palette[Back_color].B) - - // Define a colormap - for (c=0; c<256; c++) - colmap[c]=c; - - // The swap - colmap[font->Transparent]=Back_color; - colmap[Back_color]=font->Transparent; - - Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w); - - } - - SDL_FreeSurface(text_surface); - SFont_FreeFont(font); - - return new_brush; -} - -#ifdef NOTTF - #define TTFONLY __attribute__((unused)) -#else - #define TTFONLY -#endif - -// 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, T_Palette palette) -{ - T_Font *font = font_list_start; - int index=font_number; - - // Verification type de la fonte - if (font_number<0 ||font_number>=Nb_fonts) - return NULL; - - while (index--) - font = font->Next; - if (font->Is_truetype) - { - #ifndef NOTTF - 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, palette); - } -} - - diff --git a/project/jni/application/grafx2/grafx2/src/text.h b/project/jni/application/grafx2/grafx2/src/text.h deleted file mode 100644 index 6d65b274b..000000000 --- a/project/jni/application/grafx2/grafx2/src/text.h +++ /dev/null @@ -1,57 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Yves Rizoud - Copyright 2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file text.h -/// Functions related to rendering text as a brush, using TrueType or SFont. -////////////////////////////////////////////////////////////////////////////// - -/// Initialization of text settings, needs to be called once on program startup. -void Init_text(void); -/// Returns true if text.c was compiled with TrueType support. -int TrueType_is_supported(void); -/// Add a new font to the list to propose to the user. -void Add_font(const char *name); -/// -/// Creates a brush, from the parameters given: -/// @param str The text to render -/// @param font_number The index of the font to use. Pass 0 for the first font you declared with ::Add_font(), 1 for the second etc. -/// @param size The size in points (unused for bitmap fonts) -/// @param antialias Boolean, true to use antialiasing in TrueType -/// @param bold Boolean, true to use bold rendering in TrueType -/// @param italic Boolean, true to use italic rendering in TrueType -/// @param width Returns the width of the created brush, in pixels. -/// @param height Returns the height of the created brush, in pixels. -/// @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, 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. -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. -extern int Nb_fonts; diff --git a/project/jni/application/grafx2/grafx2/src/transform.c b/project/jni/application/grafx2/grafx2/src/transform.c deleted file mode 100644 index f603fa4ae..000000000 --- a/project/jni/application/grafx2/grafx2/src/transform.c +++ /dev/null @@ -1,446 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Yves Rizoud - Copyright 2009 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ -#include -#include - -#include "global.h" -#include "struct.h" -#include "transform.h" -#include "engine.h" -#include "sdlscreen.h" -#include "windows.h" -#include "input.h" -#include "help.h" -#include "misc.h" // Num2str -#include "readline.h" -#include "buttons.h" // Message_out_of_memory() -#include "pages.h" // Backup_with_new_dimensions() - -/// Reduces a fraction A/B to its smallest representation. ie (40,60) becomes (2/3) -void Factorize(short *a, short *b) -{ - // Method: brute-force. - short factor; - - factor=2; - while (factor<=*a && factor<=*b) - { - if (((*a % factor) == 0) && ((*b % factor) == 0)) - { - // common factor is found - *a/=factor; - *b/=factor; - // restart - factor=2; - } - else - factor++; - } -} - -/// Multiplies original_size by new_ratio/old_ratio, but keeps result in 1-9999 range. -short Compute_dimension(short original_size, short new_ratio, short old_ratio) -{ - long amount; - amount = (long)original_size*new_ratio/old_ratio; - if (amount>9999) - return 9999; - else if (amount<1) - return 1; - else - return amount; -} - -void Button_Transform_menu(void) -{ - enum RESIZE_UNIT { - UNIT_PIXELS = 1, - UNIT_PERCENT = 2, - UNIT_RATIO = 3 - }; - - char buffer[5]; - short clicked_button; - const char * unit_label[] = { - "", - "Pixels ", - "Percent", - "Ratio "}; - short last_unit_index = -1; - short old_ratio_width; - short old_ratio_height; - short new_ratio_width; - short new_ratio_height; - short new_width=Main_image_width; - short new_height=Main_image_height; - byte need_display_size = 0; - - // Persistent data - static short unit_index = 1; // 1= Pixels, 2= Percent, 3=Ratio - static short ratio_is_locked = 1; // True if X and Y resize should go together - - T_Dropdown_button * unit_button; - T_Special_button * input_button[4]; - short *input_value[4]; - - // Set initial ratio - if (unit_index == UNIT_PERCENT) - new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=100; - else - new_ratio_width=old_ratio_width=new_ratio_height=old_ratio_height=1; - - Open_window(215,165,"Picture transform"); - - Window_display_frame( 5, 15,205,91); - Window_display_frame( 5,110, 55,49); - Window_display_frame(64,110, 85,49); - - Window_set_normal_button(154,140, 54,14,"Cancel",0,1,KEY_ESC); // 1 - - Print_in_window( 9,114,"Mirror",MC_Dark,MC_Light); - Window_set_normal_button( 17,125, 27,14,"X\035" ,1,1,SDLK_x); // 2 - Window_set_normal_button( 17,140, 27,14,"Y\022" ,1,1,SDLK_y); // 3 - - Print_in_window( 84,114,"Rotate",MC_Dark,MC_Light); - Window_set_normal_button( 69,125, 37,14,"-90°" ,0,1,SDLK_LAST); // 4 - Window_set_normal_button(107,125, 37,14,"+90°" ,0,1,SDLK_LAST); // 5 - Window_set_normal_button( 69,140, 75,14,"180°" ,0,1,SDLK_LAST); // 6 - - Print_in_window( 87, 19,"Resize",MC_Dark,MC_Light); - Window_set_normal_button( 80, 86, 60,14,"RESIZE",1,1,SDLK_r); // 7 - Print_in_window( 51, 34,"New",MC_Dark,MC_Light); - Print_in_window( 96, 34,"Old",MC_Dark,MC_Light); - Print_in_window( 30, 44,"X:",MC_Dark,MC_Light); - Print_in_window( 30, 59,"Y:",MC_Dark,MC_Light); - Print_in_window( 80, 44,":",MC_Dark,MC_Light); - Print_in_window( 80, 59,":",MC_Dark,MC_Light); - Print_in_window( 44, 75,"Lock proportions",MC_Dark,MC_Light); - - Window_set_normal_button( 28, 72, 13,13,ratio_is_locked?"X":" ",0,1,SDLK_l);// 8 - unit_button = Window_set_dropdown_button(128,50,69,11,69,unit_label[unit_index],1,0,1,LEFT_SIDE|RIGHT_SIDE,0);// 9 - Window_dropdown_add_item(unit_button,UNIT_PIXELS,unit_label[UNIT_PIXELS]); - Window_dropdown_add_item(unit_button,UNIT_PERCENT,unit_label[UNIT_PERCENT]); - Window_dropdown_add_item(unit_button,UNIT_RATIO,unit_label[UNIT_RATIO]); - - input_button[0] = Window_set_input_button(45,43,4); // 10 - input_button[1] = Window_set_input_button(89,43,4); // 11 - input_button[2] = Window_set_input_button(45,58,4); // 12 - input_button[3] = Window_set_input_button(89,58,4); // 13 - - Update_window_area(0,0,Window_width, Window_height); - - Display_cursor(); - - do - { - // Display the coordinates with the right unit - if (last_unit_index != unit_index) - { - switch(unit_index) - { - case UNIT_PIXELS: - default: - input_value[0]=&new_width; - input_value[1]=&Main_image_width; // Don't worry, it's read-only - input_value[2]=&new_height; - input_value[3]=&Main_image_height; // Don't worry, it's read-only - break; - case UNIT_PERCENT: - case UNIT_RATIO: - input_value[0]=&new_ratio_width; - input_value[1]=&old_ratio_width; - input_value[2]=&new_ratio_height; - input_value[3]=&old_ratio_height; - break; - } - need_display_size=1; - last_unit_index=unit_index; - } - if (need_display_size) - { - short i; - Hide_cursor(); - for (i=0;i<4;i++) - { - // "Old" values are not editable, unless the unit is "ratio" - byte color = ((unit_index!=UNIT_RATIO) && (i==1 || i==3)) ? MC_Dark : MC_Black; - Num2str(*(input_value[i]),buffer,4); - Print_in_window_limited(input_button[i]->Pos_X+2,input_button[i]->Pos_Y+2,buffer,input_button[i]->Width/8,color,MC_Light); - } - Display_cursor(); - need_display_size=0; - } - - clicked_button=Window_clicked_button(); - - // Contextual help - if (Is_shortcut(Key,0x100+BUTTON_HELP)) - { - Key=0; - Window_help(BUTTON_ADJUST, "PICTURE TRANSFORM"); - } - else if (Is_shortcut(Key,0x200+BUTTON_ADJUST)) - clicked_button=1; - - else switch(clicked_button) - { - case 9: // Unit - switch(Window_attribute2) - { - case UNIT_PIXELS: - // Do nothing, pixel size was already computed. - break; - case UNIT_PERCENT: - if (unit_index == UNIT_RATIO) - { - // Approximate from current ratio - new_ratio_width = Compute_dimension(new_ratio_width,100,old_ratio_width); - new_ratio_height = Compute_dimension(new_ratio_height,100,old_ratio_height); - old_ratio_width = 100; - old_ratio_height = 100; - // Update pixel dimensions, to match percentage exactly - new_width=Compute_dimension(Main_image_width, new_ratio_width, old_ratio_width); - new_height=Compute_dimension(Main_image_height, new_ratio_height, old_ratio_height); - } - else // unit_index == UNIT_PIXELS - { - // Approximate from current pixel size - new_ratio_width = new_width*100/Main_image_width; - new_ratio_height = new_height*100/Main_image_height; - old_ratio_width = 100; - old_ratio_height = 100; - } - break; - case UNIT_RATIO: - if (unit_index == UNIT_PERCENT) - { - // Compute simplest ratio from current % - Factorize(&new_ratio_width, &old_ratio_width); - Factorize(&new_ratio_height, &old_ratio_height); - } - else // unit_index == UNIT_PIXELS - { - // Compute simplest ratio from current pixel size - new_ratio_width = new_width; - new_ratio_height = new_height; - old_ratio_width = Main_image_width; - old_ratio_height = Main_image_height; - Factorize(&new_ratio_width, &old_ratio_width); - Factorize(&new_ratio_height, &old_ratio_height); - } - break; - } - - unit_index = Window_attribute2; - break; - - case 8: // Lock proportions - ratio_is_locked = ! ratio_is_locked; - Hide_cursor(); - Print_in_window(31,75,(ratio_is_locked)?"X":" ",MC_Black,MC_Light); - Display_cursor(); - break; - - case 11: // input old width - case 13: // input old height - // "Old" values are not editable, unless the unit is "ratio" - if (unit_index!=UNIT_RATIO) - break; - case 10: // input new width - case 12: // input new height - Num2str(*( input_value[clicked_button-10]),buffer,4); - Hide_cursor(); - if (Readline(input_button[clicked_button-10]->Pos_X+2, - input_button[clicked_button-10]->Pos_Y+2, - buffer, - 4, - INPUT_TYPE_INTEGER)) - { - // Accept entered value - *(input_value[clicked_button-10])=atoi(buffer); - // 0 is not acceptable size - if (*(input_value[clicked_button-10])==0) - { - *(input_value[clicked_button-10])=1; - } - // Adapt the other coordinate if X and Y are locked - if (ratio_is_locked) - { - if (clicked_button == 10 || clicked_button == 11 ) - { - // Get Y value because X changed - if (unit_index == UNIT_PIXELS) - { - new_height=Compute_dimension(Main_image_height, new_width, Main_image_width); - } - else - { - // Copy the whole ratio - new_ratio_height=new_ratio_width; - old_ratio_height=old_ratio_width; - } - } - else // (clicked_button == 12 || clicked_button == 13) - { - // Get X value because Y changed - if (unit_index == UNIT_PIXELS) - { - new_width=Compute_dimension(Main_image_width, new_height, Main_image_height); - } - else - { - // Copy the whole ratio - new_ratio_width=new_ratio_height; - old_ratio_width=old_ratio_height; - } - } - } - - // Re-compute ratio from size in pixels - if (unit_index == UNIT_PIXELS) - { - //new_width=(long)Main_image_width*new_ratio_width/old_ratio_width; - //new_height=(long)Main_image_height*new_ratio_height/old_ratio_height; - } - else // Re-compute size in pixels from ratio - { - new_width=Compute_dimension(Main_image_width,new_ratio_width,old_ratio_width); - new_height=Compute_dimension(Main_image_height,new_ratio_height,old_ratio_height); - } - need_display_size=1; - } - Display_cursor(); - break; - } - } - while (clicked_button<=0 || clicked_button>=8); - - Close_window(); - - // The Scroll operation uses the same button as transformation menu. - if (Current_operation != OPERATION_SCROLL) - Unselect_button(BUTTON_ADJUST); - - if (clicked_button != 1) // 1 is Cancel - { - short old_width; - short old_height; - - // Determine new image dimensions - switch (clicked_button) - { - case 7 : // Resize - // Keep new_width and new_height as entered. - break; - case 2 : // Flip X - case 3 : // Flip Y - case 6 : // 180° Rotation - new_width=Main_image_width; - new_height=Main_image_height; - break; - - case 4 : // -90° Rotation - case 5 : // +90° Rotation - - new_width=Main_image_height; - new_height=Main_image_width; - break; - } - // Memorize the current dimensions - old_width=Main_image_width; - old_height=Main_image_height; - - Upload_infos_page_main(Main_backups->Pages); - // Allocate a new page - if (Backup_with_new_dimensions(new_width,new_height)) - { - // The new image is allocated, the new dimensions are already updated. - - Main_image_is_modified=1; - - // Process the transformation: - switch(clicked_button) - { - int i; - - case 2 : // Flip X - for (i=0; iPages->Nb_layers; i++) - { - memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); - Flip_X_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); - } - break; - case 3 : // Flip Y - for (i=0; iPages->Nb_layers; i++) - { - memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); - Flip_Y_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); - } - break; - case 4 : // -90° Rotation - for (i=0; iPages->Nb_layers; i++) - { - Rotate_270_deg_lowlevel(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); - } - break; - case 5 : // +90° Rotation - for (i=0; iPages->Nb_layers; i++) - { - Rotate_90_deg_lowlevel(Main_backups->Pages->Next->Image[i], Main_backups->Pages->Image[i], old_width, old_height); - } - break; - case 6 : // 180° Rotation - for (i=0; iPages->Nb_layers; i++) - { - memcpy(Main_backups->Pages->Image[i],Main_backups->Pages->Next->Image[i],Main_image_width*Main_image_height); - Rotate_180_deg_lowlevel(Main_backups->Pages->Image[i], Main_image_width, Main_image_height); - } - break; - case 7 : // Resize - for (i=0; iPages->Nb_layers; i++) - { - Rescale(Main_backups->Pages->Next->Image[i], old_width, old_height, Main_backups->Pages->Image[i], Main_image_width, Main_image_height, 0, 0); - } - break; - } - /* - for (i=0; iPages->Next->Image[i],0,0,Min(old_width,Main_image_width), - Min(old_height,Main_image_height),old_width, - Main_backups->Pages->Image[i],0,0,Main_image_width); - } - */ - Redraw_layered_image(); - Display_all_screen(); - End_of_modification(); - } - else - { - Display_cursor(); - Message_out_of_memory(); - Hide_cursor(); - } - } - Display_cursor(); -} diff --git a/project/jni/application/grafx2/grafx2/src/transform.h b/project/jni/application/grafx2/grafx2/src/transform.h deleted file mode 100644 index 26cf28d17..000000000 --- a/project/jni/application/grafx2/grafx2/src/transform.h +++ /dev/null @@ -1,29 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2009 Yves Rizoud - Copyright 2009 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file transform.h -/// Screen and functions for picture transform. -////////////////////////////////////////////////////////////////////////////// - -/// Opens and handles the Picture transform screen. -void Button_Transform_menu(void); diff --git a/project/jni/application/grafx2/grafx2/src/version.c b/project/jni/application/grafx2/grafx2/src/version.c deleted file mode 100644 index b4b5ecc25..000000000 --- a/project/jni/application/grafx2/grafx2/src/version.c +++ /dev/null @@ -1 +0,0 @@ -char SVN_revision[]="1781"; diff --git a/project/jni/application/grafx2/grafx2/src/windows.c b/project/jni/application/grafx2/grafx2/src/windows.c deleted file mode 100644 index e2e5fa27d..000000000 --- a/project/jni/application/grafx2/grafx2/src/windows.c +++ /dev/null @@ -1,3174 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2008 Franck Charlet - Copyright 2007-2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see - -******************************************************************************** - - Graphical interface management functions (windows, menu, cursor) -*/ - -#include -#include // atoi() -#include // strncpy() strlen() - -#include "windows.h" - -#include "engine.h" -#include "errors.h" -#include "global.h" -#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; - -// L'encapsulation tente une percée...ou un dernier combat. - -// Nombre de cellules réel dans la palette du menu -word Menu_cells_X; -word Palette_cells_X() -{ - return Menu_cells_X; -} -word Menu_cells_Y; -word Palette_cells_Y() -{ - return Menu_cells_Y; -} - -// Affichage d'un pixel dans le menu (si visible) -void Pixel_in_menu(word bar, word x, word y, byte color) -{ - if (Menu_is_visible && Menu_bars[bar].Visible) - Block(x*Menu_factor_X,(y+Menu_bars[bar].Top)*Menu_factor_Y+Menu_Y,Menu_factor_X,Menu_factor_Y,color); -} - -// Affichage d'un pixel dans le menu et met a jour la bitmap de skin -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[2][y*Menu_bars[bar].Skin_width + x] = color; -} - -// Affichage d'un pixel dans la fenêtre (la fenêtre doit être visible) -void Pixel_in_window(word x,word y,byte color) -{ - Block((x*Menu_factor_X)+Window_pos_X,(y*Menu_factor_Y)+Window_pos_Y,Menu_factor_X,Menu_factor_Y,color); -} - -// Affichage d'un rectangle dans la fenêtre (la fenêtre doit être visible) -void Window_rectangle(word x_pos,word y_pos,word width,word height,byte color) -{ - Block((x_pos*Menu_factor_X)+Window_pos_X,(y_pos*Menu_factor_Y)+Window_pos_Y,width*Menu_factor_X,height*Menu_factor_Y,color); -} - - -// -- Affichages de différents cadres dans une fenêtre ----------------------- - - // -- Frame général avec couleurs paramètrables -- - -void Window_display_frame_generic(word x_pos,word y_pos,word width,word height, - byte color_tl,byte color_br,byte color_s,byte color_tlc,byte color_brc) -// Paramètres de couleurs: -// color_tl =Bords Haut et Gauche -// color_br =Bords Bas et Droite -// color_s =Coins Haut-Droite et Bas-Gauche -// color_tlc=Coin Haut-Gauche -// color_brc=Coin Bas-Droite -{ - // Bord haut (sans les extrémités) - Block(Window_pos_X+((x_pos+1)*Menu_factor_X), - Window_pos_Y+(y_pos*Menu_factor_Y), - (width-2)*Menu_factor_X,Menu_factor_Y,color_tl); - - // Bord bas (sans les extrémités) - Block(Window_pos_X+((x_pos+1)*Menu_factor_X), - Window_pos_Y+((y_pos+height-1)*Menu_factor_Y), - (width-2)*Menu_factor_X,Menu_factor_Y,color_br); - - // Bord gauche (sans les extrémités) - Block(Window_pos_X+(x_pos*Menu_factor_X), - Window_pos_Y+((y_pos+1)*Menu_factor_Y), - Menu_factor_X,(height-2)*Menu_factor_Y,color_tl); - - // Bord droite (sans les extrémités) - Block(Window_pos_X+((x_pos+width-1)*Menu_factor_X), - Window_pos_Y+((y_pos+1)*Menu_factor_Y), - Menu_factor_X,(height-2)*Menu_factor_Y,color_br); - - // Coin haut gauche - Pixel_in_window(x_pos,y_pos,color_tlc); - // Coin haut droite - Pixel_in_window(x_pos+width-1,y_pos,color_s); - // Coin bas droite - Pixel_in_window(x_pos+width-1,y_pos+height-1,color_brc); - // Coin bas gauche - Pixel_in_window(x_pos,y_pos+height-1,color_s); -} - - // -- Frame dont tout le contour est d'une seule couleur -- - -void Window_display_frame_mono(word x_pos,word y_pos,word width,word height,byte color) -{ - Window_display_frame_generic(x_pos,y_pos,width,height,color,color,color,color,color); -} - - // -- Frame creux: foncé en haut-gauche et clair en bas-droite -- - -void Window_display_frame_in(word x_pos,word y_pos,word width,word height) -{ - Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_White,MC_Light,MC_Dark,MC_White); -} - - // -- Frame bombé: clair en haut-gauche et foncé en bas-droite -- - -void Window_display_frame_out(word x_pos,word y_pos,word width,word height) -{ - Window_display_frame_generic(x_pos,y_pos,width,height,MC_White,MC_Dark,MC_Light,MC_White,MC_Dark); -} - - // -- Frame de séparation: un cadre bombé dans un cadre creux (3D!!!) -- - -void Window_display_frame(word x_pos,word y_pos,word width,word height) -{ - Window_display_frame_in(x_pos,y_pos,width,height); - Window_display_frame_out(x_pos+1,y_pos+1,width-2,height-2); -} - - -//-- Affichages relatifs à la palette dans le menu --------------------------- - - // -- Affichage des couleurs courante (fore/back) de pinceau dans le menu -- - -void Display_foreback(void) -{ - if (Menu_is_visible && Menu_bars[MENUBAR_TOOLS].Visible) - { - Block((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7,Back_color); - Block((MENU_WIDTH-13)*Menu_factor_X,Menu_Y+(Menu_factor_Y<<1),Menu_factor_X<<3,Menu_factor_Y*5,Fore_color); - - Update_rect((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7); - } -} - -/*! Get the top left corner for the palette cell of a color - @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y. -*/ -word Palette_cell_X(byte index) -{ - if (Config.Palette_vertical) - { - return (MENU_WIDTH+1+((index-First_color_in_palette)%Menu_cells_X)*Menu_palette_cell_width)*Menu_factor_X; - } - else - { - return (MENU_WIDTH+1+((index-First_color_in_palette)/Menu_cells_Y)*Menu_palette_cell_width)*Menu_factor_X; - } -} - -/*! Get the top left corner for the palette cell of a color - @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y. -*/ -word Palette_cell_Y(byte index) -{ - if (Config.Palette_vertical) - { - return Menu_Y+((1+(((index-First_color_in_palette)/Menu_cells_X)*(Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y)))*Menu_factor_Y); - } - else - { - return Menu_Y+((1+(((index-First_color_in_palette)%Menu_cells_Y)*(Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y)))*Menu_factor_Y); - } -} - -void Set_fore_color(byte color) -{ - byte old_fore_color = Fore_color; - - Fore_color=color; - Reposition_palette(); - Display_foreback(); - Frame_menu_color(old_fore_color); - Frame_menu_color(Fore_color); -} - -void Set_back_color(byte color) -{ - byte old_back_color = Back_color; - - Back_color=color; - Display_foreback(); - Frame_menu_color(old_back_color); - Frame_menu_color(Back_color); -} - -/// -/// Redraw the cell in the menu palette for ::Fore_color. -/// This function checks bounds, it won't draw anything if Fore_color is not visible. -/// @param id: Color number to frame -void Frame_menu_color(byte id) -{ - word start_x,start_y,end_x,end_y; - word index; - word cell_height=Menu_bars[MENUBAR_TOOLS].Height/Menu_cells_Y; - byte color; - - if (! Menu_bars[MENUBAR_TOOLS].Visible) - return; - - if (id==Fore_color) - color = MC_White; - else if (id==Back_color) - color = MC_Dark; - else - color = MC_Black; - - if ((id>=First_color_in_palette) && (id=First_color_in_palette+Menu_cells_X*Menu_cells_Y) - First_color_in_palette+=cells; - } - if (old_color!=First_color_in_palette) - Display_menu_palette(); -} - -void Change_palette_cells() -{ - // On initialise avec la configuration de l'utilisateur - Menu_cells_X=Config.Palette_cells_X; - Menu_cells_Y=Config.Palette_cells_Y; - // Mais on sait jamais - if (Menu_cells_X<1) - Menu_cells_X=1; - if (Menu_cells_Y<1) - Menu_cells_Y=1; - - while (1) - { - Menu_palette_cell_width = ((Screen_width/Menu_factor_X)-(MENU_WIDTH+2)) / Menu_cells_X; - - // Si ça tient, c'est bon. Sinon, on retente avec une colonne de moins - if (Menu_palette_cell_width>2) - break; - Menu_cells_X--; - } - - // Cale First_color_in_palette sur un multiple du nombre de cellules (arrondi inférieur) - if (Config.Palette_vertical) - First_color_in_palette=First_color_in_palette/Menu_cells_X*Menu_cells_X; - else - First_color_in_palette=First_color_in_palette/Menu_cells_Y*Menu_cells_Y; - - // Si le nombre de cellules a beaucoup augmenté et qu'on était près de - // la fin, il faut reculer First_color_in_palette pour montrer plein - // de couleurs. - if ((int)First_color_in_palette+(Menu_cells_Y)*Menu_cells_X*2>=256) - First_color_in_palette=255/Menu_cells_Y*Menu_cells_Y-(Menu_cells_X-1)*Menu_cells_Y; - - // Mise à jour de la taille du bouton dans le menu. C'est pour pas que - // la bordure noire soit active. - Buttons_Pool[BUTTON_CHOOSE_COL].Width=(Menu_palette_cell_width*Menu_cells_X)-1; - Buttons_Pool[BUTTON_CHOOSE_COL].Height=(MENU_HEIGHT-9)/Menu_cells_Y*Menu_cells_Y-1; -} - -// Retrouve la couleur sur laquelle pointe le curseur souris. -// Cette fonction suppose qu'on a déja vérifié que le curseur est dans -// la zone rectangulaire du BUTTON_CHOOSE_COL -// La fonction renvoie -1 si on est "trop à gauche" (pas possible) -// ou après la couleur 255 (Ce qui peut arriver si la palette est affichée -// avec un nombre de lignes qui n'est pas une puissance de deux.) -int Pick_color_in_palette() -{ - int color; - int line; - int column; - - line=(((Mouse_Y-Menu_Y)/Menu_factor_Y)-1)/((Menu_bars[MENUBAR_TOOLS].Height)/Menu_cells_Y); - column=(((Mouse_X/Menu_factor_X)-(MENU_WIDTH+1))/Menu_palette_cell_width); - if (Config.Palette_vertical) - { - color=First_color_in_palette+line*Menu_cells_X+column; - } - else - { - color=First_color_in_palette+line+column*Menu_cells_Y; - } - if (color<0 || color>255) - return -1; - return color; -} - -/// Draws a solid textured area, to the right of a toolbar. -void Draw_bar_remainder(word current_menu, word x_off) -{ - word y_pos; - word x_pos; - - for (y_pos=0;y_posPages->Nb_layers; - word horiz_space; - word current_button; - word repeats=1; - - if (! Menu_bars[MENUBAR_LAYERS].Visible) - return; - - // Available space in pixels - horiz_space = Screen_width / Menu_factor_X - Menu_bars[MENUBAR_LAYERS].Skin_width; - - // Don't display all buttons if not enough room - if (horiz_space/button_width < button_number) - button_number = horiz_space/button_width; - // Only 16 icons at the moment - if (button_number > 16) // can be different from MAX_NB_LAYERS - button_number = 16; - - // Enlarge the buttons themselves if there's enough room - while (button_number*(button_width+2) < horiz_space && repeats < 20) - { - repeats+=1; - button_width+=2; - } - - x_off=Menu_bars[MENUBAR_LAYERS].Skin_width; - for (current_button=0; current_button0; i--) - { - Pixel_in_menu(MENUBAR_LAYERS, x_pos + x_off, y_pos, Gfx->Layer_sprite[sprite_index][current_button][y_pos][source_x]); - x_pos++; - } - } - // Next line - x_pos=0; - } - // Next button - x_off+=button_width; - } - // Texture any remaining space to the right. - // This overwrites any junk like deleted buttons. - Draw_bar_remainder(MENUBAR_LAYERS, x_off); - - // Update the active area of the layers pseudo-button - Buttons_Pool[BUTTON_LAYER_SELECT].Width = button_number * button_width; - - // Required to determine which layer button is clicked - Layer_button_width = button_width; - - // A screen refresh required by some callers - Update_rect( - Menu_bars[MENUBAR_LAYERS].Skin_width, - Menu_Y+Menu_bars[MENUBAR_LAYERS].Top*Menu_factor_Y, - horiz_space*Menu_factor_X, - Menu_bars[MENUBAR_LAYERS].Height*Menu_factor_Y); -} - - -/// Display the whole menu -void Display_menu(void) -{ - word x_pos; - word y_pos; - int8_t current_menu; - char str[4]; - - - if (Menu_is_visible) - { - // display menu sprite - for (current_menu = MENUBAR_COUNT - 1; current_menu >= 0; current_menu --) - { - if(Menu_bars[current_menu].Visible) - { - // Skinned area - for (y_pos=0;y_pos=Main_X_zoom) )) - { - // Prepare display of XY coordinates even if in some cases they will be - // erased with some other text - if ( (Current_operation!=OPERATION_COLORPICK) - && (Current_operation!=OPERATION_REPLACE) ) - Print_in_menu("X: Y: ",0); - else - { - // The colorpicker display the color id between the parentheses - Print_in_menu("X: Y: ( )",0); - Num2str(Colorpicker_color,str,3); - Print_in_menu(str,20); - Print_general(170*Menu_factor_X,Menu_status_Y," ",0,Colorpicker_color); - } - Print_coordinates(); - } - Print_filename(); - } - // Now update the area: menu height and whole screen width (including palette) - Update_rect(0,Menu_Y,Screen_width,Menu_height*Menu_factor_Y); - } -} - -// -- Affichage de texte ----------------------------------------------------- - - // -- Afficher une chaîne n'importe où à l'écran -- - -void Print_general(short x,short y,const char * str,byte text_color,byte background_color) -{ - word index; - int x_pos; - int y_pos; - byte *font_pixel; - short real_x; - short real_y; - byte repeat_menu_x_factor; - byte repeat_menu_y_factor; - - real_y=y; - for (y_pos=0;y_pos<8<<3;y_pos+=1<<3) - { - real_x=0; // Position dans le buffer - for (index=0;str[index]!='\0';index++) - { - // Pointeur sur le premier pixel du caractère - font_pixel=Menu_font+(((unsigned char)str[index])<<6); - for (x_pos=0;x_pos<8;x_pos+=1) - for (repeat_menu_x_factor=0;repeat_menu_x_factor size) - { - display_string[size-1]=ELLIPSIS_CHARACTER; - } - Print_in_window(x, y, display_string, text_color, background_color); -} - -/// Draws a string in a window -void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color) -{ - Print_general((x*Menu_factor_X)+Window_pos_X, - (y*Menu_factor_Y)+Window_pos_Y, - str,text_color,background_color); - Update_rect(x*Menu_factor_X+Window_pos_X,y*Menu_factor_Y+Window_pos_Y,8*Menu_factor_X*strlen(str),8*Menu_factor_Y); -} - -// Draws a string in the menu's status bar -void Print_in_menu(const char * str, short position) -{ - Print_general((18+(position<<3))*Menu_factor_X,Menu_status_Y,str,MC_Black,MC_Light); - Update_status_line(position, strlen(str)); -} - -/// Draws the mouse coordinates on the menu -/// Only update the digits and doesn't refresh the "X: Y:" labels. This function needs to be fast as it is called each time the mouse moves. -void Print_coordinates(void) -{ - char temp[5]; - - if (Menu_is_visible && !Cursor_in_menu) - { - if ( (Current_operation==OPERATION_COLORPICK) - || (Current_operation==OPERATION_RMB_COLORPICK) - || (Current_operation==OPERATION_REPLACE) ) - { - if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0) - && (Paintbrush_XPages->Filename); - - // Partial copy of the name - strncpy(display_string, Main_backups->Pages->Filename, max_size); - display_string[max_size]='\0'; - - if (string_size > max_size) - { - string_size = max_size; - display_string[string_size-1]=ELLIPSIS_CHARACTER; - } - // Erase whole area - Block(Screen_width-max_size*8*Menu_factor_X, - Menu_status_Y,Menu_factor_X*max_size*8,Menu_factor_Y<<3,MC_Light); - // Print - Print_general(Screen_width-(string_size<<3)*Menu_factor_X,Menu_status_Y,display_string,MC_Black,MC_Light); -} - -// Fonction d'affichage d'une chaine numérique avec une fonte très fine -// Spécialisée pour les compteurs RGB -void Print_counter(short x,short y,const char * str,byte text_color,byte background_color) -{ - // Macros pour écrire des litteraux binaires. - // Ex: Ob(11110000) == 0xF0 - #define Ob(x) ((unsigned)Ob_(0 ## x ## uL)) - #define Ob_(x) ((x & 1) | (x >> 2 & 2) | (x >> 4 & 4) | (x >> 6 & 8) | \ - (x >> 8 & 16) | (x >> 10 & 32) | (x >> 12 & 64) | (x >> 14 & 128)) - - byte thin_font[14][8] = { - { // 0 - Ob(00011100), - Ob(00110110), - Ob(00110110), - Ob(00110110), - Ob(00110110), - Ob(00110110), - Ob(00110110), - Ob(00011100) - }, - { // 1 - Ob(00001100), - Ob(00011100), - Ob(00111100), - Ob(00001100), - Ob(00001100), - Ob(00001100), - Ob(00001100), - Ob(00001100) - }, - { // 2 - Ob(00011100), - Ob(00110110), - Ob(00000110), - Ob(00000110), - Ob(00000110), - Ob(00001100), - Ob(00011000), - Ob(00111110) - }, - { // 3 - Ob(00011100), - Ob(00110110), - Ob(00000110), - Ob(00001100), - Ob(00000110), - Ob(00000110), - Ob(00110110), - Ob(00011100) - }, - { // 4 - Ob(00001100), - Ob(00001100), - Ob(00011000), - Ob(00011000), - Ob(00110000), - Ob(00110100), - Ob(00111110), - Ob(00000100) - }, - { // 5 - Ob(00111110), - Ob(00110000), - Ob(00110000), - Ob(00111100), - Ob(00000110), - Ob(00000110), - Ob(00110110), - Ob(00011100) - }, - { // 6 - Ob(00011100), - Ob(00110110), - Ob(00110000), - Ob(00111100), - Ob(00110110), - Ob(00110110), - Ob(00110110), - Ob(00011100) - }, - { // 7 - Ob(00111110), - Ob(00000110), - Ob(00000110), - Ob(00001100), - Ob(00011000), - Ob(00011000), - Ob(00011000), - Ob(00011000) - }, - { // 8 - Ob(00011100), - Ob(00110110), - Ob(00110110), - Ob(00011100), - Ob(00110110), - Ob(00110110), - Ob(00110110), - Ob(00011100) - }, - { // 9 - Ob(00011100), - Ob(00110110), - Ob(00110110), - Ob(00011110), - Ob(00000110), - Ob(00000110), - Ob(00110110), - Ob(00011100) - }, - { // (espace) - Ob(00000000), - Ob(00000000), - Ob(00000000), - Ob(00000000), - Ob(00000000), - Ob(00000000), - Ob(00000000), - Ob(00000000) - }, - { // + - Ob(00000000), - Ob(00001000), - Ob(00001000), - Ob(00111110), - Ob(00001000), - Ob(00001000), - Ob(00000000), - Ob(00000000) - }, - { // - - Ob(00000000), - Ob(00000000), - Ob(00000000), - Ob(00111110), - Ob(00000000), - Ob(00000000), - Ob(00000000), - Ob(00000000) - }, - { // +- - Ob(00001000), - Ob(00001000), - Ob(00111110), - Ob(00001000), - Ob(00001000), - Ob(00000000), - Ob(00111110), - Ob(00000000) - } }; - - word index; - short x_pos; - short y_pos; - for (index=0;str[index]!='\0';index++) - { - int char_number; - switch(str[index]) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - char_number=str[index]-'0'; - break; - case ' ': - default: - char_number=10; - break; - case '+': - char_number=11; - break; - case '-': - char_number=12; - break; - case '±': - char_number=13; - break; - } - for (y_pos=0;y_pos<8;y_pos++) - { - for (x_pos=0;x_pos<6;x_pos++) - { - byte color = (thin_font[char_number][y_pos] & (1 << (6-x_pos))) ? text_color:background_color; - Pixel_in_window(x+(index*6+x_pos),y+y_pos,color); - } - } - } - Update_rect(Window_pos_X+x*Menu_factor_X,Window_pos_Y+y*Menu_factor_Y,strlen(str)*Menu_factor_X*6,8*Menu_factor_Y); -} - - - -/// -/// Window asking for confirmation before an action is performed. -/// This function is able to display multi-line messages and -/// center the lines, but the carriage returns have to be explicit. -/// The function will clip the message in case of problem. -/// @return 1 if user pressed OK, 0 if CANCEL -byte Confirmation_box(char * message) -{ - short clicked_button; - word window_width = 120; - word nb_lines = 1; - const char *c = message; - short current_length=0; - short current_line; - - // Count lines, and measure max line length - for (c=message; *c != '\0'; c++) - { - if (*c == '\n') - { - current_length=0; - nb_lines++; - } - else - { - current_length++; - window_width=Max(window_width, (current_length<<3)+20); - } - } - // Safety - if (window_width>310) - window_width=310; - - Open_window(window_width,52+(nb_lines<<3),"Confirmation"); - - c=message; - for (current_line=0; current_line < nb_lines; current_line++) - { - char * next_eol; - char display_string[36+1]; - - next_eol = strchr(c, '\n'); - if (next_eol==NULL) // last line - current_length = strlen(c); - else - current_length = next_eol-c; - - // Safeguard - if (current_length>36) - current_length=36; - // Copy part of string in null-terminated buffer - strncpy(display_string, c, current_length); - display_string[current_length]='\0'; - - Print_in_window((window_width>>1)-(current_length<<2), 20+(current_line<<3), display_string, MC_Black, MC_Light); - - c += current_length; - if (*c == '\n') - c++; - } - - Window_set_normal_button((window_width/3)-20 ,29+(nb_lines<<3),40,14,"Yes",1,1,SDLK_y); // 1 - Window_set_normal_button(((window_width<<1)/3)-20,29+(nb_lines<<3),40,14,"No" ,1,1,SDLK_n); // 2 - - Update_rect(Window_pos_X, Window_pos_Y, Window_width*Menu_factor_X, Window_height*Menu_factor_Y); - - Display_cursor(); - - do - { - clicked_button=Window_clicked_button(); - if (Key==SDLK_RETURN) clicked_button=1; - if (Key==KEY_ESC) clicked_button=2; - } - while (clicked_button<=0); - Key=0; - - Close_window(); - Display_cursor(); - - return (clicked_button==1)? 1 : 0; -} - - -/// Window that allows you to enter a single value -int Requester_window(char* message, int initial_value) -{ - short clicked_button = 0; - word window_width; - char str[10]; - - window_width=(strlen(message)<<3)+20; - - if (window_width<120) - window_width = 120; - - Open_window(window_width, 60, "Request"); - - Print_in_window((window_width>>1)-(strlen(message)<<2), 20, message, - MC_Black, MC_Light); - sprintf(str, "%d", initial_value); - Window_set_input_button(10, 37, 4); // 1 - Print_in_window(11, 39, str, MC_Black, MC_Light); - Window_set_normal_button(60 ,37,40,14,"OK",1,1,SDLK_y); // 2 - Window_set_normal_button(130,37,60,14,"Cancel" ,1,1,SDLK_n); // 3 - - Update_rect(Window_pos_X, Window_pos_Y, Menu_factor_X * window_width, - Menu_factor_Y * 60); - Display_cursor(); - - do - { - clicked_button = Window_clicked_button(); - if (clicked_button == 1) - Readline(11, 39, str, 4, INPUT_TYPE_INTEGER); - if (Key == SDLK_ESCAPE) clicked_button = 2; - } - while (clicked_button <= 0); - - Key = 0; - - Close_window(); - Display_cursor(); - - return clicked_button==2?-1:atoi(str); -} - - -/// Window that show a warning message and wait for a click on the OK button -void Warning_message(char * message) -{ - short clicked_button; - word window_width; - - window_width=(strlen(message)<<3)+20; - if (window_width<120) - window_width=120; - - Open_window(window_width,60,"Warning!"); - - Print_in_window((window_width>>1)-(strlen(message)<<2),20,message,MC_Black,MC_Light); - Window_set_normal_button((window_width>>1)-20 ,37,40,14,"OK",1,1,SDLK_RETURN); // 1 - Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*window_width,Menu_factor_Y*60); - Display_cursor(); - - do - clicked_button=Window_clicked_button(); - while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); - Key=0; - - Close_window(); - Display_cursor(); -} - -/// Window that shows a big message (up to 34x12), and waits for a click on OK. -/// On call: Cursor must be displayed -/// On exit: Cursor is displayed -void Verbose_message(const char *caption, const char * message ) -{ - short clicked_button; - int line; - int last_space; - int nb_char; - char buffer[36]; - byte original_cursor_shape = Cursor_shape; - - - Open_window(300,160,caption); - - // Word-wrap the message - for (line=0; line < 12 && *message!='\0'; line++) - { - last_space = -1; - for (nb_char=0; nb_char<35 && message[nb_char]!='\0'; nb_char++) - { - buffer[nb_char]=message[nb_char]; - if (message[nb_char] == ' ') - { - last_space = nb_char; - } - else if (message[nb_char] == '\n') - { - last_space = nb_char; - break; - } - } - // Close line buffer - if (message[nb_char]=='\0' || last_space == -1) - last_space = nb_char; - buffer[last_space]='\0'; - - // Print - Print_in_window(10,20+line*8,buffer,MC_Black,MC_Light); - - // Next line - message=message+last_space; - // Strip at most one carriage return and any leading spaces - if (*message == '\n') - message++; - while (*message == ' ') - message++; - } - - Window_set_normal_button(300/2-20,160-23,40,14,"OK",1,1,SDLK_RETURN); // 1 - Update_window_area(0,0,Window_width,Window_height); - Cursor_shape=CURSOR_SHAPE_ARROW; - Display_cursor(); - - do - clicked_button=Window_clicked_button(); - while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o)); - Key=0; - - Close_window(); - Cursor_shape=original_cursor_shape; - Display_cursor(); -} - - // -- Redessiner le sprite d'un bouton dans le menu -- - -void Display_sprite_in_menu(int btn_number,char sprite_number) -{ - Buttons_Pool[btn_number].Icon=sprite_number; - - 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) -{ - switch(Paintbrush_shape) - { - 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; - } - Draw_menu_button(BUTTON_PAINTBRUSHES,BUTTON_RELEASED); -} - - // -- Dessiner un pinceau prédéfini dans la fenêtre -- - -void Display_paintbrush_in_window(word x,word y,int number) - // Pinceau = 0..NB_PAINTBRUSH_SPRITES-1 : Pinceau prédéfini -{ - word x_pos; - word y_pos; - word window_x_pos; - word window_y_pos; - int x_size; - int y_size; - word origin_x; - word origin_y; - word width; - word height; - - x_size=Menu_factor_X/Pixel_height; - if (x_size<1) - x_size=1; - y_size=Menu_factor_Y/Pixel_width; - if (y_size<1) - y_size=1; - - 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_pos à 64 lignes fct(Menu_Facteur) - word nb_colors =(block_start<=block_end)?block_end-block_start+1:block_start-block_end+1; - word Selected_line_mode=(block_start<=block_end)?0:total_lines-1; - - word start_x =Window_pos_X+(Menu_factor_X*x_pos); - word line_width =Menu_factor_X<<4; // <=> à 16 pixels fct(Menu_Facteur) - - word start_y =Window_pos_Y+(Menu_factor_Y*y_pos); - word end_y =start_y+total_lines; - word index; - - if (block_start>block_end) - { - index=block_start; - block_start=block_end; - block_end=index; - } - - for (index=start_y;indexIcon_sprite[type][j][i]); - Update_rect(ToWinX(x_pos),ToWinY(y_pos),ToWinL(ICON_SPRITE_WIDTH),ToWinH(ICON_SPRITE_HEIGHT)); -} - - - -void Display_menu_palette_avoiding_window(byte * table) -{ - // On part du principe qu'il n'y a que le bas d'une fenêtre qui puisse - // empiéter sur la palette... Et c'est déjà pas mal! - word color,real_color; - word start_x,start_y; - word end_x,end_y; - word width; - word height; - word corner_x=Window_pos_X+Window_width*Menu_factor_X; // |_ Coin bas-droit - word corner_y=Window_pos_Y+Window_height*Menu_factor_Y; // | de la fenêtre +1 - - - if (Config.Separate_colors) - { - width=(Menu_palette_cell_width-1)*Menu_factor_X; - height=Menu_factor_Y*((Menu_height-11)/Menu_cells_Y-1); - } - else - { - width=Menu_palette_cell_width*Menu_factor_X; - height=Menu_factor_Y*((Menu_height-11)/Menu_cells_Y); - } - - for (color=0,real_color=First_color_in_palette;color=corner_y) || (end_x<=Window_pos_X) || (start_x>=corner_x) ) - Block(start_x,start_y,width,height,real_color); - else - { - - if (start_x>=Window_pos_X) - { - if ( (end_x>corner_x) || (end_y>corner_y) ) - { - if ( (end_x>corner_x) && (end_y>corner_y) ) - { - Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color); - Block(start_x,corner_y,width,end_y-corner_y,real_color); - } - else - { - if (end_y>corner_y) - Block(start_x,corner_y,width,end_y-corner_y,real_color); - else - Block(corner_x,start_y,end_x-corner_x,height,real_color); - } - } - } - else - { - if (end_xcorner_y) - { - Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color); - Block(start_x,corner_y,width,end_y-corner_y,real_color); - } - else - Block(start_x,start_y,Window_pos_X-start_x,height,real_color); - } - else - { - if (end_y>corner_y) - { - Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color); - Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color); - Block(start_x,corner_y,width,end_y-corner_y,real_color); - } - else - { - Block(start_x,start_y,Window_pos_X-start_x,height,real_color); - Block(corner_x,start_y,end_x-corner_x,height,real_color); - } - } - } - } - { - // Affichage du bloc directement dans le "buffer de fond" de la fenetre. - // Cela permet au bloc de couleur d'apparaitre si on déplace la fenetre. - short x_pos; - short y_pos; - short relative_x; // besoin d'une variable signée - short relative_y; // besoin d'une variable signée - // Attention aux unités - relative_x = ((short)start_x - (short)Window_pos_X); - relative_y = ((short)start_y - (short)Window_pos_Y); - - for (y_pos=relative_y;y_pos<(relative_y+height)&&y_pos=0&&y_pos>=0) - Pixel_background(x_pos,y_pos,real_color); - } - } - } - Update_rect(MENU_WIDTH*Menu_factor_X,Menu_Y_before_window,Screen_width-(MENU_WIDTH*Menu_factor_X),(Menu_height-11)*Menu_factor_Y); -} - -// -------- Calcul des bornes de la partie d'image visible à l'écran --------- -void Compute_limits(void) -/* - Avant l'appel à cette fonction, les données de la loupe doivent être à jour. -*/ -{ - if (Main_magnifier_mode) - { - // -- Calcul des limites de la partie non zoomée de l'image -- - Limit_top =Main_offset_Y; - Limit_left=Main_offset_X; - Limit_visible_bottom =Limit_top+Menu_Y-1; - Limit_visible_right=Limit_left+Main_separator_position-1; - - if (Limit_visible_bottom>=Main_image_height) - Limit_bottom=Main_image_height-1; - else - Limit_bottom=Limit_visible_bottom; - - if (Limit_visible_right>=Main_image_width) - Limit_right=Main_image_width-1; - else - Limit_right=Limit_visible_right; - - // -- Calcul des limites de la partie zoomée de l'image -- - Limit_top_zoom =Main_magnifier_offset_Y; - Limit_left_zoom=Main_magnifier_offset_X; - Limit_visible_bottom_zoom =Limit_top_zoom+Main_magnifier_height-1; - Limit_visible_right_zoom=Limit_left_zoom+Main_magnifier_width-1; - - if (Limit_visible_bottom_zoom>=Main_image_height) - Limit_bottom_zoom=Main_image_height-1; - else - Limit_bottom_zoom=Limit_visible_bottom_zoom; - - if (Limit_visible_right_zoom>=Main_image_width) - Limit_right_zoom=Main_image_width-1; - else - Limit_right_zoom=Limit_visible_right_zoom; - } - else - { - // -- Calcul des limites de la partie visible de l'image -- - Limit_top =Main_offset_Y; - Limit_left=Main_offset_X; - Limit_visible_bottom =Limit_top+(Menu_is_visible?Menu_Y:Screen_height)-1; // A REVOIR POUR SIMPLIFICATION - Limit_visible_right=Limit_left+Screen_width-1; - - if (Limit_visible_bottom>=Main_image_height) - Limit_bottom=Main_image_height-1; - else - Limit_bottom=Limit_visible_bottom; - - if (Limit_visible_right>=Main_image_width) - Limit_right=Main_image_width-1; - else - Limit_right=Limit_visible_right; - } -} - - -// -- Calculer les coordonnées du pinceau en fonction du snap et de la loupe - -void Compute_paintbrush_coordinates(void) -{ - if ((Main_magnifier_mode) && (Mouse_X>=Main_X_zoom)) - { - Paintbrush_X=((Mouse_X-Main_X_zoom)/Main_magnifier_factor)+Main_magnifier_offset_X; - Paintbrush_Y=(Mouse_Y/Main_magnifier_factor)+Main_magnifier_offset_Y; - } - else - { - Paintbrush_X=Mouse_X+Main_offset_X; - Paintbrush_Y=Mouse_Y+Main_offset_Y; - } - - if (Snap_mode) - { - Paintbrush_X=(((Paintbrush_X+(Snap_width>>1)-Snap_offset_X)/Snap_width)*Snap_width)+Snap_offset_X; - Paintbrush_Y=(((Paintbrush_Y+(Snap_height>>1)-Snap_offset_Y)/Snap_height)*Snap_height)+Snap_offset_Y; - } - - // Handling the snap axis mode, when shift is pressed. - switch (Current_operation) - { - // Operations that don't implement it - case OPERATION_LINE: - case OPERATION_ROTATE_BRUSH: - Snap_axis=0; - break; - // Operations that implement it - default: - if (Snap_axis==0 && (SDL_GetModState() & KMOD_SHIFT)) - { - // Start "Snap axis" mode - Snap_axis=1; - Snap_axis_origin_X=Paintbrush_X; - Snap_axis_origin_Y=Paintbrush_Y; - } - } - - if (Snap_axis==1) - { - // Cursor moved - if (Paintbrush_X != Snap_axis_origin_X || Paintbrush_Y != Snap_axis_origin_Y) - { - if ((Paintbrush_X-Snap_axis_origin_X)*(Paintbrush_X-Snap_axis_origin_X) > - (Paintbrush_Y-Snap_axis_origin_Y)*(Paintbrush_Y-Snap_axis_origin_Y)) - // Displacement was bigger on X axis: lock Y - Snap_axis=2; - else - Snap_axis=3; - } - } - if (Snap_axis==2) - { - Paintbrush_Y = Snap_axis_origin_Y; - } - else if (Snap_axis==3) - { - Paintbrush_X = Snap_axis_origin_X; - } -} - - - -// -- Affichage de la limite de l'image ------------------------------------- -void Display_image_limits(void) -{ - short start; - short pos; - short end; - byte right_is_visible; - byte bottom_is_visible; - short old_zoom_limit; - - right_is_visible=Main_image_width<((Main_magnifier_mode)?Main_separator_position:Screen_width); - bottom_is_visible =Main_image_heightMain_separator_position) - { - Main_offset_X=Main_magnifier_offset_X+(Main_magnifier_width>>1) - -(Main_separator_position>>1); - if (Main_offset_X<0) - Main_offset_X=0; - else if (Main_image_widthMenu_Y) - { - Main_offset_Y=Main_magnifier_offset_Y+(Main_magnifier_height>>1) - -(Menu_Y>>1); - if (Main_offset_Y<0) - Main_offset_Y=0; - else if (Main_image_heightMain_separator_position) - { - Main_offset_X=target_x-Mouse_X; - // Do not allow the zoomed part to show something that the - // non-zoomed part doesn't see. All clipping is computed according - // to the non-zoomed part. - if (Main_magnifier_offset_X Main_offset_X+Main_separator_position) - Main_offset_X = Main_magnifier_offset_X+Main_magnifier_width-Main_separator_position; - if (Main_offset_X<0) - Main_offset_X=0; - else if (Main_image_widthMenu_Y) - { - Main_offset_Y=target_y-Mouse_Y; - // Do not allow the zoomed part to show something that the - // non-zoomed part doesn't see. All clipping is computed according - // to the non-zoomed part. - if (Main_magnifier_offset_Y Main_offset_Y) - Main_offset_Y = Main_magnifier_offset_Y+Main_magnifier_height; - if (Main_offset_Y<0) - Main_offset_Y=0; - else if (Main_image_height>1)-theoric_X)/Main_magnifier_factor)*Main_magnifier_factor); - Main_separator_position=Main_X_zoom-(Menu_factor_X*SEPARATOR_WIDTH); - - // Correction en cas de débordement sur la gauche - while (Main_separator_position*(Main_magnifier_factor+1)=theoric_X) - { - Main_separator_position-=Main_magnifier_factor; - Main_X_zoom-=Main_magnifier_factor; - } -} - - - -// -------------------- Calcul des information de la loupe ------------------- -void Compute_magnifier_data(void) -/* - Après modification des données de la loupe, il faut recalculer les limites. -*/ -{ - Compute_separator_data(); - - Main_magnifier_width=(Screen_width-Main_X_zoom)/Main_magnifier_factor; - - Main_magnifier_height=Menu_Y/Main_magnifier_factor; - if (Menu_Y%Main_magnifier_factor) - Main_magnifier_height++; - - Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); -} - -void Clip_magnifier_offsets(short *x_offset, short *y_offset) -{ - if (Main_magnifier_mode) - { - if (*x_offset) - { - if (Main_image_width<*x_offset+Main_magnifier_width) - *x_offset=Main_image_width-Main_magnifier_width; - if (*x_offset<0) - *x_offset=0; - } - if (*y_offset) - { - if (Main_image_height<*y_offset+Main_magnifier_height) - *y_offset=Main_image_height-Main_magnifier_height+(Main_magnifier_height*Main_magnifier_factor-Menu_Y>=Main_magnifier_factor/2); - if (*y_offset<0) - *y_offset=0; - } - } -} - -/// Changes magnifier factor and updates everything needed -void Change_magnifier_factor(byte factor_index, byte point_at_mouse) -{ - int target_x,target_y; // These coordinates are in image space - byte magnified_view_leads=1; - - // Values that need to be computed before switching to the new zoom factor - if (!point_at_mouse || Cursor_in_menu || !Main_magnifier_mode) - { - // Locate the pixel in center of the magnified area - target_x = Main_magnifier_offset_X + (Main_magnifier_width >> 1); - target_y = Main_magnifier_offset_Y + (Main_magnifier_height >> 1); - point_at_mouse=0; - } - else if (Mouse_X>=Main_X_zoom) - { - // Locate the pixel under the cursor, in magnified area - target_x=((Mouse_X-Main_X_zoom)/Main_magnifier_factor)+Main_magnifier_offset_X; - target_y=(Mouse_Y/Main_magnifier_factor)+Main_magnifier_offset_Y; - point_at_mouse=1; - } - else - { - // Locate the pixel under the cursor, in normal area - target_x=Mouse_X+Main_offset_X; - target_y=Mouse_Y+Main_offset_Y; - magnified_view_leads=0; - point_at_mouse=0; - } - - Main_magnifier_factor=ZOOM_FACTOR[factor_index]; - Compute_magnifier_data(); - - if (Main_magnifier_mode) - { - // Recompute the magnifier offset (center its view) - if (point_at_mouse) - { - // Target pixel must be located under the mouse position. - Main_magnifier_offset_X = target_x-((Mouse_X-Main_X_zoom)/Main_magnifier_factor); - Main_magnifier_offset_Y = target_y-((Mouse_Y)/Main_magnifier_factor); - } - else - { - // Target pixel must be positioned at new center - Main_magnifier_offset_X = target_x-(Main_magnifier_width>>1); - Main_magnifier_offset_Y = target_y-(Main_magnifier_height>>1); - } - // Fix cases where the image would overflow on edges - Clip_magnifier_offsets(&Main_magnifier_offset_X, &Main_magnifier_offset_Y); - - if (magnified_view_leads) - Position_screen_according_to_zoom(); - else - Position_screen_according_to_position(target_x, target_y); - - Pixel_preview=Pixel_preview_magnifier; - - } - else - Pixel_preview=Pixel_preview_normal; - - Compute_limits(); - 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 -- - -void Display_separator(void) -{ - // Partie grise du milieu - Block(Main_separator_position+(Menu_factor_X<<1),Menu_factor_Y, - (SEPARATOR_WIDTH-4)*Menu_factor_X, - Menu_Y-(Menu_factor_Y<<1),MC_Light); - - // Barre noire de gauche - Block(Main_separator_position,0,Menu_factor_X,Menu_Y,MC_Black); - - // Barre noire de droite - Block(Main_X_zoom-Menu_factor_X,0,Menu_factor_X,Menu_Y,MC_Black); - - // Bord haut (blanc) - Block(Main_separator_position+Menu_factor_X,0, - (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_White); - - // Bord gauche (blanc) - Block(Main_separator_position+Menu_factor_X,Menu_factor_Y, - Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_White); - - // Bord droite (gris foncé) - Block(Main_X_zoom-(Menu_factor_X<<1),Menu_factor_Y, - Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_Dark); - - // Bord bas (gris foncé) - Block(Main_separator_position+(Menu_factor_X<<1),Menu_Y-Menu_factor_Y, - (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_Dark); - - // Coin bas gauche - Block(Main_separator_position+Menu_factor_X,Menu_Y-Menu_factor_Y, - Menu_factor_X,Menu_factor_Y,MC_Light); - // Coin haut droite - Block(Main_X_zoom-(Menu_factor_X<<1),0, - Menu_factor_X,Menu_factor_Y,MC_Light); - - Update_rect(Main_separator_position,0,SEPARATOR_WIDTH*Menu_factor_X,Menu_Y); // On réaffiche toute la partie à gauche du split, ce qui permet d'effacer son ancienne position -} - - - -// -- Fonctions de manipulation du curseur ----------------------------------- - - - // -- Afficher une barre horizontale XOR zoomée - -void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width) -{ - short real_x_pos=Main_X_zoom+(x_pos-Main_magnifier_offset_X)*Main_magnifier_factor; - short real_y_pos=(y_pos-Main_magnifier_offset_Y)*Main_magnifier_factor; - short real_width=width*Main_magnifier_factor; - short end_y_pos=(real_y_pos+Main_magnifier_factor=Main_X_zoom) ) ) - || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) ) - shape=Cursor_shape; - else - shape=CURSOR_SHAPE_ARROW; - - switch(shape) - { - case CURSOR_SHAPE_TARGET : - if (!Paintbrush_hidden) - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,1); - if (!Cursor_hidden) - { - if (Config.Cursor==1) - { - start_y=(Mouse_Y<6)?6-Mouse_Y:0; - if (start_y<4) - Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-6,4-start_y); - - start_x=(Mouse_X<6)?(short)6-Mouse_X:0; - if (start_x<4) - Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x); - - end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0; - if (end_x<4) - Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x); - - end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0; - if (end_y<4) - Vertical_XOR_line (Mouse_X,Mouse_Y+3,4-end_y); - - Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y); - } - else - { - temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; - start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; - start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; - - for (y_pos=start_y,counter_y=0; counter_y<15 && y_pos < Screen_height; - y_pos++,counter_y++) - { - if( y_pos < 0 ) continue; - for (x_pos=start_x,counter_x=0; - counter_x<15 && x_pos < Screen_width; x_pos++,counter_x++) - { - if( x_pos < 0 ) continue; - color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; - Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); - if (color!=MC_Trans) - Pixel(x_pos,y_pos,color); - } - } - - Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); - } - } - break; - - case CURSOR_SHAPE_COLORPICKER: - if (!Paintbrush_hidden) - Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,1); - if (Config.Cursor==1) - { - // Barres formant la croix principale - - start_y=(Mouse_Y<5)?5-Mouse_Y:0; - if (start_y<3) - Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-5,3-start_y); - - start_x=(Mouse_X<5)?(short)5-Mouse_X:0; - if (start_x<3) - Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x); - - end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0; - if (end_x<3) - Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x); - - end_y=(Mouse_Y+6>Menu_Y/*Screen_height*/)?Mouse_Y+6-Menu_Y/*Screen_height*/:0; - if (end_y<3) - Vertical_XOR_line (Mouse_X,Mouse_Y+3,3-end_y); - - // Petites barres aux extrémités - - start_x=(!Mouse_X); - start_y=(!Mouse_Y); - end_x=(Mouse_X>=Screen_width-1); - end_y=(Mouse_Y>=Menu_Y-1); - - if (Mouse_Y>5) - Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x)); - - if (Mouse_X>5) - Vertical_XOR_line (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y)); - - if (Mouse_XCursor_offset_X[temp]; - start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; - - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) - { - if(x_pos<0) continue; - if(x_pos>=Screen_width) break; - color=Gfx->Cursor_sprite[temp][counter_y][counter_x]; - // On sauvegarde dans Cursor_background pour restaurer plus tard - Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); - if (color!=MC_Trans) - Pixel(x_pos,y_pos,color); - } - } - Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); - } - break; - - case CURSOR_SHAPE_MULTIDIRECTIONAL : - case CURSOR_SHAPE_HORIZONTAL : - if (Cursor_hidden) - break; - - case CURSOR_SHAPE_ARROW : - case CURSOR_SHAPE_HOURGLASS : - start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; - start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) - { - if(x_pos<0) continue; - if(x_pos>=Screen_width) break; - color=Gfx->Cursor_sprite[shape][counter_y][counter_x]; - // On sauvegarde dans Cursor_background pour restaurer plus tard - Cursor_background[counter_y][counter_x]=Read_pixel(x_pos,y_pos); - if (color!=MC_Trans) - Pixel(x_pos,y_pos,color); - } - } - Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); - break; - - case CURSOR_SHAPE_XOR_TARGET : - x_pos=Paintbrush_X-Main_offset_X; - y_pos=Paintbrush_Y-Main_offset_Y; - - counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR - if ((y_pos=Limit_top)) - { - Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x); - Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1); - } - - if ((x_pos=Limit_left)) - { - Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y); - Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y); - } - - if (Main_magnifier_mode) - { - // UPDATERECT - if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom)) - Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width); - if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom)) - Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height); - } - break; - case CURSOR_SHAPE_XOR_RECTANGLE : - // !!! Cette forme ne peut pas être utilisée en mode Loupe !!! - - // Petite croix au centre - start_x=(Mouse_X-3); - start_y=(Mouse_Y-3); - end_x =(Mouse_X+4); - end_y =(Mouse_Y+4); - if (start_x<0) - start_x=0; - if (start_y<0) - start_y=0; - if (end_x>Screen_width) - end_x=Screen_width; - if (end_y>Menu_Y) - end_y=Menu_Y; - - Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x); - Vertical_XOR_line (Mouse_X,start_y,end_y-start_y); - - // Grand rectangle autour - start_x=Mouse_X-(Main_magnifier_width>>1); - start_y=Mouse_Y-(Main_magnifier_height>>1); - if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X) - start_x=Limit_right-Main_magnifier_width-Main_offset_X+1; - if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) - start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; - if (start_x<0) - start_x=0; - if (start_y<0) - start_y=0; - end_x=start_x+Main_magnifier_width-1; - end_y=start_y+Main_magnifier_height-1; - - Horizontal_XOR_line(start_x,start_y,Main_magnifier_width); - Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2); - Vertical_XOR_line( end_x,start_y+1,Main_magnifier_height-2); - Horizontal_XOR_line(start_x, end_y,Main_magnifier_width); - - Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y); - - break; - default: //case CURSOR_SHAPE_XOR_ROTATION : - start_x=1-(Brush_width>>1); - start_y=1-(Brush_height>>1); - end_x=start_x+Brush_width-1; - end_y=start_y+Brush_height-1; - - if (Brush_rotation_center_is_defined) - { - if ( (Brush_rotation_center_X==Paintbrush_X) - && (Brush_rotation_center_Y==Paintbrush_Y) ) - { - cos_a=1.0; - sin_a=0.0; - } - else - { - x_pos=Paintbrush_X-Brush_rotation_center_X; - y_pos=Paintbrush_Y-Brush_rotation_center_Y; - cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos)); - sin_a=sin(acos(cos_a)); - if (y_pos>0) sin_a=-sin_a; - } - - Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); - Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); - Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); - Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); - - x1+=Brush_rotation_center_X; - y1+=Brush_rotation_center_Y; - x2+=Brush_rotation_center_X; - y2+=Brush_rotation_center_Y; - x3+=Brush_rotation_center_X; - y3+=Brush_rotation_center_Y; - x4+=Brush_rotation_center_X; - y4+=Brush_rotation_center_Y; - Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0); - Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0); - } - else - { - x1=x3=1-Brush_width; - y1=y2=start_y; - x2=x4=Paintbrush_X; - y3=y4=end_y; - - x1+=Paintbrush_X; - y1+=Paintbrush_Y; - y2+=Paintbrush_Y; - x3+=Paintbrush_X; - y3+=Paintbrush_Y; - y4+=Paintbrush_Y; - Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0); - Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0); - } - - Draw_line_preview_xor(x1,y1,x2,y2,0); - Draw_line_preview_xor(x2,y2,x4,y4,0); - Draw_line_preview_xor(x4,y4,x3,y3,0); - Draw_line_preview_xor(x3,y3,x1,y1,0); - } -} - - // -- Effacer le curseur -- - -void Hide_cursor(void) -{ - byte shape; - int start_x; // int car sont parfois négatifs ! (quand on dessine sur un bord) - int start_y; - short end_x; - short end_y; - int x_pos = 0; - int y_pos; - short counter_x = 0; - short counter_y; - int temp; - float cos_a,sin_a; - short x1,y1,x2,y2,x3,y3,x4,y4; - - if ( ( (Mouse_Y=Main_X_zoom) ) ) - || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) ) - shape=Cursor_shape; - else - shape=CURSOR_SHAPE_ARROW; - - switch(shape) - { - case CURSOR_SHAPE_TARGET : - if (!Cursor_hidden) - { - if (Config.Cursor==1) - { - start_y=(Mouse_Y<6)?6-Mouse_Y:0; - if (start_y<4) - Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-6,4-start_y); - - start_x=(Mouse_X<6)?(short)6-Mouse_X:0; - if (start_x<4) - Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x); - - end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0; - if (end_x<4) - Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x); - - end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0; - if (end_y<4) - Vertical_XOR_line (Mouse_X,Mouse_Y+3,4-end_y); - - Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y); - } - else - { - temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET; - start_x=Mouse_X-Gfx->Cursor_offset_X[temp]; - start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; - - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos < 0) continue; - if(y_pos>=Screen_height) break; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) - { - if(x_pos < 0) continue; - else if (x_pos>=Screen_width) break; - Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); - } - } - - Update_rect(Max(start_x,0),Max(start_y,0),x_pos-start_x,y_pos-start_y); - } - } - if (!Paintbrush_hidden) - { - Hide_paintbrush(Paintbrush_X,Paintbrush_Y); - } - break; - - case CURSOR_SHAPE_COLORPICKER: - if (Config.Cursor==1) - { - // Barres formant la croix principale - - start_y=(Mouse_Y<5)?5-Mouse_Y:0; - if (start_y<3) - Vertical_XOR_line (Mouse_X,Mouse_Y+start_y-5,3-start_y); - - start_x=(Mouse_X<5)?(short)5-Mouse_X:0; - if (start_x<3) - Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x); - - end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0; - if (end_x<3) - Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x); - - end_y=(Mouse_Y+6>Screen_height)?Mouse_Y+6-Screen_height:0; - if (end_y<3) - Vertical_XOR_line (Mouse_X,Mouse_Y+3,3-end_y); - - start_x=(!Mouse_X); - start_y=(!Mouse_Y); - end_x=(Mouse_X>=Screen_width-1); - end_y=(Mouse_Y>=Menu_Y-1); - - if (Mouse_Y>5) - Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x)); - - if (Mouse_X>5) - Vertical_XOR_line (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y)); - - if (Mouse_XCursor_offset_X[temp]; - start_y=Mouse_Y-Gfx->Cursor_offset_Y[temp]; - - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) - { - if(x_pos<0) continue; - if(x_pos>=Screen_width) break; - Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); - } - } - Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); - } - if (!Paintbrush_hidden) - Hide_paintbrush(Paintbrush_X,Paintbrush_Y); - break; - - case CURSOR_SHAPE_MULTIDIRECTIONAL : - case CURSOR_SHAPE_HORIZONTAL : - if (Cursor_hidden) - break; - - case CURSOR_SHAPE_ARROW : - case CURSOR_SHAPE_HOURGLASS : - start_x=Mouse_X-Gfx->Cursor_offset_X[shape]; - start_y=Mouse_Y-Gfx->Cursor_offset_Y[shape]; - - for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++) - { - if(y_pos<0) continue; - if(y_pos>=Screen_height) break; - for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++) - { - if(x_pos<0) continue; - if(x_pos>=Screen_width) break; - Pixel(x_pos,y_pos,Cursor_background[counter_y][counter_x]); - } - } - Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y); - break; - - case CURSOR_SHAPE_XOR_TARGET : - x_pos=Paintbrush_X-Main_offset_X; - y_pos=Paintbrush_Y-Main_offset_Y; - - counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR - if ((y_pos=Limit_top)) - { - Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x); - Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1); - } - - if ((x_pos=Limit_left)) - { - Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y); - Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y); - } - - if (Main_magnifier_mode) - { - // UPDATERECT - if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom)) - Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width); - if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom)) - Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height); - } - - - break; - case CURSOR_SHAPE_XOR_RECTANGLE : - // !!! Cette forme ne peut pas être utilisée en mode Loupe !!! - - // Petite croix au centre - start_x=(Mouse_X-3); - start_y=(Mouse_Y-3); - end_x =(Mouse_X+4); - end_y =(Mouse_Y+4); - if (start_x<0) - start_x=0; - if (start_y<0) - start_y=0; - if (end_x>Screen_width) - end_x=Screen_width; - if (end_y>Menu_Y) - end_y=Menu_Y; - - Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x); - Vertical_XOR_line (Mouse_X,start_y,end_y-start_y); - - // Grand rectangle autour - - start_x=Mouse_X-(Main_magnifier_width>>1); - start_y=Mouse_Y-(Main_magnifier_height>>1); - if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X) - start_x=Limit_right-Main_magnifier_width-Main_offset_X+1; - if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y) - start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1; - if (start_x<0) - start_x=0; - if (start_y<0) - start_y=0; - end_x=start_x+Main_magnifier_width-1; - end_y=start_y+Main_magnifier_height-1; - - Horizontal_XOR_line(start_x,start_y,Main_magnifier_width); - Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2); - Vertical_XOR_line( end_x,start_y+1,Main_magnifier_height-2); - Horizontal_XOR_line(start_x, end_y,Main_magnifier_width); - - Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y); - - break; - default: //case CURSOR_SHAPE_XOR_ROTATION : - start_x=1-(Brush_width>>1); - start_y=1-(Brush_height>>1); - end_x=start_x+Brush_width-1; - end_y=start_y+Brush_height-1; - - if (Brush_rotation_center_is_defined) - { - if ( (Brush_rotation_center_X==Paintbrush_X) - && (Brush_rotation_center_Y==Paintbrush_Y) ) - { - cos_a=1.0; - sin_a=0.0; - } - else - { - x_pos=Paintbrush_X-Brush_rotation_center_X; - y_pos=Paintbrush_Y-Brush_rotation_center_Y; - cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos)); - sin_a=sin(acos(cos_a)); - if (y_pos>0) sin_a=-sin_a; - } - - Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1); - Transform_point(end_x ,start_y, cos_a,sin_a, &x2,&y2); - Transform_point(start_x,end_y , cos_a,sin_a, &x3,&y3); - Transform_point(end_x ,end_y , cos_a,sin_a, &x4,&y4); - - x1+=Brush_rotation_center_X; - y1+=Brush_rotation_center_Y; - x2+=Brush_rotation_center_X; - y2+=Brush_rotation_center_Y; - x3+=Brush_rotation_center_X; - y3+=Brush_rotation_center_Y; - x4+=Brush_rotation_center_X; - y4+=Brush_rotation_center_Y; - Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0); - Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0); - } - else - { - x1=x3=1-Brush_width; - y1=y2=start_y; - x2=x4=Paintbrush_X; - y3=y4=end_y; - - x1+=Paintbrush_X; - y1+=Paintbrush_Y; - y2+=Paintbrush_Y; - x3+=Paintbrush_X; - y3+=Paintbrush_Y; - y4+=Paintbrush_Y; - Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0); - Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0); - } - - Draw_line_preview_xor(x1,y1,x2,y2,0); - Draw_line_preview_xor(x2,y2,x4,y4,0); - Draw_line_preview_xor(x4,y4,x3,y3,0); - Draw_line_preview_xor(x3,y3,x1,y1,0); - } -} - - - -// -- Fonction diverses d'affichage ------------------------------------------ - - // -- Reafficher toute l'image (en prenant en compte le facteur de zoom) -- - -void Display_all_screen(void) -{ - word width; - word height; - - // ---/\/\/\ Partie non zoomée: /\/\/\--- - if (Main_magnifier_mode) - { - if (Main_image_widthPages->Transparent_color); - } - else - { - if (Main_image_widthPages->Transparent_color); - } - if (Main_image_heightPages->Transparent_color); - - // ---/\/\/\ Partie zoomée: /\/\/\--- - if (Main_magnifier_mode) - { - // Affichage de la barre de split - Display_separator(); - - // Calcul de la largeur visible - if (Main_image_widthPages->Transparent_color); - if (heightPages->Transparent_color); - } - - // ---/\/\/\ Affichage des limites /\/\/\--- - if (Config.Display_image_limits) - Display_image_limits(); - Update_rect(0,0,Screen_width,Menu_Y); // TODO On peut faire plus fin, en évitant de mettre à jour la partie à droite du split quand on est en mode loupe. Mais c'est pas vraiment intéressant ? -} - - - -byte Best_color(byte r,byte g,byte b) -{ - int col; - int delta_r,delta_g,delta_b; - int dist; - int best_dist=0x7FFFFFFF; - int rmean; - byte best_color=0; - - for (col=0; col<256; col++) - { - if (!Exclude_color[col]) - { - delta_r=(int)Main_palette[col].R-r; - delta_g=(int)Main_palette[col].G-g; - delta_b=(int)Main_palette[col].B-b; - - rmean = ( Main_palette[col].R + r ) / 2; - - if (!(dist= ( ( (512+rmean) *delta_r*delta_r) >>8) + 4*delta_g*delta_g + (((767-rmean)*delta_b*delta_b)>>8))) - //if (!(dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11))) - return col; - - if (dist>8) + 4*delta_g*delta_g + (((767-rmean)*delta_b*delta_b)>>8); - //dist=(delta_r*delta_r*30)+(delta_g*delta_g*59)+(delta_b*delta_b*11) - - if (dist=0; i--) - { - - 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) - { - 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; - } - } - } - } - } - } - } - } - // 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--) - { - - 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 (k=0; k<3; k++) - for (j=0; jMenu_block[k][j][i]); - // Menu sprites - 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++) - for (k=0; k<16; k++) - for (j=0; jLayer_sprite[l][k][j][i]); - - // Status bar - for (k=0; k<3; k++) - for (j=0; jStatusbar_block[k][j][i]); - // Layer bar - for (k=0; k<3; k++) - for (j=0; jLayerbar_block[k][j][i]); - - // Help fonts - for (k=0; k<256; k++) - for (j=0; j<8; j++) - for (i=0; i<6; i++) - Remap_pixel(&Gfx->Help_font_norm[k][i][j]); - for (k=0; k<256; k++) - for (j=0; j<8; j++) - for (i=0; i<6; i++) - Remap_pixel(&Gfx->Bold_font[k][i][j]); - for (k=0; k<64; k++) - for (j=0; j<8; j++) - for (i=0; i<6; i++) - Remap_pixel(&Gfx->Help_font_t1[k][i][j]); - for (k=0; k<64; k++) - for (j=0; j<8; j++) - for (i=0; i<6; i++) - Remap_pixel(&Gfx->Help_font_t2[k][i][j]); - for (k=0; k<64; k++) - for (j=0; j<8; j++) - for (i=0; i<6; i++) - Remap_pixel(&Gfx->Help_font_t3[k][i][j]); - for (k=0; k<64; k++) - for (j=0; j<8; j++) - for (i=0; i<6; i++) - Remap_pixel(&Gfx->Help_font_t4[k][i][j]); - - // Drives and other misc. 8x8 icons - for (k=0; kIcon_sprite[k][j][i]); - - // Skin preview - for (j = 0; j < 173; j++) - for (i = 0; i < 16; i++) - Remap_pixel(&Gfx->Preview[i][j]); - } - Clear_border(MC_Black); -} diff --git a/project/jni/application/grafx2/grafx2/src/windows.h b/project/jni/application/grafx2/grafx2/src/windows.h deleted file mode 100644 index 579efa52d..000000000 --- a/project/jni/application/grafx2/grafx2/src/windows.h +++ /dev/null @@ -1,116 +0,0 @@ -/* vim:expandtab:ts=2 sw=2: -*/ -/* Grafx2 - The Ultimate 256-color bitmap paint program - - Copyright 2007-2008 Adrien Destugues - Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) - - Grafx2 is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; version 2 - of the License. - - Grafx2 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Grafx2; if not, see -*/ - -////////////////////////////////////////////////////////////////////////////// -///@file windows.h -/// Graphical interface management functions (windows, menu, cursor) -////////////////////////////////////////////////////////////////////////////// - -#ifndef __WINDOWS_H_ -#define __WINDOWS_H_ - -#include "struct.h" - -#define ToWinX(x) (((x)*Menu_factor_X)+Window_pos_X) -#define ToWinY(y) (((y)*Menu_factor_Y)+Window_pos_Y) -#define ToWinL(l) ((l)*Menu_factor_X) -#define ToWinH(h) ((h)*Menu_factor_Y) - -#define Update_window_area(x,y,w,h) Update_rect(Window_pos_X+(x)*Menu_factor_X,Window_pos_Y+(y)*Menu_factor_Y,(w)*Menu_factor_X,(h)*Menu_factor_Y); - -void Display_cursor(void); -void Hide_cursor(void); - -void Remap_screen_after_menu_colors_change(void); -void Compute_optimal_menu_colors(T_Components * palette); -void Remap_menu_sprites(); - -void Position_screen_according_to_zoom(void); -void Compute_separator_data(void); -void Compute_magnifier_data(void); -void Clip_magnifier_offsets(short *x_offset, short *y_offset); -void Compute_limits(void); -void Compute_paintbrush_coordinates(void); - -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); -void Pixel_in_window(word x,word y,byte color); -void Set_fore_color(byte color); -void Set_back_color(byte color); -void Frame_menu_color(byte id); -void Display_menu_palette(void); -void Display_menu(void); -void Display_layerbar(void); -void Reposition_palette(void); -void Change_palette_cells(void); -int Pick_color_in_palette(void); -word Palette_cells_X(void); -word Palette_cells_Y(void); - -void Print_general(short x,short y,const char * str,byte text_color,byte background_color); -void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color); -void Print_in_window_limited(short x,short y,const char * str,byte size,byte text_color,byte background_color); -void Print_char_in_window(short x_pos,short y_pos,const unsigned char c,byte text_color,byte background_color); -void Print_in_menu(const char * str, short position); -void Print_coordinates(void); -void Print_filename(void); -void Print_counter(short x,short y,const char * str,byte text_color,byte background_color); - -byte Confirmation_box(char * message); -void Warning_message(char * message); -void Verbose_message(const char * caption, const char * message); -int Requester_window(char* message, int initial_value); - -void Display_image_limits(void); -void Display_all_screen(void); -void Window_rectangle(word x_pos,word y_pos,word width,word height,byte color); -void Window_display_frame_generic(word x_pos,word y_pos,word width,word height, - byte color_tl,byte color_br,byte color_s,byte color_tlc,byte color_brc); -void Window_display_frame_mono(word x_pos,word y_pos,word width,word height,byte color); -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,char sprite_number); -void Display_paintbrush_in_menu(void); -void Display_paintbrush_in_window(word x,word y,int number); - -void Draw_thingumajig(word x,word y, byte color, short direction); -void Display_grad_block_in_window(word x_pos,word y_pos,word block_start,word block_end); -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); -byte Best_color_perceptual_except(byte r,byte g,byte b, byte except); - -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); - -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 diff --git a/project/jni/application/grafx2/icon.png b/project/jni/application/grafx2/icon.png index 993dc8b67e347b202cc79dc6065a4f1d2231f56e..61c074e40d9124cc0dd615c19e9cc12c3b7bcc14 100644 GIT binary patch literal 10294 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 P0|SGntDnm{r-UW|OeO() literal 1652 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4mJh`hH$2z?F*?Ycl5uZslx>HKtH{5!9NCx| ze$zPpvJ+elZ+^J3ls~_;$&$gOPbx(t~@X?Ff^Evkm%?rVlyM* zgIM05n+LA4>I<+fJI_5WG;dmL{?e^HRq^GerJ<#z=j}9>?Owh6_3ya7-(OvQ?YQ~o z69%oVPoJjpH6$7)GVFL>x%7Cx+3Y=R4eo&7mEVW!Np5 z?k4av7;vq7F1NsLV?Cpg<%ieN_J>o|PyXJ0Q0`c>i2L#LeeW&!3LG77TK%&q)-m5@ zH`nhZOU~KO&c|`Jzt!)3JTB8=F`>`@dC}*4b7Q_Jn<`Fy=Gx2bu|+Yf=}Ao;%fG|! zX2u5@&iu2fY+7s0Zn5Y6ql4!9s&oHwa9E`%y%M)6|0)<)_qV)OV&ReGVEeyjcf`W-Sqg5h zvJiIr@Q;Jr^ITx+@`c&E>c0LBezz%vyBIY znTn1~JlOr*?5|7HM$>;EE($AG1Zyiz=yVck4B@kpi*Y}G-}qPC4fo^L)(6_-|F^~O zt5Qrhds4P&?qtnC5hcat=YBVDnb64>^JI?^=hXEtTv+4E`~4oJi~8wUFXbu;eX#9; zu~pe6wYKo8ZE;_iL=}}5z2439Vb#`#YaE4*tE=a+E11e(T6eBxl~?51*DiJ2&Pg~+ zq=naA()-CYF>vNo-it>py&I;>Mo+V2V|X-mM&&&7+c$3>e3l-pY%x{x<*$^BXB+Ib z%2Gr>+ObJI628LNGWq0^yRW}~_<5~sYnbZ=GdqVe>5`zeU7fQ%uRPe#T5x9_=k=M- zD>vWzrE790jL9d}uDe4?hyjXsO?8vMD|Zv9n1 z^U2x_e;^Yn_U`vP_iCjaA`x_R%oaKDvg2%CKHwCF>n58I{|3NHB3 zGbcA_e#P7a{14TSr_V^1FK>MM^r?^SiQ0ebgVGjvecX0)#ml*iUapYY-QQr}tybRG z-)}56!#-!)wLL3zca;A$?VXC_h%Dt~R_8WZ? zbp2Quzi?KJo!>`3SV|rtDiEfGt1Q9S-WDLo=R4{YT%TsJF?bCt8~s34bcd5 zs}ovlCc8CIZK*5MqAn(-3dtRJmj7OrB($mUqwJ%$c=o!E1v`w?nU~BA%sm$>U68=~ z=w9@;L@V+2w;RM&ljF_4<)1PVjeHXI$NKD2wnuwcO^w`VUccr8vt5FI{V@FZ zHnHPu_sa8aM->0u@mg!-8me(taKh>|EyG&ZD_3%z5-#N>GN;ebKD_XU-d4?3=Y^S) zO#RNpKbbk9_8^muXGKfoZ@IF8VT(wA%P*rE%9Kw+COJ+C45$ z(&ZGjVA7v_K}aAy@xs~qkOdx-`|mI0t