;~ =============================================================================== ;~ 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 }