Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/usability/data/gui/scripts/SheetManager.lua @ 7926

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

greatly improved keyboard controlled navigation in menus with sparse button tables (deactivated buttons, deactivated rows or columns, holes, randomly placed buttons, …)

  • Property svn:eol-style set to native
File size: 8.1 KB
Line 
1-- SheetManager.lua
2
3local cursor = CEGUI.MouseCursor:getSingleton()
4local loadedSheets = {}
5local activeMenuSheets = {size = 0, topSheetTuple = nil}
6local menuSheetsRoot = guiMgr:getMenuRootWindow()
7local bInGameConsoleClosed = false
8local mainMenuLoaded = false
9orxonox.GUIManager:subscribeEventHelper(menuSheetsRoot, "KeyDown", "keyPressed")
10
11-----------------------
12--- Local functions ---
13-----------------------
14
15local function hideCursor()
16    if cursor:isVisible() then
17        cursor:hide()
18    end
19end
20
21local function showCursor()
22    if not cursor:isVisible() and inputMgr:isMouseExclusive() then
23        cursor:show()
24    end
25end
26
27
28------------------------
29--- Global functions ---
30------------------------
31
32-- Loads the GUI with the specified name
33-- The name corresponds to the filename of the *.lua and *.layout files
34-- but without the extension
35function loadSheet(name)
36    -- Check if it has already been loaded
37    local sheet = loadedSheets[name]
38    if sheet == nil then
39        -- Load the sheet
40        sheet = require(name)
41        sheet:load()
42        loadedSheets[name] = sheet
43    end
44    return sheet
45end
46
47-- ?
48function showMenuSheet(name, bHidePrevious, bNoInput, ptr)
49    local sheet = showMenuSheet(name, bHidePrevious, bNoInput)
50    sheet.overlay = ptr
51    return sheet
52end
53
54-- Shows the specified menu sheet and loads it if neccessary
55function showMenuSheet(name, bHidePrevious, bNoInput)
56    if name == "" then
57        return nil
58    end
59    -- Get sheet (or load it)
60    local menuSheet = loadSheet(name)
61
62    -- Use sheet's value if nil was provided
63    if bHidePrevious == nil then
64        bHidePrevious = menuSheet.bHidePrevious
65        assert(bHidePrevious ~= nil)
66    end
67
68    -- Set bNoInput to false if it hasn't been set.
69    if bNoInput == nil then
70        bNoInput = false
71    end
72
73    -- Count the number of sheets that don't need input till the first that does.
74    local counter = noInputSheetIndex()
75    -- Pause game control if this is the first menu to be displayed
76    -- HUGE HACK?
77    if bNoInput == false and counter == 0 then
78        orxonox.HumanController:pauseControl()
79    end
80
81    -- Hide if already displayed (to make sure it is up front in the end)
82    if activeMenuSheets[name] ~= nil then
83        hideMenuSheet(name)
84    end
85
86    if bNoInput == true then
87        menuSheet.tShowCursor = TriBool.Dontcare
88    end
89
90    -- Add the sheet in a tuple of additional information
91    local sheetTuple =
92    {
93        ["sheet"]          = menuSheet,
94        ["bHidePrevious"]  = bHidePrevious,
95        ["bNoInput"]       = bNoInput
96    }
97    table.insert(activeMenuSheets, sheetTuple) -- indexed array access
98    activeMenuSheets[name] = sheetTuple -- name access
99    activeMenuSheets.size = activeMenuSheets.size + 1
100    activeMenuSheets.topSheetTuple = sheetTuple
101
102    -- Add sheet to the root window
103    menuSheetsRoot:addChildWindow(menuSheet.window)
104
105    -- If sheet is the MainMenu
106    if name == "MainMenu" then
107        mainMenuLoaded = true
108    end
109
110    -- Handle input distribution
111    if bNoInput == false then
112        inputMgr:enterState(menuSheet.inputState)
113    end
114
115    -- Only change cursor situation if menuSheet.tShowCursor ~= TriBool.Dontcare
116    if menuSheet.tShowCursor == TriBool.True then
117        showCursor()
118    elseif menuSheet.tShowCursor == TriBool.False then
119        hideCursor()
120    end
121
122    -- Hide all previous sheets if necessary
123    local previous
124    if bHidePrevious then
125        for i = 1, activeMenuSheets.size - 1 do
126            previous = activeMenuSheets[i].sheet
127            previous:hide()
128        end
129    end
130
131    menuSheet:show()
132    menuSheetsRoot:activate()
133
134    -- select first button if the menu was opened with the keyboard
135    if previous and previous.pressedEnter and menuSheet.buttons and menuSheet:hasSelection() == false then
136        menuSheet:moveSelectionRow(1)
137    end
138
139    return menuSheet
140end
141
142function hideMenuSheet(name)
143    local sheetTuple = activeMenuSheets[name]
144    if sheetTuple == nil then
145        return
146    end
147
148    -- Hide the sheet
149    sheetTuple.sheet:hide()
150
151    -- Show sheets that were hidden by the sheet to be removed
152    local i = activeMenuSheets.size
153    -- Only do something if all sheets on top of sheetTuple
154    -- have bHidePrevious == true and sheetTuple.bHidePrevious == true
155    while i > 0 do
156        if activeMenuSheets[i].bHidePrevious then
157            if activeMenuSheets[i] == sheetTuple then
158                i = i - 1
159                while i > 0 do
160                    activeMenuSheets[i].sheet:show()
161                    if activeMenuSheets[i].bHidePrevious then
162                        break
163                    end
164                    i = i - 1
165                end
166            end
167            break
168        end
169        i = i - 1
170    end
171
172    -- Remove sheet with its tuple from the table
173    menuSheetsRoot:removeChildWindow(sheetTuple.sheet.window)
174    table.remove(activeMenuSheets, table.findIndex(activeMenuSheets, sheetTuple))
175    activeMenuSheets[name] = nil
176    activeMenuSheets.size = activeMenuSheets.size - 1
177    activeMenuSheets.topSheetTuple = activeMenuSheets[activeMenuSheets.size]
178
179    -- If sheet is the MainMenu
180    if name == "MainMenu" then
181        mainMenuLoaded = false
182    end
183
184    -- Leave the input state
185    if not sheetTuple.bNoInput then
186        inputMgr:leaveState(sheetTuple.sheet.inputState)
187    end
188
189    -- CURSOR SHOWING
190    local i = activeMenuSheets.size
191    -- Find top most sheet that doesn't have tShowCusor == TriBool.Dontcare
192    while i > 0 and activeMenuSheets[i].sheet.tShowCursor == TriBool.Dontcare do
193        i = i - 1
194    end
195    if i > 0 and activeMenuSheets[i].sheet.tShowCursor == TriBool.True then
196        showCursor()
197    else
198        hideCursor()
199    end
200
201    -- Count the number of sheets that don't need input till the first that does.
202    local counter = noInputSheetIndex()
203    -- Resume control if the last (non-noInput) menu is hidden
204    if counter == 0 then
205        orxonox.HumanController:resumeControl()
206        hideCursor()
207    end
208
209    sheetTuple.sheet:afterHide()
210end
211
212-- Hides all menu GUI sheets
213function hideAllMenuSheets()
214    while activeMenuSheets.size ~= 0 do
215        hideMenuSheet(activeMenuSheets.topSheetTuple.sheet.name)
216    end
217end
218
219function keyESC()
220    -- HUGE, very HUGE hacks!
221
222    -- If the InGameConsole is active, ignore the ESC command.
223    if bInGameConsoleClosed == true then
224        bInGameConsoleClosed = false
225        return
226    end
227
228    -- Count the number of sheets that don't need input till the first that does.
229    local counter = noInputSheetIndex()
230
231    -- If the first sheet that needs input is the MainMenu.
232    if noInputSheetCounter() == 1 and activeMenuSheets[counter].sheet.name == "MainMenu" then
233        orxonox.execute("exit")
234    -- If there is at least one sheet that needs input.
235    elseif counter > 0 then
236        orxonox.execute("hideGUI "..activeMenuSheets[counter].sheet.name)
237    else
238        showMenuSheet("InGameMenu")
239    end
240end
241
242function keyPressed(e)
243    local we = tolua.cast(e, "CEGUI::KeyEventArgs")
244    local sheet = activeMenuSheets[activeMenuSheets.size]
245    code = tostring(we.scancode)
246    -- Some preprocessing
247    if not mainMenuLoaded and not sheet.bNoInput then
248        if code == "1" then
249            keyESC()
250        elseif code == "0"then
251            orxonox.CommandExecutor:execute("openConsole")
252        end
253    end
254    sheet.sheet:keyPressed()
255end
256
257function setBackgroundImage(imageSet, imageName)
258    guiMgr:setBackgroundImage(imageSet, imageName)
259end
260
261function noInputSheetIndex()
262    -- Count the number of sheets that don't need input till the first that does.
263    local index = activeMenuSheets.size
264    while index > 0 and activeMenuSheets[index].bNoInput do
265        index = index - 1
266    end
267    return index
268end
269
270function noInputSheetCounter()
271    -- Count the number of sheets that do need input.
272    local counter = activeMenuSheets.size
273    for i = 1,activeMenuSheets.size do
274        if activeMenuSheets[i].bNoInput then
275            counter = counter - 1
276        end
277    end
278    return counter
279end
280
281function inGameConsoleClosed()
282    bInGameConsoleClosed = not bInGameConsoleClosed;
283end
284
285----------------------
286--- Initialisation ---
287----------------------
288
289hideCursor()
Note: See TracBrowser for help on using the repository browser.