attrib "key" -> "shortcut", also fix #20

This commit is contained in:
airstruck
2016-01-03 01:18:04 -05:00
parent 3abcce1615
commit c73833337e
12 changed files with 98 additions and 90 deletions

View File

@@ -124,10 +124,10 @@
The cursor left a widget, and a button was pressed.
</li>
<li><span class="parameter">PressStart</span>
A pointer button or accelerator key was pressed.
A pointer button or keyboard shortcut was pressed.
</li>
<li><span class="parameter">PressEnd</span>
A pointer button or accelerator key was released.
A pointer button or keyboard shortcut was released.
</li>
<li><span class="parameter">PressDrag</span>
A pressed cursor moved; targets originating widget.

View File

@@ -106,7 +106,7 @@ to recalculate their size and position.</p>
</tr>
<tr>
<td class="name" nowrap><a href="#key">key</a></td>
<td class="summary">Keyboard accelerator.</td>
<td class="summary">Keyboard shortcut.</td>
</tr>
</table>
<h2><a href="#Size_Attributes">Size Attributes </a></h2>
@@ -362,7 +362,7 @@ its scroll position when the widget's contents overflow its boundary.
<strong>key</strong>
</dt>
<dd>
Keyboard accelerator. </p>
Keyboard shortcut. </p>
<p>Should contain a string representing a key and optional modifiers,
separated by dashes; for example <code>&apos;ctrl-c&apos;</code> or <code>&apos;alt-shift-escape&apos;</code>.</p>

View File

