lotrointerface.com
Search Downloads

LoTROInterface SVN SequenceBars

[/] [trunk/] [Thurallor/] [Common/] [UI/] [TableControl_2/] [TableControl.lua] - Blame information for rev 177

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 176 Thurallor-7095
TableControl = class(Turbine.UI.Control);
2 Thurallor-7095
 
3 Thurallor-7095
-- Add SetRowVisible().
4 Thurallor-7095
-- SetColumnVisible(), add right-click menu to select columns
5 Thurallor-7095
-- Add horizontal / vertical orientation?
6 Thurallor-7095
-- MinimumSize (horizontal) style
7 Thurallor-7095
 
8 177 Thurallor-7095
function TableControl:Constructor(style, options)
9 176 Thurallor-7095
    Turbine.UI.Control.Constructor(self);
10 Thurallor-7095
    self:SetMouseVisible(false);
11 177 Thurallor-7095
 
12 Thurallor-7095
    if (not options) then
13 Thurallor-7095
        options = {};
14 Thurallor-7095
        options.columnLockingEnabled = true;
15 Thurallor-7095
    end
16 176 Thurallor-7095
 
17 Thurallor-7095
    if (not style) then
18 Thurallor-7095
        style = {}
19 Thurallor-7095
        style.horizontalCellSpacing = -1;
20 Thurallor-7095
        style.verticalCellSpacing = -1;
21 Thurallor-7095
        style.minimumColumnWidth = 10;
22 Thurallor-7095
        style.heading = {
23 Thurallor-7095
 
24 Thurallor-7095
            -- Built-in styles (Turbine.UI.Control)
25 Thurallor-7095
            BackColor = Turbine.UI.Color(1, 0, 0.38, .67);
26 Thurallor-7095
            Enabled = true;
27 Thurallor-7095
            Font = Turbine.UI.Lotro.Font.Verdana14;
28 177 Thurallor-7095
            ForeColor = Turbine.UI.Color.White;
29 176 Thurallor-7095
            Height = 24;
30 Thurallor-7095
            Multiline = false;
31 Thurallor-7095
            TextAlignment = Turbine.UI.ContentAlignment.MiddleCenter;
32 Thurallor-7095
            ReadOnly = true;
33 Thurallor-7095
            Selectable = false;
34 Thurallor-7095
            MarkupEnabled = true; -- so we can underline the text when sorting
35 Thurallor-7095
 
36 Thurallor-7095
            -- Special styles (TableControl)
37 Thurallor-7095
            Object = Turbine.UI.Lotro.TextBox; -- what kind of object to create for each heading
38 Thurallor-7095
            HighlightColor = Turbine.UI.Color(1, 0, 0.57, 1);
39 Thurallor-7095
        };
40 Thurallor-7095
        style.column = {
41 Thurallor-7095
            SortMethod = function(a, b)
42 Thurallor-7095
                -- Takes two cells as arguments, returns -1, 0, or 1
43 Thurallor-7095
                local aText, bText = a:GetText(), b:GetText();
44 Thurallor-7095
                if (aText < bText) then
45 Thurallor-7095
                    return -1;
46 Thurallor-7095
                elseif (aText > bText) then
47 Thurallor-7095
                    return 1;
48 Thurallor-7095
                else
49 Thurallor-7095
                    return 0;
50 Thurallor-7095
                end
51 Thurallor-7095
            end
52 Thurallor-7095
        };
53 Thurallor-7095
        style.cell = {
54 Thurallor-7095
 
55 Thurallor-7095
            -- Built-in styles (Turbine.UI.Control)
56 Thurallor-7095
            BackColor = Turbine.UI.Color(1, 0, 0.19, 0.33);
57 Thurallor-7095
            Enabled = true;
58 Thurallor-7095
            Font = Turbine.UI.Lotro.Font.Verdana14;
59 177 Thurallor-7095
            ForeColor = Turbine.UI.Color.Silver;
60 176 Thurallor-7095
            Height = 24;
61 Thurallor-7095
            Multiline = false;
62 Thurallor-7095
            TextAlignment = Turbine.UI.ContentAlignment.MiddleCenter;
63 Thurallor-7095
            ReadOnly = true;
64 Thurallor-7095
 
65 Thurallor-7095
            -- Special styles (TableControl)
66 Thurallor-7095
            Object = Turbine.UI.Lotro.TextBox; -- what kind of object to create for each cell
67 Thurallor-7095
            HighlightColor = Turbine.UI.Color(1, 0, 0.57, 1);
68 Thurallor-7095
        };
69 Thurallor-7095
        style.toolTip = {
70 Thurallor-7095
 
71 Thurallor-7095
            -- Built-in styles (Turbine.UI.Label)
72 Thurallor-7095
            BackColor = Turbine.UI.Color(0.9, 0, 0, 0);
73 Thurallor-7095
            ForeColor = Turbine.UI.Color.White;
74 Thurallor-7095
            Font = Turbine.UI.Lotro.Font.Verdana14;
75 Thurallor-7095
            FontStyle = Turbine.UI.FontStyle.Outline;
76 Thurallor-7095
            OutlineColor = Turbine.UI.Color(0.5, 0, 0, 0);
77 Thurallor-7095
            Height = 14;
78 Thurallor-7095
        };
79 Thurallor-7095
        style.edgeMover = {
80 Thurallor-7095
 
81 Thurallor-7095
            -- Built-in styles (Turbine.UI.Control)
82 Thurallor-7095
            Width = 5;
83 Thurallor-7095
            BackColor = Turbine.UI.Color(0.75, 0, .19, .33);
84 Thurallor-7095
            BackColorBlendMode = Turbine.UI.BlendMode.Overlay;
85 Thurallor-7095
        };
86 Thurallor-7095
        style.marquee = {
87 Thurallor-7095
            Color = Turbine.UI.Color(1, 0, 0.57, 1);
88 Thurallor-7095
            AntsEnabled = true;
89 Thurallor-7095
            Speed = 20; -- updates per second
90 Thurallor-7095
        };
91 Thurallor-7095
    end
92 Thurallor-7095
 
93 Thurallor-7095
    self.rows = Turbine.UI.ListBox();
94 Thurallor-7095
    self.rowsByName = {};
95 Thurallor-7095
    self.rows:SetParent(self);
96 Thurallor-7095
    -- The cell container must be in front of the headings, in case they overlap
97 Thurallor-7095
    -- due to verticalCellSpacing < 0.
98 Thurallor-7095
    self.rows:SetZOrder(1);
99 Thurallor-7095
    self.rows.MouseClick = function()
100 Thurallor-7095
        self:Deselect();
101 Thurallor-7095
    end
102 Thurallor-7095
    self.rows.SelectedIndexChanged = function()
103 Thurallor-7095
        self:_SelectRow(self.rows:GetSelectedItem());
104 Thurallor-7095
    end
105 Thurallor-7095
    self.rowWidth = 0;
106 Thurallor-7095
 
107 Thurallor-7095
    self.vScrollBar = Turbine.UI.Lotro.ScrollBar();
108 Thurallor-7095
    self.vScrollBar:SetOrientation(Turbine.UI.Orientation.Vertical);
109 Thurallor-7095
    self.vScrollBar:SetParent(self);
110 Thurallor-7095
    self.vScrollBar:SetWidth(10);
111 Thurallor-7095
    self.rows:SetVerticalScrollBar(self.vScrollBar);
112 Thurallor-7095
    self.vScrollBar.VisibleChanged = function()
113 Thurallor-7095
        self:SetWidth(self:GetWidth());
114 Thurallor-7095
    end
115 Thurallor-7095
 
116 Thurallor-7095
    self.columns = {};
117 Thurallor-7095
    self.columnsByName = {};
118 Thurallor-7095
    self.totalWeight = 0;
119 Thurallor-7095
    self.edgeMovers = {};
120 Thurallor-7095
 
121 Thurallor-7095
    self:SetStyle(style);
122 177 Thurallor-7095
    self:SetOptions(options);
123 176 Thurallor-7095
 end
124 Thurallor-7095
 
125 Thurallor-7095
function TableControl:SetStyle(style)
126 Thurallor-7095
    self.style = style;
127 Thurallor-7095
    self.rows:SetTop(self.style.heading.Height + self.style.verticalCellSpacing);
128 Thurallor-7095
    if (self.marquee) then
129 Thurallor-7095
        self:_ApplyStyles(self.marquee, style.marquee);
130 Thurallor-7095
    end
131 Thurallor-7095
    -- to do: update other styles
132 Thurallor-7095
end
133 Thurallor-7095
 
134 Thurallor-7095
function TableControl:GetStyle()
135 Thurallor-7095
    return self.style;
136 Thurallor-7095
end
137 Thurallor-7095
 
138 177 Thurallor-7095
function TableControl:SetOptions(options)
139 Thurallor-7095
    self.options = options;
140 Thurallor-7095
    -- to do: apply updated options
141 Thurallor-7095
end
142 Thurallor-7095
 
143 Thurallor-7095
function TableControl:GetOptions()
144 Thurallor-7095
    return self.options;
145 Thurallor-7095
end
146 Thurallor-7095
 
147 176 Thurallor-7095
function TableControl:GetDimensions()
148 Thurallor-7095
    return #self.rows:GetItemCount(), #self.columns;
149 Thurallor-7095
end
150 Thurallor-7095
 
151 Thurallor-7095
function TableControl:AddColumn(name, text, weight, sortMethod, locked)
152 Thurallor-7095
    if (weight == nil) then
153 Thurallor-7095
        weight = 1.0;
154 Thurallor-7095
    end
155 Thurallor-7095
    if (sortMethod == nil) then
156 Thurallor-7095
        sortMethod = self.style.column.SortMethod;
157 Thurallor-7095
    end
158 Thurallor-7095
    if (locked == nil) then
159 Thurallor-7095
        locked = false;
160 Thurallor-7095
    end
161 Thurallor-7095
 
162 Thurallor-7095
    -- Create and initialize new column object
163 Thurallor-7095
    local column = {
164 Thurallor-7095
        name = name;
165 Thurallor-7095
        heading = nil;
166 Thurallor-7095
        weight = 0; -- this gets set below
167 Thurallor-7095
        locked = false; -- this gets set below
168 Thurallor-7095
        sortMethod = sortMethod;
169 Thurallor-7095
    };
170 Thurallor-7095
    table.insert(self.columns, column);
171 Thurallor-7095
    local col = #self.columns;
172 Thurallor-7095
    self.columnsByName[name] = col;
173 Thurallor-7095
 
174 Thurallor-7095
    -- Add a cell to each row and a heading
175 Thurallor-7095
    column.heading = self:_CreateHeading(col, text);
176 Thurallor-7095
    for row = 1, self.rows:GetItemCount() do
177 Thurallor-7095
        self:SetCell(row, col);
178 Thurallor-7095
    end
179 Thurallor-7095
 
180 Thurallor-7095
    -- Add lock icon
181 Thurallor-7095
    column.lockIcon = Turbine.UI.Control();
182 Thurallor-7095
    column.lockIcon:SetParent(column.heading);
183 Thurallor-7095
    column.lockIcon:SetVisible(false);
184 Thurallor-7095
    column.lockIcon:SetBackground(0x41007E30);
185 Thurallor-7095
    column.lockIcon:SetBlendMode(Turbine.UI.BlendMode.AlphaBlend);
186 Thurallor-7095
    column.lockIcon:SetZOrder(1);
187 Thurallor-7095
    Thurallor.UI.Tooltip(L:GetText("/TableControl/HeadingMenu/UnlockColumn")):Attach(column.lockIcon);
188 Thurallor-7095
    column.lockIcon.MouseClick = function(_, args)
189 Thurallor-7095
        if (args.Button == Turbine.UI.MouseButton.Left) then
190 Thurallor-7095
            self:SetColumnLocked(name, false);
191 Thurallor-7095
        end
192 Thurallor-7095
    end
193 Thurallor-7095
--column.lockIcon:SetBackColor(Turbine.UI.Color(0.5, 1, 0, 0));
194 Thurallor-7095
 
195 Thurallor-7095
    -- Add lock mask control
196 Thurallor-7095
    column.lockMask = Turbine.UI.Control();
197 Thurallor-7095
    column.lockMask:SetZOrder(3); -- in front of cells
198 Thurallor-7095
--column.lockMask:SetBackColor(Turbine.UI.Color(0.5, 1, 0, 0));
199 Thurallor-7095
 
200 Thurallor-7095
    self:SetColumnWeight(col, weight); -- also calls _UpdateColumnWidths()
201 Thurallor-7095
    self:SetColumnLocked(name, locked);
202 Thurallor-7095
 
203 Thurallor-7095
    return column;
204 Thurallor-7095
end
205 Thurallor-7095
 
206 Thurallor-7095
function TableControl:_CreateHeading(col, text)
207 Thurallor-7095
    local heading = self.style.heading.Object();
208 Thurallor-7095
    self:_ApplyStyles(heading, self.style.heading);
209 Thurallor-7095
    heading:SetParent(self);
210 Thurallor-7095
    heading:SetText(text);
211 Thurallor-7095
    heading.col = col;
212 Thurallor-7095
 
213 Thurallor-7095
    AddCallback(heading, "MouseEnter", function()
214 Thurallor-7095
        heading.mouseInside = true;
215 Thurallor-7095
        heading:SetBackColor(self.style.heading.HighlightColor);
216 Thurallor-7095
    end);
217 Thurallor-7095
    AddCallback(heading, "MouseLeave", function()
218 Thurallor-7095
        heading.mouseInside = false;
219 Thurallor-7095
        if (not heading.mouseDown) then
220 Thurallor-7095
            heading:SetBackColor(self.style.heading.BackColor);
221 Thurallor-7095
        end
222 Thurallor-7095
    end);
223 Thurallor-7095
    AddCallback(heading, "MouseDown", function(_, args)
224 Thurallor-7095
        if (args.Button == Turbine.UI.MouseButton.Left) then
225 Thurallor-7095
            heading.mouseDown = true;
226 Thurallor-7095
            heading.mouseStartX = Turbine.UI.Display.GetMouseX();
227 Thurallor-7095
            heading.startLeft = heading:GetLeft();
228 Thurallor-7095
        end
229 Thurallor-7095
    end);
230 Thurallor-7095
    AddCallback(heading, "MouseClick", function(_, args)
231 Thurallor-7095
        if (args.Button == Turbine.UI.MouseButton.Left) then
232 Thurallor-7095
            if (heading.mouseMoved) then
233 Thurallor-7095
                heading.mouseMoved = false;
234 Thurallor-7095
            else
235 Thurallor-7095
                self:_SortColumn(heading.col);
236 Thurallor-7095
            end
237 Thurallor-7095
        elseif (args.Button == Turbine.UI.MouseButton.Right) then
238 Thurallor-7095
            self:_ShowHeadingMenu(heading.col);
239 Thurallor-7095
        end
240 Thurallor-7095
    end);
241 Thurallor-7095
    AddCallback(heading, "MouseMove", function(_, args)
242 Thurallor-7095
        if (heading.mouseDown) then
243 Thurallor-7095
            heading.mouseMoved = true;
244 Thurallor-7095
            heading:SetZOrder(1);
245 Thurallor-7095
            local deltaX = Turbine.UI.Display.GetMouseX() - heading.mouseStartX;
246 Thurallor-7095
            local left = math.min(math.max(0, heading.startLeft + deltaX), self.rowWidth - heading:GetWidth());
247 Thurallor-7095
            heading:SetLeft(left);
248 Thurallor-7095
            deltaX = left - heading.startLeft;
249 Thurallor-7095
            self:_ColumnDragged(heading.col, deltaX);
250 Thurallor-7095
        end
251 Thurallor-7095
    end);
252 Thurallor-7095
    AddCallback(heading, "MouseUp", function(_, args)
253 Thurallor-7095
        if (args.Button == Turbine.UI.MouseButton.Left) then
254 Thurallor-7095
            heading.mouseDown = false;
255 Thurallor-7095
            if (heading.mouseMoved) then
256 Thurallor-7095
                heading:SetZOrder(0);
257 Thurallor-7095
                self:_UpdateColumnWidths();
258 Thurallor-7095
            end
259 Thurallor-7095
            if (not heading.mouseInside) then
260 Thurallor-7095
                heading:SetBackColor(self.style.heading.BackColor);
261 Thurallor-7095
            end
262 Thurallor-7095
        end
263 Thurallor-7095
    end);
264 177 Thurallor-7095
    if (self.columns[col].sortMethod) then
265 Thurallor-7095
        Thurallor.UI.Tooltip(function() return L:GetText("/TableControl/HeadingMenu/SortColumn") end):Attach(heading);
266 Thurallor-7095
    end
267 176 Thurallor-7095
 
268 Thurallor-7095
    return heading;
269 Thurallor-7095
end
270 Thurallor-7095
 
271 Thurallor-7095
function TableControl:_ColumnDragged(col, deltaX)
272 Thurallor-7095
    local heading = self.columns[col].heading;
273 Thurallor-7095
    local leftEdge = heading:GetLeft();
274 Thurallor-7095
    local rightEdge = leftEdge + heading:GetWidth();
275 Thurallor-7095
 
276 Thurallor-7095
    local swapped = false;
277 Thurallor-7095
    if (deltaX < 0) then
278 Thurallor-7095
        -- Find visible column to the left, if any
279 Thurallor-7095
        for c = col - 1, 1, -1 do
280 Thurallor-7095
            local other = self.columns[c];
281 Thurallor-7095
            if (other.weight > 0) then
282 Thurallor-7095
                local center = other.heading:GetLeft() + math.floor(0.5 + (other.heading:GetWidth() / 2));
283 Thurallor-7095
                if (leftEdge < center) then
284 Thurallor-7095
--Puts("deltaX = " .. deltaX .. "; halfWidth = " .. halfWidth .. "; hw = " .. hw);
285 Thurallor-7095
--Puts("swapping left: " .. col .. ", " .. c);
286 Thurallor-7095
                    self:_SwapColumns(col, c);
287 Thurallor-7095
                    swapped = true;
288 Thurallor-7095
                    break;
289 Thurallor-7095
                end
290 Thurallor-7095
            end
291 Thurallor-7095
        end
292 Thurallor-7095
    else
293 Thurallor-7095
        -- Find visible column to the right, if any
294 Thurallor-7095
        for c = col + 1, #self.columns do
295 Thurallor-7095
            local other = self.columns[c];
296 Thurallor-7095
            if (other.weight > 0) then
297 Thurallor-7095
                local center = other.heading:GetLeft() + math.floor(0.5 + (other.heading:GetWidth() / 2));
298 Thurallor-7095
                if (rightEdge > center) then
299 Thurallor-7095
--Puts("deltaX = " .. deltaX .. "; halfWidth = " .. halfWidth .. "; hw = " .. hw);
300 Thurallor-7095
--Puts("swapping right: " .. col .. ", " .. c);
301 Thurallor-7095
                    self:_SwapColumns(col, c);
302 Thurallor-7095
                    swapped = true;
303 Thurallor-7095
                    break;
304 Thurallor-7095
                end
305 Thurallor-7095
            end
306 Thurallor-7095
        end
307 Thurallor-7095
    end
308 Thurallor-7095
 
309 Thurallor-7095
--Puts("before: " .. heading:GetLeft());
310 Thurallor-7095
    heading.startLeft = heading:GetLeft();
311 Thurallor-7095
    heading:SetLeft(leftEdge);
312 Thurallor-7095
    deltaX = leftEdge - heading.startLeft;
313 Thurallor-7095
    heading.mouseStartX = Turbine.UI.Display:GetMouseX() - deltaX;
314 Thurallor-7095
--Puts("after: " .. heading:GetLeft());
315 Thurallor-7095
end
316 Thurallor-7095
 
317 Thurallor-7095
function TableControl:_SwapColumns(a, b)
318 Thurallor-7095
    local temp = self.columns[a];
319 Thurallor-7095
    self.columns[a] = self.columns[b];
320 Thurallor-7095
    self.columns[b] = temp;
321 Thurallor-7095
 
322 Thurallor-7095
    self.columns[a].heading.col = a;
323 Thurallor-7095
    self.columns[b].heading.col = b;
324 Thurallor-7095
    self.columnsByName[self.columns[a].name] = a;
325 Thurallor-7095
    self.columnsByName[self.columns[b].name] = b;
326 Thurallor-7095
 
327 Thurallor-7095
    for row = 1, self.rows:GetItemCount() do
328 Thurallor-7095
        local cells = self.rows:GetItem(row).cells;
329 Thurallor-7095
        temp = cells[a];
330 Thurallor-7095
        cells[a] = cells[b];
331 Thurallor-7095
        cells[b] = temp;
332 Thurallor-7095
    end
333 Thurallor-7095
 
334 Thurallor-7095
    -- If one of the swapped columns is sorted, update the lastSort data structure
335 Thurallor-7095
    if (self.lastSort) then
336 Thurallor-7095
        if (self.lastSort.col == a) then
337 Thurallor-7095
            self.lastSort.col = b;
338 Thurallor-7095
            self.lastSort.compare = self:_GetCompareFunction(b);
339 Thurallor-7095
        elseif (self.lastSort.col == b) then
340 Thurallor-7095
            self.lastSort.col = a;
341 Thurallor-7095
            self.lastSort.compare = self:_GetCompareFunction(a);
342 Thurallor-7095
        end
343 Thurallor-7095
    end
344 Thurallor-7095
 
345 Thurallor-7095
    self:_UpdateColumnWidths();
346 Thurallor-7095
    self:_DoCallbacks("PresentationChanged", { Desc = "Columns swapped positions" });
347 Thurallor-7095
end
348 Thurallor-7095
 
349 Thurallor-7095
function TableControl:_ShowHeadingMenu(col)
350 Thurallor-7095
    local column = self.columns[col];
351 Thurallor-7095
    local contextMenu = Turbine.UI.ContextMenu();
352 Thurallor-7095
    local menuItems = contextMenu:GetItems();
353 Thurallor-7095
    local prevContext = L:SetContext("/TableControl/HeadingMenu");
354 Thurallor-7095
 
355 Thurallor-7095
    if (self.totalWeight > column.weight) then
356 Thurallor-7095
        local hideItem = Turbine.UI.MenuItem(L:GetText("HideColumn"));
357 Thurallor-7095
        hideItem.Click = function()
358 Thurallor-7095
            self:SetColumnWeight(col, 0);
359 Thurallor-7095
        end
360 Thurallor-7095
        menuItems:Add(hideItem);
361 Thurallor-7095
    end
362 Thurallor-7095
 
363 Thurallor-7095
    if (#self.columns > 1) then
364 Thurallor-7095
        local showItem = Turbine.UI.MenuItem(L:GetText("ShowColumns"));
365 Thurallor-7095
        local colItems = showItem:GetItems();
366 Thurallor-7095
        for c = 1, #self.columns do
367 Thurallor-7095
            local other = self.columns[c];
368 Thurallor-7095
            local name = other.heading:GetText();
369 Thurallor-7095
            local item = Turbine.UI.MenuItem(name, true, true);
370 Thurallor-7095
            if (other.weight > 0) then
371 Thurallor-7095
                item.Click = function()
372 Thurallor-7095
                    self:SetColumnWeight(c, 0);
373 Thurallor-7095
                end
374 Thurallor-7095
            else
375 Thurallor-7095
                item:SetChecked(false);
376 Thurallor-7095
                item.Click = function()
377 Thurallor-7095
                    self:SetColumnWeight(c, 1);
378 Thurallor-7095
                end
379 Thurallor-7095
            end
380 Thurallor-7095
            colItems:Add(item);
381 Thurallor-7095
        end
382 Thurallor-7095
        menuItems:Add(showItem);
383 Thurallor-7095
    end
384 Thurallor-7095
 
385 Thurallor-7095
    if (column.sortMethod) then
386 Thurallor-7095
        local sortItem = Turbine.UI.MenuItem(L:GetText("SortColumn"));
387 Thurallor-7095
        sortItem.Click = function()
388 Thurallor-7095
            self:_SortColumn(col);
389 Thurallor-7095
        end
390 Thurallor-7095
        menuItems:Add(sortItem);
391 Thurallor-7095
    end
392 Thurallor-7095
 
393 177 Thurallor-7095
    if (self.options.columnLockingEnabled) then
394 Thurallor-7095
        local lockItem = Turbine.UI.MenuItem(L:GetText("LockColumn"), true, column.locked);
395 Thurallor-7095
        lockItem.Click = function()
396 Thurallor-7095
            self:SetColumnLocked(column.name, not column.locked);
397 Thurallor-7095
        end
398 Thurallor-7095
        menuItems:Add(lockItem);
399 176 Thurallor-7095
    end
400 Thurallor-7095
 
401 Thurallor-7095
    contextMenu:ShowMenu();
402 Thurallor-7095
    L:SetContext(prevContext);
403 Thurallor-7095
end
404 Thurallor-7095
 
405 Thurallor-7095
function TableControl:SortColumn(name, dir)
406 Thurallor-7095
    local col = self.columnsByName[name];
407 Thurallor-7095
    local column = self.columns[col];
408 Thurallor-7095
    column.sortDirection = not dir;
409 Thurallor-7095
    self:_SortColumn(col);
410 Thurallor-7095
end
411 Thurallor-7095
 
412 Thurallor-7095
function TableControl:_SortColumn(col)
413 Thurallor-7095
    local column = self.columns[col];
414 Thurallor-7095
    if (not column.sortMethod) then
415 Thurallor-7095
        return;
416 Thurallor-7095
    end
417 Thurallor-7095
 
418 Thurallor-7095
    -- Show sort indication icon
419 Thurallor-7095
    if (not self.sortIcon) then
420 Thurallor-7095
        self.sortIcon = Turbine.UI.Control();
421 Thurallor-7095
        self.sortIcon:SetMouseVisible(false);
422 Thurallor-7095
        self.sortIcon:SetSize(10, 10);
423 Thurallor-7095
        self.sortIcon:SetBlendMode(Turbine.UI.BlendMode.Overlay);
424 Thurallor-7095
    end;
425 Thurallor-7095
    self.sortIcon:SetParent(column.heading);
426 Thurallor-7095
    self.sortIcon:SetZOrder(1);
427 Thurallor-7095
    local inset = math.floor(0.5 + (column.heading:GetHeight() - 10) / 2);
428 Thurallor-7095
    self.sortIcon:SetPosition(inset, inset);
429 Thurallor-7095
    if (column.sortDirection) then
430 Thurallor-7095
        self.sortIcon:SetBackground(0x4100028E); -- â–¼
431 Thurallor-7095
    else
432 Thurallor-7095
        self.sortIcon:SetBackground(0x4100028C); -- â–²
433 Thurallor-7095
    end
434 Thurallor-7095
 
435 Thurallor-7095
    -- Toggle between ascending/descending when creating the sort function
436 Thurallor-7095
    column.sortDirection = not column.sortDirection;
437 Thurallor-7095
    local compare = self:_GetCompareFunction(col);
438 Thurallor-7095
    self.lastSort = { col = col; compare = compare };
439 Thurallor-7095
    self:_ReSort();
440 Thurallor-7095
 
441 Thurallor-7095
    self:_DoCallbacks("PresentationChanged", { Desc = "Column sort changed" });
442 Thurallor-7095
end
443 Thurallor-7095
 
444 Thurallor-7095
function TableControl:_GetCompareFunction(col)
445 Thurallor-7095
    local column = self.columns[col];
446 Thurallor-7095
    if (column.sortDirection) then
447 Thurallor-7095
        return function(a, b)
448 Thurallor-7095
            -- Takes rowContainers as args, returns true or false
449 Thurallor-7095
            local sortResult = column.sortMethod(a.cells[col], b.cells[col]);
450 Thurallor-7095
            if (sortResult == 0) then
451 Thurallor-7095
                -- Make the sorting "stable" to allow sorting by multiple columns in sequence
452 Thurallor-7095
                return a.idx > b.idx;
453 Thurallor-7095
            else
454 Thurallor-7095
                return (sortResult > 0);
455 Thurallor-7095
            end
456 Thurallor-7095
        end
457 Thurallor-7095
    else
458 Thurallor-7095
        return function(a, b)
459 Thurallor-7095
            -- Takes rowContainers as args, returns true or false
460 Thurallor-7095
            local sortResult = column.sortMethod(b.cells[col], a.cells[col]);
461 Thurallor-7095
            if (sortResult == 0) then
462 Thurallor-7095
                -- Make the sorting "stable" to allow sorting by multiple columns in sequence
463 Thurallor-7095
                return a.idx > b.idx;
464 Thurallor-7095
            else
465 Thurallor-7095
                return (sortResult > 0);
466 Thurallor-7095
            end
467 Thurallor-7095
        end
468 Thurallor-7095
    end
469 Thurallor-7095
end
470 Thurallor-7095
 
471 Thurallor-7095
function TableControl:_CreateCell(row, col)
472 Thurallor-7095
    local rowContainer = self.rows:GetItem(row);
473 Thurallor-7095
    local cell = self.style.cell.Object();
474 Thurallor-7095
    self:_ApplyStyles(cell, self.style.cell);
475 Thurallor-7095
    return cell;
476 Thurallor-7095
end
477 Thurallor-7095
 
478 Thurallor-7095
function TableControl:_CreateEdgeMovers()
479 Thurallor-7095
    -- Destroy previous objects
480 Thurallor-7095
    for edge = 1, #self.edgeMovers do
481 Thurallor-7095
        self.edgeMovers[edge]:SetParent(nil);
482 Thurallor-7095
    end
483 Thurallor-7095
    self.edgeMovers = {};
484 Thurallor-7095
 
485 Thurallor-7095
    -- Only show an EdgeMover between two visible (weight > 0) columns.
486 Thurallor-7095
    local prev = nil;
487 Thurallor-7095
    for col = 1, #self.columns do
488 Thurallor-7095
        if (self.columns[col].weight > 0) then
489 Thurallor-7095
            if (prev) then
490 Thurallor-7095
                -- Found a pair of visible columns.
491 Thurallor-7095
                local edgeMover = Thurallor.UI.EdgeMover(Turbine.UI.Orientation.Vertical);
492 Thurallor-7095
                edgeMover.leftColumn = prev;
493 Thurallor-7095
                edgeMover.rightColumn = col;
494 Thurallor-7095
                edgeMover:SetParent(self);
495 Thurallor-7095
                edgeMover:SetZOrder(1); -- in front of rows
496 Thurallor-7095
                self:_ApplyStyles(edgeMover, self.style.edgeMover);
497 Thurallor-7095
                AddCallback(edgeMover, "EdgeMoved", function()
498 Thurallor-7095
                    self:_EdgeMoved(edgeMover);
499 Thurallor-7095
                end);
500 Thurallor-7095
                AddCallback(edgeMover, "MouseUp", function()
501 Thurallor-7095
                    -- EdgeMover may set a column weight to zero; if so, disable the column's EdgeMover.
502 Thurallor-7095
                    self:_CreateEdgeMovers();
503 Thurallor-7095
                end);
504 Thurallor-7095
                table.insert(self.edgeMovers, edgeMover);
505 Thurallor-7095
            end
506 Thurallor-7095
            prev = col;
507 Thurallor-7095
        end
508 Thurallor-7095
    end
509 Thurallor-7095
    self:_PlaceEdgeMovers();
510 Thurallor-7095
    self:_DoCallbacks("PresentationChanged", { Desc = "Column weight(s) changed" });
511 Thurallor-7095
end
512 Thurallor-7095
 
513 Thurallor-7095
function TableControl:_EdgeMoved(edgeMover)
514 Thurallor-7095
    local x, y = self:GetMousePosition();
515 Thurallor-7095
    local minWidth = self.style.minimumColumnWidth;
516 Thurallor-7095
 
517 Thurallor-7095
    local leftCol = self.columns[edgeMover.leftColumn];
518 Thurallor-7095
    local leftHeading = leftCol.heading;
519 Thurallor-7095
    x = math.max(x, leftHeading:GetLeft() + minWidth);
520 Thurallor-7095
 
521 Thurallor-7095
    local rightCol = self.columns[edgeMover.rightColumn];
522 Thurallor-7095
    local rightHeading = rightCol.heading;
523 Thurallor-7095
    x = math.min(x, rightHeading:GetLeft() + rightHeading:GetWidth() - minWidth);
524 Thurallor-7095
 
525 Thurallor-7095
    local leftWidth = x - leftHeading:GetLeft();
526 Thurallor-7095
    local rightWidth = rightHeading:GetLeft() + rightHeading:GetWidth() - x;
527 Thurallor-7095
    local bothWidth = leftWidth + rightWidth;
528 Thurallor-7095
    local bothWeight = leftCol.weight + rightCol.weight;
529 Thurallor-7095
 
530 Thurallor-7095
    leftCol.weight = bothWeight * (leftWidth / bothWidth);
531 Thurallor-7095
    rightCol.weight = bothWeight * (rightWidth / bothWidth);
532 Thurallor-7095
 
533 Thurallor-7095
    self:_UpdateColumnWidths();
534 Thurallor-7095
end
535 Thurallor-7095
 
536 Thurallor-7095
function TableControl:_DoCallbacks(event, args)
537 Thurallor-7095
    if (not self.callbacksDisabled) then
538 Thurallor-7095
        DoCallbacks(self, event, args);
539 Thurallor-7095
    end
540 Thurallor-7095
end
541 Thurallor-7095
 
542 Thurallor-7095
function TableControl:GetColumnWeight(colName)
543 Thurallor-7095
    local col = self.columnsByName[colName];
544 Thurallor-7095
    if (not col) then
545 Thurallor-7095
        error("no such column: " .. colName, 2);
546 Thurallor-7095
    end
547 Thurallor-7095
    local column = self.columns[col];
548 Thurallor-7095
    return column.weight;
549 Thurallor-7095
end
550 Thurallor-7095
 
551 Thurallor-7095
function TableControl:SetColumnWeight(col, weight)
552 Thurallor-7095
    local column = self.columns[col];
553 Thurallor-7095
    local prevWeight = column.weight;
554 Thurallor-7095
    self.totalWeight = self.totalWeight - prevWeight + weight;
555 Thurallor-7095
    column.weight = weight;
556 Thurallor-7095
    if ((weight == 0) and (prevWeight > 0)) then
557 Thurallor-7095
        column.heading:SetParent(nil);
558 Thurallor-7095
        for row = 1, self.rows:GetItemCount() do
559 Thurallor-7095
            local rowContainer = self.rows:GetItem(row);
560 Thurallor-7095
            rowContainer.cells[col]:SetParent(nil);
561 Thurallor-7095
        end
562 Thurallor-7095
        self:_CreateEdgeMovers();
563 Thurallor-7095
    elseif ((weight > 0) and (prevWeight == 0)) then
564 Thurallor-7095
        column.heading:SetParent(self);
565 Thurallor-7095
        for row = 1, self.rows:GetItemCount() do
566 Thurallor-7095
            local rowContainer = self.rows:GetItem(row);
567 Thurallor-7095
            rowContainer.cells[col]:SetParent(rowContainer);
568 Thurallor-7095
        end
569 Thurallor-7095
        self:_CreateEdgeMovers();
570 Thurallor-7095
    end
571 Thurallor-7095
    self:_UpdateColumnWidths();
572 Thurallor-7095
    column.prevWeight = prevWeight;
573 Thurallor-7095
end
574 Thurallor-7095
 
575 Thurallor-7095
-- "Presentation" includes (so far)
576 Thurallor-7095
--   - the user's choices of column weights, visibility and ordering
577 Thurallor-7095
--   - the sorted column and direction
578 Thurallor-7095
function TableControl:GetPresentation()
579 Thurallor-7095
    local columns = {};
580 Thurallor-7095
    for col = 1, #self.columns do
581 Thurallor-7095
        local column = self.columns[col];
582 Thurallor-7095
        table.insert(columns, { column.name, column.weight, column.locked });
583 Thurallor-7095
    end
584 Thurallor-7095
 
585 Thurallor-7095
    local presentation = {};
586 Thurallor-7095
    presentation.columns = columns;
587 Thurallor-7095
    if (self.lastSort) then
588 Thurallor-7095
        local column = self.columns[self.lastSort.col];
589 Thurallor-7095
        presentation.sort = { column = column.name; dir = column.sortDirection };
590 Thurallor-7095
    end
591 Thurallor-7095
 
592 Thurallor-7095
    return presentation;
593 Thurallor-7095
end
594 Thurallor-7095
 
595 Thurallor-7095
function TableControl:SetPresentation(presentation)
596 Thurallor-7095
 
597 Thurallor-7095
    -- Make a local copy of presentation, so we can modify it.  Remove any columns
598 Thurallor-7095
    -- from it that don't exist in the table.
599 Thurallor-7095
    local temp = {};
600 Thurallor-7095
    for n, colInfo in ipairs(presentation.columns) do
601 Thurallor-7095
        local name, weight, locked = unpack(colInfo);
602 Thurallor-7095
        if (self.columnsByName[name]) then
603 Thurallor-7095
            table.insert(temp, { name, weight, locked });
604 Thurallor-7095
        end
605 Thurallor-7095
    end
606 Thurallor-7095
    presentation.columns = temp;
607 Thurallor-7095
 
608 Thurallor-7095
    -- Get column weights from presentation
609 Thurallor-7095
    local foundColumns = {};
610 Thurallor-7095
    for col = 1, #presentation.columns do
611 Thurallor-7095
        local name, weight = unpack(presentation.columns[col]);
612 Thurallor-7095
        foundColumns[name] = weight;
613 Thurallor-7095
    end
614 Thurallor-7095
 
615 Thurallor-7095
    -- Handle columns that aren't specified in the presentation
616 Thurallor-7095
    --   Set their weight to 0.
617 Thurallor-7095
    for name, col in pairs(self.columnsByName) do
618 Thurallor-7095
        if (foundColumns[name] == nil) then
619 Thurallor-7095
            foundColumns[name] = true;
620 Thurallor-7095
            table.insert(presentation.columns, { name, 0 });
621 Thurallor-7095
        end
622 Thurallor-7095
    end
623 Thurallor-7095
 
624 Thurallor-7095
    -- Create a new cell list in each rowContainer
625 Thurallor-7095
    for row = 1, self.rows:GetItemCount() do
626 Thurallor-7095
        self.rows:GetItem(row).newCells = {};
627 Thurallor-7095
    end
628 Thurallor-7095
 
629 Thurallor-7095
    -- Apply the new ordering and weights (and locks) to the columns
630 Thurallor-7095
    local oldColumns = self.columns;
631 Thurallor-7095
    self.columns = {};
632 Thurallor-7095
    self.totalWeight = 0;
633 Thurallor-7095
    for col = 1, #presentation.columns do
634 Thurallor-7095
        local name, weight, locked = unpack(presentation.columns[col]);
635 Thurallor-7095
        local oldCol = self.columnsByName[name];
636 Thurallor-7095
        local column = oldColumns[oldCol];
637 Thurallor-7095
        self.totalWeight = self.totalWeight + weight;
638 Thurallor-7095
        column.weight = weight;
639 Thurallor-7095
        if (locked ~= nil) then
640 Thurallor-7095
            column.locked = locked;
641 Thurallor-7095
        end
642 Thurallor-7095
        column.heading.col = col;
643 Thurallor-7095
        column.heading:SetParent((weight > 0) and self or nil);
644 Thurallor-7095
        self.columnsByName[name] = col;
645 Thurallor-7095
        table.insert(self.columns, column);
646 Thurallor-7095
        for row = 1, self.rows:GetItemCount() do
647 Thurallor-7095
            local rowContainer = self.rows:GetItem(row);
648 Thurallor-7095
            local cell = rowContainer.cells[oldCol];
649 Thurallor-7095
            rowContainer.newCells[col] = cell;
650 Thurallor-7095
            cell:SetParent((weight > 0) and rowContainer or nil);
651 Thurallor-7095
        end
652 Thurallor-7095
    end
653 Thurallor-7095
 
654 Thurallor-7095
    -- Start using the new cell list in each rowContainer
655 Thurallor-7095
    for row = 1, self.rows:GetItemCount() do
656 Thurallor-7095
        local rowContainer = self.rows:GetItem(row);
657 Thurallor-7095
        rowContainer.cells = rowContainer.newCells;
658 Thurallor-7095
        rowContainer.newCells = {};
659 Thurallor-7095
    end
660 Thurallor-7095
 
661 Thurallor-7095
    -- Move the cells into their new positions
662 Thurallor-7095
    self:_CreateEdgeMovers();
663 Thurallor-7095
    self:_UpdateColumnWidths();
664 Thurallor-7095
 
665 Thurallor-7095
    -- Apply the sort (if any)
666 Thurallor-7095
    if (presentation.sort) then
667 Thurallor-7095
        local col = self.columnsByName[presentation.sort.column];
668 Thurallor-7095
        local column = self.columns[col];
669 Thurallor-7095
        if (column) then
670 Thurallor-7095
        column.sortDirection = not presentation.sort.dir;
671 Thurallor-7095
        self:_SortColumn(col);
672 Thurallor-7095
        end
673 Thurallor-7095
    end
674 Thurallor-7095
 
675 Thurallor-7095
    -- Apply the locks
676 Thurallor-7095
    for col = 1, #self.columns do
677 Thurallor-7095
        local column = self.columns[col];
678 Thurallor-7095
        self:SetColumnLocked(column.name, column.locked);
679 Thurallor-7095
    end
680 Thurallor-7095
end
681 Thurallor-7095
 
682 Thurallor-7095
function TableControl:GetRow(name)
683 Thurallor-7095
    return self.rowsByName[name];
684 Thurallor-7095
end
685 Thurallor-7095
 
686 Thurallor-7095
function TableControl:_GetToolTip(rowContainer)
687 Thurallor-7095
    local function AddLabel(parent, top, prevMaxWidth, text, align)
688 Thurallor-7095
        local label = Turbine.UI.Label();
689 Thurallor-7095
        label:SetTextAlignment(align);
690 Thurallor-7095
        self:_ApplyStyles(label, self.style.toolTip);
691 Thurallor-7095
        label:SetBackColor(nil);
692 Thurallor-7095
        label:SetText(text);
693 Thurallor-7095
        label:AutoSize();
694 Thurallor-7095
        label:SetParent(parent);
695 Thurallor-7095
        label:SetTop(top);
696 Thurallor-7095
        AddCallback(parent, "SizeChanged", function() label:SetWidth(parent:GetWidth()) end);
697 Thurallor-7095
        return top + label:GetHeight(), math.max(prevMaxWidth, label:GetWidth());
698 Thurallor-7095
    end
699 Thurallor-7095
 
700 Thurallor-7095
    local toolTip = Turbine.UI.Control();
701 Thurallor-7095
    local colNames = Turbine.UI.Control();
702 Thurallor-7095
    local cellValues = Turbine.UI.Control();
703 Thurallor-7095
    colNames:SetParent(toolTip);
704 Thurallor-7095
    cellValues:SetParent(toolTip);
705 Thurallor-7095
 
706 Thurallor-7095
    local colNamesWidth = 0;
707 Thurallor-7095
    local cellValuesWidth = 0;
708 Thurallor-7095
    local top = 0;
709 Thurallor-7095
    for c = 1, #self.columns do
710 Thurallor-7095
        local column = self.columns[c];
711 Thurallor-7095
        local colName = column.heading:GetText() .. ": ";
712 Thurallor-7095
        local cell = rowContainer.cells[c];
713 Thurallor-7095
        local cellValue = (cell.GetText and cell:GetText() and (cell:GetText() ~= "") and tostring(cell:GetText()));
714 Thurallor-7095
        if (cellValue) then
715 Thurallor-7095
            _, colNamesWidth = AddLabel(colNames, top, colNamesWidth, colName, Turbine.UI.ContentAlignment.MiddleRight);
716 Thurallor-7095
            top, cellValuesWidth = AddLabel(cellValues, top, cellValuesWidth, cellValue, Turbine.UI.ContentAlignment.MiddleLeft);
717 Thurallor-7095
        end
718 Thurallor-7095
    end
719 Thurallor-7095
 
720 Thurallor-7095
    colNames:SetSize(colNamesWidth, top);
721 Thurallor-7095
    colNames:SetPosition(0, 3);
722 Thurallor-7095
    cellValues:SetSize(cellValuesWidth, top);
723 Thurallor-7095
    cellValues:SetPosition(colNamesWidth, 3);
724 Thurallor-7095
    self:_ApplyStyles(toolTip, self.style.toolTip);
725 Thurallor-7095
    toolTip:SetSize(colNamesWidth + cellValuesWidth, top + 6);
726 Thurallor-7095
 
727 Thurallor-7095
    return toolTip;
728 Thurallor-7095
end
729 Thurallor-7095
 
730 Thurallor-7095
function TableControl:AddRow(name, moreRows)
731 Thurallor-7095
    local rowContainer = Turbine.UI.Control();
732 Thurallor-7095
    rowContainer.idx = math.huge;
733 Thurallor-7095
    rowContainer:SetWidth(self.rowWidth);
734 Thurallor-7095
    rowContainer.name = name;
735 Thurallor-7095
    rowContainer.cells = {};
736 Thurallor-7095
    self.rows:AddItem(rowContainer);
737 Thurallor-7095
    self.rowsByName[name] = rowContainer;
738 Thurallor-7095
    local row = self.rows:GetItemCount();
739 Thurallor-7095
 
740 Thurallor-7095
    -- Add new cells
741 Thurallor-7095
    self:SetRowVisible(row, false);
742 Thurallor-7095
    for col = 1, #self.columns do
743 Thurallor-7095
        self:SetCell(row, col);
744 Thurallor-7095
    end
745 177 Thurallor-7095
 
746 176 Thurallor-7095
    -- Add mask overlay.  We want the user to have to select the row before clicking again
747 Thurallor-7095
    -- on a particular cell to edit it.
748 Thurallor-7095
    local mask = Turbine.UI.Control();
749 Thurallor-7095
    mask:SetParent(rowContainer);
750 Thurallor-7095
    mask:SetSize(rowContainer:GetSize());
751 Thurallor-7095
--mask:SetBackColor(Turbine.UI.Color(0.25, 1, 0, 0));
752 Thurallor-7095
--mask:SetBackColorBlendMode(Turbine.UI.BlendMode.Overlay);
753 Thurallor-7095
    mask:SetZOrder(3); -- in front of cells
754 Thurallor-7095
    rowContainer.mask = mask;
755 Thurallor-7095
 
756 Thurallor-7095
    -- Add event behaviors
757 Thurallor-7095
    rowContainer.PositionChanged = function(ctl)
758 Thurallor-7095
        if ((self.selectedRow == ctl) and self.marquee) then
759 Thurallor-7095
            self.marquee:SetPosition(ctl:GetPosition());
760 Thurallor-7095
        end
761 Thurallor-7095
    end
762 Thurallor-7095
    rowContainer.SizeChanged = function(ctl)
763 Thurallor-7095
        ctl.mask:SetSize(ctl:GetSize());
764 Thurallor-7095
        if ((self.selectedRow == ctl) and self.marquee) then
765 Thurallor-7095
            self.marquee:SetSize(ctl:GetSize());
766 Thurallor-7095
        end
767 Thurallor-7095
    end
768 Thurallor-7095
    mask.MouseEnter = function()
769 Thurallor-7095
        for c = 1, #self.columns do
770 Thurallor-7095
            rowContainer.cells[c]:SetBackColor(self.style.cell.HighlightColor);
771 Thurallor-7095
        end
772 Thurallor-7095
    end
773 Thurallor-7095
    mask.MouseLeave = function()
774 Thurallor-7095
        for c = 1, #self.columns do
775 Thurallor-7095
            rowContainer.cells[c]:SetBackColor(self.style.cell.BackColor);
776 Thurallor-7095
        end
777 Thurallor-7095
    end
778 Thurallor-7095
    mask.MouseClick = function(_, args)
779 Thurallor-7095
        if (args.Button == Turbine.UI.MouseButton.Right) then
780 Thurallor-7095
            DoCallbacks(rowContainer, "ContextMenu");
781 Thurallor-7095
        elseif (args.Button == Turbine.UI.MouseButton.Left) then
782 Thurallor-7095
            -- The ListBox control didn't steal the left-mouse click, because the
783 Thurallor-7095
            -- user clicked the already-selected item.  *facepalm*
784 Thurallor-7095
            DoCallbacks(self.rows, "SelectedIndexChanged");
785 Thurallor-7095
        end
786 Thurallor-7095
    end
787 Thurallor-7095
    Thurallor.UI.Tooltip(function() return self:_GetToolTip(rowContainer) end):Attach(mask);
788 Thurallor-7095
 
789 Thurallor-7095
    self:_UpdateLastRow(); -- also calls SetRowVisible(row, true)
790 Thurallor-7095
 
791 Thurallor-7095
    -- Table needs to be resorted, if enabled
792 Thurallor-7095
    if ((not moreRows) and self.lastSort) then
793 Thurallor-7095
        self:ReSort();
794 Thurallor-7095
-- if not auto-sorting, then hide the sort icon
795 Thurallor-7095
    end
796 Thurallor-7095
 
797 Thurallor-7095
    -- Return a table of cells indexed by column name
798 Thurallor-7095
    local cells = {};
799 Thurallor-7095
    for c = 1, #self.columns do
800 Thurallor-7095
        local colName = self.columns[c].name;
801 Thurallor-7095
        cells[colName] = rowContainer.cells[c];
802 Thurallor-7095
    end
803 177 Thurallor-7095
 
804 Thurallor-7095
    return rowContainer, cells, row;
805 176 Thurallor-7095
end
806 Thurallor-7095
 
807 Thurallor-7095
function TableControl:ReSort(now)
808 Thurallor-7095
    if (self.lastSort) then
809 Thurallor-7095
        self.lastSort.sorted = false;
810 Thurallor-7095
        if (now) then
811 Thurallor-7095
            self:_ReSort();
812 Thurallor-7095
        else
813 Thurallor-7095
            self:SetWantsUpdates(true);
814 Thurallor-7095
        end
815 Thurallor-7095
    end
816 Thurallor-7095
end
817 Thurallor-7095
 
818 Thurallor-7095
function TableControl:Update()
819 Thurallor-7095
    self:_ReSort();
820 Thurallor-7095
    self:SetWantsUpdates(false);
821 Thurallor-7095
end
822 Thurallor-7095
 
823 Thurallor-7095
-- Reapply the most recent sort
824 Thurallor-7095
function TableControl:_ReSort()
825 Thurallor-7095
    if (self.lastSort) then
826 Thurallor-7095
        local rows = self.rows;
827 Thurallor-7095
        rows:Sort(self.lastSort.compare);
828 Thurallor-7095
        for idx = 1, rows:GetItemCount() do
829 Thurallor-7095
            local row = rows:GetItem(idx);
830 Thurallor-7095
            row.idx = idx;
831 Thurallor-7095
        end
832 Thurallor-7095
        self.lastSort.sorted = true;
833 Thurallor-7095
        self:_UpdateLastRow();
834 Thurallor-7095
    end
835 Thurallor-7095
end
836 Thurallor-7095
 
837 Thurallor-7095
-- Can specify colName or nil; returns column name of sorted column or nil
838 Thurallor-7095
function TableControl:IsSorted(colName)
839 Thurallor-7095
    if ((self.lastSort) and (self.lastSort.sorted)) then
840 Thurallor-7095
        local sortedCol = self.columns[self.lastSort.col];
841 Thurallor-7095
        if (not colName) then
842 Thurallor-7095
            return sortedCol.name;
843 Thurallor-7095
        else
844 Thurallor-7095
            if (self.lastSort.col == self.columnsByName[colName]) then
845 Thurallor-7095
                return colName;
846 Thurallor-7095
            end
847 Thurallor-7095
        end
848 Thurallor-7095
    end
849 Thurallor-7095
end
850 Thurallor-7095
 
851 Thurallor-7095
function TableControl:IsColumnLocked(colName)
852 Thurallor-7095
    if (colName) then
853 Thurallor-7095
        local col = self.columnsByName[colName];
854 Thurallor-7095
        if (col) then
855 Thurallor-7095
            return self.columns[col].locked;
856 Thurallor-7095
        end
857 Thurallor-7095
    end
858 Thurallor-7095
end
859 Thurallor-7095
 
860 Thurallor-7095
function TableControl:SetColumnLocked(colName, locked)
861 177 Thurallor-7095
    if (colName and self.options.columnLockingEnabled) then
862 176 Thurallor-7095
        local col = self.columnsByName[colName];
863 Thurallor-7095
        if (col) then
864 Thurallor-7095
            local column = self.columns[col];
865 Thurallor-7095
            local changed = (column.locked ~= locked);
866 Thurallor-7095
            column.locked = locked;
867 Thurallor-7095
            column.lockIcon:SetVisible(locked);
868 Thurallor-7095
            self:_PlaceColumnLockMasks();
869 Thurallor-7095
            if (changed) then
870 Thurallor-7095
                DoCallbacks(self, "PresentationChanged", { Desc = "Column " .. (locked and "locked" or "unlocked") });
871 Thurallor-7095
            end
872 Thurallor-7095
        end
873 Thurallor-7095
    end
874 Thurallor-7095
end
875 Thurallor-7095
 
876 Thurallor-7095
function TableControl:SelectRow(rowName)
877 Thurallor-7095
    if (rowName) then
878 Thurallor-7095
        self:_SelectRow(self.rowsByName[rowName]);
879 Thurallor-7095
    else
880 Thurallor-7095
        self:_SelectRow(nil);
881 Thurallor-7095
    end
882 Thurallor-7095
end
883 Thurallor-7095
 
884 Thurallor-7095
function TableControl:_SelectRow(rowContainer)
885 Thurallor-7095
    local oldSelectedRow = self.selectedRow;
886 Thurallor-7095
    self.selectedRow = rowContainer;
887 Thurallor-7095
 
888 Thurallor-7095
    -- Re-enable mask on previous row
889 Thurallor-7095
    if (oldSelectedRow) then
890 Thurallor-7095
        oldSelectedRow.mask:SetMouseVisible(true);
891 Thurallor-7095
    end
892 Thurallor-7095
 
893 Thurallor-7095
    -- Remove old marquee, if any
894 Thurallor-7095
    if (self.marquee) then
895 Thurallor-7095
        self.marquee:SetParent(nil);
896 Thurallor-7095
        self.marquee = nil;
897 Thurallor-7095
    end
898 Thurallor-7095
 
899 Thurallor-7095
    if (rowContainer) then
900 Thurallor-7095
        rowContainer:Focus();
901 Thurallor-7095
 
902 Thurallor-7095
        -- Create new marquee and attach it
903 Thurallor-7095
        self.marquee = Thurallor.UI.Marquee();
904 Thurallor-7095
        self:_ApplyStyles(self.marquee, self.style.marquee);
905 Thurallor-7095
        local height = 0;
906 Thurallor-7095
        for _, cell in pairs(rowContainer.cells) do
907 Thurallor-7095
            height = math.max(height, cell:GetHeight());
908 Thurallor-7095
        end
909 Thurallor-7095
        self.marquee:SetPosition(rowContainer:GetPosition());
910 Thurallor-7095
        self.marquee:SetSize(rowContainer:GetWidth(), height);
911 Thurallor-7095
        self.marquee:SetParent(self.rows);
912 Thurallor-7095
 
913 Thurallor-7095
        -- Disable mask to allow mouse clicks to reach the cells
914 Thurallor-7095
        rowContainer.mask:SetMouseVisible(false);
915 Thurallor-7095
 
916 Thurallor-7095
        -- Unless they're locked; then we still need to intercept mouse clicks
917 Thurallor-7095
        self:_PlaceColumnLockMasks();
918 Thurallor-7095
    else
919 Thurallor-7095
        self.rows:Focus();
920 Thurallor-7095
    end
921 Thurallor-7095
 
922 Thurallor-7095
    local oldName = (oldSelectedRow and oldSelectedRow.name) or nil;
923 Thurallor-7095
    local newName = (rowContainer and rowContainer.name) or nil;
924 Thurallor-7095
    self:_DoCallbacks("SelectionChanged", { New = newName; Old = oldName });
925 Thurallor-7095
end
926 Thurallor-7095
 
927 Thurallor-7095
function TableControl:Deselect()
928 Thurallor-7095
    self:_SelectRow(nil);
929 Thurallor-7095
end
930 Thurallor-7095
 
931 Thurallor-7095
function TableControl:InsertRows(beforeRow, numNewRows)
932 Thurallor-7095
end
933 Thurallor-7095
 
934 Thurallor-7095
function TableControl:RowIsVisible(row)
935 Thurallor-7095
    return (self.rows:GetItem(row):GetHeight() > 0);
936 Thurallor-7095
end
937 Thurallor-7095
 
938 Thurallor-7095
function TableControl:EnsureVisible(rowName)
939 Thurallor-7095
    if (rowName) then
940 Thurallor-7095
--        local left, top = self.rows:PointToScreen(0, 0);
941 Thurallor-7095
        local rowContainer = self.rowsByName[rowName];
942 Thurallor-7095
        if (rowContainer) then
943 Thurallor-7095
--            local x, y = rowContainer:PointToScreen(0, 0);
944 Thurallor-7095
            self.rows:EnsureVisible(self.rows:IndexOfItem(rowContainer));
945 Thurallor-7095
        end
946 Thurallor-7095
    end
947 Thurallor-7095
end
948 Thurallor-7095
 
949 Thurallor-7095
function TableControl:SetRowVisible(row, visible)
950 Thurallor-7095
    local rowContainer = self.rows:GetItem(row);
951 Thurallor-7095
    if (visible) then
952 Thurallor-7095
        -- Set container height to maximum of cell heights
953 Thurallor-7095
        local maxHeight = 0;
954 Thurallor-7095
        for _, cell in pairs(rowContainer.cells) do
955 Thurallor-7095
            maxHeight = math.max(maxHeight, cell:GetHeight());
956 Thurallor-7095
        end
957 Thurallor-7095
        if (rowContainer ~= self.lastRow) then
958 Thurallor-7095
            maxHeight = maxHeight + self.style.verticalCellSpacing;
959 Thurallor-7095
        end
960 Thurallor-7095
        rowContainer:SetHeight(maxHeight);
961 Thurallor-7095
    else
962 Thurallor-7095
        rowContainer:SetHeight(0);
963 Thurallor-7095
    end
964 Thurallor-7095
end
965 Thurallor-7095
 
966 Thurallor-7095
-- Last row needs to be slightly different cosmetically
967 Thurallor-7095
function TableControl:_UpdateLastRow()
968 Thurallor-7095
    local prev = self.lastRow;
969 Thurallor-7095
    local row = self.rows:GetItemCount();
970 Thurallor-7095
    if (row > 0) then
971 Thurallor-7095
        self.lastRow = self.rows:GetItem(row);
972 Thurallor-7095
        self:SetRowVisible(row, true);
973 Thurallor-7095
    else
974 Thurallor-7095
        self.lastRow = nil;
975 Thurallor-7095
    end
976 Thurallor-7095
    if (prev) then
977 Thurallor-7095
        self:SetRowVisible(self.rows:IndexOfItem(prev), true);
978 Thurallor-7095
    end
979 Thurallor-7095
end
980 Thurallor-7095
 
981 Thurallor-7095
function TableControl:DeleteRow(rowName)
982 Thurallor-7095
    local rowContainer = self.rowsByName[rowName];
983 Thurallor-7095
    if (self.selectedRow == rowContainer) then
984 Thurallor-7095
        self:Deselect();
985 Thurallor-7095
    end
986 Thurallor-7095
    self.rows:RemoveItem(rowContainer);
987 Thurallor-7095
    self.rowsByName[rowName] = nil;
988 Thurallor-7095
    if (self.lastRow == rowContainer) then
989 Thurallor-7095
        self.lastRow = nil;
990 Thurallor-7095
        self:_UpdateLastRow();
991 Thurallor-7095
    end
992 Thurallor-7095
end
993 Thurallor-7095
 
994 Thurallor-7095
function TableControl:GetRowCells(row)
995 Thurallor-7095
    return unpack(self.rows:GetItem(row).cells);
996 Thurallor-7095
end
997 Thurallor-7095
 
998 Thurallor-7095
function TableControl:GetCell(row, col)
999 Thurallor-7095
    return self.rows:GetItem(row).cells[col];
1000 Thurallor-7095
end
1001 Thurallor-7095
 
1002 Thurallor-7095
function TableControl:GetHeading(colName)
1003 Thurallor-7095
    local col = self.columnsByName[colName];
1004 Thurallor-7095
    if (col) then
1005 Thurallor-7095
        local column = self.columns[col];
1006 Thurallor-7095
        return column.heading;
1007 Thurallor-7095
    end
1008 Thurallor-7095
end
1009 Thurallor-7095
 
1010 Thurallor-7095
function TableControl:SetCell(row, col, object)
1011 Thurallor-7095
    local column = self.columns[col];
1012 Thurallor-7095
    local heading = column.heading;
1013 Thurallor-7095
    local rowContainer = self.rows:GetItem(row);
1014 Thurallor-7095
 
1015 Thurallor-7095
    -- Delete old cell (if any)
1016 Thurallor-7095
    local oldCell = rowContainer.cells[col];
1017 Thurallor-7095
    if (oldCell) then
1018 Thurallor-7095
        oldCell:SetParent(nil);
1019 Thurallor-7095
        if (oldCell.Close) then
1020 Thurallor-7095
            oldCell:Close();
1021 Thurallor-7095
        end
1022 Thurallor-7095
    end
1023 Thurallor-7095
 
1024 Thurallor-7095
    -- Create new cell, or use the supplied object
1025 Thurallor-7095
    local newCell = object;
1026 Thurallor-7095
    if (object == nil) then
1027 Thurallor-7095
        newCell = self:_CreateCell(row, col);
1028 Thurallor-7095
    end
1029 Thurallor-7095
 
1030 Thurallor-7095
    -- Place the cell within in the row container
1031 Thurallor-7095
    local left = heading:GetLeft();
1032 Thurallor-7095
    local width = heading:GetWidth();
1033 Thurallor-7095
    newCell:SetParent(rowContainer);
1034 Thurallor-7095
    if (column.weight == 0) then
1035 Thurallor-7095
        newCell:SetParent(nil);
1036 Thurallor-7095
    end
1037 Thurallor-7095
    rowContainer.cells[col] = newCell;
1038 Thurallor-7095
    newCell:SetWidth(width);
1039 Thurallor-7095
    newCell:SetPosition(left, top);
1040 Thurallor-7095
 
1041 Thurallor-7095
    -- Update the row container height, if necessary
1042 Thurallor-7095
    if (rowContainer:GetHeight() > 0) then
1043 Thurallor-7095
        self:SetRowVisible(true);
1044 Thurallor-7095
    end
1045 Thurallor-7095
 
1046 Thurallor-7095
    return newCell;
1047 Thurallor-7095
end
1048 Thurallor-7095
 
1049 Thurallor-7095
function TableControl:_ApplyStyles(object, styles)
1050 Thurallor-7095
    for s in keys(styles) do
1051 Thurallor-7095
        local SetFunction = object["Set" .. s];
1052 Thurallor-7095
        if (SetFunction) then
1053 Thurallor-7095
            SetFunction(object, styles[s]);
1054 Thurallor-7095
        end
1055 Thurallor-7095
    end
1056 Thurallor-7095
end
1057 Thurallor-7095
 
1058 Thurallor-7095
function TableControl:_UpdateColumnWidths()
1059 Thurallor-7095
    -- Find last visible column
1060 Thurallor-7095
    local rightCol;
1061 Thurallor-7095
    for col = 1, #self.columns do
1062 Thurallor-7095
        local column = self.columns[col];
1063 Thurallor-7095
        if (column.weight > 0) then
1064 Thurallor-7095
            rightCol = col;
1065 Thurallor-7095
        end
1066 Thurallor-7095
    end
1067 Thurallor-7095
 
1068 Thurallor-7095
    local totalWidth = self.rowWidth - ((#self.columns - 1) * self.style.horizontalCellSpacing);
1069 Thurallor-7095
    local totalWeight = self.totalWeight;
1070 Thurallor-7095
    local left = 0;
1071 Thurallor-7095
    local weightExpended = 0;
1072 Thurallor-7095
    for col = 1, #self.columns do
1073 Thurallor-7095
        local column = self.columns[col];
1074 Thurallor-7095
        local weight = column.weight;
1075 Thurallor-7095
        if (weight > 0) then
1076 Thurallor-7095
            local heading = column.heading;
1077 Thurallor-7095
            local width = math.floor(0.5 + totalWidth * (weight / totalWeight));
1078 Thurallor-7095
            width = math.min(width, self.rowWidth - left)
1079 Thurallor-7095
            if (col == rightCol) then
1080 Thurallor-7095
                width = self.rowWidth - left;
1081 Thurallor-7095
            end
1082 Thurallor-7095
            heading:SetLeft(left);
1083 Thurallor-7095
            heading:SetWidth(width);
1084 Thurallor-7095
            column.lockIcon:SetPosition(width - 19, -11);
1085 Thurallor-7095
            -- optimization to do: only need to do the following loop if heading left/width changed
1086 Thurallor-7095
            for row = 1, self.rows:GetItemCount() do
1087 Thurallor-7095
                local cell = self.rows:GetItem(row).cells[col];
1088 Thurallor-7095
                cell:SetLeft(left);
1089 Thurallor-7095
                cell:SetWidth(width);
1090 Thurallor-7095
            end
1091 Thurallor-7095
            weightExpended = weightExpended + weight;
1092 Thurallor-7095
            left = left + width + self.style.horizontalCellSpacing;
1093 Thurallor-7095
        end
1094 Thurallor-7095
    end
1095 Thurallor-7095
    self:_PlaceEdgeMovers();
1096 Thurallor-7095
    self:_PlaceColumnLockMasks();
1097 Thurallor-7095
end
1098 Thurallor-7095
 
1099 Thurallor-7095
function TableControl:SetSize(width, height)
1100 Thurallor-7095
    self:SetWidth(width);
1101 Thurallor-7095
    self:SetHeight(height);
1102 Thurallor-7095
end
1103 Thurallor-7095
 
1104 Thurallor-7095
function TableControl:SetWidth(width)
1105 Thurallor-7095
    Turbine.UI.Control.SetWidth(self, width);
1106 Thurallor-7095
    self.rowWidth = width;
1107 Thurallor-7095
    if (self.vScrollBar:IsVisible()) then
1108 Thurallor-7095
        self.rowWidth = width - 10;
1109 Thurallor-7095
        self.vScrollBar:SetLeft(self.rowWidth);
1110 Thurallor-7095
    end
1111 Thurallor-7095
    self.rows:SetWidth(self.rowWidth);
1112 Thurallor-7095
    for row = 1, self.rows:GetItemCount() do
1113 Thurallor-7095
        self.rows:GetItem(row):SetWidth(self.rowWidth);
1114 Thurallor-7095
    end
1115 Thurallor-7095
    self:_UpdateColumnWidths();
1116 Thurallor-7095
end
1117 Thurallor-7095
 
1118 Thurallor-7095
function TableControl:SetHeight(height)
1119 Thurallor-7095
    Turbine.UI.Control.SetHeight(self, height);
1120 Thurallor-7095
    self.rows:SetHeight(height - self.rows:GetTop());
1121 Thurallor-7095
    self.vScrollBar:SetHeight(height);
1122 Thurallor-7095
    self:_PlaceEdgeMovers(); -- update EdgeMover heights
1123 Thurallor-7095
end
1124 Thurallor-7095
 
1125 Thurallor-7095
function TableControl:_PlaceEdgeMovers()
1126 Thurallor-7095
    height = self:GetHeight();
1127 Thurallor-7095
    for e = 1, #self.edgeMovers do
1128 Thurallor-7095
        local edgeMover = self.edgeMovers[e];
1129 Thurallor-7095
        local headingToLeft = self.columns[edgeMover.leftColumn].heading;
1130 Thurallor-7095
        local headingToRight = self.columns[edgeMover.rightColumn].heading;
1131 Thurallor-7095
 
1132 Thurallor-7095
        local left = headingToLeft:GetLeft() + headingToLeft:GetWidth();
1133 Thurallor-7095
        local right = headingToRight:GetLeft();
1134 Thurallor-7095
        if (left > right) then -- columns overlap?
1135 Thurallor-7095
            left = right;
1136 Thurallor-7095
        end
1137 Thurallor-7095
        local center = (left + right) / 2;
1138 Thurallor-7095
        local width = edgeMover:GetWidth();
1139 Thurallor-7095
        left = math.floor(0.5 + center - (width / 2));
1140 Thurallor-7095
 
1141 Thurallor-7095
        edgeMover:SetLeft(left);
1142 Thurallor-7095
        edgeMover:SetHeight(height);
1143 Thurallor-7095
    end
1144 Thurallor-7095
end
1145 Thurallor-7095
 
1146 Thurallor-7095
function TableControl:_PlaceColumnLockMasks()
1147 Thurallor-7095
    if (self.selectedRow) then
1148 Thurallor-7095
        for col = 1, #self.columns do
1149 Thurallor-7095
            local column = self.columns[col];
1150 Thurallor-7095
            if (column.locked and (column.weight > 0))  then
1151 Thurallor-7095
                column.lockMask:SetParent(self.selectedRow);
1152 Thurallor-7095
                column.lockMask:SetPosition(column.heading:GetLeft(), 0);
1153 Thurallor-7095
                column.lockMask:SetSize(column.heading:GetWidth(), self.selectedRow:GetHeight());
1154 Thurallor-7095
                column.lockMask:SetMouseVisible(true);
1155 Thurallor-7095
            else
1156 Thurallor-7095
                column.lockMask:SetMouseVisible(false);
1157 Thurallor-7095
            end
1158 Thurallor-7095
        end
1159 Thurallor-7095
    end
1160 Thurallor-7095
end
1161 Thurallor-7095
 
1162 Thurallor-7095
-- For iterating over an array of cells in a for loop.  Example:
1163 Thurallor-7095
-- To change the color of every cell in the first two columns:
1164 Thurallor-7095
--     for cell in tblCtl:CellIterator(1, 1, nil, 2) do
1165 Thurallor-7095
--         cell:SetBackColor(Turbine.UI.Color.White);
1166 Thurallor-7095
--     end
1167 Thurallor-7095
function TableControl:CellIterator(firstRow, firstCol, lastRow, lastCol)
1168 Thurallor-7095
    if (firstRow == nil) then
1169 Thurallor-7095
        firstRow = 1;
1170 Thurallor-7095
    end
1171 Thurallor-7095
    if (lastRow == nil) then
1172 Thurallor-7095
        lastRow = self.rows:GetItemCount();
1173 Thurallor-7095
    end
1174 Thurallor-7095
    if (firstCol == nil) then
1175 Thurallor-7095
        firstCol = 1;
1176 Thurallor-7095
    end
1177 Thurallor-7095
    if (lastCol == nil) then
1178 Thurallor-7095
        lastCol = #self.columns;
1179 Thurallor-7095
    end
1180 Thurallor-7095
 
1181 Thurallor-7095
    local state = {
1182 Thurallor-7095
        ["self"] = self;
1183 Thurallor-7095
        ["firstRow"] = firstRow;
1184 Thurallor-7095
        ["firstCol"] = firstCol;
1185 Thurallor-7095
        ["lastRow"] = lastRow;
1186 Thurallor-7095
        ["lastCol"] = lastCol;
1187 Thurallor-7095
        ["row"] = firstRow;
1188 Thurallor-7095
        ["column"] = firstCol
1189 Thurallor-7095
    };
1190 Thurallor-7095
    local function iterator(state)
1191 Thurallor-7095
        if (state.row > state.lastRow) then
1192 Thurallor-7095
            return nil;
1193 Thurallor-7095
        end
1194 Thurallor-7095
        local cell = TableControl.GetCell(state.self, state.row, state.column);
1195 Thurallor-7095
        state.column = state.column + 1;
1196 Thurallor-7095
        if (state.column > state.lastCol) then
1197 Thurallor-7095
            state.column = state.firstCol;
1198 Thurallor-7095
            state.row = state.row + 1;
1199 Thurallor-7095
        end
1200 Thurallor-7095
        return cell;
1201 Thurallor-7095
    end
1202 Thurallor-7095
    return iterator, state, nil;
1203 Thurallor-7095
end
1204 Thurallor-7095
 
1205 Thurallor-7095
-- For calling member functions of many cells at once.  Examples:
1206 Thurallor-7095
--   minCellHeight = math.min(t:CellAggregator(1, 1, 1, 3):GetHeight());
1207 Thurallor-7095
--   t:CellAggregator():SetBackColor(Turbine.UI.Color(1, 1, 1, 1));
1208 Thurallor-7095
function TableControl:CellAggregator(firstRow, firstCol, lastRow, lastCol)
1209 Thurallor-7095
    local temp = {};
1210 Thurallor-7095
    temp.iterator = {self:CellIterator(firstRow, firstCol, lastRow, lastCol)};
1211 Thurallor-7095
    local temp_metatable = {};
1212 Thurallor-7095
    temp_metatable.__index = function(tab, key)
1213 Thurallor-7095
        rawset(tab, "funcName", key);
1214 Thurallor-7095
        return tab;
1215 Thurallor-7095
    end;
1216 Thurallor-7095
    temp_metatable.__call = function(tab, _, ...)
1217 Thurallor-7095
        local funcName = rawget(tab, "funcName");
1218 Thurallor-7095
        local results = {};
1219 Thurallor-7095
        for cell in unpack(rawget(tab, "iterator")) do
1220 Thurallor-7095
            local r = {cell[funcName](cell, ...)};
1221 Thurallor-7095
            for v in values(r) do
1222 Thurallor-7095
                table.insert(results, v);
1223 Thurallor-7095
            end
1224 Thurallor-7095
        end
1225 Thurallor-7095
        return unpack(results);
1226 Thurallor-7095
    end;
1227 Thurallor-7095
    setmetatable(temp, temp_metatable);
1228 Thurallor-7095
    return temp;
1229 Thurallor-7095
end
1230 Thurallor-7095
 
1231 Thurallor-7095
Thurallor = Thurallor or {};
1232 Thurallor-7095
Thurallor.UI = Thurallor.UI or {};
1233 Thurallor-7095
Thurallor.UI.TableControl = TableControl;

All times are GMT -5. The time now is 04:01 PM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui