diff --git a/doc/DataStore.md b/doc/DataStore.md index e438b73a5..337b96f05 100644 --- a/doc/DataStore.md +++ b/doc/DataStore.md @@ -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. diff --git a/doc/Events.md b/doc/Events.md index c0cfe60c3..2038379a3 100644 --- a/doc/Events.md +++ b/doc/Events.md @@ -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)) +``` + diff --git a/doc/Hacking.md b/doc/Hacking.md index 58f9fef1e..53e645df8 100644 --- a/doc/Hacking.md +++ b/doc/Hacking.md @@ -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 diff --git a/frontend/ui/event.lua b/frontend/ui/event.lua index df3759edf..349fd3f35 100644 --- a/frontend/ui/event.lua +++ b/frontend/ui/event.lua @@ -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 ]] diff --git a/frontend/ui/widget/container/widgetcontainer.lua b/frontend/ui/widget/container/widgetcontainer.lua index 801f746b8..9537c9b0a 100644 --- a/frontend/ui/widget/container/widgetcontainer.lua +++ b/frontend/ui/widget/container/widgetcontainer.lua @@ -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 diff --git a/frontend/ui/widget/eventlistener.lua b/frontend/ui/widget/eventlistener.lua index 9433a3d6c..2f0035f56 100644 --- a/frontend/ui/widget/eventlistener.lua +++ b/frontend/ui/widget/eventlistener.lua @@ -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 diff --git a/frontend/ui/widget/widget.lua b/frontend/ui/widget/widget.lua index 5cb1ad8da..e0308a361 100644 --- a/frontend/ui/widget/widget.lua +++ b/frontend/ui/widget/widget.lua @@ -1,34 +1,40 @@ -local EventListener = require("ui/widget/eventlistener") - ---[[ -This is a generic Widget interface +--[[-- +This is a generic Widget interface, which is the base class for all other widgets. -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