kgPanels

Create panels for customizing your UI, sucessor to eePanels

Wiki and FAQ

Sample Scripts

OnClick now provides a pressed and released variable you can check for.

if pressed then
  -- do mouse down actions
elseif released then
  -- do mouse up actions
end

This means your script will get called twice when someone clicks the panel.

Here is a youtube link to a video Tutorial

Ive created an Example Texture Pack.

This example pack is just a template. If you want to use it as a storage spot for your art, look at the read me file for directions on usage.

You must login to post a comment. Don't have an account? Register to get one!

  • Avatar of ImpalerCore ImpalerCore Sep 28, 2009 at 15:50 UTC - 0 likes

    Hmm, for the cast bar stuff, a good place to start would be to look at quartz addon code. I'll give some background, and hopefully should be enough for you to pick up and get your panel working.

    The events you want to listen for have the prefix UNIT_SPELLCAST_?. To get acquainted with what events are being sent, I would create a kgpanel that listens to all of these events and prints a message in the chatframe. Then, observe the events by casting different spells and see what happens. You might need a buddy or go in a battleground to interrupt you to test the interrupt event.

    <OnLoad>
    self:RegisterEvent("UNIT_SPELLCAST_SENT")
    self:RegisterEvent("UNIT_SPELLCAST_START")
    self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
    self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
    self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
    self:RegisterEvent("UNIT_SPELLCAST_STOP")
    self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
    self:RegisterEvent("UNIT_SPELLCAST_FAILED")
    self:RegisterEvent("UNIT_SPELLCAST_DELAYED")
    self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
    
    <OnEvent>
    DEFAULT_CHAT_FRAME:AddMessage( event )
    

    This should print a little text of the events being fired if you register for them.

    There are three different categories of spells, instants, casting, and channeling.

    Instants - These are sent to the server via UNIT_SPELLCAST_SENT. The server will take your spell and either accept or reject it. You get either a UNIT_SPELLCAST_SUCCEEDED if the server accepted it, or a UNIT_SPELLCAST_FAILED if it didn't. An instant cast can fail if you try to use a spell that is currently on cooldown for instance.

    Casting - These are spells that have a specific cast time before they are sent to the server. They are sent to the server using UNIT_SPELLCAST_SENT and a UNIT_SPELLCAST_START. If everything goes well, you will send a UNIT_SPELLCAST_STOP at the end of your cast time, and the server will respond with either a UNIT_SPELLCAST_SUCCEEDED or UNIT_SPELLCAST_FAILED. However, if you get interrupted, you may receive a UNIT_SPELLCAST_INTERRUPTED if your spell was interrupted. If you get hit, your cast time will lengthen, these are updated via UNIT_SPELLCAST_DELAYED.

    Channeling - These are different from casting spells. Casting spells are like instants that have a required cast time. Once the cast time is done, the server responds to it like an instant. A channeling spell is something that works over time. Applying a bandage to yourself is probably the most accessible channeling spell. Each tick applies a health buff to your character. These have different events that are applied. The channeling spell starts with a UNIT_SPELLCAST_CHANNEL_START and end with a UNIT_SPELLCAST_CHANNEL_STOP. They can also be interrupted so you can receive a UNIT_SPELLCAST_INTERRUPTED.

    This is the basic background needed to build a kgpanel that does what you require. Now comes the tricky part, putting it together.

    Using the model from Quartz, they have two boolean flags that they keep track of called 'casting' and 'channeling' that are set to true or nil based on the events that fire. You can adapt this to an OnEvent handler and use those booleans to determine whether to show or hide the panel. The first step is to create the OnLoad script handler. This will declare the booleans, and register for all the appropriate events.

    <OnLoad>
    self:RegisterEvent("UNIT_SPELLCAST_SENT")
    self:RegisterEvent("UNIT_SPELLCAST_START")
    self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
    self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
    self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
    self:RegisterEvent("UNIT_SPELLCAST_STOP")
    self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
    self:RegisterEvent("UNIT_SPELLCAST_FAILED")
    self:RegisterEvent("UNIT_SPELLCAST_DELAYED")
    self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
    
    -- These I have not messed with, you most likely do not need them
    --self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE")
    --self:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE")
    
    -- The casting and channeling state variables
    self.casting = nil
    self.channeling = nil
    

    Now comes the OnEvent handler. This function will maintain the casting and channeling boolean flags to determine whether or not your are in the middle of casting or channeling a spell. One small modification is that I'm doing this for the player unit. Each event arguments are accessed via arg1, arg2, arg3, etc... for the parameters used by the event. From the WoWWiki, all of the arg1 represent the unit id of the spell being cast. For our purposes, this will be player, so we'll ignore any spells that are not cast by the player.

    <OnEvent>
    -- Only processing player driven events.
    if arg1 ~= 'player' then
        return
    end
    
    -- Debug code to print event.
    DEFAULT_CHAT_FRAME:AddMessage( event )
    

    Now we need to look at how to know when we're casting or channeling. Thankfully, quartz has handled most of the logic for us, so we can adapt it to our kgpanel. We just observe how they change these states when these events fire.

    if event == 'UNIT_SPELLCAST_SENT' then
    elseif event == 'UNIT_SPELLCAST_START' then
    elseif event == 'UNIT_SPELLCAST_CHANNEL_START' then
    elseif event == 'UNIT_SPELLCAST_STOP' then
    elseif event == 'UNIT_SPELLCAST_CHANNEL_STOP' then
    elseif event == 'UNIT_SPELLCAST_SUCCEEDED' then
    elseif event == 'UNIT_SPELLCAST_FAILED' then
    elseif event == 'UNIT_SPELLCAST_INTERRUPTED' then
    elseif event == 'UNIT_SPELLCAST_DELAYED' then
    elseif event == 'UNIT_SPELLCAST_CHANNEL_UPDATE' then
    end
    

    The UNIT_SPELLCAST_SENT event does not signal a casting spell or a channeling spell. It is sent everytime that you send a spell event to the server by clicking a spell icon or using a spell keybind.

    if event == 'UNIT_SPELLCAST_SENT' then
      -- Do nothing
    

    The UNIT_SPELLCAST_START event does signal that we are casting a spell. If you look at quartz code, the line 'self.casting = true' means that you are "casting" a spell. This is not the same as channeling, so it is set to nil.

    elseif event == 'UNIT_SPELLCAST_START' then
        self.casting = true
        self.channeling = nil
    

    For UNIT_SPELLCAST_CHANNEL_START, you should be able to get that it marks the start of a channeling spell, but not a casting spell.

    elseif event == 'UNIT_SPELLCAST_CHANNEL_START' then
        self.casting = nil
        self.channeling = true
    

    For UNIT_SPELLCAST_STOP, this signals that the casting spell has ended. The self.channeling isn't involved at this point.

    elseif event == 'UNIT_SPELLCAST_STOP' then
        self.casting = nil
    

    And the same for UNIT_SPELLCAST_CHANNEL_STOP.

    elseif event == 'UNIT_SPELLCAST_CHANNEL_STOP' then
        self.channeling = nil
    

    If the spell succeeded, it will be preceded by a UNIT_SPELLCAST_STOP or a UNIT_SPELLCAST_CHANNEL_STOP event, so there is no need to modify the boolean state variables.

    elseif event == 'UNIT_SPELLCAST_SUCCEEDED' then
    

    The spell can fail, which can trigger from you moving while casting the spell to end it before you finished. This means that both the casting and channeling spells are stopped.

    elseif event == 'UNIT_SPELLCAST_FAILED' then
        self.casting = nil
        self.channeling = nil
    

    In the same vein as a spell failing, an interrupted spell has the same result.

    elseif event == 'UNIT_SPELLCAST_INTERRUPTED' then
        self.casting = nil
        self.channeling = nil
    

    The UNIT_SPELLCAST_DELAYED and UNIT_SPELLCAST_CHANNEL_UPDATE have more to do when your are hit while casting, but it is not enough to stop the spell. You are still casting in this event, so no change is made to the state variables.

    Put all of that together and you have the following OnEvent.

    <OnEvent>
    -- Only processing player drive events.
    if arg1 ~= 'player' then
        return
    end
    
    -- Debug code to print event.
    DEFAULT_CHAT_FRAME:AddMessage( event )
    
    if event == 'UNIT_SPELLCAST_SENT' then
    elseif event == 'UNIT_SPELLCAST_START' then
        self.casting = true
        self.channeling = nil
    elseif event == 'UNIT_SPELLCAST_CHANNEL_START' then
        self.casting = nil
        self.channeling = true
    elseif event == 'UNIT_SPELLCAST_STOP' then
        self.casting = nil
    elseif event == 'UNIT_SPELLCAST_CHANNEL_STOP' then
        self.channeling = nil
    elseif event == 'UNIT_SPELLCAST_SUCCEEDED' then
    elseif event == 'UNIT_SPELLCAST_FAILED' then
        self.casting = nil
        self.channeling = nil
    elseif event == 'UNIT_SPELLCAST_INTERRUPTED' then
        self.casting = nil
        self.channeling = nil
    elseif event == 'UNIT_SPELLCAST_DELAYED' then
    elseif event == 'UNIT_SPELLCAST_CHANNEL_UPDATE' then
    end
    

    Finally, you can use the casting and channeling boolean flags to change the visibility of the panel.

    if self.casting or self.channeling then
        self:Hide()
    else
        self:Show()
    end
    

    I didn't have WoW in front of me when I wrote this, so there may be some typos. It should be enough to get your panel to work though. Good luck!

  • Avatar of arturogatti arturogatti Sep 28, 2009 at 02:59 UTC - 0 likes

    First of all thanks for the example scripts on this post... helped me a lot! ;)

    But now i have a doubt...

    Is there a way to create a panel that hides when im casting something? (when i say casting i mean... when the "cast" bar appears)

    Thanks in advance ;)

  • Avatar of yllelder yllelder Sep 26, 2009 at 20:28 UTC - 0 likes

    I make a texture of 512x256,insert this in the game with KGpanels and when resize in the addon (512x256) leaves much larger than it is!

    Thought I'd see what size that is creating the KGpanels my screen (my actual resolution is 1280x1024). Then I take the texture and put it in the addon size (width and height) 100% x 100% to fill the screen, then the pixels KGpanels said that the total width is 1066, is smaller than the resolution real! O_o

    I tried to do the conversion as my decision whatever it says the addon (W 1066):

    If 1280 is 1066

    512 are 426.4

    But there is to do well at all (a little larger or smaller) and I do not fit the adjacent textures.

    Anyone else happens to get a texture that will leave the largest size you have?

    Where are the 214 missing pixels?

  • Avatar of ImpalerCore ImpalerCore Sep 22, 2009 at 04:29 UTC - 0 likes

    This frame shows the level number of a target when a target is selected. If the level is skull, the skull icon is displayed.

    <OnLoad>
    self:RegisterEvent("PLAYER_TARGET_CHANGED")
    self.bg:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame-Skull")
    self.text:SetPoint("CENTER",self,"CENTER",0,0)
    self:Hide()
    
    <OnEvent>
    if UnitExists("target") == nil then
        self:Hide()
    else
        local level = UnitLevel("target")
    
        if level < 0 then
            self.bg:SetTexCoord(0,1,0,1);
            self.text:SetText("")
        else
            self.bg:SetTexCoord(0,0.01,0,0.01);
            self.text:SetFormattedText("%d", level)
        end
        self:Show()
    end
    

    You can customize the panel size to control the size of the icon, and the font parameters to control the level text size and font. Have fun!

  • Avatar of ImpalerCore ImpalerCore Sep 21, 2009 at 14:01 UTC - 0 likes

    To lilgulps

    To make a panel show up when not in combat, and only to show up in a party or raid can be made by combining two of the sample scripts.

    OnLoad
    
    self:RegisterEvent("PLAYER_REGEN_DISABLED")
    self:RegisterEvent("PLAYER_REGEN_ENABLED")
    self:RegisterEvent("PLAYER_ENTERING_WORLD")
    self:RegisterEvent("PARTY_MEMBERS_CHANGED")
    self:RegisterEvent("RAID_ROSTER_UPDATE")
    self:Hide()
    
    OnEvent
    
     local pmems = GetNumPartyMembers()
     local rmems = GetNumRaidMembers()
     
    if (pmems > 0 or rmems > 0) then
      if event == "PLAYER_REGEN_ENABLED" then
        self:Show()
      elseif event == "PLAYER_REGEN_DISABLED" then
        self:Hide()
      end
    else
      self:Hide()
    end
    

    Not tested!

    Last edited Sep 21, 2009 by ImpalerCore
  • Avatar of lilgulps lilgulps Sep 20, 2009 at 09:05 UTC - 0 likes

    I am very new to writing scripts, and basically I have a panel I have created.

    I want this panel to hide when i enter combat and reappear when I exit combat. I also want this panel to hide when I am not in a group. But to show when I join a 5 man party or a raid.

    Any help? :(

  • Avatar of ImpalerCore ImpalerCore Sep 19, 2009 at 06:03 UTC - 0 likes

    I have a couple of panels that I'm trying to layer on top of each other. It seems to be working, except there seems to be a little bit of a delay, and I'm wondering if I could do something that would make the kgpanel frame more responsive.

    ---kgIconBorderPanel---
    
    <OnLoad>
    self:RegisterEvent("UNIT_TARGET")
    self:Hide()
    
    <OnEvent>
    if UnitExists("target") == nil then
        self:Hide()
    else
        self:Show()
    end
    

    This is the background panel that my class icon sits on top of. Everything appears to work fine, except there is like a 1/2 second delay when I select or deselect a target till the frame shows or hides respectively. Is there a way to make it a little more responsive? It's not a big deal if it works this way, I'm just wondering if there is something I could do to make it more responsive to changes in targets.

    ---kgIconPanel---
    
    <OnLoad>
    self:RegisterEvent("UNIT_TARGET")
    
    local f = kgPanels:FetchFrame("kgIconBorderPanel")
    self:SetParent(f)
    
    self:Hide()
    
    <OnEvent>
    local ClassIconCoord =
    {
      WARRIOR = {1,1},
      MAGE = {1,2},
      ROGUE = {1,3},
      DRUID = {1,4},
      HUNTER = {2,1},
      SHAMAN = {2,2},
      PRIEST = {2,3},
      WARLOCK = {2,4},
      PALADIN = {3,1},
      DEATHKNIGHT = {3,2},
      DEFAULT = {4,4}, -- transparent so hidden by default
    };
    
    if UnitExists("target") == nil then
       self:Hide()
       return
    end
    
    local _,class = UnitClass("target");
    local col, row = ClassIconCoord[class or "DEFAULT"][1], ClassIconCoord[class or "DEFAULT"][2];
    local left, top = (row-1)*0.25,(col-1)*0.25;
    
    self.bg:SetTexture("Interface\\Textures\\Special\\ClassIcons");
    self.bg:SetTexCoord(left,left+0.25,top,top+0.25);
    self.bg:SetPoint("TOPLEFT", self, "TOPLEFT", 6, -6);
    self.bg:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -6, 6);
    self:Show()
    

    This panel borrows code from an addon that displays a class specific icon texture from a grid of icons. Using the texcoord, I'm able to select the right icon from the complete image. Is there any way I could improve this code?

    Thanks for any advice.

    EDIT: I found out how to make it faster. Just replace the generic "UNIT_TARGET" event with "PLAYER_TARGET_CHANGED". Now the icon changes quickly :-)

    Last edited Sep 19, 2009 by ImpalerCore
  • Avatar of Kuzah Kuzah Aug 26, 2009 at 21:20 UTC - 0 likes

    @sirspikey, thanks for the suggestion, but it only says WorldFrame too.

    I was digging into the issue more and it seems that LibQTip does this, "LibQTip produces anonymous frames and even if it named them, you will have hard time doing something consistent because there are reused in undefined order."

    I was wondering if there's something we could do like parent/anchor to a 'mother' frame. Like for example I have to attach a panel to ShoppingTooltip1 2 and 3, but what if I could 'mother' frame anchor by putting in just ShoppingTooltip#. I could imagine it's easy for just a number change, but what if there was a uniquely generated string? If we could parent/anchor panels to a 'mother' frame and just use the auto resize that'd be like making a single kgpanel and it would cover every tooltip!! (since right now I have to make many panels to cover all different tooltip frame names).

  • Avatar of sirspikey sirspikey Aug 26, 2009 at 16:40 UTC - 0 likes

    @Kuzah check out the addon DevTool it helps you id the frames under your pointer. Search for it on curse.com or wowinterface.com

    Last edited Aug 26, 2009 by sirspikey: used wrong word
  • Avatar of Kuzah Kuzah Aug 26, 2009 at 05:26 UTC - 0 likes

    A different topic at hand.

    Was wondering if there was some way to nudge or resize a kgpanel that has been made to auto adjust via "Resizing your panel on the fly" from the FAQ.

    Like if I use kgpanel for all my tooltips I would like to be able to nudge the kgpanel for all tooltips and/or be able to give it a smaller or larger size than what it is now. I'm guessing I could mess with the "self:SetWidth(DropDownList1:GetWidth())" and "self:SetHeight(DropDownList1:GetHeight())", but I haven't a clue what to do.

Facts

Date created
Sep 16, 2008
Category
Last update
Jun 23, 2015
Development stage
Release
Language
  • enUS
  • frFR
  • koKR
  • zhCN
License
All Rights Reserved
Curse link
kgPanels
Reverse relationships
1
Downloads
1,893,330
Recent files
  • A: r437 for 6.2.0 Jun 23, 2015
  • A: r436 for 6.1.0 Feb 24, 2015
  • R: 1.20 for 6.0.2 Oct 24, 2014
  • R: 1.19 for 6.0.2 Oct 17, 2014
  • A: r433 for 6.0.2 Oct 17, 2014

Authors