diff --git a/checkMissing.sh b/checkMissing.sh new file mode 100755 index 000000000..701710a45 --- /dev/null +++ b/checkMissing.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# Print list of symbols inside libapplication.so which are not defined in Android libc +# Internal compiler things like '__aeabi_ddiv' or '___Unwind_Resume' may be safely ignored +rm -f exports.txt libapplication.txt +cat exports-eclair.txt > exports.txt +nm -g -p --undefined-only project/obj/local/armeabi/libapplication.so | cut -b 12- | sort > libapplication.txt +for f in project/obj/local/armeabi/*.so; do + if [ "$f" = "project/obj/local/armeabi/libapplication.so" ]; then + continue + fi + nm -g -p --defined-only $f 2>/dev/null | cut -b 12- >> exports.txt +done +cat exports.txt | sort > exports1.txt +mv -f exports1.txt exports.txt +diff libapplication.txt exports.txt | grep \< | cut -d \ -f 2 +rm libapplication.txt exports.txt \ No newline at end of file diff --git a/exports-eclair.txt b/exports-eclair.txt index eb9b6fabe..75be0042c 100644 --- a/exports-eclair.txt +++ b/exports-eclair.txt @@ -1,5 +1,4 @@ abort -absoluteTime accept access acct @@ -7,11 +6,8 @@ acos acosf acosh acoshf -acquire_wake_lock __adddf3 __addsf3 -adler32 -adler32_combine __aeabi_atexit __aeabi_cdcmpeq __aeabi_cdcmple @@ -38,7 +34,6 @@ __aeabi_dsub __aeabi_f2d __aeabi_f2iz __aeabi_f2lz -__aeabi_f2uiz __aeabi_f2ulz __aeabi_fadd __aeabi_fcmpeq @@ -58,11 +53,8 @@ __aeabi_idiv0 __aeabi_idivmod __aeabi_l2d __aeabi_l2f -__aeabi_lasr __aeabi_ldiv0 __aeabi_ldivmod -__aeabi_llsl -__aeabi_llsr __aeabi_lmul __aeabi_memclr __aeabi_memclr4 @@ -88,90 +80,20 @@ __aeabi_unwind_cpp_pr1 __aeabi_unwind_cpp_pr2 alarm alphasort -android_atomic_add -android_atomic_and -android_atomic_cmpxchg -android_atomic_dec -android_atomic_inc -android_atomic_or -android_atomic_swap -android_atomic_write -android_closeEventTagMap -android_createDisplaySurface -androidCreateRawThreadEtc -androidCreateThread -androidCreateThreadEtc -android_get_ioprio -androidGetThreadId -androidGetTid -android_log_addFilterRule -android_log_addFilterString -__android_log_assert -__android_log_btwrite -__android_log_buf_print -__android_log_buf_write -__android_log_bwrite -__android_log_dev_available -android_log_format_free -android_log_formatFromString -android_log_formatLogLine -android_log_format_new -__android_log_print -android_log_printLogLine -android_log_processBinaryLogBuffer -android_log_processLogBuffer -android_log_setPrintFormat -android_log_shouldPrintLine -__android_log_vprint -__android_log_write -android_lookupEventTag -android_memset16 -android_memset32 -android_openEventTagMap -android_quasiatomic_cmpxchg_64 -android_quasiatomic_read_64 -android_quasiatomic_swap_64 -androidSetCreateThreadFunc -android_set_ioprio -androidSetThreadPriority -androidSetThreadSchedulingGroup __arc4_getbyte arc4random arc4random_addrandom arc4random_buf arc4random_stir arc4random_uniform -arrayAdd -arrayCreate -arrayFree -arrayGet -arrayRemove -arraySet -arraySetSize -arraySize -arrayUnwrap asctime asctime64 asctime64_r asctime_r -__ashldi3 -ashmem_create_region -ashmem_get_size_region -ashmem_pin_region -ashmem_set_prot_region -ashmem_unpin_region -__ashrdi3 asin asinf asinh asinhf -asocket_abort -asocket_accept -asocket_connect -asocket_destroy -asocket_init -asocket_read -asocket_write asprintf __assert __assert2 @@ -192,7 +114,6 @@ __atomic_cmpxchg __atomic_dec __atomic_inc __atomic_swap -AUTO_OFF_TIMEOUT_DEV __b64_ntop __b64_pton basename @@ -200,32 +121,23 @@ basename_r bcopy bind bindresvport -BIO_f_ssl -BIO_new_buffer_ssl_connect -BIO_new_ssl -BIO_new_ssl_connect __bionic_brk __bionic_clone __bionic_clone_entry __bionic_libgcc_compat_hooks -BIO_ssl_copy_session_id -BIO_ssl_shutdown brk __brk bsd_signal bsearch __bss_end__ +__bss_end__ +_bss_end__ _bss_end__ __bss_start +__bss_start +__bss_start__ __bss_start__ btowc -bufferCreate -bufferFree -bufferPrepareForRead -bufferPrepareForWrite -bufferRead -bufferWrap -bufferWrite bzero cacheflush calloc @@ -238,7 +150,6 @@ ceil ceilf ceill chdir -check_srvr_ecc_cert_and_alg chmod chown chroot @@ -255,21 +166,9 @@ close closedir closelog closelog_r -__clzsi2 __cmpdf2 __cmpsf2 -compress -compress2 -compressBound -config_bool -config_find -config_load -config_load_file -config_node -config_set -config_str connect -convertUtf8ToUtf16BEUA copysign copysignf copysignl @@ -280,13 +179,7 @@ cosf cosh coshf cpuacct_add -crc32 -crc32_combine creat -create_contiguous_mspace -create_contiguous_mspace_with_base -create_contiguous_mspace_with_name -create_mspace_with_base ctime ctime64 ctime64_r @@ -296,108 +189,22 @@ _C_toupper_ _ctype_ __cxa_atexit __cxa_finalize -__cxa_guard_abort -__cxa_guard_acquire -__cxa_guard_release -__cxa_pure_virtual -d2i_SSL_SESSION daemon __data_start +__data_start daylight -deflate -deflateBound -deflateCopy -deflate_copyright -deflateEnd -deflateInit_ -deflateInit2_ -deflateParams -deflatePrime -deflateReset -deflateSetDictionary -deflateSetHeader -deflateTune delete_module -destroy_contiguous_mspace -dexCatchIteratorGetEndOffset -dexComputeChecksum -dexCreateClassLookup -dexCreateInstrFlagsTable -dexCreateInstrFormatTable -dexCreateInstrWidthTable -dexDataMapAdd -dexDataMapAlloc -dexDataMapFree -dexDataMapGet -dexDataMapVerify -dexDecodeDebugInfo -dexDecodeInstruction -dexFileFree -dexFileParse -dexFileSetupBasicPointers -dexFindCatchHandlerOffset0 -dexFindClass -dexFixByteOrdering -dexGetDexCodeSize -dexGetFirstHandlerOffset -dexGetHandlersSize -dexGetInstrOrTableWidthAbs -dexIsClassDescriptor -dexIsFieldDescriptor -dexIsReferenceDescriptor -dexIsValidMemberName -dexIsValidMemberNameUtf8_0 -dexIsValidTypeDescriptor -DEX_MEMBER_VALID_LOW_ASCII -dexOptCreateEmptyHeader -dexOptGenerateCacheFileName -dexParameterIteratorInit -dexParameterIteratorNextDescriptor -dexParameterIteratorNextIndex -dexProtoCompare -dexProtoCompareParameters -dexProtoCompareToDescriptor -dexProtoComputeArgsSize -dexProtoCopyMethodDescriptor -dexProtoGetMethodDescriptor -dexProtoGetParameterCount -dexProtoGetParameterDescriptors -dexProtoGetReturnType -dexProtoGetShorty -dexReadAndVerifyClassData -dexReadAndVerifyClassDataField -dexReadAndVerifyClassDataHeader -dexReadAndVerifyClassDataMethod -dexRoundUpPower2 -dexStringAndSizeById -dexStringCacheAbandon -dexStringCacheEnsureCopy -dexStringCacheInit -dexStringCacheRelease -dexUtf8Cmp -dexZipCloseArchive -dexZipExtractEntryToFile -dexZipFindEntry -dexZipGetEntryInfo -dexZipOpenArchive -dexZipPrepArchive difftime dirfd dirname dirname_r -disasm -disassemble -_dist_code div __div0 __divdf3 __divdi3 __divsf3 __divsi3 -dladdr dlcalloc -dlclose -dlerror dlfree dlindependent_calloc dlindependent_comalloc @@ -412,11 +219,8 @@ dlmalloc_walk_free_pages dlmalloc_walk_heap dlmallopt dlmemalign -dlopen dlpvalloc dlrealloc -dlsym -dl_unwind_find_exidx dlvalloc __dn_comp __dn_count_labels @@ -426,7 +230,6 @@ _dns_gethtbyaddr _dns_gethtbyname __dn_skipname dns_last_change_counter -do_dhcp_request _dorand48 __dorand48 drand48 @@ -434,988 +237,20 @@ drem dremf __dso_handle __dtoa +dump dup dup2 -dvmAbort -dvmAbstractMethodStub -dvmAddBreakAddr -dvmAddClassToHash -dvmAddCommandLineProperty -dvmAddInitiatingLoader -dvmAddressSetForLine -dvmAddressSetGet -dvmAddressSetSet -dvmAddSingleStep -dvmAddToIndirectRefTable -dvmAddToReferenceTable -dvmAddTrackedAlloc -dvmAllocArray -dvmAllocArrayByClass -dvmAllocAtomicCache -dvmAllocBit -dvmAllocBitVector -dvmAllocMultiArray -dvmAllocObject -dvmAllocObjectArray -dvmAllocPrimitiveArray -dvmAllocTrackerShutdown -dvmAllocTrackerStartup -dvmAppendToIndirectRefTable -dvmAsmInstructionEnd -dvmAsmInstructionStart -dvmAsmSisterEnd -dvmAsmSisterStart -dvmAssertHeapWorkerThreadRunning -dvmAttachCurrentThread -dvmBreakpointShutdown -dvmBreakpointStartup -dvmCallJNIMethod_general -dvmCallJNIMethod_staticNoRef -dvmCallJNIMethod_synchronized -dvmCallJNIMethod_virtualNoRef -dvmCallMethod -dvmCallMethodA -dvmCallMethodV -dvmCanPutArrayElement -dvmChangeStatus -dvmChangeThreadPriority -dvmCheckAsmConstants -dvmCheckBranchTarget -dvmCheckCallJNIMethod_general -dvmCheckCallJNIMethod_staticNoRef -dvmCheckCallJNIMethod_synchronized -dvmCheckCallJNIMethod_virtualNoRef -dvmCheckClassAccess -dvmCheckException -dvmCheckFieldAccess -dvmCheckMethodAccess -dvmCheckOptHeaderAndDependencies -dvmCheckSuspendPending -dvmCheckSuspendQuick -dvmCheckSwitchTargets -dvmClassPathContains -dvmClassShutdown -dvmClassStartup -dvmCleanupStackOverflow -dvmClearAllBits -dvmClearAllocFlags -dvmClearBit -dvmClearBreakAddr -dvmClearException -dvmClearIndirectRefTable -dvmClearOptException -dvmClearReferenceTable -dvmClearSingleStep -dvmCloneObject -dvmClzImpl -dvmCollectGarbage -dvmCollectGarbageInternal -dvmCompareDescriptorAndMethodProto -dvmCompareMethodNamesAndParameterProtos -dvmCompareMethodNamesAndProtos -dvmCompareMethodParameterProtos -dvmCompareMethodProtos -dvmCompareNameDescriptorAndMethod -dvmCompareNameProtoAndMethod -dvmComputeCodeWidths -dvmComputeExactFrameDepth -dvmComputeMethodArgsSize -dvmComputeStringHash -dvmComputeUtf8Hash -dvmComputeVagueFrameDepth -dvmContinueOptimization -dvmConvertArgument -dvmConvertPrimitiveValue -dvmConvertUtf8ToUtf16 -dvmCopyBitVector -dvmCopyDescriptorStringFromMethod -dvmCopyObjectArray -dvmCountSetBits -dvmCreateCstrFromString -dvmCreateCstrFromStringRegion -dvmCreateDefaultProperties -dvmCreateFileOutputTarget -dvmCreateInternalThread -dvmCreateInterpThread -dvmCreateJNIEnv -dvmCreateLogOutputTarget -dvmCreateMonitor -dvmCreateReflectMethodObject -dvmCreateReflectObjForField -dvmCreateReflectObjForMethod -dvmCreateStackTraceArray -dvmCreateStockExceptions -dvmCreateStringFromCstr -dvmCreateStringFromCstrAndLength -dvmCreateStringFromUnicode -dvmCreateSystemLibraryName -dvmCreateUninitInstanceMap -dvm_dalvik_system_DexFile -dvm_dalvik_system_SamplingProfiler -dvm_dalvik_system_VMDebug -dvm_dalvik_system_VMRuntime -dvm_dalvik_system_VMStack -dvm_dalvik_system_Zygote -dvmDbgActive -dvmDbgCondBroadcast -dvmDbgCondSignal -dvmDbgCondWait -dvmDbgConfigureStep -dvmDbgConnected -dvmDbgCreateObject -dvmDbgCreateString -dvmDbgDdmConnected -dvmDbgDdmDisconnected -dvmDbgDdmHandlePacket -dvmDbgDdmSendChunk -dvmDbgDdmSendChunkV -dvmDbgDisconnected -dvmDbgExecuteMethod -dvmDbgExit -dvmDbgFindLoadedClassBySignature -dvmDbgGetAccessFlags -dvmDbgGetAllThreads -dvmDbgGetArrayElementTag -dvmDbgGetArrayLength -dvmDbgGetClassDescriptor -dvmDbgGetClassInfo -dvmDbgGetClassList -dvmDbgGetClassLoader -dvmDbgGetClassObject -dvmDbgGetClassObjectType -dvmDbgGetFieldTag -dvmDbgGetFieldValue -dvmDbgGetInvokeReq -dvmDbgGetLocalValue -dvmDbgGetMainThreadGroupId -dvmDbgGetMethodName -dvmDbgGetObjectTag -dvmDbgGetObjectType -dvmDbgGetObjectTypeName -dvmDbgGetSignature -dvmDbgGetSignatureTag -dvmDbgGetSourceFile -dvmDbgGetStaticFieldTag -dvmDbgGetStaticFieldValue -dvmDbgGetSuperclass -dvmDbgGetSystemThreadGroupId -dvmDbgGetTagWidth -dvmDbgGetThisObject -dvmDbgGetThreadFrame -dvmDbgGetThreadFrameCount -dvmDbgGetThreadGroup -dvmDbgGetThreadGroupName -dvmDbgGetThreadGroupParent -dvmDbgGetThreadGroupThreads -dvmDbgGetThreadName -dvmDbgGetThreadSelfId -dvmDbgGetThreadStatus -dvmDbgGetThreadSuspendCount -dvmDbgGetVisibleClassList -dvmDbgInitCond -dvmDbgInitMutex -dvmDbgInvokeMethod -dvmDbgIsDebuggerConnected -dvmDbgIsInterface -dvmDbgIsSuspended -dvmDbgLastDebuggerActivity -dvmDbgLockMutex -dvmDbgMatchType -dvmDbgOutputAllFields -dvmDbgOutputAllInterfaces -dvmDbgOutputAllMethods -dvmDbgOutputArray -dvmDbgOutputLineTable -dvmDbgOutputVariableTable -dvmDbgPostClassPrepare -dvmDbgPostException -dvmDbgPostLocationEvent -dvmDbgPostThreadDeath -dvmDbgPostThreadStart -dvmDbgRegisterObjectId -dvmDbgResumeThread -dvmDbgResumeVM -dvmDbgSetArrayElements -dvmDbgSetFieldValue -dvmDbgSetLocalValue -dvmDbgSetStaticFieldValue -dvmDbgStringToUtf8 -dvmDbgSuspendSelf -dvmDbgSuspendThread -dvmDbgSuspendVM -dvmDbgThreadContinuing -dvmDbgThreadExists -dvmDbgThreadRunning -dvmDbgThreadWaiting -dvmDbgUnconfigureStep -dvmDbgUnlockMutex -dvmDbgUnwatchLocation -dvmDbgWatchLocation -dvmDdmConnected -dvmDdmDisconnected -dvmDdmGenerateThreadStats -dvmDdmGetRecentAllocations -dvmDdmGetStackTraceById -dvmDdmHandleHpifChunk -dvmDdmHandleHpsgNhsgChunk -dvmDdmHandlePacket -dvmDdmSendHeapInfo -dvmDdmSendHeapSegments -dvmDdmSendThreadNameChange -dvmDdmSendThreadNotification -dvmDdmSetThreadNotification -dvmDebuggerShutdown -dvmDebuggerStartup -dvmDecodeIndirectRef -dvmDefineClass -dvmDescriptorToDot -dvmDescriptorToName -dvmDestroyJNIEnv -dvmDestroyMutex -dvmDetachCurrentThread -dvmDetachSystemThread -dvmDetermineCat1Const -dvmDexCacheStatus -dvmDexChangeDex1 -dvmDexChangeDex2 -dvmDexFileFree -dvmDexFileOpenFromFd -dvmDexFileOpenPartial -dvmDexGetResolvedClass -dvmDexGetResolvedField -dvmDexGetResolvedMethod -dvmDexGetResolvedString -dvmDexSetResolvedClass -dvmDexSetResolvedField -dvmDexSetResolvedMethod -dvmDexSetResolvedString -dvmDisableAllocTracker -dvmDoTrackAllocation -dvmDotToDescriptor -dvmDotToSlash -dvmDumpAllClasses -dvmDumpAllThreads -dvmDumpAllThreadsEx -dvmDumpAtomicCacheStats -dvmDumpBootClassPath -dvmDumpClass -dvmDumpFp -dvmDumpIndirectRefTable -dvmDumpJniReferenceTables -dvmDumpLoaderStats -dvmDumpMonitorInfo -dvmDumpObject -dvmDumpReferenceTable -dvmDumpRunningThreadStack -dvmDumpThread -dvmDumpThreadEx -dvmDumpThreadStack -dvmDumpTrackedAllocations -dvmEmitEmulatorTrace -dvmEmulatorTraceStart -dvmEmulatorTraceStop -dvmEnableAllocTracker -dvmEncodedArrayIteratorGetNext -dvmEncodedArrayIteratorHasNext -dvmEncodedArrayIteratorInitialize -dvmExceptionShutdown -dvmExceptionStartup -dvmFieldPtr -dvmFillInStackTrace -dvmFillInStackTraceInternal -dvmFillInStackTraceRaw -dvmFindArrayClass -dvmFindArrayClassForElement -dvmFindCatchBlock -dvmFindClass -dvmFindClassByName -dvmFindClassNoInit -dvmFindDirectMethod -dvmFindDirectMethodByDescriptor -dvmFindDirectMethodHier -dvmFindDirectMethodHierByDescriptor -dvmFindFieldHier -dvmFindFieldOffset -dvmFindInReferenceTable -dvmFindInstanceField -dvmFindInstanceFieldHier -dvmFindInterfaceMethodInCache -dvmFindLoadedClass -dvmFindMethodHier -dvmFindPrimitiveClass -dvmFindStaticField -dvmFindStaticFieldHier -dvmFindSystemClass -dvmFindSystemClassNoInit -dvmFindVirtualMethod -dvmFindVirtualMethodByDescriptor -dvmFindVirtualMethodByName -dvmFindVirtualMethodHier -dvmFindVirtualMethodHierByDescriptor -dvmFixMethodFlags -dvmFloatToU4 -dvmFlushBreakpoints -dvmFprintf -dvmFreeAtomicCache -dvmFreeBitVector -dvmFreeClassInnards -dvmFreeDexOrJar -dvmFreeIndexMapSet -dvmFreeMonitorList -dvmFreeOutputTarget -dvmFreeRegisterMap -dvmFreeRegisterMapBuilder -dvmFreeUninitInstanceMap -dvmGcDetachDeadInternedStrings -dvmGcMarkDebuggerRefs -dvmGcMarkJniGlobalRefs -dvmGcPreZygoteFork -dvmGcScanInternedStrings -dvmGcScanPrimitiveClasses -dvmGcScanRootClassLoader -dvmGcScanRootThreadGroups -dvmGcShutdown -dvmGcStartup -dvmGcStartupAfterZygote -dvmGenerateProxyClass -dvmGenerateRegisterMaps -dvmGenerateRegisterMapV -dvmGenerateTrackedAllocationReport -dvmGetAnnotationDefaultValue -dvmGetArgInfoReturnType -dvmGetArgLong -dvmGetBootPathResource -dvmGetBootPathSize -dvmGetBoxedReturnType -dvmGetBranchTarget -dvmGetCaller2Class -dvmGetCaller3Class -dvmGetCallerClass -dvmGetCallerFP -dvmGetClassAnnotations -dvmGetClassSignatureAnnotation -dvmGetCurrentJNIMethod -dvmGetDeclaredClasses -dvmGetDeclaredConstructors -dvmGetDeclaredFields -dvmGetDeclaredMethods -dvmGetDeclaringClass -dvmGetEnclosingClass -dvmGetEnclosingMethod -dvmGetException -dvmGetExceptionCause -dvmGetExpandedRegisterMap -dvmGetExpandedRegisterMap0 -dvmGetExternalBytesAllocated -dvmGetFieldAnnotations -dvmGetFieldBoolean -dvmGetFieldByte -dvmGetFieldChar -dvmGetFieldDouble -dvmGetFieldFloat -dvmGetFieldFromReflectObj -dvmGetFieldInt -dvmGetFieldLong -dvmGetFieldObject -dvmGetFieldShort -dvmGetFieldSignatureAnnotation -dvmGetFromIndirectRefTable -dvmGetFromIndirectRefTableCheck -dvmGetHeapDebugInfo -dvmGetIndirectRefType -dvmGetInlineOpsTable -dvmGetInlineOpsTableLength -dvmGetInnerClass -dvmGetInterfaces -dvmGetJarFileCacheFileName -dvmGetJarFileDex -dvmGetJNIEnvForThread -dvmGetJNIRefType -dvmGetMainThreadGroup -dvmGetMethodAnnotations -dvmGetMethodCode -dvmGetMethodFromReflectObj -dvmGetMethodInsnsSize -dvmGetMethodSignatureAnnotation -dvmGetMethodSourceFile -dvmGetMethodThrows -dvmGetMonitorObject -dvmGetNextHeapWorkerObject -dvmGetNumLoadedClasses -dvmGetObjectLockHolder -dvmGetOriginalOpCode -dvmGetOtherThreadCpuTimeNsec -dvmGetOtherThreadCpuTimeUsec -dvmGetParameterAnnotations -dvmGetProperty -dvmGetRawDexFileCacheFileName -dvmGetRawDexFileDex -dvmGetRelativeTimeNsec -dvmGetRelativeTimeUsec -dvmGetStackTrace -dvmGetStackTraceRaw -dvmGetStaticFieldBoolean -dvmGetStaticFieldByte -dvmGetStaticFieldChar -dvmGetStaticFieldDouble -dvmGetStaticFieldFloat -dvmGetStaticFieldInt -dvmGetStaticFieldLong -dvmGetStaticFieldObject -dvmGetStaticFieldShort -dvmGetSystemClassLoader -dvmGetSystemThreadGroup -dvmGetSystemThreadStatus -dvmGetSysThreadId -dvmGetTargetHeapUtilization -dvmGetThisPtr -dvmGetThreadByHandle -dvmGetThreadByThreadId -dvmGetThreadCpuTimeNsec -dvmGetThreadCpuTimeUsec -dvmGetThreadFromThreadObject -dvmGetThreadJNIEnv -dvmGetThreadName -dvmGetThreadStatusStr -dvmGetUninitInstance -dvmGetVirtualizedMethod -dvmHandleStackOverflow -dvmHashcmpStrings -dvmHashForeach -dvmHashForeachRemove -dvmHashIterBegin -dvmHashIterData -dvmHashIterDone -dvmHashIterNext -dvmHashSize -dvmHashTableClear -dvmHashTableCreate -dvmHashTableFree -dvmHashTableLock -dvmHashTableLookup -dvmHashTableMemUsage -dvmHashTableNumEntries -dvmHashTableProbeCount -dvmHashTableRemove -dvmHashTableUnlock -dvmHeapAddRefToLargeTable -dvmHeapAddTableToLargeTable -dvmHeapBeginMarkStep -dvmHeapBitmapDelete -dvmHeapBitmapDeleteList -dvmHeapBitmapInit -dvmHeapBitmapInitFromTemplate -dvmHeapBitmapInitListFromTemplates -dvmHeapBitmapWalk -dvmHeapBitmapWalkList -dvmHeapBitmapXorWalk -dvmHeapBitmapXorWalkLists -dvmHeapBitmapZero -dvmHeapFinishMarkStep -dvmHeapFreeHeapRefTable -dvmHeapFreeLargeTable -dvmHeapGetNextObjectFromLargeTable -dvmHeapHandleReferences -dvmHeapHeapTableFree -dvmHeapInitHeapRefTable -dvmHeapMarkLargeTableRefs -dvmHeapMarkRootSet -dvmHeapScanMarkedObjects -dvmHeapScheduleFinalizations -dvmHeapSetHprofGcScanState -dvmHeapShutdown -dvmHeapSizeChanged -dvmHeapSourceAlloc -dvmHeapSourceAllocAndGrow -dvmHeapSourceChunkSize -dvmHeapSourceContains -dvmHeapSourceFootprint -dvmHeapSourceFree -dvmHeapSourceFreeList -dvmHeapSourceGetIdealFootprint -dvmHeapSourceGetNumHeaps -dvmHeapSourceGetObjectBitmaps -dvmHeapSourceGetPtrFlag -dvmHeapSourceGetValue -dvmHeapSourceGrowForUtilization -dvmHeapSourceReplaceObjectBitmaps -dvmHeapSourceShutdown -dvmHeapSourceStartup -dvmHeapSourceStartupAfterZygote -dvmHeapSourceStartupBeforeFork -dvmHeapSourceTrim -dvmHeapSourceWalk -dvmHeapStartup -dvmHeapStartupAfterZygote -dvmHeapSweepUnmarkedObjects -dvmHeapWorkerShutdown -dvmHeapWorkerStartup -dvmHoldsLock -dvmIdentityHashCode -dvmImplements -dvmIndirectRefTableEntries -dvmIndirectRefToIndex -dvmInitAfterZygote -dvmInitBreakpoints -dvmInitClass -dvmInitializeHeapWorkerState -dvmInitIndirectRefTable -dvmInitInterpStack -dvmInitMutex -dvmInitReferenceTable -dvmInlineNativeShutdown -dvmInlineNativeStartup -dvmInSamePackage -dvmInsnGetWidth -dvmInsnIsBranchTarget -dvmInsnIsChanged -dvmInsnIsGcPoint -dvmInsnIsInTry -dvmInsnIsOpcode -dvmInsnIsVisited -dvmInsnIsVisitedOrChanged -dvmInsnSetBranchTarget -dvmInsnSetChanged -dvmInsnSetGcPoint -dvmInsnSetInTry -dvmInsnSetVisited -dvmInstanceof -dvmInstanceofNonTrivial -dvmInstanceofShutdown -dvmInstanceofStartup -dvmInternalNativeShutdown -dvmInternalNativeStartup -dvmInterpFindInterfaceMethod -dvmInterpHandleFillArrayData -dvmInterpHandlePackedSwitch -dvmInterpHandleSparseSwitch -dvmInterpret -dvmInterpretDbg -dvmInterpretStd -dvmIntersectBitVectors -dvmInvokeMethod -dvmIsAbstractClass -dvmIsAbstractMethod -dvmIsAnnotationClass -dvmIsArray -dvmIsArrayClass -dvmIsBitSet -dvmIsBreakFrame -dvmIsBytecodeMethod -dvmIsCheckedException -dvmIsClassInitialized -dvmIsClassInitializing -dvmIsClassLinked -dvmIsClassVerified -dvmIsConstructorMethod -dvmIsDeclaredSynchronizedMethod -dvmIsDirectMethod -dvmIsFinalClass -dvmIsFinalField -dvmIsFinalMethod -dvmIsIndirectRefTableFull -dvmIsInterfaceClass -dvmIsMethodTraceActive -dvmIsMirandaMethod -dvmIsNativeMethod -dvmIsObjectArray -dvmIsOnThreadList -dvmIsPrimitiveClass -dvmIsPrivateMethod -dvmIsPrivilegedMethod -dvmIsProtectedField -dvmIsPublicClass -dvmIsPublicMethod -dvmIsReferenceTableFull -dvmIsReflectionMethod -dvmIsStaticField -dvmIsStaticMethod -dvmIsSubClass -dvmIsSuspended -dvmIsSynchronizedMethod -dvmIsValidObject -dvmIsWeakGlobalRef -dvmIterativeSleep -dvmJarFileFree -dvmJarFileOpen -dvm_java_lang_Class -dvm_java_lang_Object -dvm_java_lang_reflect_AccessibleObject -dvm_java_lang_reflect_Array -dvm_java_lang_reflect_Constructor -dvm_java_lang_reflect_Field -dvm_java_lang_reflect_Method -dvm_java_lang_reflect_Proxy -dvm_java_lang_Runtime -dvm_java_lang_String -dvm_java_lang_System -dvm_java_lang_SystemProperties -dvm_java_lang_Throwable -dvm_java_lang_VMClassLoader -dvm_java_lang_VMThread -dvm_java_security_AccessController -dvm_java_util_concurrent_atomic_AtomicLong -dvmJdwpAcceptConnection -dvmJdwpAddLocation -dvmJdwpAndroidAdbTransport -dvmJdwpAwaitingHandshake -dvmJdwpClearWaitForEventThread -dvmJdwpCloseConnection -dvmJdwpDdmSendChunkV -dvmJdwpErrorStr -dvmJdwpEstablishConnection -dvmJdwpEventAlloc -dvmJdwpEventFree -dvmJdwpEventKindStr -dvmJdwpGetDebugThread -dvmJdwpGetNowMsec -dvmJdwpIsActive -dvmJdwpIsConnected -dvmJdwpIsTransportDefined -dvmJdwpLastDebuggerActivity -dvmJdwpNetFree -dvmJdwpNetShutdown -dvmJdwpNetStartup -dvmJdwpNextEventSerial -dvmJdwpNextRequestSerial -dvmJdwpPostClassPrepare -dvmJdwpPostClassUnload -dvmJdwpPostException -dvmJdwpPostFieldAccess -dvmJdwpPostLocationEvent -dvmJdwpPostThreadChange -dvmJdwpPostVMDeath -dvmJdwpPostVMStart -dvmJdwpProcessIncoming -dvmJdwpProcessRequest -dvmJdwpRegisterEvent -dvmJdwpResetState -dvmJdwpSendBufferedRequest -dvmJdwpSendRequest -dvmJdwpSetWaitForEventThread -dvmJdwpShutdown -dvmJdwpSocketTransport -dvmJdwpStartup -dvmJdwpStepDepthStr -dvmJdwpStepSizeStr -dvmJdwpSuspendPolicyStr -dvmJdwpSuspendStatusStr -dvmJdwpThreadStatusStr -dvmJdwpUnregisterAll -dvmJdwpUnregisterEventById -dvmJniShutdown -dvmJniStartup -dvmLateEnableAssertions -dvmLateEnableCheckedJni -dvmLinearAlloc -dvmLinearAllocContains -dvmLinearAllocCreate -dvmLinearAllocDestroy -dvmLinearAllocDump -dvmLinearFree -dvmLinearReadOnly -dvmLinearReadWrite -dvmLinearRealloc -dvmLinearSetReadOnly -dvmLinearSetReadWrite -dvmLinearStrdup -dvmLineNumFromPC -dvmLinkClass -dvmLoaderInInitiatingList -dvmLoadNativeCode -dvmLockHeap -dvmLockMutex -dvmLockObject -dvmLockThreadList -dvmLogExceptionStackTrace -dvmLogGcStats -dvmLogMadviseStats -dvmLogRawStackTrace -dvmLogUnableToResolveClass -dvmLogVerifyFailure -dvmLookupClass -dvmLookupImmortalInternedString -dvmLookupInternalNativeMethod -dvmLookupInternedString -dvmMalloc -dvmMarkObjectNonNull -dvmMethodTraceAdd -dvmMethodTraceClassPrepBegin -dvmMethodTraceClassPrepEnd -dvmMethodTraceGCBegin -dvmMethodTraceGCEnd -dvmMethodTraceStart -dvmMethodTraceStop -dvmMethodTypeStr -dvmMinimumHeapSize -dvmMterpCommonExceptionThrown -dvmMterpDumpArmRegs -dvmMterpPrintMethod -dvmMterpStd -dvmMterpStdBail -dvmMterpStdRun -dvmNameToDescriptor -dvmNativeShutdown -dvmNativeStartup -dvmNormalizeWeakGlobalRef -dvmNukeThread -dvmObfuscateWeakGlobalRef -dvmObjectNotify -dvmObjectNotifyAll -dvmObjectSizeInHeap -dvmObjectToIndirectRef -dvmObjectWait -dvmOpenCachedDexFile -dvmOptimizeDexFile -dvmOptResolveClass -dvmOptResolveInstField -dvmOptResolveInterfaceMethod -dvmOptResolveMethod -dvmOptResolveStaticField -dvm_org_apache_harmony_dalvik_ddmc_DdmServer -dvm_org_apache_harmony_dalvik_ddmc_DdmVmInternal -dvm_org_apache_harmony_dalvik_NativeTestTarget -dvmPerformInlineOp4Dbg -dvmPerformInlineOp4Std -dvmPlatformInvoke -dvmPlatformInvokeHints -dvmPointerSetAddEntry -dvmPointerSetAlloc -dvmPointerSetClear -dvmPointerSetDump -dvmPointerSetFind -dvmPointerSetFree -dvmPointerSetGetCount -dvmPointerSetGetEntry -dvmPointerSetHas -dvmPointerSetIntersect -dvmPointerSetRemoveEntry -dvmPopIndirectRefTableSegment -dvmPopIndirectRefTableSegmentCheck -dvmPopJniLocals -dvmPopLocalFrame -dvmPrepForDexOpt -dvmPrepMainForJni -dvmPrepMainThread -dvmPrintDebugMessage -dvmPrintExceptionStackTrace -dvmPrintHexDump -dvmPrintHexDumpDbg -dvmPrintHexDumpEx -dvmProfilingShutdown -dvmProfilingStartup -dvmPropertiesShutdown -dvmPropertiesStartup -dvmPushIndirectRefTableSegment -dvmPushJNIFrame -dvmPushLocalFrame -dvmRaiseThreadPriorityIfNeeded -dvmRawDexFileFree -dvmRawDexFileOpen -dvmReadFieldId -dvmReadFrameId -dvmReadMethodId -dvmReadObjectId -dvmReadRefTypeId -dvmReferenceTableEntries -dvmReflectAnnotationStartup -dvmReflectProxyStartup -dvmReflectShutdown -dvmReflectStartup -dvmRegisterMapDumpStats -dvmRegisterMapGetClassData -dvmRegisterMapGetFormat -dvmRegisterMapGetLine -dvmRegisterMapGetNext -dvmRegisterMapGetNumEntries -dvmRegisterMapGetOnHeap -dvmRegisterMapGetRegWidth -dvmRegisterMapSetFormat -dvmRegisterMapSetNumEntries -dvmRegisterMapSetOnHeap -dvmRegisterMapSetRegWidth -dvmRegisterMapShutdown -dvmRegisterMapStartup -dvmRelativeCondWait -dvmReleaseJniMonitors -dvmReleaseRegisterMapLine -dvmReleaseTrackedAlloc -dvmReleaseTrackedAllocIFN -dvmRemoveFromIndirectRefTable -dvmRemoveFromReferenceTable -dvmResetThreadPriority -dvmResolveClass -dvmResolveInstField -dvmResolveInterfaceMethod -dvmResolveMethod -dvmResolveNativeMethod -dvmResolveStaticField -dvmResolveString -dvmResumeAllThreads -dvmResumeThread -dvmRewriteConstants -dvmRunFinalizationSync -dvmScheduleHeapSourceTrim -dvmSetBit -dvmSetBootPathExtraDex -dvmSetClassSerialNumber -dvmSetCloseOnExec -dvmSetCommandLineProperties -dvmSetException -dvmSetFieldBoolean -dvmSetFieldByte -dvmSetFieldChar -dvmSetFieldDouble -dvmSetFieldFloat -dvmSetFieldId -dvmSetFieldInt -dvmSetFieldLong -dvmSetFieldObject -dvmSetFieldShort -dvmSetFrameId -dvmSetJniEnvThreadId -dvmSetMethodId -dvmSetNativeFunc -dvmSetObjectId -dvmSetRefTypeId -dvmSetRegisterMap -dvmSetStaticFieldBoolean -dvmSetStaticFieldByte -dvmSetStaticFieldChar -dvmSetStaticFieldDouble -dvmSetStaticFieldFloat -dvmSetStaticFieldInt -dvmSetStaticFieldLong -dvmSetStaticFieldObject -dvmSetStaticFieldShort -dvmSetTargetHeapUtilization -dvmSetThreadJNIEnv -dvmSetTryFlags -dvmSetUninitInstance -dvmShutdown -dvmSignalCatcherShutdown -dvmSignalCatcherStartup -dvmSignalHeapWorker -dvmSlayDaemons -dvmSlotToField -dvmSlotToMethod -dvmStartAllocCounting -dvmStartInstructionCounting -dvmStartup -dvmStaticFieldPtr -dvmStdioConverterShutdown -dvmStdioConverterStartup -dvmStopAllocCounting -dvmStopInstructionCounting -dvmStringCharArray -dvmStringChars -dvmStringInternShutdown -dvmStringInternStartup -dvmStringLen -dvmStringShutdown -dvmStringUtf8ByteLen -dvm_sun_misc_Unsafe -dvmSuspendAllThreads -dvmSuspendSelf -dvmSuspendThread -dvmSweepMonitorList -dvmTestAtomicSpeed -dvmTestAtomicSpeedSub -dvmThreadInterrupt -dvmThreadObjStartup -dvmThreadSelf -dvmThreadShutdown -dvmThreadSleep -dvmThreadStartup -dvmThrowBadAllocException -dvmThrowChainedException -dvmThrowChainedExceptionByClass -dvmThrowChainedExceptionWithClassMessage -dvmThrowException -dvmThrowExceptionByClass -dvmThrowExceptionByClassWithClassMessage -dvmThrowExceptionFmt -dvmThrowExceptionFmtV -dvmThrowExceptionWithClassMessage -dvmThrowVerificationError -dvmTrackExternalAllocation -dvmTrackExternalFree -dvmTryLockMutex -dvmU4ToFloat -dvmUnboxObjectArray -dvmUndoDebuggerSuspensions -dvmUnlockCachedDexFile -dvmUnlockHeap -dvmUnlockMutex -dvmUnlockObject -dvmUnlockThreadList -dvmUnwrapPrimitive -dvmUpdateAtomicCache -dvmUseCheckedJniEnv -dvmUseCheckedJniVm -dvmUseJNIBridge -dvmUtf8Len -dvmValidateBoxClasses -dvmValidateObject -dvmVerificationShutdown -dvmVerificationStartup -dvmVerifyAllClasses -dvmVerifyClass -dvmVerifyCodeFlow -dvmVerifyObjectInClass -dvmWaitForHeapWorkerIdle -dvmWaitForSuspend -dvmWrapException -dvmWrapPrimitive _edata -eglBindAPI -eglBindTexImage -eglChooseConfig -eglCopyBuffers -eglCreateContext -eglCreateImageKHR -eglCreatePbufferFromClientBuffer -eglCreatePbufferSurface -eglCreatePixmapSurface -eglCreateWindowSurface -eglDestroyContext -eglDestroyImageKHR -eglDestroySurface -eglGetConfigAttrib -eglGetConfigs -eglGetCurrentContext -eglGetCurrentDisplay -eglGetCurrentSurface -eglGetDisplay -eglGetError -eglGetProcAddress -eglGetRenderBufferANDROID -eglInitialize -eglLockSurfaceKHR -eglMakeCurrent -eglQueryAPI -eglQueryContext -eglQueryString -eglQuerySurface -eglReleaseTexImage -eglReleaseThread -eglSetSwapRectangleANDROID -eglSurfaceAttrib -eglSwapBuffers -eglSwapInterval -eglTerminate -eglUnlockSurfaceKHR -eglWaitClient -eglWaitGL -eglWaitNative +_edata _end +_end +__end__ __end__ _endhtent endpwent endservent endusershell endutent -ensure_config_file_exists environ epoll_create epoll_ctl @@ -1428,18 +263,8 @@ erfc erfcf erff err -ERR_load_SSL_strings __errno errx -etc1_decode_block -etc1_decode_image -etc1_encode_block -etc1_encode_image -etc1_get_encoded_data_size -etc1_pkm_format_header -etc1_pkm_get_height -etc1_pkm_get_width -etc1_pkm_is_valid __evAddTime __evCmpTime __evConsIovec @@ -1457,6 +282,8 @@ execv execve execvp __exidx_end +__exidx_end +__exidx_start __exidx_start exit _exit @@ -1465,21 +292,6 @@ _exit_with_stack_teardown exp exp2 exp2f -expandBufAdd1 -expandBufAdd2BE -expandBufAdd4BE -expandBufAdd8BE -expandBufAddFieldId -expandBufAddFrameId -expandBufAddMethodId -expandBufAddObjectId -expandBufAddRefTypeId -expandBufAddSpace -expandBufAddUtf8String -expandBufAlloc -expandBufFree -expandBufGetBuffer -expandBufGetLength __exp__D expf expm1 @@ -1527,8 +339,6 @@ __fixsfsi __fixunsdfdi __fixunsdfsi __fixunssfdi -__fixunssfsi -float12ToInt __floatdidf __floatdisf __floatsidf @@ -1614,29 +424,16 @@ gamma gammaf gammaf_r gamma_r -gDvm -gDvmInlineOpsTable -gDvmMergeTab __gedf2 __gesf2 -get1 -get2BE -get2LE -get4BE -get4LE -get8BE -get8LE getaddrinfo getc getchar getchar_unlocked -get_cpu_serial_number -get_crc_table getc_unlocked getcwd __getcwd getdents -get_dhcp_error_string getdtablesize getegid getenv @@ -1676,7 +473,6 @@ getpid getppid getpriority __getpriority -get_process_name getprotobyname getprotobynumber getpt @@ -1688,7 +484,6 @@ getresuid getrlimit getrusage gets -get_sched_policy getservbyname getservbyport getservent @@ -1706,256 +501,7 @@ getusershell getutent getwc getwchar -gglBitBlti -gglFloatToFixed -gglFloatToFixedFast -gglGetPixelFormatTable -gglInit -ggl_test_codegen -gglUninit gHashTable -glActiveTexture -glAlphaFunc -glAlphaFuncx -glAlphaFuncxOES -glBindBuffer -glBindFramebufferOES -glBindRenderbufferOES -glBindTexture -glBlendEquationOES -glBlendEquationSeparateOES -glBlendFunc -glBlendFuncSeparateOES -glBufferData -glBufferSubData -glCheckFramebufferStatusOES -glClear -glClearColor -glClearColorx -glClearColorxOES -glClearDepthf -glClearDepthfOES -glClearDepthx -glClearDepthxOES -glClearStencil -glClientActiveTexture -glClipPlanef -glClipPlanefOES -glClipPlanex -glClipPlanexOES -glColor4f -glColor4ub -glColor4x -glColor4xOES -glColorMask -glColorPointer -glColorPointerBounds -glCompressedTexImage2D -glCompressedTexSubImage2D -glCopyTexImage2D -glCopyTexSubImage2D -glCullFace -glCurrentPaletteMatrixOES -glDeleteBuffers -glDeleteFramebuffersOES -glDeleteRenderbuffersOES -glDeleteTextures -glDepthFunc -glDepthMask -glDepthRangef -glDepthRangefOES -glDepthRangex -glDepthRangexOES -glDisable -glDisableClientState -glDrawArrays -glDrawElements -glDrawTexfOES -glDrawTexfvOES -glDrawTexiOES -glDrawTexivOES -glDrawTexsOES -glDrawTexsvOES -glDrawTexxOES -glDrawTexxvOES -glEGLImageTargetRenderbufferStorageOES -glEGLImageTargetTexture2DOES -glEnable -glEnableClientState -glFinish -glFlush -glFogf -glFogfv -glFogx -glFogxOES -glFogxv -glFogxvOES -glFramebufferRenderbufferOES -glFramebufferTexture2DOES -glFrontFace -glFrustumf -glFrustumfOES -glFrustumx -glFrustumxOES -glGenBuffers -glGenerateMipmapOES -glGenFramebuffersOES -glGenRenderbuffersOES -glGenTextures -glGetBooleanv -glGetBufferParameteriv -glGetBufferPointervOES -glGetClipPlanef -glGetClipPlanefOES -glGetClipPlanex -glGetClipPlanexOES -glGetError -glGetFixedv -glGetFixedvOES -glGetFloatv -glGetFramebufferAttachmentParameterivOES -glGetIntegerv -glGetLightfv -glGetLightxv -glGetLightxvOES -glGetMaterialfv -glGetMaterialxv -glGetMaterialxvOES -glGetPointerv -glGetRenderbufferParameterivOES -glGetString -glGetTexEnvfv -glGetTexEnviv -glGetTexEnvxv -glGetTexEnvxvOES -glGetTexGenfvOES -glGetTexGenivOES -glGetTexGenxvOES -glGetTexParameterfv -glGetTexParameteriv -glGetTexParameterxv -glGetTexParameterxvOES -glHint -glIsBuffer -glIsEnabled -glIsFramebufferOES -glIsRenderbufferOES -glIsTexture -glLightf -glLightfv -glLightModelf -glLightModelfv -glLightModelx -glLightModelxOES -glLightModelxv -glLightModelxvOES -glLightx -glLightxOES -glLightxv -glLightxvOES -glLineWidth -glLineWidthx -glLineWidthxOES -glLoadIdentity -glLoadMatrixf -glLoadMatrixx -glLoadMatrixxOES -glLoadPaletteFromModelViewMatrixOES -glLogicOp -glMapBufferOES -glMaterialf -glMaterialfv -glMaterialx -glMaterialxOES -glMaterialxv -glMaterialxvOES -glMatrixIndexPointerOES -glMatrixIndexPointerOESBounds -glMatrixMode -glMultiTexCoord4f -glMultiTexCoord4x -glMultiTexCoord4xOES -glMultMatrixf -glMultMatrixx -glMultMatrixxOES -glNormal3f -glNormal3x -glNormal3xOES -glNormalPointer -glNormalPointerBounds -glOrthof -glOrthofOES -glOrthox -glOrthoxOES -glPixelStorei -glPointParameterf -glPointParameterfv -glPointParameterx -glPointParameterxOES -glPointParameterxv -glPointParameterxvOES -glPointSize -glPointSizePointerOES -glPointSizePointerOESBounds -glPointSizex -glPointSizexOES -glPolygonOffset -glPolygonOffsetx -glPolygonOffsetxOES -glPopMatrix -glPushMatrix -glQueryMatrixxOES -glReadPixels -glRenderbufferStorageOES -glRotatef -glRotatex -glRotatexOES -glSampleCoverage -glSampleCoveragex -glSampleCoveragexOES -glScalef -glScalex -glScalexOES -glScissor -glShadeModel -glStencilFunc -glStencilMask -glStencilOp -glTexCoordPointer -glTexCoordPointerBounds -glTexEnvf -glTexEnvfv -glTexEnvi -glTexEnviv -glTexEnvx -glTexEnvxOES -glTexEnvxv -glTexEnvxvOES -glTexGenfOES -glTexGenfvOES -glTexGeniOES -glTexGenivOES -glTexGenxOES -glTexGenxvOES -glTexImage2D -glTexParameterf -glTexParameterfv -glTexParameteri -glTexParameteriv -glTexParameterx -glTexParameterxOES -glTexParameterxv -glTexParameterxvOES -glTexSubImage2D -glTranslatef -glTranslatex -glTranslatexOES -glUnmapBufferOES -glVertexPointer -glVertexPointerBounds -glViewport -glWeightPointerOES -glWeightPointerOESBounds gMallocLeakZygoteChild gmtime gmtime64 @@ -1981,88 +527,15 @@ __gnu_Unwind_Save_VFP_D __gnu_Unwind_Save_VFP_D_16_to_31 __gnu_Unwind_Save_WMMXC __gnu_Unwind_Save_WMMXD -gps_get_interface -gps_get_qemu_interface __gtdf2 __gtsf2 -g_utcSet -gzclearerr -gzclose -gzdirect -gzdopen -gzeof -gzerror -gzflush -gzgetc -gzgets -gzopen -gzprintf -gzputc -gzputs -gzread -gzrewind -gzseek -gzsetparams -gztell -gzungetc -gzwrite -hashmapContainsKey -hashmapCountCollisions -hashmapCreate -hashmapCurrentCapacity -hashmapForEach -hashmapFree -hashmapGet -hashmapHash -hashmapIntEquals -hashmapIntHash -hashmapLock -hashmapMemoize -hashmapPut -hashmapRemove -hashmapSize -hashmapUnlock h_errlist herror -HIDDEN_create_mspace_HIDDEN -HIDDEN_destroy_mspace_HIDDEN h_nerr __hostalias -hprofAddU1ListToRecord -hprofAddU1ToRecord -hprofAddU2ListToRecord -hprofAddU2ToRecord -hprofAddU4ListToRecord -hprofAddU4ToRecord -hprofAddU8ListToRecord -hprofAddU8ToRecord -hprofAddUtf8StringToRecord -hprofContextInit -hprofDumpClasses -hprofDumpHeap -hprofDumpHeapObject -hprofDumpStrings -hprofFinishHeapDump -hprofFlushCurrentRecord -hprofFlushRecord -hprofFreeContext -hprofLookupClassId -hprofLookupStringId -hprofMarkRootObject -hprofSetGcScanState -hprofShutdown -hprofShutdown_Class -hprofShutdown_String -hprofStartHeapDump -hprofStartNewRecord -hprofStartup -hprofStartup_Class -hprofStartup_String hstrerror -hw_get_module hypot hypotf -i2d_SSL_SESSION __ieee754_rem_pio2 __ieee754_rem_pio2f if_indextoname @@ -2078,23 +551,6 @@ inet_nsap_ntoa inet_ntoa inet_ntop inet_pton -inflate -inflateBack -inflateBackEnd -inflateBackInit_ -inflateCopy -inflate_copyright -inflateEnd -inflate_fast -inflateGetHeader -inflateInit_ -inflateInit2_ -inflatePrime -inflateReset -inflateSetDictionary -inflateSync -inflateSyncPoint -inflate_table initgroups init_module _init_thread @@ -2102,7 +558,6 @@ __init_tls inotify_add_watch inotify_init inotify_rm_watch -intToFloat12 ioctl __ioctl ioprio_get @@ -2147,18 +602,13 @@ iswspace iswupper iswxdigit isxdigit -iterators0032 j0 j0f j1 j1f jn jnf -JNI_CreateJavaVM -JNI_GetCreatedJavaVMs -JNI_GetDefaultJavaVMInitArgs jrand48 -kEntryHeaderLen __kernel_cos __kernel_cosdf __kernel_rem_pio2 @@ -2169,15 +619,13 @@ __kernel_tandf kill killpg klogctl -kMessageHeaderLen -kStackFrameLen lchown ldexp +ldexp ldexpf ldexpl ldiv __ledf2 -_length_code __lesf2 lgamma lgammaf @@ -2202,12 +650,10 @@ llroundf llroundl __llseek load_domain_search_list -load_file localtime localtime64 localtime64_r localtime_r -localtime_tz __loc_aton __loc_ntoa log @@ -2219,7 +665,6 @@ logb logbf __log__D logf -logprint_run_tests longjmp _longjmp longjmperror @@ -2231,7 +676,6 @@ lroundf lroundl lseek lseek64 -__lshrdi3 lstat __ltdf2 __ltsf2 @@ -2239,7 +683,6 @@ madvise mallinfo malloc malloc_debug_init -masterPeerInitialize mbrlen mbrtowc mbsinit @@ -2270,7 +713,6 @@ mktemp _mktemp mktime mktime64 -mktime_tz mlock mmap __mmap2 @@ -2280,24 +722,6 @@ mount mprotect mrand48 mremap -mspace_calloc -mspace_footprint -mspace_free -mspace_independent_calloc -mspace_independent_comalloc -mspace_malloc -mspace_malloc_stats -mspace_mallopt -mspace_max_allowed_footprint -mspace_max_footprint -mspace_memalign -mspace_merge_objects -mspace_realloc -mspace_set_max_allowed_footprint -mspace_trim -mspace_usable_size -mspace_walk_free_pages -mspace_walk_heap msync __muldf3 __muldi3 @@ -2305,14 +729,10 @@ __mulsf3 munlock munmap nanosleep -native_handle_close -native_handle_create -native_handle_delete nearbyint nearbyintf __nedf2 __nesf2 -NEW_PATHS nextafter nextafterf nexttowardf @@ -2343,7 +763,6 @@ __ns_samename __ns_skiprr __ns_sprintrr __ns_sprintrrf -OLD_PATHS open __open openat @@ -2351,7 +770,6 @@ __openat opendir openlog openlog_r -open_memstream optarg opterr optind @@ -2368,10 +786,6 @@ __p_class __p_class_syms pclose __p_default_section_syms -peerInitialize -peerLoop -peerSendBytes -peerSendSharedBytes perror __p_fqname __p_fqnname @@ -2389,12 +803,7 @@ prctl pread __pread64 printf -printHexData -printTypeCode __progname -property_get -property_list -property_set __p_secstodate __p_section pselect @@ -2487,16 +896,6 @@ putwc putwchar pwrite __pwrite64 -qemu_add_mapping -qemu_channel_open -qemu_check -qemu_command_format -qemu_control_command -qemu_control_query -qemu_remove_mapping -qemu_set_screen_state -qemu_start_tracing -qemu_stop_tracing qsort raise __rand48_add @@ -2506,28 +905,14 @@ _rand48_mult __rand48_seed _rand48_seed read -read1 -read2BE -read2LE -read4BE -read4LE -read8BE -read8LE -readAndVerifySignedLeb128 -readAndVerifyUnsignedLeb128 readdir readdir_r readlink -readNewUtf8String -readUtf8String readv realloc realpath reboot __reboot -record_stream_free -record_stream_get_next -record_stream_new recv recvfrom recvmsg @@ -2535,7 +920,6 @@ regcomp regerror regexec regfree -release_wake_lock remainder remainderf remove @@ -2597,7 +981,6 @@ rewinddir rint rintf rmdir -rotate90CW_4x4_16v6 round roundf roundl @@ -2615,7 +998,6 @@ scalbnf scalbnl scandir scanf -scanline_t32cb16blend_arm sched_getparam sched_get_priority_max sched_get_priority_min @@ -2628,10 +1010,6 @@ __sclose __sdidinit seed48 select -selectorAdd -selectorCreate -selectorLoop -selectorWakeUp sem_close sem_destroy sem_getvalue @@ -2646,15 +1024,9 @@ send sendfile sendmsg sendto -set1 -set2BE -set2LE -set4BE -set4LE -set8BE -set8LE setbuf setbuffer +set_dump_signal setegid setenv __set_errno @@ -2665,7 +1037,6 @@ _sethtent setitimer setjmp _setjmp -set_last_user_activity_timeout setlinebuf setlocale setlogmask @@ -2673,7 +1044,6 @@ setlogmask_r setpgid setpgrp setpriority -set_process_name setregid setresgid setresuid @@ -2681,10 +1051,9 @@ __setresuid setreuid __setreuid setrlimit -set_sched_policy -set_screen_state setservent setsid +set_signal setsockopt __set_syscall_errno settimeofday @@ -2693,7 +1062,6 @@ setuid __setuid setusershell setutent -setUtf8String setvbuf __sF __sFext @@ -2730,21 +1098,11 @@ sinf sinh sinhf __sinit -skipUtf8String __slbexpand sleep __smakebuf snprintf socket -socket_inaddr_any_server -socket_local_client -socket_local_client_connect -socket_local_server -socket_local_server_bind -socket_loopback_client -socket_loopback_server -socket_make_sockaddr_un -socket_network_client socketpair sprintf sqrt @@ -2755,383 +1113,7 @@ __srefill __srget sscanf __sseek -ssl23_accept -ssl23_connect -ssl23_default_timeout -ssl23_get_cipher -ssl23_get_cipher_by_char -ssl23_get_client_hello -ssl23_num_ciphers -ssl23_peek -ssl23_put_cipher_by_char -ssl23_read -ssl23_read_bytes -ssl23_write -ssl23_write_bytes -ssl2_accept -ssl2_callback_ctrl -ssl2_ciphers -ssl2_clear -ssl2_connect -ssl2_ctrl -ssl2_ctx_callback_ctrl -ssl2_ctx_ctrl -ssl2_default_timeout -ssl2_do_write -ssl2_enc -ssl2_enc_init -ssl2_free -ssl2_generate_key_material -ssl2_get_cipher -ssl2_get_cipher_by_char -ssl2_mac -ssl2_new -ssl2_num_ciphers -ssl2_part_read -ssl2_peek -ssl2_pending -ssl2_put_cipher_by_char -ssl2_read -ssl2_return_error -ssl2_set_certificate -ssl2_shutdown -ssl2_version_str -ssl2_write -ssl2_write_error -ssl3_accept -ssl3_alert_code -ssl3_callback_ctrl -ssl3_cert_verify_mac -ssl3_change_cipher_state -ssl3_check_cert_and_algorithm -ssl3_check_client_hello -ssl3_check_finished -ssl3_choose_cipher -ssl3_ciphers -ssl3_cleanup_key_block -ssl3_clear -ssl3_client_hello -ssl3_comp_find -ssl3_connect -ssl3_ctrl -ssl3_ctx_callback_ctrl -ssl3_ctx_ctrl -ssl3_default_timeout -ssl3_dispatch_alert -ssl3_do_change_cipher_spec -ssl3_do_compress -ssl3_do_uncompress -ssl3_do_write -ssl3_enc -ssl3_final_finish_mac -ssl3_finish_mac -ssl3_free -ssl3_generate_master_secret -ssl3_get_certificate_request -ssl3_get_cert_status -ssl3_get_cert_verify -ssl3_get_cipher -ssl3_get_cipher_by_char -ssl3_get_client_certificate -ssl3_get_client_hello -ssl3_get_client_key_exchange -ssl3_get_finished -ssl3_get_key_exchange -ssl3_get_message -ssl3_get_new_session_ticket -ssl3_get_req_cert_type -ssl3_get_server_certificate -ssl3_get_server_done -ssl3_get_server_hello -ssl3_init_finished_mac -ssl3_mac -ssl3_new -ssl3_num_ciphers -ssl3_output_cert_chain -ssl3_peek -ssl3_pending -ssl3_put_cipher_by_char -ssl3_read -ssl3_read_bytes -ssl3_read_n -ssl3_record_sequence_update -ssl3_renegotiate -ssl3_renegotiate_check -ssl3_send_alert -ssl3_send_certificate_request -ssl3_send_cert_status -ssl3_send_change_cipher_spec -ssl3_send_client_certificate -ssl3_send_client_key_exchange -ssl3_send_client_verify -ssl3_send_finished -ssl3_send_hello_request -ssl3_send_newsession_ticket -ssl3_send_server_certificate -ssl3_send_server_done -ssl3_send_server_hello -ssl3_send_server_key_exchange -ssl3_setup_buffers -ssl3_setup_key_block -ssl3_shutdown -ssl3_undef_enc_method -ssl3_version_str -ssl3_write -ssl3_write_bytes -ssl3_write_pending -SSL_accept -SSL_add_client_CA -ssl_add_clienthello_renegotiate_ext -ssl_add_clienthello_tlsext -SSL_add_dir_cert_subjects_to_stack -SSL_add_file_cert_subjects_to_stack -ssl_add_serverhello_renegotiate_ext -ssl_add_serverhello_tlsext -SSL_alert_desc_string -SSL_alert_desc_string_long -SSL_alert_type_string -SSL_alert_type_string_long -ssl_bad_method -ssl_bytes_to_cipher_list -SSL_callback_ctrl -ssl_cert_dup -ssl_cert_free -ssl_cert_inst -ssl_cert_new -ssl_cert_type -ssl_check_clienthello_tlsext -SSL_check_private_key -ssl_check_serverhello_tlsext -SSL_CIPHER_description -SSL_CIPHER_get_bits -ssl_cipher_get_evp -SSL_CIPHER_get_name -SSL_CIPHER_get_version -ssl_cipher_id_cmp -ssl_cipher_list_to_bytes -ssl_cipher_ptr_id_cmp -SSL_clear -ssl_clear_bad_session -ssl_clear_cipher_ctx -SSL_COMP_add_compression_method -SSL_COMP_get_compression_methods -SSL_COMP_get_name -SSL_connect -SSL_copy_session_id -ssl_create_cipher_list -SSL_ctrl -SSL_CTX_add_client_CA -SSL_CTX_add_session -SSL_CTX_callback_ctrl -SSL_CTX_check_private_key -SSL_CTX_ctrl -SSL_CTX_flush_sessions -SSL_CTX_free -SSL_CTX_get_cert_store -SSL_CTX_get_client_CA_list -SSL_CTX_get_client_cert_cb -SSL_CTX_get_ex_data -SSL_CTX_get_ex_new_index -SSL_CTX_get_info_callback -SSL_CTX_get_quiet_shutdown -SSL_CTX_get_timeout -SSL_CTX_get_verify_callback -SSL_CTX_get_verify_depth -SSL_CTX_get_verify_mode -SSL_CTX_load_verify_locations -SSL_CTX_new -SSL_CTX_remove_session -SSL_CTX_sess_get_get_cb -SSL_CTX_sess_get_new_cb -SSL_CTX_sess_get_remove_cb -SSL_CTX_sessions -SSL_CTX_sess_set_get_cb -SSL_CTX_sess_set_new_cb -SSL_CTX_sess_set_remove_cb -SSL_CTX_set_cert_store -SSL_CTX_set_cert_verify_callback -SSL_CTX_set_cipher_list -SSL_CTX_set_client_CA_list -SSL_CTX_set_client_cert_cb -SSL_CTX_set_client_cert_engine -SSL_CTX_set_cookie_generate_cb -SSL_CTX_set_cookie_verify_cb -SSL_CTX_set_default_passwd_cb -SSL_CTX_set_default_passwd_cb_userdata -SSL_CTX_set_default_verify_paths -SSL_CTX_set_ex_data -SSL_CTX_set_generate_session_id -SSL_CTX_set_info_callback -SSL_CTX_set_msg_callback -SSL_CTX_set_purpose -SSL_CTX_set_quiet_shutdown -SSL_CTX_set_session_id_context -SSL_CTX_set_ssl_version -SSL_CTX_set_timeout -SSL_CTX_set_tmp_dh_callback -SSL_CTX_set_tmp_rsa_callback -SSL_CTX_set_trust -SSL_CTX_set_verify -SSL_CTX_set_verify_depth -SSL_CTX_use_certificate -SSL_CTX_use_certificate_ASN1 -SSL_CTX_use_certificate_chain_file -SSL_CTX_use_certificate_file -SSL_CTX_use_PrivateKey -SSL_CTX_use_PrivateKey_ASN1 -SSL_CTX_use_PrivateKey_file -SSL_CTX_use_RSAPrivateKey -SSL_CTX_use_RSAPrivateKey_ASN1 -SSL_CTX_use_RSAPrivateKey_file -SSL_cutthrough_complete -ssl_do_client_cert_cb -SSL_do_handshake -SSL_dup -SSL_dup_CA_list -SSL_free -ssl_free_wbio_buffer -SSL_get1_session -SSL_get_certificate -SSL_get_cipher_list -SSL_get_ciphers -ssl_get_ciphers_by_id -SSL_get_client_CA_list -SSL_get_current_cipher -SSL_get_current_compression -SSL_get_current_expansion -SSL_get_default_timeout -SSL_get_error -SSL_get_ex_data -SSL_get_ex_data_X509_STORE_CTX_idx -SSL_get_ex_new_index -SSL_get_fd -SSL_get_finished -SSL_get_info_callback -ssl_get_new_session -SSL_get_peer_cert_chain -SSL_get_peer_certificate -SSL_get_peer_finished -ssl_get_prev_session -SSL_get_privatekey -SSL_get_quiet_shutdown -SSL_get_rbio -SSL_get_read_ahead -SSL_get_rfd -SSL_get_servername -SSL_get_servername_type -ssl_get_server_send_cert -SSL_get_session -SSL_get_shared_ciphers -SSL_get_shutdown -ssl_get_sign_pkey -SSL_get_SSL_CTX -SSL_get_ssl_method -SSL_get_verify_callback -SSL_get_verify_depth -SSL_get_verify_mode -SSL_get_verify_result -SSL_get_version -SSL_get_wbio -SSL_get_wfd -SSL_has_matching_session_id -ssl_init_wbio_buffer -SSL_library_init -ssl_load_ciphers -SSL_load_client_CA_file -SSL_load_error_strings -SSL_new -ssl_ok -ssl_parse_clienthello_renegotiate_ext -ssl_parse_clienthello_tlsext -ssl_parse_serverhello_renegotiate_ext -ssl_parse_serverhello_tlsext -SSL_peek -SSL_pending -SSL_read -SSL_renegotiate -SSL_renegotiate_pending -SSL_rstate_string -SSL_rstate_string_long -ssl_sess_cert_free -ssl_sess_cert_new -SSL_SESSION_cmp -SSL_SESSION_free -SSL_SESSION_get_ex_data -SSL_SESSION_get_ex_new_index -SSL_SESSION_get_id -SSL_SESSION_get_time -SSL_SESSION_get_timeout -SSL_SESSION_hash -SSL_SESSION_new -SSL_SESSION_print -SSL_SESSION_print_fp -SSL_SESSION_set_ex_data -SSL_SESSION_set_time -SSL_SESSION_set_timeout -SSL_set_accept_state -SSL_set_bio -ssl_set_cert_masks -SSL_set_cipher_list -SSL_set_client_CA_list -SSL_set_connect_state -SSL_set_ex_data -SSL_set_fd -SSL_set_generate_session_id -SSL_set_info_callback -SSL_set_msg_callback -ssl_set_peer_cert_type -SSL_set_purpose -SSL_set_quiet_shutdown -SSL_set_read_ahead -SSL_set_rfd -SSL_set_session -SSL_set_session_id_context -SSL_set_shutdown -SSL_set_SSL_CTX -SSL_set_ssl_method -SSL_set_tmp_dh_callback -SSL_set_tmp_rsa_callback -SSL_set_trust -SSL_set_verify -SSL_set_verify_depth -SSL_set_verify_result -SSL_set_wfd -SSL_shutdown -SSL_state -SSL_state_string -SSL_state_string_long -ssl_undefined_const_function -ssl_undefined_function -ssl_undefined_void_function -ssl_update_cache -SSL_use_certificate -SSL_use_certificate_ASN1 -SSL_use_certificate_file -SSL_use_PrivateKey -SSL_use_PrivateKey_ASN1 -SSL_use_PrivateKey_file -SSL_use_RSAPrivateKey -SSL_use_RSAPrivateKey_ASN1 -SSL_use_RSAPrivateKey_file -sslv23_base_method -SSLv23_client_method -SSLv23_method -SSLv23_server_method -sslv2_base_method -SSLv2_client_method -SSLv2_method -SSLv2_server_method -sslv3_base_method -SSLv3_client_method -SSLv3_enc_data -SSLv3_method -SSLv3_server_method -ssl_verify_alarm_type -ssl_verify_cert_chain -SSL_version -SSL_version_str -SSL_want -SSL_write +_stack _stack __stack_chk_fail __stack_chk_guard @@ -3143,39 +1125,23 @@ strcasestr strcat strchr strcmp -strcmp16 strcoll strcpy -strcpy16 -strcpy8to16 -strcpylen8to16 strcspn strdup -strdup8to16 strerror strerror_r strftime strftime_tz -stringForIndent strlcat strlcpy strlen -strlen16 -strlen32 -strlen8to16 strncasecmp strncat strncmp -strncmp16 strncpy -strncpy16 -strncpy16to8 strndup -strndup16to8 strnlen -strnlen16 -strnlen16to8 -strnlen32 strntoimax strntoumax strpbrk @@ -3196,8 +1162,6 @@ strtoul strtoull strtoumax strxfrm -strzcmp16 -strzcmp16_h_n __subdf3 __subsf3 __swbuf @@ -3212,19 +1176,11 @@ __sym_ntos __sym_ston sync syscall -sysChangeMapAccess __sys_clone sysconf -sysCopyMap -sysCreatePrivateMap -sysLoadFileInShmem syslog __syslog syslog_r -sysMapFileInShmemReadOnly -sysMapFileInShmemWritableReadOnly -sysMapFileSegmentInShmem -sysReleaseShmem sys_siglist sys_signame system @@ -3235,7 +1191,6 @@ __system_property_find_nth __system_property_get __system_property_read __system_property_wait -systemTime sysv_signal tan tanf @@ -3251,8 +1206,6 @@ _thread_atexit_lock _thread_atexit_unlock _thread_created_hook __thread_entry -thread_store_get -thread_store_set time timegm64 timelocal64 @@ -3270,25 +1223,6 @@ __timer_table_start_stop times timezone tkill -tls1_alert_code -tls1_cert_verify_mac -tls1_change_cipher_state -tls1_clear -tls1_default_timeout -tls1_enc -tls1_final_finish_mac -tls1_free -tls1_generate_master_secret -tls1_mac -tls1_new -tls1_process_ticket -tls1_setup_key_block -tls1_version_str -tlsv1_base_method -TLSv1_client_method -TLSv1_enc_data -TLSv1_method -TLSv1_server_method tmpfile tmpnam toascii @@ -3298,11 +1232,6 @@ toupper _toupper_tab_ towlower towupper -_tr_align -_tr_flush_block -_tr_init -_tr_stored_block -_tr_tally trunc truncate __truncdfsf2 @@ -3314,13 +1243,10 @@ tzname tzset __udivdi3 __udivsi3 -uevent_init -uevent_next_event umask umount umount2 uname -uncompress ungetc ungetwc unlink @@ -3350,15 +1276,6 @@ _Unwind_VRS_Get _Unwind_VRS_Pop _Unwind_VRS_Set usleep -utf16_to_utf8 -utf32_at -utf32_length -utf32_to_utf8 -utf8_length -utf8_length_from_utf16 -utf8_length_from_utf32 -utf8_to_utf16 -utf8_to_utf32 utime utimes utmpname @@ -3373,8 +1290,6 @@ vfork vfprintf vfscanf vfwprintf -vibrator_off -vibrator_on vprintf vscanf vsnprintf @@ -3421,15 +1336,6 @@ wcsxfrm wctob wctype wcwidth -wifi_close_supplicant_connection -wifi_command -wifi_connect_to_supplicant -wifi_load_driver -wifi_send_command -wifi_start_supplicant -wifi_stop_supplicant -wifi_unload_driver -wifi_wait_for_event wmemchr wmemcmp wmemcpy @@ -3445,2186 +1351,3 @@ y1 y1f yn ynf -_Z10gglMulDiviiii -_Z11gglFastDivxii -_Z13gglSqrtRecipxi -_Z19gglRecipQNormalizediPi -_Z24androidCreateThreadGetIDPFiPvES_PS_ -_Z7gglDivQiii -_Z7gglPowxii -_Z8gglSqrtxi -_Z9gglRecipQii -zcalloc -zcfree -_ZdaPv -_ZdaPvRKSt9nothrow_t -_ZdlPv -_ZdlPvRKSt9nothrow_t -z_errmsg -zError -_ZGVN7android9SingletonINS_19GraphicBufferMapperEE5sLockE -_ZGVN7android9SingletonINS_22GraphicBufferAllocatorEE5sLockE -ZipFileCRO_destroy -ZipFileCRO_findEntryByName -ZipFileCRO_getEntryInfo -ZipFileCRO_uncompressEntry -ZipFileXRO_open -zlibCompileFlags -zlibVersion -_ZN15KeyCharacterMap10getKeyDataEiPtS0_S0_ -_ZN15KeyCharacterMap15getDisplayLabelEi -_ZN15KeyCharacterMap3getEii -_ZN15KeyCharacterMap4loadEi -_ZN15KeyCharacterMap8find_keyEi -_ZN15KeyCharacterMap8getMatchEiPKtij -_ZN15KeyCharacterMap8try_fileEPKc -_ZN15KeyCharacterMap9find_charEtPjS0_ -_ZN15KeyCharacterMap9getEventsEPtjPN7android6VectorIiEEPNS2_IjEE -_ZN15KeyCharacterMap9getNumberEi -_ZN15KeyCharacterMapC1Ev -_ZN15KeyCharacterMapC2Ev -_ZN15KeyCharacterMapD1Ev -_ZN15KeyCharacterMapD2Ev -_ZN7android10AllocationC1ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEElj -_ZN7android10AllocationC2ERKNS_2spINS_12MemoryDealerEEERKNS1_INS_11IMemoryHeapEEElj -_ZN7android10AllocationD0Ev -_ZN7android10AllocationD1Ev -_ZN7android10AllocationD2Ev -_ZN7android10concatArgvEiPKPKc -_ZN7android10_FileAsset15ensureAlignmentEPNS_7FileMapE -_ZN7android10_FileAsset4readEPvj -_ZN7android10_FileAsset4seekEli -_ZN7android10_FileAsset5closeEv -_ZN7android10_FileAsset9getBufferEb -_ZN7android10_FileAsset9openChunkEPKcilj -_ZN7android10_FileAsset9openChunkEPNS_7FileMapE -_ZN7android10_FileAssetC1Ev -_ZN7android10_FileAssetC2Ev -_ZN7android10_FileAssetD0Ev -_ZN7android10_FileAssetD1Ev -_ZN7android10_FileAssetD2Ev -_ZN7android10ggl_expandEjii -_ZN7android10IInterface8asBinderEv -_ZN7android10IInterfaceC1Ev -_ZN7android10IInterfaceC2Ev -_ZN7android10IInterfaceD0Ev -_ZN7android10IInterfaceD1Ev -_ZN7android10IInterfaceD2Ev -_ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEElj -_ZN7android10MemoryBaseC2ERKNS_2spINS_11IMemoryHeapEEElj -_ZN7android10MemoryBaseD0Ev -_ZN7android10MemoryBaseD1Ev -_ZN7android10MemoryBaseD2Ev -_ZN7android10OverlayRef13writeToParcelEPNS_6ParcelERKNS_2spIS0_EE -_ZN7android10OverlayRef14readFromParcelERKNS_6ParcelE -_ZN7android10OverlayRefC1EPK15native_handle_tRKNS_2spINS_8IOverlayEEEjjijj -_ZN7android10OverlayRefC1Ev -_ZN7android10OverlayRefC2EPK15native_handle_tRKNS_2spINS_8IOverlayEEEjjijj -_ZN7android10OverlayRefC2Ev -_ZN7android10OverlayRefD0Ev -_ZN7android10OverlayRefD1Ev -_ZN7android10OverlayRefD2Ev -_ZN7android10PermissionC1EPKc -_ZN7android10PermissionC1ERKNS_8String16E -_ZN7android10PermissionC1ERKS0_ -_ZN7android10PermissionC2EPKc -_ZN7android10PermissionC2ERKNS_8String16E -_ZN7android10PermissionC2ERKS0_ -_ZN7android10PermissionD0Ev -_ZN7android10PermissionD1Ev -_ZN7android10PermissionD2Ev -_ZN7android10ResXMLTree5setToEPKvjb -_ZN7android10ResXMLTree6uninitEv -_ZN7android10ResXMLTreeC1EPKvjb -_ZN7android10ResXMLTreeC1Ev -_ZN7android10ResXMLTreeC2EPKvjb -_ZN7android10ResXMLTreeC2Ev -_ZN7android10ResXMLTreeD1Ev -_ZN7android10ResXMLTreeD2Ev -_ZN7android10TextOutputC1Ev -_ZN7android10TextOutputC2Ev -_ZN7android10TextOutputD0Ev -_ZN7android10TextOutputD1Ev -_ZN7android10TextOutputD2Ev -_ZN7android10VectorImpl11setCapacityEj -_ZN7android10VectorImpl12appendVectorERKS0_ -_ZN7android10VectorImpl13editArrayImplEv -_ZN7android10VectorImpl13finish_vectorEv -_ZN7android10VectorImpl13removeItemsAtEjj -_ZN7android10VectorImpl14insertVectorAtERKS0_j -_ZN7android10VectorImpl15release_storageEv -_ZN7android10VectorImpl16editItemLocationEj -_ZN7android10VectorImpl19reservedVectorImpl1Ev -_ZN7android10VectorImpl19reservedVectorImpl2Ev -_ZN7android10VectorImpl19reservedVectorImpl3Ev -_ZN7android10VectorImpl19reservedVectorImpl4Ev -_ZN7android10VectorImpl19reservedVectorImpl5Ev -_ZN7android10VectorImpl19reservedVectorImpl6Ev -_ZN7android10VectorImpl19reservedVectorImpl7Ev -_ZN7android10VectorImpl19reservedVectorImpl8Ev -_ZN7android10VectorImpl3addEPKv -_ZN7android10VectorImpl3addEv -_ZN7android10VectorImpl3popEv -_ZN7android10VectorImpl4pushEPKv -_ZN7android10VectorImpl4pushEv -_ZN7android10VectorImpl4sortEPFiPKvS2_E -_ZN7android10VectorImpl4sortEPFiPKvS2_PvES3_ -_ZN7android10VectorImpl5clearEv -_ZN7android10VectorImpl5_growEjj -_ZN7android10VectorImpl7_shrinkEjj -_ZN7android10VectorImpl8insertAtEjj -_ZN7android10VectorImpl8insertAtEPKvjj -_ZN7android10VectorImpl9replaceAtEj -_ZN7android10VectorImpl9replaceAtEPKvj -_ZN7android10VectorImplaSERKS0_ -_ZN7android10VectorImplC1Ejj -_ZN7android10VectorImplC1ERKS0_ -_ZN7android10VectorImplC2Ejj -_ZN7android10VectorImplC2ERKS0_ -_ZN7android10VectorImplD0Ev -_ZN7android10VectorImplD1Ev -_ZN7android10VectorImplD2Ev -_ZN7android11BnInterfaceINS_11IMemoryHeapEE10onAsBinderEv -_ZN7android11BnInterfaceINS_15IServiceManagerEE10onAsBinderEv -_ZN7android11BnInterfaceINS_21IPermissionControllerEE10onAsBinderEv -_ZN7android11BnInterfaceINS_7IMemoryEE10onAsBinderEv -_ZN7android11BnInterfaceINS_8IOverlayEE10onAsBinderEv -_ZN7android11FlattenableD0Ev -_ZN7android11FlattenableD1Ev -_ZN7android11FlattenableD2Ev -_ZN7android11getFileTypeEPKc -_ZN7android11ggl_pick_cbEPNS_9context_tE -_ZN7android11IMemoryHeap10descriptorE -_ZN7android11IMemoryHeap11asInterfaceERKNS_2spINS_7IBinderEEE -_ZN7android11IMemoryHeapC1Ev -_ZN7android11IMemoryHeapC2Ev -_ZN7android11IMemoryHeapD0Ev -_ZN7android11IMemoryHeapD1Ev -_ZN7android11IMemoryHeapD2Ev -_ZN7android11StringArray17cmpAscendingAlphaEPKvS2_ -_ZN7android11StringArray4sortEPFiPKvS2_E -_ZN7android11StringArray5eraseEi -_ZN7android11StringArray8setEntryEiPKc -_ZN7android11StringArray9push_backEPKc -_ZN7android11StringArrayC1Ev -_ZN7android11StringArrayC2Ev -_ZN7android11StringArrayD0Ev -_ZN7android11StringArrayD1Ev -_ZN7android11StringArrayD2Ev -_ZN7android12ARMAssembler10pcForLabelEPKc -_ZN7android12ARMAssembler11disassembleEPKc -_ZN7android12ARMAssembler14dataProcessingEiiiiij -_ZN7android12ARMAssembler1BEiPj -_ZN7android12ARMAssembler1BEiPKc -_ZN7android12ARMAssembler2BLEiPj -_ZN7android12ARMAssembler2BLEiPKc -_ZN7android12ARMAssembler2BXEii -_ZN7android12ARMAssembler3CLZEiii -_ZN7android12ARMAssembler3LDMEiiiij -_ZN7android12ARMAssembler3LDREiiij -_ZN7android12ARMAssembler3MLAEiiiiii -_ZN7android12ARMAssembler3MULEiiiii -_ZN7android12ARMAssembler3PLDEij -_ZN7android12ARMAssembler3STMEiiiij -_ZN7android12ARMAssembler3STREiiij -_ZN7android12ARMAssembler3SWIEij -_ZN7android12ARMAssembler3SWPEiiii -_ZN7android12ARMAssembler4LDRBEiiij -_ZN7android12ARMAssembler4LDRHEiiij -_ZN7android12ARMAssembler4QADDEiiii -_ZN7android12ARMAssembler4QSUBEiiii -_ZN7android12ARMAssembler4SMLAEiiiiii -_ZN7android12ARMAssembler4SMULEiiiii -_ZN7android12ARMAssembler4STRBEiiij -_ZN7android12ARMAssembler4STRHEiiij -_ZN7android12ARMAssembler4SWPBEiiii -_ZN7android12ARMAssembler5labelEPKc -_ZN7android12ARMAssembler5LDRSBEiiij -_ZN7android12ARMAssembler5LDRSHEiiij -_ZN7android12ARMAssembler5QDADDEiiii -_ZN7android12ARMAssembler5QDSUBEiiii -_ZN7android12ARMAssembler5resetEv -_ZN7android12ARMAssembler5SMLALEiiiiii -_ZN7android12ARMAssembler5SMLAWEiiiiii -_ZN7android12ARMAssembler5SMUALEiiiiii -_ZN7android12ARMAssembler5SMULLEiiiiii -_ZN7android12ARMAssembler5SMULWEiiiii -_ZN7android12ARMAssembler5UMUALEiiiiii -_ZN7android12ARMAssembler5UMULLEiiiiii -_ZN7android12ARMAssembler6epilogEj -_ZN7android12ARMAssembler6prologEv -_ZN7android12ARMAssembler7commentEPKc -_ZN7android12ARMAssembler8generateEPKc -_ZN7android12ARMAssemblerC1ERKNS_2spINS_8AssemblyEEE -_ZN7android12ARMAssemblerC2ERKNS_2spINS_8AssemblyEEE -_ZN7android12ARMAssemblerD0Ev -_ZN7android12ARMAssemblerD1Ev -_ZN7android12ARMAssemblerD2Ev -_ZN7android12AssetManager10isUpToDateEv -_ZN7android12AssetManager11getFileTypeEPKc -_ZN7android12AssetManager12addAssetPathERKNS_7String8EPPv -_ZN7android12AssetManager12openNonAssetEPKcNS_5Asset10AccessModeE -_ZN7android12AssetManager12openNonAssetEPvPKcNS_5Asset10AccessModeE -_ZN7android12AssetManager13fncScanLockedEPNS_12SortedVectorINS_8AssetDir8FileInfoEEEPKc -_ZN7android12AssetManager13scanDirLockedERKNS_7String8E -_ZN7android12AssetManager14getGlobalCountEv -_ZN7android12AssetManager15mergeInfoLockedEPNS_12SortedVectorINS_8AssetDir8FileInfoEEEPKS4_ -_ZN7android12AssetManager15openNonAssetDirEPvPKc -_ZN7android12AssetManager15setLocaleLockedEPKc -_ZN7android12AssetManager16addDefaultAssetsEv -_ZN7android12AssetManager16getZipFileLockedERKNS0_10asset_pathE -_ZN7android12AssetManager16openInPathLockedEPKcNS_5Asset10AccessModeERKNS0_10asset_pathE -_ZN7android12AssetManager16setConfigurationERKNS_15ResTable_configEPKc -_ZN7android12AssetManager20createPathNameLockedERKNS0_10asset_pathEPKc -_ZN7android12AssetManager20createPathNameLockedERKNS0_10asset_pathEPKcS5_ -_ZN7android12AssetManager21scanAndMergeDirLockedEPNS_12SortedVectorINS_8AssetDir8FileInfoEEERKNS0_10asset_pathEPKcSA_ -_ZN7android12AssetManager21scanAndMergeZipLockedEPNS_12SortedVectorINS_8AssetDir8FileInfoEEERKNS0_10asset_pathEPKcSA_ -_ZN7android12AssetManager22openAssetFromZipLockedEPKNS_9ZipFileROEPvNS_5Asset10AccessModeERKNS_7String8E -_ZN7android12AssetManager23loadFileNameCacheLockedEv -_ZN7android12AssetManager23openAssetFromFileLockedERKNS_7String8ENS_5Asset10AccessModeE -_ZN7android12AssetManager24fncScanAndMergeDirLockedEPNS_12SortedVectorINS_8AssetDir8FileInfoEEERKNS0_10asset_pathEPKcSA_SA_ -_ZN7android12AssetManager24openInLocaleVendorLockedEPKcNS_5Asset10AccessModeERKNS0_10asset_pathES2_S2_ -_ZN7android12AssetManager24openNonAssetInPathLockedEPKcNS_5Asset10AccessModeERKNS0_10asset_pathE -_ZN7android12AssetManager24purgeFileNameCacheLockedEv -_ZN7android12AssetManager25createZipSourceNameLockedERKNS_7String8ES3_S3_ -_ZN7android12AssetManager4openEPKcNS_5Asset10AccessModeE -_ZN7android12AssetManager6ZipSet10isUpToDateEv -_ZN7android12AssetManager6ZipSet11getPathNameEPKc -_ZN7android12AssetManager6ZipSet19getZipResourceTableERKNS_7String8E -_ZN7android12AssetManager6ZipSet19setZipResourceTableERKNS_7String8EPNS_8ResTableE -_ZN7android12AssetManager6ZipSet24getZipResourceTableAssetERKNS_7String8E -_ZN7android12AssetManager6ZipSet24setZipResourceTableAssetERKNS_7String8EPNS_5AssetE -_ZN7android12AssetManager6ZipSet6getZipERKNS_7String8E -_ZN7android12AssetManager6ZipSet8closeZipEi -_ZN7android12AssetManager6ZipSetC1Ev -_ZN7android12AssetManager6ZipSetC2Ev -_ZN7android12AssetManager6ZipSetD1Ev -_ZN7android12AssetManager6ZipSetD2Ev -_ZN7android12AssetManager7openDirEPKc -_ZN7android12AssetManager9setLocaleEPKc -_ZN7android12AssetManager9setVendorEPKc -_ZN7android12AssetManager9SharedZip10isUpToDateEv -_ZN7android12AssetManager9SharedZip16getResourceTableEv -_ZN7android12AssetManager9SharedZip16setResourceTableEPNS_8ResTableE -_ZN7android12AssetManager9SharedZip21getResourceTableAssetEv -_ZN7android12AssetManager9SharedZip21setResourceTableAssetEPNS_5AssetE -_ZN7android12AssetManager9SharedZip3getERKNS_7String8E -_ZN7android12AssetManager9SharedZip5gLockE -_ZN7android12AssetManager9SharedZip5gOpenE -_ZN7android12AssetManager9SharedZip6getZipEv -_ZN7android12AssetManager9SharedZipC1ERKNS_7String8El -_ZN7android12AssetManager9SharedZipC2ERKNS_7String8El -_ZN7android12AssetManager9SharedZipD0Ev -_ZN7android12AssetManager9SharedZipD1Ev -_ZN7android12AssetManager9SharedZipD2Ev -_ZN7android12AssetManagerC1ENS0_9CacheModeE -_ZN7android12AssetManagerC2ENS0_9CacheModeE -_ZN7android12AssetManagerD0Ev -_ZN7android12AssetManagerD1Ev -_ZN7android12AssetManagerD2Ev -_ZN7android12bitsPerPixelEi -_ZN7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j -_ZN7android12BnMemoryHeapC1Ev -_ZN7android12BnMemoryHeapC2Ev -_ZN7android12BnMemoryHeapD0Ev -_ZN7android12BnMemoryHeapD1Ev -_ZN7android12BnMemoryHeapD2Ev -_ZN7android12BpMemoryHeapC1ERKNS_2spINS_7IBinderEEE -_ZN7android12BpMemoryHeapC2ERKNS_2spINS_7IBinderEEE -_ZN7android12BpMemoryHeapD0Ev -_ZN7android12BpMemoryHeapD1Ev -_ZN7android12BpMemoryHeapD2Ev -_ZN7android12compare_typeINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEEEiRKT_SA_ -_ZN7android12compare_typeINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEEEiRKT_S7_ -_ZN7android12compare_typeINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEEEiRKT_S7_ -_ZN7android12compare_typeINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEEEiRKT_S9_ -_ZN7android12compare_typeINS_8AssetDir8FileInfoEEEiRKT_S5_ -_ZN7android12GGLAssembler10mul_factorERNS0_11component_tERKNS0_9integer_tES5_ -_ZN7android12GGLAssembler11base_offsetERKNS0_9pointer_tES3_RKNS0_5reg_tE -_ZN7android12GGLAssembler13build_maskingERNS0_7pixel_tERNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler13component_addERNS0_11component_tERKNS0_9integer_tES5_ -_ZN7android12GGLAssembler13component_satERKNS0_11component_tE -_ZN7android12GGLAssembler13init_texturesEPNS0_11tex_coord_tERKNS0_5reg_tES5_ -_ZN7android12GGLAssembler13scanline_coreERKNS_7needs_tEPKNS_9context_tE -_ZN7android12GGLAssembler14blending_codesEii -_ZN7android12GGLAssembler14build_blendingERNS0_11component_tERKNS0_7pixel_tEiRNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler14build_logic_opERNS0_7pixel_tERNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler14build_texturesERNS0_16fragment_parts_tERNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler14decodeTMUNeedsERKNS_7needs_tEPKNS_9context_tE -_ZN7android12GGLAssembler14mul_factor_addERNS0_11component_tERKNS0_9integer_tES5_RKS1_ -_ZN7android12GGLAssembler15build_componentERNS0_7pixel_tERKNS0_16fragment_parts_tEiRNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler15build_iterate_fERKNS0_16fragment_parts_tE -_ZN7android12GGLAssembler15build_iterate_zERKNS0_16fragment_parts_tE -_ZN7android12GGLAssembler16build_alpha_testERNS0_11component_tERKNS0_16fragment_parts_tE -_ZN7android12GGLAssembler16build_depth_testERKNS0_16fragment_parts_tEj -_ZN7android12GGLAssembler18build_blend_factorERNS0_9integer_tEiiRKNS0_7pixel_tES2_S2_RNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler18build_smooth_shadeERKNS0_16fragment_parts_tE -_ZN7android12GGLAssembler18decodeLogicOpNeedsERKNS_7needs_tE -_ZN7android12GGLAssembler19build_and_immediateEiiji -_ZN7android12GGLAssembler19init_iterated_colorERNS0_16fragment_parts_tERKNS0_5reg_tE -_ZN7android12GGLAssembler20build_iterated_colorERNS0_11component_tERKNS0_16fragment_parts_tEiRNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler21build_blendFOneMinusFERNS0_11component_tERKNS0_9integer_tES5_S5_ -_ZN7android12GGLAssembler21build_blendOneMinusFFERNS0_11component_tERKNS0_9integer_tES5_S5_ -_ZN7android12GGLAssembler21build_scanline_prologERNS0_16fragment_parts_tERKNS_7needs_tE -_ZN7android12GGLAssembler24build_incoming_componentERNS0_11component_tEiRKNS0_16fragment_parts_tEiRNS_17RegisterAllocator7ScratchES8_ -_ZN7android12GGLAssembler25build_texture_environmentERNS0_11component_tERKNS0_16fragment_parts_tEiRNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler26build_coverage_applicationERNS0_11component_tERKNS0_16fragment_parts_tERNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler33build_iterate_texture_coordinatesERKNS0_16fragment_parts_tE -_ZN7android12GGLAssembler3addERNS0_11component_tERKS1_RKNS0_7pixel_tEi -_ZN7android12GGLAssembler4loadERKNS0_9pointer_tERKNS0_7pixel_tEj -_ZN7android12GGLAssembler5blendERNS0_11component_tERKS1_RKNS0_7pixel_tEii -_ZN7android12GGLAssembler5decalERNS0_11component_tERKS1_RKNS0_7pixel_tEi -_ZN7android12GGLAssembler5resetEi -_ZN7android12GGLAssembler5storeERKNS0_9pointer_tERKNS0_7pixel_tEj -_ZN7android12GGLAssembler6epilogEj -_ZN7android12GGLAssembler6expandERNS0_11component_tERKS1_i -_ZN7android12GGLAssembler6expandERNS0_9integer_tERKNS0_11component_tEi -_ZN7android12GGLAssembler6expandERNS0_9integer_tERKS1_i -_ZN7android12GGLAssembler6prologEv -_ZN7android12GGLAssembler7extractERNS0_11component_tERKNS0_7pixel_tEi -_ZN7android12GGLAssembler7extractERNS0_9integer_tEiiii -_ZN7android12GGLAssembler7extractERNS0_9integer_tERKNS0_7pixel_tEi -_ZN7android12GGLAssembler7filter8ERKNS0_16fragment_parts_tERNS0_7pixel_tERKNS0_14texture_unit_tEiiRNS0_9pointer_tEi -_ZN7android12GGLAssembler8filter16ERKNS0_16fragment_parts_tERNS0_7pixel_tERKNS0_14texture_unit_tEiiRNS0_9pointer_tEi -_ZN7android12GGLAssembler8filter24ERKNS0_16fragment_parts_tERNS0_7pixel_tERKNS0_14texture_unit_tEiiRNS0_9pointer_tEi -_ZN7android12GGLAssembler8filter32ERKNS0_16fragment_parts_tERNS0_7pixel_tERKNS0_14texture_unit_tEiiRNS0_9pointer_tEi -_ZN7android12GGLAssembler8modulateERNS0_11component_tERKS1_RKNS0_7pixel_tEi -_ZN7android12GGLAssembler8scanlineERKNS_7needs_tEPKNS_9context_tE -_ZN7android12GGLAssembler8wrappingEiiiii -_ZN7android12GGLAssembler9build_fogERNS0_11component_tEiRNS_17RegisterAllocator7ScratchE -_ZN7android12GGLAssembler9downshiftERNS0_7pixel_tEiNS0_11component_tERKNS0_5reg_tE -_ZN7android12GGLAssemblerC1EPNS_21ARMAssemblerInterfaceE -_ZN7android12GGLAssemblerC2EPNS_21ARMAssemblerInterfaceE -_ZN7android12GGLAssemblerD0Ev -_ZN7android12GGLAssemblerD1Ev -_ZN7android12GGLAssemblerD2Ev -_ZN7android12gTextBuffersE -_ZN7android12KeyLayoutMap4loadEPKc -_ZN7android12KeyLayoutMapC1Ev -_ZN7android12KeyLayoutMapC2Ev -_ZN7android12KeyLayoutMapD1Ev -_ZN7android12KeyLayoutMapD2Ev -_ZN7android12MemoryDealer10deallocateEj -_ZN7android12MemoryDealer8allocateEj -_ZN7android12MemoryDealerC1EjPKc -_ZN7android12MemoryDealerC2EjPKc -_ZN7android12MemoryDealerD0Ev -_ZN7android12MemoryDealerD1Ev -_ZN7android12MemoryDealerD2Ev -_ZN7android12ProcessState13expungeHandleEiPNS_7IBinderE -_ZN7android12ProcessState15startThreadPoolEv -_ZN7android12ProcessState16getContextObjectERKNS_2spINS_7IBinderEEE -_ZN7android12ProcessState16getContextObjectERKNS_8String16ERKNS_2spINS_7IBinderEEE -_ZN7android12ProcessState16setContextObjectERKNS_2spINS_7IBinderEEE -_ZN7android12ProcessState16setContextObjectERKNS_2spINS_7IBinderEEERKNS_8String16E -_ZN7android12ProcessState16setSingleProcessEb -_ZN7android12ProcessState17spawnPooledThreadEb -_ZN7android12ProcessState18lookupHandleLockedEi -_ZN7android12ProcessState20becomeContextManagerEPFbRKNS_8String16ERKNS_2spINS_7IBinderEEEPvES9_ -_ZN7android12ProcessState21getWeakProxyForHandleEi -_ZN7android12ProcessState23getStrongProxyForHandleEi -_ZN7android12ProcessState4selfEv -_ZN7android12ProcessState7setArgsEiPKPKc -_ZN7android12ProcessState8setArgV0EPKc -_ZN7android12ProcessStateC1Ev -_ZN7android12ProcessStateC2Ev -_ZN7android12ProcessStateD0Ev -_ZN7android12ProcessStateD1Ev -_ZN7android12ProcessStateD2Ev -_ZN7android12ResXMLParser11setPositionERKNS0_14ResXMLPositionE -_ZN7android12ResXMLParser4nextEv -_ZN7android12ResXMLParser7restartEv -_ZN7android12ResXMLParser8nextNodeEv -_ZN7android12ResXMLParserC1ERKNS_10ResXMLTreeE -_ZN7android12ResXMLParserC2ERKNS_10ResXMLTreeE -_ZN7android12SharedBuffer5allocEj -_ZN7android12SharedBuffer7deallocEPKS0_ -_ZN7android12uptimeMillisEv -_ZN7android13back_up_filesEiPNS_16BackupDataWriterEiPKPKcS5_i -_ZN7android13bytesPerPixelEi -_ZN7android13DurationTimer12addToTimevalEP7timevall -_ZN7android13DurationTimer16subtractTimevalsEPK7timevalS3_ -_ZN7android13DurationTimer4stopEv -_ZN7android13DurationTimer5startEv -_ZN7android13ggl_init_trapEPNS_9context_tE -_ZN7android13gGLWrapperKeyE -_ZN7android13gProcessMutexE -_ZN7android13GraphicBuffer10reallocateEjjij -_ZN7android13GraphicBuffer11free_handleEv -_ZN7android13GraphicBuffer17setVerticalStrideEj -_ZN7android13GraphicBuffer4lockEjPPv -_ZN7android13GraphicBuffer4lockEjRKNS_4RectEPPv -_ZN7android13GraphicBuffer4lockEP10GGLSurfacej -_ZN7android13GraphicBuffer6unlockEv -_ZN7android13GraphicBuffer8initSizeEjjij -_ZN7android13GraphicBuffer8setIndexEi -_ZN7android13GraphicBuffer9unflattenEPKvjPij -_ZN7android13GraphicBufferC1Ejjij -_ZN7android13GraphicBufferC1EjjijjP15native_handle_tb -_ZN7android13GraphicBufferC1Ev -_ZN7android13GraphicBufferC2Ejjij -_ZN7android13GraphicBufferC2EjjijjP15native_handle_tb -_ZN7android13GraphicBufferC2Ev -_ZN7android13GraphicBufferD0Ev -_ZN7android13GraphicBufferD1Ev -_ZN7android13GraphicBufferD2Ev -_ZN7android13ResStringPool5setToEPKvjb -_ZN7android13ResStringPool6uninitEv -_ZN7android13ResStringPoolC1EPKvjb -_ZN7android13ResStringPoolC1Ev -_ZN7android13ResStringPoolC2EPKvjb -_ZN7android13ResStringPoolC2Ev -_ZN7android13ResStringPoolD1Ev -_ZN7android13ResStringPoolD2Ev -_ZN7android13roundUpPower2Ej -_ZN7android14acquire_objectERKNS_2spINS_12ProcessStateEEERKNS_18flat_binder_objectEPKv -_ZN7android14flatten_binderERKNS_2spINS_12ProcessStateEEERKNS0_INS_7IBinderEEEPNS_6ParcelE -_ZN7android14flatten_binderERKNS_2spINS_12ProcessStateEEERKNS_2wpINS_7IBinderEEEPNS_6ParcelE -_ZN7android14getFileModDateEPKc -_ZN7android14ggl_init_clearEPNS_9context_tE -_ZN7android14ggl_pack_colorEPNS_9context_tEiiiii -_ZN7android14IPCThreadState10freeBufferEPNS_6ParcelEPKhjPKjjPv -_ZN7android14IPCThreadState11clearCallerEv -_ZN7android14IPCThreadState11stopProcessEb -_ZN7android14IPCThreadState13decWeakHandleEi -_ZN7android14IPCThreadState13expungeHandleEiPNS_7IBinderE -_ZN7android14IPCThreadState13flushCommandsEv -_ZN7android14IPCThreadState13getCallingPidEv -_ZN7android14IPCThreadState13getCallingUidEv -_ZN7android14IPCThreadState13incWeakHandleEi -_ZN7android14IPCThreadState14clearLastErrorEv -_ZN7android14IPCThreadState14executeCommandEi -_ZN7android14IPCThreadState14joinThreadPoolEb -_ZN7android14IPCThreadState14talkWithDriverEb -_ZN7android14IPCThreadState15decStrongHandleEi -_ZN7android14IPCThreadState15incStrongHandleEi -_ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi -_ZN7android14IPCThreadState16threadDestructorEPv -_ZN7android14IPCThreadState20clearCallingIdentityEv -_ZN7android14IPCThreadState20writeTransactionDataEijijRKNS_6ParcelEPi -_ZN7android14IPCThreadState22attemptIncStrongHandleEi -_ZN7android14IPCThreadState22clearDeathNotificationEiPNS_8BpBinderE -_ZN7android14IPCThreadState22restoreCallingIdentityEx -_ZN7android14IPCThreadState24requestDeathNotificationEiPNS_8BpBinderE -_ZN7android14IPCThreadState27disableBackgroundSchedulingEb -_ZN7android14IPCThreadState4selfEv -_ZN7android14IPCThreadState7processEv -_ZN7android14IPCThreadState8shutdownEv -_ZN7android14IPCThreadState8transactEijRKNS_6ParcelEPS1_j -_ZN7android14IPCThreadState9sendReplyERKNS_6ParcelEj -_ZN7android14IPCThreadStateC1Ev -_ZN7android14IPCThreadStateC2Ev -_ZN7android14IPCThreadStateD1Ev -_ZN7android14IPCThreadStateD2Ev -_ZN7android14MemoryHeapBase4initEiPviiPKc -_ZN7android14MemoryHeapBase5mapfdEijj -_ZN7android14MemoryHeapBase7disposeEv -_ZN7android14MemoryHeapBaseC1Eijjj -_ZN7android14MemoryHeapBaseC1EjjPKc -_ZN7android14MemoryHeapBaseC1EPKcjj -_ZN7android14MemoryHeapBaseC1Ev -_ZN7android14MemoryHeapBaseC2Eijjj -_ZN7android14MemoryHeapBaseC2EjjPKc -_ZN7android14MemoryHeapBaseC2EPKcjj -_ZN7android14MemoryHeapBaseC2Ev -_ZN7android14MemoryHeapBaseD0Ev -_ZN7android14MemoryHeapBaseD1Ev -_ZN7android14MemoryHeapBaseD2Ev -_ZN7android14MemoryHeapPmem10MemoryPmemC1ERKNS_2spIS0_EE -_ZN7android14MemoryHeapPmem10MemoryPmemC2ERKNS_2spIS0_EE -_ZN7android14MemoryHeapPmem10MemoryPmemD0Ev -_ZN7android14MemoryHeapPmem10MemoryPmemD1Ev -_ZN7android14MemoryHeapPmem10MemoryPmemD2Ev -_ZN7android14MemoryHeapPmem12createMemoryEjj -_ZN7android14MemoryHeapPmem4slapEv -_ZN7android14MemoryHeapPmem6removeERKNS_2wpINS0_10MemoryPmemEEE -_ZN7android14MemoryHeapPmem6revokeEv -_ZN7android14MemoryHeapPmem6unslapEv -_ZN7android14MemoryHeapPmem9mapMemoryEjj -_ZN7android14MemoryHeapPmemC1ERKNS_2spINS_14MemoryHeapBaseEEEj -_ZN7android14MemoryHeapPmemC2ERKNS_2spINS_14MemoryHeapBaseEEEj -_ZN7android14MemoryHeapPmemD0Ev -_ZN7android14MemoryHeapPmemD1Ev -_ZN7android14MemoryHeapPmemD2Ev -_ZN7android14release_objectERKNS_2spINS_12ProcessStateEEERKNS_18flat_binder_objectEPKv -_ZN7android14Res_png_9patch11deserializeEPKv -_ZN7android14Res_png_9patch12deviceToFileEv -_ZN7android14Res_png_9patch12fileToDeviceEv -_ZN7android14Res_png_9patch14serializedSizeEv -_ZN7android14Res_png_9patch9serializeEPv -_ZN7android14Res_png_9patch9serializeEv -_ZN7android15checkPermissionERKNS_8String16Eij -_ZN7android15elapsedRealtimeEv -_ZN7android15EventRecurrence5parseERKNS_8String16E -_ZN7android15EventRecurrenceC1Ev -_ZN7android15EventRecurrenceC2Ev -_ZN7android15EventRecurrenceD1Ev -_ZN7android15EventRecurrenceD2Ev -_ZN7android15ggl_init_pickerEPNS_9context_tE -_ZN7android15ggl_init_rasterEPNS_9context_tE -_ZN7android15ggl_set_surfaceEPNS_9context_tEPNS_9surface_tEPK10GGLSurface -_ZN7android15ggl_system_timeEv -_ZN7android15gHooksNoContextE -_ZN7android15IServiceManager10descriptorE -_ZN7android15IServiceManager11asInterfaceERKNS_2spINS_7IBinderEEE -_ZN7android15IServiceManagerC1Ev -_ZN7android15IServiceManagerC2Ev -_ZN7android15IServiceManagerD0Ev -_ZN7android15IServiceManagerD1Ev -_ZN7android15IServiceManagerD2Ev -_ZN7android15SubRegionMemory6revokeEv -_ZN7android15SubRegionMemoryC1ERKNS_2spINS_14MemoryHeapPmemEEElj -_ZN7android15SubRegionMemoryC2ERKNS_2spINS_14MemoryHeapPmemEEElj -_ZN7android15SubRegionMemoryD0Ev -_ZN7android15SubRegionMemoryD1Ev -_ZN7android15SubRegionMemoryD2Ev -_ZN7android16BackupDataReader11HasEntitiesEv -_ZN7android16BackupDataReader12skip_paddingEv -_ZN7android16BackupDataReader14ReadEntityDataEPvj -_ZN7android16BackupDataReader14ReadNextHeaderEPbPi -_ZN7android16BackupDataReader14SkipEntityDataEv -_ZN7android16BackupDataReader16ReadEntityHeaderEPNS_7String8EPj -_ZN7android16BackupDataReader6StatusEv -_ZN7android16BackupDataReaderC1Ei -_ZN7android16BackupDataReaderC2Ei -_ZN7android16BackupDataReaderD1Ev -_ZN7android16BackupDataReaderD2Ev -_ZN7android16BackupDataWriter12SetKeyPrefixERKNS_7String8E -_ZN7android16BackupDataWriter15WriteEntityDataEPKvj -_ZN7android16BackupDataWriter17WriteEntityHeaderERKNS_7String8Ej -_ZN7android16BackupDataWriter17write_padding_forEi -_ZN7android16BackupDataWriterC1Ei -_ZN7android16BackupDataWriterC2Ei -_ZN7android16BackupDataWriterD1Ev -_ZN7android16BackupDataWriterD2Ev -_ZN7android16BnServiceManager10onTransactEjRKNS_6ParcelEPS1_j -_ZN7android16_CompressedAsset4readEPvj -_ZN7android16_CompressedAsset4seekEli -_ZN7android16_CompressedAsset5closeEv -_ZN7android16_CompressedAsset9getBufferEb -_ZN7android16_CompressedAsset9openChunkEilijj -_ZN7android16_CompressedAsset9openChunkEPNS_7FileMapEij -_ZN7android16_CompressedAssetC1Ev -_ZN7android16_CompressedAssetC2Ev -_ZN7android16_CompressedAssetD0Ev -_ZN7android16_CompressedAssetD1Ev -_ZN7android16_CompressedAssetD2Ev -_ZN7android16ggl_init_contextEPNS_9context_tE -_ZN7android16ggl_init_textureEPNS_9context_tE -_ZN7android16ggl_needs_to_envEj -_ZN7android16ggl_pick_textureEPNS_9context_tE -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl1Ev -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl2Ev -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl3Ev -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl4Ev -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl5Ev -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl6Ev -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl7Ev -_ZN7android16SortedVectorImpl25reservedSortedVectorImpl8Ev -_ZN7android16SortedVectorImpl3addEPKv -_ZN7android16SortedVectorImpl5mergeERKNS_10VectorImplE -_ZN7android16SortedVectorImpl5mergeERKS0_ -_ZN7android16SortedVectorImpl6removeEPKv -_ZN7android16SortedVectorImplaSERKS0_ -_ZN7android16SortedVectorImplC1Ejj -_ZN7android16SortedVectorImplC1ERKNS_10VectorImplE -_ZN7android16SortedVectorImplC2Ejj -_ZN7android16SortedVectorImplC2ERKNS_10VectorImplE -_ZN7android16SortedVectorImplD0Ev -_ZN7android16SortedVectorImplD1Ev -_ZN7android16SortedVectorImplD2Ev -_ZN7android16unflatten_binderERKNS_2spINS_12ProcessStateEEERKNS_6ParcelEPNS0_INS_7IBinderEEE -_ZN7android16unflatten_binderERKNS_2spINS_12ProcessStateEEERKNS_6ParcelEPNS_2wpINS_7IBinderEEE -_ZN7android17ARMAssemblerProxy10pcForLabelEPKc -_ZN7android17ARMAssemblerProxy11disassembleEPKc -_ZN7android17ARMAssemblerProxy14dataProcessingEiiiiij -_ZN7android17ARMAssemblerProxy1BEiPj -_ZN7android17ARMAssemblerProxy1BEiPKc -_ZN7android17ARMAssemblerProxy2BLEiPj -_ZN7android17ARMAssemblerProxy2BLEiPKc -_ZN7android17ARMAssemblerProxy2BXEii -_ZN7android17ARMAssemblerProxy3CLZEiii -_ZN7android17ARMAssemblerProxy3LDMEiiiij -_ZN7android17ARMAssemblerProxy3LDREiiij -_ZN7android17ARMAssemblerProxy3MLAEiiiiii -_ZN7android17ARMAssemblerProxy3MULEiiiii -_ZN7android17ARMAssemblerProxy3PLDEij -_ZN7android17ARMAssemblerProxy3STMEiiiij -_ZN7android17ARMAssemblerProxy3STREiiij -_ZN7android17ARMAssemblerProxy3SWIEij -_ZN7android17ARMAssemblerProxy3SWPEiiii -_ZN7android17ARMAssemblerProxy4LDRBEiiij -_ZN7android17ARMAssemblerProxy4LDRHEiiij -_ZN7android17ARMAssemblerProxy4QADDEiiii -_ZN7android17ARMAssemblerProxy4QSUBEiiii -_ZN7android17ARMAssemblerProxy4SMLAEiiiiii -_ZN7android17ARMAssemblerProxy4SMULEiiiii -_ZN7android17ARMAssemblerProxy4STRBEiiij -_ZN7android17ARMAssemblerProxy4STRHEiiij -_ZN7android17ARMAssemblerProxy4SWPBEiiii -_ZN7android17ARMAssemblerProxy5labelEPKc -_ZN7android17ARMAssemblerProxy5LDRSBEiiij -_ZN7android17ARMAssemblerProxy5LDRSHEiiij -_ZN7android17ARMAssemblerProxy5QDADDEiiii -_ZN7android17ARMAssemblerProxy5QDSUBEiiii -_ZN7android17ARMAssemblerProxy5resetEv -_ZN7android17ARMAssemblerProxy5SMLALEiiiiii -_ZN7android17ARMAssemblerProxy5SMLAWEiiiiii -_ZN7android17ARMAssemblerProxy5SMUALEiiiiii -_ZN7android17ARMAssemblerProxy5SMULLEiiiiii -_ZN7android17ARMAssemblerProxy5SMULWEiiiii -_ZN7android17ARMAssemblerProxy5UMUALEiiiiii -_ZN7android17ARMAssemblerProxy5UMULLEiiiiii -_ZN7android17ARMAssemblerProxy6epilogEj -_ZN7android17ARMAssemblerProxy6prologEv -_ZN7android17ARMAssemblerProxy7commentEPKc -_ZN7android17ARMAssemblerProxy8generateEPKc -_ZN7android17ARMAssemblerProxy9setTargetEPNS_21ARMAssemblerInterfaceE -_ZN7android17ARMAssemblerProxyC1EPNS_21ARMAssemblerInterfaceE -_ZN7android17ARMAssemblerProxyC1Ev -_ZN7android17ARMAssemblerProxyC2EPNS_21ARMAssemblerInterfaceE -_ZN7android17ARMAssemblerProxyC2Ev -_ZN7android17ARMAssemblerProxyD0Ev -_ZN7android17ARMAssemblerProxyD1Ev -_ZN7android17ARMAssemblerProxyD2Ev -_ZN7android17ggl_init_scanlineEPNS_9context_tE -_ZN7android17ggl_pick_scanlineEPNS_9context_tE -_ZN7android17ggl_state_changedEPNS_9context_tEi -_ZN7android17move_forward_typeINS_12AssetManager10asset_pathEEEvPT_PKS3_j -_ZN7android17move_forward_typeINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEEEvPT_PKS8_j -_ZN7android17move_forward_typeINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEEEvPT_PKS8_j -_ZN7android17move_forward_typeINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEEEvPT_PKS5_j -_ZN7android17move_forward_typeINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEEEvPT_PKS5_j -_ZN7android17move_forward_typeINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEEEvPT_PKS7_j -_ZN7android17move_forward_typeINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEEEvPT_PKS6_j -_ZN7android17move_forward_typeINS_7String8EEEvPT_PKS2_j -_ZN7android17move_forward_typeINS_8AssetDir8FileInfoEEEvPT_PKS3_j -_ZN7android17move_forward_typeINS_8BpBinder8ObituaryEEEvPT_PKS3_j -_ZN7android17move_forward_typeINS_8String16EEEvPT_PKS2_j -_ZN7android17RegisterAllocator10recycleRegEi -_ZN7android17RegisterAllocator10reserveRegEi -_ZN7android17RegisterAllocator12RegisterFile14recycleSeveralEj -_ZN7android17RegisterAllocator12RegisterFile14reserveSeveralEj -_ZN7android17RegisterAllocator12RegisterFile5resetEv -_ZN7android17RegisterAllocator12RegisterFile6obtainEv -_ZN7android17RegisterAllocator12RegisterFile7recycleEi -_ZN7android17RegisterAllocator12RegisterFile7reserveEi -_ZN7android17RegisterAllocator12RegisterFileC1ERKS1_ -_ZN7android17RegisterAllocator12RegisterFileC1Ev -_ZN7android17RegisterAllocator12RegisterFileC2ERKS1_ -_ZN7android17RegisterAllocator12RegisterFileC2Ev -_ZN7android17RegisterAllocator12RegisterFileD1Ev -_ZN7android17RegisterAllocator12RegisterFileD2Ev -_ZN7android17RegisterAllocator12registerFileEv -_ZN7android17RegisterAllocator5resetEv -_ZN7android17RegisterAllocator9obtainRegEv -_ZN7android17RestoreHelperBase13WriteSnapshotEi -_ZN7android17RestoreHelperBase9WriteFileERKNS_7String8EPNS_16BackupDataReaderE -_ZN7android17RestoreHelperBaseC1Ev -_ZN7android17RestoreHelperBaseC2Ev -_ZN7android17RestoreHelperBaseD1Ev -_ZN7android17RestoreHelperBaseD2Ev -_ZN7android17terminate_string8Ev -_ZN7android18BufferedTextOutput10moveIndentEi -_ZN7android18BufferedTextOutput10pushBundleEv -_ZN7android18BufferedTextOutput14getThreadStateEv -_ZN7android18BufferedTextOutput16threadDestructorEPv -_ZN7android18BufferedTextOutput5printEPKcj -_ZN7android18BufferedTextOutput9popBundleEv -_ZN7android18BufferedTextOutputC1Ej -_ZN7android18BufferedTextOutputC2Ej -_ZN7android18BufferedTextOutputD0Ev -_ZN7android18BufferedTextOutputD1Ev -_ZN7android18BufferedTextOutputD2Ev -_ZN7android18getPixelFormatInfoEiPNS_15PixelFormatInfoE -_ZN7android18ggl_uninit_contextEPNS_9context_tE -_ZN7android18initialize_string8Ev -_ZN7android18move_backward_typeINS_12AssetManager10asset_pathEEEvPT_PKS3_j -_ZN7android18move_backward_typeINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEEEvPT_PKS8_j -_ZN7android18move_backward_typeINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEEEvPT_PKS8_j -_ZN7android18move_backward_typeINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEEEvPT_PKS5_j -_ZN7android18move_backward_typeINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEEEvPT_PKS5_j -_ZN7android18move_backward_typeINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEEEvPT_PKS7_j -_ZN7android18move_backward_typeINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEEEvPT_PKS6_j -_ZN7android18move_backward_typeINS_7String8EEEvPT_PKS2_j -_ZN7android18move_backward_typeINS_8AssetDir8FileInfoEEEvPT_PKS3_j -_ZN7android18move_backward_typeINS_8BpBinder8ObituaryEEEvPT_PKS3_j -_ZN7android18move_backward_typeINS_8String16EEEvPT_PKS2_j -_ZN7android18terminate_string16Ev -_ZN7android18the_context_objectE -_ZN7android19ggl_uninit_scanlineEPNS_9context_tE -_ZN7android19GraphicBufferMapper14registerBufferEPK15native_handle_t -_ZN7android19GraphicBufferMapper16unregisterBufferEPK15native_handle_t -_ZN7android19GraphicBufferMapper4lockEPK15native_handle_tiRKNS_4RectEPPv -_ZN7android19GraphicBufferMapper6unlockEPK15native_handle_t -_ZN7android19GraphicBufferMapperC1Ev -_ZN7android19GraphicBufferMapperC2Ev -_ZN7android19initialize_string16Ev -_ZN7android19setTheContextObjectENS_2spINS_7BBinderEEE -_ZN7android19sw_gralloc_handle_t14registerBufferEPS0_ -_ZN7android19sw_gralloc_handle_t16unregisterBufferEPS0_ -_ZN7android19sw_gralloc_handle_t4freeEPS0_ -_ZN7android19sw_gralloc_handle_t4lockEPS0_iiiiiPPv -_ZN7android19sw_gralloc_handle_t5allocEjjiiPPK15native_handle_tPi -_ZN7android19sw_gralloc_handle_t6unlockEPS0_ -_ZN7android20setCurrentTimeMillisEx -_ZN7android21ARMAssemblerInterface10immed8_preEii -_ZN7android21ARMAssemblerInterface11immed12_preEii -_ZN7android21ARMAssemblerInterface11immed8_postEi -_ZN7android21ARMAssemblerInterface12immed12_postEi -_ZN7android21ARMAssemblerInterface13reg_scale_preEiiji -_ZN7android21ARMAssemblerInterface14buildImmediateEjRjS1_ -_ZN7android21ARMAssemblerInterface14reg_scale_postEiij -_ZN7android21ARMAssemblerInterface16isValidImmediateEj -_ZN7android21ARMAssemblerInterface3immEj -_ZN7android21ARMAssemblerInterface7reg_immEiij -_ZN7android21ARMAssemblerInterface7reg_preEii -_ZN7android21ARMAssemblerInterface7reg_regEiii -_ZN7android21ARMAssemblerInterface7reg_rrxEi -_ZN7android21ARMAssemblerInterface8reg_postEi -_ZN7android21ARMAssemblerInterfaceD0Ev -_ZN7android21ARMAssemblerInterfaceD1Ev -_ZN7android21ARMAssemblerInterfaceD2Ev -_ZN7android21defaultServiceManagerEv -_ZN7android21gPermissionControllerE -_ZN7android21IPermissionController10descriptorE -_ZN7android21IPermissionController11asInterfaceERKNS_2spINS_7IBinderEEE -_ZN7android21IPermissionControllerC1Ev -_ZN7android21IPermissionControllerC2Ev -_ZN7android21IPermissionControllerD0Ev -_ZN7android21IPermissionControllerD1Ev -_ZN7android21IPermissionControllerD2Ev -_ZN7android22BnPermissionController10onTransactEjRKNS_6ParcelEPS1_j -_ZN7android22checkCallingPermissionERKNS_8String16E -_ZN7android22checkCallingPermissionERKNS_8String16EPiS3_ -_ZN7android22gDefaultServiceManagerE -_ZN7android22GraphicBufferAllocator10sAllocListE -_ZN7android22GraphicBufferAllocator4freeEPK15native_handle_t -_ZN7android22GraphicBufferAllocator5allocEjjiiPPK15native_handle_tPi -_ZN7android22GraphicBufferAllocator5sLockE -_ZN7android22GraphicBufferAllocatorC1Ev -_ZN7android22GraphicBufferAllocatorC2Ev -_ZN7android22GraphicBufferAllocatorD1Ev -_ZN7android22GraphicBufferAllocatorD2Ev -_ZN7android22SimpleBestFitAllocator10deallocateEj -_ZN7android22SimpleBestFitAllocator12kMemoryAlignE -_ZN7android22SimpleBestFitAllocator5allocEjj -_ZN7android22SimpleBestFitAllocator7deallocEj -_ZN7android22SimpleBestFitAllocator8allocateEjj -_ZN7android22SimpleBestFitAllocatorC1Ej -_ZN7android22SimpleBestFitAllocatorC2Ej -_ZN7android22SimpleBestFitAllocatorD1Ev -_ZN7android22SimpleBestFitAllocatorD2Ev -_ZN7android23backup_helper_test_fourEv -_ZN7android23FramebufferNativeWindow10lockBufferEP23android_native_window_tP23android_native_buffer_t -_ZN7android23FramebufferNativeWindow11queueBufferEP23android_native_window_tP23android_native_buffer_t -_ZN7android23FramebufferNativeWindow13dequeueBufferEP23android_native_window_tPP23android_native_buffer_t -_ZN7android23FramebufferNativeWindow15setSwapIntervalEP23android_native_window_ti -_ZN7android23FramebufferNativeWindow18setUpdateRectangleERKNS_4RectE -_ZN7android23FramebufferNativeWindow19compositionCompleteEv -_ZN7android23FramebufferNativeWindow5queryEP23android_native_window_tiPi -_ZN7android23FramebufferNativeWindow7performEP23android_native_window_tiz -_ZN7android23FramebufferNativeWindowC1Ev -_ZN7android23FramebufferNativeWindowC2Ev -_ZN7android23FramebufferNativeWindowD1Ev -_ZN7android23FramebufferNativeWindowD2Ev -_ZN7android23gDarwinIsReallyAnnoyingE -_ZN7android24backup_helper_test_emptyEv -_ZN7android24backup_helper_test_filesEv -_ZN7android25gDarwinCantLoadAllObjectsE -_ZN7android26gDefaultServiceManagerLockE -_ZN7android27test_read_header_and_entityERNS_16BackupDataReaderEPKc -_ZN7android28backup_helper_test_null_baseEv -_ZN7android2spINS_10OverlayRefEEaSEPS1_ -_ZN7android2spINS_11IMemoryHeapEEaSEPS1_ -_ZN7android2spINS_11IMemoryHeapEEaSERKS2_ -_ZN7android2spINS_11IMemoryHeapEEaSINS_12BpMemoryHeapEEERS2_PT_ -_ZN7android2spINS_11IMemoryHeapEEC1ERKS2_ -_ZN7android2spINS_11IMemoryHeapEED1Ev -_ZN7android2spINS_12AssetManager9SharedZipEEaSEPS2_ -_ZN7android2spINS_12AssetManager9SharedZipEEaSERKS3_ -_ZN7android2spINS_12AssetManager9SharedZipEEC1ERKS3_ -_ZN7android2spINS_12AssetManager9SharedZipEED1Ev -_ZN7android2spINS_12NativeBufferEEaSEPS1_ -_ZN7android2spINS_12ProcessStateEED1Ev -_ZN7android2spINS_14MemoryHeapBaseEEaSERKS2_ -_ZN7android2spINS_15IServiceManagerEEaSEPS1_ -_ZN7android2spINS_15IServiceManagerEEaSINS_16BpServiceManagerEEERS2_PT_ -_ZN7android2spINS_15IServiceManagerEED1Ev -_ZN7android2spINS_15SubRegionMemoryEEaSEPS1_ -_ZN7android2spINS_18BufferedTextOutput11BufferStateEEaSEPS2_ -_ZN7android2spINS_21IPermissionControllerEEaSEPS1_ -_ZN7android2spINS_21IPermissionControllerEEaSERKS2_ -_ZN7android2spINS_21IPermissionControllerEEaSINS_22BpPermissionControllerEEERS2_PT_ -_ZN7android2spINS_21IPermissionControllerEED1Ev -_ZN7android2spINS_6ThreadEEaSEPS1_ -_ZN7android2spINS_6ThreadEEaSERKS2_ -_ZN7android2spINS_6ThreadEED1Ev -_ZN7android2spINS_7BBinderEED1Ev -_ZN7android2spINS_7IBinderEEaSEPS1_ -_ZN7android2spINS_7IBinderEEaSERKS2_ -_ZN7android2spINS_7IBinderEEC1ERKS2_ -_ZN7android2spINS_7IBinderEED1Ev -_ZN7android2spINS_7IMemoryEEaSEPS1_ -_ZN7android2spINS_7IMemoryEEaSINS_10AllocationEEERS2_PT_ -_ZN7android2spINS_7IMemoryEEaSINS_8BpMemoryEEERS2_PT_ -_ZN7android2spINS_8AssemblyEEaSERKS2_ -_ZN7android2spINS_8IOverlayEEaSEPS1_ -_ZN7android2spINS_8IOverlayEEaSERKS2_ -_ZN7android2spINS_8IOverlayEEaSINS_9BpOverlayEEERS2_PT_ -_ZN7android2spINS_9HeapCacheEED1Ev -_ZN7android2wpINS_7IBinder14DeathRecipientEEaSERKNS_2spIS2_EE -_ZN7android2wpINS_7IBinder14DeathRecipientEEaSERKS3_ -_ZN7android2wpINS_7IBinderEE19set_object_and_refsEPS1_PNS_7RefBase12weakref_typeE -_ZN7android2wpINS_7IBinderEEaSEPS1_ -_ZN7android2wpINS_7IBinderEEaSERKS2_ -_ZN7android2wpINS_7IBinderEEC1ERKNS_2spIS1_EE -_ZN7android30backup_helper_test_data_readerEv -_ZN7android30backup_helper_test_data_writerEv -_ZN7android31backup_helper_test_missing_fileEv -_ZN7android33egl_get_image_for_current_contextEPv -_ZN7android4aerrE -_ZN7android4alogE -_ZN7android4aoutE -_ZN7android4endlERNS_10TextOutputE -_ZN7android4Rect11makeInvalidEv -_ZN7android4Rect8offsetByEii -_ZN7android4Rect8offsetToEii -_ZN7android5Asset10handleSeekElill -_ZN7android5Asset14createFromFileEPKcNS0_10AccessModeE -_ZN7android5Asset14getGlobalCountEv -_ZN7android5Asset19getAssetAllocationsEv -_ZN7android5Asset23createFromCompressedMapEPNS_7FileMapEijNS0_10AccessModeE -_ZN7android5Asset24createFromCompressedFileEPKcNS0_10AccessModeE -_ZN7android5Asset25createFromUncompressedMapEPNS_7FileMapENS0_10AccessModeE -_ZN7android5AssetC1Ev -_ZN7android5AssetC2Ev -_ZN7android5AssetD0Ev -_ZN7android5AssetD1Ev -_ZN7android5AssetD2Ev -_ZN7android5mArgCE -_ZN7android5mArgVE -_ZN7android6AAEdge4dumpEv -_ZN7android6dedentERNS_10TextOutputE -_ZN7android6gHooksE -_ZN7android6indentERNS_10TextOutputE -_ZN7android6Parcel10appendFromEPS0_jj -_ZN7android6Parcel10writeFloatEf -_ZN7android6Parcel10writeInt32Ei -_ZN7android6Parcel10writeInt64Ex -_ZN7android6Parcel11finishWriteEj -_ZN7android6Parcel11setDataSizeEj -_ZN7android6Parcel11writeDoubleEd -_ZN7android6Parcel11writeIntPtrEi -_ZN7android6Parcel11writeObjectERKNS_18flat_binder_objectEb -_ZN7android6Parcel12restartWriteEj -_ZN7android6Parcel12writeAlignedIdEEiT_ -_ZN7android6Parcel12writeAlignedIfEEiT_ -_ZN7android6Parcel12writeAlignedIiEEiT_ -_ZN7android6Parcel12writeAlignedIxEEiT_ -_ZN7android6Parcel12writeCStringEPKc -_ZN7android6Parcel12writeInplaceEj -_ZN7android6Parcel12writeString8ERKNS_7String8E -_ZN7android6Parcel13continueWriteEj -_ZN7android6Parcel13writeString16EPKtj -_ZN7android6Parcel13writeString16ERKNS_8String16E -_ZN7android6Parcel13writeUnpaddedEPKvj -_ZN7android6Parcel14acquireObjectsEv -_ZN7android6Parcel14freeDataNoInitEv -_ZN7android6Parcel14releaseObjectsEv -_ZN7android6Parcel15setDataCapacityEj -_ZN7android6Parcel15writeWeakBinderERKNS_2wpINS_7IBinderEEE -_ZN7android6Parcel17writeNativeHandleEPK15native_handle_t -_ZN7android6Parcel17writeStrongBinderERKNS_2spINS_7IBinderEEE -_ZN7android6Parcel19ipcSetDataReferenceEPKhjPKjjPFvPS0_S2_jS4_jPvES6_ -_ZN7android6Parcel19writeFileDescriptorEi -_ZN7android6Parcel19writeInterfaceTokenERKNS_8String16E -_ZN7android6Parcel20closeFileDescriptorsEv -_ZN7android6Parcel22writeDupFileDescriptorEi -_ZN7android6Parcel5writeEPKvj -_ZN7android6Parcel5writeERKNS_11FlattenableE -_ZN7android6Parcel6removeEjj -_ZN7android6Parcel7setDataEPKhj -_ZN7android6Parcel8freeDataEv -_ZN7android6Parcel8growDataEj -_ZN7android6Parcel8setErrorEi -_ZN7android6Parcel9initStateEv -_ZN7android6ParcelC1Ev -_ZN7android6ParcelC2Ev -_ZN7android6ParcelD1Ev -_ZN7android6ParcelD2Ev -_ZN7android6Region10writeEmptyEPvj -_ZN7android6Region12subtractSelfERKNS_4RectE -_ZN7android6Region12subtractSelfERKS0_ -_ZN7android6Region12subtractSelfERKS0_ii -_ZN7android6Region13operationSelfERKNS_4RectEi -_ZN7android6Region13operationSelfERKS0_i -_ZN7android6Region13operationSelfERKS0_iii -_ZN7android6Region13translateSelfEii -_ZN7android6Region14makeBoundsSelfEv -_ZN7android6Region16addRectUncheckedEiiii -_ZN7android6Region17boolean_operationEiRS0_RKS0_RKNS_4RectE -_ZN7android6Region17boolean_operationEiRS0_RKS0_RKNS_4RectEii -_ZN7android6Region17boolean_operationEiRS0_RKS0_S3_ -_ZN7android6Region17boolean_operationEiRS0_RKS0_S3_ii -_ZN7android6Region3setEjj -_ZN7android6Region3setERKNS_4RectE -_ZN7android6Region4readEPKv -_ZN7android6Region5clearEv -_ZN7android6Region6orSelfERKNS_4RectE -_ZN7android6Region6orSelfERKS0_ -_ZN7android6Region6orSelfERKS0_ii -_ZN7android6Region7andSelfERKNS_4RectE -_ZN7android6Region7andSelfERKS0_ -_ZN7android6Region7andSelfERKS0_ii -_ZN7android6Region7isEmptyEPv -_ZN7android6Region8validateERKS0_PKc -_ZN7android6Region9translateERS0_ii -_ZN7android6Region9translateERS0_RKS0_ii -_ZN7android6RegionaSERKS0_ -_ZN7android6RegionC1EPKv -_ZN7android6RegionC1ERKNS_4RectE -_ZN7android6RegionC1ERKS0_ -_ZN7android6RegionC1Ev -_ZN7android6RegionC2EPKv -_ZN7android6RegionC2ERKNS_4RectE -_ZN7android6RegionC2ERKS0_ -_ZN7android6RegionC2Ev -_ZN7android6RegionD1Ev -_ZN7android6RegionD2Ev -_ZN7android6Thread10readyToRunEv -_ZN7android6Thread11requestExitEv -_ZN7android6Thread11_threadLoopEPv -_ZN7android6Thread18requestExitAndWaitEv -_ZN7android6Thread3runEPKcij -_ZN7android6ThreadC1Eb -_ZN7android6ThreadC2Eb -_ZN7android6ThreadD0Ev -_ZN7android6ThreadD1Ev -_ZN7android6ThreadD2Ev -_ZN7android7BBinder10onTransactEjRKNS_6ParcelEPS1_j -_ZN7android7BBinder10pingBinderEv -_ZN7android7BBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj -_ZN7android7BBinder11localBinderEv -_ZN7android7BBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E -_ZN7android7BBinder12detachObjectEPKv -_ZN7android7BBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_ -_ZN7android7BBinder4dumpEiRKNS_6VectorINS_8String16EEE -_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j -_ZN7android7BBinderC1Ev -_ZN7android7BBinderC2Ev -_ZN7android7BBinderD0Ev -_ZN7android7BBinderD1Ev -_ZN7android7BBinderD2Ev -_ZN7android7FileMap6adviseENS0_9MapAdviceE -_ZN7android7FileMap6createEPKciljb -_ZN7android7FileMap9mPageSizeE -_ZN7android7FileMapC1Ev -_ZN7android7FileMapC2Ev -_ZN7android7FileMapD1Ev -_ZN7android7FileMapD2Ev -_ZN7android7HexDumpC1EPKvjj -_ZN7android7HexDumpC2EPKvjj -_ZN7android7IBinder11localBinderEv -_ZN7android7IBinder12remoteBinderEv -_ZN7android7IBinder19queryLocalInterfaceERKNS_8String16E -_ZN7android7IBinderC1Ev -_ZN7android7IBinderC2Ev -_ZN7android7IBinderD0Ev -_ZN7android7IBinderD1Ev -_ZN7android7IBinderD2Ev -_ZN7android7IMemory10descriptorE -_ZN7android7IMemory11asInterfaceERKNS_2spINS_7IBinderEEE -_ZN7android7IMemoryC1Ev -_ZN7android7IMemoryC2Ev -_ZN7android7IMemoryD0Ev -_ZN7android7IMemoryD1Ev -_ZN7android7IMemoryD2Ev -_ZN7android7MapInfo8sMapInfoE -_ZN7android7mArgLenE -_ZN7android7Overlay11queueBufferEPv -_ZN7android7Overlay11resizeInputEjj -_ZN7android7Overlay12setParameterEii -_ZN7android7Overlay13dequeueBufferEPPv -_ZN7android7Overlay16getBufferAddressEPv -_ZN7android7Overlay7destroyEv -_ZN7android7Overlay7getCropEPjS1_S1_S1_ -_ZN7android7Overlay7setCropEjjjj -_ZN7android7OverlayC1ERKNS_2spINS_10OverlayRefEEE -_ZN7android7OverlayC2ERKNS_2spINS_10OverlayRefEEE -_ZN7android7OverlayD0Ev -_ZN7android7OverlayD1Ev -_ZN7android7OverlayD2Ev -_ZN7android7RefBase10onFirstRefEv -_ZN7android7RefBase12weakref_type14attemptIncWeakEPKv -_ZN7android7RefBase12weakref_type16attemptIncStrongEPKv -_ZN7android7RefBase12weakref_type7decWeakEPKv -_ZN7android7RefBase12weakref_type7incWeakEPKv -_ZN7android7RefBase12weakref_type7trackMeEbb -_ZN7android7RefBase13onLastWeakRefEPKv -_ZN7android7RefBase15onLastStrongRefEPKv -_ZN7android7RefBase20extendObjectLifetimeEi -_ZN7android7RefBase20onIncStrongAttemptedEjPKv -_ZN7android7RefBaseC1Ev -_ZN7android7RefBaseC2Ev -_ZN7android7RefBaseD0Ev -_ZN7android7RefBaseD1Ev -_ZN7android7RefBaseD2Ev -_ZN7android7String810appendPathEPKc -_ZN7android7String810lockBufferEj -_ZN7android7String811real_appendEPKcj -_ZN7android7String811setPathNameEPKc -_ZN7android7String811setPathNameEPKcj -_ZN7android7String812unlockBufferEj -_ZN7android7String812unlockBufferEv -_ZN7android7String816convertToResPathEv -_ZN7android7String85setToEPKc -_ZN7android7String85setToEPKcj -_ZN7android7String85setToEPKjj -_ZN7android7String85setToEPKtj -_ZN7android7String85setToERKS0_ -_ZN7android7String86appendEPKc -_ZN7android7String86appendEPKcj -_ZN7android7String86appendERKS0_ -_ZN7android7String87toLowerEjj -_ZN7android7String87toLowerEv -_ZN7android7String87toUpperEjj -_ZN7android7String87toUpperEv -_ZN7android7String8C1EPKc -_ZN7android7String8C1EPKcj -_ZN7android7String8C1EPKj -_ZN7android7String8C1EPKjj -_ZN7android7String8C1EPKt -_ZN7android7String8C1EPKtj -_ZN7android7String8C1ERKNS_8String16E -_ZN7android7String8C1ERKS0_ -_ZN7android7String8C1Ev -_ZN7android7String8C2EPKc -_ZN7android7String8C2EPKcj -_ZN7android7String8C2EPKj -_ZN7android7String8C2EPKjj -_ZN7android7String8C2EPKt -_ZN7android7String8C2EPKtj -_ZN7android7String8C2ERKNS_8String16E -_ZN7android7String8C2ERKS0_ -_ZN7android7String8C2Ev -_ZN7android7String8D1Ev -_ZN7android7String8D2Ev -_ZN7android8Assembly6resizeEj -_ZN7android8AssemblyC1Ej -_ZN7android8AssemblyC2Ej -_ZN7android8AssemblyD0Ev -_ZN7android8AssemblyD1Ev -_ZN7android8AssemblyD2Ev -_ZN7android8AssetDir8FileInfo9findEntryEPKNS_12SortedVectorIS1_EERKNS_7String8E -_ZN7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j -_ZN7android8BnMemoryC1Ev -_ZN7android8BnMemoryC2Ev -_ZN7android8BnMemoryD0Ev -_ZN7android8BnMemoryD1Ev -_ZN7android8BnMemoryD2Ev -_ZN7android8BpBinder10onFirstRefEv -_ZN7android8BpBinder10pingBinderEv -_ZN7android8BpBinder11linkToDeathERKNS_2spINS_7IBinder14DeathRecipientEEEPvj -_ZN7android8BpBinder12attachObjectEPKvPvS3_PFvS2_S3_S3_E -_ZN7android8BpBinder12detachObjectEPKv -_ZN7android8BpBinder12remoteBinderEv -_ZN7android8BpBinder12sendObituaryEv -_ZN7android8BpBinder13ObjectManager4killEv -_ZN7android8BpBinder13ObjectManager6attachEPKvPvS4_PFvS3_S4_S4_E -_ZN7android8BpBinder13ObjectManager6detachEPKv -_ZN7android8BpBinder13ObjectManagerC1Ev -_ZN7android8BpBinder13ObjectManagerC2Ev -_ZN7android8BpBinder13ObjectManagerD1Ev -_ZN7android8BpBinder13ObjectManagerD2Ev -_ZN7android8BpBinder13unlinkToDeathERKNS_2wpINS_7IBinder14DeathRecipientEEEPvjPS4_ -_ZN7android8BpBinder14reportOneDeathERKNS0_8ObituaryE -_ZN7android8BpBinder15onLastStrongRefEPKv -_ZN7android8BpBinder20onIncStrongAttemptedEjPKv -_ZN7android8BpBinder4dumpEiRKNS_6VectorINS_8String16EEE -_ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j -_ZN7android8BpBinderC1Ei -_ZN7android8BpBinderC2Ei -_ZN7android8BpBinderD0Ev -_ZN7android8BpBinderD1Ev -_ZN7android8BpBinderD2Ev -_ZN7android8BpMemoryC1ERKNS_2spINS_7IBinderEEE -_ZN7android8BpMemoryC2ERKNS_2spINS_7IBinderEEE -_ZN7android8BpMemoryD0Ev -_ZN7android8BpMemoryD1Ev -_ZN7android8BpMemoryD2Ev -_ZN7android8EGLUtils26selectConfigForPixelFormatEPvPKiiPS1_ -_ZN7android8EGLUtils27selectConfigForNativeWindowEPvPKiP23android_native_window_tPS1_ -_ZN7android8EGLUtils8strerrorEi -_ZN7android8EventHub11open_deviceEPKc -_ZN7android8EventHub11read_notifyEi -_ZN7android8EventHub12close_deviceEPKc -_ZN7android8EventHub17addExcludedDeviceEPKc -_ZN7android8EventHub17openPlatformInputEv -_ZN7android8EventHub7hasKeysEjPiPh -_ZN7android8EventHub8device_tC1EiPKcS3_ -_ZN7android8EventHub8device_tC2EiPKcS3_ -_ZN7android8EventHub8device_tD1Ev -_ZN7android8EventHub8device_tD2Ev -_ZN7android8EventHub8getEventEPiS1_S1_S1_PjS1_Px -_ZN7android8EventHub8scan_dirEPKc -_ZN7android8EventHubC1Ev -_ZN7android8EventHubC2Ev -_ZN7android8EventHubD0Ev -_ZN7android8EventHubD1Ev -_ZN7android8EventHubD2Ev -_ZN7android8ggl_pickEPNS_9context_tE -_ZN7android8gProcessE -_ZN7android8IOverlay10descriptorE -_ZN7android8IOverlay11asInterfaceERKNS_2spINS_7IBinderEEE -_ZN7android8IOverlayC1Ev -_ZN7android8IOverlayC2Ev -_ZN7android8IOverlayD0Ev -_ZN7android8IOverlayD1Ev -_ZN7android8IOverlayD2Ev -_ZN7android8ResTable11stringToIntEPKtjPNS_9Res_valueE -_ZN7android8ResTable12parsePackageEPKNS_16ResTable_packageEPKNS0_6HeaderE -_ZN7android8ResTable13collectStringEPNS_8String16EPKtjbPPKcb -_ZN7android8ResTable13setParametersEPKNS_15ResTable_configE -_ZN7android8ResTable13stringToFloatEPKtjPNS_9Res_valueE -_ZN7android8ResTable13valueToStringEPKNS_9Res_valueEjPtPj -_ZN7android8ResTable17expandResourceRefEPKtjPNS_8String16ES4_S4_PKS3_S6_PPKc -_ZN7android8ResTable3addEPKvjPvb -_ZN7android8ResTable3addEPKvjPvPNS_5AssetEb -_ZN7android8ResTable3addEPNS_5AssetEPvb -_ZN7android8ResTable3addEPS0_ -_ZN7android8ResTable5Theme10applyStyleEjb -_ZN7android8ResTable5Theme12copy_packageEPNS1_12package_infoE -_ZN7android8ResTable5Theme12free_packageEPNS1_12package_infoE -_ZN7android8ResTable5Theme5setToERKS1_ -_ZN7android8ResTable5ThemeC1ERKS0_ -_ZN7android8ResTable5ThemeC2ERKS0_ -_ZN7android8ResTable5ThemeD1Ev -_ZN7android8ResTable5ThemeD2Ev -_ZN7android8ResTable6uninitEv -_ZN7android8ResTableC1EPKvjPvb -_ZN7android8ResTableC1Ev -_ZN7android8ResTableC2EPKvjPvb -_ZN7android8ResTableC2Ev -_ZN7android8ResTableD1Ev -_ZN7android8ResTableD2Ev -_ZN7android8String1610replaceAllEtt -_ZN7android8String165setToEPKt -_ZN7android8String165setToEPKtj -_ZN7android8String165setToERKS0_ -_ZN7android8String165setToERKS0_jj -_ZN7android8String166appendEPKtj -_ZN7android8String166appendERKS0_ -_ZN7android8String166insertEjPKt -_ZN7android8String166insertEjPKtj -_ZN7android8String166removeEjj -_ZN7android8String169makeLowerEv -_ZN7android8String16C1EPKc -_ZN7android8String16C1EPKcj -_ZN7android8String16C1EPKt -_ZN7android8String16C1EPKtj -_ZN7android8String16C1ERKNS_7String8E -_ZN7android8String16C1ERKS0_ -_ZN7android8String16C1ERKS0_jj -_ZN7android8String16C1Ev -_ZN7android8String16C2EPKc -_ZN7android8String16C2EPKcj -_ZN7android8String16C2EPKt -_ZN7android8String16C2EPKtj -_ZN7android8String16C2ERKNS_7String8E -_ZN7android8String16C2ERKS0_ -_ZN7android8String16C2ERKS0_jj -_ZN7android8String16C2Ev -_ZN7android8String16D1Ev -_ZN7android8String16D2Ev -_ZN7android8ZipUtils11examineGzipEP7__sFILEPiPlS4_Pm -_ZN7android8ZipUtils15inflateToBufferEiPvll -_ZN7android8ZipUtils15inflateToBufferEP7__sFILEPvll -_ZN7android9BnOverlay10onTransactEjRKNS_6ParcelEPS1_j -_ZN7android9BpRefBase10onFirstRefEv -_ZN7android9BpRefBase15onLastStrongRefEPKv -_ZN7android9BpRefBase20onIncStrongAttemptedEjPKv -_ZN7android9BpRefBaseC1ERKNS_2spINS_7IBinderEEE -_ZN7android9BpRefBaseC2ERKNS_2spINS_7IBinderEEE -_ZN7android9BpRefBaseD0Ev -_ZN7android9BpRefBaseD1Ev -_ZN7android9BpRefBaseD2Ev -_ZN7android9CallStack5clearEv -_ZN7android9CallStack6updateEii -_ZN7android9CallStackaSERKS0_ -_ZN7android9CallStackC1ERKS0_ -_ZN7android9CallStackC1Ev -_ZN7android9CallStackC2ERKS0_ -_ZN7android9CallStackC2Ev -_ZN7android9CallStackD1Ev -_ZN7android9CallStackD2Ev -_ZN7android9CodeCache5cacheERKNS_15AssemblyKeyBaseERKNS_2spINS_8AssemblyEEE -_ZN7android9CodeCacheC1Ej -_ZN7android9CodeCacheC2Ej -_ZN7android9CodeCacheD1Ev -_ZN7android9CodeCacheD2Ev -_ZN7android9countArgvEPKPKc -_ZN7android9ggl_errorEPNS_9context_tEj -_ZN7android9HeapCache10binderDiedERKNS_2wpINS_7IBinderEEE -_ZN7android9HeapCache10dump_heapsEv -_ZN7android9HeapCache8get_heapERKNS_2spINS_7IBinderEEE -_ZN7android9HeapCache9find_heapERKNS_2spINS_7IBinderEEE -_ZN7android9HeapCache9free_heapERKNS_2spINS_7IBinderEEE -_ZN7android9HeapCache9free_heapERKNS_2wpINS_7IBinderEEE -_ZN7android9HeapCacheC1Ev -_ZN7android9HeapCacheC2Ev -_ZN7android9HeapCacheD0Ev -_ZN7android9HeapCacheD1Ev -_ZN7android9HeapCacheD2Ev -_ZN7android9SingletonINS_19GraphicBufferMapperEE5sLockE -_ZN7android9SingletonINS_19GraphicBufferMapperEE9sInstanceE -_ZN7android9SingletonINS_19GraphicBufferMapperEEC1Ev -_ZN7android9SingletonINS_19GraphicBufferMapperEEC2Ev -_ZN7android9SingletonINS_19GraphicBufferMapperEED1Ev -_ZN7android9SingletonINS_19GraphicBufferMapperEED2Ev -_ZN7android9SingletonINS_22GraphicBufferAllocatorEE5sLockE -_ZN7android9SingletonINS_22GraphicBufferAllocatorEE9sInstanceE -_ZN7android9SingletonINS_22GraphicBufferAllocatorEEC1Ev -_ZN7android9SingletonINS_22GraphicBufferAllocatorEEC2Ev -_ZN7android9SingletonINS_22GraphicBufferAllocatorEED1Ev -_ZN7android9SingletonINS_22GraphicBufferAllocatorEED2Ev -_ZN7android9StopWatch3lapEv -_ZN7android9StopWatchC1EPKcij -_ZN7android9StopWatchC2EPKcij -_ZN7android9StopWatchD1Ev -_ZN7android9StopWatchD2Ev -_ZN7android9strdupNewEPKc -_ZN7android9ZipFileRO11computeHashEPKci -_ZN7android9ZipFileRO13inflateBufferEiPKvll -_ZN7android9ZipFileRO13inflateBufferEPvPKvll -_ZN7android9ZipFileRO15parseZipArchiveEv -_ZN7android9ZipFileRO4openEPKc -_ZN7android9ZipFileRO9addToHashEPKcij -_ZN7androidlsERNS_10TextOutputEb -_ZN7androidlsERNS_10TextOutputEd -_ZN7androidlsERNS_10TextOutputEf -_ZN7androidlsERNS_10TextOutputEi -_ZN7androidlsERNS_10TextOutputEj -_ZN7androidlsERNS_10TextOutputEl -_ZN7androidlsERNS_10TextOutputEm -_ZN7androidlsERNS_10TextOutputEPKc -_ZN7androidlsERNS_10TextOutputEPKv -_ZN7androidlsERNS_10TextOutputERKNS_7HexDumpE -_ZN7androidlsERNS_10TextOutputERKNS_7String8E -_ZN7androidlsERNS_10TextOutputERKNS_8String16E -_ZN7androidlsERNS_10TextOutputERKNS_8TypeCodeE -_ZN7androidlsERNS_10TextOutputEx -_ZN7androidlsERNS_10TextOutputEy -_ZN9type_infoC1ERKS_ -_ZN9type_infoC1Ev -_ZN9type_infoC2ERKS_ -_ZN9type_infoC2Ev -_ZN9type_infoD0Ev -_ZN9type_infoD1Ev -_ZN9type_infoD2Ev -_Znaj -_ZnajRKSt9nothrow_t -_ZNK7android10_FileAsset18openFileDescriptorEPlS1_ -_ZNK7android10IInterface8asBinderEv -_ZNK7android10MemoryBase9getMemoryEPlPj -_ZNK7android10Permission12checkCallingEv -_ZNK7android10Permission17doCheckPermissionEij -_ZNK7android10Permission5checkEij -_ZNK7android10PermissionltERKS0_ -_ZNK7android10ResXMLTree12validateNodeEPKNS_15ResXMLTree_nodeE -_ZNK7android10ResXMLTree8getErrorEv -_ZNK7android10VectorImpl12itemLocationEj -_ZNK7android10VectorImpl8capacityEv -_ZNK7android10VectorImpl8itemSizeEv -_ZNK7android11IMemoryHeap22getInterfaceDescriptorEv -_ZNK7android12ARMAssembler2pcEv -_ZNK7android12ARMAssembler4baseEv -_ZNK7android12AssetManager10getLocalesEPNS_6VectorINS_7String8EEE -_ZNK7android12AssetManager11getResTableEb -_ZNK7android12AssetManager12getAssetPathEPv -_ZNK7android12AssetManager12getResourcesEb -_ZNK7android12AssetManager13nextAssetPathEPv -_ZNK7android12AssetManager26updateResourceParamsLockedEv -_ZNK7android12AssetManager6ZipSet8getIndexERKNS_7String8E -_ZNK7android12BpMemoryHeap12assertMappedEv -_ZNK7android12BpMemoryHeap18assertReallyMappedEv -_ZNK7android12BpMemoryHeap7getBaseEv -_ZNK7android12BpMemoryHeap7getSizeEv -_ZNK7android12BpMemoryHeap8getFlagsEv -_ZNK7android12BpMemoryHeap9getHeapIDEv -_ZNK7android12GGLAssembler19isAlphaSourceNeededEv -_ZNK7android12KeyLayoutMap13findScancodesEiPNS_6VectorIiEE -_ZNK7android12KeyLayoutMap3mapEiPiPj -_ZNK7android12MemoryDealer4dumpEPKc -_ZNK7android12MemoryDealer4heapEv -_ZNK7android12MemoryDealer9allocatorEv -_ZNK7android12ProcessState16isContextManagerEv -_ZNK7android12ProcessState17supportsProcessesEv -_ZNK7android12ProcessState7getArgCEv -_ZNK7android12ProcessState7getArgVEv -_ZNK7android12ResXMLParser10getCommentEPj -_ZNK7android12ResXMLParser10getStringsEv -_ZNK7android12ResXMLParser11getPositionEPNS0_14ResXMLPositionE -_ZNK7android12ResXMLParser12getCommentIDEv -_ZNK7android12ResXMLParser12getEventTypeEv -_ZNK7android12ResXMLParser12getTextValueEPNS_9Res_valueE -_ZNK7android12ResXMLParser12indexOfClassEv -_ZNK7android12ResXMLParser12indexOfStyleEv -_ZNK7android12ResXMLParser13getLineNumberEv -_ZNK7android12ResXMLParser14getElementNameEPj -_ZNK7android12ResXMLParser15getNamespaceUriEPj -_ZNK7android12ResXMLParser16getAttributeDataEj -_ZNK7android12ResXMLParser16getAttributeNameEjPj -_ZNK7android12ResXMLParser16getElementNameIDEv -_ZNK7android12ResXMLParser16indexOfAttributeEPKcS2_ -_ZNK7android12ResXMLParser16indexOfAttributeEPKtjS2_j -_ZNK7android12ResXMLParser17getAttributeCountEv -_ZNK7android12ResXMLParser17getAttributeValueEjPNS_9Res_valueE -_ZNK7android12ResXMLParser17getNamespaceUriIDEv -_ZNK7android12ResXMLParser18getAttributeNameIDEj -_ZNK7android12ResXMLParser18getNamespacePrefixEPj -_ZNK7android12ResXMLParser19getElementNamespaceEPj -_ZNK7android12ResXMLParser20getAttributeDataTypeEj -_ZNK7android12ResXMLParser20getNamespacePrefixIDEv -_ZNK7android12ResXMLParser21getAttributeNameResIDEj -_ZNK7android12ResXMLParser21getAttributeNamespaceEjPj -_ZNK7android12ResXMLParser21getElementNamespaceIDEv -_ZNK7android12ResXMLParser23getAttributeNamespaceIDEj -_ZNK7android12ResXMLParser23getAttributeStringValueEjPj -_ZNK7android12ResXMLParser25getAttributeValueStringIDEj -_ZNK7android12ResXMLParser7getTextEPj -_ZNK7android12ResXMLParser9getTextIDEv -_ZNK7android12ResXMLParser9indexOfIDEv -_ZNK7android12SharedBuffer10editResizeEj -_ZNK7android12SharedBuffer11attemptEditEv -_ZNK7android12SharedBuffer4editEv -_ZNK7android12SharedBuffer5resetEj -_ZNK7android12SharedBuffer7acquireEv -_ZNK7android12SharedBuffer7releaseEj -_ZNK7android12SortedVectorIjE10do_compareEPKvS3_ -_ZNK7android12SortedVectorIjE10do_destroyEPvj -_ZNK7android12SortedVectorIjE12do_constructEPvj -_ZNK7android12SortedVectorIjE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorIjE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorIjE7do_copyEPvPKvj -_ZNK7android12SortedVectorIjE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEE10do_compareEPKvS7_ -_ZNK7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_compareEPKvSA_ -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEE10do_compareEPKvSA_ -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEE10do_compareEPKvS7_ -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEE10do_compareEPKvS7_ -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEE10do_compareEPKvS9_ -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEE10do_compareEPKvS8_ -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPjPKcEEE10do_compareEPKvS8_ -_ZNK7android12SortedVectorINS_16key_value_pair_tIPjPKcEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPjPKcEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPjPKcEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPjPKcEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPjPKcEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPjPKcEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEE10do_compareEPKvSA_ -_ZNK7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKcPjEEE10do_compareEPKvS8_ -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKcPjEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKcPjEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKcPjEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKcPjEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKcPjEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKcPjEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_compareES3_S3_ -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE15do_move_forwardEPvS3_j -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE16do_move_backwardEPvS3_j -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE7do_copyEPvS3_j -_ZNK7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEE8do_splatEPvS3_j -_ZNK7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEE10do_compareEPKvS7_ -_ZNK7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEE12do_constructEPvj -_ZNK7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEE8do_splatEPvPKvj -_ZNK7android12SortedVectorINS_8AssetDir8FileInfoEE10do_compareEPKvS5_ -_ZNK7android12SortedVectorINS_8AssetDir8FileInfoEE10do_destroyEPvj -_ZNK7android12SortedVectorINS_8AssetDir8FileInfoEE12do_constructEPvj -_ZNK7android12SortedVectorINS_8AssetDir8FileInfoEE15do_move_forwardEPvPKvj -_ZNK7android12SortedVectorINS_8AssetDir8FileInfoEE16do_move_backwardEPvPKvj -_ZNK7android12SortedVectorINS_8AssetDir8FileInfoEE7do_copyEPvPKvj -_ZNK7android12SortedVectorINS_8AssetDir8FileInfoEE8do_splatEPvPKvj -_ZNK7android13DurationTimer13durationUsecsEv -_ZNK7android13GraphicBuffer10getFdCountEv -_ZNK7android13GraphicBuffer15getNativeBufferEv -_ZNK7android13GraphicBuffer16getFlattenedSizeEv -_ZNK7android13GraphicBuffer17getVerticalStrideEv -_ZNK7android13GraphicBuffer7flattenEPvjPij -_ZNK7android13GraphicBuffer8getIndexEv -_ZNK7android13GraphicBuffer9initCheckEv -_ZNK7android13ResStringPool13indexOfStringEPKtj -_ZNK7android13ResStringPool4sizeEv -_ZNK7android13ResStringPool7styleAtEj -_ZNK7android13ResStringPool7styleAtERKNS_17ResStringPool_refE -_ZNK7android13ResStringPool8getErrorEv -_ZNK7android13ResStringPool8stringAtEjPj -_ZNK7android13ResStringPool9string8AtEjPj -_ZNK7android14MemoryHeapBase7getBaseEv -_ZNK7android14MemoryHeapBase7getSizeEv -_ZNK7android14MemoryHeapBase8getFlagsEv -_ZNK7android14MemoryHeapBase9getDeviceEv -_ZNK7android14MemoryHeapBase9getHeapIDEv -_ZNK7android15IServiceManager22getInterfaceDescriptorEv -_ZNK7android15PixelFormatInfo15getScanlineSizeEj -_ZNK7android15SubRegionMemory9getMemoryEPlPj -_ZNK7android16SortedVectorImpl13_indexOrderOfEPKvPj -_ZNK7android16SortedVectorImpl7indexOfEPKv -_ZNK7android16SortedVectorImpl7orderOfEPKv -_ZNK7android17RegisterAllocator12RegisterFile11hasFreeRegsEv -_ZNK7android17RegisterAllocator12RegisterFile13countFreeRegsEv -_ZNK7android17RegisterAllocator12RegisterFile7touchedEv -_ZNK7android17RegisterAllocator12RegisterFileeqERKS1_ -_ZNK7android18BufferedTextOutput9getBufferEv -_ZNK7android21IPermissionController22getInterfaceDescriptorEv -_ZNK7android22GraphicBufferAllocator4dumpERNS_7String8E -_ZNK7android22SimpleBestFitAllocator4dumpEPKc -_ZNK7android22SimpleBestFitAllocator4dumpERNS_7String8EPKc -_ZNK7android22SimpleBestFitAllocator4sizeEv -_ZNK7android22SimpleBestFitAllocator6dump_lEPKc -_ZNK7android22SimpleBestFitAllocator6dump_lERNS_7String8EPKc -_ZNK7android4Rect9intersectERKS0_PS0_ -_ZNK7android4RectltERKS0_ -_ZNK7android4RectmiERKNS_5PointE -_ZNK7android4RectplERKNS_5PointE -_ZNK7android6Parcel10errorCheckEv -_ZNK7android6Parcel10ipcObjectsEv -_ZNK7android6Parcel10readDoubleEPd -_ZNK7android6Parcel10readDoubleEv -_ZNK7android6Parcel10readIntPtrEPi -_ZNK7android6Parcel10readIntPtrEv -_ZNK7android6Parcel10readObjectEb -_ZNK7android6Parcel10scanForFdsEv -_ZNK7android6Parcel11ipcDataSizeEv -_ZNK7android6Parcel11readCStringEv -_ZNK7android6Parcel11readInplaceEj -_ZNK7android6Parcel11readString8Ev -_ZNK7android6Parcel12dataCapacityEv -_ZNK7android6Parcel12dataPositionEv -_ZNK7android6Parcel12objectsCountEv -_ZNK7android6Parcel12readString16Ev -_ZNK7android6Parcel14checkInterfaceEPNS_7IBinderE -_ZNK7android6Parcel14readWeakBinderEv -_ZNK7android6Parcel15ipcObjectsCountEv -_ZNK7android6Parcel15setDataPositionEj -_ZNK7android6Parcel16enforceInterfaceERKNS_8String16E -_ZNK7android6Parcel16readNativeHandleEv -_ZNK7android6Parcel16readStrongBinderEv -_ZNK7android6Parcel18hasFileDescriptorsEv -_ZNK7android6Parcel18readFileDescriptorEv -_ZNK7android6Parcel19readString16InplaceEPj -_ZNK7android6Parcel4dataEv -_ZNK7android6Parcel4readEPvj -_ZNK7android6Parcel4readERNS_11FlattenableE -_ZNK7android6Parcel5printERNS_10TextOutputEj -_ZNK7android6Parcel7ipcDataEv -_ZNK7android6Parcel7objectsEv -_ZNK7android6Parcel8dataSizeEv -_ZNK7android6Parcel9dataAvailEv -_ZNK7android6Parcel9readFloatEPf -_ZNK7android6Parcel9readFloatEv -_ZNK7android6Parcel9readInt32EPi -_ZNK7android6Parcel9readInt32Ev -_ZNK7android6Parcel9readInt64EPx -_ZNK7android6Parcel9readInt64Ev -_ZNK7android6Region3endEv -_ZNK7android6Region4dumpEPKcj -_ZNK7android6Region4dumpERNS_7String8EPKcj -_ZNK7android6Region5beginEv -_ZNK7android6Region5mergeERKNS_4RectE -_ZNK7android6Region5mergeERKS0_ -_ZNK7android6Region5mergeERKS0_ii -_ZNK7android6Region5writeEPvj -_ZNK7android6Region8getArrayEPj -_ZNK7android6Region8getRectsERNS_6VectorINS_4RectEEE -_ZNK7android6Region8subtractERKNS_4RectE -_ZNK7android6Region8subtractERKS0_ -_ZNK7android6Region8subtractERKS0_ii -_ZNK7android6Region9intersectERKNS_4RectE -_ZNK7android6Region9intersectERKS0_ -_ZNK7android6Region9intersectERKS0_ii -_ZNK7android6Region9operationERKNS_4RectEi -_ZNK7android6Region9operationERKS0_i -_ZNK7android6Region9operationERKS0_iii -_ZNK7android6Region9translateEii -_ZNK7android6Thread11exitPendingEv -_ZNK7android6VectorIiE10do_destroyEPvj -_ZNK7android6VectorIiE12do_constructEPvj -_ZNK7android6VectorIiE15do_move_forwardEPvPKvj -_ZNK7android6VectorIiE16do_move_backwardEPvPKvj -_ZNK7android6VectorIiE7do_copyEPvPKvj -_ZNK7android6VectorIiE8do_splatEPvPKvj -_ZNK7android6VectorINS_12ARMAssembler15branch_target_tEE10do_destroyEPvj -_ZNK7android6VectorINS_12ARMAssembler15branch_target_tEE12do_constructEPvj -_ZNK7android6VectorINS_12ARMAssembler15branch_target_tEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_12ARMAssembler15branch_target_tEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_12ARMAssembler15branch_target_tEE7do_copyEPvPKvj -_ZNK7android6VectorINS_12ARMAssembler15branch_target_tEE8do_splatEPvPKvj -_ZNK7android6VectorINS_12AssetManager10asset_pathEE10do_destroyEPvj -_ZNK7android6VectorINS_12AssetManager10asset_pathEE12do_constructEPvj -_ZNK7android6VectorINS_12AssetManager10asset_pathEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_12AssetManager10asset_pathEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_12AssetManager10asset_pathEE7do_copyEPvPKvj -_ZNK7android6VectorINS_12AssetManager10asset_pathEE8do_splatEPvPKvj -_ZNK7android6VectorINS_12ProcessState12handle_entryEE10do_destroyEPvj -_ZNK7android6VectorINS_12ProcessState12handle_entryEE12do_constructEPvj -_ZNK7android6VectorINS_12ProcessState12handle_entryEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_12ProcessState12handle_entryEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_12ProcessState12handle_entryEE7do_copyEPvPKvj -_ZNK7android6VectorINS_12ProcessState12handle_entryEE8do_splatEPvPKvj -_ZNK7android6VectorINS_15ResTable_configEE10do_destroyEPvj -_ZNK7android6VectorINS_15ResTable_configEE12do_constructEPvj -_ZNK7android6VectorINS_15ResTable_configEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_15ResTable_configEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_15ResTable_configEE7do_copyEPvPKvj -_ZNK7android6VectorINS_15ResTable_configEE8do_splatEPvPKvj -_ZNK7android6VectorINS_2spINS_12AssetManager9SharedZipEEEE10do_destroyEPvj -_ZNK7android6VectorINS_2spINS_12AssetManager9SharedZipEEEE12do_constructEPvj -_ZNK7android6VectorINS_2spINS_12AssetManager9SharedZipEEEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_2spINS_12AssetManager9SharedZipEEEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_2spINS_12AssetManager9SharedZipEEEE7do_copyEPvPKvj -_ZNK7android6VectorINS_2spINS_12AssetManager9SharedZipEEEE8do_splatEPvPKvj -_ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE10do_destroyEPvj -_ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE12do_constructEPvj -_ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE7do_copyEPvPKvj -_ZNK7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEE8do_splatEPvPKvj -_ZNK7android6VectorINS_4RectEE10do_destroyEPvj -_ZNK7android6VectorINS_4RectEE12do_constructEPvj -_ZNK7android6VectorINS_4RectEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_4RectEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_4RectEE7do_copyEPvPKvj -_ZNK7android6VectorINS_4RectEE8do_splatEPvPKvj -_ZNK7android6VectorINS_7String8EE10do_destroyEPvj -_ZNK7android6VectorINS_7String8EE12do_constructEPvj -_ZNK7android6VectorINS_7String8EE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_7String8EE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_7String8EE7do_copyEPvPKvj -_ZNK7android6VectorINS_7String8EE8do_splatEPvPKvj -_ZNK7android6VectorINS_8BpBinder8ObituaryEE10do_destroyEPvj -_ZNK7android6VectorINS_8BpBinder8ObituaryEE12do_constructEPvj -_ZNK7android6VectorINS_8BpBinder8ObituaryEE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_8BpBinder8ObituaryEE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_8BpBinder8ObituaryEE7do_copyEPvPKvj -_ZNK7android6VectorINS_8BpBinder8ObituaryEE8do_splatEPvPKvj -_ZNK7android6VectorINS_8String16EE10do_destroyEPvj -_ZNK7android6VectorINS_8String16EE12do_constructEPvj -_ZNK7android6VectorINS_8String16EE15do_move_forwardEPvPKvj -_ZNK7android6VectorINS_8String16EE16do_move_backwardEPvPKvj -_ZNK7android6VectorINS_8String16EE7do_copyEPvPKvj -_ZNK7android6VectorINS_8String16EE8do_splatEPvPKvj -_ZNK7android6VectorIPKNS_13ResTable_typeEE10do_destroyEPvj -_ZNK7android6VectorIPKNS_13ResTable_typeEE12do_constructEPvj -_ZNK7android6VectorIPKNS_13ResTable_typeEE15do_move_forwardEPvPKvj -_ZNK7android6VectorIPKNS_13ResTable_typeEE16do_move_backwardEPvPKvj -_ZNK7android6VectorIPKNS_13ResTable_typeEE7do_copyEPvPKvj -_ZNK7android6VectorIPKNS_13ResTable_typeEE8do_splatEPvPKvj -_ZNK7android6VectorIPNS_7BBinderEE10do_destroyEPvj -_ZNK7android6VectorIPNS_7BBinderEE12do_constructEPvj -_ZNK7android6VectorIPNS_7BBinderEE15do_move_forwardEPvPKvj -_ZNK7android6VectorIPNS_7BBinderEE16do_move_backwardEPvPKvj -_ZNK7android6VectorIPNS_7BBinderEE7do_copyEPvPKvj -_ZNK7android6VectorIPNS_7BBinderEE8do_splatEPvPKvj -_ZNK7android6VectorIPNS_7RefBase12weakref_typeEE10do_destroyEPvj -_ZNK7android6VectorIPNS_7RefBase12weakref_typeEE12do_constructEPvj -_ZNK7android6VectorIPNS_7RefBase12weakref_typeEE15do_move_forwardEPvPKvj -_ZNK7android6VectorIPNS_7RefBase12weakref_typeEE16do_move_backwardEPvPKvj -_ZNK7android6VectorIPNS_7RefBase12weakref_typeEE7do_copyEPvPKvj -_ZNK7android6VectorIPNS_7RefBase12weakref_typeEE8do_splatEPvPKvj -_ZNK7android6VectorIPNS_8ResTable12PackageGroupEE10do_destroyEPvj -_ZNK7android6VectorIPNS_8ResTable12PackageGroupEE12do_constructEPvj -_ZNK7android6VectorIPNS_8ResTable12PackageGroupEE15do_move_forwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable12PackageGroupEE16do_move_backwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable12PackageGroupEE7do_copyEPvPKvj -_ZNK7android6VectorIPNS_8ResTable12PackageGroupEE8do_splatEPvPKvj -_ZNK7android6VectorIPNS_8ResTable4TypeEE10do_destroyEPvj -_ZNK7android6VectorIPNS_8ResTable4TypeEE12do_constructEPvj -_ZNK7android6VectorIPNS_8ResTable4TypeEE15do_move_forwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable4TypeEE16do_move_backwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable4TypeEE7do_copyEPvPKvj -_ZNK7android6VectorIPNS_8ResTable4TypeEE8do_splatEPvPKvj -_ZNK7android6VectorIPNS_8ResTable6HeaderEE10do_destroyEPvj -_ZNK7android6VectorIPNS_8ResTable6HeaderEE12do_constructEPvj -_ZNK7android6VectorIPNS_8ResTable6HeaderEE15do_move_forwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable6HeaderEE16do_move_backwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable6HeaderEE7do_copyEPvPKvj -_ZNK7android6VectorIPNS_8ResTable6HeaderEE8do_splatEPvPKvj -_ZNK7android6VectorIPNS_8ResTable7PackageEE10do_destroyEPvj -_ZNK7android6VectorIPNS_8ResTable7PackageEE12do_constructEPvj -_ZNK7android6VectorIPNS_8ResTable7PackageEE15do_move_forwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable7PackageEE16do_move_backwardEPvPKvj -_ZNK7android6VectorIPNS_8ResTable7PackageEE7do_copyEPvPKvj -_ZNK7android6VectorIPNS_8ResTable7PackageEE8do_splatEPvPKvj -_ZNK7android7BBinder10findObjectEPKv -_ZNK7android7BBinder13isBinderAliveEv -_ZNK7android7BBinder22getInterfaceDescriptorEv -_ZNK7android7IBinder13checkSubclassEPKv -_ZNK7android7IMemory11fastPointerERKNS_2spINS_7IBinderEEEl -_ZNK7android7IMemory22getInterfaceDescriptorEv -_ZNK7android7IMemory4sizeEv -_ZNK7android7IMemory6offsetEv -_ZNK7android7IMemory7pointerEv -_ZNK7android7Overlay12getHandleRefEv -_ZNK7android7Overlay14getBufferCountEv -_ZNK7android7Overlay14getWidthStrideEv -_ZNK7android7Overlay15getHeightStrideEv -_ZNK7android7Overlay8getWidthEv -_ZNK7android7Overlay9getFormatEv -_ZNK7android7Overlay9getHeightEv -_ZNK7android7Overlay9getStatusEv -_ZNK7android7RefBase10createWeakEPKv -_ZNK7android7RefBase11getWeakRefsEv -_ZNK7android7RefBase12weakref_type12getWeakCountEv -_ZNK7android7RefBase12weakref_type7refBaseEv -_ZNK7android7RefBase12weakref_type9printRefsEv -_ZNK7android7RefBase14forceIncStrongEPKv -_ZNK7android7RefBase14getStrongCountEv -_ZNK7android7RefBase9decStrongEPKv -_ZNK7android7RefBase9incStrongEPKv -_ZNK7android7String810getPathDirEv -_ZNK7android7String810getUtf32AtEjPj -_ZNK7android7String811getBasePathEv -_ZNK7android7String811getPathLeafEv -_ZNK7android7String814find_extensionEv -_ZNK7android7String814getUtf32LengthEv -_ZNK7android7String816getPathExtensionEv -_ZNK7android7String84findEPKcj -_ZNK7android7String88getUtf32EPjj -_ZNK7android7String88walkPathEPS0_ -_ZNK7android8Assembly4baseEv -_ZNK7android8Assembly4sizeEv -_ZNK7android8Assembly9decStrongEPKv -_ZNK7android8Assembly9incStrongEPKv -_ZNK7android8BpBinder10findObjectEPKv -_ZNK7android8BpBinder13isBinderAliveEv -_ZNK7android8BpBinder13ObjectManager4findEPKv -_ZNK7android8BpBinder18isDescriptorCachedEv -_ZNK7android8BpBinder22getInterfaceDescriptorEv -_ZNK7android8BpMemory9getMemoryEPlPj -_ZNK7android8EventHub10errorCheckEv -_ZNK7android8EventHub10hasKeycodeEPNS0_8device_tEi -_ZNK7android8EventHub13getDeviceNameEi -_ZNK7android8EventHub14getSwitchStateEi -_ZNK7android8EventHub14getSwitchStateEii -_ZNK7android8EventHub15getAbsoluteInfoEiiPiS1_S1_S1_ -_ZNK7android8EventHub15getKeycodeStateEi -_ZNK7android8EventHub15getKeycodeStateEii -_ZNK7android8EventHub16getDeviceClassesEi -_ZNK7android8EventHub16getScancodeStateEi -_ZNK7android8EventHub16getScancodeStateEii -_ZNK7android8EventHub17scancodeToKeycodeEiiPiPj -_ZNK7android8EventHub9getDeviceEi -_ZNK7android8IOverlay22getInterfaceDescriptorEv -_ZNK7android8ResTable10getLocalesEPNS_6VectorINS_7String8EEE -_ZNK7android8ResTable11getResourceEjPNS_9Res_valueEbPjPNS_15ResTable_configE -_ZNK7android8ResTable12getBagLockedEjPPKNS0_9bag_entryEPj -_ZNK7android8ResTable13getParametersEPNS_15ResTable_configE -_ZNK7android8ResTable13getTableCountEv -_ZNK7android8ResTable13stringToValueEPNS_9Res_valueEPNS_8String16EPKtjbbjPKS3_S8_PNS0_8AccessorEPvjb -_ZNK7android8ResTable14getTableCookieEj -_ZNK7android8ResTable15getResourceNameEjPNS0_13resource_nameE -_ZNK7android8ResTable16getBasePackageIdEj -_ZNK7android8ResTable16resolveReferenceEPNS_9Res_valueElPjS3_PNS_15ResTable_configE -_ZNK7android8ResTable17getConfigurationsEPNS_6VectorINS_15ResTable_configEEE -_ZNK7android8ResTable17identifierForNameEPKtjS2_jS2_jPj -_ZNK7android8ResTable18getBasePackageNameEj -_ZNK7android8ResTable19getBasePackageCountEv -_ZNK7android8ResTable19getTableStringBlockEj -_ZNK7android8ResTable4lockEv -_ZNK7android8ResTable5Theme12getAttributeEjPNS_9Res_valueEPj -_ZNK7android8ResTable5Theme25resolveAttributeReferenceEPNS_9Res_valueElPjS4_PNS_15ResTable_configE -_ZNK7android8ResTable5Theme9dumpToLogEv -_ZNK7android8ResTable6unlockEv -_ZNK7android8ResTable7lockBagEjPPKNS0_9bag_entryE -_ZNK7android8ResTable8getEntryEPKNS0_7PackageEiiPKNS_15ResTable_configEPPKNS_13ResTable_typeEPPKNS_14ResTable_entryEPPKNS0_4TypeE -_ZNK7android8ResTable8getErrorEv -_ZNK7android8ResTable9unlockBagEPKNS0_9bag_entryE -_ZNK7android8String1610startsWithEPKt -_ZNK7android8String1610startsWithERKS0_ -_ZNK7android8String168findLastEt -_ZNK7android8String169findFirstEt -_ZNK7android9CallStack19toStringSingleLevelEPKci -_ZNK7android9CallStack4dumpEPKc -_ZNK7android9CallStack8toStringEPKc -_ZNK7android9CallStackeqERKS0_ -_ZNK7android9CallStackgeERKS0_ -_ZNK7android9CallStackgtERKS0_ -_ZNK7android9CallStackixEi -_ZNK7android9CallStackleERKS0_ -_ZNK7android9CallStackltERKS0_ -_ZNK7android9CallStackneERKS0_ -_ZNK7android9CodeCache6lookupERKNS_15AssemblyKeyBaseE -_ZNK7android9StopWatch11elapsedTimeEv -_ZNK7android9StopWatch4nameEv -_ZNK7android9ZipFileRO12entryToIndexEPv -_ZNK7android9ZipFileRO12getEntryInfoEPvPiPlS3_S3_S3_S3_ -_ZNK7android9ZipFileRO15findEntryByNameEPKc -_ZNK7android9ZipFileRO15uncompressEntryEPvi -_ZNK7android9ZipFileRO15uncompressEntryEPvS1_ -_ZNK7android9ZipFileRO16findEntryByIndexEi -_ZNK7android9ZipFileRO16getEntryFileNameEPvPci -_ZNK7android9ZipFileRO18createEntryFileMapEPv -_ZNK9type_info4nameEv -_ZNK9type_info6beforeERKS_ -_ZNK9type_infoeqERKS_ -_ZNK9type_infoneERKS_ -_Znwj -_ZnwjRKSt9nothrow_t -_ZSt7nothrow -_ZTCN7android10AllocationE0_NS_10IInterfaceE -_ZTCN7android10AllocationE0_NS_10MemoryBaseE -_ZTCN7android10AllocationE0_NS_11BnInterfaceINS_7IMemoryEEE -_ZTCN7android10AllocationE0_NS_7IMemoryE -_ZTCN7android10AllocationE0_NS_8BnMemoryE -_ZTCN7android10AllocationE4_NS_7BBinderE -_ZTCN7android10AllocationE4_NS_7IBinderE -_ZTCN7android10MemoryBaseE0_NS_10IInterfaceE -_ZTCN7android10MemoryBaseE0_NS_11BnInterfaceINS_7IMemoryEEE -_ZTCN7android10MemoryBaseE0_NS_7IMemoryE -_ZTCN7android10MemoryBaseE0_NS_8BnMemoryE -_ZTCN7android10MemoryBaseE4_NS_7BBinderE -_ZTCN7android10MemoryBaseE4_NS_7IBinderE -_ZTCN7android10PoolThreadE0_NS_6ThreadE -_ZTCN7android11BnInterfaceINS_11IMemoryHeapEEE0_NS_10IInterfaceE -_ZTCN7android11BnInterfaceINS_11IMemoryHeapEEE0_S1_ -_ZTCN7android11BnInterfaceINS_11IMemoryHeapEEE4_NS_7BBinderE -_ZTCN7android11BnInterfaceINS_11IMemoryHeapEEE4_NS_7IBinderE -_ZTCN7android11BnInterfaceINS_15IServiceManagerEEE0_NS_10IInterfaceE -_ZTCN7android11BnInterfaceINS_15IServiceManagerEEE0_S1_ -_ZTCN7android11BnInterfaceINS_15IServiceManagerEEE4_NS_7BBinderE -_ZTCN7android11BnInterfaceINS_15IServiceManagerEEE4_NS_7IBinderE -_ZTCN7android11BnInterfaceINS_21IPermissionControllerEEE0_NS_10IInterfaceE -_ZTCN7android11BnInterfaceINS_21IPermissionControllerEEE0_S1_ -_ZTCN7android11BnInterfaceINS_21IPermissionControllerEEE4_NS_7BBinderE -_ZTCN7android11BnInterfaceINS_21IPermissionControllerEEE4_NS_7IBinderE -_ZTCN7android11BnInterfaceINS_7IMemoryEEE0_NS_10IInterfaceE -_ZTCN7android11BnInterfaceINS_7IMemoryEEE0_S1_ -_ZTCN7android11BnInterfaceINS_7IMemoryEEE4_NS_7BBinderE -_ZTCN7android11BnInterfaceINS_7IMemoryEEE4_NS_7IBinderE -_ZTCN7android11BnInterfaceINS_8IOverlayEEE0_NS_10IInterfaceE -_ZTCN7android11BnInterfaceINS_8IOverlayEEE0_S1_ -_ZTCN7android11BnInterfaceINS_8IOverlayEEE4_NS_7BBinderE -_ZTCN7android11BnInterfaceINS_8IOverlayEEE4_NS_7IBinderE -_ZTCN7android11BpInterfaceINS_11IMemoryHeapEEE0_NS_10IInterfaceE -_ZTCN7android11BpInterfaceINS_11IMemoryHeapEEE0_S1_ -_ZTCN7android11BpInterfaceINS_11IMemoryHeapEEE4_NS_9BpRefBaseE -_ZTCN7android11BpInterfaceINS_15IServiceManagerEEE0_NS_10IInterfaceE -_ZTCN7android11BpInterfaceINS_15IServiceManagerEEE0_S1_ -_ZTCN7android11BpInterfaceINS_15IServiceManagerEEE4_NS_9BpRefBaseE -_ZTCN7android11BpInterfaceINS_21IPermissionControllerEEE0_NS_10IInterfaceE -_ZTCN7android11BpInterfaceINS_21IPermissionControllerEEE0_S1_ -_ZTCN7android11BpInterfaceINS_21IPermissionControllerEEE4_NS_9BpRefBaseE -_ZTCN7android11BpInterfaceINS_7IMemoryEEE0_NS_10IInterfaceE -_ZTCN7android11BpInterfaceINS_7IMemoryEEE0_S1_ -_ZTCN7android11BpInterfaceINS_7IMemoryEEE4_NS_9BpRefBaseE -_ZTCN7android11BpInterfaceINS_8IOverlayEEE0_NS_10IInterfaceE -_ZTCN7android11BpInterfaceINS_8IOverlayEEE0_S1_ -_ZTCN7android11BpInterfaceINS_8IOverlayEEE4_NS_9BpRefBaseE -_ZTCN7android11IMemoryHeapE0_NS_10IInterfaceE -_ZTCN7android12BnMemoryHeapE0_NS_10IInterfaceE -_ZTCN7android12BnMemoryHeapE0_NS_11BnInterfaceINS_11IMemoryHeapEEE -_ZTCN7android12BnMemoryHeapE0_NS_11IMemoryHeapE -_ZTCN7android12BnMemoryHeapE4_NS_7BBinderE -_ZTCN7android12BnMemoryHeapE4_NS_7IBinderE -_ZTCN7android12BpMemoryHeapE0_NS_10IInterfaceE -_ZTCN7android12BpMemoryHeapE0_NS_11BpInterfaceINS_11IMemoryHeapEEE -_ZTCN7android12BpMemoryHeapE0_NS_11IMemoryHeapE -_ZTCN7android12BpMemoryHeapE4_NS_9BpRefBaseE -_ZTCN7android14MemoryHeapBaseE28_NS_10IInterfaceE -_ZTCN7android14MemoryHeapBaseE28_NS_11BnInterfaceINS_11IMemoryHeapEEE -_ZTCN7android14MemoryHeapBaseE28_NS_11IMemoryHeapE -_ZTCN7android14MemoryHeapBaseE28_NS_12BnMemoryHeapE -_ZTCN7android14MemoryHeapBaseE32_NS_7BBinderE -_ZTCN7android14MemoryHeapBaseE32_NS_7IBinderE -_ZTCN7android14MemoryHeapPmem10MemoryPmemE0_NS_10IInterfaceE -_ZTCN7android14MemoryHeapPmem10MemoryPmemE0_NS_11BnInterfaceINS_7IMemoryEEE -_ZTCN7android14MemoryHeapPmem10MemoryPmemE0_NS_7IMemoryE -_ZTCN7android14MemoryHeapPmem10MemoryPmemE0_NS_8BnMemoryE -_ZTCN7android14MemoryHeapPmem10MemoryPmemE4_NS_7BBinderE -_ZTCN7android14MemoryHeapPmem10MemoryPmemE4_NS_7IBinderE -_ZTCN7android14MemoryHeapPmemE0_NS_14MemoryHeapBaseE -_ZTCN7android14MemoryHeapPmemE56_NS_10IInterfaceE -_ZTCN7android14MemoryHeapPmemE56_NS_11BnInterfaceINS_11IMemoryHeapEEE -_ZTCN7android14MemoryHeapPmemE56_NS_11IMemoryHeapE -_ZTCN7android14MemoryHeapPmemE56_NS_12BnMemoryHeapE -_ZTCN7android14MemoryHeapPmemE60_NS_7BBinderE -_ZTCN7android14MemoryHeapPmemE60_NS_7IBinderE -_ZTCN7android15IServiceManagerE0_NS_10IInterfaceE -_ZTCN7android15SubRegionMemoryE0_NS_10IInterfaceE -_ZTCN7android15SubRegionMemoryE0_NS_11BnInterfaceINS_7IMemoryEEE -_ZTCN7android15SubRegionMemoryE0_NS_14MemoryHeapPmem10MemoryPmemE -_ZTCN7android15SubRegionMemoryE0_NS_7IMemoryE -_ZTCN7android15SubRegionMemoryE0_NS_8BnMemoryE -_ZTCN7android15SubRegionMemoryE4_NS_7BBinderE -_ZTCN7android15SubRegionMemoryE4_NS_7IBinderE -_ZTCN7android16BnServiceManagerE0_NS_10IInterfaceE -_ZTCN7android16BnServiceManagerE0_NS_11BnInterfaceINS_15IServiceManagerEEE -_ZTCN7android16BnServiceManagerE0_NS_15IServiceManagerE -_ZTCN7android16BnServiceManagerE4_NS_7BBinderE -_ZTCN7android16BnServiceManagerE4_NS_7IBinderE -_ZTCN7android16BpServiceManagerE0_NS_10IInterfaceE -_ZTCN7android16BpServiceManagerE0_NS_11BpInterfaceINS_15IServiceManagerEEE -_ZTCN7android16BpServiceManagerE0_NS_15IServiceManagerE -_ZTCN7android16BpServiceManagerE4_NS_9BpRefBaseE -_ZTCN7android21IPermissionControllerE0_NS_10IInterfaceE -_ZTCN7android22BnPermissionControllerE0_NS_10IInterfaceE -_ZTCN7android22BnPermissionControllerE0_NS_11BnInterfaceINS_21IPermissionControllerEEE -_ZTCN7android22BnPermissionControllerE0_NS_21IPermissionControllerE -_ZTCN7android22BnPermissionControllerE4_NS_7BBinderE -_ZTCN7android22BnPermissionControllerE4_NS_7IBinderE -_ZTCN7android22BpPermissionControllerE0_NS_10IInterfaceE -_ZTCN7android22BpPermissionControllerE0_NS_11BpInterfaceINS_21IPermissionControllerEEE -_ZTCN7android22BpPermissionControllerE0_NS_21IPermissionControllerE -_ZTCN7android22BpPermissionControllerE4_NS_9BpRefBaseE -_ZTCN7android7BBinderE0_NS_7IBinderE -_ZTCN7android7IMemoryE0_NS_10IInterfaceE -_ZTCN7android8BnMemoryE0_NS_10IInterfaceE -_ZTCN7android8BnMemoryE0_NS_11BnInterfaceINS_7IMemoryEEE -_ZTCN7android8BnMemoryE0_NS_7IMemoryE -_ZTCN7android8BnMemoryE4_NS_7BBinderE -_ZTCN7android8BnMemoryE4_NS_7IBinderE -_ZTCN7android8BpBinderE0_NS_7IBinderE -_ZTCN7android8BpMemoryE0_NS_10IInterfaceE -_ZTCN7android8BpMemoryE0_NS_11BpInterfaceINS_7IMemoryEEE -_ZTCN7android8BpMemoryE0_NS_7IMemoryE -_ZTCN7android8BpMemoryE4_NS_9BpRefBaseE -_ZTCN7android8IOverlayE0_NS_10IInterfaceE -_ZTCN7android9BnOverlayE0_NS_10IInterfaceE -_ZTCN7android9BnOverlayE0_NS_11BnInterfaceINS_8IOverlayEEE -_ZTCN7android9BnOverlayE0_NS_8IOverlayE -_ZTCN7android9BnOverlayE4_NS_7BBinderE -_ZTCN7android9BnOverlayE4_NS_7IBinderE -_ZTCN7android9BpOverlayE0_NS_10IInterfaceE -_ZTCN7android9BpOverlayE0_NS_11BpInterfaceINS_8IOverlayEEE -_ZTCN7android9BpOverlayE0_NS_8IOverlayE -_ZTCN7android9BpOverlayE4_NS_9BpRefBaseE -_ZTCN7android9HeapCacheE0_NS_7IBinder14DeathRecipientE -_ZThn4_N7android10AllocationD0Ev -_ZThn4_N7android10AllocationD1Ev -_ZThn4_N7android10MemoryBaseD0Ev -_ZThn4_N7android10MemoryBaseD1Ev -_ZThn4_N7android12BnMemoryHeap10onTransactEjRKNS_6ParcelEPS1_j -_ZThn4_N7android12BnMemoryHeapD0Ev -_ZThn4_N7android12BnMemoryHeapD1Ev -_ZThn4_N7android12BpMemoryHeapD0Ev -_ZThn4_N7android12BpMemoryHeapD1Ev -_ZThn4_N7android14MemoryHeapPmem10MemoryPmemD0Ev -_ZThn4_N7android14MemoryHeapPmem10MemoryPmemD1Ev -_ZThn4_N7android15SubRegionMemoryD0Ev -_ZThn4_N7android15SubRegionMemoryD1Ev -_ZThn4_N7android16BnServiceManager10onTransactEjRKNS_6ParcelEPS1_j -_ZThn4_N7android22BnPermissionController10onTransactEjRKNS_6ParcelEPS1_j -_ZThn4_N7android8BnMemory10onTransactEjRKNS_6ParcelEPS1_j -_ZThn4_N7android8BnMemoryD0Ev -_ZThn4_N7android8BnMemoryD1Ev -_ZThn4_N7android8BpMemoryD0Ev -_ZThn4_N7android8BpMemoryD1Ev -_ZThn4_N7android9BnOverlay10onTransactEjRKNS_6ParcelEPS1_j -_ZTTN7android10AllocationE -_ZTTN7android10IInterfaceE -_ZTTN7android10MemoryBaseE -_ZTTN7android10PoolThreadE -_ZTTN7android11BnInterfaceINS_11IMemoryHeapEEE -_ZTTN7android11BnInterfaceINS_15IServiceManagerEEE -_ZTTN7android11BnInterfaceINS_21IPermissionControllerEEE -_ZTTN7android11BnInterfaceINS_7IMemoryEEE -_ZTTN7android11BnInterfaceINS_8IOverlayEEE -_ZTTN7android11BpInterfaceINS_11IMemoryHeapEEE -_ZTTN7android11BpInterfaceINS_15IServiceManagerEEE -_ZTTN7android11BpInterfaceINS_21IPermissionControllerEEE -_ZTTN7android11BpInterfaceINS_7IMemoryEEE -_ZTTN7android11BpInterfaceINS_8IOverlayEEE -_ZTTN7android11IMemoryHeapE -_ZTTN7android12BnMemoryHeapE -_ZTTN7android12BpMemoryHeapE -_ZTTN7android12ProcessStateE -_ZTTN7android14MemoryHeapBaseE -_ZTTN7android14MemoryHeapPmem10MemoryPmemE -_ZTTN7android14MemoryHeapPmemE -_ZTTN7android15IServiceManagerE -_ZTTN7android15SubRegionMemoryE -_ZTTN7android16BnServiceManagerE -_ZTTN7android16BpServiceManagerE -_ZTTN7android21IPermissionControllerE -_ZTTN7android22BnPermissionControllerE -_ZTTN7android22BpPermissionControllerE -_ZTTN7android6ThreadE -_ZTTN7android7BBinderE -_ZTTN7android7IBinder14DeathRecipientE -_ZTTN7android7IBinderE -_ZTTN7android7IMemoryE -_ZTTN7android7OverlayE -_ZTTN7android8BnMemoryE -_ZTTN7android8BpBinderE -_ZTTN7android8BpMemoryE -_ZTTN7android8IOverlayE -_ZTTN7android9BnOverlayE -_ZTTN7android9BpOverlayE -_ZTTN7android9BpRefBaseE -_ZTTN7android9HeapCacheE -_ZTv0_n12_N7android10AllocationD0Ev -_ZTv0_n12_N7android10AllocationD1Ev -_ZTv0_n12_N7android10IInterfaceD0Ev -_ZTv0_n12_N7android10IInterfaceD1Ev -_ZTv0_n12_N7android10MemoryBaseD0Ev -_ZTv0_n12_N7android10MemoryBaseD1Ev -_ZTv0_n12_N7android10PoolThreadD0Ev -_ZTv0_n12_N7android10PoolThreadD1Ev -_ZTv0_n12_N7android11BnInterfaceINS_11IMemoryHeapEED0Ev -_ZTv0_n12_N7android11BnInterfaceINS_11IMemoryHeapEED1Ev -_ZTv0_n12_N7android11BnInterfaceINS_15IServiceManagerEED0Ev -_ZTv0_n12_N7android11BnInterfaceINS_15IServiceManagerEED1Ev -_ZTv0_n12_N7android11BnInterfaceINS_21IPermissionControllerEED0Ev -_ZTv0_n12_N7android11BnInterfaceINS_21IPermissionControllerEED1Ev -_ZTv0_n12_N7android11BnInterfaceINS_7IMemoryEED0Ev -_ZTv0_n12_N7android11BnInterfaceINS_7IMemoryEED1Ev -_ZTv0_n12_N7android11BnInterfaceINS_8IOverlayEED0Ev -_ZTv0_n12_N7android11BnInterfaceINS_8IOverlayEED1Ev -_ZTv0_n12_N7android11BpInterfaceINS_11IMemoryHeapEED0Ev -_ZTv0_n12_N7android11BpInterfaceINS_11IMemoryHeapEED1Ev -_ZTv0_n12_N7android11BpInterfaceINS_15IServiceManagerEED0Ev -_ZTv0_n12_N7android11BpInterfaceINS_15IServiceManagerEED1Ev -_ZTv0_n12_N7android11BpInterfaceINS_21IPermissionControllerEED0Ev -_ZTv0_n12_N7android11BpInterfaceINS_21IPermissionControllerEED1Ev -_ZTv0_n12_N7android11BpInterfaceINS_7IMemoryEED0Ev -_ZTv0_n12_N7android11BpInterfaceINS_7IMemoryEED1Ev -_ZTv0_n12_N7android11BpInterfaceINS_8IOverlayEED0Ev -_ZTv0_n12_N7android11BpInterfaceINS_8IOverlayEED1Ev -_ZTv0_n12_N7android11IMemoryHeapD0Ev -_ZTv0_n12_N7android11IMemoryHeapD1Ev -_ZTv0_n12_N7android12BnMemoryHeapD0Ev -_ZTv0_n12_N7android12BnMemoryHeapD1Ev -_ZTv0_n12_N7android12BpMemoryHeapD0Ev -_ZTv0_n12_N7android12BpMemoryHeapD1Ev -_ZTv0_n12_N7android12ProcessStateD0Ev -_ZTv0_n12_N7android12ProcessStateD1Ev -_ZTv0_n12_N7android14MemoryHeapBaseD0Ev -_ZTv0_n12_N7android14MemoryHeapBaseD1Ev -_ZTv0_n12_N7android14MemoryHeapPmem10MemoryPmemD0Ev -_ZTv0_n12_N7android14MemoryHeapPmem10MemoryPmemD1Ev -_ZTv0_n12_N7android14MemoryHeapPmemD0Ev -_ZTv0_n12_N7android14MemoryHeapPmemD1Ev -_ZTv0_n12_N7android15IServiceManagerD0Ev -_ZTv0_n12_N7android15IServiceManagerD1Ev -_ZTv0_n12_N7android15SubRegionMemoryD0Ev -_ZTv0_n12_N7android15SubRegionMemoryD1Ev -_ZTv0_n12_N7android16BnServiceManagerD0Ev -_ZTv0_n12_N7android16BnServiceManagerD1Ev -_ZTv0_n12_N7android16BpServiceManagerD0Ev -_ZTv0_n12_N7android16BpServiceManagerD1Ev -_ZTv0_n12_N7android21IPermissionControllerD0Ev -_ZTv0_n12_N7android21IPermissionControllerD1Ev -_ZTv0_n12_N7android22BnPermissionControllerD0Ev -_ZTv0_n12_N7android22BnPermissionControllerD1Ev -_ZTv0_n12_N7android22BpPermissionControllerD0Ev -_ZTv0_n12_N7android22BpPermissionControllerD1Ev -_ZTv0_n12_N7android6ThreadD0Ev -_ZTv0_n12_N7android6ThreadD1Ev -_ZTv0_n12_N7android7BBinderD0Ev -_ZTv0_n12_N7android7BBinderD1Ev -_ZTv0_n12_N7android7IBinder14DeathRecipientD0Ev -_ZTv0_n12_N7android7IBinder14DeathRecipientD1Ev -_ZTv0_n12_N7android7IBinderD0Ev -_ZTv0_n12_N7android7IBinderD1Ev -_ZTv0_n12_N7android7IMemoryD0Ev -_ZTv0_n12_N7android7IMemoryD1Ev -_ZTv0_n12_N7android7OverlayD0Ev -_ZTv0_n12_N7android7OverlayD1Ev -_ZTv0_n12_N7android8BnMemoryD0Ev -_ZTv0_n12_N7android8BnMemoryD1Ev -_ZTv0_n12_N7android8BpBinderD0Ev -_ZTv0_n12_N7android8BpBinderD1Ev -_ZTv0_n12_N7android8BpMemoryD0Ev -_ZTv0_n12_N7android8BpMemoryD1Ev -_ZTv0_n12_N7android8IOverlayD0Ev -_ZTv0_n12_N7android8IOverlayD1Ev -_ZTv0_n12_N7android9BnOverlayD0Ev -_ZTv0_n12_N7android9BnOverlayD1Ev -_ZTv0_n12_N7android9BpOverlayD0Ev -_ZTv0_n12_N7android9BpOverlayD1Ev -_ZTv0_n12_N7android9BpRefBaseD0Ev -_ZTv0_n12_N7android9BpRefBaseD1Ev -_ZTv0_n12_N7android9HeapCacheD0Ev -_ZTv0_n12_N7android9HeapCacheD1Ev -_ZTv0_n16_N7android14MemoryHeapBaseD0Ev -_ZTv0_n16_N7android14MemoryHeapBaseD1Ev -_ZTv0_n16_N7android14MemoryHeapPmemD0Ev -_ZTv0_n16_N7android14MemoryHeapPmemD1Ev -_ZTv0_n16_N7android8BpBinder10onFirstRefEv -_ZTv0_n16_N7android9BpRefBase10onFirstRefEv -_ZTv0_n20_N7android8BpBinder15onLastStrongRefEPKv -_ZTv0_n20_N7android9BpRefBase15onLastStrongRefEPKv -_ZTv0_n24_N7android8BpBinder20onIncStrongAttemptedEjPKv -_ZTv0_n24_N7android9BpRefBase20onIncStrongAttemptedEjPKv -_ZTv0_n28_NK7android14MemoryHeapBase9getHeapIDEv -_ZTv0_n32_NK7android14MemoryHeapBase7getBaseEv -_ZTv0_n36_NK7android14MemoryHeapBase7getSizeEv -_ZTv0_n40_NK7android14MemoryHeapBase8getFlagsEv -_ZTV9type_info -_ZTvn4_n16_N7android14MemoryHeapBaseD0Ev -_ZTvn4_n16_N7android14MemoryHeapBaseD1Ev -_ZTvn4_n16_N7android14MemoryHeapPmemD0Ev -_ZTvn4_n16_N7android14MemoryHeapPmemD1Ev -_ZTVN7android10AllocationE -_ZTVN7android10_FileAssetE -_ZTVN7android10IInterfaceE -_ZTVN7android10MemoryBaseE -_ZTVN7android10OverlayRefE -_ZTVN7android10PermissionE -_ZTVN7android10PoolThreadE -_ZTVN7android10TextOutputE -_ZTVN7android10VectorImplE -_ZTVN7android11AssemblyKeyINS_7needs_tEEE -_ZTVN7android11BnInterfaceINS_11IMemoryHeapEEE -_ZTVN7android11BnInterfaceINS_15IServiceManagerEEE -_ZTVN7android11BnInterfaceINS_21IPermissionControllerEEE -_ZTVN7android11BnInterfaceINS_7IMemoryEEE -_ZTVN7android11BnInterfaceINS_8IOverlayEEE -_ZTVN7android11BpInterfaceINS_11IMemoryHeapEEE -_ZTVN7android11BpInterfaceINS_15IServiceManagerEEE -_ZTVN7android11BpInterfaceINS_21IPermissionControllerEEE -_ZTVN7android11BpInterfaceINS_7IMemoryEEE -_ZTVN7android11BpInterfaceINS_8IOverlayEEE -_ZTVN7android11FlattenableE -_ZTVN7android11IMemoryHeapE -_ZTVN7android11StringArrayE -_ZTVN7android12ARMAssemblerE -_ZTVN7android12AssetManager9SharedZipE -_ZTVN7android12AssetManagerE -_ZTVN7android12BnMemoryHeapE -_ZTVN7android12BpMemoryHeapE -_ZTVN7android12FdTextOutputE -_ZTVN7android12GGLAssemblerE -_ZTVN7android12MemoryDealerE -_ZTVN7android12ProcessStateE -_ZTVN7android12SortedVectorIjEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tIiNS_12KeyLayoutMap3KeyEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tINS_2wpINS_7IBinderEEENS_9HeapCache11heap_info_tEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_2wpINS_12AssetManager9SharedZipEEEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_7FileRecEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tINS_7String8ENS_9FileStateEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tINS_8String16ENS_2spINS_7IBinderEEEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tINS_9CodeCache5key_tENS2_13cache_entry_tEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tIPjPKcEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tIPK15native_handle_tNS_22GraphicBufferAllocator11alloc_rec_tEEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tIPKcPjEEEE -_ZTVN7android12SortedVectorINS_16key_value_pair_tIPKvNS_8BpBinder13ObjectManager7entry_tEEEEE -_ZTVN7android12SortedVectorINS_2wpINS_14MemoryHeapPmem10MemoryPmemEEEEE -_ZTVN7android12SortedVectorINS_8AssetDir8FileInfoEEE -_ZTVN7android13GraphicBufferE -_ZTVN7android13LogTextOutputE -_ZTVN7android14MemoryHeapBaseE -_ZTVN7android14MemoryHeapPmem10MemoryPmemE -_ZTVN7android14MemoryHeapPmemE -_ZTVN7android15AssemblyKeyBaseE -_ZTVN7android15IServiceManagerE -_ZTVN7android15region_operatorINS_4RectEE17region_rasterizerE -_ZTVN7android15SubRegionMemoryE -_ZTVN7android16BnServiceManagerE -_ZTVN7android16BpServiceManagerE -_ZTVN7android16_CompressedAssetE -_ZTVN7android16ScanlineAssemblyE -_ZTVN7android16SortedVectorImplE -_ZTVN7android17ARMAssemblerProxyE -_ZTVN7android18BufferedTextOutput11BufferStateE -_ZTVN7android18BufferedTextOutputE -_ZTVN7android21ARMAssemblerInterfaceE -_ZTVN7android21IPermissionControllerE -_ZTVN7android22BnPermissionControllerE -_ZTVN7android22BpPermissionControllerE -_ZTVN7android4ListINS_7String8EEE -_ZTVN7android5AssetE -_ZTVN7android6Region10rasterizerE -_ZTVN7android6ThreadE -_ZTVN7android6VectorIiEE -_ZTVN7android6VectorINS_12ARMAssembler15branch_target_tEEE -_ZTVN7android6VectorINS_12AssetManager10asset_pathEEE -_ZTVN7android6VectorINS_12ProcessState12handle_entryEEE -_ZTVN7android6VectorINS_15ResTable_configEEE -_ZTVN7android6VectorINS_2spINS_12AssetManager9SharedZipEEEEE -_ZTVN7android6VectorINS_2spINS_18BufferedTextOutput11BufferStateEEEEE -_ZTVN7android6VectorINS_4RectEEE -_ZTVN7android6VectorINS_7String8EEE -_ZTVN7android6VectorINS_8BpBinder8ObituaryEEE -_ZTVN7android6VectorINS_8String16EEE -_ZTVN7android6VectorIPKNS_13ResTable_typeEEE -_ZTVN7android6VectorIPNS_7BBinderEEE -_ZTVN7android6VectorIPNS_7RefBase12weakref_typeEEE -_ZTVN7android6VectorIPNS_8ResTable12PackageGroupEEE -_ZTVN7android6VectorIPNS_8ResTable4TypeEEE -_ZTVN7android6VectorIPNS_8ResTable6HeaderEEE -_ZTVN7android6VectorIPNS_8ResTable7PackageEEE -_ZTVN7android7BBinderE -_ZTVN7android7IBinder14DeathRecipientE -_ZTVN7android7IBinderE -_ZTVN7android7IMemoryE -_ZTVN7android7OverlayE -_ZTVN7android7RefBaseE -_ZTVN7android8AssemblyE -_ZTVN7android8AssetDirE -_ZTVN7android8BnMemoryE -_ZTVN7android8BpBinderE -_ZTVN7android8BpMemoryE -_ZTVN7android8EventHubE -_ZTVN7android8IOverlayE -_ZTVN7android9BnOverlayE -_ZTVN7android9BpOverlayE -_ZTVN7android9BpRefBaseE -_ZTVN7android9HeapCacheE -zygote_run_oneshot -zygote_run_wait diff --git a/project/jni/application/grafx2/AndroidAppSettings.cfg b/project/jni/application/grafx2/AndroidAppSettings.cfg new file mode 100644 index 000000000..707a446a0 --- /dev/null +++ b/project/jni/application/grafx2/AndroidAppSettings.cfg @@ -0,0 +1,36 @@ +# The application settings for Android libSDL port +AppSettingVersion=17 +LibSdlVersion=1.2 +AppName="grafx2" +AppFullName=com.grafx2 +ScreenOrientation=h +InhibitSuspend=y +AppDataDownloadUrl="!Data|data.zip" +SdlVideoResize=y +SdlVideoResizeKeepAspect=n +NeedDepthBuffer=n +SwVideoMode=y +AppUsesMouse=y +AppNeedsTwoButtonMouse=y +AppNeedsArrowKeys=n +AppNeedsTextInput=n +AppUsesJoystick=n +AppHandlesJoystickSensitivity=y +AppUsesMultitouch=n +NonBlockingSwapBuffers=n +RedefinedKeys="SPACE TAB NO_REMAP NO_REMAP RETURN ESCAPE DELETE" +AppTouchscreenKeyboardKeysAmount=0 +AppTouchscreenKeyboardKeysAmountAutoFire=0 +RedefinedKeysScreenKb="SPACE TAB PLUS MINUS RETURN ESCAPE DELETE" +StartupMenuButtonTimeout=3000 +HiddenMenuOptions='OptionalDownloadConfig' +MultiABI=n +AppVersionCode=23178101 +AppVersionName="2.3.1781.01" +CompiledLibraries="jpeg png sdl_image sdl_ttf lua" +CustomBuildScript=n +AppCflags='-DVIRT_KEY -D__ENABLE_LUA__ -std=c99' +AppLdflags='' +AppSubdirsBuild='grafx2/src' +AppCmdline='sdl' +ReadmeText='^You may press "Home" now - the data will be downloaded in background' diff --git a/project/jni/application/grafx2/AndroidData/data.zip b/project/jni/application/grafx2/AndroidData/data.zip new file mode 100644 index 000000000..b665c316c Binary files /dev/null and b/project/jni/application/grafx2/AndroidData/data.zip differ diff --git a/project/jni/application/grafx2/grafx2/src/SDLMain.h b/project/jni/application/grafx2/grafx2/src/SDLMain.h new file mode 100644 index 000000000..4683df57a --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/SDLMain.h @@ -0,0 +1,11 @@ +/* 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 new file mode 100644 index 000000000..23de8ce0f --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/SFont.c @@ -0,0 +1,224 @@ +/* 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 new file mode 100644 index 000000000..446acf4eb --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/SFont.h @@ -0,0 +1,100 @@ +/* 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 new file mode 100644 index 000000000..f30015058 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/brush.c @@ -0,0 +1,1944 @@ +/* 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 new file mode 100644 index 000000000..9682b1fed --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/brush.h @@ -0,0 +1,129 @@ +/* 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 new file mode 100644 index 000000000..405ca7537 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/brush_ops.c @@ -0,0 +1,1392 @@ +/* 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 new file mode 100644 index 000000000..5499fa466 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/buttons.c @@ -0,0 +1,5478 @@ +/* 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 new file mode 100644 index 000000000..eed881dcb --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/buttons.h @@ -0,0 +1,678 @@ +/* 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 new file mode 100644 index 000000000..6f621a638 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/buttons_effects.c @@ -0,0 +1,1259 @@ +/* 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 new file mode 100644 index 000000000..0c1bb43e5 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/const.h @@ -0,0 +1,529 @@ +/* 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 new file mode 100644 index 000000000..717232fd5 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/engine.c @@ -0,0 +1,3499 @@ +/* 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 new file mode 100644 index 000000000..b9dd23c92 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/errors.h @@ -0,0 +1,54 @@ +/* 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 new file mode 100644 index 000000000..03fe76748 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/factory.c @@ -0,0 +1,1882 @@ +/* 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 new file mode 100644 index 000000000..3a1a54f5e --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/factory.h @@ -0,0 +1,13 @@ +/* vim:expandtab:ts=2 sw=2: +*/ +void Button_Brush_Factory(void); +void Repeat_script(void); + +/// Lua scripts bound to shortcut keys. +extern char * Bound_script[10]; + +/// +/// Run a lua script linked to a shortcut, 0-9. +/// Before: Cursor hidden +/// After: Cursor shown +void Run_numbered_script(byte index); diff --git a/project/jni/application/grafx2/grafx2/src/fileformats.c b/project/jni/application/grafx2/grafx2/src/fileformats.c new file mode 100644 index 000000000..4f6b1d1b0 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/fileformats.c @@ -0,0 +1,4091 @@ +/* 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 new file mode 100644 index 000000000..f0eec93cf --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/filesel.c @@ -0,0 +1,2037 @@ +/* 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 new file mode 100644 index 000000000..979783aad --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/global.h @@ -0,0 +1,1037 @@ +/* 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 new file mode 100644 index 000000000..06c99716a --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/graph.c @@ -0,0 +1,2994 @@ +/* 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 new file mode 100644 index 000000000..70c49d3c3 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/graph.h @@ -0,0 +1,123 @@ +/* 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 new file mode 100644 index 000000000..4d5068de0 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/haiku.h @@ -0,0 +1,8 @@ +#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 new file mode 100644 index 000000000..34eec25c4 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/help.c @@ -0,0 +1,863 @@ +/* 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 new file mode 100644 index 000000000..42cd7627b --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/help.h @@ -0,0 +1,66 @@ +/* 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 new file mode 100644 index 000000000..6ed351bc5 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/helpfile.h @@ -0,0 +1,2966 @@ +/* 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 new file mode 100644 index 000000000..bdf65ba4e --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/hotkeys.c @@ -0,0 +1,1846 @@ +/* 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 new file mode 100644 index 000000000..38006841e --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/hotkeys.h @@ -0,0 +1,60 @@ +/* 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 new file mode 100644 index 000000000..8be7e423b --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/init.c @@ -0,0 +1,2976 @@ +/* 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 new file mode 100644 index 000000000..3f64ae7a5 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/init.h @@ -0,0 +1,56 @@ +/* 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 new file mode 100644 index 000000000..d9e5273d0 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/input.c @@ -0,0 +1,1103 @@ +/* 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 new file mode 100644 index 000000000..9ee0d7e76 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/input.h @@ -0,0 +1,66 @@ +/* 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 new file mode 100644 index 000000000..bda37459d --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/io.c @@ -0,0 +1,498 @@ +/* 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 new file mode 100644 index 000000000..042ef3379 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/io.h @@ -0,0 +1,125 @@ +/* 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 new file mode 100644 index 000000000..584d20fb7 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/keyboard.c @@ -0,0 +1,713 @@ +/* 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 new file mode 100644 index 000000000..c2dec3f51 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/keyboard.h @@ -0,0 +1,77 @@ +/* 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 new file mode 100644 index 000000000..6b8abfb92 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/layers.c @@ -0,0 +1,391 @@ +/* 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 new file mode 100644 index 000000000..9bf83f491 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/layers.h @@ -0,0 +1,35 @@ +/* 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 new file mode 100644 index 000000000..4dd868306 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/libraw2crtc.c @@ -0,0 +1,190 @@ +/* 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 new file mode 100644 index 000000000..f689043c4 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/libraw2crtc.h @@ -0,0 +1,14 @@ +/* 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 new file mode 100644 index 000000000..d2a06de42 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/loadsave.c @@ -0,0 +1,1587 @@ +/* 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 new file mode 100644 index 000000000..8fcd6376d --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/loadsave.h @@ -0,0 +1,259 @@ +/* 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 new file mode 100644 index 000000000..08685850f --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/main.c @@ -0,0 +1,966 @@ +/* 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 new file mode 100644 index 000000000..f69531615 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/misc.c @@ -0,0 +1,880 @@ +/* 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 new file mode 100644 index 000000000..7715cea19 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/miscfileformats.c @@ -0,0 +1,2701 @@ +/* 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 new file mode 100644 index 000000000..0fee330bf --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/mountlist.c @@ -0,0 +1,934 @@ +/* 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 new file mode 100644 index 000000000..ae0c29448 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/mountlist.h @@ -0,0 +1,54 @@ +/* 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 new file mode 100644 index 000000000..1838d5d7c --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/op_c.c @@ -0,0 +1,1415 @@ +/* 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 new file mode 100644 index 000000000..76b544a2a --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/op_c.h @@ -0,0 +1,218 @@ +/* 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 new file mode 100644 index 000000000..62002a59f --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/operatio.h @@ -0,0 +1,232 @@ +/* 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 new file mode 100644 index 000000000..066eaa923 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pages.c @@ -0,0 +1,1418 @@ +/* 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 new file mode 100644 index 000000000..31a514c58 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pages.h @@ -0,0 +1,141 @@ +/* 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 new file mode 100644 index 000000000..3ca1f7d34 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/palette.c @@ -0,0 +1,2992 @@ +/* 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 new file mode 100644 index 000000000..5b68e1d42 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/palette.h @@ -0,0 +1,60 @@ +/* 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 new file mode 100644 index 000000000..b60e3b671 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pversion.c @@ -0,0 +1,2 @@ +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 new file mode 100644 index 000000000..99a63f556 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxdouble.c @@ -0,0 +1,510 @@ +/* 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 new file mode 100644 index 000000000..14810f86b --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxdouble.h @@ -0,0 +1,50 @@ +/* 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 new file mode 100644 index 000000000..476093201 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxquad.c @@ -0,0 +1,545 @@ +/* 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 new file mode 100644 index 000000000..04f219501 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxquad.h @@ -0,0 +1,50 @@ +/* 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 new file mode 100644 index 000000000..9cfaff3f7 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxsimple.c @@ -0,0 +1,481 @@ +/* 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 new file mode 100644 index 000000000..175d1a653 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxsimple.h @@ -0,0 +1,53 @@ +/* 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 new file mode 100644 index 000000000..b62a39865 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxtall.c @@ -0,0 +1,466 @@ +/* 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 new file mode 100644 index 000000000..424ec7747 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxtall.h @@ -0,0 +1,48 @@ +/* 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 new file mode 100644 index 000000000..1e45b972b --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxtall2.c @@ -0,0 +1,537 @@ +/* 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 new file mode 100644 index 000000000..478edf9f5 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxtall2.h @@ -0,0 +1,50 @@ +/* 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 new file mode 100644 index 000000000..39fb7189e --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxtriple.c @@ -0,0 +1,533 @@ +/* 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 new file mode 100644 index 000000000..29719cdd6 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxtriple.h @@ -0,0 +1,50 @@ +/* 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 new file mode 100644 index 000000000..e1aa80552 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxwide.c @@ -0,0 +1,519 @@ +/* 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 new file mode 100644 index 000000000..7ffaf24d3 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxwide.h @@ -0,0 +1,51 @@ +/* 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 new file mode 100644 index 000000000..0fcd81041 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxwide2.c @@ -0,0 +1,527 @@ +/* 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 new file mode 100644 index 000000000..d6409e971 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/pxwide2.h @@ -0,0 +1,50 @@ +/* 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 new file mode 100644 index 000000000..21827b6cf --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/readini.c @@ -0,0 +1,980 @@ +/* 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 new file mode 100644 index 000000000..e55152f36 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/readini.h @@ -0,0 +1,29 @@ +/* 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 new file mode 100644 index 000000000..cc7900beb --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/readline.c @@ -0,0 +1,675 @@ +/* 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 new file mode 100644 index 000000000..1a916e72c --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/realpath.c @@ -0,0 +1,121 @@ +/* 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 new file mode 100644 index 000000000..35f625bcd --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/realpath.h @@ -0,0 +1,36 @@ +/* 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 new file mode 100644 index 000000000..b691965f3 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/saveini.c @@ -0,0 +1,735 @@ +/* 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 new file mode 100644 index 000000000..c45b38f5e --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/saveini.h @@ -0,0 +1,27 @@ +/* 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 new file mode 100644 index 000000000..cdb0634e0 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/sdlscreen.c @@ -0,0 +1,373 @@ +/* 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 new file mode 100644 index 000000000..8c58a1412 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/sdlscreen.h @@ -0,0 +1,77 @@ +/* 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 new file mode 100644 index 000000000..b0a62f8ae --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/setup.c @@ -0,0 +1,240 @@ +/* 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 new file mode 100644 index 000000000..678695128 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/setup.h @@ -0,0 +1,157 @@ +/* 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 new file mode 100644 index 000000000..bab856dbc --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/shade.c @@ -0,0 +1,1132 @@ +/* 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 new file mode 100644 index 000000000..94278e55c --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/shade.h @@ -0,0 +1,34 @@ +/* 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 new file mode 100644 index 000000000..6e3dc579f --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/special.c @@ -0,0 +1,468 @@ +/* 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 new file mode 100644 index 000000000..75e610f22 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/struct.h @@ -0,0 +1,539 @@ +/* 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 new file mode 100644 index 000000000..f240a4398 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/text.c @@ -0,0 +1,667 @@ +/* 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 new file mode 100644 index 000000000..6d65b274b --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/text.h @@ -0,0 +1,57 @@ +/* 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 new file mode 100644 index 000000000..f603fa4ae --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/transform.c @@ -0,0 +1,446 @@ +/* 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 new file mode 100644 index 000000000..26cf28d17 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/transform.h @@ -0,0 +1,29 @@ +/* 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 new file mode 100644 index 000000000..b4b5ecc25 --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/version.c @@ -0,0 +1 @@ +char SVN_revision[]="1781"; diff --git a/project/jni/application/grafx2/grafx2/src/windows.c b/project/jni/application/grafx2/grafx2/src/windows.c new file mode 100644 index 000000000..e2e5fa27d --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/windows.c @@ -0,0 +1,3174 @@ +/* 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 new file mode 100644 index 000000000..579efa52d --- /dev/null +++ b/project/jni/application/grafx2/grafx2/src/windows.h @@ -0,0 +1,116 @@ +/* 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 new file mode 100644 index 000000000..993dc8b67 Binary files /dev/null and b/project/jni/application/grafx2/icon.png differ