hotkeys use modifiers

This commit is contained in:
airstruck
2015-11-11 23:49:54 -05:00
parent 68a250e273
commit 6aaa128463
13 changed files with 205 additions and 113 deletions

View File

@@ -144,7 +144,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-09 17:17:21 </i>
<i style="float:right;">Last updated 2015-11-11 18:35:22 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@@ -70,6 +70,10 @@ and are trapped by the first layout that can handle the event
</table>
<h2><a href="#Methods">Methods</a></h2>
<table class="function_list">
<tr>
<td class="name" nowrap><a href="#Layout:setMaster">Layout:setMaster (layout)</a></td>
<td class="summary">Set the master layout for this layout.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:setStyle">Layout:setStyle (rules)</a></td>
<td class="summary">Set the style from a definition table or function.</td>
@@ -79,6 +83,14 @@ and are trapped by the first layout that can handle the event
<td class="summary">Set the theme from a definition table or function.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:getStyle">Layout:getStyle ()</a></td>
<td class="summary">Get the style from master layout or this layout.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:getTheme">Layout:getTheme ()</a></td>
<td class="summary">Get the theme from master layout or this layout.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Layout:show">Layout:show ()</a></td>
<td class="summary">Show the layout.</td>
</tr>
@@ -138,6 +150,37 @@ and are trapped by the first layout that can handle the event
<h2 class="section-header "><a name="Methods"></a>Methods</h2>
<dl class="function">
<dt>
<a name = "Layout:setMaster"></a>
<strong>Layout:setMaster (layout)</strong>
</dt>
<dd>
Set the master layout for this layout. </p>
<p>This layout's theme and style will be set the same as the master layout, and
widgets added to this layout will be indexed and keyboard-accelerated by the
master layout instead of this layout.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">layout</span>
<span class="types"><a class="type" href="../classes/Layout.html#">Layout</a></span>
Master layout
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Layout.html#">Layout</a></span>
Self
</ol>
</dd>
<dt>
<a name = "Layout:setStyle"></a>
<strong>Layout:setStyle (rules)</strong>
@@ -154,6 +197,12 @@ and are trapped by the first layout that can handle the event
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="../classes/Layout.html#">Layout</a></span>
Self
</ol>
@@ -179,6 +228,46 @@ and are trapped by the first layout that can handle the event
</dd>
<dt>
<a name = "Layout:getStyle"></a>
<strong>Layout:getStyle ()</strong>
</dt>
<dd>
Get the style from master layout or this layout.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Style table.
</ol>
</dd>
<dt>
<a name = "Layout:getTheme"></a>
<strong>Layout:getTheme ()</strong>
</dt>
<dd>
Get the theme from master layout or this layout.
<h3>Returns:</h3>
<ol>
<span class="types"><a class="type" href="http://www.lua.org/manual/5.1/manual.html#5.5">table</a></span>
Theme table.
</ol>
</dd>
<dt>
<a name = "Layout:show"></a>
@@ -295,7 +384,7 @@ found, and focuses that widget.
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-09 17:17:21 </i>
<i style="float:right;">Last updated 2015-11-11 18:35:22 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@@ -69,10 +69,6 @@
<td class="summary">Fire an event on this widget and each ancestor.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:setValue">Widget:setValue (value)</a></td>
<td class="summary">Set widget's value property and bubble a Change event.</td>
</tr>
<tr>
<td class="name" nowrap><a href="#Widget:getPreviousSibling">Widget:getPreviousSibling ()</a></td>
<td class="summary">Get widget's previous sibling.</td>
</tr>
@@ -211,33 +207,6 @@ This table is identical to the constructed widget.
</dd>
<dt>
<a name = "Widget:setValue"></a>
<strong>Widget:setValue (value)</strong>
</dt>
<dd>
Set widget's value property and bubble a Change event.
<h3>Parameters:</h3>
<ul>
<li><span class="parameter">value</span>
<span class="types"><span class="type">mixed</span></span>
The new value of the widget.
</li>
</ul>
<h3>Returns:</h3>
<ol>
<span class="types"><span class="type">mixed</span></span>
The old value of the widget.
</ol>
</dd>
<dt>
<a name = "Widget:getPreviousSibling"></a>
@@ -611,7 +580,7 @@ on the parent widget.
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-09 17:17:21 </i>
<i style="float:right;">Last updated 2015-11-11 18:35:22 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@@ -64,7 +64,7 @@
</div> <!-- id="main" -->
<div id="about">
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
<i style="float:right;">Last updated 2015-11-09 17:17:21 </i>
<i style="float:right;">Last updated 2015-11-11 18:35:22 </i>
</div> <!-- id="about" -->
</div> <!-- id="container" -->
</body>

