This commit is contained in:
Jayvant Javier Pujara 2012-11-01 16:05:12 -04:00
commit 3bde7c3d5f
52 changed files with 6914 additions and 0 deletions

22
.gitattributes vendored Normal file
View File

@ -0,0 +1,22 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

166
.gitignore vendored Normal file
View File

@ -0,0 +1,166 @@
*.exe
*.org
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store

61
About.ahk Normal file
View File

@ -0,0 +1,61 @@
About:
; Cursor change for about box links:
; Load the cursor and start the hook:
hCurs:=DllCall("LoadCursor","UInt",NULL,"Int",32649,"UInt") ;IDC_HAND
OnMessage(0x200,"WM_MOUSEMOVE")
GuiChildInit("AboutBox")
ABw = 250
ABh = 150
ABx := CenterX(ABw)
ABy := CenterY(ABh)
DevEmail := "JJPujara@gmail.com"
SiteUrl := "http://www.reddit.com/r/LifeRPG/"
Gui, AboutBox:Add, Picture, w32 h-1, res/WP_RPG_VG.ico
Gui, AboutBox:Font, bold
Gui, AboutBox:Add, Text, x+10, LifeRPG r2
Gui, AboutBox:Font
Gui, AboutBox:Add, Text, y+1, by Jayvant Javier Pujara
Gui, AboutBox:Font, cBlue
Gui, AboutBox:Add, Text, y+1 gAboutLinkEmail vAboutLinkEmail, %DevEmail%
Gui, AboutBox:Font
Gui, AboutBox:Add, Text, xm y+10, For help and discussion,`nvisit the LifeRPG community on reddit:
Gui, AboutBox:Font, cBlue
Gui, AboutBox:Add, Text, y+1 gAboutLinkSite, %SiteUrl%
Gui, AboutBox:Font,
Gui, AboutBox:Add, Button, y+15 w80 Default gAboutBoxGuiClose, OK
Gui, AboutBox:Show, w%ABw% h%ABh% x%ABx% y%ABy%, About
return
AboutLinkEmail:
Run, mailto:%DevEmail%
return
AboutLinkSite:
Run, %SiteUrl%
return
AboutBoxGuiClose:
AboutBoxGuiEscape:
; Disable the hook and destroy the cursor:
OnMessage(0x200,"")
DllCall("DestroyCursor","Uint",hCurs)
GuiChildClose("AboutBox")
return
; Cursor hook:
WM_MOUSEMOVE(wParam,lParam)
{
Global hCurs, AboutLinkEmail
MouseGetPos,,,,ctrl
; Only change over certain controls, use Windows Spy to find them.
If ctrl in Static4,Static6
DllCall("SetCursor","UInt",hCurs)
Return
}

166
Data/.gitignore vendored Normal file
View File

@ -0,0 +1,166 @@
*.db
*.ini
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store

BIN
Electrolize-Regular.ttf Normal file

Binary file not shown.

117
FileManage.ahk Normal file
View File

@ -0,0 +1,117 @@
; Database Open/Select: =====================================================
FileOpen:
Gui, +OwnDialogs
FileSelectFile, NewDB, , data, Open a projects database, LifeRPG Database (*.db)
if (NewDB <> "")
{
if (IsObject(db))
{
OldDB := db
OldDB.Close()
}
; Set the db var to the new database:
db := DBA.DataBaseFactory.OpenDataBase("SQLite", NewDB)
; Check to see if database is old and needs to be updated:
if (ProfileGet("release") = "")
{
MsgBox Updating Database
; Add columns to projects table:
ProjectsNewCols := {"dateDone":"NUMERIC", "dateEntered":"NUMERIC", "skill":"TEXT", "levelDone":"NUMERIC"}
for col, type in ProjectsNewCols
{
db.Query("ALTER TABLE projects ADD " . col . " " . type)
}
; Create inventory table:
CreateInventory := "CREATE TABLE inventory ( id INTEGER PRIMARY KEY, item TEXT, description TEXT, value NUMERIC, date NUMERIC, category TEXT )"
db.Query(CreateInventory)
; Create finances table:
CreateFinances := "CREATE TABLE finances ( date NUMERIC, id INTEGER PRIMARY KEY, description TEXT, amount NUMERIC, category TEXT )"
db.Query(CreateFinances)
; Create profile table and fill in settings:
; points: 0
; threshold: 100
; name:
; momentum: 100
; MMTLastUpdate: Right now
; title:
; release: 2
CreateProfile := "CREATE TABLE profile ( setting TEXT, value TEXT )"
db.Query(CreateProfile)
ProfileSettings := {"points": 0, "threshold": 100, "name":"Edit Profile", "momentum": 100, "MMTLastUpdate": FormatTime(,"yyyyMMdd"), "title":"", "release":2}
for setting, value in ProfileSettings
{
ProfileRecord := {}
ProfileRecord.Setting := setting
ProfileRecord.value := value
db.Insert(ProfileRecord, "profile")
}
}
; Update GUI controls to display new database data (HUD and main projects ListView)
FileOpenGUI_Refresh()
}
return
FileNew:
Gui, +OwnDialogs
; Present dialog to set database file name
FileSelectFile, NewDB_Path, S24, New LifeRPG.db, New projects database, LifeRPG Database (*.db)
if (NewDB_Path <> "")
{
; Get the desired filename:
SplitPath, NewDB_Path, NewDB_Name, NewDB_Dir, NewDB_Ext
; Refresh everything needed to "load" database, set as default, add to recents menu
if (NewDB_Ext = "")
{
NewDB_Name .= ".db"
NewDB_Path .= ".db"
}
NewDB := NewDB_Path
if (IsObject(db))
{
OldDB := db
OldDB.Close()
}
if (FileExist(NewDB_Path))
FileDelete, %NewDB_Path%
; Copy blank database to selected location and rename to desired name:
FileCopy, Res\Blank.db, %NewDB_Path%
; Point the db var to the new database:
db := DBA.DataBaseFactory.OpenDataBase("SQLite", NewDB)
; Update GUI controls to display new database data (HUD and main projects ListView)
FileOpenGUI_Refresh()
}
return
FileOpenGUI_Refresh()
{
global
if (OldDB)
{
gosub ClearSearch
MomentumLastUpdate := ProfileGet("MMTLastUpdate")
HUD_Refresh()
}
SettingSet("File", "LastOpened", NewDB) ; Update settings file to point to new "current" database:
}
SettingSet(Section, Key, Value)
{
IniWrite, %Value%, data/Settings.ini, %Section%, %Key%
}
SettingGet(Section, Key)
{
IniRead, Setting, data/Settings.ini, %Section%, %Key%
return Setting
}

382
Functions.ahk Normal file
View File

@ -0,0 +1,382 @@
;~ ===============================================================================
;~ Useful Functions:
; Stops user from being able to resize the listView columns on the main window:
;~ OnMessage(0x4E,"WM_NOTIFY")
;~ WM_NOTIFY(wParam, lParam, msg, hwnd)
;~ { Critical
;~ Static HDN_BEGINTRACKA = -306, HDN_BEGINTRACKW = -326
;~ Code := -(~NumGet(lParam+0, 8))-1
;~ Return, Code = HDN_BEGINTRACKA || Code = HDN_BEGINTRACKW ? True : ""
;~ }
; Colored Listview rows and text
; OnMessage( WM_NOTIFY := 0x4E, "WM_NOTIFY" ) ; this line must be executed for the function to work
WM_NOTIFY( wparam, lparam, msg, hwnd ) {
Static psz, pty, lvitem, itext, offset_code, offset_row, offset_color, LVM_GETITEMTEXT
; Up to 4 istviews can be colored at a time. Remeber to forcibly redraw them if more than one is
; fully drawn at once.
Global Colored_LV_1, Colored_LV_2, Colored_LV_3, Colored_LV_4
, Colored_LV_1_BG, Colored_LV_2_BG, Colored_LV_3_BG, Colored_LV_4_BG
, Colored_LV_1_TX, Colored_LV_2_TX, Colored_LV_3_TX, Colored_LV_4_TX
Critical
If !( psz )
{
; Prep the static vars on first run, including LVITEM for getting the color values from the listview.
LVM_GETITEMTEXT := 0x1000 + ( A_IsUnicode ? 115 : 45 )
psz := A_PtrSize ? A_PtrSize : 4
pty := A_PtrSize = 8 ? "UPtr" : "UInt"
offset_code := 2 * psz
offset_row := 3 * psz + 24
offset_color := 5 * psz + 28
VarSetCapacity( lvitem, 52 + 2 * psz, 0 )
VarSetCapacity( itext, 250 << !! A_IsUnicode, 0 )
NumPut( 1, lvitem, 0, "UInt" )
NumPut( &itext, lvitem, 20, pty )
NumPut( 250, lvitem, 20 + psz, "UInt" )
}
; Get the HWND of the controls sending this notification and see if it's one of our listviews
ct_hwnd := NumGet( lparam + 0, 0, pty )
If ( ( ct_hwnd = Colored_LV_1 && which_lv := "1" ) || ( ct_hwnd = Colored_LV_2 && which_lv := "2" )
|| ( ct_hwnd = Colored_LV_3 && which_lv := "3" ) || ( ct_hwnd = Colored_LV_4 && which_lv := "4" ) )
&& ( -12 = NumGet( lparam + 0, offset_code, "Int" ) ) ; NM_CUSTOMDRAW = -12
If ( 1 = draw_stage := NumGet( lparam + 0, offset_code + 4, "Int" ) ) ; CDDS_PREPAINT = 1
Return 0x20 ; CDRF_NOTIFYITEMDRAW = 0x20
Else If ( draw_stage = 0x10001 ) ; CDDS_PREPAINT = 0x1, CDDS_ITEM = 0x10001
{
; Now we know the notification is for an item prepaint, so we can adjust the text and bg colors.
; The colors are kept in the listview itself
item := NumGet( lparam + 0, offset_row, "UInt" )
If ( 0 < 0 | Colored_LV_%which_lv%_TX )
{
NumPut( Colored_LV_%which_lv%_TX - 1, lvitem, 8, "UInt" )
SendMessage, LVM_GETITEMTEXT, item, &lvitem,, % "AHK_ID " ct_hwnd
VarSetCapacity( itext, -1 )
NumPut( Round( itext ), lparam + 0, offset_color, "UInt" )
}
If ( 0 < 0 | Colored_LV_%which_lv%_BG )
{
NumPut( Colored_LV_%which_lv%_BG - 1, lvitem, 8, "UInt" )
SendMessage, LVM_GETITEMTEXT, item, &lvitem,, % "AHK_ID " ct_hwnd
VarSetCapacity( itext, -1 )
NumPut( Round( itext ), lparam + 0, offset_color + 4, "UInt" )
}
}
; Else If ( draw_stage = 0x10002 ) ; CDDS_POSTPAINT = 0x2, CDDS_ITEM = 0x10001
; {
; ; Put here drawing to do after the item is drawn. E.g: draw custom grid lines.
; }
Static HDN_BEGINTRACKA = -306, HDN_BEGINTRACKW = -326
Code := -(~NumGet(lParam+0, 8))-1
Return, Code = HDN_BEGINTRACKA || Code = HDN_BEGINTRACKW ? True : ""
}
ProfileSet(setting, value)
{
global db
s := db.Query("UPDATE profile SET value = '" . SafeQuote(value) . "' WHERE setting = '" . setting . "'")
return s
}
FormatTime(Time="", Format="")
{
FormatTime, Out, %Time%, %Format%
return Out
}
ProfileGet(setting)
{
global db
ProfileSet := db.OpenRecordSet("SELECT value FROM profile WHERE setting = '" . setting . "'")
while (!ProfileSet.EOF)
{
Value := ProfileSet["value"]
ProfileSet.MoveNext()
}
ProfileSet.Close()
return Value
}
Uppercase(String)
{
StringUpper, String, String
return String
}
Capitalize(String)
{
StringUpper, String, String, T
return String
}
; Call to refresh skills list after adding a new skill:
RefreshSkillsList(SkillChosen="All")
{
global
if (SkillChosen = "All" || SkillChosen = "")
{
GuiControl, , FilterSkill, |All||None|
GuiControl, , FilterSkill, % ListSkills()
}
else if (SkillChosen = "None")
{
GuiControl, , FilterSkill, |All|None||
GuiControl, , FilterSkill, % ListSkills()
}
else
{
PickSkill := ListSkills()
if (InStr(PickSkill, SkillChosen))
{
GuiControl, , FilterSkill, |All|None|
StringReplace, PickedSkill, PickSkill, %SkillChosen%, %SkillChosen%|
GuiControl, , FilterSkill, % PickedSkill
}
else
{
GuiControl, , FilterSkill, |All||None|
GuiControl, , FilterSkill, % ListSkills()
}
}
GuiControlGet, FilterSkillSelected, , FilterSkill
}
ListSkills(Selected="")
{
global db
SkillList := Object()
Skills := db.OpenRecordSet("SELECT DISTINCT skill FROM projects ORDER BY skill")
while(!Skills.EOF)
{
Skill := Skills["skill"]
If (Skill <> "")
SkillList.Insert(Skill)
Skills.MoveNext()
}
Skills.Close()
SkillComboList =
For Num, Skill in SkillList
{
SkillComboList .= Skill . "|"
if (Selected and Skill = Selected)
SkillComboList .= "|"
}
return SkillComboList
}
ListDifficulties(SetDifficulty="")
{
global Difficulties
For k, diff in Difficulties
{
if (diff = SetDifficulty)
diff := diff . "|"
else if (k = 1)
diff := diff . "|"
DifficultyList .= diff . "|"
}
return DifficultyList
}
ListPriorities(SetPriority="")
{
global Priorities
For k, imp in Priorities
{
if (imp = SetPriority)
imp := imp . "|"
else if (k = 1 && SetPriority <> "All")
imp := imp . "|"
PriorityList .= imp . "|"
}
return PriorityList
}
UpdateList(NextSelection="", ImportanceSelected="All", Skill="All")
{
global
IDCol = 1
DifficultyCol = 2
ImportanceCol = 4
ParentCol = 5
Critical
Gui, 1:Default
GuiControlGet, SearchString, , SearchQuery
GuiControl, -ReDraw, MainList
LV_Delete()
Filter=
if (ImportanceSelected <> "" || FilterShowDone <> "" || Skill <> "" || SearchString <> "")
Filter .= "WHERE "
if (SearchString <> "")
Filter .= "project LIKE '%" SafeQuote(SearchString) "%' AND"
if (FilterShowDone <> 1)
Filter .= " difficulty <> 'Done' "
else if (FilterShowDone = 1)
Filter .= " difficulty = 'Done' "
if (ImportanceSelected <> "All")
Filter .= " AND importance = '" SafeQuote(ImportanceSelected) "' "
if (Skill = "None")
filter .= " AND skill = '' "
else if (Skill <> "All")
Filter .= " AND skill = '" SafeQuote(Skill) "' "
;Notification("","Select * from projects " . Filter)
Projects := db.OpenRecordSet("Select * from projects " . Filter)
while (!Projects.EOF)
{
ID := Projects["id"]
Difficulty := Projects["difficulty"]
Project := Projects["project"]
Parent := Projects["parent"]
Importance := Projects["importance"]
for k, v in Priorities
{
If (Importance = v)
Importance := k ". " v
}
If (Importance = "")
Importance := "None"
LV_Add("", ID,Difficulty,Project,Importance,Parent)
Projects.MoveNext()
}
Projects.Close()
GuiControl, -ReDraw, MainList
LV_ModifyCol(1, "Integer sortdesc") ; Enable this to sort by ID, which could show most recent or oldest first, depending.
LV_ModifyCol(ImportanceCol, "sort") ; First sort by importance
LV_ModifyCol(DifficultyCol, "sortdesc") ; Then sort by difficulty, descending. Just so happens my scheme sorts alright on its own, what luck.
If (NextSelection)
LV_Modify(NextSelection, "Focus Select Vis")
Times := LV_GetCount()
Loop % Times
{
ThisLine := A_Index
LV_GetText(Text, ThisLine, ImportanceCol)
for k, v in Priorities ; Remove those numbers added to the priorities to allow for proper sorting
{
P := k ". " v
if (Text = P)
{
LV_Modify(ThisLine,"Col" . ImportanceCol,v)
}
}
LV_GetText(ParentID, ThisLine, ParentCol)
GetParent := db.OpenRecordSet("SELECT project FROM projects WHERE id = " ParentID)
while (!GetParent.EOF)
{
ParentName := GetParent["project"]
GetParent.MoveNext()
}
GetParent.Close()
LV_Modify(ThisLine, "Col" . ParentCol,ParentName)
}
LV_ModifyCol()
Loop % LV_GetCount("Col")
LV_ModifyCol(A_Index,"AutoHdr")
LV_ModifyCol(IDCol, 0) ; Hide ID column
Loop % LV_GetCount()
{
RowNum := A_Index
LV_GetText(RowDiff, RowNum, 2)
for kDiff, vDiff in Difficulties
{
for kCol, vCol in Colors
{
if (RowDiff = vDiff)
{
if (kDiff = kCol)
LV_Modify(RowNum, "Col6", vCol)
}
else if (RowDiff = "Done")
LV_Modify(RowNum, "Col6", BGR("F5FFFA"))
}
}
}
OnMessage( WM_NOTIFY := 0x4E, "WM_NOTIFY" )
LV_ModifyCol(6, 0) ; Hide Color column
GuiControl, +ReDraw, MainList
return
}
GetParentName()
{
global
Times := LV_GetCount()
Loop % Times
{
ThisLine := A_Index
LV_GetText(ParentID, ThisLine, ParentCol)
GetParent := db.OpenRecordSet("SELECT project FROM projects WHERE id = " ParentID)
while (!GetParent.EOF)
{
ParentName := GetParent["project"]
GetParent.MoveNext()
}
GetParent.Close()
LV_Modify(ThisLine, "Col" . ParentCol,ParentName)
}
}
SafeQuote(string) ; Escape single quotes for sql update. Insert doesn't seem to need it because the DB library handles it.
{
StringReplace, string, string, ','', All
return string
}
CenterX(w)
{
global WindowFind
WinGetPos,Fx,Fy,Fw,Fh,A
return Fx + Round(Fw/2) - Round(w/2)
}
CenterY(h)
{
global WindowFind
WinGetPos,Fx,Fy,Fw,Fh,A
return Fy + Round(Fh/2) - Round(h/2)
}
GuiMsgBox(Name, Title, Text, w=170, h=60)
{
GuiChildInit(Name)
Gui, %Name%:Add, Text, w%w% Center, %Text%
Gui, %Name%:Add, Button, % "Default g" Name "Yes w40 x" Round((w-80)/2), &Yes
Gui, %Name%:Add, Button, Default x+1 g%Name%No w40, &No
MX := CenterX(w)
MY := CenterY(h)
Gui, %Name%:Show, w%w% h%h% x%mx% y%my%, %Title%
Gui, %Name%:-MinimizeBox -MaximizeBox
return
}
GuiChildInit(Child, Parent=1)
{
Gui, %Child%:New
Gui, %Child%:+Owner%Parent%
Gui, %Parent%:+Disabled
Gui, %Child%:Default
return
}
GuiChildClose(Child, Parent=1)
{
Gui, %Parent%:-Disabled
Gui, %Child%:Cancel
Gui, %Parent%:Default
return
}

343
HUD.ahk Normal file
View File

@ -0,0 +1,343 @@
;~ ===============================================================================
; HUD and functions:
HUD_Color = 15384E
HUD_Trans = 200
HUD_Color2 = 48B1DF
; Create a new independent Guis for the HUD
; Level Module:
LevelX = 80
LevelY = 45
LevelW = 450
LevelH = 80
Gui, HUD_Level:New
Gui, HUD_Level:+LastFound +AlwaysOnTop -Caption +ToolWindow
Gui, HUD_Level:Color, %HUD_Color%
;Gui, HUD_Level:Add, Picture, x0 y0 w400 h70 , Res\BG.png
Gui, HUD_Level:Font, S14 Q5 bold, Electrolize
Gui, HUD_Level:Add, Progress, vHUD_Progress x12 y12 w425 h18 cWhite Background48B1DF
NameSize = 260
Gui, HUD_Level:Add, Text, vHUD_Name x12 y+1 w%NameSize% r1 c%HUD_Color2% BackgroundTrans, % ProfileGet("name")
Gui, HUD_Level:Font, s10
PointsSize := 424 - NameSize
Gui, HUD_Level:Add, Text, vHUD_Points x+1 w%PointsSize% Right cWhite BackgroundTrans,
Gui, HUD_Level:Font, s14
Gui, HUD_Level:Add, Text, vHUD_Text x12 y+7 w425 cWhite BackgroundTrans ; Shows current level and temporarily shows new XP awards.
HUD_LevelText := "LEVEL "
HUD_LevelTitle :=
;Gui, HUD_Level:Color, 15384E
WinSet, Transparent, %HUD_Trans%
Winset, ExStyle, +0x20
Gui, HUD_Level:Show, x%LevelX% y%LevelY% w%LevelW% h%LevelH% NoActivate
Gui, HUD_Level:Hide
; Momentum Module:
Gui, HUD_Momentum:New
Gui, HUD_Momentum:+LastFound +AlwaysOnTop -Caption +ToolWindow
Gui, HUD_Momentum:Color, %HUD_Color%
Gui, HUD_Momentum:Font, S14 Q5 bold, Electrolize
Gui, HUD_Momentum:Add, Text, x9 y4 cWhite BackgroundTrans, MMT
MMTStart := ProfileGet("momentum")
Gui, HUD_Momentum:Add, Progress, vHUD_MomentumBar x+5 y8 w325 h13 cRed Background48B1DF, % MMTStart
Gui, HUD_Momentum:Add, Text, vHUD_MomentumPerc x388 y4 w59 cWhite BackgroundTrans Center, % MMTStart . "%"
WinSet, Transparent, %HUD_Trans%
Winset, ExStyle, +0x20
Gui, HUD_Momentum:Show, x80 y135 w450 h30 NoActivate
Gui, HUD_Momentum:Hide
HUD_Refresh()
{
global
; HUD Update:
; name
; level + title
; points/threshold
; momentum bar
; progress bar!
GuiControl, HUD_Level:, HUD_Progress, % ProgressGet()
GuiControl, HUD_Level:, HUD_Name, % ProfileGet("name")
GuiControl, HUD_Level:, HUD_Text, % HUD_LevelText . LevelCheck() . " " . ProfileGet("title")
GuiControl, HUD_Level:, HUD_Points, % PointsCheck() . "/" . ThreshCheck()
MMTNow := ProfileGet("momentum")
GuiControl, HUD_Momentum:, HUD_MomentumBar, % MMTNow
GuiControl, HUD_Momentum:, HUD_MomentumPerc, % MMTNow . "%"
}
HUD_MouseOverHide(ByRef hX, ByRef hY, ByRef hW, ByRef hH)
{
global HUD_Trans
SetTimer, Mouse, 100
Mouse:
CoordMode, Mouse, Screen
MouseGetPos, x, y
;ToolTip, %GuiX% (%GuiW% + %GuiX%) `n %x% %y%
; if the mouse (x) is located horizontally in a greater position than the hud's X starting position
; and less than that x position plus the HUD's width
; and vertically (y) greater than the HUD's y position
; and lower than that y pos plus the HUD's height
; then hide the HUD.
if (((x >= hX && x <= (hX+hW))) && ((y >= hY) && (y <= (165)))) ; 80-530; 45-125 ; hY+hH+
{
Gui, HUD_Level:+LastFound
WinSet, Transparent, 0
WinSet, ExStyle, +0x20
Gui, HUD_Momentum:+LastFound
WinSet, Transparent, 0
WinSet, ExStyle, +0x20
}
else
{
Gui, HUD_Level:+LastFound
WinSet, Transparent, %HUD_Trans%
WinSet, AlwaysOnTop, On
Gui, HUD_Momentum:+LastFound
WinSet, Transparent, %HUD_Trans%
WinSet, AlwaysOnTop, On
}
return
}
HUD_Progress(PreviousLevelPoints="toggle",PreviousLevel="")
{
global
split = 0
;SetTimer, DestProg, Off
SetTimer, ClearAwardText, off
SetTimer, HideAgain, off
static VisibState = 0
Gui, HUD_Level:Default
if (VisibState = 1) ; HUD is visible
{
if (PreviousLevelPoints = "toggle") ; toggle called, so hide HUD and return
{
Gui, HUD_Level:Hide
Gui, HUD_Momentum:Hide
VisibState = 0 ; HUD now hidden
}
else ; update progress bar and then clear award text from control after a few seconds.
{
HUD_Update(PreviousLevelPoints, PreviousLevel)
SetTimer, ClearAwardText, 2000
return
ClearAwardText:
Critical
Gui, HUD_Level:Default
GuiControl, , HUD_Text, % HUD_LevelText . LevelCheck() . " " . ProfileGet("title")
SetTimer, ClearAwardText, off
return
}
}
else if (VisibState = 0) ; HUD is not visible
{
if (PreviousLevelPoints = "toggle") ; toggle called, so show HUD
{
GuiControl,, HUD_Progress, % ProgressGet() ; Update progress bar
GuiControl,, HUD_Text, % HUD_LevelText . LevelCheck() . " " . ProfileGet("title")
GuiControl,, HUD_Points, % PointsCheck() . "/" . ThreshCheck()
Gui, HUD_Level:Show, x80 y45 NoActivate
WinSet, AlwaysOnTop, On
Gui, HUD_Momentum:Show, NoActivate
WinSet, AlwaysOnTop, On
HUD_MouseOverHide(LevelX, LevelY, LevelW, LevelH)
VisibState = 1 ; HUD now showing
}
else ; show HUD temporarily when points are awarded, update progress bar and text, and then hide again.
{
Gui, HUD_Level:Show, x80 y45 NoActivate
WinSet, AlwaysOnTop, On
Gui, HUD_Momentum:Show, NoActivate
WinSet, AlwaysOnTop, On
HUD_Update(PreviousLevelPoints, PreviousLevel)
SetTimer, HideAgain, 2500
return
HideAgain:
Critical
Gui, HUD_Level:Hide
Gui, HUD_Momentum:Hide
SetTimer, HideAgain, off
return
}
}
return
}
; Animate the progress bars and numbers and check for leveling up event:
HUD_Update(PreviousLevelPoints, PreviousLevel)
{
global
Gui, HUD_Level:Default ; Operate on the Level module
CurrentLevelPoints := ProgressGet()
if (PreviousLevelPoints < CurrentLevelPoints)
{
; slide up to sub100 value CurrentLevelPoints
GuiControl,, HUD_Progress, % PreviousLevelPoints
if (CurrentLevelPoints >= 100)
{
split = 1
CurrentLevelPoints = 100
}
else
split = 0
AnimationCount := CurrentLevelPoints - PreviousLevelPoints
AnimPoints := PointsCheck() - AnimationCount
Loop % AnimationCount
{
GuiControl,, HUD_Progress, % PreviousLevelPoints + A_Index
;GuiControl,, HUD_Text, % HUD_LevelText . PreviousLevel . " +" . A_Index . " XP"
GuiControl,, HUD_Text, % HUD_LevelText . PreviousLevel . " +" . A_Index . " XP " . ProfileGet("title")
GuiControl,, HUD_Points, % AnimPoints + A_Index . "/" . ThreshCheck()
Sleep 50
}
if (split = 1)
{
GuiControl,, HUD_Progress, 0
NewLevelPoints := ProgressGet() - 100
Loop % NewLevelPoints
{
GuiControl,, HUD_Progress, % A_Index
;GuiControl,, HUD_Text, % HUD_LevelText . LevelCheck() . " +" . A_Index
GuiControl,, HUD_Text, % HUD_LevelText . LevelCheck() . " +" . A_Index . " XP " . ProfileGet("title")
GuiControl,, HUD_Points, % (PointsCheck()-NewLevelPoints) + A_Index . "/" . ThreshCheck()
Sleep 50
}
}
}
LevelCheck()
}
HUD_Message(message, duration="2500")
{
;Gui, 2:Destroy
Gui, Message:New
; Example: On-screen display (OSD) via transparent window:
CustomColor = 9AFF9A ; Can be any RGB color (it will be made transparent below).
Gui Message:+LastFound +AlwaysOnTop -Caption +ToolWindow ; +ToolWindow avoids a taskbar button and an alt-tab menu item.
Gui, Message:Color, %CustomColor%
Gui, Message:Font, s25 Q5, Electrolize ; Set a large font size (32-point).
Gui, Message:Add, Text, Center cLime, %message% ; XX & YY serve to auto-size the window.
; Make all pixels of this color transparent and make the text itself translucent (150):
WinSet, TransColor, %CustomColor% 255
;VertPos := A_ScreenHeight - offset
Gui, Message:Show, x60 y99 NoActivate ; NoActivate avoids deactivating the currently active window.
;Sleep 2000
SetTimer, DestroyMsg, %duration%
return
DestroyMsg:
Gui, Message:Destroy
SetTimer, DestroyMsg, Off
return
}
PointsCheck()
{
; The current number of points I have
global db
PointsSet := db.OpenRecordSet("SELECT value FROM profile WHERE setting = 'points'")
while (!PointsSet.EOF)
{
Points := PointsSet["value"]
PointsSet.MoveNext()
}
PointsSet.Close()
return Points
}
; Could combine these two functions into one ^ \/, plus the writing ones:
ThreshCheck()
{
; The next upcoming point threshold to level up again
global db
ThresholdSet := db.OpenRecordSet("SELECT value FROM profile WHERE setting = 'threshold'")
while (!ThresholdSet.EOF)
{
Threshold := ThresholdSet["value"]
ThresholdSet.MoveNext()
}
ThresholdSet.Close()
return Threshold
}
PointsWrite(Points)
{
;global PointsFile
;IniWrite, %Points%, %PointsFile%, Data, Points ; Store certain number of awarded points in file
global db
bool := db.Query("UPDATE profile SET value = " . Points . " WHERE setting = 'points'")
return
}
ThreshWrite(Threshold)
{
;global PointsFile
;IniWrite, %Threshold%, %PointsFile%, Data, Threshold
global db
bool := db.Query("UPDATE profile SET value = " . Threshold . " WHERE setting = 'threshold'")
return
}
ProgressGet() {
CurrentProgress := 100 - (ThreshCheck() - PointsCheck()) ; How many points until next level up event
return CurrentProgress ; What shows up on progress bar
}
LevelCheck() {
global LevelUpSound
; Threshold starts at 100, i.e. you start at level 1
If (PointsCheck() >= ThreshCheck())
{
;Set next threshold
;Threshold should go up.
if (FileExist(LevelUpSound))
SoundPlay, %LevelUpSound%
ThreshWrite(ThreshCheck() + 100) ; Write new threshold
LevelNow := Floor(ThreshCheck()/100)
;HUD_Message("Level Up! Level " LevelNow, 5000) ; This *could* be a fancier notification than just a tray notification
Notification("LEVEL UP!", "You have reached Level " . LevelNow)
}
Return Floor(ThreshCheck()/100)
}
LevelGet()
{
return Floor(ThreshCheck()/100)
}
; Main function to call to award points:
UpdateProgress(Message, Award, Sound="") ; Call to give user some points and show a notification
{
PreviousLevelPoints := ProgressGet()
PreviousLevel := LevelCheck()
;SoundPlay, %Sound%
;HUD_Message(Message) HUD_message should be altered to be a fancy HUD message
Notification(Message, "+" . Award . " XP Awarded")
PointsWrite(PointsCheck() + Award)
HUD_Progress(PreviousLevelPoints, PreviousLevel)
return
}
Notification(Title, Message="", Duration=9)
{
Notify(Title, Message, Duration, "GC=15384E GR=0 GT=200 TS=14 TC=ffffff TF=Electrolize MS=14 MC=48B1DF MF=Electrolize BW=0 BR=0")
return
}

