vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2 Non Event functions for FlexBar
3 Last Modified
4 01/09/2005 Initial version
5 08/05/2005 Fixed concatenation errors - Ratbert_CP
6 08/05/2005 Fixed arethmetic error - Ratbert_CP
7 08/06/2005 Fixed spelling error in GetText to GetText() - Shirtan
8 08/10/2005 Minor changes for floating buttons, fixed sort for script List - Sherkhan
9 08/12/2005 Reorganized LoadProfile, and many instances where we were applying things globally to all buttons - Sherkhan
10 instead of just to an individual button or group. Hopefully will truly fix Floating Button issue.
11 Also made changes to reduce looping for efficiency.
12 08/12/2005 Added Text3 Field - Sherkhan
13 08/21/2005 Added commands for showing button information on KeyBinding key pressed
14 --]]
15  
16 local util = Utility_Class:New()
17  
18 function FB_ApplySettings()
19 -- For each button, apply the saved settings.
20 -- Originally every slash command came through here.
21 -- changed that so that any conditional slash commands
22 -- call the appropriate apply function only for the buttons
23 -- they are changing, and save only the setting they are
24 -- changing to the profile. The reason being I don't want
25 -- all the potentially expensive code in scaling etc to execute
26 -- on conditionals if they don't have to.
27 local index
28 for index = 1,FBNumButtons do
29 FB_Apply_SingleSetting(index)
30 end
31 end
32  
33 function FB_GetCoordsForGroup(groupnum)
34 -- Just update the group coordinates, instead of all groups or all buttons
35 local members = FB_GetGroupMembers(groupnum)
36 if members.n < 1 then return end
37  
38 for index = 1, members.n do
39 FB_GetCoords(members[index])
40 end
41  
42 end
43  
44 function FB_Apply_SingleSetting(buttonnum)
45 -- Removed all code for Saving anything to the Character Profile from this function as the Save
46 -- now takes place on individual move or change actions on a per button basis - Never globally
47 -- Apply settings to a single button
48 local button, frame = FB_GetWidgets(buttonnum)
49 -- Apply hide state
50 FB_ApplyHidden(buttonnum)
51 -- Apply alpha
52 FB_ApplyAlpha(buttonnum)
53 -- Apply scale
54 FB_ApplyScale(buttonnum)
55 -- Apply lock state
56 FB_ApplyLocked(buttonnum)
57 -- Apply remap
58 FB_ApplyRemap(buttonnum)
59 -- Apply show grid
60 FB_ApplyGrid(buttonnum)
61 -- Save button state to character profile
62 FB_SaveState(buttonnum)
63  
64 FlexBarButton_UpdateUsable(button)
65  
66 -- Update hotkey text
67 if FBButtonInfoShown == true then
68 FB_ShowSingleButtonInfo(buttonnum)
69 else
70 FB_TextSub(buttonnum)
71 FlexBarButton_UpdateHotkeys(button)
72 FB_ApplyTextPosition(buttonnum)
73 end
74 end
75  
76 function FB_ResyncSettings()
77 -- For each button, get coords and save to profile.
78 -- Coords are only saved by wow for user placed items - the others
79 -- don't get saved.
80 local index
81  
82 -- check to see if the scale has gotten munged by an alt tab, and reapply settings
83 if FlexBar:GetScale() > .25 then
84 FB_LoadProfile()
85 return
86 end
87 -- Removed code that would get the button coordinates from here.
88 -- No reason to update the save profile coordinates on a timer.
89 end
90  
91 function FB_ReformAllGroups()
92 -- For each button, check group status, attach to appropriate frame.
93 -- This function is called as part of FB_LoadProfile Only - otherwise the individual groups or
94 -- buttons are set.
95 if(FB_DebugFlag == 1) then
96 FB_ReportToUser("<< FB_ReformAllGroups: All Groups are Being Reformed >>");
97 end
98  
99 local index
100 for index = 1,FBNumButtons do
101 -- Check to see that buttons have base coords in the current profile, if not then get some.
102 -- This cas can occur when FlexBar is initially installed, or has not been configured for
103 -- a character (resetall as well)
104 if((not FBState[index]["xcoord"]) or (not FBState[index]["ycoord"])) then
105 FB_UpdateButtonLoc(index)
106 end
107  
108 local button, frame = FB_GetWidgets(index)
109 if FBState[index]["group"] and (FBState[index]["group"] ~= index) then
110 FB_LockButton(index)
111 local anchor = FBState[index]["group"]
112  
113 -- Check to see that anchor button has base coords, if not then get some !
114 if((not FBState[anchor]["xcoord"]) or (not FBState[anchor]["ycoord"])) then
115 FB_UpdateButtonLoc(anchor)
116 end
117  
118 local x = FBState[index]["xcoord"] - FBState[anchor]["xcoord"]
119 local y = FBState[index]["ycoord"] - FBState[anchor]["ycoord"]
120 frame:ClearAllPoints()
121 frame:SetPoint("BOTTOMRIGHT", "FlexFrame" .. FBState[index]["group"], "BOTTOMRIGHT", x, y)
122 FBState[index]["locked"] = true
123 elseif FBState[index]["group"] and (FBState[index]["group"] == index) then
124 local x = FBState[index]["xcoord"]
125 local y = FBState[index]["ycoord"]
126 frame:ClearAllPoints()
127 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
128 else
129 local x = FBState[index]["xcoord"]
130 local y = FBState[index]["ycoord"]
131 frame:ClearAllPoints()
132 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
133 end
134 -- Changed ApplySettings to this call (does a loop once, instead of 2 seperate loops, accomplishes same thing
135 FB_Apply_SingleSetting(index)
136 end
137  
138 -- Generate group data for use InGroupBounds()
139 for index = 1, FBNumButtons do
140 -- local button, frame = FB_GetWidgets(index) (needless call was being made, values never used here)
141 if FBState[index]["group"] == index then
142 FBGroupData[index] = FB_GetBoundingButtons(index)
143 else
144 FBGroupData[index] = nil;
145 end
146 end
147 end
148  
149 function FB_DisbandGroup(group)
150 -- For each group button in the group to be disbanded, attach to UIParent.
151 local index
152 local members = FB_GetGroupMembers(group)
153  
154 if members.n < 1 then return end
155  
156 if(FB_DebugFlag == 1) then
157 FB_ReportToUser("<< FB_DisbandGroup: Group #"..group.." being Disbanded >>");
158 end
159  
160 for index = 1, members.n do
161 local button, frame = FB_GetWidgets(members[index])
162 local x = FBState[members[index]]["xcoord"]
163 local y = FBState[members[index]]["ycoord"]
164 frame:ClearAllPoints()
165 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
166 FB_Apply_SingleSetting(members[index])
167 end
168  
169 -- Clear group Bounding data
170 FBGroupData[group] = nil;
171 end
172  
173 function FB_ReformGroup(group)
174 -- For each group button, attach to appropriate frame.
175 local index
176 local members = FB_GetGroupMembers(group)
177  
178 if members.n < 1 then return end
179  
180 if(FB_DebugFlag == 1) then
181 FB_ReportToUser("<< FB_ReformGroup: Group #"..group.." Being Reformed >>");
182 end
183  
184 -- Check to see that buttons have base coords, if not then get some
185 -- The only time no base coordinates will exist is after a resetall or when
186 -- FlexBar is initially being configured for a character.
187 if ((not FBState[group]["xcoord"]) or (not FBState[group]["ycoord"])) then
188 FB_GetCoordsForGroup(group)
189 end
190  
191 for index = 1, members.n do
192 local button, frame = FB_GetWidgets(members[index])
193 if (FBState[members[index]]["group"] ~= members[index]) then
194 -- Group button attach to Anchor with relative coordintates on frame
195 FB_LockButton(members[index])
196 local x = FBState[members[index]]["xcoord"] - FBState[group]["xcoord"]
197 local y = FBState[members[index]]["ycoord"] - FBState[group]["ycoord"]
198 frame:ClearAllPoints()
199 frame:SetPoint("BOTTOMRIGHT", "FlexFrame" .. FBState[members[index]]["group"], "BOTTOMRIGHT", x, y)
200 FBState[members[index]]["locked"] = true
201 else
202 -- Group Anchor Button
203 local x = FBState[members[index]]["xcoord"]
204 local y = FBState[members[index]]["ycoord"]
205 frame:ClearAllPoints()
206 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
207 end
208 FB_Apply_SingleSetting(members[index])
209 end
210  
211 -- Generate group data for use InGroupBounds()
212 FBGroupData[group] = FB_GetBoundingButtons(group)
213 end
214  
215 function FB_UpdateButtonLoc(buttonnum)
216 -- The button frame has been moved (MoveABS, MoveREL), update co-ordinates
217 if(FB_DebugFlag == 1) then
218 FB_ReportToUser("<< FB_UpdateButtonLoc: Button #"..buttonnum.." Update >>");
219 end
220  
221 -- Store button
222 FB_GetCoords(buttonnum)
223 end
224  
225 function FB_RaiseEvent(event, source)
226 -- raise no events until a profile is loaded.
227 FBLastEvent = event
228 FBLastSource = source
229  
230 if not FBProfileLoaded then return end
231  
232 -- Respond to events raised throughout the code.
233 -- Source is the originator of the event
234 if (FB_DebugFlag == 3) then
235 util:Print(event)
236 util:Print(source)
237 end
238  
239 event = string.lower(event)
240 -- If event is being watched for, process the commands associated with it.
241 if FBQuickEventDispatch[event] then
242 local qd = FBQuickEventDispatch[event]
243 if type(source) == "string" then source = string.lower(source) end
244 local index, cur_event
245 for index, cur_event in ipairs(qd) do
246 if not source or not cur_event["target"] or
247 FB_InTable(source, cur_event["target"]) then
248 FBEventArgs = cur_event["args"]
249 local dispatch = FBcmd.CommandList[cur_event["command"]]
250 dispatch("")
251 FBEventArgs = nil
252 end
253 end
254 end
255 -- Dispatch to extended handlers
256  
257 local handlers = FBExtHandlers[string.upper(event)]
258 if handlers then
259 local index, dispatch
260 for index, dispatch in pairs(handlers) do
261 dispatch(event, source)
262 end
263 end
264  
265 end
266  
267 -- Group utility functions
268 function FB_CheckGroups()
269 -- Check for mouse entering/leaving groups
270 local group, value, list
271 list = FBEventToggleInfo["boundcheck"][FBEventToggles["boundcheck"].."list"]
272 if not list then return end
273 local x,y = GetCursorPosition()
274 x = x / UIParent:GetScale()
275 y = y / UIParent:GetScale()
276 if abs(x-FBCursorLoc.x) < 1 and abs(y-FBCursorLoc.y) < 1 then return end
277 for group, value in pairs(list) do
278 if FB_InGroupBounds(group, x, y) and
279 not FB_InGroupBounds(group, FBCursorLoc.x, FBCursorLoc.y) then
280 FB_RaiseEvent("MouseEnterGroup", group)
281 end
282 if not FB_InGroupBounds(group, x, y) and
283 FB_InGroupBounds(group, FBCursorLoc.x, FBCursorLoc.y) then
284 FB_RaiseEvent("MouseLeaveGroup", group)
285 end
286 end
287 FBCursorLoc.x = x
288 FBCursorLoc.y = y
289 end
290  
291 function FB_InGroupBounds(group, x, y)
292 -- Check to see if x,y is inside group
293 local button, frame = FB_GetWidgets(group)
294 local dim = 36 * button:GetScale()
295 if x < FBState[FBGroupData[group]["left"]]["xcoord"] - 1 or
296 x > FBState[FBGroupData[group]["right"]]["xcoord"] + dim or
297 y < FBState[FBGroupData[group]["bottom"]]["ycoord"] - dim or
298 y > FBState[FBGroupData[group]["top"]]["ycoord"] + 1 then
299 return false
300 else
301 return true
302 end
303 end
304  
305 function FB_GetBoundingButtons(group)
306 -- Return a table with the bounding buttons of a group, to
307 -- speed up in bounds checks.
308 local members = FB_GetGroupMembers(group)
309 local index
310 local bounds = {}
311 local button1=members[1]
312 bounds["top"] = button1
313 bounds["bottom"] = button1
314 bounds["left"] = button1
315 bounds["right"] = button1
316  
317 for index = 1, members.n do
318 if FBState[members[index]]["xcoord"] > FBState[bounds["right"]]["xcoord"] then
319 bounds["right"] = members[index]
320 end
321 if FBState[members[index]]["xcoord"] < FBState[bounds["left"]]["xcoord"] then
322 bounds["left"] = members[index]
323 end
324 if FBState[members[index]]["ycoord"] > FBState[bounds["top"]]["ycoord"] then
325 bounds["top"] = members[index]
326 end
327 if FBState[members[index]]["ycoord"] < FBState[bounds["bottom"]]["ycoord"] then
328 bounds["bottom"] = members[index]
329 end
330 end
331 return bounds
332 end
333  
334 function FB_GetGroupMembers(group)
335 -- returns a table with all the members in <group>
336 local members = {}
337 members.n = 0
338 local index
339 for index = 1, FBNumButtons do
340 if FBState[index]["group"] == group then
341 members.n = members.n + 1
342 members[members.n] = index
343 end
344 end
345 return members
346 end
347  
348 function FB_VerticalGroup(group, width, padding)
349 -- Arranges buttons in group vertically, width columns wide with
350 -- the specified padding between them.
351 local members = FB_GetGroupMembers(group)
352 if members.n < 1 then return end
353 local dim = padding + (38 * (FBState[members[1]]["scale"] or 1))
354 local index = 1
355 while index <= members.n do
356 local index2
357 for index2 = 1, width do
358 if index <= members.n then
359 FB_MoveButtonABS(members[index], 300 + ((index2-1)*dim), 500-(floor((index-1)/width)*dim))
360 end
361 index = index+1
362 end
363 end
364 FB_ReformGroup(group)
365 end
366  
367 function FB_HorizontalGroup(group, height, padding)
368 -- Arranges buttons in group horizontally, height rows high with
369 -- the specified padding between them.
370 local members = FB_GetGroupMembers(group)
371 if members.n < 1 then return end
372 local dim = padding + (38 * (FBState[members[1]]["scale"] or 1))
373 local index = 1
374 while index <= members.n do
375 local index2
376 for index2 = 1, height do
377 if index <= members.n then
378 FB_MoveButtonABS(members[index], 300+(floor((index-1)/height)*dim), 500-((index2-1)*dim))
379 end
380 index = index+1
381 end
382 end
383 FB_ReformGroup(group)
384 end
385  
386 function FB_CircularGroup(group, padding)
387 -- Arranges group buttons in a circle with the specified padding between them.
388 -- Starts at 10 O'clock and moves clockwise, with the 7th in the center.
389 -- 0
390 -- 0 0
391 -- 0
392 -- 0 0
393 -- 0
394 -- Max buttons for this is 7
395 local coords = {{-1,.5},{0,1},{1,.5},{1,-.5},{0,-1},{-1,-.5},{0,0}}
396 local members = FB_GetGroupMembers(group)
397 if members.n < 1 or members.n > 7 then return end
398 local dim = padding + (38 * (FBState[members[1]]["scale"] or 1))
399 for index = 1, members.n do
400 FB_MoveButtonABS(members[index], 300+(coords[index][1]*dim), 300+(coords[index][2]*dim))
401 end
402  
403 FB_ReformGroup(group)
404 end
405  
406  
407 -- Button utility functions
408  
409 function FB_GetWidgets(buttonnum)
410 -- returns the button and frame (handle) associated with buttonnum
411 local button = getglobal("FlexBarButton" .. buttonnum)
412 local frame = getglobal("FlexFrame" .. buttonnum)
413 return button, frame
414 end
415  
416 function FB_GetButtonNum(frame)
417 -- takes either a button or handle (frame) and returns the button number
418 local firsti, lasti, num = string.find(frame:GetName(), "(%d+)")
419 return num+0
420 end
421  
422 function FB_GetCoords(buttonnum)
423 local button, frame = FB_GetWidgets(buttonnum)
424 -- Save the coordinates of the handle - On programmatically moved buttons,
425 -- WoW won't do it automatically for us across sessions.
426 local x = frame:GetRight()
427 local y = frame:GetBottom()
428 local oldX = FBState[buttonnum]["xcoord"]
429 local oldY = FBState[buttonnum]["ycoord"]
430 FBState[buttonnum]["xcoord"] = x
431 FBState[buttonnum]["ycoord"] = y
432 FBSavedProfile[FBProfileName][buttonnum].State["xcoord"] = x
433 FBSavedProfile[FBProfileName][buttonnum].State["ycoord"] = y
434  
435 FB_UpdateSmartPet(buttonnum)
436  
437 if(FB_DebugFlag == 2) then
438 if ( oldX and oldY ) then
439 if (oldX ~= x) or (oldY ~= y) then
440 FB_ReportToUser("<< FB_GetCoords: Moved Button #"..buttonnum.." from ("..oldX..", "..oldY..") to ("..x..","..y..") >>");
441 else
442 FB_ReportToUser("<< FB_GetCoords: ReSet Button #"..buttonnum.." to ("..x..","..y..") >>");
443 end
444 else
445 FB_ReportToUser("<< FB_GetCoords: Set Button #"..buttonnum.." to ("..x..","..y..") >>");
446 end
447 end
448 FBSavedProfile[FBProfileName][buttonnum].State["ycoord"] = frame:GetBottom()
449 end
450  
451 function FB_SaveState(buttonnum)
452 local button, frame = FB_GetWidgets(buttonnum)
453 -- Save the current button state to the current character's profile.
454 if FBSavedProfile[FBProfileName] == nil then
455 FBSavedProfile[FBProfileName] = {}
456 end
457 FBSavedProfile[FBProfileName][buttonnum].State = util:TableCopy(FBState[buttonnum])
458 end
459  
460 function FB_LoadState(buttonnum)
461 local button, frame = FB_GetWidgets(buttonnum)
462  
463 -- load the current button state from the current character's profile.
464 if FBSavedProfile[FBProfileName] == nil then
465 return
466 end
467 if not FBSavedProfile[FBProfileName][buttonnum] then
468 FBSavedProfile[FBProfileName][buttonnum] = {}
469 FBSavedProfile[FBProfileName][buttonnum].State = {}
470 FBSavedProfile[FBProfileName][buttonnum].State["hidden"] = "true"
471 end
472 FBState[buttonnum] = util:TableCopy(FBSavedProfile[FBProfileName][buttonnum].State)
473 FBState[buttonnum]["oldid"] = button:GetID()
474 FBIDtoButtonNum[button:GetID()] = buttonnum
475  
476 -- Move button to its saved location
477 if FBState[buttonnum]["xcoord"] and FBState[buttonnum]["ycoord"] then
478 local x = FBState[buttonnum]["xcoord"]
479 local y = FBState[buttonnum]["ycoord"]
480  
481 if(FB_DebugFlag == 1) then
482 FB_ReportToUser("<< FB_LoadState: B-"..buttonnum.." to ("..x..","..y..") >>");
483 end
484  
485 frame:ClearAllPoints()
486 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
487 end
488 end
489  
490 function FB_MoveButtonABS(button1, x, y)
491 -- Moves the button and handle so the top left of the button and bottom right of the
492 -- frame are x pixels to the right of the bottom right corner and y pixels above it.
493 -- will work with either a button or handle passed to it.
494 local button, frame = FB_GetWidgets(button1)
495 frame:ClearAllPoints()
496 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
497  
498 FB_UpdateButtonLoc(button1)
499 end
500  
501 function FB_MoveButtonRel(button1, button2, dx, dy)
502 -- Moves button1's top left point (bottom right of handle) x pixels to the left of
503 -- and y pixels above button2's top left point (bottom right of it's handle)
504 -- Leaves button anchored on UIParent.
505 local x = FBState[button2]["xcoord"] + dx
506 local y = FBState[button2]["ycoord"] + dy
507 local button, frame = FB_GetWidgets(button1)
508 frame:ClearAllPoints()
509 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
510  
511 FB_UpdateButtonLoc(button1)
512 end
513  
514 function FB_LockButton(buttonnum)
515 local button, frame = FB_GetWidgets(buttonnum)
516 -- Lock the button by shrinking the handle underneath the
517 -- corner of the button.
518 if frame:GetHeight() == 1 then return end -- is already locked
519 -- If it's user placed, the relative points change. Reset it so we know that
520 -- it is set with it's bottom-right corner relative to the UIParent's bottom left.
521 if frame:IsUserPlaced() then
522 local x = frame:GetRight()
523 local y = frame:GetBottom()
524 frame:ClearAllPoints()
525 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
526 end
527 frame:SetHeight(1)
528 frame:SetWidth(1)
529 end
530  
531 function FB_UnlockButton(buttonnum)
532 local button, frame = FB_GetWidgets(buttonnum)
533 -- unlock button by enlarging the handle to normal size.
534 if frame:GetHeight() == 10 then return end -- is already unlocked
535 -- If it's user placed, the relative points change. Reset it so we know that
536 -- it is set with it's bottom-right corner relative to the UIParent's bottom left.
537 -- While I can't see how a button could be user placed if it's already locked,
538 -- better safe than sorry.
539 if frame:IsUserPlaced() then
540 local x = frame:GetRight()
541 local y = frame:GetBottom()
542 frame:ClearAllPoints()
543 frame:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMLEFT", x, y)
544 end
545 frame:SetHeight(10)
546 frame:SetWidth(10)
547 end
548  
549 -- Functions called by timers to check status of a variety of things and raise the appropriate events
550 function FB_ItemEnchantEvents()
551 -- check for item enchantments
552 local hasMainHandEnchant, mainHandExpiration, mainHandCharges,
553 hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo()
554  
555 if hasMainHandEnchant and not FBItemEnchants["mainhand"] then
556 FB_MoneyToggle();
557 FlexBarTooltip:SetInventoryItem("player",16)
558 local i = 6
559 local text = getglobal("FlexBarTooltipTextLeft"..i)
560 while text and text:IsVisible() and text:GetText() ~= nil do
561 if text and text:GetText() and strfind(text:GetText(),"Durability") then break end
562 i = i+1
563 text = getglobal("FlexBarTooltipTextLeft"..i)
564 end
565 local i = i - 1
566 local text = getglobal("FlexBarTooltipTextLeft"..i)
567 local name = text:GetText()
568 name = string.gsub(name," %(%d+ %a+%)","")
569 FBItemEnchants["mainhand"] = string.lower(name)
570 FBItemEnchants["mainhandcharges"] = mainHandCharges
571 FB_RaiseEvent("GainItemBuff",name)
572 FBBuffs["itembuffs"]["'"..name.."'"] = true
573 FB_MoneyToggle();
574 end
575 if not hasMainHandEnchant and FBItemEnchants["mainhand"] then
576 FB_RaiseEvent("LoseItemBuff",FBItemEnchants["mainhand"])
577 FBItemEnchants["mainhand"] = nil
578 FBItemEnchants["mainhandcharges"] = nil
579 FBItemEnchants["mainhandtimeleft"] = nil
580 end
581 if hasoffHandEnchant and not FBItemEnchants["offhand"] then
582 FB_MoneyToggle();
583 FlexBarTooltip:SetOwner(UIParent, "ANCHOR_NONE");
584 FlexBarTooltip:SetInventoryItem("player",17)
585 local i = 6
586 local text = getglobal("FlexBarTooltipTextLeft"..i)
587 while text and text:IsVisible() and text:GetText() ~= nil do
588 if text and text:GetText() and strfind(text:GetText(),"Durability") then break end
589 i = i+1
590 text = getglobal("FlexBarTooltipTextLeft"..i)
591 end
592 local i = i - 1
593 local text = getglobal("FlexBarTooltipTextLeft"..i)
594 local name = text:GetText()
595 name = string.gsub(name," %(%d+ %a+%)","")
596 FBItemEnchants["offhand"] = string.lower(name)
597 FBItemEnchants["offhandcharges"] = offHandCharges
598 FB_RaiseEvent("GainItemBuff",name)
599 FBBuffs["itembuffs"]["'"..name.."'"] = true
600 FB_MoneyToggle();
601 end
602 if not hasoffHandEnchant and FBItemEnchants["offhand"] then
603 FB_RaiseEvent("LoseItemBuff",FBItemEnchants["offhand"])
604 FBItemEnchants["offhand"] = nil
605 FBItemEnchants["offhandcharges"] = nil
606 FBItemEnchants["offhandtimeleft"] = nil
607 end
608 if mainHandCharges ~= FBItemEnchants["mainhandcharges"] then
609 FB_RaiseEvent("MainHandCharges",mainHandCharges)
610 end
611 if offHandCharges ~= FBItemEnchants["offhandcharges"] then
612 FB_RaiseEvent("OffHandCharges",offHandCharges)
613 end
614 FBItemEnchants["mainhandcharges"] = mainHandCharges
615 FBItemEnchants["offhandcharges"] = offHandCharges
616 if mainHandExpiration then
617 FBItemEnchants["mainhandtimeleft"] = mainHandExpiration - GetTime()
618 else
619 FBItemEnchants["mainhandtimeleft"] = 0
620 end
621 if offHandExpiration then
622 FBItemEnchants["offhandtimeleft"] = offHandExpiration - GetTime()
623 else
624 FBItemEnchants["offhandtimeleft"] = 0
625 end
626 end
627  
628 function FB_DeathEvents()
629 -- check for unit being dead or a ghost
630 local index, value, list
631 list = FBEventToggleInfo["deathcheck"][FBEventToggles["deathcheck"] .."list"]
632 if not list then return end
633 for index, value in pairs(list) do
634 if UnitExists(index) then
635 if FBUnitStatus[index] ~= "dead" and UnitIsDeadOrGhost(index) then
636 FB_RaiseEvent("UnitDied",index)
637 FBUnitStatus[index] = "dead"
638 if index == "player" then
639 FBSavedProfile[FBProfileName].Buffs = {}
640 end
641 end
642 if FBUnitStatus[index] == "dead" and not UnitIsDeadOrGhost(index) then
643 FB_RaiseEvent("UnitRessed",index)
644 FBUnitStatus[index] = "alive"
645 end
646 end
647 end
648 end
649  
650 function FB_CombatEvents()
651 -- check for unit "affecting combat" New to 1300
652 local index, value, list
653 list = FBEventToggleInfo["affectcombat"][FBEventToggles["affectcombat"] .."list"]
654 if not list then return end
655 for index, value in pairs(list) do
656 if UnitExists(index) then
657 if FBUnitCombat[index] and not UnitAffectingCombat(index) then
658 FB_RaiseEvent("EndCombat",index)
659 FBUnitCombat[index] = nil
660 end
661 if not FBUnitCombat[index] and UnitAffectingCombat(index) then
662 FB_RaiseEvent("StartCombat",index)
663 FBUnitCombat[index] = true
664 end
665 end
666 end
667 end
668  
669 function FB_CheckPets(pet)
670 if UnitExists(pet) then -- gained a pet
671 if FBEventToggles["petcheck"] == "high" or FBEventToggleInfo["petcheck"]["lowlist"][pet] then
672 FB_RaiseEvent("PetSummoned",pet)
673 end
674 if pet == "pet" then -- legacy gainpet for player only - incudes type for warlocks
675 FB_RaiseEvent("GainPet",UnitCreatureFamily("pet"))
676 table.insert(FBPetTypes,UnitCreatureFamily("pet"))
677 end
678 else
679 if FBEventToggles["petcheck"] == "high" or FBEventToggleInfo["petcheck"]["lowlist"][pet] then
680 FB_RaiseEvent("PetDismissed",pet)
681 end
682 if pet == "pet" then -- legacy losepet for player only
683 FB_RaiseEvent("LosePet")
684 end
685 end
686 end
687  
688 function FB_PetEvents()
689 -- Called every .5 seconds to check for a change in pet status
690 local petname = UnitName("pet")
691 if petname and not FBPetname then
692 FB_RaiseEvent("GainPet","petname")
693 end
694 if not petname and FBPetname then
695 FB_RaiseEvent("LosePet")
696 end
697  
698 FBPetname = petname
699 end
700  
701 local allpartyunits = {"player","pet"}
702 local index
703 for index = 1,4 do
704 table.insert(allpartyunits,"party"..index)
705 table.insert(allpartyunits,"partypet"..index)
706 end
707  
708 local allraidunits = {}
709 for index = 1,40 do
710 table.insert(allraidunits,"raid"..index)
711 table.insert(allraidunits,"raidpet"..index)
712 end
713  
714 function FB_TargetTargetEvents()
715 -- Called every .1 seconds to check for a target of your target and whether it's one of:
716 -- player, pet, party1-party4, partypet1-partypet4 or the name of the unit.
717 -- Timer will only run while we have a target, but check for existence of targettarget
718 if not UnitExists("targettarget") then
719 if FBLastTargetTarget then
720 FB_RaiseEvent("targetlosttarget")
721 FBLastTargetTarget = nil
722 FBLastTargetTargetName = nil
723 end
724 return
725 end
726  
727 local unit
728 if UnitInParty("targettarget") then
729 -- unit in party
730 for i,v in ipairs(allpartyunits) do
731 if UnitIsUnit("targettarget",v) then
732 unit = v
733 break
734 end
735 end
736 end
737  
738 -- otherwise get unit type (hostile/neutral/friendly pc/npc)
739 if not unit then
740 local pctype
741 if UnitIsPlayer("targettarget") then
742 pctype = "pc"
743 else
744 pctype = "npc"
745 end
746 if UnitIsEnemy("targettarget","player") then
747 unit = "hostile" .. pctype
748 elseif UnitIsFriend("targettarget","player") then
749 unit = "friendly" .. pctype
750 else
751 unit = "neutral" .. pctype
752 end
753 end
754  
755 -- if it's a friendly pc and the event toggle is set to high check for it being a raid member.
756 if unit == "friendlypc" and FBEventToggles["targetcheck"] == "high" then
757 for i,v in ipairs(allraidunits) do
758 if UnitIsUnit("targettarget",v) then
759 unit = v
760 break
761 end
762 end
763 end
764  
765 if FBLastTargetTarget ~= unit then
766 if not FBLastTargetTarget then
767 FB_RaiseEvent("targetgaintarget",unit)
768 elseif FBLastTargetTarget ~= unit or FBLastTargetTargetName ~= UnitName("targettarget") then
769 FB_RaiseEvent("targetchangedtarget",unit)
770 end
771 end
772  
773 FBLastTargetTarget = unit
774 FBLastTargetTargetName = UnitName("targettarget")
775 end
776  
777 function FB_UsableEvents()
778 -- usable events.
779 local index, value, list
780 list = FBEventToggleInfo["usablecheck"][FBEventToggles["usablecheck"].."list"]
781 if not list then return end
782 for index, value in pairs(list) do
783 local button, frame = FB_GetWidgets(index)
784 if HasAction(button:GetID()) then
785 local isUsable, notEnoughMana = IsUsableAction(button:GetID());
786 if FBState[index]["isUsable"] and not isUsable then
787 FB_RaiseEvent("NotUsable", FB_GetButtonNum(button))
788 end
789 if not FBState[index]["isUsable"] and isUsable then
790 FB_RaiseEvent("IsUsable", FB_GetButtonNum(button))
791 end
792 FBState[index]["isUsable"] = isUsable
793 end
794 end
795 end
796  
797 function FB_ManaEvents()
798 -- mana events.
799 local index, value, list
800 list = FBEventToggleInfo["manacheck"][FBEventToggles["manacheck"].."list"]
801 if not list then return end
802 for index, value in pairs(list) do
803 local button, frame = FB_GetWidgets(index)
804 if HasAction(button:GetID()) then
805 local isUsable, notEnoughMana = IsUsableAction(button:GetID());
806 if FBState[index]["notEnoughMana"] and not notEnoughMana then
807 FB_RaiseEvent("EnoughMana", FB_GetButtonNum(button))
808 end
809 if not FBState[index]["notEnoughMana"] and notEnoughMana then
810 FB_RaiseEvent("NotEnoughMana", FB_GetButtonNum(button))
811 end
812  
813 FBState[index]["notEnoughMana"]=notEnoughMana
814 end
815 end
816 end
817  
818 function FB_RangeEvents()
819 -- Range events.
820 local index, value, list
821 list = FBEventToggleInfo["rangecheck"][FBEventToggles["rangecheck"].."list"]
822 if not list then return end
823 for index, value in pairs(list) do
824 local button, frame = FB_GetWidgets(index)
825 if HasAction(button:GetID()) then
826 local inRange = IsActionInRange(button:GetID());
827 if FBState[index]["inRange"] ~= 0 and inRange == 0 then
828 FB_RaiseEvent("OutOfRange", index)
829 end
830 if FBState[index]["inRange"] == 0 and inRange ~= 0 then
831 FB_RaiseEvent("NowInRange", index)
832 end
833 FBState[index]["inRange"] = inRange
834 end
835 end
836 end
837  
838 function FB_CooldownEvents()
839 -- raise cooldown events
840 local index, value, list
841 list = FBEventToggleInfo["cooldowncheck"][FBEventToggles["cooldowncheck"].."list"]
842 if not list then return end
843 for index, value in pairs(list) do
844 local button, frame = FB_GetWidgets(index)
845 if HasAction(button:GetID()) then
846 local start, duration, enable = GetActionCooldown(button:GetID())
847 if FBState[index]["start"] == nil then FBState["start"] = 0 end
848 if start == 0 and FBState[index]["start"] ~= 0 then
849 FB_RaiseEvent("CoolDownMet", index)
850 end
851 if start ~= 0 and FBState[index]["start"] == 0 then
852 FB_RaiseEvent("CoolDownStart", index)
853 end
854 FBState[index]["start"] = start
855 end
856 end
857 end
858  
859 function FB_KeyEvents()
860 -- raise modifier key down/up events
861 if IsShiftKeyDown() and not FBKeyStates["shift"] then
862 FB_RaiseEvent("ShiftKeyDown")
863 end
864 if not IsShiftKeyDown() and FBKeyStates["shift"] then
865 FB_RaiseEvent("ShiftKeyUp")
866 end
867 FBKeyStates["shift"] = IsShiftKeyDown()
868 if IsAltKeyDown() and not FBKeyStates["alt"] then
869 FB_RaiseEvent("AltKeyDown")
870 end
871 if not IsAltKeyDown() and FBKeyStates["alt"] then
872 FB_RaiseEvent("AltKeyUp")
873 end
874 FBKeyStates["alt"] = IsAltKeyDown()
875 if IsControlKeyDown() and not FBKeyStates["control"] then
876 FB_RaiseEvent("ControlKeyDown")
877 end
878 if not IsControlKeyDown() and FBKeyStates["control"] then
879 FB_RaiseEvent("ControlKeyUp")
880 end
881 FBKeyStates["control"] = IsControlKeyDown()
882  
883 end
884  
885 -- General Utility functions
886  
887 function FB_RegisterEvent(event, name, callback, wowevent)
888 -- Register a handler for an event
889 -- all names will be upper case
890 -- WoW events and FB events are in the same table
891 if wowevent then
892 FlexBar:RegisterEvent(event)
893 end
894 if not FBExtHandlers[string.upper(event)] then
895 FBExtHandlers[string.upper(event)] = {}
896 end
897  
898 FBExtHandlers[string.upper(event)][string.lower(name)] = callback
899 end
900  
901 function FB_UnregisterEvent(event, name)
902 -- Un load a handler
903 if not FBExtHandlers[string.upper(event)] then return end
904 FBExtHandlers[string.upper(event)][string.lower(name)] = nil
905 end
906  
907 function FB_Report(msg)
908 -- little helper function to display feedback of actions to the user.
909 if not FBToggles["verbose"] then return end
910 util:Print("FB> " .. msg)
911 end
912  
913 function FB_ReportToUser(msg)
914 -- little helper function to display feedback of actions to the user - reguardless of configuration.
915 util:Print(msg)
916 end
917  
918 function FB_LoadProfile()
919  
920 if(FB_DebugFlag == 1) then
921 FB_ReportToUser("<< FB_LoadProfile Entry >>");
922 end
923  
924 -- Load the current character's profile back into the buttons.
925 if (UnitName("player") == nil) or
926 (string.lower(UnitName("player")) == "unknown entity") or
927 UnitName("player") == UNKNOWNBEING or
928 UnitName("player") == UNKNOWNOBJECT then
929 FBTimers["loadprofile"] = Timer_Class:New(1, nil,
930 ".... loading", nil, FB_LoadProfile)
931 return
932 end
933  
934 FBCharName = UnitName("player")
935 FBProfileName = FBCharName .. " of " .. GetCVar("RealmName")
936  
937 local index
938 if FBSavedProfile[FBProfileName] == nil then
939 if FBSavedProfile[FBCharName] ~= nil then
940 util:Print("Updating to per-server/character saved profiles")
941 util:Print("Copying profile for " .. FBCharName .. " to " .. FBProfileName)
942 FBSavedProfile[FBProfileName] = util:TableCopy(FBSavedProfile[FBCharName])
943 else
944 util:Print("No profile for " .. FBProfileName .." found, creating a new one")
945 FBSavedProfile[FBProfileName] = {}
946 for index = 1, FBNumButtons do
947 FBSavedProfile[FBProfileName][index] = {}
948 FBSavedProfile[FBProfileName][index].State = {}
949 FBSavedProfile[FBProfileName][index].State["hidden"] = true
950 end
951 FBSavedProfile[FBProfileName].Events = {}
952 FBSavedProfile[FBProfileName].Events.n = 0
953 end
954 end
955  
956 for index = 1, FBNumButtons do
957 FB_LoadState(index)
958 end
959  
960 if FBSavedProfile[FBProfileName].Buffs == nil then
961 FBSavedProfile[FBProfileName].Buffs = {}
962 end
963  
964 if FBSavedProfile[FBProfileName].EventToggles == nil then
965 FBSavedProfile[FBProfileName].EventToggles = {}
966 local index,value
967 for index,value in pairs(FBEventToggleInfo) do
968 FBSavedProfile[FBProfileName].EventToggles[index] = value["toggle"]
969 end
970 else
971 local index,value
972 for index,value in pairs(FBEventToggleInfo) do
973 if FBSavedProfile[FBProfileName].EventToggles[index] == nil then
974 FBSavedProfile[FBProfileName].EventToggles[index] = value["toggle"]
975 end
976 end
977 end
978  
979 if FBSavedProfile[FBProfileName].FlexActions == nil then
980 FBSavedProfile[FBProfileName].FlexActions = {}
981 end
982  
983  
984 FBEventToggles = FBSavedProfile[FBProfileName].EventToggles
985 FBEventToggleInfo["boundcheck"]["highlist"] = FBGroupData
986 FBProfileLoaded=true;
987 FBEvents = util:TableCopy(FBSavedProfile[FBProfileName].Events)
988 FB_CreateQuickDispatch()
989  
990 -- Add ReformAllGroups call to properly setup all groups and buttons.
991 FB_ReformAllGroups()
992  
993 -- Using FlexBar's scale to see if the buttons need rescaling
994 FlexBar:SetScale(.25)
995  
996 util:Echo("Flex Bar settings for " .. FBProfileName .. " loaded")
997  
998 -- Start Resync timer - just used to check for an overall UI scale change. If scale has gotten changed for some
999 -- reason, it will reload the profile.
1000 FBTimers["resync"] = Timer_Class:New(5, true, nil, nil, FB_ResyncSettings)
1001  
1002 -- set a recurring timers to check for the variety of events that don't necessarily have real
1003 -- WoW events (some of these do, but was just easier to copy/paste the timer code. A liittle
1004 -- sloppy, but the extra overhead for group checking is minimal, and for form checking not only
1005 -- minimal but well worth it to get fades that normally don't get reported in UNIT_LOSE_AURA)
1006 FBTimers["boundcheck"] = Timer_Class:New(.1, true, nil, nil, FB_CheckGroups)
1007 FBTimers["cooldowncheck"] = Timer_Class:New(1, true, nil, nil, FB_CooldownEvents)
1008 FBTimers["manacheck"] = Timer_Class:New(1, true, nil, nil, FB_ManaEvents)
1009 FBTimers["usablecheck"] = Timer_Class:New(.5, true, nil, nil, FB_UsableEvents)
1010 FBTimers["rangecheck"] = Timer_Class:New(.25, true, nil, nil, FB_RangeEvents)
1011 FBTimers["targettarget"] = Timer_Class:New(.1, true, nil, nil, FB_TargetTargetEvents)
1012 FBTimers["deathcheck"] = Timer_Class:New(.5, true, nil, nil, FB_DeathEvents)
1013 FBTimers["keycheck"] = Timer_Class:New(.1, true, nil, nil, FB_KeyEvents)
1014 FBTimers["affectcombat"] = Timer_Class:New(.25, true, nil, nil, FB_CombatEvents)
1015 FBTimers["itembuffs"] = Timer_Class:New(.33, true, nil, nil, FB_ItemEnchantEvents)
1016 -- FB_GetSpellInfo()
1017 FB_RestoreScripts()
1018 FB_CheckAutoItems()
1019 FB_Set_PerformanceOptions()
1020 FB_RaiseEvent("ProfileLoaded",FBProfileName)
1021 -- pre-load buffs
1022 FB_CheckAllBuffs("player")
1023 FB_GeneratePetIDList()
1024 FB_MimicPetButtons()
1025 end
1026  
1027 function FB_RestoreScripts()
1028 -- function to rebuild scripts > 1024 characters long
1029 local name, script, index, value
1030 for name, script in pairs(FBTextChunks) do
1031 FBScripts[name] = ""
1032 for index,value in ipairs(script) do
1033 FBScripts[name] = FBScripts[name] .. value
1034 end
1035 end
1036 end
1037  
1038 function FB_GetButtonList(list)
1039 -- regularize arguments to functions that take button lists
1040 -- returns a list of buttons to be affected as a list, with the
1041 -- number of buttons in list.n
1042 local return_value = {}
1043 return_value.n = 0
1044 if list == nil then
1045 return return_value
1046 elseif type(list) == "number" then
1047 return_value[1]=list
1048 return_value.n = 1
1049 return return_value
1050 elseif type(list) == "table" then
1051 local index
1052 list.n = 0
1053 for index in ipairs(list) do
1054 list.n = list.n+1
1055 end
1056 return_value=list
1057 return return_value
1058 else
1059 util:Print("Nil passed to FB_GetButtonList - report this")
1060 end
1061 end
1062  
1063 function FB_DisplayScripts()
1064 local scripts = {}
1065 local ind, value
1066 for ind, value in pairs(FBScripts) do
1067 table.insert(scripts, ind)
1068 end
1069 table.sort(scripts, function(v1,v2) return string.lower(v1) < string.lower(v2) end)
1070  
1071 local count, index, val
1072 local scriptnames = {}
1073 count=0
1074 for index,val in pairs(scripts) do
1075 count=count+1
1076 scriptnames[count]=val
1077 end
1078  
1079 if FBScriptCount > count - 16 then FBScriptCount = count - 14 end
1080 if FBScriptCount < 1 then FBScriptCount = 1 end
1081  
1082 for index = 0,15 do
1083 local button=getglobal("FBScriptsMenu"..index)
1084 if scriptnames[index+FBScriptCount] then
1085 button:SetText(scriptnames[index+FBScriptCount])
1086 else
1087 button:SetText("")
1088 end
1089 end
1090 end
1091  
1092 function FB_CastSpellByName(spellname)
1093 -- function to replace CastSpellByName
1094 CastSpellByName(spellname)
1095 return
1096  
1097 --[[
1098 if FBPlayerSpells[spellname] then
1099 CastSpell(FBPlayerSpells[spellname],1)
1100 elseif FBPlayerMaxRank[spellname] then
1101 CastSpell(FBPlayerMaxRank[spellname],1)
1102 elseif FBPetSpells[spellname] then
1103 CastSpell(FBPetSpells[spellname],BOOKTYPE_PET)
1104 elseif FBPetMaxRank[spellname] then
1105 CastSpell(FBPetMaxRank[spellname],BOOKTYPE_PET)
1106 else
1107 util:Echo("ERROR: Attempt to cast non-existent spell","red")
1108 end ]]
1109 end
1110  
1111 function FBCastcmd:Dispatch(msg)
1112 -- implement my castspellbyname as a slash command for macros
1113 CastSpellByName(msg)
1114 end
1115  
1116 function FBDoIncmd:Dispatch(msg)
1117 -- implement my in as a slash command
1118 local firsti, lasti, seconds = string.find(msg,"^(%d+)%s+")
1119 if not firsti then return end
1120 FBcmd:Dispatch("runmacro macro='"..string.sub(msg,lasti+1).."' in=".. seconds)
1121 end
1122  
1123 function FBUsecmd:Dispatch(msg)
1124 -- implement my usebyname as a slash command for macros
1125 FB_UseByName(msg)
1126 end
1127  
1128 function FBEchocmd:Dispatch(msg)
1129 -- implement echo as a slash command for macros
1130 local _,_,capture = string.find(msg,"#(%w+)")
1131 local color = "white"
1132 if capture and Utility_Class.ColorList[string.lower(capture)] then
1133 msg = string.gsub(msg,"#"..capture.."%s*","")
1134 color = string.lower(capture)
1135 end
1136 local variable
1137 for variable in string.gfind(msg,"(%%%w+)") do
1138 if FBTextSubstitutions[string.lower(variable)] then
1139 msg = string.gsub(msg, "%"..variable, FBTextSubstitutions[string.lower(variable)]())
1140 end
1141 end
1142 for variable in string.gfind(msg,"$([%w%p]+)$") do
1143 RunScript("FBMacroValue="..variable)
1144 variable = string.gsub(variable,"([%(%)%.%%%+%-%*%?%[%]%^%$])","%%%1")
1145 msg = string.gsub(msg,"$"..variable.."$",tostring(FBMacroValue))
1146 end
1147 util:Echo(msg,color)
1148 end
1149  
1150 function FBPrintcmd:Dispatch(msg)
1151 -- implement echo as a slash command for macros
1152 local _,_,capture = string.find(msg,"#(%w+)")
1153 local color = "white"
1154 if capture and Utility_Class.ColorList[string.lower(capture)] then
1155 msg = string.gsub(msg,"#"..capture.."%s*","")
1156 color = string.lower(capture)
1157 end
1158 local variable
1159 for variable in string.gfind(msg,"(%%%w+)") do
1160 if FBTextSubstitutions[string.lower(variable)] then
1161 msg = string.gsub(msg, "%"..variable, FBTextSubstitutions[string.lower(variable)]())
1162 end
1163 end
1164 for variable in string.gfind(msg,"$([%w%p]+)$") do
1165 RunScript("FBMacroValue="..variable)
1166 variable = string.gsub(variable,"([%(%)%.%%%+%-%*%?%[%]%^%$])","%%%1")
1167 msg = string.gsub(msg,"$"..variable.."$",tostring(FBMacroValue))
1168 end
1169 util:Print(msg,color)
1170 end
1171  
1172 function FB_GetSpellInfo()
1173 -- Load tables up with spell position by name for a CastSpellByName that works in scripts
1174 FBPlayerSpells = {}
1175 FBPlayerMaxRank = {}
1176 FBPetSpells = {}
1177 FBPetMaxRank = {}
1178 local index = 1
1179  
1180 while true do
1181 local spellname, spellrank = GetSpellName(index,1)
1182 if not spellname then break end
1183 if not spellrank then spellrank = "" end
1184 if not IsSpellPassive(index,1) then
1185 FBPlayerSpells[spellname.."("..spellrank..")"] = index
1186 FBPlayerMaxRank[spellname] = index
1187 end
1188 index = index+1
1189 end
1190  
1191 if not HasPetSpells() then return end
1192  
1193 local index = 1
1194  
1195 while true do
1196 local spellname, spellrank = GetSpellName(index,BOOKTYPE_PET)
1197 if not spellname then break end
1198 if not spellrank then spellrank = "" end
1199 FBPetSpells[spellname.."("..spellrank..")"] = index
1200 FBPetMaxRank[spellname] = index
1201 index = index+1
1202 end
1203 end
1204  
1205 function FB_InTable(value1, table1)
1206 -- Simple utility function to check for the existence of
1207 -- value1 in table1
1208 local index, value
1209 for index,value in pairs(table1) do
1210 if type(value) == "string" then value=string.lower(value) end
1211 if value == value1 then
1212 return true;
1213 end
1214 end
1215 return false
1216 end
1217  
1218 function FB_Execute_Command(command)
1219 -- Simple function to execute a string as though it were typed in the chat box
1220 local variable
1221 for variable in string.gfind(command,"(%%%w+)") do
1222 if FBTextSubstitutions[string.lower(variable)] then
1223 command = string.gsub(command, "%"..variable, FBTextSubstitutions[string.lower(variable)]())
1224 end
1225 end
1226 for variable in string.gfind(command,"%$([%w%p]+)%$") do
1227 RunScript("FBMacroValue="..variable)
1228 variable = string.gsub(variable,"([%(%)%.%%%+%-%*%?%[%]%^%$])","%%%1")
1229 command = string.gsub(command,"%$"..variable.."%$",tostring(FBMacroValue))
1230 end
1231 FlexBar_Command_EditBox:SetText(command)
1232 local editbox = FlexBar_Command_EditBox
1233 ChatEdit_SendText(editbox)
1234 end
1235  
1236 function FB_Execute_ConfigString(config)
1237 -- Execute config contained in a string
1238 local capture
1239 FBTestConfig = {}
1240 config = "\n" .. config .. "\n"
1241 for capture in string.gfind(config,"([^%\n]+)") do
1242 if capture ~= "" and not string.find(capture,"%s*%-%-") then
1243 table.insert(FBTestConfig, capture)
1244 end
1245 end
1246 FBcmd:Dispatch("loadconfig config='FBTestConfig'")
1247 end
1248  
1249 function FB_Execute_MultilineMacro(macro, macroname)
1250 -- Execute multi-line macro contained in a string
1251 -- Clear FBEventArgs: When doing a RunMacro off an event, this was causing /FlexBar Commands to not execute
1252 FBEventArgs = nil
1253 -- Macro is waiting, and someone tried to re-run it.
1254 if FBMacroWait[macroname] and FBMacroWait[macroname]["time"] > GetTime() then return end
1255 local skip = 0
1256 local count = 1
1257 local capture
1258 config = "\n" .. macro .. "\n"
1259 for capture in string.gfind(config,"([^%\n]+)") do
1260 if (FBMacroWait[macroname] and (count > FBMacroWait[macroname]["line"])) or (not FBMacroWait[macroname])then
1261 if string.sub(capture,1,3) == "/if" then
1262 if not FB_CheckConditional(string.sub(capture,4)) then
1263 skip = 1
1264 end
1265 elseif string.sub(capture,1,5) == "/else" then
1266 if skip == 1 then skip = 0 else skip = 1 end
1267 elseif string.sub(capture,1,4) == "/end" then
1268 skip = 0
1269 elseif string.sub(capture,1,6) == "/break" then
1270 FBMacroWait[macroname] = nil
1271 return
1272 elseif skip == 0 then
1273 if capture ~= "" then
1274 local _,_,delay = string.find(string.lower(capture),"/fbwait (%d+)")
1275 if delay then
1276 FBMacroWait[macroname] = {}
1277 FBMacroWait[macroname]["time"] = GetTime() + (delay/10)
1278 FBMacroWait[macroname]["line"] = count
1279 FBTimers[macroname .. "wait timer"] =
1280 Timer_Class:New((delay/10)+.1,nil,nil,nil,function() FB_Execute_MultilineMacro(macro, macroname) end)
1281 return
1282 end
1283 FB_Execute_Command(capture)
1284 end
1285 end
1286 end
1287 count=count+1
1288 end
1289 FBMacroWait[macroname] = nil
1290 end
1291  
1292 function FB_CheckTextSub()
1293 -- Scan text subs on health, mana, combopoints, scan-inventory or simply 1 time per second for timers
1294 if (FBButtonInfoShown == true) then return end
1295 local index
1296 for index = 1, FBNumButtons do
1297 FB_TextSub(index)
1298 end
1299 end
1300  
1301 function FB_GetBagLocation(name)
1302 -- find a location with the item named
1303 local bagnum, slotindex
1304 if FBBagContents[name] then
1305 return FBBagContents[name]["bag"],FBBagContents[name]["slot"]
1306 else
1307 return nil
1308 end
1309 end
1310  
1311 function FB_UseByName(name)
1312 -- Function to use an item by name
1313 local bag, slot = FB_GetBagLocation(name)
1314 if bag then
1315 if bag < 5 then
1316 UseContainerItem(bag,slot)
1317 else
1318 UseInventoryItem(slot)
1319 end
1320 else
1321 util:Echo(name .. " not found on your person", "yellow")
1322 end
1323 end
1324  
1325 function FB_PlaceItemOnActionBar(name, id)
1326 -- Function to place an item on the bar by name
1327 local bag, slot = FB_GetBagLocation(name)
1328 if bag then
1329 if bag < 5 then
1330 PickupContainerItem(bag,slot)
1331 PlaceAction(id)
1332 else
1333 PickupInventoryItem(FB_GetInvLocation(name))
1334 PlaceAction(id)
1335 end
1336 else
1337 util:Echo(name .. " not found on your person", "yellow")
1338 end
1339 end
1340  
1341 function FB_ScanInventory()
1342 -- creates a table indexed by item name with total count and a location
1343 local index, value
1344 for index, value in pairs(FBBagContents) do
1345 if type(value) == "table" then
1346 value["count"] = 0
1347 value["bag"] = nil
1348 value["slot"] = nil
1349 end
1350 end
1351 local bag, slot
1352 -- search bags left to right
1353 for bag = 0,4 do
1354 if bag == 0 then
1355 FBBagContents["allbagsnumslots"] = GetContainerNumSlots(bag)
1356 FBBagContents["backpacknumslots"] = GetContainerNumSlots(bag)
1357 FBBagContents["allbagsnumslotsleft"] = GetContainerNumSlots(bag)
1358 FBBagContents["backpacknumslotsleft"] = GetContainerNumSlots(bag)
1359 FBBagContents["allbagsnumslotsused"] = 0
1360 FBBagContents["backpacknumslotsused"] = 0
1361 else
1362 local name = "bag"..bag
1363 FBBagContents[name.."numslots"] = GetContainerNumSlots(bag)
1364 FBBagContents[name.."numslotsleft"] = GetContainerNumSlots(bag)
1365 FBBagContents[name.."numslotsused"] = 0
1366 FBBagContents["allbagsnumslots"] = FBBagContents["allbagsnumslots"] + GetContainerNumSlots(bag)
1367 FBBagContents["allbagsnumslotsleft"] = FBBagContents["allbagsnumslotsleft"] + GetContainerNumSlots(bag)
1368 end
1369 for slot = 1,GetContainerNumSlots(bag) do
1370 local link = GetContainerItemLink(bag, slot)
1371 local name
1372 if link then
1373 _,_,name = string.find(link,"%[([^%[%]]+)%]")
1374 end
1375 if name then
1376 FBBagContents["allbagsnumslotsused"] = FBBagContents["allbagsnumslotsused"] + 1
1377 FBBagContents["allbagsnumslotsleft"] = FBBagContents["allbagsnumslotsleft"] - 1
1378 if bag == 0 then
1379 FBBagContents["backpacknumslotsused"] = FBBagContents["backpacknumslotsused"] + 1
1380 FBBagContents["backpacknumslotsleft"] = FBBagContents["backpacknumslotsleft"] - 1
1381 else
1382 FBBagContents["bag"..bag.."numslotsused"] = FBBagContents["bag"..bag.."numslotsused"] + 1
1383 FBBagContents["bag"..bag.."numslotsleft"] = FBBagContents["bag"..bag.."numslotsleft"] - 1
1384 end
1385 if not FBBagContents[name] then
1386 FBBagContents[name] = {}
1387 FBBagContents[name]["bag"] = bag
1388 FBBagContents[name]["slot"] = slot
1389 local text,count = GetContainerItemInfo(bag,slot)
1390 if not count then count = 0 end
1391 FBBagContents[name]["count"] = count
1392 else
1393 local text,count = GetContainerItemInfo(bag,slot)
1394 FBBagContents[name]["bag"] = bag
1395 FBBagContents[name]["slot"] = slot
1396 if not count then count = 0 end
1397 FBBagContents[name]["count"] = FBBagContents[name]["count"] + count
1398 end
1399 end
1400 end
1401 end
1402 bag = 5
1403 for slot = 1,23 do
1404 local link = GetInventoryItemLink("player",slot)
1405 local name
1406 if link then
1407 _,_,name = string.find(link,"%[([^%[%]]+)%]")
1408 end
1409 if name then
1410 if not FBBagContents[name] then
1411 FBBagContents[name] = {}
1412 end
1413 FBBagContents[name]["bag"] = bag
1414 FBBagContents[name]["slot"] = slot
1415 FBBagContents[name]["count"] = 1
1416 end
1417 end
1418 end
1419  
1420 function FB_CheckAutoItems()
1421 -- Check to see if an auto item is empty
1422 if not FBProfileLoaded then return end
1423 FB_ScanInventory()
1424 local index,value
1425 for index,value in pairs(FBSavedProfile[FBProfileName].FlexActions) do
1426 if value["action"] == "autoitem" and GetActionCount(index) == 0 and value["count"] > 0 then
1427 -- used last one
1428 if FBEventToggles["autoitems"] ~= "off" then FB_RaiseEvent("AutoItemOut",value["name"]) end
1429 value["count"] = 0
1430 end
1431  
1432 if value["action"] == "autoitem" and value["count"] == 0 and
1433 FBBagContents[value["name"]] and
1434 FBBagContents[value["name"]]["count"] and
1435 FBBagContents[value["name"]]["count"] > 0 then
1436 -- was out, now have some
1437 FB_PlaceItemOnActionBar(value["name"],index)
1438 if FBEventToggles["autoitems"] ~= "off" then FB_RaiseEvent("AutoItemRestored",value["name"]) end
1439 value["count"] = FBBagContents[value["name"]]["count"]
1440 PutItemInBackpack() -- just in case it was occupied
1441 end
1442  
1443 end
1444 end
1445  
1446 function FB_FlexActionButtonBindingCode(buttonnum, keystate)
1447 -- The code in the xml was out of control, moved to here
1448 local echonum = FBState[buttonnum]["echo"]
1449 if ( keystate == "down" ) then
1450 if not FBState[buttonnum]["disabled"] then
1451 FlexBarButtonDown(buttonnum);
1452 end
1453 if FBEventToggles["buttonevents"] ~= "off" then
1454 FB_RaiseEvent("LeftButtonDown",buttonnum)
1455 if echonum then
1456 FB_RaiseEvent("LeftButtonDown",echonum)
1457 end
1458 end
1459 else
1460 if FBEventToggles["buttonevents"] ~= "off" then
1461 FB_RaiseEvent("LeftButtonUp",buttonnum)
1462 if echonum then
1463 FB_RaiseEvent("LeftButtonUp",echonum)
1464 end
1465 end
1466 if not FBState[buttonnum]["disabled"] then
1467 FlexBarButtonUp(buttonnum);
1468 end
1469 end
1470 end
1471  
1472 function FB_BindingKeyEvents(source, keystate)
1473 -- Code from FlexBar event bindings
1474 if FBEventToggles["bindingkeyevents"] ~= "off" then
1475 if ( keystate == "down" ) then
1476 FB_RaiseEvent("BindingKeyDown", source);
1477 else
1478 FB_RaiseEvent("BindingKeyUp", source);
1479 end
1480 end
1481 end
1482  
1483 function FB_SetCommandTimer(action, args)
1484 -- Put a command on a timer
1485 if not args["in"] then return nil end
1486 if args["ttoggle"] and not args["tname"] then
1487 util:Print("Error: must specify a name for toggle to work")
1488 return true
1489 end
1490 local name = args["tname"] or action .. GetTime()
1491 local delay = args["in"]/10
1492 if args["ttoggle"] and FBTimers[name] and FBTimers[name]:GetRunning() then
1493 FBTimers[name] = nil
1494 return true
1495 end
1496 -- have to allocate more memory for this - no way out that I can see
1497 local timerargs = util:TableCopy(args)
1498 timerargs["tname"] = nil
1499 timerargs["in"] = nil
1500 timerargs["ttoggle"] = nil
1501 FBTimers[name] = Timer_Class:New(delay,nil,nil,nil,function() FB_CommandTimerDispatch(action,timerargs) end)
1502 return true
1503 end
1504  
1505 function FB_CommandTimerDispatch(action, args)
1506 FBEventArgs = args
1507 local dispatch = FBcmd.CommandList[action]
1508 dispatch("")
1509 FBEventArgs = nil
1510 end
1511  
1512 function FB_GetEventMsg(action, args)
1513 -- Creates a new table with the parameters needed for RaiseEvent and populates FBEvents.
1514 local event = {}
1515 -- if there is no "ON" directive then return nil
1516 if args["on"] == nil then
1517 return nil
1518 else
1519 event["on"] = args["on"]
1520 end
1521 -- copy the target over to the event
1522 if args["target"] and type(args["target"]) == "table" then
1523 event["target"] = util:TableCopy(args["target"])
1524 else
1525 if args["target"] then
1526 event["target"] = {args["target"]}
1527 else
1528 event["target"] = nil
1529 end
1530 end
1531 -- Set up the message string to go to Command_Class:Dispatch
1532 local msg = action
1533 local index, value
1534 for index, value in pairs(args) do
1535 if index~= "on" and index~="target" then
1536 if type(value) ~= "table" then
1537 if type(value) == "string" then value="'"..value.."'" end
1538 msg = msg .. " " .. index .. "=" .. value
1539 else
1540 msg = msg .. " " .. index .. "=" .. "["
1541 local index2, value2
1542 for index2, value2 in ipairs(value) do
1543 if type(value2) == "string" then value2="'"..value2.."'" end
1544 msg = msg .. " " .. value2
1545 end
1546 msg = msg .. " ]"
1547 end
1548 end
1549 end
1550 -- Copy out the target text for the list events command.
1551 event["command"]=msg
1552 local targettext = "Target="
1553 if args["target"] == nil then
1554 targettext = targettext .. "No target"
1555 elseif type(args["target"]) == "string" then
1556 targettext = targettext .. "'" .. args["target"] .. "'"
1557 elseif type(args["target"]) == "table" then
1558 local index2, value2
1559 targettext=targettext .. "[ "
1560 for index2, value2 in ipairs(args["target"]) do
1561 targettext = targettext .. " " .. value2
1562 end
1563 targettext = targettext .. " ]"
1564 else
1565 targettext = targettext .. args["target"]
1566 end
1567 event["targettext"]=targettext
1568  
1569 if FBEvents.n == nil then FBEvents.n = 0 end
1570 FBEvents.n = FBEvents.n + 1
1571 FBEvents[FBEvents.n] = util:TableCopy(event)
1572 FB_Report("On " .. FBEvents[FBEvents.n]["on"] .. " " .. FBEvents[FBEvents.n]["targettext"] .. " : " .. FBEvents[FBEvents.n]["command"])
1573 FBSavedProfile[FBProfileName].Events = util:TableCopy(FBEvents)
1574 FB_CreateQuickDispatch()
1575 return true
1576 end
1577  
1578 function FB_CreateQuickDispatch()
1579 -- Creates a quick dispatch table from the linear event table
1580  
1581 local index, event
1582 FBQuickEventDispatch = {}
1583 for index, event in pairs(FBEventToggleInfo) do
1584 event["lowlist"] = {}
1585 if FBToggles["autoperf"] then
1586 FBEventToggles[index] = "off"
1587 end
1588 end
1589 for index, event in ipairs(FBEvents) do
1590 local args = FBcmd:GetParameters(event["command"])
1591 local quickevent = {}
1592 local eventname = string.lower(event["on"])
1593 local command
1594 _,_,command = string.find(event["command"],"(%w+)")
1595 if FBQuickEventDispatch[eventname] == nil then
1596 FBQuickEventDispatch[eventname] = {}
1597 end
1598 if FBToggles["autoperf"] and string.lower(eventname) ~= "profileloaded" and FBEventGroups[eventname] then
1599 FBEventToggles[FBEventGroups[eventname]] = "low"
1600 end
1601 if event["target"] then
1602 quickevent["target"] = util:TableCopy(event["target"])
1603 local index, target
1604 for index, target in ipairs(quickevent["target"]) do
1605 if FBEventGroups[eventname] then
1606 FBEventToggleInfo[FBEventGroups[eventname]]["lowlist"][target] = true
1607 end
1608 end
1609 end
1610 quickevent["command"] = command
1611 quickevent["args"] = util:TableCopy(args)
1612 table.insert(FBQuickEventDispatch[eventname], quickevent)
1613 end
1614 end
1615  
1616 function FB_MimicPetButtons()
1617 -- Have button duplicate appearance of petbutton
1618 if not FBProfileLoaded then return end
1619 for i in pairs(FBPetActions) do
1620 local button = FB_GetWidgets(i)
1621 local id = button:GetID()
1622  
1623 if FBSavedProfile[FBProfileName].FlexActions[id] and
1624 FBSavedProfile[FBProfileName].FlexActions[id]["action"] == "pet" then
1625  
1626 local petbuttonID = FBSavedProfile[FBProfileName].FlexActions[id]["id"]
1627 local name, subtext, texture, isToken,
1628 isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(petbuttonID)
1629 local buttonnum = FB_GetButtonNum(button)
1630  
1631 if not name or name == "" then name = "Empty Pet Button" end
1632  
1633 if isToken then
1634 FBSavedProfile[FBProfileName].FlexActions[id]["texture"] = getglobal( texture )
1635 FBSavedProfile[FBProfileName].FlexActions[id]["name"] = TEXT(getglobal( name ))
1636 else
1637 FBSavedProfile[FBProfileName].FlexActions[id]["texture"] = texture
1638 FBSavedProfile[FBProfileName].FlexActions[id]["name"] = name
1639 end
1640  
1641 if subtext then
1642 FBSavedProfile[FBProfileName].FlexActions[id]["name"] =
1643 FBSavedProfile[FBProfileName].FlexActions[id]["name"] .. "\n" .. subtext
1644 end
1645 if autoCastAllowed then
1646 getglobal(button:GetName() .. "AutoCastable"):Show()
1647 else
1648 getglobal(button:GetName() .. "AutoCastable"):Hide()
1649 end
1650  
1651 if autoCastEnabled then
1652 getglobal(button:GetName() .. "AutoCast"):Show()
1653 else
1654 getglobal(button:GetName() .. "AutoCast"):Hide()
1655 end
1656  
1657 if isActive then
1658 button:SetChecked(1)
1659 FBState[i]["checked"] = true
1660 else
1661 button:SetChecked(0)
1662 FBState[i]["checked"] = nil
1663 end
1664  
1665 if GetPetActionsUsable() then
1666 SetDesaturation(getglobal(button:GetName() .. "Icon"),nil)
1667 else
1668 SetDesaturation(getglobal(button:GetName() .. "Icon"),1)
1669 end
1670 end
1671 FlexBarButton_Update(button)
1672 FlexBarButton_UpdateCooldown(button)
1673 end
1674 end
1675  
1676 function FB_GeneratePetIDList()
1677 -- generate a table to speed pet button processing
1678 for i = 1, 120 do
1679 local button = FB_GetWidgets(i)
1680 local id = button:GetID()
1681 if FBSavedProfile[FBProfileName].FlexActions[id] and FBSavedProfile[FBProfileName].FlexActions[id]["action"] == "pet" then
1682 FBPetActions[i] = true
1683 else
1684 FBPetActions[i] = nil
1685 end
1686 end
1687 end
1688  
1689 function FB_ResetPetItems(button)
1690 if not (FBSavedProfile[FBProfileName].FlexActions[id] and
1691 FBSavedProfile[FBProfileName].FlexActions[id]["action"] == "pet") then
1692  
1693 local buttonnum = FB_GetButtonNum(button)
1694  
1695 getglobal(button:GetName() .. "AutoCastable"):Hide()
1696 getglobal(button:GetName() .. "AutoCast"):Hide()
1697 SetDesaturation(getglobal(button:GetName() .. "Icon"),nil)
1698 FBState[buttonnum]["checked"] = nil
1699  
1700 FlexBarButton_Update(button)
1701 FlexBarButton_UpdateCooldown(button)
1702 FlexBarButton_UpdateState(button)
1703  
1704 FBPetActions[buttonnum] = nil
1705 end
1706 end
1707  
1708 local workinglist = {}
1709 workinglist.n = 0
1710 function FB_GetBuffs(target)
1711 -- return a list of the buffs currently on a target
1712 local index
1713 for index = 1, workinglist.n do
1714 table.remove(workinglist,1)
1715 end
1716 local count = 1
1717 FB_MoneyToggle();
1718 FlexBarTooltip:SetOwner(UIParent, "ANCHOR_NONE");
1719 while UnitBuff(target,count) do
1720 FlexBarTooltip:SetUnitBuff(target,count)
1721 local buffname = string.lower(FlexBarTooltipTextLeft1:GetText())
1722 table.insert(workinglist,buffname)
1723 count = count+1
1724 end
1725 FB_MoneyToggle();
1726 workinglist.n = count
1727 return workinglist
1728 end
1729  
1730 local typelist = {}
1731 function FB_GetDebuffs(target)
1732 -- return a list of the DeBuffs currently on a target, and a list of the types and their count
1733 local index
1734 for index = 1, workinglist.n do
1735 table.remove(workinglist,1)
1736 end
1737 for index in pairs(typelist) do
1738 typelist[index] = nil
1739 end
1740 local count = 1
1741 FB_MoneyToggle();
1742 FlexBarTooltip:SetOwner(UIParent, "ANCHOR_NONE");
1743 while UnitDebuff(target,count) do
1744 FlexBarTooltip:SetUnitDebuff(target,count)
1745 local buffname = string.lower(FlexBarTooltipTextLeft1:GetText())
1746 local debufftype = FlexBarTooltipTextRight1:GetText()
1747 if debufftype then debufftype = string.lower(debufftype) end
1748 table.insert(workinglist,buffname)
1749 if debufftype and FlexBarTooltipTextRight1:IsVisible() then
1750 if typelist[debufftype] then
1751 typelist[debufftype] = typelist[debufftype] + 1
1752 else
1753 typelist[debufftype] = 1
1754 end
1755 end
1756 count = count+1
1757 end
1758 FB_MoneyToggle();
1759 workinglist.n = count
1760 return workinglist,typelist
1761 end
1762  
1763 -- Keep track of the buffs/debuffs/debufftypes gained/lost for the player
1764 -- Need to raise them after all the information has been updated so if= works correctly
1765  
1766 local playerbuffschanged = {}
1767 playerbuffschanged["gainbuff"] = {}
1768 playerbuffschanged["losebuff"] = {}
1769 playerbuffschanged["gaindebuff"] = {}
1770 playerbuffschanged["losedebuff"] = {}
1771 playerbuffschanged["gaindebufftype"] = {}
1772 playerbuffschanged["losedebufftype"] = {}
1773 local unitbuffschanged = {}
1774 unitbuffschanged["gainbuff"] = {}
1775 unitbuffschanged["losebuff"] = {}
1776 unitbuffschanged["gaindebuff"] = {}
1777 unitbuffschanged["losedebuff"] = {}
1778 unitbuffschanged["gaindebufftype"] = {}
1779 unitbuffschanged["losedebufftype"] = {}
1780  
1781 function FB_CheckAllBuffs(unit)
1782 -- Scan for new/dropped buffs, debuffs and debuff types on unit
1783 if not FBProfileLoaded then return end
1784 if (not UnitName(unit)) then return end
1785  
1786 if FBEventToggles["buffcheck"] == "off" then return end
1787 if FBEventToggles["buffcheck"] == "low" and not FBEventToggleInfo["buffcheck"]["lowlist"][unit] then return end
1788  
1789 if(FB_DebugFlag == 4) then
1790 FB_ReportToUser("<< FB_CheckAllBuffs: Checking Buffs for "..unit.." >>");
1791 end
1792  
1793 local newbuffs = FB_GetBuffs(unit)
1794 local buffschanged = false
1795 local index,value
1796 for index,value in pairs(playerbuffschanged) do
1797 while value[1] do
1798 table.remove(value,1)
1799 end
1800 end
1801 for index,value in pairs(unitbuffschanged) do
1802 while value[1] do
1803 table.remove(value,1)
1804 end
1805 end
1806 if not FBLastBuffs["buffs"][unit] then
1807 FBLastBuffs["buffs"][unit] = {}
1808 end
1809 if not FBLastBuffs["debuffs"][unit] then
1810 FBLastBuffs["debuffs"][unit] = {}
1811 end
1812 if not FBLastBuffs["debufftypes"][unit] then
1813 FBLastBuffs["debufftypes"][unit] = {}
1814 end
1815 local index, value
1816 for index, value in ipairs(newbuffs) do
1817 if not FBLastBuffs["buffs"][unit][string.lower(value)] then
1818 -- gained a buff
1819 FBLastBuffs["buffs"][unit][string.lower(value)] = true
1820 FBBuffs["buffs"]["'"..value.."'"] = true
1821 if unit == "player" then
1822 table.insert(playerbuffschanged["gainbuff"],value)
1823 else
1824 buffschanged = true
1825 table.insert(unitbuffschanged["gainbuff"],value)
1826 end
1827 end
1828 end
1829 for index,value in pairs(FBLastBuffs["buffs"][unit]) do
1830 if not FB_InTable(index,newbuffs) then
1831 -- lost a buff
1832 FBLastBuffs["buffs"][unit][string.lower(index)] = nil
1833 if unit == "player" then
1834 table.insert(playerbuffschanged["losebuff"],index)
1835 else
1836 buffschanged = true
1837 table.insert(unitbuffschanged["losebuff"],index)
1838 end
1839 end
1840 end
1841  
1842 local debuffschanged = false
1843 local newdebuffs, newafflictions = FB_GetDebuffs(unit)
1844 if not FBLastBuffs["debuffs"][unit] then
1845 FBLastBuffs["debuffs"][unit] = {}
1846 end
1847 local index, value
1848 for index, value in ipairs(newdebuffs) do
1849 if not FBLastBuffs["debuffs"][unit][value] then
1850 -- gained a debuff
1851 FBLastBuffs["debuffs"][unit][string.lower(value)] = true
1852 FBBuffs["debuffs"]["'"..value.."'"] = true
1853 if unit == "player" then
1854 table.insert(playerbuffschanged["gaindebuff"],value)
1855 else
1856 debuffschanged = true
1857 table.insert(unitbuffschanged["gaindebuff"],value)
1858 end
1859 end
1860 end
1861 for index,value in pairs(FBLastBuffs["debuffs"][unit]) do
1862 if not FB_InTable(index,newdebuffs) then
1863 -- lost a buff
1864 FBLastBuffs["debuffs"][unit][string.lower(index)] = nil
1865 if unit == "player" then
1866 table.insert(playerbuffschanged["losedebuff"],index)
1867 else
1868 debuffschanged = true
1869 table.insert(unitbuffschanged["losedebuff"],index)
1870 end
1871 end
1872 end
1873  
1874 local afflictionschanged = false
1875 for index, value in pairs(newafflictions) do
1876 if not FBLastBuffs["debufftypes"][unit][string.lower(index)] or
1877 value > FBLastBuffs["debufftypes"][unit][string.lower(index)] then
1878 -- gained a new type of debuff
1879 FBLastBuffs["debufftypes"][unit][string.lower(index)] = value
1880 FBBuffs["debufftypes"]["'"..index.."'"] = true
1881 if unit == "player" then
1882 table.insert(playerbuffschanged["gaindebufftype"],index)
1883 else
1884 afflictionschanged = true
1885 table.insert(unitbuffschanged["gaindebufftype"],index)
1886 end
1887 end
1888 end
1889 for index,value in pairs(FBLastBuffs["debufftypes"][unit]) do
1890 if not newafflictions[string.lower(index)] or
1891 value > newafflictions[string.lower(index)] then
1892 -- lost an debuff type
1893 FBLastBuffs["debufftypes"][unit][string.lower(index)] = newafflictions[string.lower(index)]
1894 if unit == "player" then
1895 table.insert(playerbuffschanged["losedebufftype"],index)
1896 else
1897 afflictionschanged = true
1898 table.insert(unitbuffschanged["losedebufftype"],index)
1899 end
1900 end
1901 end
1902  
1903 for index,value in pairs(playerbuffschanged) do
1904 local i,v
1905 for i,v in ipairs(value) do
1906 FB_RaiseEvent(index,v)
1907 end
1908 end
1909  
1910 if buffschanged == true then
1911 FB_RaiseEvent("UnitBuff", unit)
1912 end
1913 if debuffschanged == true then
1914 FB_RaiseEvent("UnitDebuff",unit)
1915 end
1916 if afflictionschanged == true then
1917 FB_RaiseEvent("UnitDebuffType",unit)
1918 end
1919  
1920 for index,value in pairs(unitbuffschanged) do
1921 local i,v
1922 for i,v in ipairs(value) do
1923 FB_RaiseEvent(unit .. index,v)
1924 end
1925 end
1926 end
1927 -- Apply saved states (From FB.State) to the buttons.
1928 -- Removed group checks - if the user wants an entire
1929 -- group to change, they need to explicitly say so.
1930  
1931 function FB_ApplyHidden(buttonnum)
1932 local button, frame = FB_GetWidgets(buttonnum)
1933 -- Apply hidden state
1934 if FBState[buttonnum]["hidden"] then
1935 frame:Hide()
1936 else
1937 frame:Show()
1938 end
1939 end
1940  
1941 function FB_ApplyAlpha(buttonnum)
1942 local button, frame = FB_GetWidgets(buttonnum)
1943 -- Apply alpha
1944 if FBState[buttonnum]["alpha"] then
1945 button:SetAlpha(FBState[buttonnum]["alpha"])
1946 end
1947 end
1948  
1949 function FB_ApplyScale(buttonnum)
1950 local button, frame = FB_GetWidgets(buttonnum)
1951 -- Apply scale
1952 if FBState[buttonnum]["scale"] then
1953 button:SetScale(FBState[buttonnum]["scale"])
1954 else
1955 button:SetScale(1)
1956 end
1957 end
1958  
1959 function FB_ApplyLocked(buttonnum)
1960 local button, frame = FB_GetWidgets(buttonnum)
1961 -- Determine whether the button should be locked or not and apply
1962 -- Only the anchor of a group may be locked/unlocked.
1963 if FBState[buttonnum]["group"] and
1964 buttonnum ~= FBState[buttonnum]["group"] then
1965 return
1966 end;
1967  
1968 if FBState[buttonnum]["locked"] then
1969 FB_LockButton(buttonnum)
1970 else
1971 FB_UnlockButton(buttonnum)
1972 end
1973 end
1974  
1975 function FB_ApplyRemap(buttonnum)
1976 local button, frame = FB_GetWidgets(buttonnum)
1977 -- Apply remap
1978 if FBState[buttonnum]["remap"] then
1979 button:SetID(FBState[buttonnum]["remap"])
1980 FlexBarButton_Update(button)
1981 FlexBarButton_UpdateState(button)
1982 else
1983 button:SetID(FBState[buttonnum]["oldid"])
1984 FlexBarButton_Update(button)
1985 FlexBarButton_UpdateState(button)
1986 end
1987  
1988 end
1989  
1990 function FB_ApplyGrid(buttonnum)
1991 local button, frame = FB_GetWidgets(buttonnum)
1992 -- Apply grid
1993 if FBState[buttonnum]["hidegrid"] then
1994 button.showgrid=0
1995 frame:DisableDrawLayer()
1996 else
1997 button.showgrid=1
1998 button:Show()
1999 frame:EnableDrawLayer()
2000 end
2001 FlexBarButton_Update(button)
2002 FlexBarButton_UpdateState(button)
2003 end
2004  
2005 function FB_ApplyTextPosition(buttonnum)
2006 local button, frame = FB_GetWidgets(buttonnum)
2007 local buttonname = button:GetName()
2008 local text = getglobal(buttonname.."HotKey")
2009 local text2 = getglobal(buttonname.."Text2")
2010 local text3 = getglobal(buttonname.."Text3")
2011  
2012 local textpos = FBState[buttonnum]["justifytext"]
2013 local text2pos = FBState[buttonnum]["justifytext2"]
2014 local text3pos = FBState[buttonnum]["justifytext3"]
2015  
2016 if textpos == nil then textpos = "TOPRIGHT" end
2017 text:SetJustifyH("CENTER")
2018 local pos = string.upper(textpos)
2019 if string.find(pos,"LEFT") then
2020 text:SetJustifyH("LEFT")
2021 end
2022 if string.find(pos,"RIGHT") then
2023 text:SetJustifyH("RIGHT")
2024 end
2025 text:ClearAllPoints()
2026 text:SetPoint(pos,buttonname,pos,0,0)
2027  
2028 if text2pos == nil then text2pos = "BOTTOMLEFT" end
2029 text2:SetJustifyH("CENTER")
2030 local pos = string.upper(text2pos)
2031 if string.find(pos,"LEFT") then
2032 text2:SetJustifyH("LEFT")
2033 end
2034 if string.find(pos,"RIGHT") then
2035 text2:SetJustifyH("RIGHT")
2036 end
2037 text2:ClearAllPoints()
2038 text2:SetPoint(pos,buttonname,pos,0,0)
2039  
2040 if text3pos == nil then text3pos = "CENTER" end
2041 text3:SetJustifyH("CENTER")
2042 local pos = string.upper(text3pos)
2043 if string.find(pos,"LEFT") then
2044 text3:SetJustifyH("LEFT")
2045 end
2046 if string.find(pos,"RIGHT") then
2047 text3:SetJustifyH("RIGHT")
2048 end
2049 text3:ClearAllPoints()
2050 text3:SetPoint(pos,buttonname,pos,0,0)
2051 FB_SaveState(buttonnum)
2052 end
2053  
2054 -- Toggle Preserve for GameTooltip_ClearMoney functionality
2055 function FB_MoneyToggle()
2056 if( Save_Original_GameTooltip_ClearMoney ) then
2057 GameTooltip_ClearMoney = Save_Original_GameTooltip_ClearMoney;
2058 Save_Original_GameTooltip_ClearMoney = nil;
2059 FlexBarTooltip:SetOwner(UIParent, "ANCHOR_NONE");
2060 else
2061 Save_Original_GameTooltip_ClearMoney = GameTooltip_ClearMoney;
2062 GameTooltip_ClearMoney = FB_GameTooltip_ClearMoney;
2063 FlexBarTooltip:SetOwner(UIParent, "ANCHOR_NONE");
2064 end
2065 end
2066  
2067 function FB_GameTooltip_ClearMoney()
2068 -- Intentionally empty; don't clear money while we use hidden tooltips
2069 end
2070  
2071 function FB_StoreGroupOffsetForMove(group)
2072 -- Stores group button offset values for non-anchor buttons prior to a group anchor move taking
2073 -- place. This is required in order to ensure all group button locations are properly updated
2074 -- at the time the group anchor is moved. For programmatical moves it seems that the WoW Update
2075 -- time for button locations not attached to UIParent in memory varies.
2076 local index
2077 local members = FB_GetGroupMembers(group)
2078  
2079 if members.n < 1 then return end
2080  
2081 if(FB_DebugFlag == 2) then
2082 FB_ReportToUser("<< FB_StoreGroupOffsetForMove: Group #"..group.." Store Offsets >>");
2083 end
2084  
2085 local anchor = FBState[members[1]]["group"]
2086 local aX = FBState[anchor]["xcoord"]
2087 local aY = FBState[anchor]["ycoord"]
2088  
2089 for index = 1, members.n do
2090 if (members[index] ~= anchor) then
2091 local oX = FBState[members[index]]["xcoord"] - aX
2092 local oY = FBState[members[index]]["ycoord"] - aY
2093  
2094 FBGroupMoveOffset[members[index]]["xcoord"] = oX
2095 FBGroupMoveOffset[members[index]]["ycoord"] = oY
2096  
2097 if(FB_DebugFlag == 2) then
2098 FB_ReportToUser("<< StoreOffset B# "..members[index].." (oX="..oX..", oY="..oY.."), (aX="..aX..", aY="..aY..") >>");
2099 --FB_PrintButtonSnapshot(members[index])
2100 end
2101 end
2102 end
2103 end
2104  
2105 function FB_RestoreGroupOffsetAfterMove(group)
2106 -- Resets stored values for non-anchor buttons after a group move command has been executed.
2107 -- This way we do not have to wait some indeterminate amount of time to get coordinates for the group.
2108 local index
2109 local members = FB_GetGroupMembers(group)
2110  
2111 if members.n < 1 then return end
2112  
2113 if(FB_DebugFlag == 2) then
2114 FB_ReportToUser("<< FB_RestoreGroupOffsetAfterMove: Group #"..group.." Restore Offsets >>");
2115 end
2116  
2117 local anchor = FBState[members[1]]["group"]
2118 local aX = FBState[anchor]["xcoord"]
2119 local aY = FBState[anchor]["ycoord"]
2120  
2121 for index = 1, members.n do
2122 if (members[index] ~= anchor) then
2123 local oX = FBGroupMoveOffset[members[index]]["xcoord"]
2124 local oY = FBGroupMoveOffset[members[index]]["ycoord"]
2125  
2126 FBState[members[index]]["xcoord"] = aX + oX
2127 FBState[members[index]]["ycoord"] = aY + oY
2128 FBSavedProfile[FBProfileName][members[index]].State["xcoord"] = aX + oX
2129 FBSavedProfile[FBProfileName][members[index]].State["ycoord"] = aY + oY
2130  
2131 FB_UpdateSmartPet(members[index])
2132  
2133 if(FB_DebugFlag == 2) then
2134 FB_ReportToUser("<< RestOffset B# "..members[index].." (oX="..oX..", oY="..oY.."), (aX="..aX..", aY="..aY..") >>");
2135 --FB_PrintButtonSnapshot(members[index])
2136 end
2137 end
2138 end
2139 end
2140  
2141 function FB_SetDebugLevel(val)
2142 util:Print("<< FB_SetDebugLevel: Debug Level changed to: "..val.." >>", "red");
2143 FB_DebugFlag = val
2144 end
2145  
2146 function FB_ShowButtonInfo()
2147 if(FB_DebugFlag == 1) then
2148 FB_ReportToUser("<< FB_ShowButtonInfo: Entry >>");
2149 end
2150  
2151 local index
2152  
2153 for index = 1,FBNumButtons do
2154 FB_ShowSingleButtonInfo(index)
2155 end
2156  
2157 FBButtonInfoShown = true
2158 end
2159  
2160 function FB_ShowSingleButtonInfo(btn)
2161 if(FB_DebugFlag == 1) then
2162 FB_ReportToUser("<< FB_ShowButtonInfo: Entry >>");
2163 end
2164  
2165 local grp, map
2166 local text1, text2, text3
2167  
2168 FBButtonTextSave[btn]["text1"] = FBState[btn]["hotkeytext"]
2169 FBButtonTextSave[btn]["text2"] = FBState[btn]["text2"]
2170 FBButtonTextSave[btn]["text3"] = FBState[btn]["text3"]
2171  
2172 text1 = getglobal("FlexBarButton"..btn.."HotKey")
2173 text2 = getglobal("FlexBarButton"..btn.."Text2")
2174 text3 = getglobal("FlexBarButton"..btn.."Text3")
2175  
2176 text1:SetText("b"..btn)
2177  
2178 if(FBState[btn]["group"]) then
2179 grp = "g"..FBState[btn]["group"]
2180 else
2181 grp = "none"
2182 end
2183  
2184 text2:SetText(grp)
2185  
2186 if(FBState[btn]["remap"]) then
2187 map = "r"..FBState[btn]["remap"]
2188 else
2189 map = "none"
2190 end
2191  
2192 text3:SetText(map)
2193  
2194 end
2195 function FB_RestoreButtonText()
2196 if(FB_DebugFlag == 1) then
2197 FB_ReportToUser("<< FB_RestoreButtonText Entry >>");
2198 end
2199  
2200 local index, button
2201 local text1, text2, text3
2202  
2203 for index = 1,FBNumButtons do
2204 text1 = getglobal("FlexBarButton"..index.."HotKey")
2205 text2 = getglobal("FlexBarButton"..index.."Text2")
2206 text3 = getglobal("FlexBarButton"..index.."Text3")
2207  
2208 text1:SetText(FBButtonTextSave[index]["text1"])
2209 text2:SetText(FBButtonTextSave[index]["text2"])
2210 text3:SetText(FBButtonTextSave[index]["text3"])
2211  
2212 FB_TextSub(index)
2213 FB_ApplyTextPosition(index)
2214 button = FB_GetWidgets(index)
2215 FlexBarButton_UpdateHotkeys(button)
2216 end
2217  
2218 FBButtonInfoShown = false
2219 end
2220  
2221 function FB_UpdateSmartPet(btn)
2222 if IsAddOnLoaded("SmartPet") and
2223 FBSavedProfile[FBProfileName].FlexActions[btn] and
2224 FBSavedProfile[FBProfileName].FlexActions[btn].action == "pet" then
2225 local petid = FBSavedProfile[FBProfileName].FlexActions[btn].id
2226 local smartie = getglobal("SmartPetActionButton"..petid)
2227 local flexie = getglobal("FlexBarButton"..btn)
2228 if not smartie then
2229 FB_ReportToUser("SmartPet action button "..petid.." not found")
2230 else
2231 if smartie:GetParent() ~= flexie then
2232 smartie:SetParent(flexie)
2233 smartie:ClearAllPoints()
2234 smartie:SetPoint("BOTTOM", flexie, "TOP", 0, 0)
2235 end
2236 end
2237 end
2238 end