mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user