mirror of https://github.com/koreader/koreader
refactor refresh
Lots of the device-related distinction wandered into base/ffi/framebuffer_<driver>. This eases the refresh logic in UI manager, which basically only decides what kind of refresh to trigger. The device specific configuration in the framebuffer driver decides how to realize that whish. screen.lua is gone, in its place is now the framebuffer driver. The device abstraction decides what framebuffer driver to load.pull/1217/head
parent
7b91935df0
commit
63af71188a
@ -1,246 +0,0 @@
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
local einkfb = require("ffi/framebuffer")
|
||||
local Geom = require("ui/geometry")
|
||||
local util = require("ffi/util")
|
||||
local DEBUG = require("dbg")
|
||||
|
||||
--[[
|
||||
Codes for rotation modes:
|
||||
|
||||
1 for no rotation,
|
||||
2 for landscape with bottom on the right side of screen, etc.
|
||||
|
||||
2
|
||||
+--------------+
|
||||
| +----------+ |
|
||||
| | | |
|
||||
| | Freedom! | |
|
||||
| | | |
|
||||
| | | |
|
||||
3 | | | | 1
|
||||
| | | |
|
||||
| | | |
|
||||
| +----------+ |
|
||||
| |
|
||||
| |
|
||||
+--------------+
|
||||
0
|
||||
--]]
|
||||
|
||||
|
||||
local Screen = {
|
||||
cur_rotation_mode = 0,
|
||||
native_rotation_mode = nil,
|
||||
blitbuffer_rotation_mode = 0,
|
||||
|
||||
bb = nil,
|
||||
saved_bb = nil,
|
||||
|
||||
screen_size = Geom:new(),
|
||||
viewport = nil,
|
||||
|
||||
fb = einkfb.open("/dev/fb0"),
|
||||
-- will be set upon loading by Device class:
|
||||
device = nil,
|
||||
}
|
||||
|
||||
function Screen:new(o)
|
||||
local o = o or {}
|
||||
setmetatable(o, self)
|
||||
self.__index = self
|
||||
if o.init then o:init() end
|
||||
return o
|
||||
end
|
||||
|
||||
function Screen:init()
|
||||
self.bb = self.fb.bb
|
||||
self.blitbuffer_rotation_mode = self.bb:getRotation()
|
||||
-- asking the framebuffer for orientation is error prone,
|
||||
-- so we do this simple heuristic (for now)
|
||||
self.screen_size.w = self.bb:getWidth()
|
||||
self.screen_size.h = self.bb:getHeight()
|
||||
if self.screen_size.w > self.screen_size.h then
|
||||
self.native_rotation_mode = 1
|
||||
self.screen_size.w, self.screen_size.h = self.screen_size.h, self.screen_size.w
|
||||
else
|
||||
self.native_rotation_mode = 0
|
||||
end
|
||||
self.cur_rotation_mode = self.native_rotation_mode
|
||||
end
|
||||
|
||||
--[[
|
||||
set a rectangle that represents the area of the screen we are working on
|
||||
--]]
|
||||
function Screen:setViewport(viewport)
|
||||
self.viewport = self.screen_size:intersect(viewport)
|
||||
self.bb = self.fb.bb:viewport(
|
||||
self.viewport.x, self.viewport.y,
|
||||
self.viewport.w, self.viewport.h)
|
||||
end
|
||||
|
||||
function Screen:refresh(refresh_type, waveform_mode, wait_for_marker, x, y, w, h)
|
||||
if self.viewport and x and y then
|
||||
--[[
|
||||
we need to adapt the coordinates when we have a viewport.
|
||||
this adaptation depends on the rotation:
|
||||
|
||||
0,0 fb.w
|
||||
+---+---------------------------+---+
|
||||
| |v.y v.y| |
|
||||
|v.x| |vx2|
|
||||
+---+---------------------------+---+
|
||||
| | v.w | |
|
||||
| | | |
|
||||
| | | |
|
||||
| |v.h (viewport) | |
|
||||
| | | | fb.h
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
+---+---------------------------+---+
|
||||
|v.x| |vx2|
|
||||
| |vy2 vy2| |
|
||||
+---+---------------------------+---+
|
||||
|
||||
The viewport offset v.y/v.x only applies when rotation is 0 degrees.
|
||||
For other rotations (0,0 is in one of the other edges), we need to
|
||||
recalculate the offsets.
|
||||
--]]
|
||||
|
||||
local vx2 = self.screen_size.w - (self.viewport.x + self.viewport.w)
|
||||
local vy2 = self.screen_size.h - (self.viewport.y + self.viewport.h)
|
||||
|
||||
if self.cur_rotation_mode == 0 then
|
||||
-- (0,0) is at top left of screen
|
||||
x = x + self.viewport.x
|
||||
y = y + self.viewport.y
|
||||
elseif self.cur_rotation_mode == 1 then
|
||||
-- (0,0) is at bottom left of screen
|
||||
x = x + vy2
|
||||
y = y + self.viewport.x
|
||||
elseif self.cur_rotation_mode == 2 then
|
||||
-- (0,0) is at bottom right of screen
|
||||
x = x + vx2
|
||||
y = y + vy2
|
||||
else
|
||||
-- (0,0) is at top right of screen
|
||||
x = x + self.viewport.y
|
||||
y = y + vx2
|
||||
end
|
||||
end
|
||||
self.fb:refresh(refresh_type, waveform_mode, wait_for_marker, x, y, w, h)
|
||||
end
|
||||
|
||||
function Screen:getSize()
|
||||
return Geom:new{w = self.bb:getWidth(), h = self.bb:getHeight()}
|
||||
end
|
||||
|
||||
function Screen:getWidth()
|
||||
return self.bb:getWidth()
|
||||
end
|
||||
|
||||
function Screen:getScreenWidth()
|
||||
return self.screen_size.w
|
||||
end
|
||||
|
||||
function Screen:getScreenHeight()
|
||||
return self.screen_size.h
|
||||
end
|
||||
|
||||
function Screen:getHeight()
|
||||
return self.bb:getHeight()
|
||||
end
|
||||
|
||||
function Screen:getDPI()
|
||||
if self.dpi == nil then
|
||||
self.dpi = G_reader_settings:readSetting("screen_dpi")
|
||||
end
|
||||
if self.dpi == nil then
|
||||
self.dpi = self.device.display_dpi
|
||||
end
|
||||
if self.dpi == nil then
|
||||
self.dpi = 160
|
||||
end
|
||||
return self.dpi
|
||||
end
|
||||
|
||||
function Screen:setDPI(dpi)
|
||||
G_reader_settings:saveSetting("screen_dpi", dpi)
|
||||
end
|
||||
|
||||
function Screen:scaleByDPI(px)
|
||||
local dpi = self:getDPI()
|
||||
-- larger screen needs larger scale
|
||||
local size_scale = math.min(self:getWidth(), self:getHeight())/dpi/3.6
|
||||
-- scaled positive px should also be positive
|
||||
return math.ceil(px * size_scale * dpi/167)
|
||||
end
|
||||
|
||||
function Screen:getRotationMode()
|
||||
return self.cur_rotation_mode
|
||||
end
|
||||
|
||||
function Screen:getScreenMode()
|
||||
if self:getWidth() > self:getHeight() then
|
||||
return "landscape"
|
||||
else
|
||||
return "portrait"
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:setRotationMode(mode)
|
||||
self.bb:rotateAbsolute(-90 * (mode - self.native_rotation_mode - self.blitbuffer_rotation_mode))
|
||||
if self.viewport then
|
||||
self.fb.bb:setRotation(self.bb:getRotation())
|
||||
end
|
||||
self.cur_rotation_mode = mode
|
||||
end
|
||||
|
||||
function Screen:setScreenMode(mode)
|
||||
if mode == "portrait" then
|
||||
if self.cur_rotation_mode ~= 0 then
|
||||
self:setRotationMode(0)
|
||||
end
|
||||
elseif mode == "landscape" then
|
||||
if self.cur_rotation_mode == 0 or self.cur_rotation_mode == 2 then
|
||||
self:setRotationMode(DLANDSCAPE_CLOCKWISE_ROTATION and 1 or 3)
|
||||
elseif self.cur_rotation_mode == 1 or self.cur_rotation_mode == 3 then
|
||||
self:setRotationMode((self.cur_rotation_mode + 2) % 4)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:toggleNightMode()
|
||||
self.bb:invert()
|
||||
if self.viewport then
|
||||
-- invert and blank out the full framebuffer when we are working on a viewport
|
||||
self.fb.bb:invert()
|
||||
self.fb.bb:fill(Blitbuffer.COLOR_WHITE)
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:saveCurrentBB()
|
||||
if self.saved_bb then self.saved_bb:free() end
|
||||
self.saved_bb = self.bb:copy()
|
||||
end
|
||||
|
||||
function Screen:restoreFromSavedBB()
|
||||
if self.saved_bb then
|
||||
self.bb:blitFullFrom(self.saved_bb)
|
||||
-- free data
|
||||
self.saved_bb:free()
|
||||
self.saved_bb = nil
|
||||
end
|
||||
end
|
||||
|
||||
function Screen:shot(filename)
|
||||
DEBUG("write PNG file", filename)
|
||||
self.bb:writePNG(filename)
|
||||
end
|
||||
|
||||
function Screen:close()
|
||||
DEBUG("close screen framebuffer")
|
||||
self.fb:close()
|
||||
end
|
||||
|
||||
return Screen
|
Loading…
Reference in New Issue