TextBoxWidget: allow showing bits of text in bold

Allow for embedding "tags" (invalid Unicode codepoints)
in the text string to trigger some text formatting:
for now only bolding some parts of text is possible.

Use it with fulltext search "all results" to highlight the
matched word (instead of the previously used brackets).
This commit is contained in:
poire-z
2024-01-15 16:30:14 +01:00
parent 487e5f667a
commit 43d36b2ea9
4 changed files with 71 additions and 8 deletions

View File

@@ -7,6 +7,7 @@ local InputDialog = require("ui/widget/inputdialog")
local Menu = require("ui/widget/menu")
local Notification = require("ui/widget/notification")
local SpinWidget = require("ui/widget/spinwidget")
local TextBoxWidget = require("ui/widget/textboxwidget")
local UIManager = require("ui/uimanager")
local Utf8Proc = require("ffi/utf8proc")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
@@ -525,14 +526,17 @@ function ReaderSearch:showFindAllResults(not_cached)
if item.matched_word_suffix then
word = word .. item.matched_word_suffix
end
-- Make this word bolder, using Poor Text Formatting provided by TextBoxWidget
-- (we know this text ends up in a TextBoxWidget).
local text = TextBoxWidget.PTF_BOLD_START .. word .. TextBoxWidget.PTF_BOLD_END
-- append context before and after the word
local text = "" .. word .. ""
if item.prev_text then
text = item.prev_text .. text
end
if item.next_text then
text = text .. item.next_text
end
text = TextBoxWidget.PTF_HEADER .. text -- enable handling of our bold tags
item.text = text
item.mandatory = self.ui.bookmark:getBookmarkPageString(item.start)
end

View File

@@ -12,6 +12,7 @@ local FFIUtil = require("ffi/util")
local Geom = require("ui/geometry")
local KOPTContext = require("ffi/koptcontext")
local Persist = require("persist")
local TextBoxWidget = require("ui/widget/textboxwidget")
local TileCacheItem = require("document/tilecacheitem")
local Utf8Proc = require("ffi/utf8proc")
local logger = require("logger")
@@ -1510,15 +1511,18 @@ function KoptInterface:findAllText(doc, pattern, case_insensitive, nb_context_wo
i_next, j_next = i, j
end
end
text = "" .. table.concat(text, " ") .. ""
-- Make this word bolder, using Poor Text Formatting provided by TextBoxWidget
-- (we know this text ends up in a TextBoxWidget).
text = TextBoxWidget.PTF_BOLD_START .. table.concat(text, " ") .. TextBoxWidget.PTF_BOLD_END
local prev_text = get_prev_text(text_boxes, i_prev, j_prev, nb_context_words)
if prev_text then
text = prev_text .. text
text = prev_text .. " " .. text
end
local next_text = get_next_text(text_boxes, i_next, j_next, nb_context_words)
if next_text then
text = text .. next_text
text = text .. " " .. next_text
end
text = TextBoxWidget.PTF_HEADER .. text -- enable handling of our bold tags
res_item.text = text
table.insert(res, res_item)
if #res == max_hits then

View File

@@ -289,17 +289,25 @@ end
-- @int glyph index
-- @bool[opt=false] bold whether the glyph should be artificially boldened
-- @treturn glyph
function RenderText:getGlyphByIndex(face, glyphindex, bold)
function RenderText:getGlyphByIndex(face, glyphindex, bold, bolder)
if face.is_real_bold then
bold = false -- don't embolden glyphs already bold
end
local hash = "xglyph|"..face.hash.."|"..glyphindex.."|"..(bold and 1 or 0)
local hash = "xglyph|"..face.hash.."|"..glyphindex.."|"..(bold and 1 or 0)..(bolder and "x" or "")
local glyph = GlyphCache:check(hash)
if glyph then
-- cache hit
return glyph
end
local rendered_glyph = face.ftsize:renderGlyphByIndex(glyphindex, bold and face.embolden_half_strength)
local embolden_strength
if bold or bolder then
embolden_strength = face.embolden_half_strength
if bolder then
-- Even if not bold, get it bolder than the strength we'd use for bold
embolden_strength = embolden_strength * 1.5
end
end
local rendered_glyph = face.ftsize:renderGlyphByIndex(glyphindex, embolden_strength)
if not rendered_glyph then
logger.warn("error rendering glyph (glyphindex=", glyphindex, ") for face", face)
return

View File

@@ -110,6 +110,17 @@ local TextBoxWidget = InputContainer:extend{
-- for internal use
for_measurement_only = nil, -- When the widget is a one-off used to compute text height
-- Some Poor Text Formatting (PTF, not not to be confused with Richer RTF :)) can be done
-- by embedding some chars in self.text (these codepoints are not part of Unicode, so
-- hopefully not present naturally in any provided self.text).
PTF_HEADER = "\u{FFF1}", -- should be put at start of 'text' to indicate we may find other PTF_ chars
PTF_BOLD_START = "\u{FFF2}", -- start a sequence of bold chars
PTF_BOLD_END = "\u{FFF3}", -- end a sequence of bold chars
_ptf_char_is_bold = nil,
-- This uses fake/synthetic bold, making each glyph bolder without modifying advance.
-- Some other possible formatting we could implement is different alignment (center,
-- right) of some lines in the provided text.
}
function TextBoxWidget:init()
@@ -154,6 +165,41 @@ function TextBoxWidget:init()
self.text_height = self.lines_per_page * self.line_height_px
end
-- Check for Poor Text Formatting
if not self.charlist and self.text and type(self.text) == "string"
and self.text:sub(1, #TextBoxWidget.PTF_HEADER) == TextBoxWidget.PTF_HEADER then
-- Support for very simple text styling (bold only for now)
self._ptf_char_is_bold = {}
-- Alas, we can't let any of our flag characters be fed to xtext (even with ASCII control
-- chars, it would give them a width, which would result at best in spurious added spacing).
-- So, split text into a table of chars, filter our flags out keeping track of where they
-- start and end bold, and rebuild self.text without them.
local charlist = util.splitToChars(self.text)
table.remove(charlist, 1)
local is_bold = false
local len = #charlist
local i = 1
while i <= len do
local ch = charlist[i]
if ch == TextBoxWidget.PTF_BOLD_START then
is_bold = true
table.remove(charlist, i)
len = len - 1
elseif ch == TextBoxWidget.PTF_BOLD_END then
is_bold = false
table.remove(charlist, i)
len = len - 1
else
if is_bold then
self._ptf_char_is_bold[i] = true
end
i = i + 1
end
end
self.text = table.concat(charlist, "")
charlist = nil -- luacheck: no unused
end
self:_computeTextDimensions()
self:_updateLayout()
if self.editable then
@@ -822,7 +868,8 @@ function TextBoxWidget:_renderText(start_row_idx, end_row_idx)
for _, xglyph in ipairs(line.xglyphs) do
if not xglyph.no_drawing then
local face = self.face.getFallbackFont(xglyph.font_num) -- callback (not a method)
local glyph = RenderText:getGlyphByIndex(face, xglyph.glyph, self.bold)
local bolder = self._ptf_char_is_bold and self._ptf_char_is_bold[xglyph.text_index] or false
local glyph = RenderText:getGlyphByIndex(face, xglyph.glyph, self.bold, bolder)
local color = self.fgcolor
if self._alt_color_for_rtl then
color = xglyph.is_rtl and Blitbuffer.COLOR_DARK_GRAY or Blitbuffer.COLOR_BLACK