38
Help.ahk Normal file
View File

@ -0,0 +1,38 @@
; Help menu items:========================================================================
ReferenceHotkeys:
GuiChildInit("RefHkeys")
RHw = 300
RHh = 250
RHx := CenterX(RHw)
RHy := CenterY(RHh)
HKRefText =
(
To toggle the Heads-Up Display, press: Alt+F2
To quickly add a project to your list for later, from anywhere; when you're doing anything, press:
Ctrl+Alt+A
To quickly log a finished project without having to add it to the list first, press:
Ctrl+Alt+D
To quickly give yourself points, use the following:
5 Points: Ctrl+Shift+1
10 Points: Ctrl+Shift+2
25 Points: Ctrl+Shift+3
100 Points (Instantly go up a whole level!): Ctrl+Shift+4
)
Gui, RefHkeys:Add, Edit,% "ReadOnly w" RHw-20 " h" RHh-20, % HKRefText
Gui, RefHkeys:Show, w%RHw% h%RHh% x%RHx% y%RHy%, Reference
return
RefHKeysGuiEscape:
RefHKeysGuiClose:
GuiChildClose("RefHKeys")
return
Discussion:
Run http://www.reddit.com/r/LifeRPG
return

48
Hotkeys.ahk Normal file
View File

@ -0,0 +1,48 @@
;~ ===============================================================================
;~ Hotkeys:
;~ Pressing Alt+V focuses user on the ListView:
#If WinActive(WindowFind)
!x::
GuiControl, Focus, MainList
LV_Modify(1, "Select Focus")
return
;~ Enables Ctrl+Backspace deletion in edit fields:
#If WinActive("ahk_class AutoHotkeyGUI")
^BS::
send, ^+{left}{delete}
return
;~ Give yourself points manually:
#If ; Clear out context sensitivity
; Easy tasks
^+1::
UpdateProgress("Really Easy Achievement", 5, "increase.wav")
return
; Medium difficulty
^+2::
UpdateProgress("Pretty Easy Achievement", 10, "medium.wav")
return
; Heavy lifting
^+3::
UpdateProgress("Medium Achievement", 25, "hard.wav")
return
; Completed big project
^+4::
UpdateProgress("Hard Achievement", 100, "goal.wav")
return
!F2::
HUD_Progress()
return
;~ !F1::
;~ if (WinActive(WindowFind))
;~ WinMinimize, %WindowFind%
;~ else
;~ WinActivate, %WindowFind%
;~ return

389
LVCustomColors.ahk Normal file
View File

@ -0,0 +1,389 @@
LV_Initialize(Gui_Number="", Control="", Column="")
{
local hGUI, hLV
;Get either class or hWnd of control
If !Control ;Control omitted
{
If (Gui_Number > 99)
hLV := Gui_Number
Else ;No hWnd => default
Control = SysListView321
}
Else If RegExMatch(Control, "^[1-9]\d*$") ;ClassNN Number provided
Control = SysListView32%Control%
Else If !RegExMatch(Control, "^(SysListView32)?[1-9]\d*$") ;Not a ClassNN => control's associated var
{
If (!(Gui_Number > 0) || (Gui_Number > 99))
Gui_Number = 1
If _%Gui_Number%_%Control%_
Return
GuiControlGet, hLV, %Gui_Number%:hWnd, %Control%
If ErrorLevel
Return
_%Gui_Number%_%Control%_ := hLV
} ;Otherwise, ClassNN was provided.
If hLV
{
If (_%hLV%_ || !HWND2GuiNClass(hLV, Gui_Number, Control))
Return
}
Else If Control ;Control found/provided
{
If (!(Gui_Number > 0) || (Gui_Number > 99))
Gui_Number = 1
If _%Gui_Number%_%Control%_
Return
Gui, %Gui_Number%:+LastFoundExist
If !(hGUI := WinExist())
Return
GuiControlGet, hLV, %Gui_Number%:HWND, %Control%
If ErrorLevel
Return
}
Else
Return
hLV+=0
;Save handle to quickly get it from gui+control
_%Gui_Number%_%Control%_ := hLV
;Save gui and control to quickly get it from handle
_%hLV%_ := Gui_Number "|" Control
;Save column containing indexes
If !Column
_%hLV%_Col_ = 1
Else
_%hLV%_Col_ := Column
;Maintain a list of registered handles for wm_notify to operate on every registered control
If !_LTV_h_List_
_LTV_h_List_ := "|" hLV "|"
Else
_LTV_h_List_ .= hLV "|"
;Maintain a list of modified indexes for disposal
;Colors bound to indexes
_%hLV%_0_Text = |
_%hLV%_0_Back = |
;Colors bound to lines
_%hLV%_0_LText = |
_%hLV%_0_LBack = |
OnMessage( 0x4E, "WM_NOTIFY" )
Return hLV
}
LV_Change(Gui_Number="", Control="", Select="", Column="")
{
local hLV
;Get either class or hWnd of control
If !Control ;Control omitted
{
If (Gui_Number > 99)
hLV := Gui_Number
Else ;No hWnd => default
Control = SysListView321
}
Else If RegExMatch(Control, "^[1-9]\d*$") ;ClassNN Number provided
Control = SysListView32%Control%
Else If !RegExMatch(Control, "^(SysListView32)?[1-9]\d*$") ;Not a ClassNN or a NN => control's associated var
{
If (!(Gui_Number > 0) || (Gui_Number > 99))
Gui_Number = 1
If !(hLV := _%Gui_Number%_%Control%_) ;May not have been initialized
{
If !(hLV := LV_Initialize(Gui_Number, Control, Column))
Return
}
} ;Otherwise, ClassNN was provided.
If hLV
{
hLV+=0
If !_%hLV%_ ;May not have been initialized
{
If !LV_Initialize(hLV, "", Column)
Return
}
Loop, Parse, _%hLV%_, |
{
If (A_Index = 1)
Gui_Number := A_LoopField
Else
Control := A_LoopField
}
}
Else If Control ;Control found/provided
{
If (!(Gui_Number > 0) || (Gui_Number > 99))
Gui_Number = 1
If !(hLV := _%Gui_Number%_%Control%_) ;May not have been initialized
{
If !(hLV := LV_Initialize(Gui_Number, Control, Column))
Return
}
}
Else
Return
_LV_h_ := hLV+0
If (Select != 0)
{
Gui, %Gui_Number%:Default
Gui, ListView, %Control%
}
If (Column && (Column != _%hLV%_Col_))
_%hLV%_Col_ := Column
Return 1
}
LV_SetColor(Index="", TextColor="", BackColor="", Redraw=1)
{
local i, j, L
If !_LV_h_
Return
Index+=0
If (Index < 0)
{
L = L
i = 1
Index := -Index-1
}
Else If (Index > 0)
{
i = 1
Index--
}
Else If ((Index = "-0") || (Index = "-"))
{
L = L
Index = 0
ControlGet, i, List, Count, , ahk_id %_LV_h_%
}
Else
{
Index = 0
ControlGet, i, List, Count, , ahk_id %_LV_h_%
}
Loop, %i%
{
j := A_Index+Index
If (TextColor != "")
{
If (TextColor >= 0)
{
If !InStr(_%_LV_h_%_0_%L%Text, "|" j "|")
_%_LV_h_%_0_%L%Text .= j "|"
_%_LV_h_%_%j%_%L%Text := TextColor
}
Else
{
_%_LV_h_%_%j%_%L%Text =
StringReplace, _%_LV_h_%_0_%L%Text, _%_LV_h_%_0_%L%Text, |%j%|, |
}
}
If (BackColor != "")
{
If (BackColor >= 0)
{
If !InStr(_%_LV_h_%_0_%L%Back, "|" j "|")
_%_LV_h_%_0_%L%Back .= j "|"
_%_LV_h_%_%j%_%L%Back := BackColor
}
Else
{
_%_LV_h_%_%j%_%L%Back =
StringReplace, _%_LV_h_%_0_%L%Back, _%_LV_h_%_0_%L%Back, |%j%|, |
}
}
}
If Redraw
WinSet, Redraw,, ahk_id %_LV_h_%
Return 1
}
LV_GetColor(Index, T="Text") ;Index of the item from which to get color , T="Text" ; T="Back" , L=0 : linked to lines; L=1 : linked to rows
{
local L
If (Index<0)
{
L = L
Index := -Index
}
Return _%_LV_h_%_%Index%_%L%%T%
}
LV_Destroy(Gui_Number="", Control="", DeactivateWMNotify="")
{
local hLV
;Get either class or hWnd of control
If !Control ;Control omitted
{
If (Gui_Number > 99)
hLV := Gui_Number
Else ;No hWnd => default
Control = SysListView321
}
Else If Control RegExMatch(Control, "^[1-9]\d*$") ;ClassNN Number provided
Control = SysListView32%Control%
Else If !RegExMatch(Control, "^(SysListView32)?[1-9]\d*$") ;Not a ClassNN or a NN => control's associated var
{
If (!(Gui_Number > 0) || (Gui_Number > 99))
Gui_Number = 1
If !(hLV := _%Gui_Number%_%Control%_)
Return
} ;Otherwise, ClassNN was provided.
If hLV
{
hLV+=0
If !_%hLV%_
Return
Loop, Parse, _%hLV%_, |
{
If (A_Index = 1)
Gui_Number := A_LoopField
Else
Control := A_LoopField
}
}
Else If Control ;Control found/provided
{
If (!(Gui_Number > 0) || (Gui_Number > 99))
Gui_Number = 1
If !(hLV := _%Gui_Number%_%Control%_)
Return
}
Else
Return
Loop, Parse, _%hLV%_0_Text, |
_%hLV%_%A_LoopField%_Text =
_%hLV%_0_Text =
Loop, Parse, _%hLV%_0_Back, |
_%hLV%_%A_LoopField%_Back =
_%hLV%_0_Back =
Loop, Parse, _%hLV%_0_LText, |
_%hLV%_%A_LoopField%_LText =
_%hLV%_0_LText =
Loop, Parse, _%hLV%_0_LBack, |
_%hLV%_%A_LoopField%_LBack =
_%hLV%_0_LBack =
_%Gui_Number%_%Control%_ =
_%hLV%_Col_ =
_%hLV%_ =
WinSet, Redraw,, ahk_id %hLV%
StringReplace, _LTV_h_List_, _LTV_h_List_, |%hLV%|, |, A
If ((_LTV_h_List_ = "|") && DeactivateWMNotify)
OnMessage( 0x4E, "" )
If (hLV = _LV_h_)
_LV_h_ =
Return 1
}
DecodeInteger( p_type, p_address, p_offset) ;, p_hex=false )
{
;old_FormatInteger := A_FormatInteger
;ifEqual, p_hex, 1, SetFormat, Integer, hex
;else, SetFormat, Integer, dec
StringRight, size, p_type, 1
loop, %size%
value += *( ( p_address+p_offset )+( A_Index-1 ) ) << ( 8*( A_Index-1 ) )
if ( size <= 4 and InStr( p_type, "u" ) != 1 and *( p_address+p_offset+( size-1 ) ) & 0x80 )
value := -( ( ~value+1 ) & ( ( 2**( 8*size ) )-1 ) )
;SetFormat, Integer, %old_FormatInteger%
return, value
}
EncodeInteger( p_value, p_size, p_address, p_offset )
{
loop, %p_size%
DllCall( "RtlFillMemory", "uint", p_address+p_offset+A_Index-1, "uint", 1, "uchar", p_value >> ( 8*( A_Index-1 ) ) )
}
;Retrieves gui number and classNN from hwnd of a gui control
HWND2GuiNClass(hWnd, ByRef Gui = "", ByRef Control = "")
{
WinGetClass, Cc, ahk_id %hWnd%
Loop, 99
{
Gui, %A_Index%:+LastFoundExist
If !WinExist()
Continue
Gui_Number := A_Index
Loop
{
GuiControlGet, hWCc, %Gui_Number%:HWND, %Cc%%A_Index%
If !hWCc
Break
If (hWnd = hWCc)
{
Ctrl := Cc A_Index
Break
}
}
If Ctrl
{
Gui := A_Index
Control := Ctrl
Return 1
}
}
}
LV_WM_NOTIFY(p_l)
{
local draw_stage, Current_Line, hLV, Index1, Index
static IndexList
Critical
If InStr(_LTV_h_List_, "|" (hLV := DecodeInteger( "uint4", p_l, 0 )) "|")
{
If (DecodeInteger( "int4", p_l, 8 ) = -12) ; NM_CUSTOMDRAW
{
draw_stage := DecodeInteger( "uint4", p_l, 12 )
If ( draw_stage = 1 ) ; CDDS_PREPAINT
{
ControlGet, IndexList, List, % "Col" _%hLV%_Col_, , ahk_id %hLV%
If !RegexMatch(IndexList, "S)^([1-9]\d*\n)*[1-9]\d*$") ;The index column must contain exclusively strictly positive decimal integers
IndexList =
Return, 0x20 ; CDRF_NOTIFYITEMDRAW
}
Else If ( draw_stage = 0x10001 ) ; CDDS_ITEM
{
Current_Line := DecodeInteger( "uint4", p_l, 36 )+1
If IndexList
RegexMatch(IndexList, "S)(?:.*?\n){" Current_Line-1 "}(.*?)(?:\n|$)", Index)
If (IndexList && (_%hLV%_%Index1%_Text != ""))
EncodeInteger( _%hLV%_%Index1%_Text, 4, p_l, 48 ) ; indexed foreground
Else If (_%hLV%_%Current_Line%_LText != "")
EncodeInteger( _%hLV%_%Current_Line%_LText, 4, p_l, 48 ) ; line foreground
If (IndexList && (_%hLV%_%Index1%_Back != ""))
EncodeInteger( _%hLV%_%Index1%_Back, 4, p_l, 52 ) ; indexed background
Else If (_%hLV%_%Current_Line%_LBack != "")
EncodeInteger( _%hLV%_%Current_Line%_LBack, 4, p_l, 52 ) ; line background
}
}
}
}
WM_NOTIFY( p_w, p_l, p_m )
{
Critical
;/*
;Prevents column resizing, uncomment if resizing is buggy
Index := DecodeInteger( "int4", p_l, 8 )
If ((Index = -326) || (Index = -306)) ; HDN_BEGINTRACKA = -306, HDN_BEGINTRACKW = -326
Return 1
;*/
;ADD YOUR CODE HERE
Return LV_WM_NOTIFY(p_l)
}

