Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Merge "InputFieldDelegate refactoring" into androidx-master-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Treehugger Robot authored and Gerrit Code Review committed Jul 10, 2019
2 parents a050bb4 + 86d9a63 commit 407cdf8
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 134 deletions.
57 changes: 33 additions & 24 deletions ui/ui-framework/src/main/java/androidx/ui/core/InputField.kt
Original file line number Diff line number Diff line change
Expand Up @@ -92,52 +92,61 @@ fun InputField(
/** Called when the InputMethod requested an editor action */
onEditorActionPerformed: (Any) -> Unit = {} // TODO(nona): Define argument type
) {
// Ambients
val style = +ambient(CurrentTextStyleAmbient)
val mergedStyle = style.merge(editorStyle.textStyle)
val textInputService = +ambient(TextInputServiceAmbient)
val hasFocus = +state { false }

val processor = +memo { EditProcessor() }
processor.onNewState(value, textInputService)

val density = +ambient(DensityAmbient)
val resourceLoader = +ambient(FontLoaderAmbient)

// TODO(nona): Add parameter for text direction, softwrap, etc.
val delegate = InputFieldDelegate(
// Memos
val processor = +memo { EditProcessor() }
val mergedStyle = style.merge(editorStyle.textStyle)
val textPainter = +memo(value, mergedStyle, density, resourceLoader) {
// TODO(nona): Add parameter for text direction, softwrap, etc.
TextPainter(
text = AnnotatedString(text = value.text),
style = mergedStyle,
density = density,
resourceLoader = resourceLoader
),
processor,
onValueChange
)
)
}

// States
val hasFocus = +state { false }

processor.onNewState(value, textInputService)
TextInputEventObserver(
onPress = { delegate.onPress(textInputService) },
onPress = { InputFieldDelegate.onPress(textInputService) },
onFocus = {
hasFocus.value = true
textInputService?.startInput(
initState = value,
keyboardType = keyboardType,
onEditCommand = { delegate.onEditCommand(it) },
onEditorActionPerformed = onEditorActionPerformed)
InputFieldDelegate.onFocus(
textInputService,
value,
processor,
keyboardType,
onValueChange,
onEditorActionPerformed)
},
onBlur = {
hasFocus.value = false
textInputService?.stopInput()
InputFieldDelegate.onBlur(textInputService)
},
onDragAt = { delegate.onDragAt(it) },
onRelease = { delegate.onRelease(it) }
onDragAt = { InputFieldDelegate.onDragAt(it) },
onRelease = { InputFieldDelegate.onRelease(it, textPainter, processor, onValueChange) }
) {
Layout(
children = @Composable {
Draw { canvas, _ -> delegate.draw(canvas, value, editorStyle, hasFocus.value) }
Draw { canvas, _ -> InputFieldDelegate.draw(
canvas,
value,
textPainter,
hasFocus.value,
editorStyle) }
},
layoutBlock = { _, constraints ->
delegate.layout(constraints).let { layout(it.first, it.second) {} }
InputFieldDelegate.layout(textPainter, constraints).let {
layout(it.first, it.second) {}
}
}
)
}
Expand Down Expand Up @@ -248,4 +257,4 @@ private fun DragPositionGestureDetector(
children()
}
}
}
}
235 changes: 142 additions & 93 deletions ui/ui-framework/src/main/java/androidx/ui/core/InputFieldDelegate.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,110 +21,159 @@ import androidx.ui.engine.geometry.Offset
import androidx.ui.input.EditOperation
import androidx.ui.input.EditProcessor
import androidx.ui.input.EditorState
import androidx.ui.input.KeyboardType
import androidx.ui.input.SetSelectionEditOp
import androidx.ui.input.TextInputService
import androidx.ui.painting.Canvas
import androidx.ui.text.TextPainter

