diff --git a/assdraw/assdraw.vcproj b/assdraw/assdraw.vcproj
new file mode 100644
index 0000000000000000000000000000000000000000..f61c1636aa10feff0b9688dad4a2c38cdb228ce4
--- /dev/null
+++ b/assdraw/assdraw.vcproj
@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8,00"
+	Name="assdraw"
+	ProjectGUID="{3BC75951-691C-4703-A29A-D29E298248AC}"
+	RootNamespace="assdraw"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\src\agg_bcspline.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\agg_vcgen_bcspline.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\wxAGG\AGGWindow.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\assdraw.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\assdraw_settings.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\canvas.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\canvas_mouse.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\cmd.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\dlgctrl.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\engine.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\library.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\settings.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\src\_common.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\agg_bcspline.h"
+				>
+			</File>
+			<File
+				RelativePath=".\src\agg_conv_bcspline.h"
+				>
+			</File>
+			<File
+				RelativePath=".\src\agg_vcgen_bcspline.h"
+				>
+			</File>
+			<File
+				RelativePath=".\src\agghelper.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\wxAGG\AGGWindow.h"
+				>
+			</File>
+			<File
+				RelativePath=".\src\assdraw.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\canvas.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\canvas_mouse.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\cmd.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\dlgctrl.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\engine.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\enums.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\include_once.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\library.hpp"
+				>
+			</File>
+			<File
+				RelativePath=".\src\wxAGG\PixelFormatConvertor.h"
+				>
+			</File>
+			<File
+				RelativePath=".\src\resource.h"
+				>
+			</File>
+			<File
+				RelativePath=".\src\settings.hpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+			<File
+				RelativePath=".\src\assdraw.rc"
+				>
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/assdraw/src/ASSDraw3.dev b/assdraw/src/ASSDraw3.dev
new file mode 100644
index 0000000000000000000000000000000000000000..5afb0aa9216c2e0828d6b064b59b480a5326067c
--- /dev/null
+++ b/assdraw/src/ASSDraw3.dev
@@ -0,0 +1,323 @@
+[Project]
+FileName=ASSDraw3.dev
+Name=ASSDraw
+UnitCount=26
+Type=0
+Ver=3
+IsCpp=1
+Folders=AGG
+CommandLine=
+CompilerSettings=0000000001001000000100
+PchHead=-1
+PchSource=-1
+ProfilesCount=1
+ProfileIndex=0
+
+[Unit1]
+FileName=assdraw.cpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[VersionInfo]
+Major=3
+Minor=0
+Release=0
+Build=0
+LanguageID=1033
+CharsetID=1252
+CompanyName=ai-chan
+FileVersion=3.0.0.0
+FileDescription=A tool for designing shapes to be used in ASS subtitle
+InternalName=ASSDraw3
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=ASSDraw3.exe
+ProductName=ASSDraw
+ProductVersion=3
+AutoIncBuildNrOnRebuild=0
+AutoIncBuildNrOnCompile=0
+UnitCount=20
+
+[Unit3]
+FileName=cmd.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit4]
+FileName=engine.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit5]
+FileName=assdraw.rc
+CompileCpp=1
+Folder=Resources
+Compile=1
+Link=0
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit7]
+FileName=engine.cpp
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+CompileCpp=1
+
+[Unit9]
+FileName=include_once.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit6]
+FileName=assdraw.hpp
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+CompileCpp=1
+
+[Unit2]
+FileName=cmd.cpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Profile1]
+ProfileName=Default Profile
+Type=0
+ObjFiles=
+Includes=E:\DEV;E:\DEV\agg-2.5\include;E:\DEV\wxTreeMultiCtrl\include
+Libs=E:\DEV\agg-2.5;E:\DEV\wxTreeMultiCtrl
+PrivateResource=E:\DEV\_projects\ASSDraw 3\Default Profile\ASSDraw_private.rc
+ResourceIncludes=
+MakeIncludes=
+Compiler=
+CppCompiler=-D__WXMSW__ -DNO_GCC_PRAGMA -fno-rtti -fno-exceptions_@@_ -Wno-deprecated_@@_
+Linker=-lwxmsw28_propgrid_@@_-mwindows_@@_-lwxmsw28_@@_-lwxmsw28_gl_@@_-lwxtiff_@@_-lwxjpeg_@@_-lwxpng_@@_-lwxzlib_@@_-lwxregex_@@_-lwxexpat_@@_-lkernel32_@@_-luser32_@@_-lgdi32_@@_-lcomdlg32_@@_-lwinspool_@@_-lwinmm_@@_-lshell32_@@_-lcomctl32_@@_-lole32_@@_-loleaut32_@@_-luuid_@@_-lrpcrt4_@@_-ladvapi32_@@_-lwsock32_@@_-lodbc32_@@_-lopengl32_@@_-lagg_@@_
+PreprocDefines=
+CompilerSettings=0000000001001000000100
+Icon=
+ExeOutput=E:\DEV\_projects\ASSDraw 3\Default Profile\
+ObjectOutput=E:\DEV\_projects\ASSDraw 3\Default Profile\
+OverrideOutput=1
+OverrideOutputName=ASSDraw3.exe
+HostApplication=
+CommandLine=
+UseCustomMakefile=0
+CustomMakefile=
+IncludeVersionInfo=1
+SupportXPThemes=1
+CompilerSet=0
+compilerType=0
+
+[Unit8]
+FileName=dlgctrl.cpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit10]
+FileName=resource.h
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit15]
+FileName=agg_bcspline.cpp
+CompileCpp=1
+Folder=AGG
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit16]
+FileName=enums.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit18]
+FileName=library.cpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit17]
+FileName=library.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit13]
+FileName=wxAGG\AGGWindow.cpp
+CompileCpp=1
+Folder=AGG
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit14]
+FileName=agg_vcgen_bcspline.cpp
+CompileCpp=1
+Folder=AGG
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit11]
+FileName=canvas.cpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit12]
+FileName=canvas.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit20]
+FileName=dlgctrl.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit19]
+FileName=_common.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit21]
+FileName=settings.cpp
+CompileCpp=1
+Folder=ASSDraw
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit22]
+FileName=settings.hpp
+CompileCpp=1
+Folder=ASSDraw
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit23]
+FileName=assdraw_settings.cpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit24]
+FileName=agghelper.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit25]
+FileName=canvas_mouse.hpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
+[Unit26]
+FileName=canvas_mouse.cpp
+CompileCpp=1
+Folder=
+Compile=1
+Link=1
+Priority=1000
+OverrideBuildCmd=0
+BuildCmd=
+
diff --git a/assdraw/src/ASSDraw3.layout b/assdraw/src/ASSDraw3.layout
new file mode 100644
index 0000000000000000000000000000000000000000..8ed9b9f28e4d60002c700340c55b62c17d587131
--- /dev/null
+++ b/assdraw/src/ASSDraw3.layout
@@ -0,0 +1,185 @@
+[Editor_10]
+CursorCol=32
+CursorRow=553
+TopLine=535
+LeftChar=1
+Open=1
+Top=0
+[Editor_7]
+CursorCol=6
+CursorRow=227
+TopLine=197
+LeftChar=1
+Open=1
+Top=1
+[Editor_5]
+CursorCol=11
+CursorRow=19
+TopLine=1
+LeftChar=1
+Open=1
+Top=0
+[Editor_18]
+CursorCol=11
+CursorRow=14
+TopLine=1
+LeftChar=1
+Open=0
+Top=0
+[Editor_19]
+CursorCol=12
+CursorRow=3
+TopLine=3
+LeftChar=1
+Open=0
+Top=0
+[Editor_11]
+CursorCol=8
+CursorRow=44
+TopLine=31
+LeftChar=1
+Open=0
+Top=0
+[Editor_3]
+CursorCol=1
+CursorRow=268
+TopLine=243
+LeftChar=1
+Open=1
+Top=0
+[Editor_15]
+CursorCol=15
+CursorRow=7
+TopLine=1
+LeftChar=1
+Open=1
+Top=0
+[Editor_8]
+CursorCol=1
+CursorRow=69
+TopLine=33
+LeftChar=1
+Open=0
+Top=0
+[Editor_16]
+CursorCol=2
+CursorRow=25
+TopLine=1
+LeftChar=1
+Open=0
+Top=0
+[Editor_0]
+CursorCol=39
+CursorRow=212
+TopLine=184
+LeftChar=1
+Open=1
+Top=0
+[Editors]
+Focused=7
+Order=5,0,10,17,3,6,7,22,21,20,15
+[Editor_1]
+Open=0
+Top=0
+CursorCol=21
+CursorRow=63
+TopLine=30
+LeftChar=1
+[Editor_2]
+Open=0
+Top=0
+CursorCol=7
+CursorRow=83
+TopLine=50
+LeftChar=1
+[Editor_4]
+Open=0
+Top=0
+CursorCol=19
+CursorRow=21
+TopLine=21
+LeftChar=1
+[Editor_6]
+Open=1
+Top=0
+CursorCol=1
+CursorRow=577
+TopLine=556
+LeftChar=1
+[Editor_9]
+Open=0
+Top=0
+CursorCol=1
+CursorRow=1
+TopLine=1
+LeftChar=1
+[Editor_12]
+Open=0
+Top=0
+CursorCol=6
+CursorRow=99
+TopLine=91
+LeftChar=1
+[Editor_13]
+Open=0
+Top=0
+CursorCol=1
+CursorRow=204
+TopLine=170
+LeftChar=1
+[Editor_14]
+Open=0
+Top=0
+CursorCol=1
+CursorRow=290
+TopLine=256
+LeftChar=1
+[Editor_17]
+Open=1
+Top=0
+CursorCol=68
+CursorRow=133
+TopLine=112
+LeftChar=1
+[Editor_20]
+Open=1
+Top=0
+CursorCol=46
+CursorRow=195
+TopLine=163
+LeftChar=1
+[Editor_21]
+Open=1
+Top=0
+CursorCol=2
+CursorRow=58
+TopLine=57
+LeftChar=1
+[Editor_22]
+Open=1
+Top=0
+CursorCol=32
+CursorRow=160
+TopLine=129
+LeftChar=1
+[Editor_23]
+Open=0
+Top=0
+CursorCol=2
+CursorRow=6
+TopLine=1
+LeftChar=1
+[Editor_24]
+CursorCol=1
+CursorRow=56
+TopLine=25
+LeftChar=1
+Open=0
+Top=0
+[Editor_25]
+Open=0
+Top=0
+CursorCol=18
+CursorRow=8
+TopLine=1
+LeftChar=1
diff --git a/assdraw/src/Makefile.win b/assdraw/src/Makefile.win
new file mode 100644
index 0000000000000000000000000000000000000000..aa45a440ec6a583cb26ccafc1cba11f15dfa1f6d
--- /dev/null
+++ b/assdraw/src/Makefile.win
@@ -0,0 +1,69 @@
+# Project: ASSDraw
+# Compiler: Default GCC compiler
+# Compiler Type: MingW 3
+# Makefile created by wxDev-C++ 6.10.2 on 20/01/08 23:46
+
+CPP       = g++.exe
+CC        = gcc.exe
+WINDRES   = windres.exe
+OBJ       = ../Default\ Profile/assdraw.o ../Default\ Profile/cmd.o ../Default\ Profile/engine.o ../Default\ Profile/dlgctrl.o ../Default\ Profile/canvas.o ../Default\ Profile/AGGWindow.o ../Default\ Profile/agg_vcgen_bcspline.o ../Default\ Profile/agg_bcspline.o ../Default\ Profile/library.o ../Default\ Profile/settings.o ../Default\ Profile/assdraw_settings.o ../Default\ Profile/canvas_mouse.o ../Default\ Profile/ASSDraw3_private.res
+LINKOBJ   = "../Default Profile/assdraw.o" "../Default Profile/cmd.o" "../Default Profile/engine.o" "../Default Profile/dlgctrl.o" "../Default Profile/canvas.o" "../Default Profile/AGGWindow.o" "../Default Profile/agg_vcgen_bcspline.o" "../Default Profile/agg_bcspline.o" "../Default Profile/library.o" "../Default Profile/settings.o" "../Default Profile/assdraw_settings.o" "../Default Profile/canvas_mouse.o" "../Default Profile/ASSDraw3_private.res"
+LIBS      = -L"D:/Program Files/Dev-Cpp/Lib" -L"E:/DEV/agg-2.5" -L"E:/DEV/wxTreeMultiCtrl" -lwxmsw28_propgrid -mwindows -lwxmsw28 -lwxmsw28_gl -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregex -lwxexpat -lkernel32 -luser32 -lgdi32 -lcomdlg32 -lwinspool -lwinmm -lshell32 -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lwsock32 -lodbc32 -lopengl32 -lagg  -s 
+INCS      = -I"include" -I"E:/DEV" -I"E:/DEV/agg-2.5/include" -I"E:/DEV/wxTreeMultiCtrl/include"
+CXXINCS   = -I"D:/Program Files/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"D:/Program Files/Dev-Cpp/include/c++/3.4.2/backward" -I"D:/Program Files/Dev-Cpp/include/c++/3.4.2/mingw32" -I"D:/Program Files/Dev-Cpp/include/c++/3.4.2" -I"D:/Program Files/Dev-Cpp/include" -I"D:/Program Files/Dev-Cpp/" -I"D:/Program Files/Dev-Cpp/include/common/wx/msw" -I"D:/Program Files/Dev-Cpp/include/common/wx/generic" -I"D:/Program Files/Dev-Cpp/include/common/wx/fl" -I"D:/Program Files/Dev-Cpp/include/common/wx/gizmos" -I"D:/Program Files/Dev-Cpp/include/common/wx/html" -I"D:/Program Files/Dev-Cpp/include/common/wx/mmedia" -I"D:/Program Files/Dev-Cpp/include/common/wx/net" -I"D:/Program Files/Dev-Cpp/include/common/wx/ogl" -I"D:/Program Files/Dev-Cpp/include/common/wx/plot" -I"D:/Program Files/Dev-Cpp/include/common/wx/protocol" -I"D:/Program Files/Dev-Cpp/include/common/wx/stc" -I"D:/Program Files/Dev-Cpp/include/common/wx/svg" -I"D:/Program Files/Dev-Cpp/include/common/wx/xml" -I"D:/Program Files/Dev-Cpp/include/common/wx/xrc" -I"D:/Program Files/Dev-Cpp/include/common/wx" -I"D:/Program Files/Dev-Cpp/include/common" -I"E:/dev/ACE-5.5" -I"E:/DEV" -I"E:/DEV/agg-2.5/include" -I"E:/DEV/wxTreeMultiCtrl/include"
+RCINCS    = --include-dir "D:/PROGRA~1/Dev-Cpp/include/common"
+BIN       = ../Default\ Profile/ASSDraw3.exe
+DEFINES   = 
+CXXFLAGS  = $(CXXINCS) $(DEFINES) -D__WXMSW__ -DNO_GCC_PRAGMA -fno-rtti -fno-exceptions  -Wno-deprecated   -fexpensive-optimizations -O3
+CFLAGS    = $(INCS) $(DEFINES)   -fexpensive-optimizations -O3
+GPROF     = gprof.exe
+RM        = rm -f
+LINK      = g++.exe
+
+.PHONY: all all-before all-after clean clean-custom
+all: all-before $(BIN) all-after
+
+clean: clean-custom
+	$(RM) $(OBJ) $(BIN)
+
+$(BIN): $(OBJ)
+	$(LINK) $(LINKOBJ) -o "..\Default Profile\ASSDraw3.exe" $(LIBS)
+
+../Default\ Profile/assdraw.o: $(GLOBALDEPS) assdraw.cpp assdraw.hpp _common.hpp enums.hpp include_once.hpp
+	$(CPP) -c assdraw.cpp -o "../Default Profile/assdraw.o" $(CXXFLAGS)
+
+../Default\ Profile/cmd.o: $(GLOBALDEPS) cmd.cpp
+	$(CPP) -c cmd.cpp -o "../Default Profile/cmd.o" $(CXXFLAGS)
+
+../Default\ Profile/engine.o: $(GLOBALDEPS) engine.cpp
+	$(CPP) -c engine.cpp -o "../Default Profile/engine.o" $(CXXFLAGS)
+
+../Default\ Profile/dlgctrl.o: $(GLOBALDEPS) dlgctrl.cpp assdraw.hpp _common.hpp
+	$(CPP) -c dlgctrl.cpp -o "../Default Profile/dlgctrl.o" $(CXXFLAGS)
+
+../Default\ Profile/canvas.o: $(GLOBALDEPS) canvas.cpp assdraw.hpp _common.hpp cmd.hpp agghelper.hpp
+	$(CPP) -c canvas.cpp -o "../Default Profile/canvas.o" $(CXXFLAGS)
+
+../Default\ Profile/AGGWindow.o: $(GLOBALDEPS) wxAGG/AGGWindow.cpp wxAGG/AGGWindow.h wxAGG/PixelFormatConvertor.h
+	$(CPP) -c wxAGG/AGGWindow.cpp -o "../Default Profile/AGGWindow.o" $(CXXFLAGS)
+
+../Default\ Profile/agg_vcgen_bcspline.o: $(GLOBALDEPS) agg_vcgen_bcspline.cpp agg_vcgen_bcspline.h agg_bcspline.h
+	$(CPP) -c agg_vcgen_bcspline.cpp -o "../Default Profile/agg_vcgen_bcspline.o" $(CXXFLAGS)
+
+../Default\ Profile/agg_bcspline.o: $(GLOBALDEPS) agg_bcspline.cpp agg_bcspline.h
+	$(CPP) -c agg_bcspline.cpp -o "../Default Profile/agg_bcspline.o" $(CXXFLAGS)
+
+../Default\ Profile/library.o: $(GLOBALDEPS) library.cpp assdraw.hpp _common.hpp library.hpp engine.hpp _common.hpp wxAGG/AGGWindow.h wxAGG/PixelFormatConvertor.h agg_conv_bcspline.h agg_vcgen_bcspline.h agg_bcspline.h
+	$(CPP) -c library.cpp -o "../Default Profile/library.o" $(CXXFLAGS)
+
+../Default\ Profile/settings.o: $(GLOBALDEPS) settings.cpp assdraw.hpp _common.hpp settings.hpp _common.hpp
+	$(CPP) -c settings.cpp -o "../Default Profile/settings.o" $(CXXFLAGS)
+
+../Default\ Profile/assdraw_settings.o: $(GLOBALDEPS) assdraw_settings.cpp assdraw.hpp _common.hpp
+	$(CPP) -c assdraw_settings.cpp -o "../Default Profile/assdraw_settings.o" $(CXXFLAGS)
+
+../Default\ Profile/canvas_mouse.o: $(GLOBALDEPS) canvas_mouse.cpp canvas_mouse.hpp _common.hpp enums.hpp engine.hpp _common.hpp wxAGG/AGGWindow.h wxAGG/PixelFormatConvertor.h agg_conv_bcspline.h agg_vcgen_bcspline.h agg_bcspline.h canvas.hpp engine.hpp enums.hpp
+	$(CPP) -c canvas_mouse.cpp -o "../Default Profile/canvas_mouse.o" $(CXXFLAGS)
+
+../Default\ Profile/ASSDraw3_private.res: ../Default\ Profile/ASSDraw3_private.rc assdraw.rc 
+	$(WINDRES) --input-format=rc -o "../Default Profile/ASSDraw3_private.res" $(RCINCS) ../DEFAUL~1/ASSDRA~1.RC -O coff
diff --git a/assdraw/src/_common.hpp b/assdraw/src/_common.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..93c17f23559b2376fec4baa155e1357f6d107e99
--- /dev/null
+++ b/assdraw/src/_common.hpp
@@ -0,0 +1,14 @@
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+    #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+    #include "wx/wx.h"
+#endif
+
+#define TITLE wxT("ASSDraw3")
+
+#define __DPDS__ wxDefaultPosition, wxDefaultSize
diff --git a/assdraw/src/agg_bcspline.cpp b/assdraw/src/agg_bcspline.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b06539dc26355eb4e73a0b3250973d6297db102a
--- /dev/null
+++ b/assdraw/src/agg_bcspline.cpp
@@ -0,0 +1,289 @@
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry (AGG) - Version 2.5
+// A high quality rendering engine for C++
+// Copyright (C) 2002-2006 Maxim Shemanarev
+// Contact: mcseem@antigrain.com
+//          mcseemagg@yahoo.com
+//          http://antigrain.com
+// 
+// AGG is free software; 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.
+// 
+// AGG is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with AGG; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+// MA 02110-1301, USA.
+//----------------------------------------------------------------------------
+
+#include "agg_bcspline.h"
+
+namespace agg
+{
+    //------------------------------------------------------------------------
+    bcspline::bcspline() :
+        m_max(0),
+        m_num(0),
+        m_x(0),
+        m_y(0),
+        m_last_idx(-1)
+    {
+    }
+
+    //------------------------------------------------------------------------
+    bcspline::bcspline(int num) :
+        m_max(0),
+        m_num(0),
+        m_x(0),
+        m_y(0),
+        m_last_idx(-1)
+    {
+        init(num);
+    }
+
+    //------------------------------------------------------------------------
+    bcspline::bcspline(int num, const double* x, const double* y) :
+        m_max(0),
+        m_num(0),
+        m_x(0),
+        m_y(0),
+        m_last_idx(-1)
+    {
+        init(num, x, y);
+    }
+
+    
+    //------------------------------------------------------------------------
+    void bcspline::init(int max)
+    {
+        if(max > 2 && max > m_max)
+        {
+            m_am.resize(max * 3);
+            m_max = max;
+            m_x   = &m_am[m_max];
+            m_y   = &m_am[m_max * 2];
+        }
+        m_num = 0;
+        m_last_idx = -1;
+    }
+
+
+    //------------------------------------------------------------------------
+    void bcspline::add_point(double x, double y)
+    {
+        if(m_num < m_max)
+        {
+            m_x[m_num] = x;
+            m_y[m_num] = y;
+            ++m_num;
+        }
+    }
+
+
+    //------------------------------------------------------------------------
+    void bcspline::prepare()
+    {
+        if(m_num > 2)
+        {
+            int i, k, n1;
+            double* temp; 
+            double* r; 
+            double* s;
+            double h, p, d, f, e;
+    
+            for(k = 0; k < m_num; k++) 
+            {
+                m_am[k] = 0.0;
+            }
+
+            n1 = 3 * m_num;
+
+            pod_array<double> al(n1);
+            temp = &al[0];
+
+            for(k = 0; k < n1; k++) 
+            {
+                temp[k] = 0.0;
+            }
+
+            r = temp + m_num;
+            s = temp + m_num * 2;
+
+            n1 = m_num - 1;
+            d = m_x[1] - m_x[0];
+            e = (m_y[1] - m_y[0]) / d;
+
+            for(k = 1; k < n1; k++) 
+            {
+                h     = d;
+                d     = m_x[k + 1] - m_x[k];
+                f     = e;
+                e     = (m_y[k + 1] - m_y[k]) / d;
+                al[k] = d / (d + h);
+                r[k]  = 1.0 - al[k];
+                s[k]  = 6.0 * (e - f) / (h + d);
+            }
+
+            for(k = 1; k < n1; k++) 
+            {
+                p = 1.0 / (r[k] * al[k - 1] + 2.0);
+                al[k] *= -p;
+                s[k] = (s[k] - r[k] * s[k - 1]) * p; 
+            }
+
+            m_am[n1]     = 0.0;
+            al[n1 - 1]   = s[n1 - 1];
+            m_am[n1 - 1] = al[n1 - 1];
+
+            for(k = n1 - 2, i = 0; i < m_num - 2; i++, k--) 
+            {
+                al[k]   = al[k] * al[k + 1] + s[k];
+                m_am[k] = al[k];
+            }
+        }
+        m_last_idx = -1;
+    }
+
+
+
+    //------------------------------------------------------------------------
+    void bcspline::init(int num, const double* x, const double* y)
+    {
+        if(num > 2)
+        {
+            init(num);
+            int i;
+            for(i = 0; i < num; i++)
+            {
+                add_point(*x++, *y++);
+            }
+            prepare();
+        }
+        m_last_idx = -1;
+    }
+
+
+    //------------------------------------------------------------------------
+    void bcspline::bsearch(int n, const double *x, double x0, int *i) 
+    {
+        int j = n - 1;
+        int k;
+          
+        for(*i = 0; (j - *i) > 1; ) 
+        {
+            if(x0 < x[k = (*i + j) >> 1]) j = k; 
+            else                         *i = k;
+        }
+    }
+
+
+
+    //------------------------------------------------------------------------
+    double bcspline::interpolation(double x, int i) const
+    {
+        int j = i + 1;
+        double d = m_x[i] - m_x[j];
+        double h = x - m_x[j];
+        double r = m_x[i] - x;
+        double p = d * d / 6.0;
+        return (m_am[j] * r * r * r + m_am[i] * h * h * h) / 6.0 / d +
+               ((m_y[j] - m_am[j] * p) * r + (m_y[i] - m_am[i] * p) * h) / d;
+    }
+
+
+    //------------------------------------------------------------------------
+    double bcspline::extrapolation_left(double x) const
+    {
+        double d = m_x[1] - m_x[0];
+        return (-d * m_am[1] / 6 + (m_y[1] - m_y[0]) / d) * 
+               (x - m_x[0]) + 
+               m_y[0];
+    }
+
+    //------------------------------------------------------------------------
+    double bcspline::extrapolation_right(double x) const
+    {
+        double d = m_x[m_num - 1] - m_x[m_num - 2];
+        return (d * m_am[m_num - 2] / 6 + (m_y[m_num - 1] - m_y[m_num - 2]) / d) * 
+               (x - m_x[m_num - 1]) + 
+               m_y[m_num - 1];
+    }
+
+    //------------------------------------------------------------------------
+    double bcspline::get(double x) const
+    {
+        if(m_num > 2)
+        {
+            int i;
+
+            // Extrapolation on the left
+            if(x < m_x[0]) return extrapolation_left(x);
+
+            // Extrapolation on the right
+            if(x >= m_x[m_num - 1]) return extrapolation_right(x);
+
+            // Interpolation
+            bsearch(m_num, m_x, x, &i);
+            return interpolation(x, i);
+        }
+        return 0.0;
+    }
+
+
+    //------------------------------------------------------------------------
+    double bcspline::get_stateful(double x) const
+    {
+        if(m_num > 2)
+        {
+            // Extrapolation on the left
+            if(x < m_x[0]) return extrapolation_left(x);
+
+            // Extrapolation on the right
+            if(x >= m_x[m_num - 1]) return extrapolation_right(x);
+
+            if(m_last_idx >= 0)
+            {
+                // Check if x is not in current range
+                if(x < m_x[m_last_idx] || x > m_x[m_last_idx + 1])
+                {
+                    // Check if x between next points (most probably)
+                    if(m_last_idx < m_num - 2 && 
+                       x >= m_x[m_last_idx + 1] &&
+                       x <= m_x[m_last_idx + 2])
+                    {
+                        ++m_last_idx;
+                    }
+                    else
+                    if(m_last_idx > 0 && 
+                       x >= m_x[m_last_idx - 1] && 
+                       x <= m_x[m_last_idx])
+                    {
+                        // x is between pevious points
+                        --m_last_idx;
+                    }
+                    else
+                    {
+                        // Else perform full search
+                        bsearch(m_num, m_x, x, &m_last_idx);
+                    }
+                }
+                return interpolation(x, m_last_idx);
+            }
+            else
+            {
+                // Interpolation
+                bsearch(m_num, m_x, x, &m_last_idx);
+                return interpolation(x, m_last_idx);
+            }
+        }
+        return 0.0;
+    }
+
+}
+
diff --git a/assdraw/src/agg_bcspline.h b/assdraw/src/agg_bcspline.h
new file mode 100644
index 0000000000000000000000000000000000000000..05d2364978ffdc8f920cfa0fd01fb5c975dee97b
--- /dev/null
+++ b/assdraw/src/agg_bcspline.h
@@ -0,0 +1,81 @@
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry (AGG) - Version 2.5
+// A high quality rendering engine for C++
+// Copyright (C) 2002-2006 Maxim Shemanarev
+// Contact: mcseem@antigrain.com
+//          mcseemagg@yahoo.com
+//          http://antigrain.com
+// 
+// AGG is free software; 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.
+// 
+// AGG is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with AGG; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+// MA 02110-1301, USA.
+//----------------------------------------------------------------------------
+
+#ifndef AGG_bcspline_INCLUDED
+#define AGG_bcspline_INCLUDED
+
+#include "agg_array.h"
+
+namespace agg
+{
+    //----------------------------------------------------------------bcspline
+    // A very simple class of Bi-cubic Spline interpolation.
+    // First call init(num, x[], y[]) where num - number of source points, 
+    // x, y - arrays of X and Y values respectively. Here Y must be a function 
+    // of X. It means that all the X-coordinates must be arranged in the ascending
+    // order. 
+    // Then call get(x) that calculates a value Y for the respective X. 
+    // The class supports extrapolation, i.e. you can call get(x) where x is
+    // outside the given with init() X-range. Extrapolation is a simple linear 
+    // function.
+    //
+    //  See Implementation agg_bcspline.cpp
+    //------------------------------------------------------------------------
+    class bcspline 
+    {
+    public:
+        bcspline();
+        bcspline(int num);
+        bcspline(int num, const double* x, const double* y);
+
+        void   init(int num);
+        void   add_point(double x, double y);
+        void   prepare();
+
+        void   init(int num, const double* x, const double* y);
+
+        double get(double x) const;
+        double get_stateful(double x) const;
+    
+    private:
+        bcspline(const bcspline&);
+        const bcspline& operator = (const bcspline&);
+
+        static void bsearch(int n, const double *x, double x0, int *i);
+        double extrapolation_left(double x) const;
+        double extrapolation_right(double x) const;
+        double interpolation(double x, int i) const;
+
+        int               m_max;
+        int               m_num;
+        double*           m_x;
+        double*           m_y;
+        pod_array<double> m_am;
+        mutable int       m_last_idx;
+    };
+
+
+}
+
+#endif
diff --git a/assdraw/src/agg_conv_bcspline.h b/assdraw/src/agg_conv_bcspline.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d40b9619193291dda4ebeff3ae26aa076a5bb48
--- /dev/null
+++ b/assdraw/src/agg_conv_bcspline.h
@@ -0,0 +1,58 @@
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry (AGG) - Version 2.5
+// A high quality rendering engine for C++
+// Copyright (C) 2002-2006 Maxim Shemanarev
+// Contact: mcseem@antigrain.com
+//          mcseemagg@yahoo.com
+//          http://antigrain.com
+// 
+// AGG is free software; 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.
+// 
+// AGG is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with AGG; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+// MA 02110-1301, USA.
+//----------------------------------------------------------------------------
+
+#ifndef AGG_conv_bcspline_INCLUDED
+#define AGG_conv_bcspline_INCLUDED
+
+#include "agg_basics.h"
+#include "agg_vcgen_bcspline.h"
+#include "agg_conv_adaptor_vcgen.h"
+
+
+namespace agg
+{
+
+    //---------------------------------------------------------conv_bcspline
+    template<class VertexSource> 
+    struct conv_bcspline : public conv_adaptor_vcgen<VertexSource, vcgen_bcspline>
+    {
+        typedef conv_adaptor_vcgen<VertexSource, vcgen_bcspline> base_type;
+
+        conv_bcspline(VertexSource& vs) : 
+            conv_adaptor_vcgen<VertexSource, vcgen_bcspline>(vs) {}
+
+        void   interpolation_step(double v) { base_type::generator().interpolation_step(v); }
+        double interpolation_step() const { return base_type::generator().interpolation_step(); }
+
+    private:
+        conv_bcspline(const conv_bcspline<VertexSource>&);
+        const conv_bcspline<VertexSource>& 
+            operator = (const conv_bcspline<VertexSource>&);
+    };
+
+}
+
+
+#endif
+
diff --git a/assdraw/src/agg_vcgen_bcspline.cpp b/assdraw/src/agg_vcgen_bcspline.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3276ac1f8cd529819509c846b4335e7c04645ca0
--- /dev/null
+++ b/assdraw/src/agg_vcgen_bcspline.cpp
@@ -0,0 +1,203 @@
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry (AGG) - Version 2.5
+// A high quality rendering engine for C++
+// Copyright (C) 2002-2006 Maxim Shemanarev
+// Contact: mcseem@antigrain.com
+//          mcseemagg@yahoo.com
+//          http://antigrain.com
+// 
+// AGG is free software; 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.
+// 
+// AGG is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with AGG; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+// MA 02110-1301, USA.
+//----------------------------------------------------------------------------
+
+#include "agg_vcgen_bcspline.h"
+
+namespace agg
+{
+
+    //------------------------------------------------------------------------
+    vcgen_bcspline::vcgen_bcspline() :
+        m_src_vertices(),
+        m_spline_x(),
+        m_spline_y(),
+        m_interpolation_step(1.0/50.0),
+        m_closed(0),
+        m_status(initial),
+        m_src_vertex(0)
+    {
+    }
+
+
+    //------------------------------------------------------------------------
+    void vcgen_bcspline::remove_all()
+    {
+        m_src_vertices.remove_all();
+        m_closed = 0;
+        m_status = initial;
+        m_src_vertex = 0;
+    }
+
+
+    //------------------------------------------------------------------------
+    void vcgen_bcspline::add_vertex(double x, double y, unsigned cmd)
+    {
+        m_status = initial;
+        if(is_move_to(cmd))
+        {
+            m_src_vertices.modify_last(point_d(x, y));
+        }
+        else
+        {
+            if(is_vertex(cmd))
+            {
+                m_src_vertices.add(point_d(x, y));
+            }
+            else
+            {
+                m_closed = get_close_flag(cmd);
+            }
+        }
+    }
+
+
+    //------------------------------------------------------------------------
+    void vcgen_bcspline::rewind(unsigned)
+    {
+        m_cur_abscissa = 0.0;
+        m_max_abscissa = 0.0;
+        m_src_vertex = 0;
+        if(m_status == initial && m_src_vertices.size() > 2)
+        {
+            if(m_closed)
+            {
+                m_spline_x.init(m_src_vertices.size() + 8);
+                m_spline_y.init(m_src_vertices.size() + 8);
+                m_spline_x.add_point(0.0, m_src_vertices.prev(m_src_vertices.size() - 3).x);
+                m_spline_y.add_point(0.0, m_src_vertices.prev(m_src_vertices.size() - 3).y);
+                m_spline_x.add_point(1.0, m_src_vertices[m_src_vertices.size() - 3].x);
+                m_spline_y.add_point(1.0, m_src_vertices[m_src_vertices.size() - 3].y);
+                m_spline_x.add_point(2.0, m_src_vertices[m_src_vertices.size() - 2].x);
+                m_spline_y.add_point(2.0, m_src_vertices[m_src_vertices.size() - 2].y);
+                m_spline_x.add_point(3.0, m_src_vertices[m_src_vertices.size() - 1].x);
+                m_spline_y.add_point(3.0, m_src_vertices[m_src_vertices.size() - 1].y);
+            }
+            else
+            {
+                m_spline_x.init(m_src_vertices.size());
+                m_spline_y.init(m_src_vertices.size());
+            }
+            unsigned i;
+            for(i = 0; i < m_src_vertices.size(); i++)
+            {
+                double x = m_closed ? i + 4 : i;
+                m_spline_x.add_point(x, m_src_vertices[i].x);
+                m_spline_y.add_point(x, m_src_vertices[i].y);
+            }
+            m_cur_abscissa = 0.0;
+            m_max_abscissa = m_src_vertices.size() - 1;
+            if(m_closed)
+            {
+                m_cur_abscissa = 4.0;
+                m_max_abscissa += 5.0;
+                m_spline_x.add_point(m_src_vertices.size() + 4, m_src_vertices[0].x);
+                m_spline_y.add_point(m_src_vertices.size() + 4, m_src_vertices[0].y);
+                m_spline_x.add_point(m_src_vertices.size() + 5, m_src_vertices[1].x);
+                m_spline_y.add_point(m_src_vertices.size() + 5, m_src_vertices[1].y);
+                m_spline_x.add_point(m_src_vertices.size() + 6, m_src_vertices[2].x);
+                m_spline_y.add_point(m_src_vertices.size() + 6, m_src_vertices[2].y);
+                m_spline_x.add_point(m_src_vertices.size() + 7, m_src_vertices.next(2).x);
+                m_spline_y.add_point(m_src_vertices.size() + 7, m_src_vertices.next(2).y);
+            }
+            m_spline_x.prepare();
+            m_spline_y.prepare();
+        }
+        m_status = ready;
+    }
+
+
+
+
+
+
+    //------------------------------------------------------------------------
+    unsigned vcgen_bcspline::vertex(double* x, double* y)
+    {
+        unsigned cmd = path_cmd_line_to;
+        while(!is_stop(cmd))
+        {
+            switch(m_status)
+            {
+            case initial:
+                rewind(0);
+
+            case ready:
+                if(m_src_vertices.size() < 2)
+                {
+                    cmd = path_cmd_stop;
+                    break;
+                }
+
+                if(m_src_vertices.size() == 2)
+                {
+                    *x = m_src_vertices[m_src_vertex].x;
+                    *y = m_src_vertices[m_src_vertex].y;
+                    m_src_vertex++;
+                    if(m_src_vertex == 1) return path_cmd_move_to;
+                    if(m_src_vertex == 2) return path_cmd_line_to;
+                    cmd = path_cmd_stop;
+                    break;
+                }
+
+                cmd = path_cmd_move_to;
+                m_status = polygon;
+                m_src_vertex = 0;
+
+            case polygon:
+                if(m_cur_abscissa >= m_max_abscissa)
+                {
+                    if(m_closed)
+                    {
+                        m_status = end_poly;
+                        break;
+                    }
+                    else
+                    {
+                        *x = m_src_vertices[m_src_vertices.size() - 1].x;
+                        *y = m_src_vertices[m_src_vertices.size() - 1].y;
+                        m_status = end_poly;
+                        return path_cmd_line_to;
+                    }
+                }
+
+                *x = m_spline_x.get(m_cur_abscissa);
+                *y = m_spline_y.get(m_cur_abscissa);
+                m_src_vertex++;
+                m_cur_abscissa += m_interpolation_step;
+                return (m_src_vertex == 1) ? path_cmd_move_to : path_cmd_line_to;
+
+            case end_poly:
+                m_status = stop;
+                return path_cmd_end_poly | m_closed;
+
+            case stop:
+                return path_cmd_stop;
+            }
+        }
+        return cmd;
+    }
+
+
+}
+
diff --git a/assdraw/src/agg_vcgen_bcspline.h b/assdraw/src/agg_vcgen_bcspline.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f92d994201171311b56a723f59bbfe811ffb960
--- /dev/null
+++ b/assdraw/src/agg_vcgen_bcspline.h
@@ -0,0 +1,83 @@
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry (AGG) - Version 2.5
+// A high quality rendering engine for C++
+// Copyright (C) 2002-2006 Maxim Shemanarev
+// Contact: mcseem@antigrain.com
+//          mcseemagg@yahoo.com
+//          http://antigrain.com
+// 
+// AGG is free software; 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.
+// 
+// AGG is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with AGG; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
+// MA 02110-1301, USA.
+//----------------------------------------------------------------------------
+
+#ifndef AGG_vcgen_bcspline_INCLUDED
+#define AGG_vcgen_bcspline_INCLUDED
+
+#include "agg_basics.h"
+#include "agg_array.h"
+#include "agg_bcspline.h"
+
+
+namespace agg
+{
+
+    //==========================================================vcgen_bcspline
+    class vcgen_bcspline
+    {
+        enum status_e
+        {
+            initial,
+            ready,
+            polygon,
+            end_poly,
+            stop
+        };
+
+    public:
+        typedef pod_bvector<point_d, 6> vertex_storage;
+
+        vcgen_bcspline();
+
+        void interpolation_step(double v) { m_interpolation_step = v; }
+        double interpolation_step() const { return m_interpolation_step; }
+
+        // Vertex Generator Interface
+        void remove_all();
+        void add_vertex(double x, double y, unsigned cmd);
+
+        // Vertex Source Interface
+        void     rewind(unsigned path_id);
+        unsigned vertex(double* x, double* y);
+
+    private:
+        vcgen_bcspline(const vcgen_bcspline&);
+        const vcgen_bcspline& operator = (const vcgen_bcspline&);
+
+        vertex_storage m_src_vertices;
+        bcspline        m_spline_x;
+        bcspline        m_spline_y;
+        double         m_interpolation_step;
+        unsigned       m_closed;
+        status_e       m_status;
+        unsigned       m_src_vertex;
+        double         m_cur_abscissa;
+        double         m_max_abscissa;
+    };
+
+}
+
+
+#endif
+
diff --git a/assdraw/src/agghelper.hpp b/assdraw/src/agghelper.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..de0ce66fccccd7c019d6a67ae540063bdf551a38
--- /dev/null
+++ b/assdraw/src/agghelper.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "agg_path_storage.h"
+
+class agghelper
+{
+public:
+	
+	static agg::path_storage RectanglePath(double left, double right, double top, double bottom)
+	{
+		agg::path_storage path;
+		path.move_to(left,top);
+		path.line_to(right,top);
+		path.line_to(right,bottom);
+		path.line_to(left,bottom);
+		path.line_to(left,top);
+		return path;
+	}
+	
+};
diff --git a/assdraw/src/assdraw.cpp b/assdraw/src/assdraw.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..132c018822a95a70d0ae3c149d2185afeedecac6
--- /dev/null
+++ b/assdraw/src/assdraw.cpp
@@ -0,0 +1,768 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        assdraw.cpp
+// Purpose:     ASSDraw main source file
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+
+#include "assdraw.hpp"
+#include "enums.hpp"
+#include "include_once.hpp"
+#include <wx/clipbrd.h>
+#include <wx/wfstream.h>
+#include <wx/filename.h>
+#include <wx/dynlib.h>
+#include <wx/stdpaths.h>
+
+//DEFINE_EVENT_TYPE(wxEVT_SETTINGS_CHANGED)
+
+// initialize wxWidget to accept our App class
+IMPLEMENT_APP(ASSDrawApp)
+
+BEGIN_EVENT_TABLE(ASSDrawFrame, wxFrame)
+    EVT_TOOL(TB_CLEAR, ASSDrawFrame::OnSelect_Clear)
+    EVT_TOOL(TB_PREVIEW, ASSDrawFrame::OnSelect_Preview)
+    //EVT_TOOL(TB_EDITSRC, ASSDrawFrame::OnSelect_EditSrc)
+    EVT_TOOL(TB_TRANSFORM, ASSDrawFrame::OnSelect_Transform)
+    EVT_TOOL_RANGE(MODE_ARR, MODE_DEL, ASSDrawFrame::OnChoose_Mode)
+    EVT_TOOL_RANGE(DRAG_DWG, DRAG_BOTH, ASSDrawFrame::OnChoose_DragMode)
+    EVT_TOOL_RCLICKED(wxID_ANY, ASSDrawFrame::OnToolRClick)
+    EVT_COMMAND(wxID_ANY, wxEVT_SETTINGS_CHANGED, ASSDrawFrame::OnSettingsChanged) 
+    EVT_MENU_RANGE(MENU_TB_ALL, MENU_TB_BGIMG, ASSDrawFrame::OnChoose_TBarRClickMenu)
+#if wxUSE_MENUS
+    EVT_MENU(MENU_CLEAR, ASSDrawFrame::OnSelect_Clear)
+    EVT_MENU(MENU_PREVIEW, ASSDrawFrame::OnSelect_Preview)
+    EVT_MENU(MENU_TRANSFORM, ASSDrawFrame::OnSelect_Transform)
+    EVT_MENU(MENU_LIBRARY, ASSDrawFrame::OnSelect_Library)
+    EVT_MENU(MENU_SETTINGS, ASSDrawFrame::OnSelect_Settings)
+    EVT_MENU(MENU_RESETPERSPECTIVE, ASSDrawFrame::OnSelect_ResetPerspective)
+    EVT_MENU(MENU_HELP, ASSDrawFrame::OnSelect_Help)
+    EVT_MENU(wxID_ABOUT, ASSDrawFrame::OnSelect_About)
+    EVT_MENU(MENU_UNDO, ASSDrawFrame::OnSelect_Undo)
+    EVT_MENU(MENU_REDO, ASSDrawFrame::OnSelect_Redo)
+    EVT_MENU(MENU_PASTE, ASSDrawFrame::OnSelect_Paste)
+    EVT_MENU(MENU_BGIMG_REMOVE, ASSDrawFrame::OnSelect_RemoveBG)
+    EVT_MENU(MENU_BGIMG_ALPHA, ASSDrawFrame::OnSelect_AlphaBG)
+    EVT_MENU_RANGE(MODE_ARR, MODE_NUT_BILINEAR, ASSDrawFrame::OnChoose_Mode)
+    EVT_MENU_RANGE(DRAG_DWG, DRAG_BOTH, ASSDrawFrame::OnChoose_DragMode)
+    EVT_MENU_RANGE(MENU_REPOS_TOPLEFT, MENU_REPOS_BOTRIGHT, ASSDrawFrame::OnChoose_Recenter)
+    EVT_MENU_RANGE(MENU_REPOS_BGTOPLEFT, MENU_REPOS_BGBOTRIGHT, ASSDrawFrame::OnChoose_RecenterToBG)
+#endif //wxUSE_MENUS
+	EVT_CLOSE(ASSDrawFrame::OnClose)
+END_EVENT_TABLE()
+
+// ----------------------------------------------------------------------------
+// the application class: ASSDrawApp
+// ----------------------------------------------------------------------------
+
+// 'Main program' equivalent: the program execution "starts" here
+bool ASSDrawApp::OnInit()
+{
+    // create the main application window
+    ASSDrawFrame * assdrawframe = new ASSDrawFrame( this, TITLE, wxDefaultPosition, wxSize(640, 480) );
+	SetTopWindow(assdrawframe);
+    return TRUE;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// main frame: ASSDrawFrame
+// ----------------------------------------------------------------------------
+
+// constructor
+
+ASSDrawFrame::ASSDrawFrame( wxApp *app, const wxString& title, const wxPoint& pos, const wxSize& size, long style)
+       : wxFrame(NULL, wxID_ANY, title, pos, size, style)
+{
+	m_app = app;
+    m_mgr.SetManagedWindow(this);
+    m_mgr.SetFlags(m_mgr.GetFlags() | wxAUI_MGR_ALLOW_ACTIVE_PANE);
+
+    // set the frame icon
+    SetIcon(wxICON(appico));
+    
+   	// Create status bar for the frame
+	#if wxUSE_STATUSBAR
+    CreateStatusBar(3);
+    int statwidths[] = { 64, -1, 64 };
+    GetStatusBar()->SetStatusWidths(3, statwidths);
+    SetStatusBarPane(1);
+	#endif // wxUSE_STATUSBAR
+	
+	InitializeDefaultSettings();
+	
+	// load config
+	configfile = wxFileName(::wxGetCwd(), _T("ASSDraw3.cfg")).GetFullPath();
+	if (!::wxFileExists(configfile))
+		configfile = wxFileName(wxStandardPaths::Get().GetUserConfigDir(), _T("ASSDraw3.cfg")).GetFullPath();
+
+	bool firsttime = !::wxFileExists(configfile);
+	if (firsttime) wxFileOutputStream(configfile).Close();
+	wxFileInputStream cfgf(configfile);
+	config = new wxFileConfig(cfgf);
+
+	// nullify transformdlg
+	transformdlg = NULL;
+
+	Maximize(true);
+	Show(true); // to get the right client size, must call Show() first
+
+	// config
+	LoadSettings();
+
+	// THE CANVAS
+    m_canvas = new ASSDrawCanvas( this , this );
+
+	// shapes library
+	shapelib = new ASSDrawShapeLibrary(this, this);
+
+	// source text ctrl
+	srctxtctrl = new ASSDrawSrcTxtCtrl(this, this);
+
+	// settings
+	/*
+	settingsdlg = NULL;
+	wxString settingsdllfile = wxFileName(::wxGetCwd(), "settings.dll").GetFullPath();
+
+	if (::wxFileExists(settingsdllfile))
+	{
+		wxDynamicLibrary settingsdll(settingsdllfile);
+		wxString symbol("CreateASSDrawSettingsDialogInstance");
+		if (settingsdll.IsLoaded() && settingsdll.HasSymbol(symbol)) 
+		{
+			typedef ASSDrawSettingsDialog* (*FuncType)(wxWindow*,ASSDrawFrame*,int);
+			FuncType func = (FuncType) settingsdll.GetSymbol(symbol);
+			//wxDYNLIB_FUNCTION(ASSDrawSettingsDialog, CreateASSDrawSettingsDialogInstance, settingsdll)
+			//ASSDrawSettingsDialog* test = func(NULL,this,971231);
+			//test->Reparent(this);
+			//test->Init();
+			//SetTitle(settingsdllfile);
+			//settingsdlg = func(NULL,this, 809131);
+			//settingsdlg->Init();
+			//m_mgr.AddPane(settingsdlg, wxAuiPaneInfo().Name(wxT("settings")).Caption(wxT("Settings")).Right().Layer(3).Position(0).CloseButton(true).BestSize(wxSize(240, 480)).MinSize(wxSize(200, 200)));
+		}
+	}
+	*/
+	
+	settingsdlg = new ASSDrawSettingsDialog(this, this);
+	settingsdlg->Init();
+	
+	SetMenus();
+	SetToolBars();
+	SetPanes();
+
+	// config
+
+	config->SetPath(_T("info"));
+	wxString version;
+	config->Read("version", &version);
+	config->SetPath("..");
+
+	default_perspective = m_mgr.SavePerspective(); // back up default perspective
+	config->SetPath("perspective");
+	wxString perspective;
+	if (config->Read("perspective", &perspective) && version == VERSION) m_mgr.LoadPerspective(perspective, false);
+	config->SetPath("..");
+
+	config->SetPath("library");
+	int n = 0;
+	config->Read("n", &n);
+	for (int i = 0; i < n; i++)
+	{
+		wxString libcmds;
+		config->Read(wxString::Format("%d",i), &libcmds);
+		shapelib->AddShapePreview(libcmds);		
+	}
+	config->SetPath("..");
+	
+    m_mgr.Update();
+	m_canvas->SetFocus();
+	m_canvas->Show();
+	
+	wxSize clientsize = m_canvas->GetClientSize();
+	m_canvas->ChangeZoomLevelTo(DEFAULT_SCALE, wxPoint(clientsize.x / 2, clientsize.y / 2));
+	m_canvas->MoveCanvasOriginTo(clientsize.x / 2, clientsize.y / 2);
+	UpdateASSCommandStringToSrcTxtCtrl(m_canvas->GenerateASS());
+
+	UpdateFrameUI();
+	ApplySettings();
+
+	#ifdef BETAVERSION
+	wxDateTime expire(15, wxDateTime::Dec, 2007, 0, 0, 0);
+	wxDateTime now = wxDateTime::Now();
+	if (now.IsLaterThan(expire))
+	{
+	 	wxMessageDialog expired(this, "Thank you for trying ASSDraw3. This beta version has expired. Please visit http://malakith.net/aegisub/index.php?topic=912.0 to get the latest release. Visit now?", wxT("Beta version"), wxYES_NO | wxICON_INFORMATION);
+	 	if (expired.ShowModal() == wxID_YES)
+			::wxLaunchDefaultBrowser(wxString("http://malakith.net/aegisub/index.php?topic=912.0"));
+		Close();
+	}
+	SetTitle(wxString::Format("%s beta %d (expires %s)", TITLE, BETAVERSION, expire.FormatDate().c_str()));
+	#endif
+
+	if (firsttime)
+		_About();
+	else if (!behaviors.nosplashscreen)
+		_About(3);
+
+	helpcontroller.SetParentWindow(this);
+	helpcontroller.Initialize(wxFileName(::wxGetCwd(), "ASSDraw3.chm").GetFullPath());
+}
+
+void ASSDrawFrame::SetToolBars()
+{
+    drawtbar = new wxToolBar(this, wxID_ANY, __DPDS__ , wxTB_FLAT | wxTB_TEXT | wxTB_NODIVIDER | wxTB_HORIZONTAL);
+	drawtbar->AddTool(TB_CLEAR, _T("Clear"), wxBITMAP(new_), wxNullBitmap, wxITEM_NORMAL, "", TIPS_CLEAR);
+    //tbar->AddTool(TB_EDITSRC, _T("Source"), wxBITMAP(src_), wxNullBitmap, wxITEM_NORMAL, "", TIPS_EDITSRC);
+    drawtbar->AddCheckTool(TB_PREVIEW, _T("Preview"), wxBITMAP(preview_), wxNullBitmap, "", TIPS_PREVIEW);
+    //drawtbar->AddTool(TB_TRANSFORM, _T("Transform"), wxBITMAP(rot_), wxNullBitmap, wxITEM_NORMAL, "", TIPS_TRANSFORM);
+	zoomslider = new wxSlider(drawtbar, TB_ZOOMSLIDER, 1000, 100, 5000, __DPDS__ );
+	//zoomslider->SetSize(280, zoomslider->GetSize().y);
+	zoomslider->Connect(wxEVT_SCROLL_LINEUP, wxScrollEventHandler(ASSDrawFrame::OnZoomSliderChanged), NULL, this);
+	zoomslider->Connect(wxEVT_SCROLL_LINEDOWN, wxScrollEventHandler(ASSDrawFrame::OnZoomSliderChanged), NULL, this);
+	zoomslider->Connect(wxEVT_SCROLL_PAGEUP, wxScrollEventHandler(ASSDrawFrame::OnZoomSliderChanged), NULL, this);
+	zoomslider->Connect(wxEVT_SCROLL_PAGEDOWN, wxScrollEventHandler(ASSDrawFrame::OnZoomSliderChanged), NULL, this);
+	zoomslider->Connect(wxEVT_SCROLL_THUMBTRACK, wxScrollEventHandler(ASSDrawFrame::OnZoomSliderChanged), NULL, this);
+	zoomslider->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(ASSDrawFrame::OnZoomSliderChanged), NULL, this);
+	drawtbar->AddControl(zoomslider);
+    drawtbar->Realize();
+
+    m_mgr.AddPane(drawtbar, wxAuiPaneInfo().Name(wxT("drawtbar")).Caption(TBNAME_DRAW).
+                  ToolbarPane().Top().Position(0).Dockable(true).LeftDockable(false).RightDockable(false));
+
+    modetbar = new wxToolBar(this, wxID_ANY, __DPDS__ , wxTB_FLAT | wxTB_TEXT | wxTB_NODIVIDER | wxTB_HORIZONTAL);
+    modetbar->AddRadioTool(MODE_ARR, _T("Drag"), wxBITMAP(arr_), wxNullBitmap, "", TIPS_ARR);
+    modetbar->AddRadioTool(MODE_M, _T("Move"), wxBITMAP(m_), wxNullBitmap, "", TIPS_M);
+    //modetbar->AddRadioTool(MODE_N, _T("Move*"), wxBITMAP(n_), wxNullBitmap, "", TIPS_N);
+    modetbar->AddRadioTool(MODE_L, _T("Line"), wxBITMAP(l_), wxNullBitmap, "", TIPS_L);
+    modetbar->AddRadioTool(MODE_B, _T("Bezier"), wxBITMAP(b_), wxNullBitmap, "", TIPS_B);
+    //modetbar->AddRadioTool(MODE_S, _T("Spline"), wxBITMAP(s_), wxNullBitmap, "", TIPS_S);
+    //modetbar->AddRadioTool(MODE_P, _T("Extend"), wxBITMAP(p_), wxNullBitmap, "", TIPS_P);
+    //modetbar->AddRadioTool(MODE_C, _T("Close"), wxBITMAP(c_), wxNullBitmap, "", TIPS_C);
+    modetbar->AddRadioTool(MODE_DEL, _T("Delete"), wxBITMAP(del_), wxNullBitmap, "", TIPS_DEL);
+    modetbar->AddRadioTool(MODE_SCALEROTATE, _T("Scale/Rotate"), wxBITMAP(sc_rot_), wxNullBitmap, "", TIPS_SCALEROTATE);
+    modetbar->AddRadioTool(MODE_NUT_BILINEAR, _T("Bilinear"), wxBITMAP(nut_), wxNullBitmap, "", TIPS_NUTB);
+    //modetbar->AddRadioTool(MODE_NUT_PERSPECTIVE, _T("NUT:P"), wxBITMAP(arr_), wxNullBitmap, "", "");
+    modetbar->Realize();
+
+    m_mgr.AddPane(modetbar, wxAuiPaneInfo().Name(wxT("modetbar")).Caption(TBNAME_MODE).
+                  ToolbarPane().Top().Position(1).Dockable(true).LeftDockable(false).RightDockable(false));
+
+    bgimgtbar = new wxToolBar(this, wxID_ANY, __DPDS__ , wxTB_FLAT | wxTB_TEXT | wxTB_NODIVIDER | wxTB_HORIZONTAL);
+	bgimgtbar->SetToolBitmapSize(wxSize(24,15));
+    bgimgtbar->AddCheckTool(DRAG_DWG, _T("Pan drawing"), wxBITMAP(pan_shp), wxNullBitmap, "", TIPS_DWG);
+    bgimgtbar->AddCheckTool(DRAG_BGIMG, _T("Pan background"), wxBITMAP(pan_bg), wxNullBitmap, "", TIPS_BGIMG);
+    //bgimgtbar->AddRadioTool(DRAG_BOTH, _T("Pan both"), wxBITMAP(pan_both), wxNullBitmap, "", TIPS_BOTH);
+    bgimgtbar->Realize();
+
+    m_mgr.AddPane(bgimgtbar, wxAuiPaneInfo().Name(wxT("bgimgtbar")).Caption(TBNAME_BGIMG).
+                  ToolbarPane().Top().Position(2).Dockable(true).LeftDockable(false).RightDockable(false));
+	
+}
+
+void ASSDrawFrame::SetMenus()
+{
+#if wxUSE_MENUS
+	drawMenu = new wxMenu;
+	drawMenu->Append(MENU_CLEAR, _T("&Clear\tCtrl+N"), TIPS_CLEAR);
+	//drawMenu->Append(MENU_EDITSRC, _T("&Source"), TIPS_EDITSRC);
+	drawMenu->Append(MENU_PREVIEW, _T("&Preview\tCtrl+P"), TIPS_PREVIEW, wxITEM_CHECK);
+	drawMenu->Append(MENU_TRANSFORM, _T("&Transform"), TIPS_TRANSFORM);
+	drawMenu->Append(MENU_PASTE, _T("&Paste\tCtrl+V"), TIPS_PASTE);
+	drawMenu->AppendSeparator();
+	drawMenu->Append(MENU_UNDO, _T("&Undo\tCtrl+Z"), TIPS_UNDO);
+	drawMenu->Append(MENU_REDO, _T("&Redo\tCtrl+Y"), TIPS_REDO);
+	drawMenu->Enable(MENU_UNDO, false);
+	drawMenu->Enable(MENU_REDO, false);
+
+	modeMenu = new wxMenu;
+	modeMenu->Append(MODE_ARR, _T("D&rag\tF1"), TIPS_ARR, wxITEM_RADIO);
+	modeMenu->Append(MODE_M, _T("Draw &M\tF2"), TIPS_M, wxITEM_RADIO);
+	modeMenu->Append(MODE_L, _T("Draw &L\tF3"), TIPS_L, wxITEM_RADIO);
+	modeMenu->Append(MODE_B, _T("Draw &B\tF4"), TIPS_B, wxITEM_RADIO);
+	modeMenu->Append(MODE_DEL, _T("&Delete\tF5"), TIPS_DEL, wxITEM_RADIO);
+	modeMenu->Append(MODE_SCALEROTATE, _T("&Scale/Rotate\tF6"), TIPS_NUTB, wxITEM_RADIO);
+	modeMenu->Append(MODE_NUT_BILINEAR, _T("&Bilinear transformation\tF7"), TIPS_SCALEROTATE, wxITEM_RADIO);
+
+	bgimgMenu = new wxMenu;
+	bgimgMenu->Append(DRAG_DWG, _T("Pan/Zoom &Drawing\tShift+F1"), TIPS_DWG, wxITEM_CHECK);
+	bgimgMenu->Append(DRAG_BGIMG, _T("Pan/Zoom Back&ground\tShift+F2"), TIPS_BGIMG, wxITEM_CHECK);
+	bgimgMenu->AppendSeparator();
+	bgimgMenu->Append(MENU_BGIMG_ALPHA, _T("Set background image opacity"), "");
+	wxMenu* reposbgMenu = new wxMenu;
+	reposbgMenu->Append( MENU_REPOS_BGTOPLEFT, "Top left\tCtrl+Shift+7" );
+	reposbgMenu->Append( MENU_REPOS_BGTOPRIGHT, "Top right\tCtrl+Shift+9" );
+	reposbgMenu->Append( MENU_REPOS_BGCENTER, "&Center\tCtrl+Shift+5" );
+	reposbgMenu->Append( MENU_REPOS_BGBOTLEFT, "Bottom left\tCtrl+Shift+1" );
+	reposbgMenu->Append( MENU_REPOS_BGBOTRIGHT, "Bottom right\tCtrl+Shift+3" );
+	bgimgMenu->Append(MENU_BGIMG_RECENTER, _T("Reposition [&0, 0]"), reposbgMenu);
+	bgimgMenu->Append(MENU_BGIMG_REMOVE, _T("Remove background\tShift+Del"), "");
+
+	wxMenu* reposMenu = new wxMenu;
+	reposMenu->Append( MENU_REPOS_TOPLEFT, "Top left\tCtrl+7" );
+	reposMenu->Append( MENU_REPOS_TOPRIGHT, "Top right\tCtrl+9" );
+	reposMenu->Append( MENU_REPOS_CENTER, "&Center\tCtrl+5" );
+	reposMenu->Append( MENU_REPOS_BOTLEFT, "Bottom left\tCtrl+1" );
+	reposMenu->Append( MENU_REPOS_BOTRIGHT, "Bottom right\tCtrl+3" );
+
+	tbarMenu = new wxMenu;
+	tbarMenu->AppendCheckItem(MENU_TB_DRAW, TBNAME_DRAW);
+	tbarMenu->AppendCheckItem(MENU_TB_MODE, TBNAME_MODE);
+	tbarMenu->AppendCheckItem(MENU_TB_BGIMG, TBNAME_BGIMG);
+	tbarMenu->AppendSeparator();
+	tbarMenu->Append(MENU_TB_ALL, "Show all");
+	tbarMenu->Append(MENU_TB_NONE, "Hide all");
+	tbarMenu->Append(MENU_TB_DOCK, "Dock all");
+	tbarMenu->Append(MENU_TB_UNDOCK, "Undock all");
+
+	viewMenu = new wxMenu;
+	viewMenu->Append(MENU_LIBRARY, _T("&Library"), TIPS_LIBRARY, wxITEM_CHECK);
+	if (settingsdlg)
+		viewMenu->Append(MENU_SETTINGS, _T("&Settings"), "", wxITEM_CHECK);
+	viewMenu->Append(MENU_TBAR, _T("&Toolbars"), tbarMenu);
+	viewMenu->Append(MENU_RECENTER, _T("Reposition [&0, 0]"), reposMenu);
+	viewMenu->AppendSeparator();
+	viewMenu->Append(MENU_RESETPERSPECTIVE, _T("&Reset workspace"));
+
+	wxMenu* helpMenu = new wxMenu;
+	helpMenu->Append(MENU_HELP, _T("&Manual"));
+	helpMenu->Append(wxID_ABOUT, _T("&About"));
+
+	wxMenuBar *menuBar = new wxMenuBar();
+	menuBar->Append(drawMenu, _T("&Canvas"));
+	menuBar->Append(modeMenu, _T("&Mode"));
+	menuBar->Append(bgimgMenu, _T("&Background"));
+	menuBar->Append(viewMenu, _T("&Workspace"));
+	menuBar->Append(helpMenu, _T("&Help"));
+
+
+	SetMenuBar(menuBar);
+#endif // wxUSE_MENUS
+}
+
+void ASSDrawFrame::SetPanes()
+{
+	m_mgr.AddPane(shapelib, wxAuiPaneInfo().Name(wxT("library")).Caption(wxT("Shapes Library")).
+                  Right().Layer(2).Position(0).CloseButton(true).BestSize(wxSize(120, 480)).MinSize(wxSize(100, 200)));
+
+	m_mgr.AddPane(m_canvas, wxAuiPaneInfo().Name(wxT("canvas")).CenterPane());
+
+	m_mgr.AddPane(srctxtctrl, wxAuiPaneInfo().Name(wxT("commands")).Caption(wxT("Drawing commands")).
+                  Bottom().Layer(1).CloseButton(false).BestSize(wxSize(320, 48)));
+	
+	if (settingsdlg)
+		m_mgr.AddPane(settingsdlg, wxAuiPaneInfo().Name(wxT("settings")).Caption(wxT("Settings")).
+                  Right().Layer(3).Position(0).CloseButton(true).BestSize(wxSize(240, 480)).MinSize(wxSize(200, 200)).Show(false));
+}
+
+ASSDrawFrame::~ASSDrawFrame()
+{
+	config->SetPath("info");
+	config->Write("assdraw3.exe", wxStandardPaths::Get().GetExecutablePath());
+	config->Write("version", VERSION);
+	config->SetPath("..");
+
+	SaveSettings();
+	
+	config->SetPath("perspective");
+	config->Write("perspective", m_mgr.SavePerspective());
+	config->SetPath("..");
+
+	config->DeleteGroup("library");
+	config->SetPath("library");
+	typedef std::vector< ASSDrawShapePreview *> PrevVec;
+	PrevVec shapes = shapelib->GetShapePreviews();
+	int n = shapes.size();
+	config->Write("n", n);
+	for (int i = 0; i < n; i++)
+		config->Write(wxString::Format("%d",i), shapes[i]->GenerateASS());
+	config->SetPath("..");
+
+	wxFileOutputStream cfgf(configfile);
+	config->Save(cfgf);
+	delete config;
+	
+	if (settingsdlg) settingsdlg->Destroy(); // we need this since wxPropertyGrid must be Clear()ed before deleting
+
+	m_mgr.UnInit();
+}
+
+void ASSDrawFrame::_Clear()
+{
+	wxMessageDialog msgb(this, _T("Clear the canvas and create a new drawing?"), 
+                  _T("Confirmation"), wxOK | wxCANCEL | wxICON_QUESTION );
+	if (msgb.ShowModal() == wxID_OK)
+	{
+		m_canvas->RefreshUndocmds();
+		m_canvas->AddUndo("Clear canvas");
+		m_canvas->ResetEngine(true);
+	    wxSize siz = m_canvas->GetClientSize();
+		m_canvas->ChangeZoomLevelTo(DEFAULT_SCALE, wxPoint(siz.x / 2, siz.y / 2));
+		m_canvas->MoveCanvasOriginTo(siz.x / 2, siz.y / 2);
+		UpdateUndoRedoMenu();
+		m_canvas->RefreshDisplay();
+	}
+}
+
+void ASSDrawFrame::_Preview()
+{
+	m_canvas->SetPreviewMode( !m_canvas->IsPreviewMode() );
+	UpdateFrameUI();
+	m_canvas->RefreshDisplay();
+}
+
+void ASSDrawFrame::_ToggleLibrary()
+{
+	m_mgr.GetPane(shapelib).Show(!m_mgr.GetPane(shapelib).IsShown());
+	m_mgr.Update();
+	UpdateFrameUI();
+}
+
+void ASSDrawFrame::_ToggleSettings()
+{
+	if (settingsdlg == NULL) return;
+	m_mgr.GetPane(settingsdlg).Show(!m_mgr.GetPane(settingsdlg).IsShown());
+	m_mgr.Update();
+	UpdateFrameUI();
+}
+
+void ASSDrawFrame::_ResetPerspective()
+{
+	m_mgr.LoadPerspective(default_perspective, false);
+	UpdateFrameUI();
+	m_mgr.Update();
+	DRAGMODE bck = m_canvas->GetDragMode();
+	if (m_canvas->HasBackgroundImage()) m_canvas->SetDragMode(DRAGMODE(true, true));
+	wxSize clientsize = m_canvas->GetClientSize();
+	m_canvas->ChangeZoomLevelTo(DEFAULT_SCALE, wxPoint(clientsize.x / 2, clientsize.y / 2));
+	m_canvas->MoveCanvasOriginTo(clientsize.x / 2, clientsize.y / 2);
+	m_canvas->SetDragMode(bck);
+	UpdateFrameUI();
+}
+
+void ASSDrawFrame::_Transform()
+{
+	if (transformdlg == NULL)
+		transformdlg = new ASSDrawTransformDlg( this );
+
+	if (transformdlg->ShowModal() == wxID_OK)
+	{
+		m_canvas->Transform(
+			transformdlg->xformvals.f1,
+			transformdlg->xformvals.f2,
+			transformdlg->xformvals.f3,
+			transformdlg->xformvals.f4,
+			transformdlg->xformvals.f5,
+			transformdlg->xformvals.f6,
+			transformdlg->xformvals.f7,
+			transformdlg->xformvals.f8 );
+		m_canvas->AddUndo("Transform");
+		m_canvas->RefreshDisplay();
+		UpdateUndoRedoMenu();
+	}
+}
+
+void ASSDrawFrame::_Paste()
+{
+	if (wxTheClipboard->Open())
+	{
+		if (wxTheClipboard->IsSupported( wxDF_BITMAP ))
+		{
+			wxBitmapDataObject data;
+			wxTheClipboard->GetData( data );
+			m_canvas->SetBackgroundImage( data.GetBitmap().ConvertToImage() );
+			//m_canvas->AskUserForBackgroundAlpha();
+		}
+		else if (wxTheClipboard->IsSupported( wxDF_TEXT ))
+		{
+			wxTextDataObject data;
+			wxTheClipboard->GetData( data );
+			UpdateASSCommandStringToSrcTxtCtrl( data.GetText() );
+		}
+		wxTheClipboard->Close();
+	}
+}
+
+void ASSDrawFrame::OnChoose_Recenter(wxCommandEvent& event)
+{
+	int x = 0, y = 0;
+	wxSize f = m_canvas->GetClientSize();
+
+	switch (event.GetId())
+	{
+	case MENU_REPOS_TOPLEFT: x = 0, y = 0; break;
+	case MENU_REPOS_TOPRIGHT: x = f.x, y = 0; break;
+	case MENU_REPOS_CENTER: x = f.x / 2, y = f.y / 2; break;
+	case MENU_REPOS_BOTLEFT: x = 0, y = f.y; break;
+	case MENU_REPOS_BOTRIGHT: x = f.x, y = f.y; break;
+	}
+
+	m_canvas->MoveCanvasOriginTo(x, y);
+	m_canvas->RefreshDisplay();
+}
+
+void ASSDrawFrame::OnChoose_RecenterToBG(wxCommandEvent& event)
+{
+	unsigned w, h;
+	wxRealPoint disp;
+	double scale;
+	if (m_canvas->GetBackgroundInfo(w, h, disp, scale))
+	{
+		int x = 0, y = 0;
+		int lx = (int)disp.x, ty = (int)disp.y;
+		int rx = lx + (int)(w * scale);
+		int by = ty + (int)(h * scale);
+		
+		switch (event.GetId())
+		{
+		case MENU_REPOS_BGTOPLEFT: x = lx, y = ty; break;
+		case MENU_REPOS_BGTOPRIGHT: x = rx, y = ty; break;
+		case MENU_REPOS_BGCENTER: x = (rx + lx) / 2, y = (by + ty) / 2; break;
+		case MENU_REPOS_BGBOTLEFT: x = lx, y = by; break;
+		case MENU_REPOS_BGBOTRIGHT: x = rx, y = by; break;
+		}
+	
+		m_canvas->MoveCanvasDrawing(x - m_canvas->GetOriginX(), y - m_canvas->GetOriginY());
+		m_canvas->RefreshDisplay();
+	}
+}
+
+void ASSDrawFrame::_Help()
+{
+	helpcontroller.DisplayContents();
+}
+
+void ASSDrawFrame::_About(unsigned timeout)
+{
+	ASSDrawAboutDlg *aboutdlg = new ASSDrawAboutDlg( this, timeout );
+	aboutdlg->ShowModal();
+	aboutdlg->Destroy();
+}
+
+void ASSDrawFrame::OnChoose_Mode(wxCommandEvent& event)
+{
+	m_canvas->SetDrawMode( (MODE) event.GetId() );
+	UpdateFrameUI();
+}
+
+void ASSDrawFrame::OnChoose_DragMode(wxCommandEvent& event)
+{
+	DRAGMODE dm = m_canvas->GetDragMode();
+	switch (event.GetId())
+	{
+		case DRAG_DWG: dm.drawing = !dm.drawing; break;
+		case DRAG_BGIMG: dm.bgimg = !dm.bgimg; break;
+	}
+	m_canvas->SetDragMode( dm );
+	UpdateFrameUI();
+}
+
+void ASSDrawFrame::OnZoomSliderChanged(wxScrollEvent &event)
+{
+	double zoom = (double) event.GetPosition() / 100.0;
+	m_canvas->ChangeZoomLevelTo(zoom, wxPoint((int) m_canvas->GetOriginX(), (int) m_canvas->GetOriginY()));
+}
+
+void ASSDrawFrame::OnToolRClick(wxCommandEvent& event)
+{
+	int id = event.GetId();
+	if (drawtbar->FindById(id) != NULL
+		|| modetbar->FindById(id) != NULL
+		|| bgimgtbar->FindById(id) != NULL)
+	{
+		PopupMenu(tbarMenu);
+	}
+}
+
+void ASSDrawFrame::OnChoose_TBarRClickMenu(wxCommandEvent& event)
+{
+	int id = event.GetId();
+	wxToolBar* tbar[3] = { drawtbar, modetbar, bgimgtbar };
+	bool tb[3] = { false, false, false };
+	bool show[2] = { false, true };
+	bool dock[2] = { false, true };
+	switch (id)
+	{
+	case MENU_TB_ALL: 
+		tb[0] = true, tb[1] = true, tb[2] = true;
+		show[0] = true, show[1] = true;
+		break;
+	case MENU_TB_NONE: 
+		tb[0] = true, tb[1] = true, tb[2] = true;
+		show[0] = true, show[1] = false;
+		break;
+	case MENU_TB_DOCK: 
+		tb[0] = true, tb[1] = true, tb[2] = true;
+		dock[0] = true, dock[1] = true;
+		break;
+	case MENU_TB_UNDOCK: 
+		tb[0] = true, tb[1] = true, tb[2] = true;
+		dock[0] = true, dock[1] = false;
+		break;
+	case MENU_TB_DRAW: 
+		tb[0] = true;
+		show[0] = true, show[1] = !m_mgr.GetPane(tbar[0]).IsShown();
+		break;
+	case MENU_TB_MODE: 
+		tb[1] = true;
+		show[0] = true, show[1] = !m_mgr.GetPane(tbar[1]).IsShown();
+		break;
+	case MENU_TB_BGIMG: 
+		tb[2] = true;
+		show[0] = true, show[1] = !m_mgr.GetPane(tbar[2]).IsShown();
+		break;
+	}
+	for (int i = 0; i < 3; i++)
+	{
+		if (tb[i])
+		{
+			if (show[0])
+				m_mgr.GetPane(tbar[i]).Show(show[1]);
+			if (dock[0])
+				if (dock[1])
+					m_mgr.GetPane(tbar[i]).Dock();
+				else
+					m_mgr.GetPane(tbar[i]).Float();
+		}
+	}
+	m_mgr.Update();
+	UpdateFrameUI();
+}
+
+void ASSDrawFrame::UpdateASSCommandStringFromSrcTxtCtrl(wxString cmds)
+{
+	m_canvas->ParseASS(cmds, true);
+	m_canvas->RefreshDisplay();
+}
+
+void ASSDrawFrame::UpdateASSCommandStringToSrcTxtCtrl(wxString cmd)
+{
+	if (behaviors.capitalizecmds)
+		cmd.UpperCase();
+	else
+		cmd.LowerCase();
+	srctxtctrl->ChangeValue(cmd);
+	//srctxtctrl->AppendText(cmd);
+}
+
+void ASSDrawFrame::UndoOrRedo(bool isundo)
+{
+	if (isundo)
+		m_canvas->Undo();
+	else
+		m_canvas->Redo();
+	UpdateUndoRedoMenu();
+	UpdateFrameUI();
+}
+
+void ASSDrawFrame::UpdateUndoRedoMenu()
+{
+	wxString nextUndo = m_canvas->GetTopUndo();
+	if (nextUndo.IsSameAs(""))
+	{
+		drawMenu->SetLabel(MENU_UNDO, "Undo\tCtrl+Z");
+		drawMenu->Enable(MENU_UNDO, false);
+	}
+	else
+	{
+		drawMenu->SetLabel(MENU_UNDO, wxString::Format("Undo: %s\tCtrl+Z", nextUndo.c_str()));
+		drawMenu->Enable(MENU_UNDO, true);
+	}
+	wxString nextRedo = m_canvas->GetTopRedo();
+	if (nextRedo.IsSameAs(""))
+	{
+		drawMenu->SetLabel(MENU_REDO, "Redo\tCtrl+Y");
+		drawMenu->Enable(MENU_REDO, false);
+	}
+	else
+	{
+		drawMenu->SetLabel(MENU_REDO, wxString::Format("Redo: %s\tCtrl+Y", nextRedo.c_str()));
+		drawMenu->Enable(MENU_REDO, true);
+	}
+}
+
+void ASSDrawFrame::UpdateFrameUI(unsigned level)
+{
+	bool hasbg = m_canvas->HasBackgroundImage();
+	int zoom = (int) round(m_canvas->GetScale() * 100.0);
+	switch (level)
+	{
+	case 0: // all
+		drawtbar->ToggleTool(TB_PREVIEW, m_canvas->IsPreviewMode());
+		modetbar->ToggleTool(m_canvas->GetDrawMode(), true);
+		#if wxUSE_MENUS
+		drawMenu->Check(MENU_PREVIEW, m_canvas->IsPreviewMode());
+		modeMenu->Check(m_canvas->GetDrawMode(), true);
+		#endif
+	case 2: // bgimg & toolbars
+		//bgimgtbar->ToggleTool(m_canvas->GetDragMode(), true);
+		bgimgtbar->ToggleTool(DRAG_DWG, m_canvas->GetDragMode().drawing);
+		bgimgtbar->ToggleTool(DRAG_BGIMG, m_canvas->GetDragMode().bgimg);
+		bgimgtbar->EnableTool(DRAG_BGIMG, hasbg);
+		//m_mgr.GetPane(bgimgtbar).Show(hasbg);
+		m_mgr.Update();
+		#if wxUSE_MENUS
+		viewMenu->Check(MENU_LIBRARY, m_mgr.GetPane(shapelib).IsShown());
+		if (settingsdlg)
+			viewMenu->Check(MENU_SETTINGS, m_mgr.GetPane(settingsdlg).IsShown());
+		//bgimgMenu->Check(m_canvas->GetDragMode(), true);
+		bgimgMenu->Check(DRAG_DWG, m_canvas->GetDragMode().drawing);
+		bgimgMenu->Check(DRAG_BGIMG, m_canvas->GetDragMode().bgimg);
+		bgimgMenu->Enable(DRAG_BGIMG, hasbg);
+		bgimgMenu->Enable(DRAG_BOTH, hasbg);
+		bgimgMenu->Enable(MENU_BGIMG_ALPHA, hasbg);
+		bgimgMenu->Enable(MENU_BGIMG_RECENTER, hasbg);
+		bgimgMenu->Enable(MENU_BGIMG_REMOVE, hasbg);
+		tbarMenu->Check(MENU_TB_DRAW, m_mgr.GetPane(drawtbar).IsShown());
+		tbarMenu->Check(MENU_TB_MODE, m_mgr.GetPane(modetbar).IsShown());
+		tbarMenu->Check(MENU_TB_BGIMG, m_mgr.GetPane(bgimgtbar).IsShown());
+		#endif
+	case 3:	// zoom slider
+		zoomslider->SetValue(zoom);
+		SetStatusText( wxString::Format("%d%%", zoom), 2 );
+		zoomslider->Enable(m_canvas->GetDragMode().drawing && m_canvas->CanZoom());
+	}
+}
+
+void ASSDrawFrame::OnClose(wxCloseEvent &event)
+{
+	if (event.CanVeto() && behaviors.confirmquit)
+	{
+		if (wxMessageDialog(this, wxT("Do you want to close ASSDraw3 now?"), wxT("Confirmation"), wxOK | wxCANCEL).ShowModal() == wxID_OK)
+			Destroy();	
+		else
+			event.Veto();
+	}
+	else
+		Destroy();	
+}
diff --git a/assdraw/src/assdraw.hpp b/assdraw/src/assdraw.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..065383d74f183300e3da732ca9e99a587ae1950c
--- /dev/null
+++ b/assdraw/src/assdraw.hpp
@@ -0,0 +1,208 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        assdraw.hpp
+// Purpose:     header file for ASSDraw main source file; also includes
+//              declarations for all GUI elements (except wxRuler, which has
+//              its own header file)
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "_common.hpp"
+
+#include <vector>
+#include <wx/aui/aui.h>
+#include <wx/fileconf.h>
+#include <wx/help.h>
+
+#include "canvas.hpp" // the canvas
+#include "dlgctrl.hpp" // custom dialogs & controls
+#include "settings.hpp" // settings property grid
+#include "library.hpp" // shape library
+
+//#define BETAVERSION 2
+#define VERSION "3.0 final"
+
+// this header file declares the following classes
+class ASSDrawApp;
+class ASSDrawFrame;
+class ASSDrawCanvas;
+
+class ASSDrawApp : public wxApp 
+{ 
+public:      
+    bool OnInit();
+};
+
+class ASSDrawFrame : public wxFrame
+{
+public:
+    // constructor
+    ASSDrawFrame(wxApp *app, const wxString& title, const wxPoint& pos, const wxSize& size = wxDefaultSize,
+            long style = wxDEFAULT_FRAME_STYLE);
+    virtual ~ASSDrawFrame();
+
+    // event handlers (these functions should _not_ be virtual)
+	// OnSelect_* for single items, OnChoose_* for many-choose-one items
+	void OnSelect_Clear(wxCommandEvent& WXUNUSED(event)) { _Clear(); }
+	void OnSelect_Preview(wxCommandEvent& WXUNUSED(event)) { _Preview(); }
+	void OnSelect_Transform(wxCommandEvent& WXUNUSED(event)) { _Transform(); }
+	void OnSelect_Library(wxCommandEvent& WXUNUSED(event)) { _ToggleLibrary(); }
+	void OnSelect_Settings(wxCommandEvent& WXUNUSED(event)) { _ToggleSettings(); }
+	void OnSelect_ResetPerspective(wxCommandEvent& WXUNUSED(event)) { _ResetPerspective(); }
+	void OnSelect_Help(wxCommandEvent& WXUNUSED(event)) { _Help(); }
+	void OnSelect_About(wxCommandEvent& WXUNUSED(event)) { _About(); }
+	void OnSelect_Undo(wxCommandEvent& WXUNUSED(event)) { UndoOrRedo( true ); }
+	void OnSelect_Redo(wxCommandEvent& WXUNUSED(event)) { UndoOrRedo( false ); }
+	void OnSelect_Paste(wxCommandEvent& WXUNUSED(event)) { _Paste(); }
+	void OnSelect_RemoveBG(wxCommandEvent& WXUNUSED(event)) { m_canvas->RemoveBackgroundImage(); }
+	void OnSelect_AlphaBG(wxCommandEvent& WXUNUSED(event)) { m_canvas->AskUserForBackgroundAlpha(); }
+	void OnChoose_Recenter(wxCommandEvent& event);
+	void OnChoose_RecenterToBG(wxCommandEvent& event);
+	void OnChoose_Mode(wxCommandEvent& event);
+	void OnChoose_DragMode(wxCommandEvent& event);
+	void OnZoomSliderChanged(wxScrollEvent &event);
+	void OnToolRClick(wxCommandEvent& event);
+	void OnChoose_TBarRClickMenu(wxCommandEvent& event);
+	void OnSettingsChanged(wxCommandEvent& event);
+	void OnClose(wxCloseEvent &event);
+
+	void UpdateASSCommandStringToSrcTxtCtrl(wxString cmds);
+	void UpdateASSCommandStringFromSrcTxtCtrl(wxString cmds);
+
+	void UndoOrRedo(bool isundo);
+	void UpdateUndoRedoMenu();
+
+    void _Clear();
+    void _Preview();
+    void _Transform();
+	void _ToggleLibrary();
+	void _ToggleSettings();
+    void _Help();
+    void _About(unsigned timeout = 0);
+    void _Paste();
+    void _ResetPerspective();
+
+	void UpdateFrameUI(unsigned level = 0);
+
+    // the canvas
+    wxApp *m_app;
+    ASSDrawCanvas* m_canvas;
+	wxAuiManager m_mgr;
+	wxString default_perspective;
+	ASSDrawSrcTxtCtrl* srctxtctrl;
+
+	// config
+	wxString configfile;
+	wxFileConfig *config;
+	
+    // toolbars
+    wxToolBar *drawtbar, *modetbar, *bgimgtbar;
+	
+	// zoom slider
+	wxSlider* zoomslider;
+	
+	//library
+	ASSDrawShapeLibrary *shapelib;
+	typedef std::vector< ASSDrawEngine* > DrawEngineVec;
+	DrawEngineVec libshapes;
+	
+	// menus
+#if wxUSE_MENUS
+    wxMenu *drawMenu;
+    wxMenu *modeMenu;
+    wxMenu *bgimgMenu;
+    wxMenu *viewMenu;
+    wxMenu *tbarMenu;
+#endif
+
+	// dialogs
+	ASSDrawTransformDlg* transformdlg;	
+	ASSDrawSettingsDialog* settingsdlg;
+	
+	// colors
+	struct
+	{
+		wxColour canvas_bg;
+		wxColour canvas_shape_normal;
+		wxColour canvas_shape_preview;
+		wxColour canvas_shape_outline;
+		wxColour canvas_shape_guideline;
+		wxColour canvas_shape_mainpoint;
+		wxColour canvas_shape_controlpoint;
+		wxColour canvas_shape_selectpoint;
+		wxColour library_shape;
+		wxColour library_libarea;
+		wxColour origin, ruler_h, ruler_v;
+	} colors;
+
+	struct
+	{
+		long canvas_shape_normal;
+		long canvas_shape_preview;
+		long canvas_shape_outline;
+		long canvas_shape_guideline;
+		long canvas_shape_mainpoint;
+		long canvas_shape_controlpoint;
+		long canvas_shape_selectpoint;
+	} alphas;
+
+	struct
+	{
+		long origincross;
+	} sizes;
+	
+	struct
+	{
+		bool capitalizecmds;
+		bool autoaskimgopac;
+		bool parse_spc;
+		bool nosplashscreen;
+		bool confirmquit;
+	} behaviors;
+	
+	void LoadSettings();
+	void SaveSettings();
+	void InitializeDefaultSettings();
+	void ApplySettings();
+	static void wxColourToAggRGBA(wxColour &colour, agg::rgba &rgba);
+	static void wxColourSetAlpha(wxColour &colour, long alpha);
+
+protected:
+	virtual void SetToolBars();
+	virtual void SetMenus();
+	virtual void SetPanes();
+	DECLARE_EVENT_TABLE()
+	
+	wxHelpController helpcontroller;
+
+};
diff --git a/assdraw/src/assdraw.rc b/assdraw/src/assdraw.rc
new file mode 100644
index 0000000000000000000000000000000000000000..1ee736c0de833a0a99e80639bb74a98e50baf043
--- /dev/null
+++ b/assdraw/src/assdraw.rc
@@ -0,0 +1,101 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+APPICO                  ICON                    "../tsukasa.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+ASSDRAW3_               BITMAP                  "../bitmaps/assdraw3.bmp"
+NEW_                    BITMAP                  "../bitmaps/new_.bmp"
+SRC_                    BITMAP                  "../bitmaps/src_.bmp"
+PREVIEW_                BITMAP                  "../bitmaps/preview_.bmp"
+ARR_                    BITMAP                  "../bitmaps/arr_.bmp"
+M_                      BITMAP                  "../bitmaps/m_.bmp"
+N_                      BITMAP                  "../bitmaps/n_.bmp"
+L_                      BITMAP                  "../bitmaps/l_.bmp"
+B_                      BITMAP                  "../bitmaps/b_.bmp"
+S_                      BITMAP                  "../bitmaps/s_.bmp"
+P_                      BITMAP                  "../bitmaps/p_.bmp"
+C_                      BITMAP                  "../bitmaps/c_.bmp"
+DEL_                    BITMAP                  "../bitmaps/del_.bmp"
+NUT_                    BITMAP                  "../bitmaps/nut_.bmp"
+SC_ROT_                 BITMAP                  "../bitmaps/sc_rot_.bmp"
+ROT_                    BITMAP                  "../bitmaps/rot_.bmp"
+HELP_                   BITMAP                  "../bitmaps/help_.bmp"
+TRANSFORM               BITMAP                  "../bitmaps/transform.bmp"
+PAN_SHP                 BITMAP                  "../bitmaps/pan_shp.bmp"
+PAN_BG                  BITMAP                  "../bitmaps/pan_bg.bmp"
+//PAN_BOTH                BITMAP                  "../bitmaps/pan_both.bmp"
+ADD                     BITMAP                  "../bitmaps/add_.bmp"
+CHECK                   BITMAP                  "../bitmaps/check_.bmp"
+UNCHECK                 BITMAP                  "../bitmaps/uncheck_.bmp"
+DELCROSS                BITMAP                  "../bitmaps/del_cross.bmp"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/assdraw/src/assdraw_settings.cpp b/assdraw/src/assdraw_settings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..860cdcd184c89d5ea4d4888be74af48d5f68c3f7
--- /dev/null
+++ b/assdraw/src/assdraw_settings.cpp
@@ -0,0 +1,190 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "assdraw.hpp"
+
+void ASSDrawFrame::InitializeDefaultSettings()
+{
+	colors.canvas_bg = wxColour(0xFF, 0xFF, 0xFF);
+	colors.canvas_shape_normal = wxColour(0x0, 0x0, 0xFF, 0x99);
+	colors.canvas_shape_preview = wxColour(0x0, 0x0, 0xFF);
+	colors.canvas_shape_outline = wxColour(0x0, 0x0, 0x0);
+	colors.canvas_shape_guideline = wxColour(0x66, 0x66, 0x66);
+	colors.canvas_shape_mainpoint = wxColour(0xFF, 0x0, 0x0, 0xCC);
+	colors.canvas_shape_controlpoint = wxColour(0x0, 0xFF, 0x0, 0xCC);
+	colors.canvas_shape_selectpoint = wxColour(0x0, 0x0, 0xCC);
+	colors.library_shape = wxColour(0x0, 0x66, 0x99);
+	colors.library_libarea = wxColour(0xFF, 0xFF, 0x99);
+	colors.origin = wxColour(0xFF, 0x0, 0x0);
+	colors.ruler_h = wxColour(0x0, 0x0, 0x66);
+	colors.ruler_v = wxColour(0x66, 0x0, 0x0);
+
+	alphas.canvas_shape_normal = 128;
+	alphas.canvas_shape_preview = 255;
+	alphas.canvas_shape_outline = 255;
+	alphas.canvas_shape_guideline = 255;
+	alphas.canvas_shape_mainpoint = 128;
+	alphas.canvas_shape_controlpoint = 128;
+	alphas.canvas_shape_selectpoint = 255;
+
+	sizes.origincross = 2;
+
+	behaviors.capitalizecmds = false;
+	behaviors.autoaskimgopac = true;
+	behaviors.parse_spc = false;
+	behaviors.nosplashscreen = false;
+	behaviors.confirmquit = true;
+}
+
+void ASSDrawFrame::ApplySettings()
+{
+	wxColourSetAlpha(colors.canvas_shape_normal, alphas.canvas_shape_normal);
+	wxColourSetAlpha(colors.canvas_shape_preview, alphas.canvas_shape_preview);
+	wxColourSetAlpha(colors.canvas_shape_outline, alphas.canvas_shape_outline);
+	wxColourSetAlpha(colors.canvas_shape_guideline, alphas.canvas_shape_guideline);
+	wxColourSetAlpha(colors.canvas_shape_mainpoint, alphas.canvas_shape_mainpoint);
+	wxColourSetAlpha(colors.canvas_shape_controlpoint, alphas.canvas_shape_controlpoint);
+	wxColourSetAlpha(colors.canvas_shape_selectpoint, alphas.canvas_shape_selectpoint);
+
+	wxColourToAggRGBA(colors.canvas_shape_normal, m_canvas->rgba_shape_normal);
+	wxColourToAggRGBA(colors.canvas_shape_preview, m_canvas->rgba_shape);
+	wxColourToAggRGBA(colors.canvas_shape_outline, m_canvas->rgba_outline);
+	wxColourToAggRGBA(colors.canvas_shape_guideline, m_canvas->rgba_guideline);
+	wxColourToAggRGBA(colors.canvas_shape_mainpoint, m_canvas->rgba_mainpoint);
+	wxColourToAggRGBA(colors.canvas_shape_controlpoint, m_canvas->rgba_controlpoint);
+	wxColourToAggRGBA(colors.canvas_shape_selectpoint, m_canvas->rgba_selectpoint);
+	wxColourToAggRGBA(colors.origin, m_canvas->rgba_origin);
+	wxColourToAggRGBA(colors.ruler_h, m_canvas->rgba_ruler_h);
+	wxColourToAggRGBA(colors.ruler_v, m_canvas->rgba_ruler_v);
+
+	m_canvas->color_bg.r = colors.canvas_bg.Red();
+	m_canvas->color_bg.g = colors.canvas_bg.Green();
+	m_canvas->color_bg.b = colors.canvas_bg.Blue();
+	m_canvas->color_bg.a = colors.canvas_bg.Alpha();
+	m_canvas->PrepareBackgroundBitmap(-1.0);
+	m_canvas->Refresh();
+
+	shapelib->libarea->SetBackgroundColour(colors.library_libarea);
+	typedef std::vector< ASSDrawShapePreview *> PrevVec;
+	PrevVec shapes = shapelib->GetShapePreviews();
+	int n = shapes.size();
+	for (int i = 0; i < n; i++)
+		wxColourToAggRGBA(colors.library_shape, shapes[i]->rgba_shape);
+	shapelib->libarea->Refresh();
+	
+	m_canvas->SetDrawCmdSet(wxT(behaviors.parse_spc? "m n l b s p c _":"m n l b _"));
+
+	UpdateASSCommandStringToSrcTxtCtrl(m_canvas->GenerateASS());
+}
+
+void ASSDrawFrame::wxColourToAggRGBA(wxColour &colour, agg::rgba &rgba)
+{
+	rgba.r = (double) colour.Red() / 255.0;
+	rgba.g = (double) colour.Green() / 255.0;
+	rgba.b = (double) colour.Blue() / 255.0;
+	rgba.a = (double) colour.Alpha() / 255.0;
+}
+
+void ASSDrawFrame::wxColourSetAlpha(wxColour &colour, long alpha)
+{
+	colour.Set(colour.Red(), colour.Green(), colour.Blue(), alpha);
+}
+
+void ASSDrawFrame::OnSettingsChanged(wxCommandEvent& event)
+{
+	ApplySettings();
+}
+
+void ASSDrawFrame::LoadSettings()
+{
+	#define CFGREADCOLOR(color) if (config->Read(#color, &tmpstr)) color.Set(tmpstr);
+	#define CFGREAD(var) config->Read(#var, &var);
+	config->SetPath("settings");
+	wxString tmpstr;
+	CFGREADCOLOR(colors.canvas_bg)
+	CFGREADCOLOR(colors.canvas_shape_normal)
+	CFGREADCOLOR(colors.canvas_shape_preview)
+	CFGREADCOLOR(colors.canvas_shape_controlpoint)
+	CFGREADCOLOR(colors.canvas_shape_guideline)
+	CFGREADCOLOR(colors.canvas_shape_mainpoint)
+	CFGREADCOLOR(colors.canvas_shape_outline)
+	CFGREADCOLOR(colors.canvas_shape_selectpoint)
+	CFGREADCOLOR(colors.library_libarea)
+	CFGREADCOLOR(colors.library_shape)
+	CFGREADCOLOR(colors.origin)
+	CFGREADCOLOR(colors.ruler_h)
+	CFGREADCOLOR(colors.ruler_v)
+	CFGREAD(alphas.canvas_shape_normal)
+	CFGREAD(alphas.canvas_shape_preview)
+	CFGREAD(alphas.canvas_shape_controlpoint)
+	CFGREAD(alphas.canvas_shape_guideline)
+	CFGREAD(alphas.canvas_shape_mainpoint)
+	CFGREAD(alphas.canvas_shape_outline)
+	CFGREAD(alphas.canvas_shape_selectpoint)
+	CFGREAD(sizes.origincross)
+	CFGREAD(behaviors.autoaskimgopac)
+	CFGREAD(behaviors.capitalizecmds)
+	CFGREAD(behaviors.parse_spc)
+	CFGREAD(behaviors.nosplashscreen)
+	CFGREAD(behaviors.confirmquit)
+	config->SetPath("..");
+}
+
+void ASSDrawFrame::SaveSettings()
+{
+	#define CFGWRITE(var) config->Write(#var, var);
+	#define CFGWRITECOLOR(color) config->Write(#color, color.GetAsString(wxC2S_HTML_SYNTAX));
+	config->SetPath("settings");
+	CFGWRITECOLOR(colors.canvas_bg)
+	CFGWRITECOLOR(colors.canvas_shape_normal)
+	CFGWRITECOLOR(colors.canvas_shape_preview)
+	CFGWRITECOLOR(colors.canvas_shape_controlpoint)
+	CFGWRITECOLOR(colors.canvas_shape_guideline)
+	CFGWRITECOLOR(colors.canvas_shape_mainpoint)
+	CFGWRITECOLOR(colors.canvas_shape_outline)
+	CFGWRITECOLOR(colors.canvas_shape_selectpoint)
+	CFGWRITECOLOR(colors.library_libarea)
+	CFGWRITECOLOR(colors.library_shape)
+	CFGWRITECOLOR(colors.origin)
+	CFGWRITECOLOR(colors.ruler_h)
+	CFGWRITECOLOR(colors.ruler_v)
+	CFGWRITE(alphas.canvas_shape_normal)
+	CFGWRITE(alphas.canvas_shape_preview)
+	CFGWRITE(alphas.canvas_shape_controlpoint)
+	CFGWRITE(alphas.canvas_shape_guideline)
+	CFGWRITE(alphas.canvas_shape_mainpoint)
+	CFGWRITE(alphas.canvas_shape_outline)
+	CFGWRITE(alphas.canvas_shape_selectpoint)
+	CFGWRITE(sizes.origincross)
+	CFGWRITE(behaviors.autoaskimgopac)
+	CFGWRITE(behaviors.capitalizecmds)
+	CFGWRITE(behaviors.parse_spc)
+	CFGWRITE(behaviors.nosplashscreen)
+	CFGWRITE(behaviors.confirmquit)
+	config->SetPath("..");
+}
diff --git a/assdraw/src/bitmaps/Copy of assdraw3.bmp b/assdraw/src/bitmaps/Copy of assdraw3.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..4fe735e5bf1bc4002571d9e50ea67e9f68af2087
Binary files /dev/null and b/assdraw/src/bitmaps/Copy of assdraw3.bmp differ
diff --git a/assdraw/src/bitmaps/add_.bmp b/assdraw/src/bitmaps/add_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..5a87ed3fb61ecf967c3c6e8c688499cb34ba5e2d
Binary files /dev/null and b/assdraw/src/bitmaps/add_.bmp differ
diff --git a/assdraw/src/bitmaps/arr_.bmp b/assdraw/src/bitmaps/arr_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..34ec029d12add935038ec13030ba1ee9c85f6536
Binary files /dev/null and b/assdraw/src/bitmaps/arr_.bmp differ
diff --git a/assdraw/src/bitmaps/arr_1.bmp b/assdraw/src/bitmaps/arr_1.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..14f71ee262bdbf90349b6a4192a7773ec0faf601
Binary files /dev/null and b/assdraw/src/bitmaps/arr_1.bmp differ
diff --git a/assdraw/src/bitmaps/assdraw3.bmp b/assdraw/src/bitmaps/assdraw3.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..debaf3c8ba7af02954fce4a505d249fdac00f2f9
Binary files /dev/null and b/assdraw/src/bitmaps/assdraw3.bmp differ
diff --git a/assdraw/src/bitmaps/b_.bmp b/assdraw/src/bitmaps/b_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3046a904840686fb8a5f1fded2d8b9e7cfa29e2c
Binary files /dev/null and b/assdraw/src/bitmaps/b_.bmp differ
diff --git a/assdraw/src/bitmaps/b_.cur b/assdraw/src/bitmaps/b_.cur
new file mode 100644
index 0000000000000000000000000000000000000000..117906dd9c265a87b372c16f74027af59e493fc1
Binary files /dev/null and b/assdraw/src/bitmaps/b_.cur differ
diff --git a/assdraw/src/bitmaps/c_.bmp b/assdraw/src/bitmaps/c_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8a37dae867d6be4f4791b6912361795a637de096
Binary files /dev/null and b/assdraw/src/bitmaps/c_.bmp differ
diff --git a/assdraw/src/bitmaps/check_.bmp b/assdraw/src/bitmaps/check_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..41ca19aa3d69b56c0cb7a33245e35fea8559ac6b
Binary files /dev/null and b/assdraw/src/bitmaps/check_.bmp differ
diff --git a/assdraw/src/bitmaps/del_.bmp b/assdraw/src/bitmaps/del_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..034986fd0cd52f869f4e60611cb833efb6ad2f7b
Binary files /dev/null and b/assdraw/src/bitmaps/del_.bmp differ
diff --git a/assdraw/src/bitmaps/del_cross.bmp b/assdraw/src/bitmaps/del_cross.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..e6dc0957f5f7a9211784f97967b15aca428d45d2
Binary files /dev/null and b/assdraw/src/bitmaps/del_cross.bmp differ
diff --git a/assdraw/src/bitmaps/help.bmp b/assdraw/src/bitmaps/help.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..d5636e9aa2cbf0489f307f7b3e7db32fc7264a68
Binary files /dev/null and b/assdraw/src/bitmaps/help.bmp differ
diff --git a/assdraw/src/bitmaps/help_.bmp b/assdraw/src/bitmaps/help_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..eac6f2e5eb678eafb65feadc64fcb829892980fa
Binary files /dev/null and b/assdraw/src/bitmaps/help_.bmp differ
diff --git a/assdraw/src/bitmaps/l_.bmp b/assdraw/src/bitmaps/l_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..92af791d0f08bec6d5fa88807a2176ceecea60cc
Binary files /dev/null and b/assdraw/src/bitmaps/l_.bmp differ
diff --git a/assdraw/src/bitmaps/m_.bmp b/assdraw/src/bitmaps/m_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..5e5b4c8610a1893cacce226dbc9b2b8dde127ea9
Binary files /dev/null and b/assdraw/src/bitmaps/m_.bmp differ
diff --git a/assdraw/src/bitmaps/n_.bmp b/assdraw/src/bitmaps/n_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..47c4ad7f2be9cbeec5ff75e88ec98af4f8300adc
Binary files /dev/null and b/assdraw/src/bitmaps/n_.bmp differ
diff --git a/assdraw/src/bitmaps/new_.bmp b/assdraw/src/bitmaps/new_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..3c8f88d4144db9ca9042c7b5b7ab92a552365c7c
Binary files /dev/null and b/assdraw/src/bitmaps/new_.bmp differ
diff --git a/assdraw/src/bitmaps/nut_.bmp b/assdraw/src/bitmaps/nut_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..f76644e38be090e22b53f724db2c2b1c243c388d
Binary files /dev/null and b/assdraw/src/bitmaps/nut_.bmp differ
diff --git a/assdraw/src/bitmaps/p_.bmp b/assdraw/src/bitmaps/p_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..67aeafa72c8792ba6eab9499c8424a228d02d06f
Binary files /dev/null and b/assdraw/src/bitmaps/p_.bmp differ
diff --git a/assdraw/src/bitmaps/pan_bg.bmp b/assdraw/src/bitmaps/pan_bg.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..0587ca30ea3908745c46d726ad9d92e2f170e9e5
Binary files /dev/null and b/assdraw/src/bitmaps/pan_bg.bmp differ
diff --git a/assdraw/src/bitmaps/pan_both.bmp b/assdraw/src/bitmaps/pan_both.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..84eb52fd04e479f512e58564a8e3dfacf78243a4
Binary files /dev/null and b/assdraw/src/bitmaps/pan_both.bmp differ
diff --git a/assdraw/src/bitmaps/pan_shape.bmp b/assdraw/src/bitmaps/pan_shape.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..32ada0ae3d649175b6017150b02972a3e27c6735
Binary files /dev/null and b/assdraw/src/bitmaps/pan_shape.bmp differ
diff --git a/assdraw/src/bitmaps/pan_shp.bmp b/assdraw/src/bitmaps/pan_shp.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..1b5da621bf7b9b8e2d29f51724c3a225d0230ab0
Binary files /dev/null and b/assdraw/src/bitmaps/pan_shp.bmp differ
diff --git a/assdraw/src/bitmaps/preview_.bmp b/assdraw/src/bitmaps/preview_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b8b6fbe983d6abbfc6e7e77ef160f440575aaaff
Binary files /dev/null and b/assdraw/src/bitmaps/preview_.bmp differ
diff --git a/assdraw/src/bitmaps/rot_.bmp b/assdraw/src/bitmaps/rot_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b2c14a9065c762907a37fa72a54187a778d283bb
Binary files /dev/null and b/assdraw/src/bitmaps/rot_.bmp differ
diff --git a/assdraw/src/bitmaps/s_.bmp b/assdraw/src/bitmaps/s_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..1e8afab554fc392c634052869b72aec8d0c3b80a
Binary files /dev/null and b/assdraw/src/bitmaps/s_.bmp differ
diff --git a/assdraw/src/bitmaps/sc_rot_.bmp b/assdraw/src/bitmaps/sc_rot_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..546d7fdf176d709e65d428eb0f8a6c653d4dedf4
Binary files /dev/null and b/assdraw/src/bitmaps/sc_rot_.bmp differ
diff --git a/assdraw/src/bitmaps/src_.bmp b/assdraw/src/bitmaps/src_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..ae2e55e07d7146b4f94f9f94860a157264995cf9
Binary files /dev/null and b/assdraw/src/bitmaps/src_.bmp differ
diff --git a/assdraw/src/bitmaps/transform.bmp b/assdraw/src/bitmaps/transform.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..8ae24e5adedc729b62762af2530d9e2792564817
Binary files /dev/null and b/assdraw/src/bitmaps/transform.bmp differ
diff --git a/assdraw/src/bitmaps/uncheck_.bmp b/assdraw/src/bitmaps/uncheck_.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..b600bebece5db6b7773a9cde2d0f3a9a7aa1ebae
Binary files /dev/null and b/assdraw/src/bitmaps/uncheck_.bmp differ
diff --git a/assdraw/src/canvas.cpp b/assdraw/src/canvas.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ab8eadeca23e14b511f03267edde60b829fa93be
--- /dev/null
+++ b/assdraw/src/canvas.cpp
@@ -0,0 +1,2057 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        canvas.cpp
+// Purpose:     implementations of ASSDraw main canvas class
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#include "assdraw.hpp"
+#include "cmd.hpp"
+#include "agg_gsv_text.h"
+#include "agg_ellipse.h"
+#include "agg_conv_dash.h"
+#include "agg_trans_bilinear.h"
+#include "agg_trans_perspective.h"
+
+#include "agghelper.hpp"
+#include <math.h>
+#include <wx/image.h>
+#include <wx/filename.h>
+
+// ----------------------------------------------------------------------------
+// the main drawing canvas: ASSDrawCanvas
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(ASSDrawCanvas, ASSDrawEngine)
+    EVT_MOTION (ASSDrawCanvas::OnMouseMove)
+    EVT_LEFT_UP(ASSDrawCanvas::OnMouseLeftUp)
+    EVT_LEFT_DOWN(ASSDrawCanvas::OnMouseLeftDown)
+    EVT_RIGHT_UP(ASSDrawCanvas::OnMouseRightUp)
+    EVT_RIGHT_DOWN(ASSDrawCanvas::OnMouseRightDown)
+    EVT_RIGHT_DCLICK(ASSDrawCanvas::OnMouseRightDClick)
+	EVT_MOUSEWHEEL(ASSDrawCanvas::OnMouseWheel)
+    EVT_KEY_DOWN(ASSDrawCanvas::CustomOnKeyDown)
+    EVT_KEY_UP(ASSDrawCanvas::CustomOnKeyUp)
+	EVT_MENU(MENU_DRC_LNTOBEZ, ASSDrawCanvas::OnSelect_ConvertLineToBezier)
+	EVT_MENU(MENU_DRC_BEZTOLN, ASSDrawCanvas::OnSelect_ConvertBezierToLine)
+	EVT_MENU(MENU_DRC_C1CONTBEZ, ASSDrawCanvas::OnSelect_C1ContinuityBezier)
+	EVT_MENU(MENU_DRC_MOVE00, ASSDrawCanvas::OnSelect_Move00Here)
+	EVT_MOUSE_CAPTURE_LOST(ASSDrawCanvas::CustomOnMouseCaptureLost)
+END_EVENT_TABLE()
+
+ASSDrawCanvas::ASSDrawCanvas(wxWindow *parent, ASSDrawFrame *frame, int extraflags)
+ : ASSDrawEngine( parent, extraflags )
+{
+	m_frame = frame;
+	preview_mode = false;
+    lastDrag_left = NULL;
+    lastDrag_right = NULL;
+    dragAnchor_left = NULL;
+    dragAnchor_right = NULL;
+    newcommand = NULL;
+    mousedownAt_point = NULL;
+    pointedAt_point = NULL;
+    draw_mode = MODE_ARR;
+
+    //drag_mode = DRAG_DWG;
+    dragOrigin = false;
+	hilite_cmd = NULL;
+	hilite_point = NULL;
+	capturemouse_left = false;
+	capturemouse_right = false;
+	//was_preview_mode = false;
+	bgimg.bgbmp = NULL;
+	bgimg.bgimg = NULL;
+	bgimg.alpha = 0.5;
+	rectbound2upd = -1, rectbound2upd2 = -1;
+	
+	rgba_shape_normal = agg::rgba(0,0,1,0.5);
+	rgba_outline = agg::rgba(0,0,0);
+	rgba_guideline = agg::rgba(0.5,0.5,0.5);
+	rgba_mainpoint = agg::rgba(1,0,0,0.75);
+	rgba_controlpoint = agg::rgba(0,1,0,0.75);
+	rgba_selectpoint = agg::rgba(0,0,1,0.75);
+	rgba_origin = agg::rgba(0,0,0);
+	rgba_ruler_h = agg::rgba(0,0,1);
+	rgba_ruler_v = agg::rgba(1,0,0);
+
+	wxFlexGridSizer* sizer = new wxFlexGridSizer(1, 1);
+    sizer->AddGrowableRow(0);
+    sizer->AddGrowableCol(0);
+    sizer->Add( this, 0, wxGROW|wxGROW, 5);
+    parent->SetSizer(sizer);
+
+	// for background image loading
+	::wxInitAllImageHandlers();
+	bgimg.bgbmp = NULL;
+	bgimg.bgimg = NULL;
+	// drag image background file
+	SetDropTarget(new ASSDrawFileDropTarget(this));
+	
+	hasStatusBar = m_frame->GetStatusBar() != NULL;
+
+	// cursor = crosshair
+	SetCursor( *wxCROSS_CURSOR );
+
+	bgimg.alpha_dlg = new wxDialog(this, wxID_ANY, wxString("Background image opacity"));
+	bgimg.alpha_slider = new wxSlider(bgimg.alpha_dlg, TB_BGALPHA_SLIDER, 50, 0, 100, __DPDS__ , wxSL_LABELS);
+	bgimg.alpha_slider->SetSize(280, bgimg.alpha_slider->GetSize().y);
+	bgimg.alpha_dlg->Fit();
+	bgimg.alpha_dlg->Show(false);
+	bgimg.alpha_slider->Connect(wxEVT_SCROLL_LINEUP, wxScrollEventHandler(ASSDrawCanvas::OnAlphaSliderChanged), NULL, this);
+	bgimg.alpha_slider->Connect(wxEVT_SCROLL_LINEDOWN, wxScrollEventHandler(ASSDrawCanvas::OnAlphaSliderChanged), NULL, this);
+	bgimg.alpha_slider->Connect(wxEVT_SCROLL_PAGEUP, wxScrollEventHandler(ASSDrawCanvas::OnAlphaSliderChanged), NULL, this);
+	bgimg.alpha_slider->Connect(wxEVT_SCROLL_PAGEDOWN, wxScrollEventHandler(ASSDrawCanvas::OnAlphaSliderChanged), NULL, this);
+	bgimg.alpha_slider->Connect(wxEVT_SCROLL_THUMBTRACK, wxScrollEventHandler(ASSDrawCanvas::OnAlphaSliderChanged), NULL, this);
+	bgimg.alpha_slider->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(ASSDrawCanvas::OnAlphaSliderChanged), NULL, this);
+	
+	RefreshUndocmds();
+
+}
+
+// Destructor
+ASSDrawCanvas::~ASSDrawCanvas()
+{
+	ASSDrawEngine::ResetEngine(false);
+	if (pointsys) delete pointsys;
+	if (bgimg.bgbmp) delete bgimg.bgbmp;
+	if (bgimg.bgimg) delete bgimg.bgimg;
+}
+
+void ASSDrawCanvas::ParseASS(wxString str, bool addundo)
+{
+	if (addundo)
+		AddUndo(wxT("Modify drawing commands"));
+
+	ASSDrawEngine::ParseASS(str);
+
+	RefreshUndocmds();
+}
+
+void ASSDrawCanvas::ResetEngine(bool addM)
+{
+	ClearPointsSelection();
+	SetHighlighted(NULL, NULL);
+	SetPreviewMode(false);
+	SetDrawMode(MODE_ARR);
+	ASSDrawEngine::ResetEngine(addM);
+	RefreshUndocmds();
+}
+
+void ASSDrawCanvas::SetPreviewMode(bool mode)
+{
+	//was_preview_mode = mode;
+	preview_mode = mode;
+	if (preview_mode)
+	{
+		if (mousedownAt_point != NULL)
+		{
+			mousedownAt_point->cmd_main->Init();
+			mousedownAt_point = NULL;
+		}
+
+		if (pointedAt_point != NULL)
+			pointedAt_point = NULL;
+
+		SetHighlighted( NULL, NULL );
+
+		RefreshDisplay();
+	}
+}
+
+// (Re)draw canvas
+void ASSDrawCanvas::RefreshDisplay() 
+{ 
+	ASSDrawEngine::RefreshDisplay();
+	wxString asscmds = GenerateASS();
+	if (oldasscmds != asscmds)
+	{
+		m_frame->UpdateASSCommandStringToSrcTxtCtrl(asscmds);
+		oldasscmds = asscmds;
+	}
+}
+
+void ASSDrawCanvas::SetDrawMode( MODE mode ) 
+{ 
+	draw_mode = mode; 
+
+	if (!selected_points.empty())
+		ClearPointsSelection();
+
+	RefreshDisplay();
+
+	if (IsTransformMode())
+	{
+		isshapetransformable = cmds.size() > 1;
+		
+		if (isshapetransformable)
+		{
+
+			// backup cmds
+			backupcmds.free_all();
+			for (DrawCmdList::iterator iterate = cmds.begin(); iterate != cmds.end(); iterate++)
+			{
+				DrawCmd* cmd = (*iterate);
+				for (PointList::iterator iterate2 = cmd->controlpoints.begin(); iterate2 != cmd->controlpoints.end(); iterate2++)
+				{
+					wxPoint pp = (*iterate2)->ToWxPoint();
+					backupcmds.move_to(pp.x, pp.y);
+				}
+				wxPoint pp = (*iterate)->m_point->ToWxPoint();
+				backupcmds.move_to(pp.x, pp.y);			
+			}
+	
+			// calculate bounding rectangle
+			agg::trans_affine mtx;
+			trans_path *rm, *rb;
+			agg::conv_curve<trans_path> *rc;
+			ConstructPathsAndCurves(mtx, rm, rb, rc);
+			rasterizer.reset();
+			rasterizer.add_path(*rc);
+			delete rm, rb, rc;
+		    int minx = rasterizer.min_x(), miny = rasterizer.min_y();
+		    int maxx = rasterizer.max_x(), maxy = rasterizer.max_y();
+		    
+		    rectbound[0] = wxRealPoint(minx, miny);
+		    rectbound[1] = wxRealPoint(maxx, miny);
+		    rectbound[2] = wxRealPoint(maxx, maxy);
+		    rectbound[3] = wxRealPoint(minx, maxy);
+		    for (int i = 0; i < 4; i++)
+		    	rectbound2[i] = rectbound[i];
+	
+		    rectbound2upd = -1;
+		    rectbound2upd2 = -1;
+		    
+		    backupowner = NONE;
+		    InitiateDraggingIfTransformMode();
+		    
+		    if (maxx - minx < 5 || maxy - miny < 5)
+		    	isshapetransformable = false;
+		}	    
+	}
+	
+	RefreshUndocmds();
+	m_frame->UpdateFrameUI();
+	
+}
+
+void ASSDrawCanvas::SetDragMode( DRAGMODE mode )
+{
+	drag_mode = mode;
+}
+
+bool ASSDrawCanvas::IsTransformMode()
+{ 
+	return draw_mode == MODE_NUT_BILINEAR || draw_mode == MODE_SCALEROTATE; 
+}
+
+bool ASSDrawCanvas::CanZoom()
+{
+	return !IsTransformMode() || !drag_mode.drawing;
+}
+
+bool ASSDrawCanvas::CanMove()
+{
+	return !IsTransformMode() || dragAnchor_left == NULL;
+}
+
+// Do the dragging
+void ASSDrawCanvas::OnMouseMove(wxMouseEvent &event)
+{
+	mouse_point = event.GetPosition();
+	int xx, yy, wx, wy;
+	xx = mouse_point.x; yy = mouse_point.y;
+	pointsys->FromWxPoint ( mouse_point, wx, wy );
+	if (event.Dragging())
+	{
+		if (IsTransformMode() && isshapetransformable && backupowner == LEFT)
+		{
+			// update bounding polygon
+			if (rectbound2upd > -1)
+			{
+				wxPoint diff = mouse_point - *dragAnchor_left;
+				wxRealPoint rdiff(diff.x, diff.y);
+				switch(draw_mode)
+				{
+				case MODE_NUT_BILINEAR:
+					if (rectbound2upd2 == -1) //only one vertex dragged
+						rectbound2[rectbound2upd].x = xx, rectbound2[rectbound2upd].y = yy;
+					else
+					{
+						rectbound2[rectbound2upd].x += diff.x, rectbound2[rectbound2upd].y += diff.y;
+						rectbound2[rectbound2upd2].x += diff.x, rectbound2[rectbound2upd2].y += diff.y;
+					}
+					undodesc = "Bilinear transform";
+					*dragAnchor_left = mouse_point;
+					break;
+				case MODE_SCALEROTATE:
+					if (rectbound2upd2 == -1) //only one vertex dragged
+					{
+						int adjacent[2] = { (rectbound2upd + 3) % 4, (rectbound2upd + 1) % 4 };
+						int opposite = (rectbound2upd + 2) % 4; 
+						wxRealPoint newpoint = backup[rectbound2upd] + rdiff;
+						//wxPoint newadjacent[2];
+						double nx, ny;
+						for (int i = 0; i < 2; i++)
+						{
+							bool isect = agg::calc_intersection(
+								backup[opposite].x, backup[opposite].y, 
+								backup[adjacent[i]].x, backup[adjacent[i]].y,
+								newpoint.x, newpoint.y,
+								backup[adjacent[i]].x + diff.x, backup[adjacent[i]].y + diff.y,
+								&nx, &ny);
+							if (isect && !(fabs(nx - backup[opposite].x) < 10 && fabs(ny - backup[opposite].y) < 10))
+								rectbound2[adjacent[i]] = wxRealPoint(nx, ny);
+						}
+						GetThe4thPoint(backup[opposite].x, backup[opposite].y, 
+							rectbound2[adjacent[0]].x, rectbound2[adjacent[0]].y,
+							rectbound2[adjacent[1]].x, rectbound2[adjacent[1]].y, 
+							&rectbound2[rectbound2upd].x, &rectbound2[rectbound2upd].y);
+						if (event.ShiftDown()) // shift down = maintain aspect ratio (damn so complicated)
+						{
+							// first create the guide points, which are basically backup points reoriented based on mouse position
+							wxRealPoint guide[4];
+							guide[opposite] = backup[opposite];
+							guide[adjacent[0]] = backup[adjacent[0]];
+							guide[adjacent[1]] = backup[adjacent[1]];
+							for (int i = 0; i < 2; i++)
+							{
+								if ((rectbound2[adjacent[i]].x < guide[opposite].x && guide[opposite].x < guide[adjacent[i]].x)
+									|| (rectbound2[adjacent[i]].x > guide[opposite].x && guide[opposite].x > guide[adjacent[i]].x)
+									|| (rectbound2[adjacent[i]].y < guide[opposite].y && guide[opposite].y < guide[adjacent[i]].y)
+									|| (rectbound2[adjacent[i]].y > guide[opposite].y && guide[opposite].y > guide[adjacent[i]].y))
+								{
+									guide[adjacent[i]] = guide[opposite] - (guide[adjacent[i]] - guide[opposite]);
+								}
+							}
+							guide[rectbound2upd] = guide[adjacent[0]] + (guide[adjacent[1]] - guide[opposite]);
+							// now we determine which rescaled sides have larger enlargement/shrinkage ratio ..
+							double ix[2], iy[2], dx[2], dy[2];
+							for (int i = 0; i < 2; i++)
+							{
+								agg::calc_intersection(guide[opposite].x, guide[opposite].y, guide[rectbound2upd].x, guide[rectbound2upd].y,
+									rectbound2[rectbound2upd].x, rectbound2[rectbound2upd].y,
+									rectbound2[adjacent[i]].x, rectbound2[adjacent[i]].y, &ix[i], &iy[i]);
+								dx[i] = ix[i] - guide[opposite].x;
+								dy[i] = iy[i] - guide[opposite].y;
+							}
+							// .. and modify the other sides to follow the ratio
+							for (int i = 0; i < 2; i++)
+							{
+								int j = (i + 1) % 2;
+								if (fabs(dx[i]) > fabs(dx[j]) || fabs(dy[i]) > fabs(dy[j]))
+								{
+									rectbound2[rectbound2upd].x = ix[i];
+									rectbound2[rectbound2upd].y = iy[i];
+									GetThe4thPoint(rectbound2[adjacent[i]].x, rectbound2[adjacent[i]].y,
+										guide[opposite].x, guide[opposite].y, ix[i], iy[i],
+										&rectbound2[adjacent[j]].x, &rectbound2[adjacent[j]].y);
+								}
+							}
+						}
+					}
+					else // an edge dragged (i.e. move 2 vertices in sync)
+					{
+						// it is guaranteed that rectbound2upd and rectbound2upd2 are in clockwise direction
+						// from the way they are detected in OnMouseLeftDown()
+						int toupd[2] = { rectbound2upd, rectbound2upd2 };
+						int adjacent[2] = { (rectbound2upd2 + 2) % 4, (rectbound2upd2 + 1) % 4 };
+						wxRealPoint vertexone = backup[toupd[0]] + rdiff, vertextwo = backup[toupd[1]] + rdiff;
+						double nx, ny;
+						for (int i = 0; i < 2; i++)
+						{
+							agg::calc_intersection(
+								rectbound2[adjacent[i]].x, rectbound2[adjacent[i]].y,
+								backup[toupd[i]].x, backup[toupd[i]].y,
+								vertexone.x, vertexone.y,
+								vertextwo.x, vertextwo.y,
+								&nx, &ny);
+							if (!(fabs(nx - backup[adjacent[i]].x) < 10 && fabs(ny - backup[adjacent[i]].y) < 10))
+								rectbound2[toupd[i]].x = (int) nx, rectbound2[toupd[i]].y = (int) ny;
+						}
+					}
+					UpdateTranformModeRectCenter();
+					//*dragAnchor_left = mouse_point;
+					undodesc = "Scale";
+					break;
+				}
+			
+				// update points
+				UpdateNonUniformTransformation();
+				RefreshDisplay();
+			}
+		}
+		else if (draw_mode != MODE_DEL)
+		{
+
+			// point left-dragged
+			if (mousedownAt_point != NULL && mousedownAt_point->isselected) 
+			{
+				if (!mousedownAt_point->IsAt( wx, wy ))
+				{
+					if (draw_mode == MODE_ARR) {
+						int movex = wx - mousedownAt_point->x(), movey = wy - mousedownAt_point->y();
+						PointSet::iterator iter = selected_points.begin();
+						for (; iter != selected_points.end(); iter++)			
+							(*iter)->setXY( (*iter)->x() + movex, (*iter)->y() + movey );
+					}
+					else
+						mousedownAt_point->setXY( wx, wy );
+	
+					EnforceC1Continuity (mousedownAt_point->cmd_main, mousedownAt_point);
+											
+					RefreshDisplay();
+					if (undodesc == "")
+					{
+						if (mousedownAt_point->type == MP)
+							undodesc = wxT("Drag point");
+						else
+							undodesc = wxT("Drag control point");
+					}
+				}
+			} 
+			// origin left-dragged
+			else if (dragOrigin) 
+			{
+				if (wx != 0 || wy != 0)
+				{
+					wxPoint wxp = pointsys->ToWxPoint ( wx, wy );
+					MovePoints(-wx, -wy);
+					pointsys->originx = wxp.x;
+					pointsys->originy = wxp.y;
+					RefreshDisplay();
+					undodesc = wxT("Move origin");
+				}          
+			}
+			else if (dragAnchor_left != NULL)
+			{
+				// handle left-dragging here
+				if (lastDrag_left && dragAnchor_left != lastDrag_left)
+			       delete lastDrag_left;
+				lastDrag_left = new wxPoint(xx, yy);
+				int ax = dragAnchor_left->x, ay = dragAnchor_left->y;
+				int sx = lastDrag_left->x, sy = lastDrag_left->y;
+				int lx, rx, ty, by;
+				if (ax > sx) lx = sx, rx = ax;
+				else lx = ax, rx = sx;
+				if (ay > sy) ty = sy, by = ay;
+				else ty = ay, by = sy;
+				SelectPointsWithin( lx, rx, ty, by, GetSelectMode(event) );
+				RefreshDisplay();
+			}
+		}
+
+		// right-dragged
+		if (dragAnchor_right != NULL)
+		{
+			if (draw_mode == MODE_SCALEROTATE)
+			{
+				if (backupowner == RIGHT)
+				{
+					double cx = rectcenter.x, cy = rectcenter.y; // center x,y
+					double diameter = sqrt(pow(rectbound2[0].x - rectbound2[2].x, 2) + pow(rectbound2[0].y - rectbound2[2].y, 2));
+					double radius = diameter / 2;
+					double old_dx = dragAnchor_right->x - cx, old_dy = dragAnchor_right->y - cy;
+					double new_dx = mouse_point.x - cx, new_dy = mouse_point.y - cy;
+					double old_angle = atan2(old_dy, old_dx);
+					double new_angle = atan2(new_dy, new_dx);
+					double delta = new_angle - old_angle;
+					for (int i = 0; i < 4; i++)
+					{
+						old_dx = backup[i].x - cx, old_dy = backup[i].y - cy;
+						old_angle = atan2(old_dy, old_dx);
+						new_angle = old_angle + delta;
+						new_dx = radius * cos(new_angle), new_dy = radius * sin(new_angle);
+						rectbound2[i].x = (int)(new_dx + cx), rectbound2[i].y = (int)(new_dy + cy);
+					}
+					UpdateNonUniformTransformation();
+					RefreshDisplay();
+					undodesc = "Rotate";
+				}
+			}
+			else if (CanMove()) 
+			{
+				MoveCanvas(xx - dragAnchor_right->x, yy - dragAnchor_right->y);
+				dragAnchor_right->x = xx;
+				dragAnchor_right->y = yy;
+				RefreshDisplay();
+			}
+		}		
+	}    
+	else if (!preview_mode)// not dragging and not preview mode
+    {
+		if (IsTransformMode())
+		{
+			int oldrectbound = rectbound2upd;
+			rectbound2upd = -1;
+			rectbound2upd2 = -1;
+			for (int i = 0; i < 4; i++)
+			{
+				if (abs((int)rectbound2[i].x - mouse_point.x) <= pointsys->scale
+					&& abs((int)rectbound2[i].y - mouse_point.y) <= pointsys->scale)
+						rectbound2upd = i;
+			}
+			for (int i = 0; rectbound2upd == -1 && i < 4; i++)
+			{
+				int j = (i+1) % 4;
+				wxRealPoint &pi = rectbound2[i], &pj = rectbound2[j];
+				double dy = fabs(pj.y - pi.y);
+				double dy3 = dy / 3;
+				double dx = fabs(pj.x - pi.x);
+				double dx3 = dx / 3;
+				double ix, iy;
+				bool intersect = false;
+				if (dy > dx)
+				{
+					intersect = agg::calc_intersection(
+						pi.x, pi.y, pj.x, pj.y,
+	                    mouse_point.x - pointsys->scale, mouse_point.y,
+						mouse_point.x + pointsys->scale, mouse_point.y, &ix, &iy);
+					intersect &= fabs(mouse_point.x - ix) <= pointsys->scale;
+					intersect &= (pj.y > pi.y? 
+						pj.y - dy3 > iy && iy > pi.y + dy3:
+						pj.y + dy3 < iy && iy < pi.y - dy3);
+				}
+				else
+				{
+					intersect = agg::calc_intersection(
+						pi.x, pi.y, pj.x, pj.y,
+	                    mouse_point.x, mouse_point.y - pointsys->scale,
+						mouse_point.x, mouse_point.y + pointsys->scale, &ix, &iy);
+					intersect &= fabs(mouse_point.y - iy) <= pointsys->scale;
+					intersect &= (pj.x > pi.x? 
+						pj.x - dx3 > ix && ix > pi.x + dx3:
+						pj.x + dx3 < ix && ix < pi.x - dx3);
+				}
+				if (intersect)
+				{
+					rectbound2upd = i;
+					rectbound2upd2 = j;
+				}
+			}
+			if (rectbound2upd != -1 || oldrectbound != -1)
+				RefreshDisplay();
+		}
+		else
+		{
+	         /* figure out if the mouse is pointing at a point of a command
+	            we need not do this for dragging since this same block has set
+	            the related variables before the user starts to hold the button
+	            (well, before you can drag something you have to move the pointer
+	            over that thing first, right?) and we don't want to mess with those 
+	            when it's dragging
+	         */
+	         
+			// check if mouse points on any control point first
+			Point* last_pointedAt_point = pointedAt_point;
+			ControlAt( wx, wy, pointedAt_point );
+	
+			// then check if mouse points on any m_points
+			// override any control point set to pointedAt_point above
+			DrawCmd* p = PointAt( wx, wy );
+			if (p != NULL)
+			{
+				pointedAt_point = p->m_point;
+			}
+	         
+			if (pointedAt_point != last_pointedAt_point)
+			{
+				if (pointedAt_point != NULL)
+					SetHighlighted( pointedAt_point->cmd_main, pointedAt_point );
+				else
+					SetHighlighted( NULL, NULL );
+				RefreshDisplay();
+			}
+		}
+	} // not dragging and preview mode = ignore all mouse movements
+
+	// we are not done yet?
+    // oh yeah, we need to set the status bar just for fun
+    if (hasStatusBar)
+	{
+        m_frame->SetStatusText( 
+            wxString::Format( wxT("%5d %5d"), (int)wx, (int)wy ), 0 );
+        if (pointedAt_point == NULL || 
+             (newcommand != NULL && !newcommand->initialized) )
+           m_frame->SetStatusText( wxT(""), 1 );
+        else
+           m_frame->SetStatusText( wxT(" ") + pointedAt_point->cmd_main->ToString().Upper(), 1 );
+	}
+
+}
+
+// End drag points
+void ASSDrawCanvas::OnMouseLeftUp(wxMouseEvent& event)
+{
+	ProcessOnMouseLeftUp();
+	event.Skip( true );
+}
+
+void ASSDrawCanvas::ProcessOnMouseLeftUp()
+{
+	if (!capturemouse_left) return;
+	
+	// draw mode
+	if (newcommand != NULL) 
+	{
+		newcommand->Init();
+		switch (newcommand->type)
+		{
+		case M:
+			undodesc = wxT("Add a new M"); break;
+		case L:
+			undodesc = wxT("Add a new L"); break;
+		case B:
+			undodesc = wxT("Add a new B"); break;
+		}
+		newcommand = NULL;
+		// we need to manually refresh the GUI to draw the new control points
+		RefreshDisplay();
+	}
+	else if ( draw_mode == MODE_DEL // if it's delete mode
+				&& mousedownAt_point != NULL // and mouse down at a point
+				&& mousedownAt_point == pointedAt_point ) // and released at the same point
+	{
+		// first take care of mouse readings
+		pointedAt_point = NULL;
+		Point *lastmousedownAt_point = mousedownAt_point;
+		mousedownAt_point = NULL;
+
+		// try deleting
+		CMDTYPE t = lastmousedownAt_point->cmd_main->type;
+		if ( DeleteCommand( lastmousedownAt_point->cmd_main ) )
+		{
+			ClearPointsSelection();
+			SetHighlighted( NULL, NULL );
+			RefreshDisplay();
+			switch (t)
+			{
+			case M:
+				undodesc = wxT("Delete a M"); break;
+			case L:
+				undodesc = wxT("Delete a L"); break;
+			case B:
+				undodesc = wxT("Delete a B"); break;
+			}
+		}
+		else
+		{
+			RefreshDisplay(); // redraw before showing the error box
+			wxMessageDialog msgb(m_frame, 
+			_T("You must delete that command/point last"), 
+			_T("Error"), wxOK | wxICON_EXCLAMATION );
+			msgb.ShowModal();
+		}
+	}
+	else if ( lastDrag_left && dragAnchor_left ) // point selection
+	{
+		if (lastDrag_left && dragAnchor_left != lastDrag_left)
+		    delete lastDrag_left;
+	    delete dragAnchor_left;			
+		lastDrag_left = NULL;
+		dragAnchor_left = NULL;
+	}
+	
+	if (dragOrigin)
+	{
+		dragOrigin = false;
+		RefreshDisplay(); // clear the crosshair
+	}
+
+	rectbound2upd = -1;
+	rectbound2upd2 = -1;
+    backupowner = NONE;
+
+	if (!undodesc.IsSameAs(""))
+	{
+		AddUndo( undodesc );
+		undodesc = "";
+		RefreshUndocmds();
+	}
+
+	mousedownAt_point = NULL;
+
+	if (HasCapture())
+		ReleaseMouse();
+	capturemouse_left = false;
+	
+	RefreshDisplay();
+}
+
+// Set up to drag points, if any
+void ASSDrawCanvas::OnMouseLeftDown(wxMouseEvent& event)
+{
+
+    // no drawing in preview mode
+	if (preview_mode /*|| was_preview_mode*/)
+		return;
+
+	wxPoint q = event.GetPosition();
+
+	// wxPoint to Point
+	int px, py;
+	pointsys->FromWxPoint(q, px, py);
+	
+	// create new cmd if in draw mode / or delete point if del tool selected
+	switch (draw_mode)
+	{
+	case MODE_M:
+		newcommand = NewCmd(M, px, py);
+		break;
+	case MODE_L:
+		newcommand = NewCmd(L, px, py);
+		break;
+	case MODE_B:
+		newcommand = NewCmd(B, px, py);
+		break;
+	}
+
+	// continue working on the new command (if any)
+	// only if it is not mouse down on any control point
+	if (newcommand != NULL)
+	{
+		if (pointedAt_point != NULL && pointedAt_point->type == CP)
+		{
+			// oops, user clicked on a control point so cancel new command
+			// and let him drag the control point
+			delete newcommand;
+            newcommand = NULL;
+		}
+		else 
+		{
+			// first set to drag the new command no matter what
+			mousedownAt_point = newcommand->m_point;
+	      
+			// if user drags from existing point, insert the new command
+			// else append the new command
+			if (pointedAt_point != NULL)
+				InsertCmd( newcommand, pointedAt_point->cmd_main );
+			else
+			{
+				if (cmds.empty() && newcommand->type != M)
+					AppendCmd( M, px, py );
+				newcommand = AppendCmd( newcommand );
+			}
+
+			pointedAt_point = mousedownAt_point;
+	           
+			//highlight it
+			SetHighlighted( newcommand, newcommand->m_point );
+		}                    
+	}
+
+	// we already calculated pointedAt_point in OnMouseMove() so just use it
+	mousedownAt_point = pointedAt_point;
+	SELECTMODE smode = GetSelectMode(event);
+	if (mousedownAt_point && !mousedownAt_point->isselected)
+	{
+		if (smode == NEW)
+		{
+			ClearPointsSelection();
+			mousedownAt_point->isselected = true;
+			selected_points.insert(mousedownAt_point);
+		}
+		else
+		{
+			wxPoint wxp = mousedownAt_point->ToWxPoint();
+			SelectPointsWithin(wxp.x, wxp.x, wxp.y, wxp.y, smode);
+		}
+	}
+	else if (!mousedownAt_point && smode == NEW)
+		ClearPointsSelection();
+
+	if ( mousedownAt_point == NULL && px == 0 && py == 0 )
+		dragOrigin = true;
+
+	if ( mousedownAt_point == NULL && !dragOrigin )
+	{
+		dragAnchor_left = new wxPoint(q.x, q.y);
+		lastDrag_left = dragAnchor_left;
+	}
+
+	if (InitiateDraggingIfTransformMode())
+	    backupowner = LEFT;
+	
+	CaptureMouse();
+	capturemouse_left = true;
+	RefreshDisplay();
+
+	event.Skip( true );
+}
+
+// End drag the canvas
+void ASSDrawCanvas::OnMouseRightUp(wxMouseEvent& event)
+{
+	ProcessOnMouseRightUp();
+	event.Skip( true );
+}
+
+void ASSDrawCanvas::ProcessOnMouseRightUp()
+{
+	if (!capturemouse_right) return;
+
+    if (lastDrag_right && dragAnchor_right != lastDrag_right)
+        delete lastDrag_right;
+    if (dragAnchor_right)
+        delete dragAnchor_right;
+	dragAnchor_right = NULL;
+	lastDrag_right = NULL;
+
+	// don't crash the program
+	if (HasCapture())
+		ReleaseMouse();
+	capturemouse_right = false;
+
+	rectbound2upd = -1;
+	rectbound2upd2 = -1;
+    backupowner = NONE;
+
+	if (!undodesc.IsSameAs(""))
+	{
+		AddUndo( undodesc );
+		undodesc = "";
+		RefreshUndocmds();
+	}
+
+	RefreshDisplay();
+	SetFocus();
+}
+
+// Set up to drag the canvas
+void ASSDrawCanvas::OnMouseRightDown(wxMouseEvent &event)
+{
+	wxPoint q = event.GetPosition();
+	dragAnchor_right = new wxPoint(q.x, q.y);
+	lastDrag_right = dragAnchor_right;
+	CaptureMouse();
+	capturemouse_right = true;
+
+	if (InitiateDraggingIfTransformMode())
+	    backupowner = RIGHT;
+//	was_preview_mode = preview_mode;
+//	preview_mode = false;
+
+	event.Skip( true );
+}
+
+// Reset to point-and-drag mode
+void ASSDrawCanvas::OnMouseRightDClick(wxMouseEvent& event)
+{
+	wxMenu* menu = new wxMenu();
+
+	if (pointedAt_point)
+	{
+		ProcessOnMouseLeftUp();
+		ProcessOnMouseRightUp();
+		dblclicked_point_right = pointedAt_point;
+		pointedAt_point = NULL;
+		wxMenuItem *cmdmenuitem = new wxMenuItem(menu, MENU_DUMMY, dblclicked_point_right->cmd_main->ToString());
+		wxFont f = cmdmenuitem->GetFont();
+		f.SetWeight(wxFONTWEIGHT_BOLD);
+		cmdmenuitem->SetFont(f);
+		menu->Append(cmdmenuitem); 
+		menu->Enable(MENU_DUMMY, false);
+		switch (dblclicked_point_right->cmd_main->type)
+		{
+			case L:
+				menu->Append(MENU_DRC_LNTOBEZ, "Convert to Bezier curve (B command)");
+				break;
+			case B:
+				if (dblclicked_point_right->type != MP) break;
+				menu->AppendCheckItem(MENU_DRC_BEZTOLN, "Convert to line (L command)");
+				if (dblclicked_point_right->cmd_next && dblclicked_point_right->cmd_next->type == B)
+				{
+					menu->AppendCheckItem(MENU_DRC_C1CONTBEZ, "Smooth connection");
+					if (static_cast<DrawCmd_B*>(dblclicked_point_right->cmd_main)->C1Cont)
+						menu->Check(MENU_DRC_C1CONTBEZ, true);
+				}
+				break;
+		}
+
+	}
+	else
+	{
+		menu->Append(MENU_DRC_MOVE00, "Move [0,0] here");
+		menu->AppendSeparator();
+		menu->AppendRadioItem(MODE_ARR, _T("Mode: D&rag"));
+		menu->AppendRadioItem(MODE_M, _T("Mode: Draw &M"));
+		menu->AppendRadioItem(MODE_L, _T("Mode: Draw &L"));
+		menu->AppendRadioItem(MODE_B, _T("Mode: Draw &B"));
+		menu->AppendRadioItem(MODE_DEL, _T("Mode: &Delete"));
+		menu->Check(GetDrawMode(), true);
+	}
+
+	if (menu->GetMenuItemCount() > 0) // only if there is menu item
+	{
+		SetHighlighted(NULL, NULL);
+		mousedownAt_point = NULL;
+		RefreshDisplay();
+		PopupMenu(menu);
+	}
+	delete menu;
+
+	event.Skip( true );
+}
+
+bool ASSDrawCanvas::InitiateDraggingIfTransformMode()
+{
+	if (IsTransformMode() && isshapetransformable && backupowner == NONE)
+	{
+		for (int i = 0; i < 4; i++)
+			backup[i] = rectbound2[i];
+		UpdateTranformModeRectCenter();
+		return true;
+	}
+	else
+		return false;
+}
+
+void ASSDrawCanvas::UpdateTranformModeRectCenter()
+{
+	double cx, cy;
+	if (agg::calc_intersection(rectbound2[0].x, rectbound2[0].y, rectbound2[2].x, rectbound2[2].y,
+		rectbound2[1].x, rectbound2[1].y, rectbound2[3].x, rectbound2[3].y, &cx, &cy))
+	{ 
+		rectcenter = wxRealPoint(cx, cy); 
+	}	
+}
+
+bool ASSDrawCanvas::GetThe4thPoint(double ox, double oy, double a1x, double a1y, double a2x, double a2y, double *x, double *y)
+{
+	/*
+	return agg::calc_intersection(a1x, a1y,
+		a2x + a1x - ox,
+		a2y + a1y - oy,
+		a2x, a2y,
+		a1x + a2x - ox,
+		a1y + a2y - oy,
+		x, y);	//*/
+	
+	*x = a1x + a2x - ox;
+	*y = a1y + a2y - oy;
+	return true;
+}
+
+// Mousewheel
+void ASSDrawCanvas::OnMouseWheel(wxMouseEvent &event)
+{
+	double amount = event.GetWheelRotation() / event.GetWheelDelta();
+	if (event.ControlDown()) amount /= 10.0;
+	bgimg.new_center = wxRealPoint(mouse_point.x, mouse_point.y);
+	ChangeZoomLevel( amount, mouse_point );
+}
+
+void ASSDrawCanvas::ChangeZoomLevelTo( double zoom, wxPoint bgzoomctr )
+{
+	ChangeZoomLevel(zoom - pointsys->scale, bgzoomctr);
+}
+
+void ASSDrawCanvas::ChangeZoomLevel( double amount, wxPoint bgzoomctr )
+{
+	double old_scale = pointsys->scale;
+	/*
+	switch (drag_mode)
+	{
+	case DRAG_BGIMG:
+	    ChangeBackgroundZoomLevel(bgimg.scale + amount / 10.0,  wxRealPoint(bgzoomctr.x, bgzoomctr.y));
+		break;
+
+	case DRAG_BOTH:
+		ChangeDrawingZoomLevel( amount );
+	    ChangeBackgroundZoomLevel(bgimg.scale * pointsys->scale / old_scale, 
+			wxRealPoint(pointsys->originx, pointsys->originy));
+		break;
+
+	case DRAG_DWG:
+		ChangeDrawingZoomLevel( amount );
+		break;
+	}
+	*/
+	
+	if (CanZoom() && drag_mode.drawing)
+		ChangeDrawingZoomLevel( amount );
+
+	if (CanZoom() && drag_mode.bgimg)
+		if (drag_mode.drawing)
+		    ChangeBackgroundZoomLevel(bgimg.scale * pointsys->scale / old_scale, wxRealPoint(pointsys->originx, pointsys->originy));
+		else
+		    ChangeBackgroundZoomLevel(bgimg.scale + amount / 10.0,  wxRealPoint(bgzoomctr.x, bgzoomctr.y));
+	
+	RefreshDisplay();
+}
+
+void ASSDrawCanvas::ChangeDrawingZoomLevel( double scrollamount )
+{
+	if (!CanZoom()) return;
+    double zoom = pointsys->scale + scrollamount;
+    if (zoom <= 50.0)
+	{
+		if (zoom < 1.0) zoom = 1.0;
+		pointsys->scale = zoom;
+	}
+	
+	m_frame->UpdateFrameUI();
+}
+
+void ASSDrawCanvas::ChangeBackgroundZoomLevel(double zoom, wxRealPoint newcenter)
+{
+	bgimg.new_scale = zoom;
+	bgimg.new_center = newcenter;
+	if (bgimg.new_scale < 0.01) bgimg.new_scale = 0.01;
+	UpdateBackgroundImgScalePosition();	
+}
+
+void ASSDrawCanvas::MoveCanvasOriginTo(double originx, double originy)
+{
+	MoveCanvas(originx - pointsys->originx, originy - pointsys->originy);
+}
+
+void ASSDrawCanvas::MoveCanvas(double xamount, double yamount)
+{
+	/*
+	if (drag_mode == DRAG_DWG || drag_mode == DRAG_BOTH)
+		MoveCanvasDrawing(xamount, yamount);
+	if (drag_mode == DRAG_BGIMG || drag_mode == DRAG_BOTH)
+		MoveCanvasBackground(xamount, yamount);
+	*/
+	if (CanMove() && drag_mode.drawing)
+		MoveCanvasDrawing(xamount, yamount);
+	if (CanMove() && drag_mode.bgimg)
+		MoveCanvasBackground(xamount, yamount);
+}
+
+void ASSDrawCanvas::MoveCanvasDrawing(double xamount, double yamount)
+{
+	if (!CanMove()) return;
+	pointsys->originx += xamount;
+	pointsys->originy += yamount;		
+	if (IsTransformMode())
+	{
+	    for (int i = 0; i < 4; i++)
+	    {
+	    	rectbound[i].x += (int) xamount;
+	    	rectbound[i].y += (int) yamount;
+	    	rectbound2[i].x += (int) xamount;
+	    	rectbound2[i].y += (int) yamount;
+		}
+		unsigned vertices = backupcmds.total_vertices();
+		double x, y;
+		for (int i = 0; i < vertices; i++)
+		{
+			backupcmds.vertex(i, &x, &y);
+	        backupcmds.modify_vertex(i, x + xamount, y + yamount);
+		}
+	}
+}
+
+void ASSDrawCanvas::MoveCanvasBackground(double xamount, double yamount)
+{
+	//bgimg.new_center.x += xamount, bgimg.new_center.y += yamount;
+	bgimg.new_disp.x += xamount;
+	bgimg.new_disp.y += yamount;
+	UpdateBackgroundImgScalePosition();	
+}
+
+void ASSDrawCanvas::OnSelect_ConvertLineToBezier(wxCommandEvent& WXUNUSED(event))
+{
+	if (!dblclicked_point_right) return;
+	AddUndo( wxT("Convert Line to Bezier") );
+	DrawCmd_B *newB = new DrawCmd_B(dblclicked_point_right->x(), dblclicked_point_right->y(), 
+		pointsys, dblclicked_point_right->cmd_main);
+	InsertCmd ( newB, dblclicked_point_right->cmd_main );
+	ClearPointsSelection();
+	SetHighlighted(NULL, NULL);
+	DeleteCommand(dblclicked_point_right->cmd_main);
+	pointedAt_point = newB->m_point;
+	newB->Init();
+	RefreshDisplay();
+	RefreshUndocmds();
+}
+
+void ASSDrawCanvas::OnSelect_ConvertBezierToLine(wxCommandEvent& WXUNUSED(event))
+{
+	if (!dblclicked_point_right) return;
+	AddUndo( wxT("Convert Bezier to Line") );
+	DrawCmd_L *newL = new DrawCmd_L(dblclicked_point_right->x(), dblclicked_point_right->y(), pointsys, dblclicked_point_right->cmd_main);
+	InsertCmd ( newL, dblclicked_point_right->cmd_main );
+	ClearPointsSelection();
+	SetHighlighted(NULL, NULL);
+	DeleteCommand(dblclicked_point_right->cmd_main);
+	pointedAt_point = newL->m_point;
+	newL->Init();
+	RefreshDisplay();
+	RefreshUndocmds();
+}
+
+void ASSDrawCanvas::OnSelect_C1ContinuityBezier(wxCommandEvent& WXUNUSED(event))
+{
+	if (!dblclicked_point_right) return;
+	DrawCmd_B *cmdb = static_cast<DrawCmd_B*>(dblclicked_point_right->cmd_main);
+	AddUndo( wxT(cmdb->C1Cont? "Unset continuous":"Set continuous") );
+	cmdb->C1Cont = !cmdb->C1Cont;
+	RefreshUndocmds();
+}
+
+void ASSDrawCanvas::OnSelect_Move00Here(wxCommandEvent& WXUNUSED(event))
+{
+	AddUndo( wxT("Move origin") );
+	int wx, wy;
+	pointsys->FromWxPoint(mouse_point, wx, wy);
+	wxPoint wxp = pointsys->ToWxPoint(wx, wy);
+	pointsys->originx = wxp.x;
+	pointsys->originy = wxp.y;
+	MovePoints(-wx, -wy);
+	RefreshDisplay();
+	RefreshUndocmds();
+}
+
+void ASSDrawCanvas::ConnectSubsequentCmds (DrawCmd* cmd1, DrawCmd* cmd2)
+{
+	ASSDrawEngine::ConnectSubsequentCmds(cmd1, cmd2);
+	if (cmd1 && cmd1->type == B)
+	{
+		DrawCmd_B *cmd1b = static_cast< DrawCmd_B* >(cmd1);
+		cmd1b->C1Cont = false;
+	}
+}
+
+void ASSDrawCanvas::EnforceC1Continuity (DrawCmd* cmd, Point* pnt)
+{
+	if (!cmd || !pnt) return;
+	if (cmd->type != B && cmd->type != S) return;
+	if (pnt->type == MP) return;
+	Point *theotherpoint, *mainpoint;
+	if (pnt->num == 1)
+	{
+		if (!cmd->prev || (cmd->prev->type != B && cmd->prev->type != S)) return;
+		DrawCmd_B *prevb = static_cast< DrawCmd_B* >(cmd->prev);
+		if (!prevb->C1Cont) return;
+		PointList::iterator it = prevb->controlpoints.end();
+		it--;
+		theotherpoint = *it;
+		mainpoint = prevb->m_point;
+	}
+	else if (pnt->num = cmd->controlpoints.size())
+	{
+		DrawCmd_B *thisb = static_cast< DrawCmd_B* >(cmd);
+		if (!thisb->C1Cont) return;
+		theotherpoint = *(cmd->m_point->cmd_next->controlpoints.begin());		
+		mainpoint = thisb->m_point;
+	}
+	else
+		return;
+	theotherpoint->setXY( mainpoint->x() + mainpoint->x() - pnt->x(),
+		mainpoint->y() + mainpoint->y() - pnt->y() );
+}
+
+// Undo/Redo system
+void ASSDrawCanvas::AddUndo( wxString desc ) 
+{
+	PrepareUndoRedo(_undo, false, "", desc);
+	undos.push_back( _undo );
+	// also empty redos
+	redos.clear();
+	m_frame->UpdateUndoRedoMenu();
+}
+
+bool ASSDrawCanvas::UndoOrRedo(bool isundo)
+{
+	std::list<UndoRedo>* main = (isundo? &undos:&redos);
+	std::list<UndoRedo>* sub = (isundo? &redos:&undos);
+
+	if (main->empty())
+		return false;
+
+	UndoRedo r = main->back();
+	// push into sub
+	UndoRedo nr(r);
+	PrepareUndoRedo(nr, true, GenerateASS(), r.desc); 
+	//PrepareUndoRedo(nr, false, "", r.desc);
+	sub->push_back( nr );
+	// parse
+	r.Export(this);
+	// delete that
+	std::list<UndoRedo>::iterator iter = main->end();
+	iter--;
+	main->erase(iter);
+
+	// reset some values before refreshing
+	mousedownAt_point = NULL;
+	pointedAt_point = NULL;
+	SetHighlighted ( NULL, NULL );
+	ClearPointsSelection();
+	RefreshDisplay();
+	RefreshUndocmds();
+	return true;
+}
+
+bool ASSDrawCanvas::Undo()
+{
+	return UndoOrRedo( true );
+}
+
+bool ASSDrawCanvas::Redo()
+{
+	return UndoOrRedo( false );
+}
+
+wxString ASSDrawCanvas::GetTopUndo()
+{
+	if (undos.empty())
+		return "";
+	else
+		return undos.back().desc;
+}
+
+wxString ASSDrawCanvas::GetTopRedo()
+{
+	if (redos.empty())
+		return "";
+	else
+		return redos.back().desc;
+}
+
+void ASSDrawCanvas::RefreshUndocmds()
+{
+	_undo.Import(this, true, GenerateASS());
+}
+
+void ASSDrawCanvas::PrepareUndoRedo(UndoRedo& ur, bool prestage, wxString cmds, wxString desc) 
+{
+	ur.Import(this, prestage, cmds);
+	ur.desc = desc;	
+}
+
+// set command and point to highlight
+void ASSDrawCanvas::SetHighlighted ( DrawCmd* cmd, Point* point )
+{
+     hilite_cmd = cmd;
+     hilite_point = point;
+}
+
+int ASSDrawCanvas::SelectPointsWithin( int lx, int rx, int ty, int by, SELECTMODE smode )
+{
+
+	DrawCmdList::iterator iterate = cmds.begin();
+	for (; iterate != cmds.end(); iterate++)
+	{
+		wxPoint wx = (*iterate)->m_point->ToWxPoint();
+
+		if (wx.x >= lx && wx.x <= rx && wx.y >= ty && wx.y <= by)
+			(*iterate)->m_point->isselected = (smode != DEL);
+		else
+	    	(*iterate)->m_point->isselected &= (smode != NEW);
+
+		if ((*iterate)->m_point->isselected)
+	    	selected_points.insert((*iterate)->m_point);
+	    else
+			selected_points.erase((*iterate)->m_point);
+
+		PointList::iterator pnt_iterator = (*iterate)->controlpoints.begin();
+		PointList::iterator end = (*iterate)->controlpoints.end();
+		for (; pnt_iterator != end; pnt_iterator++)
+		{
+			wxPoint wx = (*pnt_iterator)->ToWxPoint();
+
+			if (wx.x >= lx && wx.x <= rx && wx.y >= ty && wx.y <= by)
+	    		(*pnt_iterator)->isselected = (smode != DEL);
+		    else
+	    		(*pnt_iterator)->isselected &= (smode != NEW);
+			
+			if ((*pnt_iterator)->isselected)
+				selected_points.insert(*pnt_iterator);
+			else
+				selected_points.erase(*pnt_iterator);
+		}
+	}
+
+	return selected_points.size();
+
+}
+
+void ASSDrawCanvas::ClearPointsSelection()
+{
+	if (!selected_points.empty())
+	{
+		PointSet::iterator piter = selected_points.begin();
+		for (; piter != selected_points.end(); piter++)
+		{
+			(*piter)->isselected = false;
+		}
+		selected_points.clear();
+	}
+}
+
+SELECTMODE ASSDrawCanvas::GetSelectMode(wxMouseEvent& event)
+{
+	SELECTMODE smode = NEW;
+	bool CtrlDown = event.CmdDown();
+	bool AltDown = event.AltDown();
+	if (CtrlDown && !AltDown) smode = ADD;
+	else if (!CtrlDown && AltDown) smode = DEL;
+	return smode;
+}
+
+void ASSDrawCanvas::DoDraw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx )
+{
+	ASSDrawEngine::Draw_Clear( rbase );
+	int ww, hh; GetClientSize(&ww, &hh);
+
+	if (bgimg.bgbmp)
+	{ 
+		rasterizer.reset();
+	    interpolator_type interpolator(bgimg.img_mtx);
+	    PixelFormat::AGGType ipixfmt(bgimg.ibuf);
+		span_gen_type spangen(ipixfmt, agg::rgba_pre(0, 0, 0), interpolator);
+		agg::conv_transform< agg::path_storage > bg_border(bgimg.bg_path, bgimg.path_mtx);
+		agg::conv_clip_polygon< agg::conv_transform< agg::path_storage > > bg_clip(bg_border);
+		bg_clip.clip_box(0, 0, ww, hh);
+		rasterizer.add_path(bg_clip);
+		agg::render_scanlines_aa(rasterizer, scanline, rbase, bgimg.spanalloc, spangen);
+	}
+
+	ASSDrawEngine::Draw_Draw( rbase, rprim, rsolid, mtx, preview_mode? rgba_shape:rgba_shape_normal );
+		
+	if (!preview_mode)
+	{
+		// [0, 0]
+		rasterizer.reset();
+		agg::path_storage org_path;
+		org_path.move_to(0, m_frame->sizes.origincross);
+		org_path.line_to(0, -m_frame->sizes.origincross);
+		org_path.move_to(m_frame->sizes.origincross, 0);
+		org_path.line_to(-m_frame->sizes.origincross, 0);
+		agg::conv_transform< agg::path_storage > org_path_t(org_path, mtx);
+	    agg::conv_curve< agg::conv_transform< agg::path_storage > > crosshair(org_path_t);
+		agg::conv_stroke< agg::conv_curve< agg::conv_transform< agg::path_storage > > > chstroke(crosshair);
+		rasterizer.add_path(chstroke);
+		rsolid.color(rgba_origin);
+		render_scanlines(rsolid, false);
+
+		if (IsTransformMode() && isshapetransformable)
+		{
+			if (draw_mode == MODE_SCALEROTATE)
+			{
+				// rotation centerpoint
+				rasterizer.reset();
+				double len = 10.0; //m_frame->sizes.origincross * pointsys->scale;
+				org_path.free_all();
+				org_path.move_to(rectcenter.x - len, rectcenter.y - len);
+				org_path.line_to(rectcenter.x + len, rectcenter.y + len);
+				org_path.move_to(rectcenter.x + len, rectcenter.y - len);
+				org_path.line_to(rectcenter.x - len, rectcenter.y + len);
+				agg::conv_stroke< agg::path_storage > cstroke(org_path);
+				rasterizer.add_path(cstroke);
+				agg::ellipse circ(rectcenter.x, rectcenter.y, len, len);
+				agg::conv_stroke< agg::ellipse > c(circ);
+				rasterizer.add_path(c);
+				rsolid.color(rgba_origin);
+				render_scanlines(rsolid, false);
+			}
+
+			rasterizer.reset();
+			agg::path_storage org_path;
+			org_path.move_to(rectbound2[0].x, rectbound2[0].y);
+			org_path.line_to(rectbound2[1].x, rectbound2[1].y);
+			org_path.line_to(rectbound2[2].x, rectbound2[2].y);
+			org_path.line_to(rectbound2[3].x, rectbound2[3].y);
+			org_path.line_to(rectbound2[0].x, rectbound2[0].y);
+			agg::conv_stroke<agg::path_storage> chstroke(org_path);
+			chstroke.width(1);
+			rsolid.color(rgba_origin);
+			rasterizer.add_path(chstroke);
+			if (rectbound2upd != -1)
+			{
+				agg::ellipse circ(rectbound2[rectbound2upd].x, rectbound2[rectbound2upd].y, 
+					pointsys->scale, pointsys->scale);
+				agg::conv_contour< agg::ellipse > c(circ);
+				rasterizer.add_path(c);
+			}
+			if (rectbound2upd2 != -1)
+			{
+				agg::ellipse circ(rectbound2[rectbound2upd2].x, rectbound2[rectbound2upd2].y, 
+					pointsys->scale, pointsys->scale);
+				agg::conv_contour< agg::ellipse > c(circ);
+				rasterizer.add_path(c);
+			}
+			render_scanlines(rsolid, false);
+		}
+		else
+		{
+			// outlines
+			agg::conv_stroke< agg::conv_transform< agg::path_storage > > bguidestroke(*rb_path);
+			bguidestroke.width(1);
+			rsolid.color(rgba_guideline);
+			rasterizer.add_path(bguidestroke);
+			render_scanlines(rsolid);
+	
+			agg::conv_stroke< agg::conv_curve< agg::conv_transform< agg::path_storage > > > stroke(*rm_curve);
+			stroke.width(1);
+			rsolid.color(rgba_outline);
+			rasterizer.add_path(stroke);
+			render_scanlines(rsolid);
+	
+			double diameter = pointsys->scale;
+			double radius = diameter / 2.0;
+			// hilite
+			if (hilite_cmd && hilite_cmd->type != M)
+			{
+				rasterizer.reset();
+				agg::path_storage h_path;
+				AddDrawCmdToAGGPathStorage(hilite_cmd, h_path, HILITE);
+				agg::conv_transform< agg::path_storage> h_path_trans(h_path, mtx);
+			    agg::conv_curve< agg::conv_transform< agg::path_storage> > curve(h_path_trans);
+				agg::conv_dash< agg::conv_curve< agg::conv_transform< agg::path_storage > > > d(curve);
+				d.add_dash(10,5);
+				agg::conv_stroke< agg::conv_dash< agg::conv_curve< agg::conv_transform< agg::path_storage > > > > stroke(d);
+				stroke.width(3);
+				rsolid.color(rgba_outline);
+				rasterizer.add_path(stroke);
+				render_scanlines(rsolid);
+			}
+			
+			// m_point
+			rasterizer.reset();
+			DrawCmdList::iterator ci = cmds.begin();
+			while (ci != cmds.end())
+			{
+				double lx = (*ci)->m_point->x() * pointsys->scale + pointsys->originx - radius;
+				double ty = (*ci)->m_point->y() * pointsys->scale + pointsys->originy - radius;
+				agg::path_storage sqp = agghelper::RectanglePath(lx, lx + diameter, ty, ty + diameter);
+				agg::conv_contour< agg::path_storage > c(sqp);
+				rasterizer.add_path(c);
+				ci++;
+			}
+			render_scanlines_aa_solid(rbase, rgba_mainpoint);
+	
+			// control_points
+			rasterizer.reset();
+			ci = cmds.begin();
+			while (ci != cmds.end())
+			{
+				PointList::iterator pi = (*ci)->controlpoints.begin();
+				while (pi != (*ci)->controlpoints.end())
+				{
+					agg::ellipse circ((*pi)->x() * pointsys->scale + pointsys->originx, 
+						(*pi)->y() * pointsys->scale + pointsys->originy, radius, radius);
+					agg::conv_contour< agg::ellipse > c(circ);
+					rasterizer.add_path(c);
+					pi++;
+				}
+				ci++;
+			}
+			render_scanlines_aa_solid(rbase, rgba_controlpoint);
+		
+			// selection
+			rasterizer.reset();
+			PointSet::iterator si = selected_points.begin();
+			while (si != selected_points.end())
+			{
+				agg::ellipse circ((*si)->x() * pointsys->scale + pointsys->originx, 
+					(*si)->y() * pointsys->scale + pointsys->originy, radius + 3, radius + 3);
+				agg::conv_stroke< agg::ellipse > s(circ);
+				rasterizer.add_path(s);
+				si++;
+			}
+			render_scanlines_aa_solid(rbase, rgba_selectpoint);
+	
+			// hover
+			if (hilite_point)
+			{
+				rasterizer.reset();
+				agg::ellipse circ(hilite_point->x() * pointsys->scale + pointsys->originx, 
+					hilite_point->y() * pointsys->scale + pointsys->originy, radius + 3, radius + 3);
+				agg::conv_stroke< agg::ellipse > s(circ);
+				s.width(2);
+				rasterizer.add_path(s);
+				render_scanlines_aa_solid(rbase, rgba_selectpoint);
+	
+				rasterizer.reset();
+				agg::gsv_text t;
+				t.flip(true);
+				t.size(8.0);
+				wxPoint pxy = hilite_point->ToWxPoint(true);
+				t.start_point(pxy.x + 5, pxy.y -5 );
+				t.text(wxString::Format("%d,%d", hilite_point->x(), hilite_point->y()));
+				agg::conv_stroke< agg::gsv_text > pt(t);
+				pt.line_cap(agg::round_cap);
+				pt.line_join(agg::round_join);
+				pt.width(1.5);
+				rasterizer.add_path(pt);
+				rsolid.color(agg::rgba(0,0,0));
+				render_scanlines(rsolid, false);
+				
+				rasterizer.reset();
+				agg::path_storage sb_path;
+				sb_path.move_to(pxy.x, 0);
+				sb_path.line_to(pxy.x, hh);
+				sb_path.move_to(0, pxy.y);
+				sb_path.line_to(ww, pxy.y);
+			    agg::conv_curve< agg::path_storage > curve(sb_path);
+				agg::conv_dash< agg::conv_curve< agg::path_storage > > d(curve);
+				d.add_dash(10,5);
+				agg::conv_stroke< agg::conv_dash< agg::conv_curve< agg::path_storage > > > stroke(d);
+				stroke.width(1);
+				rsolid.color(agg::rgba(0,0,0,0.5));
+				rasterizer.add_path(stroke);
+				render_scanlines(rsolid);
+			}
+			
+			// selection box
+			if (lastDrag_left)
+			{
+				double x1 = lastDrag_left->x, y1 = lastDrag_left->y;
+				double x2 = dragAnchor_left->x, y2 = dragAnchor_left->y;
+				double lx, rx, ty, by;
+				if (x1 < x2) lx = x1, rx = x2;
+				else lx = x2, rx = x1;
+				if (y1 < y2) ty = y1, by = y2;
+				else ty = y2, by = y1;
+				rasterizer.reset();
+				agg::path_storage sb_path = agghelper::RectanglePath(lx, rx, ty, by);
+			    agg::conv_curve< agg::path_storage > curve(sb_path);
+				agg::conv_dash< agg::conv_curve< agg::path_storage > > d(curve);
+				d.add_dash(10,5);
+				agg::conv_stroke< agg::conv_dash< agg::conv_curve< agg::path_storage > > > stroke(d);
+				stroke.width(1.0);
+				rsolid.color(agg::rgba(0,0,0,0.5));
+				rasterizer.add_path(stroke);
+				render_scanlines(rsolid);
+			}
+		}		
+	}
+	
+	// ruler
+	int w, h;
+	GetClientSize( &w, &h );
+	double scale = pointsys->scale;
+	double coeff = 9 / scale + 1;
+	int numdist = (int) floor(coeff) * 5;
+	{
+		rsolid.color(rgba_ruler_h);
+		rasterizer.reset();
+		agg::path_storage rlr_path;
+		double start = pointsys->originx;
+		int t = - (int) floor(start / scale);
+		double s = (start + t * scale);
+		double collect = s;
+		int len;
+
+		for (; s <= w; s += scale)
+		{
+			bool longtick = t % numdist == 0;
+			if (longtick)
+			{
+				len = 10;
+				agg::gsv_text txt;
+				txt.flip(true);
+				txt.size(6.0);
+				txt.start_point(s, 20);
+				txt.text(wxString::Format("%d", t));
+				agg::conv_stroke< agg::gsv_text > pt(txt);
+				rasterizer.add_path(pt);
+			}
+			else
+				len = 5;
+			t++ ;
+			collect += scale;
+			if (collect > 5.0)
+			{
+				collect = 0.0;
+				rlr_path.move_to(s, 0);
+				rlr_path.line_to(s, len);
+			}
+		}
+		agg::conv_stroke< agg::path_storage > rlr_stroke(rlr_path);
+		rlr_stroke.width(1);
+		rasterizer.add_path(rlr_stroke);
+		render_scanlines(rsolid, false);
+	}
+	{
+		rasterizer.reset();
+		rsolid.color(rgba_ruler_v);
+		agg::path_storage rlr_path;
+		double start = pointsys->originy;
+		int t = - (int) floor(start / scale);
+		double s = (start + t * scale);
+		double collect = 0;
+		int len;
+
+		for (; s <= h; s += scale)
+		{
+			bool longtick = t % numdist == 0;
+			if (longtick)
+			{
+				len = 10;
+				agg::gsv_text txt;
+				txt.flip(true);
+				txt.size(6.0);
+				txt.start_point(12, s);
+				txt.text(wxString::Format("%d", t));
+				agg::conv_stroke< agg::gsv_text > pt(txt);
+				rasterizer.add_path(pt);
+			}
+			else
+				len = 5;
+			t++ ;
+			collect += scale;
+			if (collect > 5.0)
+			{
+				collect = 0.0;
+				rlr_path.move_to(0, s);
+				rlr_path.line_to(len, s);
+			}
+		}
+		agg::conv_stroke< agg::path_storage > rlr_stroke(rlr_path);
+		rlr_stroke.width(1);
+		rasterizer.add_path(rlr_stroke);
+		render_scanlines(rsolid, false);
+	}
+
+}
+
+void ASSDrawCanvas::ReceiveBackgroundImageFileDropEvent(const wxString& filename)
+{
+	const wxChar *shortfname = wxFileName::FileName(filename).GetFullName().c_str();
+	m_frame->SetStatusText(wxString::Format("Loading '%s' as canvas background ...", shortfname), 1);
+	wxImage img;
+	img.LoadFile(filename);
+	if (img.IsOk())
+	{
+		SetBackgroundImage(img, filename);
+	}
+	m_frame->SetStatusText(wxT("Canvas background loaded"), 1);
+}
+
+void ASSDrawCanvas::RemoveBackgroundImage()
+{
+	if (bgimg.bgimg) delete bgimg.bgimg;
+	bgimg.bgimg = NULL;
+	if (bgimg.bgbmp) delete bgimg.bgbmp;
+	bgimg.bgbmp = NULL;
+	bgimg.bgimgfile = "";
+	RefreshDisplay();
+	drag_mode = DRAGMODE();
+	bgimg.alpha_dlg->Show(false);
+	m_frame->UpdateFrameUI();
+}
+
+void ASSDrawCanvas::SetBackgroundImage(const wxImage& img, wxString fname, bool ask4alpha)
+{
+	if (bgimg.bgimg) delete bgimg.bgimg;
+	bgimg.bgimg = new wxImage(img);
+	bgimg.bgimgfile = fname;
+	PrepareBackgroundBitmap(bgimg.alpha);
+    UpdateBackgroundImgScalePosition(true);
+	RefreshDisplay();
+	m_frame->UpdateFrameUI();
+	if (ask4alpha && m_frame->behaviors.autoaskimgopac)
+		AskUserForBackgroundAlpha();
+}
+
+void ASSDrawCanvas::AskUserForBackgroundAlpha()
+{
+	bgimg.alpha_slider->SetValue((int) (100 - bgimg.alpha * 100));
+	bgimg.alpha_dlg->Show();
+	SetFocus();
+}
+	
+void ASSDrawCanvas::PrepareBackgroundBitmap(double alpha)
+{
+	if (alpha >= 0.0 && alpha <= 1.0) bgimg.alpha = alpha;
+	if (bgimg.bgimg == NULL) return;
+	if (bgimg.bgbmp) delete bgimg.bgbmp;
+	bgimg.bgbmp = new wxBitmap(*bgimg.bgimg);
+    PixelData data(*bgimg.bgbmp);
+    wxAlphaPixelFormat::ChannelType* pd = (wxAlphaPixelFormat::ChannelType*) &data.GetPixels().Data();
+    const int stride = data.GetRowStride();
+    if (stride < 0)
+        pd += (data.GetHeight() - 1) * stride;
+    bgimg.ibuf.attach(pd, data.GetWidth(), data.GetHeight(), stride);
+    
+    // apply alpha
+	rasterizer.reset();
+	unsigned w = bgimg.bgbmp->GetWidth(), h = bgimg.bgbmp->GetHeight();
+	bgimg.bg_path = agghelper::RectanglePath(0, w, 0, h);
+    agg::conv_contour< agg::path_storage > cont(bgimg.bg_path);
+	rasterizer.add_path(cont);
+	PixelFormat::AGGType pxt(bgimg.ibuf);
+	RendererBase rpxt(pxt);
+	agg::render_scanlines_aa_solid(rasterizer, scanline, rpxt, agg::rgba(color_bg.r / 255.0, color_bg.g / 255.0, color_bg.b / 255.0, bgimg.alpha));
+}
+
+void ASSDrawCanvas::UpdateBackgroundImgScalePosition(bool firsttime)
+{
+	if (bgimg.bgbmp == NULL) return;
+	// transform the enclosing polygon
+	unsigned w = bgimg.bgbmp->GetWidth(), h = bgimg.bgbmp->GetHeight();
+	bgimg.bg_path = agghelper::RectanglePath(0, w, 0, h);
+    // linear interpolation on image buffer
+    wxRealPoint center, disp;
+    double scale;
+    if (firsttime) // first time
+    {
+	    bgimg.img_mtx = agg::trans_affine();
+	    scale = 1.0;
+		center = wxRealPoint(0.0, 0.0);
+	    disp = wxRealPoint(0.0, 0.0);
+	    bgimg.path_mtx = bgimg.img_mtx;
+	}
+	else
+	{
+		wxRealPoint d_disp(bgimg.new_disp.x - bgimg.disp.x, bgimg.new_disp.y - bgimg.disp.y);
+		scale = bgimg.new_scale;
+		disp = bgimg.disp;
+		center = bgimg.new_center;
+		if (bgimg.scale == scale)
+		{
+		    bgimg.img_mtx.invert();
+		    bgimg.img_mtx *= agg::trans_affine_translation(d_disp.x, d_disp.y);
+			d_disp.x /= scale;
+			d_disp.y /= scale;
+		}
+		else
+		{
+			d_disp.x /= scale;
+			d_disp.y /= scale;
+		    bgimg.img_mtx = agg::trans_affine();
+			disp.x += (center.x - bgimg.center.x) * (1.0 - 1.0 / bgimg.scale);
+			disp.y += (center.y - bgimg.center.y) * (1.0 - 1.0 / bgimg.scale);
+		    bgimg.img_mtx *= agg::trans_affine_translation(-center.x + disp.x, -center.y + disp.y);
+		    bgimg.img_mtx *= agg::trans_affine_scaling(scale);
+		    bgimg.img_mtx *= agg::trans_affine_translation(center.x + d_disp.x, center.y + d_disp.y);
+		}
+	    bgimg.path_mtx = bgimg.img_mtx;
+	    bgimg.img_mtx.invert();
+	    disp.x += d_disp.x;
+	    disp.y += d_disp.y;
+	}
+    //update
+    bgimg.scale = scale;
+    bgimg.center = center;
+    bgimg.disp = disp;
+    bgimg.new_scale = scale;
+    bgimg.new_center = center;
+    bgimg.new_disp = disp;
+}
+
+bool ASSDrawCanvas::GetBackgroundInfo(unsigned& w, unsigned& h, wxRealPoint& disp, double& scale)
+{
+	if (!HasBackgroundImage()) return false;
+	w = bgimg.bgbmp->GetWidth(), h = bgimg.bgbmp->GetHeight();
+	double t, l;
+	agg::conv_transform<agg::path_storage, agg::trans_affine> trr(bgimg.bg_path, bgimg.path_mtx);
+	trr.rewind(0);
+	trr.vertex(&l, &t);
+	disp = wxRealPoint(l, t);
+	scale = bgimg.scale;
+	return true;
+}
+
+void ASSDrawCanvas::UpdateNonUniformTransformation()
+{
+	double bound[8] = {
+		rectbound2[0].x, rectbound2[0].y,
+		rectbound2[1].x, rectbound2[1].y,
+		rectbound2[2].x, rectbound2[2].y,
+		rectbound2[3].x, rectbound2[3].y };
+	agg::path_storage trans;
+	unsigned vertices = backupcmds.total_vertices();
+	double x, y;
+	
+	//if (draw_mode == MODE_NUT_BILINEAR)
+	//{
+		agg::trans_bilinear trans_b(rectbound[0].x, rectbound[0].y, rectbound[2].x, rectbound[2].y, bound);
+		agg::conv_transform<agg::path_storage, agg::trans_bilinear> transb(backupcmds, trans_b);
+		transb.rewind(0);
+		for (int i = 0; i < vertices; i++)
+		{
+			transb.vertex(&x, &y);
+			trans.move_to(x, y);
+		}
+	//}
+	/*	else
+	{
+		agg::trans_perspective trans_p(rectbound[0].x, rectbound[0].y, rectbound[2].x, rectbound[2].y, bound);
+		agg::conv_transform<agg::path_storage, agg::trans_perspective> transp(backupcmds, trans_p);
+		transp.rewind(0);
+		for (int i = 0; i < vertices; i++)
+		{
+			transp.vertex(&x, &y);
+			trans.move_to(x, y);
+		}
+	}
+	*/
+	trans.rewind(0);
+	for (DrawCmdList::iterator iterate = cmds.begin(); iterate != cmds.end(); iterate++)
+	{
+		DrawCmd* cmd = (*iterate);
+		for (PointList::iterator iterate2 = cmd->controlpoints.begin(); iterate2 != cmd->controlpoints.end(); iterate2++)
+		{
+	        double x, y;
+	        trans.vertex(&x, &y);
+	        int wx, wy;
+			pointsys->FromWxPoint ( wxPoint((int)x, (int)y), wx, wy );
+			(*iterate2)->setXY(wx, wy);
+		}
+	    double x, y;
+	    trans.vertex(&x, &y);
+	    int wx, wy;
+		pointsys->FromWxPoint ( wxPoint((int)x, (int)y), wx, wy );
+		(*iterate)->m_point->setXY(wx, wy);
+	}
+	
+}
+
+void ASSDrawCanvas::CustomOnKeyDown(wxKeyEvent &event)
+{
+	int keycode = event.GetKeyCode();
+	//m_frame->SetStatusText(wxString::Format("Key: %d", keycode));
+	double scrollamount = (event.GetModifiers() == wxMOD_CMD? 10.0:1.0);	
+    if (event.GetModifiers() == wxMOD_SHIFT)
+	{
+		MODE d_mode = GetDrawMode();
+        if ((int) d_mode > (int) MODE_ARR && (int) d_mode < (int) MODE_SCALEROTATE)
+		{
+			mode_b4_shift = d_mode;
+			SetDrawMode( MODE_ARR );
+			m_frame->UpdateFrameUI();
+		}
+    }
+    else
+    {
+		switch (keycode)
+		{
+		case WXK_PAGEUP:
+			ChangeZoomLevel( 1.0 /scrollamount, wxPoint( (int) pointsys->originx, (int) pointsys->originy ) );
+			RefreshDisplay();
+			break;
+		case WXK_PAGEDOWN:
+			ChangeZoomLevel( - 1.0 /scrollamount, wxPoint( (int) pointsys->originx, (int) pointsys->originy ) );
+			RefreshDisplay();
+			break;
+		case WXK_UP:
+			MoveCanvas(0.0, -scrollamount);
+			RefreshDisplay();
+			break;
+		case WXK_DOWN:
+			MoveCanvas(0.0, scrollamount);
+			RefreshDisplay();
+			break;
+		case WXK_LEFT:
+			MoveCanvas(-scrollamount, 0.0);
+			RefreshDisplay();
+			break; 
+		case WXK_RIGHT:
+			MoveCanvas(scrollamount, 0.0);
+			RefreshDisplay();
+			break;
+		case WXK_TAB:
+			if (mousedownAt_point == NULL && !IsTransformMode() && cmds.size() > 0)
+			{
+				if (pointedAt_point == NULL)
+				{
+					Point *nearest = NULL;
+					double dist = 0.0;
+					DrawCmdList::iterator it = cmds.begin();
+					while(it != cmds.end())
+					{
+						wxPoint point = (*it)->m_point->ToWxPoint();
+						double distance = sqrt(pow(point.x - mouse_point.x, 2) + pow(point.y - mouse_point.y, 2));
+						if (nearest == NULL || distance < dist)
+						{
+							nearest = (*it)->m_point;
+							dist = distance;
+						}
+						PointList::iterator it2 = (*it)->controlpoints.begin();
+						while (it2 != (*it)->controlpoints.end())
+						{
+							wxPoint point = (*it2)->ToWxPoint();
+							double distance = sqrt(pow(point.x - mouse_point.x, 2) + pow(point.y - mouse_point.y, 2));
+							if (nearest == NULL || distance < dist)
+							{
+								nearest = (*it2);
+								dist = distance;
+							}						
+							it2++;	
+						}
+						it++;
+					}
+					if (nearest != NULL)
+					{
+						wxPoint point = nearest->ToWxPoint();
+						WarpPointer(point.x, point.y);
+					}
+				}
+				else
+				{
+					Point *warpto = NULL;
+					if (pointedAt_point->type == MP)
+					{
+						if (pointedAt_point->cmd_next != NULL)
+						{
+							if (pointedAt_point->cmd_next->controlpoints.size() > 0)
+								warpto = pointedAt_point->cmd_next->controlpoints.front();
+							else
+								warpto = pointedAt_point->cmd_next->m_point;
+						}
+					}
+					else
+					{
+						PointList::iterator it = pointedAt_point->cmd_main->controlpoints.begin();
+						while (*it != pointedAt_point) it++;
+						it++;
+						if (it == pointedAt_point->cmd_main->controlpoints.end())
+							warpto = pointedAt_point->cmd_main->m_point;
+						else
+							warpto = *it;
+					}
+					if (warpto == NULL)
+						warpto = cmds.front()->m_point;
+					wxPoint point = warpto->ToWxPoint();
+					WarpPointer(point.x, point.y);
+				}
+			}
+			break;
+		default:
+	        event.Skip();
+		}
+	}
+}
+
+void ASSDrawCanvas::CustomOnKeyUp(wxKeyEvent &event)
+{
+	int keycode = event.GetKeyCode();
+	if (event.GetModifiers() != wxMOD_SHIFT && (int) mode_b4_shift > (int) MODE_ARR)
+	{
+		SetDrawMode( mode_b4_shift );
+		m_frame->UpdateFrameUI();
+		mode_b4_shift = MODE_ARR;
+	}
+}
+
+void ASSDrawCanvas::OnAlphaSliderChanged(wxScrollEvent &event)
+{
+	double pos = (double) event.GetPosition();
+	PrepareBackgroundBitmap(1.0 - pos / 100.0);
+	RefreshDisplay();
+}
+
+void ASSDrawCanvas::CustomOnMouseCaptureLost(wxMouseCaptureLostEvent &event)
+{
+	if (capturemouse_left)
+		ProcessOnMouseLeftUp();
+
+	if (capturemouse_right)
+		ProcessOnMouseRightUp();
+}
+
+void UndoRedo::Import(ASSDrawCanvas *canvas, bool prestage, wxString cmds)
+{
+	if (prestage)
+	{
+		this->cmds = cmds;
+		this->backupcmds.free_all();
+		this->backupcmds.concat_path(canvas->backupcmds);
+		for (int i = 0; i < 4; i++)
+		{
+			this->rectbound[i] = canvas->rectbound[i];
+			this->rectbound2[i] = canvas->rectbound2[i];
+			this->backup[i] = canvas->backup[i];
+		}
+		this->isshapetransformable = canvas->isshapetransformable;
+	}
+	else
+	{
+	    this->originx = canvas->pointsys->originx;
+		this->originy = canvas->pointsys->originy;
+	    this->scale = canvas->pointsys->scale;
+	
+		this->bgimgfile = canvas->bgimg.bgimgfile;
+		this->bgdisp = canvas->bgimg.disp;
+		this->bgcenter = canvas->bgimg.center;
+		this->bgscale = canvas->bgimg.scale;
+		this->bgalpha = canvas->bgimg.alpha;
+		this->c1cont = canvas->PrepareC1ContData();
+		this->draw_mode = canvas->draw_mode;
+	}
+}
+
+void UndoRedo::Export(ASSDrawCanvas *canvas)
+{
+	canvas->pointsys->originx = this->originx;
+	canvas->pointsys->originy = this->originy;
+	canvas->pointsys->scale = this->scale;
+	canvas->ParseASS( this->cmds );
+	DrawCmdList::iterator it1 = canvas->cmds.begin();
+	std::vector< bool >::iterator it2 = this->c1cont.begin();
+	for(; it1 != canvas->cmds.end() && it2 != this->c1cont.end(); it1++, it2++)
+		if (*it2 && (*it1)->type == B)
+			static_cast<DrawCmd_B*>(*it1)->C1Cont = true;
+
+	if (canvas->bgimg.bgimgfile != this->bgimgfile)
+	{
+		canvas->RemoveBackgroundImage();
+		if (!this->bgimgfile.IsSameAs("<clipboard>") && ::wxFileExists(this->bgimgfile))
+		{
+			canvas->bgimg.alpha = this->bgalpha;
+			canvas->ReceiveBackgroundImageFileDropEvent(this->bgimgfile);
+		}
+	}
+	else
+	{
+		canvas->bgimg.new_scale = this->bgscale;
+		canvas->bgimg.new_center = this->bgcenter;
+		canvas->bgimg.new_disp = this->bgdisp;
+		canvas->bgimg.alpha = this->bgalpha;
+		canvas->UpdateBackgroundImgScalePosition();
+	}	
+	
+
+	//canvas->SetDrawMode(this->draw_mode);
+	canvas->draw_mode = this->draw_mode;
+	if (canvas->IsTransformMode())
+	{
+		canvas->backupcmds.free_all();
+		canvas->backupcmds.concat_path(this->backupcmds);
+		for (int i = 0; i < 4; i++)
+		{
+			canvas->rectbound[i] = this->rectbound[i];
+			canvas->rectbound2[i] = this->rectbound2[i];
+			canvas->backup[i] = this->backup[i];
+		}
+		canvas->UpdateNonUniformTransformation();
+		canvas->InitiateDraggingIfTransformMode();
+		canvas->rectbound2upd = -1;
+		canvas->rectbound2upd2 = -1;
+		canvas->isshapetransformable = this->isshapetransformable;
+	}
+}
diff --git a/assdraw/src/canvas.hpp b/assdraw/src/canvas.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..23f4abf4b6deb3fdb93af3abc31d62fd697ed0a8
--- /dev/null
+++ b/assdraw/src/canvas.hpp
@@ -0,0 +1,303 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        canvas.hpp
+// Purpose:     header file for ASSDraw main canvas class
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include <vector>
+
+#include "engine.hpp"
+#include "enums.hpp"
+
+#include <wx/dnd.h>
+#include <wx/splitter.h>
+#include <wx/clntdata.h>
+
+#include "agg_span_allocator.h"
+#include "agg_span_interpolator_linear.h"
+#include "agg_span_image_filter_rgb.h"
+#include "agg_span_image_filter_rgba.h"
+#include "agg_image_accessors.h"
+#include "agg_conv_clip_polygon.h"
+
+class ASSDrawFrame;
+class ASSDrawCanvas;
+
+struct UndoRedo
+{
+	wxString cmds;
+	wxString desc;
+	double originx, originy, scale;
+
+	std::vector< bool > c1cont;
+	wxString bgimgfile;
+	wxRealPoint bgdisp, bgcenter;
+	double bgscale, bgalpha;
+
+	MODE draw_mode;
+	agg::path_storage backupcmds;
+	wxRealPoint rectbound[4], rectbound2[4], backup[4];
+	bool isshapetransformable;
+
+	void Import(ASSDrawCanvas *canvas, bool prestage, wxString cmds = _T(""));
+	void Export(ASSDrawCanvas *canvas);
+	
+};
+
+// for multiple point selection
+enum SELECTMODE { NEW, ADD, DEL };
+
+class ASSDrawCanvas: public ASSDrawEngine, public wxClientData
+{
+public:
+	ASSDrawCanvas( wxWindow *parent, ASSDrawFrame *frame, int extraflags = 0 );
+
+    // destructor
+    ~ASSDrawCanvas();
+
+    virtual void ResetEngine(bool addM);
+	virtual void SetPreviewMode( bool mode );
+	virtual bool IsPreviewMode() { return preview_mode; }
+	virtual void ParseASS(wxString str, bool addundo = false);
+
+	virtual void SetDrawMode( MODE mode );
+	virtual MODE GetDrawMode() { return draw_mode; }
+	virtual bool IsTransformMode();
+	virtual void SetDragMode( DRAGMODE mode );
+	virtual DRAGMODE GetDragMode() { return drag_mode; }
+	virtual void RefreshDisplay();
+	virtual bool CanZoom();
+	virtual bool CanMove();
+	
+    virtual void OnMouseMove(wxMouseEvent &event);
+    virtual void OnMouseLeftUp(wxMouseEvent &event);
+    virtual void OnMouseLeftDown(wxMouseEvent &event);
+    virtual void OnMouseRightUp(wxMouseEvent &event);
+    virtual void OnMouseRightDown(wxMouseEvent &event);
+    virtual void OnMouseRightDClick(wxMouseEvent &event);
+    virtual void OnMouseWheel(wxMouseEvent &event);
+    virtual void CustomOnKeyDown(wxKeyEvent &event);
+    virtual void CustomOnKeyUp(wxKeyEvent &event);
+	virtual void ChangeZoomLevel(double zoomamount, wxPoint bgzoomctr);
+	virtual void ChangeZoomLevelTo(double zoom, wxPoint bgzoomctr);
+	virtual void ChangeDrawingZoomLevel(double zoom);
+	virtual void ChangeBackgroundZoomLevel(double zoom, wxRealPoint newcenter);
+	virtual void MoveCanvas(double xamount, double yamount);
+	virtual void MoveCanvasOriginTo(double originx, double originy);
+	virtual void MoveCanvasDrawing(double xamount, double yamount);
+	virtual void MoveCanvasBackground(double xamount, double yamount);
+	virtual void OnSelect_ConvertLineToBezier(wxCommandEvent& WXUNUSED(event));
+	virtual void OnSelect_ConvertBezierToLine(wxCommandEvent& WXUNUSED(event));
+	virtual void OnSelect_C1ContinuityBezier(wxCommandEvent& WXUNUSED(event));
+	virtual void OnSelect_Move00Here(wxCommandEvent& WXUNUSED(event));
+	void OnAlphaSliderChanged(wxScrollEvent &event);
+	
+	// to replace _PointSystem() that has been made protected
+	double GetScale() { return pointsys->scale; }
+	double GetOriginX() { return pointsys->originx; }
+	double GetOriginY() { return pointsys->originy; }
+
+	// undo/redo system
+	virtual void AddUndo( wxString desc );
+	virtual bool UndoOrRedo(bool isundo);
+	virtual bool Undo();
+	virtual bool Redo();
+	virtual wxString GetTopUndo();
+	virtual wxString GetTopRedo();
+	virtual void RefreshUndocmds();
+
+	virtual bool HasBackgroundImage() { return bgimg.bgimg != NULL; }
+	virtual void RemoveBackgroundImage();
+	virtual void ReceiveBackgroundImageFileDropEvent(const wxString& filename);
+	virtual void SetBackgroundImage(const wxImage& img, wxString fname = _T("<clipboard>"), bool ask4alpha = true);
+	virtual void PrepareBackgroundBitmap(double alpha);
+	virtual void AskUserForBackgroundAlpha();
+	virtual bool GetBackgroundInfo(unsigned& w, unsigned& h, wxRealPoint& disp, double& scale);
+	
+	agg::rgba rgba_shape_normal, rgba_outline, rgba_guideline;
+	agg::rgba rgba_mainpoint, rgba_controlpoint, rgba_selectpoint;
+	agg::rgba rgba_origin, rgba_ruler_h, rgba_ruler_v;
+	
+protected:
+
+	typedef PixelFormat::AGGType::color_type color_type;
+	typedef agg::span_interpolator_linear<> interpolator_type;
+	typedef agg::span_image_filter_rgb_bilinear_clip<PixelFormat::AGGType, interpolator_type> span_gen_type;
+	
+    // The GUI window
+	ASSDrawFrame* m_frame;
+
+	// highlight mechanism
+	DrawCmd* hilite_cmd;
+	Point* hilite_point;
+		
+	// mouse capture
+	bool capturemouse_left, capturemouse_right;
+	virtual void CustomOnMouseCaptureLost(wxMouseCaptureLostEvent &event);
+    virtual void ProcessOnMouseLeftUp();
+    virtual void ProcessOnMouseRightUp();
+
+	// selection mechanism
+	PointSet selected_points;
+
+	// if it has status bar
+	bool hasStatusBar;
+
+	// some mouse readings
+    Point* mousedownAt_point;
+	Point* pointedAt_point;
+	Point* dblclicked_point_right;
+	wxPoint mouse_point;
+
+	// The wxPoint being dragged by left button
+    wxPoint* dragAnchor_left;
+	wxPoint* lastDrag_left;
+
+	// The wxPoint being dragged by right button
+    wxPoint* dragAnchor_right;
+	wxPoint* lastDrag_right;
+	
+	// true if the drawing origin (0, 0) is being dragged
+    bool dragOrigin;
+
+	// The newest command being initialized thru dragging action
+    DrawCmd* newcommand;
+
+	// the draw mode
+    MODE draw_mode;
+    DRAGMODE drag_mode;
+
+    // holding shift key temporarily switches to drag mode (MODE_ARR)
+    // so we want to save the mode before the key-down to restore it on key-up
+    MODE mode_b4_shift;
+
+	// true if preview mode (i.e don't draw anything except the shape itself;
+    // also draw the shape as closed)
+    bool preview_mode;
+
+	// background image!
+	struct
+	{
+		agg::rendering_buffer ibuf;
+		wxImage *bgimg;
+		wxBitmap *bgbmp;
+		wxString bgimgfile;
+		agg::path_storage bg_path;		
+		agg::span_allocator<color_type> spanalloc;
+		//span_gen_type spangen;
+        agg::trans_affine img_mtx, path_mtx;
+        
+        wxRealPoint disp, center, new_disp, new_center;
+        double scale, new_scale, alpha;
+		wxDialog* alpha_dlg;
+		wxSlider* alpha_slider;
+	} bgimg;
+	
+	// Undo/redo system (simply stores the ASS commands)
+	std::list<UndoRedo> undos;
+	std::list<UndoRedo> redos;
+	UndoRedo _undo;
+
+	// last action and commands (for undo/redo system)
+	wxString undodesc;
+	
+	wxString oldasscmds;
+
+	// was preview_mode
+	//bool was_preview_mode;
+
+	PointSystem* _PointSystem() { return pointsys; }
+
+	// for Undo/Redo system
+	virtual void PrepareUndoRedo(UndoRedo& ur, bool prestage, wxString cmds, wxString desc);
+	
+	// -------------------- points highlight/selection ---------------------------
+
+	// set command and point to highlight
+	virtual void SetHighlighted ( DrawCmd* cmd, Point* point );
+
+	// selects all points within (lx, ty) , (rx, by) returns # of selected points
+	virtual int SelectPointsWithin( int lx, int rx, int ty, int by, SELECTMODE smode = NEW );
+	virtual void ClearPointsSelection();
+	virtual SELECTMODE GetSelectMode(wxMouseEvent &event);
+	
+	// -------------------- misc ---------------------------
+
+	// non-uniform transformation
+	virtual bool InitiateDraggingIfTransformMode();
+	virtual void UpdateTranformModeRectCenter();
+	virtual bool GetThe4thPoint(double ox, double oy, double a1x, double a1y, double a2x, double a2y, double *x, double *y);
+	enum { NONE, LEFT, RIGHT } backupowner;
+	agg::path_storage backupcmds;
+	int rectbound2upd, rectbound2upd2;
+	wxRealPoint rectbound[4], rectbound2[4], backup[4], rectcenter;
+	bool isshapetransformable;
+
+	// do the real drawing
+	virtual void DoDraw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx );
+
+	// update background image scale & position
+	virtual void UpdateBackgroundImgScalePosition(bool firsttime = false);
+	
+	// perform extra stuff other than calling ASSDrawEngine::ConnectSubsequentCmds
+	virtual void ConnectSubsequentCmds (DrawCmd* cmd1, DrawCmd* cmd2);
+
+	// make sure the c1 continuity is followed after performing a drag-point action
+	virtual void EnforceC1Continuity (DrawCmd* cmd, Point* pnt);
+	
+	// after the bounding quadrangle has changed, update the shape to fill up inside it
+	virtual void UpdateNonUniformTransformation();
+
+	friend class UndoRedo;
+	
+	DECLARE_EVENT_TABLE()
+};
+
+class ASSDrawFileDropTarget : public wxFileDropTarget
+{
+public:
+	ASSDrawFileDropTarget(ASSDrawCanvas *canvas): wxFileDropTarget()
+	{
+		m_canvas = canvas;
+	}
+
+	virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
+	{
+		m_canvas->ReceiveBackgroundImageFileDropEvent(filenames.Item(0));
+	}
+
+protected:
+	ASSDrawCanvas *m_canvas;
+
+};
diff --git a/assdraw/src/canvas_mouse.cpp b/assdraw/src/canvas_mouse.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..22b64a5f459c20b957478a90a3ce8094ca5b0e3d
--- /dev/null
+++ b/assdraw/src/canvas_mouse.cpp
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "canvas_mouse.hpp"
+#include "canvas.hpp"
+
+DEFINE_EVENT_TYPE( wxEVT_MOUSEONCANVAS )
+
+
+ASSDrawMouseOnCanvasEvent::ASSDrawMouseOnCanvasEvent(const ASSDrawCanvas* canvas)
+ : wxNotifyEvent(),
+   _canvas(canvas)
+{
+	_data = NULL;
+}
+
+wxEvent* ASSDrawMouseOnCanvasEvent::Clone()
+{
+	ASSDrawMouseOnCanvasEvent *clone = new ASSDrawMouseOnCanvasEvent(_canvas);
+	clone->SetData(_data);
+	return clone;
+}
+
+void ASSDrawMouseOnCanvasEvent::SetData(MouseOnCanvasData *data)
+{
+	_data = data;
+}
+
+MouseOnCanvasData* ASSDrawMouseOnCanvasEvent::GetData()
+{
+	return _data;
+}
diff --git a/assdraw/src/canvas_mouse.hpp b/assdraw/src/canvas_mouse.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d64011336cf8cac65fdc4bf2c67b0f20c7862bc4
--- /dev/null
+++ b/assdraw/src/canvas_mouse.hpp
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "_common.hpp"
+#include "enums.hpp"
+#include "engine.hpp"
+
+#include <wx/event.h>
+
+struct MouseOnCanvasData
+{
+	MODE mode;
+	wxMouseEvent event;
+	enum { NONE, LEFT, RIGHT, BOTH } button;
+
+    Point* mousedownAt_point;
+	Point* pointedAt_point;
+	Point* dblclicked_point_right;
+
+	wxPoint mouse_point;
+    wxPoint* dragAnchor_left;
+	wxPoint* lastDrag_left;
+    wxPoint* dragAnchor_right;
+	wxPoint* lastDrag_right;
+};
+
+class ASSDrawCanvas;
+
+class ASSDrawMouseOnCanvasEvent : public wxNotifyEvent
+{
+public:
+	ASSDrawMouseOnCanvasEvent(const ASSDrawCanvas* canvas);
+	
+	wxEvent* Clone();
+	
+	void SetData(MouseOnCanvasData *data);
+	
+	MouseOnCanvasData* GetData();
+	
+private:
+	const ASSDrawCanvas* _canvas;
+	MouseOnCanvasData* _data;
+
+};
+
+DECLARE_EVENT_TYPE( wxEVT_MOUSEONCANVAS, -1 )
+
+typedef void (wxEvtHandler::*wxMouseOnCanvasEventFunction)(ASSDrawMouseOnCanvasEvent&);
+
+#define EVT_MOUSEONCANVAS(fn) \
+    DECLARE_EVENT_TABLE_ENTRY( wxEVT_MOUSEONCANVAS, -1, -1, \
+    (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) (wxNotifyEventFunction) \
+    wxStaticCastEvent( wxMouseOnCanvasEventFunction, & fn ), (wxObject *) NULL ),
+
+class ASSDrawMouseOnCanvasHandler
+{
+	
+	
+};
diff --git a/assdraw/src/cmd.cpp b/assdraw/src/cmd.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5c3ee3eee1dca9a4a5d0143d3b06814c5ef95e1d
--- /dev/null
+++ b/assdraw/src/cmd.cpp
@@ -0,0 +1,212 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        cmd.cpp
+// Purpose:     ASSDraw drawing command classes
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#include "cmd.hpp" // the header for this file
+#include <wx/log.h>
+// ----------------------------------------------------------------------------
+// DrawCmd_M
+// ----------------------------------------------------------------------------
+
+// constructor
+DrawCmd_M::DrawCmd_M ( int x, int y, PointSystem *ps, DrawCmd *prev ) 
+     : DrawCmd ( x, y, ps, prev ) 
+{
+     type = M;
+}
+
+// to ASS drawing command
+wxString DrawCmd_M::ToString()
+{
+     return wxString::Format(_T("m %d %d"), m_point->x(), m_point->y());
+}
+
+
+
+// ----------------------------------------------------------------------------
+// DrawCmd_L
+// ----------------------------------------------------------------------------
+
+// constructor
+DrawCmd_L::DrawCmd_L ( int x, int y, PointSystem *ps, DrawCmd *prev ) 
+     : DrawCmd ( x, y, ps, prev ) 
+{
+     type = L;
+}
+
+// to ASS drawing command
+wxString DrawCmd_L::ToString()
+{
+     return wxString::Format(wxT("l %d %d"), m_point->x(), m_point->y());
+}
+
+
+
+// ----------------------------------------------------------------------------
+// DrawCmd_B
+// ----------------------------------------------------------------------------
+
+// constructor
+DrawCmd_B::DrawCmd_B 
+( int x, int y, int x1, int y1, int x2, int y2, PointSystem *ps, DrawCmd *prev ) 
+    : DrawCmd ( x, y, ps, prev ) 
+{
+     type = B;
+     controlpoints.push_back( new Point(x1, y1, ps, CP, this, 1) );
+     controlpoints.push_back( new Point(x2, y2, ps, CP, this, 2) );
+     initialized = true;
+     C1Cont = false;
+}
+
+// constructor
+DrawCmd_B::DrawCmd_B ( int x, int y, PointSystem *ps, DrawCmd *prev ) 
+    : DrawCmd ( x, y, ps, prev ) 
+{
+     type = B;
+     initialized = false;
+     C1Cont = false;
+}
+
+// initialize; generate control points
+void DrawCmd_B::Init ( unsigned n )
+{
+     // Ignore if this is already initted
+     if (initialized) return;
+
+     wxPoint wx0 = prev->m_point->ToWxPoint();
+     wxPoint wx1 = m_point->ToWxPoint();
+     int xdiff = (wx1.x - wx0.x) / 3;     
+     int ydiff = (wx1.y - wx0.y) / 3;     
+     int xg, yg;
+
+     // first control
+     m_point->pointsys->FromWxPoint( wx0.x + xdiff, wx0.y + ydiff, xg, yg );
+     controlpoints.push_back( new Point( xg, yg, m_point->pointsys, CP, this, 1 ) );
+
+     // second control
+     m_point->pointsys->FromWxPoint( wx1.x - xdiff, wx1.y - ydiff, xg, yg );
+     controlpoints.push_back( new Point( xg, yg, m_point->pointsys, CP, this, 2 ) );
+
+     initialized = true;
+     
+}
+
+// to ASS drawing command
+wxString DrawCmd_B::ToString()
+{
+	PointList::iterator iterate = controlpoints.begin();
+	Point* c1 = (*iterate++);
+	Point* c2 = (*iterate);
+	if (initialized)
+		return wxString::Format(wxT("b %d %d %d %d %d %d"), c1->x(), c1->y(), c2->x(), c2->y(), m_point->x(), m_point->y());
+	else
+		return wxString::Format(wxT("b ? ? ? ? %d %d"), m_point->x(), m_point->y());
+}
+
+
+// ----------------------------------------------------------------------------
+// DrawCmd_S
+// ----------------------------------------------------------------------------
+
+// constructor
+DrawCmd_S::DrawCmd_S
+	( int x, int y, PointSystem *ps, DrawCmd *prev )
+    : DrawCmd ( x, y, ps, prev )
+{
+	type = S;
+	initialized = false;
+	closed = false;
+}
+
+// constructor
+DrawCmd_S::DrawCmd_S
+	( int x, int y, std::vector< int > vals, PointSystem *ps, DrawCmd *prev )
+    : DrawCmd ( x, y, ps, prev )
+{
+	type = S;
+	std::vector< int >::iterator it = vals.begin();
+	unsigned n = 0;
+	while (it != vals.end())
+	{
+		int ix = *it; it++;
+		int iy = *it; it++;
+		n++;
+		//::wxLogMessage("%d %d\n", ix, iy);
+		controlpoints.push_back( new Point( ix, iy, ps, CP, this, n ) );
+	}
+
+	initialized = true;
+	closed = false;
+}
+
+// initialize; generate control points
+void DrawCmd_S::Init(unsigned n)
+{
+     // Ignore if this is already initted
+     if (initialized) return;
+
+     wxPoint wx0 = prev->m_point->ToWxPoint();
+     wxPoint wx1 = m_point->ToWxPoint();
+     int xdiff = (wx1.x - wx0.x) / 3;
+     int ydiff = (wx1.y - wx0.y) / 3;
+     int xg, yg;
+
+     // first control
+     m_point->pointsys->FromWxPoint( wx0.x + xdiff, wx0.y + ydiff, xg, yg );
+     controlpoints.push_back( new Point( xg, yg, m_point->pointsys, CP, this, 1 ) );
+
+     // second control
+     m_point->pointsys->FromWxPoint( wx1.x - xdiff, wx1.y - ydiff, xg, yg );
+     controlpoints.push_back( new Point( xg, yg, m_point->pointsys, CP, this, 2 ) );
+
+     initialized = true;
+
+}
+
+// to ASS drawing command
+wxString DrawCmd_S::ToString()
+{
+	PointList::iterator iterate = controlpoints.begin();
+	wxString assout = _T("s");
+	for (; iterate != controlpoints.end(); iterate++)
+	{
+		if (initialized)
+			assout = wxString::Format(wxT("%s %d %d"), assout.c_str(), (*iterate)->x(), (*iterate)->y()); 
+		else
+			assout = wxString::Format(wxT("%s ? ?"), assout.c_str());
+	}
+	assout = wxString::Format(wxT("%s %d %d"), assout.c_str(), m_point->x(), m_point->y());
+	if (closed) assout = wxString::Format(wxT("%s c"), assout.c_str());
+	return assout;
+}
diff --git a/assdraw/src/cmd.hpp b/assdraw/src/cmd.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..25ef16102644b29909116ee6eb36764b752f8af9
--- /dev/null
+++ b/assdraw/src/cmd.hpp
@@ -0,0 +1,112 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// Name:        cmd.hpp
+// Purpose:     header file for ASSDraw drawing command classes
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "engine.hpp" // include the engine header for DrawCmd
+#include <vector> // ok, we use vector too
+
+// this header file declares the following classes
+class DrawCmd_M;
+class DrawCmd_L;
+class DrawCmd_B;
+
+// The M command
+class DrawCmd_M: public DrawCmd
+{
+public:
+	// Constructor
+	DrawCmd_M ( int x, int y, PointSystem *ps, DrawCmd *prev );
+	
+	// to ASS drawing command
+	wxString ToString();
+
+};
+
+// The L command
+class DrawCmd_L: public DrawCmd
+{
+public:
+	// Constructor
+	DrawCmd_L ( int x, int y, PointSystem *ps, DrawCmd *prev );
+	
+	// to ASS drawing command
+	wxString ToString();
+	
+};
+
+// The B command
+class DrawCmd_B: public DrawCmd
+{
+public:
+	// Constructor
+	DrawCmd_B ( int x, int y, int x1, int y1, int x2, int y2,  PointSystem *ps, DrawCmd *prev );
+	
+	// Special constructor where only m_point is defined
+	// Need to call Init() to generate the controls
+	DrawCmd_B ( int x, int y, PointSystem *ps, DrawCmd *prev );
+	
+	// Init this B command; generate controlpoints
+	void Init ( unsigned n = 0 );
+	
+	// to ASS drawing command
+	wxString ToString();
+	
+	//special
+	bool C1Cont;
+	
+};
+
+// The S command
+class DrawCmd_S: public DrawCmd
+{
+public:
+	// Constructor
+	DrawCmd_S ( int x, int y, PointSystem *ps, DrawCmd *prev );
+
+	// Constructor (with points info)
+	DrawCmd_S ( int x, int y, std::vector< int > vals, PointSystem *ps, DrawCmd *prev );
+
+	// Init this S command; generate controlpoints
+	void Init ( unsigned n = 0 );
+
+	// to ASS drawing command
+	wxString ToString();
+
+	// special
+	bool closed;
+};
+
diff --git a/assdraw/src/dlgctrl.cpp b/assdraw/src/dlgctrl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1ee6f9b8918782ca74a7c7cd4e222527370c01ea
--- /dev/null
+++ b/assdraw/src/dlgctrl.cpp
@@ -0,0 +1,372 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        dlgctrl.cpp
+// Purpose:     custom dialogs and controls
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#include "assdraw.hpp"
+
+BEGIN_EVENT_TABLE(ASSDrawSrcTxtCtrl, wxTextCtrl)
+	EVT_CHAR(ASSDrawSrcTxtCtrl::CustomOnChar)
+	EVT_TEXT(wxID_ANY, ASSDrawSrcTxtCtrl::CustomOnText)
+END_EVENT_TABLE()
+
+BEGIN_EVENT_TABLE(ASSDrawTransformDlg, wxDialog)
+	EVT_COMBOBOX(-1, ASSDrawTransformDlg::OnTemplatesCombo)
+END_EVENT_TABLE()
+
+//BEGIN_EVENT_TABLE(ASSDrawCanvasRecenterButton, wxWindow)
+//END_EVENT_TABLE()
+
+// ----------------------------------------------------------------------------
+// ASSDrawSrcTxtCtrl
+// ----------------------------------------------------------------------------
+
+ASSDrawSrcTxtCtrl::ASSDrawSrcTxtCtrl(wxWindow *parent, ASSDrawFrame *frame)
+	: wxTextCtrl(parent, wxID_ANY, "", __DPDS__ , wxTE_MULTILINE )
+{
+	m_frame = frame;
+}
+
+void ASSDrawSrcTxtCtrl::CustomOnChar(wxKeyEvent &event)
+{
+	switch (event.GetKeyCode())
+	{
+	case WXK_RETURN:
+		m_frame->UpdateASSCommandStringFromSrcTxtCtrl(GetValue());
+		break;
+	case WXK_TAB:
+		break; //do nothing
+	default:
+		//m_frame->SetTitle(wxString::Format("Key: %d", event.GetKeyCode()));
+		event.Skip(true);
+	}
+	
+	//SetBackgroundColour(IsModified()? wxColour(0xFF, 0xFF, 0x99):*wxWHITE);
+}
+
+void ASSDrawSrcTxtCtrl::CustomOnText(wxCommandEvent &event)
+{
+	//SetBackgroundColour(IsModified()? wxColour(0xFF, 0xFF, 0x99):*wxWHITE);
+}
+
+// ----------------------------------------------------------------------------
+// ASSDrawTransformDlg
+// ----------------------------------------------------------------------------
+
+ASSDrawTransformDlg::ASSDrawTransformDlg(ASSDrawFrame* parent)
+ : wxDialog(parent, -1, wxString(_T("Transform")))
+{
+	m_frame = parent;
+
+    wxBoxSizer* sizer_main = new wxBoxSizer(wxVERTICAL);
+    this->SetSizer(sizer_main);
+
+    wxBoxSizer* sizer_templates = new wxBoxSizer(wxHORIZONTAL);
+    sizer_main->Add(sizer_templates, 0, wxGROW|wxLEFT, 5);
+
+    sizer_templates->Add(new wxStaticText( this, -1, _("Templates"), __DPDS__ , 0 ),
+						0, wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE, 5);
+
+    combo_templates = new wxComboBox( this, -1, combo_templatesStrings[0], __DPDS__ , 10, combo_templatesStrings, wxCB_READONLY );
+    sizer_templates->Add(combo_templates, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+
+    wxFlexGridSizer* sizer_fields = new wxFlexGridSizer(3, 4, 0, 0);
+    sizer_main->Add(sizer_fields, 0, wxALIGN_CENTER_HORIZONTAL|wxLEFT, 5);
+
+	int flag_txtctrl = wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxALL;
+	int flag_statictxt = wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL|wxADJUST_MINSIZE;
+
+	sizer_fields->Add(new wxStaticText( this, -1, _("m11"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_m11 = new wxTextCtrl( this, -1, _T("1.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_m11, 0, flag_txtctrl, 5);
+
+    sizer_fields->Add(new wxStaticText( this, -1, _("m12"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_m12 = new wxTextCtrl( this, -1, _T("0.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_m12, 0, flag_txtctrl, 5);
+
+    sizer_fields->Add(new wxStaticText( this, -1, _("m21"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_m21 = new wxTextCtrl( this, -1, _T("0.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_m21, 0, flag_txtctrl, 5);
+
+    sizer_fields->Add(new wxStaticText( this, -1, _("m22"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_m22 = new wxTextCtrl( this, -1, _T("1.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_m22, 0, flag_txtctrl, 5);
+
+    sizer_fields->Add(new wxStaticText( this, -1, _("mx"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_mx = new wxTextCtrl( this, -1, _T("0.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_mx, 0, flag_txtctrl, 5);
+
+    sizer_fields->Add(new wxStaticText( this, -1, _("my"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_my = new wxTextCtrl( this, -1, _T("0.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_my, 0, flag_txtctrl, 5);
+
+    sizer_fields->Add(new wxStaticText( this, -1, _("nx"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_nx = new wxTextCtrl( this, -1, _T("0.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_nx, 0, flag_txtctrl, 5);
+
+    sizer_fields->Add(new wxStaticText( this, -1, _("ny"), __DPDS__ , 0 ),
+						0, flag_statictxt, 5);
+
+    txtctrl_ny = new wxTextCtrl( this, -1, _T("0.0"), __DPDS__ , wxTE_RIGHT );
+    sizer_fields->Add(txtctrl_ny, 0, flag_txtctrl, 5);
+
+    wxBitmap staticbmp_bmp(wxBITMAP(transform));
+    wxStaticBitmap* staticbmp = new wxStaticBitmap( this, -1, staticbmp_bmp, wxDefaultPosition, wxSize(224, 56), 0 );
+    sizer_main->Add(staticbmp, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
+
+    wxStdDialogButtonSizer* sizer_stdbutt = new wxStdDialogButtonSizer;
+
+    sizer_main->Add(sizer_stdbutt, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
+    wxButton* button_ok = new wxButton( this, wxID_OK, _("&OK"), __DPDS__ , 0 );
+    sizer_stdbutt->AddButton(button_ok);
+
+    wxButton* button_cancel = new wxButton( this, wxID_CANCEL, _("&Cancel"), __DPDS__ , 0 );
+    sizer_stdbutt->AddButton(button_cancel);
+
+    sizer_stdbutt->Realize();
+
+	sizer_main->Fit(this);
+
+}
+
+void ASSDrawTransformDlg::OnTemplatesCombo(wxCommandEvent &event)
+{
+	int pos = -1;
+	for (int i = 0; i < combo_templatesCount; i++)
+		if (combo_templatesStrings[i].IsSameAs(((wxComboBox *) event.GetEventObject())->GetValue()))
+		{
+			pos = i;
+			break;
+		}
+	if (pos == -1)
+		return;
+
+	txtctrl_m11->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f1) );
+	txtctrl_m12->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f2) );
+	txtctrl_m21->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f3) );
+	txtctrl_m22->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f4) );
+	txtctrl_mx->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f5) );
+	txtctrl_my->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f6) );
+	txtctrl_nx->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f7) );
+	txtctrl_ny->SetValue( wxString::Format("%.1f", combo_templatesValues[pos].f8) );
+}
+
+void ASSDrawTransformDlg::EndModal(int retCode)
+{
+	if (retCode != wxID_OK)
+	{
+		wxDialog::EndModal(retCode);
+		return;
+	}
+
+	bool ok = true;
+
+	ok = ok && txtctrl_m11->GetValue().ToDouble( &xformvals.f1 );
+	ok = ok && txtctrl_m12->GetValue().ToDouble( &xformvals.f2 );
+	ok = ok && txtctrl_m21->GetValue().ToDouble( &xformvals.f3 );
+	ok = ok && txtctrl_m22->GetValue().ToDouble( &xformvals.f4 );
+	ok = ok && txtctrl_mx->GetValue().ToDouble( &xformvals.f5 );
+	ok = ok && txtctrl_my->GetValue().ToDouble( &xformvals.f6 );
+	ok = ok && txtctrl_nx->GetValue().ToDouble( &xformvals.f7 );
+	ok = ok && txtctrl_ny->GetValue().ToDouble( &xformvals.f8 );
+
+	if (ok)
+		wxDialog::EndModal(wxID_OK);
+	else
+	    wxMessageBox("One or more values entered are not real numbers.\nPlease fix.", _T("Value error"), wxOK | wxICON_INFORMATION, m_frame);
+
+}
+
+
+ASSDrawAboutDlg::ASSDrawAboutDlg(ASSDrawFrame *parent, unsigned timeout)
+	: wxDialog(parent, wxID_ANY, wxString(TITLE), __DPDS__ , wxSIMPLE_BORDER), time_out(timeout)
+{
+	SetBackgroundColour(*wxWHITE);
+	htmlwin = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxSize(396, 200), wxHW_DEFAULT_STYLE | wxSIMPLE_BORDER);
+	htmlwin->SetPage(
+"<html><body> \
+<p>ASSDraw3 is a tool for designing shapes to be used in ASS subtitle file. \
+<p>To add lines or curves, initiate the draw mode by clicking on the drawing tools. \
+Then, either click on empty space or drag from an existing point to add the new lines/curves. \
+Control points for Bezier curves are generated once you release the mouse button. \
+<p>To modify shapes, drag their points (squares) and control points (circles) in the drag mode. \
+<p><b>Some tips & tricks:</b> \
+<ul> \
+<li> Set background image by dragging image file from explorer onto the canvas \
+<li> Use the Shapes Library to store your drawings \
+<li> Ctrl-Z for undo, Ctrl-Y for redo \
+<li> Use your mousewheel to zoom in/out (PageUp/PageDown keys work too) \
+<li> Dragging with right mouse button moves the drawing and/or background image around. \
+<li> Double clicking with right mouse button for popup menus. \
+<li> Holding shift key while in the draw mode temporarily switches to the drag mode \
+<li> The shapes origin (coordinate [0, 0] depicted by the small cross) is draggable \
+</ul> \
+<p><b>Acknowledgements:</b> \
+<ul> \
+<li> Maxim Shemanarev <a href=\"http://www.antigrain.com\">http://www.antigrain.com</a> for his Anti-Grain Geometry (AGG) graphic toolkit. \
+<li> wxWidgets Project <a href=\"http://www.wxwidgets.org\">http://www.wxwidgets.org</a> for the ultracool GUI toolkit. \
+<li> Adrian Secord <a href=\"http://mrl.nyu.edu/~ajsecord/index.html\">http://mrl.nyu.edu/~ajsecord/index.html</a> for wxAGG, that combines AGG and wxWidgets\
+<li> jfs, ArchMageZeratul, RoRo and everyone at Aegisub's forum <a href=\"http://malakith.net/aegisub\">http://malakith.net/aegisub</a> for all suggestions and supports. \
+</ul> \
+<p>ai-chan recommends Aegisub for all your subtitle and typesetting needs! \
+</body></html>"
+	);	
+	htmlwin->Connect(wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler(ASSDrawAboutDlg::OnURL), NULL, this);
+	
+	wxFlexGridSizer *sizer = new wxFlexGridSizer(1);
+	sizer->AddGrowableCol(0);
+	//sizer->AddGrowableRow(1);
+	
+	sizer->Add(new BigStaticBitmapCtrl(this, wxBITMAP(assdraw3_), *wxWHITE, this), 1, wxEXPAND);
+	sizer->Add(htmlwin, 1, wxLEFT | wxRIGHT, 2);
+	sizer->Add(new wxStaticText(this, wxID_ANY, wxString::Format("Version: %s", VERSION)), 1, wxEXPAND | wxALL, 2);
+	sizer->Add(new wxButton(this, wxID_OK), 0, wxALIGN_CENTER | wxBOTTOM, 10);
+	SetSizer(sizer);
+	sizer->Layout();
+	sizer->Fit(this);
+	
+	Center();
+	//if (CanSetTransparent()) SetTransparent(0xCC);
+	
+	timer.SetOwner(this);
+	Connect(wxEVT_TIMER, wxTimerEventHandler(ASSDrawAboutDlg::OnTimeout));
+	Connect(wxEVT_ENTER_WINDOW, wxMouseEventHandler(ASSDrawAboutDlg::OnMouseEnterWindow));
+}
+
+ASSDrawAboutDlg::~ASSDrawAboutDlg()
+{
+	timer.Stop();	
+}
+
+int ASSDrawAboutDlg::ShowModal()
+{
+	if (time_out > 0)
+		timer.Start(time_out * 1000, true);
+	wxDialog::ShowModal();
+}
+
+void ASSDrawAboutDlg::OnURL(wxHtmlLinkEvent &event)
+{
+	wxString URL(event.GetLinkInfo().GetHref());
+	if (URL.StartsWith("http://"))
+		::wxLaunchDefaultBrowser(URL);
+	else
+		event.Skip(true);
+}
+
+void ASSDrawAboutDlg::OnTimeout(wxTimerEvent& event)
+{
+	if (IsShown())
+		EndModal(wxID_OK);
+}
+
+void ASSDrawAboutDlg::OnMouseEnterWindow(wxMouseEvent& event)
+{
+	// if mouse enters this dialog, stop the timout timer
+	// and dialog will only close through user input
+	timer.Stop();	
+}
+
+BEGIN_EVENT_TABLE(BigStaticBitmapCtrl, wxPanel)
+	EVT_PAINT(BigStaticBitmapCtrl::OnPaint)
+    EVT_MOTION (BigStaticBitmapCtrl::OnMouseMove)
+    EVT_LEFT_UP(BigStaticBitmapCtrl::OnMouseLeftUp)
+    EVT_LEFT_DOWN(BigStaticBitmapCtrl::OnMouseLeftDown)
+END_EVENT_TABLE()
+
+BigStaticBitmapCtrl::BigStaticBitmapCtrl(wxWindow *parent, wxBitmap bmap, wxColour bgcol, wxWindow *todrag)
+	: wxPanel(parent, wxID_ANY)
+{
+	bitmap = bmap;
+	bgbrush = wxBrush(bgcol);
+	window_to_drag = todrag;
+	SetSize(bitmap.GetWidth(), bitmap.GetHeight());
+	Refresh();
+}
+
+BigStaticBitmapCtrl::~BigStaticBitmapCtrl()
+{	
+}
+
+void BigStaticBitmapCtrl::OnPaint(wxPaintEvent& event)
+{
+    wxPaintDC dc(this);
+	dc.SetBackground(bgbrush);
+	dc.Clear();
+    dc.DrawBitmap(bitmap, wxPoint(0,0));
+}
+
+void BigStaticBitmapCtrl::OnMouseLeftDown(wxMouseEvent &event)
+{
+	if (window_to_drag != NULL)
+	{
+		dragpoint = event.GetPosition();
+	}
+	CaptureMouse();
+}
+
+void BigStaticBitmapCtrl::OnMouseLeftUp(wxMouseEvent &event)
+{
+	ReleaseMouse();	
+}
+
+void BigStaticBitmapCtrl::OnMouseMove(wxMouseEvent &event)
+{
+	if (window_to_drag != NULL && event.Dragging() && HasCapture())
+	{
+		wxPoint npoint(event.GetPosition());
+		wxPoint wndpos = window_to_drag->GetScreenPosition();
+		wxPoint thispos = this->GetScreenPosition();
+		//ReleaseMouse();
+		window_to_drag->Move(wndpos.x + npoint.x - dragpoint.x,
+							 wndpos.y + npoint.y - dragpoint.y);
+		//CaptureMouse();
+		if (thispos == this->GetScreenPosition()) // if this ctrl did not move when window_to_drag moved
+			dragpoint = npoint;
+	}
+	event.Skip(true);
+}
diff --git a/assdraw/src/dlgctrl.hpp b/assdraw/src/dlgctrl.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b5225d181a0ff9dba99c92c868205869134529a0
--- /dev/null
+++ b/assdraw/src/dlgctrl.hpp
@@ -0,0 +1,115 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "_common.hpp"
+#include <wx/html/htmlwin.h>
+#include <wx/timer.h>
+
+
+class ASSDrawFrame;
+
+class ASSDrawSrcTxtCtrl : public wxTextCtrl
+{
+public:
+	ASSDrawSrcTxtCtrl(wxWindow *parent, ASSDrawFrame *frame);
+	virtual void CustomOnChar(wxKeyEvent &event);
+	virtual void CustomOnText(wxCommandEvent &event);
+
+protected:
+	ASSDrawFrame *m_frame;
+	DECLARE_EVENT_TABLE()
+};
+
+struct EightDouble
+{
+	double f1, f2, f3, f4, f5, f6, f7, f8;
+};
+
+class ASSDrawTransformDlg : public wxDialog
+{
+
+public:
+	ASSDrawTransformDlg(ASSDrawFrame* parent);
+	void OnTemplatesCombo(wxCommandEvent &event);
+	void EndModal(int retCode);
+
+	ASSDrawFrame* m_frame;
+	wxComboBox* combo_templates;
+	wxTextCtrl* txtctrl_m11;
+	wxTextCtrl* txtctrl_m12;
+	wxTextCtrl* txtctrl_m21;
+	wxTextCtrl* txtctrl_m22;
+	wxTextCtrl* txtctrl_mx;
+	wxTextCtrl* txtctrl_my;
+	wxTextCtrl* txtctrl_nx;
+	wxTextCtrl* txtctrl_ny;
+	EightDouble xformvals;
+
+	static wxString combo_templatesStrings[];
+	static int combo_templatesCount;
+	static EightDouble combo_templatesValues[];
+
+	DECLARE_EVENT_TABLE()
+
+};
+
+class ASSDrawAboutDlg : public wxDialog
+{
+public:
+	ASSDrawAboutDlg(ASSDrawFrame *parent, unsigned timeout = 0);
+	virtual ~ASSDrawAboutDlg();
+	virtual void OnURL(wxHtmlLinkEvent &event);
+	virtual int ShowModal();
+	virtual void OnTimeout(wxTimerEvent& event);
+	virtual void OnMouseEnterWindow(wxMouseEvent& event);
+
+protected:
+	wxTimer timer;
+	wxHtmlWindow *htmlwin;
+	const unsigned time_out;
+};
+
+class BigStaticBitmapCtrl : public wxPanel
+{
+public:
+	BigStaticBitmapCtrl(wxWindow *parent, wxBitmap bmap, wxColour bgcol, wxWindow *todrag = NULL);
+	virtual ~BigStaticBitmapCtrl();
+	virtual void OnPaint(wxPaintEvent& event);
+	virtual void OnMouseLeftDown(wxMouseEvent &event);
+	virtual void OnMouseLeftUp(wxMouseEvent &event);
+	virtual void OnMouseMove(wxMouseEvent &event);
+
+protected:
+	wxBitmap bitmap;
+	wxBrush bgbrush;
+	wxWindow *window_to_drag;
+	wxPoint dragpoint, wndpos;
+
+	DECLARE_EVENT_TABLE()
+};
diff --git a/assdraw/src/engine.cpp b/assdraw/src/engine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa23da6849f74cc1a6da25a5b5439c22a0ca1faf
--- /dev/null
+++ b/assdraw/src/engine.cpp
@@ -0,0 +1,749 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        engine.cpp
+// Purpose:     ASSDraw drawing engine
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#include "engine.hpp" // the header
+#include "cmd.hpp"    // we need the drawing command classes declaration
+#include <wx/tokenzr.h> // we use string tokenizer
+#include <vector> // ok, we use vector too
+#include <stdio.h>
+#include <algorithm>
+
+      
+
+// ----------------------------------------------------------------------------
+// Point
+// ----------------------------------------------------------------------------
+
+// constructor
+Point::Point ( int _x, int _y, PointSystem* ps, POINTTYPE t, DrawCmd* cmd, unsigned n ) 
+{
+	x_ = _x;
+	y_ = _y;
+	pointsys = ps;
+	cmd_main = cmd; 
+	cmd_next = NULL; 
+	type = t;
+	isselected = false;
+	num = n;
+}      
+
+// setters
+void Point::setXY( int _x, int _y)
+{
+	x_ = _x;
+	y_ = _y;
+}
+
+// simply returns true if px and py are the coordinate values
+bool Point::IsAt( int px, int py ) 
+{
+	return (x_ == px && y_ == py );
+}
+      
+// convert this point to wxPoint using scale and originx, originy
+wxPoint Point::ToWxPoint ( bool useorigin )
+{
+	if (useorigin)
+		return pointsys->ToWxPoint( x_, y_ );
+	else
+		return *(new wxPoint(x_ * (int) pointsys->scale, y_ * (int) pointsys->scale ));
+}
+      
+// check if wxpoint is nearby this point
+bool Point::CheckWxPoint ( wxPoint wxpoint ) 
+{
+	wxPoint p = ToWxPoint();
+	int cx, cy;
+	pointsys->FromWxPoint( wxpoint, cx, cy );
+	//delete &p;
+	return (x_ == cx && y_ == cy );
+}
+      
+
+
+// ----------------------------------------------------------------------------
+// DrawCmd
+// ----------------------------------------------------------------------------
+
+// constructor
+DrawCmd::DrawCmd ( int x, int y, PointSystem *ps, DrawCmd *pv ) 
+{ 
+	m_point = new Point ( x, y, ps, MP, this );
+	m_point->cmd_main = this;
+	prev = pv;
+	dobreak = false;
+	invisible = false;
+}       
+
+// destructor
+DrawCmd::~DrawCmd ( )
+{
+	if (m_point)
+		delete m_point;
+	for (PointList::iterator iter_cpoint = controlpoints.begin();
+			iter_cpoint != controlpoints.end(); iter_cpoint++)
+		delete (*iter_cpoint);
+} 
+
+
+
+// ----------------------------------------------------------------------------
+// ASSDrawEngine
+// ----------------------------------------------------------------------------
+
+BEGIN_EVENT_TABLE(ASSDrawEngine, GUI::AGGWindow)
+    EVT_PAINT  (ASSDrawEngine::OnPaint)
+END_EVENT_TABLE()
+
+// constructor
+ASSDrawEngine::ASSDrawEngine( wxWindow *parent, int extraflags )
+ : GUI::AGGWindow(parent, -1, wxDefaultPosition, wxDefaultSize,
+        wxNO_FULL_REPAINT_ON_RESIZE | extraflags )
+{
+	pointsys = new PointSystem(1, 0, 0) ;
+	refresh_called = false;
+	fitviewpoint_hmargin = 10;
+	fitviewpoint_vmargin = 10;
+	setfitviewpoint = false;
+	rgba_shape = agg::rgba(0,0,1);
+	color_bg = PixelFormat::AGGType::color_type(255, 255, 255);
+	drawcmdset = wxT("m n l b s p c _"); //the spaces and underscore are in there for a reason, guess?
+	ResetEngine();
+}
+
+ASSDrawEngine::~ASSDrawEngine()
+{
+    ResetEngine ( false );
+    delete pointsys;
+}
+
+// parse ASS draw commands; returns the number of parsed commands
+int ASSDrawEngine::ParseASS ( wxString str )
+{
+	ResetEngine( false );
+	str.Replace(_T("\t"), _T(""));
+	str.Replace(_T("\r"), _T(""));
+	str.Replace(_T("\n"), _T(""));
+	str = str.Lower() + wxT(" _ _");
+	// we don't use regex because the pattern is too simple
+	wxStringTokenizer tkz( str, wxT(" ") );
+	wxString currcmd(wxT(""));
+	std::vector<int> val;
+	wxString token;
+	long tmp_int;
+	
+	bool n_collected = false;
+	DrawCmd_S *s_command = NULL;
+	wxPoint tmp_n_pnt;
+	
+	while ( tkz.HasMoreTokens() )
+	{
+		token = tkz.GetNextToken();
+		
+		if ( drawcmdset.Find(token) > -1 )
+		{
+			bool done;
+			
+			do {
+				done = true;
+				
+				// N
+				if (currcmd.IsSameAs(wxT("n")) && val.size() >= 2)
+				{
+					tmp_n_pnt.x = val[0], tmp_n_pnt.y = val[1];
+					n_collected = true;
+				}
+				else if(n_collected)
+				{
+					AppendCmd ( L, tmp_n_pnt.x, tmp_n_pnt.y );
+					n_collected = false;
+				}
+				
+				if (s_command != NULL)
+				{
+					bool ends = true;
+					if (currcmd.IsSameAs(wxT("p"))&& val.size() >= 2)
+					{
+						s_command->m_point->type = CP;
+						s_command->m_point->num = s_command->controlpoints.size() + 1;
+						s_command->controlpoints.push_back(s_command->m_point);
+						s_command->m_point = new Point(val[0], val[1], pointsys, MP, s_command);
+						ends = false;
+					}
+					else if (currcmd.IsSameAs(wxT("c")))
+						s_command->closed = true;
+
+					if (ends)
+					{
+						AppendCmd(s_command);
+						s_command = NULL;	
+					}
+				}
+				
+				// M
+				if (currcmd.IsSameAs(wxT("m")) && val.size() >= 2)
+					AppendCmd ( M, val[0], val[1] );
+				
+				// L
+				if (currcmd.IsSameAs(wxT("l")) && val.size() >= 2)
+				{
+					AppendCmd ( L, val[0], val[1] );
+					val.erase(val.begin(), val.begin()+2);
+					// L is greedy
+					if (val.size() >= 2)
+						done = false;
+				}
+				
+				// B
+				if (currcmd.IsSameAs(wxT("b")) && val.size() >= 6)
+				{
+					AppendCmd ( new DrawCmd_B(val[4], val[5], val[0], val[1],
+					val[2], val[3], pointsys, LastCmd()) );
+					val.erase(val.begin(), val.begin()+6);
+					// so is B
+					if (val.size() >= 6)
+						done = false;
+				}
+				
+				// S
+				if (currcmd.IsSameAs(wxT("s")) && val.size() >= 6)
+				{
+					int num = (val.size() / 2) * 2;
+					std::vector<int> val2;
+					int i = 0;
+					for (; i < num - 2; i++)
+						val2.push_back(val[i]);
+
+					s_command = new DrawCmd_S(val[num - 2], val[num - 1], val2, pointsys, LastCmd());
+				}
+				// more to come later
+			} while (!done);
+			
+			val.clear();
+			currcmd = token;
+		}
+		else if (token.ToLong( &tmp_int ))
+		{
+			val.push_back( (int) tmp_int );
+		}	
+	}
+	
+	return (int) cmds.size();
+}
+
+// generate ASS draw commands
+wxString ASSDrawEngine::GenerateASS ( )
+{
+    wxString output = _T("");
+    for (DrawCmdList::iterator iterate = cmds.begin(); iterate != cmds.end(); iterate++)
+         output = output + (*iterate)->ToString() + _T(" ");
+     return output;
+}
+
+// reset; delete all points and add a new M(0,0)
+void ASSDrawEngine::ResetEngine()
+{
+     ResetEngine(true);
+}
+
+// reset; delete all points and add a new M(0,0) if addM == true
+void ASSDrawEngine::ResetEngine( bool addM )
+{
+	for (DrawCmdList::iterator iterate = cmds.begin(); iterate != cmds.end(); iterate++)
+		delete (*iterate);
+	cmds.clear();
+	if (addM) AppendCmd( M, 0, 0 );
+}
+
+// Create draw command of type 'type' and m_point (x, y), append to the
+// list and return it
+DrawCmd* ASSDrawEngine::AppendCmd ( CMDTYPE type, int x, int y )
+{
+
+	// use a variation of this method
+	return AppendCmd( NewCmd( type, x, y ) );
+}
+
+// Append draw command
+DrawCmd* ASSDrawEngine::AppendCmd ( DrawCmd* cmd )
+{
+	// no NULL command!
+	if (cmd == NULL) return NULL;
+
+	// set dependency of this command on the m_point of the last command
+	if (!cmds.empty())
+		ConnectSubsequentCmds( cmds.back(), cmd );
+	else
+	{
+		// since this is the first command, if it's not an M make it into one
+		if (cmd->type != M)
+			cmd = NewCmd( M, cmd->m_point->x(), cmd->m_point->y() );
+		ConnectSubsequentCmds( NULL, cmd );
+	}
+	// put it in the list
+	cmds.push_back( cmd );
+
+	return cmd;
+}
+
+// create draw command of type 'type' and m_point (x, y), insert to the
+// list after the _cmd and return it
+DrawCmd* ASSDrawEngine::InsertCmd ( CMDTYPE type, int x, int y, DrawCmd* _cmd )
+{
+     // prepare the new DrawCmd
+     DrawCmd* c = NewCmd( type, x, y );
+
+     // use a variation of this method
+     InsertCmd( c, _cmd );
+
+     return NULL;
+}
+
+// insert draw command cmd after _cmd
+void ASSDrawEngine::InsertCmd ( DrawCmd* cmd, DrawCmd* _cmd )
+{
+     DrawCmdList::iterator iterate = cmds.begin();
+     for (; iterate != cmds.end() && *iterate != _cmd; iterate++)
+     {
+         // do nothing
+     }
+
+     if (iterate == cmds.end())
+     {
+        AppendCmd( cmd );
+     }
+     else
+     {
+        iterate++;
+        if (iterate != cmds.end())
+        {
+           ConnectSubsequentCmds( cmd, (*iterate) );
+        }
+        cmds.insert( iterate, cmd );
+        ConnectSubsequentCmds( _cmd, cmd );
+     }
+}
+
+DrawCmd* ASSDrawEngine::NewCmd ( CMDTYPE type, int x, int y )
+{
+     DrawCmd* c = NULL;
+
+     switch (type)
+     {
+        case M:
+             c = new DrawCmd_M(x, y, pointsys, LastCmd());
+             break;
+        case L:
+             c = new DrawCmd_L(x, y, pointsys, LastCmd());
+             break;
+        case B:
+             c = new DrawCmd_B(x, y, pointsys, LastCmd());
+             break;
+        case S:
+             c = new DrawCmd_S(x, y, pointsys, LastCmd());
+             break;
+     }
+     return c;
+}
+
+// returns the iterator for the list
+DrawCmdList::iterator ASSDrawEngine::Iterator ( )
+{
+	return cmds.begin();
+}
+
+// returns the 'end' iterator for the list
+DrawCmdList::iterator ASSDrawEngine::IteratorEnd ( )
+{
+	return cmds.end();
+}
+
+// returns the last command in the list
+DrawCmd* ASSDrawEngine::LastCmd ()
+{
+	if (cmds.size() == 0)
+		return NULL;
+	else
+		return cmds.back();
+}
+
+// move all points by relative amount of x, y coordinates
+void ASSDrawEngine::MovePoints ( int x, int y )
+{
+     DrawCmdList::iterator iterate = cmds.begin();
+     PointList::iterator iterate2;
+
+     for (; iterate != cmds.end(); iterate++)
+     {
+         (*iterate)->m_point->setXY( (*iterate)->m_point->x() + x, (*iterate)->m_point->y() + y );
+         for (iterate2 = (*iterate)->controlpoints.begin(); 
+		 	iterate2 != (*iterate)->controlpoints.end(); iterate2++)
+         {
+			(*iterate2)->setXY( (*iterate2)->x() + x, (*iterate2)->y() + y );
+         }
+	}
+}
+
+// transform all points using the calculation:
+//   | (m11)  (m12) | x | (x - mx) | + | nx |
+//   | (m21)  (m22) |   | (y - my) |   | ny |
+void ASSDrawEngine::Transform( float m11, float m12, float m21, float m22,
+							float mx, float my, float nx, float ny )
+{
+    DrawCmdList::iterator iterate = cmds.begin();
+    PointList::iterator iterate2;
+	float x, y;
+	for (; iterate != cmds.end(); iterate++)
+	{
+		x = ((float) (*iterate)->m_point->x()) - mx;
+		y = ((float) (*iterate)->m_point->y()) - my;
+		(*iterate)->m_point->setXY((int) (x * m11 + y * m12 + nx), (int) (x * m21 + y * m22 + ny) );
+		for (iterate2 = (*iterate)->controlpoints.begin();
+			 iterate2 != (*iterate)->controlpoints.end(); iterate2++)
+		{
+			x = ((float) (*iterate2)->x()) - mx;
+			y = ((float) (*iterate2)->y()) - my;
+			(*iterate2)->setXY((int) (x * m11 + y * m12 + nx), (int) (x * m21 + y * m22 + ny) );
+		}
+	}
+}
+
+// returns some DrawCmd if its m_point = (x, y)
+DrawCmd* ASSDrawEngine::PointAt ( int x, int y )
+{
+     DrawCmd* c = NULL;
+	 DrawCmdList::iterator iterate = cmds.begin();
+
+     for (; iterate != cmds.end(); iterate++)
+     {
+         if ( (*iterate)->m_point->IsAt( x, y ) )
+            c = (*iterate);
+     }
+
+     //delete &iterate;
+
+     return c;
+}
+
+// returns some DrawCmd if one of its control point = (x, y)
+// also set &point to refer to that control point
+DrawCmd* ASSDrawEngine::ControlAt ( int x, int y, Point* &point )
+{
+	DrawCmd* c = NULL;
+	point = NULL;
+	DrawCmdList::iterator cmd_iterator = cmds.begin();
+	PointList::iterator pnt_iterator;
+	PointList::iterator end;
+
+	for (; cmd_iterator != cmds.end(); cmd_iterator++)
+	{
+		pnt_iterator = (*cmd_iterator)->controlpoints.begin();
+		end = (*cmd_iterator)->controlpoints.end();
+		for (; pnt_iterator != end; pnt_iterator++)
+		{
+			if ( (*pnt_iterator)->IsAt( x, y ) )
+			{
+				c = (*cmd_iterator);
+				point = (*pnt_iterator);
+			}
+		}
+	}
+
+	return c;
+}
+
+// attempts to delete a commmand, returns true|false if successful|fail
+bool ASSDrawEngine::DeleteCommand ( DrawCmd* cmd )
+{
+	
+	DrawCmdList::iterator iterate = cmds.begin();
+	// can't delete the first command without deleting other commands first
+	if ( cmd == (*iterate) && cmds.size() > 1) return false;
+	
+	DrawCmd* lastiter = NULL;
+	
+	for (; iterate != cmds.end(); iterate++)
+	{
+		if ( cmd == (*iterate) )
+		{
+			iterate++;
+			DrawCmd* nxt = (iterate != cmds.end()? (*iterate):NULL);
+			ConnectSubsequentCmds( lastiter, nxt );
+			iterate--;
+			cmds.erase( iterate );
+			delete cmd;
+			break;
+		}
+		else
+			lastiter = (*iterate);
+	}
+	
+	return true;
+}
+
+// set stuff to connect two drawing commands cmd1 and cmd2 such that
+// cmd1 comes right before cmd2
+void ASSDrawEngine::ConnectSubsequentCmds (DrawCmd* cmd1, DrawCmd* cmd2)
+{
+	if (cmd1 != NULL)
+	{
+		cmd1->m_point->cmd_next = cmd2;
+	}
+	
+	if (cmd2 != NULL)
+	{
+		cmd2->prev = cmd1;
+	}
+}
+
+void ASSDrawEngine::RefreshDisplay() 
+{
+	if (!refresh_called)
+	{
+		Refresh();
+		refresh_called = true;
+	}
+}
+
+void ASSDrawEngine::OnPaint(wxPaintEvent& event)
+{
+	draw();
+	onPaint(event);
+	if (setfitviewpoint)
+	{
+		FitToViewPoint( fitviewpoint_hmargin, fitviewpoint_vmargin );
+		setfitviewpoint = false;
+		RefreshDisplay();
+	}
+}
+
+void ASSDrawEngine::draw()
+{
+	refresh_called = false;
+	
+	PixelFormat::AGGType pixf(rBuf);
+	RendererBase rbase(pixf);
+	RendererPrimitives rprim(rbase);
+	RendererSolid rsolid(rbase);
+
+	agg::trans_affine mtx;
+	ConstructPathsAndCurves(mtx, rm_path, rb_path, rm_curve);
+
+	rasterizer.reset();
+	update_rendered_bound_coords(true);
+	DoDraw(rbase, rprim, rsolid, mtx);
+	
+	delete rm_path, rb_path, rm_curve;
+}
+
+void ASSDrawEngine::ConstructPathsAndCurves(agg::trans_affine& mtx, 
+	trans_path*& _rm_path, trans_path*& _rb_path, agg::conv_curve<trans_path>*& _rm_curve)
+{
+    mtx *= agg::trans_affine_scaling(pointsys->scale);
+    mtx *= agg::trans_affine_translation(pointsys->originx, pointsys->originy);
+
+	m_path.remove_all();
+	b_path.remove_all();
+
+	DrawCmdList::iterator ci = cmds.begin();
+	while (ci != cmds.end())
+	{
+		AddDrawCmdToAGGPathStorage(*ci, m_path);
+		AddDrawCmdToAGGPathStorage(*ci, b_path, CTRL_LN);
+		ci++;
+	}
+	_rm_path = new trans_path(m_path, mtx);
+	_rb_path = new trans_path(b_path, mtx);
+    _rm_curve = new agg::conv_curve<trans_path>(*rm_path);
+}
+
+void ASSDrawEngine::DoDraw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx )
+{
+	Draw_Clear( rbase );
+	Draw_Draw( rbase, rprim, rsolid, mtx, rgba_shape );
+}
+
+void ASSDrawEngine::Draw_Clear( RendererBase& rbase )
+{
+	rbase.clear(color_bg);
+}
+
+void ASSDrawEngine::Draw_Draw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx, agg::rgba color )
+{
+    agg::conv_contour< agg::conv_curve< agg::conv_transform< agg::path_storage > > > contour(*rm_curve);
+	rasterizer.add_path(contour);
+	render_scanlines_aa_solid(rbase, color);
+}
+
+void ASSDrawEngine::AddDrawCmdToAGGPathStorage(DrawCmd* cmd, agg::path_storage& path, DRAWCMDMODE mode)
+{
+	if (mode == HILITE && cmd->prev)
+		path.move_to(cmd->prev->m_point->x(), cmd->prev->m_point->y());
+
+	switch(cmd->type)
+	{
+	case M:
+		path.move_to(cmd->m_point->x(),cmd->m_point->y());
+		break;
+
+	case B:
+		if (cmd->initialized)
+		{
+			//path.move_to(cmd->prev->m_point->x(),cmd->prev->m_point->y());
+			PointList::iterator iterate = cmd->controlpoints.begin();
+			int x[2], y[2];
+			x[0] = (*iterate)->x();
+			y[0] = (*iterate)->y();
+			iterate++;
+			x[1] = (*iterate)->x();
+			y[1] = (*iterate)->y();
+			path.curve4(x[0], y[0], x[1], y[1], cmd->m_point->x(),cmd->m_point->y());
+    		break;
+		}
+
+	case L:
+		if (mode == CTRL_LN)
+			path.move_to(cmd->m_point->x(),cmd->m_point->y());
+		else
+			path.line_to(cmd->m_point->x(),cmd->m_point->y());
+		break;
+		
+	case S:
+		unsigned np = cmd->controlpoints.size();
+        agg::pod_array<double> m_polygon(np * 2);
+        unsigned _pn = 0;
+		PointList::iterator iterate = cmd->controlpoints.begin();
+		while (iterate != cmd->controlpoints.end())
+		{
+	        m_polygon[_pn] = (*iterate)->x(); _pn++;
+	        m_polygon[_pn] = (*iterate)->y(); _pn++;
+	        iterate++;
+		}
+        //m_polygon[_pn++] = cmd->m_point->x();
+        //m_polygon[_pn++] = cmd->m_point->y();
+		//path.move_to(cmd->prev->m_point->x(),cmd->prev->m_point->y());
+		if (mode == CTRL_LN)
+		{
+			_pn = 0;
+			while (_pn < np * 2)
+			{
+				path.line_to((int) m_polygon[_pn],(int) m_polygon[_pn + 1]);
+				_pn += 2;
+			}
+	        path.line_to(cmd->m_point->x(), cmd->m_point->y());
+		}	
+		else
+		{	
+			//path.line_to((int) m_polygon[0],(int) m_polygon[1]);
+	        aggpolygon poly(&m_polygon[0], np, false, false);
+	        agg::conv_bcspline<agg::simple_polygon_vertex_source>  bspline(poly);
+	        bspline.interpolation_step(0.01);
+	        agg::path_storage npath;
+	        npath.join_path(bspline);
+	        path.join_path(npath);
+	        if (mode == HILITE)
+	        	path.move_to((int) m_polygon[np * 2 - 2], (int) m_polygon[np * 2 - 1] );
+	        path.line_to(cmd->m_point->x(), cmd->m_point->y());
+		}
+		break;
+	}	
+
+}
+
+void ASSDrawEngine::render_scanlines_aa_solid(RendererBase& rbase, agg::rgba rgba, bool affectboundaries)
+{
+	agg::render_scanlines_aa_solid(rasterizer, scanline, rbase, rgba);
+	if (affectboundaries) update_rendered_bound_coords();
+}
+
+void ASSDrawEngine::render_scanlines(RendererSolid& rsolid, bool affectboundaries)
+{
+	agg::render_scanlines(rasterizer, scanline, rsolid);
+	if (affectboundaries) update_rendered_bound_coords();
+}
+
+void ASSDrawEngine::update_rendered_bound_coords(bool rendered_fresh)
+{
+    int min_x = rasterizer.min_x();
+    int min_y = rasterizer.min_y();
+    int max_x = rasterizer.max_x();
+    int max_y = rasterizer.max_y();
+	if (min_x < rendered_min_x || rendered_fresh) rendered_min_x = min_x;
+	if (min_y < rendered_min_y || rendered_fresh) rendered_min_y = min_y;
+	if (max_x > rendered_max_x || rendered_fresh) rendered_max_x = max_x;
+	if (max_y > rendered_max_y || rendered_fresh) rendered_max_y = max_y;
+}
+
+void ASSDrawEngine::FitToViewPoint(int hmargin, int vmargin)
+{
+	wxSize v = GetClientSize();
+	double wide = rendered_max_x - rendered_min_x;
+	double high = rendered_max_y - rendered_min_y;
+	double widthratio = (double) (v.x - hmargin * 2) / wide;
+	double heightratio = (double) (v.y - vmargin * 2) / high;
+	double ratio = (widthratio < heightratio? widthratio:heightratio);
+	pointsys->scale = pointsys->scale * ratio;
+	if (pointsys->scale < 0.01) pointsys->scale = 0.01;
+	double new_min_x = pointsys->originx + (rendered_min_x - pointsys->originx) * ratio;
+	double new_max_x = pointsys->originx + (rendered_max_x - pointsys->originx) * ratio;
+	pointsys->originx += (v.x - new_max_x + new_min_x) / 2 - new_min_x;
+	double new_min_y = pointsys->originy + (rendered_min_y - pointsys->originy) * ratio;
+	double new_max_y = pointsys->originy + (rendered_max_y - pointsys->originy) * ratio;
+	pointsys->originy += (v.y - new_max_y + new_min_y) / 2 - new_min_y;
+	RefreshDisplay();
+}
+
+void ASSDrawEngine::SetFitToViewPointOnNextPaint(int hmargin, int vmargin)
+{
+	if (vmargin >= 0) fitviewpoint_vmargin = vmargin;
+	if (hmargin >= 0) fitviewpoint_hmargin = hmargin;
+	setfitviewpoint = true;
+}
+
+std::vector< bool > ASSDrawEngine::PrepareC1ContData()
+{
+	std::vector< bool > out;
+	for (DrawCmdList::iterator it = cmds.begin(); it != cmds.end(); it++)
+	{
+		bool c1 = false;
+		if ((*it)->type == B)
+		{
+			DrawCmd_B *cmdb = static_cast<DrawCmd_B *>(*it);
+			c1 = cmdb->C1Cont;
+		}
+		out.push_back(c1);
+	}
+	return out;
+}
diff --git a/assdraw/src/engine.hpp b/assdraw/src/engine.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b730ec6fcc2f996e98af4fd2b6785598901ee78a
--- /dev/null
+++ b/assdraw/src/engine.hpp
@@ -0,0 +1,406 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        engine.hpp
+// Purpose:     header file for ASSDraw drawing engine
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "_common.hpp"
+
+// we use these 2 standard libraries
+#include <math.h>
+#include <list>
+#include <set>
+#include <vector>
+
+// agg support
+#include "wxAGG/AGGWindow.h"
+#include "agg_color_rgba.h"
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_scanline_p.h"
+#include "agg_renderer_base.h"
+#include "agg_renderer_primitives.h"
+#include "agg_renderer_scanline.h"
+#include "agg_path_storage.h"
+#include "agg_curves.h"
+#include "agg_conv_curve.h"
+#include "agg_conv_contour.h"
+#include "agg_conv_stroke.h"
+#include "agg_conv_bcspline.h"
+#include "agg_math.h"
+
+#define DEFAULT_SCALE 10
+
+// this header file declare the following classes
+class DrawEngine;
+class Point;
+class PointSystem;
+class DrawCmd;
+
+typedef std::list<DrawCmd*> DrawCmdList;
+typedef std::list<Point*> PointList;
+typedef std::set<Point*> PointSet;
+
+// Command type
+enum CMDTYPE 
+{
+     M = 0,
+     N = 1,
+     L = 2,
+     B = 3,
+     S = 4,
+     P = 5,
+     C = 6     
+};
+
+// Point type
+enum POINTTYPE
+{
+	MP, // main point
+	CP  // control point
+};
+
+// A PointSystem is a centralized entity holding the parameters:
+// scale, originx and originy, all of which are needed by Point
+class PointSystem
+{
+public:
+	double scale, originx, originy;
+
+	PointSystem ( double sc = 1.0, double origx = 0.0, double origy = 0.0 )
+	{ 	Set( sc, origx, origy ); }
+
+	// set scale, originx and originy;
+	void Set( double sc, double origx, double origy )
+	{ scale = sc, originx = origx, originy = origy; }
+	
+	wxRealPoint ToWxRealPoint ( double x, double y )
+	{ return wxRealPoint( originx + x * scale, originy + y * scale ); }
+
+	// given drawing command coordinates returns the wxPoint on the GUI
+	wxPoint ToWxPoint ( double x, double y )
+	{ return wxPoint( (int) (originx + x * scale), (int) (originy + y * scale) ); }
+
+	// given wxPoint on the GUI returns the nearest drawing command coords
+	void FromWxPoint ( int wxpx, int wxpy, int &x, int &y )
+	{
+		x = int( floor( ((double) wxpx - originx) / scale + 0.5 ) );
+		y = int( floor( ((double) wxpy - originy) / scale + 0.5 ) );
+	}                   
+
+	// given wxPoint on the GUI returns the nearest drawing command coords
+	void FromWxPoint ( wxPoint wxp, int &x, int &y )
+	{
+		FromWxPoint( wxp.x, wxp.y, x, y );
+	}
+};
+
+// The point class
+// note: this actually refers to the x,y-coordinate in drawing commands,
+// not the coordinate in the GUI
+class Point
+{
+public:
+	POINTTYPE type;
+	PointSystem *pointsys;
+
+	// drawing commands that depend on this point
+	DrawCmd* cmd_main;
+	DrawCmd* cmd_next;
+	bool isselected;
+	unsigned num;
+
+	// constructor
+	//Point ( ) { cmd_main = NULL; cmd_next = NULL; }
+
+	// constructor
+	Point ( int _x, int _y, PointSystem* ps, POINTTYPE t, DrawCmd* cmd, unsigned n = 0 );
+
+	// getters
+	int x() { return x_; }
+
+	int y() { return y_; }
+
+	//set x and y
+	void setXY( int _x, int _y);
+	
+	// simply returns true if px and py are the coordinate values
+	bool IsAt( int px, int py );
+
+	// convert this point to wxPoint using scale and originx, originy
+	wxPoint ToWxPoint () { return ToWxPoint(true); }
+
+	// convert this point to wxPoint using scale;
+	// also use originx and originy if useorigin = true
+	wxPoint ToWxPoint (bool useorigin);
+
+	// check if wxpoint is nearby this point
+	bool CheckWxPoint ( wxPoint wxpoint );
+
+private:
+	int x_, y_;
+
+};
+
+// The base class for all draw commands
+class DrawCmd
+{
+public:
+	CMDTYPE type;
+	      
+	// main point (almost every command has one)
+	// for B and S it's the last (destination) point
+	Point* m_point;
+
+	// other points than the main point
+	// subclasses must populate this list even if they define 
+	// new variables for other points
+	PointList controlpoints; 
+
+	// Linked list feature
+	DrawCmd *prev;
+
+	// Must set to true if the next command should NOT utilize this command
+	// for the drawing
+	bool dobreak;
+
+	// Set to true if invisible m_point (not drawn)
+	bool invisible;
+
+	// true if this DrawCmd has been initialized with Init(), false otherwise
+	// (initialized means that the control points have been generated)
+	bool initialized;
+
+	// -----------------------------------------------------------
+	// Constructor(s)
+	DrawCmd ( int x, int y, PointSystem *ps, DrawCmd *pv );
+	      
+	// Destructor
+	virtual ~DrawCmd ();
+
+	// Init the draw command (for example to generate the control points)
+	virtual void Init(unsigned n = 0) { initialized = true; }
+
+	virtual wxString ToString() { return wxT(""); }
+
+};
+
+class ASSDrawEngine: public GUI::AGGWindow
+{
+public:
+	ASSDrawEngine( wxWindow *parent, int extraflags = 0 );
+
+    // destructor
+    ~ASSDrawEngine();
+
+	virtual void SetDrawCmdSet(wxString set) { drawcmdset = set; }
+
+    virtual void ResetEngine();
+    virtual void ResetEngine(bool addM);
+    virtual void RefreshDisplay();
+
+	void FitToViewPoint(int hmargin, int vmargin);
+	void SetFitToViewPointOnNextPaint(int hmargin = -1, int vmargin = -1);
+
+	PointSystem* _PointSystem() { return pointsys; }
+
+	// ASS draw commands; returns the number of parsed commands
+	virtual int ParseASS ( wxString str );
+	// generate ASS draw commands
+	virtual wxString GenerateASS ( );
+
+	// drawing
+    virtual void OnPaint(wxPaintEvent &event);
+
+	// -------------------- adding new commands ----------------------------
+
+	// create draw command of type 'type' and m_point (x, y), append to the
+	// list and return it
+	virtual DrawCmd* AppendCmd ( CMDTYPE type, int x, int y );
+
+	// append draw command
+	virtual DrawCmd* AppendCmd ( DrawCmd* cmd );
+
+	// create draw command of type 'type' and m_point (x, y), insert to the
+	// list after the _cmd and return it
+	virtual DrawCmd* InsertCmd ( CMDTYPE type, int x, int y, DrawCmd* _cmd );
+
+	// insert draw command cmd after _cmd
+	virtual void InsertCmd ( DrawCmd* cmd, DrawCmd* _cmd );
+
+	// Create new DrawCmd
+	DrawCmd* NewCmd ( CMDTYPE type, int x, int y );
+
+	// -------------------- read/modify commands ---------------------------
+
+	// returns the iterator for the list
+	virtual DrawCmdList::iterator Iterator ( );
+
+	// returns the 'end' iterator for the list
+	virtual DrawCmdList::iterator IteratorEnd ( );
+
+	// returns the last command in the list
+	virtual DrawCmd* LastCmd ();
+
+	// returns the total number of commands in the list
+	//virtual int CmdCount () { return cmds.size(); }
+
+	// move all points by relative amount of x, y coordinates
+	virtual void MovePoints ( int x, int y );
+
+	// transform all points using the calculation:
+	//   | (m11)  (m12) | x | (x - mx) | + | nx |
+	//   | (m21)  (m22) |   | (y - my) |   | ny |
+	virtual void Transform( float m11, float m12, float m21, float m22,
+							float mx, float my, float nx, float ny );
+
+	// returns some DrawCmd if its m_point = (x, y)
+	virtual DrawCmd* PointAt ( int x, int y );
+
+	// returns some DrawCmd if one of its control point = (x, y)
+	// also set &point to refer to that control point
+	virtual DrawCmd* ControlAt ( int x, int y, Point* &point );
+
+	// attempts to delete a commmand, returns true|false if successful|fail
+	virtual bool DeleteCommand ( DrawCmd* cmd );
+	
+	agg::rgba rgba_shape;
+	PixelFormat::AGGType::color_type color_bg;
+
+protected:
+	/// The AGG base renderer
+	typedef agg::renderer_base<PixelFormat::AGGType> RendererBase;
+	/// The AGG primitives renderer
+	typedef agg::renderer_primitives<RendererBase> RendererPrimitives;
+	/// The AGG solid renderer
+	typedef agg::renderer_scanline_aa_solid<RendererBase> RendererSolid;
+	
+	enum DRAWCMDMODE {
+		NORMAL,
+		CTRL_LN,
+		HILITE
+	};
+
+	DrawCmdList cmds;
+	wxString drawcmdset;
+
+	PointSystem* pointsys;
+	
+	// for FitToViewPoint feature
+	bool setfitviewpoint;
+	int fitviewpoint_vmargin, fitviewpoint_hmargin;
+
+	// AGG
+	agg::rasterizer_scanline_aa<> rasterizer;   ///< Scanline rasterizer
+	agg::scanline_p8  scanline;                 ///< Scanline container
+	void render_scanlines_aa_solid(RendererBase& rbase, agg::rgba rbga, bool affectboundaries = true);
+	void render_scanlines(RendererSolid& rsolid, bool affectboundaries = true);
+	int rendered_min_x, rendered_min_y, rendered_max_x, rendered_max_y; //bounding coord of rendered shapes
+	void update_rendered_bound_coords(bool rendered_fresh = false);
+
+	typedef agg::conv_transform<agg::path_storage> trans_path;
+	agg::path_storage m_path, b_path;
+	trans_path *rm_path, *rb_path;
+	agg::conv_curve<trans_path> *rm_curve;
+
+	void draw();
+	virtual void ConstructPathsAndCurves(agg::trans_affine& mtx, trans_path*& _rm_path, trans_path*& _rb_path, agg::conv_curve<trans_path>*& _rm_curve);
+	virtual void DoDraw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx  );
+	virtual void Draw_Clear( RendererBase& rbase );
+	virtual void Draw_Draw( RendererBase& rbase, RendererPrimitives& rprim, RendererSolid& rsolid, agg::trans_affine& mtx, agg::rgba color );
+	bool refresh_called;
+	
+	// set stuff to connect two drawing commands cmd1 and cmd2 such that
+	// cmd1 comes right before cmd2
+	virtual void ConnectSubsequentCmds (DrawCmd* cmd1, DrawCmd* cmd2);
+	
+	virtual void AddDrawCmdToAGGPathStorage(DrawCmd* cmd, agg::path_storage& path, DRAWCMDMODE mode = NORMAL);
+	
+	virtual std::vector< bool > PrepareC1ContData();
+
+	DECLARE_EVENT_TABLE()
+};
+
+namespace agg
+{
+    class simple_polygon_vertex_source
+    {
+    public:
+        simple_polygon_vertex_source(const double* polygon, unsigned np, 
+                                     bool roundoff = false,
+                                     bool close = true) :
+            m_polygon(polygon),
+            m_num_points(np),
+            m_vertex(0),
+            m_roundoff(roundoff),
+            m_close(close)
+        {
+        }
+
+        void close(bool f) { m_close = f;    }
+        bool close() const { return m_close; }
+
+        void rewind(unsigned)
+        {
+            m_vertex = 0;
+        }
+
+        unsigned vertex(double* x, double* y)
+        {
+            if(m_vertex > m_num_points) return path_cmd_stop;
+            if(m_vertex == m_num_points) 
+            {
+                ++m_vertex;
+                return path_cmd_end_poly | (m_close ? path_flags_close : 0);
+            }
+            *x = m_polygon[m_vertex * 2];
+            *y = m_polygon[m_vertex * 2 + 1];
+            if(m_roundoff)
+            {
+                *x = floor(*x) + 0.5;
+                *y = floor(*y) + 0.5;
+            }
+            ++m_vertex;
+            return (m_vertex == 1) ? path_cmd_move_to : path_cmd_line_to;
+        }
+
+    private:
+        const double* m_polygon;
+        unsigned m_num_points;
+        unsigned m_vertex;
+        bool     m_roundoff;
+        bool     m_close;
+    };
+};
+
+typedef agg::simple_polygon_vertex_source aggpolygon;
diff --git a/assdraw/src/enums.hpp b/assdraw/src/enums.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5921705687ebffb7d25fccdd9eb56512b41a424
--- /dev/null
+++ b/assdraw/src/enums.hpp
@@ -0,0 +1,113 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+// enum for IDs of menus
+enum {
+	MENU_DUMMY = 200,
+	MENU_CLEAR,
+	MENU_PREVIEW,
+	MENU_TRANSFORM,
+	MENU_LIBRARY,
+	MENU_HELP,
+	MENU_RESETPERSPECTIVE,
+	MENU_SETTINGS,
+	MENU_UNDO,
+	MENU_REDO,
+	MENU_PASTE,
+	MENU_BGIMG_LOAD,
+	MENU_BGIMG_ALPHA,
+	MENU_BGIMG_REMOVE,
+	MENU_RECENTER,
+	MENU_TBAR,
+	MENU_REPOS_TOPLEFT,
+	MENU_REPOS_TOPRIGHT,
+	MENU_REPOS_CENTER,
+	MENU_REPOS_BOTLEFT,
+	MENU_REPOS_BOTRIGHT,
+	MENU_BGIMG_RECENTER,
+	MENU_REPOS_BGTOPLEFT,
+	MENU_REPOS_BGTOPRIGHT,
+	MENU_REPOS_BGCENTER,
+	MENU_REPOS_BGBOTLEFT,
+	MENU_REPOS_BGBOTRIGHT,
+	MENU_DRC_LNTOBEZ,
+	MENU_DRC_C1CONTBEZ,
+	MENU_DRC_BEZTOLN,
+	MENU_DRC_MOVE00,
+	MENU_TB_ALL,
+	MENU_TB_NONE,
+	MENU_TB_DOCK,
+	MENU_TB_UNDOCK,
+	MENU_TB_DRAW,
+	MENU_TB_MODE,
+	MENU_TB_BGIMG
+};
+
+// enum for modes (i.e. create m, b, l etc or normal mode)
+// also use as tools IDs
+enum MODE
+{
+    MODE_ARR = 100,
+    MODE_M = 101,
+    MODE_N = 102,
+    MODE_L = 103,
+    MODE_B = 104,
+    MODE_S = 105,
+    MODE_P = 106,
+    MODE_C = 107,
+    MODE_DEL = 108,
+	MODE_SCALEROTATE = 109,
+	MODE_NUT_BILINEAR = 110
+};
+
+// enum for IDs of other tools on the toolbar
+enum {
+     TB_CLEAR = 111,
+     TB_EDITSRC = 112,
+     TB_PREVIEW = 113,
+     TB_TRANSFORM = 114,
+     TB_HELP = 115,
+     TB_ZOOMSLIDER = 116,
+     TB_BGALPHA_SLIDER = 117
+};
+
+enum DRAGMODETOOL
+{
+    DRAG_DWG = 120,
+    DRAG_BGIMG = 121,
+    DRAG_BOTH = 122
+};
+
+struct DRAGMODE
+{
+	bool drawing;
+	bool bgimg;
+	DRAGMODE() { drawing = true, bgimg = false; }
+	DRAGMODE(bool d, bool b) { drawing = d, bgimg = b; }
+};
diff --git a/assdraw/src/include_once.hpp b/assdraw/src/include_once.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa7624ac7f20c0ddcbcb89fb3747a7bbb775705e
--- /dev/null
+++ b/assdraw/src/include_once.hpp
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        include_once.hpp
+// Purpose:     A header file that is included exactly once for the whole code
+//              (supposed to be included by assdraw.cpp only)
+//              Put must-define-exactly-once codes here
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+// tooltips
+const wxString TIPS_CLEAR = wxT("Clear the canvas and create a new drawing");
+const wxString TIPS_EDITSRC = wxT("Edit the source");
+const wxString TIPS_PREVIEW = wxT("Draw the shapes without enlarged points and control points");
+const wxString TIPS_TRANSFORM = wxT("Transform the drawing using matrix transformation");
+const wxString TIPS_LIBRARY = wxT("Shapes library");
+const wxString TIPS_HELP = wxT("Help! Help!");
+const wxString TIPS_PASTE = wxT("Depending on what's in the clipboard, import as drawing commands or background");
+const wxString TIPS_UNDO = wxT("Undo last action");
+const wxString TIPS_REDO = wxT("Redo last undo");
+const wxString TIPS_ARR = wxT("Drag mode");
+const wxString TIPS_M = wxT("Draw M mode (Close current shape and move the virtual pen to a new point)");
+const wxString TIPS_N = wxT("Draw N mode (Same as M but doesn't close the shape)");
+const wxString TIPS_L = wxT("Draw L mode (Straight line)");
+const wxString TIPS_B = wxT("Draw B mode (Cubic Bezier curve)");
+const wxString TIPS_S = wxT("Draw S mode (Spline)");
+const wxString TIPS_P = wxT("Draw P mode (Extends a spline with another point)");
+const wxString TIPS_C = wxT("Draw C mode (Close the last spline)");
+const wxString TIPS_DEL = wxT("Delete mode");
+const wxString TIPS_NUTB = wxT("Bilinear transformation mode: Drag the vertices to distort the shape; Dragging an edge moves two adjacent vertices together");
+const wxString TIPS_SCALEROTATE = wxT("Scale/Rotate mode: Drag a vertex or an edge to rescale the shape; Right-drag to rotate");
+const wxString TIPS_DWG = wxT("Right-dragging pans drawing, mousewheel zooms in/out drawing");
+const wxString TIPS_BGIMG = wxT("Right-dragging pans background, mousewheel zooms in/out background");
+const wxString TIPS_BOTH = wxT("Right-dragging pans drawing & background, mousewheel zooms in/out drawing & background");
+
+const wxString TBNAME_DRAW = wxT("Canvas");
+const wxString TBNAME_MODE = wxT("Drawing mode");
+const wxString TBNAME_BGIMG = wxT("Background");
+const wxString TBNAME_ZOOM = wxT("Zoom");
+
+wxString ASSDrawTransformDlg::combo_templatesStrings[] = {
+	_("<Select>"),
+	_("Move 5 units down"),
+	_("Move 5 units right"),
+	_("Rotate 90� clockwise at (1, 2)"),
+	_("Rotate 90� counterclockwise at (-1, 2)"),
+	_("Rotate 180� at (0, 0)"),
+	_("Flip horizontally at X = 4"),
+	_("Flip vertically at Y = 3"),
+	_("Scale up horizontally by a factor of 2"),
+	_("Scale up vertically by a factor of 3")
+};
+
+int ASSDrawTransformDlg::combo_templatesCount = 10;
+
+EightDouble ASSDrawTransformDlg::combo_templatesValues[] = {
+	{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, //<Select>
+	{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 5.0f }, //5 units down
+	{ 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 5.0f, 0.0f }, //5 units left
+	{ 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 2.0f, 1.0f, 2.0f }, //90 CW (1,2)
+	{ 0.0f, 1.0f, -1.0f, 0.0f, -1.0f, 2.0f, -1.0f, 2.0f }, //90 CCW, (-1,2)
+	{ -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, //180 (0,0)
+	{ -1.0f, 0.0f, 0.0f, 1.0f, 4.0f, 0.0f, 4.0f, 0.0f }, //Flip X = 4
+	{ 1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 3.0f, 0.0f, 3.0f }, //Flip Y = 3
+	{ 2.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f }, //Scale X * 2
+	{ 1.0f, 0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f, 0.0f } //Scale Y * 3
+};
diff --git a/assdraw/src/library.cpp b/assdraw/src/library.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1f6932eb0a30f5eba74d4602a6cba8466811f54c
--- /dev/null
+++ b/assdraw/src/library.cpp
@@ -0,0 +1,259 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "assdraw.hpp"
+#include "library.hpp"
+
+#include <wx/clipbrd.h>
+
+BEGIN_EVENT_TABLE(ASSDrawShapePreview, ASSDrawEngine)
+    EVT_SIZE(ASSDrawShapePreview::OnSize)
+END_EVENT_TABLE()
+
+ASSDrawShapePreview::ASSDrawShapePreview( wxWindow *parent, ASSDrawShapeLibrary *_shapelib, wxString initialcmds )
+	: ASSDrawEngine(parent, wxSIMPLE_BORDER)
+{
+	shapelib = _shapelib;
+	if (ParseASS(initialcmds) > 0)
+		SetFitToViewPointOnNextPaint(5, 5);
+	cb = new wxCheckBox(this, wxID_ANY, "");
+}
+
+void ASSDrawShapePreview::OnSize(wxSizeEvent& event)
+{
+	return;
+	wxSize siz = event.GetSize();
+	
+	if (shapelib->layout == HORIZONTAL)
+		SetSize(siz.x, siz.x);
+	else
+		SetSize(siz.y, siz.y);	
+	SetFitToViewPointOnNextPaint(10, 10);
+}
+
+BEGIN_EVENT_TABLE(ASSDrawShapeLibrary, wxScrolledWindow)
+    EVT_SIZE(ASSDrawShapeLibrary::OnSize)
+    EVT_MENU_RANGE(MENU_RANGE_START, MENU_RANGE_END, ASSDrawShapeLibrary::OnPopupMenuClicked)
+    EVT_TOOL(TOOL_SAVE, ASSDrawShapeLibrary::SaveShapeFromCanvas)
+    EVT_TOOL_RANGE(TOOL_CHECK, TOOL_UNCHECK, ASSDrawShapeLibrary::CheckUncheckAllPreviews)
+    EVT_TOOL(TOOL_DELETE, ASSDrawShapeLibrary::DeleteChecked)
+END_EVENT_TABLE()
+
+ASSDrawShapeLibrary::ASSDrawShapeLibrary( wxWindow *parent, ASSDrawFrame *frame ) 
+	: wxScrolledWindow(parent, wxID_ANY)
+{
+	m_frame = frame;
+	//sizer = NULL;
+	layout = VERTICAL;
+	
+	wxToolBar *tbar = new wxToolBar(this, wxID_ANY, __DPDS__ , wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT | wxTB_NODIVIDER);
+	tbar->SetMargins(0, 3);
+	tbar->AddTool(TOOL_SAVE, wxBITMAP(add), "Save canvas");
+	tbar->AddSeparator();
+	tbar->AddTool(TOOL_CHECK, wxBITMAP(check), "Select all");
+	tbar->AddTool(TOOL_UNCHECK, wxBITMAP(uncheck), "Select none");
+	tbar->AddTool(TOOL_DELETE, wxBITMAP(delcross), "Delete selected");
+
+	libarea = new wxScrolledWindow(this, wxID_ANY, __DPDS__ , wxScrolledWindowStyle | wxSIMPLE_BORDER);
+	libarea->SetBackgroundColour(wxColour(0xFF, 0xFF, 0x99));
+	sizer = new wxFlexGridSizer(0, 1, 0, 0);
+	((wxFlexGridSizer*) sizer)->AddGrowableCol(0);
+	libarea->SetSizer(sizer);
+	libarea->SetScrollbars(20, 20, 50, 50);
+	libsizer = new wxFlexGridSizer(2, 1, 0, 0);
+	libsizer->AddGrowableCol(0);
+	libsizer->AddGrowableRow(1);
+	libsizer->Add(tbar, 0, wxBOTTOM, 2);
+	libsizer->Add(libarea,1,wxEXPAND);
+	tbar->Realize();
+	libsizer->Layout();
+
+	SetSizer(libsizer);
+}
+
+void ASSDrawShapeLibrary::OnSize(wxSizeEvent& event)
+{
+	if (sizer == NULL || sizer->GetChildren().size() == 0) return;
+
+	wxSize siz = GetClientSize();
+	libsizer->SetDimension(0, 0, siz.x, siz.y);
+			
+	UpdatePreviewDisplays();
+}
+
+ASSDrawShapePreview* ASSDrawShapeLibrary::AddShapePreview(wxString cmds, bool addtotop)
+{
+	ASSDrawShapePreview *prev = new ASSDrawShapePreview(libarea, this, cmds);
+	prev->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler(ASSDrawShapeLibrary::OnMouseLeftDClick), NULL, this);
+	prev->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(ASSDrawShapeLibrary::OnMouseRightClick), NULL, this);
+	ASSDrawFrame::wxColourToAggRGBA(m_frame->colors.library_shape, prev->rgba_shape);
+	if (addtotop)
+		sizer->Insert(0, prev, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5);
+	else
+		sizer->Add(prev, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5);
+	UpdatePreviewDisplays();
+	return prev;
+}
+
+void ASSDrawShapeLibrary::UpdatePreviewDisplays()
+{
+	wxSize siz = GetClientSize();
+	int dim = siz.x - 15;
+	libarea->Show(false);
+	wxwxSizerItemListNode *node = sizer->GetChildren().GetFirst();
+	while (node != NULL)
+	{
+		ASSDrawShapePreview *shprvw = (ASSDrawShapePreview *) node->GetData()->GetWindow();
+		shprvw->SetSize(dim, dim);
+		sizer->SetItemMinSize(shprvw, dim - 20, dim - 20);
+		shprvw->SetFitToViewPointOnNextPaint(10, 10);
+		shprvw->Refresh();
+		node = node->GetNext();
+	}
+	sizer->Layout();
+	sizer->FitInside(libarea);	
+	libarea->Show(true);
+}
+
+void ASSDrawShapeLibrary::OnMouseLeftDClick(wxMouseEvent &event)
+{
+	ASSDrawShapePreview *preview = (ASSDrawShapePreview *) event.GetEventObject();
+	LoadToCanvas(preview);
+}
+
+void ASSDrawShapeLibrary::OnMouseRightClick(wxMouseEvent &event)
+{
+	ASSDrawShapePreview *prev = (ASSDrawShapePreview *) event.GetEventObject();
+	if (prev && prev->shapelib == this)
+	{
+		activepreview = prev;
+		wxMenu *menu = new wxMenu;
+		wxMenuItem *menuload = new wxMenuItem(menu, MENU_LOAD, wxT("Load to canvas"));
+		wxFont f = menuload->GetFont();
+		f.SetWeight(wxFONTWEIGHT_BOLD);
+		menuload->SetFont(f);
+		menu->Append(menuload);
+		//menu->Append(MENU_LOAD, wxT("Load to canvas"))->GetFont().SetWeight(wxFONTWEIGHT_BOLD);
+		menu->Append(MENU_COPYCLIPBOARD, wxT("Copy commands to clipboard"));
+		menu->Append(MENU_SAVECANVAS, wxT("Save canvas here"));
+		wxMenu *submenu = new wxMenu;
+		submenu->Append(MENU_DELETE, wxT("Confirm delete?"));
+		menu->Append(MENU_DUMMY, wxT("Delete from library"), submenu);
+		PopupMenu(menu);
+		delete menu;
+	}
+}
+
+void ASSDrawShapeLibrary::OnPopupMenuClicked(wxCommandEvent &event)
+{
+	int id = event.GetId();
+	switch(id)
+	{
+	case MENU_LOAD:
+		LoadToCanvas(activepreview);
+		break;
+	case MENU_COPYCLIPBOARD:
+		if (wxTheClipboard->Open())
+		{
+			if (wxTheClipboard->IsSupported( wxDF_TEXT ))
+			{
+				wxTheClipboard->SetData( new wxTextDataObject( activepreview->GenerateASS() ) );
+			}
+			wxTheClipboard->Close();
+		}
+		break;
+	case MENU_SAVECANVAS:
+		activepreview->ParseASS(m_frame->m_canvas->GenerateASS());
+		activepreview->SetFitToViewPointOnNextPaint();
+		activepreview->RefreshDisplay();
+		break;
+	case MENU_DELETE:
+		sizer->Detach(activepreview);
+		activepreview->Show(false);
+		activepreview->Destroy();
+		UpdatePreviewDisplays();
+		Refresh();
+		break;
+	}
+}
+
+void ASSDrawShapeLibrary::SaveShapeFromCanvas(wxCommandEvent& WXUNUSED(event))
+{
+	AddShapePreview(m_frame->m_canvas->GenerateASS(), true);	
+}
+
+void ASSDrawShapeLibrary::CheckUncheckAllPreviews(wxCommandEvent &event)
+{
+	bool checked = event.GetId() == TOOL_CHECK;	
+	wxwxSizerItemListNode *node = sizer->GetChildren().GetFirst();
+	while (node != NULL)
+	{
+		ASSDrawShapePreview *shprvw = (ASSDrawShapePreview *) node->GetData()->GetWindow();
+		shprvw->cb->SetValue(checked);
+		node = node->GetNext();
+	}
+}
+
+void ASSDrawShapeLibrary::DeleteChecked(wxCommandEvent& WXUNUSED(event))
+{
+	wxwxSizerItemListNode *node = sizer->GetChildren().GetFirst();
+	while (node != NULL)
+	{
+		ASSDrawShapePreview *shprvw = (ASSDrawShapePreview *) node->GetData()->GetWindow();
+		if (shprvw->cb->GetValue())
+		{
+			sizer->Detach(shprvw);
+			shprvw->Show(false);
+			shprvw->Destroy();
+		}
+		node = node->GetNext();
+	}
+	UpdatePreviewDisplays();
+	Refresh();
+}
+
+std::vector< ASSDrawShapePreview *> ASSDrawShapeLibrary::GetShapePreviews()
+{
+	std::vector< ASSDrawShapePreview *> out;
+	wxwxSizerItemListNode *node = sizer->GetChildren().GetFirst();
+	while (node != NULL)
+	{
+		ASSDrawShapePreview *shprvw = (ASSDrawShapePreview *) node->GetData()->GetWindow();
+		out.push_back(shprvw);
+		node = node->GetNext();
+	}
+	return out;
+}
+
+void ASSDrawShapeLibrary::LoadToCanvas(ASSDrawShapePreview *preview)
+{
+	m_frame->m_canvas->AddUndo("Load shape from library");
+	m_frame->m_canvas->ParseASS(preview->GenerateASS());
+	m_frame->m_canvas->RefreshDisplay();
+	m_frame->m_canvas->RefreshUndocmds();
+	m_frame->UpdateFrameUI();
+}	
diff --git a/assdraw/src/library.hpp b/assdraw/src/library.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..20179d12f2e7845a1541701cb22c95d46d7e83e6
--- /dev/null
+++ b/assdraw/src/library.hpp
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "engine.hpp"
+#include <wx/scrolwin.h>
+
+class ASSDrawFrame;
+class ASSDrawShapeLibrary;
+
+enum LIBLAYOUT { VERTICAL, HORIZONTAL };
+
+enum {
+	MENU_RANGE_START = 450,
+	MENU_LOAD,
+	MENU_COPYCLIPBOARD,
+	MENU_SAVECANVAS,
+	MENU_DELETE,
+	MENU_RANGE_END,
+	TOOL_SAVE,
+	TOOL_CHECK,
+	TOOL_UNCHECK,
+	TOOL_DELETE
+};
+
+class ASSDrawShapePreview : public ASSDrawEngine
+{
+protected:
+	ASSDrawShapePreview( wxWindow *parent, ASSDrawShapeLibrary *shapelib, wxString initialcmds = _T(""));
+	virtual void OnSize(wxSizeEvent& event);
+
+	ASSDrawShapeLibrary *shapelib;
+	wxCheckBox *cb;
+	DECLARE_EVENT_TABLE()
+	friend class ASSDrawShapeLibrary;
+};
+
+class ASSDrawShapeLibrary : public wxScrolledWindow
+{
+public:
+	ASSDrawShapeLibrary( wxWindow *parent, ASSDrawFrame *frame );
+	virtual ASSDrawShapePreview* AddShapePreview(wxString cmds, bool addtotop = false);
+	virtual void OnSize(wxSizeEvent& event);
+	virtual void OnMouseLeftDClick(wxMouseEvent &event);
+	virtual void OnMouseRightClick(wxMouseEvent &event);
+	virtual void OnPopupMenuClicked(wxCommandEvent &event);
+	virtual void SaveShapeFromCanvas(wxCommandEvent& WXUNUSED(event));
+	virtual void CheckUncheckAllPreviews(wxCommandEvent &event);
+	virtual void DeleteChecked(wxCommandEvent& WXUNUSED(event));
+	virtual void UpdatePreviewDisplays();
+	virtual std::vector< ASSDrawShapePreview *> GetShapePreviews();
+	virtual void LoadToCanvas(ASSDrawShapePreview *preview);
+	
+	wxScrolledWindow* libarea;
+	wxFlexGridSizer *libsizer;
+	wxSizer* sizer;
+	LIBLAYOUT layout;
+protected:
+	ASSDrawFrame *m_frame;
+	ASSDrawShapePreview *activepreview;
+
+	DECLARE_EVENT_TABLE()
+};
diff --git a/assdraw/src/resource.h b/assdraw/src/resource.h
new file mode 100644
index 0000000000000000000000000000000000000000..dab23b6f5eca659ec0413ba3d8883374829280f5
--- /dev/null
+++ b/assdraw/src/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by assdraw.rc
+//
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        105
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1000
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/assdraw/src/settings.cpp b/assdraw/src/settings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..41bd680c13f42a25dd5b4c7bc0f1436c345808cd
--- /dev/null
+++ b/assdraw/src/settings.cpp
@@ -0,0 +1,223 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+///////////////////////////////////////////////////////////////////////////////
+// Name:        settings.cpp
+// Purpose:     settings property grid
+// Author:      ai-chan
+// Created:     08/26/06
+// Copyright:   (c) ai-chan
+// Licence:     3-clause BSD
+///////////////////////////////////////////////////////////////////////////////
+
+#include "assdraw.hpp"
+#include "settings.hpp"
+
+DEFINE_EVENT_TYPE(wxEVT_SETTINGS_CHANGED)
+
+// ----------------------------------------------------------------------------
+// ASSDrawSettingsDialog
+// ----------------------------------------------------------------------------
+
+ASSDrawSettingsDialog::ASSDrawSettingsDialog(wxWindow *parent, ASSDrawFrame *frame, int id)
+ : wxPanel(parent, id)
+{
+	m_frame = frame;
+	propgrid = NULL;
+}
+	
+void ASSDrawSettingsDialog::Init()
+{
+    propgrid = new wxPropertyGrid(this,
+		wxID_ANY,
+		wxDefaultPosition,
+		wxDefaultSize,
+		//wxPG_BOLD_MODIFIED |
+		//wxPG_SPLITTER_AUTO_CENTER |
+		//wxPG_AUTO_SORT |
+		//wxPG_HIDE_MARGIN | wxPG_STATIC_SPLITTER |
+		wxPG_TOOLTIPS |
+		//wxPG_NOCATEGORIES |
+		wxTAB_TRAVERSAL //|
+		//wxSUNKEN_BORDER
+	);
+
+    #define APPENDCOLOURPROP(pgid, label, color) pgid = propgrid->Append( wxColourProperty(wxT(label), wxPG_LABEL, color) );
+    #define APPENDUINTPROP(pgid, label, uint) \
+		pgid = propgrid->Append( wxUIntProperty(wxT(label), wxPG_LABEL, uint) ); \
+		propgrid->SetPropertyValidator( pgid, validator );
+    #define APPENDBOOLPROP(pgid, label, boolvar) \
+	    pgid = propgrid->Append( wxBoolProperty ( wxT(label), wxPG_LABEL, boolvar ) ); \
+    	propgrid->SetPropertyAttribute( pgid, wxPG_BOOL_USE_CHECKBOX, (long)1 );
+	wxLongPropertyValidator validator(0x0,0xFF);
+    
+    propgrid->Append( wxPropertyCategory(wxT("Appearance"),wxPG_LABEL) );
+	APPENDCOLOURPROP(colors_canvas_bg_pgid, "Canvas", m_frame->colors.canvas_bg)
+	APPENDCOLOURPROP(colors_canvas_shape_normal_pgid, "Drawing", m_frame->colors.canvas_shape_normal)
+	APPENDUINTPROP(alphas_canvas_shape_normal_pgid, "Drawing @", m_frame->alphas.canvas_shape_normal)
+	APPENDCOLOURPROP(colors_canvas_shape_preview_pgid, "Preview", m_frame->colors.canvas_shape_preview)
+	APPENDUINTPROP(alphas_canvas_shape_preview_pgid, "Preview @", m_frame->alphas.canvas_shape_preview)
+	APPENDCOLOURPROP(colors_canvas_shape_outline_pgid, "Outline", m_frame->colors.canvas_shape_outline)
+	APPENDUINTPROP(alphas_canvas_shape_outline_pgid, "Outline @", m_frame->alphas.canvas_shape_outline)
+	APPENDCOLOURPROP(colors_canvas_shape_guideline_pgid, "Control lines", m_frame->colors.canvas_shape_guideline)
+	APPENDUINTPROP(alphas_canvas_shape_guideline_pgid, "Control lines @", m_frame->alphas.canvas_shape_guideline)
+	APPENDCOLOURPROP(colors_canvas_shape_mainpoint_pgid, "Points", m_frame->colors.canvas_shape_mainpoint)
+	APPENDUINTPROP(alphas_canvas_shape_mainpoint_pgid, "Points @", m_frame->alphas.canvas_shape_mainpoint)
+	APPENDCOLOURPROP(colors_canvas_shape_controlpoint_pgid, "Control points", m_frame->colors.canvas_shape_controlpoint)
+	APPENDUINTPROP(alphas_canvas_shape_controlpoint_pgid, "Control points @", m_frame->alphas.canvas_shape_controlpoint)
+	APPENDCOLOURPROP(colors_canvas_shape_selectpoint_pgid, "Selected points", m_frame->colors.canvas_shape_selectpoint)
+	APPENDUINTPROP(alphas_canvas_shape_selectpoint_pgid, "Selected points @", m_frame->alphas.canvas_shape_selectpoint)
+	APPENDCOLOURPROP(colors_library_libarea_pgid, "Library", m_frame->colors.library_libarea)
+	APPENDCOLOURPROP(colors_library_shape_pgid, "Library shapes", m_frame->colors.library_shape)
+	APPENDCOLOURPROP(colors_origin_pgid, "Origin", m_frame->colors.origin)
+	APPENDUINTPROP(sizes_origincross_pgid, "Origin cross size", m_frame->sizes.origincross)
+	APPENDCOLOURPROP(colors_ruler_h_pgid, "H ruler", m_frame->colors.ruler_h)
+	APPENDCOLOURPROP(colors_ruler_v_pgid, "V ruler", m_frame->colors.ruler_v)
+
+    propgrid->Append( wxPropertyCategory(wxT("Behaviors"),wxPG_LABEL) );
+	APPENDBOOLPROP(behaviors_capitalizecmds_pgid, "Capitalize commands", m_frame->behaviors.capitalizecmds);
+	APPENDBOOLPROP(behaviors_autoaskimgopac_pgid, "Ask for image opacity", m_frame->behaviors.autoaskimgopac);
+	APPENDBOOLPROP(behaviors_parse_spc_pgid, "Parse S/P/C", m_frame->behaviors.parse_spc);
+	APPENDBOOLPROP(behaviors_nosplashscreen_pgid, "No splash screen", m_frame->behaviors.nosplashscreen);
+	APPENDBOOLPROP(behaviors_confirmquit_pgid, "Confirm quit", m_frame->behaviors.confirmquit);
+	
+	wxFlexGridSizer *sizer = new wxFlexGridSizer(2, 1, 0, 0);
+	sizer->AddGrowableCol(0);
+	sizer->AddGrowableRow(0);
+	sizer->Add(propgrid, 1, wxEXPAND);
+
+	wxBoxSizer *bsizer = new wxBoxSizer(wxHORIZONTAL);
+	wxButton *abutton = new wxButton(this, wxID_ANY, "Apply");
+	abutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ASSDrawSettingsDialog::OnSettingsApplyButtonClicked), NULL, this);
+	bsizer->Add(abutton, 2, wxEXPAND);
+	wxButton *rbutton = new wxButton(this, wxID_ANY, "Revert");
+	rbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ASSDrawSettingsDialog::OnSettingsRevertButtonClicked), NULL, this);
+	bsizer->Add(rbutton, 1, wxEXPAND);
+	bsizer->Layout();
+
+	sizer->Add(bsizer, 1, wxEXPAND);
+	sizer->Layout();
+	SetSizer(sizer);
+}
+
+ASSDrawSettingsDialog::~ASSDrawSettingsDialog()
+{
+	if (propgrid) propgrid->Clear();
+}
+
+void ASSDrawSettingsDialog::OnSettingsApplyButtonClicked(wxCommandEvent &event)
+{
+
+	wxButton *button = (wxButton *) event.GetEventObject();
+	//wxPropertyGrid *propgrid = (wxPropertyGrid *) button->GetClientData();
+	if (propgrid == NULL) return;
+
+	#define PARSECOLOR(color, pgid) \
+	{ \
+		wxVariant variant = propgrid->GetPropertyValue(pgid); \
+		color = *wxGetVariantCast(variant,wxColour); \
+	}
+
+	#define PARSE(ptr, pgid) propgrid->GetPropertyValue(pgid).Convert(ptr);
+
+	PARSECOLOR(m_frame->colors.canvas_bg, colors_canvas_bg_pgid)
+	PARSECOLOR(m_frame->colors.canvas_shape_controlpoint, colors_canvas_shape_controlpoint_pgid)
+	PARSECOLOR(m_frame->colors.canvas_shape_guideline, colors_canvas_shape_guideline_pgid)
+	PARSECOLOR(m_frame->colors.canvas_shape_mainpoint, colors_canvas_shape_mainpoint_pgid)
+	PARSECOLOR(m_frame->colors.canvas_shape_normal, colors_canvas_shape_normal_pgid)
+	PARSECOLOR(m_frame->colors.canvas_shape_outline, colors_canvas_shape_outline_pgid)
+	PARSECOLOR(m_frame->colors.canvas_shape_preview, colors_canvas_shape_preview_pgid)
+	PARSECOLOR(m_frame->colors.canvas_shape_selectpoint, colors_canvas_shape_selectpoint_pgid)
+	PARSECOLOR(m_frame->colors.library_libarea, colors_library_libarea_pgid)
+	PARSECOLOR(m_frame->colors.library_shape, colors_library_shape_pgid)
+	PARSECOLOR(m_frame->colors.origin, colors_origin_pgid)
+	PARSECOLOR(m_frame->colors.ruler_h, colors_ruler_h_pgid)
+	PARSECOLOR(m_frame->colors.ruler_v, colors_ruler_v_pgid)
+	
+	PARSE(&m_frame->alphas.canvas_shape_controlpoint, alphas_canvas_shape_controlpoint_pgid)
+	PARSE(&m_frame->alphas.canvas_shape_guideline, alphas_canvas_shape_guideline_pgid)
+	PARSE(&m_frame->alphas.canvas_shape_mainpoint, alphas_canvas_shape_mainpoint_pgid)
+	PARSE(&m_frame->alphas.canvas_shape_normal, alphas_canvas_shape_normal_pgid)
+	PARSE(&m_frame->alphas.canvas_shape_outline, alphas_canvas_shape_outline_pgid)
+	PARSE(&m_frame->alphas.canvas_shape_preview, alphas_canvas_shape_preview_pgid)
+	PARSE(&m_frame->alphas.canvas_shape_selectpoint, alphas_canvas_shape_selectpoint_pgid)
+
+	PARSE(&m_frame->sizes.origincross, sizes_origincross_pgid)
+
+	PARSE(&m_frame->behaviors.autoaskimgopac, behaviors_autoaskimgopac_pgid)
+	PARSE(&m_frame->behaviors.capitalizecmds, behaviors_capitalizecmds_pgid)
+	PARSE(&m_frame->behaviors.parse_spc, behaviors_parse_spc_pgid)
+	PARSE(&m_frame->behaviors.nosplashscreen, behaviors_nosplashscreen_pgid)
+	PARSE(&m_frame->behaviors.confirmquit, behaviors_confirmquit_pgid)
+
+	wxCommandEvent evento( wxEVT_SETTINGS_CHANGED, event.GetId() );
+    evento.SetEventObject( button );
+    m_frame->GetEventHandler()->ProcessEvent( evento );
+	
+}
+
+void ASSDrawSettingsDialog::OnSettingsRevertButtonClicked(wxCommandEvent &event)
+{
+	RefreshSettingsDisplay();
+}
+
+void ASSDrawSettingsDialog::RefreshSettingsDisplay()
+{
+	if (propgrid == NULL) return;
+	 
+	#define UPDATESETTING(value, pgid) propgrid->SetPropertyValue(pgid, value);
+
+	UPDATESETTING(m_frame->colors.canvas_bg, colors_canvas_bg_pgid)
+	UPDATESETTING(m_frame->colors.canvas_shape_controlpoint, colors_canvas_shape_controlpoint_pgid)
+	UPDATESETTING(m_frame->colors.canvas_shape_guideline, colors_canvas_shape_guideline_pgid)
+	UPDATESETTING(m_frame->colors.canvas_shape_mainpoint, colors_canvas_shape_mainpoint_pgid)
+	UPDATESETTING(m_frame->colors.canvas_shape_normal, colors_canvas_shape_normal_pgid)
+	UPDATESETTING(m_frame->colors.canvas_shape_outline, colors_canvas_shape_outline_pgid)
+	UPDATESETTING(m_frame->colors.canvas_shape_preview, colors_canvas_shape_preview_pgid)
+	UPDATESETTING(m_frame->colors.canvas_shape_selectpoint, colors_canvas_shape_selectpoint_pgid)
+	UPDATESETTING(m_frame->colors.library_libarea, colors_library_libarea_pgid)
+	UPDATESETTING(m_frame->colors.library_shape, colors_library_shape_pgid)
+	UPDATESETTING(m_frame->colors.origin, colors_origin_pgid)
+	UPDATESETTING(m_frame->colors.ruler_h, colors_ruler_h_pgid)
+	UPDATESETTING(m_frame->colors.ruler_v, colors_ruler_v_pgid)
+
+	UPDATESETTING(m_frame->alphas.canvas_shape_controlpoint, alphas_canvas_shape_controlpoint_pgid)
+	UPDATESETTING(m_frame->alphas.canvas_shape_guideline, alphas_canvas_shape_guideline_pgid)
+	UPDATESETTING(m_frame->alphas.canvas_shape_mainpoint, alphas_canvas_shape_mainpoint_pgid)
+	UPDATESETTING(m_frame->alphas.canvas_shape_normal, alphas_canvas_shape_normal_pgid)
+	UPDATESETTING(m_frame->alphas.canvas_shape_outline, alphas_canvas_shape_outline_pgid)
+	UPDATESETTING(m_frame->alphas.canvas_shape_preview, alphas_canvas_shape_preview_pgid)
+	UPDATESETTING(m_frame->alphas.canvas_shape_selectpoint, alphas_canvas_shape_selectpoint_pgid)
+
+	UPDATESETTING(m_frame->sizes.origincross, sizes_origincross_pgid)
+
+	UPDATESETTING(m_frame->behaviors.capitalizecmds, behaviors_capitalizecmds_pgid)
+	UPDATESETTING(m_frame->behaviors.autoaskimgopac, behaviors_autoaskimgopac_pgid)
+	UPDATESETTING(m_frame->behaviors.parse_spc, behaviors_parse_spc_pgid)
+	UPDATESETTING(m_frame->behaviors.nosplashscreen, behaviors_nosplashscreen_pgid)
+	UPDATESETTING(m_frame->behaviors.confirmquit, behaviors_confirmquit_pgid)
+
+}
diff --git a/assdraw/src/settings.hpp b/assdraw/src/settings.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c11c42c369febe0398fbf8fdcb023cefcd371045
--- /dev/null
+++ b/assdraw/src/settings.hpp
@@ -0,0 +1,119 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "_common.hpp"
+#include <wx/propgrid/propgrid.h>
+#include <wx/propgrid/advprops.h>
+
+class ASSDrawFrame;
+
+DECLARE_EVENT_TYPE(wxEVT_SETTINGS_CHANGED, -1)
+
+class ASSDrawSettingsDialog : public wxPanel
+{
+public:
+
+	ASSDrawFrame* m_frame;
+
+	ASSDrawSettingsDialog( wxWindow *parent, ASSDrawFrame *frame, int id = wxID_ANY );
+	virtual ~ASSDrawSettingsDialog();
+
+	virtual void Init();
+	virtual void OnSettingsApplyButtonClicked(wxCommandEvent &event);
+	virtual void OnSettingsRevertButtonClicked(wxCommandEvent &event);
+	virtual void RefreshSettingsDisplay();
+
+	wxPGId colors_canvas_bg_pgid;
+	wxPGId colors_canvas_shape_normal_pgid;
+	wxPGId colors_canvas_shape_preview_pgid;
+	wxPGId colors_canvas_shape_outline_pgid;
+	wxPGId colors_canvas_shape_guideline_pgid;
+	wxPGId colors_canvas_shape_mainpoint_pgid;
+	wxPGId colors_canvas_shape_controlpoint_pgid;
+	wxPGId colors_canvas_shape_selectpoint_pgid;
+	wxPGId colors_library_shape_pgid;
+	wxPGId colors_library_libarea_pgid;
+	wxPGId colors_origin_pgid;
+	wxPGId colors_ruler_h_pgid;
+	wxPGId colors_ruler_v_pgid;
+	wxPGId alphas_canvas_shape_normal_pgid;
+	wxPGId alphas_canvas_shape_preview_pgid;
+	wxPGId alphas_canvas_shape_outline_pgid;
+	wxPGId alphas_canvas_shape_guideline_pgid;
+	wxPGId alphas_canvas_shape_mainpoint_pgid;
+	wxPGId alphas_canvas_shape_controlpoint_pgid;
+	wxPGId alphas_canvas_shape_selectpoint_pgid;
+	wxPGId sizes_origincross_pgid;
+	wxPGId behaviors_capitalizecmds_pgid;
+	wxPGId behaviors_autoaskimgopac_pgid;
+	wxPGId behaviors_parse_spc_pgid;
+	wxPGId behaviors_nosplashscreen_pgid;
+	wxPGId behaviors_confirmquit_pgid;
+
+	wxPropertyGrid *propgrid;
+	//DECLARE_EVENT_TABLE()
+
+};
+
+class wxLongPropertyValidator : public wxValidator
+{
+public:
+
+    wxLongPropertyValidator( const int min, const int max )
+        : wxValidator()
+    {
+		m_min = min, m_max = max;
+    }
+
+    virtual wxObject* Clone() const
+    {
+        return new wxLongPropertyValidator( m_min, m_max );
+    }
+
+    virtual bool Validate(wxWindow* WXUNUSED(parent))
+	{
+	    wxTextCtrl* tc = wxDynamicCast(GetWindow(), wxTextCtrl);
+	    wxCHECK_MSG(tc, true, wxT("validator window must be wxTextCtrl"));
+
+	    wxString val = tc->GetValue();
+
+		long valint = 0;
+		val.ToLong(&valint);
+
+		if (valint < m_min) valint = m_min;
+		if (valint > m_max) valint = m_max;
+
+		tc->SetValue(wxString::Format(_T("%d"), valint));
+
+	    return true;
+	}
+
+private:
+    int m_min, m_max;
+};
diff --git a/assdraw/src/tsukasa.ico b/assdraw/src/tsukasa.ico
new file mode 100644
index 0000000000000000000000000000000000000000..f645f0773c987c58343e8a4b1d722ad64f900f5d
Binary files /dev/null and b/assdraw/src/tsukasa.ico differ
diff --git a/assdraw/src/wxAGG/AGGWindow.cpp b/assdraw/src/wxAGG/AGGWindow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..024124ece19b2462bb6d697441ee75d6737e75e4
--- /dev/null
+++ b/assdraw/src/wxAGG/AGGWindow.cpp
@@ -0,0 +1,124 @@
+#include "AGGWindow.h"
+
+#include "agg_rendering_buffer.h"
+#include "agg_pixfmt_rgb.h"
+
+namespace GUI {
+    
+    BEGIN_EVENT_TABLE(AGGWindow, wxWindow)
+        EVT_PAINT(AGGWindow::onPaint)
+        EVT_SIZE(AGGWindow::onSize)
+        EVT_ERASE_BACKGROUND(AGGWindow::onEraseBackground)
+    END_EVENT_TABLE()
+    
+    AGGWindow::AGGWindow(wxWindow* parent, wxWindowID id, 
+                       const wxPoint& pos, const wxSize& size, long style):
+        wxWindow(parent, id, pos, size, style, wxT("AGGWindow")),
+        bitmap(NULL) {
+    }
+    
+    void AGGWindow::init(const int width, const int height) {
+        memDC.SelectObject(wxNullBitmap);
+        delete bitmap;  
+        
+        int ncheight = height, ncwidth = width;
+        if (ncwidth < 1) ncwidth = 1;
+        if (ncheight < 1) ncheight = 1;
+  
+        bitmap = new wxBitmap(ncwidth, ncheight, PixelFormat::wxWidgetsType::BitsPerPixel);
+        memDC.SelectObject(*bitmap);
+
+        // Draw the bitmap
+        attachAndDraw();
+        
+        // Request a full redraw of the window
+        Refresh(false);
+    }
+    
+    AGGWindow::~AGGWindow() {
+        memDC.SelectObject(wxNullBitmap);
+        delete bitmap;
+    }
+
+    void AGGWindow::attachAndDraw() {
+        // Get raw access to the wxWidgets bitmap -- this locks the pixels and 
+        // unlocks on destruction.
+        PixelData data(*bitmap);
+        assert(data);
+
+#if 1
+        // This cast looks like it is ignoring byte-ordering, but the 
+        // pixel format already explicitly handles that.
+        assert(data.GetPixels().IsOk());
+        wxAlphaPixelFormat::ChannelType* pd = (wxAlphaPixelFormat::ChannelType*) &data.GetPixels().Data();
+
+        // wxWidgets always returns a pointer to the first row of pixels, whether
+        // that is stored at the beginning of the buffer (stride > 0) or at the 
+        // end of the buffer (stride < 0).  AGG always wants a pointer to the 
+        // beginning of the buffer, no matter what the stride.  (AGG does handle
+        // negative strides correctly.)
+        // Upshot: if the stride is negative, rewind the pointer from the end of 
+        // the buffer to the beginning. 
+        const int stride = data.GetRowStride();
+        if (stride < 0) 
+            pd += (data.GetHeight() - 1) * stride;
+
+        rBuf.attach(pd, data.GetWidth(), data.GetHeight(), stride);
+
+        // Call the user code to actually draw.
+        draw();
+#else
+        PixelData::Iterator p(data);
+
+        // we draw a (10, 10)-(20, 20) rect manually using the given r, g, b
+        p.Offset(data, 10, 10);
+
+        for ( int y = 0; y < 10; ++y )
+        {
+            PixelData::Iterator rowStart = p;
+
+            for ( int x = 0; x < 10; ++x, ++p )
+            {
+                p.Red() = 255;
+                p.Green() = 0;
+                p.Blue() = 255;
+            }
+
+            p = rowStart;
+            p.OffsetY(data, 1);
+        }
+#endif
+    }
+    
+    void AGGWindow::onSize(wxSizeEvent& event) {
+        const wxSize size = GetClientSize();
+        if (bitmap && size.GetWidth() == bitmap->GetWidth() && size.GetHeight() == bitmap->GetHeight())
+            return;
+        
+        init(size.GetWidth(), size.GetHeight());
+    }
+    
+    void AGGWindow::onPaint(wxPaintEvent& event) {
+        wxPaintDC dc(this);
+
+        wxCoord width, height;
+        dc.GetSize(&width, &height);
+        if (!bitmap || bitmap->GetWidth() != width || bitmap->GetHeight() != height) 
+            init(width, height);
+        
+        // Iterate over regions needing repainting
+        wxRegionIterator regions(GetUpdateRegion());
+        wxRect rect;
+        while (regions) {
+            rect = regions.GetRect();
+            dc.Blit(rect.x, rect.y, rect.width, rect.height, &memDC, rect.x, rect.y);
+            ++regions;
+        }
+    }
+
+    void AGGWindow::onEraseBackground(wxEraseEvent& WXUNUSED(event)) {
+	    // Do nothing to "avoid flashing in MSW"  Grr.
+    }
+
+}
+
diff --git a/assdraw/src/wxAGG/AGGWindow.h b/assdraw/src/wxAGG/AGGWindow.h
new file mode 100644
index 0000000000000000000000000000000000000000..01039da39f2ef62e016e83fb80c1611c7f7c4862
--- /dev/null
+++ b/assdraw/src/wxAGG/AGGWindow.h
@@ -0,0 +1,68 @@
+#ifndef WX_AGG_WINDOW_H
+#define WX_AGG_WINDOW_H
+
+#include "PixelFormatConvertor.h"
+
+#include <wx/bitmap.h>
+#include <wx/rawbmp.h>
+#include <wx/window.h>
+#include <wx/dcmemory.h>
+
+#include "agg_rendering_buffer.h"
+
+namespace GUI {
+    
+    /// A simple widget that displays a bitmap that AGG can draw on.
+    /// It reallocates the bitmap so that it always is the current size of the 
+    /// entire panel and calls the virtual method draw() to draw to the bitmap.
+    /// This should be useable anywhere a wxWindow can be, e.g. in actual windows, 
+    /// buttons, etc.
+    class AGGWindow: public wxWindow {
+        public:
+        /// Create an AGGWindow.  Defaults are taken from wxWindow::wxWindow(), see 
+        /// that documentation for more information.
+        AGGWindow(wxWindow* parent, wxWindowID id = wxID_ANY, 
+                  const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, 
+                  long style = wxTAB_TRAVERSAL);
+        
+        /// Clean up resources held
+        virtual ~AGGWindow();
+        
+        protected:
+           
+        /// The conversion between wxWidgets' pixel format and AGG's pixel format
+        typedef PixelFormatConvertor<wxNativePixelFormat> PixelFormat;
+
+        /// The wxWidgets "pixel data" type, an accessor to the raw pixels
+        typedef wxPixelData<wxBitmap, PixelFormat::wxWidgetsType> PixelData;
+
+        
+        /// Create the bitmap given the current size.
+        void init(const int width, const int height);
+
+        /// Attach the AGG rendering buffer to the bitmap and call the user draw() code.
+        void attachAndDraw();
+    
+        /// Paint the bitmap onto the panel.
+        void onPaint(wxPaintEvent& event);
+        
+        /// Resize the bitmap to match the window.
+        void onSize(wxSizeEvent& event);
+
+        /// Handle the erase-background event.
+        void onEraseBackground(wxEraseEvent& event);
+        
+        /// Draw into the bitmap using AGG.
+        virtual void draw() = 0;
+
+        
+        wxBitmap* bitmap;               ///< wxWidgets bitmap for AGG to draw into
+        wxMemoryDC memDC;               ///< Memory "device context" for drawing the bitmap
+        
+        agg::rendering_buffer rBuf;     ///< AGG's rendering buffer, pointing into the bitmap
+    
+        DECLARE_EVENT_TABLE()           /// Allocate wxWidgets storage for event handlers
+    };
+}
+    
+#endif
diff --git a/assdraw/src/wxAGG/PixelFormatConvertor.h b/assdraw/src/wxAGG/PixelFormatConvertor.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1b0741c4235fa71dd8c23674e2df381e81f886d
--- /dev/null
+++ b/assdraw/src/wxAGG/PixelFormatConvertor.h
@@ -0,0 +1,117 @@
+/*
+* Copyright (c) 2007, ai-chan
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the ASSDraw3 Team nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY AI-CHAN ``AS IS'' AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL AI-CHAN BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WX_AGG_PIXEL_FORMAT_CONVERTOR_H
+#define WX_AGG_PIXEL_FORMAT_CONVERTOR_H
+
+#include "agg_pixfmt_rgb.h"
+#include "agg_pixfmt_rgba.h"
+
+namespace {
+
+    /// Given a particular combination of channel type, bits per pixel and 
+    /// channel indices, return the AGG format that matches.
+    /// The actual template specializations that follow give the actual types, 
+    /// and using a combination of parameters that are not listed will give 
+    /// a compile-time error.
+    template <typename Channel, int bitsPerPixel, int r, int g, int b, int a> 
+    struct wxWidgetsToAGGHelper {
+        //empty
+    };
+
+    /// 24-bit RGB 
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 24, 0, 1, 2, -1> {
+        typedef agg::pixfmt_rgb24 format;
+    };
+
+    /// 24-bit BGR
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 24, 2, 1, 0, -1> {
+        typedef agg::pixfmt_bgr24 format;
+    };
+
+    /// 32-bit RGB, alpha unused but stored as ARGB. 
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 1, 2, 3, -1> {
+        typedef agg::pixfmt_argb32 format;
+    };
+
+    /// 32-bit RGB, alpha unused but stored as RGBA.
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 0, 1, 2, -1> {
+        typedef agg::pixfmt_rgba32 format;
+    };
+
+    /// 32-bit BGR, alpha unused but stored as ABGR. 
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 3, 2, 1, -1> {
+        typedef agg::pixfmt_abgr32 format;
+    };
+
+    /// 32-bit BGR, alpha unused but stored as BGRA.
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 2, 1, 0, -1> {
+        typedef agg::pixfmt_bgra32 format;
+    };
+
+    /// 32-bit RGBA
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 0, 1, 2, 3> {
+        typedef agg::pixfmt_rgba32 format;
+    };
+
+    /// 32-bit BGRA
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 2, 1, 0, 3> {
+        typedef agg::pixfmt_bgra32 format;
+    };
+
+    /// 32-bit ARGB
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 1, 2, 3, 0> {
+        typedef agg::pixfmt_argb32 format;
+    };
+
+    /// 32-bit ABGR
+    template <> struct wxWidgetsToAGGHelper<unsigned char, 32, 3, 2, 1, 0> {
+        typedef agg::pixfmt_abgr32 format;
+    };
+}
+
+namespace GUI {
+    /// Convert between a wxWidgets pixel format class and an AGG pixel format class.
+    /// Usage examples: 
+    /// PixelFormatConvertor<wxNativePixelFormat>::AGGType or 
+    /// PixelFormatConvertor<wxAlphaPixelFormat>::AGGType.
+    template <typename wxWidgetsPixelFormat>
+    class PixelFormatConvertor {
+    public:
+        typedef wxWidgetsPixelFormat wxWidgetsType;
+
+        // Break out the wxWidgets parameters and feed to the helper class.
+        typedef typename wxWidgetsToAGGHelper<typename wxWidgetsPixelFormat::ChannelType, 
+                                              wxWidgetsPixelFormat::BitsPerPixel,
+                                              wxWidgetsPixelFormat::RED,
+                                              wxWidgetsPixelFormat::GREEN,
+                                              wxWidgetsPixelFormat::BLUE,
+                                              wxWidgetsPixelFormat::ALPHA>::format AGGType;
+    };
+}
+
+#endif