Skip to content

Commit bc7729f

Browse files
committed
#3466 qlitehtml: improved slection process (a bit)
Signed-off-by: Patrizio Bekerle <patrizio@bekerle.com>
1 parent 21838ad commit bc7729f

File tree

2 files changed

+73
-11
lines changed

2 files changed

+73
-11
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
- Added support for copying selected text with `Ctrl + C` in the QLiteHtml preview
1818
(for [#3466](https://github.com/pbek/QOwnNotes/issues/3466))
1919
- Both plain text and HTML (rich text) formats are copied to the clipboard
20+
- The copied HTML includes all formatting (colors, fonts, bold, italic, etc.) as inline styles
21+
- Improved text selection in the QLiteHtml preview (but it's still clunky)
22+
(for [#3466](https://github.com/pbek/QOwnNotes/issues/3466))
23+
- Selection now only selects the specific text you click and drag over
24+
- Fixed an issue where entire paragraphs or blocks would be selected instead of precise text
2025

2126
## 26.2.6
2227

src/libraries/qlitehtml/src/container_qpainter.cpp

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,61 @@ static Selection::Element selectionDetails(const litehtml::element::ptr &element
196196
const QString &text,
197197
const QPoint &pos)
198198
{
199-
// shortcut, which _might_ not really be correct
200-
if (element->get_children_count() > 0)
201-
return {element, -1, -1}; // everything selected
199+
// If element has children, the text contains all descendant text concatenated
200+
// For better precision, we should find the actual leaf child at this position
201+
if (element->get_children_count() > 0) {
202+
// Try to find a child leaf element that contains this position
203+
const std::function<Selection::Element(litehtml::element::ptr, QPoint)> findLeaf =
204+
[&findLeaf, pos](const litehtml::element::ptr &elem,
205+
const QPoint &offset) -> Selection::Element {
206+
if (!elem)
207+
return {};
208+
209+
const QRect elemPos = toQRect(elem->get_position()).translated(offset);
210+
211+
if (!elemPos.contains(pos))
212+
return {};
213+
214+
// Try children first
215+
for (int i = 0; i < int(elem->get_children_count()); ++i) {
216+
const litehtml::element::ptr child = elem->get_child(i);
217+
Selection::Element result = findLeaf(child, elemPos.topLeft());
218+
if (result.element)
219+
return result;
220+
}
221+
222+
// No children found, use this element if it has text
223+
litehtml::tstring elemText;
224+
elem->get_text(elemText);
225+
if (!elemText.empty()) {
226+
const QString textStr = QString::fromStdString(elemText);
227+
const QFont &font = toQFont(elem->get_font());
228+
const QFontMetrics fm(font);
229+
const QPoint relativePos = pos - elemPos.topLeft();
230+
231+
int previous = 0;
232+
for (int i = 0; i < textStr.size(); ++i) {
233+
const int width = fm.size(0, textStr.left(i + 1)).width();
234+
if ((width + previous) / 2 >= relativePos.x())
235+
return {elem, i, previous};
236+
previous = width;
237+
}
238+
return {elem, int(textStr.size()), previous};
239+
}
240+
241+
return {};
242+
};
243+
244+
const QRect elementRect = toQRect(element->get_placement());
245+
Selection::Element result = findLeaf(element, elementRect.topLeft());
246+
if (result.element)
247+
return result;
248+
249+
// Fallback: return the element with index at the start
250+
return {element, 0, 0};
251+
}
252+
253+
// Element has no children - calculate precise character position
202254
const QFont &font = toQFont(element->get_font());
203255
const QFontMetrics fm(font);
204256
int previous = 0;
@@ -219,26 +271,30 @@ static Selection::Element deepest_child_at_point(const litehtml::document::ptr &
219271
if (!document)
220272
return {};
221273

222-
// the following does not find the "smallest" element, it often consists of children
223-
// with individual words as text...
274+
// Find the element at this point
224275
const litehtml::element::ptr element = document->root()->get_element_by_point(pos.x(),
225276
pos.y(),
226277
viewportPos.x(),
227278
viewportPos.y());
228-
// ...so try to find a better match
279+
// Recursively find the deepest child that contains the point and has text
229280
const std::function<Selection::Element(litehtml::element::ptr, QRect)> recursion =
230281
[&recursion, pos, mode](const litehtml::element::ptr &element,
231282
const QRect &placement) -> Selection::Element {
232283
if (!element)
233284
return {};
234-
Selection::Element result;
285+
286+
// First, try to find a deeper child that contains the point
287+
Selection::Element deepestResult;
235288
for (int i = 0; i < int(element->get_children_count()); ++i) {
236289
const litehtml::element::ptr child = element->get_child(i);
237-
result = recursion(child,
238-
toQRect(child->get_position()).translated(placement.topLeft()));
239-
if (result.element)
240-
return result;
290+
const QRect childPlacement = toQRect(child->get_position())
291+
.translated(placement.topLeft());
292+
deepestResult = recursion(child, childPlacement);
293+
if (deepestResult.element)
294+
return deepestResult;
241295
}
296+
297+
// No deeper child found, check if this element itself has text content
242298
if (placement.contains(pos)) {
243299
litehtml::tstring text;
244300
element->get_text(text);
@@ -250,6 +306,7 @@ static Selection::Element deepest_child_at_point(const litehtml::document::ptr &
250306
: Selection::Element({element, -1, -1});
251307
}
252308
}
309+
253310
return {};
254311
};
255312
return recursion(element, element ? toQRect(element->get_placement()) : QRect());

0 commit comments

Comments
 (0)