52
Lib/ADO.ahk Normal file
View File

@ -0,0 +1,52 @@

/*
* Provides Static ADO Helper classes and Enums
*
*/
class ADO
{
class CursorType
{
static adOpenUnspecified := -1
static adOpenForwardOnly := 0
static adOpenKeyset := 1
static adOpenDynamic := 2
static adOpenStatic := 3
}
class LockType
{
static adLockUnspecified := -1
static adLockReadOnly := 1
static adLockPessimistic := 2
static adLockOptimistic := 3
static adLockBatchOptimistic := 4
}
class CommandType
{
static adCmdUnspecified := -1
static adCmdText := 1
static adCmdTable := 2
static adCmdStoredProc := 4
static adCmdUnknown := 8
static adCmdFile := 256
static adCmdTableDirect := 512
}
class AffectEnum
{
static adAffectCurrent := 1
static adAffectGroup := 2
}
class ObjectStateEnum
{
static adStateClosed := 0 ; The object is closed
static adStateOpen := 1 ; The object is open
static adStateConnecting := 2 ; The object is connecting
static adStateExecuting := 4 ; The object is executing a command
static adStateFetching := 8 ; The rows of the object are being retrieved
}
}

94
Lib/Base.ahk Normal file
View File

@ -0,0 +1,94 @@
/**************************************
base classes
***************************************
*/
global null := 0 ; for better readability
/*
Check for same (base) Type
*/
is(obj, type){
if(IsObject(type))
type := typeof(type)
while(IsObject(obj)){
if(obj.__Class == type){
return true
}
obj := obj.base
}
return false
}
typeof(obj){
if(IsObject(obj)){
cls := obj.__Class
if(cls != "")
return cls
while(IsObject(obj)){
if(obj.__Class != ""){
return obj.__Class
}
obj := obj.base
}
return "Object"
}
return "NonObject"
}
IsObjectMember(obj, memberStr){
if(IsObject(obj)){
return ObjHasKey(obj, memberStr) || IsMetaProperty(memberStr)
}
}
IsMetaProperty(str){
static metaProps := "__New,__Get,__Set,__Class"
if str in %metaProps%
return true
else
return false
}
/**
* Provides some common used Exception Templates
*
*/
class Exceptions
{
NotImplemented(){
return Exception("A not implemented Method was called.",-1)
}
MustOverride(){
return Exception("This Method must be overriden",-1)
}
ArgumentException(furtherInfo=""){
return Exception("A wrong Argument has been passed to this Method`n" furtherInfo,-1)
}
}
;Base
{
"".base.__Call := "Default__Warn"
"".base.__Set := "Default__Warn"
"".base.__Get := "Default__Warn"
Default__Warn(nonobj, p1="", p2="", p3="", p4="")
{
ListLines
MsgBox A non-object value was improperly invoked.`n`nSpecifically: %nonobj%
}
}

104
Lib/Collection.ahk Normal file
View File

@ -0,0 +1,104 @@
#Include <Base>
/*
Basic Collection implementation
*/
class Collection
{
; Methoden Implementation
/*
Fügt ein Element der Collection hinzu
*/
Add(obj){
this.Insert(obj)
}
/*
Fügt eine Auflistung dieser Collection hinzu
*/
AddRange(objs){
if(IsObject(objs)){
for each, item in objs
this.Insert(item)
} else
throw Exceptions.ArgumentException("Must submit Array!")
}
Clear(){
this.Remove(this.MinIndex(), this.MaxIndex())
}
RemoveItem(item){
for k, e in this
if(e = item)
this.Remove(k)
}
/*
Returns the count of elements contained in this collection
*/
Count(){
return this.SetCapacity(0)
}
/*
* Returns true if this collection is empty
*/
IsEmpty(){
return this.Count() == 0
}
First(){
return this[this.MinIndex()]
}
Last(){
return this[this.MaxIndex()]
}
/*
Sortiert die Liste
*/
Sort(comparer=""){
if(IsFunc(comparer))
comparer := "F " comparer
for each, num in this
nums .= num "`n"
Sort, nums, % comparer
this.Clear()
Loop, parse, nums, `,
this.Add(A_LoopField)
}
ToString(){
str := ""
for k, v in this
{
valStr := ""
if(IsObject(v)){
valStr := "{" . typeof(v) . "}"
if(IsFunc(v.ToString)){
valStr .= " " . v.ToString()
}
}else{
valStr := "'" v "'"
}
str .= k ": " . valStr . "`n"
}
return str
}
/*
Konstruktor - erstellt eine neue, (leere) Collection
enum : Element die zubign vorhanden sein sollen
*/
__New(enum = 0){
if(IsObject(enum)){
this.AddRange(enum)
}
}
}

27
Lib/DBA.ahk Normal file
View File

@ -0,0 +1,27 @@
/*
DataBase NameSpace Import
*/
#Include <Base>
#Include <Collection>
;drivers
#Include <SQLite_L>
#Include <mySQL>
#Include <ADO>
class DBA ; namespace DBA
{
#Include <DataBaseFactory>
#Include <DataBaseAbstract>
; Concrete SQL Providers
#Include <DataBaseSQLLite>
#Include <DataBaseMySQL>
#Include <DataBaseADO>
#Include <RecordSetSqlLite>
#Include <RecordSetADO>
#Include <RecordSetMySQL>
}

200
Lib/DataBaseADO.ahk Normal file
View File

@ -0,0 +1,200 @@
;namespace DBA
/*
Represents a Connection to a ADO Database
*/
class DataBaseADO extends DBA.DataBase
{
_connection := null
_connectionData := ""
__New(connectionString){
this._connectionData := connectionString
this.Connect()
}
/*
(Re) Connects to the db with the given creditals
*/
Connect(){
if(IsObject(this._connection))
{
this.Close()
}
this._connection := ComObjCreate("ADODB.connection")
;connection.Open connectionstring,userID,password,options
this._connection.Open(this._connectionData)
}
Close(){
if(this.IsConnected())
{
this._connection.Close()
this._connection := null
}
}
/*
* Is this connection open?
*/
IsConnected(){
return (IsObject(this._connection) && this._connection.State != ADO.ObjectStateEnum.adStateClosed)
}
IsValid(){
return IsObject(this._connection)
}
GetLastError(){
; todo
}
GetLastErrorMsg(){
errMsg := ""
for objErr in this._connection.Errors
{
errMsg .= objErr.Number " " objErr.Description " Source:" objErr.Source "`n"
}
return errMsg
}
SetTimeout(timeout = 1000){
if(this.IsValid())
this._connection.ConnectionTimeout := (timeout / 1000)
}
Changes() {
/*
ToDo
*/
}
/*
Querys the DB and returns a RecordSet
*/
OpenRecordSet(sql, editable = false){
return new DBA.RecordSetADO(sql, this._connection, editable)
}
/*
Querys the DB and returns a ResultTable or true/false
*/
Query(sql){
ret := false
if(this.IsValid())
{
;Execute( commandtext,ra,options)
affectedRows := 0
rs := this._connection.Execute(sql, affectedRows)
if(IsObject(rs) && rs.State != ADO.ObjectStateEnum.adStateClosed)
{
ret := this.FetchADORecordSet(rs)
rs.Close()
}else{
ret := affectedRows
}
}
return ret
}
EscapeString(str){
return Mysql_escape_string(str)
}
BeginTransaction(){
if(this.IsValid())
this._connection.BeginTrans()
}
EndTransaction(){
if(this.IsValid())
this._connection.CommitTrans()
}
Rollback(){
if(this.IsValid())
this._connection.RollbackTrans()
}
FetchADORecordSet(adoRS){
tbl := null
if(IsObject(adoRS) && !adoRS.EOF)
{
columnNames := new Collection()
myRows := new Collection()
for field in adoRS.Fields
columnNames.add(field.Name)
fetchedArray := adoRS.GetRows() ; returns a COM-SafeArray Wrapper
colSize := fetchedArray.MaxIndex(1) + 1
rowSize := fetchedArray.MaxIndex(2) + 1
loop, % rowSize
{
i := A_index - 1
datafields := new Collection()
loop, % colSize
{
j := A_index - 1
datafields.add(fetchedArray[j,i])
}
myRows.Add(new DBA.Row(columnNames, datafields))
}
tbl := new DBA.Table(myRows, columnNames)
}
return tbl
}
InsertMany(records, tableName){
;objRecordset.Open source,actconn,cursortyp,locktyp,opt
rs := ComObjCreate("ADODB.Recordset")
/* batch
rs.Open(tableName, this._connection, ADO.CursorType.adOpenKeyset, ADO.LockType.adLockBatchOptimistic, ADO.CommandType.adCmdTable)
for each, record in records
{
rs.AddNew()
for column, value in record
{
rs.Fields[column].Value := value
}
}
rs.UpdateBatch()
*/
rs.Open(tableName, this._connection, ADO.CursorType.adOpenKeyset, ADO.LockType.adLockOptimistic, ADO.CommandType.adCmdTable)
for each, record in records
{
rs.AddNew()
for column, value in record
{
rs.Fields[column].Value := value
}
rs.Update()
}
rs.Close()
}
Insert(record, tableName){
records := new Collection()
records.Add(record)
return this.InsertMany(records, tableName)
}
}

308
Lib/DataBaseAbstract.ahk Normal file
View File

