Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix double click to select full words #5243

Merged
merged 18 commits into from
Mar 17, 2024

Conversation

KleberPF
Copy link
Contributor

Leaving this as a draft because I want some opinions if this is a good approach or not. Heavily inspired by this comment from @Nerixyz, but adding an id to each element instead of the prev/next approach. Currently works on basic tests, haven't tested more advanced stuff (RTL text, CJK characters, etc)

Copy link
Contributor

@Nerixyz Nerixyz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using IDs for words is a good idea. However, I think the concept shouldn't "leak" beyond MessageLayout, i.e. ChannelView and *MessageBuilder shouldn't know about it.

One bug this implementation has is that it assumes that one TextElement has at most one word. This isn't the case. The EmotePopup for example, adds an element with multiple words:

builder.emplace<TextElement>("no emotes available",
MessageElementFlag::Text,
MessageColor::System);

MessageLayoutContainer should generate the IDs. When a TextElement adds its elements to the container, it generates a new ID for each word by calling something like container.nextWordID(). This way, message builders don't need to know about word-IDs. (if you put the next ID after containsRTL, it doesn't consume extra space)

Getting the word bounds should hide the concept of word-IDs too. It should have a single method like layout.getWordBoundsAt(QPoint) which finds the layout element and finds the bounds of all layout elements with that word-ID (or returns the element's bounds if it has an ID of -1).

Comment on lines 485 to 487
wordEnd += element->hasTrailingSpace()
? element->getSelectionIndexCount() - 1
: element->getSelectionIndexCount();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works1 because elements created from one word don't have trailing spaces in between. However, this should be handled here. Only if the last element had a trailing space, the selection index should be reduced by one.

Footnotes

  1. Actually, it doesn't work here, as this can be called with -1 in which case multiple elements can be selected and the selection won't span the entire group.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now this is done after the loop checking the last element

@@ -1817,7 +1817,7 @@ void ChannelView::mouseMoveEvent(QMouseEvent *event)
if (this->isDoubleClick_ && hoverLayoutElement)
{
auto [wordStart, wordEnd] =
getWordBounds(layout.get(), hoverLayoutElement, relativePos);
layout->getWordBounds(hoverLayoutElement->getWordId());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can pass -1 to getWordBounds. Example:

  • Open emote popup in a channel that that doesn't have BTTV, FFZ or 7TV emotes
  • Click on Channel, find no emotes available
  • Double click next to the text (a few pixels)
  • Quickly move the mouse over the text

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we choose which logic to use inside layout->getWordBounds

Comment on lines 90 to 92
/**
* Elements that are part of the same word originally have the same id
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(See top level comment)

Suggested change
/**
* Elements that are part of the same word originally have the same id
*/
/// @brief ID of a word inside its container
///
/// One word has exactly one ID that is used to identify elements created
/// from the same word (due to wrapping).
/// IDs are unique in a MessageLayoutContainer.

Btw, if you put this before text_, it won't consume extra space and fit into the padding.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

@KleberPF
Copy link
Contributor Author

KleberPF commented Mar 10, 2024

Thanks for the feedback. I think I implemented everything you pointed out, and it seems to be working well. There might be some off by one errors because the messages are kinda scuffed on KDE Plasma

image

I can fix it a bit by shrinking and stretching the window, but it doesn't fix 100%.

@KleberPF
Copy link
Contributor Author

I tested this a bit more and everything seems to be working. Not sure if there is any point in documenting the tests as they would be just screenshots of random selections but let me know if I should. I'll remove the draft as it seems the final version will be something close to this.

@KleberPF KleberPF marked this pull request as ready for review March 13, 2024 01:33
@KleberPF KleberPF changed the title Draft: Fix double click to select full words Fix double click to select full words Mar 13, 2024
Copy link
Member

@pajlada pajlada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed some stuff, mostly small things. Could you review the comments I added to make sure I understood the code correctly?

src/messages/layouts/MessageLayout.cpp Outdated Show resolved Hide resolved
Comment on lines 457 to 460
if (element->getWordId() != -1)
{
return this->container_.getWordBounds(element);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment here for what this significes? It's not clear to me what it means when the element we're looking at has a word id of -1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 basically means that the element can't span across multiple lines (like an emote, for example). I agree the code is not very self explanatory here. Do you want a comment here or should I encapsulate that inside a function like element->canBeMultiline() (name is kinda bad but you get the idea)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a comment here is fine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

tests/src/MessageLayout.cpp Outdated Show resolved Hide resolved
this->layout->layout(WIDTH, 1, MessageElementFlag::Text, false);
}

MockApplication mockApplication;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't quite understand how constructing MockApplication here makes it so any all to getIApp gets the MockApplication. Also this should probably only be done once instead of each time a test is created

Copy link
Member

@pajlada pajlada Mar 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MockApplication inherits from mocks::EmptyApplicatino, which inherits from IApplication which sets a singleton to point to itself (check mocks/EmptyApplication & src/Application.cpp)

tests/src/MessageLayout.cpp Show resolved Hide resolved
@pajlada
Copy link
Member

pajlada commented Mar 16, 2024

Testing RTL selections - it's very scuffed. Luckily, it's already scuffed before this PR, which means I don't think it's a blocker.

@pajlada pajlada added this to the Investigate before 2.5.0 milestone Mar 16, 2024
@pajlada pajlada enabled auto-merge (squash) March 17, 2024 13:17
@pajlada pajlada merged commit c10e364 into Chatterino:master Mar 17, 2024
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants