Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/usability/data/gui/scripts/GUISheet.lua @ 7927

Last change on this file since 7927 was 7927, checked in by landauf, 13 years ago

renamed afterHide()/onAfterHide() as quit()/onQuit() as this seems to fit the purpose better

  • Property svn:eol-style set to native
File size: 10.2 KB
Line 
1-- GUISheet.lua
2
3local P = {}
4_G[_REQUIREDNAME or "GUISheet"] = P
5P.__index = P
6
7-- Don't use directly --> use HUDSheet.new or MenuSheet.new
8function P.new(_name)
9    local newSheet = { name = _name }
10    setmetatable(newSheet, P)
11    return newSheet
12end
13
14-- Override this function if you need to do work on load
15function P:onLoad()
16end
17
18-- Override this function if you need to do work on show
19function P:onShow()
20end
21
22-- Override this function if you need to do work on hide
23function P:onHide()
24end
25
26-- Override this function if you need to do work on quit
27function P:onQuit()
28end
29
30-- show function for the GUI
31function P:show()
32    self.window:show()
33    self.bVisible = true
34
35    -- set the selected button's state
36    if self.buttons and self:hasSelection() then
37        self:setButtonStateSelected()
38    end
39
40    self:onShow()
41end
42
43-- hide function for the GUI
44function P:hide()
45    self.window:hide()
46    self.bVisible = false
47
48    self:onHide()
49end
50
51function P:quit()
52    -- reset the selected button
53    if self.buttons then
54        self:resetSelection()
55    end
56
57    self:onQuit()
58end
59
60function P:load()
61    -- Load the layout that describes the sheet
62    self.window = winMgr:loadWindowLayout(self.name .. ".layout")
63    if self.window == nil then
64        error("Could not load layout file for GUI sheet '"..self.name.."'")
65    end
66    -- Hide it at first
67    self:hide()
68    -- Allow sheets to do some work upon loading
69    self:onLoad()
70
71    -- Also load additional sheets to avoid display lags
72    if self.loadAlong then
73        for k, sheet in pairs(self.loadAlong) do
74            loadSheet(sheet)
75        end
76    end
77    return self
78end
79
80-- Handles key pressed while the gui sheed is displayed
81function P:keyPressed()
82    if self.buttons then
83        if code == "208" then     -- key down
84            self:moveSelectionRow(1)
85        elseif code == "200" then -- key up
86            self:moveSelectionRow(-1)
87        elseif code == "205" then -- key right
88            self:moveSelectionColumn(1)
89        elseif code == "203" then -- key left
90            self:moveSelectionColumn(-1)
91        elseif code == "28"  then -- key enter
92            self:pressSelectedButton()
93        end
94    end
95
96    self.onKeyPressed()
97end
98
99-- Override this function if you want to ract on keystrokes
100function P:onKeyPressed()
101end
102
103
104-------------------------------------------------------------------------------
105-- Keyboard control -----------------------------------------------------------
106-------------------------------------------------------------------------------
107
108-- Initializes the buttons table, used to control the menu with the keyboard
109-- ratio: the button's with divided by the button's height (used to calculate distance between buttons - adjust this until you get the desired behavior)
110function P:initButtons(rows, columns, ratio)
111    self.rows = rows
112    self.columns = columns
113    self.buttons = {}
114    self.selectedRow = 0
115    self.selectedColumn = 0
116
117    if ratio then
118        self.ratio = ratio
119    else
120        self.ratio = 1
121    end
122end
123
124-- Defines the button for a given position in the table. The upper-left button is at position (1, 1)
125function P:setButton(row, column, button)
126    assert(self.rows ~= nil and self.columns ~= nil and self.buttons ~= nil, "You have to call initButtons() before using setButton()")
127    assert(row > 0 and column > 0 and row <= self.rows and column <= self.columns, "(" .. row .. "/" .. column .. ") is not in the valid bounds of the table (1/1)-(" .. self.rows .. "/" .. self.columns .. ")")
128
129    self.buttons[(row - 1) * self.columns + (column - 1)] = button
130end
131
132-- Returns the button at a given position in the table. The upper-left button is at position (1, 1)
133function P:getButton(row, column)
134    return self.buttons[(row - 1) * self.columns + (column - 1)]
135end
136
137-- Returns the selected button
138function P:getSelectedButton()
139    return self:getButton(self.selectedRow, self.selectedColumn)
140end
141
142-- Presses the selected button if any
143function P:pressSelectedButton()
144    if self:hasSelection() then
145        self.pressedEnter = true
146        self:getSelectedButton().callback()
147        self.pressedEnter = false
148    end
149end
150
151-- Sets the selection to a given row and column. The upper-left button is at position (1, 1)
152function P:setSelection(row, column)
153    assert(row > 0 and column > 0 and row <= self.rows and column <= self.columns, "(" .. row .. "/" .. column .. ") is not in the valid bounds of the table (1/1)-(" .. self.rows .. "/" .. self.columns .. ")")
154
155    if self:hasSelection() then
156        self:setButtonStateNormal()
157    end
158
159    self.selectedRow = row
160    self.selectedColumn = column
161
162    self:setButtonStateSelected()
163end
164
165-- Moves the selection by a given number of rows (a positive value means down, a negative value means up)
166function P:moveSelectionRow(relRow)
167    self:moveSelection(relRow, "selectedRow", "selectedColumn", "rows", "columns", true)
168end
169
170-- Moves the selection by a given number of columns (a positive value means right, a negative value means left)
171function P:moveSelectionColumn(relColumn)
172    self:moveSelection(relColumn, "selectedColumn", "selectedRow", "columns", "rows", false)
173end
174
175-- Generic move function, the values are determined at runtime depending on the arguments
176function P:moveSelection(relMove, selectedThis, selectedOther, limitThis, limitOther, isRow)
177    -- if there's no selection yet, prepare it such that the selection enters the table from the desired side
178    if self.selectedRow > 0 or self.selectedColumn > 0 then
179        self:setButtonStateNormal()
180    else
181        if relMove > 0 then
182            self[selectedThis] = 0
183            self[selectedOther] = 1
184        elseif relMove < 0 then
185            self[selectedThis] = self[limitThis] + 1
186            self[selectedOther] = 1
187        else
188            return
189        end
190    end
191
192    -- move the selection according to the parameters
193    self[selectedThis] = self[selectedThis] + relMove
194
195    -- wrap around on overflow or underflow
196    while self[selectedThis] > self[limitThis] do self[selectedThis] = self[selectedThis] - self[limitThis] end
197    while self[selectedThis] <= 0              do self[selectedThis] = self[selectedThis] + self[limitThis] end
198
199    -- if the button is deactivated, search the button closest to the desired location
200    if self:getSelectedButton() == nil then
201        local min = self.rows + self.columns * self.ratio
202        local minV1, minV2
203        local limit, step
204
205        if relMove > 0 then
206            limit = self[limitThis]
207            step = 1
208        else
209            limit = 1
210            step = -1
211        end
212
213        for v1 = self[selectedThis], limit, step do
214            for v2 = 1, self[limitOther] do
215                local button
216                if isRow == true then
217                    button = self:getButton(v1, v2)
218                else
219                    button = self:getButton(v2, v1)
220                end
221                if button then
222                    local distance
223                    if isRow == true then
224                        distance = math.sqrt((self[selectedThis] - v1)^2 + ((self[selectedOther] - v2) * self.ratio)^2)
225                    else
226                        distance = math.sqrt(((self[selectedThis] - v1) * self.ratio)^2 + (self[selectedOther] - v2)^2)
227                    end
228                    if distance < min then
229                        min = distance; minV1 = v1; minV2 = v2
230                    end
231                end
232            end
233        end
234
235        if minV1 and minV2 then
236            self[selectedThis] = minV1
237            self[selectedOther] = minV2
238        elseif self:hasButtons() then
239            -- no suitable button found - wrap around and search again
240            if relMove > 0 then
241                self[selectedThis] = 0
242            else
243                self[selectedThis] = self[limitThis] + 1
244            end
245            self:moveSelection(relMove, selectedThis, selectedOther, limitThis, limitOther, isRow)
246        end
247    end
248
249    if self:hasSelection() == true then
250        self:setButtonStateSelected()
251    end
252end
253
254-- Resets the selection
255function P:resetSelection()
256    if self:hasSelection() then
257        self:setButtonStateNormal()
258    end
259
260    self.selectedRow = 0
261    self.selectedColumn = 0
262end
263
264-- Checks if there's at least one button in the table
265function P:hasButtons()
266    local count = 0
267    for r = 1, self.rows do
268        for c = 1, self.columns do
269            if self:getButton(r, c) then
270                count = count + 1
271            end
272        end
273    end
274
275    return (count > 0)
276end
277
278-- Determines if a button is selected
279function P:hasSelection()
280    if self.selectedRow and self.selectedRow > 0 and self.selectedColumn and self.selectedColumn > 0 then
281        return true
282    else
283        return false
284    end
285end
286
287-- Sets the selected button's state to normal
288function P:setButtonStateNormal()
289    self:setButtonState("Normal")
290end
291
292-- Sets the selected button's state to selected
293function P:setButtonStateSelected()
294    self:setButtonState("Selected")
295end
296
297-- Sets the selected button's state to pushed
298function P:setButtonStatePushed()
299    self:setButtonState("Pushed")
300end
301
302-- Sets the selected button's state
303function P:setButtonState(state)
304    if self:getSelectedButton() then
305        local element = self:getSelectedButton().button
306        local offset = getElementStateOffset(element)
307
308        if offset then
309            element:setProperty("NormalImageRightEdge",  string.sub(element:getProperty("NormalImageRightEdge"),  1, offset) .. state)
310            element:setProperty("NormalImageLeftEdge",   string.sub(element:getProperty("NormalImageLeftEdge"),   1, offset) .. state)
311            element:setProperty("NormalImageBackground", string.sub(element:getProperty("NormalImageBackground"), 1, offset) .. state)
312        end
313    end
314end
315
316-- Gets the offset of the button's current state
317function getElementStateOffset(element)
318    local property = element:getProperty("NormalImageRightEdge")
319
320    if string.sub(property, string.len(property) - 5, string.len(property)) == "Normal" then
321        return -7
322    elseif string.sub(property, string.len(property) - 7, string.len(property)) == "Selected" then
323        return -9
324    elseif string.sub(property, string.len(property) - 5, string.len(property)) == "Pushed" then
325        return -7
326    else
327        return nil
328    end
329end
330
331return P
Note: See TracBrowser for help on using the repository browser.