Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

implemented new keyboard control of menu buttons with these new features:

  • more intuitive placement of buttons in table (row/column format instead of linear index)
  • no need to overwrite onShow() and onKeyPressed() functions, no need for P.buttonList
  • highlights the selected button in a different layout than mouse hovering
  • remembers the selection while moving through the menu hierarchy, but resets it if the menu is closed
  • allows preselected button (for example "Yes" in decision popup)
  • when opening a menu, the first selected button is not always the upper left, but instead depends on the pressed key (e.g. the 'up' key selects the button at the bottom, while the 'down' key selects the button at the top. once a button is selected, the keys behave as usual)

+ fixed wrong callback function in ingame menu

  • Property svn:eol-style set to native
File size: 8.3 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 just after the sheet has been hidden
27function P:onAfterHide()
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:afterHide()
52    -- reset the selected button
53    if self.buttons then
54        self:resetSelection()
55    end
56
57    self:onAfterHide()
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:moveSelection(1, 0)
85        elseif code == "200" then -- key up
86            self:moveSelection(-1, 0)
87        elseif code == "205" then -- key right
88            self:moveSelection(0, 1)
89        elseif code == "203" then -- key left
90            self:moveSelection(0, -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
109function P:initButtons(rows, columns)
110    self.rows = rows
111    self.columns = columns
112    self.buttons = {}
113    self.selectedRow = 0
114    self.selectedColumn = 0
115end
116
117-- Defines the button for a given position in the table. The upper-left button is at position (1, 1)
118function P:setButton(row, column, button)
119    assert(self.rows ~= nil and self.columns ~= nil and self.buttons ~= nil, "You have to call initButtons() before using setButton()")
120    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 .. ")")
121
122    self.buttons[(row - 1) * self.columns + (column - 1)] = button
123end
124
125-- Returns the button at a given position in the table. The upper-left button is at position (1, 1)
126function P:getButton(row, column)
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    return self.buttons[(row - 1) * self.columns + (column - 1)]
130end
131
132-- Returns the selected button
133function P:getSelectedButton()
134    assert(self.selectedRow > 0 and self.selectedColumn > 0, "no button selected")
135
136    return self:getButton(self.selectedRow, self.selectedColumn)
137end
138
139-- Presses the selected button if any
140function P:pressSelectedButton()
141    if self:hasSelection() then
142        self:getSelectedButton().callback()
143    end
144end
145
146-- Sets the selection to a given row and column. The upper-left button is at position (1, 1)
147function P:setSelection(row, column)
148    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 .. ")")
149
150    if self:hasSelection() then
151        self:setButtonStateNormal()
152    end
153
154    self.selectedRow = row
155    self.selectedColumn = column
156
157    self:setButtonStateSelected()
158end
159
160-- Moves the selection by a given number of rows and columns (positive values mean increasing row/column, negative values mean decreasing row/column)
161function P:moveSelection(relRow, relColumn)
162    -- if there's no selection yet, prepare it such that the selection enters the table from the desired side
163    if self:hasSelection() == false then
164        -- note: we assume either relRow or relColumn is 0, thus no diagonal movement. therefore the following checks can be separated
165        if relRow > 0 then
166            self.selectedRow = 0
167            self.selectedColumn = 1
168        elseif relRow < 0 then
169            self.selectedRow = self.rows + 1
170            self.selectedColumn = 1
171        end
172
173        if relColumn > 0 then
174            self.selectedRow = 1
175            self.selectedColumn = 0
176        elseif relColumn < 0 then
177            self.selectedRow = 1
178            self.selectedColumn = self.columns + 1
179        end
180    else
181        self:setButtonStateNormal()
182    end
183
184    -- move the selection according to the parameters
185    self.selectedRow = self.selectedRow + relRow
186    self.selectedColumn = self.selectedColumn + relColumn
187
188    -- wrap around on overflow
189    while self.selectedRow > self.rows do
190        self.selectedRow = self.selectedRow - self.rows
191    end
192    while self.selectedColumn > self.columns do
193        self.selectedColumn = self.selectedColumn - self.columns
194    end
195
196    -- wrap around on underflow
197    while self.selectedRow <= 0 do
198        self.selectedRow = self.selectedRow + self.rows
199    end
200    while self.selectedColumn <= 0 do
201        self.selectedColumn = self.selectedColumn + self.columns
202    end
203
204    -- if the button is deactivated, call this function again
205    if self:getSelectedButton() == nil then
206        self:moveSelection(relRow, relColumn)
207    else
208        self:setButtonStateSelected()
209    end
210end
211
212-- Resets the selection
213function P:resetSelection()
214    if self:hasSelection() then
215        self:setButtonStateNormal()
216    end
217
218    self.selectedRow = 0
219    self.selectedColumn = 0
220end
221
222-- Determines if a button is selected
223function P:hasSelection()
224    if self.selectedRow == 0 or self.selectedColumn == 0 then
225        return false
226    else
227        return true
228    end
229end
230
231-- Sets the selected button's state to normal
232function P:setButtonStateNormal()
233    self:setButtonState("Normal")
234end
235
236-- Sets the selected button's state to selected
237function P:setButtonStateSelected()
238    self:setButtonState("Selected")
239end
240
241-- Sets the selected button's state to pushed
242function P:setButtonStatePushed()
243    self:setButtonState("Pushed")
244end
245
246-- Sets the selected button's state
247function P:setButtonState(state)
248    if self:getSelectedButton() then
249        local element = self:getSelectedButton().button
250        local offset = getElementStateOffset(element)
251
252        if offset then
253            element:setProperty("NormalImageRightEdge",  string.sub(element:getProperty("NormalImageRightEdge"),  1, offset) .. state)
254            element:setProperty("NormalImageLeftEdge",   string.sub(element:getProperty("NormalImageLeftEdge"),   1, offset) .. state)
255            element:setProperty("NormalImageBackground", string.sub(element:getProperty("NormalImageBackground"), 1, offset) .. state)
256        end
257    end
258end
259
260-- Gets the offset of the button's current state
261function getElementStateOffset(element)
262    local property = element:getProperty("NormalImageRightEdge")
263
264    if string.sub(property, string.len(property) - 5, string.len(property)) == "Normal" then
265        return -7
266    elseif string.sub(property, string.len(property) - 7, string.len(property)) == "Selected" then
267        return -9
268    elseif string.sub(property, string.len(property) - 5, string.len(property)) == "Pushed" then
269        return -7
270    else
271        return nil
272    end
273end
274
275return P
Note: See TracBrowser for help on using the repository browser.