| Nenue@6 | 1 --- Dialog Generator | 
| Nenue@6 | 2 -- @file-author@ | 
| Nenue@6 | 3 -- @project-revision@ @project-hash@ | 
| Nenue@6 | 4 -- @file-revision@ @file-hash@ | 
| Nenue@6 | 5 -- Created: 1/1/2016 3:37 PM | 
| Nenue@6 | 6 --- Framescript template for generating intelligible dialog panels | 
| Nenue@6 | 7 --[[ | 
| Nenue@6 | 8 -- Frame << TkListFrame | 
| Nenue@6 | 9 -- { | 
| Nenue@6 | 10 --    Frame <rows> << TkListItem                <--  Any number of list item frames with parentArray="rows" | 
| Nenue@6 | 11 --    { | 
| Nenue@6 | 12           :GetRow(row, values, id, offset)      <--  Populates the uiobjects that make up the given row, with data from values[id], on display row offset | 
| Nenue@6 | 13           <opts>                                <--  Any layered region of child frame with parentArray=opts" | 
| Nenue@6 | 14       } | 
| Nenue@6 | 15       Button <buttons>                      <--  Any frame with parentArray="buttons" | 
| Nenue@6 | 16 | 
| Nenue@6 | 17       .Click (button, list)                 <--  Defines results of using a control button | 
| Nenue@6 | 18       .Check (button, row, list)            <--  Defines results of operating a row widget | 
| Nenue@6 | 19       .Wheel (list, delta)                  <--  Defines response to mousewheel action over the list panel | 
| Nenue@6 | 20    } | 
| Nenue@6 | 21 | 
| Nenue@6 | 22    Globals: | 
| Nenue@6 | 23    TkList_Init ( object, values, offset, numRows ) | 
| Nenue@6 | 24     Takes the return from CreateFrame and a table of values and establishes a scrollable list interface. | 
| Nenue@6 | 25 | 
| Nenue@6 | 26    TkPanel_Init ( object ) | 
| Nenue@6 | 27     TkList_Init without the scrollable list operations. Lines up control buttons and nothing else. | 
| Nenue@6 | 28 --]] | 
| Nenue@6 | 29 local TK_LIST_SPACING = 1 | 
| Nenue@6 | 30 local TK_LIST_PADDING = 3 | 
| Nenue@6 | 31 local TK_LIST_HEADING_SIZE = 26 | 
| Nenue@6 | 32 local TK_LIST_ITEM_HEIGHT = 24 | 
| Nenue@6 | 33 local TK_LIST_DISPLAY_ITEMS = 10 | 
| Nenue@6 | 34 | 
| Nenue@6 | 35 local print = function(...) | 
| Nenue@6 | 36   if _G.Devian and _G.DevianDB.workspace ~= 1 then | 
| Nenue@6 | 37     _G.print('Xui', ...) | 
| Nenue@6 | 38   end | 
| Nenue@6 | 39 end | 
| Nenue@6 | 40 -- GLOBALS: TkList_SetView, TkList_Init, Turok | 
| Nenue@6 | 41 local type, error, pairs, ipairs, tonumber, max, CreateFrame = type, error, pairs, ipairs, tonumber, math.max, CreateFrame | 
| Nenue@6 | 42 local checkval = function(valtype, t, fallback) | 
| Nenue@6 | 43   return (type(t) == valtype) and t or (fallback or error('Expected table reference, got '..type(t))) | 
| Nenue@6 | 44 end | 
| Nenue@6 | 45 local tableval = function(t, fallback) | 
| Nenue@6 | 46   return checkval('table', t, fallback or {}) | 
| Nenue@6 | 47 end | 
| Nenue@6 | 48 local funcval = function(f, fallback) | 
| Nenue@6 | 49   return checkval('function', f, fallback or function() end) | 
| Nenue@6 | 50 end | 
| Nenue@6 | 51 | 
| Nenue@6 | 52 --- Orders list row | 
| Nenue@6 | 53 -- Does an ipairs iteration over self.opts and distributes the referenced objects along the horizontal axis of 'self' | 
| Nenue@6 | 54 -- Note that members are only aligned horizontally; no column alignment is done. Widths can be set by datafunc to accomplish that. | 
| Nenue@6 | 55 local function TkListItem_Init (listrow) | 
| Nenue@6 | 56   if not listrow.opts then | 
| Nenue@6 | 57     print('no options to enumerate') | 
| Nenue@6 | 58     return | 
| Nenue@6 | 59   end | 
| Nenue@6 | 60   local rwidth = TK_LIST_PADDING*2 | 
| Nenue@6 | 61   for i, z in pairs(listrow.opts) do | 
| Nenue@6 | 62     if i > 1 then | 
| Nenue@6 | 63       z:SetPoint('LEFT', listrow.opts[i-1], 'RIGHT', TK_LIST_SPACING, 0) | 
| Nenue@6 | 64     else | 
| Nenue@6 | 65       z:SetPoint('LEFT', listrow, 'LEFT', TK_LIST_PADDING, 0) | 
| Nenue@6 | 66     end | 
| Nenue@6 | 67     rwidth = rwidth + z:GetWidth()+TK_LIST_SPACING | 
| Nenue@6 | 68     z:Show() | 
| Nenue@6 | 69   end | 
| Nenue@6 | 70   listrow:SetSize(rwidth-TK_LIST_PADDING*2,TK_LIST_ITEM_HEIGHT) | 
| Nenue@6 | 71   listrow:Show() | 
| Nenue@6 | 72   print(rwidth) | 
| Nenue@6 | 73   return rwidth | 
| Nenue@6 | 74 end | 
| Nenue@6 | 75 | 
| Nenue@6 | 76 | 
| Nenue@6 | 77 --- | 
| Nenue@6 | 78 local function TkControls_Init(self) | 
| Nenue@6 | 79   local buttonsize = (self._dwidth - (#self.buttons -1) * TK_LIST_SPACING - TK_LIST_PADDING*2) / #self.buttons | 
| Nenue@6 | 80   for n, b in ipairs(self.buttons) do | 
| Nenue@6 | 81     --print('Spirit', buttonsize) | 
| Nenue@6 | 82     b:SetWidth(buttonsize) | 
| Nenue@6 | 83     b:SetPoint('TOPLEFT', self, 'BOTTOMLEFT', buttonsize* (n-1) + TK_LIST_SPACING * (n-1) + TK_LIST_PADDING, -TK_LIST_PADDING) | 
| Nenue@6 | 84   end | 
| Nenue@6 | 85   self.controls:SetHeight(self.buttons[1]:GetHeight()+ TK_LIST_PADDING*2) | 
| Nenue@6 | 86 end | 
| Nenue@6 | 87 | 
| Nenue@6 | 88 --- Populates the list frame with items | 
| Nenue@6 | 89 function TkList_SetView(self, start_num, num_rows) | 
| Nenue@6 | 90   print(self, start_num, num_rows) | 
| Nenue@6 | 91   if not start_num then | 
| Nenue@6 | 92     start_num = self.offset | 
| Nenue@6 | 93   end | 
| Nenue@6 | 94 | 
| Nenue@6 | 95   if not num_rows then | 
| Nenue@6 | 96     num_rows = self.num_rows | 
| Nenue@6 | 97   end | 
| Nenue@6 | 98 | 
| Nenue@6 | 99   if start_num > #self.info then | 
| Nenue@6 | 100     start_num = #self.info - #self.info % num_rows | 
| Nenue@6 | 101   elseif start_num < 1 then | 
| Nenue@6 | 102     start_num = 1 | 
| Nenue@6 | 103   end | 
| Nenue@6 | 104 | 
| Nenue@6 | 105   print('  ', self:GetName(), start_num, num_rows, #self.info) | 
| Nenue@6 | 106   self.offset = start_num | 
| Nenue@6 | 107 | 
| Nenue@6 | 108   for draw_num = 1, num_rows do | 
| Nenue@6 | 109     local actual_row = draw_num + start_num - 1 | 
| Nenue@6 | 110     if not self.rows[draw_num] then | 
| Nenue@6 | 111       self.rows[draw_num] = CreateFrame('Frame', self:GetName()..'_Option_'..draw_num, self, 'TurokListItem') | 
| Nenue@6 | 112       self.rows[draw_num]:SetHeight(TK_LIST_ITEM_HEIGHT) | 
| Nenue@6 | 113       self.rows[draw_num].row_num = draw_num | 
| Nenue@6 | 114     end | 
| Nenue@6 | 115     self.rows[draw_num].actual_row = actual_row | 
| Nenue@6 | 116     local row = self.rows[draw_num] | 
| Nenue@6 | 117     if self.info[actual_row] then | 
| Nenue@6 | 118       print( actual_row, draw_num) | 
| Nenue@6 | 119       self.GetRow(row, self.info, actual_row, draw_num) | 
| Nenue@6 | 120       row:Show() | 
| Nenue@6 | 121     else | 
| Nenue@6 | 122       print('|cFF888888'..actual_row, draw_num) | 
| Nenue@6 | 123       row:Hide() | 
| Nenue@6 | 124     end | 
| Nenue@6 | 125     row:SetParent(self) | 
| Nenue@6 | 126   end | 
| Nenue@6 | 127 end | 
| Nenue@6 | 128 | 
| Nenue@6 | 129 --- Prime TkListFrame template-spawn for use | 
| Nenue@6 | 130 -- @param self frame object to list-ify | 
| Nenue@6 | 131 -- @param info array of list item values | 
| Nenue@6 | 132 -- @param datafunc function that takes 1) frame object 2) info table 3) index number 4) row number | 
| Nenue@6 | 133 -- @param offset starting offset for initial view | 
| Nenue@6 | 134 function TkList_Init (self, info, offset, num_rows) | 
| Nenue@6 | 135   -- error checking | 
| Nenue@6 | 136   --[[if type(info) ~= 'table' then | 
| Nenue@6 | 137     error('arg #2 info must be an associative array') | 
| Nenue@6 | 138   end | 
| Nenue@6 | 139   if type(datafunc) ~= 'function' then | 
| Nenue@6 | 140     error('arg #3 needs a funcref or method name from the frame object') | 
| Nenue@6 | 141   end | 
| Nenue@6 | 142   --]] | 
| Nenue@6 | 143   self.GetRow = funcval(self.GetRow, function() end) | 
| Nenue@6 | 144   self.info = tableval(info, {}) | 
| Nenue@6 | 145   for i, v in ipairs(info) do | 
| Nenue@6 | 146     print('Main', i, '=', v.spellName, v.spellTab) | 
| Nenue@6 | 147     self.max_row = i | 
| Nenue@6 | 148   end | 
| Nenue@6 | 149   print('Main', 'last row #', self.max_row) | 
| Nenue@6 | 150 | 
| Nenue@6 | 151 | 
| Nenue@6 | 152   -- obtain data contents | 
| Nenue@6 | 153   self._dwidth = 0 | 
| Nenue@6 | 154   self.rows = {} | 
| Nenue@6 | 155   self.offset = offset and offset or 1 | 
| Nenue@6 | 156   self.num_rows = (tonumber(num_rows) ~= nil) and num_rows or TK_LIST_DISPLAY_ITEMS | 
| Nenue@6 | 157   self.name:SetHeight(TK_LIST_HEADING_SIZE) | 
| Nenue@6 | 158   TkList_SetView(self, offset) | 
| Nenue@6 | 159 | 
| Nenue@6 | 160   -- sort out the proper width | 
| Nenue@6 | 161   local rwidth = 1 | 
| Nenue@6 | 162   local  k = 0 | 
| Nenue@6 | 163   for n, item in ipairs(self.rows) do | 
| Nenue@6 | 164     print(item:GetName()) | 
| Nenue@6 | 165     if item:IsShown() then | 
| Nenue@6 | 166       if n > 1 then | 
| Nenue@6 | 167         item:SetPoint('TOPLEFT', self.rows[n-1], 'BOTTOMLEFT', 0, - TK_LIST_SPACING) | 
| Nenue@6 | 168       else | 
| Nenue@6 | 169         item:SetPoint('TOPLEFT', self, 'TOPLEFT', TK_LIST_PADDING, -(TK_LIST_PADDING+TK_LIST_HEADING_SIZE+TK_LIST_SPACING)) | 
| Nenue@6 | 170       end | 
| Nenue@6 | 171       k = k+1 | 
| Nenue@6 | 172       self._dwidth = max(self._dwidth, TkListItem_Init(item)) | 
| Nenue@6 | 173     end | 
| Nenue@6 | 174   end | 
| Nenue@6 | 175 | 
| Nenue@6 | 176   TkControls_Init(self) | 
| Nenue@6 | 177 | 
| Nenue@6 | 178   self:SetSize(self._dwidth , (k*TK_LIST_ITEM_HEIGHT)+(TK_LIST_PADDING*2)+(k*TK_LIST_SPACING)+TK_LIST_HEADING_SIZE) | 
| Nenue@6 | 179 end | 
| Nenue@6 | 180 | 
| Nenue@6 | 181 --- Set up for a non-list-style panel, no iterative controls | 
| Nenue@6 | 182 function TkPanel_Init(self) | 
| Nenue@6 | 183   self._dwidth = self:GetWidth() | 
| Nenue@6 | 184   TkControls_Init(self) | 
| Nenue@6 | 185   --self:SetSize(self._dwidth , (k*TK_LIST_ITEM_HEIGHT)+(TK_LIST_PADDING*2)+(k*TK_LIST_SPACING)+TK_LIST_HEADING_SIZE) | 
| Nenue@6 | 186 end |