2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2021-12-01 11:37:18 +00:00
|
|
|
Utilities for 2D geometry.
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
All of these apply to full rectangles:
|
|
|
|
|
|
|
|
local Geom = require("ui/geometry")
|
2017-09-11 08:32:39 +00:00
|
|
|
Geom:new{ x = 1, y = 0, w = Screen:scaleBySize(100), h = Screen:scaleBySize(200), }
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
Some behaviour is defined for points:
|
|
|
|
|
|
|
|
Geom:new{ x = 0, y = 0, }
|
|
|
|
|
|
|
|
Some behaviour is defined for dimensions:
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2017-09-11 08:32:39 +00:00
|
|
|
Geom:new{ w = Screen:scaleBySize(600), h = Screen:scaleBySize(800), }
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
Just use it on simple tables that have x, y and/or w, h
|
Revamp flash_ui handling, once more, with feeling ;) (#7262)
* Simplify flash_ui handling (by handling the unhighlight pre-callback, c.f., #7262 for more details).
* UIManager: Handle translucent window-level widgets (and those wrapped in a translucent MovableContainer) properly in setDirty directly, making sure what's *underneath* them gets repainted to avoid alpha layering glitches. (This was previously handled via localized hacks).
* Update UIManager's documentation, and format it properly for ldoc parsing, making the HTML docs more useful.
* ReaderView: Reinitialize the various page areas when opening a new document, to prevent poisoning from the previous document.
* Event: Handle nils in an event's arguments.
* CheckButton/RadioButton: Switch to simple inversion to handle highlighting
* CheckButton: Make the highlight span the inner frame's width, instead of just the text's width, if possible.
* AlphaContainer: Fix & simplify, given the UIManager alpha handling.
* MovableContainer: When translucent, cache the canvas bb used for composition.
* Avoid spurious refreshes in a few widgets using various dummy *TextWidgets in order to first compute a text height.
* KeyValuePage: Avoid floats in size computations.
2021-02-20 17:22:48 +00:00
|
|
|
or define your own types using this as a metatable.
|
|
|
|
|
|
|
|
Where @{ffi.blitbuffer|BlitBuffer} is concerned, a point at (0, 0) means the top-left corner.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
local Math = require("optmath")
|
|
|
|
|
|
|
|
--[[--
|
Revamp flash_ui handling, once more, with feeling ;) (#7262)
* Simplify flash_ui handling (by handling the unhighlight pre-callback, c.f., #7262 for more details).
* UIManager: Handle translucent window-level widgets (and those wrapped in a translucent MovableContainer) properly in setDirty directly, making sure what's *underneath* them gets repainted to avoid alpha layering glitches. (This was previously handled via localized hacks).
* Update UIManager's documentation, and format it properly for ldoc parsing, making the HTML docs more useful.
* ReaderView: Reinitialize the various page areas when opening a new document, to prevent poisoning from the previous document.
* Event: Handle nils in an event's arguments.
* CheckButton/RadioButton: Switch to simple inversion to handle highlighting
* CheckButton: Make the highlight span the inner frame's width, instead of just the text's width, if possible.
* AlphaContainer: Fix & simplify, given the UIManager alpha handling.
* MovableContainer: When translucent, cache the canvas bb used for composition.
* Avoid spurious refreshes in a few widgets using various dummy *TextWidgets in order to first compute a text height.
* KeyValuePage: Avoid floats in size computations.
2021-02-20 17:22:48 +00:00
|
|
|
Represents a full rectangle (all fields are set), a point (x & y are set), or a dimension (w & h are set).
|
2016-12-04 23:13:49 +00:00
|
|
|
@table Geom
|
|
|
|
]]
|
2013-10-18 20:38:07 +00:00
|
|
|
local Geom = {
|
Revamp flash_ui handling, once more, with feeling ;) (#7262)
* Simplify flash_ui handling (by handling the unhighlight pre-callback, c.f., #7262 for more details).
* UIManager: Handle translucent window-level widgets (and those wrapped in a translucent MovableContainer) properly in setDirty directly, making sure what's *underneath* them gets repainted to avoid alpha layering glitches. (This was previously handled via localized hacks).
* Update UIManager's documentation, and format it properly for ldoc parsing, making the HTML docs more useful.
* ReaderView: Reinitialize the various page areas when opening a new document, to prevent poisoning from the previous document.
* Event: Handle nils in an event's arguments.
* CheckButton/RadioButton: Switch to simple inversion to handle highlighting
* CheckButton: Make the highlight span the inner frame's width, instead of just the text's width, if possible.
* AlphaContainer: Fix & simplify, given the UIManager alpha handling.
* MovableContainer: When translucent, cache the canvas bb used for composition.
* Avoid spurious refreshes in a few widgets using various dummy *TextWidgets in order to first compute a text height.
* KeyValuePage: Avoid floats in size computations.
2021-02-20 17:22:48 +00:00
|
|
|
x = 0, -- left origin
|
|
|
|
y = 0, -- top origin
|
|
|
|
w = 0, -- width
|
|
|
|
h = 0, -- height
|
2012-05-18 22:37:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function Geom:new(o)
|
2024-01-17 01:19:37 +00:00
|
|
|
if not o then
|
|
|
|
o = {
|
|
|
|
x = 0, y = 0,
|
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
|
|
|
end
|
2014-03-13 13:52:43 +00:00
|
|
|
setmetatable(o, self)
|
|
|
|
self.__index = self
|
|
|
|
return o
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Makes a deep copy of itself.
|
2016-12-04 23:13:49 +00:00
|
|
|
@treturn Geom
|
|
|
|
]]
|
2012-06-10 15:36:19 +00:00
|
|
|
function Geom:copy()
|
2014-03-13 13:52:43 +00:00
|
|
|
local n = Geom:new()
|
|
|
|
n.x = self.x
|
|
|
|
n.y = self.y
|
|
|
|
n.w = self.w
|
|
|
|
n.h = self.h
|
|
|
|
return n
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function Geom:__tostring()
|
2014-03-13 13:52:43 +00:00
|
|
|
return self.w.."x"..self.h.."+"..self.x.."+"..self.y
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Offsets rectangle or point by relative values
|
2016-12-04 23:13:49 +00:00
|
|
|
@int dx x delta
|
|
|
|
@int dy y delta
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:offsetBy(dx, dy)
|
2014-03-13 13:52:43 +00:00
|
|
|
self.x = self.x + dx
|
|
|
|
self.y = self.y + dy
|
|
|
|
return self
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
|
|
|
Offsets rectangle or point to certain coordinates
|
|
|
|
@int x new x
|
|
|
|
@int y new y
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:offsetTo(x, y)
|
2014-03-13 13:52:43 +00:00
|
|
|
self.x = x
|
|
|
|
self.y = y
|
|
|
|
return self
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2021-09-02 21:50:10 +00:00
|
|
|
Scales rectangle (top-left corner is rounded down, bottom-right corner is rounded up) or dimension
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
If a single factor is given, it is applied to both width and height
|
|
|
|
|
|
|
|
@int zx scale for x axis
|
|
|
|
@int zy scale for y axis
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:scaleBy(zx, zy)
|
2021-09-02 21:50:10 +00:00
|
|
|
self.w = math.ceil(self.w * zx - 0.001)
|
|
|
|
self.h = math.ceil(self.h * (zy or zx) - 0.001)
|
2014-03-13 13:52:43 +00:00
|
|
|
return self
|
2012-06-10 15:36:19 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2021-09-02 21:50:10 +00:00
|
|
|
This method also takes care of x and y on top of @{Geom:scaleBy},
|
|
|
|
c.f., fz_round_rect in MµPDF,
|
|
|
|
<https://github.com/ArtifexSoftware/mupdf/blob/d00de0e96a4a5ec90ffc30837d40cd624a6a89e0/source/fitz/geometry.c#L400-L416>
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@int zx scale for x axis
|
|
|
|
@int zy scale for y axis
|
|
|
|
]]
|
2012-12-02 09:09:32 +00:00
|
|
|
function Geom:transformByScale(zx, zy)
|
2021-09-02 21:50:10 +00:00
|
|
|
self.x = math.floor(self.x * zx + 0.001)
|
|
|
|
self.y = math.floor(self.y * (zy or zx) + 0.001)
|
2014-03-13 13:52:43 +00:00
|
|
|
self:scaleBy(zx, zy)
|
2012-12-02 09:09:32 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
|
|
|
Returns area of itself.
|
|
|
|
|
|
|
|
@treturn int
|
|
|
|
]]
|
|
|
|
function Geom:area()
|
2014-03-13 13:52:43 +00:00
|
|
|
if not self.w or not self.h then
|
|
|
|
return 0
|
|
|
|
else
|
|
|
|
return self.w * self.h
|
|
|
|
end
|
2013-07-22 13:59:22 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
|
|
|
Enlarges or shrinks dimensions or rectangles
|
2012-06-10 15:36:19 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
Note that for rectangles the offset stays the same
|
|
|
|
|
|
|
|
@int dw width delta
|
|
|
|
@int dh height delta
|
|
|
|
]]
|
2012-06-10 15:36:19 +00:00
|
|
|
function Geom:changeSizeBy(dw, dh)
|
2014-03-13 13:52:43 +00:00
|
|
|
self.w = self.w + dw
|
|
|
|
self.h = self.h + dh
|
|
|
|
return self
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
|
|
|
Returns a new outer rectangle that contains both us and a given rectangle
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
Works for rectangles, dimensions and points
|
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
@treturn Geom
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:combine(rect_b)
|
2021-10-23 10:12:43 +00:00
|
|
|
return Geom.boundingBox({self, rect_b})
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
|
|
|
Returns a new rectangle for the part that we and a given rectangle share
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
@tparam Geom rect_b
|
|
|
|
@treturn Geom
|
2012-05-18 22:37:49 +00:00
|
|
|
]]--
|
2019-08-23 17:53:53 +00:00
|
|
|
--- @todo what happens if there is no rectangle shared? currently behaviour is undefined.
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:intersect(rect_b)
|
2014-03-13 13:52:43 +00:00
|
|
|
local intersected = self:copy()
|
2021-05-13 11:05:05 +00:00
|
|
|
if not rect_b or rect_b:area() == 0 then return intersected end
|
|
|
|
|
2014-03-13 13:52:43 +00:00
|
|
|
if self.x < rect_b.x then
|
|
|
|
intersected.x = rect_b.x
|
|
|
|
end
|
|
|
|
if self.y < rect_b.y then
|
|
|
|
intersected.y = rect_b.y
|
|
|
|
end
|
|
|
|
if self.x + self.w < rect_b.x + rect_b.w then
|
|
|
|
intersected.w = self.x + self.w - intersected.x
|
|
|
|
else
|
|
|
|
intersected.w = rect_b.x + rect_b.w - intersected.x
|
|
|
|
end
|
|
|
|
if self.y + self.h < rect_b.y + rect_b.h then
|
|
|
|
intersected.h = self.y + self.h - intersected.y
|
|
|
|
else
|
|
|
|
intersected.h = rect_b.y + rect_b.h - intersected.y
|
|
|
|
end
|
|
|
|
return intersected
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Returns true if self does not share any area with rect_b
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2012-12-03 05:48:41 +00:00
|
|
|
function Geom:notIntersectWith(rect_b)
|
2021-05-13 11:05:05 +00:00
|
|
|
if not rect_b or rect_b:area() == 0 then return true end
|
|
|
|
|
2014-03-13 13:52:43 +00:00
|
|
|
if (self.x >= (rect_b.x + rect_b.w))
|
|
|
|
or (self.y >= (rect_b.y + rect_b.h))
|
|
|
|
or (rect_b.x >= (self.x + self.w))
|
|
|
|
or (rect_b.y >= (self.y + self.h)) then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
2012-12-03 05:48:41 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Returns true if self geom shares area with rect_b.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2014-10-21 09:24:19 +00:00
|
|
|
function Geom:intersectWith(rect_b)
|
|
|
|
return not self:notIntersectWith(rect_b)
|
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Set size of dimension or rectangle to size of given dimension/rectangle.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:setSizeTo(rect_b)
|
2014-03-13 13:52:43 +00:00
|
|
|
self.w = rect_b.w
|
|
|
|
self.h = rect_b.h
|
|
|
|
return self
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2021-05-13 11:05:05 +00:00
|
|
|
Checks whether geom is within current rectangle
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-13 16:06:02 +00:00
|
|
|
Works for dimensions, too. For points, it is basically an equality check.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
2021-05-13 11:05:05 +00:00
|
|
|
@tparam Geom geom
|
2016-12-04 23:13:49 +00:00
|
|
|
]]
|
2021-05-13 11:05:05 +00:00
|
|
|
function Geom:contains(geom)
|
|
|
|
if not geom then return false end
|
|
|
|
|
|
|
|
if self.x <= geom.x
|
|
|
|
and self.y <= geom.y
|
|
|
|
and self.x + self.w >= geom.x + geom.w
|
|
|
|
and self.y + self.h >= geom.y + geom.h
|
2014-03-13 13:52:43 +00:00
|
|
|
then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Checks for equality.
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-13 16:06:02 +00:00
|
|
|
Works for rectangles, points, and dimensions.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:__eq(rect_b)
|
2014-03-13 13:52:43 +00:00
|
|
|
if self.x == rect_b.x
|
|
|
|
and self.y == rect_b.y
|
|
|
|
and self:equalSize(rect_b)
|
|
|
|
then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Checks the size of a dimension/rectangle for equality.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:equalSize(rect_b)
|
2016-12-04 06:57:57 +00:00
|
|
|
if self.w == rect_b.w and self.h == rect_b.h then
|
2014-03-13 13:52:43 +00:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Checks if our size is smaller than the size of the given dimension/rectangle.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:__lt(rect_b)
|
2014-03-13 13:52:43 +00:00
|
|
|
if self.w < rect_b.w and self.h < rect_b.h then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Checks if our size is smaller or equal to the size of the given dimension/rectangle.
|
2016-12-04 23:13:49 +00:00
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:__le(rect_b)
|
2014-03-13 13:52:43 +00:00
|
|
|
if self.w <= rect_b.w and self.h <= rect_b.h then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Offsets the current rectangle by dx, dy while fitting it into the space
|
|
|
|
of a given rectangle.
|
2012-05-18 22:37:49 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
This can also be called with dx=0 and dy=0, which will fit the current
|
2016-12-13 16:06:02 +00:00
|
|
|
rectangle into the given rectangle.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
@int dx
|
|
|
|
@int dy
|
|
|
|
]]
|
2012-05-18 22:37:49 +00:00
|
|
|
function Geom:offsetWithin(rect_b, dx, dy)
|
2014-03-13 13:52:43 +00:00
|
|
|
-- check size constraints and shrink us when we're too big
|
|
|
|
if self.w > rect_b.w then
|
|
|
|
self.w = rect_b.w
|
|
|
|
end
|
|
|
|
if self.h > rect_b.h then
|
|
|
|
self.h = rect_b.h
|
|
|
|
end
|
|
|
|
-- offset
|
|
|
|
self.x = self.x + dx
|
|
|
|
self.y = self.y + dy
|
|
|
|
-- check offsets
|
|
|
|
if self.x < rect_b.x then
|
|
|
|
self.x = rect_b.x
|
|
|
|
end
|
|
|
|
if self.y < rect_b.y then
|
|
|
|
self.y = rect_b.y
|
|
|
|
end
|
|
|
|
if self.x + self.w > rect_b.x + rect_b.w then
|
|
|
|
self.x = rect_b.x + rect_b.w - self.w
|
|
|
|
end
|
|
|
|
if self.y + self.h > rect_b.y + rect_b.h then
|
|
|
|
self.y = rect_b.y + rect_b.h - self.h
|
|
|
|
end
|
2012-05-18 22:37:49 +00:00
|
|
|
end
|
2012-12-03 05:48:41 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Centers the current rectangle at position x and y of a given rectangle.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
@int dx
|
|
|
|
@int dy
|
|
|
|
]]
|
2014-01-02 03:08:06 +00:00
|
|
|
function Geom:centerWithin(rect_b, x, y)
|
2014-03-13 13:52:43 +00:00
|
|
|
-- check size constraints and shrink us when we're too big
|
|
|
|
if self.w > rect_b.w then
|
|
|
|
self.w = rect_b.w
|
|
|
|
end
|
|
|
|
if self.h > rect_b.h then
|
|
|
|
self.h = rect_b.h
|
|
|
|
end
|
|
|
|
-- place to center
|
|
|
|
self.x = x - self.w/2
|
|
|
|
self.y = y - self.h/2
|
|
|
|
-- check boundary
|
|
|
|
if self.x < rect_b.x then
|
|
|
|
self.x = rect_b.x
|
|
|
|
end
|
|
|
|
if self.y < rect_b.y then
|
|
|
|
self.y = rect_b.y
|
|
|
|
end
|
|
|
|
if self.x + self.w > rect_b.x + rect_b.w then
|
|
|
|
self.x = rect_b.x + rect_b.w - self.w
|
|
|
|
end
|
|
|
|
if self.y + self.h > rect_b.y + rect_b.h then
|
|
|
|
self.y = rect_b.y + rect_b.h - self.h
|
|
|
|
end
|
2014-01-02 03:08:06 +00:00
|
|
|
end
|
|
|
|
|
2013-03-10 05:18:50 +00:00
|
|
|
function Geom:shrinkInside(rect_b, dx, dy)
|
2014-03-13 13:52:43 +00:00
|
|
|
self:offsetBy(dx, dy)
|
|
|
|
return self:intersect(rect_b)
|
2013-03-10 05:18:50 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Returns the Euclidean distance between two geoms.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom rect_b
|
|
|
|
]]
|
2013-02-02 20:42:59 +00:00
|
|
|
function Geom:distance(geom)
|
2022-09-21 21:26:22 +00:00
|
|
|
return math.sqrt((self.x - geom.x)^2 + (self.y - geom.y)^2)
|
2013-02-02 20:42:59 +00:00
|
|
|
end
|
2013-03-26 12:59:47 +00:00
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Returns the midpoint of two geoms.
|
2016-12-04 23:13:49 +00:00
|
|
|
|
|
|
|
@tparam Geom geom
|
|
|
|
@treturn Geom
|
|
|
|
]]
|
2013-03-26 12:59:47 +00:00
|
|
|
function Geom:midpoint(geom)
|
2014-03-13 13:52:43 +00:00
|
|
|
return Geom:new{
|
2015-10-03 17:06:24 +00:00
|
|
|
x = Math.round((self.x + geom.x) / 2),
|
|
|
|
y = Math.round((self.y + geom.y) / 2),
|
2014-03-13 13:52:43 +00:00
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
2013-03-26 12:59:47 +00:00
|
|
|
end
|
|
|
|
|
2016-12-04 23:13:49 +00:00
|
|
|
--[[--
|
2016-12-13 16:06:02 +00:00
|
|
|
Returns the center point of this geom.
|
2016-12-04 23:13:49 +00:00
|
|
|
@treturn Geom
|
|
|
|
]]
|
2013-10-12 15:07:13 +00:00
|
|
|
function Geom:center()
|
2014-03-13 13:52:43 +00:00
|
|
|
return Geom:new{
|
2015-10-03 17:06:24 +00:00
|
|
|
x = self.x + Math.round(self.w / 2),
|
|
|
|
y = self.y + Math.round(self.h / 2),
|
2014-03-13 13:52:43 +00:00
|
|
|
w = 0, h = 0,
|
|
|
|
}
|
2013-10-12 15:07:13 +00:00
|
|
|
end
|
2013-10-18 20:38:07 +00:00
|
|
|
|
Page Overlap: Fix rectangle computation and arrow mode (#7269)
* In ReaderPaging, the panning step pre-PanningUpdate can be wildly overshot near page edges, so, use the corrected value instead by recomputing it after the panning has been effectively computed by ReaderView.
This fixes slight inaccuracies, as well as glaring mistakes when going backwards, or when near page edges.
This is in line with how ReaderRolling computes the value, which I only realized later because I'm an idiot.
* Minor cleanups around the handling of the dim_area Geom object in general.
* Fix the "Arrow" page overlap mode to be painted in the right coordinates when going backward. Issue might not have been terribly clear because of the previous issue ;).
* Center the arrow's point, while we're here.
* Don't use AlphaContainer to make it translucent, because AlphaContainer is horribly broken, and has weird quirks and behavior that make no sense to me unless some very specific and unlikely constraints are met, and they definitely aren't here.
This fixes the arrow copying an arrow-sized square of the original page the book was opened on on the top-left corner of *every* page with an arrow. (lol).
* Do real proper alpha-blending via Icon/ImageWidget from the original icon, instead of faking it via addBlitFrom, in order to avoid the dimming *around* the triangle's shape.
2021-02-10 19:06:41 +00:00
|
|
|
--[[--
|
|
|
|
Resets an existing Geom object to zero.
|
|
|
|
@treturn Geom
|
|
|
|
]]
|
|
|
|
function Geom:clear()
|
|
|
|
self.x = 0
|
|
|
|
self.y = 0
|
|
|
|
self.w = 0
|
|
|
|
self.h = 0
|
|
|
|
return self
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[--
|
|
|
|
Checks if a dimension or rectangle is empty.
|
Revamp flash_ui handling, once more, with feeling ;) (#7262)
* Simplify flash_ui handling (by handling the unhighlight pre-callback, c.f., #7262 for more details).
* UIManager: Handle translucent window-level widgets (and those wrapped in a translucent MovableContainer) properly in setDirty directly, making sure what's *underneath* them gets repainted to avoid alpha layering glitches. (This was previously handled via localized hacks).
* Update UIManager's documentation, and format it properly for ldoc parsing, making the HTML docs more useful.
* ReaderView: Reinitialize the various page areas when opening a new document, to prevent poisoning from the previous document.
* Event: Handle nils in an event's arguments.
* CheckButton/RadioButton: Switch to simple inversion to handle highlighting
* CheckButton: Make the highlight span the inner frame's width, instead of just the text's width, if possible.
* AlphaContainer: Fix & simplify, given the UIManager alpha handling.
* MovableContainer: When translucent, cache the canvas bb used for composition.
* Avoid spurious refreshes in a few widgets using various dummy *TextWidgets in order to first compute a text height.
* KeyValuePage: Avoid floats in size computations.
2021-02-20 17:22:48 +00:00
|
|
|
@treturn bool
|
Page Overlap: Fix rectangle computation and arrow mode (#7269)
* In ReaderPaging, the panning step pre-PanningUpdate can be wildly overshot near page edges, so, use the corrected value instead by recomputing it after the panning has been effectively computed by ReaderView.
This fixes slight inaccuracies, as well as glaring mistakes when going backwards, or when near page edges.
This is in line with how ReaderRolling computes the value, which I only realized later because I'm an idiot.
* Minor cleanups around the handling of the dim_area Geom object in general.
* Fix the "Arrow" page overlap mode to be painted in the right coordinates when going backward. Issue might not have been terribly clear because of the previous issue ;).
* Center the arrow's point, while we're here.
* Don't use AlphaContainer to make it translucent, because AlphaContainer is horribly broken, and has weird quirks and behavior that make no sense to me unless some very specific and unlikely constraints are met, and they definitely aren't here.
This fixes the arrow copying an arrow-sized square of the original page the book was opened on on the top-left corner of *every* page with an arrow. (lol).
* Do real proper alpha-blending via Icon/ImageWidget from the original icon, instead of faking it via addBlitFrom, in order to avoid the dimming *around* the triangle's shape.
2021-02-10 19:06:41 +00:00
|
|
|
]]
|
|
|
|
function Geom:isEmpty()
|
|
|
|
if self.w == 0 or self.h == 0 then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2021-10-23 10:12:43 +00:00
|
|
|
--[[--
|
|
|
|
Returns a bounding box which encompasses all passed rectangles.
|
|
|
|
@tparam Geom rectangles to encompass
|
|
|
|
@treturn Geom bounding box or nil if no rectangles passed
|
|
|
|
]]
|
|
|
|
function Geom.boundingBox(boxes)
|
|
|
|
local bounding_box
|
|
|
|
for _, geom in ipairs(boxes) do
|
|
|
|
-- Easier to work with (x0,x0)+(x1,y1) pairs.
|
|
|
|
local box = { x0 = geom.x, y0 = geom.y,
|
|
|
|
x1 = geom.x + geom.w, y1 = geom.y + geom.h }
|
|
|
|
if not bounding_box then
|
|
|
|
bounding_box = box
|
|
|
|
else
|
|
|
|
if box.x0 < bounding_box.x0 then bounding_box.x0 = box.x0 end
|
|
|
|
if box.y0 < bounding_box.y0 then bounding_box.y0 = box.y0 end
|
|
|
|
if box.x1 > bounding_box.x1 then bounding_box.x1 = box.x1 end
|
|
|
|
if box.y1 > bounding_box.y1 then bounding_box.y1 = box.y1 end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if bounding_box then
|
|
|
|
return Geom:new{
|
|
|
|
x = bounding_box.x0,
|
|
|
|
y = bounding_box.y0,
|
|
|
|
w = bounding_box.x1 - bounding_box.x0,
|
|
|
|
h = bounding_box.y1 - bounding_box.y0,
|
|
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-10-18 20:38:07 +00:00
|
|
|
return Geom
|