/**
* Delegate class of the UI implementation of the InputField.
*/
internal class InputFieldDelegate(
/**
* A text painter used for this InputField
*/
private val textPainter: TextPainter,

/**
* An edit processor used for this InputField
*/
private val editProcessor: EditProcessor,

/**
* A callback called when new editor state is created.
*/
private val onValueChange: (EditorState) -> Unit
) {
internal class InputFieldDelegate {
companion object {
/**
* Process text layout with given constraint.
*
* @param textPainter The text painter
* @param constraints The layout constraints
* @return the bounding box size(width and height) of the layout result
*/
@JvmStatic
fun layout(textPainter: TextPainter, constraints: Constraints): Pair<IntPx, IntPx> {
textPainter.layout(constraints)
return Pair(textPainter.width.px.round(), textPainter.height.px.round())
}

/**
* Process text layout with given constraint.
*
* @param constraints the layout constraints
* @return the bounding box size(width and height) of the layout result
*/
fun layout(constraints: Constraints): Pair<IntPx, IntPx> {
textPainter.layout(constraints)
return Pair(textPainter.width.px.round(), textPainter.height.px.round())
}
/**
* Draw the text content to the canvas
*
* @param canvas The target canvas.
* @param value The editor state
* @param textPainter The text painter
* @param hasFocus true if this widget is focused, otherwise false
* @param editorStyle The editor style.
*/
@JvmStatic
fun draw(
canvas: Canvas,
value: EditorState,
textPainter: TextPainter,
hasFocus: Boolean,
editorStyle: EditorStyle
) {
value.composition?.let {
textPainter.paintBackground(
it.start,
it.end,
editorStyle.compositionColor,
canvas,
Offset.zero
)
}
if (value.selection.collapsed) {
if (hasFocus) {
textPainter.paintCursor(value.selection.start, canvas)
}
} else {
textPainter.paintBackground(
value.selection.start,
value.selection.end,
editorStyle.selectionColor,
canvas,
Offset.zero
)
}
textPainter.paint(canvas, Offset.zero)
}

/**
* Draw the text content to the canvas
*
* @param canvas the target canvas.
* @param value the editor state.
* @param editorStyle the editor style.
*/
fun draw(canvas: Canvas, value: EditorState, editorStyle: EditorStyle, drawCursor: Boolean) {
value.composition?.let {
textPainter.paintBackground(
it.start,
it.end,
editorStyle.compositionColor,
canvas,
Offset.zero
)
/**
* Called when edit operations are passed from TextInputService
*
* @param ops A list of edit operations.
* @param editProcessor The edit processor
* @param onValueChange The callback called when the new editor state arrives.
*/
@JvmStatic
internal fun onEditCommand(
ops: List<EditOperation>,
editProcessor: EditProcessor,
onValueChange: (EditorState) -> Unit
) {
onValueChange(editProcessor.onEditCommands(ops))
}
if (value.selection.collapsed) {
if (drawCursor) {
textPainter.paintCursor(value.selection.start, canvas)
}
} else {
textPainter.paintBackground(
value.selection.start,
value.selection.end,
editorStyle.selectionColor,
canvas,
Offset.zero
)

/**
* Called when onPress event is fired.
*
* @param textInputService The text input service
*/
@JvmStatic
fun onPress(textInputService: TextInputService?) {
textInputService?.showSoftwareKeyboard()
}
textPainter.paint(canvas, Offset.zero)
}

/**
* Called when edit operations are passed from TextInputService
*
* @param ops A list of edit operations.
*/
fun onEditCommand(ops: List<EditOperation>) {
onValueChange(editProcessor.onEditCommands(ops))
}
/**
* Called when onDrag event is fired.
*
* @param position The event position in widget coordinate.
*/
@JvmStatic
fun onDragAt(position: PxPosition) {
// TODO(nona): Implement this function
Log.d("InputFieldDelegate", "onDrag: $position")
}

/**
* Called when onPress event is fired.
*
* @param position The event position in widget coordinate.
*/
fun onPress(textInputService: TextInputService?) {
textInputService?.showSoftwareKeyboard()
}
/**
* Called when onRelease event is fired.
*
* @param position The event position in widget coordinate.
* @param textPainter The text painter
* @param editProcessor The edit processor
* @param onValueChange The callback called when the new editor state arrives.
*/
@JvmStatic
fun onRelease(
position: PxPosition,
textPainter: TextPainter,
editProcessor: EditProcessor,
onValueChange: (EditorState) -> Unit
) {
val offset = textPainter.getPositionForOffset(position.toOffset())
onEditCommand(listOf(SetSelectionEditOp(offset, offset)), editProcessor, onValueChange)
}

/**
* Called when onDrag event is fired.
*
* @param position The event position in widget coordinate.
*/
fun onDragAt(position: PxPosition) {
// TODO(nona): Implement this function
Log.d("InputFieldDelegate", "onDrag: $position")
}
/**
* Called when the widget gained input focus
*
* @param textInputService The text input service
* @param value The editor state
* @param editProcessor The edit processor
* @param keyboardType The keyboard type
* @param onValueChange The callback called when the new editor state arrives.
* @param onEditorActionPerformed The callback called when the editor action arrives.
*/
@JvmStatic
fun onFocus(
textInputService: TextInputService?,
value: EditorState,
editProcessor: EditProcessor,
keyboardType: KeyboardType,
onValueChange: (EditorState) -> Unit,
onEditorActionPerformed: (Any) -> Unit
) {
textInputService?.startInput(
initState = value,
keyboardType = keyboardType,
onEditCommand = { onEditCommand(it, editProcessor, onValueChange) },
onEditorActionPerformed = onEditorActionPerformed)
}

/**
* Called when onRelease event is fired.
*
* @param position The event position in widget coordinate.
*/
fun onRelease(position: PxPosition) {
val offset = textPainter.getPositionForOffset(position.toOffset())
onEditCommand(listOf(SetSelectionEditOp(offset, offset)))
/**
* Called when the widget loses input focus
*
* @param textInputService The text input service
*/
@JvmStatic
fun onBlur(textInputService: TextInputService?) {
textInputService?.stopInput()
}
}
}
}

0 comments on commit 407cdf8

Please sign in to comment.