mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
doc: event propagation for widgets
This commit is contained in:
@@ -1,20 +1,17 @@
|
||||
Data Store
|
||||
==========
|
||||
|
||||
LuaSettings
|
||||
-----------
|
||||
## LuaSettings ##
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
DocSettings
|
||||
-----------
|
||||
## DocSettings ##
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
SQLite3
|
||||
-------
|
||||
## SQLite3 ##
|
||||
|
||||
KOReader ships with the SQLite3 library, which is a great embedded database for
|
||||
desktop and mobile applications.
|
||||
|
||||
@@ -1,10 +1,45 @@
|
||||
Builtin Events
|
||||
==============
|
||||
Events
|
||||
======
|
||||
|
||||
Reader Events
|
||||
-------------
|
||||
## Overview ##
|
||||
|
||||
All widgets is a subclass of @{ui.widget.eventlistener}, therefore inherit
|
||||
the @{ui.widget.eventlistener:handleEvent|handleEvent} method. To send an event
|
||||
to a widget, you can simply invoke the handleEvent method like the following:
|
||||
|
||||
```lua
|
||||
widget_foo:handleEvent(Event:new("Timeout"))
|
||||
```
|
||||
|
||||
|
||||
## Builtin events ##
|
||||
|
||||
### Reader events ###
|
||||
|
||||
* UpdatePos: emitted by typesetting related modules to notify other modules to
|
||||
recalculate the view based on the new typesetting.
|
||||
|
||||
* PosUpdate: emitted by readerrolling module to signal a change in pos.
|
||||
|
||||
|
||||
## Event propagation ##
|
||||
|
||||
Most of the UI components is a subclass of
|
||||
@{ui.widget.container.widgetcontainer|WidgetContainer}. A WidgetContainer is an array that
|
||||
stores a list of children widgets.
|
||||
|
||||
When @{ui.widget.container.widgetcontainer:handleEvent|WidgetContainer:handleEvent} is called with a new
|
||||
event, it will run roughly the following code:
|
||||
|
||||
```lua
|
||||
-- First propagate event to its children
|
||||
for _, widget in ipairs(self) do
|
||||
if widget:handleEvent(event) then
|
||||
-- stop propagating when an event handler returns true
|
||||
return true
|
||||
end
|
||||
end
|
||||
-- If not consumed by children, try consume by itself
|
||||
return self["on"..event.name](self, unpack(event.args))
|
||||
```
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
Hacking
|
||||
=======
|
||||
|
||||
Developing UI Widgets
|
||||
---------------------
|
||||
## Developing UI widgets ##
|
||||
|
||||
`tools/wbuilder.lua` is your friend, if you need to create new UI widgets. It
|
||||
sets up a minimal environment to bootstrap KOReader's UI framework to avoid
|
||||
|
||||
@@ -8,7 +8,7 @@ widgets event-aware see the implementation in @{ui.widget.container.widgetcontai
|
||||
]]
|
||||
|
||||
--[[--
|
||||
@field handler name for the handler method
|
||||
@field handler name for the handler method: `"on"..Event.name`
|
||||
@field args array of arguments for the event
|
||||
@table Event
|
||||
]]
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
--[[--
|
||||
WidgetContainer is a container for another Widget. Base class for all the widget containers.
|
||||
WidgetContainer is a container for one or multiple Widgets. It is the base
|
||||
class for all the container widgets.
|
||||
|
||||
It handles event propagation and paiting (with different alignments) for its children.
|
||||
Child widgets are stored in WidgetContainer as conventional array items:
|
||||
|
||||
WidgetContainer:new{
|
||||
ChildWidgetFoo:new{},
|
||||
ChildWidgetBar:new{},
|
||||
...
|
||||
}
|
||||
|
||||
It handles event propagation and painting (with different alignments) for its children.
|
||||
]]
|
||||
|
||||
local Geom = require("ui/geometry")
|
||||
@@ -85,8 +94,8 @@ end
|
||||
|
||||
--[[--
|
||||
WidgetContainer will pass event to its children by calling their handleEvent
|
||||
methods. If no child responded to the event (by returning true), it will call its own
|
||||
handleEvent method.
|
||||
methods. If no child consumes the event (by returning true), it will try
|
||||
to react to the event by itself.
|
||||
|
||||
@tparam ui.event.Event event
|
||||
@treturn bool true if event is consumed, othewise false. A consumed event will
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
--[[
|
||||
The EventListener is an interface that handles events
|
||||
--[[--
|
||||
The EventListener is an interface that handles events. This is the base class
|
||||
for @{ui.widget.widget}
|
||||
|
||||
EventListeners have a rudimentary event handler/dispatcher that
|
||||
will call a method "onEventName" for an event with name
|
||||
"EventName"
|
||||
--]]
|
||||
]]
|
||||
|
||||
local EventListener = {}
|
||||
local DEBUG = require("dbg")
|
||||
|
||||
@@ -16,6 +18,15 @@ function EventListener:new(new_o)
|
||||
return o
|
||||
end
|
||||
|
||||
--[[--
|
||||
Invoke handler method for an event.
|
||||
|
||||
Handler method name is determined by @{ui.event.Event}'s handler field.
|
||||
By default, it's `"on"..Event.name`.
|
||||
|
||||
@tparam ui.event.Event event
|
||||
@treturn bool return true if event is consumed successfully.
|
||||
]]
|
||||
function EventListener:handleEvent(event)
|
||||
if self[event.handler] then
|
||||
if self.id or self.name then
|
||||
|
||||
@@ -1,34 +1,40 @@
|
||||
local EventListener = require("ui/widget/eventlistener")
|
||||
--[[--
|
||||
This is a generic Widget interface, which is the base class for all other widgets.
|
||||
|
||||
--[[
|
||||
This is a generic Widget interface
|
||||
|
||||
widgets can be queried about their size and can be paint.
|
||||
Widgets can be queried about their size and can be painted on screen.
|
||||
that's it for now. Probably we need something more elaborate
|
||||
later.
|
||||
|
||||
if the table that was given to us as parameter has an "init"
|
||||
If the table that was given to us as parameter has an "init"
|
||||
method, it will be called. use this to set _instance_ variables
|
||||
rather than class variables.
|
||||
--]]
|
||||
]]
|
||||
|
||||
local EventListener = require("ui/widget/eventlistener")
|
||||
local Widget = EventListener:new()
|
||||
|
||||
--[[
|
||||
Use this method to define a class that's inherited from current class.
|
||||
It only setup the metabale (or prototype chain) and will not initiatie
|
||||
a real instance, i.e. call self:init()
|
||||
--]]
|
||||
function Widget:extend(from_o)
|
||||
local o = from_o or {}
|
||||
--[[--
|
||||
Use this method to define a subclass widget class that's inherited from a
|
||||
base class widget. It only setups the metabale (or prototype chain) and will
|
||||
not initiate a real instance, i.e. call self:init().
|
||||
|
||||
@tparam Widget baseclass
|
||||
@treturn Widget
|
||||
]]
|
||||
function Widget:extend(baseclass)
|
||||
local o = baseclass or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
return o
|
||||
end
|
||||
|
||||
--[[
|
||||
--[[--
|
||||
Use this method to initiatie a instance of a class, don't use it for class
|
||||
definition.
|
||||
--]]
|
||||
definition because it also calls self:init().
|
||||
|
||||
@tparam Widget o
|
||||
@treturn Widget
|
||||
]]
|
||||
function Widget:new(o)
|
||||
o = self:extend(o)
|
||||
-- Both o._init and o.init are called on object creation. But o._init is
|
||||
@@ -40,10 +46,26 @@ function Widget:new(o)
|
||||
return o
|
||||
end
|
||||
|
||||
--[[
|
||||
FIXME: enable this doc section when we verified all self.dimen is a Geom so we
|
||||
can return self.dime:copy().
|
||||
|
||||
Return size of the widget.
|
||||
|
||||
@treturn ui.geometry.Geom
|
||||
--]]
|
||||
function Widget:getSize()
|
||||
return self.dimen
|
||||
end
|
||||
|
||||
--[[--
|
||||
Paint widget to a BlitBuffer.
|
||||
|
||||
@tparam BlitBuffer BlitBuffer to paint to. If it's the screen BlitBuffer, then
|
||||
widget will show up on screen refresh.
|
||||
@int x x offset within the BlitBuffer
|
||||
@int y y offset within the BlitBuffer
|
||||
]]
|
||||
function Widget:paintTo(bb, x, y)
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user