View Single Post
02-13-16, 02:51 PM   #29
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,326
Since MunkDev wants to address the button layout code and this is moving into the realm of protected frames, I'll offer a rewrite of the entire code and explain the changes along the way.

Here's what I have so far:
Lua Code:
  1. --------------------------
  2. --[[    Layout Settings ]]
  3. --------------------------
  4. local ButtonSize=32;--  Size to make buttons
  5.  
  6. local Padding=12;-- Buttons are placed this far from the edge of the container frame
  7. local Backdrop={
  8.     bgFile="Interface\\DialogFrame\\UI-DialogBox-Background",
  9.     edgeFile="Interface\\DialogFrame\\UI-DialogBox-Border",
  10.     tile=true,tileSize=32,edgeSize=32,
  11.     insets={left=11,right=12,top=12,bottom=12}
  12. };
  13.  
  14. local ButtonData={--    Note: Buttons will be created top-down, then left-right
  15. --[[    Data Format (All arguments are optional)
  16.         Icon:       Icon file
  17.         Text:       Button text
  18.         Tooltip:    Tooltip text
  19.         Message:    Message to send     Format: {<Message>, <Channel>, ...} Can contain multiple messages as pairs of message and channel strings
  20.         Emote:      Perform emote       Format: {<EmoteToken>, <TargetUnit>}    -or-    <EmoteToken>
  21.         Attributes: List of attributes to apply (keys are attributes, values are values)
  22. --]]
  23.     {-- Container 1
  24.         {-- Column 1
  25.             {
  26.                 Icon="Interface\\Icons\\Ability_rogue_sprint";
  27.                 Tooltip="Amphitheater of Annihilation(AoA)";
  28.                 Message={
  29.                     "Amphitheater of Annihilation(AoA) - EVENT:STADIUM RACING - Block the entrance!","INSTANCE_CHAT";
  30.                     "AoA AoA GO NOW! - Block the entrance!","RAID_WARNING";
  31.                 };
  32.                 Emote="FOLLOW";
  33.             };
  34.             {
  35.                 Icon="Interface\\Icons\\spell_fire_fire";
  36.                 Tooltip="Brute's Rise(BR)";
  37.                 Message={
  38.                     "Brute's Rise(BR) - EVENT:OGRE FIRES - Block the stairs!","INSTANCE_CHAT";
  39.                     "BR BR GO NOW! MOVE IT! Block the stairs!","RAID_WARNING";
  40.                 };
  41.                 Emote="FOLLOW";
  42.             };
  43.             {
  44.                 Icon="Interface\\Icons\\achievement_boss_furyfurnace";
  45.                 Tooltip="Ring of Conquest(RoC)";
  46.                 Message={
  47.                     "Ring of Conquest GO RoC - Let's get some fragments, scrolls, wands and class books","INSTANCE_CHAT";
  48.                     "Ring of Conquest GO RoC","RAID_WARNING";
  49.                 };
  50.                 Emote="FOLLOW";
  51.             };
  52.             {
  53.                 Icon="Interface\\Icons\\Trade_archaeology_apexisstatue";
  54.                 Tooltip="Ashran Excavation(Mines)";
  55.                 Message={
  56.                     "Ashran Excavation(Mines) - EVENT:APEXIS MARKS - Secure the center!","INSTANCE_CHAT";
  57.                     "MINES! GO NOW! MOVE IT! - Secure the center!","RAID_WARNING";
  58.                 };
  59.                 Emote="FOLLOW";
  60.             };
  61.             {
  62.                 Icon="Interface\\Icons\\achievement_reputation_ogre";
  63.                 Tooltip="Seat of Kor'lok";
  64.                 Message={
  65.                     "Seat of Kor'lok - Kor'lok - Kill the ogre!","INSTANCE_CHAT";
  66.                     "Kor'lok! - Kill the ogre!","RAID_WARNING";
  67.                 };
  68.                 Emote="FOLLOW";
  69.             };
  70.             {
  71.                 Icon="Interface\\Icons\\Spell_lifegivingspeed";
  72.                 Tooltip="Molten Quarry(MQ)";
  73.                 Message={
  74.                     "Molten Quarry(MQ) - EVENT:Empowered Ore - Block the entrance!","INSTANCE_CHAT";
  75.                     "MQ MQ GO NOW! MOVE IT! - Block the entrance!","RAID_WARNING";
  76.                 };
  77.                 Emote="FOLLOW";
  78.             };
  79.             {
  80.                 Icon="Interface\\Icons\\Achievement_halloween_ghost_01";
  81.                 Tooltip="Ashmaul Burial Grounds(ABG)";
  82.                 Message={
  83.                     "Ashmaul Burial Grounds(ABG) - EVENT:RISEN SPIRITS - Clear the center and block the entrance!","INSTANCE_CHAT";
  84.                     "ABG ABG GO NOW! MOVE IT! - Clear the center and block the entrance!","RAID_WARNING";
  85.                 };
  86.                 Emote="FOLLOW";
  87.             };
  88.         };
  89.         {-- Column 2
  90.             {
  91.                 Icon="Interface\\Icons\\achievement_pvp_a_h";
  92.                 Tooltip="Warspear Keep";
  93.                 Message={
  94.                     "Warspear Keep!","INSTANCE_CHAT";
  95.                     "Warspear Keep!","RAID_WARNING";
  96.                 };
  97.                 Emote="FOLLOW";
  98.             };
  99.             {
  100.                 Icon="Interface\\Icons\\achievement_garrison_tier02_horde";
  101.                 Tooltip="Emberfall Tower";
  102.                 Message={
  103.                     "Emberfall Tower! Go Go Go! Stack at the flag","INSTANCE_CHAT";
  104.                     "Emberfall Tower!","RAID_WARNING";
  105.                 };
  106.                 Emote="FOLLOW";
  107.             };
  108.             {
  109.                 Icon="Interface\\Icons\\achievement_garrison_tier01_horde";
  110.                 Tooltip="Volrath's Advance";
  111.                 Message={
  112.                     "Volrath's Advance! Go Go Go! Stack at the flag","INSTANCE_CHAT";
  113.                     "Volrath's Advance! VA VA VA","RAID_WARNING";
  114.                 };
  115.                 Emote="FOLLOW";
  116.             };
  117.             {
  118.                 Icon="Interface\\Icons\\achievement_doublejeopardy";
  119.                 Tooltip="The Crossroads";
  120.                     "The Crossroads - Get to Crossroads! Stack at the flag","INSTANCE_CHAT";
  121.                     "The Crossroads - XR XR XR","RAID_WARNING";
  122.                 Message={
  123.                 };
  124.                 Emote="FOLLOW";
  125.             };
  126.             {
  127.                 Icon="Interface\\Icons\\achievement_garrison_tier01_alliance";
  128.                 Tooltip="Tremblade's Vanguard";
  129.                 Message={
  130.                     "Tremblade's Vanguard! Go Go Go! Stack at the flag","INSTANCE_CHAT";
  131.                     "Tremblade's Vanguard! TV TV TV","RAID_WARNING";
  132.                 };
  133.                 Emote="FOLLOW";
  134.             };
  135.             {
  136.                 Icon="Interface\\Icons\\achievement_garrison_tier02_alliance";
  137.                 Tooltip="Archmage Overwatch";
  138.                 Message={
  139.                     "Archmage Overwatch! Go Go Go! Stack at the flag","INSTANCE_CHAT";
  140.                     "Archmage Overwatch! AO AO AO","RAID_WARNING";
  141.                 };
  142.                 Emote="FOLLOW";
  143.             };
  144.             {
  145.                 Icon="Interface\\Icons\\achievement_pvp_h_a";
  146.                 Tooltip="Stormshield Stronghold";
  147.                 Message={
  148.                     "Stormshield Stronghold!","INSTANCE_CHAT";
  149.                     "Stormshield Stronghold!","RAID_WARNING";
  150.                 };
  151.                 Emote="FOLLOW";
  152.             };
  153.         };
  154.     };
  155.  
  156.     {-- Container 2
  157.         {-- Column 1
  158.             {
  159.                 Icon="Interface\\Icons\\Spell_holy_mindvision";
  160.                 Tooltip="Song flower";
  161.                 Message={
  162.                     "Song Flower - Increases all stats by 15%. This effect persists through death. Pick them up in The Dark Woods (the arakkoa area)","INSTANCE_CHAT";
  163.                     "Use Song Flower! 15% to all stats","RAID_WARNING";
  164.                     "You should also pick up Star Root Tuber in Root Den (the saberon area). It gives you are small heal and 40% damage reduction for 10 sec. when used. The Tuber is not as visible as the Song Flowers, but once you know what to look for, it's easy to find them.","INSTANCE_CHAT";
  165.                 };
  166.                 Emote="DRINK";
  167.             };
  168.             {
  169.                 Icon="Interface\\Icons\\Misc_arrowleft";
  170.                 Tooltip="Get out of the road";
  171.                 Message={
  172.                     "Get out of the main road - Stampede or Frost wyrm incoming - Move it!","INSTANCE_CHAT";
  173.                     "GET OUT OF THE ROAD! STAMPEDE OR FROST WYRM INCOMING!","RAID_WARNING";
  174.                 };
  175.                 Emote="DUCK";
  176.             };
  177.             {
  178.                 Icon="Interface\\Icons\\Spell_nature_bloodlust";
  179.                 Tooltip="Bloodlust";
  180.                 Message={
  181.                     "Time to fight! Pop Bloodlust/Time Warp/Heroism","INSTANCE_CHAT";
  182.                     "Pop Bloodlust - Time Warp - Heroism!!","RAID_WARNING";
  183.                 };
  184.                 Emote="FLEX";
  185.             };
  186.         };
  187.  
  188.         {-- Column 2
  189.             {
  190.                 Icon="Interface\\Icons\\misc_arrowlup";
  191.                 Tooltip="Push";
  192.                 Message={
  193.                     "PUSH PUSH! Give them nothing! But take from them EVERYTHING!","INSTANCE_CHAT";
  194.                     "PUSH PUSH PUSH!","RAID_WARNING";
  195.                 };
  196.                 Emote="CHARGE";
  197.             };
  198.             {
  199.                 Icon="Interface\\Icons\\ability_defend";
  200.                 Tooltip="Hold Position";
  201.                 Message={
  202.                     "Hold this position. Stay grouped. Form a wall and let any attackers break upon it. Protect the healers.","INSTANCE_CHAT";
  203.                     "HOLD THE POSITION - STAY GROUPED","RAID_WARNING";
  204.                 };
  205.                 Emote="ENCOURAGE";
  206.             };
  207.             {
  208.                 Icon="Interface\\Icons\\misc_arrowdown";
  209.                 Tooltip="Retreat";
  210.                 Message={
  211.                     "Time for a tactical retreat. Stay grouped. Disengage from combat quickly. Like Top Gear, we will leave stragglers behind","INSTANCE_CHAT";
  212.                     "MOVE BACK! STAY GROUPED!","RAID_WARNING";
  213.                 };
  214.                 Emote="FLEE";
  215.             };
  216.         };
  217.  
  218.         {-- Column 3
  219.             {
  220.                 Icon="Interface\\Icons\\Inv_enchant_formulasuperior_01";
  221.                 Tooltip="Scroll of Protection";
  222.                 Message={
  223.                     "One player use Scroll of Protection(SoP) now. If you see another player use one, don't use yours for 10-15 sec. SoP reduces damage taken by 60% for 15 seconds.","INSTANCE_CHAT";
  224.                     "Use Scroll of Protection!","RAID_WARNING";
  225.                 };
  226.                 Emote="INCOMING";
  227.             };
  228.             {
  229.                 Icon="Interface\\Icons\\achievement_bg_xkills_avgraveyard";
  230.                 Tooltip="Market Graveyard";
  231.                 Message={
  232.                     "Capture Market Graveyard. No more than 5 should disengage from combat to capture the graveyard, unless the raid is moving past it anyway or not engaged in combat.","INSTANCE_CHAT";
  233.                     "CAP THE GY!","RAID_WARNING";
  234.                 };
  235.                 Emote="GO";
  236.             };
  237.             {
  238.                 Icon="Interface\\TargetingFrame\\UI-RaidTargetingIcon_8";
  239.                 Tooltip="Place World Marker/Right-click to remove";
  240.                 Message={
  241.                     "{rt8} is used by a commander to mark the battlefront, gathering spots, defensive lines and on AA if it is dropped.","INSTANCE_CHAT";
  242.                     "{rt8} Get to {rt8}","RAID_WARNING";--  {rt8} is locale-independant form of {skull}
  243.                 };
  244.                 Attributes={
  245.                     type="macro";
  246.                     macrotext1=SLASH_WORLD_MARKER1.." 8";
  247.                     macrotext2=SLASH_CLEAR_WORLD_MARKER1.." 8";
  248.                 };
  249.             };
  250.         };
  251.     };
  252. };
  253.  
  254. ------------------------------------------------------------------
  255. --[[    Addon Code (Don't change anything below this line)  ]]
  256. ------------------------------------------------------------------
  257. --  Button Handlers
  258. local function Container_OnEvent(self)
  259.     if not (self.HasProtectedFrame and InCombatLockdown()) then--   Check if we have a protected button and can show/hide ourselves (Protected frames are protected in combat)
  260.         self:SetShown(GetZoneText()==GetMapNameByID(978))
  261.     end
  262. end
  263.  
  264. local function Button_OnEnter(self)
  265.     GameTooltip:SetOwner(self,"ANCHOR_TOP");
  266.     GameTooltip:AddLine(self.Tooltip,0,1,0.5);
  267.     GameTooltip:Show();
  268. end
  269. local function Button_OnLeave(self) if GameTooltip:IsOwned(self) then GameTooltip:Hide(); end end
  270. local function Button_OnDragStart(self) self:GetParent():StartMoving(); end
  271. local function Button_OnDragStop(self) self:GetParent():StopMovingOrSizing(); end
  272. local function Button_OnClick(self)
  273.     if self.Message then
  274.         for i=1,#self.Message,2 do
  275.             SendChatMessage(self.Message[i],self.Message[i+1]);
  276.         end
  277.     end
  278.     if self.Emote then
  279.         if type(self.Emote)=="table" then
  280.             local target; do--  Prototype variable
  281.                 local unit=self.Emote[2];
  282.                 if unit and UnitExists(unit) and UnitIsPlayer(unit) then
  283.                     local name,server=UnitName(unit);-- Unit name and server
  284.                     target=name..(server and "-"..server:gsub("%s","") or "");--    Format name to <name-server> if necessary
  285.                 end
  286.             end
  287.             DoEmote(self.Emote[1],target);
  288.         else
  289.             DoEmote(self.Emote);
  290.         end
  291.     end
  292. end
  293.  
  294. local OffsetX=0;
  295. for containerid,buttonlist in ipairs(ButtonData) do
  296. --  Container Frame
  297.     local container=CreateFrame("Frame","AshranCommander"..containerid,UIParent);
  298.     container:SetBackdrop(Backdrop);
  299.     container:Hide();-- Start hidden
  300.  
  301. --  Enable Dragging
  302.     container:EnableMouse(true);
  303.     container:SetMovable(true);
  304.     container:SetClampedToScreen(true);
  305.     container:RegisterForDrag("LeftButton");
  306.     container:SetScript("OnDragStart",container.StartMoving);
  307.     container:SetScript("OnDragStop",container.StopMovingOrSizing);
  308.  
  309. --  Event Handlers
  310.     container:RegisterEvent("PLAYER_ENTERING_WORLD");-- Load screen disapears
  311.     container:RegisterEvent("ZONE_CHANGED_NEW_AREA");-- Moved into new area
  312.     container:RegisterEvent("PLAYER_REGEN_ENABLED");--  Retry when exiting combat
  313.     container:SetScript("OnEvent",Container_OnEvent);
  314.  
  315. --  Button Factory
  316.     local numrows,buttonid=0,1;
  317.     for column,rowlist in ipairs(buttonlist) do
  318.         numrows=math.max(numrows,#rowlist);
  319.         for row,data in ipairs(rowlist) do
  320.             local btn=CreateFrame("Button","$parentButton"..buttonid,container,data.Attributes and "SecureActionButtonTemplate");
  321.             btn:SetPoint("TOPLEFT",(column-1)*ButtonSize+Padding,-(row-1)*ButtonSize-Padding);--    Yay, math!
  322.             btn:SetSize(ButtonSize,ButtonSize);
  323.  
  324. --          Extra flair
  325.             btn:SetPushedTexture("Interface\\Buttons\\UI-Quickslot-Depress");
  326.             btn:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square","ADD");
  327.  
  328. --          Pushed texture replaces normal texture
  329.             local icon=btn:CreateTexture(nil,"BACKGROUND");
  330.             icon:SetTexture(data.Icon or "Interface\\Icons\\INV_Misc_QuestionMark");
  331.             icon:SetAllPoints(btn);
  332.  
  333. --          Button Text
  334.             if data.Text then
  335.                 btn:SetNormalFontObject("GameFontNormalSmall");
  336.                 btn:SetHighlightFontObject("GameFontHighlightSmall");
  337.                 btn:SetDisabledFontObject("GameFontDisableSmall");
  338.                 btn:SetText(data.Text);
  339.             end
  340.  
  341. --          Register clicks and drag
  342.             btn:RegisterForClicks("AnyUp");--   By default, buttons only respond to LeftUp
  343.             btn:RegisterForDrag("LeftButton");
  344.             btn:HookScript("OnDragStart",Button_OnDragStart);
  345.             btn:HookScript("OnDragStop",Button_OnDragStop);
  346.  
  347. --          Attribute Setup
  348.             if data.Attributes then
  349.                 container.HasProtectedFrame=true;-- Lets the container frame know we have protected buttons now
  350.                 for key,val in pairs(data.Attributes) do btn:SetAttribute(key,val); end
  351.             end
  352.  
  353. --          Tooltip Setup
  354.             if data.Tooltip then
  355.                 btn.Tooltip=data.Tooltip;
  356.                 btn:HookScript("OnEnter",Button_OnEnter);
  357.                 btn:HookScript("OnLeave",Button_OnLeave);
  358.             end
  359.  
  360. --          Chat Handling
  361.             if data.Message or data.Emote then
  362.                 btn.Message=data.Message;
  363.                 btn.Emote=data.Emote;
  364.                 btn:HookScript("OnClick",Button_OnClick);
  365.             end
  366.         end
  367.     end
  368.  
  369. --  We get to apply the position and size now
  370.     local width=#buttonlist*ButtonSize+Padding*2;
  371.     container:SetPoint("TOPLEFT",256+OffsetX,-256);
  372.     container:SetSize(width,numrows*ButtonSize+Padding*2);--    More math, yay!
  373.     OffsetX=OffsetX+width;
  374. end

You'll notice a settings section at the top where you can tweak the UI. The button factory was moved from its dedicated function into a loop at the bottom. Container frame size is calculated using the data in the settings section. The container frame is also created as initially hidden. Since we're starting to deal with protected frames, the show/hide event code checks InCombatLockdown() and also listens to PLAYER_REGEN_ENABLED in order to retry once out of combat. Buttons are now directly anchored to the container frame with some mathematical magic instead of anchored to each other. Script handlers on the buttons are now using Frame:HookScript() in order to avoid taint and preserve scripts set by inherited templates.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 02-23-16 at 03:11 PM.
  Reply With Quote