View File

@@ -59,7 +59,7 @@ local mainForm = { id = 'mainWindow', type = 'panel',
{ text = 'Licenses', key = 'f3' },
},
},
{ type = 'panel', id = 'toolbar', flow = 'x',
{ type = 'panel', id = 'toolbar', style = 'toolbar', flow = 'x',
{ type = 'button', id = 'newButton', style = 'toolButton', key = 'z',
icon = 'icon/32px/Blueprint.png' },
{ type = 'button', id = 'loadButton', style = 'toolButton',
@@ -84,11 +84,11 @@ local mainForm = { id = 'mainWindow', type = 'panel',
{ type = 'panel', text = 'A slider', align = 'bottom', height = 24, padding = 4 },
{ type = 'slider', height = 32, margin = 4, id = 'slidey', value = 0 },
{ type = 'panel', text = 'A stepper', align = 'bottom', height = 24, padding = 4 },
{ type = 'stepper', height = 32, margin = 4, options = {
{ type = 'stepper', height = 32, margin = 4,
{ value = 1, text = 'Thing One' },
{ value = 2, text = 'Thing Two' },
{ value = 3, text = 'Thing Three' },
} },
},
{ type = 'panel', text = 'A progress bar', align = 'bottom', height = 24, padding = 4 },
{ type = 'progress', height = 32, margin = 4, id = 'progressBar', },
},
@@ -114,7 +114,7 @@ layout.leftSideBox:addChild {
}
layout.slidey:onChange(function (event)
layout.progressBar:setValue(event.value)
layout.progressBar.value = event.value
end)
layout:onMove(function (event)

View File

@@ -20,6 +20,14 @@ function Input:handleDisplay (layout)
Event.Display:emit(layout)
end
function Input:getModifierFlags ()
local alt = love.keyboard.isDown('lalt', 'ralt') and 1 or 0
local ctrl = love.keyboard.isDown('lctrl', 'rctrl') and 2 or 0
local shift = love.keyboard.isDown('lshift', 'rshift') and 4 or 0
return alt + ctrl + shift
end
function Input:handleKeyPress (layout, key, x, y)
local widget = layout.focusedWidget or layout:getWidgetAt(x, y)
local hit = true
@@ -29,7 +37,10 @@ function Input:handleKeyPress (layout, key, x, y)
end
local result = widget:bubbleEvent('KeyPress', {
hit = hit,
key = key, x = x, y = y
key = key,
modifierFlags = self:getModifierFlags(),
x = x,
y = y
})
if result ~= nil then return result end
return hit
@@ -44,7 +55,10 @@ function Input:handleKeyRelease (layout, key, x, y)
end
local result = widget:bubbleEvent('KeyRelease', {
hit = hit,
key = key, x = x, y = y
key = key,
modifierFlags = self:getModifierFlags(),
x = x,
y = y
})
if result ~= nil then return result end
return hit

View File

@@ -91,7 +91,7 @@ function Layout:setStyle (rules)
if type(rules) == 'function' then
rules = rules()
end
self.style = Style(rules or {}, { 'id', 'style' })
self.style = Style(rules or {}, { 'style' })
return self
end
@@ -228,6 +228,7 @@ function Layout:getWidgetAt (x, y, root)
end
-- Internal, called from Widget:new
--[[
function Layout:addWidget (widget)
if widget.id then
self[widget.id] = widget
@@ -236,14 +237,19 @@ function Layout:addWidget (widget)
self.accelerators[widget.key] = widget
end
end
]]
-- Add handlers for keyboard accelerators and tab focus
function Layout:addDefaultHandlers ()
self.accelerators = {}
for i = 0, 8 do
self.accelerators[i] = {}
end
self:onKeyPress(function (event)
-- tab / shift-tab cycles focused widget
-- tab/shift-tab cycles focused widget
if event.key == 'tab' then
if love.keyboard.isDown('lshift', 'rshift') then
self:focusPreviousWidget()
@@ -253,7 +259,7 @@ function Layout:addDefaultHandlers ()
return
end
-- space / enter presses focused widget
-- space/enter presses focused widget
local widget = self.focusedWidget
if widget and event.key == 'space' or event.key == ' '
or event.key == 'return' then
@@ -263,7 +269,8 @@ function Layout:addDefaultHandlers ()
end
-- accelerators
local acceleratedWidget = self.accelerators[event.key]
local entry = self.accelerators[event.modifierFlags]
local acceleratedWidget = entry and entry[event.key]
if acceleratedWidget then
acceleratedWidget.hovered = true
self.input:handlePressStart(self, event.key, event.x, event.y,
@@ -283,7 +290,8 @@ function Layout:addDefaultHandlers ()
end
-- accelerators
local acceleratedWidget = self.accelerators[event.key]
local entry = self.accelerators[event.modifierFlags]
local acceleratedWidget = entry and entry[event.key]
if acceleratedWidget then
acceleratedWidget.hovered = false

View File

@@ -35,8 +35,6 @@ return function (config)
type = 'button',
icon = RESOURCE .. 'triangle_right.png',
},
menu = {
height = 24,
},
@@ -85,6 +83,10 @@ return function (config)
slider_hovered = {
},
stepper = {
slices = RESOURCE .. 'button_pressed.png',
},
['stepper.item'] = {
align = 'center middle',
},
text = {
align = 'left middle',

View File

@@ -71,9 +71,50 @@ local function metaNewIndex (self, property, value)
return
end
if property == 'value' then
local oldValue = self.value
self.shadowProperties[property] = value
self:bubbleEvent('Change', {
value = value,
oldValue = oldValue,
})
return
end
if property == 'key' then
self.shadowProperties[property] = value
if not value then return end
local mainKey = (value):match '[^%-]+$'
local alt = (value):match 'alt%-' and 1 or 0
local ctrl = (value):match 'ctrl%-' and 2 or 0
local shift = (value):match 'shift%-' and 4 or 0
local modifierFlags = alt + ctrl + shift
local layout = self.layout.master or self.layout
layout.accelerators[modifierFlags][mainKey] = self
return
end
if property == 'id' then
self.shadowProperties[property] = value
if not value then return end
local layout = self.layout.master or self.layout
layout[value] = self
return
end
rawset(self, property, value)
end
local shadowKeys = {
'font', 'fontSize', 'textColor', 'width', 'height', 'value', 'key', 'id'
}
--[[--
Widget pseudo-constructor.
@@ -98,19 +139,16 @@ local function metaCall (Widget, layout, self)
setmetatable(self, { __index = metaIndex, __newindex = metaNewIndex })
for _, property
in ipairs { 'font', 'fontSize', 'textColor', 'width', 'height' } do
for _, property in ipairs(shadowKeys) do
local value = rawget(self, property)
rawset(self, property, nil)
if value ~= nil then
self[property] = value
end
self[property] = value
end
self.type = self.type or 'generic'
self.fontData = Font(self.font, self.fontSize, self.textColor)
layout:addWidget(self)
-- layout:addWidget(self)
local decorate = Widget.typeDecorators[self.type]
@@ -151,27 +189,6 @@ function Widget:bubbleEvent (eventName, data)
return event:emit(self.layout, data)
end
--[[--
Set widget's value property and bubble a Change event.
@tparam mixed value
The new value of the widget.
@treturn mixed
The old value of the widget.
--]]--
function Widget:setValue (value)
local oldValue = self.value
self.value = value
self:bubbleEvent('Change', {
value = value,
oldValue = oldValue,
})
return oldValue
end
--[[--
Get widget's previous sibling.

View File

@@ -132,15 +132,14 @@ local function initialize (self)
key = ' '
edgeType = 'menu.expander'
else
key = key:gsub('%f[%w].', string.upper)
key = key:gsub('%f[%w].', string.upper) -- :gsub('-', '+')
end
self.height = self.fontData:getLineHeight() + pad * 2
self.flow = 'x'
self:addChild({ icon = icon, width = self.height })
self:addChild({ text = text, width = textWidth })
self:addChild({ text = key, align = 'middle right',
minwidth = self.height,
textColor = keyColor, type = edgeType })
self:addChild { icon = icon, width = self.height }
self:addChild { text = text, width = textWidth }
self:addChild { text = key, align = 'middle right',
minwidth = self.height, textColor = keyColor, type = edgeType }
self.icon = nil
self.text = nil

View File

@@ -4,7 +4,7 @@ return function (self)
return value < 0 and 0 or value > 1 and 1 or value
end
self:setValue(clamp(self.value or 0.5))
self.value = clamp(self.value or 0.5)
self.step = self.step or 0.01
self.flow = 'x' -- TODO: support vertical slider
@@ -28,9 +28,9 @@ return function (self)
thumb:onKeyPress(function (event)
local key = event.key
if key == 'left' or key == 'down' then
self:setValue(clamp(self.value - self.step))
self.value = clamp(self.value - self.step)
elseif event.key == 'right' or key == 'up' then
self:setValue(clamp(self.value + self.step))
self.value = clamp(self.value + self.step)
end
end)
@@ -38,7 +38,7 @@ return function (self)
local x1, y1, x2, y2 = self:getRectangle(true, true)
local halfThumb = thumb:getWidth() / 2
x1, x2 = x1 + halfThumb, x2 - halfThumb
self:setValue(clamp((event.x - x1) / (x2 - x1)))
self.value = clamp((event.x - x1) / (x2 - x1))
thumb:focus()
end

View File

@@ -1,22 +1,17 @@
return function (self)
self.items = {}
self.index = 1
self.flow = 'x' -- TODO: support vertical stepper
local decrement = self:addChild {
type = 'stepper.left',
}
for index, child in ipairs(self) do
child.type = child.type or 'stepper.item'
self.items[index] = child
self[index] = nil
end
local view = self:addChild {
type = 'text',
align = 'middle center',
margin = 0,
canFocus = false,
}
local increment = self:addChild {
type = 'stepper.right',
}
local decrement = self:addChild { type = 'stepper.left' }
local view = self:addChild()
local increment = self:addChild { type = 'stepper.right' }
self:onReshape(function (event)
decrement.width = decrement:getHeight()
@@ -24,30 +19,30 @@ return function (self)
end)
local function updateValue ()
if not self.options then return end
local option = self.options[self.index]
self:setValue(option.value)
view.text = option.text
local item = self.items[self.index]
self.value = item.value
view[1] = nil
view:addChild(item)
item:reshape()
end
decrement:onPress(function (event)
if not self.options then return end
if not self.items then return end
self.index = self.index - 1
if self.index < 1 then
self.index = #self.options
self.index = #self.items
end
updateValue()
end)
increment:onPress(function (event)
if not self.options then return end
if not self.items then return end
self.index = self.index + 1
if self.index > #self.options then
if self.index > #self.items then
self.index = 1
end
updateValue()
end)
updateValue()
end

View File

@@ -113,7 +113,7 @@ local function deleteRange (self)
if first ~= last then
local left = text:sub(1, first)
text = left .. text:sub(last + 1)
self:setValue(text)
self.value = text
setCaretFromText(self, left)
return true
end
@@ -132,7 +132,7 @@ local function deleteCharacterLeft (self)
local offset = utf8.offset(text, -1, first) or 0
local left = text:sub(1, offset)
text = left .. text:sub(first + 1)
self:setValue(text)
self.value = text
setCaretFromText(self, left)
end
@@ -150,7 +150,7 @@ local function pasteFromClipboard (self)
local first, last = getRange(self)
local left = text:sub(1, first) .. pasted
text = left .. text:sub(last + 1)
self:setValue(text)
self.value = text
setCaretFromText(self, left)
end
@@ -160,12 +160,11 @@ local function insertText (self, newText)
local left = text:sub(1, first) .. newText
self.value = left .. text:sub(last + 1)
self:setValue(self.value)
setCaretFromText(self, left)
end
return function (self)
self:setValue(self.value or self.text or '')
self.value = self.value or self.text or ''
self.text = ''
self.highlight = self.highlight or { 0x80, 0x80, 0x80 }
self.scrollX = 0