-
Notifications
You must be signed in to change notification settings - Fork 9
/
dynamic_loot_filter.ahk
267 lines (235 loc) · 8.77 KB
/
dynamic_loot_filter.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/*
GUI construction code is labeled with headers for each section,
so the code is searchable by looking for "[section-name]", where
section-name is the title of the GroupBox dispalyed in the GUI.
Example: search "[Chaos Recipe Rares]" to find the code that
builds the chaos recipe rares section of the GUI.
*/
; General AHK boilerplate settings
#SingleInstance Force
#NoEnv
SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1 ; Run at full speed (do not sleep every n lines)
FileEncoding, UTF-8-RAW
; TODO: For now, this doesn't work - also have to find out how to run python backend as admin.
; Uncomment this to run as Admin, if having problems accessing files
/*
if (not A_IsAdmin) {
Run, *RunAs "%A_ScriptFullPath%"
}
*/
; Includes: note that we first include the ahk_include subdirectory
#Include %A_ScriptDir%\ahk_include
#Include backend_interface.ahk
#Include consts.ahk
#Include general_helper.ahk
#Include gui_build.ahk
#Include gui_helper.ahk
#Include gui_interaction.ahk
#Include gui_placeholder.ahk
#Include poe_helper.ahk
; Set system tray icon and clear standard menu options
Menu, Tray, Icon, %kDlfIconPath%
Menu, Tray, NoStandard
; ============================= Global Variables =============================
; TODO - Refactor dependent code and remove this
python_command := GetPythonCommand()
; Profiles
g_profiles := []
g_active_profile := ""
; List of backend function calls corresponding to changes that have
; occurred since last filter load or write.
g_ui_changes := []
; Local GUI state data (may contain changes not yet applied to filter).
; See backend_interface.ahk for detailed outline of keys and values.
; Note: for elements whose state is fully contained in the current state of the UI,
; for example Chaos Recipe items, this ui_data_dict will not be updated when UI changes.
; Added by gui_interaction: "matched_rule_tags" -> [type_tag, tier_tag]
g_ui_data_dict := {}
; Run Main then wait for GUI input
Main()
Return
; ============================= Profile Helper Functions =============================
; Returns the active profile, or None if there are no active profiles
InitializeProfiles() {
global kBackendCliOutputPath
global g_profiles, g_active_profile
exit_code := RunBackendCliFunction("get_all_profile_names")
if (exit_code != 0) {
ExitApp
}
g_profiles := ReadFileLines(kBackendCliOutputPath)
if (Length(g_profiles) == 0) {
BuildCreateProfileGui()
return None()
}
g_active_profile := g_profiles[1]
return g_active_profile
}
; ============================= To Refactor - Profile Creation =============================
BuildCreateProfileGui() {
; Use global mode so vVariables and HWNDhIdentifiers created here end up global
global
Gui, 2: Color, 0x111122
anchor_x := 8, anchor_y := 8
h := 28, w := 574, button_w := 70, edit_w := w - button_w - 10
spacing_y := h + 12
x := anchor_x, y := anchor_y
; Title
Gui, 2: Font, c0x00e8b2 s15 Bold, Segoe UI
Gui, 2: Add, Text, x0 y%y% h%h% w%w% +Center, Create New Profile
; Profile Name
y += spacing_y + 8
Gui, 2: Font, c0x00e8b2 s14 Norm, Segoe UI
Gui, 2: Add, Text, x%x% y%y% h%h% w%w%, Profile Name
y += h
Gui, 2: Font, cBlack s14 Norm, Segoe UI
Gui, 2: Add, Edit, x%x% y%y% h32 w250 vNewProfileName
; Downloaded Filter Path
y += spacing_y + 4
Gui, 2: Font, c0x00e8b2 s14 Norm, Segoe UI
Gui, 2: Add, Text, x%x% y%y% h%h% w%w%, Downloaded Filter Path
y += h
Gui, 2: Font, cBlack s12 Norm, Segoe UI
placeholder_text := "Example: C:\Users\UserName\Downloads\NeversinkStrict.Filter"
Gui, 2: Add, Edit, x%x% y%y% h%h% w%edit_w% vNewProfileDownloadedFilterPath HWNDhNewProfileDownloadedFilterEdit, %placeholder_text%
button_x := x + w - button_w
Gui, 2: Font, c0x00e8b2 s10 Bold, Segoe UI
Gui, 2: Add, Button, x%button_x% y%y% h%h% w%button_w% gBrowseDownloadDirectory, Browse
; Path of Exile Filters Directory
y += spacing_y
Gui, 2: Font, c0x00e8b2 s14 Norm, Segoe UI
Gui, 2: Add, Text, x%x% y%y% h%h%, Path of Exile Filters Directory
y += h
Gui, 2: Font, cBlack s12 Norm, Segoe UI
placeholder_text := "Example: C:\Users\UserName\Documents\My Games\Path of Exile"
Gui, 2: Add, Edit, x%x% y%y% h%h% w%edit_w% vNewProfilePoeFiltersDirectory HWNDhNewProfilePoeFiltersDirectoryEdit, %placeholder_text%
button_x := x + w - button_w
Gui, 2: Font, c0x00e8b2 s10 Bold, Segoe UI
Gui, 2: Add, Button, x%button_x% y%y% h%h% w%button_w% gBrowsePoeDirectory, Browse
; Remove Downloaded Filter on Import
y += spacing_y + 6
Gui, 2: Font, c0x00e8b2 s14 Norm, Segoe UI
Gui, 2: Add, Checkbox, vRemoveDownloadedFilter -Checked x%x% y%y% h26 w%w%, Remove downloaded filter on import
; Create Button
y += spacing_y + 10
Gui, 2: Font, s14 Bold, Segoe UI
Gui, 2: Add, Button, x145 y%y% w250 h36 gCreateProfileSubmit, Create
; Show UI
window_w := w + 16
Gui, 2: -Border
Gui, 2: Show, w%window_w% h378
GUi, 1: Hide
Return
}
BrowseDownloadDirectory() {
FileSelectFile, selected_path, , , Select Downloaded Filter, Filter Files (*.filter)
GuiControl, 2:, NewProfileDownloadedFilterPath, %selected_path%
return
}
BrowsePoeDirectory() {
FileSelectFolder, selected_directory, , , Select Path of Exile Filters Directory
GuiControl, 2:, NewProfilePoeFiltersDirectory, %selected_directory%
return
}
CreateProfileSubmit() {
global kBackendCliInputPath
global NewProfileName, NewProfileDownloadedFilterPath, NewProfilePoeFiltersDirectory, RemoveDownloadedFilter
Gui, 2: Submit, NoHide
if (NewProfileName == ""){
MsgBox, Missing profile name!
return
}
if ((NewProfileDownloadedFilterPath == "") or InStr(NewProfileDownloadedFilterPath, "...")) {
MsgBox, Missing downloaded filter path!
return
}
if ((NewProfilePoeFiltersDirectory == "") or InStr(NewProfilePoeFiltersDirectory, "...")) {
MsgBox, Missing Path of Exile filters directory!
return
}
SplitPath, NewProfileDownloadedFilterPath, downloaded_filter_filename, download_directory
FileDelete, %kBackendCliInputPath%
FileAppend, % "DownloadDirectory:" download_directory "`n", %kBackendCliInputPath%
FileAppend, % "DownloadedLootFilterFilename:" downloaded_filter_filename "`n", %kBackendCliInputPath%
FileAppend, % "PathOfExileDirectory:" NewProfilePoeFiltersDirectory "`n", %kBackendCliInputPath%
if (!RemoveDownloadedFilter){
FileAppend, % "RemoveDownloadedFilter:False`n", %kBackendCliInputPath%
}
Gui, 2: Destroy
exit_code := RunBackendCliFunction("create_new_profile " Quoted(NewProfileName))
if (exit_code != 0){
UpdateStatusMessage("Profile Creation Failed")
}
Reload
}
2GuiEscape() {
2GuiClose()
}
2GuiClose() {
Gui, 2: Destroy
Gui, 1: Show
return
}
GuiEscape() {
MinimizeToTray()
}
GuiClose() {
MinimizeToTray()
}
; ============================= Load/Import Filter =============================
LoadOrImportFilter(active_profile) {
global kBackendCliOutputPath
CheckType(active_profile, "string")
RunBackendCliFunction("check_filters_exist " Quoted(active_profile))
output_lines := ReadFileLines(kBackendCliOutputPath)
downloaded_filter_exists := output_lines[1]
input_filter_exists := output_lines[2]
; output_filter_exists := output_lines[3] ; unused for now
if (input_filter_exists) {
RunBackendCliFunction("load_input_filter " Quoted(active_profile))
} else if (downloaded_filter_exists) {
RunBackendCliFunction("import_downloaded_filter " Quoted(active_profile))
} else {
DebugMessage("Neither input nor downloaded filter found. "
. "Please place your downloaded filter in your downloads directory.")
ExitApp
}
}
; ============================= Main Thread =============================
Main() {
global g_ui_data_dict
active_profile := InitializeProfiles()
; If no profiles exist, return from this thread and wait for profile creation GUI
if (IsNone(active_profile)) {
return
}
; Load input or import downloaded filter (displays error and exits if neither exist)
LoadOrImportFilter(active_profile)
; Initialize GUI
g_ui_data_dict := QueryAllFilterData(active_profile)
QueryHotkeys(g_ui_data_dict)
BuildGui(g_ui_data_dict)
}
; ================================== Hotkeys ==================================
ToggleGUIHotkey() {
if (IsPoeActive()) {
RestoreFromTray()
MakeDlfActive()
} else if (IsDlfActive()) {
MinimizeToTray()
MakePoeActive()
}
}
WriteFilterHotkey() {
UpdateFilter()
MinimizeToTray()
MakePoeActive()
}
ReloadFilterHotkey() {
if (IsPoeActive()) {
SendChatMessage("/itemfilter DynamicLootFilter")
}
}
; For efficient testing
; Numpad0::Reload