@@ -1,34 +1,34 @@
return { id = 'mainWindow',
{ type = 'menu',
{ text = 'File',
{ text = 'Save', id = 'menuSave', key = 'ctrl-s',
{ text = 'Save', id = 'menuSave', shortcut = 'ctrl-s',
status = 'Save to disk' },
{ text = 'Quit', id = 'menuQuit', key = 'escape',
{ text = 'Quit', id = 'menuQuit', shortcut = 'escape',
status = 'Quit the demo' },
},
{ text = 'Edit',
{ text = 'Cut', key = 'ctrl-c' },
{ text = 'Copy', key = 'ctrl-x' },
{ text = 'Paste', key = 'ctrl-v' },
{ text = 'Cut', shortcut = 'ctrl-c' },
{ text = 'Copy', shortcut = 'ctrl-x' },
{ text = 'Paste', shortcut = 'ctrl-v' },
{ type = 'slider' },
},
{ text = 'View',
{ text = 'Theme',
{ text = 'Light', key = 'ctrl-l', id = 'themeLight', },
{ text = 'Dark', key = 'ctrl-d', id = 'themeDark' },
{ text = 'Light', shortcut = 'ctrl-l', id = 'themeLight', },
{ text = 'Dark', shortcut = 'ctrl-d', id = 'themeDark' },
},
{ text = 'Style',
{ text = 'Default' },
},
},
{ text = 'Help',
{ id = 'about', text = 'About Luigi', icon = 'icon/16px/Book.png', key = 'f1', },
{ id = 'aboutDemo', text = 'About Luigi Demo', icon = 'icon/16px/Book Red.png', key = 'f2' },
{ id = 'license', text = 'License', key = 'f3' },
{ id = 'about', text = 'About Luigi', icon = 'icon/16px/Book.png', shortcut = 'f1', },
{ id = 'aboutDemo', text = 'About Luigi Demo', icon = 'icon/16px/Book Red.png', shortcut = 'f2' },
{ id = 'license', text = 'License', shortcut = 'f3' },
},
},
{ style = 'toolbar',
{ id = 'newButton', style = 'toolButton', key = 'z',
{ id = 'newButton', style = 'toolButton', shortcut = 'z',
icon = 'icon/32px/Blueprint.png',
status = 'Create a new thing' },
{ id = 'loadButton', style = 'toolButton',
@@ -88,10 +88,12 @@ return { id = 'mainWindow',
{ type = 'label', text = 'Flow test' },
{ type = 'check', text = 'Vertical controls', id = 'flowToggle', },
{ type = 'label', text = 'Some radio widgets' },
{ type = 'radio', text = 'One fish' },
{ type = 'radio', text = 'Two fish' },
{ type = 'radio', text = 'Red fish' },
{ type = 'radio', text = 'Blue fish' },
{
{ type = 'radio', text = 'One fish' },
{ type = 'radio', text = 'Two fish' },
{ type = 'radio', text = 'Red fish' },
{ type = 'radio', text = 'Blue fish' },
},
}
},
},

View File

@@ -128,22 +128,9 @@ Attribute.context = {}
function Attribute.context.set (widget, value)
widget.attributes.context = value
for i = #widget, 1, -1 do
local child = widget[i]
if child.isContextMenu then
table.remove(widget, i)
end
end
if not value then return end
widget:addChild {
type = 'menu',
isContextMenu = true,
width = 0,
height = 0,
value
}
value.menuLayout.isContextMenu = true
widget.contextMenu = value
value.isContextMenu = true
widget.layout:createWidget { type = 'menu', value }
end
Attribute.context.get = cascade
@@ -218,7 +205,7 @@ Should contain `true` if the widget can be focused by pressing the tab key.
Attribute.focusable = {}
--[[--
Keyboard accelerator.
Keyboard shortcut.
Should contain a string representing a key and optional modifiers,
separated by dashes; for example `'ctrl-c'` or `'alt-shift-escape'`.
@@ -228,25 +215,25 @@ as if it had been pressed with a mouse or touch interface.
Setting this attribute re-registers the widget with its layout.
@attrib key
@attrib shortcut
--]]--
Attribute.key = {}
Attribute.shortcut = {}
function Attribute.key.set (widget, value)
function Attribute.shortcut.set (widget, value)
local layout = widget.layout.master or widget.layout
local oldValue = widget.attributes.key
local oldValue = widget.attributes.shortcut
if oldValue then
local mainKey, modifierFlags = parseKeyCombo(oldValue)
layout.accelerators[modifierFlags][mainKey] = nil
layout.shortcuts[modifierFlags][mainKey] = nil
end
if value then
local mainKey, modifierFlags = parseKeyCombo(value)
layout.accelerators[modifierFlags][mainKey] = widget
layout.shortcuts[modifierFlags][mainKey] = widget
end
widget.attributes.key = value
widget.attributes.shortcut = value
end
--[[--

View File

@@ -56,8 +56,12 @@ local callback = {
Backend.run = function ()
local event = sdl.Event()
local tickInterval = 16 -- ~60 fps (with room)
local nextTick = 0
local sdl = sdl
while true do
sdl.pumpEvents()
while sdl.pollEvent(event) ~= 0 do
@@ -94,8 +98,14 @@ Backend.run = function ()
sdl.setRenderDrawColor(renderer, 0, 0, 0, 255)
sdl.renderClear(renderer)
callback.draw()
local now = sdl.getTicks()
if nextTick > now then
sdl.delay(nextTick - now)
end
nextTick = now + tickInterval
sdl.renderPresent(renderer)
sdl.delay(1)
end
end
@@ -185,9 +195,7 @@ Backend.getMousePosition = function ()
end
local function SystemCursor (id)
local cursor = sdl.createSystemCursor(id)
ffi.gc(cursor, sdl.freeCursor)
return cursor
return ffi.gc(sdl.createSystemCursor(id), sdl.freeCursor)
end
local systemCursors = {
@@ -258,13 +266,17 @@ end
local lastScissor
Backend.setScissor = function (x, y, w, h)
-- y = y and Backend.getWindowHeight() - (y + h)
lastScissor = x and sdl.Rect(x, y, w, h)
sdl.renderSetClipRect(renderer, lastScissor)
end
Backend.getScissor = function ()
if lastScissor ~= nil then
return lastScissor.x, lastScissor.y, lastScissor.w, lastScissor.h
local x, y = lastScissor.x, lastScissor.y
local w, h = lastScissor.w, lastScissor.h
-- y = y and Backend.getWindowHeight() - (y + h)
return x, y, w, h
end
end

View File

@@ -38,8 +38,8 @@ Event.names = {
'Leave', -- The cursor left a widget, and no button was pressed.
'PressEnter', -- The cursor entered a widget, and a button was pressed.
'PressLeave', -- The cursor left a widget, and a button was pressed.
'PressStart', -- A pointer button or accelerator key was pressed.
'PressEnd', -- A pointer button or accelerator key was released.
'PressStart', -- A pointer button or keyboard shortcut was pressed.
'PressEnd', -- A pointer button or keyboard shortcut was released.
'PressDrag', -- A pressed cursor moved; targets originating widget.
'PressMove', -- A pressed cursor moved; targets widget at cursor position.
'Press', -- A pointer button was pressed and released on the same widget.

View File

@@ -147,12 +147,12 @@ function Input:handlePressedMove (layout, x, y)
})
self.passedWidgets[button] = widget
end
end
end
end -- if originWidget
end -- mouse buttons
return hit
end
function Input:handlePressStart (layout, button, x, y, widget, accelerator)
function Input:handlePressStart (layout, button, x, y, widget, shortcut)
local widget = widget or layout:getWidgetAt(x, y)
local hit = true
if not widget then
@@ -170,13 +170,13 @@ function Input:handlePressStart (layout, button, x, y, widget, accelerator)
widget:bubbleEvent('PressStart', {
hit = hit,
button = button,
accelerator = accelerator,
shortcut = shortcut,
x = x, y = y
})
return hit
end
function Input:handlePressEnd (layout, button, x, y, widget, accelerator)
function Input:handlePressEnd (layout, button, x, y, widget, shortcut)
local widget = widget or layout:getWidgetAt(x, y)
local hit = true
if not widget then
@@ -191,7 +191,7 @@ function Input:handlePressEnd (layout, button, x, y, widget, accelerator)
widget:bubbleEvent('PressEnd', {
hit = hit,
origin = originWidget,
accelerator = accelerator,
shortcut = shortcut,
button = button,
x = x, y = y
})
@@ -199,7 +199,7 @@ function Input:handlePressEnd (layout, button, x, y, widget, accelerator)
widget:bubbleEvent('Press', {
hit = hit,
button = button,
accelerator = accelerator,
shortcut = shortcut,
x = x, y = y
})
end

View File

@@ -60,6 +60,25 @@ function Layout:constructor (data, master)
self.isReady = true
end
--[[--
Create a detached widget.
Internal function used to create widgets that are associated with
a layout, but "detached" from it.
Used by context menus, which use their "owner" widget's layout
for theme and style information but appear in a separate layout.
@tparam table data
A tree of widget data.
@treturn Widget
A widget instance.
--]]--
function Layout:createWidget (data)
return Widget(self, data)
end
local function clearWidget (widget)
widget.textData = nil
widget.fontData = nil
@@ -97,10 +116,6 @@ Master layout
function Layout:setMaster (layout)
self.master = layout
function self:addWidget (...)
return layout:addWidget(...)
end
reset(self)
return self
end
@@ -259,12 +274,12 @@ function Layout:getWidgetAt (x, y, root)
if root:isAt(x, y) then return root end
end
-- Add handlers for keyboard accelerators, tab focus, and mouse wheel scroll
-- Add handlers for keyboard shortcuts, tab focus, and mouse wheel scroll
function Layout:addDefaultHandlers ()
self.accelerators = {}
self.shortcuts = {}
for i = 0, 8 do
self.accelerators[i] = {}
self.shortcuts[i] = {}
end
self:onPressStart(function (event)
@@ -299,8 +314,8 @@ function Layout:addDefaultHandlers ()
self:onKeyPress(function (event)
-- keyboard accelerators
local entry = self.accelerators[event.modifierFlags]
-- keyboard shortcuts
local entry = self.shortcuts[event.modifierFlags]
local acceleratedWidget = entry and entry[event.key]
if acceleratedWidget then
acceleratedWidget.hovered = true
@@ -331,8 +346,8 @@ function Layout:addDefaultHandlers ()
self:onKeyRelease(function (event)
-- accelerators
local entry = self.accelerators[event.modifierFlags]
-- shortcuts
local entry = self.shortcuts[event.modifierFlags]
local acceleratedWidget = entry and entry[event.key]
if acceleratedWidget then

View File

@@ -239,6 +239,10 @@ end
--[[--
Define a custom attribute for this widget.
When an attribute is defined, the current value is stored locally and
removed from the widget's own properties and its attributes collection.
Then, the newly-defined setter is called with the stored value.
@tparam string name
The name of the attribute.
@@ -249,9 +253,11 @@ A table, optionally containing `get` and `set` functions (see `Attribute`).
Return this widget for chaining.
--]]--
function Widget:defineAttribute (name, descriptor)
local value = self[name]
local value = rawget(self, name)
if value == nil then value = self.attributes[name] end
self.attributeDescriptors[name] = descriptor or {}
rawset(self, name, nil)
self.attributes[name] = nil
self[name] = value
return self
end

View File

@@ -13,10 +13,10 @@ local Backend = require(ROOT .. 'backend')
local Layout, Event
local function checkMouseButton (layout, event)
local function checkMouseButton (self, event)
local button = event.button
if not button then return false end
if layout.isContextMenu then
if self.isContextMenu then
return button == 'left' or button == 'right'
end
return button == 'left'
@@ -133,14 +133,14 @@ local function registerLayoutEvents (self)
if self.parentMenu == self.rootMenu then
deactivateSiblings(self.rootMenu[1])
end
elseif checkMouseButton(menuLayout, event) then
elseif checkMouseButton(self, event) then
activate(event)
end
end)
menuLayout:onPress(function (event)
-- if event.button ~= 'left' then return end
if not checkMouseButton(menuLayout, event) then return end
if not checkMouseButton(self, event) then return end
for widget in event.target:eachAncestor(true) do
if widget.type == 'menu.item' and #widget.items == 0 then
menuLayout:hide()
@@ -151,7 +151,7 @@ local function registerLayoutEvents (self)
menuLayout:onPressEnd(function (event)
-- if event.button ~= 'left' then return end
if not checkMouseButton(menuLayout, event) then return end
if not checkMouseButton(self, event) then return end
for widget in event.target:eachAncestor(true) do
if widget.type == 'menu.item' and #widget.items == 0
and event.target ~= event.origin then
@@ -231,7 +231,6 @@ local function createLayout (self)
end
return function (self)
self.context = false
extractChildren(self)
initialize(self)
registerEvents(self)

View File

@@ -41,26 +41,16 @@ Contains the index in `items` of the item being displayed.
self.items = {}
self.index = 1
self.flow = 'x' -- TODO: support vertical stepper
local contextMenu
for index, child in ipairs(self) do
child.type = child.type or 'stepper.item'
if child.isContextMenu then
contextMenu = child
else
self.items[index] = child
end
self.items[index] = child
self[index] = nil
end
local before = self:addChild { type = 'stepper.before' }
local view = self:addChild { type = 'stepper.view' }
local after = self:addChild { type = 'stepper.after' }
if contextMenu then
self:addChild(contextMenu)
end
self:onReshape(function (event)
if self.flow == 'x' then

View File

@@ -198,13 +198,10 @@ This color is used to indicate the selected range of text.
--]]--
self:defineAttribute('highlight')
local defaultHighlight = { 0x80, 0x80, 0x80, 0x80 }
--[[--
@section end
--]]--
if not self.highlight then
self.highlight = { 0x80, 0x80, 0x80, 0x80 }
end
self.scrollX = 0
@@ -286,7 +283,7 @@ This color is used to indicate the selected range of text.
if self.focused then
-- draw highlighted selection
Backend.setColor(self.highlight)
Backend.setColor(self.highlight or defaultHighlight)
Backend.drawRectangle('fill', startX, y, width, height)
-- draw cursor selection
if Backend.getTime() % 2 < 1.75 then