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
RichText improvements #18447
RichText improvements #18447
Conversation
cocos/ui/UIRichText.cpp
Outdated
int getNextWordPos(const StringUtils::StringUTF8& text, int idx) | ||
{ | ||
const StringUtils::StringUTF8::CharUTF8Store& str = text.getString(); | ||
auto it = std::find_if(str.begin() + idx + 1, str.end(), isUTF8CharWrappable); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if idx
== str.length(), then it may have problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it will be out of bounds. I will add an if condition
leftStr = text.getAsCharSequence(0, newidx); | ||
label->setString(leftStr); | ||
textRendererWidth = label->getContentSize().width; | ||
if (textRendererWidth < originalLeftSpaceWidth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if textRendererWidth == originalLeftSpaceWidth, then should return newidx
instead of idx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I will add an if condition
// skip spaces | ||
StringUtils::StringUTF8::CharUTF8Store& str = utf8Text.getString(); | ||
int rightStart = leftLength; | ||
while (rightStart < (int)str.size() && str[rightStart].isASCII() && std::isspace(str[rightStart]._char[0], std::locale())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why need to skip spaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In original code, it skips one space.
But I think skipping all spaces may be better.
eg(_ instead of space): "abcd________________123"
suppose it is splitted after letter 'd'
Should it desplay like
abcd
123
or
abcd
________________123
? please give me some advice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not idea. How it been displayed on Android/iOS UI element? I think can have the same behavior as them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I test it with iOS's webview. It trims the spaces. see below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
K, thanks.
cocos/ui/UIRichText.cpp
Outdated
} | ||
if (row.empty()) | ||
{ | ||
maxHeight = std::max(fontSize, _defaultHeights[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why height compare with font size?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for continuous new lines.
eg:"abc\n\n123" should display like this:
abc
123
cocos/ui/UIRichText.cpp
Outdated
Label* leftRenderer = nullptr; | ||
if (fileExist) | ||
addNewLine(); | ||
_defaultHeights.back() = fontSize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why height vector record font size?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also for continuous new lines.
eg:"abc\n\n123" should display like this:
abc
123
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may be should use another name for the member variable, the name is _defaultHeights
, but the element value is font size, it is hard to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about _emptyLineHeights
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand why height is equal to font size. When i reviewed the codes, it seems font size is used as height.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- there is a
RichText
with fontSize 20 containsRichElementText
(string="abc\n\n123", fontSize=10).
Then it will display like this:
abc
123
Now, the gap between two lines should be equal to RichElementText
's fontSize 10
- In another case, there is a
RichText
with fontSize 20 containsRichElementText
("abc"),RichElementNewLine
,RichElementNewLine
,RichElementText
("123").
Then it will display like this:
abc
123
Now, the gap between two lines should be equal to RichText
's fontSize 20
leftStr.append(ch._char); | ||
label->setString(leftStr); | ||
textRendererWidth = label->getContentSize().width; | ||
if (originalLeftSpaceWidth < textRendererWidth) // protruded, undo add |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if originalLeftSpaceWidth == textRendererWidth, then it should return leftLength
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK
// gap for empty line, if _lineHeights[i] == 0, use current RichText's fontSize | ||
if (row.empty()) | ||
{ | ||
maxHeight = (_lineHeights[i] != 0.0f ? _lineHeights[i] : fontSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use font size for height? And when row will be empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider the following two cases:
- a
RichText
with fontSize 20 containsRichElementText
(string="abc\n\n123", fontSize=10).
Then it will display like this:
abc
123
Now, the gap between two lines should be equal to RichElementText
's fontSize 10
- a
RichText
with fontSize 20 containsRichElementText
("abc"),RichElementNewLine
,RichElementNewLine
,RichElementText
("123").
Then it will display like this:
abc
123
Now, the gap between two lines should be equal to RichText
's fontSize 20
In both of two cases, row.empty() == true. because of RichText::addNewLine()
, the code _elementRenders.emplace_back();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just use vertical space instead of font size? Use font size as line height is strange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vertical space is not same as font size.please see below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sounds reasonable
cocos/ui/UIRichText.cpp
Outdated
while (_elementRenders.back().empty()) | ||
{ | ||
_elementRenders.pop_back(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When element render will be empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the case of end with some new lines, for example, the last element of a RichText
is RichElementNewLine
, or RichElementText
with some \n
's.
RichText::addNewLine()
will be invoked, but no renders in the vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why remove them? May be it is the expected effect, use some new line at the end to make some space at the end of content.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first, I think new lines at end of RichText is meaningless.
Maybe we can add a method to decide whether trim or not, how about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it may make things complex. If they don't want the effect, then why add these new lines explicitly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I see. I will delete these codes
@minggo const Size& Label::getContentSize() const
{
if (_systemFontDirty || _contentDirty)
{
const_cast<Label*>(this)->updateContent();
}
return _contentSize;
}
Rect Label::getBoundingBox() const
{
const_cast<Label*>(this)->getContentSize();
return Node::getBoundingBox();
} It means that when invoke Are these codes necessary similarly? const Size& RichText::getContentSize() const
{
if (_formatTextDirty)
{
const_cast<RichText*>(this)->formatText();
}
return Widget::getContentSize();
}
Rect RichText::getBoundingBox() const
{
if (_formatTextDirty)
{
const_cast<RichText*>(this)->formatText();
}
return Widget::getBoundingBox();
} |
From the logic it seems it is needed, but i am not sure. Do you meet any problem? |
I did not notice this problem. |
I am not sure too, since some call back is invoked from UIWidget. So let's keep as it is and fix them when meet issue. |
OK |
* commit 'bceb242ebd9c0bf60fdf1cfcf671efc47f07e1ee': (28 commits) no message (cocos2d#18460) Added missing #include statement (cocos2d#18452) Fix cocos2d::log va_list re-use bug (cocos2d#18426) Improve StringUtils::format implementation. (cocos2d#18425) RichText improvements (cocos2d#18447) Update CCTableView.cpp (cocos2d#18451) Update UIWebViewImpl-ios.mm (cocos2d#18448) Reverts add search path logic in PR cocos2d#17435 . (cocos2d#18419) Fix 60 fps for android (cocos2d#18445) set texture anti-alias by deault in RenderTexture (cocos2d#18442) fix typos (cocos2d#18444) [ci skip][AUTO]: updating luabinding & jsbinding & cocos_file.json automatically (cocos2d#18440) Spine update (cocos2d#18438) remove vs2013 libs (cocos2d#18439) Revert cocos2d#18327 (cocos2d#18436) [ci skip][AUTO]: updating luabinding & jsbinding & cocos_file.json automatically (cocos2d#18435) update glfw to 3.2.1 (cocos2d#18434) Editbox init member variable (cocos2d#18432) [ci skip][AUTO]: updating luabinding & jsbinding & cocos_file.json automatically (cocos2d#18431) Update spine (cocos2d#18427) ... # Conflicts: # build/cocos2d_libs.xcodeproj/project.pbxproj # cocos/Android.mk # cocos/base/CCConsole.cpp # cocos/editor-support/spine/Android.mk # cocos/editor-support/spine/Animation.c # cocos/editor-support/spine/Animation.h # cocos/editor-support/spine/AnimationState.c # cocos/editor-support/spine/AnimationState.h # cocos/editor-support/spine/AnimationStateData.h # cocos/editor-support/spine/Atlas.c # cocos/editor-support/spine/Atlas.h # cocos/editor-support/spine/AtlasAttachmentLoader.c # cocos/editor-support/spine/AtlasAttachmentLoader.h # cocos/editor-support/spine/Attachment.h # cocos/editor-support/spine/AttachmentLoader.h # cocos/editor-support/spine/Bone.c # cocos/editor-support/spine/Bone.h # cocos/editor-support/spine/BoneData.h # cocos/editor-support/spine/BoundingBoxAttachment.c # cocos/editor-support/spine/BoundingBoxAttachment.h # cocos/editor-support/spine/CMakeLists.txt # cocos/editor-support/spine/Event.h # cocos/editor-support/spine/EventData.h # cocos/editor-support/spine/IkConstraint.c # cocos/editor-support/spine/IkConstraint.h # cocos/editor-support/spine/IkConstraintData.h # cocos/editor-support/spine/MeshAttachment.c # cocos/editor-support/spine/MeshAttachment.h # cocos/editor-support/spine/PathAttachment.c # cocos/editor-support/spine/PathAttachment.h # cocos/editor-support/spine/PathConstraint.c # cocos/editor-support/spine/PathConstraint.h # cocos/editor-support/spine/PathConstraintData.h # cocos/editor-support/spine/RegionAttachment.c # cocos/editor-support/spine/RegionAttachment.h # cocos/editor-support/spine/Skeleton.c # cocos/editor-support/spine/Skeleton.h # cocos/editor-support/spine/SkeletonAnimation.cpp # cocos/editor-support/spine/SkeletonAnimation.h # cocos/editor-support/spine/SkeletonBatch.cpp # cocos/editor-support/spine/SkeletonBatch.h # cocos/editor-support/spine/SkeletonBinary.c # cocos/editor-support/spine/SkeletonBinary.h # cocos/editor-support/spine/SkeletonBounds.c # cocos/editor-support/spine/SkeletonBounds.h # cocos/editor-support/spine/SkeletonData.h # cocos/editor-support/spine/SkeletonJson.c # cocos/editor-support/spine/SkeletonJson.h # cocos/editor-support/spine/SkeletonRenderer.cpp # cocos/editor-support/spine/SkeletonRenderer.h # cocos/editor-support/spine/Skin.h # cocos/editor-support/spine/Slot.c # cocos/editor-support/spine/Slot.h # cocos/editor-support/spine/SlotData.c # cocos/editor-support/spine/SlotData.h # cocos/editor-support/spine/TransformConstraint.c # cocos/editor-support/spine/TransformConstraint.h # cocos/editor-support/spine/TransformConstraintData.h # cocos/editor-support/spine/VertexAttachment.c # cocos/editor-support/spine/VertexAttachment.h # cocos/editor-support/spine/extension.c # cocos/editor-support/spine/extension.h # cocos/editor-support/spine/kvec.h # cocos/editor-support/spine/proj.win32/libSpine.vcxproj # cocos/editor-support/spine/proj.win32/libSpine.vcxproj.filters # cocos/editor-support/spine/spine.h # cocos/ui/UIRichText.h # plugin # tools/cocos2d-console
* commit 'a88ad877314a7b27cd16b33368862f1a3bdc95bd': Bug in mp3reader.cpp (cocos2d#18476) Uses Images.xcassets instead of several icon png files. (cocos2d#18485) fix comments for JniHelper.h (cocos2d#18481) Fixing crash in Allocator if there are no allocated pages (cocos2d#12908) Unregister spine event lua event handler should set listener to null. (cocos2d#12845) --force-yes => --allow, -y (cocos2d#18464) Add Comments for JniHelper.h (cocos2d#18477) no message (cocos2d#18460) Added missing #include statement (cocos2d#18452) Fix cocos2d::log va_list re-use bug (cocos2d#18426) Improve StringUtils::format implementation. (cocos2d#18425) RichText improvements (cocos2d#18447) Update CCTableView.cpp (cocos2d#18451) Update UIWebViewImpl-ios.mm (cocos2d#18448) # Conflicts: # cocos/base/CCConsole.cpp
Guys, introducing the trimming spaces on the right side of a text element makes no sense. It should not trim any space, since a RichText is made out of several elements, and spaces on the right side of text elements are used to literally put space between those elements. For example, say you have this UIRichText made up of 3 elements, text, image, and another text: text[space]Image[space]text which should be rendered as: text image text yet it appears as: textimagetext If for some reason you need it to trim right side spaces, then at least give us the option to turn that functionality on or off by some kind of flag bit (such as RichElementText::TRIM_RIGHT_SPACE etc). |
This is a PR to improve RichText.
There is a feedback that can not get the real height of a richtext from many forums.
I modify
_customSize.height
in functionRichText::formatRenderers
to make content size equals to real size.refactor split algorithm with
StringUtils::StringUTF8
.Helper::getSubStringOfUTF8String
several times with same string.StringUtils::StringUTF8
convers string only once.StringUtils::StringUTF8
is easier thanHelper::getSubStringOfUTF8String
. Related: The first character is disappeared at the head of a new line in UIRichTxt #18323getNextWordPos
to make it runs faster.handle ‘\n’ for new line, and support continuous ‘\n’. Related: UIRichText does not handle well "\n" #14188
改进RichText
许多论坛反馈RichText无法获取真实高度。我在函数
RichText::formatRenderers
里面修改了_customSize.height
,使得content size等于真实尺寸。用StringUtils::StringUTF8重构了字符串切割算法
对文本中的\n处理为换行。并支持连续的\n UIRichText does not handle well "\n" #14188