/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <dali/public-api/object/property-notification.h>
#include <dali/public-api/rendering/geometry.h>
#include <dali/public-api/rendering/renderer.h>
+#include <dali/public-api/size-negotiation/relayout-container.h>
// INTERNAL INCLUDES
#include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
mHidePrimaryCursorAndGrabHandle(false)
{
mQuadVertexFormat["aPosition"] = Property::VECTOR2;
- mHighlightShader = Shader::New(SHADER_TEXT_DECORATOR_SHADER_VERT, SHADER_TEXT_DECORATOR_SHADER_FRAG);
+ mHighlightShader = Shader::New(SHADER_TEXT_DECORATOR_SHADER_VERT, SHADER_TEXT_DECORATOR_SHADER_FRAG, Shader::Hint::NONE, "TEXT_DECORATOR");
SetupGestures();
}
* Relayout of the decorations owned by the decorator.
* @param[in] size The Size of the UI control the decorator is adding it's decorations to.
*/
- void Relayout(const Vector2& size)
+ void Relayout(const Vector2& size, RelayoutContainer& container)
{
mControlSize = size;
// TODO - Remove this if nothing is active
- CreateActiveLayer();
+ CreateLayer(mActiveLayer, DecorationType::ACTIVE_LAYER);
+ CreateLayer(mCursorLayer, DecorationType::CURSOR_LAYER);
// Show or hide the cursors
CreateCursors();
const CursorImpl& cursor = mCursor[PRIMARY_CURSOR];
mPrimaryCursorVisible = (!mHidePrimaryCursorAndGrabHandle) && ((mControlSize.width - (cursor.position.x + mCursorWidth) > -Math::MACHINE_EPSILON_1000) &&
(cursor.position.x > -Math::MACHINE_EPSILON_1000) &&
- (mControlSize.height - (cursor.position.y + cursor.cursorHeight) > -Math::MACHINE_EPSILON_1000) &&
- (cursor.position.y > -Math::MACHINE_EPSILON_1000));
+ (mControlSize.height - cursor.position.y > -Math::MACHINE_EPSILON_1000) &&
+ (cursor.position.y + cursor.cursorHeight > -Math::MACHINE_EPSILON_1000));
if(mPrimaryCursorVisible)
{
mPrimaryCursor.SetProperty(Actor::Property::POSITION, Vector2(cursor.position.x, cursor.position.y));
mPrimaryCursor.SetProperty(Actor::Property::SIZE, Size(mCursorWidth, cursor.cursorHeight));
+
+ container.Add(mPrimaryCursor, Size(mCursorWidth, cursor.cursorHeight));
}
mPrimaryCursor.SetProperty(Actor::Property::VISIBLE, mPrimaryCursorVisible && mCursorBlinkStatus);
}
const CursorImpl& cursor = mCursor[SECONDARY_CURSOR];
mSecondaryCursorVisible = ((mControlSize.width - (cursor.position.x + mCursorWidth) > -Math::MACHINE_EPSILON_1000) &&
(cursor.position.x > -Math::MACHINE_EPSILON_1000) &&
- (mControlSize.height - (cursor.position.y + cursor.cursorHeight) > -Math::MACHINE_EPSILON_1000) &&
- (cursor.position.y > -Math::MACHINE_EPSILON_1000));
+ (mControlSize.height - cursor.position.y > -Math::MACHINE_EPSILON_1000) &&
+ (cursor.position.y + cursor.cursorHeight > -Math::MACHINE_EPSILON_1000));
if(mSecondaryCursorVisible)
{
mSecondaryCursor.SetProperty(Actor::Property::POSITION, Vector2(cursor.position.x, cursor.position.y));
mSecondaryCursor.SetProperty(Actor::Property::SIZE, Size(mCursorWidth, cursor.cursorHeight));
+
+ container.Add(mSecondaryCursor, Size(mCursorWidth, cursor.cursorHeight));
}
mSecondaryCursor.SetProperty(Actor::Property::VISIBLE, mSecondaryCursorVisible && mCursorBlinkStatus);
}
{
grabHandle.horizontallyVisible = ((mControlSize.width - (grabHandle.position.x + floor(0.5f * mCursorWidth)) > -Math::MACHINE_EPSILON_1000) &&
(grabHandle.position.x > -Math::MACHINE_EPSILON_1000));
- grabHandle.verticallyVisible = (((mControlSize.height - grabHandle.lineHeight) - grabHandle.position.y > -Math::MACHINE_EPSILON_1000) &&
- (grabHandle.position.y > -Math::MACHINE_EPSILON_1000));
+ grabHandle.verticallyVisible = ((fabsf(mControlSize.height - grabHandle.lineHeight) - grabHandle.position.y > -Math::MACHINE_EPSILON_1000) &&
+ (grabHandle.position.y + grabHandle.lineHeight > -Math::MACHINE_EPSILON_1000));
const bool isVisible = grabHandle.horizontallyVisible && grabHandle.verticallyVisible && (!mHidePrimaryCursorAndGrabHandle);
if(isVisible)
primary.horizontallyVisible = ((mControlSize.width - primary.position.x > -Math::MACHINE_EPSILON_1000) &&
(primary.position.x > -Math::MACHINE_EPSILON_1000));
- primary.verticallyVisible = (((mControlSize.height - primary.lineHeight) - primary.position.y > -Math::MACHINE_EPSILON_1000) &&
+ primary.verticallyVisible = ((fabsf(mControlSize.height - primary.lineHeight) - primary.position.y > -Math::MACHINE_EPSILON_1000) &&
(primary.position.y + (primary.verticallyFlipped ? 0.f : primary.lineHeight) > -Math::MACHINE_EPSILON_1000));
secondary.horizontallyVisible = ((mControlSize.width - secondary.position.x > -Math::MACHINE_EPSILON_1000) &&
(secondary.position.x > -Math::MACHINE_EPSILON_1000));
- secondary.verticallyVisible = (((mControlSize.height - secondary.lineHeight) - secondary.position.y > -Math::MACHINE_EPSILON_1000) &&
+ secondary.verticallyVisible = ((fabsf(mControlSize.height - secondary.lineHeight) - secondary.position.y > -Math::MACHINE_EPSILON_1000) &&
(secondary.position.y + (secondary.verticallyFlipped ? 0.f : secondary.lineHeight) > -Math::MACHINE_EPSILON_1000));
const bool primaryVisible = primary.horizontallyVisible && primary.verticallyVisible;
if(!mPrimaryCursor.GetParent())
{
- mActiveLayer.Add(mPrimaryCursor);
+ mCursorLayer.Add(mPrimaryCursor);
}
}
if(!mSecondaryCursor.GetParent())
{
- mActiveLayer.Add(mSecondaryCursor);
+ mCursorLayer.Add(mSecondaryCursor);
}
}
else
mPanDetector.DetectedSignal().Connect(this, &Decorator::Impl::OnPan);
}
- void CreateActiveLayer()
+ void CreateLayer(Actor& layer, DecorationType type)
{
- if(!mActiveLayer)
+ if(!layer)
{
- mActiveLayer = Actor::New();
+ layer = Actor::New();
#ifdef DECORATOR_DEBUG
- mActiveLayer.SetProperty(Actor::Property::NAME, "ActiveLayerActor");
+ if(type == DecorationType::ACTIVE_LAYER)
+ {
+ layer.SetProperty(Actor::Property::NAME, "ActiveLayerActor");
+ }
+ else if(type == DecorationType::CURSOR_LAYER)
+ {
+ layer.SetProperty(Actor::Property::NAME, "CursorLayerActor");
+ }
#endif
+ bool needsClipping = false;
+ if(type == DecorationType::CURSOR_LAYER)
+ {
+ needsClipping = true;
+ }
- mActiveLayer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
- mActiveLayer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+ layer.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ layer.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
- // Add the active layer telling the controller it doesn't need clipping.
- mController.AddDecoration(mActiveLayer, false);
+ mController.AddDecoration(layer, type, needsClipping);
}
- mActiveLayer.RaiseToTop();
+ layer.RaiseToTop();
}
void SetSelectionHandleMarkerSize(HandleImpl& handle)
grabHandle.actor = ImageView::New(mHandleImages[GRAB_HANDLE][HANDLE_IMAGE_RELEASED]);
GetImpl(grabHandle.actor).SetDepthIndex(DepthIndex::DECORATION);
grabHandle.actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
+ grabHandle.actor.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
// Area that Grab handle responds to, larger than actual handle so easier to move
#ifdef DECORATOR_DEBUG
primary.actor.SetProperty(Dali::Actor::Property::NAME, "SelectionHandleOne");
#endif
primary.actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_RIGHT); // Change to BOTTOM_RIGHT if Look'n'Feel requires handle above text.
+ primary.actor.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
GetImpl(primary.actor).SetDepthIndex(DepthIndex::DECORATION);
primary.actor.SetProperty(Actor::Property::COLOR, mHandleColor);
secondary.actor.SetProperty(Dali::Actor::Property::NAME, "SelectionHandleTwo");
#endif
secondary.actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); // Change to BOTTOM_LEFT if Look'n'Feel requires handle above text.
+ secondary.actor.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
GetImpl(secondary.actor).SetDepthIndex(DepthIndex::DECORATION);
secondary.actor.SetProperty(Actor::Property::COLOR, mHandleColor);
}
}
+ void CreateSelectionPopup()
+ {
+ if(!mCopyPastePopup.actor)
+ {
+ mCopyPastePopup.actor = TextSelectionPopup::New(&mTextSelectionPopupCallbackInterface);
+#ifdef DECORATOR_DEBUG
+ mCopyPastePopup.actor.SetProperty(Dali::Actor::Property::NAME, "mCopyPastePopup");
+#endif
+ mCopyPastePopup.actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ mCopyPastePopup.actor.SetProperty(Actor::Property::DRAW_MODE, DrawMode::OVERLAY_2D);
+ mCopyPastePopup.actor.OnRelayoutSignal().Connect(this, &Decorator::Impl::SetPopupPosition); // Position popup after size negotiation
+ }
+ }
+
void CalculateHandleWorldCoordinates(HandleImpl& handle, Vector2& position)
{
// Gets the world position of the active layer. The active layer is where the handles are added.
void ApplyDisplacement(HandleImpl& handle, float yLocalPosition)
{
- if( handle.actor )
+ if(handle.actor)
{
float adjustedDisplacementX = 0.0f;
float adjustedDisplacementY = 0.0f;
- if (mSmoothHandlePanEnabled)
+ if(mSmoothHandlePanEnabled)
{
adjustedDisplacementX = CalculateAdjustedDisplacement(handle.position.x, handle.grabDisplacementX, mControlSize.x);
adjustedDisplacementY = CalculateAdjustedDisplacement(handle.position.y, handle.grabDisplacementY, (mControlSize.y - handle.lineHeight));
}
// Add the highlight box telling the controller it needs clipping.
- mController.AddDecoration(mHighlightActor, true);
+ mController.AddDecoration(mHighlightActor, DecorationType::NONE_LAYER, true);
}
void UpdateHighlight()
Timer mScrollTimer; ///< Timer used to scroll the text when the grab handle is moved close to the edges.
Actor mActiveLayer; ///< Actor for active handles and alike that ensures they are above all else.
+ Actor mCursorLayer; ///< Actor for cursor layer. this is for cursor clipping.
PropertyNotification mHandleVerticalLessThanNotification; ///< Notifies when the 'y' coord of the active layer is less than a given value.
PropertyNotification mHandleVerticalGreaterThanNotification; ///< Notifies when the 'y' coord of the active layer is grater than a given value.
PropertyNotification mHandleHorizontalLessThanNotification; ///< Notifies when the 'x' coord of the active layer is less than a given value.
WorldToLocalCoordinatesBoundingBox(mImpl->mBoundingBox, boundingBox);
}
-void Decorator::Relayout(const Vector2& size)
+void Decorator::Relayout(const Vector2& size, RelayoutContainer& container)
{
- mImpl->Relayout(size);
+ mImpl->Relayout(size, container);
}
void Decorator::UpdatePositions(const Vector2& scrollOffset)
void Decorator::SetCursorColor(Cursor cursor, const Dali::Vector4& color)
{
mImpl->mCursor[cursor].color = color;
+
+ if(cursor == PRIMARY_CURSOR && mImpl->mPrimaryCursor)
+ {
+ mImpl->mPrimaryCursor.SetBackgroundColor(color);
+ }
+ else if(cursor == SECONDARY_CURSOR && mImpl->mSecondaryCursor)
+ {
+ mImpl->mSecondaryCursor.SetBackgroundColor(color);
+ }
}
const Dali::Vector4& Decorator::GetColor(Cursor cursor) const
void Decorator::SetCursorWidth(int width)
{
mImpl->mCursorWidth = static_cast<float>(width);
+
+ if(mImpl->mPrimaryCursorVisible && mImpl->mPrimaryCursor)
+ {
+ mImpl->mPrimaryCursor.SetProperty(Actor::Property::SIZE, Size(mImpl->mCursorWidth, mImpl->mCursor[PRIMARY_CURSOR].cursorHeight));
+ }
+ if(mImpl->mSecondaryCursorVisible && mImpl->mSecondaryCursor)
+ {
+ mImpl->mSecondaryCursor.SetProperty(Actor::Property::SIZE, Size(mImpl->mCursorWidth, mImpl->mCursor[SECONDARY_CURSOR].cursorHeight));
+ }
}
int Decorator::GetCursorWidth() const
void Decorator::SetEditable(bool editable)
{
mImpl->mHidePrimaryCursorAndGrabHandle = !editable;
- mImpl->Relayout(mImpl->mControlSize);
+ // If editable is false, all decorators should be disabled.
+ if(!editable)
+ {
+ if(IsHighlightActive())
+ {
+ SetHighlightActive(false);
+ }
+ if(IsHandleActive(LEFT_SELECTION_HANDLE))
+ {
+ SetHandleActive(LEFT_SELECTION_HANDLE, false);
+ }
+ if(IsHandleActive(RIGHT_SELECTION_HANDLE))
+ {
+ SetHandleActive(RIGHT_SELECTION_HANDLE, false);
+ }
+ if(IsPopupActive())
+ {
+ SetPopupActive(false);
+ }
+ }
}
/** Handles **/
void Decorator::SetHandleColor(const Vector4& color)
{
mImpl->mHandleColor = color;
+
+ Impl::HandleImpl& grabHandle = mImpl->mHandle[GRAB_HANDLE];
+ Impl::HandleImpl& primaryHandle = mImpl->mHandle[LEFT_SELECTION_HANDLE];
+ Impl::HandleImpl& secondaryHandle = mImpl->mHandle[RIGHT_SELECTION_HANDLE];
+
+ if(grabHandle.actor)
+ {
+ grabHandle.actor.SetProperty(Actor::Property::COLOR, color);
+ }
+ if(primaryHandle.actor)
+ {
+ primaryHandle.actor.SetProperty(Actor::Property::COLOR, color);
+ }
+ if(secondaryHandle.actor)
+ {
+ secondaryHandle.actor.SetProperty(Actor::Property::COLOR, color);
+ }
}
const Vector4& Decorator::GetHandleColor() const
void Decorator::SetHighlightColor(const Vector4& color)
{
mImpl->mHighlightColor = color;
+
+ if(mImpl->mHighlightActor)
+ {
+ mImpl->mHighlightActor.SetProperty(Actor::Property::COLOR, color);
+ }
}
const Vector4& Decorator::GetHighlightColor() const
void Decorator::SetEnabledPopupButtons(TextSelectionPopup::Buttons& enabledButtonsBitMask)
{
mImpl->mEnabledPopupButtons = enabledButtonsBitMask;
-
- if(!mImpl->mCopyPastePopup.actor)
- {
- mImpl->mCopyPastePopup.actor = TextSelectionPopup::New(&mImpl->mTextSelectionPopupCallbackInterface);
-#ifdef DECORATOR_DEBUG
- mImpl->mCopyPastePopup.actor.SetProperty(Dali::Actor::Property::NAME, "mCopyPastePopup");
-#endif
- mImpl->mCopyPastePopup.actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
- mImpl->mCopyPastePopup.actor.OnRelayoutSignal().Connect(mImpl, &Decorator::Impl::SetPopupPosition); // Position popup after size negotiation
- }
-
+ mImpl->CreateSelectionPopup();
mImpl->mCopyPastePopup.actor.EnableButtons(mImpl->mEnabledPopupButtons);
}
return mImpl->mEnabledPopupButtons;
}
+void Decorator::SetSelectionPopupStyle(const Property::Map& options)
+{
+ mImpl->CreateSelectionPopup();
+ mImpl->mCopyPastePopup.actor.SetProperties(options);
+}
+
+void Decorator::GetSelectionPopupStyle(Property::Map& options)
+{
+ if(mImpl->mCopyPastePopup.actor)
+ {
+ mImpl->mCopyPastePopup.actor.GetProperties(options);
+ }
+}
+
/** Scroll **/
void Decorator::SetScrollThreshold(float threshold)