From 138def10c381d7cf77a17127f65792d82355b69a Mon Sep 17 00:00:00 2001 From: chrox Date: Fri, 14 Dec 2012 18:20:04 +0800 Subject: [PATCH 1/7] Demo version of koptreader config dialog. --- frontend/document/document.lua | 4 +- frontend/document/koptdocument.lua | 176 ++++++++++++++- frontend/ui/config.lua | 213 ++++++++++++++++++ frontend/ui/reader/readerconfig.lua | 66 ++++++ frontend/ui/reader/readermenu.lua | 2 +- frontend/ui/reader/readerpaging.lua | 14 +- frontend/ui/readerui.lua | 12 + frontend/ui/widget.lua | 20 +- resources/icons/appbar.checkmark.thick.png | Bin 0 -> 433 bytes .../appbar.checkmark.thick.unchecked.png | Bin 0 -> 190 bytes resources/icons/appbar.chevron.left.png | Bin 0 -> 422 bytes resources/icons/appbar.chevron.right.png | Bin 0 -> 410 bytes resources/icons/appbar.column.two.large.png | Bin 0 -> 565 bytes resources/icons/appbar.crop.large.png | Bin 0 -> 1041 bytes resources/icons/appbar.grade.b.large.png | Bin 0 -> 909 bytes resources/icons/appbar.settings.large.png | Bin 0 -> 1743 bytes resources/icons/appbar.text.size.large.png | Bin 0 -> 1338 bytes .../appbar.transform.rotate.right.large.png | Bin 0 -> 992 bytes .../src/appbar.checkmark.thick.unchecked.xaml | 4 + .../icons/src/appbar.checkmark.thick.xaml | 4 + resources/icons/src/appbar.chevron.left.xaml | 4 + resources/icons/src/appbar.chevron.right.xaml | 4 + resources/icons/src/appbar.column.one.xaml | 4 + resources/icons/src/appbar.column.three.xaml | 4 + resources/icons/src/appbar.column.two.xaml | 4 + resources/icons/src/appbar.crop.xaml | 4 + resources/icons/src/appbar.grade.b.xaml | 4 + resources/icons/src/appbar.settings.xaml | 5 + resources/icons/src/appbar.text.size.xaml | 4 + .../src/appbar.transform.rotate.right.xaml | 4 + resources/icons/src/license.txt | 44 ++++ 31 files changed, 587 insertions(+), 13 deletions(-) create mode 100644 frontend/ui/config.lua create mode 100644 frontend/ui/reader/readerconfig.lua create mode 100644 resources/icons/appbar.checkmark.thick.png create mode 100644 resources/icons/appbar.checkmark.thick.unchecked.png create mode 100644 resources/icons/appbar.chevron.left.png create mode 100644 resources/icons/appbar.chevron.right.png create mode 100644 resources/icons/appbar.column.two.large.png create mode 100644 resources/icons/appbar.crop.large.png create mode 100644 resources/icons/appbar.grade.b.large.png create mode 100644 resources/icons/appbar.settings.large.png create mode 100644 resources/icons/appbar.text.size.large.png create mode 100644 resources/icons/appbar.transform.rotate.right.large.png create mode 100644 resources/icons/src/appbar.checkmark.thick.unchecked.xaml create mode 100644 resources/icons/src/appbar.checkmark.thick.xaml create mode 100644 resources/icons/src/appbar.chevron.left.xaml create mode 100644 resources/icons/src/appbar.chevron.right.xaml create mode 100644 resources/icons/src/appbar.column.one.xaml create mode 100644 resources/icons/src/appbar.column.three.xaml create mode 100644 resources/icons/src/appbar.column.two.xaml create mode 100644 resources/icons/src/appbar.crop.xaml create mode 100644 resources/icons/src/appbar.grade.b.xaml create mode 100644 resources/icons/src/appbar.settings.xaml create mode 100644 resources/icons/src/appbar.text.size.xaml create mode 100644 resources/icons/src/appbar.transform.rotate.right.xaml create mode 100644 resources/icons/src/license.txt diff --git a/frontend/document/document.lua b/frontend/document/document.lua index fca96135b..e5ee097c8 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -252,7 +252,7 @@ end -- load implementations: -require "document/pdfdocument" -require "document/djvudocument" +--require "document/pdfdocument" +--require "document/djvudocument" require "document/koptdocument" require "document/credocument" diff --git a/frontend/document/koptdocument.lua b/frontend/document/koptdocument.lua index dcd265699..a67fd1daf 100644 --- a/frontend/document/koptdocument.lua +++ b/frontend/document/koptdocument.lua @@ -3,6 +3,175 @@ require "ui/geometry" require "ui/screen" require "ui/device" +KOPTOptions = { + { + name="font_size", + option_text="", + items_text={"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"}, + text_font_size={14,16,20,23,26,30,34,38,42,46}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true, true, true, true, true, true, true, true}, + values={0.2, 0.3, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.2, 2.8}, + default_value=DKOPTREADER_CONFIG_FONT_SIZE, + show = true, + draw_index = nil,}, + { + name="text_wrap", + option_text="Reflow", + items_text={"on","off"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true}, + values={1, 0}, + default_value=DKOPTREADER_CONFIG_TEXT_WRAP, + show = true, + draw_index = nil,}, + { + name="trim_page", + option_text="Trim Page", + items_text={"auto","manual"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true}, + values={1, 0}, + default_value=DKOPTREADER_CONFIG_TRIM_PAGE, + show = true, + draw_index = nil,}, + { + name="detect_indent", + option_text="Indentation", + items_text={"enable","disable"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true}, + values={1, 0}, + default_value=DKOPTREADER_CONFIG_DETECT_INDENT, + show = false, + draw_index = nil,}, + { + name="defect_size", + option_text="Defect Size", + items_text={"small","medium","large"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true}, + values={0.5, 1.0, 2.0}, + default_value=DKOPTREADER_CONFIG_DEFECT_SIZE, + show = true, + draw_index = nil,}, + { + name="page_margin", + option_text="Page Margin", + items_text={"small","medium","large"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true}, + values={0.02, 0.06, 0.10}, + default_value=DKOPTREADER_CONFIG_PAGE_MARGIN, + show = true, + draw_index = nil,}, + { + name="line_spacing", + option_text="Line Spacing", + items_text={"small","medium","large"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true}, + values={1.0, 1.2, 1.4}, + default_value=DKOPTREADER_CONFIG_LINE_SPACING, + show = true, + draw_index = nil,}, + { + name="word_spacing", + option_text="Word Spacing", + items_text={"small","medium","large"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true}, + values={0.05, 0.15, 0.375}, + default_value=DKOPTREADER_CONFIG_WORD_SAPCING, + show = true, + draw_index = nil,}, + { + name="multi_threads", + option_text="Multi Threads", + items_text={"on","off"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true}, + values={1, 0}, + default_value=DKOPTREADER_CONFIG_MULTI_THREADS, + show = true, + draw_index = nil,}, + { + name="quality", + option_text="Render Quality", + items_text={"low","medium","high"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true}, + values={0.5, 0.8, 1.0}, + default_value=DKOPTREADER_CONFIG_RENDER_QUALITY, + show = true, + draw_index = nil,}, + { + name="auto_straighten", + option_text="Auto Straighten", + items_text={"0","5","10"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true}, + values={0, 5, 10}, + default_value=DKOPTREADER_CONFIG_AUTO_STRAIGHTEN, + show = true, + draw_index = nil,}, + { + name="justification", + option_text="Justification", + items_text={"auto","left","center","right","full"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true, true, true}, + values={-1,0,1,2,3}, + default_value=DKOPTREADER_CONFIG_JUSTIFICATION, + show = true, + draw_index = nil,}, + { + name="max_columns", + option_text="Columns", + items_text={"1","2","3","4"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true, true}, + values={1,2,3,4}, + default_value=DKOPTREADER_CONFIG_MAX_COLUMNS, + show = true, + draw_index = nil,}, + { + name="contrast", + option_text="Contrast", + items_text={"lightest","lighter","default","darker","darkest"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true, true, true}, + values={2.0, 1.5, 1.0, 0.5, 0.2}, + default_value=DKOPTREADER_CONFIG_CONTRAST, + show = true, + draw_index = nil,}, + { + name="screen_rotation", + option_text="Screen Rotation", + items_text={"0","90","180","270"}, + current_item=nil, + text_dirty=true, + marker_dirty={true, true, true, true}, + values={0, 90, 180, 270}, + default_value=DKOPTREADER_CONFIG_SCREEN_ROTATION, + show = true, + draw_index = nil,}, +} + -- Any document processed by K2pdfopt is called a koptdocument KoptDocument = Document:new{ _document = false, @@ -12,6 +181,7 @@ KoptDocument = Document:new{ dc_null = DrawContext.new(), screen_size = Screen:getSize(), screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167, + options = KOPTOptions, configurable = { font_size = 1.0, page_margin = 0.06, @@ -28,7 +198,7 @@ KoptDocument = Document:new{ max_columns = 2, contrast = 1.0, screen_rotation = 0, - } + }, } function KoptDocument:init() @@ -42,6 +212,7 @@ function KoptDocument:init() end self.is_open = true self.info.has_pages = true + self.info.configurable = true if self._document:needsPassword() then self.is_locked = true else @@ -62,6 +233,7 @@ function KoptDocument:init() end self.is_open = true self.info.has_pages = true + self.info.configurable = true self:_readMetadata() end end @@ -161,7 +333,7 @@ function KoptDocument:getPageDimensions(pageno, zoom, rotation) Cache:insert(hash, CacheItem:new{ kctx = kc }) return page_size end - DEBUG("Found cached koptcontex on page", pageno, cached) + --DEBUG("Found cached koptcontex on page", pageno, cached) local fullwidth, fullheight = cached.kctx:getPageDim() local page_size = Geom:new{ w = fullwidth, h = fullheight } return page_size diff --git a/frontend/ui/config.lua b/frontend/ui/config.lua new file mode 100644 index 000000000..a9c72eccd --- /dev/null +++ b/frontend/ui/config.lua @@ -0,0 +1,213 @@ +require "ui/widget" +require "ui/focusmanager" +require "ui/infomessage" +require "ui/font" + +ConfigMenuItem = InputContainer:new{ + dimen = nil, +} + +function ConfigMenuItem:init() +-- we need this table per-instance, so we declare it here + if Device:isTouchDevice() then + self.ges_events = { + TapSelect = { + GestureRange:new{ + ges = "tap", + range = self.dimen, + }, + doc = "Select Menu Item", + }, + } + else + self.active_key_events = { + Select = { {"Press"}, doc = "chose selected item" }, + } + end +end + +function ConfigMenuItem:onFocus() + self[1].inverse = true + self.key_events = self.active_key_events + return true +end + +function ConfigMenuItem:onUnfocus() + self[1].inverse = false + self.key_events = { } + return true +end + +function ConfigMenuItem:onTapSelect() + self.config:onShowDialog(self.dialog) + return true +end + +MenuItemDialog = FocusManager:new{ + dimen = nil, + menu_item = nil, + title = nil, + is_borderless = false, +} + +--[[ +Widget that displays config menu +--]] +ConfigDialog = FocusManager:new{ + -- set this to true to not paint as popup menu + is_borderless = false, +} + +function ConfigDialog:init() + self.menu_dimen = self.dimen:copy() + ----------------------------------- + -- start to set up widget layout -- + ----------------------------------- + self.screen_rotate_options = HorizontalGroup:new{ + + } + self.screen_rotate_icon = ImageWidget:new{ + file = "resources/icons/appbar.transform.rotate.right.large.png" + } + self.screen_rotate_dialog = FrameContainer:new{ + dimen = self.screen_rotate_options:getSize(), + background = 0, + bordersize = 0, + padding = 0, + margin = 0, + self.screen_rotate_options, + } + self.page_crop_icon = ImageWidget:new{ + file = "resources/icons/appbar.crop.large.png" + } + self.page_layout_icon = ImageWidget:new{ + file = "resources/icons/appbar.column.two.large.png" + } + self.text_font_icon = ImageWidget:new{ + file = "resources/icons/appbar.text.size.large.png" + } + self.contrast_icon = ImageWidget:new{ + file = "resources/icons/appbar.grade.b.large.png" + } + self.more_options_icon = ImageWidget:new{ + file = "resources/icons/appbar.settings.large.png" + } + self.icon_spacing = HorizontalSpan:new{ + width = (Screen:getWidth() - 64*6 - 20) / 7 + } + + self.icon_dimen = Geom:new{ + w = 64, + h = 64, -- hardcoded for now + } + + -- group for config layout + local config_dialog = VerticalGroup:new{ + align = "center", + HorizontalGroup:new{ + align = "center", + MenuItemDialog:new{ + self.screen_rotate_dialog, + dimen = self.screen_rotate_dialog:getSize(), + title = "Screen Rotation", + }, + }, + HorizontalGroup:new{ + align = "center", + self.icon_spacing, + ConfigMenuItem:new{ + self.screen_rotate_icon, + dimen = self.icon_dimen:new(), + config = self, + }, + self.icon_spacing, + ConfigMenuItem:new{ + self.page_crop_icon, + dimen = self.icon_dimen:new(), + dialog = "Crop dialog", + config = self, + }, + self.icon_spacing, + ConfigMenuItem:new{ + self.page_layout_icon, + dimen = self.icon_dimen:new(), + config = self, + }, + self.icon_spacing, + ConfigMenuItem:new{ + self.text_font_icon, + dimen = self.icon_dimen:new(), + config = self, + }, + self.icon_spacing, + ConfigMenuItem:new{ + self.contrast_icon, + dimen = self.icon_dimen:new(), + config = self, + }, + self.icon_spacing, + ConfigMenuItem:new{ + self.more_options_icon, + dimen = self.icon_dimen:new(), + config = self, + }, + self.icon_spacing, + } + } + -- maintain reference to content so we can change it later + self.config_dialog = config_dialog + + self[1] = BottomContainer:new{ + dimen = Screen:getSize(), + FrameContainer:new{ + dimen = config_dialog:getSize(), + background = 0, + config_dialog + } + } + + ------------------------------------------ + -- start to set up input event callback -- + ------------------------------------------ + if Device:isTouchDevice() then + self.ges_events.TapCloseMenu = { + GestureRange:new{ + ges = "tap", + range = Geom:new{ + x = 0, y = 0, + w = Screen:getWidth(), + h = Screen:getHeight(), + } + } + } + else + -- set up keyboard events + self.key_events.Close = { {"Back"}, doc = "close config menu" } + -- we won't catch presses to "Right" + self.key_events.FocusRight = nil + end + self.key_events.Select = { {"Press"}, doc = "select current menu item"} + + UIManager.repaint_all = true +end + +function ConfigDialog:onShowDialog(dialog) + DEBUG("Showing dialog of item", dialog) + UIManager:show(dialog) + return true +end + +function ConfigDialog:onCloseMenu() + UIManager:close(self) + if self.close_callback then + self.close_callback() + end + return true +end + +function ConfigDialog:onTapCloseMenu(arg, ges_ev) + if ges_ev.pos:notIntersectWith(self.menu_dimen) then + self:onCloseMenu() + return true + end +end \ No newline at end of file diff --git a/frontend/ui/reader/readerconfig.lua b/frontend/ui/reader/readerconfig.lua new file mode 100644 index 000000000..626b1ac83 --- /dev/null +++ b/frontend/ui/reader/readerconfig.lua @@ -0,0 +1,66 @@ +require "ui/config" + +ReaderConfig = InputContainer:new{ + dimen = Geom:new{ + x = 0, + y = 7*Screen:getHeight()/8, + w = Screen:getWidth(), + h = Screen:getHeight()/8, + } +} + +function ReaderConfig:init() + DEBUG("init ReaderConfig.") + if Device:isTouchDevice() then + self.ges_events = { + TapShowConfigMenu = { + GestureRange:new{ + ges = "tap", + range = self.dimen:copy(), + } + } + } + else + self.key_events = { + ShowConfigMenu = { { "AA" }, doc = "show config dialog" }, + } + end +end + +function ReaderConfig:onShowConfigMenu() + local config_dialog = ConfigDialog:new{ + configurable = self.configurable, + options = self.options, + dimen = self.dimen:copy(), + } + + function config_dialog:onConfigChoice(item) + if item.callback then + item.callback() + end + end + + local dialog_container = CenterContainer:new{ + config_dialog, + dimen = self.dimen:copy(), + } + config_dialog.close_callback = function () + UIManager:close(menu_container) + end + -- maintain a reference to menu_container + self.dialog_container = dialog_container + + UIManager:show(config_dialog) + + return true +end + +function ReaderConfig:onTapShowConfigMenu() + self:onShowConfigMenu() + return true +end + +function ReaderConfig:onSetDimensions(dimen) + -- update gesture listenning range according to new screen orientation + self:init() +end diff --git a/frontend/ui/reader/readermenu.lua b/frontend/ui/reader/readermenu.lua index 4f7214267..91b754ccf 100644 --- a/frontend/ui/reader/readermenu.lua +++ b/frontend/ui/reader/readermenu.lua @@ -15,7 +15,7 @@ function ReaderMenu:init() range = Geom:new{ x = 0, y = 0, w = Screen:getWidth(), - h = Screen:getHeight()/2 + h = Screen:getHeight()/4, } } }, diff --git a/frontend/ui/reader/readerpaging.lua b/frontend/ui/reader/readerpaging.lua index f06739123..64f804180 100644 --- a/frontend/ui/reader/readerpaging.lua +++ b/frontend/ui/reader/readerpaging.lua @@ -14,10 +14,10 @@ function ReaderPaging:init() GestureRange:new{ ges = "tap", range = Geom:new{ - x = Screen:getWidth()/2, - y = Screen:getHeight()/2, - w = Screen:getWidth(), - h = Screen:getHeight() + x = Screen:getWidth()/4, + y = Screen:getHeight()/4, + w = 3*Screen:getWidth()/4, + h = 5*Screen:getHeight()/8, } } }, @@ -26,9 +26,9 @@ function ReaderPaging:init() ges = "tap", range = Geom:new{ x = 0, - y = Screen:getHeight()/2, - w = Screen:getWidth()/2, - h = Screen:getHeight()/2, + y = Screen:getHeight()/4, + w = Screen:getWidth()/4, + h = 5*Screen:getHeight()/8, } } } diff --git a/frontend/ui/readerui.lua b/frontend/ui/readerui.lua index 19d953540..a56b99c4d 100644 --- a/frontend/ui/readerui.lua +++ b/frontend/ui/readerui.lua @@ -8,6 +8,7 @@ require "ui/reader/readerrolling" require "ui/reader/readertoc" require "ui/reader/readerfont" require "ui/reader/readermenu" +require "ui/reader/readerconfig" --[[ This is an abstraction for a reader interface @@ -113,6 +114,17 @@ function ReaderUI:init() } table.insert(self, font_menu) end + if self.document.info.configurable then + -- configurable controller + local config_dialog = ReaderConfig:new{ + configurable = self.document.configurable, + options = self.document.options, + dialog = self.dialog, + view = self[1], + ui = self + } + table.insert(self, config_dialog) + end --DEBUG(self.doc_settings) -- we only read settings after all the widgets are initialized self:handleEvent(Event:new("ReadSettings", self.doc_settings)) diff --git a/frontend/ui/widget.lua b/frontend/ui/widget.lua index df50504d0..e6f8819e7 100644 --- a/frontend/ui/widget.lua +++ b/frontend/ui/widget.lua @@ -113,7 +113,21 @@ function WidgetContainer:free() end end +--[[ +BottomContainer contains its content (1 widget) at the bottom of its own dimensions +]] +BottomContainer = WidgetContainer:new() +function BottomContainer:paintTo(bb, x, y) + local contentSize = self[1]:getSize() + if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then + -- throw error? paint to scrap buffer and blit partially? + -- for now, we ignore this + end + self[1]:paintTo(bb, + x + (self.dimen.w - contentSize.w)/2, + y + (self.dimen.h - contentSize.h)) +end --[[ CenterContainer centers its content (1 widget) within its own dimensions @@ -326,6 +340,7 @@ end ImageWidget shows an image from a file ]] ImageWidget = Widget:new{ + invert = nil, file = nil, _bb = nil } @@ -349,6 +364,9 @@ end function ImageWidget:paintTo(bb, x, y) local size = self:getSize() bb:blitFrom(self._bb, x, y, 0, 0, size.w, size.h) + if self.invert then + bb:invertRect(x, y, size.w, size.h) + end end function ImageWidget:free() @@ -635,8 +653,8 @@ end function InputContainer:onGesture(ev) for name, gsseq in pairs(self.ges_events) do for _, gs_range in ipairs(gsseq) do + --DEBUG("gs_range", gs_range) if gs_range:match(ev) then - --DEBUG(gs_range) local eventname = gsseq.event or name return self:handleEvent(Event:new(eventname, gsseq.args, ev)) end diff --git a/resources/icons/appbar.checkmark.thick.png b/resources/icons/appbar.checkmark.thick.png new file mode 100644 index 0000000000000000000000000000000000000000..1daf67824d2ada08c035fbe63486665e041ef166 GIT binary patch literal 433 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!1~*R^$B+!?x6=*1m;*&z-MOVV3R(;1=&sSt zd2@u7CHw&!%Wa)QK`||B=k93mxFr%5!IGoH!p%Lo`lQW{I;C?dkN&f~Yjif!-}B_I z!T*CH$0U+_43EtSeJ--@{Jm$%mo6&aX_@}@EAO3#n;z_0kEQQ4+y02X{=)K18{d^< z`V}nx57J{7Z#U4k3W?@>Xx;PAea6>sirs8CTGty?#Xm4Rb8ZiV%sZ)n-}3Vgs!P<$ ze_#+(!lvI6;>1s;*b3=DjSL74G){)!Z!V6dl)V@QVc+iM%S4k+-r2HyVv|9Khb-QHIB z2Xj;>KWgRCV_;bDdezOZS8T4<9gi(u^O3QB-Gz6t>go1j8omy*8cY~7nJyh;|KYd1 gmmg@}tZP+_-$PlH{@E9P267oZUHx3vIVCg!08uVLMF0Q* literal 0 HcmV?d00001 diff --git a/resources/icons/appbar.chevron.left.png b/resources/icons/appbar.chevron.left.png new file mode 100644 index 0000000000000000000000000000000000000000..7c96681b0e48a7158f18c710d38ba7bae959433b GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!25V0j$B+!?x6}9XF*=I0{#B6@?ex-?x>&*V z{sFH|W7Bkjz2~?yw!}FoFAVn(5poQ1X)o5=H1lrKn?6~~$#+u9Q=ZNFeb@Kh)RP&V z4ICYCbYMM4iY%x3f?&gpyBoHbJUJM(ta~#55n}=IJ=@phmzHdJzWL|AMyu5u+)ZQ| zw@j0Co3TFn{;LNGd{U1EK1aVA{SLN0XkXvYV+MENo78e-$pt7p~}8@aBhAr^PP^k)zgi zbCj|=gp!lvI6;>1s;*b3=DjSL74G){)!Z!27ON#$B+!?x6?QBF**vg^|!b!7vAf)Sh%-> zX>Q!=Yn|*Ln5_2t*)*yzaMP8#m?`q(zf0-O(6>i@KKUCRJ*&3+|NpaZp6Z?OIg^zZ*W)La9(t4a?@Y#`$-+b^G=lO$ydA+ud7bWVKT~q#Nb#Cm)24pbJuJyTad}1G)SEw4|FK;4-F!-M zO;?QjiT8o|5#swhJM0(4ZP(eyR(QMPhwQ5ub7>Lxi3_>CgIl}&Kf0T>pKxS&FS(U- k()`O@f&z@lsG7x2Yf{N=|E!bE!0=@7boFyt=akR{068X{H~;_u literal 0 HcmV?d00001 diff --git a/resources/icons/appbar.column.two.large.png b/resources/icons/appbar.column.two.large.png new file mode 100644 index 0000000000000000000000000000000000000000..6fc0150b71908951ba30ff851895400b7fd420ea GIT binary patch literal 565 zcmV-50?Pe~P)00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY4c7nw4c7reD4Tcy000McNliru+zbp01~Dz)Y!Cnd0m4Z{ zK~!ko?V7!c!ax*-hD6kJO1JPulTCKw9d_EuK zzU27OU8~jLWpp?kcDr3rV7J@B0@v#`$bkhemkTox-wdqR zYZx8O&uX<2IoxF*pg?39Xf~TLdN3HYS}nge3z-%^y(Ymg`>gjYU^0No~00k&O0SZvyzY077S#D^dcG$bZ00000NkvXXu0mjf Ds+I6! literal 0 HcmV?d00001 diff --git a/resources/icons/appbar.crop.large.png b/resources/icons/appbar.crop.large.png new file mode 100644 index 0000000000000000000000000000000000000000..e2d342d2489e2446f942ec2c2aca8085c4bd9b25 GIT binary patch literal 1041 zcmV+s1n&EZP)00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY4c7nw4c7reD4Tcy000McNliru+zbp00vnPDV8Q?Z1D;7l zK~!ko?O97mGEo#ZwTx0LDkA9ppdg6a6$yFAWQK4N6hRA#z-4cz_&1UcK?|XZD3tC!ubar;KpIuyB z%nA^hOvYldXti38$CGz4az`kW$t*1`?d|P7KR*)$adB}WrW*MC{4|@*hlhvXDZ?<+ z)6?hY=i(6X@$s>+uwb*<*x<{{i^*iVySwA3h=q&y_xJhvd56Qn{b_l5d2n#>H$}X^ zzyIgLHa9nO7ctTTwzjtNb|G{H?Ck6m(sPwEB*SX8uCA_%)k?Iqv=qo*CX-ddVF`Z6tY;3Sy2_zsEixuHI%4{W`o}R|X$8+yM;cqK< z4Wv>j9LKM(um8r4mKe!o(r7gLd_Ga$2NH<{hGAUxa=Cn9U;uRi@pv2n;P?9>T%k}L z92^h?fwX{FET-4%1Azd1e3ih=1+oD1a*ilQ(K<61F| zMss#{Cd3elPXU2Iz+f=M<8cVDtE+Q5onvETLL67#YQXRJ0|2<}8yXs1E|);;dD{V> z&u26mlgT86H#Ro9T&~g4QQ?|34?E!XdJP5xmwj_{Gf9$yvgbj-)z#J1)Kn^!;$BMJ zZuju;u+UaTS>n0JaXg()LwIXzD@l^MrcsCpxVgFEf^BVWBuV!7_m{`0^ZXs?=;&~} z-90@$WxFTwX(hV5yDu*<%gH{^4n!i6+uK_<^7{Jvuf-~rYJGj3q9}@@e&Ji$>D$|z z)9GX*LqkLD?d?U6RZtl2e#h?au4w+DL3b)43HVP1Fn&R z)oLxB#P;?!yJ0jnHF>>W$P{WcnxfmNTCG;A)zBmdTF}+iRk{GJR?AKm3Ps_sm1;l| zP*yXyva-Uq{v#tJypSLWqQ1VKU0VEfA?XN70we*F07-x(0QvX=mDgWHh?Swk00000 LNkvXXu0mjf@_Osf literal 0 HcmV?d00001 diff --git a/resources/icons/appbar.grade.b.large.png b/resources/icons/appbar.grade.b.large.png new file mode 100644 index 0000000000000000000000000000000000000000..b7e62c28f6d9a658858164ad1e10ee1180c2639f GIT binary patch literal 909 zcmV;819JR{P)00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY4c7nw4c7reD4Tcy000McNliru+zbp01sBx+x-I|!0~$$0 zK~!ko?V8U^GC>%}Efom@4O}II7iCikGC@3bSjnJ3L=Z3i2OYv=2T>5BO9<8}x_Mca zh`=9*DDYBVI#lEjL=B1rk#bX5FQTUJK?vb>7h5f7c;|cCR;$%2l}b9DzP!Bjdc7Eiajz;54-cS((Qr8Y zZ~I20VYAsd`Va^NfQ~{EiG-pkg+jsBAeBmiJ_n>y>FVk#o2yhRA(+IAi;Ha5($W$H z052~uY}U%k3g`f>R_pHWZlJZkzCKEN_e%hKdwZ|1uLJY#!^6YhPN%;mhGF*i_k+RU zK-cH<84L!108UR&A0Hok$23hB3WfXo`)aj1VCbi(kB*MqZZ~}OfIuM7Xf)AibS(A2 zZ|6eG%gYo+Jv}`+9FB>Vl%weV{r&3dN+=X=Y;4G6GAK*RulVEfc-rkYtR-bn7K^1^ zE<;&T_H=!HZ8Di?ng(SK*zI;4$G=Xi)#~%}b3UKv=wi8C-rd~|g+k!g1Fcr;s=2v2 zHaDBif)3DVG#G|qbKC7U=m6Pl_Ve?T&E?*G0RrIQ;DE#BjC``u&^*YJKG-|KR!N&+4;)la%#1D^0`o{ zRN`@!+wJDpdjSZ$(`K{T@ApHnu{BUSo$lh|qW`Uf3BcuY-QM2v3qBJDFdB^{NuHmd zb7U4^74f0RH+55C~i2uqC8#00000NkvXXu0mjf$M2yd literal 0 HcmV?d00001 diff --git a/resources/icons/appbar.settings.large.png b/resources/icons/appbar.settings.large.png new file mode 100644 index 0000000000000000000000000000000000000000..f43f732f6e9ac5f64ec10c83f27c65cf55cffbc3 GIT binary patch literal 1743 zcmV;=1~B=FP)00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY4c7nw4c7reD4Tcy000McNliru+zbp01u+KlKhppJ23$!* zK~!ko?OIz%8(k1iG%+b^wW(H(HHxSd)S{x`1zIbHsuV>^#fM^1DixvihA#zaTEU_q z?fy_`MyvzsEn^R~;JnfcC~ zGc#w-5fTI;ILl-wIOB8<;2gj?03HZMQH4U`ZEYoK zkw_%FySseo;>82+-n}FJK@g<5x%q5(V0n32C=^l^MMOlL4G+A3|DHCxPfbnD%*^~v z4=gV)Z*Fdac~BJf^z>xXRZvjCxd&hYOifL>ySqyylHAKIy zfR^Fm;d}S)_4f913}9?*%+=M^WQR~FOifK485yB+CM6|-9scp-N9w4fqoX%(-h_sR znnG50cQUbzix1<RWM@OcCIF9Rdx{8VlYP_eVs;VmP zO9_G?=I7@DVOt;&+`4t^&!0a42|GJGrKP1(sT3f@)zww6*Yg5^Ac&Nd6eh(*MMWrz z!U$PdSOB=<>C>mY6mtYYeEeLg zzPGoxKp=2*bWBJ{7#$t8sC2cnvr{USEiEmq;fM_2;NYOXzFw(R+S}X1M2y75M3RJ= znHhybLFKHhtR!*P*4DDhm&s(0A3vU+o`wYg4iQv(`}VE*a16u3!op}dg+gIhR~N}q zkkfQp8ohe;YHx231OUS@OH*cNXQ#P@PoF+nQw+CRxFpN}I=yW=Z)KN33wI0yx_2!?kv9SPV zPft%P0kC*LBodXEm;3ws!%O`9`Lp?FQc{wen;W3UB>k}-08JjiaeQcK=>Glt7cN|2 zl^7l#P8vQkGD2Io#>K^*oSc|*uB@!UN1>>wD79Kmt+hazcz=KY_3PKHxr~}M$H&KS z+_+(0TIc8IQ#(SLnVB#rn`h6SX|-CbYN5Hgxx&IirnQlpno4_m(rUGXgM-Bf<-lY{H5{Z8O`o&i{{o%t0z+x4P#YII$TU%RTAsUV5+O=x{IVB|} zya2#346OK+E?&I&;>C-@!$WFho1C0fsZ`F+&R_}7&d&S$`|tpSkjbmPy`9PLw8z4r zpdk6bw7R<5)6)YV@~f(8^K)sTe^WY18kRB`|SK@hoI4%QSC6VuexgdoVB zJ9k*k5{X1wt+u+l8jurB1UL#?-~o+BLwoTkl}fX-vnMAfO`L6QZLBt>r>C3lGaDNl znGVpW7e7CL{^Vv8lQ8)C`Bhd{Zf|c>YYo6*fT;)b?c2B8w{Mf!LPA0yJ6y1NK%>!k zd3h<7%8rf>K+9<; zU%oszIN+`gJiv2E{8v4{rv||)K!#|lLOy?u&mX^$ID$D#}^kDjYcDiq9}?QjmF^MV4f~& lc>!QcI)8R~4&eU|;2$XnkIP70R5t(s002ovPDHLkV1ftPHH82G literal 0 HcmV?d00001 diff --git a/resources/icons/appbar.text.size.large.png b/resources/icons/appbar.text.size.large.png new file mode 100644 index 0000000000000000000000000000000000000000..a1dc6b305766b0a68d7016e5b419a8aa60317269 GIT binary patch literal 1338 zcmV-A1;zS_P)00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY4c7nw4c7reD4Tcy000McNliru+zbp01_=e-)Q$iE1jk84 zK~!ko?ODq&GhG-Tv{Y0jE=e^)1*uCKM9?T&w_+h0Ayy4yY2}vq2ds!U*x0ZjX~ecv z)uzNkG!|HBDwL?uq_k+MwmR>kNz|d5d z>>n2f00V#lzyM$XFaQ_;41gGfMR&pa`np=JCQ%q08|&%m`8fnQO=)awBsbXC*N6Y0 zB+zQ79S%oMPR{rDH;E3H%eC9>DJdzxF$Q!x9r@`o40E|$27}?32Jz0$4iza{yNip9Uq>OWRtpbKPfsT$CH zVVGPl|MTY$Fck;{v|8=(@G!YqqtS@WY%-awrKKgF6zc8mh1V`FF5)=ubUKk?K&2$B zR4U}D+S=OUNgh& zz#xyutE{XHJ+LTB^2y1G-EK!t`Fy^;y}h`lQ6x>}a(Re3ot>Rglw`ncLPA0`iI|F; zii(Qhh0Dv!AqB73o1UIdwr-)9?4kAqGq)6B4<}WC~YPDwRmJ^Ye40 z*@uS*;J9$2J3Ks$LkuAKlb@e25{be`y1Tn+u?RS>L?V$&r9d{L!lEbvbaZq8BVAox zv;Y8RrBW%6#{-Hwr7$3O(A(P^o6Uw-ZEkMD%E-nJS(3lLzPMa2kmzt6pP88fmS0_6 z#Y7>!Uhnhy;4`(ix5LUvCj?6}oR?iLSLiQ?!>OyQ!!Qgs8_@}@DEO0^nYppC0gu1D zyb!Sn=qUh5O-)T44k!47%jJe+(`YovUW*ci0)YUZ&yT&~g-dctNlCcE+}s>d&%$D{ z$V)OA0He_uuclq6(}m2M&1PWs?CdNwyRx!ECEh5-0L2?H71`e2CNj(C^TlE@Nji=Y z1|;BuffW}CFUdfps#Gdq--?O~>Lr;FfX!wDnv)nMSd!o0-;8=eXS$Y?m-Q8W} zJ1>z)guGjZ{JFKYMU;!gV)6d|zSrxe3qYgMG&eWXqtL*>08)Q#ZH>IL00aPT$)lsA zQFu=z649fO&*#g?$Uxe%SS;iKCMG7(O-o|p)6-LKZfmMj(vz#{acLBg7vnnE6KWMm{_fBW(A z5iF~)z*pzh)m5aC$;nCh{zQX9Wo2bV9|x#hfZ$%0NQelj*XzNahsAO@9Fzdu+}sfD zcYl9R1;G6LJeAWI78Vj&`274#O-%*#)oL}RN=#IMi;Ii%^75#hOrcOvQ6qWt!{Kmb zG8vVUOalPbH%%BO7K^E5o7UD=l3DmgfljCM`~4Au*zI-`g&@*{L^3oq6cNC~!vl$h z%gal6iNRoqkVZ`=Q+<7Xj2^%+Y;bV!_V$)UfzRg)1OgI;($Z3;Qt5Cw!UwOfuK{Y& w`$qN)h569U0AK(x02lxa00sa9;QtKZFB@z+W@3WyNB{r;07*qoM6N<$g03=aYybcN literal 0 HcmV?d00001 diff --git a/resources/icons/appbar.transform.rotate.right.large.png b/resources/icons/appbar.transform.rotate.right.large.png new file mode 100644 index 0000000000000000000000000000000000000000..141c71e9652ca8954d52c51abe659cde81871b76 GIT binary patch literal 992 zcmV<610Vc}P)00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmY4c7nw4c7reD4Tcy000McNliru+zbp01|cwLd~^T+18qq} zK~!ko?U_qRIzb%AcTHNch%8px=yj-&^ia~NBzhdAOAipFOVN3uYYRms^tc4kL6GoJ zw@xA+A|vur*d?knewFAt}&7Gc}LJV+scW1NNd_Et~J`imzT5FYQY~Y z%WiCJ6!-NsP1o1g`~Cj2vooIOtE;O?k~A8PBuO?lHda+t73c{wGc%W$mtL=zAP9M# zq);eS^#3m$4vV7bbUHs*;W%!!TBoO{_xJZXjuW$KVqya9($&?KNF=}pzXgnmZzP`@eSgXvKOeWLd;GkZwPbQOzL?RxKKR!O@b)Jrn4vL~w z0kE*JAS;PPBEeuV7!2<1?Y+FbWbKtorBbPsN|#V`b2ClTfk1#|*{P{1olXa9Fjre! zyS~28vaH>1hd3IgC~9YC$K`TqG+!H%R>@J`-rhQ$&fI%TNlA$y2r30=XlMuo0;8j& zM@L7nCNv~T9vmEukB>u~k(HK~Zf$L?tgPTT4slA!FpSUVD=RDe;d8Xu?`dRYQy;bznt}HAc3J#v zwOYaC>2n}dV7{-M4=@b#uUdn_AoCD7w$Z}X+uIAq;ZOpA41dar5r86ETwK(BXlQ5% zJ|EzDUP}C5UtiG@LICiE5F8%%eMx!zRqkrp;47}>P zzrX+7F%$|(4d&BdHi=uDg<>lp(NFi4O z#L3BttYceSTSY}h#*W2eu~;l)S5{U^hngG!Eg=Me01yBIKmZ6pVZ8(DLjnILqU`Jd O0000 + + + diff --git a/resources/icons/src/appbar.checkmark.thick.xaml b/resources/icons/src/appbar.checkmark.thick.xaml new file mode 100644 index 000000000..4f4dd3e02 --- /dev/null +++ b/resources/icons/src/appbar.checkmark.thick.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.chevron.left.xaml b/resources/icons/src/appbar.chevron.left.xaml new file mode 100644 index 000000000..84d295396 --- /dev/null +++ b/resources/icons/src/appbar.chevron.left.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.chevron.right.xaml b/resources/icons/src/appbar.chevron.right.xaml new file mode 100644 index 000000000..482e1aa94 --- /dev/null +++ b/resources/icons/src/appbar.chevron.right.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.column.one.xaml b/resources/icons/src/appbar.column.one.xaml new file mode 100644 index 000000000..a0c661538 --- /dev/null +++ b/resources/icons/src/appbar.column.one.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.column.three.xaml b/resources/icons/src/appbar.column.three.xaml new file mode 100644 index 000000000..8ba3afd46 --- /dev/null +++ b/resources/icons/src/appbar.column.three.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.column.two.xaml b/resources/icons/src/appbar.column.two.xaml new file mode 100644 index 000000000..ee5bd4ecb --- /dev/null +++ b/resources/icons/src/appbar.column.two.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.crop.xaml b/resources/icons/src/appbar.crop.xaml new file mode 100644 index 000000000..76ed90bc1 --- /dev/null +++ b/resources/icons/src/appbar.crop.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.grade.b.xaml b/resources/icons/src/appbar.grade.b.xaml new file mode 100644 index 000000000..45e0a2b02 --- /dev/null +++ b/resources/icons/src/appbar.grade.b.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.settings.xaml b/resources/icons/src/appbar.settings.xaml new file mode 100644 index 000000000..be1618ed8 --- /dev/null +++ b/resources/icons/src/appbar.settings.xaml @@ -0,0 +1,5 @@ + + + + + diff --git a/resources/icons/src/appbar.text.size.xaml b/resources/icons/src/appbar.text.size.xaml new file mode 100644 index 000000000..a8b5f6378 --- /dev/null +++ b/resources/icons/src/appbar.text.size.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/appbar.transform.rotate.right.xaml b/resources/icons/src/appbar.transform.rotate.right.xaml new file mode 100644 index 000000000..343073b23 --- /dev/null +++ b/resources/icons/src/appbar.transform.rotate.right.xaml @@ -0,0 +1,4 @@ + + + + diff --git a/resources/icons/src/license.txt b/resources/icons/src/license.txt new file mode 100644 index 000000000..a35a4c656 --- /dev/null +++ b/resources/icons/src/license.txt @@ -0,0 +1,44 @@ +Read the license: +http://creativecommons.org/licenses/by/3.0/ * + +Basicaly, use it anyway you want but include this license file in the source if your project is open source. Nothing is needed in the front facing project (UNLESS you are using any of the icons listed below). Commercial use is not only allowed but encouraged. This pack was made to promote consistency in applications. + +Creator +- Austin Andrews (@templarian) + +Contributor** +- Oren Nachman + - appbar.chevron.down + - appbar.chevron.up + - appbar.chevron.left + - appbar.chevron.right + +Attribution*** +- Kris Vandermotten (@kvandermotten) + - appbar.medical.pulse +- Constantin Kichinsky (@kichinsky) + - appbar.currency.rubles + - appbar.currency.grivna +- Massimo Savazzi (@msavazzi) + - List of missing exported icons +- Proletkult Graphik, from The Noun Project + - appbar.draw.pen (inspired) +- Olivier Guin, from The Noun Project + - appbar.draw.marker +- Gibran Bisio, from The Noun Project + - appbar.draw.bucket +Andrew Forrester, from The Noun Project + - appbar.fingerprint + +** Developers and designers that emailed Templarian the source .design icons to be added into the package. PNGs also accepted, but may take longer to be added. +*** Icons I've copied so closely you want to attribute them and are also under the CC license. + +Contact +- http://templarian.com/ +- admin[@]templarian[.]com + +* Does not apply to copyrighted logos +- Skype +- Facebook +- Twitter +- etc... \ No newline at end of file From 755e012dbaab48b3d2747bd8538e6ba071650865 Mon Sep 17 00:00:00 2001 From: chrox Date: Wed, 19 Dec 2012 23:45:51 +0800 Subject: [PATCH 2/7] add config options --- frontend/ui/config.lua | 344 +++++++++++++++++++++++++++++---------- frontend/ui/graphics.lua | 6 +- frontend/ui/widget.lua | 34 ++++ 3 files changed, 299 insertions(+), 85 deletions(-) diff --git a/frontend/ui/config.lua b/frontend/ui/config.lua index a9c72eccd..7862380cf 100644 --- a/frontend/ui/config.lua +++ b/frontend/ui/config.lua @@ -3,6 +3,24 @@ require "ui/focusmanager" require "ui/infomessage" require "ui/font" +FixedTextWidget = TextWidget:new{} +function FixedTextWidget:getSize() + local tsize = sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true) + if not tsize then + return Geom:new{} + end + self._length = tsize.x + self._height = self.face.size + return Geom:new{ + w = self._length, + h = self._height, + } +end + +function FixedTextWidget:paintTo(bb, x, y) + renderUtf8Text(bb, x, y+self._height, self.face, self.text, true) +end + ConfigMenuItem = InputContainer:new{ dimen = nil, } @@ -26,20 +44,13 @@ function ConfigMenuItem:init() end end -function ConfigMenuItem:onFocus() - self[1].inverse = true - self.key_events = self.active_key_events - return true -end - -function ConfigMenuItem:onUnfocus() - self[1].inverse = false - self.key_events = { } - return true -end - function ConfigMenuItem:onTapSelect() - self.config:onShowDialog(self.dialog) + for _, item in pairs(self.config.menu_items) do + item[1].invert = false + end + self[1].invert = true + self.config:onShowOptions(self.options) + UIManager.repaint_all = true return true end @@ -50,50 +61,188 @@ MenuItemDialog = FocusManager:new{ is_borderless = false, } +ConfigIcons = HorizontalGroup:new{} +function ConfigIcons:init() + for c = 1, #self.icons do + table.insert(self, self.spacing) + table.insert(self, self.icons[c]) + end + table.insert(self, self.spacing) +end + +ConfigOption = CenterContainer:new{dimen = Geom:new{ w = Screen:getWidth(), h = 100},} +function ConfigOption:init() + local vertical_group = VerticalGroup:new{} + for c = 1, #self.options do + local name_align = self.options[c].name_align_right + local item_align = self.options[c].item_align_center + local horizontal_group = HorizontalGroup:new{} + local option_name_container = RightContainer:new{ + dimen = Geom:new{ w = Screen:getWidth()*(name_align and name_align or 0.33), h = 30}, + } + local option_name = TextWidget:new{ + text = self.options[c].name, + face = self.options[c].name_face, + } + table.insert(option_name_container, option_name) + table.insert(horizontal_group, option_name_container) + local option_items_container = CenterContainer:new{ + dimen = Geom:new{w = Screen:getWidth()*(item_align and item_align or 0.66), h = 30} + } + local option_items_group = HorizontalGroup:new{} + for d = 1, #self.options[c].items do + local option_item = TextWidget:new{ + text = self.options[c].items[d], + face = self.options[c].item_face, + } + table.insert(option_items_group, option_item) + table.insert(option_items_group, self.options[c].spacing) + end + table.insert(option_items_container, option_items_group) + table.insert(horizontal_group, option_items_container) + table.insert(vertical_group, horizontal_group) + end + self[1] = vertical_group +end + +ConfigFontSize = CenterContainer:new{dimen = Geom:new{ w = Screen:getWidth(), h = 100},} +function ConfigFontSize:init() + local vertical_group = VerticalGroup:new{} + local horizontal_group = HorizontalGroup:new{align = "bottom"} + for c = 1, #self.items do + local widget = FixedTextWidget:new{ + text = self.items[c], + face = Font:getFace(self.item_font_face, self.item_font_size[c]), + } + table.insert(horizontal_group, self.spacing) + table.insert(horizontal_group, widget) + end + table.insert(vertical_group, horizontal_group) + self[1] = vertical_group +end + --[[ Widget that displays config menu --]] ConfigDialog = FocusManager:new{ - -- set this to true to not paint as popup menu + -- face for option names + tface = Font:getFace("tfont", 20), + -- face for option items + cface = Font:getFace("cfont", 16), is_borderless = false, } -function ConfigDialog:init() +function ConfigDialog:init() self.menu_dimen = self.dimen:copy() ----------------------------------- -- start to set up widget layout -- ----------------------------------- - self.screen_rotate_options = HorizontalGroup:new{ - - } self.screen_rotate_icon = ImageWidget:new{ file = "resources/icons/appbar.transform.rotate.right.large.png" } - self.screen_rotate_dialog = FrameContainer:new{ - dimen = self.screen_rotate_options:getSize(), - background = 0, - bordersize = 0, - padding = 0, - margin = 0, - self.screen_rotate_options, + self.screen_rotate_options = ConfigOption:new{ + options = { + { + name = "Screen Rotation", + name_face = Font:getFace("tfont", 20), + items = {"portrait", "landscape"}, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 30 }, + } + }, } + self.page_crop_icon = ImageWidget:new{ file = "resources/icons/appbar.crop.large.png" } + self.page_crop_options = ConfigOption:new{ + options = { + { + name = "Page Crop", + name_face = Font:getFace("tfont", 20), + items = {"auto", "manual"}, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 30 }, + } + }, + } + self.page_layout_icon = ImageWidget:new{ file = "resources/icons/appbar.column.two.large.png" } + self.page_layout_options = ConfigOption:new{ + options = { + { + name = "Page Margin", + name_face = Font:getFace("tfont", 20), + items = {"small", "medium", "large"}, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 30 }, + }, + { + name = "Line Spacing", + name_face = Font:getFace("tfont", 20), + items = {"small", "medium", "large"}, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 30 }, + }, + { + name = "Word Spacing", + name_face = Font:getFace("tfont", 20), + items = {"small", "medium", "large"}, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 30 }, + }, + }, + } + self.text_font_icon = ImageWidget:new{ file = "resources/icons/appbar.text.size.large.png" } + self.text_font_options = ConfigFontSize:new{ + items = {"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"}, + item_font_face = "cfont", + item_font_size={14,16,20,23,26,30,34,38,42,46}, + spacing = HorizontalSpan:new{ width = Screen:getWidth()*0.03 }, + } + self.contrast_icon = ImageWidget:new{ file = "resources/icons/appbar.grade.b.large.png" } + self.contrast_options = ConfigOption:new{ + options = { + { + name = "Contrast", + name_face = Font:getFace("tfont", 20), + name_align_right = 0.2, + items = {"lightest", "lighter", "default", "darker", "darkest"}, + item_align_center = 0.8, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 30 }, + } + }, + } + self.more_options_icon = ImageWidget:new{ file = "resources/icons/appbar.settings.large.png" } - self.icon_spacing = HorizontalSpan:new{ - width = (Screen:getWidth() - 64*6 - 20) / 7 + self.more_options = ConfigOption:new{ + options = { + { + name = "Render Quality", + name_face = Font:getFace("tfont", 20), + items = {"low", "default", "high"}, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 20 }, + }, + { + name = "Auto Straighten", + name_face = Font:getFace("tfont", 20), + items = {"0 deg", "5 deg", "10 deg"}, + item_face = Font:getFace("cfont", 16), + spacing = HorizontalSpan:new{ width = 20 }, + }, + } } self.icon_dimen = Geom:new{ @@ -101,68 +250,99 @@ function ConfigDialog:init() h = 64, -- hardcoded for now } - -- group for config layout - local config_dialog = VerticalGroup:new{ - align = "center", - HorizontalGroup:new{ - align = "center", - MenuItemDialog:new{ - self.screen_rotate_dialog, - dimen = self.screen_rotate_dialog:getSize(), - title = "Screen Rotation", - }, - }, + self.reading_progress = VerticalGroup:new{ + ProgressWidget:new{ + width = Screen:getWidth()*0.7, + height = 5, + percentage = 0.0, + } + } + local default_options = CenterContainer:new{ HorizontalGroup:new{ - align = "center", - self.icon_spacing, - ConfigMenuItem:new{ - self.screen_rotate_icon, - dimen = self.icon_dimen:new(), - config = self, - }, - self.icon_spacing, - ConfigMenuItem:new{ - self.page_crop_icon, - dimen = self.icon_dimen:new(), - dialog = "Crop dialog", - config = self, - }, - self.icon_spacing, - ConfigMenuItem:new{ - self.page_layout_icon, - dimen = self.icon_dimen:new(), - config = self, - }, - self.icon_spacing, - ConfigMenuItem:new{ - self.text_font_icon, - dimen = self.icon_dimen:new(), - config = self, - }, - self.icon_spacing, - ConfigMenuItem:new{ - self.contrast_icon, - dimen = self.icon_dimen:new(), - config = self, + CenterContainer:new{ + VerticalGroup:new{ + align = "center", + self.reading_progress, + }, + dimen = Geom:new{ w = Screen:getWidth()*0.8, h = 100}, }, - self.icon_spacing, - ConfigMenuItem:new{ - self.more_options_icon, - dimen = self.icon_dimen:new(), - config = self, + CenterContainer:new{ + TextWidget:new{ + text = "Goto", + face = self.tface, + }, + dimen = Geom:new{ w = Screen:getWidth()*0.2, h = 100}, }, - self.icon_spacing, - } + }, + dimen = Geom:new{ w = Screen:getWidth(), h = 100}, + } + + self.menu_items = { + ConfigMenuItem:new{ + self.screen_rotate_icon, + options = self.screen_rotate_options, + dimen = self.icon_dimen:new(), + config = self, + }, + ConfigMenuItem:new{ + self.page_crop_icon, + options = self.page_crop_options, + dimen = self.icon_dimen:new(), + config = self, + }, + ConfigMenuItem:new{ + self.page_layout_icon, + options = self.page_layout_options, + dimen = self.icon_dimen:new(), + config = self, + }, + ConfigMenuItem:new{ + self.text_font_icon, + options = self.text_font_options, + dimen = self.icon_dimen:new(), + config = self, + }, + ConfigMenuItem:new{ + self.contrast_icon, + options = self.contrast_options, + dimen = self.icon_dimen:new(), + config = self, + }, + ConfigMenuItem:new{ + self.more_options_icon, + options = self.more_options, + dimen = self.icon_dimen:new(), + config = self, + }, + } + + local config_icons = ConfigIcons:new{ + icons = self.menu_items, + spacing = HorizontalSpan:new{ + width = (Screen:getWidth() - self.icon_dimen.w * #self.menu_items - 20) / (#self.menu_items+1) + }, + } + + local config_menu = FrameContainer:new{ + dimen = config_icons:getSize(), + background = 0, + config_icons, + } + + -- group for config layout + local config_layout = VerticalGroup:new{ + default_options, + config_menu, } -- maintain reference to content so we can change it later - self.config_dialog = config_dialog + self.config_layout = config_layout self[1] = BottomContainer:new{ dimen = Screen:getSize(), FrameContainer:new{ - dimen = config_dialog:getSize(), + dimen = config_layout:getSize(), background = 0, - config_dialog + config_layout, } } @@ -191,9 +371,9 @@ function ConfigDialog:init() UIManager.repaint_all = true end -function ConfigDialog:onShowDialog(dialog) - DEBUG("Showing dialog of item", dialog) - UIManager:show(dialog) +function ConfigDialog:onShowOptions(options) + self.config_layout[1] = options + UIManager.repaint_all = true return true end diff --git a/frontend/ui/graphics.lua b/frontend/ui/graphics.lua index 6a35fd8fb..d864b5e80 100644 --- a/frontend/ui/graphics.lua +++ b/frontend/ui/graphics.lua @@ -70,9 +70,9 @@ function blitbuffer.progressBar(bb, x, y, w, h, if load_m_h*2 > h then load_m_h = h/2 end - blitbuffer.paintBorder(fb.bb, x, y, w, h, 2, 15) - fb.bb:paintRect(x+load_m_w, y+load_m_h, - (w-2*load_m_w)*load_percent, (h-2*load_m_h), c) + bb:paintBorder(x, y, w, h, 2, 15) + bb:paintRect(x+load_m_w, y+load_m_h, + (w-2*load_m_w)*load_percent, (h-2*load_m_h), c) end diff --git a/frontend/ui/widget.lua b/frontend/ui/widget.lua index e6f8819e7..42290f62a 100644 --- a/frontend/ui/widget.lua +++ b/frontend/ui/widget.lua @@ -145,6 +145,22 @@ function CenterContainer:paintTo(bb, x, y) y + (self.dimen.h - contentSize.h)/2) end +--[[ +RightContainer aligns its content (1 widget) at the right of its own dimensions +]] +RightContainer = WidgetContainer:new() + +function RightContainer:paintTo(bb, x, y) + local contentSize = self[1]:getSize() + if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then + -- throw error? paint to scrap buffer and blit partially? + -- for now, we ignore this + end + self[1]:paintTo(bb, + x + (self.dimen.w - contentSize.w), + y + (self.dimen.h - contentSize.h)/2) +end + --[[ A FrameContainer is some graphics content (1 widget) that is surrounded by a frame ]] @@ -376,6 +392,24 @@ function ImageWidget:free() end end +--[[ +ProgressWidget shows a progress bar +]] +ProgressWidget = Widget:new{ + width = nil, + height = nil, + pecentage = nil, +} + +function ProgressWidget:getSize() + return { w = self.width, h = self.height } +end + +function ProgressWidget:paintTo(bb, x, y) + local size = self:getSize() + bb:progressBar(x, y, self.width, self.height, size.w, size.h, 2, 2, self.percentage, 15) +end + --[[ A Layout widget that puts objects besides each others ]] From 074522a36b1b3ec4702bca969a5873de85aa8faf Mon Sep 17 00:00:00 2001 From: chrox Date: Mon, 24 Dec 2012 07:54:44 +0800 Subject: [PATCH 3/7] first usable koptreader for new UI --- frontend/document/koptdocument.lua | 238 +++----------- frontend/ui/config.lua | 472 ++++++++++++---------------- frontend/ui/reader/readerconfig.lua | 165 +++++++++- frontend/ui/widget.lua | 2 +- 4 files changed, 413 insertions(+), 464 deletions(-) diff --git a/frontend/document/koptdocument.lua b/frontend/document/koptdocument.lua index a67fd1daf..ba09dcbc8 100644 --- a/frontend/document/koptdocument.lua +++ b/frontend/document/koptdocument.lua @@ -2,175 +2,41 @@ require "cache" require "ui/geometry" require "ui/screen" require "ui/device" +require "ui/reader/readerconfig" -KOPTOptions = { - { - name="font_size", - option_text="", - items_text={"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"}, - text_font_size={14,16,20,23,26,30,34,38,42,46}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true, true, true, true, true, true, true, true}, - values={0.2, 0.3, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.2, 2.8}, - default_value=DKOPTREADER_CONFIG_FONT_SIZE, - show = true, - draw_index = nil,}, - { - name="text_wrap", - option_text="Reflow", - items_text={"on","off"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true}, - values={1, 0}, - default_value=DKOPTREADER_CONFIG_TEXT_WRAP, - show = true, - draw_index = nil,}, - { - name="trim_page", - option_text="Trim Page", - items_text={"auto","manual"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true}, - values={1, 0}, - default_value=DKOPTREADER_CONFIG_TRIM_PAGE, - show = true, - draw_index = nil,}, - { - name="detect_indent", - option_text="Indentation", - items_text={"enable","disable"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true}, - values={1, 0}, - default_value=DKOPTREADER_CONFIG_DETECT_INDENT, - show = false, - draw_index = nil,}, - { - name="defect_size", - option_text="Defect Size", - items_text={"small","medium","large"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true}, - values={0.5, 1.0, 2.0}, - default_value=DKOPTREADER_CONFIG_DEFECT_SIZE, - show = true, - draw_index = nil,}, - { - name="page_margin", - option_text="Page Margin", - items_text={"small","medium","large"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true}, - values={0.02, 0.06, 0.10}, - default_value=DKOPTREADER_CONFIG_PAGE_MARGIN, - show = true, - draw_index = nil,}, - { - name="line_spacing", - option_text="Line Spacing", - items_text={"small","medium","large"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true}, - values={1.0, 1.2, 1.4}, - default_value=DKOPTREADER_CONFIG_LINE_SPACING, - show = true, - draw_index = nil,}, - { - name="word_spacing", - option_text="Word Spacing", - items_text={"small","medium","large"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true}, - values={0.05, 0.15, 0.375}, - default_value=DKOPTREADER_CONFIG_WORD_SAPCING, - show = true, - draw_index = nil,}, - { - name="multi_threads", - option_text="Multi Threads", - items_text={"on","off"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true}, - values={1, 0}, - default_value=DKOPTREADER_CONFIG_MULTI_THREADS, - show = true, - draw_index = nil,}, - { - name="quality", - option_text="Render Quality", - items_text={"low","medium","high"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true}, - values={0.5, 0.8, 1.0}, - default_value=DKOPTREADER_CONFIG_RENDER_QUALITY, - show = true, - draw_index = nil,}, - { - name="auto_straighten", - option_text="Auto Straighten", - items_text={"0","5","10"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true}, - values={0, 5, 10}, - default_value=DKOPTREADER_CONFIG_AUTO_STRAIGHTEN, - show = true, - draw_index = nil,}, - { - name="justification", - option_text="Justification", - items_text={"auto","left","center","right","full"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true, true, true}, - values={-1,0,1,2,3}, - default_value=DKOPTREADER_CONFIG_JUSTIFICATION, - show = true, - draw_index = nil,}, - { - name="max_columns", - option_text="Columns", - items_text={"1","2","3","4"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true, true}, - values={1,2,3,4}, - default_value=DKOPTREADER_CONFIG_MAX_COLUMNS, - show = true, - draw_index = nil,}, - { - name="contrast", - option_text="Contrast", - items_text={"lightest","lighter","default","darker","darkest"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true, true, true}, - values={2.0, 1.5, 1.0, 0.5, 0.2}, - default_value=DKOPTREADER_CONFIG_CONTRAST, - show = true, - draw_index = nil,}, - { - name="screen_rotation", - option_text="Screen Rotation", - items_text={"0","90","180","270"}, - current_item=nil, - text_dirty=true, - marker_dirty={true, true, true, true}, - values={0, 90, 180, 270}, - default_value=DKOPTREADER_CONFIG_SCREEN_ROTATION, - show = true, - draw_index = nil,}, -} +Configurable = {} + +function Configurable:hash(sep) + local hash = "" + local excluded = {multi_threads = true,} + for key,value in pairs(self) do + if type(value) == "number" and not excluded[key] then + hash = hash..sep..value + end + end + return hash +end + +function Configurable:loadDefaults() + for i=1,#KOPTOptions do + local options = KOPTOptions[i].options + for j=1,#KOPTOptions[i].options do + local key = KOPTOptions[i].options[j].name + self[key] = KOPTOptions[i].options[j].default_value + end + end +end + +function Configurable:loadSettings(settings, prefix) + for key,value in pairs(self) do + if type(value) == "number" then + saved_value = settings:readSetting(prefix..key) + self[key] = (saved_value == nil) and self[key] or saved_value + --Debug("Configurable:loadSettings", "key", key, "saved value", saved_value,"Configurable.key", self[key]) + end + end + --Debug("loaded config:", dump(Configurable)) +end -- Any document processed by K2pdfopt is called a koptdocument KoptDocument = Document:new{ @@ -181,27 +47,11 @@ KoptDocument = Document:new{ dc_null = DrawContext.new(), screen_size = Screen:getSize(), screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167, - options = KOPTOptions, - configurable = { - font_size = 1.0, - page_margin = 0.06, - line_spacing = 1.2, - word_spacing = 0.15, - quality = 1.0, - text_wrap = 1, - defect_size = 1.0, - trim_page = 0, - detect_indent = 1, - multi_threads = 0, - auto_straighten = 0, - justification = -1, - max_columns = 2, - contrast = 1.0, - screen_rotation = 0, - }, + configurable = Configurable, } function KoptDocument:init() + self.configurable:loadDefaults() self.file_type = string.lower(string.match(self.file, ".+%.([^.]+)") or "") if self.file_type == "pdf" then local ok @@ -318,7 +168,7 @@ end -- calculates page dimensions function KoptDocument:getPageDimensions(pageno, zoom, rotation) -- check cached page size - local hash = "kctx|"..self.file.."|"..pageno + local hash = "kctx|"..self.file.."|"..pageno.."|"..self.configurable:hash('|') local cached = Cache:check(hash) if not cached then local kc = self:getKOPTContext(pageno) @@ -341,7 +191,7 @@ end function KoptDocument:renderPage(pageno, rect, zoom, rotation, render_mode) self.render_mode = render_mode - local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation + local hash = "renderpg|"..self.file.."|"..pageno.."|"..self.configurable:hash('|') local page_size = self:getPageDimensions(pageno, zoom, rotation) -- this will be the size we actually render local size = page_size @@ -356,9 +206,12 @@ function KoptDocument:renderPage(pageno, rect, zoom, rotation, render_mode) return end -- only render required part - hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..tostring(rect) + hash = "renderpg|"..self.file.."|"..pageno.."|"..self.configurable:hash('|').."|"..tostring(rect) size = rect end + + local cached = Cache:check(hash) + if cached then return cached end -- prepare cache item with contained blitbuffer local tile = CacheItem:new{ @@ -369,13 +222,16 @@ function KoptDocument:renderPage(pageno, rect, zoom, rotation, render_mode) } -- draw to blitbuffer - local kc_hash = "kctx|"..self.file.."|"..pageno + local kc_hash = "kctx|"..self.file.."|"..pageno.."|"..self.configurable:hash('|') local page = self._document:openPage(pageno) local cached = Cache:check(kc_hash) if cached then page:rfdraw(cached.kctx, tile.bb) page:close() - Cache:insert(hash, tile) + DEBUG("cached hash", hash) + if not Cache:check(hash) then + Cache:insert(hash, tile) + end return tile end DEBUG("Error: cannot render page before reflowing.") diff --git a/frontend/ui/config.lua b/frontend/ui/config.lua index 7862380cf..dcbad462e 100644 --- a/frontend/ui/config.lua +++ b/frontend/ui/config.lua @@ -21,12 +21,10 @@ function FixedTextWidget:paintTo(bb, x, y) renderUtf8Text(bb, x, y+self._height, self.face, self.text, true) end -ConfigMenuItem = InputContainer:new{ - dimen = nil, -} - -function ConfigMenuItem:init() --- we need this table per-instance, so we declare it here +MenuBarItem = InputContainer:new{} +function MenuBarItem:init() + self.dimen = self[1]:getSize() + -- we need this table per-instance, so we declare it here if Device:isTouchDevice() then self.ges_events = { TapSelect = { @@ -44,8 +42,8 @@ function ConfigMenuItem:init() end end -function ConfigMenuItem:onTapSelect() - for _, item in pairs(self.config.menu_items) do +function MenuBarItem:onTapSelect() + for _, item in pairs(self.items) do item[1].invert = false end self[1].invert = true @@ -54,12 +52,46 @@ function ConfigMenuItem:onTapSelect() return true end -MenuItemDialog = FocusManager:new{ - dimen = nil, - menu_item = nil, - title = nil, - is_borderless = false, -} +OptionTextItem = InputContainer:new{} +function OptionTextItem:init() + local text_widget = self[1] + self.dimen = text_widget:getSize() + self[1] = UnderlineContainer:new{ + text_widget, + padding = self.padding, + color = self.color, + } + -- we need this table per-instance, so we declare it here + if Device:isTouchDevice() then + self.ges_events = { + TapSelect = { + GestureRange:new{ + ges = "tap", + range = self.dimen, + }, + doc = "Select Option Item", + }, + } + else + self.active_key_events = { + Select = { {"Press"}, doc = "chose selected item" }, + } + end +end + +function OptionTextItem:onTapSelect() + for _, item in pairs(self.items) do + item[1].color = 0 + end + self[1].color = 15 + local option_value = nil + if type(self.values) == "table" then + option_value = self.values[self.current_item] + self.config:onConfigChoice(self.name, option_value) + end + UIManager.repaint_all = true + return true +end ConfigIcons = HorizontalGroup:new{} function ConfigIcons:init() @@ -70,282 +102,191 @@ function ConfigIcons:init() table.insert(self, self.spacing) end -ConfigOption = CenterContainer:new{dimen = Geom:new{ w = Screen:getWidth(), h = 100},} +ConfigOption = CenterContainer:new{dimen = Geom:new{ w = Screen:getWidth(), h = math.floor(150*Screen:getWidth()/600)}} function ConfigOption:init() + local default_name_font_size = math.floor(20*Screen:getWidth()/600) + local default_item_font_size = math.floor(16*Screen:getWidth()/600) + local default_items_spacing = math.floor(30*Screen:getWidth()/600) + local default_option_height = math.floor(30*Screen:getWidth()/600) local vertical_group = VerticalGroup:new{} for c = 1, #self.options do - local name_align = self.options[c].name_align_right - local item_align = self.options[c].item_align_center - local horizontal_group = HorizontalGroup:new{} - local option_name_container = RightContainer:new{ - dimen = Geom:new{ w = Screen:getWidth()*(name_align and name_align or 0.33), h = 30}, - } - local option_name = TextWidget:new{ - text = self.options[c].name, - face = self.options[c].name_face, - } - table.insert(option_name_container, option_name) - table.insert(horizontal_group, option_name_container) - local option_items_container = CenterContainer:new{ - dimen = Geom:new{w = Screen:getWidth()*(item_align and item_align or 0.66), h = 30} - } - local option_items_group = HorizontalGroup:new{} - for d = 1, #self.options[c].items do - local option_item = TextWidget:new{ - text = self.options[c].items[d], - face = self.options[c].item_face, + if self.options[c].show ~= false then + local name_align = self.options[c].name_align_right and self.options[c].name_align_right or 0.33 + local item_align = self.options[c].item_align_center and self.options[c].item_align_center or 0.66 + local name_font_face = self.options[c].name_font_face and self.options[c].name_font_face or "tfont" + local name_font_size = self.options[c].name_font_size and self.options[c].name_font_size or default_name_font_size + local item_font_face = self.options[c].item_font_face and self.options[c].item_font_face or "cfont" + local item_font_size = self.options[c].item_font_size and self.options[c].item_font_size or default_item_font_size + local option_height = self.options[c].height and self.options[c].height or default_option_height + local items_spacing = HorizontalSpan:new{ width = self.options[c].spacing and self.options[c].spacing or default_items_spacing} + + local horizontal_group = HorizontalGroup:new{} + if self.options[c].name_text then + local option_name_container = RightContainer:new{ + dimen = Geom:new{ w = Screen:getWidth()*name_align, h = option_height}, + } + local option_name = TextWidget:new{ + text = self.options[c].name_text, + face = Font:getFace(name_font_face, name_font_size), + } + table.insert(option_name_container, option_name) + table.insert(horizontal_group, option_name_container) + end + + if self.options[c].widget == "ProgressWidget" then + local widget_container = CenterContainer:new{ + dimen = Geom:new{w = Screen:getWidth()*self.options[c].widget_align_center, h = option_height} + } + local widget = ProgressWidget:new{ + width = self.options[c].width, + height = self.options[c].height, + percentage = self.options[c].percentage, + } + table.insert(widget_container, widget) + table.insert(horizontal_group, widget_container) + end + + local option_items_container = CenterContainer:new{ + dimen = Geom:new{w = Screen:getWidth()*item_align, h = option_height} } - table.insert(option_items_group, option_item) - table.insert(option_items_group, self.options[c].spacing) - end - table.insert(option_items_container, option_items_group) - table.insert(horizontal_group, option_items_container) - table.insert(vertical_group, horizontal_group) - end + local option_items_group = HorizontalGroup:new{} + local option_items_fixed = false + local option_items = {} + if type(self.options[c].item_font_size) == "table" then + option_items_group.align = "bottom" + option_items_fixed = true + end + -- make current index according to configurable table + local current_item = nil + if self.options[c].name then + local val = self.config.configurable[self.options[c].name] + local min_diff = math.abs(val - self.options[c].values[1]) + local diff = nil + for index, val_ in pairs(self.options[c].values) do + if val == val_ then + current_item = index + break + end + diff = math.abs(val - val_) + if diff <= min_diff then + min_diff = diff + current_item = index + end + end + end + + for d = 1, #self.options[c].item_text do + local option_item = nil + if option_items_fixed then + option_item = OptionTextItem:new{ + FixedTextWidget:new{ + text = self.options[c].item_text[d], + face = Font:getFace(item_font_face, item_font_size[d]), + }, + padding = 3, + color = d == current_item and 15 or 0, + } + else + option_item = OptionTextItem:new{ + TextWidget:new{ + text = self.options[c].item_text[d], + face = Font:getFace(item_font_face, item_font_size), + }, + padding = -3, + color = d == current_item and 15 or 0, + } + end + option_items[d] = option_item + option_item.items = option_items + option_item.name = self.options[c].name + option_item.values = self.options[c].values + option_item.current_item = d + option_item.config = self.config + table.insert(option_items_group, option_item) + table.insert(option_items_group, items_spacing) + end + table.insert(option_items_container, option_items_group) + table.insert(horizontal_group, option_items_container) + table.insert(vertical_group, horizontal_group) + end -- if + end -- for self[1] = vertical_group end -ConfigFontSize = CenterContainer:new{dimen = Geom:new{ w = Screen:getWidth(), h = 100},} -function ConfigFontSize:init() - local vertical_group = VerticalGroup:new{} - local horizontal_group = HorizontalGroup:new{align = "bottom"} - for c = 1, #self.items do - local widget = FixedTextWidget:new{ - text = self.items[c], - face = Font:getFace(self.item_font_face, self.item_font_size[c]), +ConfigPanel = VerticalGroup:new{} +function ConfigPanel:init() + local default_option = ConfigOption:new{ + options = self.config_options.default_options + } + local menu_bar = FrameContainer:new{ + background = 0, + } + local menu_items = {} + local icons_width = 0 + local icons_height = 0 + for c = 1, #self.config_options do + local menu_icon = ImageWidget:new{ + file = self.config_options[c].icon + } + local icon_dimen = menu_icon:getSize() + icons_width = icons_width + icon_dimen.w + icons_height = icon_dimen.h > icons_height and icon_dimen.h or icons_height + + menu_items[c] = MenuBarItem:new{ + menu_icon, + options = ConfigOption:new{ + options = self.config_options[c].options, + config = self.config_dialog, + }, + config = self.config_dialog, + items = menu_items, } - table.insert(horizontal_group, self.spacing) - table.insert(horizontal_group, widget) end - table.insert(vertical_group, horizontal_group) - self[1] = vertical_group + menu_bar[1] = ConfigIcons:new{ + icons = menu_items, + spacing = HorizontalSpan:new{ + width = (Screen:getWidth() - icons_width) / (#menu_items+1) + } + } + menu_bar.dimen = Geom:new{ w = Screen:getWidth(), h = icons_height} + + self[1] = default_option + self[2] = menu_bar end --[[ Widget that displays config menu --]] -ConfigDialog = FocusManager:new{ - -- face for option names - tface = Font:getFace("tfont", 20), - -- face for option items - cface = Font:getFace("cfont", 16), - is_borderless = false, +ConfigDialog = InputContainer:new{ + --is_borderless = false, } -function ConfigDialog:init() - self.menu_dimen = self.dimen:copy() - ----------------------------------- - -- start to set up widget layout -- - ----------------------------------- - self.screen_rotate_icon = ImageWidget:new{ - file = "resources/icons/appbar.transform.rotate.right.large.png" - } - self.screen_rotate_options = ConfigOption:new{ - options = { - { - name = "Screen Rotation", - name_face = Font:getFace("tfont", 20), - items = {"portrait", "landscape"}, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 30 }, - } - }, - } - - self.page_crop_icon = ImageWidget:new{ - file = "resources/icons/appbar.crop.large.png" - } - self.page_crop_options = ConfigOption:new{ - options = { - { - name = "Page Crop", - name_face = Font:getFace("tfont", 20), - items = {"auto", "manual"}, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 30 }, - } - }, - } - - self.page_layout_icon = ImageWidget:new{ - file = "resources/icons/appbar.column.two.large.png" - } - self.page_layout_options = ConfigOption:new{ - options = { - { - name = "Page Margin", - name_face = Font:getFace("tfont", 20), - items = {"small", "medium", "large"}, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 30 }, - }, - { - name = "Line Spacing", - name_face = Font:getFace("tfont", 20), - items = {"small", "medium", "large"}, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 30 }, - }, - { - name = "Word Spacing", - name_face = Font:getFace("tfont", 20), - items = {"small", "medium", "large"}, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 30 }, - }, - }, - } - - self.text_font_icon = ImageWidget:new{ - file = "resources/icons/appbar.text.size.large.png" - } - self.text_font_options = ConfigFontSize:new{ - items = {"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"}, - item_font_face = "cfont", - item_font_size={14,16,20,23,26,30,34,38,42,46}, - spacing = HorizontalSpan:new{ width = Screen:getWidth()*0.03 }, - } - - self.contrast_icon = ImageWidget:new{ - file = "resources/icons/appbar.grade.b.large.png" - } - self.contrast_options = ConfigOption:new{ - options = { - { - name = "Contrast", - name_face = Font:getFace("tfont", 20), - name_align_right = 0.2, - items = {"lightest", "lighter", "default", "darker", "darkest"}, - item_align_center = 0.8, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 30 }, - } - }, - } - - self.more_options_icon = ImageWidget:new{ - file = "resources/icons/appbar.settings.large.png" - } - self.more_options = ConfigOption:new{ - options = { - { - name = "Render Quality", - name_face = Font:getFace("tfont", 20), - items = {"low", "default", "high"}, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 20 }, - }, - { - name = "Auto Straighten", - name_face = Font:getFace("tfont", 20), - items = {"0 deg", "5 deg", "10 deg"}, - item_face = Font:getFace("cfont", 16), - spacing = HorizontalSpan:new{ width = 20 }, - }, - } - } - - self.icon_dimen = Geom:new{ - w = 64, - h = 64, -- hardcoded for now - } - - self.reading_progress = VerticalGroup:new{ - ProgressWidget:new{ - width = Screen:getWidth()*0.7, - height = 5, - percentage = 0.0, - } - } - local default_options = CenterContainer:new{ - HorizontalGroup:new{ - CenterContainer:new{ - VerticalGroup:new{ - align = "center", - self.reading_progress, - }, - dimen = Geom:new{ w = Screen:getWidth()*0.8, h = 100}, - }, - CenterContainer:new{ - TextWidget:new{ - text = "Goto", - face = self.tface, - }, - dimen = Geom:new{ w = Screen:getWidth()*0.2, h = 100}, - }, - }, - dimen = Geom:new{ w = Screen:getWidth(), h = 100}, - } - - self.menu_items = { - ConfigMenuItem:new{ - self.screen_rotate_icon, - options = self.screen_rotate_options, - dimen = self.icon_dimen:new(), - config = self, - }, - ConfigMenuItem:new{ - self.page_crop_icon, - options = self.page_crop_options, - dimen = self.icon_dimen:new(), - config = self, - }, - ConfigMenuItem:new{ - self.page_layout_icon, - options = self.page_layout_options, - dimen = self.icon_dimen:new(), - config = self, - }, - ConfigMenuItem:new{ - self.text_font_icon, - options = self.text_font_options, - dimen = self.icon_dimen:new(), - config = self, - }, - ConfigMenuItem:new{ - self.contrast_icon, - options = self.contrast_options, - dimen = self.icon_dimen:new(), - config = self, - }, - ConfigMenuItem:new{ - self.more_options_icon, - options = self.more_options, - dimen = self.icon_dimen:new(), - config = self, - }, - } - - local config_icons = ConfigIcons:new{ - icons = self.menu_items, - spacing = HorizontalSpan:new{ - width = (Screen:getWidth() - self.icon_dimen.w * #self.menu_items - 20) / (#self.menu_items+1) - }, +function ConfigDialog:init() + ------------------------------------------ + -- start to set up widget layout --------- + ------------------------------------------ + self.config_panel = ConfigPanel:new{ + config_options = self.config_options, + config_dialog = self, } - local config_menu = FrameContainer:new{ - dimen = config_icons:getSize(), - background = 0, - config_icons, - } + local config_panel_size = self.config_panel:getSize() - -- group for config layout - local config_layout = VerticalGroup:new{ - default_options, - config_menu, + self.menu_dimen = Geom:new{ + x = (Screen:getWidth() - config_panel_size.w)/2, + y = Screen:getHeight() - config_panel_size.h, + w = config_panel_size.w, + h = config_panel_size.h, } - -- maintain reference to content so we can change it later - self.config_layout = config_layout self[1] = BottomContainer:new{ dimen = Screen:getSize(), FrameContainer:new{ - dimen = config_layout:getSize(), + dimen = self.config_panel:getSize(), background = 0, - config_layout, + self.config_panel, } } - ------------------------------------------ -- start to set up input event callback -- ------------------------------------------ @@ -372,7 +313,7 @@ function ConfigDialog:init() end function ConfigDialog:onShowOptions(options) - self.config_layout[1] = options + self.config_panel[1] = options UIManager.repaint_all = true return true end @@ -388,6 +329,7 @@ end function ConfigDialog:onTapCloseMenu(arg, ges_ev) if ges_ev.pos:notIntersectWith(self.menu_dimen) then self:onCloseMenu() + --self.ui:handleEvent(Event:new("GotoPageRel", 0)) return true end -end \ No newline at end of file +end diff --git a/frontend/ui/reader/readerconfig.lua b/frontend/ui/reader/readerconfig.lua index 626b1ac83..e7f3fab04 100644 --- a/frontend/ui/reader/readerconfig.lua +++ b/frontend/ui/reader/readerconfig.lua @@ -1,5 +1,157 @@ require "ui/config" +KOPTOptions = { + default_options = { + { + widget = "ProgressWidget", + widget_align_center = 0.8, + width = Screen:getWidth()*0.7, + height = 5, + percentage = 0.0, + item_text = {"Goto"}, + item_align_center = 0.2, + item_font_face = "tfont", + item_font_size = 20, + } + }, + { + icon = "resources/icons/appbar.transform.rotate.right.large.png", + options = { + { + name="screen_rotation", + name_text = "Screen Rotation", + item_text = {"portrait", "landscape"}, + values = {0, 90}, + default_value = 0, + } + } + }, + { + icon = "resources/icons/appbar.crop.large.png", + options = { + { + name="trim_page", + name_text = "Page Crop", + item_text = {"auto", "manual"}, + values = {1, 0}, + default_value = 1, + } + } + }, + { + icon = "resources/icons/appbar.column.two.large.png", + options = { + { + name = "text_wrap", + name_text = "Reflow", + item_text = {"on","off"}, + values = {1, 0}, + default_value = 1, + show = false + }, + { + name = "max_columns", + name_text = "Columns", + item_text = {"1","2","3","4"}, + values = {1,2,3,4}, + default_value = 2, + show = false + }, + { + name = "page_margin", + name_text = "Page Margin", + item_text = {"small", "medium", "large"}, + values = {0.02, 0.06, 0.10}, + default_value = 0.06, + }, + { + name = "line_spacing", + name_text = "Line Spacing", + item_text = {"small", "medium", "large"}, + values = {1.0, 1.2, 1.4}, + default_value = 1.2, + }, + { + name = "word_spacing", + name_text = "Word Spacing", + item_text = {"small", "medium", "large"}, + values = {0.05, 0.15, 0.375}, + default_value = 0.15, + }, + { + name = "justification", + name_text = "Justification", + item_text = {"auto","left","center","right","full"}, + values = {-1,0,1,2,3}, + default_value = -1, + }, + } + }, + { + icon = "resources/icons/appbar.text.size.large.png", + options = { + { + name = "font_size", + item_text = {"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"}, + item_align_center = 1.0, + spacing = Screen:getWidth()*0.03, + item_font_size = {14,16,20,23,26,30,34,38,42,46}, + values = {0.2, 0.3, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.2, 2.8}, + default_value = 1.0, + }, + } + }, + { + icon = "resources/icons/appbar.grade.b.large.png", + options = { + { + name = "contrast", + name_text = "Contrast", + name_align_right = 0.2, + item_text = {"lightest", "lighter", "default", "darker", "darkest"}, + item_align_center = 0.8, + values = {2.0, 1.5, 1.0, 0.5, 0.2}, + default_value = 1.0, + } + } + }, + { + icon = "resources/icons/appbar.settings.large.png", + options = { + { + name = "quality", + name_text = "Render Quality", + item_text = {"low", "default", "high"}, + values={0.5, 0.8, 1.0}, + default_value = 1.0, + }, + { + name = "auto_straighten", + name_text = "Auto Straighten", + item_text = {"0 deg", "5 deg", "10 deg"}, + values = {0, 5, 10}, + default_value = 0, + }, + { + name = "detect_indent", + name_text = "Indentation", + item_text = {"enable","disable"}, + values = {1, 0}, + default_value = 1, + show = false, + }, + { + name = "defect_size", + name_text = "Defect Size", + item_text = {"small","medium","large"}, + values = {0.5, 1.0, 2.0}, + default_value = 1.0, + show = false, + }, + } + }, +} + ReaderConfig = InputContainer:new{ dimen = Geom:new{ x = 0, @@ -10,7 +162,6 @@ ReaderConfig = InputContainer:new{ } function ReaderConfig:init() - DEBUG("init ReaderConfig.") if Device:isTouchDevice() then self.ges_events = { TapShowConfigMenu = { @@ -29,15 +180,15 @@ end function ReaderConfig:onShowConfigMenu() local config_dialog = ConfigDialog:new{ - configurable = self.configurable, - options = self.options, dimen = self.dimen:copy(), + ui = self.ui, + configurable = self.configurable, + config_options = KOPTOptions, } - function config_dialog:onConfigChoice(item) - if item.callback then - item.callback() - end + function config_dialog:onConfigChoice(option_name, option_value) + self.configurable[option_name] = option_value + --DEBUG("configurable", self.configurable) end local dialog_container = CenterContainer:new{ diff --git a/frontend/ui/widget.lua b/frontend/ui/widget.lua index 42290f62a..de8f3e7c5 100644 --- a/frontend/ui/widget.lua +++ b/frontend/ui/widget.lua @@ -374,7 +374,7 @@ function ImageWidget:getSize() if not self._bb then self:_render() end - return { w = self._bb:getWidth(), h = self._bb:getHeight() } + return Geom:new{ w = self._bb:getWidth(), h = self._bb:getHeight() } end function ImageWidget:paintTo(bb, x, y) From a649301e69a438876e8541cccefaebe815c29b12 Mon Sep 17 00:00:00 2001 From: chrox Date: Mon, 24 Dec 2012 08:19:34 +0800 Subject: [PATCH 4/7] make pdfreader and djvureader the defaults --- frontend/document/document.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index e5ee097c8..fca96135b 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -252,7 +252,7 @@ end -- load implementations: ---require "document/pdfdocument" ---require "document/djvudocument" +require "document/pdfdocument" +require "document/djvudocument" require "document/koptdocument" require "document/credocument" From 99a7ebaeb63bbf7cf9721af9bbe8529a78357413 Mon Sep 17 00:00:00 2001 From: chrox Date: Mon, 24 Dec 2012 16:55:10 +0800 Subject: [PATCH 5/7] larger option text in paperwhite --- frontend/ui/config.lua | 6 ++++-- frontend/ui/reader/readerconfig.lua | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/ui/config.lua b/frontend/ui/config.lua index dcbad462e..69495c770 100644 --- a/frontend/ui/config.lua +++ b/frontend/ui/config.lua @@ -105,7 +105,7 @@ end ConfigOption = CenterContainer:new{dimen = Geom:new{ w = Screen:getWidth(), h = math.floor(150*Screen:getWidth()/600)}} function ConfigOption:init() local default_name_font_size = math.floor(20*Screen:getWidth()/600) - local default_item_font_size = math.floor(16*Screen:getWidth()/600) + local default_item_font_size = math.floor(20*Screen:getWidth()/600) local default_items_spacing = math.floor(30*Screen:getWidth()/600) local default_option_height = math.floor(30*Screen:getWidth()/600) local vertical_group = VerticalGroup:new{} @@ -203,7 +203,9 @@ function ConfigOption:init() option_item.current_item = d option_item.config = self.config table.insert(option_items_group, option_item) - table.insert(option_items_group, items_spacing) + if d ~= #self.options[c].item_text then + table.insert(option_items_group, items_spacing) + end end table.insert(option_items_container, option_items_group) table.insert(horizontal_group, option_items_container) diff --git a/frontend/ui/reader/readerconfig.lua b/frontend/ui/reader/readerconfig.lua index e7f3fab04..a2e98c421 100644 --- a/frontend/ui/reader/readerconfig.lua +++ b/frontend/ui/reader/readerconfig.lua @@ -95,7 +95,7 @@ KOPTOptions = { item_text = {"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"}, item_align_center = 1.0, spacing = Screen:getWidth()*0.03, - item_font_size = {14,16,20,23,26,30,34,38,42,46}, + item_font_size = {20,24,28,32,36,38,40,42,46,50}, values = {0.2, 0.3, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.2, 2.8}, default_value = 1.0, }, @@ -109,6 +109,7 @@ KOPTOptions = { name_text = "Contrast", name_align_right = 0.2, item_text = {"lightest", "lighter", "default", "darker", "darkest"}, + item_font_size = math.floor(18*Screen:getWidth()/600), item_align_center = 0.8, values = {2.0, 1.5, 1.0, 0.5, 0.2}, default_value = 1.0, From e525264b01d1fad3123c95d5ef6d866045e3644b Mon Sep 17 00:00:00 2001 From: chrox Date: Mon, 24 Dec 2012 17:36:52 +0800 Subject: [PATCH 6/7] save/restore koptconfig to setting files --- frontend/document/koptdocument.lua | 8 ++++++++ frontend/ui/reader/readerconfig.lua | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/frontend/document/koptdocument.lua b/frontend/document/koptdocument.lua index ba09dcbc8..98a92d66e 100644 --- a/frontend/document/koptdocument.lua +++ b/frontend/document/koptdocument.lua @@ -38,6 +38,14 @@ function Configurable:loadSettings(settings, prefix) --Debug("loaded config:", dump(Configurable)) end +function Configurable:saveSettings(settings, prefix) + for key,value in pairs(self) do + if type(value) == "number" then + settings:saveSetting(prefix..key, value) + end + end +end + -- Any document processed by K2pdfopt is called a koptdocument KoptDocument = Document:new{ _document = false, diff --git a/frontend/ui/reader/readerconfig.lua b/frontend/ui/reader/readerconfig.lua index a2e98c421..5e1f3b26f 100644 --- a/frontend/ui/reader/readerconfig.lua +++ b/frontend/ui/reader/readerconfig.lua @@ -216,3 +216,12 @@ function ReaderConfig:onSetDimensions(dimen) -- update gesture listenning range according to new screen orientation self:init() end + +function ReaderConfig:onReadSettings(config) + DEBUG("read setting", config) + self.configurable:loadSettings(config, 'kopt_') +end + +function ReaderConfig:onCloseDocument() + self.configurable:saveSettings(self.ui.doc_settings, 'kopt_') +end From 349bcb996ed8fccf9de45f44deba9630ef8ebc99 Mon Sep 17 00:00:00 2001 From: chrox Date: Thu, 3 Jan 2013 22:24:38 +0800 Subject: [PATCH 7/7] use koptinterface to reflow text in pdf/djvu readers --- frontend/document/djvudocument.lua | 39 ++++- frontend/document/document.lua | 1 - frontend/document/koptdocument.lua | 249 ---------------------------- frontend/document/koptinterface.lua | 113 +++++++++++++ frontend/document/pdfdocument.lua | 36 +++- frontend/ui/reader/readerconfig.lua | 53 +++++- frontend/ui/reader/readerpaging.lua | 5 +- 7 files changed, 236 insertions(+), 260 deletions(-) delete mode 100644 frontend/document/koptdocument.lua create mode 100644 frontend/document/koptinterface.lua diff --git a/frontend/document/djvudocument.lua b/frontend/document/djvudocument.lua index d8f627e06..1b2a2b55c 100644 --- a/frontend/document/djvudocument.lua +++ b/frontend/document/djvudocument.lua @@ -1,14 +1,23 @@ require "cache" require "ui/geometry" +require "ui/screen" +require "ui/device" +require "ui/reader/readerconfig" +require "document/koptinterface" DjvuDocument = Document:new{ _document = false, -- libdjvulibre manages its own additional cache, default value is hard written in c module. djvulibre_cache_size = nil, - dc_null = DrawContext.new() + dc_null = DrawContext.new(), + screen_size = Screen:getSize(), + screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167, + configurable = Configurable, + koptinterface = KoptInterface, } function DjvuDocument:init() + self.configurable:loadDefaults() if not validDjvuFile(self.file) then self.error_message = "Not a valid DjVu file" return @@ -22,6 +31,7 @@ function DjvuDocument:init() end self.is_open = true self.info.has_pages = true + self.info.configurable = true self:_readMetadata() end @@ -38,7 +48,8 @@ end function DjvuDocument:getUsedBBox(pageno) -- djvu does not support usedbbox, so fake it. local used = {} - used.x, used.y, used.w, used.h = 0.01, 0.01, -0.01, -0.01 + local native_dim = self:getNativePageDimensions(pageno) + used.x0, used.y0, used.x1, used.y1 = 0, 0, native_dim.w, native_dim.h return used end @@ -52,4 +63,28 @@ function DjvuDocument:invertTextYAxel(pageno, text_table) return text_table end +function DjvuDocument:getPageDimensions(pageno, zoom, rotation) + if self.configurable.text_wrap == 1 then + return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation) + else + return Document.getPageDimensions(self, pageno, zoom, rotation) + end +end + +function DjvuDocument:renderPage(pageno, rect, zoom, rotation, render_mode) + if self.configurable.text_wrap == 1 then + return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, render_mode) + else + return Document.renderPage(self, pageno, rect, zoom, rotation, render_mode) + end +end + +function DjvuDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, render_mode) + if self.configurable.text_wrap == 1 then + self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode) + else + Document.drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode) + end +end + DocumentRegistry:addProvider("djvu", "application/djvu", DjvuDocument) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index fca96135b..3482c21e1 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -254,5 +254,4 @@ end require "document/pdfdocument" require "document/djvudocument" -require "document/koptdocument" require "document/credocument" diff --git a/frontend/document/koptdocument.lua b/frontend/document/koptdocument.lua deleted file mode 100644 index 98a92d66e..000000000 --- a/frontend/document/koptdocument.lua +++ /dev/null @@ -1,249 +0,0 @@ -require "cache" -require "ui/geometry" -require "ui/screen" -require "ui/device" -require "ui/reader/readerconfig" - -Configurable = {} - -function Configurable:hash(sep) - local hash = "" - local excluded = {multi_threads = true,} - for key,value in pairs(self) do - if type(value) == "number" and not excluded[key] then - hash = hash..sep..value - end - end - return hash -end - -function Configurable:loadDefaults() - for i=1,#KOPTOptions do - local options = KOPTOptions[i].options - for j=1,#KOPTOptions[i].options do - local key = KOPTOptions[i].options[j].name - self[key] = KOPTOptions[i].options[j].default_value - end - end -end - -function Configurable:loadSettings(settings, prefix) - for key,value in pairs(self) do - if type(value) == "number" then - saved_value = settings:readSetting(prefix..key) - self[key] = (saved_value == nil) and self[key] or saved_value - --Debug("Configurable:loadSettings", "key", key, "saved value", saved_value,"Configurable.key", self[key]) - end - end - --Debug("loaded config:", dump(Configurable)) -end - -function Configurable:saveSettings(settings, prefix) - for key,value in pairs(self) do - if type(value) == "number" then - settings:saveSetting(prefix..key, value) - end - end -end - --- Any document processed by K2pdfopt is called a koptdocument -KoptDocument = Document:new{ - _document = false, - -- muPDF manages its own additional cache - mupdf_cache_size = 5 * 1024 * 1024, - djvulibre_cache_size = nil, - dc_null = DrawContext.new(), - screen_size = Screen:getSize(), - screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167, - configurable = Configurable, -} - -function KoptDocument:init() - self.configurable:loadDefaults() - self.file_type = string.lower(string.match(self.file, ".+%.([^.]+)") or "") - if self.file_type == "pdf" then - local ok - ok, self._document = pcall(pdf.openDocument, self.file, self.mupdf_cache_size) - if not ok then - self.error_message = self.doc -- will contain error message - return - end - self.is_open = true - self.info.has_pages = true - self.info.configurable = true - if self._document:needsPassword() then - self.is_locked = true - else - self:_readMetadata() - end - - elseif self.file_type == "djvu" then - if not validDjvuFile(self.file) then - self.error_message = "Not a valid DjVu file" - return - end - - local ok - ok, self._document = pcall(djvu.openDocument, self.file, self.djvulibre_cache_size) - if not ok then - self.error_message = self.doc -- will contain error message - return - end - self.is_open = true - self.info.has_pages = true - self.info.configurable = true - self:_readMetadata() - end -end - -function KoptDocument:unlock(password) - if not self._document:authenticatePassword(password) then - self._document:close() - return false, "wrong password" - end - self.is_locked = false - return self:_readMetadata() -end - --- check DjVu magic string to validate -function validDjvuFile(filename) - f = io.open(filename, "r") - if not f then return false end - local magic = f:read(8) - f:close() - if not magic or magic ~= "AT&TFORM" then return false end - return true -end - -function KoptDocument:getUsedBBox(pageno) - if self.file_type == "pdf" then - local hash = "pgubbox|"..self.file.."|"..pageno - local cached = Cache:check(hash) - if cached then - return cached.ubbox - end - local page = self._document:openPage(pageno) - local used = {} - used.x0, used.y0, used.x1, used.y1 = page:getUsedBBox() - local pwidth, pheight = page:getSize(self.dc_null) - if used.x1 == 0 then used.x1 = pwidth end - if used.y1 == 0 then used.y1 = pheight end - -- clamp to page BBox - if used.x0 < 0 then used.x0 = 0 end; - if used.y0 < 0 then used.y0 = 0 end; - if used.x1 > pwidth then used.x1 = pwidth end - if used.y1 > pheight then used.y1 = pheight end - --@TODO give size for cacheitem? 02.12 2012 (houqp) - Cache:insert(hash, CacheItem:new{ - ubbox = used, - }) - page:close() - DEBUG("UsedBBox", used) - return used - elseif self.file_type == "djvu" then - -- djvu does not support usedbbox, so fake it. - local used = {} - local native_dim = self:getNativePageDimensions(pageno) - used.x0, used.y0, used.x1, used.y1 = 0, 0, native_dim.w, native_dim.h - return used - end -end - --- get reflow context -function KoptDocument:getKOPTContext(pageno) - local kc = KOPTContext.new() - kc:setTrim(self.configurable.trim_page) - kc:setWrap(self.configurable.text_wrap) - kc:setIndent(self.configurable.detect_indent) - kc:setRotate(self.configurable.screen_rotation) - kc:setColumns(self.configurable.max_columns) - kc:setDeviceDim(self.screen_size.w, self.screen_size.h) - kc:setDeviceDPI(self.screen_dpi) - kc:setStraighten(self.configurable.auto_straighten) - kc:setJustification(self.configurable.justification) - kc:setZoom(self.configurable.font_size) - kc:setMargin(self.configurable.page_margin) - kc:setQuality(self.configurable.quality) - kc:setContrast(self.configurable.contrast) - kc:setDefectSize(self.configurable.defect_size) - kc:setLineSpacing(self.configurable.line_spacing) - kc:setWordSpacing(self.configurable.word_spacing) - local bbox = self:getUsedBBox(pageno) - kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1) - return kc -end - --- calculates page dimensions -function KoptDocument:getPageDimensions(pageno, zoom, rotation) - -- check cached page size - local hash = "kctx|"..self.file.."|"..pageno.."|"..self.configurable:hash('|') - local cached = Cache:check(hash) - if not cached then - local kc = self:getKOPTContext(pageno) - local page = self._document:openPage(pageno) - -- reflow page - page:reflow(kc, 0) - page:close() - local fullwidth, fullheight = kc:getPageDim() - DEBUG("page::reflowPage:", "fullwidth:", fullwidth, "fullheight:", fullheight) - local page_size = Geom:new{ w = fullwidth, h = fullheight } - -- cache reflowed page size and kc - Cache:insert(hash, CacheItem:new{ kctx = kc }) - return page_size - end - --DEBUG("Found cached koptcontex on page", pageno, cached) - local fullwidth, fullheight = cached.kctx:getPageDim() - local page_size = Geom:new{ w = fullwidth, h = fullheight } - return page_size -end - -function KoptDocument:renderPage(pageno, rect, zoom, rotation, render_mode) - self.render_mode = render_mode - local hash = "renderpg|"..self.file.."|"..pageno.."|"..self.configurable:hash('|') - local page_size = self:getPageDimensions(pageno, zoom, rotation) - -- this will be the size we actually render - local size = page_size - -- we prefer to render the full page, if it fits into cache - if not Cache:willAccept(size.w * size.h / 2) then - -- whole page won't fit into cache - DEBUG("rendering only part of the page") - -- TODO: figure out how to better segment the page - if not rect then - DEBUG("aborting, since we do not have a specification for that part") - -- required part not given, so abort - return - end - -- only render required part - hash = "renderpg|"..self.file.."|"..pageno.."|"..self.configurable:hash('|').."|"..tostring(rect) - size = rect - end - - local cached = Cache:check(hash) - if cached then return cached end - - -- prepare cache item with contained blitbuffer - local tile = CacheItem:new{ - size = size.w * size.h / 2 + 64, -- estimation - excerpt = size, - pageno = pageno, - bb = Blitbuffer.new(size.w, size.h) - } - - -- draw to blitbuffer - local kc_hash = "kctx|"..self.file.."|"..pageno.."|"..self.configurable:hash('|') - local page = self._document:openPage(pageno) - local cached = Cache:check(kc_hash) - if cached then - page:rfdraw(cached.kctx, tile.bb) - page:close() - DEBUG("cached hash", hash) - if not Cache:check(hash) then - Cache:insert(hash, tile) - end - return tile - end - DEBUG("Error: cannot render page before reflowing.") -end - -DocumentRegistry:addProvider("pdf", "application/pdf", KoptDocument) -DocumentRegistry:addProvider("djvu", "application/djvu", KoptDocument) diff --git a/frontend/document/koptinterface.lua b/frontend/document/koptinterface.lua new file mode 100644 index 000000000..a45951b3f --- /dev/null +++ b/frontend/document/koptinterface.lua @@ -0,0 +1,113 @@ +require "cache" +require "ui/geometry" +require "ui/screen" +require "ui/device" +require "ui/reader/readerconfig" + +KoptInterface = {} + +-- get reflow context +function KoptInterface:getKOPTContext(doc, pageno) + local kc = KOPTContext.new() + kc:setTrim(doc.configurable.trim_page) + kc:setWrap(doc.configurable.text_wrap) + kc:setIndent(doc.configurable.detect_indent) + kc:setRotate(doc.configurable.screen_rotation) + kc:setColumns(doc.configurable.max_columns) + kc:setDeviceDim(doc.screen_size.w, doc.screen_size.h) + kc:setDeviceDPI(doc.screen_dpi) + kc:setStraighten(doc.configurable.auto_straighten) + kc:setJustification(doc.configurable.justification) + kc:setZoom(doc.configurable.font_size) + kc:setMargin(doc.configurable.page_margin) + kc:setQuality(doc.configurable.quality) + kc:setContrast(doc.configurable.contrast) + kc:setDefectSize(doc.configurable.defect_size) + kc:setLineSpacing(doc.configurable.line_spacing) + kc:setWordSpacing(doc.configurable.word_spacing) + local bbox = doc:getUsedBBox(pageno) + kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1) + return kc +end + +-- calculates page dimensions +function KoptInterface:getPageDimensions(doc, pageno, zoom, rotation) + -- check cached page size + local hash = "kctx|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|') + local cached = Cache:check(hash) + if not cached then + local kc = self:getKOPTContext(doc, pageno) + local page = doc._document:openPage(pageno) + -- reflow page + page:reflow(kc, 0) + page:close() + local fullwidth, fullheight = kc:getPageDim() + DEBUG("page::reflowPage:", "fullwidth:", fullwidth, "fullheight:", fullheight) + local page_size = Geom:new{ w = fullwidth, h = fullheight } + -- cache reflowed page size and kc + Cache:insert(hash, CacheItem:new{ kctx = kc }) + return page_size + end + --DEBUG("Found cached koptcontex on page", pageno, cached) + local fullwidth, fullheight = cached.kctx:getPageDim() + local page_size = Geom:new{ w = fullwidth, h = fullheight } + return page_size +end + +function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode) + doc.render_mode = render_mode + local hash = "renderpg|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|') + local page_size = self:getPageDimensions(doc, pageno, zoom, rotation) + -- this will be the size we actually render + local size = page_size + -- we prefer to render the full page, if it fits into cache + if not Cache:willAccept(size.w * size.h / 2) then + -- whole page won't fit into cache + DEBUG("rendering only part of the page") + -- TODO: figure out how to better segment the page + if not rect then + DEBUG("aborting, since we do not have a specification for that part") + -- required part not given, so abort + return + end + -- only render required part + hash = "renderpg|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|').."|"..tostring(rect) + size = rect + end + + local cached = Cache:check(hash) + if cached then return cached end + + -- prepare cache item with contained blitbuffer + local tile = CacheItem:new{ + size = size.w * size.h / 2 + 64, -- estimation + excerpt = size, + pageno = pageno, + bb = Blitbuffer.new(size.w, size.h) + } + + -- draw to blitbuffer + local kc_hash = "kctx|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|') + local page = doc._document:openPage(pageno) + local cached = Cache:check(kc_hash) + if cached then + page:rfdraw(cached.kctx, tile.bb) + page:close() + DEBUG("cached hash", hash) + if not Cache:check(hash) then + Cache:insert(hash, tile) + end + return tile + end + DEBUG("Error: cannot render page before reflowing.") +end + +function KoptInterface:drawPage(doc, target, x, y, rect, pageno, zoom, rotation, render_mode) + local tile = self:renderPage(doc, pageno, rect, zoom, rotation, render_mode) + DEBUG("now painting", tile, rect) + target:blitFrom(tile.bb, + x, y, + rect.x - tile.excerpt.x, + rect.y - tile.excerpt.y, + rect.w, rect.h) +end diff --git a/frontend/document/pdfdocument.lua b/frontend/document/pdfdocument.lua index 17d2eb4df..85709c5a6 100644 --- a/frontend/document/pdfdocument.lua +++ b/frontend/document/pdfdocument.lua @@ -1,14 +1,23 @@ require "cache" require "ui/geometry" +require "ui/screen" +require "ui/device" +require "ui/reader/readerconfig" +require "document/koptinterface" PdfDocument = Document:new{ _document = false, -- muPDF manages its own additional cache mupdf_cache_size = 5 * 1024 * 1024, - dc_null = DrawContext.new() + dc_null = DrawContext.new(), + screen_size = Screen:getSize(), + screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167, + configurable = Configurable, + koptinterface = KoptInterface, } function PdfDocument:init() + self.configurable:loadDefaults() local ok ok, self._document = pcall(pdf.openDocument, self.file, self.mupdf_cache_size) if not ok then @@ -17,6 +26,7 @@ function PdfDocument:init() end self.is_open = true self.info.has_pages = true + self.info.configurable = true if self._document:needsPassword() then self.is_locked = true else @@ -50,4 +60,28 @@ function PdfDocument:getUsedBBox(pageno) return used end +function PdfDocument:getPageDimensions(pageno, zoom, rotation) + if self.configurable.text_wrap == 1 then + return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation) + else + return Document.getPageDimensions(self, pageno, zoom, rotation) + end +end + +function PdfDocument:renderPage(pageno, rect, zoom, rotation, render_mode) + if self.configurable.text_wrap == 1 then + return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, render_mode) + else + return Document.renderPage(self, pageno, rect, zoom, rotation, render_mode) + end +end + +function PdfDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, render_mode) + if self.configurable.text_wrap == 1 then + self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode) + else + Document.drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode) + end +end + DocumentRegistry:addProvider("pdf", "application/pdf", PdfDocument) diff --git a/frontend/ui/reader/readerconfig.lua b/frontend/ui/reader/readerconfig.lua index 5e1f3b26f..b13ce0dc3 100644 --- a/frontend/ui/reader/readerconfig.lua +++ b/frontend/ui/reader/readerconfig.lua @@ -46,8 +46,8 @@ KOPTOptions = { name_text = "Reflow", item_text = {"on","off"}, values = {1, 0}, - default_value = 1, - show = false + default_value = 0, + show = true }, { name = "max_columns", @@ -153,6 +153,48 @@ KOPTOptions = { }, } +Configurable = {} + +function Configurable:hash(sep) + local hash = "" + local excluded = {multi_threads = true,} + for key,value in pairs(self) do + if type(value) == "number" and not excluded[key] then + hash = hash..sep..value + end + end + return hash +end + +function Configurable:loadDefaults() + for i=1,#KOPTOptions do + local options = KOPTOptions[i].options + for j=1,#KOPTOptions[i].options do + local key = KOPTOptions[i].options[j].name + self[key] = KOPTOptions[i].options[j].default_value + end + end +end + +function Configurable:loadSettings(settings, prefix) + for key,value in pairs(self) do + if type(value) == "number" then + saved_value = settings:readSetting(prefix..key) + self[key] = (saved_value == nil) and self[key] or saved_value + --Debug("Configurable:loadSettings", "key", key, "saved value", saved_value,"Configurable.key", self[key]) + end + end + --Debug("loaded config:", dump(Configurable)) +end + +function Configurable:saveSettings(settings, prefix) + for key,value in pairs(self) do + if type(value) == "number" then + settings:saveSetting(prefix..key, value) + end + end +end + ReaderConfig = InputContainer:new{ dimen = Geom:new{ x = 0, @@ -189,7 +231,9 @@ function ReaderConfig:onShowConfigMenu() function config_dialog:onConfigChoice(option_name, option_value) self.configurable[option_name] = option_value - --DEBUG("configurable", self.configurable) + if option_name == "text_wrap" then + self.ui:handleEvent(Event:new("RedrawCurrentPage")) + end end local dialog_container = CenterContainer:new{ @@ -199,7 +243,7 @@ function ReaderConfig:onShowConfigMenu() config_dialog.close_callback = function () UIManager:close(menu_container) end - -- maintain a reference to menu_container + self.dialog_container = dialog_container UIManager:show(config_dialog) @@ -218,7 +262,6 @@ function ReaderConfig:onSetDimensions(dimen) end function ReaderConfig:onReadSettings(config) - DEBUG("read setting", config) self.configurable:loadSettings(config, 'kopt_') end diff --git a/frontend/ui/reader/readerpaging.lua b/frontend/ui/reader/readerpaging.lua index 64f804180..f9da309e7 100644 --- a/frontend/ui/reader/readerpaging.lua +++ b/frontend/ui/reader/readerpaging.lua @@ -227,5 +227,6 @@ function ReaderPaging:onGotoPageRel(diff) return true end - - +function ReaderPaging:onRedrawCurrentPage() + self.ui:handleEvent(Event:new("PageUpdate", self.current_page)) +end