Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Mar 15, 2011, 9:47:11 PM (13 years ago)
Author:
landauf
Message:

merged usability branch back to trunk

incomplete summary of the changes in this branch:

  • enhanced keyboard navigation in GUIs
  • implemented new graphics menu and changeable window size at runtime
  • added developer mode
  • HUD shows if game is paused, game pauses if ingame menu is opened
  • removed a few obsolete commands and hid some that are more for internal use
  • numpad works in console and gui
  • faster loading of level info
  • enhanced usage of compositors (Shader class)
  • improved camera handling, configurable FOV and aspect ratio
Location:
code/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/trunk

  • code/trunk/data/gui/scripts/GUISheet.lua

    r7689 r8079  
    1616end
    1717
     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-- Override this function if you want to react on keystrokes
     31function P:onKeyPressed()
     32end
     33
     34-- Override this function if you want to update the gui after the window was resized
     35function P:onWindowResized()
     36end
     37
    1838-- show function for the GUI
    1939function P:show()
     
    2141    self.bVisible = true
    2242
     43    -- set the selected button's state
     44    self:setSelectedButtonsStateToSelected()
     45
    2346    self:onShow()
    24 end
    25 
    26 -- Override this function if you need to do work on show
    27 function P:onShow()
    2847end
    2948
     
    3655end
    3756
    38 -- Override this function if you need to do work on hide
    39 function P:onHide()
    40 end
    41 
    42 -- Override this function if you need to do work just after the sheet has been hidden
    43 function P:afterHide()
     57function P:quit()
     58    -- reset the selected button
     59    if self.buttons then
     60        self:resetSelection()
     61    end
     62
     63    self:onQuit()
    4464end
    4565
     
    6484end
    6585
    66 function P:onKeyPressed(e)
     86-- Handles key pressed while the gui sheed is displayed
     87function P:keyPressed()
     88    if self.buttons then
     89        if code == "208" then     -- key down
     90            self:moveSelectionRow(1)
     91        elseif code == "200" then -- key up
     92            self:moveSelectionRow(-1)
     93        elseif code == "205" then -- key right
     94            self:moveSelectionColumn(1)
     95        elseif code == "203" then -- key left
     96            self:moveSelectionColumn(-1)
     97        elseif code == "28" or code == "156"  then -- key enter or key numpad enter
     98            self:pressSelectedButton()
     99        end
     100    end
     101
     102    self:onKeyPressed()
     103end
     104
     105function P:windowResized()
     106    self:onWindowResized()
     107end
     108
     109
     110-------------------------------------------------------------------------------
     111-- Keyboard control -----------------------------------------------------------
     112-------------------------------------------------------------------------------
     113
     114-- Initializes the buttons table, used to control the menu with the keyboard
     115function P:initButtons(rows, columns)
     116    self.rows = rows
     117    self.columns = columns
     118    self.buttons = {}
     119    self.selectedRow = 0
     120    self.selectedColumn = 0
     121    self.ratio = 1
     122end
     123
     124-- 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)
     125function P:setRatio(ratio)
     126    self.ratio = ratio
     127end
     128
     129-- Defines the button for a given position in the table. The upper-left button is at position (1, 1)
     130function P:setButton(row, column, button)
     131    if not self.buttons then
     132        -- init the table
     133        self:initButtons(row, column)
     134    elseif row > self.rows or column > self.columns then
     135        -- rearrange the table
     136        local maxRows = math.max(self.rows, row)
     137        local maxColumns = math.max(self.columns, column)
     138
     139        for r = self.rows, 1, -1 do
     140            for c = self.columns, 1, -1 do
     141                local b = self:getButton(r, c)
     142                if b then
     143                    self.buttons[(r - 1) * self.columns + (c - 1)] = nil
     144                    self.buttons[(r - 1) * maxColumns + (c - 1)] = b
     145                end
     146            end
     147        end
     148
     149        self.rows = maxRows
     150        self.columns = maxColumns
     151    end
     152
     153    self.buttons[(row - 1) * self.columns + (column - 1)] = button
     154end
     155
     156-- Returns the button at a given position in the table. The upper-left button is at position (1, 1)
     157function P:getButton(row, column)
     158    if self.buttons then
     159        return self.buttons[(row - 1) * self.columns + (column - 1)]
     160    else
     161        return nil
     162    end
     163end
     164
     165-- Returns the selected button
     166function P:getSelectedButton()
     167    if self:hasSelection() then
     168        return self:getButton(self.selectedRow, self.selectedColumn)
     169    else
     170        return nil
     171    end
     172end
     173
     174-- Presses the selected button if any
     175function P:pressSelectedButton()
     176    if self:getSelectedButton() then
     177        self.pressedEnter = true
     178        self:getSelectedButton().callback()
     179        self.pressedEnter = false
     180    end
     181end
     182
     183-- Sets the selection to a given row and column. The upper-left button is at position (1, 1)
     184function P:setSelection(row, column)
     185    if not self.buttons then
     186        return
     187    end
     188
     189    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 .. ")")
     190
     191    self:setSelectedButtonsStateToNormal()
     192
     193    self.selectedRow = row
     194    self.selectedColumn = column
     195
     196    self:setSelectedButtonsStateToSelected()
     197end
     198
     199-- Sets the selection to the button closest to the given row and column. The upper-left button is at position (1, 1)
     200function P:setSelectionNear(row, column)
     201    if not self.buttons then
     202        return
     203    end
     204
     205    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 .. ")")
     206
     207    if self:getButton(row, column) then
     208        self:setSelection(row, column)
     209    else
     210        local min = 1000000
     211        local minRow, minColumn
     212
     213        for r = 1, self.rows do
     214            for c = 1, self.columns do
     215                if self:getButton(r, c) then
     216                    local distance = math.sqrt((row - r)^2 + ((column - c) * self.ratio)^2)
     217                    if distance < min then
     218                        min = distance; minRow = r; minColumn = c
     219                    end
     220                end
     221            end
     222        end
     223
     224        if minRow and minColumn then
     225            self:setSelection(minRow, minColumn)
     226        else
     227            self:resetSelection()
     228        end
     229    end
     230end
     231
     232-- Moves the selection by a given number of rows (a positive value means down, a negative value means up)
     233function P:moveSelectionRow(relRow)
     234    self:moveSelection(relRow, "selectedRow", "selectedColumn", "rows", "columns", true)
     235end
     236
     237-- Moves the selection by a given number of columns (a positive value means right, a negative value means left)
     238function P:moveSelectionColumn(relColumn)
     239    self:moveSelection(relColumn, "selectedColumn", "selectedRow", "columns", "rows", false)
     240end
     241
     242-- Generic move function, the values are determined at runtime depending on the arguments
     243function P:moveSelection(relMove, selectedThis, selectedOther, limitThis, limitOther, isRow)
     244    if not self.buttons then
     245        return
     246    end
     247
     248    -- if there's no selection yet, prepare it such that the selection enters the table from the desired side
     249    if self.selectedRow > 0 or self.selectedColumn > 0 then
     250        self:setSelectedButtonsStateToNormal()
     251    else
     252        if relMove > 0 then
     253            self[selectedThis] = 0
     254            self[selectedOther] = 1
     255        elseif relMove < 0 then
     256            self[selectedThis] = self[limitThis] + 1
     257            self[selectedOther] = 1
     258        else
     259            return
     260        end
     261    end
     262
     263    -- move the selection according to the parameters
     264    self[selectedThis] = self[selectedThis] + relMove
     265
     266    -- wrap around on overflow or underflow
     267    while self[selectedThis] > self[limitThis] do self[selectedThis] = self[selectedThis] - self[limitThis] end
     268    while self[selectedThis] <= 0              do self[selectedThis] = self[selectedThis] + self[limitThis] end
     269
     270    -- if the button is deactivated, search the button closest to the desired location
     271    if self:getSelectedButton() == nil then
     272        local min = 1000000
     273        local minV1, minV2
     274        local limit, step
     275
     276        if relMove > 0 then
     277            limit = self[limitThis]
     278            step = 1
     279        else
     280            limit = 1
     281            step = -1
     282        end
     283
     284        for v1 = self[selectedThis], limit, step do
     285            for v2 = 1, self[limitOther] do
     286                local button
     287                if isRow == true then
     288                    button = self:getButton(v1, v2)
     289                else
     290                    button = self:getButton(v2, v1)
     291                end
     292                if button then
     293                    local distance
     294                    if isRow == true then
     295                        distance = math.sqrt((self[selectedThis] - v1)^2 + ((self[selectedOther] - v2) * self.ratio)^2)
     296                    else
     297                        distance = math.sqrt(((self[selectedThis] - v1) * self.ratio)^2 + (self[selectedOther] - v2)^2)
     298                    end
     299                    if distance < min then
     300                        min = distance; minV1 = v1; minV2 = v2
     301                    end
     302                end
     303            end
     304        end
     305
     306        if minV1 and minV2 then
     307            self[selectedThis] = minV1
     308            self[selectedOther] = minV2
     309        elseif self:hasButtons() then
     310            -- no suitable button found - wrap around and search again
     311            if relMove > 0 then
     312                self[selectedThis] = 0
     313            else
     314                self[selectedThis] = self[limitThis] + 1
     315            end
     316            self:moveSelection(relMove, selectedThis, selectedOther, limitThis, limitOther, isRow)
     317        end
     318    end
     319
     320    self:setSelectedButtonsStateToSelected()
     321end
     322
     323-- Resets the selection
     324function P:resetSelection()
     325    self:setSelectedButtonsStateToNormal()
     326
     327    self.selectedRow = 0
     328    self.selectedColumn = 0
     329end
     330
     331-- Checks if there's at least one button in the table
     332function P:hasButtons()
     333    local count = 0
     334    for r = 1, self.rows do
     335        for c = 1, self.columns do
     336            if self:getButton(r, c) then
     337                count = count + 1
     338            end
     339        end
     340    end
     341
     342    return (count > 0)
     343end
     344
     345-- Determines if a button is selected
     346function P:hasSelection()
     347    if self.selectedRow and self.selectedRow > 0 and self.selectedColumn and self.selectedColumn > 0 then
     348        return true
     349    else
     350        return false
     351    end
     352end
     353
     354-- Sets the selected button's state to normal
     355function P:setSelectedButtonsStateToNormal()
     356    self:setSelectedButtonsState("Normal")
     357end
     358
     359-- Sets the selected button's state to selected
     360function P:setSelectedButtonsStateToSelected()
     361    self:setSelectedButtonsState("Selected")
     362end
     363
     364-- Sets the selected button's state to pushed
     365function P:setSelectedButtonsStateToPushed()
     366    self:setSelectedButtonsState("Pushed")
     367end
     368
     369-- Sets the selected button's state
     370function P:setSelectedButtonsState(state)
     371    if self:getSelectedButton() then
     372        local element = self:getSelectedButton().button
     373        local offset = getElementStateOffset(element)
     374
     375        if offset then
     376            element:setProperty("NormalImageRightEdge",  string.sub(element:getProperty("NormalImageRightEdge"),  1, offset) .. state)
     377            element:setProperty("NormalImageLeftEdge",   string.sub(element:getProperty("NormalImageLeftEdge"),   1, offset) .. state)
     378            element:setProperty("NormalImageBackground", string.sub(element:getProperty("NormalImageBackground"), 1, offset) .. state)
     379        end
     380    end
     381end
     382
     383-- Gets the offset of the button's current state
     384function getElementStateOffset(element)
     385    local property = element:getProperty("NormalImageRightEdge")
     386
     387    if string.sub(property, string.len(property) - 5, string.len(property)) == "Normal" then
     388        return -7
     389    elseif string.sub(property, string.len(property) - 7, string.len(property)) == "Selected" then
     390        return -9
     391    elseif string.sub(property, string.len(property) - 5, string.len(property)) == "Pushed" then
     392        return -7
     393    else
     394        return nil
     395    end
    67396end
    68397
Note: See TracChangeset for help on using the changeset viewer.