From 5025be971df9dc77da541010bc528633786bb0a5 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 10 Jun 2012 17:52:09 +0200 Subject: [PATCH] separated dialog.lua into source files for each individual function --- frontend/ui/button.lua | 45 +++++ frontend/ui/confirmbox.lua | 82 +++++++++ frontend/ui/filechooser.lua | 2 +- frontend/ui/focusmanager.lua | 82 +++++++++ frontend/ui/infomessage.lua | 54 ++++++ frontend/ui/{dialog.lua => menu.lua} | 260 +-------------------------- frontend/ui/ui.lua | 1 - reader.lua | 1 + wtest.lua | 4 + 9 files changed, 271 insertions(+), 260 deletions(-) create mode 100644 frontend/ui/button.lua create mode 100644 frontend/ui/confirmbox.lua create mode 100644 frontend/ui/focusmanager.lua create mode 100644 frontend/ui/infomessage.lua rename frontend/ui/{dialog.lua => menu.lua} (55%) diff --git a/frontend/ui/button.lua b/frontend/ui/button.lua new file mode 100644 index 000000000..e63dfe022 --- /dev/null +++ b/frontend/ui/button.lua @@ -0,0 +1,45 @@ +require "ui/widget" + +--[[ +a button widget +]] +Button = WidgetContainer:new{ + text = nil, -- mandatory + preselect = false +} + +function Button:init() + -- set FrameContainer content + self[1] = FrameContainer:new{ + margin = 0, + bordersize = 3, + background = 0, + radius = 15, + padding = 2, + + HorizontalGroup:new{ + HorizontalSpan:new{ width = 8 }, + TextWidget:new{ + text = self.text, + face = Font:getFace("cfont", 20) + }, + HorizontalSpan:new{ width = 8 }, + } + } + if self.preselect then + self[1].color = 15 + else + self[1].color = 5 + end +end + +function Button:onFocus() + self[1].color = 15 + return true +end + +function Button:onUnfocus() + self[1].color = 5 + return true +end + diff --git a/frontend/ui/confirmbox.lua b/frontend/ui/confirmbox.lua new file mode 100644 index 000000000..5bc40e29c --- /dev/null +++ b/frontend/ui/confirmbox.lua @@ -0,0 +1,82 @@ +require "ui/widget" +require "ui/focusmanager" +require "ui/button" + +--[[ +Widget that shows a message and OK/Cancel buttons +]] +ConfirmBox = FocusManager:new{ + text = "no text", + width = nil, + ok_text = "OK", + cancel_text = "Cancel", + ok_callback = function() end, + cancel_callback = function() end, +} + +function ConfirmBox:init() + -- calculate box width on the fly if not given + if not self.width then + self.width = Screen:getWidth() - 200 + end + -- build bottons + self.key_events.Close = { {{"Home","Back"}}, doc = "cancel" } + self.key_events.Select = { {{"Enter","Press"}}, doc = "chose selected option" } + + local ok_button = Button:new{ + text = self.ok_text, + } + local cancel_button = Button:new{ + text = self.cancel_text, + preselect = true + } + + self.layout = { { ok_button, cancel_button } } + self.selected.x = 2 -- Cancel is default + + self[1] = CenterContainer:new{ + dimen = Screen:getSize(), + FrameContainer:new{ + margin = 2, + background = 0, + padding = 10, + HorizontalGroup:new{ + ImageWidget:new{ + file = "resources/info-i.png" + }, + HorizontalSpan:new{ width = 10 }, + VerticalGroup:new{ + align = "left", + TextBoxWidget:new{ + text = self.text, + face = Font:getFace("cfont", 30), + width = self.width, + }, + VerticalSpan:new{ width = 10 }, + HorizontalGroup:new{ + ok_button, + HorizontalSpan:new{ width = 10 }, + cancel_button, + } + } + } + } + } +end + +function ConfirmBox:onClose() + UIManager:close(self) + return true +end + +function ConfirmBox:onSelect() + DEBUG("selected:", self.selected.x) + if self.selected.x == 1 then + self:ok_callback() + else + self:cancel_callback() + end + UIManager:close(self) + return true +end + diff --git a/frontend/ui/filechooser.lua b/frontend/ui/filechooser.lua index 515f3f8b8..2ab853bb7 100644 --- a/frontend/ui/filechooser.lua +++ b/frontend/ui/filechooser.lua @@ -1,4 +1,4 @@ -require "ui/dialog" -- for Menu +require "ui/menu" FileChooser = Menu:new{ path = ".", diff --git a/frontend/ui/focusmanager.lua b/frontend/ui/focusmanager.lua new file mode 100644 index 000000000..0f5000c10 --- /dev/null +++ b/frontend/ui/focusmanager.lua @@ -0,0 +1,82 @@ +--[[ +Wrapper Widget that manages focus for a whole dialog + +supports a 2D model of active elements + +e.g.: + layout = { + { textinput, textinput }, + { okbutton, cancelbutton } + } + +this is a dialog with 2 rows. in the top row, there is the +single (!) widget . when the focus is in this +group, left/right movement seems (!) to be doing nothing. + +in the second row, there are two widgets and you can move +left/right. also, you can go up from both to reach , +and from that go down and (depending on internat coordinates) +reach either or . + +but notice that this does _not_ do the layout for you, +it rather defines an abstract layout. +]] +FocusManager = InputContainer:new{ + selected = nil, -- defaults to x=1, y=1 + layout = nil, -- mandatory + movement_allowed = { x = true, y = true } +} + +function FocusManager:init() + self.selected = { x = 1, y = 1 } + self.key_events = { + -- these will all generate the same event, just with different arguments + FocusUp = { {"Up"}, doc = "move focus up", event = "FocusMove", args = {0, -1} }, + FocusDown = { {"Down"}, doc = "move focus down", event = "FocusMove", args = {0, 1} }, + FocusLeft = { {"Left"}, doc = "move focus left", event = "FocusMove", args = {-1, 0} }, + FocusRight = { {"Right"}, doc = "move focus right", event = "FocusMove", args = {1, 0} }, + } +end + +function FocusManager:onFocusMove(args) + local dx, dy = unpack(args) + + if (dx ~= 0 and not self.movement_allowed.x) + or (dy ~= 0 and not self.movement_allowed.y) then + return true + end + + if not self.layout or not self.layout[self.selected.y] or not self.layout[self.selected.y][self.selected.x] then + return true + end + local current_item = self.layout[self.selected.y][self.selected.x] + while true do + if self.selected.x + dx > #self.layout[self.selected.y] + or self.selected.x + dx < 1 then + break -- abort when we run into horizontal borders + end + + -- move cyclic in vertical direction + if self.selected.y + dy > #self.layout then + self.selected.y = 1 + elseif self.selected.y + dy < 1 then + self.selected.y = #self.layout + else + self.selected.y = self.selected.y + dy + end + self.selected.x = self.selected.x + dx + + if self.layout[self.selected.y][self.selected.x] ~= current_item + or not self.layout[self.selected.y][self.selected.x].is_inactive then + -- we found a different object to focus + current_item:handleEvent(Event:new("Unfocus")) + self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus")) + -- trigger a repaint (we need to be the registered widget!) + UIManager:setDirty(self) + break + end + end + + return true +end + diff --git a/frontend/ui/infomessage.lua b/frontend/ui/infomessage.lua new file mode 100644 index 000000000..85efe3ee6 --- /dev/null +++ b/frontend/ui/infomessage.lua @@ -0,0 +1,54 @@ +require "ui/ui" +require "ui/widget" + +--[[ +Widget that displays an informational message + +it vanishes on key press or after a given timeout +]] +InfoMessage = InputContainer:new{ + face = Font:getFace("infofont", 25), + text = "", + timeout = nil, + + key_events = { + AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" } + } +} + +function InfoMessage:init() + -- we construct the actual content here because self.text is only available now + self[1] = CenterContainer:new{ + dimen = Screen:getSize(), + FrameContainer:new{ + margin = 2, + background = 0, + HorizontalGroup:new{ + align = "center", + ImageWidget:new{ + file = "resources/info-i.png" + }, + HorizontalSpan:new{ width = 10 }, + TextBoxWidget:new{ + text = self.text, + face = Font:getFace("cfont", 30) + } + } + } + } +end + +function InfoMessage:onShow() + -- triggered by the UIManager after we got successfully shown (not yet painted) + if self.timeout then + UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end) + end + return true +end + +function InfoMessage:onAnyKeyPressed() + -- triggered by our defined key events + UIManager:close(self) + return true +end + diff --git a/frontend/ui/dialog.lua b/frontend/ui/menu.lua similarity index 55% rename from frontend/ui/dialog.lua rename to frontend/ui/menu.lua index 21079e14c..af1d789ad 100644 --- a/frontend/ui/dialog.lua +++ b/frontend/ui/menu.lua @@ -1,264 +1,8 @@ require "ui/widget" +require "ui/focusmanager" +require "ui/infomessage" require "ui/font" ---[[ -Wrapper Widget that manages focus for a whole dialog - -supports a 2D model of active elements - -e.g.: - layout = { - { textinput, textinput }, - { okbutton, cancelbutton } - } - -this is a dialog with 2 rows. in the top row, there is the -single (!) widget . when the focus is in this -group, left/right movement seems (!) to be doing nothing. - -in the second row, there are two widgets and you can move -left/right. also, you can go up from both to reach , -and from that go down and (depending on internat coordinates) -reach either or . - -but notice that this does _not_ do the layout for you, -it rather defines an abstract layout. -]] -FocusManager = InputContainer:new{ - selected = nil, -- defaults to x=1, y=1 - layout = nil, -- mandatory - movement_allowed = { x = true, y = true } -} - -function FocusManager:init() - self.selected = { x = 1, y = 1 } - self.key_events = { - -- these will all generate the same event, just with different arguments - FocusUp = { {"Up"}, doc = "move focus up", event = "FocusMove", args = {0, -1} }, - FocusDown = { {"Down"}, doc = "move focus down", event = "FocusMove", args = {0, 1} }, - FocusLeft = { {"Left"}, doc = "move focus left", event = "FocusMove", args = {-1, 0} }, - FocusRight = { {"Right"}, doc = "move focus right", event = "FocusMove", args = {1, 0} }, - } -end - -function FocusManager:onFocusMove(args) - local dx, dy = unpack(args) - - if (dx ~= 0 and not self.movement_allowed.x) - or (dy ~= 0 and not self.movement_allowed.y) then - return true - end - - if not self.layout or not self.layout[self.selected.y] or not self.layout[self.selected.y][self.selected.x] then - return true - end - local current_item = self.layout[self.selected.y][self.selected.x] - while true do - if self.selected.x + dx > #self.layout[self.selected.y] - or self.selected.x + dx < 1 then - break -- abort when we run into horizontal borders - end - - -- move cyclic in vertical direction - if self.selected.y + dy > #self.layout then - self.selected.y = 1 - elseif self.selected.y + dy < 1 then - self.selected.y = #self.layout - else - self.selected.y = self.selected.y + dy - end - self.selected.x = self.selected.x + dx - - if self.layout[self.selected.y][self.selected.x] ~= current_item - or not self.layout[self.selected.y][self.selected.x].is_inactive then - -- we found a different object to focus - current_item:handleEvent(Event:new("Unfocus")) - self.layout[self.selected.y][self.selected.x]:handleEvent(Event:new("Focus")) - -- trigger a repaint (we need to be the registered widget!) - UIManager:setDirty(self) - break - end - end - - return true -end - - ---[[ -a button widget -]] -Button = WidgetContainer:new{ - text = nil, -- mandatory - preselect = false -} - -function Button:init() - -- set FrameContainer content - self[1] = FrameContainer:new{ - margin = 0, - bordersize = 3, - background = 0, - radius = 15, - padding = 2, - - HorizontalGroup:new{ - HorizontalSpan:new{ width = 8 }, - TextWidget:new{ - text = self.text, - face = Font:getFace("cfont", 20) - }, - HorizontalSpan:new{ width = 8 }, - } - } - if self.preselect then - self[1].color = 15 - else - self[1].color = 5 - end -end - -function Button:onFocus() - self[1].color = 15 - return true -end - -function Button:onUnfocus() - self[1].color = 5 - return true -end - - ---[[ -Widget that shows a message and OK/Cancel buttons -]] -ConfirmBox = FocusManager:new{ - text = "no text", - width = nil, - ok_text = "OK", - cancel_text = "Cancel", - ok_callback = function() end, - cancel_callback = function() end, -} - -function ConfirmBox:init() - -- calculate box width on the fly if not given - if not self.width then - self.width = Screen:getWidth() - 200 - end - -- build bottons - self.key_events.Close = { {{"Home","Back"}}, doc = "cancel" } - self.key_events.Select = { {{"Enter","Press"}}, doc = "chose selected option" } - - local ok_button = Button:new{ - text = self.ok_text, - } - local cancel_button = Button:new{ - text = self.cancel_text, - preselect = true - } - - self.layout = { { ok_button, cancel_button } } - self.selected.x = 2 -- Cancel is default - - self[1] = CenterContainer:new{ - dimen = Screen:getSize(), - FrameContainer:new{ - margin = 2, - background = 0, - padding = 10, - HorizontalGroup:new{ - ImageWidget:new{ - file = "resources/info-i.png" - }, - HorizontalSpan:new{ width = 10 }, - VerticalGroup:new{ - align = "left", - TextBoxWidget:new{ - text = self.text, - face = Font:getFace("cfont", 30), - width = self.width, - }, - VerticalSpan:new{ width = 10 }, - HorizontalGroup:new{ - ok_button, - HorizontalSpan:new{ width = 10 }, - cancel_button, - } - } - } - } - } -end - -function ConfirmBox:onClose() - UIManager:close(self) - return true -end - -function ConfirmBox:onSelect() - DEBUG("selected:", self.selected.x) - if self.selected.x == 1 then - self:ok_callback() - else - self:cancel_callback() - end - UIManager:close(self) - return true -end - - ---[[ -Widget that displays an informational message - -it vanishes on key press or after a given timeout -]] -InfoMessage = InputContainer:new{ - face = Font:getFace("infofont", 25), - text = "", - timeout = nil, - - key_events = { - AnyKeyPressed = { { Input.group.Any }, seqtext = "any key", doc = "close dialog" } - } -} - -function InfoMessage:init() - -- we construct the actual content here because self.text is only available now - self[1] = CenterContainer:new{ - dimen = Screen:getSize(), - FrameContainer:new{ - margin = 2, - background = 0, - HorizontalGroup:new{ - align = "center", - ImageWidget:new{ - file = "resources/info-i.png" - }, - HorizontalSpan:new{ width = 10 }, - TextBoxWidget:new{ - text = self.text, - face = Font:getFace("cfont", 30) - } - } - } - } -end - -function InfoMessage:onShow() - -- triggered by the UIManager after we got successfully shown (not yet painted) - if self.timeout then - UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end) - end - return true -end - -function InfoMessage:onAnyKeyPressed() - -- triggered by our defined key events - UIManager:close(self) - return true -end - - --[[ Widget that displays a shortcut icon for menu item ]] diff --git a/frontend/ui/ui.lua b/frontend/ui/ui.lua index 233163ad1..d7de574d4 100644 --- a/frontend/ui/ui.lua +++ b/frontend/ui/ui.lua @@ -2,7 +2,6 @@ require "ui/geometry" require "ui/inputevent" require "ui/widget" require "ui/screen" -require "ui/dialog" require "settings" -- for DEBUG(), TODO: put DEBUG() somewhere else diff --git a/reader.lua b/reader.lua index 9e2b32351..0d49706d5 100644 --- a/reader.lua +++ b/reader.lua @@ -2,6 +2,7 @@ package.path = "./frontend/?.lua" require "ui/ui" require "ui/readerui" require "ui/filechooser" +require "ui/infomessage" require "document/document" function showReader(file) diff --git a/wtest.lua b/wtest.lua index b6e9dd065..dd18eb9c3 100644 --- a/wtest.lua +++ b/wtest.lua @@ -1,7 +1,11 @@ print(package.path) package.path = "./frontend/?.lua" +require "ui/widget" require "ui/ui" require "ui/readerui" +require "ui/menu" +require "ui/infomessage" +require "ui/confirmbox" require "document/document" TestGrid = Widget:new{}