From: Adeel Kazmi Date: Mon, 5 Oct 2020 10:41:15 +0000 (+0100) Subject: (Text Controller) Moved event handling, InputFont & Placeholder related methods into... X-Git-Tag: dali_1.9.34~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=d48e9b8b161367ad699c0352dfeb0128832bbe59;hp=27e7fb1ad1e36527c7af8b739ec49ac19b4ff309 (Text Controller) Moved event handling, InputFont & Placeholder related methods into separate structs Change-Id: If7b2eb2bde0bbb9a9bf04bd37d1d679c7038f5e0 --- diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index f35ae3f..0d6b781 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -140,7 +140,10 @@ SET( toolkit_src_files ${toolkit_src_dir}/text/shaper.cpp ${toolkit_src_dir}/text/text-enumerations-impl.cpp ${toolkit_src_dir}/text/text-controller.cpp + ${toolkit_src_dir}/text/text-controller-event-handler.cpp ${toolkit_src_dir}/text/text-controller-impl.cpp + ${toolkit_src_dir}/text/text-controller-input-font-handler.cpp + ${toolkit_src_dir}/text/text-controller-placeholder-handler.cpp ${toolkit_src_dir}/text/text-effects-style.cpp ${toolkit_src_dir}/text/text-font-style.cpp ${toolkit_src_dir}/text/text-io.cpp diff --git a/dali-toolkit/internal/text/text-controller-event-handler.cpp b/dali-toolkit/internal/text/text-controller-event-handler.cpp new file mode 100644 index 0000000..b9b260b --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-event-handler.cpp @@ -0,0 +1,908 @@ +/* + * Copyright (c) 2020 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 + +// EXTERNAL INCLUDES +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace +{ + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +#endif + +const std::string KEY_C_NAME = "c"; +const std::string KEY_V_NAME = "v"; +const std::string KEY_X_NAME = "x"; +const std::string KEY_A_NAME = "a"; +const std::string KEY_INSERT_NAME = "Insert"; + +} // namespace + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +void Controller::EventHandler::KeyboardFocusGainEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + if( ( EventData::INACTIVE == controller.mImpl->mEventData->mState ) || + ( EventData::INTERRUPTED == controller.mImpl->mEventData->mState ) ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + controller.mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered. + controller.mImpl->mEventData->mUpdateInputStyle = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + controller.mImpl->NotifyInputMethodContextMultiLineStatus(); + if( controller.mImpl->IsShowingPlaceholderText() ) + { + // Show alternative placeholder-text when editing + controller.ShowPlaceholderText(); + } + + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::KeyboardFocusLostEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + if( EventData::INTERRUPTED != controller.mImpl->mEventData->mState ) + { + controller.mImpl->ChangeState( EventData::INACTIVE ); + + if( !controller.mImpl->IsShowingRealText() ) + { + // Revert to regular placeholder-text when not editing + controller.ShowPlaceholderText(); + } + } + } + controller.mImpl->RequestRelayout(); +} + +bool Controller::EventHandler::KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected KeyEvent" ); + + bool textChanged = false; + bool relayoutNeeded = false; + + if( ( NULL != controller.mImpl->mEventData ) && + ( keyEvent.GetState() == KeyEvent::DOWN ) ) + { + int keyCode = keyEvent.GetKeyCode(); + const std::string& keyString = keyEvent.GetKeyString(); + const std::string keyName = keyEvent.GetKeyName(); + + const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() ); + + // Pre-process to separate modifying events from non-modifying input events. + if( isNullKey ) + { + // In some platforms arrive key events with no key code. + // Do nothing. + return false; + } + else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode ) + { + // Do nothing + return false; + } + else if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode ) || + ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) || + ( Dali::DALI_KEY_CURSOR_UP == keyCode ) || + ( Dali::DALI_KEY_CURSOR_DOWN == keyCode ) ) + { + // If don't have any text, do nothing. + if( !controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) + { + return false; + } + + uint32_t cursorPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + uint32_t numberOfCharacters = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + uint32_t cursorLine = controller.mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition ); + uint32_t numberOfLines = controller.mImpl->mModel->GetNumberOfLines(); + + // Logic to determine whether this text control will lose focus or not. + if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) || + ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) || + ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) || + ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) || + ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) || + ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) ) + { + // Release the active highlight. + if( controller.mImpl->mEventData->mState == EventData::SELECTING ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + + // Update selection position. + controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->RequestRelayout(); + } + return false; + } + + controller.mImpl->mEventData->mCheckScrollAmount = true; + Event event( Event::CURSOR_KEY_EVENT ); + event.p1.mInt = keyCode; + event.p2.mBool = keyEvent.IsShiftModifier(); + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + // Will request for relayout. + relayoutNeeded = true; + } + else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode ) + { + // Left or Right Control key event is received before Ctrl-C/V/X key event is received + // If not handle it here, any selected text will be deleted + + // Do nothing + return false; + } + else if ( keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier()) + { + bool consumed = false; + if (keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME) + { + // Ctrl-C or Ctrl+Insert to copy the selected text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY ); + consumed = true; + } + else if (keyName == KEY_V_NAME) + { + // Ctrl-V to paste the copied text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE ); + consumed = true; + } + else if (keyName == KEY_X_NAME) + { + // Ctrl-X to cut the selected text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT ); + consumed = true; + } + else if (keyName == KEY_A_NAME) + { + // Ctrl-A to select All the text + controller.TextPopupButtonTouched( Toolkit::TextSelectionPopup::SELECT_ALL ); + consumed = true; + } + return consumed; + } + else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) || + ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) ) + { + textChanged = controller.DeleteEvent( keyCode ); + + // Will request for relayout. + relayoutNeeded = true; + } + else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) || + IsKey( keyEvent, Dali::DALI_KEY_MENU ) || + IsKey( keyEvent, Dali::DALI_KEY_HOME ) ) + { + // Power key/Menu/Home key behaviour does not allow edit mode to resume. + controller.mImpl->ChangeState( EventData::INACTIVE ); + + // Will request for relayout. + relayoutNeeded = true; + + // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. + } + else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) ) + { + // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled + // and a character is typed after the type of a upper case latin character. + + // Do nothing. + return false; + } + else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) ) + { + // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. + // Do nothing. + return false; + } + else + { + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", &controller, keyString.c_str() ); + if (!controller.IsEditable()) return false; + + if( !keyString.empty() ) + { + // InputMethodContext is no longer handling key-events + controller.mImpl->ClearPreEditFlag(); + + controller.InsertText( keyString, COMMIT ); + + textChanged = true; + + // Will request for relayout. + relayoutNeeded = true; + } + + } + + if ( ( controller.mImpl->mEventData->mState != EventData::INTERRUPTED ) && + ( controller.mImpl->mEventData->mState != EventData::INACTIVE ) && + ( !isNullKey ) && + ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) && + ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) && + ( Dali::DALI_KEY_VOLUME_UP != keyCode ) && + ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) ) + { + // Should not change the state if the key is the shift send by the InputMethodContext. + // Otherwise, when the state is SELECTING the text controller can't send the right + // surrounding info to the InputMethodContext. + controller.mImpl->ChangeState( EventData::EDITING ); + + // Will request for relayout. + relayoutNeeded = true; + } + + if( relayoutNeeded ) + { + controller.mImpl->RequestRelayout(); + } + } + + if( textChanged && + ( NULL != controller.mImpl->mEditableControlInterface ) ) + { + // Do this last since it provides callbacks into application code + controller.mImpl->mEditableControlInterface->TextChanged(); + } + + return true; +} + +void Controller::EventHandler::TapEvent(Controller& controller, unsigned int tapCount, float x, float y) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected TapEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", controller.mImpl->mEventData->mState ); + EventData::State state( controller.mImpl->mEventData->mState ); + bool relayoutNeeded( false ); // to avoid unnecessary relayouts when tapping an empty text-field + + if( controller.mImpl->IsClipboardVisible() ) + { + if( EventData::INACTIVE == state || EventData::EDITING == state) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); + } + relayoutNeeded = true; + } + else if( 1u == tapCount ) + { + if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state ) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); // If Popup shown hide it here so can be shown again if required. + } + + if( controller.mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) ) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); + relayoutNeeded = true; + } + else + { + if( controller.mImpl->IsShowingPlaceholderText() && !controller.mImpl->IsFocusedPlaceholderAvailable() ) + { + // Hide placeholder text + controller.ResetText(); + } + + if( EventData::INACTIVE == state ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + } + else if( !controller.mImpl->IsClipboardEmpty() ) + { + controller.mImpl->ChangeState( EventData::EDITING_WITH_POPUP ); + } + relayoutNeeded = true; + } + } + else if( 2u == tapCount ) + { + if( controller.mImpl->mEventData->mSelectionEnabled && + controller.mImpl->IsShowingRealText() ) + { + relayoutNeeded = true; + controller.mImpl->mEventData->mIsLeftHandleSelected = true; + controller.mImpl->mEventData->mIsRightHandleSelected = true; + } + } + + // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated + if( relayoutNeeded ) + { + Event event( Event::TAP_EVENT ); + event.p1.mUint = tapCount; + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + controller.mImpl->RequestRelayout(); + } + } + + // Reset keyboard as tap event has occurred. + controller.mImpl->ResetInputMethodContext(); +} + +void Controller::EventHandler::PanEvent(Controller& controller, GestureState state, const Vector2& displacement) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected PanEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + Event event( Event::PAN_EVENT ); + event.p1.mInt = static_cast( state ); + event.p2.mFloat = displacement.x; + event.p3.mFloat = displacement.y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::LongPressEvent(Controller& controller, GestureState state, float x, float y) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected LongPressEvent" ); + + if( ( state == GestureState::STARTED ) && + ( NULL != controller.mImpl->mEventData ) ) + { + // The 1st long-press on inactive text-field is treated as tap + if( EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + controller.mImpl->ChangeState( EventData::EDITING ); + + Event event( Event::TAP_EVENT ); + event.p1.mUint = 1; + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + + controller.mImpl->RequestRelayout(); + } + else if( !controller.mImpl->IsShowingRealText() ) + { + Event event( Event::LONG_PRESS_EVENT ); + event.p1.mInt = static_cast( state ); + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + controller.mImpl->RequestRelayout(); + } + else if( !controller.mImpl->IsClipboardVisible() ) + { + // Reset the InputMethodContext to commit the pre-edit before selecting the text. + controller.mImpl->ResetInputMethodContext(); + + Event event( Event::LONG_PRESS_EVENT ); + event.p1.mInt = static_cast( state ); + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + controller.mImpl->RequestRelayout(); + + controller.mImpl->mEventData->mIsLeftHandleSelected = true; + controller.mImpl->mEventData->mIsRightHandleSelected = true; + } + } +} + +void Controller::EventHandler::SelectEvent(Controller& controller, float x, float y, SelectionType selectType) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" ); + + if( NULL != controller.mImpl->mEventData ) + { + if( selectType == SelectionType::ALL ) + { + Event event( Event::SELECT_ALL ); + controller.mImpl->mEventData->mEventQueue.push_back( event ); + } + else if( selectType == SelectionType::NONE ) + { + Event event( Event::SELECT_NONE ); + controller.mImpl->mEventData->mEventQueue.push_back( event ); + } + else + { + Event event( Event::SELECT ); + event.p2.mFloat = x; + event.p3.mFloat = y; + controller.mImpl->mEventData->mEventQueue.push_back( event ); + } + + controller.mImpl->mEventData->mCheckScrollAmount = true; + controller.mImpl->mEventData->mIsLeftHandleSelected = true; + controller.mImpl->mEventData->mIsRightHandleSelected = true; + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::ProcessModifyEvents(Controller& controller) +{ + Vector& events = controller.mImpl->mModifyEvents; + + if( 0u == events.Count() ) + { + // Nothing to do. + return; + } + + for( Vector::ConstIterator it = events.Begin(), + endIt = events.End(); + it != endIt; + ++it ) + { + const ModifyEvent& event = *it; + + if( ModifyEvent::TEXT_REPLACED == event.type ) + { + // A (single) replace event should come first, otherwise we wasted time processing NOOP events + DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" ); + + controller.TextReplacedEvent(); + } + else if( ModifyEvent::TEXT_INSERTED == event.type ) + { + controller.TextInsertedEvent(); + } + else if( ModifyEvent::TEXT_DELETED == event.type ) + { + // Placeholder-text cannot be deleted + if( !controller.mImpl->IsShowingPlaceholderText() ) + { + controller.TextDeletedEvent(); + } + } + } + + if( NULL != controller.mImpl->mEventData ) + { + // When the text is being modified, delay cursor blinking + controller.mImpl->mEventData->mDecorator->DelayCursorBlink(); + + // Update selection position after modifying the text + controller.mImpl->mEventData->mLeftSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + controller.mImpl->mEventData->mRightSelectionPosition = controller.mImpl->mEventData->mPrimaryCursorPosition; + } + + // DISCARD temporary text + events.Clear(); +} + +void Controller::EventHandler::TextReplacedEvent(Controller& controller) +{ + // The natural size needs to be re-calculated. + controller.mImpl->mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + controller.mImpl->mUpdateTextDirection = true; + + // Apply modifications to the model + controller.mImpl->mOperationsPending = ALL_OPERATIONS; +} + +void Controller::EventHandler::TextInsertedEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( NULL != controller.mImpl->mEventData && "Unexpected TextInsertedEvent" ); + + if( NULL == controller.mImpl->mEventData ) + { + return; + } + + controller.mImpl->mEventData->mCheckScrollAmount = true; + + // The natural size needs to be re-calculated. + controller.mImpl->mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + controller.mImpl->mUpdateTextDirection = true; + + // Apply modifications to the model; TODO - Optimize this + controller.mImpl->mOperationsPending = ALL_OPERATIONS; +} + +void Controller::EventHandler::TextDeletedEvent(Controller& controller) +{ + DALI_ASSERT_DEBUG( NULL != controller.mImpl->mEventData && "Unexpected TextDeletedEvent" ); + + if( NULL == controller.mImpl->mEventData ) + { + return; + } + + if (!controller.IsEditable()) return; + + controller.mImpl->mEventData->mCheckScrollAmount = true; + + // The natural size needs to be re-calculated. + controller.mImpl->mRecalculateNaturalSize = true; + + // The text direction needs to be updated. + controller.mImpl->mUpdateTextDirection = true; + + // Apply modifications to the model; TODO - Optimize this + controller.mImpl->mOperationsPending = ALL_OPERATIONS; +} + +bool Controller::EventHandler::DeleteEvent(Controller& controller, int keyCode) +{ + DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", &controller, keyCode ); + + bool removed = false; + + if( NULL == controller.mImpl->mEventData ) + { + return removed; + } + + if (!controller.IsEditable()) return false; + + // InputMethodContext is no longer handling key-events + controller.mImpl->ClearPreEditFlag(); + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + removed = controller.RemoveSelectedText(); + } + else if( ( controller.mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) ) + { + // Remove the character before the current cursor position + removed = controller.RemoveText( -1, + 1, + UPDATE_INPUT_STYLE ); + } + else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE ) + { + // Remove the character after the current cursor position + removed = controller.RemoveText( 0, + 1, + UPDATE_INPUT_STYLE ); + } + + if( removed ) + { + if( ( 0u != controller.mImpl->mModel->mLogicalModel->mText.Count() ) || + !controller.mImpl->IsPlaceholderAvailable() ) + { + controller.mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); + } + else + { + controller.ShowPlaceholderText(); + } + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->mEventData->mScrollAfterDelete = true; + } + + return removed; +} + +InputMethodContext::CallbackData Controller::EventHandler::OnInputMethodContextEvent(Controller& controller, InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent) +{ + // Whether the text needs to be relaid-out. + bool requestRelayout = false; + + // Whether to retrieve the text and cursor position to be sent to the InputMethodContext. + bool retrieveText = false; + bool retrieveCursor = false; + + switch( inputMethodContextEvent.eventName ) + { + case InputMethodContext::COMMIT: + { + controller.InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT ); + requestRelayout = true; + retrieveCursor = true; + break; + } + case InputMethodContext::PRE_EDIT: + { + controller.InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT ); + requestRelayout = true; + retrieveCursor = true; + break; + } + case InputMethodContext::DELETE_SURROUNDING: + { + const bool textDeleted = controller.RemoveText( inputMethodContextEvent.cursorOffset, + inputMethodContextEvent.numberOfChars, + DONT_UPDATE_INPUT_STYLE ); + + if( textDeleted ) + { + if( ( 0u != controller.mImpl->mModel->mLogicalModel->mText.Count() ) || + !controller.mImpl->IsPlaceholderAvailable() ) + { + controller.mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); + } + else + { + controller.ShowPlaceholderText(); + } + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->mEventData->mScrollAfterDelete = true; + + requestRelayout = true; + } + break; + } + case InputMethodContext::GET_SURROUNDING: + { + retrieveText = true; + retrieveCursor = true; + break; + } + case InputMethodContext::PRIVATE_COMMAND: + { + // PRIVATECOMMAND event is just for getting the private command message + retrieveText = true; + retrieveCursor = true; + break; + } + case InputMethodContext::VOID: + { + // do nothing + break; + } + } // end switch + + if( requestRelayout ) + { + controller.mImpl->mOperationsPending = ALL_OPERATIONS; + controller.mImpl->RequestRelayout(); + } + + std::string text; + CharacterIndex cursorPosition = 0u; + Length numberOfWhiteSpaces = 0u; + + if( retrieveCursor ) + { + numberOfWhiteSpaces = controller.mImpl->GetNumberOfWhiteSpaces( 0u ); + + cursorPosition = controller.mImpl->GetLogicalCursorPosition(); + + if( cursorPosition < numberOfWhiteSpaces ) + { + cursorPosition = 0u; + } + else + { + cursorPosition -= numberOfWhiteSpaces; + } + } + + if( retrieveText ) + { + if( !controller.mImpl->IsShowingPlaceholderText() ) + { + // Retrieves the normal text string. + controller.mImpl->GetText( numberOfWhiteSpaces, text ); + } + else + { + // When the current text is Placeholder Text, the surrounding text should be empty string. + // It means DALi should send empty string ("") to IME. + text = ""; + } + } + + InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); + + if( requestRelayout && + ( NULL != controller.mImpl->mEditableControlInterface ) ) + { + // Do this last since it provides callbacks into application code + controller.mImpl->mEditableControlInterface->TextChanged(); + } + + return callbackData; +} + +void Controller::EventHandler::PasteClipboardItemEvent(Controller& controller) +{ + // Retrieve the clipboard contents first + ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); + std::string stringToPaste( notifier.GetContent() ); + + // Commit the current pre-edit text; the contents of the clipboard should be appended + controller.mImpl->ResetInputMethodContext(); + + // Temporary disable hiding clipboard + controller.mImpl->SetClipboardHideEnable( false ); + + // Paste + controller.PasteText( stringToPaste ); + + controller.mImpl->SetClipboardHideEnable( true ); +} + +void Controller::EventHandler::DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y) +{ + DALI_ASSERT_DEBUG( controller.mImpl->mEventData && "Unexpected DecorationEvent" ); + + if( NULL != controller.mImpl->mEventData ) + { + switch( handleType ) + { + case GRAB_HANDLE: + { + Event event( Event::GRAB_HANDLE_EVENT ); + event.p1.mUint = state; + event.p2.mFloat = x; + event.p3.mFloat = y; + + controller.mImpl->mEventData->mEventQueue.push_back( event ); + break; + } + case LEFT_SELECTION_HANDLE: + { + Event event( Event::LEFT_SELECTION_HANDLE_EVENT ); + event.p1.mUint = state; + event.p2.mFloat = x; + event.p3.mFloat = y; + + controller.mImpl->mEventData->mEventQueue.push_back( event ); + break; + } + case RIGHT_SELECTION_HANDLE: + { + Event event( Event::RIGHT_SELECTION_HANDLE_EVENT ); + event.p1.mUint = state; + event.p2.mFloat = x; + event.p3.mFloat = y; + + controller.mImpl->mEventData->mEventQueue.push_back( event ); + break; + } + case LEFT_SELECTION_HANDLE_MARKER: + case RIGHT_SELECTION_HANDLE_MARKER: + { + // Markers do not move the handles. + break; + } + case HANDLE_TYPE_COUNT: + { + DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" ); + } + } + + controller.mImpl->RequestRelayout(); + } +} + +void Controller::EventHandler::TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button) +{ + if( NULL == controller.mImpl->mEventData ) + { + return; + } + + switch( button ) + { + case Toolkit::TextSelectionPopup::CUT: + { + if (!controller.IsEditable()) return; + controller.mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text + controller.mImpl->mOperationsPending = ALL_OPERATIONS; + + if( ( 0u != controller.mImpl->mModel->mLogicalModel->mText.Count() ) || + !controller.mImpl->IsPlaceholderAvailable() ) + { + controller.mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); + } + else + { + controller.ShowPlaceholderText(); + } + + controller.mImpl->mEventData->mUpdateCursorPosition = true; + controller.mImpl->mEventData->mScrollAfterDelete = true; + + controller.mImpl->RequestRelayout(); + + if( NULL != controller.mImpl->mEditableControlInterface ) + { + controller.mImpl->mEditableControlInterface->TextChanged(); + } + break; + } + case Toolkit::TextSelectionPopup::COPY: + { + controller.mImpl->SendSelectionToClipboard( false ); // Text not modified + + controller.mImpl->mEventData->mUpdateCursorPosition = true; + + controller.mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup + break; + } + case Toolkit::TextSelectionPopup::PASTE: + { + controller.mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item + break; + } + case Toolkit::TextSelectionPopup::SELECT: + { + const Vector2& currentCursorPosition = controller.mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR ); + + if( controller.mImpl->mEventData->mSelectionEnabled ) + { + // Creates a SELECT event. + controller.SelectEvent( currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE ); + } + break; + } + case Toolkit::TextSelectionPopup::SELECT_ALL: + { + // Creates a SELECT_ALL event + controller.SelectEvent( 0.f, 0.f, SelectionType::ALL ); + break; + } + case Toolkit::TextSelectionPopup::CLIPBOARD: + { + controller.mImpl->ShowClipboard(); + break; + } + case Toolkit::TextSelectionPopup::NONE: + { + // Nothing to do. + break; + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/text-controller-event-handler.h b/dali-toolkit/internal/text/text-controller-event-handler.h new file mode 100644 index 0000000..51d1648 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-event-handler.h @@ -0,0 +1,67 @@ +#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H +#define DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H + +/* + * Copyright (c) 2020 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. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Controller::EventHandler +{ + static void KeyboardFocusGainEvent(Controller& controller); + static void KeyboardFocusLostEvent(Controller& controller); + static bool KeyEvent(Controller& controller, const Dali::KeyEvent& keyEvent); + static void TapEvent(Controller& controller, unsigned int tapCount, float x, float y); + static void PanEvent(Controller& controller, GestureState state, const Vector2& displacement); + static void LongPressEvent(Controller& controller, GestureState state, float x, float y); + static void SelectEvent(Controller& controller, float x, float y, SelectionType selectType); + static void ProcessModifyEvents(Controller& controller); + static void TextReplacedEvent(Controller& controller); + static void TextInsertedEvent(Controller& controller); + static void TextDeletedEvent(Controller& controller); + static bool DeleteEvent(Controller& controller, int keyCode); + static InputMethodContext::CallbackData OnInputMethodContextEvent(Controller& controller, InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent); + static void PasteClipboardItemEvent(Controller& controller); + static void DecorationEvent(Controller& controller, HandleType handleType, HandleState state, float x, float y); + static void TextPopupButtonTouched(Controller& controller, Dali::Toolkit::TextSelectionPopup::Buttons button); +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_CONTROLLER_EVENT_HANDLER_H diff --git a/dali-toolkit/internal/text/text-controller-input-font-handler.cpp b/dali-toolkit/internal/text/text-controller-input-font-handler.cpp new file mode 100644 index 0000000..21bd604 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-input-font-handler.cpp @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2020 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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +namespace +{ + +/** + * @brief Adds a new font description run for the selected text. + * + * The new font parameters are added after the call to this method. + * + * @param[in] eventData The event data pointer. + * @param[in] logicalModel The logical model where to add the new font description run. + * @param[out] startOfSelectedText Index to the first selected character. + * @param[out] lengthOfSelectedText Number of selected characters. + */ +FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData, + LogicalModelPtr logicalModel, + CharacterIndex& startOfSelectedText, + Length& lengthOfSelectedText ) +{ + const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition; + + // Get start and end position of selection + startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition; + lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText; + + // Add the font run. + const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count(); + logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u ); + + FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns ); + + fontDescriptionRun.characterRun.characterIndex = startOfSelectedText; + fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText; + + // Recalculate the selection highlight as the metrics may have changed. + eventData->mUpdateLeftSelectionPosition = true; + eventData->mUpdateRightSelectionPosition = true; + eventData->mUpdateHighlightBox = true; + + return fontDescriptionRun; +} + +} // unnamed namespace + +void Controller::InputFontHandler::SetInputFontFamily(Controller& controller, const std::string& fontFamily) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.familyName = fontFamily; + controller.mImpl->mEventData->mInputStyle.isFamilyDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.familyLength = fontFamily.size(); + fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; + memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength ); + fontDescriptionRun.familyDefined = true; + + // The memory allocated for the font family name is freed when the font description is removed from the logical model. + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font changes, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +const std::string& Controller::InputFontHandler::GetInputFontFamily(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.familyName; + } + + // Return the default font's family if there is no EventData. + return controller.GetDefaultFontFamily(); +} + +void Controller::InputFontHandler::SetInputFontWeight(const Controller& controller, FontWeight weight) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.weight = weight; + controller.mImpl->mEventData->mInputStyle.isWeightDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.weight = weight; + fontDescriptionRun.weightDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +bool Controller::InputFontHandler::IsInputFontWeightDefined(const Controller& controller) +{ + bool defined = false; + + if( NULL != controller.mImpl->mEventData ) + { + defined = controller.mImpl->mEventData->mInputStyle.isWeightDefined; + } + + return defined; +} + +FontWeight Controller::InputFontHandler::GetInputFontWeight(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.weight; + } + + return controller.GetDefaultFontWeight(); +} + +void Controller::InputFontHandler::SetInputFontWidth(Controller& controller, FontWidth width) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.width = width; + controller.mImpl->mEventData->mInputStyle.isWidthDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.width = width; + fontDescriptionRun.widthDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +bool Controller::InputFontHandler::IsInputFontWidthDefined(const Controller& controller) +{ + bool defined = false; + + if( NULL != controller.mImpl->mEventData ) + { + defined = controller.mImpl->mEventData->mInputStyle.isWidthDefined; + } + + return defined; +} + +FontWidth Controller::InputFontHandler::GetInputFontWidth(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.width; + } + + return controller.GetDefaultFontWidth(); +} + +void Controller::InputFontHandler::SetInputFontSlant(Controller& controller, FontSlant slant) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.slant = slant; + controller.mImpl->mEventData->mInputStyle.isSlantDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.slant = slant; + fontDescriptionRun.slantDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +bool Controller::InputFontHandler::IsInputFontSlantDefined(const Controller& controller) +{ + bool defined = false; + + if( NULL != controller.mImpl->mEventData ) + { + defined = controller.mImpl->mEventData->mInputStyle.isSlantDefined; + } + + return defined; +} + +FontSlant Controller::InputFontHandler::GetInputFontSlant(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.slant; + } + + return controller.GetDefaultFontSlant(); +} + +void Controller::InputFontHandler::SetInputFontPointSize(Controller& controller, float size) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mInputStyle.size = size; + controller.mImpl->mEventData->mInputStyle.isSizeDefined = true; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState || EventData::EDITING == controller.mImpl->mEventData->mState || EventData::INACTIVE == controller.mImpl->mEventData->mState ) + { + CharacterIndex startOfSelectedText = 0u; + Length lengthOfSelectedText = 0u; + + if( EventData::SELECTING == controller.mImpl->mEventData->mState ) + { + // Update a font description run for the selecting state. + FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( controller.mImpl->mEventData, + controller.mImpl->mModel->mLogicalModel, + startOfSelectedText, + lengthOfSelectedText ); + + fontDescriptionRun.size = static_cast( size * 64.f ); + fontDescriptionRun.sizeDefined = true; + + controller.mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; + } + else + { + controller.mImpl->mTextUpdateInfo.mCharacterIndex = 0; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = controller.mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; + controller.mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = controller.mImpl->mModel->mLogicalModel->mText.Count(); + } + + // Request to relayout. + controller.mImpl->mOperationsPending = static_cast( controller.mImpl->mOperationsPending | + VALIDATE_FONTS | + SHAPE_TEXT | + GET_GLYPH_METRICS | + LAYOUT | + UPDATE_LAYOUT_SIZE | + REORDER | + ALIGN ); + controller.mImpl->mRecalculateNaturalSize = true; + controller.mImpl->RequestRelayout(); + + // As the font might change, recalculate the handle positions is needed. + controller.mImpl->mEventData->mUpdateLeftSelectionPosition = true; + controller.mImpl->mEventData->mUpdateRightSelectionPosition = true; + controller.mImpl->mEventData->mUpdateHighlightBox = true; + controller.mImpl->mEventData->mScrollAfterUpdatePosition = true; + } + } +} + +float Controller::InputFontHandler::GetInputFontPointSize(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mInputStyle.size; + } + + // Return the default font's point size if there is no EventData. + return controller.GetDefaultFontSize( Text::Controller::POINT_SIZE ); +} +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/text-controller-input-font-handler.h b/dali-toolkit/internal/text/text-controller-input-font-handler.h new file mode 100644 index 0000000..066ac49 --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-input-font-handler.h @@ -0,0 +1,60 @@ +#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H +#define DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H + +/* + * Copyright (c) 2020 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. + * + */ + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Controller::InputFontHandler +{ + static void SetInputFontFamily(Controller& controller, const std::string& fontFamily); + static const std::string& GetInputFontFamily(const Controller& controller); + static void SetInputFontWeight(const Controller& controller, FontWeight weight); + static bool IsInputFontWeightDefined(const Controller& controller); + static FontWeight GetInputFontWeight(const Controller& controller); + static void SetInputFontWidth(Controller& controller, FontWidth width); + static bool IsInputFontWidthDefined(const Controller& controller); + static FontWidth GetInputFontWidth(const Controller& controller); + static void SetInputFontSlant(Controller& controller, FontSlant slant); + static bool IsInputFontSlantDefined(const Controller& controller); + static FontSlant GetInputFontSlant(const Controller& controller); + static void SetInputFontPointSize(Controller& controller, float size); + static float GetInputFontPointSize(const Controller& controller); +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_CONTROLLER_INPUT_FONT_HANDLER_H diff --git a/dali-toolkit/internal/text/text-controller-placeholder-handler.cpp b/dali-toolkit/internal/text/text-controller-placeholder-handler.cpp new file mode 100644 index 0000000..f567cbd --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-placeholder-handler.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2020 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 + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace +{ + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +#endif + +const std::string EMPTY_STRING(""); + +const char * const PLACEHOLDER_TEXT = "text"; +const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused"; +const char * const PLACEHOLDER_COLOR = "color"; +const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily"; +const char * const PLACEHOLDER_FONT_STYLE = "fontStyle"; +const char * const PLACEHOLDER_POINT_SIZE = "pointSize"; +const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize"; +const char * const PLACEHOLDER_ELLIPSIS = "ellipsis"; + +} // namespace + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +void Controller::PlaceholderHandler::SetPlaceholderTextElideEnabled(Controller& controller, bool enabled) +{ + controller.mImpl->mEventData->mIsPlaceholderElideEnabled = enabled; + controller.mImpl->mEventData->mPlaceholderEllipsisFlag = true; + + // Update placeholder if there is no text + if( controller.mImpl->IsShowingPlaceholderText() || + ( 0u == controller.mImpl->mModel->mLogicalModel->mText.Count() ) ) + { + controller.ShowPlaceholderText(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextElideEnabled(const Controller& controller) +{ + return controller.mImpl->mEventData->mIsPlaceholderElideEnabled; +} + +void Controller::PlaceholderHandler::SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( PLACEHOLDER_TYPE_INACTIVE == type ) + { + controller.mImpl->mEventData->mPlaceholderTextInactive = text; + } + else + { + controller.mImpl->mEventData->mPlaceholderTextActive = text; + } + + // Update placeholder if there is no text + if( controller.mImpl->IsShowingPlaceholderText() || + ( 0u == controller.mImpl->mModel->mLogicalModel->mText.Count() ) ) + { + controller.ShowPlaceholderText(); + } + } +} + +void Controller::PlaceholderHandler::GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( PLACEHOLDER_TYPE_INACTIVE == type ) + { + text = controller.mImpl->mEventData->mPlaceholderTextInactive; + } + else + { + text = controller.mImpl->mEventData->mPlaceholderTextActive; + } + } +} + +void Controller::PlaceholderHandler::SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily; + DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str()); + controller.mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty(); + + controller.mImpl->RequestRelayout(); + } +} + +const std::string& Controller::PlaceholderHandler::GetPlaceholderFontFamily(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.family; + } + + return EMPTY_STRING; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight; + controller.mImpl->mEventData->mPlaceholderFont->weightDefined = true; + + controller.mImpl->RequestRelayout(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextFontWeightDefined(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->weightDefined; + } + return false; +} + +FontWeight Controller::PlaceholderHandler::GetPlaceholderTextFontWeight(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.weight; + } + + return TextAbstraction::FontWeight::NORMAL; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontWidth(Controller& controller, FontWidth width) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width; + controller.mImpl->mEventData->mPlaceholderFont->widthDefined = true; + + controller.mImpl->RequestRelayout(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextFontWidthDefined(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->widthDefined; + } + return false; +} + +FontWidth Controller::PlaceholderHandler::GetPlaceholderTextFontWidth(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.width; + } + + return TextAbstraction::FontWidth::NORMAL; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant; + controller.mImpl->mEventData->mPlaceholderFont->slantDefined = true; + + controller.mImpl->RequestRelayout(); + } +} + +bool Controller::PlaceholderHandler::IsPlaceholderTextFontSlantDefined(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->slantDefined; + } + return false; +} + +FontSlant Controller::PlaceholderHandler::GetPlaceholderTextFontSlant(const Controller& controller) +{ + if( ( NULL != controller.mImpl->mEventData ) && ( NULL != controller.mImpl->mEventData->mPlaceholderFont ) ) + { + return controller.mImpl->mEventData->mPlaceholderFont->mFontDescription.slant; + } + + return TextAbstraction::FontSlant::NORMAL; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( NULL == controller.mImpl->mEventData->mPlaceholderFont ) + { + controller.mImpl->mEventData->mPlaceholderFont = new FontDefaults(); + } + + switch( type ) + { + case POINT_SIZE: + { + controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize; + controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true; + controller.mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag + break; + } + case PIXEL_SIZE: + { + // Point size = Pixel size * 72.f / DPI + unsigned int horizontalDpi = 0u; + unsigned int verticalDpi = 0u; + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.GetDpi( horizontalDpi, verticalDpi ); + + controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi ); + controller.mImpl->mEventData->mPlaceholderFont->sizeDefined = true; + controller.mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag + break; + } + } + + controller.mImpl->RequestRelayout(); + } +} + +float Controller::PlaceholderHandler::GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type ) +{ + float value = 0.0f; + if( NULL != controller.mImpl->mEventData ) + { + switch( type ) + { + case POINT_SIZE: + { + if( NULL != controller.mImpl->mEventData->mPlaceholderFont ) + { + value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize; + } + else + { + // If the placeholder text font size is not set, then return the default font size. + value = controller.GetDefaultFontSize( POINT_SIZE ); + } + break; + } + case PIXEL_SIZE: + { + if( NULL != controller.mImpl->mEventData->mPlaceholderFont ) + { + // Pixel size = Point size * DPI / 72.f + unsigned int horizontalDpi = 0u; + unsigned int verticalDpi = 0u; + TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); + fontClient.GetDpi( horizontalDpi, verticalDpi ); + + value = controller.mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f; + } + else + { + // If the placeholder text font size is not set, then return the default font size. + value = controller.GetDefaultFontSize( PIXEL_SIZE ); + } + break; + } + } + return value; + } + + return value; +} + +void Controller::PlaceholderHandler::SetPlaceholderTextColor(Controller& controller, const Vector4& textColor ) +{ + if( NULL != controller.mImpl->mEventData ) + { + controller.mImpl->mEventData->mPlaceholderTextColor = textColor; + } + + if( controller.mImpl->IsShowingPlaceholderText() ) + { + controller.mImpl->mModel->mVisualModel->SetTextColor( textColor ); + controller.mImpl->RequestRelayout(); + } +} + +const Vector4& Controller::PlaceholderHandler::GetPlaceholderTextColor(const Controller& controller) +{ + if( NULL != controller.mImpl->mEventData ) + { + return controller.mImpl->mEventData->mPlaceholderTextColor; + } + + return Color::BLACK; +} + +void Controller::PlaceholderHandler::SetPlaceholderProperty(Controller& controller, const Property::Map& map ) +{ + const Property::Map::SizeType count = map.Count(); + + for( Property::Map::SizeType position = 0; position < count; ++position ) + { + KeyValuePair keyValue = map.GetKeyValue( position ); + Property::Key& key = keyValue.first; + Property::Value& value = keyValue.second; + + if( key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT ) + { + std::string text = ""; + value.Get( text ); + SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_INACTIVE, text); + } + else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED ) + { + std::string text = ""; + value.Get( text ); + SetPlaceholderText(controller, Controller::PLACEHOLDER_TYPE_ACTIVE, text); + } + else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR ) + { + Vector4 textColor; + value.Get( textColor ); + if( GetPlaceholderTextColor(controller) != textColor ) + { + SetPlaceholderTextColor(controller, textColor); + } + } + else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY ) + { + std::string fontFamily = ""; + value.Get( fontFamily ); + SetPlaceholderFontFamily(controller, fontFamily); + } + else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE ) + { + SetFontStyleProperty( &controller, value, Text::FontStyle::PLACEHOLDER ); + } + else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE ) + { + float pointSize; + value.Get( pointSize ); + if( !Equals(GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE), pointSize) ) + { + SetPlaceholderTextFontSize(controller, pointSize, Text::Controller::POINT_SIZE); + } + } + else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE ) + { + float pixelSize; + value.Get( pixelSize ); + if( !Equals(GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE), pixelSize) ) + { + SetPlaceholderTextFontSize(controller, pixelSize, Text::Controller::PIXEL_SIZE); + } + } + else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS ) + { + bool ellipsis; + value.Get( ellipsis ); + SetPlaceholderTextElideEnabled(controller, ellipsis); + } + } +} + +void Controller::PlaceholderHandler::GetPlaceholderProperty(Controller& controller, Property::Map& map) +{ + if( NULL != controller.mImpl->mEventData ) + { + if( !controller.mImpl->mEventData->mPlaceholderTextActive.empty() ) + { + map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = controller.mImpl->mEventData->mPlaceholderTextActive; + } + if( !controller.mImpl->mEventData->mPlaceholderTextInactive.empty() ) + { + map[ Text::PlaceHolder::Property::TEXT ] = controller.mImpl->mEventData->mPlaceholderTextInactive; + } + + map[ Text::PlaceHolder::Property::COLOR ] = controller.mImpl->mEventData->mPlaceholderTextColor; + map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily(controller); + + Property::Value fontStyleMapGet; + GetFontStyleProperty( &controller, fontStyleMapGet, Text::FontStyle::PLACEHOLDER ); + map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet; + + // Choose font size : POINT_SIZE or PIXEL_SIZE + if( !controller.mImpl->mEventData->mIsPlaceholderPixelSize ) + { + map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize(controller, Text::Controller::POINT_SIZE); + } + else + { + map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize(controller, Text::Controller::PIXEL_SIZE); + } + + if( controller.mImpl->mEventData->mPlaceholderEllipsisFlag ) + { + map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled(controller); + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/text-controller-placeholder-handler.h b/dali-toolkit/internal/text/text-controller-placeholder-handler.h new file mode 100644 index 0000000..273c69b --- /dev/null +++ b/dali-toolkit/internal/text/text-controller-placeholder-handler.h @@ -0,0 +1,69 @@ +#ifndef DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H +#define DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H + +/* + * Copyright (c) 2020 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. + * + */ + +// EXTERNAL INCLUDES +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Controller::PlaceholderHandler +{ + static void SetPlaceholderTextElideEnabled(Controller& controller, bool enabled); + static bool IsPlaceholderTextElideEnabled(const Controller& controller); + static void SetPlaceholderText(Controller& controller, PlaceholderType type, const std::string& text); + static void GetPlaceholderText(const Controller& controller, PlaceholderType type, std::string& text); + static void SetPlaceholderFontFamily(Controller& controller, const std::string& placeholderTextFontFamily); + static const std::string& GetPlaceholderFontFamily(const Controller& controller); + static void SetPlaceholderTextFontWeight(Controller& controller, FontWeight weight); + static bool IsPlaceholderTextFontWeightDefined(const Controller& controller); + static FontWeight GetPlaceholderTextFontWeight(const Controller& controller); + static void SetPlaceholderTextFontWidth(Controller& controller, FontWidth width); + static bool IsPlaceholderTextFontWidthDefined(const Controller& controller); + static FontWidth GetPlaceholderTextFontWidth(const Controller& controller); + static void SetPlaceholderTextFontSlant(Controller& controller, FontSlant slant); + static bool IsPlaceholderTextFontSlantDefined(const Controller& controller); + static FontSlant GetPlaceholderTextFontSlant(const Controller& controller); + static void SetPlaceholderTextFontSize(Controller& controller, float fontSize, FontSizeType type); + static float GetPlaceholderTextFontSize(const Controller& controller, FontSizeType type ); + static void SetPlaceholderTextColor(Controller& controller, const Vector4& textColor ); + static const Vector4& GetPlaceholderTextColor(const Controller& controller); + static void SetPlaceholderProperty(Controller& controller, const Property::Map& map ); + static void GetPlaceholderProperty(Controller& controller, Property::Map& map); +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_TEXT_CONTROLLER_PLACEHOLDER_HANDLER_H diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 797ae32..31c1edf 100755 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -22,49 +22,29 @@ #include #include #include -#include #include -#include -#include -#include // INTERNAL INCLUDES -#include -#include #include #include #include -#include +#include #include +#include +#include #include -#include namespace { #if defined(DEBUG_ENABLED) - Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); +Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, true, "LOG_TEXT_CONTROLS"); #endif const float MAX_FLOAT = std::numeric_limits::max(); const std::string EMPTY_STRING(""); -const std::string KEY_C_NAME = "c"; -const std::string KEY_V_NAME = "v"; -const std::string KEY_X_NAME = "x"; -const std::string KEY_A_NAME = "a"; -const std::string KEY_INSERT_NAME = "Insert"; - -const char * const PLACEHOLDER_TEXT = "text"; -const char * const PLACEHOLDER_TEXT_FOCUSED = "textFocused"; -const char * const PLACEHOLDER_COLOR = "color"; -const char * const PLACEHOLDER_FONT_FAMILY = "fontFamily"; -const char * const PLACEHOLDER_FONT_STYLE = "fontStyle"; -const char * const PLACEHOLDER_POINT_SIZE = "pointSize"; -const char * const PLACEHOLDER_PIXEL_SIZE = "pixelSize"; -const char * const PLACEHOLDER_ELLIPSIS = "ellipsis"; - float ConvertToEven( float value ) { int intValue(static_cast( value )); @@ -92,44 +72,6 @@ namespace Toolkit namespace Text { -/** - * @brief Adds a new font description run for the selected text. - * - * The new font parameters are added after the call to this method. - * - * @param[in] eventData The event data pointer. - * @param[in] logicalModel The logical model where to add the new font description run. - * @param[out] startOfSelectedText Index to the first selected character. - * @param[out] lengthOfSelectedText Number of selected characters. - */ -FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData, - LogicalModelPtr logicalModel, - CharacterIndex& startOfSelectedText, - Length& lengthOfSelectedText ) -{ - const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition; - - // Get start and end position of selection - startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition; - lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText; - - // Add the font run. - const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count(); - logicalModel->mFontDescriptionRuns.Resize( numberOfRuns + 1u ); - - FontDescriptionRun& fontDescriptionRun = *( logicalModel->mFontDescriptionRuns.Begin() + numberOfRuns ); - - fontDescriptionRun.characterRun.characterIndex = startOfSelectedText; - fontDescriptionRun.characterRun.numberOfCharacters = lengthOfSelectedText; - - // Recalculate the selection highlight as the metrics may have changed. - eventData->mUpdateLeftSelectionPosition = true; - eventData->mUpdateRightSelectionPosition = true; - eventData->mUpdateHighlightBox = true; - - return fontDescriptionRun; -} - // public : Constructor. ControllerPtr Controller::New() @@ -594,20 +536,12 @@ Vector2 Controller::GetTextFitContentSize() const void Controller::SetPlaceholderTextElideEnabled( bool enabled ) { - mImpl->mEventData->mIsPlaceholderElideEnabled = enabled; - mImpl->mEventData->mPlaceholderEllipsisFlag = true; - - // Update placeholder if there is no text - if( mImpl->IsShowingPlaceholderText() || - ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) ) - { - ShowPlaceholderText(); - } + PlaceholderHandler::SetPlaceholderTextElideEnabled(*this, enabled); } bool Controller::IsPlaceholderTextElideEnabled() const { - return mImpl->mEventData->mIsPlaceholderElideEnabled; + return PlaceholderHandler::IsPlaceholderTextElideEnabled(*this); } void Controller::SetSelectionEnabled( bool enabled ) @@ -776,39 +710,12 @@ void Controller::GetText( std::string& text ) const void Controller::SetPlaceholderText( PlaceholderType type, const std::string& text ) { - if( NULL != mImpl->mEventData ) - { - if( PLACEHOLDER_TYPE_INACTIVE == type ) - { - mImpl->mEventData->mPlaceholderTextInactive = text; - } - else - { - mImpl->mEventData->mPlaceholderTextActive = text; - } - - // Update placeholder if there is no text - if( mImpl->IsShowingPlaceholderText() || - ( 0u == mImpl->mModel->mLogicalModel->mText.Count() ) ) - { - ShowPlaceholderText(); - } - } + PlaceholderHandler::SetPlaceholderText(*this, type, text); } void Controller::GetPlaceholderText( PlaceholderType type, std::string& text ) const { - if( NULL != mImpl->mEventData ) - { - if( PLACEHOLDER_TYPE_INACTIVE == type ) - { - text = mImpl->mEventData->mPlaceholderTextInactive; - } - else - { - text = mImpl->mEventData->mPlaceholderTextActive; - } - } + PlaceholderHandler::GetPlaceholderText(*this, type, text ); } void Controller::UpdateAfterFontChange( const std::string& newDefaultFont ) @@ -867,29 +774,12 @@ const std::string& Controller::GetDefaultFontFamily() const void Controller::SetPlaceholderFontFamily( const std::string& placeholderTextFontFamily ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.family = placeholderTextFontFamily; - DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::SetPlaceholderFontFamily %s\n", placeholderTextFontFamily.c_str()); - mImpl->mEventData->mPlaceholderFont->familyDefined = !placeholderTextFontFamily.empty(); - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderFontFamily(*this, placeholderTextFontFamily); } const std::string& Controller::GetPlaceholderFontFamily() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.family; - } - - return EMPTY_STRING; + return PlaceholderHandler::GetPlaceholderFontFamily(*this); } void Controller::SetDefaultFontWeight( FontWeight weight ) @@ -940,37 +830,17 @@ FontWeight Controller::GetDefaultFontWeight() const void Controller::SetPlaceholderTextFontWeight( FontWeight weight ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.weight = weight; - mImpl->mEventData->mPlaceholderFont->weightDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontWeight(*this, weight); } bool Controller::IsPlaceholderTextFontWeightDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->weightDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontWeightDefined(*this);; } FontWeight Controller::GetPlaceholderTextFontWeight() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.weight; - } - - return TextAbstraction::FontWeight::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontWeight(*this); } void Controller::SetDefaultFontWidth( FontWidth width ) @@ -1021,37 +891,17 @@ FontWidth Controller::GetDefaultFontWidth() const void Controller::SetPlaceholderTextFontWidth( FontWidth width ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.width = width; - mImpl->mEventData->mPlaceholderFont->widthDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontWidth(*this, width); } bool Controller::IsPlaceholderTextFontWidthDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->widthDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontWidthDefined(*this); } FontWidth Controller::GetPlaceholderTextFontWidth() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.width; - } - - return TextAbstraction::FontWidth::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontWidth(*this); } void Controller::SetDefaultFontSlant( FontSlant slant ) @@ -1101,37 +951,17 @@ FontSlant Controller::GetDefaultFontSlant() const void Controller::SetPlaceholderTextFontSlant( FontSlant slant ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - mImpl->mEventData->mPlaceholderFont->mFontDescription.slant = slant; - mImpl->mEventData->mPlaceholderFont->slantDefined = true; - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontSlant(*this, slant); } bool Controller::IsPlaceholderTextFontSlantDefined() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->slantDefined; - } - return false; + return PlaceholderHandler::IsPlaceholderTextFontSlantDefined(*this); } FontSlant Controller::GetPlaceholderTextFontSlant() const { - if( ( NULL != mImpl->mEventData ) && ( NULL != mImpl->mEventData->mPlaceholderFont ) ) - { - return mImpl->mEventData->mPlaceholderFont->mFontDescription.slant; - } - - return TextAbstraction::FontSlant::NORMAL; + return PlaceholderHandler::GetPlaceholderTextFontSlant(*this); } void Controller::SetDefaultFontSize( float fontSize, FontSizeType type ) @@ -1211,85 +1041,12 @@ float Controller::GetDefaultFontSize( FontSizeType type ) const void Controller::SetPlaceholderTextFontSize( float fontSize, FontSizeType type ) { - if( NULL != mImpl->mEventData ) - { - if( NULL == mImpl->mEventData->mPlaceholderFont ) - { - mImpl->mEventData->mPlaceholderFont = new FontDefaults(); - } - - switch( type ) - { - case POINT_SIZE: - { - mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = fontSize; - mImpl->mEventData->mPlaceholderFont->sizeDefined = true; - mImpl->mEventData->mIsPlaceholderPixelSize = false; // Font size flag - break; - } - case PIXEL_SIZE: - { - // Point size = Pixel size * 72.f / DPI - unsigned int horizontalDpi = 0u; - unsigned int verticalDpi = 0u; - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - fontClient.GetDpi( horizontalDpi, verticalDpi ); - - mImpl->mEventData->mPlaceholderFont->mDefaultPointSize = ( fontSize * 72.f ) / static_cast< float >( horizontalDpi ); - mImpl->mEventData->mPlaceholderFont->sizeDefined = true; - mImpl->mEventData->mIsPlaceholderPixelSize = true; // Font size flag - break; - } - } - - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextFontSize(*this, fontSize, type); } float Controller::GetPlaceholderTextFontSize( FontSizeType type ) const { - float value = 0.0f; - if( NULL != mImpl->mEventData ) - { - switch( type ) - { - case POINT_SIZE: - { - if( NULL != mImpl->mEventData->mPlaceholderFont ) - { - value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize; - } - else - { - // If the placeholder text font size is not set, then return the default font size. - value = GetDefaultFontSize( POINT_SIZE ); - } - break; - } - case PIXEL_SIZE: - { - if( NULL != mImpl->mEventData->mPlaceholderFont ) - { - // Pixel size = Point size * DPI / 72.f - unsigned int horizontalDpi = 0u; - unsigned int verticalDpi = 0u; - TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get(); - fontClient.GetDpi( horizontalDpi, verticalDpi ); - - value = mImpl->mEventData->mPlaceholderFont->mDefaultPointSize * static_cast< float >( horizontalDpi ) / 72.f; - } - else - { - // If the placeholder text font size is not set, then return the default font size. - value = GetDefaultFontSize( PIXEL_SIZE ); - } - break; - } - } - return value; - } - - return value; + return PlaceholderHandler::GetPlaceholderTextFontSize(*this, type); } void Controller::SetDefaultColor( const Vector4& color ) @@ -1315,26 +1072,12 @@ const Vector4& Controller::GetDefaultColor() const void Controller::SetPlaceholderTextColor( const Vector4& textColor ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mPlaceholderTextColor = textColor; - } - - if( mImpl->IsShowingPlaceholderText() ) - { - mImpl->mModel->mVisualModel->SetTextColor( textColor ); - mImpl->RequestRelayout(); - } + PlaceholderHandler::SetPlaceholderTextColor(*this, textColor); } const Vector4& Controller::GetPlaceholderTextColor() const { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mPlaceholderTextColor; - } - - return Color::BLACK; + return PlaceholderHandler::GetPlaceholderTextColor(*this); } void Controller::SetShadowOffset( const Vector2& shadowOffset ) @@ -1581,404 +1324,102 @@ const Vector4& Controller::GetInputColor() const void Controller::SetInputFontFamily( const std::string& fontFamily ) { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.familyName = fontFamily; - mImpl->mEventData->mInputStyle.isFamilyDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.familyLength = fontFamily.size(); - fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength]; - memcpy( fontDescriptionRun.familyName, fontFamily.c_str(), fontDescriptionRun.familyLength ); - fontDescriptionRun.familyDefined = true; + InputFontHandler::SetInputFontFamily(*this, fontFamily); +} - // The memory allocated for the font family name is freed when the font description is removed from the logical model. +const std::string& Controller::GetInputFontFamily() const +{ + return InputFontHandler::GetInputFontFamily(*this); +} - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } +void Controller::SetInputFontWeight( FontWeight weight ) +{ + InputFontHandler::SetInputFontWeight(*this, weight); +} - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); +bool Controller::IsInputFontWeightDefined() const +{ + return InputFontHandler::IsInputFontWeightDefined(*this); +} - // As the font changes, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } +FontWeight Controller::GetInputFontWeight() const +{ + return InputFontHandler::GetInputFontWeight(*this); } -const std::string& Controller::GetInputFontFamily() const +void Controller::SetInputFontWidth( FontWidth width ) { - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.familyName; - } + InputFontHandler::SetInputFontWidth(*this, width); +} - // Return the default font's family if there is no EventData. - return GetDefaultFontFamily(); +bool Controller::IsInputFontWidthDefined() const +{ + return InputFontHandler::IsInputFontWidthDefined(*this); } -void Controller::SetInputFontWeight( FontWeight weight ) +FontWidth Controller::GetInputFontWidth() const { - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.weight = weight; - mImpl->mEventData->mInputStyle.isWeightDefined = true; + return InputFontHandler::GetInputFontWidth(*this); +} - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; +void Controller::SetInputFontSlant( FontSlant slant ) +{ + InputFontHandler::SetInputFontSlant(*this, slant); +} - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); +bool Controller::IsInputFontSlantDefined() const +{ + return InputFontHandler::IsInputFontSlantDefined(*this); +} - fontDescriptionRun.weight = weight; - fontDescriptionRun.weightDefined = true; +FontSlant Controller::GetInputFontSlant() const +{ + return InputFontHandler::GetInputFontSlant(*this); +} - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } +void Controller::SetInputFontPointSize( float size ) +{ + InputFontHandler::SetInputFontPointSize(*this, size); +} - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); +float Controller::GetInputFontPointSize() const +{ + return InputFontHandler::GetInputFontPointSize(*this); +} - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } +void Controller::SetInputLineSpacing( float lineSpacing ) +{ + if( NULL != mImpl->mEventData ) + { + mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing; + mImpl->mEventData->mInputStyle.isLineSpacingDefined = true; } } -bool Controller::IsInputFontWeightDefined() const +float Controller::GetInputLineSpacing() const { - bool defined = false; - if( NULL != mImpl->mEventData ) { - defined = mImpl->mEventData->mInputStyle.isWeightDefined; + return mImpl->mEventData->mInputStyle.lineSpacing; } - return defined; + return 0.f; } -FontWeight Controller::GetInputFontWeight() const +void Controller::SetInputShadowProperties( const std::string& shadowProperties ) { if( NULL != mImpl->mEventData ) { - return mImpl->mEventData->mInputStyle.weight; + mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties; } - - return GetDefaultFontWeight(); } -void Controller::SetInputFontWidth( FontWidth width ) +const std::string& Controller::GetInputShadowProperties() const { if( NULL != mImpl->mEventData ) { - mImpl->mEventData->mInputStyle.width = width; - mImpl->mEventData->mInputStyle.isWidthDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.width = width; - fontDescriptionRun.widthDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } -} - -bool Controller::IsInputFontWidthDefined() const -{ - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isWidthDefined; - } - - return defined; -} - -FontWidth Controller::GetInputFontWidth() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.width; - } - - return GetDefaultFontWidth(); -} - -void Controller::SetInputFontSlant( FontSlant slant ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.slant = slant; - mImpl->mEventData->mInputStyle.isSlantDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.slant = slant; - fontDescriptionRun.slantDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } -} - -bool Controller::IsInputFontSlantDefined() const -{ - bool defined = false; - - if( NULL != mImpl->mEventData ) - { - defined = mImpl->mEventData->mInputStyle.isSlantDefined; - } - - return defined; -} - -FontSlant Controller::GetInputFontSlant() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.slant; - } - - return GetDefaultFontSlant(); -} - -void Controller::SetInputFontPointSize( float size ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.size = size; - mImpl->mEventData->mInputStyle.isSizeDefined = true; - - if( EventData::SELECTING == mImpl->mEventData->mState || EventData::EDITING == mImpl->mEventData->mState || EventData::INACTIVE == mImpl->mEventData->mState ) - { - CharacterIndex startOfSelectedText = 0u; - Length lengthOfSelectedText = 0u; - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - // Update a font description run for the selecting state. - FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData, - mImpl->mModel->mLogicalModel, - startOfSelectedText, - lengthOfSelectedText ); - - fontDescriptionRun.size = static_cast( size * 64.f ); - fontDescriptionRun.sizeDefined = true; - - mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText; - } - else - { - mImpl->mTextUpdateInfo.mCharacterIndex = 0; - mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mModel->mLogicalModel->mText.Count(); - } - - // Request to relayout. - mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | - VALIDATE_FONTS | - SHAPE_TEXT | - GET_GLYPH_METRICS | - LAYOUT | - UPDATE_LAYOUT_SIZE | - REORDER | - ALIGN ); - mImpl->mRecalculateNaturalSize = true; - mImpl->RequestRelayout(); - - // As the font might change, recalculate the handle positions is needed. - mImpl->mEventData->mUpdateLeftSelectionPosition = true; - mImpl->mEventData->mUpdateRightSelectionPosition = true; - mImpl->mEventData->mUpdateHighlightBox = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - } -} - -float Controller::GetInputFontPointSize() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.size; - } - - // Return the default font's point size if there is no EventData. - return GetDefaultFontSize( Text::Controller::POINT_SIZE ); -} - -void Controller::SetInputLineSpacing( float lineSpacing ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.lineSpacing = lineSpacing; - mImpl->mEventData->mInputStyle.isLineSpacingDefined = true; - } -} - -float Controller::GetInputLineSpacing() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.lineSpacing; - } - - return 0.f; -} - -void Controller::SetInputShadowProperties( const std::string& shadowProperties ) -{ - if( NULL != mImpl->mEventData ) - { - mImpl->mEventData->mInputStyle.shadowProperties = shadowProperties; - } -} - -const std::string& Controller::GetInputShadowProperties() const -{ - if( NULL != mImpl->mEventData ) - { - return mImpl->mEventData->mInputStyle.shadowProperties; - } + return mImpl->mEventData->mInputStyle.shadowProperties; + } return EMPTY_STRING; } @@ -2433,107 +1874,12 @@ void Controller::GetHiddenInputOption(Property::Map& options ) void Controller::SetPlaceholderProperty( const Property::Map& map ) { - const Property::Map::SizeType count = map.Count(); - - for( Property::Map::SizeType position = 0; position < count; ++position ) - { - KeyValuePair keyValue = map.GetKeyValue( position ); - Property::Key& key = keyValue.first; - Property::Value& value = keyValue.second; - - if( key == Toolkit::Text::PlaceHolder::Property::TEXT || key == PLACEHOLDER_TEXT ) - { - std::string text = ""; - value.Get( text ); - SetPlaceholderText( Controller::PLACEHOLDER_TYPE_INACTIVE, text ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::TEXT_FOCUSED || key == PLACEHOLDER_TEXT_FOCUSED ) - { - std::string text = ""; - value.Get( text ); - SetPlaceholderText( Controller::PLACEHOLDER_TYPE_ACTIVE, text ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::COLOR || key == PLACEHOLDER_COLOR ) - { - Vector4 textColor; - value.Get( textColor ); - if( GetPlaceholderTextColor() != textColor ) - { - SetPlaceholderTextColor( textColor ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::FONT_FAMILY || key == PLACEHOLDER_FONT_FAMILY ) - { - std::string fontFamily = ""; - value.Get( fontFamily ); - SetPlaceholderFontFamily( fontFamily ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::FONT_STYLE || key == PLACEHOLDER_FONT_STYLE ) - { - SetFontStyleProperty( this, value, Text::FontStyle::PLACEHOLDER ); - } - else if( key == Toolkit::Text::PlaceHolder::Property::POINT_SIZE || key == PLACEHOLDER_POINT_SIZE ) - { - float pointSize; - value.Get( pointSize ); - if( !Equals( GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ), pointSize ) ) - { - SetPlaceholderTextFontSize( pointSize, Text::Controller::POINT_SIZE ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::PIXEL_SIZE || key == PLACEHOLDER_PIXEL_SIZE ) - { - float pixelSize; - value.Get( pixelSize ); - if( !Equals( GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ), pixelSize ) ) - { - SetPlaceholderTextFontSize( pixelSize, Text::Controller::PIXEL_SIZE ); - } - } - else if( key == Toolkit::Text::PlaceHolder::Property::ELLIPSIS || key == PLACEHOLDER_ELLIPSIS ) - { - bool ellipsis; - value.Get( ellipsis ); - SetPlaceholderTextElideEnabled( ellipsis ); - } - } + PlaceholderHandler::SetPlaceholderProperty(*this, map); } void Controller::GetPlaceholderProperty( Property::Map& map ) { - if( NULL != mImpl->mEventData ) - { - if( !mImpl->mEventData->mPlaceholderTextActive.empty() ) - { - map[ Text::PlaceHolder::Property::TEXT_FOCUSED ] = mImpl->mEventData->mPlaceholderTextActive; - } - if( !mImpl->mEventData->mPlaceholderTextInactive.empty() ) - { - map[ Text::PlaceHolder::Property::TEXT ] = mImpl->mEventData->mPlaceholderTextInactive; - } - - map[ Text::PlaceHolder::Property::COLOR ] = mImpl->mEventData->mPlaceholderTextColor; - map[ Text::PlaceHolder::Property::FONT_FAMILY ] = GetPlaceholderFontFamily(); - - Property::Value fontStyleMapGet; - GetFontStyleProperty( this, fontStyleMapGet, Text::FontStyle::PLACEHOLDER ); - map[ Text::PlaceHolder::Property::FONT_STYLE ] = fontStyleMapGet; - - // Choose font size : POINT_SIZE or PIXEL_SIZE - if( !mImpl->mEventData->mIsPlaceholderPixelSize ) - { - map[ Text::PlaceHolder::Property::POINT_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::POINT_SIZE ); - } - else - { - map[ Text::PlaceHolder::Property::PIXEL_SIZE ] = GetPlaceholderTextFontSize( Text::Controller::PIXEL_SIZE ); - } - - if( mImpl->mEventData->mPlaceholderEllipsisFlag ) - { - map[ Text::PlaceHolder::Property::ELLIPSIS ] = IsPlaceholderTextElideEnabled(); - } - } + PlaceholderHandler::GetPlaceholderProperty(*this, map); } Toolkit::DevelText::TextDirection::Type Controller::GetTextDirection() @@ -2783,417 +2129,37 @@ void Controller::ProcessInputStyleChangedSignals() void Controller::KeyboardFocusGainEvent() { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusGainEvent" ); - - if( NULL != mImpl->mEventData ) - { - if( ( EventData::INACTIVE == mImpl->mEventData->mState ) || - ( EventData::INTERRUPTED == mImpl->mEventData->mState ) ) - { - mImpl->ChangeState( EventData::EDITING ); - mImpl->mEventData->mUpdateCursorPosition = true; //If editing started without tap event, cursor update must be triggered. - mImpl->mEventData->mUpdateInputStyle = true; - mImpl->mEventData->mScrollAfterUpdatePosition = true; - } - mImpl->NotifyInputMethodContextMultiLineStatus(); - if( mImpl->IsShowingPlaceholderText() ) - { - // Show alternative placeholder-text when editing - ShowPlaceholderText(); - } - - mImpl->RequestRelayout(); - } + EventHandler::KeyboardFocusGainEvent(*this); } void Controller::KeyboardFocusLostEvent() { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyboardFocusLostEvent" ); - - if( NULL != mImpl->mEventData ) - { - if( EventData::INTERRUPTED != mImpl->mEventData->mState ) - { - mImpl->ChangeState( EventData::INACTIVE ); - - if( !mImpl->IsShowingRealText() ) - { - // Revert to regular placeholder-text when not editing - ShowPlaceholderText(); - } - } - } - mImpl->RequestRelayout(); + EventHandler::KeyboardFocusLostEvent(*this); } bool Controller::KeyEvent( const Dali::KeyEvent& keyEvent ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected KeyEvent" ); - - bool textChanged = false; - bool relayoutNeeded = false; - - if( ( NULL != mImpl->mEventData ) && - ( keyEvent.GetState() == KeyEvent::DOWN ) ) - { - int keyCode = keyEvent.GetKeyCode(); - const std::string& keyString = keyEvent.GetKeyString(); - const std::string keyName = keyEvent.GetKeyName(); - - const bool isNullKey = ( 0 == keyCode ) && ( keyString.empty() ); - - // Pre-process to separate modifying events from non-modifying input events. - if( isNullKey ) - { - // In some platforms arrive key events with no key code. - // Do nothing. - return false; - } - else if( Dali::DALI_KEY_ESCAPE == keyCode || Dali::DALI_KEY_BACK == keyCode || Dali::DALI_KEY_SEARCH == keyCode ) - { - // Do nothing - return false; - } - else if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode ) || - ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode ) || - ( Dali::DALI_KEY_CURSOR_UP == keyCode ) || - ( Dali::DALI_KEY_CURSOR_DOWN == keyCode ) ) - { - // If don't have any text, do nothing. - if( !mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters ) - { - return false; - } - - uint32_t cursorPosition = mImpl->mEventData->mPrimaryCursorPosition; - uint32_t numberOfCharacters = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters; - uint32_t cursorLine = mImpl->mModel->mVisualModel->GetLineOfCharacter( cursorPosition ); - uint32_t numberOfLines = mImpl->mModel->GetNumberOfLines(); - - // Logic to determine whether this text control will lose focus or not. - if( ( Dali::DALI_KEY_CURSOR_LEFT == keyCode && 0 == cursorPosition && !keyEvent.IsShiftModifier() ) || - ( Dali::DALI_KEY_CURSOR_RIGHT == keyCode && numberOfCharacters == cursorPosition && !keyEvent.IsShiftModifier() ) || - ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && cursorLine == numberOfLines -1 ) || - ( Dali::DALI_KEY_CURSOR_DOWN == keyCode && numberOfCharacters == cursorPosition && cursorLine -1 == numberOfLines -1 ) || - ( Dali::DALI_KEY_CURSOR_UP == keyCode && cursorLine == 0 ) || - ( Dali::DALI_KEY_CURSOR_UP == keyCode && numberOfCharacters == cursorPosition && cursorLine == 1 ) ) - { - // Release the active highlight. - if( mImpl->mEventData->mState == EventData::SELECTING ) - { - mImpl->ChangeState( EventData::EDITING ); - - // Update selection position. - mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->RequestRelayout(); - } - return false; - } - - mImpl->mEventData->mCheckScrollAmount = true; - Event event( Event::CURSOR_KEY_EVENT ); - event.p1.mInt = keyCode; - event.p2.mBool = keyEvent.IsShiftModifier(); - mImpl->mEventData->mEventQueue.push_back( event ); - - // Will request for relayout. - relayoutNeeded = true; - } - else if ( Dali::DevelKey::DALI_KEY_CONTROL_LEFT == keyCode || Dali::DevelKey::DALI_KEY_CONTROL_RIGHT == keyCode ) - { - // Left or Right Control key event is received before Ctrl-C/V/X key event is received - // If not handle it here, any selected text will be deleted - - // Do nothing - return false; - } - else if ( keyEvent.IsCtrlModifier() && !keyEvent.IsShiftModifier()) - { - bool consumed = false; - if (keyName == KEY_C_NAME || keyName == KEY_INSERT_NAME) - { - // Ctrl-C or Ctrl+Insert to copy the selected text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::COPY ); - consumed = true; - } - else if (keyName == KEY_V_NAME) - { - // Ctrl-V to paste the copied text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::PASTE ); - consumed = true; - } - else if (keyName == KEY_X_NAME) - { - // Ctrl-X to cut the selected text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::CUT ); - consumed = true; - } - else if (keyName == KEY_A_NAME) - { - // Ctrl-A to select All the text - TextPopupButtonTouched( Toolkit::TextSelectionPopup::SELECT_ALL ); - consumed = true; - } - return consumed; - } - else if( ( Dali::DALI_KEY_BACKSPACE == keyCode ) || - ( Dali::DevelKey::DALI_KEY_DELETE == keyCode ) ) - { - textChanged = DeleteEvent( keyCode ); - - // Will request for relayout. - relayoutNeeded = true; - } - else if( IsKey( keyEvent, Dali::DALI_KEY_POWER ) || - IsKey( keyEvent, Dali::DALI_KEY_MENU ) || - IsKey( keyEvent, Dali::DALI_KEY_HOME ) ) - { - // Power key/Menu/Home key behaviour does not allow edit mode to resume. - mImpl->ChangeState( EventData::INACTIVE ); - - // Will request for relayout. - relayoutNeeded = true; - - // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. - } - else if( ( Dali::DALI_KEY_SHIFT_LEFT == keyCode ) || ( Dali::DALI_KEY_SHIFT_RIGHT == keyCode ) ) - { - // DALI_KEY_SHIFT_LEFT or DALI_KEY_SHIFT_RIGHT is the key code for Shift. It's sent (by the InputMethodContext?) when the predictive text is enabled - // and a character is typed after the type of a upper case latin character. - - // Do nothing. - return false; - } - else if( ( Dali::DALI_KEY_VOLUME_UP == keyCode ) || ( Dali::DALI_KEY_VOLUME_DOWN == keyCode ) ) - { - // This branch avoids calling the InsertText() method of the 'else' branch which can delete selected text. - // Do nothing. - return false; - } - else - { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p keyString %s\n", this, keyString.c_str() ); - if (!IsEditable()) return false; - - if( !keyString.empty() ) - { - // InputMethodContext is no longer handling key-events - mImpl->ClearPreEditFlag(); - - InsertText( keyString, COMMIT ); - - textChanged = true; - - // Will request for relayout. - relayoutNeeded = true; - } - - } - - if ( ( mImpl->mEventData->mState != EventData::INTERRUPTED ) && - ( mImpl->mEventData->mState != EventData::INACTIVE ) && - ( !isNullKey ) && - ( Dali::DALI_KEY_SHIFT_LEFT != keyCode ) && - ( Dali::DALI_KEY_SHIFT_RIGHT != keyCode ) && - ( Dali::DALI_KEY_VOLUME_UP != keyCode ) && - ( Dali::DALI_KEY_VOLUME_DOWN != keyCode ) ) - { - // Should not change the state if the key is the shift send by the InputMethodContext. - // Otherwise, when the state is SELECTING the text controller can't send the right - // surrounding info to the InputMethodContext. - mImpl->ChangeState( EventData::EDITING ); - - // Will request for relayout. - relayoutNeeded = true; - } - - if( relayoutNeeded ) - { - mImpl->RequestRelayout(); - } - } - - if( textChanged && - ( NULL != mImpl->mEditableControlInterface ) ) - { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); - } - - return true; -} - -void Controller::TapEvent( unsigned int tapCount, float x, float y ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected TapEvent" ); - - if( NULL != mImpl->mEventData ) - { - DALI_LOG_INFO( gLogFilter, Debug::Concise, "TapEvent state:%d \n", mImpl->mEventData->mState ); - EventData::State state( mImpl->mEventData->mState ); - bool relayoutNeeded( false ); // to avoid unnecessary relayouts when tapping an empty text-field - - if( mImpl->IsClipboardVisible() ) - { - if( EventData::INACTIVE == state || EventData::EDITING == state) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); - } - relayoutNeeded = true; - } - else if( 1u == tapCount ) - { - if( EventData::EDITING_WITH_POPUP == state || EventData::EDITING_WITH_PASTE_POPUP == state ) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); // If Popup shown hide it here so can be shown again if required. - } - - if( mImpl->IsShowingRealText() && ( EventData::INACTIVE != state ) ) - { - mImpl->ChangeState( EventData::EDITING_WITH_GRAB_HANDLE ); - relayoutNeeded = true; - } - else - { - if( mImpl->IsShowingPlaceholderText() && !mImpl->IsFocusedPlaceholderAvailable() ) - { - // Hide placeholder text - ResetText(); - } - - if( EventData::INACTIVE == state ) - { - mImpl->ChangeState( EventData::EDITING ); - } - else if( !mImpl->IsClipboardEmpty() ) - { - mImpl->ChangeState( EventData::EDITING_WITH_POPUP ); - } - relayoutNeeded = true; - } - } - else if( 2u == tapCount ) - { - if( mImpl->mEventData->mSelectionEnabled && - mImpl->IsShowingRealText() ) - { - relayoutNeeded = true; - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - } - } - - // Handles & cursors must be repositioned after Relayout() i.e. after the Model has been updated - if( relayoutNeeded ) - { - Event event( Event::TAP_EVENT ); - event.p1.mUint = tapCount; - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } - } - - // Reset keyboard as tap event has occurred. - mImpl->ResetInputMethodContext(); -} - -void Controller::PanEvent( GestureState state, const Vector2& displacement ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected PanEvent" ); - - if( NULL != mImpl->mEventData ) - { - Event event( Event::PAN_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = displacement.x; - event.p3.mFloat = displacement.y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } -} - -void Controller::LongPressEvent( GestureState state, float x, float y ) -{ - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected LongPressEvent" ); - - if( ( state == GestureState::STARTED ) && - ( NULL != mImpl->mEventData ) ) - { - // The 1st long-press on inactive text-field is treated as tap - if( EventData::INACTIVE == mImpl->mEventData->mState ) - { - mImpl->ChangeState( EventData::EDITING ); - - Event event( Event::TAP_EVENT ); - event.p1.mUint = 1; - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - - mImpl->RequestRelayout(); - } - else if( !mImpl->IsShowingRealText() ) - { - Event event( Event::LONG_PRESS_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - mImpl->RequestRelayout(); - } - else if( !mImpl->IsClipboardVisible() ) - { - // Reset the InputMethodContext to commit the pre-edit before selecting the text. - mImpl->ResetInputMethodContext(); - - Event event( Event::LONG_PRESS_EVENT ); - event.p1.mInt = static_cast( state ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - mImpl->RequestRelayout(); + return EventHandler::KeyEvent(*this, keyEvent); +} - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - } - } +void Controller::TapEvent( unsigned int tapCount, float x, float y ) +{ + EventHandler::TapEvent(*this, tapCount, x, y); } -void Controller::SelectEvent( float x, float y, SelectionType selectType ) +void Controller::PanEvent( GestureState state, const Vector2& displacement ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::SelectEvent\n" ); + EventHandler::PanEvent(*this, state, displacement); +} - if( NULL != mImpl->mEventData ) - { - if( selectType == SelectionType::ALL ) - { - Event event( Event::SELECT_ALL ); - mImpl->mEventData->mEventQueue.push_back( event ); - } - else if( selectType == SelectionType::NONE ) - { - Event event( Event::SELECT_NONE ); - mImpl->mEventData->mEventQueue.push_back( event ); - } - else - { - Event event( Event::SELECT ); - event.p2.mFloat = x; - event.p3.mFloat = y; - mImpl->mEventData->mEventQueue.push_back( event ); - } +void Controller::LongPressEvent( GestureState state, float x, float y ) +{ + EventHandler::LongPressEvent(*this, state, x, y); +} - mImpl->mEventData->mCheckScrollAmount = true; - mImpl->mEventData->mIsLeftHandleSelected = true; - mImpl->mEventData->mIsRightHandleSelected = true; - mImpl->RequestRelayout(); - } +void Controller::SelectEvent( float x, float y, SelectionType selectType ) +{ + EventHandler::SelectEvent(*this, x, y, selectType); } void Controller::SetTextSelectionRange(const uint32_t *start, const uint32_t *end) @@ -3236,142 +2202,12 @@ string Controller::GetSelectedText() const InputMethodContext::CallbackData Controller::OnInputMethodContextEvent( InputMethodContext& inputMethodContext, const InputMethodContext::EventData& inputMethodContextEvent ) { - // Whether the text needs to be relaid-out. - bool requestRelayout = false; - - // Whether to retrieve the text and cursor position to be sent to the InputMethodContext. - bool retrieveText = false; - bool retrieveCursor = false; - - switch( inputMethodContextEvent.eventName ) - { - case InputMethodContext::COMMIT: - { - InsertText( inputMethodContextEvent.predictiveString, Text::Controller::COMMIT ); - requestRelayout = true; - retrieveCursor = true; - break; - } - case InputMethodContext::PRE_EDIT: - { - InsertText( inputMethodContextEvent.predictiveString, Text::Controller::PRE_EDIT ); - requestRelayout = true; - retrieveCursor = true; - break; - } - case InputMethodContext::DELETE_SURROUNDING: - { - const bool textDeleted = RemoveText( inputMethodContextEvent.cursorOffset, - inputMethodContextEvent.numberOfChars, - DONT_UPDATE_INPUT_STYLE ); - - if( textDeleted ) - { - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - - requestRelayout = true; - } - break; - } - case InputMethodContext::GET_SURROUNDING: - { - retrieveText = true; - retrieveCursor = true; - break; - } - case InputMethodContext::PRIVATE_COMMAND: - { - // PRIVATECOMMAND event is just for getting the private command message - retrieveText = true; - retrieveCursor = true; - break; - } - case InputMethodContext::VOID: - { - // do nothing - break; - } - } // end switch - - if( requestRelayout ) - { - mImpl->mOperationsPending = ALL_OPERATIONS; - mImpl->RequestRelayout(); - } - - std::string text; - CharacterIndex cursorPosition = 0u; - Length numberOfWhiteSpaces = 0u; - - if( retrieveCursor ) - { - numberOfWhiteSpaces = mImpl->GetNumberOfWhiteSpaces( 0u ); - - cursorPosition = mImpl->GetLogicalCursorPosition(); - - if( cursorPosition < numberOfWhiteSpaces ) - { - cursorPosition = 0u; - } - else - { - cursorPosition -= numberOfWhiteSpaces; - } - } - - if( retrieveText ) - { - if( !mImpl->IsShowingPlaceholderText() ) - { - // Retrieves the normal text string. - mImpl->GetText( numberOfWhiteSpaces, text ); - } - else - { - // When the current text is Placeholder Text, the surrounding text should be empty string. - // It means DALi should send empty string ("") to IME. - text = ""; - } - } - - InputMethodContext::CallbackData callbackData( ( retrieveText || retrieveCursor ), cursorPosition, text, false ); - - if( requestRelayout && - ( NULL != mImpl->mEditableControlInterface ) ) - { - // Do this last since it provides callbacks into application code - mImpl->mEditableControlInterface->TextChanged(); - } - - return callbackData; + return EventHandler::OnInputMethodContextEvent(*this, inputMethodContext, inputMethodContextEvent); } void Controller::PasteClipboardItemEvent() { - // Retrieve the clipboard contents first - ClipboardEventNotifier notifier( ClipboardEventNotifier::Get() ); - std::string stringToPaste( notifier.GetContent() ); - - // Commit the current pre-edit text; the contents of the clipboard should be appended - mImpl->ResetInputMethodContext(); - - // Temporary disable hiding clipboard - mImpl->SetClipboardHideEnable( false ); - - // Paste - PasteText( stringToPaste ); - - mImpl->SetClipboardHideEnable( true ); + EventHandler::PasteClipboardItemEvent(*this); } // protected : Inherit from Text::Decorator::ControllerInterface. @@ -3405,138 +2241,14 @@ void Controller::SetEditable( bool editable ) void Controller::DecorationEvent( HandleType handleType, HandleState state, float x, float y ) { - DALI_ASSERT_DEBUG( mImpl->mEventData && "Unexpected DecorationEvent" ); - - if( NULL != mImpl->mEventData ) - { - switch( handleType ) - { - case GRAB_HANDLE: - { - Event event( Event::GRAB_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case LEFT_SELECTION_HANDLE: - { - Event event( Event::LEFT_SELECTION_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case RIGHT_SELECTION_HANDLE: - { - Event event( Event::RIGHT_SELECTION_HANDLE_EVENT ); - event.p1.mUint = state; - event.p2.mFloat = x; - event.p3.mFloat = y; - - mImpl->mEventData->mEventQueue.push_back( event ); - break; - } - case LEFT_SELECTION_HANDLE_MARKER: - case RIGHT_SELECTION_HANDLE_MARKER: - { - // Markers do not move the handles. - break; - } - case HANDLE_TYPE_COUNT: - { - DALI_ASSERT_DEBUG( !"Controller::HandleEvent. Unexpected handle type" ); - } - } - - mImpl->RequestRelayout(); - } + EventHandler::DecorationEvent(*this, handleType, state, x, y); } // protected : Inherit from TextSelectionPopup::TextPopupButtonCallbackInterface. void Controller::TextPopupButtonTouched( Dali::Toolkit::TextSelectionPopup::Buttons button ) { - if( NULL == mImpl->mEventData ) - { - return; - } - - switch( button ) - { - case Toolkit::TextSelectionPopup::CUT: - { - if (!IsEditable()) return; - mImpl->SendSelectionToClipboard( true ); // Synchronous call to modify text - mImpl->mOperationsPending = ALL_OPERATIONS; - - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - - mImpl->RequestRelayout(); - - if( NULL != mImpl->mEditableControlInterface ) - { - mImpl->mEditableControlInterface->TextChanged(); - } - break; - } - case Toolkit::TextSelectionPopup::COPY: - { - mImpl->SendSelectionToClipboard( false ); // Text not modified - - mImpl->mEventData->mUpdateCursorPosition = true; - - mImpl->RequestRelayout(); // Cursor, Handles, Selection Highlight, Popup - break; - } - case Toolkit::TextSelectionPopup::PASTE: - { - mImpl->RequestGetTextFromClipboard(); // Request clipboard service to retrieve an item - break; - } - case Toolkit::TextSelectionPopup::SELECT: - { - const Vector2& currentCursorPosition = mImpl->mEventData->mDecorator->GetPosition( PRIMARY_CURSOR ); - - if( mImpl->mEventData->mSelectionEnabled ) - { - // Creates a SELECT event. - SelectEvent( currentCursorPosition.x, currentCursorPosition.y, SelectionType::INTERACTIVE ); - } - break; - } - case Toolkit::TextSelectionPopup::SELECT_ALL: - { - // Creates a SELECT_ALL event - SelectEvent( 0.f, 0.f, SelectionType::ALL ); - break; - } - case Toolkit::TextSelectionPopup::CLIPBOARD: - { - mImpl->ShowClipboard(); - break; - } - case Toolkit::TextSelectionPopup::NONE: - { - // Nothing to do. - break; - } - } + EventHandler::TextPopupButtonTouched(*this, button); } void Controller::DisplayTimeExpired() @@ -4158,163 +2870,27 @@ void Controller::CalculateVerticalOffset( const Size& controlSize ) void Controller::ProcessModifyEvents() { - Vector& events = mImpl->mModifyEvents; - - if( 0u == events.Count() ) - { - // Nothing to do. - return; - } - - for( Vector::ConstIterator it = events.Begin(), - endIt = events.End(); - it != endIt; - ++it ) - { - const ModifyEvent& event = *it; - - if( ModifyEvent::TEXT_REPLACED == event.type ) - { - // A (single) replace event should come first, otherwise we wasted time processing NOOP events - DALI_ASSERT_DEBUG( it == events.Begin() && "Unexpected TEXT_REPLACED event" ); - - TextReplacedEvent(); - } - else if( ModifyEvent::TEXT_INSERTED == event.type ) - { - TextInsertedEvent(); - } - else if( ModifyEvent::TEXT_DELETED == event.type ) - { - // Placeholder-text cannot be deleted - if( !mImpl->IsShowingPlaceholderText() ) - { - TextDeletedEvent(); - } - } - } - - if( NULL != mImpl->mEventData ) - { - // When the text is being modified, delay cursor blinking - mImpl->mEventData->mDecorator->DelayCursorBlink(); - - // Update selection position after modifying the text - mImpl->mEventData->mLeftSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - mImpl->mEventData->mRightSelectionPosition = mImpl->mEventData->mPrimaryCursorPosition; - } - - // DISCARD temporary text - events.Clear(); + EventHandler::ProcessModifyEvents(*this); } void Controller::TextReplacedEvent() { - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model - mImpl->mOperationsPending = ALL_OPERATIONS; + EventHandler::TextReplacedEvent(*this); } void Controller::TextInsertedEvent() { - DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextInsertedEvent" ); - - if( NULL == mImpl->mEventData ) - { - return; - } - - mImpl->mEventData->mCheckScrollAmount = true; - - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model; TODO - Optimize this - mImpl->mOperationsPending = ALL_OPERATIONS; + EventHandler::TextInsertedEvent(*this); } void Controller::TextDeletedEvent() { - DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "Unexpected TextDeletedEvent" ); - - if( NULL == mImpl->mEventData ) - { - return; - } - - if (!IsEditable()) return; - - mImpl->mEventData->mCheckScrollAmount = true; - - // The natural size needs to be re-calculated. - mImpl->mRecalculateNaturalSize = true; - - // The text direction needs to be updated. - mImpl->mUpdateTextDirection = true; - - // Apply modifications to the model; TODO - Optimize this - mImpl->mOperationsPending = ALL_OPERATIONS; + EventHandler::TextDeletedEvent(*this); } bool Controller::DeleteEvent( int keyCode ) { - DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Controller::KeyEvent %p KeyCode : %d \n", this, keyCode ); - - bool removed = false; - - if( NULL == mImpl->mEventData ) - { - return removed; - } - - if (!IsEditable()) return false; - - // InputMethodContext is no longer handling key-events - mImpl->ClearPreEditFlag(); - - if( EventData::SELECTING == mImpl->mEventData->mState ) - { - removed = RemoveSelectedText(); - } - else if( ( mImpl->mEventData->mPrimaryCursorPosition > 0 ) && ( keyCode == Dali::DALI_KEY_BACKSPACE) ) - { - // Remove the character before the current cursor position - removed = RemoveText( -1, - 1, - UPDATE_INPUT_STYLE ); - } - else if( keyCode == Dali::DevelKey::DALI_KEY_DELETE ) - { - // Remove the character after the current cursor position - removed = RemoveText( 0, - 1, - UPDATE_INPUT_STYLE ); - } - - if( removed ) - { - if( ( 0u != mImpl->mModel->mLogicalModel->mText.Count() ) || - !mImpl->IsPlaceholderAvailable() ) - { - mImpl->QueueModifyEvent( ModifyEvent::TEXT_DELETED ); - } - else - { - ShowPlaceholderText(); - } - mImpl->mEventData->mUpdateCursorPosition = true; - mImpl->mEventData->mScrollAfterDelete = true; - } - - return removed; + return EventHandler::DeleteEvent(*this, keyCode); } // private : Helpers. @@ -4496,23 +3072,20 @@ Actor Controller::CreateBackgroundActor() // private : Private contructors & copy operator. Controller::Controller() -: mImpl( NULL ) +: Controller(nullptr, nullptr, nullptr) { - mImpl = new Controller::Impl( nullptr, nullptr, nullptr ); } Controller::Controller( ControlInterface* controlInterface ) +:Controller( controlInterface, nullptr, nullptr) { - mImpl = new Controller::Impl( controlInterface, NULL, NULL ); } Controller::Controller( ControlInterface* controlInterface, EditableControlInterface* editableControlInterface, SelectableControlInterface* selectableControlInterface ) +: mImpl(new Controller::Impl(controlInterface, editableControlInterface, selectableControlInterface)) { - mImpl = new Controller::Impl( controlInterface, - editableControlInterface, - selectableControlInterface ); } // The copy constructor and operator are left unimplemented. diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 3faab75..54444b1 100755 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_TEXT_CONTROLLER_H /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -1751,6 +1751,10 @@ public: private: + struct EventHandler; + struct InputFontHandler; + struct PlaceholderHandler; + Impl* mImpl; };