├── .gitignore ├── example.png ├── .gitattributes ├── README.md ├── lib ├── Fuzzy.ahk ├── Class Hotkey.ahk ├── Class GUI.ahk └── Class LV_Colors.ahk └── WindowSwitcher.ahk /.gitignore: -------------------------------------------------------------------------------- 1 | AHK-Studio Backup 2 | 3 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Run1e/WindowSwitcher/HEAD/example.png -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WindowSwitcher 2 | 3 | Binds (by default) to `CTRL+ALT+I` and allows you to enter data to open a specific window on your desktop. 4 | 5 | ![Example of WindowSwitcher popup window](example.png) 6 | 7 | ## How to use 8 | 9 | To use this: 10 | 11 | - Download and install [AutoHotkey](https://github.com/Lexikos/AutoHotkey_L/releases) 12 | - Clone or download this repository 13 | - Run (doubleclick) `WindowSwitcher.ahk` in the root 14 | - Press `CTRL+ALT+I` to test 15 | 16 | ## How to override shortcut key 17 | 18 | To override the shortcut key edit [WindowSwitcher.ahk](WindowSwitcher.ahk#L8) and look for setting `Key := "^!I"` and replace it with the Autohotkey expression of your liking. Read more about that here: https://www.autohotkey.com/docs/Hotkeys.htm 19 | 20 | For example, to use the capslock key: 21 | 22 | ```ahk 23 | Key := "Capslock" 24 | ``` 25 | 26 | NOTE: This will disable the capslock key which is likely not a bad thing anyway. 27 | -------------------------------------------------------------------------------- /lib/Fuzzy.ahk: -------------------------------------------------------------------------------- 1 | Fuzzy(input, arr, att) { 2 | 3 | arren:=[] 4 | input := StrReplace(input, " ", "") 5 | 6 | if !StrLen(input) { ; input is empty, just return the array 7 | for id, item in arr 8 | arren.Insert(item) 9 | return arren 10 | } 11 | 12 | for id, item in arr { 13 | taken:=[], needle:="i)", limit:=false 14 | name:=StrReplace(item[att], " ", "") 15 | Loop, Parse, input 16 | taken[A_LoopField] := (StrLen(taken[A_LoopField])?taken[A_LoopField]+1:1) 17 | for char, hits in taken { 18 | StrReplace(name, char, char, found) 19 | if (found Count) 109 | return 110 | this.LV.Modify(New, "Select Vis") 111 | this.Control("Focus", this.Edit) 112 | } 113 | 114 | Open() { 115 | if this.IsVisible 116 | return 117 | this.List := [] 118 | this.LV.Delete() 119 | WinGet windows, List 120 | Added := [] 121 | Loop %windows% 122 | { 123 | ID := windows%A_Index% 124 | if !WinExist("ahk_id" ID) || (this.ahkid = "ahk_id" id) 125 | continue 126 | WinGetTitle Title, % "ahk_id" ID 127 | WinGet, ProcessName, ProcessName, % "ahk_id" ID 128 | ProcessName := StrSplit(ProcessName, ".").1 129 | WinGet, Exe, ProcessPath, % "ahk_id" ID 130 | if StrLen(Exe) && StrLen(Title) && !(Title ~= IgnoreEquals) && (!Added.HasKey(Title)) { 131 | if !this.Icons.HasKey(Exe) 132 | Icon := this.Icons[Exe] := this.IL.Add(Exe) 133 | else 134 | Icon := this.Icons[Exe] 135 | if !Icon 136 | continue 137 | this.List.Push({Title:Title, Exe:Exe, hwnd:ID, Search:(Title " " ProcessName)}) 138 | if !AllowDupe 139 | Added[Title] := true 140 | this.LV.Add("Icon" Icon, Title, ID) 141 | } 142 | } this.SizeCtrl() 143 | this.Show("Hide") ; "activate" 144 | this.Animate("FADE_IN", FadeTime) 145 | this.Show() 146 | this.Control("Focus", this.Edit) 147 | } 148 | 149 | SizeCtrl(Pos := 1) { 150 | static VERT_SCROLL, ROW_HEIGHT 151 | if !VERT_SCROLL 152 | SysGet, VERT_SCROLL, 2 153 | if !ROW_HEIGHT 154 | ROW_HEIGHT := LV_EX_GetRowHeight(this.LV.hwnd) 155 | this.LV.Redraw(false) 156 | Count := this.LV.GetCount() 157 | this.LV.ModifyCol(1, Width - ((Count > MaxItems) ? VERT_SCROLL : 0)) 158 | this.Pos(A_ScreenWidth/2 - Width/2, A_ScreenHeight/2 - MoveUp,, 26 + (MaxItems > Count ? Count : MaxItems) * ROW_HEIGHT) 159 | this.Control("Move", this.LV.hwnd, "h" (ROW_HEIGHT * (MaxItems > Count ? Count : MaxItems))) 160 | this.LV.Modify((Pos>Count?Count:Pos), "Select Vis") 161 | this.LV.ModifyCol(2, 0) 162 | this.LV.Redraw(true) 163 | } 164 | 165 | Close() { 166 | if !this.IsVisible 167 | return 168 | this.SetText(this.Edit, "") 169 | this.Hide() 170 | } 171 | 172 | Toggle() { 173 | this[this.IsVisible ? "Close" : "Open"]() 174 | } 175 | 176 | CtrlBackspace() { 177 | this.Control("-Redraw", "Edit1") 178 | ControlSend, Edit1, ^+{Left}{Backspace}, % this.ahkid 179 | this.Control("+Redraw", "Edit1") 180 | } 181 | 182 | Escape() { 183 | this.Close() 184 | } 185 | } 186 | 187 | Command(cmd) { 188 | if (cmd = "reload") 189 | reload 190 | if (cmd = "Exit") 191 | ExitApp 192 | } 193 | 194 | pa(array, depth=5, indentLevel:=" ") { ; tidbit, this has saved my life 195 | try { 196 | for k,v in Array { 197 | lst.= indentLevel "[" k "]" 198 | if (IsObject(v) && depth>1) 199 | lst.="`n" pa(v, depth-1, indentLevel . " ") 200 | else 201 | lst.=" => " v 202 | lst.="`n" 203 | } return rtrim(lst, "`r`n `t") 204 | } return 205 | } 206 | 207 | m(x*) { 208 | for a, b in x 209 | text .= (IsObject(b)?pa(b):b) "`n" 210 | MsgBox, 0, msgbox, % text 211 | } 212 | 213 | LV_EX_GetRowHeight(HLV, Row := 1) { 214 | Return LV_EX_GetItemRect(HLV, Row).H 215 | } 216 | 217 | LV_EX_GetItemRect(HLV, Row := 1, LVIR := 0, Byref RECT := "") { 218 | ; LVM_GETITEMRECT = 0x100E -> http://msdn.microsoft.com/en-us/library/bb761049(v=vs.85).aspx 219 | VarSetCapacity(RECT, 16, 0) 220 | NumPut(LVIR, RECT, 0, "Int") 221 | SendMessage, 0x100E, % (Row - 1), % &RECT, , % "ahk_id " . HLV 222 | If (ErrorLevel = 0) 223 | Return False 224 | Result := {} 225 | Result.X := NumGet(RECT, 0, "Int") 226 | Result.Y := NumGet(RECT, 4, "Int") 227 | Result.R := NumGet(RECT, 8, "Int") 228 | Result.B := NumGet(RECT, 12, "Int") 229 | Result.W := Result.R - Result.X 230 | Result.H := Result.B - Result.Y 231 | Return Result 232 | } 233 | 234 | #Include lib\Class LV_Colors.ahk 235 | #Include lib\Class GUI.ahk 236 | #Include lib\Class Hotkey.ahk 237 | #Include lib\Fuzzy.ahk -------------------------------------------------------------------------------- /lib/Class GUI.ahk: -------------------------------------------------------------------------------- 1 | Class Gui { 2 | static Instances := [] 3 | 4 | __New(Title := "AutoHotkey Window", Options := "") { 5 | Gui, New, % "+hwndhwnd " Options, % Title 6 | this.hwnd := hwnd 7 | this.ahkid := "ahk_id" hwnd 8 | this.IsVisible := false 9 | Gui % this.hwnd ": -E0x10" ; disable drag-drop by default 10 | Gui.Instances[hwnd] := this 11 | this.Controls := [] 12 | return this 13 | } 14 | 15 | Add(ControlType, Options := "", Params := "", Function := "") { 16 | Gui % this.hwnd ":Add", % ControlType, % Options " hwndControlHWND", % Params 17 | if Function { 18 | GuiControl, +g, % ControlHWND, % Function ; ty geekdude for this amazing godsent knowledge, may the darkness of labels be eternally abolished 19 | this.Controls.Push(ControlHWND) 20 | } 21 | return ControlHWND 22 | } 23 | 24 | Control(Command := "", Control := "", ControlParams := "") { 25 | GuiControl % this.hwnd ":" Command, % Control, % ControlParams 26 | } 27 | 28 | Show(Options := "", Title := "") { 29 | this.IsVisible := !InStr(Options, "Hide") 30 | Gui % this.hwnd ":Show", % Options, % Title 31 | } 32 | 33 | Hide(Options := "") { 34 | this.IsVisible := false 35 | Gui % this.hwnd ":Hide", % Options 36 | } 37 | 38 | SetDefault() { 39 | Gui % this.hwnd ":Default" 40 | } 41 | 42 | Activate() { 43 | WinActivate % this.ahkid 44 | } 45 | 46 | Tab(num) { 47 | Gui % this.hwnd ":Tab", % num 48 | } 49 | 50 | Disable() { 51 | Gui % this.hwnd ":+Disabled" 52 | } 53 | 54 | Enable() { 55 | Gui % this.hwnd ":-Disabled" 56 | } 57 | 58 | ControlGet(Command, Value := "", Control := "") { 59 | ControlGet, out, % Command, % (StrLen(Value) ? Value : ""), % (StrLen(Control) ? Control : ""), % this.ahkid 60 | return out 61 | } 62 | 63 | GuiControlGet(Command := "", Control := "", Param := "") { 64 | GuiControlGet, out, % (StrLen(Command) ? Command : ""), % (StrLen(Control) ? Control : ""), % (StrLen(Param) ? Param : "") 65 | return out 66 | } 67 | 68 | Pos(x := "", y := "", w := "", h := "") { 69 | this.Show( (StrLen(x) ? "x" x : "") . " " 70 | . (StrLen(y) ? "y" y : "") . " " 71 | . (StrLen(w) ? "w" w : "") . " " 72 | . (StrLen(h) ? "h" h : "") . " " 73 | . (this.IsVisible ? "" : "Hide")) 74 | } 75 | 76 | SetIcon(Icon) { 77 | hIcon := DllCall("LoadImage", UInt,0, Str, Icon, UInt, 1, UInt, 0, UInt, 0, UInt, 0x10) 78 | SendMessage, 0x80, 0, hIcon ,, % this.ahkid ; One affects Title bar and 79 | SendMessage, 0x80, 1, hIcon ,, % this.ahkid ; the other the ALT+TAB menu 80 | } 81 | 82 | Destroy() { 83 | this.IsVisible := false 84 | Gui % this.hwnd ":Destroy" 85 | for Index, Control in this.Controls 86 | GuiControl, -g, % Control 87 | Gui.Instances[this.hwnd] := "" 88 | } 89 | 90 | Color(BackgroundColor := "", ControlColor := "") { 91 | Gui % this.hwnd ":Color", % BackgroundColor, % ControlColor 92 | } 93 | 94 | Options(Options, ext := "") { 95 | Gui % this.hwnd ":" Options, % ext 96 | } 97 | 98 | Margin(HorizontalMargin, VerticalMargin) { 99 | Gui % this.hwnd ":Margin", % HorizontalMargin, % VerticalMargin 100 | } 101 | 102 | Font(Options := "", Font := "") { 103 | Gui % this.hwnd ":Font", % Options, % Font 104 | } 105 | 106 | Submit(Hide := false, Options := "") { 107 | Gui % this.hwnd ":Submit", % (this.IsVisible:=!Hide ? "" : "NoHide") " " Options 108 | } 109 | 110 | GetText(Control) { 111 | ControlGetText, ControlText, % Control, % this.ahkid 112 | return ControlText 113 | } 114 | 115 | SetText(Control, Text := "") { 116 | this.Control(, Control, Text) 117 | } 118 | 119 | DropFilesToggle(Toggle) { 120 | this.Options((Toggle ? "+" : "-") . "E0x10") 121 | } 122 | 123 | Animate(Type, Duration := 80) { 124 | static Anims := {ROLL_LEFT_TO_RIGHT: 0x20001 125 | , ROLL_RIGHT_TO_LEFT: 0x20002 126 | , ROLL_TOP_TO_BOTTOM: 0x20004 127 | , ROLL_BOTTOM_TO_TOP: 0x20008 128 | , ROLL_DIAG_TL_TO_BR: 0x20005 129 | , ROLL_DIAG_TR_TO_BL: 0x20006 130 | , ROLL_DIAG_BL_TO_TR: 0x20009 131 | , ROLL_DIAG_BR_TO_TL: 0x2000a 132 | , SLIDE_LEFT_TO_RIGHT: 0x40001 133 | , SLIDE_RIGHT_TO_LEFT: 0x40002 134 | , SLIDE_TOP_TO_BOTTOM: 0x40004 135 | , SLIDE_BOTTOM_TO_TOP: 0x40008 136 | , SLIDE_DIAG_TL_TO_BR: 0x40005 137 | , SLIDE_DIAG_TR_TO_BL: 0x40006 138 | , SLIDE_DIAG_BL_TO_TR: 0x40009 139 | , SLIDE_DIAG_BR_TO_TL: 0x40010 140 | , ZOOM_IN: 0x16 141 | , ZOOM_OUT: 0x10010 142 | , FADE_IN: 0xa0000 143 | , FADE_OUT: 0x90000} 144 | 145 | return DllCall("AnimateWindow", "UInt", this.hwnd, "Int", Duration, "UInt", Anims.HasKey(Type)?Anims[Type]:Type) 146 | } 147 | 148 | WinSet(Command, Param := "") { 149 | WinSet, % Command, % Param, % this.ahkid 150 | } 151 | 152 | Escape() { 153 | this.Close() 154 | } 155 | 156 | Class ListView { 157 | __New(Parent, Options, Headers, Function := "") { 158 | this.Parent := Parent 159 | this.Function := Function 160 | this.hwnd := Parent.Add("ListView", Options, Headers, Function) 161 | return this 162 | } 163 | 164 | Add(Options := "", Fields*) { 165 | this.SetDefault() 166 | return LV_Add(Options, Fields*) 167 | } 168 | 169 | Insert(Row, Options := "", Col*) { 170 | this.SetDefault() 171 | return LV_Insert(Row, Options, Col*) 172 | } 173 | 174 | Delete(Row := "") { 175 | this.SetDefault() 176 | if StrLen(Row) 177 | return LV_Delete(Row) 178 | else 179 | return LV_Delete() 180 | } 181 | 182 | GetCount(Option := "") { 183 | this.SetDefault() 184 | return LV_GetCount(Option) 185 | } 186 | 187 | GetNext(Start := "", Option := "") { 188 | this.SetDefault() 189 | return LV_GetNext(Start, Option) 190 | } 191 | 192 | GetText(Row, Column := "") { 193 | this.SetDefault() 194 | LV_GetText(Text, Row, Column) 195 | return Text 196 | } 197 | 198 | Modify(Row, Options := "", NewCol*) { 199 | this.SetDefault() 200 | return LV_Modify(Row, Options, NewCol*) 201 | } 202 | 203 | ModifyCol(Column := "", Options := "", Title := "") { 204 | this.SetDefault() 205 | return LV_ModifyCol(Column, Options, Title) 206 | } 207 | 208 | Redraw(Toggle) { 209 | this.SetDefault() 210 | return this.Parent.Control((Toggle?"+":"-") "Redraw", this.hwnd) 211 | } 212 | 213 | SetImageList(ID, LargeIcons := false) { 214 | this.SetDefault() 215 | return LV_SetImageList(ID, !LargeIcons) 216 | } 217 | 218 | SetDefault() { 219 | this.Parent.SetDefault() 220 | this.Parent.Options("ListView", this.hwnd) 221 | } 222 | } 223 | 224 | Class ImageList { 225 | static Instances := [] 226 | 227 | __New(InitialCount := 5, GrowCount := 2, LargeIcons := false) { 228 | this.ID := IL_Create(InitialCount, GrowCount, LargeIcons) 229 | Gui.ListView.ImageList.Instances[this.ID] := this 230 | return this 231 | } 232 | 233 | Destroy() { 234 | Gui.ListView.ImageList.Instances.Remove(this.ID) 235 | return IL_Destroy(this.ID) 236 | } 237 | 238 | Add(File) { 239 | return IL_Add(this.ID, File) 240 | } 241 | } 242 | } 243 | 244 | GuiClose(GuiHwnd) { 245 | (Instance := Gui.Instances[GuiHwnd]).Close.Call(Instance) 246 | } 247 | 248 | GuiEscape(GuiHwnd) { 249 | (Instance := Gui.Instances[GuiHwnd]).Escape.Call(Instance) 250 | } 251 | 252 | GuiSize(GuiHwnd, EventInfo, Width, Height) { 253 | (Instance := Gui.Instances[GuiHwnd]).Size.Call( Instance 254 | , EventInfo 255 | , Width 256 | , Height) 257 | } 258 | 259 | GuiDropFiles(GuiHwnd, FileArray, CtrlHwnd, X, Y) { 260 | (Instance := Gui.Instances[GuiHwnd]).DropFiles.Call(Instance, FileArray, CtrlHwnd, X, Y) 261 | } 262 | 263 | GuiContextMenu(GuiHwnd, CtrlHwnd, EventInfo, IsRightClick, X, Y) { 264 | (Instance := Gui.Instances[GuiHwnd]).ContextMenu.Call( Instance 265 | , CtrlHwnd 266 | , EventInfo 267 | , IsRightClick 268 | , X 269 | , Y) 270 | } -------------------------------------------------------------------------------- /lib/Class LV_Colors.ahk: -------------------------------------------------------------------------------- 1 | ; ====================================================================================================================== 2 | ; Namespace: LV_Colors 3 | ; Function: Individual row and cell coloring for AHK ListView controls. 4 | ; Tested with: AHK 1.1.23.05 (A32/U32/U64) 5 | ; Tested on: Win 10 (x64) 6 | ; Changelog: 7 | ; 1.1.04.01/2016-05-03/just me - added change to remove the focus rectangle from focused rows 8 | ; 1.1.04.00/2016-05-03/just me - added SelectionColors method 9 | ; 1.1.03.00/2015-04-11/just me - bugfix for StaticMode 10 | ; 1.1.02.00/2015-04-07/just me - bugfixes for StaticMode, NoSort, and NoSizing 11 | ; 1.1.01.00/2015-03-31/just me - removed option OnMessage from __New(), restructured code 12 | ; 1.1.00.00/2015-03-27/just me - added AlternateRows and AlternateCols, revised code. 13 | ; 1.0.00.00/2015-03-23/just me - new version using new AHK 1.1.20+ features 14 | ; 0.5.00.00/2014-08-13/just me - changed 'static mode' handling 15 | ; 0.4.01.00/2013-12-30/just me - minor bug fix 16 | ; 0.4.00.00/2013-12-30/just me - added static mode 17 | ; 0.3.00.00/2013-06-15/just me - added "Critical, 100" to avoid drawing issues 18 | ; 0.2.00.00/2013-01-12/just me - bugfixes and minor changes 19 | ; 0.1.00.00/2012-10-27/just me - initial release 20 | ; ====================================================================================================================== 21 | ; CLASS LV_Colors 22 | ; 23 | ; The class provides six public methods to set individual colors for rows and/or cells, to clear all colors, to 24 | ; prevent/allow sorting and rezising of columns dynamically, and to deactivate/activate the message handler for 25 | ; WM_NOTIFY messages (see below). 26 | ; 27 | ; The message handler for WM_NOTIFY messages will be activated for the specified ListView whenever a new instance is 28 | ; created. If you want to temporarily disable coloring call MyInstance.OnMessage(False). This must be done also before 29 | ; you try to destroy the instance. To enable it again, call MyInstance.OnMessage(). 30 | ; 31 | ; To avoid the loss of Gui events and messages the message handler might need to be set 'critical'. This can be 32 | ; achieved by setting the instance property 'Critical' ti the required value (e.g. MyInstance.Critical := 100). 33 | ; New instances default to 'Critical, Off'. Though sometimes needed, ListViews or the whole Gui may become 34 | ; unresponsive under certain circumstances if Critical is set and the ListView has a g-label. 35 | ; ====================================================================================================================== 36 | Class LV_Colors { 37 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 38 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 39 | ; META FUNCTIONS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 40 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 41 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 42 | ; =================================================================================================================== 43 | ; __New() Create a new LV_Colors instance for the given ListView 44 | ; Parameters: HWND - ListView's HWND. 45 | ; Optional ------------------------------------------------------------------------------------------ 46 | ; StaticMode - Static color assignment, i.e. the colors will be assigned permanently to the row 47 | ; contents rather than to the row number. 48 | ; Values: True/False 49 | ; Default: False 50 | ; NoSort - Prevent sorting by click on a header item. 51 | ; Values: True/False 52 | ; Default: True 53 | ; NoSizing - Prevent resizing of columns. 54 | ; Values: True/False 55 | ; Default: True 56 | ; =================================================================================================================== 57 | __New(HWND, StaticMode := False, NoSort := True, NoSizing := True) { 58 | If (This.Base.Base.__Class) ; do not instantiate instances 59 | Return False 60 | If This.Attached[HWND] ; HWND is already attached 61 | Return False 62 | If !DllCall("IsWindow", "Ptr", HWND) ; invalid HWND 63 | Return False 64 | VarSetCapacity(Class, 512, 0) 65 | DllCall("GetClassName", "Ptr", HWND, "Str", Class, "Int", 256) 66 | If (Class <> "SysListView32") ; HWND doesn't belong to a ListView 67 | Return False 68 | ; ---------------------------------------------------------------------------------------------------------------- 69 | ; Set LVS_EX_DOUBLEBUFFER (0x010000) style to avoid drawing issues. 70 | SendMessage, 0x1036, 0x010000, 0x010000, , % "ahk_id " . HWND ; LVM_SETEXTENDEDLISTVIEWSTYLE 71 | ; Get the default colors 72 | SendMessage, 0x1025, 0, 0, , % "ahk_id " . HWND ; LVM_GETTEXTBKCOLOR 73 | This.BkClr := ErrorLevel 74 | SendMessage, 0x1023, 0, 0, , % "ahk_id " . HWND ; LVM_GETTEXTCOLOR 75 | This.TxClr := ErrorLevel 76 | ; Get the header control 77 | SendMessage, 0x101F, 0, 0, , % "ahk_id " . HWND ; LVM_GETHEADER 78 | This.Header := ErrorLevel 79 | ; Set other properties 80 | This.HWND := HWND 81 | This.IsStatic := !!StaticMode 82 | This.AltCols := False 83 | This.AltRows := False 84 | This.NoSort(!!NoSort) 85 | This.NoSizing(!!NoSizing) 86 | This.OnMessage() 87 | This.Critical := "Off" 88 | This.Attached[HWND] := True 89 | } 90 | ; =================================================================================================================== 91 | __Delete() { 92 | This.Attached.Remove(HWND, "") 93 | This.OnMessage(False) 94 | WinSet, Redraw, , % "ahk_id " . This.HWND 95 | } 96 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 97 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 98 | ; PUBLIC METHODS ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 99 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 100 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 101 | ; =================================================================================================================== 102 | ; Clear() Clears all row and cell colors. 103 | ; Parameters: AltRows - Reset alternate row coloring (True / False) 104 | ; Default: False 105 | ; AltCols - Reset alternate column coloring (True / False) 106 | ; Default: False 107 | ; Return Value: Always True. 108 | ; =================================================================================================================== 109 | Clear(AltRows := False, AltCols := False) { 110 | If (AltCols) 111 | This.AltCols := False 112 | If (AltRows) 113 | This.AltRows := False 114 | This.Remove("Rows") 115 | This.Remove("Cells") 116 | Return True 117 | } 118 | ; =================================================================================================================== 119 | ; AlternateRows() Sets background and/or text color for even row numbers. 120 | ; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 121 | ; Default: Empty -> default background color 122 | ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 123 | ; Default: Empty -> default text color 124 | ; Return Value: True on success, otherwise false. 125 | ; =================================================================================================================== 126 | AlternateRows(BkColor := "", TxColor := "") { 127 | If !(This.HWND) 128 | Return False 129 | This.AltRows := False 130 | If (BkColor = "") && (TxColor = "") 131 | Return True 132 | BkBGR := This.BGR(BkColor) 133 | TxBGR := This.BGR(TxColor) 134 | If (BkBGR = "") && (TxBGR = "") 135 | Return False 136 | This["ARB"] := (BkBGR <> "") ? BkBGR : This.BkClr 137 | This["ART"] := (TxBGR <> "") ? TxBGR : This.TxClr 138 | This.AltRows := True 139 | Return True 140 | } 141 | ; =================================================================================================================== 142 | ; AlternateCols() Sets background and/or text color for even column numbers. 143 | ; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 144 | ; Default: Empty -> default background color 145 | ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 146 | ; Default: Empty -> default text color 147 | ; Return Value: True on success, otherwise false. 148 | ; =================================================================================================================== 149 | AlternateCols(BkColor := "", TxColor := "") { 150 | If !(This.HWND) 151 | Return False 152 | This.AltCols := False 153 | If (BkColor = "") && (TxColor = "") 154 | Return True 155 | BkBGR := This.BGR(BkColor) 156 | TxBGR := This.BGR(TxColor) 157 | If (BkBGR = "") && (TxBGR = "") 158 | Return False 159 | This["ACB"] := (BkBGR <> "") ? BkBGR : This.BkClr 160 | This["ACT"] := (TxBGR <> "") ? TxBGR : This.TxClr 161 | This.AltCols := True 162 | Return True 163 | } 164 | ; =================================================================================================================== 165 | ; SelectionColors() Sets background and/or text color for selected rows. 166 | ; Parameters: BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 167 | ; Default: Empty -> default selected background color 168 | ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 169 | ; Default: Empty -> default selected text color 170 | ; Return Value: True on success, otherwise false. 171 | ; =================================================================================================================== 172 | SelectionColors(BkColor := "", TxColor := "") { 173 | If !(This.HWND) 174 | Return False 175 | This.SelColors := False 176 | If (BkColor = "") && (TxColor = "") 177 | Return True 178 | BkBGR := This.BGR(BkColor) 179 | TxBGR := This.BGR(TxColor) 180 | If (BkBGR = "") && (TxBGR = "") 181 | Return False 182 | This["SELB"] := BkBGR 183 | This["SELT"] := TxBGR 184 | This.SelColors := True 185 | Return True 186 | } 187 | ; =================================================================================================================== 188 | ; Row() Sets background and/or text color for the specified row. 189 | ; Parameters: Row - Row number 190 | ; Optional ------------------------------------------------------------------------------------------ 191 | ; BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 192 | ; Default: Empty -> default background color 193 | ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 194 | ; Default: Empty -> default text color 195 | ; Return Value: True on success, otherwise false. 196 | ; =================================================================================================================== 197 | Row(Row, BkColor := "", TxColor := "") { 198 | If !(This.HWND) 199 | Return False 200 | If This.IsStatic 201 | Row := This.MapIndexToID(Row) 202 | This["Rows"].Remove(Row, "") 203 | If (BkColor = "") && (TxColor = "") 204 | Return True 205 | BkBGR := This.BGR(BkColor) 206 | TxBGR := This.BGR(TxColor) 207 | If (BkBGR = "") && (TxBGR = "") 208 | Return False 209 | This["Rows", Row, "B"] := (BkBGR <> "") ? BkBGR : This.BkClr 210 | This["Rows", Row, "T"] := (TxBGR <> "") ? TxBGR : This.TxClr 211 | Return True 212 | } 213 | ; =================================================================================================================== 214 | ; Cell() Sets background and/or text color for the specified cell. 215 | ; Parameters: Row - Row number 216 | ; Col - Column number 217 | ; Optional ------------------------------------------------------------------------------------------ 218 | ; BkColor - Background color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 219 | ; Default: Empty -> row's background color 220 | ; TxColor - Text color as RGB color integer (e.g. 0xFF0000 = red) or HTML color name. 221 | ; Default: Empty -> row's text color 222 | ; Return Value: True on success, otherwise false. 223 | ; =================================================================================================================== 224 | Cell(Row, Col, BkColor := "", TxColor := "") { 225 | If !(This.HWND) 226 | Return False 227 | If This.IsStatic 228 | Row := This.MapIndexToID(Row) 229 | This["Cells", Row].Remove(Col, "") 230 | If (BkColor = "") && (TxColor = "") 231 | Return True 232 | BkBGR := This.BGR(BkColor) 233 | TxBGR := This.BGR(TxColor) 234 | If (BkBGR = "") && (TxBGR = "") 235 | Return False 236 | If (BkBGR <> "") 237 | This["Cells", Row, Col, "B"] := BkBGR 238 | If (TxBGR <> "") 239 | This["Cells", Row, Col, "T"] := TxBGR 240 | Return True 241 | } 242 | ; =================================================================================================================== 243 | ; NoSort() Prevents/allows sorting by click on a header item for this ListView. 244 | ; Parameters: Apply - True/False 245 | ; Default: True 246 | ; Return Value: True on success, otherwise false. 247 | ; =================================================================================================================== 248 | NoSort(Apply := True) { 249 | If !(This.HWND) 250 | Return False 251 | If (Apply) 252 | This.SortColumns := False 253 | Else 254 | This.SortColumns := True 255 | Return True 256 | } 257 | ; =================================================================================================================== 258 | ; NoSizing() Prevents/allows resizing of columns for this ListView. 259 | ; Parameters: Apply - True/False 260 | ; Default: True 261 | ; Return Value: True on success, otherwise false. 262 | ; =================================================================================================================== 263 | NoSizing(Apply := True) { 264 | Static OSVersion := DllCall("GetVersion", "UChar") 265 | If !(This.Header) 266 | Return False 267 | If (Apply) { 268 | If (OSVersion > 5) 269 | Control, Style, +0x0800, , % "ahk_id " . This.Header ; HDS_NOSIZING = 0x0800 270 | This.ResizeColumns := False 271 | } 272 | Else { 273 | If (OSVersion > 5) 274 | Control, Style, -0x0800, , % "ahk_id " . This.Header ; HDS_NOSIZING 275 | This.ResizeColumns := True 276 | } 277 | Return True 278 | } 279 | ; =================================================================================================================== 280 | ; OnMessage() Adds/removes a message handler for WM_NOTIFY messages for this ListView. 281 | ; Parameters: Apply - True/False 282 | ; Default: True 283 | ; Return Value: Always True 284 | ; =================================================================================================================== 285 | OnMessage(Apply := True) { 286 | If (Apply) && !This.HasKey("OnMessageFunc") { 287 | This.OnMessageFunc := ObjBindMethod(This, "On_WM_Notify") 288 | OnMessage(0x004E, This.OnMessageFunc) ; add the WM_NOTIFY message handler 289 | } 290 | Else If !(Apply) && This.HasKey("OnMessageFunc") { 291 | OnMessage(0x004E, This.OnMessageFunc, 0) ; remove the WM_NOTIFY message handler 292 | This.OnMessageFunc := "" 293 | This.Remove("OnMessageFunc") 294 | } 295 | WinSet, Redraw, , % "ahk_id " . This.HWND 296 | Return True 297 | } 298 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 299 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 300 | ; PRIVATE PROPERTIES +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 301 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 302 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 303 | Static Attached := {} 304 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 305 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 306 | ; PRIVATE METHODS +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 307 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 308 | ; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 309 | On_WM_NOTIFY(W, L, M, H) { 310 | ; Notifications: NM_CUSTOMDRAW = -12, LVN_COLUMNCLICK = -108, HDN_BEGINTRACKA = -306, HDN_BEGINTRACKW = -326 311 | Critical, % This.Critical 312 | If ((HCTL := NumGet(L + 0, 0, "UPtr")) = This.HWND) || (HCTL = This.Header) { 313 | Code := NumGet(L + (A_PtrSize * 2), 0, "Int") 314 | If (Code = -12) 315 | Return This.NM_CUSTOMDRAW(This.HWND, L) 316 | If !This.SortColumns && (Code = -108) 317 | Return 0 318 | If !This.ResizeColumns && ((Code = -306) || (Code = -326)) 319 | Return True 320 | } 321 | } 322 | ; ------------------------------------------------------------------------------------------------------------------- 323 | NM_CUSTOMDRAW(H, L) { 324 | ; Return values: 0x00 (CDRF_DODEFAULT), 0x20 (CDRF_NOTIFYITEMDRAW / CDRF_NOTIFYSUBITEMDRAW) 325 | Static SizeNMHDR := A_PtrSize * 3 ; Size of NMHDR structure 326 | Static SizeNCD := SizeNMHDR + 16 + (A_PtrSize * 5) ; Size of NMCUSTOMDRAW structure 327 | Static OffItem := SizeNMHDR + 16 + (A_PtrSize * 2) ; Offset of dwItemSpec (NMCUSTOMDRAW) 328 | Static OffItemState := OffItem + A_PtrSize ; Offset of uItemState (NMCUSTOMDRAW) 329 | Static OffCT := SizeNCD ; Offset of clrText (NMLVCUSTOMDRAW) 330 | Static OffCB := OffCT + 4 ; Offset of clrTextBk (NMLVCUSTOMDRAW) 331 | Static OffSubItem := OffCB + 4 ; Offset of iSubItem (NMLVCUSTOMDRAW) 332 | ; ---------------------------------------------------------------------------------------------------------------- 333 | DrawStage := NumGet(L + SizeNMHDR, 0, "UInt") 334 | , Row := NumGet(L + OffItem, "UPtr") + 1 335 | , Col := NumGet(L + OffSubItem, "Int") + 1 336 | , Item := Row - 1 337 | If This.IsStatic 338 | Row := This.MapIndexToID(Row) 339 | ; CDDS_SUBITEMPREPAINT = 0x030001 -------------------------------------------------------------------------------- 340 | If (DrawStage = 0x030001) { 341 | UseAltCol := !(Col & 1) && (This.AltCols) 342 | , ColColors := This["Cells", Row, Col] 343 | , ColB := (ColColors.B <> "") ? ColColors.B : UseAltCol ? This.ACB : This.RowB 344 | , ColT := (ColColors.T <> "") ? ColColors.T : UseAltCol ? This.ACT : This.RowT 345 | , NumPut(ColT, L + OffCT, "UInt"), NumPut(ColB, L + OffCB, "UInt") 346 | Return (!This.AltCols && !This.HasKey(Row) && (Col > This["Cells", Row].MaxIndex())) ? 0x00 : 0x20 347 | } 348 | ; CDDS_ITEMPREPAINT = 0x010001 ----------------------------------------------------------------------------------- 349 | If (DrawStage = 0x010001) { 350 | ; LVM_GETITEMSTATE = 0x102C, LVIS_SELECTED = 0x0002 351 | If (This.SelColors) && DllCall("SendMessage", "Ptr", H, "UInt", 0x102C, "Ptr", Item, "Ptr", 0x0002, "UInt") { 352 | ; Remove the CDIS_SELECTED (0x0001) and CDIS_FOCUS (0x0010) states from uItemState and set the colors. 353 | NumPut(NumGet(L + OffItemState, "UInt") & ~0x0011, L + OffItemState, "UInt") 354 | If (This.SELB <> "") 355 | NumPut(This.SELB, L + OffCB, "UInt") 356 | If (This.SELT <> "") 357 | NumPut(This.SELT, L + OffCT, "UInt") 358 | Return 0x02 ; CDRF_NEWFONT 359 | } 360 | UseAltRow := (Item & 1) && (This.AltRows) 361 | , RowColors := This["Rows", Row] 362 | , This.RowB := RowColors ? RowColors.B : UseAltRow ? This.ARB : This.BkClr 363 | , This.RowT := RowColors ? RowColors.T : UseAltRow ? This.ART : This.TxClr 364 | If (This.AltCols || This["Cells"].HasKey(Row)) 365 | Return 0x20 366 | NumPut(This.RowT, L + OffCT, "UInt"), NumPut(This.RowB, L + OffCB, "UInt") 367 | Return 0x00 368 | } 369 | ; CDDS_PREPAINT = 0x000001 --------------------------------------------------------------------------------------- 370 | Return (DrawStage = 0x000001) ? 0x20 : 0x00 371 | } 372 | ; ------------------------------------------------------------------------------------------------------------------- 373 | MapIndexToID(Row) { ; provides the unique internal ID of the given row number 374 | SendMessage, 0x10B4, % (Row - 1), 0, , % "ahk_id " . This.HWND ; LVM_MAPINDEXTOID 375 | Return ErrorLevel 376 | } 377 | ; ------------------------------------------------------------------------------------------------------------------- 378 | BGR(Color, Default := "") { ; converts colors to BGR 379 | Static Integer := "Integer" ; v2 380 | ; HTML Colors (BGR) 381 | Static HTML := {AQUA: 0xFFFF00, BLACK: 0x000000, BLUE: 0xFF0000, FUCHSIA: 0xFF00FF, GRAY: 0x808080, GREEN: 0x008000 382 | , LIME: 0x00FF00, MAROON: 0x000080, NAVY: 0x800000, OLIVE: 0x008080, PURPLE: 0x800080, RED: 0x0000FF 383 | , SILVER: 0xC0C0C0, TEAL: 0x808000, WHITE: 0xFFFFFF, YELLOW: 0x00FFFF} 384 | If Color Is Integer 385 | Return ((Color >> 16) & 0xFF) | (Color & 0x00FF00) | ((Color & 0xFF) << 16) 386 | Return (HTML.HasKey(Color) ? HTML[Color] : Default) 387 | } 388 | } --------------------------------------------------------------------------------