flickerstreak@25: local ReAction = ReAction flickerstreak@25: local L = ReAction.L flickerstreak@25: local _G = _G flickerstreak@25: local CreateFrame = CreateFrame flickerstreak@33: local InCombatLockdown = InCombatLockdown flickerstreak@33: local floor = math.floor flickerstreak@33: local min = math.min flickerstreak@33: local format = string.format flickerstreak@33: local GameTooltip = GameTooltip flickerstreak@33: flickerstreak@33: flickerstreak@25: flickerstreak@25: -- update ReAction revision if this file is newer flickerstreak@33: local revision = tonumber(("$Revision$"):match("%d+")) flickerstreak@25: if revision > ReAction.revision then flickerstreak@25: Reaction.revision = revision flickerstreak@25: end flickerstreak@25: flickerstreak@28: ------ BAR CLASS ------ flickerstreak@28: local Bar = { _classID = {} } flickerstreak@25: flickerstreak@28: local function Constructor( self, name, config ) flickerstreak@25: self.name, self.config = name, config flickerstreak@25: flickerstreak@25: if type(config) ~= "table" then flickerstreak@28: error("ReAction.Bar: config table required") flickerstreak@25: end flickerstreak@25: flickerstreak@25: local f = CreateFrame("Frame",nil,config.parent or UIParent,"SecureStateDriverTemplate") flickerstreak@25: f:SetFrameStrata("MEDIUM") flickerstreak@30: config.width = config.width or 480 flickerstreak@30: config.height = config.height or 40 flickerstreak@25: f:SetWidth(config.width) flickerstreak@25: f:SetWidth(config.height) flickerstreak@25: flickerstreak@25: self.frame = f flickerstreak@25: self:RefreshLayout() flickerstreak@25: self:ApplyAnchor() flickerstreak@25: f:Show() flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:Destroy() flickerstreak@25: local f = self.frame flickerstreak@25: f:UnregisterAllEvents() flickerstreak@25: f:Hide() flickerstreak@25: f:SetParent(UIParent) flickerstreak@25: f:ClearAllPoints() flickerstreak@25: self.labelString = nil flickerstreak@25: self.controlFrame = nil flickerstreak@25: self.frame = nil flickerstreak@25: self.config = nil flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:RefreshLayout() flickerstreak@25: ReAction:CallMethodOnAllModules("RefreshBar", self) flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:ApplyAnchor() flickerstreak@25: local f, config = self.frame, self.config flickerstreak@25: f:SetWidth(config.width) flickerstreak@25: f:SetHeight(config.height) flickerstreak@25: local anchor = config.anchor flickerstreak@25: if anchor then flickerstreak@25: local anchorTo flickerstreak@25: if config.anchorTo then flickerstreak@28: anchorTo = ReAction:GetBar(config.anchorTo) or _G[config.anchorTo] flickerstreak@25: end flickerstreak@25: f:SetPoint(anchor, anchorTo, config.relativePoint, config.x or 0, config.y or 0) flickerstreak@25: else flickerstreak@25: f:SetPoint("CENTER") flickerstreak@25: end flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:GetFrame() flickerstreak@25: return self.frame flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:GetSize() flickerstreak@25: return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200 flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:SetSize(w,h) flickerstreak@25: self.config.width = w flickerstreak@25: self.config.height = h flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:GetButtonSize() flickerstreak@25: local w = self.config.btnWidth or 32 flickerstreak@25: local h = self.config.btnHeight or 32 flickerstreak@25: -- TODO: get from modules? flickerstreak@25: return w,h flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:SetButtonSize(w,h) flickerstreak@25: if w > 0 and h > 0 then flickerstreak@25: self.config.btnWidth = w flickerstreak@25: self.config.btnHeight = h flickerstreak@25: end flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:GetButtonGrid() flickerstreak@25: local cfg = self.config flickerstreak@25: local r = cfg.btnRows or 1 flickerstreak@25: local c = cfg.btnColumns or 1 flickerstreak@25: local s = cfg.spacing or 4 flickerstreak@25: return r,c,s flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:SetButtonGrid(r,c,s) flickerstreak@25: if r > 0 and c > 0 and s > 0 then flickerstreak@25: local cfg = self.config flickerstreak@25: cfg.btnRows = r flickerstreak@25: cfg.btnColumns = c flickerstreak@25: cfg.spacing = s flickerstreak@25: end flickerstreak@25: end flickerstreak@25: flickerstreak@25: function Bar:GetName() flickerstreak@25: return self.name flickerstreak@25: end flickerstreak@25: flickerstreak@33: function Bar:SetName(name) flickerstreak@33: self.name = name flickerstreak@33: if self.controlLabelString then flickerstreak@33: self.controlLabelString:SetText(self.name) flickerstreak@33: end flickerstreak@33: end flickerstreak@33: flickerstreak@25: function Bar:PlaceButton(f, idx, baseW, baseH) flickerstreak@25: local r, c, s = self:GetButtonGrid() flickerstreak@25: local bh, bw = self:GetButtonSize() flickerstreak@25: local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based flickerstreak@25: local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s flickerstreak@25: local scale = bw/baseW flickerstreak@25: flickerstreak@25: f:ClearAllPoints() flickerstreak@25: f:SetPoint("TOPLEFT",x/scale,-y/scale) flickerstreak@25: f:SetScale(scale) flickerstreak@25: -- f:Show() flickerstreak@25: end flickerstreak@25: flickerstreak@28: flickerstreak@28: flickerstreak@33: flickerstreak@33: flickerstreak@33: flickerstreak@33: flickerstreak@33: -- flickerstreak@33: -- Bar config overlay flickerstreak@33: -- flickerstreak@33: local StoreExtents, RecomputeButtonSize, RecomputeButtonSpacing, RecomputeGrid, ClampToButtons, HideGameTooltip, CreateControls flickerstreak@33: flickerstreak@33: do flickerstreak@33: -- upvalue some of these for small OnUpdate performance boost flickerstreak@33: local GetSize = Bar.GetSize flickerstreak@33: local GetButtonSize = Bar.GetButtonSize flickerstreak@33: local GetButtonGrid = Bar.GetButtonGrid flickerstreak@33: local SetSize = Bar.SetSize flickerstreak@33: local SetButtonSize = Bar.SetButtonSize flickerstreak@33: local SetButtonGrid = Bar.SetButtonGrid flickerstreak@33: local ApplyAnchor = Bar.ApplyAnchor flickerstreak@33: flickerstreak@33: StoreExtents = function(bar) flickerstreak@33: local f = bar.frame flickerstreak@33: local point, relativeTo, relativePoint, x, y = f:GetPoint(1) flickerstreak@33: relativeTo = relativeTo or f:GetParent() flickerstreak@33: local anchorTo flickerstreak@33: for name, b in pairs(ReAction.bars) do flickerstreak@33: if b then flickerstreak@33: if b:GetFrame() == relativeTo then flickerstreak@33: anchorTo = name flickerstreak@33: break flickerstreak@33: end flickerstreak@33: end flickerstreak@33: end flickerstreak@33: anchorTo = anchorTo or relativeTo:GetName() flickerstreak@33: local c = bar.config flickerstreak@33: c.anchor = point flickerstreak@33: c.anchorTo = anchorTo flickerstreak@33: c.relativePoint = relativePoint flickerstreak@33: c.x = x flickerstreak@33: c.y = y flickerstreak@33: c.width, c.height = f:GetWidth(), f:GetHeight() flickerstreak@33: end flickerstreak@33: flickerstreak@33: RecomputeButtonSize = function(bar) flickerstreak@33: local w, h = GetSize(bar) flickerstreak@33: local bw, bh = GetButtonSize(bar) flickerstreak@33: local r, c, s = GetButtonGrid(bar) flickerstreak@33: flickerstreak@33: local scaleW = (floor(w/c) - s) / bw flickerstreak@33: local scaleH = (floor(h/r) - s) / bh flickerstreak@33: local scale = min(scaleW, scaleH) flickerstreak@33: flickerstreak@33: SetButtonSize(bar, scale * bw, scale * bh, s) flickerstreak@33: end flickerstreak@33: flickerstreak@33: RecomputeButtonSpacing = function(bar) flickerstreak@33: local w, h = GetSize(bar) flickerstreak@33: local bw, bh = GetButtonSize(bar) flickerstreak@33: local r, c, s = GetButtonGrid(bar) flickerstreak@33: flickerstreak@33: SetButtonGrid(bar,r,c,min(floor(w/c) - bw, floor(h/r) - bh)) flickerstreak@33: end flickerstreak@33: flickerstreak@33: RecomputeGrid = function(bar) flickerstreak@33: local w, h = GetSize(bar) flickerstreak@33: local bw, bh = GetButtonSize(bar) flickerstreak@33: local r, c, s = GetButtonGrid(bar) flickerstreak@33: flickerstreak@33: SetButtonGrid(bar, floor(h/(bh+s)), floor(w/(bw+s)), s) flickerstreak@33: end flickerstreak@33: flickerstreak@33: ClampToButtons = function(bar) flickerstreak@33: local bw, bh = GetButtonSize(bar) flickerstreak@33: local r, c, s = GetButtonGrid(bar) flickerstreak@50: SetSize(bar, (bw+s)*c + 1, (bh+s)*r + 1) flickerstreak@33: end flickerstreak@33: flickerstreak@33: HideGameTooltip = function() flickerstreak@33: GameTooltip:Hide() flickerstreak@33: end flickerstreak@33: flickerstreak@33: CreateControls = function(bar) flickerstreak@33: local f = bar.frame flickerstreak@33: flickerstreak@33: f:SetMovable(true) flickerstreak@33: f:SetResizable(true) flickerstreak@33: f:SetClampedToScreen(true) flickerstreak@33: flickerstreak@33: -- buttons on the bar should be direct children of the bar frame. flickerstreak@33: -- The control elements need to float on top of this, which we could flickerstreak@33: -- do with SetFrameLevel() or Raise(), but it's more reliable to do it flickerstreak@33: -- via frame nesting, hence good old foo's appearance here. flickerstreak@33: local foo = CreateFrame("Frame",nil,f) flickerstreak@33: foo:SetAllPoints() flickerstreak@33: flickerstreak@33: local control = CreateFrame("Button", nil, foo) flickerstreak@33: control:EnableMouse(true) flickerstreak@33: control:SetToplevel(true) flickerstreak@33: control:SetPoint("TOPLEFT", -4, 4) flickerstreak@33: control:SetPoint("BOTTOMRIGHT", 4, -4) flickerstreak@33: control:SetBackdrop({ flickerstreak@33: edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", flickerstreak@33: tile = true, flickerstreak@33: tileSize = 16, flickerstreak@33: edgeSize = 16, flickerstreak@33: insets = { left = 0, right = 0, top = 0, bottom = 0 }, flickerstreak@33: }) flickerstreak@33: flickerstreak@33: -- textures flickerstreak@33: local bgTex = control:CreateTexture(nil,"BACKGROUND") flickerstreak@33: bgTex:SetTexture(0.7,0.7,1.0,0.2) flickerstreak@33: bgTex:SetPoint("TOPLEFT",4,-4) flickerstreak@33: bgTex:SetPoint("BOTTOMRIGHT",-4,4) flickerstreak@33: local hTex = control:CreateTexture(nil,"HIGHLIGHT") flickerstreak@33: hTex:SetTexture(0.7,0.7,1.0,0.2) flickerstreak@33: hTex:SetPoint("TOPLEFT",4,-4) flickerstreak@33: hTex:SetPoint("BOTTOMRIGHT",-4,4) flickerstreak@33: hTex:SetBlendMode("ADD") flickerstreak@33: flickerstreak@33: -- label flickerstreak@33: local label = control:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") flickerstreak@33: label:SetAllPoints() flickerstreak@33: label:SetJustifyH("CENTER") flickerstreak@33: label:SetShadowColor(0,0,0,1) flickerstreak@33: label:SetShadowOffset(2,-2) flickerstreak@33: label:SetTextColor(1,1,1,1) flickerstreak@33: label:SetText(bar:GetName()) flickerstreak@33: label:Show() flickerstreak@33: bar.controlLabelString = label -- so that bar:SetName() can update it flickerstreak@33: flickerstreak@33: local StopResize = function() flickerstreak@33: f:StopMovingOrSizing() flickerstreak@33: f.isMoving = false flickerstreak@33: f:SetScript("OnUpdate",nil) flickerstreak@33: StoreExtents(bar) flickerstreak@33: ClampToButtons(bar) flickerstreak@33: ApplyAnchor(bar) flickerstreak@33: end flickerstreak@33: flickerstreak@33: -- edge drag handles flickerstreak@33: for _, point in pairs({"LEFT","TOP","RIGHT","BOTTOM"}) do flickerstreak@33: local edge = CreateFrame("Frame",nil,control) flickerstreak@33: edge:EnableMouse(true) flickerstreak@33: edge:SetWidth(8) flickerstreak@33: edge:SetHeight(8) flickerstreak@33: if point == "TOP" or point == "BOTTOM" then flickerstreak@33: edge:SetPoint(point.."LEFT") flickerstreak@33: edge:SetPoint(point.."RIGHT") flickerstreak@33: else flickerstreak@33: edge:SetPoint("TOP"..point) flickerstreak@33: edge:SetPoint("BOTTOM"..point) flickerstreak@33: end flickerstreak@33: local tex = edge:CreateTexture(nil,"HIGHLIGHT") flickerstreak@33: tex:SetTexture(1.0,0.82,0,0.7) flickerstreak@33: tex:SetBlendMode("ADD") flickerstreak@33: tex:SetAllPoints() flickerstreak@33: edge:RegisterForDrag("LeftButton") flickerstreak@33: edge:SetScript("OnMouseDown", flickerstreak@33: function() flickerstreak@33: local bw, bh = GetButtonSize(bar) flickerstreak@33: local r, c, s = GetButtonGrid(bar) flickerstreak@33: f:SetMinResize( bw+s+1, bh+s+1 ) flickerstreak@33: f:StartSizing(point) flickerstreak@33: f:SetScript("OnUpdate", flickerstreak@33: function() flickerstreak@33: RecomputeGrid(bar) flickerstreak@33: bar:RefreshLayout() flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: edge:SetScript("OnMouseUp", StopResize) flickerstreak@33: edge:SetScript("OnEnter", flickerstreak@33: function() flickerstreak@33: GameTooltip:SetOwner(f, "ANCHOR_"..point) flickerstreak@33: GameTooltip:AddLine(L["Drag to add/remove buttons"]) flickerstreak@33: GameTooltip:Show() flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: edge:SetScript("OnLeave", HideGameTooltip) flickerstreak@33: edge:Show() flickerstreak@33: end flickerstreak@33: flickerstreak@33: -- corner drag handles, again nested in an anonymous frame so that they are on top flickerstreak@33: local foo2 = CreateFrame("Frame",nil,control) flickerstreak@33: foo2:SetAllPoints(true) flickerstreak@33: for _, point in pairs({"BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT"}) do flickerstreak@33: local corner = CreateFrame("Frame",nil,foo2) flickerstreak@33: corner:EnableMouse(true) flickerstreak@33: corner:SetWidth(12) flickerstreak@33: corner:SetHeight(12) flickerstreak@33: corner:SetPoint(point) flickerstreak@33: local tex = corner:CreateTexture(nil,"HIGHLIGHT") flickerstreak@33: tex:SetTexture(1.0,0.82,0,0.7) flickerstreak@33: tex:SetBlendMode("ADD") flickerstreak@33: tex:SetAllPoints() flickerstreak@33: corner:RegisterForDrag("LeftButton","RightButton") flickerstreak@33: local updateTooltip = function() flickerstreak@33: local size, size2 = bar:GetButtonSize() flickerstreak@33: local rows, cols, spacing = bar:GetButtonGrid() flickerstreak@33: size = (size == size2) and tostring(size) or format("%dx%d",size,size2) flickerstreak@33: GameTooltipTextRight4:SetText(size) flickerstreak@33: GameTooltipTextRight5:SetText(tostring(spacing)) flickerstreak@33: end flickerstreak@33: corner:SetScript("OnMouseDown", flickerstreak@33: function(_,btn) flickerstreak@33: local bw, bh = GetButtonSize(bar) flickerstreak@33: local r, c, s = GetButtonGrid(bar) flickerstreak@33: if btn == "LeftButton" then -- button resize flickerstreak@33: f:SetMinResize( (s+12)*c+1, (s+12)*r+1 ) flickerstreak@33: f:SetScript("OnUpdate", flickerstreak@33: function() flickerstreak@33: RecomputeButtonSize(bar) flickerstreak@33: bar:RefreshLayout() flickerstreak@33: updateTooltip() flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: elseif btn == "RightButton" then -- spacing resize flickerstreak@33: f:SetMinResize( bw*c, bh*r ) flickerstreak@33: f:SetScript("OnUpdate", flickerstreak@33: function() flickerstreak@33: RecomputeButtonSpacing(bar) flickerstreak@33: bar:RefreshLayout() flickerstreak@33: updateTooltip() flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: end flickerstreak@33: f:StartSizing(point) flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: corner:SetScript("OnMouseUp",StopResize) flickerstreak@33: corner:SetScript("OnEnter", flickerstreak@33: function() flickerstreak@33: GameTooltip:SetOwner(f, "ANCHOR_"..point) flickerstreak@33: GameTooltip:AddLine(L["Drag to resize buttons"]) flickerstreak@33: GameTooltip:AddLine(L["Right-click-drag"]) flickerstreak@33: GameTooltip:AddLine(L["to change spacing"]) flickerstreak@33: local size, size2 = bar:GetButtonSize() flickerstreak@33: local rows, cols, spacing = bar:GetButtonGrid() flickerstreak@33: size = (size == size2) and tostring(size) or format("%dx%d",size,size2) flickerstreak@33: GameTooltip:AddDoubleLine(L["Size:"], size) flickerstreak@33: GameTooltip:AddDoubleLine(L["Spacing:"], tostring(spacing)) flickerstreak@33: GameTooltip:Show() flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: corner:SetScript("OnLeave", flickerstreak@33: function() flickerstreak@33: GameTooltip:Hide() flickerstreak@33: f:SetScript("OnUpdate",nil) flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: flickerstreak@33: end flickerstreak@33: flickerstreak@33: control:RegisterForDrag("LeftButton") flickerstreak@33: control:RegisterForClicks("RightButtonDown") flickerstreak@33: flickerstreak@33: control:SetScript("OnDragStart", flickerstreak@33: function() flickerstreak@33: f:StartMoving() flickerstreak@33: f.isMoving = true flickerstreak@33: -- TODO: snap indicator update install flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: flickerstreak@33: control:SetScript("OnDragStop", flickerstreak@33: function() flickerstreak@33: f:StopMovingOrSizing() flickerstreak@33: f.isMoving = false flickerstreak@33: f:SetScript("OnUpdate",nil) flickerstreak@33: -- TODO: snap frame here flickerstreak@33: StoreExtents(bar) flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: flickerstreak@33: control:SetScript("OnEnter", flickerstreak@33: function() flickerstreak@33: -- add bar type and status information to name flickerstreak@33: local name = bar.name flickerstreak@33: for _, m in ReAction:IterateModules() do flickerstreak@33: --[[ flickerstreak@33: local suffix = safecall(m,"GetBarNameModifier",bar) flickerstreak@33: if suffix then flickerstreak@33: name = ("%s %s"):format(name,suffix) flickerstreak@33: end flickerstreak@33: --]] flickerstreak@33: end flickerstreak@33: flickerstreak@33: GameTooltip:SetOwner(f, "ANCHOR_TOPRIGHT") flickerstreak@33: GameTooltip:AddLine(name) flickerstreak@33: GameTooltip:AddLine(L["Drag to move"]) flickerstreak@33: --GameTooltip:AddLine(L["Shift-drag for sticky mode"]) flickerstreak@33: GameTooltip:AddLine(L["Right-click for options"]) flickerstreak@33: GameTooltip:Show() flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: flickerstreak@33: control:SetScript("OnLeave", HideGameTooltip) flickerstreak@33: flickerstreak@33: control:SetScript("OnClick", flickerstreak@33: function() flickerstreak@33: bar:ShowMenu() flickerstreak@33: end flickerstreak@33: ) flickerstreak@33: flickerstreak@33: return control flickerstreak@33: end flickerstreak@33: end flickerstreak@33: flickerstreak@33: flickerstreak@33: local OpenMenu, CloseMenu flickerstreak@33: do flickerstreak@33: -- Looking for a lightweight AceConfig3-struct-compatible flickerstreak@33: -- replacement for Dewdrop, encapsulate here flickerstreak@33: -- Considering Blizzard's EasyMenu/UIDropDownMenu, but that's flickerstreak@33: -- a bit tricky to convert from AceConfig3-struct flickerstreak@33: local Dewdrop = AceLibrary("Dewdrop-2.0") flickerstreak@33: OpenMenu = function(frame, opts) flickerstreak@33: Dewdrop:Open(frame, "children", opts, "cursorX", true, "cursorY", true) flickerstreak@33: end flickerstreak@33: CloseMenu = function(frame) flickerstreak@33: if Dewdrop:GetOpenedParent() == frame then flickerstreak@33: Dewdrop:Close() flickerstreak@33: end flickerstreak@33: end flickerstreak@33: end flickerstreak@33: flickerstreak@33: flickerstreak@33: function Bar:ShowControls(show) flickerstreak@33: if show then flickerstreak@33: if not self.controlFrame then flickerstreak@33: self.controlFrame = CreateControls(self) flickerstreak@33: end flickerstreak@33: self.controlFrame:Show() flickerstreak@33: elseif self.controlFrame then flickerstreak@33: CloseMenu(self.controlFrame) flickerstreak@33: self.controlFrame:Hide() flickerstreak@33: end flickerstreak@33: end flickerstreak@33: flickerstreak@33: function Bar:ShowMenu() flickerstreak@33: if not self.menuOpts then flickerstreak@33: self.menuOpts = { flickerstreak@33: type = "group", flickerstreak@33: args = { flickerstreak@33: openConfig = { flickerstreak@33: type = "execute", flickerstreak@50: name = L["Layout..."], flickerstreak@50: desc = L["Open the layout editor for this bar"], flickerstreak@50: func = function() CloseMenu(self.controlFrame); ReAction:CallModuleMethod("ConfigUI","LaunchLayoutEditor",self) end, flickerstreak@33: disabled = InCombatLockdown, flickerstreak@33: order = 1 flickerstreak@33: }, flickerstreak@33: delete = { flickerstreak@33: type = "execute", flickerstreak@33: name = L["Delete Bar"], flickerstreak@33: desc = L["Remove the bar from the current profile"], flickerstreak@50: confirm = L["Are you sure you want to remove this bar?"], flickerstreak@33: func = function() ReAction:EraseBar(self) end, flickerstreak@33: order = 2 flickerstreak@33: }, flickerstreak@33: } flickerstreak@33: } flickerstreak@33: end flickerstreak@33: OpenMenu(self.controlFrame, self.menuOpts) flickerstreak@33: end flickerstreak@33: flickerstreak@33: flickerstreak@33: flickerstreak@28: ------ Export as a class-factory ------ flickerstreak@28: ReAction.Bar = { flickerstreak@28: new = function(self, ...) flickerstreak@28: local x = { } flickerstreak@28: for k,v in pairs(Bar) do flickerstreak@28: x[k] = v flickerstreak@28: end flickerstreak@28: Constructor(x, ...) flickerstreak@28: return x flickerstreak@28: end flickerstreak@28: }