#include <dali-toolkit/public-api/controls/slider/slider.h>
#include <dali-toolkit/public-api/controls/super-blur-view/super-blur-view.h>
#include <dali-toolkit/public-api/controls/table-view/table-view.h>
+#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
#include <dali-toolkit/public-api/controls/text-controls/text-label.h>
#include <dali-toolkit/public-api/controls/tool-bar/tool-bar.h>
#include <dali-toolkit/public-api/controls/view/view.h>
const Property::Index TextField::PROPERTY_ENABLE_CURSOR_BLINK( Internal::TextField::TEXTFIELD_PROPERTY_START_INDEX + 5 );
const Property::Index TextField::PROPERTY_CURSOR_BLINK_INTERVAL( Internal::TextField::TEXTFIELD_PROPERTY_START_INDEX + 6 );
const Property::Index TextField::PROPERTY_CURSOR_BLINK_DURATION( Internal::TextField::TEXTFIELD_PROPERTY_START_INDEX + 7 );
+const Property::Index TextField::PROPERTY_GRAB_HANDLE_IMAGE( Internal::TextField::TEXTFIELD_PROPERTY_START_INDEX + 8 );
namespace Internal
{
PropertyRegistration property6( mType, "enable-cursor-blink", Toolkit::TextField::PROPERTY_ENABLE_CURSOR_BLINK, Property::BOOLEAN, &TextField::SetProperty, &TextField::GetProperty );
PropertyRegistration property7( mType, "cursor-blink-interval", Toolkit::TextField::PROPERTY_CURSOR_BLINK_INTERVAL, Property::FLOAT, &TextField::SetProperty, &TextField::GetProperty );
PropertyRegistration property8( mType, "cursor-blink-duration", Toolkit::TextField::PROPERTY_CURSOR_BLINK_DURATION, Property::FLOAT, &TextField::SetProperty, &TextField::GetProperty );
+PropertyRegistration property9( mType, "grab-handle-image", Toolkit::TextField::PROPERTY_GRAB_HANDLE_IMAGE, Property::STRING, &TextField::SetProperty, &TextField::GetProperty );
} // namespace
}
break;
}
+ case Toolkit::TextField::PROPERTY_GRAB_HANDLE_IMAGE:
+ {
+ ResourceImage image = ResourceImage::New( value.Get< std::string >() );
+
+ if( impl.mDecorator )
+ {
+ impl.mDecorator->SetGrabHandleImage( image );
+ }
+ break;
+ }
}
}
}
}
break;
}
+ case Toolkit::TextField::PROPERTY_GRAB_HANDLE_IMAGE:
+ {
+ if( impl.mDecorator )
+ {
+ ResourceImage image = ResourceImage::DownCast( impl.mDecorator->GetCursorImage() );
+ if( image )
+ {
+ value = image.GetUrl();
+ }
+ }
+ break;
+ }
}
}
void TextField::OnInitialize()
{
- mDecorator = Text::Decorator::New( *this );
+ mController = Text::Controller::New( *this );
+
+ mDecorator = Text::Decorator::New( *this, *mController );
- mController = Text::Controller::New();
mController->GetLayoutEngine().SetLayout( LayoutEngine::SINGLE_LINE_BOX );
- //mController->EnableTextInput( mDecorator ); TODO
+
+ mController->EnableTextInput( mDecorator );
+
+ // Forward input events to controller
+ EnableGestureDetection( Gesture::Tap );
}
void TextField::OnRelayout( const Vector2& size, ActorSizeContainer& container )
}
}
+void TextField::OnTap( const TapGesture& tap )
+{
+ mController->TapEvent( tap.localPoint.x, tap.localPoint.y );
+}
+
+void TextField::RequestTextRelayout()
+{
+ RelayoutRequest();
+}
+
TextField::TextField()
: Control( ControlBehaviour( CONTROL_BEHAVIOUR_NONE ) )
{
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/public-api/controls/text-controls/text-field.h>
#include <dali-toolkit/public-api/text/decorator/text-decorator.h>
+#include <dali-toolkit/public-api/text/text-control-interface.h>
#include <dali-toolkit/public-api/text/text-controller.h>
namespace Dali
/**
* @brief A control which renders a short text string.
*/
-class TextField : public Control
+class TextField : public Control, public Text::ControlInterface
{
public:
*/
virtual void OnRelayout( const Vector2& size, ActorSizeContainer& container );
-private: // Implementation
+ /**
+ * @copydoc Control::OnTap()
+ */
+ virtual void OnTap( const TapGesture& tap );
/**
- * Helper for SetProperty.
- * @param[in] text The new "text" property value.
+ * @copydoc Text::ControlInterface::RequestTextRelayout()
*/
- void SetText( const std::string& text );
+ virtual void RequestTextRelayout();
+
+private: // Implementation
/**
* Construct a new TextField.
void TextLabel::OnInitialize()
{
- mController = Text::Controller::New();
+ mController = Text::Controller::New( *this );
}
Vector3 TextLabel::GetNaturalSize()
}
}
+void TextLabel::RequestTextRelayout()
+{
+ RelayoutRequest();
+}
+
TextLabel::TextLabel()
: Control( ControlBehaviour( CONTROL_BEHAVIOUR_NONE ) )
{
/**
* @brief A control which renders a short text string.
*/
-class TextLabel : public Control
+class TextLabel : public Control, public Text::ControlInterface
{
public:
*/
virtual float GetHeightForWidth( float width );
+ /**
+ * @copydoc Text::ControlInterface::RequestTextRelayout()
+ */
+ virtual void RequestTextRelayout();
+
private: // Implementation
/**
const std::string TextField::ENABLE_CURSOR_BLINK_PROPERTY_NAME("enable-cursor-blink");
const std::string TextField::CURSOR_BLINK_INTERVAL_PROPERTY_NAME("cursor-blink-interval");
const std::string TextField::CURSOR_BLINK_DURATION_PROPERTY_NAME("cursor-blink-duration");
+const std::string TextField::GRAB_HANDLE_IMAGE_PROPERTY_NAME("grab-handle-image");
TextField TextField::New()
{
static const Property::Index PROPERTY_ENABLE_CURSOR_BLINK; ///< name "enable-cursor-blink", type BOOLEAN
static const Property::Index PROPERTY_CURSOR_BLINK_INTERVAL; ///< name "cursor-blink-interval", type FLOAT
static const Property::Index PROPERTY_CURSOR_BLINK_DURATION; ///< name "cursor-blink-duration", type FLOAT
+ static const Property::Index PROPERTY_GRAB_HANDLE_IMAGE; ///< name "grab-handle-image", type STRING
// Property names
static const std::string PLACEHOLDER_TEXT_PROPERTY_NAME; ///< Property, name "placeholder-text", type STRING
static const std::string ENABLE_CURSOR_BLINK_PROPERTY_NAME; ///< Property, name "enable-cursor-blink", type BOOLEAN
static const std::string CURSOR_BLINK_INTERVAL_PROPERTY_NAME; ///< Property, name "cursor-blink-interval", type FLOAT
static const std::string CURSOR_BLINK_DURATION_PROPERTY_NAME; ///< Property, name "cursor-blink-duration", type FLOAT
+ static const std::string GRAB_HANDLE_IMAGE_PROPERTY_NAME; ///< Property, name "grab-handle-image", type STRING
/**
* Create the TextField control.
$(public_api_src_dir)/text/script.cpp \
$(public_api_src_dir)/text/segmentation.cpp \
$(public_api_src_dir)/text/shaper.cpp \
+ $(public_api_src_dir)/text/text-control-interface.cpp \
$(public_api_src_dir)/text/text-controller.cpp \
$(public_api_src_dir)/text/text-view.cpp \
$(public_api_src_dir)/text/text-view-interface.cpp \
$(public_api_src_dir)/text/script-run.h \
$(public_api_src_dir)/text/segmentation.h \
$(public_api_src_dir)/text/shaper.h \
+ $(public_api_src_dir)/text/text-control-interface.h \
$(public_api_src_dir)/text/text-controller.h \
$(public_api_src_dir)/text/text-definitions.h \
$(public_api_src_dir)/text/text-view.h \
Vector4 color;
};
- Impl(Dali::Toolkit::Internal::Control& parent)
+ Impl(Dali::Toolkit::Internal::Control& parent, Observer& observer)
: mParent(parent),
+ mObserver(observer),
mActiveCursor(ACTIVE_CURSOR_NONE),
mCursorBlinkInterval(0.5f),
mCursorBlinkDuration(0.0f)
}
Internal::Control& mParent;
+ Observer& mObserver;
unsigned int mActiveCursor;
CursorImpl mCursor[CURSOR_COUNT];
Image mCursorImage;
+ Image mGrabHandleImage;
float mCursorBlinkInterval;
float mCursorBlinkDuration;
};
-DecoratorPtr Decorator::New(Internal::Control& parent)
+DecoratorPtr Decorator::New( Internal::Control& parent, Observer& observer )
{
- return DecoratorPtr( new Decorator(parent) );
+ return DecoratorPtr( new Decorator(parent, observer) );
}
void Decorator::Relayout( const Vector2& size )
return mImpl->mCursorBlinkDuration;
}
+void Decorator::SetGrabHandleImage( Dali::Image image )
+{
+ mImpl->mGrabHandleImage = image;
+}
+
+Dali::Image Decorator::GetGrabHandleImage() const
+{
+ return mImpl->mGrabHandleImage;
+}
+
Decorator::~Decorator()
{
delete mImpl;
}
-Decorator::Decorator(Dali::Toolkit::Internal::Control& parent)
+Decorator::Decorator(Dali::Toolkit::Internal::Control& parent, Observer& observer)
: mImpl( NULL )
{
- mImpl = new Decorator::Impl(parent);
+ mImpl = new Decorator::Impl(parent, observer);
}
} // namespace Text
ACTIVE_CURSOR_BOTH ///< Both primary and secondary cursor are active
};
+// The state information for grab handle events
+enum GrabHandleState
+{
+ GRAB_HANDLE_MOVING,
+ GRAB_HANDLE_RELEASED
+};
+
/**
* @brief A Text Decorator is used to display cursors, handles, selection highlights and pop-ups.
*
* The decorator is responsible for clipping decorations which are positioned outside of the parent area.
* In some cases the decorations will be moved or flipped around, to maintain visibility on-screen.
+ *
+ * Decorator components forward input events to a controller class through an observer interface.
+ * The controller is responsible for selecting which components are active.
*/
class Decorator : public RefObject
{
public:
+ class Observer
+ {
+ public:
+
+ /**
+ * @brief Constructor.
+ */
+ Observer() {};
+
+ /**
+ * @brief Virtual destructor.
+ */
+ virtual ~Observer() {};
+
+ /**
+ * @brief An input event from the grab handle.
+ *
+ * @param[in] state The grab handle state.
+ * @param[in] x The x position relative to the top-left of the parent control.
+ */
+ virtual void GrabHandleEvent( GrabHandleState state, float x ) = 0;
+ };
+
/**
* @brief Create a new instance of a Decorator.
*
* @param[in] parent Decorations will be added to this parent control.
+ * @param[in] observer A class which receives input events from Decorator components.
* @return A pointer to a new Decorator.
*/
- static DecoratorPtr New( Dali::Toolkit::Internal::Control& parent );
+ static DecoratorPtr New( Dali::Toolkit::Internal::Control& parent, Observer& observer );
/**
* @brief The decorator waits until a relayout before creating actors etc.
void SetActiveCursor( ActiveCursor activeCursor );
/**
- * @brief Sets whether a cursor should be visible.
+ * @brief Query which of the cursors are active.
*
* @return Which of the cursors are active (if any).
*/
*/
float GetCursorBlinkDuration() const;
+ /**
+ * @brief Sets whether the grab handle is active.
+ *
+ * @note The grab handle follows the cursor position set with SetPosition(Cursor, ...)
+ * @param[in] active True if the grab handle should be active.
+ */
+ void SetGrabHandleActive( bool active );
+
+ /**
+ * @brief Query whether the grab handle is active.
+ *
+ * @return True if the grab handle should be active.
+ */
+ bool IsGrabHandleActive() const;
+
+ /**
+ * @brief Sets the image for the grab handle.
+ *
+ * @param[in] image The image to use.
+ */
+ void SetGrabHandleImage( Dali::Image image );
+
+ /**
+ * @brief Retrieves the image for the grab handle.
+ *
+ * @return The grab handle image.
+ */
+ Dali::Image GetGrabHandleImage() const;
+
protected:
/**
/**
* @brief Private constructor.
* @param[in] parent Decorations will be added to this parent control.
+ * @param[in] observer A class which receives input events from Decorator components.
*/
- Decorator(Dali::Toolkit::Internal::Control& parent);
+ Decorator(Dali::Toolkit::Internal::Control& parent, Observer& observer );
// Undefined
Decorator( const Decorator& handle );
--- /dev/null
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-toolkit/public-api/text/text-control-interface.h>
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+ControlInterface::ControlInterface()
+{
+}
+
+ControlInterface::~ControlInterface()
+{
+}
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
--- /dev/null
+#ifndef __DALI_TOOLKIT_TEXT_CONTROL_INTERFACE_H__
+#define __DALI_TOOLKIT_TEXT_CONTROL_INTERFACE_H__
+
+/*
+ * Copyright (c) 2015 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Text
+{
+
+/**
+ * @brief An interface that the Text::Controller uses to request a text relayout.
+ */
+class ControlInterface
+{
+public:
+
+ /**
+ * @brief Constructor.
+ */
+ ControlInterface();
+
+ /**
+ * @brief Virtual destructor.
+ */
+ virtual ~ControlInterface();
+
+ /**
+ * @brief Called to request a text relayout.
+ */
+ virtual void RequestTextRelayout() = 0;
+};
+
+} // namespace Text
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif // __DALI_TOOLKIT_TEXT_CONTROL_INTERFACE_H__
namespace Text
{
+struct Controller::TextInput
+{
+ // Used to queue input events until DoRelayout()
+ enum EventType
+ {
+ KEYBOARD_FOCUS_GAIN_EVENT,
+ KEYBOARD_FOCUS_LOST_EVENT,
+ TAP_EVENT,
+ GRAB_HANDLE_EVENT
+ };
+
+ union Param
+ {
+ int mInt;
+ float mFloat;
+ };
+
+ struct Event
+ {
+ Event( EventType eventType )
+ : type( eventType )
+ {
+ p1.mInt = 0;
+ p2.mInt = 0;
+ }
+
+ EventType type;
+ Param p1;
+ Param p2;
+ };
+
+ TextInput( DecoratorPtr decorator )
+ : mDecorator( decorator )
+ {
+ }
+
+ DecoratorPtr mDecorator;
+
+ std::vector<Event> mEventQueue;
+};
+
struct Controller::Impl
{
- Impl()
- : mNewText(),
+ Impl( ControlInterface& controlInterface )
+ : mControlInterface( controlInterface ),
+ mNewText(),
mOperations( NO_OPERATION ),
- mControlSize()
+ mControlSize(),
+ mTextInput( NULL )
{
mLogicalModel = LogicalModel::New();
mVisualModel = VisualModel::New();
mFontClient = TextAbstraction::FontClient::Get();
}
+ ~Impl()
+ {
+ delete mTextInput;
+ }
+
+ ControlInterface& mControlInterface;
+
std::string mNewText;
LogicalModelPtr mLogicalModel;
OperationsMask mOperations;
Size mControlSize;
+
+ // Avoid allocating everything for text input until EnableTextInput()
+ Controller::TextInput* mTextInput;
};
-ControllerPtr Controller::New()
+ControllerPtr Controller::New( ControlInterface& controlInterface )
{
- return ControllerPtr( new Controller() );
+ return ControllerPtr( new Controller( controlInterface ) );
}
void Controller::SetText( const std::string& text )
// Keep until size negotiation
mImpl->mNewText = text;
mImpl->mOperations = ALL_OPERATIONS;
+
+ if( mImpl->mTextInput )
+ {
+ // Cancel previously queued events
+ mImpl->mTextInput->mEventQueue.clear();
+
+ // TODO - Hide selection decorations
+ }
+}
+
+void Controller::EnableTextInput( DecoratorPtr decorator )
+{
+ if( !mImpl->mTextInput )
+ {
+ mImpl->mTextInput = new TextInput( decorator );
+ }
}
bool Controller::Relayout( const Vector2& size )
viewUpdated = true;
}
+ // TODO - process input events to move grab handle
+
return viewUpdated;
}
return mImpl->mLayoutEngine;
}
+void Controller::RequestRelayout()
+{
+ mImpl->mControlInterface.RequestTextRelayout();
+}
+
+void Controller::KeyboardFocusGainEvent()
+{
+ DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusGainEvent" );
+
+ if( mImpl->mTextInput )
+ {
+ TextInput::Event event( TextInput::KEYBOARD_FOCUS_GAIN_EVENT );
+ mImpl->mTextInput->mEventQueue.push_back( event );
+
+ RequestRelayout();
+ }
+}
+
+void Controller::KeyboardFocusLostEvent()
+{
+ DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected KeyboardFocusLostEvent" );
+
+ if( mImpl->mTextInput )
+ {
+ TextInput::Event event( TextInput::KEYBOARD_FOCUS_LOST_EVENT );
+ mImpl->mTextInput->mEventQueue.push_back( event );
+
+ RequestRelayout();
+ }
+}
+
+void Controller::TapEvent( float x, float y)
+{
+ DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected TapEvent" );
+
+ if( mImpl->mTextInput )
+ {
+ TextInput::Event event( TextInput::TAP_EVENT );
+ event.p1.mFloat = x;
+ event.p2.mFloat = y;
+
+ RequestRelayout();
+ }
+}
+
+void Controller::GrabHandleEvent( GrabHandleState state, float x )
+{
+ DALI_ASSERT_DEBUG( mImpl->mTextInput && "Unexpected GrabHandleEvent" );
+
+ if( mImpl->mTextInput )
+ {
+ TextInput::Event event( TextInput::GRAB_HANDLE_EVENT );
+ event.p1.mInt = state;
+ event.p2.mFloat = x;
+
+ RequestRelayout();
+ }
+}
+
Controller::~Controller()
{
delete mImpl;
}
-Controller::Controller()
+Controller::Controller( ControlInterface& controlInterface )
: mImpl( NULL )
{
- mImpl = new Controller::Impl();
+ mImpl = new Controller::Impl( controlInterface );
}
} // namespace Text
*/
// INTERNAL INCLUDES
+#include <dali-toolkit/public-api/text/decorator/text-decorator.h>
+#include <dali-toolkit/public-api/text/text-control-interface.h>
#include <dali-toolkit/public-api/text/text-view.h>
// EXTERNAL INCLUDES
class LayoutEngine;
typedef IntrusivePtr<Controller> ControllerPtr;
+typedef Dali::Toolkit::Text::ControlInterface ControlInterface;
/**
* @brief A Text Controller is used by UI Controls which display text.
*
* It manipulates the Logical & Visual text models on behalf of the UI Controls.
* It provides a view of the text that can be used by rendering back-ends.
+ *
+ * For selectable/editable UI controls, the controller handles input events from the UI control
+ * and decorations (grab handles etc) via an observer interface.
*/
-class Controller : public RefObject
+class Controller : public RefObject, public Decorator::Observer
{
private:
/**
* @brief Create a new instance of a Controller.
*
+ * @param[in] controlInterface An interface used to request a text relayout.
* @return A pointer to a new Controller.
*/
- static ControllerPtr New();
+ static ControllerPtr New( ControlInterface& controlInterface );
/**
* @brief Replaces any text previously set.
void SetText( const std::string& text );
/**
+ * @brief Called to enable text input.
+ *
+ * @note Only selectable or editable controls should calls this.
+ * @param[in] decorator Used to create cursor, selection handle decorations etc.
+ */
+ void EnableTextInput( DecoratorPtr decorator );
+
+ /**
* @brief Triggers a relayout which updates View (if necessary).
*
* @note UI Controls are expected to minimize calls to this method e.g. call once after size negotiation.
*/
View& GetView();
+ /**
+ * @brief Caller by editable UI controls when keyboard focus is gained.
+ */
+ void KeyboardFocusGainEvent();
+
+ /**
+ * @brief Caller by editable UI controls when focus is lost.
+ */
+ void KeyboardFocusLostEvent();
+
+ /**
+ * @brief Caller by editable UI controls when focus is lost.
+ */
+ void TapEvent( float x, float y );
+
+ /**
+ * @copydoc Dali::Toolkit::Text::Decorator::Observer::GrabHandleEvent()
+ */
+ virtual void GrabHandleEvent( GrabHandleState state, float x );
+
protected:
/**
private:
/**
- * @brief Private constructor.
+ * @brief Request a relayout using the ControlInterface.
*/
- Controller();
+ void RequestRelayout();
/**
- * @brief Populates the visual model.
+ * @brief Private constructor.
*/
- void UpdateVisualModel();
+ Controller( ControlInterface& controlInterface );
// Undefined
Controller( const Controller& handle );
struct Impl;
Impl* mImpl;
+
+ // Avoid allocating this for non-editable controls
+ struct TextInput;
};
} // namespace Text