mirror of https://github.com/axmolengine/axmol.git
RichText and ScrollView enhancements (#1696)
* Add id tag to several RichText elements to allow locating the nodes in RichText Add font related styling to paragraph tags * Move functionality out of ListView and into ScrollView to allow scrolling to a specific child node within a ScrollView * Add function to allow finding protected child node by name * Example of anchor tags to local RichText content in a ScrollView * Fix string storage type
This commit is contained in:
parent
8e2e577e2f
commit
978d15db78
|
@ -128,6 +128,17 @@ Node* ProtectedNode::getProtectedChildByTag(int tag)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node* ProtectedNode::getProtectedChildByName(std::string_view name)
|
||||||
|
{
|
||||||
|
// AXASSERT(!name.empty(), "Invalid name");
|
||||||
|
for (auto&& child : _protectedChildren)
|
||||||
|
{
|
||||||
|
if (child && child->getName() == name)
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/* "remove" logic MUST only be on this method
|
/* "remove" logic MUST only be on this method
|
||||||
* If a class want's to extend the 'removeChild' behavior it only needs
|
* If a class want's to extend the 'removeChild' behavior it only needs
|
||||||
* to override this method
|
* to override this method
|
||||||
|
|
|
@ -94,6 +94,15 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual Node* getProtectedChildByTag(int tag);
|
virtual Node* getProtectedChildByTag(int tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a child from the container with its name.
|
||||||
|
*
|
||||||
|
* @param name An identifier to find the child node.
|
||||||
|
*
|
||||||
|
* @return a Node object whose name equals to the input parameter.
|
||||||
|
*/
|
||||||
|
virtual Node* getProtectedChildByName(std::string_view name);
|
||||||
|
|
||||||
////// REMOVES //////
|
////// REMOVES //////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||||
|
Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md).
|
||||||
|
|
||||||
https://axmolengine.github.io/
|
https://axmolengine.github.io/
|
||||||
|
|
||||||
|
@ -28,8 +29,6 @@ THE SOFTWARE.
|
||||||
|
|
||||||
NS_AX_BEGIN
|
NS_AX_BEGIN
|
||||||
|
|
||||||
static const float DEFAULT_TIME_IN_SEC_FOR_SCROLL_TO_ITEM = 1.0f;
|
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -45,7 +44,6 @@ ListView::ListView()
|
||||||
, _topPadding(0.0f)
|
, _topPadding(0.0f)
|
||||||
, _rightPadding(0.0f)
|
, _rightPadding(0.0f)
|
||||||
, _bottomPadding(0.0f)
|
, _bottomPadding(0.0f)
|
||||||
, _scrollTime(DEFAULT_TIME_IN_SEC_FOR_SCROLL_TO_ITEM)
|
|
||||||
, _curSelectedIndex(-1)
|
, _curSelectedIndex(-1)
|
||||||
, _innerContainerDoLayoutDirty(true)
|
, _innerContainerDoLayoutDirty(true)
|
||||||
, _eventCallback(nullptr)
|
, _eventCallback(nullptr)
|
||||||
|
@ -523,17 +521,6 @@ float ListView::getBottomPadding() const
|
||||||
return _bottomPadding;
|
return _bottomPadding;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListView::setScrollDuration(float time)
|
|
||||||
{
|
|
||||||
if (time >= 0)
|
|
||||||
_scrollTime = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
float ListView::getScrollDuration() const
|
|
||||||
{
|
|
||||||
return _scrollTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::setDirection(Direction dir)
|
void ListView::setDirection(Direction dir)
|
||||||
{
|
{
|
||||||
switch (dir)
|
switch (dir)
|
||||||
|
@ -642,13 +629,6 @@ void ListView::interceptTouchEvent(TouchEventType event, Widget* sender, Touch*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Vec2 calculateItemPositionWithAnchor(Widget* item, const Vec2& itemAnchorPoint)
|
|
||||||
{
|
|
||||||
Vec2 origin(item->getLeftBoundary(), item->getBottomBoundary());
|
|
||||||
Vec2 size = item->getContentSize();
|
|
||||||
return origin + Vec2(size.width * itemAnchorPoint.x, size.height * itemAnchorPoint.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Widget* findClosestItem(const Vec2& targetPosition,
|
static Widget* findClosestItem(const Vec2& targetPosition,
|
||||||
const Vector<Widget*>& items,
|
const Vector<Widget*>& items,
|
||||||
const Vec2& itemAnchorPoint,
|
const Vec2& itemAnchorPoint,
|
||||||
|
@ -676,7 +656,7 @@ static Widget* findClosestItem(const Vec2& targetPosition,
|
||||||
|
|
||||||
// Binary search
|
// Binary search
|
||||||
ssize_t midIndex = (firstIndex + lastIndex) / 2;
|
ssize_t midIndex = (firstIndex + lastIndex) / 2;
|
||||||
Vec2 itemPosition = calculateItemPositionWithAnchor(items.at(midIndex), itemAnchorPoint);
|
Vec2 itemPosition = ListView::calculateItemPositionWithAnchor(items.at(midIndex), itemAnchorPoint);
|
||||||
float distanceFromMid = (targetPosition - itemPosition).length();
|
float distanceFromMid = (targetPosition - itemPosition).length();
|
||||||
if (distanceFromFirst <= distanceFromLast)
|
if (distanceFromFirst <= distanceFromLast)
|
||||||
{
|
{
|
||||||
|
@ -830,17 +810,6 @@ void ListView::jumpToPercentBothDirection(const Vec2& percent)
|
||||||
ScrollView::jumpToPercentBothDirection(percent);
|
ScrollView::jumpToPercentBothDirection(percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2 ListView::calculateItemDestination(const Vec2& positionRatioInView, Widget* item, const Vec2& itemAnchorPoint)
|
|
||||||
{
|
|
||||||
const Vec2& contentSize = getContentSize();
|
|
||||||
Vec2 positionInView;
|
|
||||||
positionInView.x += contentSize.width * positionRatioInView.x;
|
|
||||||
positionInView.y += contentSize.height * positionRatioInView.y;
|
|
||||||
|
|
||||||
Vec2 itemPosition = calculateItemPositionWithAnchor(item, itemAnchorPoint);
|
|
||||||
return -(itemPosition - positionInView);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ListView::jumpToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint)
|
void ListView::jumpToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint)
|
||||||
{
|
{
|
||||||
Widget* item = getItem(itemIndex);
|
Widget* item = getItem(itemIndex);
|
||||||
|
@ -875,8 +844,7 @@ void ListView::scrollToItem(ssize_t itemIndex,
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Vec2 destination = calculateItemDestination(positionRatioInView, item, itemAnchorPoint);
|
ScrollView::scrollToItem(item, positionRatioInView, itemAnchorPoint, timeInSec);
|
||||||
startAutoScrollToDestination(destination, timeInSec, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t ListView::getCurSelectedIndex() const
|
ssize_t ListView::getCurSelectedIndex() const
|
||||||
|
@ -920,12 +888,12 @@ void ListView::copyClonedWidgetChildren(Widget* model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListView::copySpecialProperties(Widget* widget)
|
void ListView::copySpecialProperties(Widget* model)
|
||||||
{
|
{
|
||||||
ListView* listViewEx = dynamic_cast<ListView*>(widget);
|
ListView* listViewEx = dynamic_cast<ListView*>(model);
|
||||||
if (listViewEx)
|
if (listViewEx)
|
||||||
{
|
{
|
||||||
ScrollView::copySpecialProperties(widget);
|
ScrollView::copySpecialProperties(model);
|
||||||
setItemModel(listViewEx->_model);
|
setItemModel(listViewEx->_model);
|
||||||
setItemsMargin(listViewEx->_itemsMargin);
|
setItemsMargin(listViewEx->_itemsMargin);
|
||||||
setGravity(listViewEx->_gravity);
|
setGravity(listViewEx->_gravity);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||||
|
Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md).
|
||||||
|
|
||||||
https://axmolengine.github.io/
|
https://axmolengine.github.io/
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ public:
|
||||||
* @js NA
|
* @js NA
|
||||||
* @lua NA
|
* @lua NA
|
||||||
*/
|
*/
|
||||||
virtual ~ListView();
|
~ListView() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an empty ListView.
|
* Create an empty ListView.
|
||||||
|
@ -288,31 +289,16 @@ public:
|
||||||
*/
|
*/
|
||||||
float getBottomPadding() const;
|
float getBottomPadding() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the time in seconds to scroll between items.
|
|
||||||
* Subsequent calls of function 'scrollToItem', will take 'time' seconds for scrolling.
|
|
||||||
* @param time The seconds needed to scroll between two items. 'time' must be >= 0
|
|
||||||
* @see scrollToItem(ssize_t, const Vec2&, const Vec2&)
|
|
||||||
*/
|
|
||||||
void setScrollDuration(float time);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the time in seconds to scroll between items.
|
|
||||||
* @return The time in seconds to scroll between items
|
|
||||||
* @see setScrollDuration(float)
|
|
||||||
*/
|
|
||||||
float getScrollDuration() const;
|
|
||||||
|
|
||||||
// override methods
|
// override methods
|
||||||
virtual void doLayout() override;
|
void doLayout() override;
|
||||||
virtual void requestDoLayout() override;
|
void requestDoLayout() override;
|
||||||
virtual void addChild(Node* child) override;
|
void addChild(Node* child) override;
|
||||||
virtual void addChild(Node* child, int localZOrder) override;
|
void addChild(Node* child, int localZOrder) override;
|
||||||
virtual void addChild(Node* child, int zOrder, int tag) override;
|
void addChild(Node* child, int zOrder, int tag) override;
|
||||||
virtual void addChild(Node* child, int zOrder, std::string_view name) override;
|
void addChild(Node* child, int zOrder, std::string_view name) override;
|
||||||
virtual void removeAllChildren() override;
|
void removeAllChildren() override;
|
||||||
virtual void removeAllChildrenWithCleanup(bool cleanup) override;
|
void removeAllChildrenWithCleanup(bool cleanup) override;
|
||||||
virtual void removeChild(Node* child, bool cleanup = true) override;
|
void removeChild(Node* child, bool cleanup = true) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query the closest item to a specific position in inner container.
|
* @brief Query the closest item to a specific position in inner container.
|
||||||
|
@ -367,17 +353,17 @@ public:
|
||||||
/**
|
/**
|
||||||
* Override functions
|
* Override functions
|
||||||
*/
|
*/
|
||||||
virtual void jumpToBottom() override;
|
void jumpToBottom() override;
|
||||||
virtual void jumpToTop() override;
|
void jumpToTop() override;
|
||||||
virtual void jumpToLeft() override;
|
void jumpToLeft() override;
|
||||||
virtual void jumpToRight() override;
|
void jumpToRight() override;
|
||||||
virtual void jumpToTopLeft() override;
|
void jumpToTopLeft() override;
|
||||||
virtual void jumpToTopRight() override;
|
void jumpToTopRight() override;
|
||||||
virtual void jumpToBottomLeft() override;
|
void jumpToBottomLeft() override;
|
||||||
virtual void jumpToBottomRight() override;
|
void jumpToBottomRight() override;
|
||||||
virtual void jumpToPercentVertical(float percent) override;
|
void jumpToPercentVertical(float percent) override;
|
||||||
virtual void jumpToPercentHorizontal(float percent) override;
|
void jumpToPercentHorizontal(float percent) override;
|
||||||
virtual void jumpToPercentBothDirection(const Vec2& percent) override;
|
void jumpToPercentBothDirection(const Vec2& percent) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Jump to specific item
|
* @brief Jump to specific item
|
||||||
|
@ -391,15 +377,20 @@ public:
|
||||||
* @brief Scroll to specific item
|
* @brief Scroll to specific item
|
||||||
* @param positionRatioInView Specifies the position with ratio in list view's content size.
|
* @param positionRatioInView Specifies the position with ratio in list view's content size.
|
||||||
* @param itemAnchorPoint Specifies an anchor point of each item for position to calculate distance.
|
* @param itemAnchorPoint Specifies an anchor point of each item for position to calculate distance.
|
||||||
* @param timeInSec Scroll time
|
|
||||||
*/
|
*/
|
||||||
void scrollToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint);
|
void scrollToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Scroll to specific item
|
||||||
|
* @param positionRatioInView Specifies the position with ratio in list view's content size.
|
||||||
|
* @param itemAnchorPoint Specifies an anchor point of each item for position to calculate distance.
|
||||||
|
* @param timeInSec Scroll time
|
||||||
|
*/
|
||||||
void scrollToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint, float timeInSec);
|
void scrollToItem(ssize_t itemIndex, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint, float timeInSec);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Query current selected widget's index.
|
* @brief Query current selected widget's index.
|
||||||
*
|
*
|
||||||
|
|
||||||
* @return An index of a selected item.
|
* @return An index of a selected item.
|
||||||
*/
|
*/
|
||||||
ssize_t getCurSelectedIndex() const;
|
ssize_t getCurSelectedIndex() const;
|
||||||
|
@ -423,14 +414,14 @@ public:
|
||||||
* Direction Direction::VERTICAL means vertical scroll, Direction::HORIZONTAL means horizontal scroll.
|
* Direction Direction::VERTICAL means vertical scroll, Direction::HORIZONTAL means horizontal scroll.
|
||||||
* @param dir Set the list view's scroll direction.
|
* @param dir Set the list view's scroll direction.
|
||||||
*/
|
*/
|
||||||
virtual void setDirection(Direction dir) override;
|
void setDirection(Direction dir) override;
|
||||||
|
|
||||||
virtual std::string getDescription() const override;
|
std::string getDescription() const override;
|
||||||
|
|
||||||
virtual bool init() override;
|
bool init() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void handleReleaseLogic(Touch* touch) override;
|
void handleReleaseLogic(Touch* touch) override;
|
||||||
|
|
||||||
virtual void onItemListChanged();
|
virtual void onItemListChanged();
|
||||||
|
|
||||||
|
@ -439,19 +430,18 @@ protected:
|
||||||
void remedyVerticalLayoutParameter(LinearLayoutParameter* layoutParameter, ssize_t itemIndex);
|
void remedyVerticalLayoutParameter(LinearLayoutParameter* layoutParameter, ssize_t itemIndex);
|
||||||
void remedyHorizontalLayoutParameter(LinearLayoutParameter* layoutParameter, ssize_t itemIndex);
|
void remedyHorizontalLayoutParameter(LinearLayoutParameter* layoutParameter, ssize_t itemIndex);
|
||||||
|
|
||||||
virtual void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
virtual Widget* createCloneInstance() override;
|
Widget* createCloneInstance() override;
|
||||||
virtual void copySpecialProperties(Widget* model) override;
|
void copySpecialProperties(Widget* model) override;
|
||||||
virtual void copyClonedWidgetChildren(Widget* model) override;
|
void copyClonedWidgetChildren(Widget* model) override;
|
||||||
void selectedItemEvent(TouchEventType event);
|
void selectedItemEvent(TouchEventType event);
|
||||||
virtual void interceptTouchEvent(Widget::TouchEventType event, Widget* sender, Touch* touch) override;
|
void interceptTouchEvent(Widget::TouchEventType event, Widget* sender, Touch* touch) override;
|
||||||
|
|
||||||
virtual Vec2 getHowMuchOutOfBoundary(const Vec2& addition = Vec2::ZERO) override;
|
Vec2 getHowMuchOutOfBoundary(const Vec2& addition = Vec2::ZERO) override;
|
||||||
|
|
||||||
virtual void startAttenuatingAutoScroll(const Vec2& deltaMove, const Vec2& initialVelocity) override;
|
void startAttenuatingAutoScroll(const Vec2& deltaMove, const Vec2& initialVelocity) override;
|
||||||
|
|
||||||
void startMagneticScroll();
|
void startMagneticScroll();
|
||||||
Vec2 calculateItemDestination(const Vec2& positionRatioInView, Widget* item, const Vec2& itemAnchorPoint);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Widget* _model;
|
Widget* _model;
|
||||||
|
@ -470,8 +460,6 @@ protected:
|
||||||
float _rightPadding;
|
float _rightPadding;
|
||||||
float _bottomPadding;
|
float _bottomPadding;
|
||||||
|
|
||||||
float _scrollTime;
|
|
||||||
|
|
||||||
ssize_t _curSelectedIndex;
|
ssize_t _curSelectedIndex;
|
||||||
|
|
||||||
bool _innerContainerDoLayoutDirty;
|
bool _innerContainerDoLayoutDirty;
|
||||||
|
|
|
@ -151,11 +151,12 @@ RichElementText* RichElementText::create(int tag,
|
||||||
const Color3B& shadowColor,
|
const Color3B& shadowColor,
|
||||||
const Vec2& shadowOffset,
|
const Vec2& shadowOffset,
|
||||||
int shadowBlurRadius,
|
int shadowBlurRadius,
|
||||||
const Color3B& glowColor)
|
const Color3B& glowColor,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
RichElementText* element = new RichElementText();
|
RichElementText* element = new RichElementText();
|
||||||
if (element->init(tag, color, opacity, text, fontName, fontSize, flags, url, outlineColor, outlineSize, shadowColor,
|
if (element->init(tag, color, opacity, text, fontName, fontSize, flags, url, outlineColor, outlineSize, shadowColor,
|
||||||
shadowOffset, shadowBlurRadius, glowColor))
|
shadowOffset, shadowBlurRadius, glowColor, id))
|
||||||
{
|
{
|
||||||
element->autorelease();
|
element->autorelease();
|
||||||
return element;
|
return element;
|
||||||
|
@ -177,7 +178,8 @@ bool RichElementText::init(int tag,
|
||||||
const Color3B& shadowColor,
|
const Color3B& shadowColor,
|
||||||
const Vec2& shadowOffset,
|
const Vec2& shadowOffset,
|
||||||
int shadowBlurRadius,
|
int shadowBlurRadius,
|
||||||
const Color3B& glowColor)
|
const Color3B& glowColor,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
if (RichElement::init(tag, color, opacity))
|
if (RichElement::init(tag, color, opacity))
|
||||||
{
|
{
|
||||||
|
@ -192,6 +194,7 @@ bool RichElementText::init(int tag,
|
||||||
_shadowOffset = shadowOffset;
|
_shadowOffset = shadowOffset;
|
||||||
_shadowBlurRadius = shadowBlurRadius;
|
_shadowBlurRadius = shadowBlurRadius;
|
||||||
_glowColor = glowColor;
|
_glowColor = glowColor;
|
||||||
|
_id = id;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -202,10 +205,11 @@ RichElementImage* RichElementImage::create(int tag,
|
||||||
uint8_t opacity,
|
uint8_t opacity,
|
||||||
std::string_view filePath,
|
std::string_view filePath,
|
||||||
std::string_view url,
|
std::string_view url,
|
||||||
Widget::TextureResType texType)
|
Widget::TextureResType texType,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
RichElementImage* element = new RichElementImage();
|
RichElementImage* element = new RichElementImage();
|
||||||
if (element->init(tag, color, opacity, filePath, url, texType))
|
if (element->init(tag, color, opacity, filePath, url, texType, id))
|
||||||
{
|
{
|
||||||
element->autorelease();
|
element->autorelease();
|
||||||
return element;
|
return element;
|
||||||
|
@ -219,7 +223,8 @@ bool RichElementImage::init(int tag,
|
||||||
uint8_t opacity,
|
uint8_t opacity,
|
||||||
std::string_view filePath,
|
std::string_view filePath,
|
||||||
std::string_view url,
|
std::string_view url,
|
||||||
Widget::TextureResType texType)
|
Widget::TextureResType texType,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
if (RichElement::init(tag, color, opacity))
|
if (RichElement::init(tag, color, opacity))
|
||||||
{
|
{
|
||||||
|
@ -230,6 +235,7 @@ bool RichElementImage::init(int tag,
|
||||||
_scaleY = 1.0f;
|
_scaleY = 1.0f;
|
||||||
_url = url;
|
_url = url;
|
||||||
_textureType = texType;
|
_textureType = texType;
|
||||||
|
_id = id;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -250,13 +256,19 @@ void RichElementImage::setUrl(std::string_view url)
|
||||||
_url = url;
|
_url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RichElementImage::setId(std::string_view id)
|
||||||
|
{
|
||||||
|
_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
RichElementCustomNode* RichElementCustomNode::create(int tag,
|
RichElementCustomNode* RichElementCustomNode::create(int tag,
|
||||||
const Color3B& color,
|
const Color3B& color,
|
||||||
uint8_t opacity,
|
uint8_t opacity,
|
||||||
ax::Node* customNode)
|
ax::Node* customNode,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
RichElementCustomNode* element = new RichElementCustomNode();
|
RichElementCustomNode* element = new RichElementCustomNode();
|
||||||
if (element->init(tag, color, opacity, customNode))
|
if (element->init(tag, color, opacity, customNode, id))
|
||||||
{
|
{
|
||||||
element->autorelease();
|
element->autorelease();
|
||||||
return element;
|
return element;
|
||||||
|
@ -265,11 +277,16 @@ RichElementCustomNode* RichElementCustomNode::create(int tag,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RichElementCustomNode::init(int tag, const Color3B& color, uint8_t opacity, ax::Node* customNode)
|
bool RichElementCustomNode::init(int tag,
|
||||||
|
const Color3B& color,
|
||||||
|
uint8_t opacity,
|
||||||
|
ax::Node* customNode,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
if (RichElement::init(tag, color, opacity))
|
if (RichElement::init(tag, color, opacity))
|
||||||
{
|
{
|
||||||
_customNode = customNode;
|
_customNode = customNode;
|
||||||
|
_id = id;
|
||||||
_customNode->retain();
|
_customNode->retain();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -339,6 +356,7 @@ public:
|
||||||
Vec2 shadowOffset; /*!< shadow effect offset value */
|
Vec2 shadowOffset; /*!< shadow effect offset value */
|
||||||
int shadowBlurRadius; /*!< the shadow effect blur radius */
|
int shadowBlurRadius; /*!< the shadow effect blur radius */
|
||||||
Color3B glowColor; /*!< the glow effect color value */
|
Color3B glowColor; /*!< the glow effect color value */
|
||||||
|
std::string name; /*!< the name of this element */
|
||||||
|
|
||||||
void setColor(const Color3B& acolor)
|
void setColor(const Color3B& acolor)
|
||||||
{
|
{
|
||||||
|
@ -398,6 +416,8 @@ public:
|
||||||
|
|
||||||
std::tuple<bool, Color3B> getGlow() const;
|
std::tuple<bool, Color3B> getGlow() const;
|
||||||
|
|
||||||
|
std::string getName() const;
|
||||||
|
|
||||||
void startElement(void* ctx, const char* name, const char** atts) override;
|
void startElement(void* ctx, const char* name, const char** atts) override;
|
||||||
|
|
||||||
void endElement(void* ctx, const char* name) override;
|
void endElement(void* ctx, const char* name) override;
|
||||||
|
@ -569,6 +589,11 @@ MyXMLVisitor::MyXMLVisitor(RichText* richText) : _fontElements(20), _richText(ri
|
||||||
|
|
||||||
elementImg->setScaleX(scaleX);
|
elementImg->setScaleX(scaleX);
|
||||||
elementImg->setScaleY(scaleY);
|
elementImg->setScaleY(scaleY);
|
||||||
|
|
||||||
|
if (tagAttrValueMap.find("id") != tagAttrValueMap.end())
|
||||||
|
{
|
||||||
|
elementImg->setId(tagAttrValueMap.at("id").asString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return make_pair(ValueMap(), elementImg);
|
return make_pair(ValueMap(), elementImg);
|
||||||
});
|
});
|
||||||
|
@ -581,6 +606,12 @@ MyXMLVisitor::MyXMLVisitor(RichText* richText) : _fontElements(20), _richText(ri
|
||||||
{
|
{
|
||||||
attrValueMap[RichText::KEY_URL] = tagAttrValueMap.at("href").asString();
|
attrValueMap[RichText::KEY_URL] = tagAttrValueMap.at("href").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tagAttrValueMap.find("id") != tagAttrValueMap.end())
|
||||||
|
{
|
||||||
|
attrValueMap[RichText::KEY_ID] = tagAttrValueMap.at("id").asString();
|
||||||
|
}
|
||||||
|
|
||||||
return make_pair(attrValueMap, nullptr);
|
return make_pair(attrValueMap, nullptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -589,7 +620,32 @@ MyXMLVisitor::MyXMLVisitor(RichText* richText) : _fontElements(20), _richText(ri
|
||||||
return make_pair(ValueMap(), richElement);
|
return make_pair(ValueMap(), richElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
MyXMLVisitor::setTagDescription("p", false, nullptr,
|
MyXMLVisitor::setTagDescription(
|
||||||
|
"p", true,
|
||||||
|
[](const ValueMap& tagAttrValueMap) -> std::pair<ValueMap, RichElement*> {
|
||||||
|
ValueMap attrValueMap;
|
||||||
|
if (tagAttrValueMap.find("size") != tagAttrValueMap.end())
|
||||||
|
{
|
||||||
|
attrValueMap[RichText::KEY_FONT_SIZE] = tagAttrValueMap.at("size").asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tagAttrValueMap.find("color") != tagAttrValueMap.end())
|
||||||
|
{
|
||||||
|
attrValueMap[RichText::KEY_FONT_COLOR_STRING] = tagAttrValueMap.at("color").asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tagAttrValueMap.find("face") != tagAttrValueMap.end())
|
||||||
|
{
|
||||||
|
attrValueMap[RichText::KEY_FONT_FACE] = tagAttrValueMap.at("face").asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tagAttrValueMap.find("id") != tagAttrValueMap.end())
|
||||||
|
{
|
||||||
|
attrValueMap[RichText::KEY_ID] = tagAttrValueMap.at("id").asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_pair(attrValueMap, nullptr);
|
||||||
|
},
|
||||||
[] { return RichElementNewLine::create(0, 2, Color3B::WHITE, 255); });
|
[] { return RichElementNewLine::create(0, 2, Color3B::WHITE, 255); });
|
||||||
|
|
||||||
constexpr auto headerTagEnterHandler = [](const ValueMap& tagAttrValueMap,
|
constexpr auto headerTagEnterHandler = [](const ValueMap& tagAttrValueMap,
|
||||||
|
@ -616,6 +672,11 @@ MyXMLVisitor::MyXMLVisitor(RichText* richText) : _fontElements(20), _richText(ri
|
||||||
|
|
||||||
attrValueMap[RichText::KEY_TEXT_BOLD] = true;
|
attrValueMap[RichText::KEY_TEXT_BOLD] = true;
|
||||||
|
|
||||||
|
if (tagAttrValueMap.find("id") != tagAttrValueMap.end())
|
||||||
|
{
|
||||||
|
attrValueMap[RichText::KEY_ID] = tagAttrValueMap.at("id").asString();
|
||||||
|
}
|
||||||
|
|
||||||
return make_pair(attrValueMap, nullptr);
|
return make_pair(attrValueMap, nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -817,6 +878,16 @@ std::tuple<bool, Color3B> MyXMLVisitor::getGlow() const
|
||||||
return std::make_tuple(false, Color3B::WHITE);
|
return std::make_tuple(false, Color3B::WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MyXMLVisitor::getName() const
|
||||||
|
{
|
||||||
|
for (auto i = _fontElements.rbegin(), iRend = _fontElements.rend(); i != iRend; ++i)
|
||||||
|
{
|
||||||
|
if (!i->name.empty())
|
||||||
|
return i->name;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
void MyXMLVisitor::startElement(void* /*ctx*/, const char* elementName, const char** atts)
|
void MyXMLVisitor::startElement(void* /*ctx*/, const char* elementName, const char** atts)
|
||||||
{
|
{
|
||||||
auto it = _tagTables.find(elementName);
|
auto it = _tagTables.find(elementName);
|
||||||
|
@ -960,7 +1031,49 @@ void MyXMLVisitor::startElement(void* /*ctx*/, const char* elementName, const ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (attrValueMap.find(RichText::KEY_URL) != attrValueMap.end())
|
||||||
|
{
|
||||||
|
attributes.url = attrValueMap.at(RichText::KEY_URL).asString();
|
||||||
|
attributes.setColor(_richText->getAnchorFontColor3B());
|
||||||
|
if (_richText->isAnchorTextBoldEnabled())
|
||||||
|
{
|
||||||
|
attributes.bold = true;
|
||||||
|
}
|
||||||
|
if (_richText->isAnchorTextItalicEnabled())
|
||||||
|
{
|
||||||
|
attributes.italics = true;
|
||||||
|
}
|
||||||
|
if (_richText->isAnchorTextUnderlineEnabled())
|
||||||
|
{
|
||||||
|
attributes.line = StyleLine::UNDERLINE;
|
||||||
|
}
|
||||||
|
if (_richText->isAnchorTextDelEnabled())
|
||||||
|
{
|
||||||
|
attributes.line = StyleLine::STRIKETHROUGH;
|
||||||
|
}
|
||||||
|
if (_richText->isAnchorTextOutlineEnabled())
|
||||||
|
{
|
||||||
|
attributes.effect = StyleEffect::OUTLINE;
|
||||||
|
attributes.outlineColor = _richText->getAnchorTextOutlineColor3B();
|
||||||
|
attributes.outlineSize = _richText->getAnchorTextOutlineSize();
|
||||||
|
}
|
||||||
|
if (_richText->isAnchorTextShadowEnabled())
|
||||||
|
{
|
||||||
|
attributes.effect = StyleEffect::SHADOW;
|
||||||
|
attributes.shadowColor = _richText->getAnchorTextShadowColor3B();
|
||||||
|
attributes.shadowOffset = _richText->getAnchorTextShadowOffset();
|
||||||
|
attributes.shadowBlurRadius = _richText->getAnchorTextShadowBlurRadius();
|
||||||
|
}
|
||||||
|
if (_richText->isAnchorTextGlowEnabled())
|
||||||
|
{
|
||||||
|
attributes.effect = StyleEffect::GLOW;
|
||||||
|
attributes.glowColor = _richText->getAnchorTextGlowColor3B();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attrValueMap.find(RichText::KEY_ID) != attrValueMap.end())
|
||||||
|
{
|
||||||
|
attributes.name = attrValueMap.at(RichText::KEY_ID).asString();
|
||||||
|
}
|
||||||
pushBackFontElement(attributes);
|
pushBackFontElement(attributes);
|
||||||
}
|
}
|
||||||
if (richElement)
|
if (richElement)
|
||||||
|
@ -1017,6 +1130,7 @@ void MyXMLVisitor::textHandler(void* /*ctx*/, const char* str, size_t len)
|
||||||
auto outline = getOutline();
|
auto outline = getOutline();
|
||||||
auto shadow = getShadow();
|
auto shadow = getShadow();
|
||||||
auto glow = getGlow();
|
auto glow = getGlow();
|
||||||
|
auto name = getName();
|
||||||
|
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
if (italics)
|
if (italics)
|
||||||
|
@ -1038,7 +1152,7 @@ void MyXMLVisitor::textHandler(void* /*ctx*/, const char* str, size_t len)
|
||||||
|
|
||||||
auto element = RichElementText::create(0, color, 255, text, face, fontSize, flags, url, std::get<1>(outline),
|
auto element = RichElementText::create(0, color, 255, text, face, fontSize, flags, url, std::get<1>(outline),
|
||||||
std::get<2>(outline), std::get<1>(shadow), std::get<2>(shadow),
|
std::get<2>(outline), std::get<1>(shadow), std::get<2>(shadow),
|
||||||
std::get<3>(shadow), std::get<1>(glow));
|
std::get<3>(shadow), std::get<1>(glow), name);
|
||||||
_richText->pushBackElement(element);
|
_richText->pushBackElement(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1125,6 +1239,7 @@ const std::string RichText::KEY_ANCHOR_TEXT_SHADOW_OFFSET_WIDTH("KEY_ANCHOR_TEXT
|
||||||
const std::string RichText::KEY_ANCHOR_TEXT_SHADOW_OFFSET_HEIGHT("KEY_ANCHOR_TEXT_SHADOW_OFFSET_HEIGHT");
|
const std::string RichText::KEY_ANCHOR_TEXT_SHADOW_OFFSET_HEIGHT("KEY_ANCHOR_TEXT_SHADOW_OFFSET_HEIGHT");
|
||||||
const std::string RichText::KEY_ANCHOR_TEXT_SHADOW_BLUR_RADIUS("KEY_ANCHOR_TEXT_SHADOW_BLUR_RADIUS");
|
const std::string RichText::KEY_ANCHOR_TEXT_SHADOW_BLUR_RADIUS("KEY_ANCHOR_TEXT_SHADOW_BLUR_RADIUS");
|
||||||
const std::string RichText::KEY_ANCHOR_TEXT_GLOW_COLOR("KEY_ANCHOR_TEXT_GLOW_COLOR");
|
const std::string RichText::KEY_ANCHOR_TEXT_GLOW_COLOR("KEY_ANCHOR_TEXT_GLOW_COLOR");
|
||||||
|
const std::string RichText::KEY_ID("KEY_ID");
|
||||||
|
|
||||||
RichText::RichText() : _formatTextDirty(true), _leftSpaceWidth(0.0f)
|
RichText::RichText() : _formatTextDirty(true), _leftSpaceWidth(0.0f)
|
||||||
{
|
{
|
||||||
|
@ -1702,6 +1817,9 @@ void RichText::formatText(bool force)
|
||||||
label->enableGlow(Color4B(elmtText->_glowColor));
|
label->enableGlow(Color4B(elmtText->_glowColor));
|
||||||
}
|
}
|
||||||
label->setTextColor(Color4B(elmtText->_color));
|
label->setTextColor(Color4B(elmtText->_color));
|
||||||
|
|
||||||
|
label->setName(elmtText->_id);
|
||||||
|
|
||||||
elementRenderer = label;
|
elementRenderer = label;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1732,6 +1850,7 @@ void RichText::formatText(bool force)
|
||||||
UrlTouchListenerComponent::create(elementRenderer, elmtImage->_url,
|
UrlTouchListenerComponent::create(elementRenderer, elmtImage->_url,
|
||||||
std::bind(&RichText::openUrl, this, std::placeholders::_1)));
|
std::bind(&RichText::openUrl, this, std::placeholders::_1)));
|
||||||
elementRenderer->setColor(element->_color);
|
elementRenderer->setColor(element->_color);
|
||||||
|
elementRenderer->setName(elmtImage->_id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1774,7 +1893,7 @@ void RichText::formatText(bool force)
|
||||||
handleTextRenderer(elmtText->_text, elmtText->_fontName, elmtText->_fontSize, elmtText->_color,
|
handleTextRenderer(elmtText->_text, elmtText->_fontName, elmtText->_fontSize, elmtText->_color,
|
||||||
elmtText->_opacity, elmtText->_flags, elmtText->_url, elmtText->_outlineColor,
|
elmtText->_opacity, elmtText->_flags, elmtText->_url, elmtText->_outlineColor,
|
||||||
elmtText->_outlineSize, elmtText->_shadowColor, elmtText->_shadowOffset,
|
elmtText->_outlineSize, elmtText->_shadowColor, elmtText->_shadowOffset,
|
||||||
elmtText->_shadowBlurRadius, elmtText->_glowColor);
|
elmtText->_shadowBlurRadius, elmtText->_glowColor, elmtText->_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RichElement::Type::IMAGE:
|
case RichElement::Type::IMAGE:
|
||||||
|
@ -1782,13 +1901,13 @@ void RichText::formatText(bool force)
|
||||||
RichElementImage* elmtImage = static_cast<RichElementImage*>(element);
|
RichElementImage* elmtImage = static_cast<RichElementImage*>(element);
|
||||||
handleImageRenderer(elmtImage->_filePath, elmtImage->_textureType, elmtImage->_color,
|
handleImageRenderer(elmtImage->_filePath, elmtImage->_textureType, elmtImage->_color,
|
||||||
elmtImage->_opacity, elmtImage->_width, elmtImage->_height, elmtImage->_url,
|
elmtImage->_opacity, elmtImage->_width, elmtImage->_height, elmtImage->_url,
|
||||||
elmtImage->_scaleX, elmtImage->_scaleY);
|
elmtImage->_scaleX, elmtImage->_scaleY, elmtImage->_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RichElement::Type::CUSTOM:
|
case RichElement::Type::CUSTOM:
|
||||||
{
|
{
|
||||||
RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(element);
|
RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(element);
|
||||||
handleCustomRenderer(elmtCustom->_customNode);
|
handleCustomRenderer(elmtCustom->_customNode, elmtCustom->_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RichElement::Type::NEWLINE:
|
case RichElement::Type::NEWLINE:
|
||||||
|
@ -1972,7 +2091,8 @@ void RichText::handleTextRenderer(std::string_view text,
|
||||||
const Color3B& shadowColor,
|
const Color3B& shadowColor,
|
||||||
const Vec2& shadowOffset,
|
const Vec2& shadowOffset,
|
||||||
int shadowBlurRadius,
|
int shadowBlurRadius,
|
||||||
const Color3B& glowColor)
|
const Color3B& glowColor,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
bool fileExist = FileUtils::getInstance()->isFileExist(fontName);
|
bool fileExist = FileUtils::getInstance()->isFileExist(fontName);
|
||||||
RichText::WrapMode wrapMode = static_cast<RichText::WrapMode>(_defaults.at(KEY_WRAP_MODE).asInt());
|
RichText::WrapMode wrapMode = static_cast<RichText::WrapMode>(_defaults.at(KEY_WRAP_MODE).asInt());
|
||||||
|
@ -1982,6 +2102,7 @@ void RichText::handleTextRenderer(std::string_view text,
|
||||||
ss << text;
|
ss << text;
|
||||||
std::string currentText;
|
std::string currentText;
|
||||||
size_t realLines = 0;
|
size_t realLines = 0;
|
||||||
|
auto isFirstLabel = true;
|
||||||
while (std::getline(ss, currentText, '\n'))
|
while (std::getline(ss, currentText, '\n'))
|
||||||
{
|
{
|
||||||
if (realLines > 0)
|
if (realLines > 0)
|
||||||
|
@ -2026,6 +2147,12 @@ void RichText::handleTextRenderer(std::string_view text,
|
||||||
textRenderer->setTextColor(Color4B(color));
|
textRenderer->setTextColor(Color4B(color));
|
||||||
textRenderer->setOpacity(opacity);
|
textRenderer->setOpacity(opacity);
|
||||||
|
|
||||||
|
if (isFirstLabel && !id.empty())
|
||||||
|
{
|
||||||
|
textRenderer->setName(id);
|
||||||
|
isFirstLabel = false;
|
||||||
|
}
|
||||||
|
|
||||||
// textRendererWidth will get 0.0f, when we've got glError: 0x0501 in Label::getContentSize
|
// textRendererWidth will get 0.0f, when we've got glError: 0x0501 in Label::getContentSize
|
||||||
// It happens when currentText is very very long so that can't generate a texture
|
// It happens when currentText is very very long so that can't generate a texture
|
||||||
const float textRendererWidth = textRenderer->getContentSize().width;
|
const float textRendererWidth = textRenderer->getContentSize().width;
|
||||||
|
@ -2094,7 +2221,8 @@ void RichText::handleImageRenderer(std::string_view filePath,
|
||||||
int height,
|
int height,
|
||||||
std::string_view url,
|
std::string_view url,
|
||||||
float scaleX,
|
float scaleX,
|
||||||
float scaleY)
|
float scaleY,
|
||||||
|
std::string_view id)
|
||||||
{
|
{
|
||||||
Sprite* imageRenderer;
|
Sprite* imageRenderer;
|
||||||
if (textureType == Widget::TextureResType::LOCAL)
|
if (textureType == Widget::TextureResType::LOCAL)
|
||||||
|
@ -2110,6 +2238,8 @@ void RichText::handleImageRenderer(std::string_view filePath,
|
||||||
if (height != -1)
|
if (height != -1)
|
||||||
imageRenderer->setScaleY(height / currentSize.height);
|
imageRenderer->setScaleY(height / currentSize.height);
|
||||||
|
|
||||||
|
imageRenderer->setName(id);
|
||||||
|
|
||||||
imageRenderer->setScaleX(imageRenderer->getScaleX() * scaleX);
|
imageRenderer->setScaleX(imageRenderer->getScaleX() * scaleX);
|
||||||
imageRenderer->setScaleY(imageRenderer->getScaleY() * scaleY);
|
imageRenderer->setScaleY(imageRenderer->getScaleY() * scaleY);
|
||||||
|
|
||||||
|
@ -2122,9 +2252,15 @@ void RichText::handleImageRenderer(std::string_view filePath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RichText::handleCustomRenderer(ax::Node* renderer)
|
void RichText::handleCustomRenderer(ax::Node* renderer, std::string_view id)
|
||||||
{
|
{
|
||||||
Vec2 imgSize = renderer->getContentSize();
|
Vec2 imgSize = renderer->getContentSize();
|
||||||
|
|
||||||
|
if (!id.empty())
|
||||||
|
{
|
||||||
|
renderer->setName(id);
|
||||||
|
}
|
||||||
|
|
||||||
_leftSpaceWidth -= imgSize.width;
|
_leftSpaceWidth -= imgSize.width;
|
||||||
if (_leftSpaceWidth < 0.0f)
|
if (_leftSpaceWidth < 0.0f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -121,6 +121,7 @@ public:
|
||||||
* @param shadowOffset shadow effect offset value
|
* @param shadowOffset shadow effect offset value
|
||||||
* @param shadowBlurRadius the shadow effect blur radius
|
* @param shadowBlurRadius the shadow effect blur radius
|
||||||
* @param glowColor glow color
|
* @param glowColor glow color
|
||||||
|
* @param id ID of element
|
||||||
* @return True if initialize success, false otherwise.
|
* @return True if initialize success, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool init(int tag,
|
bool init(int tag,
|
||||||
|
@ -136,7 +137,8 @@ public:
|
||||||
const Color3B& shadowColor = Color3B::BLACK,
|
const Color3B& shadowColor = Color3B::BLACK,
|
||||||
const Vec2& shadowOffset = Vec2(2.0, -2.0),
|
const Vec2& shadowOffset = Vec2(2.0, -2.0),
|
||||||
int shadowBlurRadius = 0,
|
int shadowBlurRadius = 0,
|
||||||
const Color3B& glowColor = Color3B::WHITE);
|
const Color3B& glowColor = Color3B::WHITE,
|
||||||
|
std::string_view id = ""sv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a RichElementText with various arguments.
|
* @brief Create a RichElementText with various arguments.
|
||||||
|
@ -155,6 +157,7 @@ public:
|
||||||
* @param shadowOffset shadow effect offset value
|
* @param shadowOffset shadow effect offset value
|
||||||
* @param shadowBlurRadius the shadow effect blur radius
|
* @param shadowBlurRadius the shadow effect blur radius
|
||||||
* @param glowColor glow color
|
* @param glowColor glow color
|
||||||
|
* @param id ID of element
|
||||||
* @return RichElementText instance.
|
* @return RichElementText instance.
|
||||||
*/
|
*/
|
||||||
static RichElementText* create(int tag,
|
static RichElementText* create(int tag,
|
||||||
|
@ -170,7 +173,8 @@ public:
|
||||||
const Color3B& shadowColor = Color3B::BLACK,
|
const Color3B& shadowColor = Color3B::BLACK,
|
||||||
const Vec2& shadowOffset = Vec2(2.0, -2.0),
|
const Vec2& shadowOffset = Vec2(2.0, -2.0),
|
||||||
int shadowBlurRadius = 0,
|
int shadowBlurRadius = 0,
|
||||||
const Color3B& glowColor = Color3B::WHITE);
|
const Color3B& glowColor = Color3B::WHITE,
|
||||||
|
std::string_view id = ""sv);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _text;
|
std::string _text;
|
||||||
|
@ -184,6 +188,7 @@ protected:
|
||||||
Vec2 _shadowOffset; /*!< shadow effect offset value */
|
Vec2 _shadowOffset; /*!< shadow effect offset value */
|
||||||
int _shadowBlurRadius; /*!< the shadow effect blur radius */
|
int _shadowBlurRadius; /*!< the shadow effect blur radius */
|
||||||
Color3B _glowColor; /*!< attributes of glow tag */
|
Color3B _glowColor; /*!< attributes of glow tag */
|
||||||
|
std::string _id; /*!< ID of this text field */
|
||||||
friend class RichText;
|
friend class RichText;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -210,6 +215,7 @@ public:
|
||||||
* @param filePath A image file name.
|
* @param filePath A image file name.
|
||||||
* @param url uniform resource locator
|
* @param url uniform resource locator
|
||||||
* @param texType texture type, may be a valid file path, or a sprite frame name
|
* @param texType texture type, may be a valid file path, or a sprite frame name
|
||||||
|
* @param id ID of element
|
||||||
* @return True if initialize success, false otherwise.
|
* @return True if initialize success, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool init(int tag,
|
bool init(int tag,
|
||||||
|
@ -217,7 +223,8 @@ public:
|
||||||
uint8_t opacity,
|
uint8_t opacity,
|
||||||
std::string_view filePath,
|
std::string_view filePath,
|
||||||
std::string_view url = "",
|
std::string_view url = "",
|
||||||
Widget::TextureResType texType = Widget::TextureResType::LOCAL);
|
Widget::TextureResType texType = Widget::TextureResType::LOCAL,
|
||||||
|
std::string_view id = ""sv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a RichElementImage with various arguments.
|
* @brief Create a RichElementImage with various arguments.
|
||||||
|
@ -228,6 +235,7 @@ public:
|
||||||
* @param filePath A image file name.
|
* @param filePath A image file name.
|
||||||
* @param url uniform resource locator
|
* @param url uniform resource locator
|
||||||
* @param texType texture type, may be a valid file path, or a sprite frame name
|
* @param texType texture type, may be a valid file path, or a sprite frame name
|
||||||
|
* @param id ID of element
|
||||||
* @return A RichElementImage instance.
|
* @return A RichElementImage instance.
|
||||||
*/
|
*/
|
||||||
static RichElementImage* create(int tag,
|
static RichElementImage* create(int tag,
|
||||||
|
@ -235,7 +243,8 @@ public:
|
||||||
uint8_t opacity,
|
uint8_t opacity,
|
||||||
std::string_view filePath,
|
std::string_view filePath,
|
||||||
std::string_view url = "",
|
std::string_view url = "",
|
||||||
Widget::TextureResType texType = Widget::TextureResType::LOCAL);
|
Widget::TextureResType texType = Widget::TextureResType::LOCAL,
|
||||||
|
std::string_view id = ""sv);
|
||||||
|
|
||||||
void setWidth(int width);
|
void setWidth(int width);
|
||||||
void setHeight(int height);
|
void setHeight(int height);
|
||||||
|
@ -243,6 +252,7 @@ public:
|
||||||
void setScaleX(float scaleX) { _scaleX = scaleX; }
|
void setScaleX(float scaleX) { _scaleX = scaleX; }
|
||||||
void setScaleY(float scaleY) { _scaleY = scaleY; }
|
void setScaleY(float scaleY) { _scaleY = scaleY; }
|
||||||
void setUrl(std::string_view url);
|
void setUrl(std::string_view url);
|
||||||
|
void setId(std::string_view id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _filePath;
|
std::string _filePath;
|
||||||
|
@ -254,6 +264,7 @@ protected:
|
||||||
float _scaleX;
|
float _scaleX;
|
||||||
float _scaleY;
|
float _scaleY;
|
||||||
std::string _url; /*!< attributes of anchor tag */
|
std::string _url; /*!< attributes of anchor tag */
|
||||||
|
std::string _id; /*!< attributes of anchor tag */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -283,9 +294,10 @@ public:
|
||||||
* @param color A color in Color3B.
|
* @param color A color in Color3B.
|
||||||
* @param opacity A opacity in GLubyte.
|
* @param opacity A opacity in GLubyte.
|
||||||
* @param customNode A custom node pointer.
|
* @param customNode A custom node pointer.
|
||||||
|
* @param id ID of element
|
||||||
* @return True if initialize success, false otherwise.
|
* @return True if initialize success, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool init(int tag, const Color3B& color, uint8_t opacity, Node* customNode);
|
bool init(int tag, const Color3B& color, uint8_t opacity, Node* customNode, std::string_view id = ""sv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a RichElementCustomNode with various arguments.
|
* @brief Create a RichElementCustomNode with various arguments.
|
||||||
|
@ -294,12 +306,19 @@ public:
|
||||||
* @param color A color in Color3B.
|
* @param color A color in Color3B.
|
||||||
* @param opacity A opacity in GLubyte.
|
* @param opacity A opacity in GLubyte.
|
||||||
* @param customNode A custom node pointer.
|
* @param customNode A custom node pointer.
|
||||||
|
* @param id ID of element
|
||||||
* @return A RichElementCustomNode instance.
|
* @return A RichElementCustomNode instance.
|
||||||
*/
|
*/
|
||||||
static RichElementCustomNode* create(int tag, const Color3B& color, uint8_t opacity, Node* customNode);
|
static RichElementCustomNode* create(int tag,
|
||||||
|
const Color3B& color,
|
||||||
|
uint8_t opacity,
|
||||||
|
Node* customNode,
|
||||||
|
std::string_view id = ""sv);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Node* _customNode{};
|
Node* _customNode{};
|
||||||
|
std::string _id;
|
||||||
|
|
||||||
friend class RichText;
|
friend class RichText;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -431,6 +450,7 @@ public:
|
||||||
static const std::string KEY_ANCHOR_TEXT_SHADOW_OFFSET_HEIGHT; /*!< key of shadow offset (height) of anchor tag */
|
static const std::string KEY_ANCHOR_TEXT_SHADOW_OFFSET_HEIGHT; /*!< key of shadow offset (height) of anchor tag */
|
||||||
static const std::string KEY_ANCHOR_TEXT_SHADOW_BLUR_RADIUS; /*!< key of shadow blur radius of anchor tag */
|
static const std::string KEY_ANCHOR_TEXT_SHADOW_BLUR_RADIUS; /*!< key of shadow blur radius of anchor tag */
|
||||||
static const std::string KEY_ANCHOR_TEXT_GLOW_COLOR; /*!< key of glow color of anchor tag */
|
static const std::string KEY_ANCHOR_TEXT_GLOW_COLOR; /*!< key of glow color of anchor tag */
|
||||||
|
static const std::string KEY_ID; /*!< key of id */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Default constructor.
|
* @brief Default constructor.
|
||||||
|
@ -611,7 +631,8 @@ protected:
|
||||||
const Color3B& shadowColor = Color3B::BLACK,
|
const Color3B& shadowColor = Color3B::BLACK,
|
||||||
const Vec2& shadowOffset = Vec2(2.0, -2.0),
|
const Vec2& shadowOffset = Vec2(2.0, -2.0),
|
||||||
int shadowBlurRadius = 0,
|
int shadowBlurRadius = 0,
|
||||||
const Color3B& glowColor = Color3B::WHITE);
|
const Color3B& glowColor = Color3B::WHITE,
|
||||||
|
std::string_view id = ""sv);
|
||||||
void handleImageRenderer(std::string_view filePath,
|
void handleImageRenderer(std::string_view filePath,
|
||||||
Widget::TextureResType textureType,
|
Widget::TextureResType textureType,
|
||||||
const Color3B& color,
|
const Color3B& color,
|
||||||
|
@ -620,8 +641,9 @@ protected:
|
||||||
int height,
|
int height,
|
||||||
std::string_view url,
|
std::string_view url,
|
||||||
float scaleX = 1.f,
|
float scaleX = 1.f,
|
||||||
float scaleY = 1.f);
|
float scaleY = 1.f,
|
||||||
void handleCustomRenderer(Node* renderer);
|
std::string_view id = ""sv);
|
||||||
|
void handleCustomRenderer(Node* renderer, std::string_view id = ""sv);
|
||||||
void formatRenderers();
|
void formatRenderers();
|
||||||
void addNewLine(int quantity = 1);
|
void addNewLine(int quantity = 1);
|
||||||
void doHorizontalAlignment(const Vector<Node*>& row, float rowWidth);
|
void doHorizontalAlignment(const Vector<Node*>& row, float rowWidth);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||||
|
Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md).
|
||||||
|
|
||||||
https://axmolengine.github.io/
|
https://axmolengine.github.io/
|
||||||
|
|
||||||
|
@ -32,19 +33,23 @@ THE SOFTWARE.
|
||||||
#include "2d/Camera.h"
|
#include "2d/Camera.h"
|
||||||
NS_AX_BEGIN
|
NS_AX_BEGIN
|
||||||
|
|
||||||
static const int NUMBER_OF_GATHERED_TOUCHES_FOR_MOVE_SPEED = 5;
|
namespace
|
||||||
static const float OUT_OF_BOUNDARY_BREAKING_FACTOR = 0.05f;
|
{
|
||||||
static const float BOUNCE_BACK_DURATION = 1.0f;
|
constexpr float DEFAULT_TIME_IN_SEC_FOR_SCROLL_TO_ITEM = 1.0f;
|
||||||
|
constexpr int NUMBER_OF_GATHERED_TOUCHES_FOR_MOVE_SPEED = 5;
|
||||||
|
constexpr float OUT_OF_BOUNDARY_BREAKING_FACTOR = 0.05f;
|
||||||
|
constexpr float BOUNCE_BACK_DURATION = 1.0f;
|
||||||
|
|
||||||
#define MOVE_INCH 7.0f / 160.0f
|
float convertDistanceFromPointToInch(const Vec2& dis)
|
||||||
|
|
||||||
static float convertDistanceFromPointToInch(const Vec2& dis)
|
|
||||||
{
|
{
|
||||||
auto glView = Director::getInstance()->getGLView();
|
auto glView = Director::getInstance()->getGLView();
|
||||||
int dpi = Device::getDPI();
|
int dpi = Device::getDPI();
|
||||||
float distance = Vec2(dis.x * glView->getScaleX() / dpi, dis.y * glView->getScaleY() / dpi).getLength();
|
float distance = Vec2(dis.x * glView->getScaleX() / dpi, dis.y * glView->getScaleY() / dpi).getLength();
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#define MOVE_INCH (7.0f / 160.0f)
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
|
@ -78,6 +83,7 @@ ScrollView::ScrollView()
|
||||||
, _horizontalScrollBar(nullptr)
|
, _horizontalScrollBar(nullptr)
|
||||||
, _scrollViewEventListener(nullptr)
|
, _scrollViewEventListener(nullptr)
|
||||||
, _eventCallback(nullptr)
|
, _eventCallback(nullptr)
|
||||||
|
, _scrollTime(DEFAULT_TIME_IN_SEC_FOR_SCROLL_TO_ITEM)
|
||||||
{
|
{
|
||||||
setTouchEnabled(true);
|
setTouchEnabled(true);
|
||||||
_propagateTouchEvents = false;
|
_propagateTouchEvents = false;
|
||||||
|
@ -1587,6 +1593,51 @@ Widget* ScrollView::findNextFocusedWidget(ax::ui::Widget::FocusDirection directi
|
||||||
return Widget::findNextFocusedWidget(direction, current);
|
return Widget::findNextFocusedWidget(direction, current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ScrollView::setScrollDuration(float time)
|
||||||
|
{
|
||||||
|
if (time >= 0)
|
||||||
|
_scrollTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ScrollView::getScrollDuration() const
|
||||||
|
{
|
||||||
|
return _scrollTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 ScrollView::calculateItemPositionWithAnchor(const Node* node, const Vec2& itemAnchorPoint)
|
||||||
|
{
|
||||||
|
auto boundingBox = node->getBoundingBox();
|
||||||
|
Vec2 origin(boundingBox.origin.x, boundingBox.origin.y);
|
||||||
|
Vec2 size = node->getContentSize();
|
||||||
|
return origin + Vec2(size.width * itemAnchorPoint.x, size.height * itemAnchorPoint.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2 ScrollView::calculateItemDestination(const Vec2& positionRatioInView, const Node* item, const Vec2& itemAnchorPoint)
|
||||||
|
{
|
||||||
|
const Vec2& contentSize = getContentSize();
|
||||||
|
Vec2 positionInView;
|
||||||
|
positionInView.x += contentSize.width * positionRatioInView.x;
|
||||||
|
positionInView.y += contentSize.height * positionRatioInView.y;
|
||||||
|
|
||||||
|
Vec2 itemPosition = calculateItemPositionWithAnchor(item, itemAnchorPoint);
|
||||||
|
return -(itemPosition - positionInView);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollView::scrollToItem(Node* item, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint)
|
||||||
|
{
|
||||||
|
scrollToItem(item, positionRatioInView, itemAnchorPoint, _scrollTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollView::scrollToItem(Node* item, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint, float timeInSec)
|
||||||
|
{
|
||||||
|
if (item == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto destination = calculateItemDestination(positionRatioInView, item, itemAnchorPoint);
|
||||||
|
startAutoScrollToDestination(destination, timeInSec, true);
|
||||||
|
}
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
||||||
NS_AX_END
|
NS_AX_END
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||||
|
Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md).
|
||||||
|
|
||||||
https://axmolengine.github.io/
|
https://axmolengine.github.io/
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ public:
|
||||||
* @js NA
|
* @js NA
|
||||||
* @lua NA
|
* @lua NA
|
||||||
*/
|
*/
|
||||||
virtual ~ScrollView();
|
~ScrollView() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an empty ScrollView.
|
* Create an empty ScrollView.
|
||||||
|
@ -340,24 +341,24 @@ public:
|
||||||
virtual void addEventListener(const ccScrollViewCallback& callback);
|
virtual void addEventListener(const ccScrollViewCallback& callback);
|
||||||
|
|
||||||
// override functions
|
// override functions
|
||||||
virtual void addChild(Node* child) override;
|
void addChild(Node* child) override;
|
||||||
virtual void addChild(Node* child, int localZOrder) override;
|
void addChild(Node* child, int localZOrder) override;
|
||||||
virtual void addChild(Node* child, int localZOrder, int tag) override;
|
void addChild(Node* child, int localZOrder, int tag) override;
|
||||||
virtual void addChild(Node* child, int localZOrder, std::string_view name) override;
|
void addChild(Node* child, int localZOrder, std::string_view name) override;
|
||||||
virtual void removeAllChildren() override;
|
void removeAllChildren() override;
|
||||||
virtual void removeAllChildrenWithCleanup(bool cleanup) override;
|
void removeAllChildrenWithCleanup(bool cleanup) override;
|
||||||
virtual void removeChild(Node* child, bool cleanup = true) override;
|
void removeChild(Node* child, bool cleanup = true) override;
|
||||||
virtual Vector<Node*>& getChildren() override;
|
Vector<Node*>& getChildren() override;
|
||||||
virtual const Vector<Node*>& getChildren() const override;
|
const Vector<Node*>& getChildren() const override;
|
||||||
virtual ssize_t getChildrenCount() const override;
|
ssize_t getChildrenCount() const override;
|
||||||
virtual Node* getChildByTag(int tag) const override;
|
Node* getChildByTag(int tag) const override;
|
||||||
virtual Node* getChildByName(std::string_view name) const override;
|
Node* getChildByName(std::string_view name) const override;
|
||||||
// touch event callback
|
// touch event callback
|
||||||
virtual bool onTouchBegan(Touch* touch, Event* unusedEvent) override;
|
bool onTouchBegan(Touch* touch, Event* unusedEvent) override;
|
||||||
virtual void onTouchMoved(Touch* touch, Event* unusedEvent) override;
|
void onTouchMoved(Touch* touch, Event* unusedEvent) override;
|
||||||
virtual void onTouchEnded(Touch* touch, Event* unusedEvent) override;
|
void onTouchEnded(Touch* touch, Event* unusedEvent) override;
|
||||||
virtual void onTouchCancelled(Touch* touch, Event* unusedEvent) override;
|
void onTouchCancelled(Touch* touch, Event* unusedEvent) override;
|
||||||
virtual void update(float dt) override;
|
void update(float dt) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Toggle bounce enabled when scroll to the edge.
|
* @brief Toggle bounce enabled when scroll to the edge.
|
||||||
|
@ -453,7 +454,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Set the scroll bar's color
|
* @brief Set the scroll bar's color
|
||||||
*
|
*
|
||||||
* @param the scroll bar's color
|
* @param color the scroll bar's color
|
||||||
*/
|
*/
|
||||||
void setScrollBarColor(const Color3B& color);
|
void setScrollBarColor(const Color3B& color);
|
||||||
|
|
||||||
|
@ -467,7 +468,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Set the scroll bar's opacity
|
* @brief Set the scroll bar's opacity
|
||||||
*
|
*
|
||||||
* @param the scroll bar's opacity
|
* @param opacity the scroll bar's opacity
|
||||||
*/
|
*/
|
||||||
void setScrollBarOpacity(uint8_t opacity);
|
void setScrollBarOpacity(uint8_t opacity);
|
||||||
|
|
||||||
|
@ -481,7 +482,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Set scroll bar auto hide state
|
* @brief Set scroll bar auto hide state
|
||||||
*
|
*
|
||||||
* @param scroll bar auto hide state
|
* @param autoHideEnabled scroll bar auto hide state
|
||||||
*/
|
*/
|
||||||
void setScrollBarAutoHideEnabled(bool autoHideEnabled);
|
void setScrollBarAutoHideEnabled(bool autoHideEnabled);
|
||||||
|
|
||||||
|
@ -495,7 +496,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Set scroll bar auto hide time
|
* @brief Set scroll bar auto hide time
|
||||||
*
|
*
|
||||||
* @param scroll bar auto hide time
|
* @param autoHideTime bar auto hide time
|
||||||
*/
|
*/
|
||||||
void setScrollBarAutoHideTime(float autoHideTime);
|
void setScrollBarAutoHideTime(float autoHideTime);
|
||||||
|
|
||||||
|
@ -509,7 +510,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Set the touch total time threshold
|
* @brief Set the touch total time threshold
|
||||||
*
|
*
|
||||||
* @param the touch total time threshold
|
* @param touchTotalTimeThreshold the touch total time threshold
|
||||||
*/
|
*/
|
||||||
void setTouchTotalTimeThreshold(float touchTotalTimeThreshold);
|
void setTouchTotalTimeThreshold(float touchTotalTimeThreshold);
|
||||||
|
|
||||||
|
@ -526,7 +527,7 @@ public:
|
||||||
* @see `Layout::Type`
|
* @see `Layout::Type`
|
||||||
* @param type Layout type enum.
|
* @param type Layout type enum.
|
||||||
*/
|
*/
|
||||||
virtual void setLayoutType(Type type) override;
|
void setLayoutType(Type type) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the layout type for scrollview.
|
* Get the layout type for scrollview.
|
||||||
|
@ -534,22 +535,22 @@ public:
|
||||||
* @see `Layout::Type`
|
* @see `Layout::Type`
|
||||||
* @return LayoutType
|
* @return LayoutType
|
||||||
*/
|
*/
|
||||||
virtual Type getLayoutType() const override;
|
Type getLayoutType() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the "class name" of widget.
|
* Return the "class name" of widget.
|
||||||
*/
|
*/
|
||||||
virtual std::string getDescription() const override;
|
std::string getDescription() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @lua NA
|
* @lua NA
|
||||||
*/
|
*/
|
||||||
virtual void onEnter() override;
|
void onEnter() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @lua NA
|
* @lua NA
|
||||||
*/
|
*/
|
||||||
virtual void onExit() override;
|
void onExit() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a widget is in a layout, you could call this method to get the next focused widget within a specified
|
* When a widget is in a layout, you could call this method to get the next focused widget within a specified
|
||||||
|
@ -558,7 +559,22 @@ public:
|
||||||
*@param current the current focused widget
|
*@param current the current focused widget
|
||||||
*@return the next focused widget in a layout
|
*@return the next focused widget in a layout
|
||||||
*/
|
*/
|
||||||
virtual Widget* findNextFocusedWidget(FocusDirection direction, Widget* current) override;
|
Widget* findNextFocusedWidget(FocusDirection direction, Widget* current) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the time in seconds to scroll between items.
|
||||||
|
* Subsequent calls of function 'scrollToItem', will take 'time' seconds for scrolling.
|
||||||
|
* @param time The seconds needed to scroll between two items. 'time' must be >= 0
|
||||||
|
* @see scrollToItem(ssize_t, const Vec2&, const Vec2&)
|
||||||
|
*/
|
||||||
|
void setScrollDuration(float time);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the time in seconds to scroll between items.
|
||||||
|
* @return The time in seconds to scroll between items
|
||||||
|
* @see setScrollDuration(float)
|
||||||
|
*/
|
||||||
|
float getScrollDuration() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether the user is currently dragging the ScrollView to scroll it
|
* @return Whether the user is currently dragging the ScrollView to scroll it
|
||||||
|
@ -569,7 +585,26 @@ public:
|
||||||
*/
|
*/
|
||||||
bool isAutoScrolling() const { return _autoScrolling; }
|
bool isAutoScrolling() const { return _autoScrolling; }
|
||||||
|
|
||||||
virtual bool init() override;
|
bool init() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Scroll to specific item
|
||||||
|
* @param item Item to scroll to
|
||||||
|
* @param positionRatioInView Specifies the position with ratio in list view's content size.
|
||||||
|
* @param itemAnchorPoint Specifies an anchor point of each item for position to calculate distance.
|
||||||
|
*/
|
||||||
|
void scrollToItem(Node* item, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Scroll to specific item
|
||||||
|
* @param item Item to scroll to
|
||||||
|
* @param positionRatioInView Specifies the position with ratio in list view's content size.
|
||||||
|
* @param itemAnchorPoint Specifies an anchor point of each item for position to calculate distance.
|
||||||
|
* @param timeInSec Scroll time
|
||||||
|
*/
|
||||||
|
void scrollToItem(Node* item, const Vec2& positionRatioInView, const Vec2& itemAnchorPoint, float timeInSec);
|
||||||
|
|
||||||
|
static Vec2 calculateItemPositionWithAnchor(const Node* node, const Vec2& itemAnchorPoint);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum class MoveDirection
|
enum class MoveDirection
|
||||||
|
@ -580,14 +615,14 @@ protected:
|
||||||
RIGHT,
|
RIGHT,
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual void initRenderer() override;
|
void initRenderer() override;
|
||||||
|
|
||||||
virtual void onSizeChanged() override;
|
void onSizeChanged() override;
|
||||||
virtual void doLayout() override;
|
void doLayout() override;
|
||||||
|
|
||||||
virtual Widget* createCloneInstance() override;
|
Widget* createCloneInstance() override;
|
||||||
virtual void copySpecialProperties(Widget* model) override;
|
void copySpecialProperties(Widget* model) override;
|
||||||
virtual void copyClonedWidgetChildren(Widget* model) override;
|
void copyClonedWidgetChildren(Widget* model) override;
|
||||||
|
|
||||||
virtual void initScrollBar();
|
virtual void initScrollBar();
|
||||||
virtual void removeScrollBar();
|
virtual void removeScrollBar();
|
||||||
|
@ -622,7 +657,7 @@ protected:
|
||||||
virtual void handleMoveLogic(Touch* touch);
|
virtual void handleMoveLogic(Touch* touch);
|
||||||
virtual void handleReleaseLogic(Touch* touch);
|
virtual void handleReleaseLogic(Touch* touch);
|
||||||
|
|
||||||
virtual void interceptTouchEvent(Widget::TouchEventType event, Widget* sender, Touch* touch) override;
|
void interceptTouchEvent(Widget::TouchEventType event, Widget* sender, Touch* touch) override;
|
||||||
|
|
||||||
void processScrollEvent(MoveDirection dir, bool bounce);
|
void processScrollEvent(MoveDirection dir, bool bounce);
|
||||||
void processScrollingEvent();
|
void processScrollingEvent();
|
||||||
|
@ -631,6 +666,8 @@ protected:
|
||||||
|
|
||||||
void updateScrollBar(const Vec2& outOfBoundary);
|
void updateScrollBar(const Vec2& outOfBoundary);
|
||||||
|
|
||||||
|
Vec2 calculateItemDestination(const Vec2& positionRatioInView, const Node* item, const Vec2& itemAnchorPoint);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual float getAutoScrollStopEpsilon() const;
|
virtual float getAutoScrollStopEpsilon() const;
|
||||||
bool fltEqualZero(const Vec2& point) const;
|
bool fltEqualZero(const Vec2& point) const;
|
||||||
|
@ -678,6 +715,8 @@ protected:
|
||||||
|
|
||||||
Ref* _scrollViewEventListener;
|
Ref* _scrollViewEventListener;
|
||||||
ccScrollViewCallback _eventCallback;
|
ccScrollViewCallback _eventCallback;
|
||||||
|
|
||||||
|
float _scrollTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
|
@ -53,6 +53,7 @@ UIRichTextTests::UIRichTextTests()
|
||||||
ADD_TEST_CASE(UIRichTextNewline);
|
ADD_TEST_CASE(UIRichTextNewline);
|
||||||
ADD_TEST_CASE(UIRichTextHeaders);
|
ADD_TEST_CASE(UIRichTextHeaders);
|
||||||
ADD_TEST_CASE(UIRichTextParagraph);
|
ADD_TEST_CASE(UIRichTextParagraph);
|
||||||
|
ADD_TEST_CASE(UIRichTextScrollTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1053,3 +1054,130 @@ bool UIRichTextParagraph::init()
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UIRichTextScrollTo::init()
|
||||||
|
{
|
||||||
|
if (UIRichTextTestBase::init())
|
||||||
|
{
|
||||||
|
auto& widgetSize = _widget->getContentSize();
|
||||||
|
|
||||||
|
// Add the alert
|
||||||
|
Text* alert = Text::create("Paragraph Tag", "fonts/Marker Felt.ttf", 30);
|
||||||
|
alert->setColor(Color3B(159, 168, 176));
|
||||||
|
alert->setPosition(
|
||||||
|
Vec2(widgetSize.width / 2.0f, widgetSize.height / 2.0f - alert->getContentSize().height * 3.125));
|
||||||
|
_widget->addChild(alert);
|
||||||
|
|
||||||
|
createButtonPanel();
|
||||||
|
|
||||||
|
#ifdef AX_PLATFORM_PC
|
||||||
|
_defaultContentSize = Size(290, 150);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ScrollView
|
||||||
|
_scrollView = ScrollView::create();
|
||||||
|
_scrollView->setContentSize(_defaultContentSize);
|
||||||
|
_scrollView->setInnerContainerSize(_defaultContentSize);
|
||||||
|
_scrollView->setBounceEnabled(true);
|
||||||
|
_scrollView->setDirection(ScrollView::Direction::VERTICAL);
|
||||||
|
_scrollView->setLayoutType(Layout::Type::VERTICAL);
|
||||||
|
_scrollView->setScrollBarEnabled(true);
|
||||||
|
_scrollView->setScrollBarWidth(4);
|
||||||
|
_scrollView->setScrollBarPositionFromCorner(Vec2(2, 2));
|
||||||
|
_scrollView->setScrollBarColor(Color3B::WHITE);
|
||||||
|
_scrollView->setScrollBarAutoHideEnabled(false);
|
||||||
|
_scrollView->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
|
||||||
|
_scrollView->setPosition(_widget->getContentSize() / 2);
|
||||||
|
_scrollView->setLocalZOrder(10);
|
||||||
|
_widget->addChild(_scrollView);
|
||||||
|
|
||||||
|
ValueMap valMap;
|
||||||
|
valMap[RichText::KEY_ANCHOR_FONT_COLOR_STRING] = "#00ffdd";
|
||||||
|
|
||||||
|
// RichText
|
||||||
|
_richText = RichText::createWithXML(
|
||||||
|
R"(<h1>Quick Links</h1>
|
||||||
|
<a href="#fancy_header">Jump To Fancy Header</a><br/>
|
||||||
|
<a href="#paragraph_2">Jump To Second Paragraph</a><br/>
|
||||||
|
<a href="#some_link">Jump To Web Search</a><br/>
|
||||||
|
<br/>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
|
||||||
|
dolore magna aliqua.
|
||||||
|
Purus faucibus ornare suspendisse sed nisi. Viverra aliquet eget sit amet tellus cras adipiscing.
|
||||||
|
Ut tellus elementum sagittis vitae.
|
||||||
|
Risus feugiat in ante metus dictum at. Semper eget duis at tellus at. Iaculis eu non diam phasellus vestibulum
|
||||||
|
lorem sed risus.
|
||||||
|
Sed vulputate odio ut enim. Morbi tristique senectus et netus et malesuada fames.</p>
|
||||||
|
<h1 id="fancy_header">Fancy Header</h1>
|
||||||
|
<p id="paragraph_2">This is the second paragraph! Cras sed felis eget velit aliquet sagittis id consectetur purus.
|
||||||
|
Turpis nunc eget lorem dolor sed viverra ipsum nunc.
|
||||||
|
Ultrices tincidunt arcu non sodales neque sodales ut etiam sit. Risus feugiat in ante metus dictum at tempor.
|
||||||
|
Id neque aliquam vestibulum morbi blandit cursus risus.</p>
|
||||||
|
<p>Tortor condimentum lacinia quis vel eros donec ac. Molestie ac feugiat sed lectus.
|
||||||
|
Aliquam id diam maecenas ultricies mi eget mauris.
|
||||||
|
Ullamcorper malesuada proin libero nunc consequat interdum varius.
|
||||||
|
Sollicitudin nibh sit amet commodo nulla facilisi nullam vehicula ipsum.
|
||||||
|
Diam quam nulla porttitor massa id neque aliquam vestibulum morbi. Sed velit dignissim sodales ut.
|
||||||
|
Morbi leo urna molestie at elementum eu facilisis.
|
||||||
|
Cursus metus aliquam eleifend mi in. Euismod lacinia at quis risus sed vulputate odio.
|
||||||
|
Sit amet mattis vulputate enim nulla aliquet porttitor lacus luctus.</p>
|
||||||
|
<a id="some_link" href="https://google.com">Google!</a>)",
|
||||||
|
valMap);
|
||||||
|
_richText->ignoreContentAdaptWithSize(false);
|
||||||
|
_richText->setContentSize(Size(_defaultContentSize.width, 0));
|
||||||
|
_richText->setAnchorPoint(Vec2::ANCHOR_MIDDLE_TOP);
|
||||||
|
_richText->setOpenUrlHandler([this](std::string_view url) {
|
||||||
|
// Check if the href starts with a "#" character
|
||||||
|
if (url.starts_with('#'))
|
||||||
|
{
|
||||||
|
auto* node = _richText->getProtectedChildByName(url.substr(1));
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
// Scroll to the location of that node, and the reason it works is because
|
||||||
|
// the ScrollView inner container is the same height as the RichText
|
||||||
|
_scrollView->scrollToItem(node, Vec2::ANCHOR_MIDDLE_TOP, Vec2::ANCHOR_MIDDLE_TOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!url.empty())
|
||||||
|
{
|
||||||
|
Application::getInstance()->openURL(url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto contentSize = _scrollView->getInnerContainerSize();
|
||||||
|
_richText->setPosition(Vec2(contentSize.width / 2, contentSize.height));
|
||||||
|
_richText->setLocalZOrder(10);
|
||||||
|
|
||||||
|
_richText->formatText();
|
||||||
|
_scrollView->addChild(_richText);
|
||||||
|
|
||||||
|
updateScrollViewSize();
|
||||||
|
|
||||||
|
// test remove all children, this call won't effect the test
|
||||||
|
_richText->removeAllChildren();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIRichTextScrollTo::updateScrollViewSize()
|
||||||
|
{
|
||||||
|
auto newHeight = 0.f;
|
||||||
|
auto&& children = _scrollView->getChildren();
|
||||||
|
for (auto&& child : children)
|
||||||
|
{
|
||||||
|
auto&& contentSize = child->getContentSize();
|
||||||
|
newHeight += contentSize.height;
|
||||||
|
if (const auto* widget = dynamic_cast<Widget*>(child))
|
||||||
|
{
|
||||||
|
if (const auto* layoutParam = widget->getLayoutParameter())
|
||||||
|
{
|
||||||
|
auto&& margin = layoutParam->getMargin();
|
||||||
|
newHeight += margin.top + margin.bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_scrollView->setInnerContainerSize(Size(_scrollView->getInnerContainerSize().width, newHeight));
|
||||||
|
_scrollView->scrollToTop(0.f, false);
|
||||||
|
}
|
||||||
|
|
|
@ -220,4 +220,17 @@ public:
|
||||||
bool init() override;
|
bool init() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UIRichTextScrollTo : public UIRichTextTestBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CREATE_FUNC(UIRichTextScrollTo);
|
||||||
|
|
||||||
|
bool init() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void updateScrollViewSize();
|
||||||
|
|
||||||
|
ax::ui::ScrollView* _scrollView;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* defined(__TestCpp__UIRichTextTest__) */
|
#endif /* defined(__TestCpp__UIRichTextTest__) */
|
||||||
|
|
Loading…
Reference in New Issue