How to add custom cells

Custom cells are handled using the "abstract factory" design pattern: LibQTip expects a factory (the CellProvider) able to create the cells. The CellProvider and the Cells should implement a given interface: CellProvider and Cell.

In each of the following examples, we create a custom cell providing colored labels.

Home brew CellProvider

The Cell

First look at the Cell interface. A LibQtip Cell should be a Frame widget that implements an additional method :SetupCell. Parenting, showing/hiding and anchoring of the cell itself is handled by LibQTip, so we do not care about this. We have to take care of any additional widgets though.

-- Create an empty cell prototype
local cellPrototype = {}
 
-- This prototype should "inherited" from the Frame prototype
-- So we create a dummy frame to be used in a metatable index.
setmetatable(cellPrototype, { __index = CreateFrame("Frame") })

We create an additional method for our internal use. We will call this method once per cell.

function cellPrototype:InitializeCell()
   -- Create the FontString to dispaly
   self.fontString = self:CreateFontString()
   self.fontString:SetAllPoints(self)
   self.fontString:SetFontObject(GameTooltipText)
   -- Setup the default color: white
   self.r, self.g, self.b = 1, 1, 1
end

The SetupCell method: this method can be called several times, the extra arguments after font should be remembered

function cellPrototype:SetupCell(tooltip, value, justification, font, r, g, b)
   -- Apply the setting
   local fs = self.fontString
   fs:SetFontObject(font or tooltip:GetFont())
   fs:SetJustifyH(justification)
   fs:SetText(tostring(value))

   -- Apply our specific settings, using default values if need be
   self.r, self.g, self.b = r or self.r, g or self.g, b or self.b
   fs:SetTextColor(self.r, self.g, self.b)

   -- Show the fontstring and return our size
   fs:Show()
   return fs:GetStringWidth(), fs:GetStringHeight()
end

Another internal method, that our provider call to cleanup the cell.

function cellPrototype:CleanupCell()
   -- This reset the default text color
   self.r, self.g, self.b = 1, 1, 1
end

The CellProvider

The CellProvider should implements the AcquireCell and ReleaseCell methods. Moreover, though it is not mandatory, it is recommended that it recycles the widgets.

-- The provider with some attributes
local myProvider = {
   -- The heap we will store unused cells into
   heap = {},

   -- The prototype we use for cells,
   cellPrototype = cellPrototype,

   -- The metatable for using the prototype above
   cellMetatable = { __index = cellPrototype }
}

The AcquireCell method: try to get a cell from the heap. If not possible, create a new cell. In this case, do not forget to initialize it. Notice we do not need the tooltip argument in this implementation.

function myProvider:AcquireCell(tooltip)
   -- Try to get an unused cell from the heap
   local cell = table.remove(self.heap)

   if not cell then
     -- Not cell available, create a new one
     cell = CreateFrame("Frame")

     -- Override the metatable
     setmetatable(cell, self.cellMetatable)

     -- Now initialize the cell with our method
     cell:InitializeCell()
   end
   return cell
end

The :ReleaseCell method: clean the cell and put it into the heap.

function myProvider:ReleaseCell(cell)
   -- Cleanup the cell
   cell:CleanupCell()

   -- Put it back into our heap
   table.insert(self.heap, cell)
end

The :GetCellPrototype method: just return our prototype and metatable.

function myProvider:GetCellPrototype()
   return self.cellPrototype, self.cellMetatable
end

Using the provider

Once our provider has been created, we can create cell using the :SetCell methods.

 -- Create a tooltip with 2 columns
 local tip = LibQTip:Acquire("MyOwnAddonTip", 2, "LEFT", "RIGHT")
 -- Add a new line, filling only the left column
 local y,x = tip:AddLine("Label:")
 -- Add a custom cell using our provided
 -- We simply pass :SetCell our provider, followed by the specific arguments (r, g, b)
 tip:SetCell(y, x, "Red text", myProvider, 1, 0, 0)

Using LibQTip:CreateCellProvider()

This method creates a fully fledged provider, with cell recycling. Only the cell methods have to be provided. This save us some code. See Standard CellProvider API for more details.

Brand new provider

Compared to the homebrew method we have only to provide the cell methods.

First, let's create the cell provider.

 local myProvider, cellPrototype = LibQTip:CreateCellProvider()

Now add the Cell methods into the cellPrototype. Theses are the same as for home brew Cells, except for the name.

function cellPrototype:InitializeCell()
   self.fontString = self:CreateFontString()
   self.fontString:SetAllPoints(self)
   self.fontString:SetFontObject(GameTooltipText)
   self.r, self.g, self.b = 1, 1, 1
end
 
function cellPrototype:SetupCell(tooltip, value, justification, font, r, g, b)
   local fs = self.fontString
   fs:SetFontObject(font or tooltip:GetFont())
   fs:SetJustifyH(justification)
   fs:SetText(tostring(value))
   self.r, self.g, self.b = r or self.r, g or self.g, b or self.b
   fs:SetTextColor(self.r, self.g, self.b)
   fs:Show()
   return fs:GetStringWidth(), fs:GetStringHeight()
end
 
function cellPrototype:ReleaseCell()
   self.r, self.g, self.b = 1, 1, 1
end

Subclassing existing provider

This is done using the baseProvider of the :CreateCellProvider method. Here we will implements our colored label based on the LibQTip LabelProvider.

First, we create the derived provider. We need to keep a reference to the base cell prototype to handler "super" calls.

  local myProvider, cellPrototype, baseCellPrototype = LibQTip:CreateCellProvider(LibQTip.LabelProvider)

Now we override the :InitializeCell method to setup the default color:

function cellPrototype:InitializeCell()
   -- This how to call the base method, notice the use of "dot" and "self"
   baseCellPrototype.InitializeCell(self)
   -- Additional code follow:
   self.r, self.g, self.b = 1, 1, 1
end

We also override the :SetupCell method:

function cellPrototype:SetupCell(tooltip, value, justification, font, r, g, b)
   -- Call the base method
   local width, height = baseCellPrototype.SetupCell(self, tooltip, value, justification, font, r, g, b)
   -- The base LabelProvider stores its FontString in the fontString attribute
   -- Sets it color
   self.r, self.g, self.b = r or self.r, g or self.g, b or self.b
   self.fontString:SetTextColor(self.r, self.g, self.b)
   -- Return the 
   return width, height
end

We add an additional method to cleanup the cell:

function cellPrototype:ReleaseCell()
   self.r, self.g, self.b = 1, 1, 1
end

Comments

Posts Quoted:
Reply
Clear All Quotes