@ -0,0 +1,308 @@
; namespace DBA
/*
#####################################################################################
Abstract Database Classes
Base for all concrete implementations for the supported DataBases.
#####################################################################################
*/
/*
data := Row[index]
data := Row["ColumnName"]
*/
class Row
{
_columns := 0
_fields := new Collection()
Count(){
return this._fields.Count()
}
ToString(){
return this._fields.ToString()
}
__Get(param){
if(IsObject(param)){
throw Exception("Expected Index or Column Name!", -1)
}
if(!IsObjectMember(this, param)){
if param is Integer
{
; // assume that an indexed access is desired
; // return the corresponding ROW
if(this.ContainsIndex(param))
return this._fields[param]
} else {
; // assume that an columnname access is desired
; // find index
index := 0
for i, col in this._columns
{
if(col = param){
index := i
break
}
}
if(this.ContainsIndex(index)){
return this._fields[index]
}
}
}
}
ContainsIndex(index){
return ((index > 0) && (index <= this._fields.Count()))
}
/*
Creates a New Row.
columns : Collection of the Columnames
fields: Collection of the Fields (Data)
*/
__New(columns, fields){
if(!is(columns, "Collection")){
throw Exception("columns must be a Collection Object",-1)
}
if(!is(fields, "Collection")){
throw Exception("fields must be a Collection Object",-1)
}
this._fields := fields
this._columns := columns
}
__NewEnum() {
return new DBA.Row.Enumerator(this)
}
class Enumerator {
__new(row) {
this.columnEnum := ObjNewEnum(row.columns)
this.fieldEnum := ObjNewEnum(row.fields)
}
next(ByRef key, ByRef val) {
return this.columnEnum.next("", key)
&& this.fieldEnum.next("",val)
}
}
}
/*
row := table[index]
*/
class Table
{
Rows := new Collection()
Columns := new Collection()
Count(){
return this.Rows.Count()
}
ToString(){
colstr := this.Columns.ToString()
StringReplace, colstr, colstr, `n, |
return "(" this.Rows.Count() ")" . colstr
}
__Get(param){
if(IsObject(param)){
throw Exception("Expected non-Object Index!",-1)
}
if(!IsObjectMember(this, param)){
if param is Integer
{
; // assume that an indexed access is desired
; // return the corresponding ROW
if((param > 0) && (param < this.Rows.Count()) )
return this.Rows[param]
}
}
}
/*
Creates a New Table.
rows: Collection of the Rows (Data)
columns : Collection of the Columnames
*/
__New(rows, columns){
if(!is(rows, "Collection")){
throw Exception("rows must be a Collection Object",-1)
}
if(!is(columns, "Collection")){
throw Exception("rows must be a Collection Object",-1)
}
this.Rows := rows
this.Columns := columns
}
__NewEnum() {
return ObjNewEnum(this.rows)
}
}
class DataBase
{
static NULL := Object()
static TRUE := Object()
static FALSE := Object()
__delete() {
this.Close()
}
IsValid(){
throw Exceptions.MustOverride()
}
Query(sql){
throw Exceptions.MustOverride()
}
QueryValue(sQry){
rs := this.OpenRecordSet(sQry)
value := rs[1]
rs.Close()
return value
}
QueryRow(sQry){
rs := this.OpenRecordSet(sQry)
myrow := rs.getCurrentRow()
rs.Close()
return myrow
}
OpenRecordSet(sql, editable = false){
throw Exceptions.MustOverride()
}
ToSqlLiteral(value) {
if (IsObject(value)) {
if (value == DBA.DataBase.NULL)
return "NULL"
if (value == DBA.DataBase.TRUE)
return "TRUE"
if (value == DBA.DataBase.FALSE)
return "FALSE"
}
return "'" this.EscapeString(value) "'"
}
EscapeString(string){
throw Exceptions.MustOverride()
}
QuoteIdentifier(identifier){
throw Exceptions.MustOverride()
}
BeginTransaction(){
throw Exceptions.MustOverride()
}
EndTransaction(){
throw Exceptions.MustOverride()
}
Rollback(){
throw Exceptions.MustOverride()
}
Insert(record, tableName){
throw Exceptions.MustOverride()
}
InsertMany(records, tableName){
throw Exceptions.MustOverride()
}
Update(fields, constraints, tableName, safe = True){
throw Exceptions.MustOverride()
}
Close(){
throw Exceptions.MustOverride()
}
}
class RecordSet
{
_currentRow := 0 ; Row
__delete() {
this.Close()
}
AddNew(){
throw Exceptions.MustOverride()
}
MoveNext(){
throw Exceptions.MustOverride()
}
Delete(){
throw Exceptions.MustOverride()
}
Update(){
throw Exceptions.MustOverride()
}
Close(){
throw Exceptions.MustOverride()
}
getEOF(){
throw Exceptions.MustOverride()
}
IsValid(){
throw Exceptions.MustOverride()
}
getColumnNames(){
throw Exceptions.MustOverride()
}
getCurrentRow(){
return this._currentRow
}
__Get(param){
if(IsObject(param)){
throw Exception("Expected Index or Column Name!",-1)
}
if(param = "EOF")
return this.getEOF()
if(!IsObjectMember(this, param) && param != "_currentRow"){
if(!is(this._currentRow, DBA.Row))
return ""
;// assume memberaccess are the column names/indexes
return this._currentRow[param]
}
}
}

36
Lib/DataBaseFactory.ahk Normal file
View File

@ -0,0 +1,36 @@
class DataBaseFactory
{
static AvaiableTypes := ["SQLite", "MySQL", "ADO"]
/*
This static Method returns an Instance of an DataBase derived Object
*/
OpenDataBase(dbType, connectionString){
if(dbType = "SQLite")
{
OutputDebug, Open Database of known type [%dbType%]
SQLite_Startup()
;//parse connection string. for now assume its a path to the requested DB
handle := SQLite_OpenDB(connectionString)
if(handle == 0)
throw Exception("SQLite: The connection to the the given Datebase could not be etablished. Is the following SQLite connection string valid?`n`n" connectionString,-1)
return new DBA.DataBaseSQLLite(handle)
} if(dbType = "MySQL") {
OutputDebug, Open Database of known type [%dbType%]
MySQL_StartUp()
conData := MySQL_CreateConnectionData(connectionString)
return new DBA.DataBaseMySQL(conData)
} if(dbType = "ADO") {
OutputDebug, Open Database of known type [%dbType%]
return new DBA.DataBaseADO(connectionString)
} else {
throw Exception("The given Database Type is unknown! [" . dbType "]",-1)
}
}
__New(){
throw Exception("This is a static class, dont instante it!",-1)
}
}

249
Lib/DataBaseMySQL.ahk Normal file
View File

@ -0,0 +1,249 @@
;namespace DBA
/*
Represents a Connection to a SQLite Database
*/
class DataBaseMySQL extends DBA.DataBase
{
_handleDB := 0
_connectionData := []
__New(connectionData){
if(!IsObject(connectionData))
throw Exception("Expected connectionData Array!")
this._connectionData := connectionData
this.Connect()
}
/*
(Re) Connects to the db with the given creditals
*/
Connect(){
connectionData := this._connectionData
if(!connectionData.Port){
dbHandle := MySQL_Connect(connectionData.Server, connectionData.Uid, connectionData.Pwd, connectionData.Database)
} else {
dbHandle := MySQL_Connect(connectionData.Server, connectionData.Uid, connectionData.Pwd, connectionData.Database, connectionData.Port)
}
this._handleDB := dbHandle
}
Close(){
/*
ToDo!
*/
}
IsValid(){
return (this._handleDB != 0)
}
GetLastError(){
return MySQL_GetLastErrorNo(this._handleDB)
}
GetLastErrorMsg(){
return MySQL_GetLastErrorMsg(this._handleDB)
}
SetTimeout(timeout = 1000){
/*
todo
*/
}
ErrMsg() {
return DllCall("libmySQL.dll\mysql_error", "UInt", this._handleDB, "AStr")
}
ErrCode() {
return DllCall("libmySQL.dll\mysql_errno", "UInt", this._handleDB) ; "Cdecl UInt"
}
Changes() {
/*
ToDo
*/
}
/*
Querys the DB and returns a RecordSet
*/
OpenRecordSet(sql, editable = false){
result := MySQL_Query(this._handleDB, sql)
if (result != 0) {
errCode := this.ErrCode()
if(errCode == 2003 || errCode == 2006 || errCode == 0){ ;// we've lost the connection
;// try reconnect
this.Connect()
result := MySQL_Query(this._handleDB, sql)
if (result != 0)
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query failed because of lost connection. Reconnect failed too." errCode, sql), -1)
} else {
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query Failed Error " errCode, sql), -1)
}
}
requestResult := MySQL_Use_Result(this._handleDB)
if(!requestResult)
return false
return new DBA.RecordSetMySQL(this._handleDB, requestResult)
}
/*
Querys the DB and returns a ResultTable or true/false
*/
Query(sql){
return this._GetTableObj(sql)
}
EscapeString(str){
return Mysql_escape_string(str)
}
QuoteIdentifier(identifier) {
; ` characters are actually valid. Technically everthing but a literal null U+0000.
; Everything else is fair game: http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
StringReplace, identifier, identifier, ``, ````, All
return "``" identifier "``"
}
BeginTransaction(){
this.Query("START TRANSACTION;")
}
EndTransaction(){
this.Query("COMMIT;")
}
Rollback(){
this.Query("ROLLBACK;")
}
InsertMany(records, tableName){
if(!is(records, Collection) || records.IsEmpty())
return false
sql := "INSERT INTO " tableName "`n"
colString := ""
for column, value in records.First()
{
colstring .= this.QuoteIdentifier(column) ","
}
StringTrimRight, colstring, colstring, 1
sql .= "(" colstring ")`nVALUES`n"
for each, record in records
{
valString := ""
for column, value in record
{
valString .= this.ToSqlLiteral(value) ","
}
StringTrimRight, valString, valString, 1
sql .= "(" valString "),`n"
}
StringTrimRight, colstring, colstring, 1
sql := Trim(sql," `t`r`n,") ";"
;FileAppend,`n---------`n%sql%`n, dba_sql.log
return this.Query(sql)
}
Insert(record, tableName){
records := new Collection()
records.Add(record)
return this.InsertMany(records, tableName)
}
Update(fields, constraints, tableName, safe = True) {
if (safe) ;limitation: information_schema doesn't work with temp tables
for k, row in this.Query("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_KEY = 'PRI' AND TABLE_NAME = " this.ToSqlLiteral(tableName)).Rows
if (!constraints.HasKey(row[1]))
return -1 ; error handling....
WHERE := ""
for col, val in constraints
WHERE .= ", " this.QuoteIdentifier(col) " = " this.ToSqlLiteral(val)
WHERE := SubStr(WHERE, 3)
SET := ""
for col, val in fields
SET .= "AND " this.QuoteIdentifier(col) " = " this.EscapeString(val)
SET := SubStr(SET, 5)
query := "UPDATE " this.QuoteIdentifier(tableName) " SET " SET " WHERE " WHERE
return db.Query(query)
}
_GetTableObj(sql, maxResult = -1) {
result := MySQL_Query(this._handleDB, sql)
/*
* Instant reconnect attempt
*/
if (result != 0) {
errCode := this.ErrCode()
if(errCode == 2003 || errCode == 2006 || errCode == 0){ ;// we've lost the connection
;// try reconnect
this.Connect()
result := MySQL_Query(this._handleDB, sql)
if (result != 0)
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query failed because of lost connection. Reconnect failed too." errCode, sql), -1)
} else {
throw new Exception(BuildMySQLErrorStr(this._handleDB, "Query Failed Error " errCode, sql), -1)
}
}
requestResult := MySql_Store_Result(this._handleDB)
if (!requestResult) ; the query was a non {SELECT, SHOW, DESCRIBE, EXPLAIN or CHECK TABLE} statement which doesn't yield any resultset
return
mysqlFields := MySQL_fetch_fields(requestResult)
colNames := new Collection()
columnCount := 0
for each, mysqlField in mysqlFields
{
colNames.Add(mysqlField.Name())
columnCount++
}
rowptr := 0
myRows := new Collection()
while((rowptr := MySQL_fetch_row(requestResult)))
{
rowIndex := A_Index
datafields := new Collection()
lengths := MySQL_fetch_lengths(requestResult)
Loop, % columnCount
{
length := GetUIntAtAddress(lengths, A_Index - 1)
fieldPointer := GetPtrAtAddress(rowptr, A_Index - 1)
if (fieldPointer != 0) ; "NULL values in the row are indicated by NULL pointers." See http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-row.html
fieldValue := StrGet(fieldPointer, length, "CP0")
else
fieldValue := "" ; Should use DBA.DataBase.NULL from database-types branch?
datafields.Add(fieldValue)
}
myRows.Add(new DBA.Row(colNames, datafields))
}
MySQL_free_result(requestResult)
tbl := new DBA.Table(myRows, colNames)
return tbl
}
}

310
Lib/DataBaseSQLLite.ahk Normal file
View File

@ -0,0 +1,310 @@

; namespace DBA
class SQLite
{
GetVersion(){
return SQLite_LibVersion()
}
SQLiteExe(dbFile, commands, ByRef output){
return SQLite_SQLiteExe(dbFile, commands, output)
}
__New(){
throw Exception("This is a static Class. Don't create Instances from it!",-1)
}
}
/*
Represents a Connection to a SQLite Database
*/
class DataBaseSQLLite extends DBA.DataBase
{
_handleDB := 0
__New(handleDB){
this._handleDB := handleDB
if(!this.IsValid())
{
throw Exception("Can not create a DataBaseSQLLite instance, because the connection handle is not valid!")
}
}
Close(){
return SQLite_CloseDB(this._handleDB)
}
IsValid(){
return (this._handleDB != 0)
}
GetLastError(){
code := 0
SQLite_ErrCode(this._handleDB, code)
return code
}
GetLastErrorMsg(){
msg := ""
SQLite_ErrMsg(this._handleDB, msg)
return msg
}
SetTimeout(timeout = 1000){
return SQLite_SetTimeout(this._handleDB, timeout)
}
ErrMsg() {
if (RC := DllCall("SQLite3\sqlite3_errmsg", "UInt", this._handleDB, "Cdecl UInt"))
return StrGet(RC, "UTF-8")
return ""
}
ErrCode() {
return DllCall("SQLite3\sqlite3_errcode", "UInt", this._handleDB, "Cdecl UInt")
}
Changes() {
return DllCall("SQLite3\sqlite3_changes", "UInt", this._handleDB, "Cdecl UInt")
}
/*
Querys the DB and returns a RecordSet
*/
OpenRecordSet(sql, editable = false){
return new DBA.RecordSetSqlLite(this, SQlite_Query(this._handleDB, sql))
}
/*
Querys the DB and returns a ResultTable or true/false
*/
Query(sql){
ret := null
if (RegExMatch(sql, "i)^\s*SELECT\s")){ ; check if this is a selection query
try
{
ret := this._GetTableObj(sql)
} catch e
throw Exception("Select Query failed.`n`n" sql "`n`nChild Exception:`n" e.What "`n" e.Message "`n" e.File "@" e.Line, -1)
} else {
try
{
ret := SQLite_Exec(this._handleDB, sql)
} catch e
throw Exception("Non Selection Query failed.`n`n" sql "`n`nChild Exception:`n" e.What " `n" e.Message, -1)
}
return ret
}
EscapeString(str){
StringReplace, str, str, ', '', All ; replace all single quotes with double single-quotes. pascal escape'
return str
}
QuoteIdentifier(identifier) {
; ` characters are actually valid. Technically everthing but a literal null U+0000.
; Everything else is fair game: http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
StringReplace, identifier, identifier, ``, ````, All
return "``" identifier "``"
}
BeginTransaction(){
this.Query("BEGIN TRANSACTION;")
}
EndTransaction(){
this.Query("COMMIT TRANSACTION;")
}
Rollback(){
this.Query("ROLLBACK TRANSACTION;")
}
InsertMany(records, tableName){
if(!is(records, Collection) || records.IsEmpty())
return false
colString := ""
valString := ""
columns := {}
for column, value in records.First()
{
colString .= "," this.QuoteIdentifier(column)
valString .= ",?"
columns[column] := A_Index
}
sql := "INSERT INTO " this.QuoteIdentifier(tableName) "`n(" SubStr(colstring, 2) ")`nVALUES`n(" SubStr(valString, 2) ")"
types := []
for i,row in this._GetTableObj("PRAGMA table_info(" this.QuoteIdentifier(tableName) ")").Rows
{
if columns.HasKey(row.name)
types[columns[row.name]] := row.types
}
this.BeginTransaction()
query := SQLite_Query(this._handleDB, sql) ;prepare the query
if ErrorLevel
msgbox % errorlevel
try
{
for i, record in records
{
for col, val in record
{
if (!columns.HasKey(col) || !types.HasKey(columns[col]))
throw "Irregular params"
SQLite_bind(query, columns[col], val, types[columns[col]])
}
SQLite_Step(query)
SQLite_Reset(query)
}
}
catch e
{
this.Rollback()
throw Exception("InsertMany failed.`n`nChild Exception:`n" e.What " `n" e.Message, -1)
}
SQLite_QueryFinalize(query)
this.EndTransaction()
return True
}
Insert(record, tableName){
col := new Collection()
col.Add(record)
return this.InsertMany(col, tableName)
}
_GetTableObj(sql, maxResult = -1) {
err := 0, rc := 0, GetRows := 0
i := 0
rows := cols := 0
names := new Collection()
dbh := this._handleDB
SQLite_LastError(" ")
if(!_SQLite_CheckDB(dbh)) {
SQLite_LastError("ERROR: Invalid database handle " . dbh)
ErrorLevel := _SQLite_ReturnCode("SQLITE_ERROR")
return False
}
if maxResult Is Not Integer
maxResult := -1
if (maxResult < -1)
maxResult := -1
mytable := ""
Err := 0
_SQLite_StrToUTF8(SQL, UTF8)
RC := DllCall("SQlite3\sqlite3_get_table", "Ptr", dbh, "Ptr", &UTF8, "Ptr*", mytable
, "Ptr*", rows, "Ptr*", cols, "Ptr*", err, "Cdecl Int")
If (ErrorLevel) {
SQLite_LastError("ERROR: DLLCall sqlite3_get_table failed!")
Return False
}
If (rc) {
SQLite_LastError(StrGet(err, "UTF-8"))
DllCall("SQLite3\sqlite3_free", "Ptr", err, "cdecl")
ErrorLevel := rc
return false
}
if (maxResult = 0) {
DllCall("SQLite3\sqlite3_free_table", "Ptr", mytable, "Cdecl")
If (ErrorLevel) {
SQLite_LastError("ERROR: DLLCall sqlite3_close failed!")
Return False
}
Return True
}
if (maxResult = 1)
GetRows := 0
else if (maxResult > 1) && (maxResult < rows)
GetRows := MaxResult
else
GetRows := rows
Offset := 0
Loop, % cols
{
names.Add(StrGet(NumGet(mytable+0, Offset), "UTF-8"))
Offset += A_PtrSize
}
myRows := new Collection()
Loop, %GetRows% {
i := A_Index
fields := new Collection()
Loop, % Cols
{
fields.Add(StrGet(NumGet(mytable+0, Offset), "UTF-8"))
Offset += A_PtrSize
}
myRows.Add(new DBA.Row(Names, fields))
}
tbl := new DBA.Table(myRows, Names)
; Free Results Memory
DllCall("SQLite3\sqlite3_free_table", "Ptr", mytable, "Cdecl")
if (ErrorLevel) {
SQLite_LastError("ERROR: DLLCall sqlite3_close failed!")
return false
}
return tbl
}
ReturnCode(RC) {
static RCODE := {SQLITE_OK: 0 ; Successful result
, SQLITE_ERROR: 1 ; SQL error or missing database
, SQLITE_INTERNAL: 2 ; NOT USED. Internal logic error in SQLite
, SQLITE_PERM: 3 ; Access permission denied
, SQLITE_ABORT: 4 ; Callback routine requested an abort
, SQLITE_BUSY: 5 ; The database file is locked
, SQLITE_LOCKED: 6 ; A table in the database is locked
, SQLITE_NOMEM: 7 ; A malloc() failed
, SQLITE_READONLY: 8 ; Attempt to write a readonly database
, SQLITE_INTERRUPT: 9 ; Operation terminated by sqlite3_interrupt()
, SQLITE_IOERR: 10 ; Some kind of disk I/O error occurred
, SQLITE_CORRUPT: 11 ; The database disk image is malformed
, SQLITE_NOTFOUND: 12 ; NOT USED. Table or record not found
, SQLITE_FULL: 13 ; Insertion failed because database is full
, SQLITE_CANTOPEN: 14 ; Unable to open the database file
, SQLITE_PROTOCOL: 15 ; NOT USED. Database lock protocol error
, SQLITE_EMPTY: 16 ; Database is empty
, SQLITE_SCHEMA: 17 ; The database schema changed
, SQLITE_TOOBIG: 18 ; String or BLOB exceeds size limit
, SQLITE_CONSTRAINT: 19 ; Abort due to constraint violation
, SQLITE_MISMATCH: 20 ; Data type mismatch
, SQLITE_MISUSE: 21 ; Library used incorrectly
, SQLITE_NOLFS: 22 ; Uses OS features not supported on host
, SQLITE_AUTH: 23 ; Authorization denied
, SQLITE_FORMAT: 24 ; Auxiliary database format error
, SQLITE_RANGE: 25 ; 2nd parameter to sqlite3_bind out of range
, SQLITE_NOTADB: 26 ; File opened that is not a database file
, SQLITE_ROW: 100 ; sqlite3_step() has another row ready
, SQLITE_DONE: 101} ; sqlite3_step() has finished executing
return RCODE.HasKey(RC) ? RCODE[RC] : ""
}
}

415
Lib/Notify.ahk Normal file
View File

