What do you guys think about switching to a more OOP code base? Here's an unfinished example
Code: Select all
#SingleInstance, Off
#NoEnv
SetBatchLines, -1
Menu, Tray, Icon, %A_AhkPath%, 2
FileEncoding, UTF-8
MyTester := new CodeQuickTester()
return
class CodeQuickTester
{
static Msftedit := DllCall("LoadLibrary", "Str", "Msftedit.dll")
__New()
{
this.DefaultPath := "C:\Windows\ShellNew\Template.ahk"
this.DefaultName := "GeekDude"
this.DefaultDesc := ""
this.FGColor := 0xCDEDED
this.BGColor := 0x3F3F3F
this.TabSize := 4
this.Indent := "`t"
this.TypeFace := "Consolas"
this.Font := "s9 wBold"
this.Title := "CodeQuickTester"
this.Shell := ComObjCreate("WScript.Shell")
; TODO: This makes the class never get garbage collected. Oops!
Buttons := new this.MenuButtons(this)
Menu :=
( Join
[
["&File", [
["&Save`tCtrl+S", Buttons.Save.Bind(Buttons)],
["&Open`tCtrl+O", Buttons.Open.Bind(Buttons)],
["&Fetch", Buttons.Fetch.Bind(Buttons)]
]], ["&Tools", [
["&Paste`tCtrl+P", Buttons.Paste.Bind(Buttons)],
["Re&indent", Buttons.Indent.Bind(Buttons)],
["Install", Buttons.Install.Bind(Buttons)],
["&Help`tF1", Buttons.Help.Bind(Buttons)]
]]
]
)
Gui, New, +Resize +hWndhMainWindow
this.hMainWindow := hMainWindow
Gui, Menu, % this.CreateMenuBar(Menu)
Gui, Margin, 5, 5
Gui, Font, % this.Font, % this.TypeFace
this.InitRichEdit()
Gui, Font, s8 w400 q0, Microsoft Sans Serif
Gui, Add, Button, hWndhRunButton, &Run
RunFunc := this.RunButton.Bind(this) ; TODO: This makes the class never get garbage collected. Oops!
GuiControl, +g, %hRunButton%, %RunFunc%
this.hRunButton := hRunButton
Gui, Add, StatusBar
SB_SetParts(70, 70, 70)
WinEvents.Register(this.hMainWindow, new this.Events(this))
Gui, Show, w640 h480, % this.Title
}
InitRichEdit()
{
Gui, Add, Custom, ClassRichEdit50W hWndhWnd +0x5031b1c4 +E0x20000
this.hCodeEditor := hWnd
; Set background color
SendMessage, 0x443, 0, this.BGColor,, ahk_id %hWnd% ; EM_SETBKGNDCOLOR
; Set FG color
VarSetCapacity(CharFormat, 116, 0)
NumPut(116, CharFormat, 0, "UInt") ; cbSize := sizeOf(CHARFORMAT2)
NumPut(0x40000000, CharFormat, 4, "UInt") ; dwMask := CFM_COLOR
NumPut(this.FGColor, CharFormat, 20, "UInt") ; crTextColor := 0xBBGGRR
SendMessage, 0x444, 0, &CharFormat,, ahk_id %hWnd% ; EM_SETCHARFORMAT
; Set tab size to 4
VarSetCapacity(TabStops, 4, 0), NumPut(this.TabSize*4, TabStops, "UInt")
SendMessage, 0x0CB, 1, &TabStops,, ahk_id %hWnd% ; EM_SETTABSTOPS
; Change text limit from 32,767 to max
SendMessage, 0x435, 0, -1,, ahk_id %hWnd% ; EM_EXLIMITTEXT
; Disable inconsistent formatting
SendMessage, 0x4CC, 1, 1,, ahk_id %hWnd% ; EM_SETEDITSTYLE SES_EMULATESYSEDIT
}
CreateMenuBar(Menu)
{
static MenuName := 0
MyMenuName := "CQT_" MenuName, MenuName++
for each, Item in Menu
{
Ref := Item[2]
if IsObject(Ref) && Ref._NewEnum()
Ref := ":" this.CreateMenuBar(Ref)
Menu, %MyMenuName%, Add, % Item[1], %Ref%
}
return MyMenuName
}
RunButton()
{
if (this.Exec.Status == 0) ; Running
this.Exec.Terminate() ; CheckIfRunning updates the GUI
else ; Not running or doesn't exist
{
GuiControlGet, CodeEditor,, % this.hCodeEditor
; GuiControlGet, Params, Params:
this.Exec := ExecScript(CodeEditor, "", DeHashBang(CodeEditor)) ; TODO: Implement Params
GuiControl,, % this.hRunButton, &Kill
BoundFunc := this.CheckIfRunning.Bind(this, Context := {})
Context.BoundFunc := BoundFunc
SetTimer, %BoundFunc%, 100
}
}
CheckIfRunning(Context)
{
if (this.Exec.Status == 1)
{
BoundFunc := Context.BoundFunc
SetTimer, %BoundFunc%, Delete
GuiControl,, % this.hRunButton, &Run ; TODO: Make sure I don't have to specify default gui
}
}
class MenuButtons
{
__New(Parent)
{
this.Parent := Parent
}
Save()
{
Gui, +OwnDialogs
FileSelectFile, FilePath, S2
if ErrorLevel
return
GuiControlGet, CodeEditor,, % this.Parent.hCodeEditor
; TODO: Confirm before overwrite
FileOpen(FilePath, "w").Write(CodeEditor)
}
Open()
{
; TODO
}
Fetch()
{
; TODO
}
Paste()
{
; TODO
}
Indent()
{
; TODO
}
Help()
{
Run, %A_AhkPath%\..\AutoHotkey.chm
}
Install()
{
; TODO
}
}
class Events
{
__New(Parent)
{
this.Parent := Parent
}
Size()
{
ToolTip, hi
GuiControl, Move, % this.Parent.hCodeEditor, % "x" 5 "y" 5 "w" A_GuiWidth-10 "h" A_GuiHeight-60
ButtonWidth := (A_GuiWidth-10)
GuiControl, Move, % this.Parent.hRunButton, % "x" 5 "y" A_GuiHeight-50 "w" ButtonWidth "h" 22
}
Close()
{
; TODO: Allow multiple instances?
ExitApp
}
}
}
; TODO: Decide if I should keep a separate class for
; event dispatching or if I should handle it all inline.
class WinEvents ; static class
{
static Table := {}
Register(hWnd, Class)
{
Gui, +LabelWinEvents.
this.Table[hWnd] := Class
}
Unregister(hWnd)
{
this.Table.Delete(hWnd)
}
Dispatch(hWnd, Type)
{
Class := this.Table[hWnd]
; TODO: Decide if it should use a prefix for the method name
Class[Type].Call(Class)
}
; These *CANNOT* be added dynamically or handled dynamically via __Call
Close()
{
WinEvents.Dispatch(this, "Close")
}
Escape()
{
WinEvents.Dispatch(this, "Escape")
}
Size()
{
WinEvents.Dispatch(this, "Size")
}
ContextMenu()
{
WinEvents.Dispatch(this, "ContextMenu")
}
DropFiles()
{
WinEvents.Dispatch(this, "DropFiles")
}
}
; Modified from https://github.com/cocobelgica/AutoHotkey-Util/blob/master/ExecScript.ahk
ExecScript(Script, Params="", AhkPath="")
{
Name := "AHK_CQT_" A_TickCount
Pipe := []
Loop, 2
{
Pipe[A_Index] := DllCall("CreateNamedPipe"
, "Str", "\\.\pipe\" name
, "UInt", 2, "UInt", 0
, "UInt", 255, "UInt", 0
, "UInt", 0, "UPtr", 0
, "UPtr", 0, "UPtr")
}
if !FileExist(AhkPath)
AhkPath := A_AhkPath
Call = "%AhkPath%" /CP65001 "\\.\pipe\%Name%"
Shell := ComObjCreate("WScript.Shell")
Exec := Shell.Exec(Call " " Params)
DllCall("ConnectNamedPipe", "UPtr", Pipe[1], "UPtr", 0)
DllCall("CloseHandle", "UPtr", Pipe[1])
DllCall("ConnectNamedPipe", "UPtr", Pipe[2], "UPtr", 0)
FileOpen(Pipe[2], "h", "UTF-8").Write(Script)
DllCall("CloseHandle", "UPtr", Pipe[2])
return Exec
}
DeHashBang(Script)
{
AhkPath := A_AhkPath
if RegExMatch(Script, "`a)^\s*`;#!\s*(.+)", Match)
{
AhkPath := Trim(Match1)
Vars := {"%A_ScriptDir%": A_WorkingDir
, "%A_WorkingDir%": A_WorkingDir
, "%A_AppData%": A_AppData
, "%A_AppDataCommon%": A_AppDataCommon
, "%A_LineFile%": A_ScriptFullPath
, "%A_AhkPath%": A_AhkPath
, "%A_AhkDir%": A_AhkPath "\.."}
for SearchText, Replacement in Vars
StringReplace, AhkPath, AhkPath, %SearchText%, %Replacement%, All
}
return AhkPath
}