forked from ElRapt/FleshWound
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathFleshWound_GUI.lua
More file actions
465 lines (438 loc) · 18 KB
/
Copy pathFleshWound_GUI.lua
File metadata and controls
465 lines (438 loc) · 18 KB
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
-- FleshWound_GUI.lua
local addonName, addonTable = ...
local GUI = {}
addonTable.GUI = GUI
local L = addonTable.L
local CONSTANTS = {
SIZES = {
MAIN_FRAME_WIDTH = 320,
MAIN_FRAME_HEIGHT = 540,
BODY_IMAGE_WIDTH = 300,
BODY_IMAGE_HEIGHT = 500,
GENERIC_DIALOG_WIDTH = 550,
GENERIC_DIALOG_HEIGHT = 500,
NOTE_DIALOG_WIDTH = 400,
NOTE_DIALOG_HEIGHT = 450,
PROFILE_MANAGER_WIDTH = 500,
PROFILE_MANAGER_HEIGHT = 500,
CREATE_PROFILE_WIDTH = 300,
CREATE_PROFILE_HEIGHT = 200,
RENAME_PROFILE_WIDTH = 300,
RENAME_PROFILE_HEIGHT = 200,
},
LIMITS = {
MAX_NOTE_LENGTH = 125,
MAX_PROFILE_NAME_LENGTH = 50,
},
BACKDROPS = {
GENERIC_DIALOG = {
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
tile = true,
tileSize = 32,
edgeSize = 24,
insets = { left = 5, right = 5, top = 5, bottom = 5 },
},
DIALOG_FRAME = {
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
tile = true,
tileSize = 32,
edgeSize = 32,
insets = { left = 11, right = 12, top = 12, bottom = 11 },
},
TOOLTIP_FRAME = {
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
tile = false,
tileSize = 0,
edgeSize = 14,
insets = { left = 4, right = 4, top = 4, bottom = 4 },
},
BANNER_FRAME = {
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
tile = false,
tileSize = 0,
edgeSize = 16,
insets = { left = 4, right = 4, top = 4, bottom = 4 },
},
EDIT_BOX = {
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
edgeFile = nil,
tile = false,
tileSize = 0,
edgeSize = 0,
insets = { left = 0, right = 0, top = 0, bottom = 0 },
},
},
IMAGES = {
DIALOG_BG = "Interface\\DialogFrame\\UI-DialogBox-Background",
DIALOG_EDGE = "Interface\\DialogFrame\\UI-DialogBox-Border",
TOOLTIP_BG = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border",
BODY_IMAGE = "Interface\\AddOns\\" .. addonName .. "\\Textures\\body_image.tga",
ICON_BOOK = "Interface\\ICONS\\INV_Misc_Book_09",
ICON_HIGHLIGHT_SQUARE = "Interface\\Buttons\\ButtonHilight-Square",
ICON_MOUSE_HIGHLIGHT = "Interface\\Buttons\\UI-Common-MouseHilight",
},
ICONS = {
BANDAGE = "Interface\\Icons\\INV_Misc_Bandage_01",
BLOOD = "Interface\\Icons\\Spell_Druid_Bloodythrash",
BONE = "Interface\\Icons\\INV_Misc_Bone_01",
FIRE = "Interface\\Icons\\Spell_Fire_Immolation",
SCAR = "Interface\\Icons\\Spell_Misc_Petheal",
POISON = "Interface\\Icons\\Ability_Rogue_Deviouspoisons",
INFECTED = "Interface\\Icons\\Ability_Druid_Infectedwound",
},
SEVERITIES = {
{ id = 1, displayName = L.SEVERITY_NONE, color = {0, 0, 0, 0.0} },
{ id = 2, displayName = L.SEVERITY_UNKNOWN, color = {0.5, 0.5, 0.5, 0.4} },
{ id = 3, displayName = L.SEVERITY_BENIGN, color = {0, 1, 0, 0.4} },
{ id = 4, displayName = L.SEVERITY_MODERATE, color = {1, 1, 0, 0.4} },
{ id = 5, displayName = L.SEVERITY_SEVERE, color = {1, 0.5, 0, 0.4} },
{ id = 6, displayName = L.SEVERITY_CRITICAL, color = {1, 0, 0, 0.4} },
{ id = 7, displayName = L.SEVERITY_DEADLY, color = {0.6, 0, 0.6, 0.4} },
},
STATUSES = {
{ id = 1, displayName = L.STATUS_NONE, icon = nil },
{ id = 2, displayName = L.STATUS_BANDAGED, icon = "Interface\\Icons\\INV_Misc_Bandage_01" },
{ id = 3, displayName = L.STATUS_BLEEDING, icon = "Interface\\Icons\\Spell_Druid_Bloodythrash" },
{ id = 4, displayName = L.STATUS_BROKEN_BONE,icon = "Interface\\Icons\\INV_Misc_Bone_01" },
{ id = 5, displayName = L.STATUS_BURN, icon = "Interface\\Icons\\Spell_Fire_Immolation" },
{ id = 6, displayName = L.STATUS_SCARRED, icon = "Interface\\Icons\\Spell_Misc_Petheal" },
{ id = 7, displayName = L.STATUS_POISONED, icon = "Interface\\Icons\\Ability_Rogue_Deviouspoisons" },
{ id = 8, displayName = L.STATUS_INFECTED, icon = "Interface\\Icons\\Ability_Druid_Infectedwound" },
},
REGIONS = {
{ id = 1, nameKey = "Head", localName = L.HEAD, x = 130, y = 420, width = 50, height = 75 },
{ id = 2, nameKey = "Torso", localName = L.TORSO, x = 130, y = 275, width = 50, height = 120 },
{ id = 3, nameKey = "LeftArm", localName = L.LEFT_ARM, x = 75, y = 300, width = 50, height = 120 },
{ id = 4, nameKey = "RightArm", localName = L.RIGHT_ARM, x = 185, y = 300, width = 50, height = 120 },
{ id = 5, nameKey = "LeftHand", localName = L.LEFT_HAND, x = 40, y = 180, width = 50, height = 100 },
{ id = 6, nameKey = "RightHand", localName = L.RIGHT_HAND,x = 215, y = 180, width = 50, height = 100 },
{ id = 7, nameKey = "LeftLeg", localName = L.LEFT_LEG, x = 100, y = 50, width = 50, height = 130 },
{ id = 8, nameKey = "RightLeg", localName = L.RIGHT_LEG, x = 155, y = 50, width = 50, height = 130 },
{ id = 9, nameKey = "LeftFoot", localName = L.LEFT_FOOT, x = 110, y = 0, width = 50, height = 50 },
{ id = 10, nameKey = "RightFoot", localName = L.RIGHT_FOOT,x = 150, y = 0, width = 50, height = 50 },
},
STATUS_PRIORITY = {
[4] = 1,
[5] = 2,
[8] = 3,
[3] = 4,
[7] = 5,
[6] = 6,
[2] = 7,
},
}
GUI.CONSTANTS = CONSTANTS
local Severities = CONSTANTS.SEVERITIES
local SeveritiesByID = {}
for _, sev in ipairs(Severities) do
SeveritiesByID[sev.id] = sev
end
local Statuses = CONSTANTS.STATUSES
local StatusesByID = {}
for _, st in ipairs(Statuses) do
StatusesByID[st.id] = st
end
GUI.Severities = Severities
GUI.SeveritiesByID = SeveritiesByID
GUI.Statuses = Statuses
GUI.StatusesByID = StatusesByID
--- Saves the position of a given frame.
-- @param frameName string The unique name of the frame.
-- @param frame Frame The frame whose position is to be saved.
function GUI:SaveWindowPosition(frameName, frame)
addonTable.FleshWoundData.positions = addonTable.FleshWoundData.positions or {}
local key = frame.dialogPositionKey or frameName -- Use global key if available
local pos = addonTable.FleshWoundData.positions
local point, _, relativePoint, xOfs, yOfs = frame:GetPoint()
pos[key] = { point = point, relativePoint = relativePoint, xOfs = xOfs, yOfs = yOfs }
end
--- Restores the position of a given frame.
-- @param frameName string The unique name of the frame.
-- @param frame Frame The frame to be positioned.
function GUI:RestoreWindowPosition(frameName, frame)
local pos = addonTable.FleshWoundData.positions and addonTable.FleshWoundData.positions[frameName]
if pos then
frame:ClearAllPoints()
frame:SetPoint(pos.point, UIParent, pos.relativePoint, pos.xOfs, pos.yOfs)
else
frame:SetPoint("CENTER")
end
end
--- Creates a scroll frame with an attached child frame.
-- @param parent Frame The parent frame.
-- @param left number Left offset.
-- @param top number Top offset.
-- @param right number Right offset.
-- @param bottom number Bottom offset.
-- @return Frame, Frame The scroll frame and its child.
function GUI:CreateScrollFrame(parent, left, top, right, bottom)
local scrollFrame = CreateFrame("ScrollFrame", nil, parent, "UIPanelScrollFrameTemplate")
scrollFrame:SetPoint("TOPLEFT", parent, "TOPLEFT", left, top)
scrollFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", right, bottom)
local scrollChild = CreateFrame("Frame", nil, scrollFrame)
scrollChild:SetSize(scrollFrame:GetWidth(), 1)
scrollFrame:SetScrollChild(scrollChild)
return scrollFrame, scrollChild
end
--- Creates a standardized button.
-- @param parent Frame The parent frame.
-- @param text string The button text.
-- @param width number Button width.
-- @param height number Button height.
-- @param point string Anchor point.
-- @param relativeTo Frame|string Relative frame or string.
-- @param offsetX number Horizontal offset.
-- @param offsetY number Vertical offset.
-- @return Button The created button.
function GUI:CreateButton(parent, text, width, height, point, relativeTo, offsetX, offsetY)
local button = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
button:SetSize(width, height)
if type(relativeTo) == "string" then
button:SetPoint(point, parent, relativeTo, offsetX, offsetY)
else
button:SetPoint(point, relativeTo, offsetX, offsetY)
end
button:SetText(text)
return button
end
--- Initializes the main FleshWound UI.
function GUI:Initialize()
self.displayingRemote = false
self.activeRemoteProfileName = nil
self:CreateMainFrame()
self:RestoreWindowPosition("FleshWoundFrame", self.frame)
self:CreateBodyRegions()
self:CreateTemporaryProfileBanner()
self:UpdateRegionColors()
self:UpdateProfileBanner()
end
--- Explicitly display a remote profile
function GUI:DisplayRemoteProfile(profileName)
self.displayingRemote = true
self.activeRemoteProfileName = profileName
if addonTable.remoteProfiles[profileName] then
addonTable.remoteProfiles[profileName].lastAccess = time()
end
if addonTable.CleanupRemoteProfiles then
addonTable:CleanupRemoteProfiles()
end
self:CloseAllDialogs()
if self.frame then
self.frame:Show()
end
self:UpdateProfileBanner()
self:UpdateRegionColors()
if self.frame and self.frame.ProfileButton then
self.frame.ProfileButton:Hide()
end
end
--- Explicitly display local data (the user's own profile)
function GUI:DisplayLocalProfile()
local prev = self.activeRemoteProfileName
self.displayingRemote = false
self.activeRemoteProfileName = nil
if addonTable.ClearRemoteProfile then
addonTable:ClearRemoteProfile(prev)
end
self:CloseAllDialogs()
if self.frame then
self.frame:Show()
end
self:UpdateProfileBanner()
self:UpdateRegionColors()
if self.frame and self.frame.ProfileButton then
self.frame.ProfileButton:Show()
end
end
function GUI:GetActiveWoundData()
if self.displayingRemote and self.activeRemoteProfileName then
local entry = addonTable.remoteProfiles[self.activeRemoteProfileName]
if not entry then return {} end
entry.lastAccess = time()
return entry.data or {}
end
return addonTable.woundData or {}
end
function GUI:UpdateProfileBanner()
if not (self.frame and self.tempProfileBannerFrame and self.tempProfileBanner) then
return
end
if self.displayingRemote and self.activeRemoteProfileName then
self.tempProfileBanner:SetText(string.format(L.VIEWING_PROFILE, self.activeRemoteProfileName))
else
local currentProfileName = addonTable.FleshWoundData.currentProfile or "Unknown"
self.tempProfileBanner:SetText(string.format(L.VIEWING_PROFILE, currentProfileName))
end
self.tempProfileBannerFrame:Show()
end
function GUI:CreateTemporaryProfileBanner()
if not self.frame then return end
local bannerFrame = CreateFrame("Frame", nil, self.frame, "BackdropTemplate")
bannerFrame:SetSize(self.frame:GetWidth() - 20, 30)
bannerFrame:SetPoint("TOP", self.frame, "TOP", 0, 25)
bannerFrame:SetBackdrop(CONSTANTS.BACKDROPS.BANNER_FRAME)
bannerFrame:SetBackdropColor(0, 0, 0, 0.7)
bannerFrame:Hide()
local bannerText = bannerFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
bannerText:SetPoint("CENTER", bannerFrame, "CENTER", 0, 0)
bannerText:SetJustifyH("CENTER")
bannerText:SetTextColor(1, 0.8, 0, 1)
self.tempProfileBannerFrame = bannerFrame
self.tempProfileBanner = bannerText
end
--- Closes all relevant dialogs when switching modes
function GUI:CloseAllDialogs()
if addonTable.Dialogs then
addonTable.Dialogs:CloseAllDialogs()
end
if self.frame then
self.frame:Hide()
end
end
function GUI:CreateMainFrame()
local frame = CreateFrame("Frame", "FleshWoundFrame", UIParent, "BackdropTemplate")
self.frame = frame
frame:SetSize(CONSTANTS.SIZES.MAIN_FRAME_WIDTH, CONSTANTS.SIZES.MAIN_FRAME_HEIGHT)
frame:SetPoint("CENTER")
frame:SetBackdrop(CONSTANTS.BACKDROPS.DIALOG_FRAME)
frame:SetFrameStrata("DIALOG")
frame:SetMovable(true)
frame:EnableMouse(true)
frame:RegisterForDrag("LeftButton")
frame:SetScript("OnDragStart", function(f) f:StartMoving() end)
frame:SetScript("OnDragStop", function(f)
f:StopMovingOrSizing()
GUI:SaveWindowPosition("FleshWoundFrame", f)
end)
frame.CloseButton = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
frame.CloseButton:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -5, -5)
frame.CloseButton:SetScript("OnClick", function() frame:Hide() end)
table.insert(UISpecialFrames, frame:GetName())
frame.BodyImage = frame:CreateTexture(nil, "BACKGROUND")
frame.BodyImage:SetSize(CONSTANTS.SIZES.BODY_IMAGE_WIDTH, CONSTANTS.SIZES.BODY_IMAGE_HEIGHT)
frame.BodyImage:SetPoint("CENTER", frame, "CENTER", 0, 0)
frame.BodyImage:SetTexture(CONSTANTS.IMAGES.BODY_IMAGE)
frame.ProfileButton = CreateFrame("Button", nil, frame)
frame.ProfileButton:SetSize(35, 35)
frame.ProfileButton:SetPoint("TOPLEFT", frame, "TOPLEFT", 15, -15)
frame.ProfileButton:SetNormalTexture(CONSTANTS.IMAGES.ICON_BOOK)
frame.ProfileButton:SetHighlightTexture(CONSTANTS.IMAGES.ICON_HIGHLIGHT_SQUARE)
frame.ProfileButton:SetScript("OnClick", function()
if addonTable.Dialogs then
addonTable.Dialogs:CloseAllDialogs()
end
if addonTable.ProfileManager then
addonTable.ProfileManager:OpenProfileManager()
end
end)
end
function GUI:CreateBodyRegions()
local frame = self.frame
frame.BodyRegions = {}
for _, region in ipairs(CONSTANTS.REGIONS) do
self:CreateBodyRegion(frame, region)
end
end
function GUI:CreateBodyRegion(frame, region)
local btn = CreateFrame("Button", nil, frame)
local Dialogs = addonTable.Dialogs
btn:SetSize(region.width, region.height)
btn:SetPoint("BOTTOMLEFT", frame.BodyImage, "BOTTOMLEFT", region.x, region.y)
btn:SetHighlightTexture(CONSTANTS.IMAGES.ICON_MOUSE_HIGHLIGHT)
btn.regionID = region.id
btn:SetScript("OnClick", function()
if addonTable.Dialogs then
addonTable.Dialogs:CloseAllDialogs()
end
Dialogs:OpenRegionDialog(btn.regionID, false)
end)
local regionMarker = btn:CreateTexture(nil, "OVERLAY")
regionMarker:SetSize(10, 10)
regionMarker:SetPoint("CENTER", btn, "CENTER")
regionMarker:SetColorTexture(0, 1, 0, 1)
btn.regionMarker = regionMarker
local overlay = btn:CreateTexture(nil, "ARTWORK")
local inset = 7
overlay:SetPoint("TOPLEFT", btn, "TOPLEFT", inset, -inset)
overlay:SetPoint("BOTTOMRIGHT", btn, "BOTTOMRIGHT", -inset, inset)
overlay:SetColorTexture(0, 0, 0, 0)
btn.overlay = overlay
local countText = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
countText:SetPoint("TOPRIGHT", btn, "TOPRIGHT", 0, -30)
countText:SetJustifyH("RIGHT")
countText:Hide()
btn.countText = countText
btn.statusIcons = {}
local iconSize = 14
local iconSpacing = 2
for i = 1, 3 do
local icon = btn:CreateTexture(nil, "OVERLAY")
icon:SetSize(iconSize, iconSize)
if i == 1 then
icon:SetPoint("TOPLEFT", btn, "TOPLEFT", 0, 0)
else
icon:SetPoint("LEFT", btn.statusIcons[i - 1], "RIGHT", iconSpacing, 0)
end
icon:Hide()
btn.statusIcons[i] = icon
end
frame.BodyRegions[region.id] = btn
end
function GUI:UpdateRegionColors()
local frame = self.frame
if not (frame and frame.BodyRegions) then return end
local data = self:GetActiveWoundData()
local statusPriority = CONSTANTS.STATUS_PRIORITY
for regionID, btn in pairs(frame.BodyRegions) do
local highestID = addonTable.Utils.GetHighestSeverityID(regionID, data)
local sev = SeveritiesByID[highestID] or { color = {0, 0, 0, 0} }
local r, g, b, a = sev.color[1], sev.color[2], sev.color[3], sev.color[4]
btn.overlay:SetColorTexture(r, g, b, a)
local notes = data[regionID]
local count = notes and #notes or 0
if count > 0 then
btn.countText:SetText(count)
btn.countText:Show()
else
btn.countText:Hide()
end
local foundStatuses = {}
if notes then
for _, note in ipairs(notes) do
if note.statusIDs then
for _, stID in ipairs(note.statusIDs) do
foundStatuses[stID] = true
end
end
end
end
local sortedStatuses = {}
for stID in pairs(foundStatuses) do
table.insert(sortedStatuses, stID)
end
table.sort(sortedStatuses, function(a, b)
return (statusPriority[a] or 999) < (statusPriority[b] or 999)
end)
for i = 1, 3 do
local iconTexture = btn.statusIcons[i]
local stID = sortedStatuses[i]
if stID then
local stData = StatusesByID[stID]
if stData and stData.icon then
iconTexture:SetTexture(stData.icon)
iconTexture:Show()
else
iconTexture:Hide()
end
else
iconTexture:Hide()
end
end
end
end
return GUI