@ -0,0 +1,415 @@
;
;———————— Notify() 0.4991 by gwarble ————————
;————— —————
;——— easy multiple tray area notifications ———
;—— http://www.autohotkey.net/~gwarble/Notify/ ——
;——————————————————————————————————————————————————————
;
; Notify([Title,Message,Duration,Options])
;
; Duration seconds to show notification [Default: 30]
; 0 for permanent/remain until clicked (flashing)
; -3 negative value to ExitApp on click/timeout
; "-0" for permanent and ExitApp when clicked (needs "")
;
; Options string of options, single-space seperated, ie:
; "TS=16 TM=8 TF=Times New Roman GC_=Blue SI_=1000"
; most options are remembered (static), some not (local)
; Option_= can be used for non-static call, ie:
; "GC=Blue" makes all future blue, "GC_=Blue" only takes effect once
; "Wait=ID" to wait for a notification
; "Update=ID" to change Title, Message, and Progress Bar (with 'Duration')
;
; Return ID (Gui Number used)
; 0 if failed (too many open most likely)
; VarValue if Options includes: Return=VarName
;——————————————————————————————————————————————————————
Notify(Title="Notify()",Message="",Duration="",Options="")
{
static GNList, ACList, ATList, AXList, Exit, _Wallpaper_, _Title_, _Message_, _Progress_, _Image_, Saved
static GF := 50 ; Gui First Number
static GL := 74 ; Gui Last Number (which defines range and allowed count)
static GC,GR,GT,BC,BK,BW,BR,BT,BF ; static options, remembered between calls
static TS,TW,TC,TF,MS,MW,MC,MF
static SI,SC,ST,IW,IH,IN,XC,XS,XW,PC,PB
If (Options) ; skip parsing steps if Options param isn't used
{
If (A_AutoTrim = "Off")
{
AutoTrim, On
_AutoTrim = 1
} ; ¶
Options = %Options%
Options.=" " ; poor whitespace handling for next parsing step (ensures last option is parsed)
Loop,Parse,Options,= ; parse options string at "="s, needs better whitespace handling
{
If A_Index = 1 ; first option handling
Option := A_LoopField ; sets options VarName
Else ; for the rest after the first,
{ ; split at the last space, apply the first chunk to the VarValue for the last Option
%Option% := SubStr(A_LoopField, 1, (pos := InStr(A_LoopField, A_Space, false, 0))-1)
%Option% = % %Option%
Option := SubStr(A_LoopField, pos+1) ; and set the next option to the last chunk (from the last space to the "=")
}
}
If _AutoTrim
AutoTrim, Off
If Wait <> ; option Wait=ID used, normal Notify window not being created
{
If Wait Is Number ; waits for a specific notify
{
Gui %Wait%:+LastFound ; i'd like to remove this to not affect calling script...
If NotifyGuiID := WinExist() ; but think i have to use hWnd's for reference instead of gui numbers which will
{ ; probably happen in my AHK_L transition since gui numbers won't matter anymore
WinWaitClose, , , % Abs(Duration) ; wait to close for duration
If (ErrorLevel && Duration < 1) ; destroys window when done waiting if duration is negative
{ ; otherwise lets the calling script procede after waiting the duration (without destroying)
Gui, % Wait + GL - GF + 1 ":Destroy" ; destroys border gui
If ST
DllCall("AnimateWindow","UInt",NotifyGuiID,"Int",ST,"UInt","0x00050001") ; slides window out to the right if ST or SC are used
Gui, %Wait%:Destroy ; and destroys it
}
}
}
Else ; wait for all notify's if "Wait=All" is used in the options string
{ ; loops through all existing notify's and performs the same wait logic
Loop, % GL-GF ; (with or without destroying if negative or not)
{
Wait := A_Index + GF - 1
Gui %Wait%:+LastFound
If NotifyGuiID := WinExist()
{
WinWaitClose, , , % Abs(Duration)
If (ErrorLevel && Duration < 1)
{
Gui, % Wait + GL - GF + 1 ":Destroy" ; destroys border gui
If ST
DllCall("AnimateWindow","UInt",NotifyGuiID,"Int",ST,"UInt","0x00050001") ; slides window out to the right if ST or SC are used
Gui, %Wait%:Destroy ; and destroys it
}
}
}
GNList := ACList := ATList := AXList := "" ; clears internal variables since they're all destroyed now
}
Return
}
If Update <> ; option "Update=ID" being used, Notify window will not be created
{ ; title, message, image and progress position can be updated
If Title <>
GuiControl, %Update%:,_Title_,%Title%
If Message <>
GuiControl, %Update%:,_Message_,%Message%
If Duration <>
GuiControl, %Update%:,_Progress_,%Duration%
If Image <>
GuiControl, %Update%:,_Image_,%Image%
If Wallpaper <>
GuiControl, %Update%:,_Wallpaper_,%Image%
Return
}
If Style = Save ; option "Style=Save" is used to save the existing window style
{ ; and call it back later with "Style=Load"
Saved := Options " GC=" GC " GR=" GR " GT=" GT " BC=" BC " BK=" BK " BW=" BW " BR=" BR " BT=" BT " BF=" BF
Saved .= " TS=" TS " TW=" TW " TC=" TC " TF=" TF " MS=" MS " MW=" MW " MC=" MC " MF=" MF
Saved .= " IW=" IW " IH=" IH " IN=" IN " PW=" PW " PH=" PH " PC=" PC " PB=" PB " XC=" XC " XS=" MS " XW=" XW
Saved .= " SI=" SI " SC=" SC " ST=" ST " WF=" Image " IF=" IF
} ; this needs some major improvement to have multiple saved instead of just one, otherwise pointless
If Return <>
Return, % (%Return%)
If Style <> ; option "Style=Default will reset all variables back to defaults... except options also specified
{ ; so "Style=Default GC=Blue" is allowed, which will reset all defaults and then set GC=Blue
If Style = Default
Return % Notify(Title,Message,Duration, ; maybe handled poorly by calling itself, but it saves having to have the defaults set in two areas... thoughts?
(
"GC= GR= GT= BC= BK= BW= BR= BT= BF= TS= TW= TC= TF=
MS= MW= MC= MF= SI= ST= SC= IW=
IH= IN= XC= XS= XW= PC= PB= " Options "Style=")
) ; below are more internally saved styles, which may move to an auxiliary function at some point, but could use some improvement
Else If Style = ToolTip
Return % Notify(Title,Message,Duration,"SI=50 GC=FFFFAA BC=00000 GR=0 BR=0 BW=1 BT=255 TS=8 MS=8 " Options "Style=")
Else If Style = BalloonTip
Return % Notify(Title,Message,Duration,"SI=350 GC=FFFFAA BC=00000 GR=13 BR=15 BW=1 BT=255 TS=10 MS=8 AX=1 XC=999922 IN=8 Image=" A_WinDir "\explorer.exe " Options "Style=")
Else If Style = Error
Return % Notify(Title,Message,Duration,"SI=250 GC=Default BC=00000 GR=0 BR=0 BW=1 BT=255 TS=12 MS=12 AX=1 XC=666666 IN=10 IW=32 IH=32 Image=" A_WinDir "\explorer.exe " Options "Style=")
Else If Style = Warning
Return % Notify(Title,Message,Duration,"SI=250 GC=Default BC=00000 GR=0 BR=0 BW=1 BT=255 TS=12 MS=12 AX=1 XC=666666 IN=9 IW=32 IH=32 Image=" A_WinDir "\explorer.exe " Options "Style=")
Else If Style = Info
Return % Notify(Title,Message,Duration,"SI=250 GC=Default BC=00000 GR=0 BR=0 BW=1 BT=255 TS=12 MS=12 AX=1 XC=666666 IN=8 IW=32 IH=32 Image=" A_WinDir "\explorer.exe " Options "Style=")
Else If Style = Question
Return % Notify(Title,Message,Duration,"SI=250 GC=Default BC=00000 GR=0 BR=0 BW=1 BT=255 TS=12 MS=12 AX=1 XC=666666 Image=24 IW=32 IH=32 " Options "Style=")
Else If Style = Progress
Return % Notify(Title,Message,Duration,"SI=100 GC=Default BC=00000 GR=9 BR=13 BW=2 BT=105 TS=10 MS=10 PG=100 PH=10 GW=300 " Options "Style=")
Else If Style = Huge
Return % Notify(Title,Message,Duration,"SI=100 ST=200 SC=200 GC=FFFFAA BC=00000 GR=27 BR=39 BW=6 BT=105 TS=24 MS=22 " Options "Style=")
Else If Style = Load
Return % Notify(Title,Message,Duration,Saved)
}
}
;—————— end if options ————————————————————————————————————————————————————————————————————————————
GC_ := GC_<>"" ? GC_ : GC := GC<>"" ? GC : "FFFFAA" ; defaults are set here, and static overrides are used and saved
GR_ := GR_<>"" ? GR_ : GR := GR<>"" ? GR : 9 ; and non static options (with OP_=) are used but not saved
GT_ := GT_<>"" ? GT_ : GT := GT<>"" ? GT : "Off"
BC_ := BC_<>"" ? BC_ : BC := BC<>"" ? BC : "000000"
BK_ := BK_<>"" ? BK_ : BK := BK<>"" ? BK : "Silver"
BW_ := BW_<>"" ? BW_ : BW := BW<>"" ? BW : 2
BR_ := BR_<>"" ? BR_ : BR := BR<>"" ? BR : 13
BT_ := BT_<>"" ? BT_ : BT := BT<>"" ? BT : 105
BF_ := BF_<>"" ? BF_ : BF := BF<>"" ? BF : 350
TS_ := TS_<>"" ? TS_ : TS := TS<>"" ? TS : 10
TW_ := TW_<>"" ? TW_ : TW := TW<>"" ? TW : 625
TC_ := TC_<>"" ? TC_ : TC := TC<>"" ? TC : "Default"
TF_ := TF_<>"" ? TF_ : TF := TF<>"" ? TF : "Default"
MS_ := MS_<>"" ? MS_ : MS := MS<>"" ? MS : 10
MW_ := MW_<>"" ? MW_ : MW := MW<>"" ? MW : "Default"
MC_ := MC_<>"" ? MC_ : MC := MC<>"" ? MC : "Default"
MF_ := MF_<>"" ? MF_ : MF := MF<>"" ? MF : "Default"
SI_ := SI_<>"" ? SI_ : SI := SI<>"" ? SI : 0
SC_ := SC_<>"" ? SC_ : SC := SC<>"" ? SC : 0
ST_ := ST_<>"" ? ST_ : ST := ST<>"" ? ST : 0
IW_ := IW_<>"" ? IW_ : IW := IW<>"" ? IW : 32
IH_ := IH_<>"" ? IH_ : IH := IH<>"" ? IH : 32
IN_ := IN_<>"" ? IN_ : IN := IN<>"" ? IN : 0
XF_ := XF_<>"" ? XF_ : XF := XF<>"" ? XF : "Arial Black"
XC_ := XC_<>"" ? XC_ : XC := XC<>"" ? XC : "Default"
XS_ := XS_<>"" ? XS_ : XS := XS<>"" ? XS : 12
XW_ := XW_<>"" ? XW_ : XW := XW<>"" ? XW : 800
PC_ := PC_<>"" ? PC_ : PC := PC<>"" ? PC : "Default"
PB_ := PB_<>"" ? PB_ : PB := PB<>"" ? PB : "Default"
wPW := ((PW<>"") ? ("w" PW) : ("")) ; needs improvement, poor handling of explicit sizes and progress widths
hPH := ((PH<>"") ? ("h" PH) : (""))
If GW <>
{
wGW = w%GW%
wPW := "w" GW - 20
}
hGH := ((GH<>"") ? ("h" GH) : (""))
wGW_ := ((GW<>"") ? ("w" GW - 20) : (""))
hGH_ := ((GH<>"") ? ("h" GH - 20) : (""))
;————————————————————————————————————————————————————————————————————————
If Duration = ; default if duration is not used or set to ""
Duration = 30
GN := GF ; find the next available gui number to use, starting from GF (default 50)
Loop ; within the defined range GF to GL
IfNotInString, GNList, % "|" GN
Break
Else
If (++GN > GL) ;=== too many notifications open, returns 0, handle this error in the calling script
Return 0 ; this is uncommon as the screen is too cluttered by this point anyway
GNList .= "|" GN
GN2 := GN + GL - GF + 1
If AC <> ; saves the action to be used when clicked or timeout (or x-button is clicked)
ACList .= "|" GN "=" AC ; need to add different clicks for Title, Message, Image as well
If AT <> ; saved internally in a list, then parsed by the timer or click routine
ATList .= "|" GN "=" AT ; to run the script-side subroutine/label "AC=LabelName"
If AX <>
AXList .= "|" GN "=" AX
P_DHW := A_DetectHiddenWindows ; start finding location based on what other Notify() windows are on the screen
P_TMM := A_TitleMatchMode ; saved to restore these settings after changing them, so the calling script won't know
DetectHiddenWindows On ; as they are needed to find all as they are being made as well... or hidden for some reason...
SetTitleMatchMode 1 ; and specific window title match is a little more failsafe
If (WinExist("_Notify()_GUI_")) ;=== find all Notifications from ALL scripts, for placement
WinGetPos, OtherX, OtherY ;=== change this to a loop for all open notifications and find the highest?
DetectHiddenWindows %P_DHW% ;=== using the last Notify() made at this point, which may be better
SetTitleMatchMode %P_TMM% ; and the global settings are restored for the calling thread
Gui, %GN%:-Caption +ToolWindow +AlwaysOnTop -Border ; here begins the creation of the window
Gui, %GN%:Color, %GC_% ; with the logic to add or not add certain controls, Wallpaper, Image, Title, Progress, Message
If FileExist(WP) ; and some placement logic depending if they are used or not... could definitely be improved
{
Gui, %GN%:Add, Picture, x0 y0 w0 h0 v_Wallpaper_, % WP ; wallpaper added first, stretched to size later
ImageOptions = x+8 y+4
}
If Image <> ; icon image added next, sized, and spacing added for whats next
{
If FileExist(Image)
Gui, %GN%:Add, Picture, w%IW_% h%IH_% Icon%IN_% v_Image_ %ImageOptions%, % Image
Else
Gui, %GN%:Add, Picture, w%IW_% h%IH_% Icon%Image% v_Image_ %ImageOptions%, %A_WinDir%\system32\shell32.dll
ImageOptions = x+10
}
If Title <> ; title text control added next, if used
{
Gui, %GN%:Font, w%TW_% s%TS_% c%TC_%, %TF_%
Gui, %GN%:Add, Text, %ImageOptions% BackgroundTrans v_Title_, % Title
}
If PG ; then the progress bar, if called for
Gui, %GN%:Add, Progress, Range0-%PG% %wPW% %hPH% c%PC_% Background%PB_% v_Progress_
Else
If ((Title) && (Message)) ; some spacing tweaks if both used
Gui, %GN%:Margin, , -5
If Message <> ; and finally the message text control if used
{
Gui, %GN%:Font, w%MW_% s%MS_% c%MC_%, %MF_%
Gui, %GN%:Add, Text, BackgroundTrans v_Message_, % Message
}
If ((Title) && (Message)) ; final spacing
Gui, %GN%:Margin, , 8
Gui, %GN%:Show, Hide %wGW% %hGH%, _Notify()_GUI_ ; final sizing
Gui %GN%:+LastFound ; would like to get rid of this to prevent calling script being affected
WinGetPos, GX, GY, GW, GH ; final positioning
GuiControl, %GN%:, _Wallpaper_, % "*w" GW " *h" GH " " WP ; stretch that wallpaper to size
GuiControl, %GN%:MoveDraw, _Title_, % "w" GW-20 " h" GH-10 ; poor handling of text wrapping when gui has explicit size called
GuiControl, %GN%:MoveDraw, _Message_, % "w" GW-20 " h" GH-10 ; needs improvement (and if image is used or not)
If AX <> ; add the corner "X" for closing with a different action than otherwise clicked
{
GW += 10
Gui, %GN%:Font, w%XW_% s%XS_% c%XC_%, Arial Black ; × (multiply) is the character used for the X-Button
Gui, %GN%:Add, Text, % "x" GW-15 " y-2 Center w12 h20 g_Notify_Kill_" GN - GF + 1, % chr(0x00D7) ;××
}
Gui, %GN%:Add, Text, x0 y0 w%GW% h%GH% BackgroundTrans g_Notify_Action_Clicked_ ; to catch clicks anywhere on the gui
If (GR_) ; may have to be removed for seperate title/message/etc actions
WinSet, Region, % "0-0 w" GW " h" GH " R" GR_ "-" GR_
If (GT_) ; non-functioning GT option, since the border gui gets in the way
WinSet, Transparent, % GT_ ; will be addressed someday, leaving it in
SysGet, Workspace, MonitorWorkArea ; positioning
NewX := WorkSpaceRight-GW-5
If (OtherY)
NewY := OtherY-GH-2-BW_*2
Else
NewY := WorkspaceBottom-GH-5
If NewY < % WorkspaceTop
NewY := WorkspaceBottom-GH-5
Gui, %GN2%:-Caption +ToolWindow +AlwaysOnTop -Border +E0x20 ; border gui
Gui, %GN2%:Color, %BC_%
Gui %GN2%:+LastFound
If (BR_)
WinSet, Region, % "0-0 w" GW+(BW_*2) " h" GH+(BW_*2) " R" BR_ "-" BR_
If (BT_)
WinSet, Transparent, % BT_
Gui, %GN2%:Show, % "Hide x" NewX-BW_ " y" NewY-BW_ " w" GW+(BW_*2) " h" GH+(BW_*2), _Notify()_BGGUI_ ; actual creation of border gui! but still not shown
Gui, %GN%:Show, % "Hide x" NewX " y" NewY " w" GW, _Notify()_GUI_ ; actual creation of Notify() gui! but still not shown
Gui %GN%:+LastFound ; need to get rid of this so calling script isn't affected
If SI_
DllCall("AnimateWindow","UInt",WinExist(),"Int",SI_,"UInt","0x00040008") ; animated in, if SI is used
Else
Gui, %GN%:Show, NA, _Notify()_GUI_ ; otherwise, just shown
Gui, %GN2%:Show, NA, _Notify()_BGGUI_ ; and the border shown
WinSet, AlwaysOnTop, On ; and set to Always on Top
If ((Duration < 0) OR (Duration = "-0")) ; saves internally that ExitApp should happen when this
Exit := GN ; notify dissappears
If (Duration)
SetTimer, % "_Notify_Kill_" GN - GF + 1, % - Abs(Duration) * 1000 ; timer set depending on Duration parameter
Else
SetTimer, % "_Notify_Flash_" GN - GF + 1, % BF_ ; timer set to flash border if the Notify has 0 (infinite) duration
Return %GN% ; end of Notify(), returns Gui ID number used
;==========================================================================
;========================================== when a notification is clicked:
_Notify_Action_Clicked_: ; option AC=Label means Label: subroutine will be called here when clicked
; Critical
SetTimer, % "_Notify_Kill_" A_Gui - GF + 1, Off
Gui, % A_Gui + GL - GF + 1 ":Destroy"
If SC
{
Gui, %A_Gui%:+LastFound
DllCall("AnimateWindow","UInt",WinExist(),"Int",SC,"UInt", "0x00050001")
}
Gui, %A_Gui%:Destroy
If (ACList)
Loop,Parse,ACList,|
If ((Action := SubStr(A_LoopField,1,2)) = A_Gui)
{
Temp_Notify_Action:= SubStr(A_LoopField,4)
StringReplace, ACList, ACList, % "|" A_Gui "=" Temp_Notify_Action, , All
If IsLabel(_Notify_Action := Temp_Notify_Action)
Gosub, %_Notify_Action%
_Notify_Action =
Break
}
StringReplace, GNList, GNList, % "|" A_Gui, , All
SetTimer, % "_Notify_Flash_" A_Gui - GF + 1, Off
If (Exit = A_Gui)
ExitApp
Return
;==========================================================================
;=========================================== when a notification times out:
_Notify_Kill_1:
_Notify_Kill_2: ; this needs a different method, too many labels
_Notify_Kill_3: ; they are used for Timers, different for each Notify() based on duration...
_Notify_Kill_4:
_Notify_Kill_5:
_Notify_Kill_6:
_Notify_Kill_7:
_Notify_Kill_8:
_Notify_Kill_9:
_Notify_Kill_10:
_Notify_Kill_11:
_Notify_Kill_12:
_Notify_Kill_13:
_Notify_Kill_14:
_Notify_Kill_15:
_Notify_Kill_16:
_Notify_Kill_17:
_Notify_Kill_18:
_Notify_Kill_19:
_Notify_Kill_20:
_Notify_Kill_21:
_Notify_Kill_22:
_Notify_Kill_23:
_Notify_Kill_24:
_Notify_Kill_25:
Critical
StringReplace, GK, A_ThisLabel, _Notify_Kill_
SetTimer, _Notify_Flash_%GK%, Off
GK := GK + GF - 1
Gui, % GK + GL - GF + 1 ":Destroy"
If ST
{
Gui, %GK%:+LastFound
DllCall("AnimateWindow","UInt",WinExist(),"Int",ST,"UInt", "0x00050001")
}
Gui, %GK%:Destroy
StringReplace, GNList, GNList, % "|" GK, , All
If (Exit = GK)
ExitApp
Return 1
;==========================================================================
;======================================== flashes a permanent notification:
_Notify_Flash_1:
_Notify_Flash_2:
_Notify_Flash_3:
_Notify_Flash_4: ; this needs a different method, too many labels
_Notify_Flash_5: ; they are used for Timers, different for each Notify() based on flash speed...
_Notify_Flash_6: ; when duration is 0 (infinite)
_Notify_Flash_7: ; this may feature may be removed completely, Update given the ability to affect GC and BC
_Notify_Flash_8: ; and then the flashing could be handled script-side via returned gui number and a script-side timer
_Notify_Flash_9:
_Notify_Flash_10:
_Notify_Flash_11:
_Notify_Flash_12:
_Notify_Flash_13:
_Notify_Flash_14:
_Notify_Flash_15:
_Notify_Flash_16:
_Notify_Flash_17:
_Notify_Flash_18:
_Notify_Flash_19:
_Notify_Flash_20:
_Notify_Flash_21:
_Notify_Flash_22:
_Notify_Flash_23:
_Notify_Flash_24:
_Notify_Flash_25:
StringReplace, FlashGN, A_ThisLabel, _Notify_Flash_
FlashGN += GF - 1
FlashGN2 := FlashGN + GL - GF + 1
If Flashed%FlashGN2% := !Flashed%FlashGN2%
Gui, %FlashGN2%:Color, %BK%
Else
Gui, %FlashGN2%:Color, %BC%
Return
}

109
Lib/RecordSetADO.ahk Normal file
View File

@ -0,0 +1,109 @@
;namespace DBA
/*
Represents a result set of ADO
http://www.w3schools.com/ado/ado_ref_recordset.asp
*/
class RecordSetADO extends DBA.RecordSet
{
_adoRS := 0 ; ado recordset
__New(sql, adoConnection, editable = false){
this._adoRS := ComObjCreate("ADODB.Recordset")
if(editable)
this._adoRS.Open(sql, adoConnection, ADO.CursorType.adOpenKeyset, ADO.LockType.adLockOptimistic, ADO.CommandType.adCmdTable)
else
this._adoRS.Open(sql, adoConnection)
}
/*
Is this RecordSet valid?
*/
IsValid(){
return (IsObject(this._adoRS))
}
/*
Returns an Array with all Column Names
*/
getColumnNames(){
colNames := new Collection()
for adoField in this._adoRS.Fields
colNames.add(adoField.Name)
return colNames
}
getEOF(){
return this._adoRS.EOF
}
AddNew(){
if(this.IsValid())
{
this._adoRS.AddNew()
}
}
MoveNext() {
if(this.IsValid())
{
this._adoRS.MoveNext()
}
}
Delete(){
if(this.IsValid() && !this.getEOF())
{
this._adoRS.Delete(ADO.AffectEnum.adAffectCurrent)
}
}
Update(){
if(this.IsValid() && !this.getEOF())
{
this._adoRS.Update()
}
}
Reset() {
if(this.IsValid()){
this._adoRS.MoveFirst()
}
}
Count(){
cnt := 0
if(this.IsValid())
cnt := this._adoRS.RecordCount
return cnt
}
Close() {
if(this.IsValid())
this._adoRS.Close()
}
__Get(param){
if(IsObject(param)){
throw Exception("Expected Index or Column Name!",-1)
}
if(param = "EOF")
return this.getEOF()
if(!IsObjectMember(this, param) && param != "_currentRow"){
if(this.IsValid())
{
df := this._adoRS.Fields[param]
return df.Value
}
}
}
}

109
Lib/RecordSetMySQL.ahk Normal file
View File

@ -0,0 +1,109 @@
;namespace DBA
/*
Represents a result set of an MySQL Query
*/
class RecordSetMySQL extends DBA.RecordSet
{
_colNames := 0 ; Collection<ColumnNames>
_colCount := 0
_query := 0 ; ptr to Resultset/Query
_db := 0 ; ptr to DataBase
_eof := false ; bool
CurrentRow := 0 ; int - row number
__New(db, requestResult){
this._db := db
this._query := requestResult
if(this._query != 0){
this._colNames := this.getColumnNames()
this.MoveNext()
}
}
/*
Is this RecordSet valid?
*/
IsValid(){
return (this._query != 0)
}
/*
Returns an Array with all Column Names
*/
getColumnNames(){
mysqlFields := MySQL_fetch_fields(this._query)
colNames := new Collection()
i := 0
for each, mysqlField in mysqlFields
{
colNames.Add(mysqlField.Name())
i++
}
this._colCount := i
return colNames
}
getEOF(){
return this._eof
}
MoveNext() {
static EOR := -1
this.ErrorMsg := ""
this.ErrorCode := 0
this._currentRow := 0
if (!this._query) {
this.ErrorMsg := "Invalid query handle!"
this._eof := true
return false
}
rowptr := MySQL_fetch_row(this._query)
if (!rowptr){
; // we reached eof
this.ErrorMsg := "RecordSet is empty! (eof)"
this.ErrorCode := 1
this._eof := true
return false
}
lengths := MySQL_fetch_lengths(this._query)
datafields := new Collection()
Loop % this._colCount
{
length := GetUIntAtAddress(lengths, A_Index - 1)
fieldPointer := GetPtrAtAddress(rowptr, A_Index - 1)
fieldValue := StrGet(fieldPointer, length, "CP0")
datafields.Add(fieldValue)
}
this._currentRow := new DBA.Row(this._colNames, datafields)
this.CurrentRow++
return true
}
Reset() {
throw Exception("Not Supported!",-1)
}
Close() {
this.ErrorMsg := ""
this.ErrorCode := 0
if(this._query == 0)
return true
MySQL_free_result(this._query)
this._query := 0
return true
}
}

139
Lib/RecordSetSqlLite.ahk Normal file
View File

@ -0,0 +1,139 @@
;namespace DBA
/*
Represents a result set of an SQLite Query
*/
class RecordSetSqlLite extends DBA.RecordSet
{
_currentRow := 0 ; Row
_colNames := 0 ; Collection<ColumnNames>
_query := 0 ; int Handle to the Query
_db := 0 ; SQLiteDataBase
_eof := false ; bool
/*
Is this RecordSet valid?
*/
IsValid(){
return (this._query != 0)
}
/*
Returns an Array with all Column Names
*/
getColumnNames(){
SQLite_FetchNames(this._query, names)
return new Collection(names)
}
getEOF(){
return this._eof
}
MoveNext() {
static SQLITE_NULL := 5
static EOR := -1
this.ErrorMsg := ""
this.ErrorCode := 0
this._currentRow := 0
if (!this._query) {
this.ErrorMsg := "Invalid query handle!"
this._eof := true
return false
}
rc := DllCall("SQlite3\sqlite3_step", "UInt", this._query, "Cdecl Int")
if (rc != this._db.ReturnCode("SQLITE_ROW")) {
if (rc = this._db.ReturnCode("SQLITE_DONE")) {
this.ErrorMsg := "EOR"
this.ErrorCode := rc
this._eof := true
return EOR
}
this.ErrorMessage := This._db.ErrMsg()
this.ErrorCode := rc
this._eof := true
return false
}
rc := DllCall("SQlite3\sqlite3_data_count", "UInt", this._query, "Cdecl Int")
if (rc < 1) {
this.ErrorMsg := "RecordSet is empty!"
this.ErrorCode := this._db.ReturnCode("SQLITE_EMPTY")
this._eof := true
return false
}
; fill the internal row structure
;_currentRow := new Row()
fields := new Collection()
Loop, %rc% {
ctype := DllCall("SQlite3\sqlite3_column_type", "UInt", this._query, "Int", A_Index - 1, "Cdecl Int")
if (ctype == SQLITE_NULL) {
fields[A_Index] := ""
} else {
strPtr := DllCall("SQlite3\sqlite3_column_text", "UInt", this._query, "Int", A_Index - 1, "Cdecl UInt")
fields[A_Index] := StrGet(strPtr, "UTF-8")
}
}
this._currentRow := new DBA.Row(this._colNames, fields)
this.CurrentRow++
return true
}
Reset() {
this.ErrorMsg := ""
this.ErrorCode := 0
if (!this._query) {
this.ErrorMsg := "Invalid query handle!"
return false
}
rc := DllCall("SQlite3\sqlite3_reset", "UInt", this._query, "Cdecl Int")
if (rc) {
this.ErrorMsg := This._db.ErrMsg()
this.ErrorCode := rc
return false
}
this.CurrentRow := 0
this.MoveNext()
return true
}
Close() {
this.ErrorMsg := ""
this.ErrorCode := 0
if(this._query == 0)
return true
rc := DllCall("SQlite3\sqlite3_finalize", "UInt", this._query, "Cdecl Int")
if (rc) {
this.ErrorMsg := this._db.ErrMsg()
this.ErrorCode := rc
return false
}
this._query := 0
return true
}
__New(db, query){
if(!is(db, DBA.DataBaseSQLLite)){
throw Exception("db must be a DataBaseSQLLite Object",-1)
}
this._db := db
this._query := query
if(query != 0){
this._colNames := this.getColumnNames()
this.MoveNext()
}
}
}

1044
Lib/SQLite_L.ahk Normal file

File diff suppressed because it is too large Load Diff

1
Lib/clean.bat Normal file
View File

@ -0,0 +1 @@
del *.bak

15
Lib/license.txt Normal file
View File

@ -0,0 +1,15 @@
AHK DBA - OOP Database Access Framework
Copyright (C) 2012 IsNull and other contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

431
Lib/mySQL.ahk Normal file
View File

@ -0,0 +1,431 @@
/*============================================================
mysql.ahk
Provides a set of functions to connect and query a mysql database
Based upon the published lib of panofish
http://www.autohotkey.com/forum/topic67280.html
Offical Documentation of the C-API
http://dev.mysql.com/doc/refman/5.0/en/c.html
============================================================
*/
/*
Parses the given Connectionstring to a ConnectionData
An typical Connectionstring looks like:
Server=myServerAddress;Port=1234;Database=myDataBase;Uid=myUsername;Pwd=myPassword;
Further Info: http://www.connectionstrings.com/mysql
*/
MySQL_CreateConnectionData(connectionString){
connectionData := {}
StringSplit, connstr, connectionString, `;
Loop, % connstr0
{
StringSplit, segment, connstr%a_index%, =
connectionData[segment1] := segment2
}
return connectionData
}
MySQL_StartUp(){
global MySQL_ExternDir
MySQL_ExternDir := A_WorkingDir
libDllpath := MySQL_DLLPath()
if(!FileExist(libDllpath))
{
msg := "MySQL Libaray not found!`n" libDllpath " (file missing)"
OutputDebug, %msg%
throw Exception(msg,-1)
}
hModule := DllCall("LoadLibrary", "Str", libDllpath)
if (hModule == 0)
{
msg := "LoadLibrary failed, can't load module:`n" libDllpath
OutputDebug, %msg%
throw Exception(msg, -1)
}else
return hModule
}
MySQL_DLLPath(forcedPath = "") {
static DLLPath := ""
static dllname := "libmySQL.dll"
if(DLLPath == ""){
; search the dll
prefix := (A_PtrSize == 8) ? "x64\" : ""
dllpath := prefix . dllname
if (FileExist(A_ScriptDir . "\" . dllpath))
DLLPath := A_ScriptDir . "\" . dllpath
else
DLLPath := A_ScriptDir . "\Lib\" . dllpath
}
if (forcedPath != "")
DLLPath := forcedPath
return DLLPath
}
/*****************************************************************
Connect to mysql database and return db handle
host:
user:
password:
database:
port: 3306(default)
******************************************************************
*/
MySQL_Connect(host, user, password, database, port = 3306){
db := DllCall("libmySQL.dll\mysql_init", "ptr", 0)
if (db = 0)
throw Exception("MySQL Error 445, Not enough memory to connect to MySQL", -1)
connection := DllCall("libmySQL.dll\mysql_real_connect"
, "ptr", db
, "AStr", host ; host name
, "AStr", user ; user name
, "AStr", password ; password
, "AStr", database ; database name
, "UInt", port ; port
, "UInt", 0 ; unix_socket
, "UInt", 0) ; client_flag
If (connection == 0)
throw Exception(BuildMySQLErrorStr(db, "Cannot connect to database"), -1)
;debugging only:
;MsgBox % "Ping database: " . MySQL_Ping(db) . "`nServer version: " . MySQL_GetVersion(db)
return db
}
MySQL_Close(db){
DllCall("libmySQL.dll\mysql_close", "ptr", db)
}
MySQL_GetVersion(db){
serverVersion := DllCall("libmySQL.dll\mysql_get_server_info", "ptr", db, "AStr")
return serverVersion
}
MySQL_Ping(db){
return DllCall("libmySQL.dll\mysql_ping", "ptr", db)
}
MySQL_GetLastErrorNo(db){
return DllCall("libmySQL.dll\mysql_errno", "ptr", db)
}
MySQL_GetLastErrorMsg(db){
return DllCall("libmySQL.dll\mysql_error", "ptr", db, "AStr")
}
/*
Retrieves a complete result set to the client.
*/
MySQL_Store_Result(db) {
return DllCall("libmySQL.dll\mysql_store_result", "ptr", db)
}
/*
Retrieves the resultset row-by-row
*/
MySQL_Use_Result(db) {
return DllCall("libmySQL.dll\mysql_use_result", "ptr", db)
}
/*
Returns a requestResult for the given query
*/
MySQL_Query(db, query){
return DllCall("libmySQL.dll\mysql_query", "ptr", db , "AStr", query)
}
MySQL_free_result(requestResult){
return DllCall("libmySQL.dll\mysql_free_result", "ptr", requestResult)
}
/*
Returns the number of columns in a result set.
*/
MySQL_num_fields(requestResult) {
Return DllCall("libmySQL.dll\mysql_num_fields", "ptr", requestResult)
}
/*
Returns the lengths of all columns in the current row.
*/
MySQL_fetch_lengths(requestResult) {
Return , DllCall("libmySQL.dll\mysql_fetch_lengths", "ptr", requestResult)
}
/*
Fetches the next row from the result set.
*/
MySQL_fetch_row(requestResult) {
Return , DllCall("libmySQL.dll\mysql_fetch_row", "ptr", requestResult)
}
/*
Fetches given Field
*/
Mysql_fetch_field_direct(requestResult, fieldnum) {
return DllCall("libmySQL.dll\mysql_fetch_field_direct", "ptr", requestResult, "Uint", fieldnum)
}
/*
Fetches the next field from the result set.
*/
Mysql_fetch_field(requestResult) {
return DllCall("libmySQL.dll\mysql_fetch_field", "ptr", requestResult)
}
/*
Fetches all fields of the resultSet
*/
MySQL_fetch_fields(requestResult){
global MySQL_Field
fields := []
fieldCount := MySQL_num_fields(requestResult)
Loop, % fieldCount
{
fptr := Mysql_fetch_field(requestResult)
fields[A_index] := new MySQL_Field(fptr)
}
return fields
}
/*
; mysql error handling
*/
BuildMySQLErrorStr(db, message, query="") {
errorCode := DllCall("libmySQL.dll\mysql_errno", "UInt", db)
errorStr := DllCall("libmySQL.dll\mysql_error", "UInt", db, "AStr")
Return, "MySQL Error: " message "Error " errorCode ": " errorStr "`n`n" query
}
;============================================================
; mysql get address
;============================================================
GetUIntAtAddress(_addr, _offset)
{
return NumGet(_addr+0,_offset * 4, "uint")
}
GetPtrAtAddress(_addr, _offset)
{
return NumGet(_addr+0,_offset * A_PtrSize, "ptr")
}
;============================================================
; internal: dump resultset from given Query to string
;============================================================
__MySQL_Query_Dump(_db, _query)
{
local resultString, result, requestResult, fieldCount
local row, lengths, length, fieldPointer, field
result := DllCall("libmySQL.dll\mysql_query", "UInt", _db , "AStr", _query)
If (result != 0)
throw new Exception(BuildMySQLErrorStr(_db, "dbQuery Fail", RegExReplace(_query , "\t", " ")), -1)
requestResult := MySql_Store_Result(_db)
if (requestResult = 0) { ; call must have been an insert or delete ... a select would return results to pass back
return
}
fieldCount := MySQL_num_fields(requestResult)
myfields := MySQL_fetch_fields(requestResult)
for each, fifi in myfields
{
MsgBox % "name: " fifi.Name() "`n org name: " fifi.OrgName() "`ntable: " fifi.Table() "`norg table: " fifi.OrgTable()
}
Loop
{
row := MySQL_fetch_row(requestResult)
if (!row)
break
; Get a pointer on a table of lengths (unsigned long)
lengths := MySQL_fetch_lengths(requestResult)
Loop %fieldCount%
{
length := GetUIntAtAddress(lengths, A_Index - 1)
fieldPointer := GetPtrAtAddress(row, A_Index - 1)
field := StrGet(fieldPointer, length, "CP0")
resultString := resultString . field
if (A_Index < fieldCount)
resultString := resultString . "|" ; seperator for fields
}
resultString := resultString . "`n" ; seperator for records
}
MySQL_free_result(requestResult)
resultString := RegExReplace(resultString , "`n$", "")
return resultString
}
;============================================================
; Escape mysql special characters
; This must be done to sql insert columns where the characters might contain special characters, such as user input fields
;
; Escape Sequence Character Represented by Sequence
; \' A single quote (“'”) character.
; \" A double quote (“"”) character.
; \n A newline (linefeed) character.
; \r A carriage return character.
; \t A tab character.
; \\ A backslash (“\”) character.
; \% A “%” character. Usually indicates a wildcard character
; \_ A “_” character. Usually indicates a wildcard character
; \b A backspace character.
;
; these 2 have not yet been included yet
; \Z ASCII 26 (Control+Z). Stands for END-OF-FILE on Windows
; \0 An ASCII NUL (0x00) character.
;
; example call:
; description := mysql_escape_string(description)
;============================================================
Mysql_escape_string(unescaped_string)
{
escaped_string := RegExReplace(unescaped_string, "\\", "\\") ; \
escaped_string := RegExReplace(escaped_string, "'", "\'") ; '
escaped_string := RegExReplace(escaped_string, "`t", "\t") ; \t
escaped_string := RegExReplace(escaped_string, "`n", "\n") ; \n
escaped_string := RegExReplace(escaped_string, "`r", "\r") ; \r
escaped_string := RegExReplace(escaped_string, "`b", "\b") ; \b
; these characters appear to insert fine in mysql
;escaped_string := RegExReplace(escaped_string, "%", "\%") ; %
;escaped_string := RegExReplace(escaped_string, "_", "\_") ; _
;escaped_string := RegExReplace(escaped_string, """", "\""") ; "
return escaped_string
}
/*
typedef struct st_mysql_field {
char *name; /* Name of column */
char *org_name; /* Original column name, if an alias */
char *table; /* Table of column if column was a field */
char *org_table; /* Org table name, if table was an alias */
char *db; /* Database for table */
char *catalog; /* Catalog for table */
char *def; /* Default value (set by mysql_list_fields) */
unsigned long length; /* Width of column (create length) */
unsigned long max_length; /* Max width for selected set */
unsigned int name_length;
unsigned int org_name_length;
unsigned int table_length;
unsigned int org_table_length;
unsigned int db_length;
unsigned int catalog_length;
unsigned int def_length;
unsigned int flags; /* Div flags */
unsigned int decimals; /* Number of decimals in field */
unsigned int charsetnr; /* Character set */
enum enum_field_types type; /* Type of field. See mysql_com.h for types */
void *extension;
} MYSQL_FIELD;
*/
/*
'mysql_port is a long
'mysql_unix port is a long (pointer)
'sizeof(MYSQL_FIELD)=32
Public Type API_MYSQL_FIELD
name As Long
table As Long
def As Long
type As API_enum_field_types
length As Long
max_length As Long
flags As Long
decimals As Long
End Type
*/
class MySQL_Field
{
ptr := 0
__new(ptr){
this.ptr := ptr
}
Name(){
adr := GetPtrAtAddress(this.ptr, 0)
return StrGet(adr, 255, "CP0")
}
OrgName(){
adr := GetPtrAtAddress(this.ptr, 4)
return StrGet(adr, 255, "CP0")
}
Table(){
adr := GetPtrAtAddress(this.ptr, 8)
return StrGet(adr, 255, "CP0")
}
OrgTable(){
adr := GetPtrAtAddress(this.ptr, 12)
return StrGet(adr, 255, "CP0")
}
}

27
Lib/readme.txt Normal file
View File

@ -0,0 +1,27 @@
AHK DBA - OOP Database Access Framework for AutoHotkey (_L)
Currently DBA supports SQLite, MySQL and ADO.
DBA is an object oriented wrapper around several different
databases/database providers to standardize the access interface.
It is similar to ADO from MS or the jdbc driver in Java.
Copyright (C) 2012 IsNull and other contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

203
Lib/sqlite3.def Normal file
View File

@ -0,0 +1,203 @@
EXPORTS
sqlite3_aggregate_context
sqlite3_aggregate_count
sqlite3_auto_extension
sqlite3_backup_finish
sqlite3_backup_init
sqlite3_backup_pagecount
sqlite3_backup_remaining
sqlite3_backup_step
sqlite3_bind_blob
sqlite3_bind_double
sqlite3_bind_int
sqlite3_bind_int64
sqlite3_bind_null
sqlite3_bind_parameter_count
sqlite3_bind_parameter_index
sqlite3_bind_parameter_name
sqlite3_bind_text
sqlite3_bind_text16
sqlite3_bind_value
sqlite3_bind_zeroblob
sqlite3_blob_bytes
sqlite3_blob_close
sqlite3_blob_open
sqlite3_blob_read
sqlite3_blob_reopen
sqlite3_blob_write
sqlite3_busy_handler
sqlite3_busy_timeout
sqlite3_changes
sqlite3_clear_bindings
sqlite3_close
sqlite3_collation_needed
sqlite3_collation_needed16
sqlite3_column_blob
sqlite3_column_bytes
sqlite3_column_bytes16
sqlite3_column_count
sqlite3_column_database_name
sqlite3_column_database_name16
sqlite3_column_decltype
sqlite3_column_decltype16
sqlite3_column_double
sqlite3_column_int
sqlite3_column_int64
sqlite3_column_name
sqlite3_column_name16
sqlite3_column_origin_name
sqlite3_column_origin_name16
sqlite3_column_table_name
sqlite3_column_table_name16
sqlite3_column_text
sqlite3_column_text16
sqlite3_column_type
sqlite3_column_value
sqlite3_commit_hook
sqlite3_compileoption_get
sqlite3_compileoption_used
sqlite3_complete
sqlite3_complete16
sqlite3_config
sqlite3_context_db_handle
sqlite3_create_collation
sqlite3_create_collation16
sqlite3_create_collation_v2
sqlite3_create_function
sqlite3_create_function16
sqlite3_create_function_v2
sqlite3_create_module
sqlite3_create_module_v2
sqlite3_data_count
sqlite3_db_config
sqlite3_db_filename
sqlite3_db_handle
sqlite3_db_mutex
sqlite3_db_readonly
sqlite3_db_release_memory
sqlite3_db_status
sqlite3_declare_vtab
sqlite3_enable_load_extension
sqlite3_enable_shared_cache
sqlite3_errcode
sqlite3_errmsg
sqlite3_errmsg16
sqlite3_exec
sqlite3_expired
sqlite3_extended_errcode
sqlite3_extended_result_codes
sqlite3_file_control
sqlite3_finalize
sqlite3_free
sqlite3_free_table
sqlite3_get_autocommit
sqlite3_get_auxdata
sqlite3_get_table
sqlite3_global_recover
sqlite3_initialize
sqlite3_interrupt
sqlite3_last_insert_rowid
sqlite3_libversion
sqlite3_libversion_number
sqlite3_limit
sqlite3_load_extension
sqlite3_log
sqlite3_malloc
sqlite3_memory_alarm
sqlite3_memory_highwater
sqlite3_memory_used
sqlite3_mprintf
sqlite3_mutex_alloc
sqlite3_mutex_enter
sqlite3_mutex_free
sqlite3_mutex_leave
sqlite3_mutex_try
sqlite3_next_stmt
sqlite3_open
sqlite3_open16
sqlite3_open_v2
sqlite3_os_end
sqlite3_os_init
sqlite3_overload_function
sqlite3_prepare
sqlite3_prepare16
sqlite3_prepare16_v2
sqlite3_prepare_v2
sqlite3_profile
sqlite3_progress_handler
sqlite3_randomness
sqlite3_realloc
sqlite3_release_memory
sqlite3_reset
sqlite3_reset_auto_extension
sqlite3_result_blob
sqlite3_result_double
sqlite3_result_error
sqlite3_result_error16
sqlite3_result_error_code
sqlite3_result_error_nomem
sqlite3_result_error_toobig
sqlite3_result_int
sqlite3_result_int64
sqlite3_result_null
sqlite3_result_text
sqlite3_result_text16
sqlite3_result_text16be
sqlite3_result_text16le
sqlite3_result_value
sqlite3_result_zeroblob
sqlite3_rollback_hook
sqlite3_rtree_geometry_callback
sqlite3_set_authorizer
sqlite3_set_auxdata
sqlite3_shutdown
sqlite3_sleep
sqlite3_snprintf
sqlite3_soft_heap_limit
sqlite3_soft_heap_limit64
sqlite3_sourceid
sqlite3_sql
sqlite3_status
sqlite3_step
sqlite3_stmt_busy
sqlite3_stmt_readonly
sqlite3_stmt_status
sqlite3_stricmp
sqlite3_strnicmp
sqlite3_table_column_metadata
sqlite3_test_control
sqlite3_thread_cleanup
sqlite3_threadsafe
sqlite3_total_changes
sqlite3_trace
sqlite3_transfer_bindings
sqlite3_update_hook
sqlite3_uri_boolean
sqlite3_uri_int64
sqlite3_uri_parameter
sqlite3_user_data
sqlite3_value_blob
sqlite3_value_bytes
sqlite3_value_bytes16
sqlite3_value_double
sqlite3_value_int
sqlite3_value_int64
sqlite3_value_numeric_type
sqlite3_value_text
sqlite3_value_text16
sqlite3_value_text16be
sqlite3_value_text16le
sqlite3_value_type
sqlite3_vfs_find
sqlite3_vfs_register
sqlite3_vfs_unregister
sqlite3_vmprintf
sqlite3_vsnprintf
sqlite3_vtab_config
sqlite3_vtab_on_conflict
sqlite3_wal_autocheckpoint
sqlite3_wal_checkpoint
sqlite3_wal_checkpoint_v2
sqlite3_wal_hook
sqlite3_win32_mbcs_to_utf8
sqlite3_win32_utf8_to_mbcs

BIN
Lib/sqlite3.dll Normal file

Binary file not shown.

BIN
Lib/x64/sqlite3.dll Normal file

Binary file not shown.

43
Main.ahk Normal file
View File

@ -0,0 +1,43 @@
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
;#Warn ; Recommended for catching common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir, %A_ScriptDir% ; Ensures a consistent starting directory.
SetBatchLines -1
#SingleInstance force
#NoTrayIcon
/* ===============================================================================
* LifeRPG r2 - Motivation and Confidence Building System
* Initial Release 9/20/2012
*
* Copyright (c) 2012 by Jayvant Javier Pujara
* Licensed under GPL
* JJPujara@gmail.com
*
*
* ===============================================================================
*/
#Include <DBA>
#Include Settings.ahk
#Include HUD.ahk
#Include Momentum.ahk
#Include Functions.ahk
#Include MenuBar.ahk
#Include ProjectsView.ahk
#Include Hotkeys.ahk
#Include Search.ahk
#Include ProjectManage.ahk
#Include ProjectRemove.ahk
#Include ProjectComplete.ahk
#Include SubprojectAdd.ahk
#Include SkillsView.ahk
#Include ProjectLog.ahk
#Include ProfileEdit.ahk
#Include SettingsEdit.ahk
#Include About.ahk
#Include Help.ahk
#Include FileManage.ahk
MenuHandler:
return

39
MenuBar.ahk Normal file
View File

@ -0,0 +1,39 @@
; Menu Bar: ===================================================================================
Gui, 1:Default
; File:==========================================
Menu, FileMenu, Add, &New...`tCtrl+N, FileNew
Menu, FileMenu, Add, &Open...`tCtrl+O, FileOpen
;~ ; Create another menu destined to become a submenu of the above menu.
;~ Menu, Submenu1, Add, Item1, MenuHandler
;~ Menu, Submenu1, Add, Item2, MenuHandler
;~ ; Create a submenu in the first menu (a right-arrow indicator). When the user selects it, the second menu is displayed.
;~ Menu, FileMenu, Add, Recently Opened, :Submenu1
;~ ^ Leave for later release
Menu, FileMenu, Add
Menu, FileMenu, Add, E&xit, GuiClose
; View:===========================================
Menu, ViewMenu, Add, &Skill Stats...`tCtrl+K, SkillsView
Menu, ViewMenu, Add, &Project Log...`tCtrl+L, ProjectLog
; Options:=========================================
Menu, OptionsMenu, Add, &Profile...`tCtrl+P, ProfileEdit
Menu, OptionsMenu, Add, &Settings...`tCtrl+S, SettingsEdit
; Help:===========================================
Menu, HelpMenu, Add, &Reference..., ReferenceHotkeys
Menu, HelpMenu, Add, &Discussion, Discussion
Menu, HelpMenu, Add
Menu, HelpMenu, Add, &About, About
; Attach the sub-menus that were created above.
Menu, MenuBar, Add, &File, :FileMenu
Menu, MenuBar, Add, &View, :ViewMenu
Menu, MenuBar, Add, &Options, :OptionsMenu
Menu, MenuBar, Add, &Help, :HelpMenu
Gui, Menu, MenuBar

41
Momentum.ahk Normal file
View File

@ -0,0 +1,41 @@
; Momentum Bar: ==================================================
; Get date momentum bar last updated:
MomentumLastUpdate := ProfileGet("MMTLastUpdate")
MomentumTimer()
MomentumTimer(){
global db, HUD_MomentumBar, HUD_MomentumPerc, MomentumLastUpdate
; Start timer to check current date:
gosub MomentumUpdate
SetTimer, MomentumUpdate, 1000
return
MomentumUpdate:
CurrentDate := FormatTime(,"yyyyMMdd")
; When current date does not match date momentum bar last updated,
if (MomentumLastUpdate <> CurrentDate) ; Momentum bar needs to be lowered:
{
; Compare both dates to see how long ago in days last update was:
DateDiff := CurrentDate
DateDiff -= MomentumLastUpdate, Days
; Multiply difference in days by percentage loss in MMT bar,
MMTLoss := DateDiff * 15
; and move MMT down:
; Check the database to see what the current momentum level is.
MMTCurrent := ProfileGet("momentum")
; Calculate current level minus calculated loss.
MMTNew := MMTCurrent - MMTLoss
; If result is 0 or less than 0, just make the MMT level 0:
if (MMTNew <= 0)
MMTNew = 0
; Update database and HUD momentum bar:
db.Query("UPDATE profile SET value = " . MMTNew . " WHERE setting = 'momentum'") ; update momentum value in database
db.Query("UPDATE profile SET value = " . CurrentDate . " WHERE setting = 'MMTLastUpdate'") ; update when MMT last updated
MMTNow := ProfileGet("momentum")
GuiControl, HUD_Momentum:, HUD_MomentumBar, % MMTNow
GuiControl, HUD_Momentum:, HUD_MomentumPerc, % MMTNow . "%"
MomentumLastUpdate := ProfileGet("MMTLastUpdate")
}
return
}

93
OFL.txt Normal file
View File

@ -0,0 +1,93 @@
Copyright (c) 2011, Cyreal (www.cyreal.org),
with Reserved Font Name "Electrolize".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

41
ProfileEdit.ahk Normal file
View File

@ -0,0 +1,41 @@
; Edit User Profile:================================================================
ProfileEdit:
; Initialize modal child GUI window:
GuiChildInit("Profile")
; Define size and title etc:
ProfileW = 230
ProfileH = 140
ProfileX := CenterX(ProfileW)
ProfileY := CenterY(ProfileH)
ProfileTitle := "Edit Your Profile"
; Create content and fields:
; Name:
Gui, Profile:Add, Text, , Name:
Gui, Profile:Add, Edit, vProfileNameEdit w120 Limit21 r1, % ProfileGet("name")
; Title:
Gui, Profile:Add, Text, , Title:
Gui, Profile:Add, Edit, vProfileTitleEdit w200 r1, % ProfileGet("title")
; Save button:
Gui, Profile:Add, Button, Default y+10 w80 gProfileSubmit, Save
; Cancel:
Gui, Profile:Add, Button, x+10 w80 gProfileGuiClose, Cancel
; Show GUI:
Gui, Show, w%ProfileW% h%ProfileH% x%ProfileX% y%ProfileY%, %ProfileTitle%
; hang out here until user saves or closes:
return
; What do to when user submits:
ProfileSubmit:
Gui, Profile:Submit, NoHide
db.Query("UPDATE profile SET value = '" . SafeQuote(ProfileNameEdit) . "' WHERE setting = 'name'")
db.Query("UPDATE profile SET value = '" . SafeQuote(ProfileTitleEdit) . "' WHERE setting = 'title'")
GuiControl, HUD_Level:, HUD_Name, % ProfileGet("name")
GuiControl, HUD_Level:, HUD_Text, % HUD_LevelText . LevelCheck() . " " . ProfileGet("title")
; What to do when user closes or escapes window:
ProfileGuiClose:
ProfileGuiEscape:
GuiChildClose("Profile") ; Close up GUI child window.
return

88
ProjectComplete.ahk Normal file
View File

@ -0,0 +1,88 @@
;~ ===============================================================================
;~ Confirm Project completion:
CompleteProject:
Selection := LV_GetNext("","F")
LV_GetText(SelectedProjectID, Selection, 1)
LV_GetText(ProjectCompletionState, Selection, 2)
If (SelectedProjectID == "ID" || ProjectCompletionState = "Done")
{
return
}
else
{
GuiMsgBox("CompleteProject", "Complete Project", "Done with project?")
return
CompleteProjectYes:
Gui, CompleteProject:Submit, NoHide
GuiChildClose("CompleteProject")
CompleteProject(SelectedProjectID)
MomentumPrev := ProfileGet("momentum")
if (MomentumPrev < 100)
{
Anim := 100 - MomentumPrev
Loop % Anim
{
GuiControl, HUD_Momentum:, HUD_MomentumBar, % MomentumPrev + A_Index
GuiControl, HUD_Momentum:, HUD_MomentumPerc, % MomentumPrev + A_Index . "%"
Sleep 10
}
ProfileSet("momentum", 100)
Notification(Uppercase("Momentum Restored"), "Your MMT is back to 100%")
}
gosub FilterUpdate
RefreshSkillsList(FilterSkillSelected)
return
CompleteProjectNo:
CompleteProjectGuiClose:
CompleteProjectGuiEscape:
GuiChildClose("CompleteProject")
return
}
return
CompleteProject(SelectedProjectID)
{
global db, Difficulties, Awards
; Get the difficulty to know how many points to award and the skill to show in notification
CompletedProject := db.OpenRecordSet("SELECT * FROM projects WHERE id = " SelectedProjectID)
while (!CompletedProject.EOF)
{
DifficultyToAward := CompletedProject["difficulty"]
SkillToIncrease := CompletedProject["skill"]
CompletedProject.MoveNext()
}
CompletedProject.Close()
; Mark project as done:
db.Query("UPDATE projects SET difficulty = 'Done', importance = '', dateDone = " . A_Now . ", levelDone = " . LevelGet() . " WHERE id = " SelectedProjectID)
; Get the level count for the skill if the project has one:
if (SkillToIncrease)
{
Table := db.Query("SELECT COUNT(skill) FROM projects WHERE skill = '" . SkillToIncrease . "' AND difficulty = 'Done'")
columnCount := table.Columns.Count()
for each, row in table.Rows
{
Loop, % columnCount
SkillLevel := row[A_index]
}
}
; Get the amount of points to award for the chosen level
for Num, Difficulty in Difficulties
{
if (DifficultyToAward = Difficulty)
for Key, Award in Awards
{
if (Num = Key)
AwardGiven := Award
}
}
UpdateProgress(DifficultyToAward . " Achievement", AwardGiven)
if (SkillToIncrease)
Notification("SKILL INCREASED", SkillToIncrease . " increased to " . SkillLevel)
}

78
ProjectLog.ahk Normal file
View File

@ -0,0 +1,78 @@
; Project Log Dialog/Window: ============================================
;#If !WinActive(ProjectLogTitle . " ahk_class AutoHotkeyGUI") && WinActive("LifeRPG ahk_class AutoHotkeyGUI")
;^l::
ProjectLog:
ProjectLogTitle := "Project Log"
GuiChildInit("ProjectLog")
;Notification(FilterSkillSelected,"")
Gui, ProjectLog:Add, Button, gProjectLogDateMoveBack, <
Gui, ProjectLog:Add, DateTime, vProjectLogDate gProjectLogRefresh x+1, LongDate
Gui, ProjectLog:Add, Button, gProjectLogDateMoveForward x+1, >
ColProjLogTime = 1
ColProjLogName = 2
ColProjLogSkill = 3
ColProjLogLevel = 4
PLw = 600
PLh = 400
Gui, ProjectLog:Add, ListView, y+1 xm w%PLw% r10 -Multi vProjectLogList gProjectLogRefresh, Time|Project|Skill|Level ; Set up skills list LV
PLx := CenterX(PLw)
PLy := CenterY(PLh)
gosub ProjectLogRefresh
Gui, ProjectLog:Show, x%PLx% y%PLy%, % ProjectLogTitle ;Project Log ; Show Project Log window
Send {Right 2}
return
ProjectLogRefresh:
Gui, ProjectLog:ListView, ProjectLogList
GuiControlGet, ProjectLogDate, , ProjectLogDate
LV_Delete()
ProjectLogSet := db.OpenRecordSet("SELECT * FROM projects WHERE dateDone LIKE '" . FormatTime(ProjectLogDate,"yyyyMMdd") . "%'")
while (!ProjectLogSet.EOF)
{
ProjectLogTime := ProjectLogSet["dateDone"]
ProjectLogName := ProjectLogSet["project"]
ProjectLogSkill := ProjectLogSet["skill"]
ProjectLogLevel := ProjectLogSet["levelDone"]
LV_Add("", ProjectLogTime, ProjectLogName, ProjectLogSkill, ProjectLogLevel)
ProjectLogSet.MoveNext()
}
ProjectLogSet.Close()
GuiControl, -Redraw, ProjectLogList
LV_ModifyCol(ColProjLogTime, "sortasc")
Loop % LV_GetCount()
{
LV_GetText(PLRow, A_Index, ColProjLogTime)
LV_Modify(A_Index, "", FormatTime(PLRow, "Time"))
}
LV_ModifyCol()
Loop % LV_GetCount("Col")
{
LV_ModifyCol(A_Index, "AutoHDR")
}
GuiControl, +Redraw, ProjectLogList
return
ProjectLogDateMoveBack:
ProjectLogDateMove("Backward")
return
ProjectLogDateMoveForward:
ProjectLogDateMove("Forward")
return
ProjectLogDateMove(Direction)
{
GuiControlGet, ProjLogCurrDate, , ProjectLogDate
if (Direction = "Forward")
ProjLogCurrDate += 1, Days
else if (Direction = "Backward")
ProjLogCurrDate += -1, Days
GuiControl, ProjectLog:, ProjectLogDate, % ProjLogCurrDate
gosub ProjectLogRefresh
}
ProjectLogGuiEscape:
ProjectLogGuiClose:
GuiChildClose("ProjectLog")
return

215
ProjectManage.ahk Normal file
View File

@ -0,0 +1,215 @@
; QuickAdd:
#If !WinExist("ahk_group exclude")
^!d::
Action := "QuickDone"
ProjectManage(Action)
return
#If
#If !WinExist("ahk_group exclude")
^!a::
Action := "QuickAdd"
ProjectManage(Action)
return
#If
; Add a new project:
AddProject:
Action := "Add"
ProjectManage(Action)
return
; Edit a selected project:
EditProject:
Action := "Edit"
ProjectManage(Action)
return
SkillAutoComplete:
Critical
Gui, ProjectManager:Submit, NoHide
If (!GetKeyState("BackSpace","P") && ProjectSkillEdit && Pos := InStr(SkillsDB, "|" . ProjectSkillEdit))
{
Found := SubStr(SkillsDB, pos+1, InStr(SkillsDB, "|", 1, Pos + 1) - Pos - 1)
GuiControl, ProjectManager:Text, ProjectSkillEdit, %Found%
SendInput % "{End}" . "+{Left " . StrLen(Found) - StrLen(ProjectSkillEdit) . "}"
}
return
ProjectManagerSubmit:
Gui, ProjectManager:Submit, NoHide
if (ProjectNameEdit = "")
{
MsgBox, 8192, Error, Can't make a project with no name!
return
}
if (ProjectSkillEdit = "All" || ProjectSkillEdit = "None")
{
MsgBox, 8192, Error, "All" and "None" can't be used as skill names!
return
}
if (Action = "Add" || Action = "QuickDone" || Action = "QuickAdd")
{
Record := {}
Record.Project := ProjectNameEdit
Record.Difficulty := ProjectDifficultyEdit
Record.Importance := ProjectImportanceEdit
Record.Skill := Capitalize(ProjectSkillEdit)
Record.dateEntered := A_Now
S := db.Insert(Record, "projects")
if (Action = "QuickDone" || Action = "QuickAdd")
{
Gui, ProjectManager:Cancel
Gui, 1:Default
if (Action = "QuickDone")
{
table := db.Query("SELECT MAX(id) FROM projects")
columnCount := table.Columns.Count()
for each, row in table.Rows
{
Loop, % columnCount
QuickID := row[A_index]
}
CompleteProject(QuickID)
}
}
}
else if (Action = "Edit")
{
db.Query("UPDATE projects SET project = '" SafeQuote(ProjectNameEdit) "' WHERE ID = " SelectedProjectID )
db.Query("UPDATE projects SET difficulty = '" SafeQuote(ProjectDifficultyEdit) "' WHERE ID = " SelectedProjectID )
db.Query("UPDATE projects SET importance = '" SafeQuote(ProjectImportanceEdit) "' WHERE ID = " SelectedProjectID )
; Make sure skill is title cased, just to look good:
StringUpper, ProjectSkillEdit, ProjectSkillEdit, T
db.Query("UPDATE projects SET skill = '" SafeQuote(ProjectSkillEdit) "' WHERE ID = " SelectedProjectID )
}
;UpdateList(Selection, FilterImportanceSelected, FilterSkillSelected)
;Notification(Selection . FilterImportanceSelected . FilterSkillSelected, "")
;GuiControlGet, FilterSkillSelected, , FilterSkill
if (Action = "Add" || Action = "Edit")
{
GuiChildClose("ProjectManager")
}
else if (Action = "QuickAdd" || Action = "QuickDone")
{
Gui, ProjectManager:Cancel
Gui, 1:Default
}
gosub FilterUpdate
RefreshSkillsList(FilterSkillSelected)
return
; Fall through below to close window.
ProjectManagerGuiEscape:
ProjectManagerGuiClose:
if (Action = "Add" || Action = "Edit")
{
GuiChildClose("ProjectManager")
}
else if (Action = "QuickAdd" || Action = "QuickDone")
{
Gui, ProjectManager:Cancel
Gui, 1:Default
}
return
ProjectManage(Action)
{
;global db, ProjectNameEdit, ProjectDifficultyEdit, ProjectImportanceEdit, ProjectSkillEdit
global
ProjectNameEdit =
ProjectDifficultyEdit =
ProjectImportanceEdit =
ProjectSkillEdit =
; Get the row number of the selected project from the main project ListView:
Selection := LV_GetNext("","F")
; If editing, get the ID number of that project:
if (Action = "Edit")
{
LV_GetText(SelectedProjectID, Selection, 1) ; Get project ID number from hidden column of ListView
; If no row is selected and edit is called, do nothing and go back:
If (SelectedProjectID == "ID")
{
return
}
else ; Get the data for the selected project to populate the edit fields:
{
ProjectInfo := db.OpenRecordSet("SELECT * FROM projects WHERE id = " SelectedProjectID )
while(!ProjectInfo.EOF)
{
ProjectName := ProjectInfo["project"]
ProjectDifficulty := ProjectInfo["difficulty"]
ProjectImportance := ProjectInfo["importance"]
ProjectSkill := ProjectInfo["skill"]
ProjectInfo.MoveNext()
}
ProjectInfo.Close()
}
}
else if (Action = "Add" || Action = "QuickDone" || Action = "QuickAdd")
{
ProjectName =
ProjectDifficulty =
ProjectImportance =
ProjectSkill =
}
; Build the GUI window to either add or edit a project:
; Initiate a modal child window owned by the main window (by default):
if (Action = "Add" || Action = "Edit")
GuiChildInit("ProjectManager")
else if (Action = "QuickDone" || Action = "QuickAdd")
{
Gui, ProjectManager:New
Gui, ProjectManager:Default
}
; Name of project:
Gui, ProjectManager:Add, Text, , &Project Name:
Gui, ProjectManager:Add, Edit, vProjectNameEdit W270 r1, %ProjectName%
; Difficulty:
Gui, ProjectManager:Add, Text, , &Difficulty:
DifficultyList := ListDifficulties(ProjectDifficulty)
Gui, ProjectManager:Add, DropDownList, vProjectDifficultyEdit, %DifficultyList%
; Importance:
if (Action <> "QuickDone")
{
Gui, ProjectManager:Add, Text, , &Importance:
PriorityList := ListPriorities(ProjectImportance)
Gui, ProjectManager:Add, DropDownList, vProjectImportanceEdit, %PriorityList%
}
; Skill:
Gui, ProjectManager:Add, Text, x+20 y52, Set S&kill:
; To set this, we need to go through all the skills on the table and get all the distinct skills:
SkillsDB := ListSkills(ProjectSkill)
Gui, ProjectManager:Add, ComboBox, vProjectSkillEdit gSkillAutoComplete w130 r7, % SkillsDB ;% ListSkills(ProjectSkill) ;Diplomacy|Art|Piracy|Cleaning|Hunting
; Submit button:
Gui, ProjectManager:Add, Button, Default gProjectManagerSubmit w80 x15 y+70, &Submit
; Set size of this window:
Width = 300
Height = 200
; Calculate position for centering this child GUI window on wherever the main project list window is:
xc := CenterX(300)
yc := CenterY(200)
; Show window:
StringUpper, Action, Action, T
if (Action = "QuickDone")
{
StringReplace, PMTitle, Action, done, Done
}
else if (Action = "QuickAdd")
StringReplace, PMTitle, Action, add, Add
else
PMTitle := Action
Gui, ProjectManager:Show, w%Width% h%Height% x%xc% y%yc%, %PMTitle% Project
return
}
; Kind of duplicate with other skills get function I just made

33
ProjectRemove.ahk Normal file
View File

@ -0,0 +1,33 @@
;~ ===============================================================================
;~ Confirm project deletion/removal:
RemoveProject:
Selection := LV_GetNext("","F")
LV_GetText(SelectedProjectID, Selection, 1)
If (SelectedProjectID == "ID")
{
return
}
else
{
GuiMsgBox("RemoveProject", "Remove Project", "Delete this project?")
return
RemoveProjectYes:
Gui, RemoveProject:Submit, NoHide
db.Query("DELETE FROM projects WHERE id = " SelectedProjectID )
GuiChildClose("RemoveProject")
RefreshSkillsList(FilterSkillSelected)
;Notification("RefreshSkillList(",FilterSkillSelected)
gosub FilterUpdate
;Notification(Selection . ", " . FilterImportanceSelected . ", " . FilterSkillSelected,"")
UpdateList(Selection, FilterImportanceSelected, FilterSkillSelected)
return
RemoveProjectNo:
RemoveProjectGuiClose:
RemoveProjectGuiEscape:
GuiChildClose("RemoveProject")
return
}
return

78
ProjectsView.ahk Normal file
View File

@ -0,0 +1,78 @@
;~ ===============================================================================
;~ Building and Displaying the Main GUI:
Send !{F2}
; Improves performance for adding elements to ListView:
CountUp := db.Query("SELECT * FROM projects")
CountUp := CountUp.Rows.Count()
WinVis = true
; Buttons for Main Gui Window:
Gui, 1:Default
Gui, Add, Button, y3 x15 gAddProject, &Add Project ; Press Alt+A to add project
Gui, Add, Button, y3 x+1 gEditProject, &Edit Project ; Edit project (Alt+E, and so on)
Gui, Add, Button, y3 x+1 gAddSubproject, Su&bproject ; Create subproject for selected task
Gui, Add, Button, y3 x+1 gCompleteProject, Project &Done ; Confirm project is done
Gui, Add, Button, y3 x+1 gRemoveProject, &Remove Project ; Confirm project deletion
;~ Search bar:
Gui, Add, Text, x15 y+1, &Search:%A_Space% ; Pressing Alt+C once focuses on search box
try {
Gui, Add, Edit, vSearchQuery gSearch x+1 w320 h20,
Gui, Add, Button, gClearSearch vClearSearchButton x+1, &Clear ; Pressing Alt+C again clears the search and thus resets the ListView
;~ Filter view by importance:
Gui, Add, Text, x+10 vImpChooseText, &Importance:
Gui, Add, DropDownList, vImportanceChoose gImportanceUpdate x+5 w60, All|| ; Filtering subroutines are located in Search.ahk
GuiControl, , ImportanceChoose, % ListPriorities("All")
; Filter view by skill:
Gui, Add, Text, x+10 vSkillChooseText, S&kill:
Gui, Add, DropDownList, vFilterSkill gFilterSkillUpdate x+5 r10, All||None|
GuiControl, , FilterSkill, % ListSkills()
; Show done or not:
Gui, Add, Checkbox, vFilterShowDone gFilterUpdate x+10, Show do&ne
;~ ListView:
Gui, Add, ListView, x0 y+15 r20 Grid AltSubmit -Multi Count%CountUp% vMainList hwndColored_LV_1, ID|Difficulty|Project|Importance|Parent|Color
}
Colored_LV_1_BG = 6
GuiControl, Focus, SearchQuery ; Focus on search bar by default
Gui, Show, w827 h600, %AppTitle% ; Show the GUI we've created
UpdateList() ; Show all projects
Gui, +Resize +MinSize621x ; Make GUI resizable
return
;~ ===============================================================================
;~ Main GUI Resizing information:
GuiSize:
if A_EventInfo = 1 ; The window has been minimized. No action needed.
return
; Otherwise, the window has been resized or maximized. Resize the controls to match.
GuiControl, Move, Mainlist, % "H" . (A_GuiHeight - 55) . " W" . (A_GuiWidth)
; Resize search bar to fit dropdown filter controls:
if (A_GuiWidth > 811) ;827)
{
SearchBarWidth := Round(A_GuiWidth*.40)
}
else if (A_GuiWidth <= 811)
{
SearchBarWidth := Round(A_GuiWidth*.20)
}
GuiControl, MoveDraw, SearchQuery, % "w" SearchBarWidth
GuiControl, MoveDraw, ClearSearchButton, % "x" 50 + SearchBarWidth + 10
GuiControl, MoveDraw, ImpChooseText, % "x" 50 + SearchBarWidth + 55
GuiControl, MoveDraw, ImportanceChoose, % "x" 50 + SearchBarWidth + 120
GuiControl, MoveDraw, SkillChooseText, % "x" 50 + SearchBarWidth + 190
GuiControl, MoveDraw, FilterSkill, % "x" 50 + SearchBarWidth + 220
GuiControl, MoveDraw, FilterShowDone, % "x" 50 + SearchBarWidth + 350
return
;~ ===============================================================================
;~ What to do when main window is closed:
GuiClose:
ExitApp

168
Res/.gitignore vendored Normal file
View File

@ -0,0 +1,168 @@
*.exe
*.org
*.wav
*.db
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
Res/WP_RPG_VG.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

45
Search.ahk Normal file
View File

@ -0,0 +1,45 @@
;~ ===============================================================================
;~ Filter ListView by priority:
;~ UpdateList(,FilterImportanceSelected,FilterSkillSelected)
;~ return
;~ ===============================================================================
; Filter main projects ListView by available skills:
FilterUpdate:
ImportanceUpdate:
FilterSkillUpdate:
GuiControlGet, FilterImportanceSelected, 1:, ImportanceChoose
GuiControlGet, FilterSkillSelected, 1:, FilterSkill
GuiControlGet, FilterShowDone, 1:, FilterShowDone
UpdateList(Selection,FilterImportanceSelected,FilterSkillSelected)
return
;~ ===============================================================================
;~ Clear the search bar and reset the ListView:
ClearSearch:
Critical
GuiControl, , ImportanceChoose, |All||
GuiControl, , ImportanceChoose, % ListPriorities()
GuiControl, , FilterSkill, |All||None| ; Put | at start to reset out the DDL
GuiControl, , FilterSkill, % ListSkills()
GuiControl, , FilterShowDone, 0
GuiControl, , SearchQuery
GuiControl, Focus, SearchQuery
return
;~ ===============================================================================
;~ Search subroutine:
Search:
Critical
GuiControlGet, SearchString, , SearchQuery
GuiControlGet, FilterImportanceSelected, , ImportanceChoose
GuiControlGet, FilterSkillSelected, , FilterSkill
GuiControlGet, FilterShowDone,
UpdateList(Selection, FilterImportanceSelected, FilterSkillSelected)
return

86
Settings.ahk Normal file
View File

@ -0,0 +1,86 @@
;~ Autoload and initial settings loading section:============================================
;~ "Character" class, disabled for now b/c have to make HUD progress bar automatically fit:
;CharacterClass := "Artist"
;~ Set icon for window corner:
IconFile := "res/WP_RPG_VG.ico"
if FileExist(IconFile)
Menu, Tray, Icon, %IconFile%
Menu, Tray, NoStandard
;~ Project difficulties:
Difficulties := ["Really Easy", "Pretty Easy", "Medium", "Hard"]
; Award points for each difficulty:
Awards := [5, 10, 25, 100]
; Difficulty colors:
Colors := [BGR("ADFF2F"), BGR("87CEFA"), BGR("FFD700"), BGR("FF6347")]
;~ Priorities:
Priorities := ["Must", "Should", "Could", "Want"]
BGR(RGB)
{
R := SubStr(RGB, 1, 2)
G := SubStr(RGB, 3, 2)
B := SubStr(RGB, 5, 2)
return "0x" . B . G . R
}
;~ The window title text:
AppTitle := "LifeRPG"
;~ Make it easier for the script to identify its own window if need be:
WindowFind := AppTitle . " ahk_class AutoHotkeyGUI"
;~ Level up sound location:
LevelUpSound := SettingGet("Sound", "LevelUp")
if (LevelUpSound = "Error" || !FileExist(LevelUpSound))
LevelUpSound := ""
; Open connection to SQLite database:
ConnectionString := SettingGet("File", "LastOpened") ; Get last used database from settings.
if (ConnectionString = "Error" || ConnectionString = "") ; That means it's the first time it was run, so load the default db.
ConnectionString := "data/LifeRPG.db"
AskLoad:
if (!FileExist(ConnectionString)) ; User must have deleted or moved last used db, so ask to pick another or make a new one.
{
Gui +OwnDialogs
MsgBox, 51, %AppTitle% Error, Last loaded database `n"%connectionString%" `nwas not found.`n`nWould you like to open a different database?`nIf not, you must create a new one before you can continue.`n`nOtherwise, hit Cancel to quit the program.
IfMsgBox Yes
{
gosub FileOpen
if (!IsObject(db))
gosub AskLoad
}
else IfMsgBox No
{
gosub FileNew
if (!IsObject(db))
gosub AskLoad
}
else
ExitApp
}
else ; we can go ahead and load the last used db:
db := DBA.DataBaseFactory.OpenDataBase("SQLite", ConnectionString)
; Hotkey do not activate list:
GroupAdd, exclude, New projects database
GroupAdd, exclude, Open a projects database
GroupAdd, exclude, Add Project ahk_class AutoHotkeyGUI
GroupAdd, exclude, Reference ahk_class AutoHotkeyGUI
GroupAdd, exclude, Edit Project ahk_class AutoHotkeyGUI
GroupAdd, exclude, Add Subproject ahk_class AutoHotkeyGUI
GroupAdd, exclude, Remove Project ahk_class AutoHotkeyGUI
GroupAdd, exclude, Complete Project ahk_class AutoHotkeyGUI
GroupAdd, exclude, QuickDone Project ahk_class AutoHotkeyGUI
GroupAdd, exclude, QuickAdd Project ahk_class AutoHotkeyGUI
GroupAdd, exclude, Skill Stats ahk_class AutoHotkeyGUI
GroupAdd, exclude, About ahk_class AutoHotkeyGUI
GroupAdd, exclude, Edit Your Profile ahk_class AutoHotkeyGUI
GroupAdd, exclude, Project Log ahk_class AutoHotkeyGUI
SettingsTitle := "Edit LifeRPG Settings"
GroupAdd, exclude, % SettingsTitle . " ahk_class AutoHotkeyGUI"

59
SettingsEdit.ahk Normal file
View File

@ -0,0 +1,59 @@
; Edit app settings: ===================================================
;#If !WinActive("Skill Stats ahk_class AutoHotkeyGUI") && WinActive("LifeRPG ahk_class AutoHotkeyGUI")
;^s::
SettingsEdit:
GuiChildInit("SettingsEdit")
; Define size and positions:
SettingsW = 400
SettingsH = 140
SettingsX := CenterX(SettingsW)
SettingsY := CenterY(SettingsH)
; Create content and fields:
; Level Up Sound:
Gui, SettingsEdit:Add, Text, , Select sound file to use for &Level-Up Sound:
SettingLocationLevelUp := SettingGet("Sound","LevelUp")
if (SettingLocationLevelUp = "Error")
SettingLocationLevelUp := ""
Gui, SettingsEdit:Add, Edit, vSettingsEditLevelUpEdit w300 r1, % SettingLocationLevelUp
Gui, SettingsEdit:Add, Button, x+1 gLevelUpSoundBrowse w80, &Browse
Gui, SettingsEdit:Add, Button, y+1 xm gSoundTestLevelUp w40, Test
Gui, SettingsEdit:Add, Button, x+1 gSoundTestLevelUpStop w40, Stop
; Save button:
Gui, SettingsEdit:Add, Button, Default y+30 xm w80 gSettingsEditSubmit, &Save
; Cancel:
Gui, SettingsEdit:Add, Button, x+10 w80 gSettingsEditGuiClose, &Cancel
; Show GUI:
Gui, SettingsEdit:Show, w%SettingsW% h%SettingsH% x%SettingsX% y%SettingsY%, %SettingsTitle%
; hang out here until user saves or closes:
return
LevelUpSoundBrowse:
Gui +OwnDialogs
FileSelectFile, NewLocationLevelUpSound, , , Select a sound file , Audio (*.wav; *.mp3)
GuiControl, SettingsEdit:, SettingsEditLevelUpEdit, % NewLocationLevelUpSound
return
SoundTestLevelUp:
GuiControlGet, LUSFile, SettingsEdit:, SettingsEditLevelUpEdit
SoundPlay % LUSFile
return
SoundTestLevelUpStop:
SoundPlay 341589134759384759348.wav
return
; What do to when user submits:
SettingsEditSubmit:
Gui, SettingsEdit:Submit, NoHide
SettingSet("Sound","LevelUp", SettingsEditLevelUpEdit)
LevelUpSound := SettingsEditLevelUpEdit
; What to do when user closes or escapes window:
SettingsEditGuiClose:
SettingsEditGuiEscape:
GuiChildClose("SettingsEdit") ; Close up GUI child window.
return

85
SkillsView.ahk Normal file
View File

@ -0,0 +1,85 @@
; View the user's current levels in all the skills he has completed projects in:
SkillsView:
GuiChildInit("SkillsView")
;Notification(FilterSkillSelected,"")
ColSkillName = 1
ColSkillLevel = 2
Gui, SkillsView:Add, ListView, w300 r20 -Multi gSkillsListEvent vSkillsListView, Skill|Level ; Set up skills list LV
Gui, SkillsView:Add, Button, Hidden Default w0 h0 gSkillsListEvent, OK
SVw = 300
SVh = 400
SVx := CenterX(SVw)
SVy := CenterY(SVh)
; Populate the Skill Stats ListView with skills and stats:
; 1. Get the skills count for all done items from the projects table
; First we need to add all skills to the LV
; SELECT DISTINCT skill FROM projects WHERE difficulty <> 'Done' ORDER BY skill
; 2. Add to ListView
SkillsList := db.OpenRecordSet("SELECT DISTINCT skill FROM projects WHERE skill IS NOT NULL AND skill <> '' ORDER BY skill")
while (!SkillsList.EOF)
{
SkillListName := SkillsList["skill"]
LV_Add("", SkillListName)
RowNum := A_Index
Table := db.Query("SELECT COUNT(skill) FROM projects WHERE skill = '" . SkillListName . "' AND difficulty = 'Done'")
columnCount := table.Columns.Count()
for each, row in table.Rows
{
Loop, % columnCount
;msgbox % row[A_index]
LV_Modify(RowNum,"Col2", row[A_Index])
}
SkillsList.MoveNext()
}
SkillsList.Close()
;LV_ModifyCol()
LV_ModifyCol(ColSkillLevel, "AutoHDR integer sortdesc")
Loop % LV_GetCount("Col")
{
LV_ModifyCol(A_Index, "AutoHDR")
}
Gui, SkillsView:Show, x%SVx% y%SVy%, Skill Stats ; Show skills list window
SkillCount := LV_GetCount()
if (FilterSkillSelected = "All" || FilterSkillSelected = "None" || !FilterSkillSelected)
return
else
{
Loop % SkillCount
{
HighlightLine := A_Index
LV_GetText(SkillToHighlight, HighlightLine, ColSkillName)
if (SkillToHighlight = FilterSkillSelected)
{
LV_Modify(HighlightLine, "Focus Select Vis")
}
}
}
return
SkillsListEvent: ; Jump to double-clicked skill
GuiControlGet, FocusedControl, FocusV
if (FocusedControl = "SkillsListView")
{
if (LV_GetNext(0, "Focused") = 0)
return
else
LV_GetText(SDC, LV_GetNext(0, "Focused"))
}
else if (A_GuiEvent = "DoubleClick" )
LV_GetText(SDC, A_EventInfo)
GuiChildClose("SkillsView")
RefreshSkillsList(SDC)
UpdateList(,,FilterSkillSelected)
return
SkillsViewGuiEscape:
SkillsViewGuiClose:
GuiChildClose("SkillsView")
return
ExploreObj(Obj, NewRow="`n", Equal=" = ", Indent="`t", Depth=12, CurIndent="") {
for k,v in Obj
ToReturn .= CurIndent . k . (IsObject(v) && depth>1 ? NewRow . ExploreObj(v, NewRow, Equal, Indent, Depth-1, CurIndent . Indent) : Equal . v) . NewRow
return RTrim(ToReturn, NewRow)
}

75
SubprojectAdd.ahk Normal file
View File

@ -0,0 +1,75 @@
;~ ===============================================================================
;~ Add subproject for a selected project:
AddSubproject:
Selection := LV_GetNext("","F")
LV_GetText(SelectedProjectID, Selection, 1)
If (SelectedProjectID == "ID")
{
return
}
else
{
ProjectInfo := db.OpenRecordSet("SELECT * FROM projects WHERE id = " SelectedProjectID )
while(!ProjectInfo.EOF)
{
ParentProjectName := ProjectInfo["project"]
ProjectInfo.MoveNext()
}
ProjectInfo.Close()
;UpdateList(Selection)
}
GuiChildInit("AddSubproject")
Gui, AddSubproject:Add, Text, w270, Parent Project:`n%ParentProjectName%
;Gui, AddSubproject:Add, Text, vParentName W270, %ParentProjectName%
Gui, AddSubproject:Add, Text, , Subproject Name:
Gui, AddSubproject:Add, Edit, vProjectName W270,
Gui, AddSubproject:Add, Text, section, &Difficulty:
Gui, AddSubproject:Add, DropDownList, vProjectDifficulty, % ListDifficulties("Really Easy")
Gui, AddSubproject:Add, Text, ys, Set S&kill:
SPSkills := ListSkills()
Gui, AddSubproject:Add, ComboBox, vProjectSkill gSPSkillAutoComplete w130 r7, % SPSkills
Gui, AddSubproject:Add, Text, xm, Impo&rtance:
Gui, AddSubproject:Add, DropDownList, vProjectImportance, % ListPriorities("Must")
Gui, AddSubproject:Add, Button, Default gAddSubprojectSubmit w80 xm y+20, &Submit
WinGetPos,xd,yd,wd,hd,%WindowFind%
xc := CenterX(300)
yc := CenterY(200)
Gui, AddSubproject:Show, w300 h240 x%xc% y%yc%, Add Subproject
return
SPSkillAutoComplete:
Critical
Gui, AddSubproject:Submit, NoHide
If (!GetKeyState("BackSpace","P") && ProjectSkill && Pos := InStr(SPSkills, "|" . ProjectSkill))
{
Found := SubStr(SPSkills, pos+1, InStr(SPSkills, "|", 1, Pos + 1) - Pos - 1)
GuiControl, AddSubproject:Text, ProjectSkill, %Found%
SendInput % "{End}" . "+{Left " . StrLen(Found) - StrLen(ProjectSkill) . "}"
}
return
AddSubprojectSubmit:
Gui, AddSubproject:Submit, NoHide
Record := {}
Record.Project := ProjectName
Record.Difficulty := ProjectDifficulty
Record.Importance := ProjectImportance
Record.Parent := SelectedProjectID
Record.skill := ProjectSkill
Record.dateEntered := A_Now
S := db.Insert(Record, "projects")
gosub FilterUpdate
RefreshSkillsList(FilterSkillSelected)
AddSubprojectGuiEscape:
AddSubprojectGuiClose:
GuiChildClose("AddSubproject")
;UpdateList(Selection)
return

15
license.txt Normal file
View File

@ -0,0 +1,15 @@
LifeRPG - Confidence and Motivation Building System
Copyright (C) 2012 Jayvant Javier Pujara and other contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

27
readme.txt Normal file
View File

@ -0,0 +1,27 @@
LifeRPG Release 2 - Confidence and Motivation Building System
by Jayvant Javier Pujara
JJPujara@gmail.com
About:
Organize your life; build confidence, momentum, motivation, and have fun.
Discussion:
http://www.reddit.com/r/LifeRPG/
Copyright (C) 2012 Jayvant Javier Pujara and other contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.