mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
The calculation did not correctly calculate the offset in rotated modes when the rotation was 90 or 270 degrees. Under these circumstances, getWidth() and getHeight() did return rotated values for the framebuffer, while Device.viewport did return not rotated values.
215 lines
5.5 KiB
Lua
215 lines
5.5 KiB
Lua
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
|
|
-- adapt to viewport, depending on rotation
|
|
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 + (self.fb.bb:getWidth()-self.viewport.h)
|
|
y = y + self.viewport.x
|
|
elseif self.cur_rotation_mode == 2 then
|
|
-- (0,0) is at bottom right of screen
|
|
x = x + (self.fb.bb:getWidth()-self.viewport.w)
|
|
y = y + (self.fb.bb:getHeight()-self.viewport.h)
|
|
else
|
|
-- (0,0) is at top right of screen
|
|
x = x + self.viewport.y
|
|
y = y + (self.fb.bb:getHeight()-self.viewport.w)
|
|
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)
|
|
-- scaled positive px should also be positive
|
|
return math.ceil(px * self:getDPI()/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
|