blob: 2d3a9e8c46a3efb691e9e4470b1523af80394845 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/painting.dart';
import 'box.dart';
import 'object.dart';
import 'paragraph.dart';
import 'proxy_box.dart' show SizeChangedCallback;
const _kCursorGap = 1.0; // pixels
const _kCursorHeightOffset = 2.0; // pixels
const _kCursorWidth = 1.0; // pixels
/// A render object used by EditableText widgets. This is similar to
/// RenderParagraph but also renders a cursor and provides support for
/// scrolling.
class RenderEditableParagraph extends RenderParagraph {
RenderEditableParagraph({
TextSpan text,
Color cursorColor,
bool showCursor,
this.onContentSizeChanged,
Offset scrollOffset
}) : _cursorColor = cursorColor,
_showCursor = showCursor,
_scrollOffset = scrollOffset,
super(text);
Color _cursorColor;
bool _showCursor;
SizeChangedCallback onContentSizeChanged;
Offset _scrollOffset;
Size _contentSize;
Color get cursorColor => _cursorColor;
void set cursorColor(Color value) {
if (_cursorColor == value)
return;
_cursorColor = value;
markNeedsPaint();
}
bool get showCursor => _showCursor;
void set showCursor(bool value) {
if (_showCursor == value)
return;
_showCursor = value;
markNeedsPaint();
}
Offset get scrollOffset => _scrollOffset;
void set scrollOffset(Offset value) {
if (_scrollOffset == value)
return;
_scrollOffset = value;
markNeedsPaint();
}
// Editable text does not support line wrap.
bool get allowLineWrap => false;
double _getIntrinsicWidth(BoxConstraints constraints) {
// There should be no difference between the minimum and maximum width
// because we only support single-line text.
layoutText(constraints);
return constraints.constrainWidth(
textPainter.size.width + _kCursorGap + _kCursorWidth
);
}
double getMinIntrinsicWidth(BoxConstraints constraints) {
return _getIntrinsicWidth(constraints);
}
double getMaxIntrinsicWidth(BoxConstraints constraints) {
return _getIntrinsicWidth(constraints);
}
void performLayout() {
layoutText(constraints);
Offset cursorPadding = const Offset(_kCursorGap + _kCursorWidth, 0.0);
Size newContentSize = textPainter.size + cursorPadding;
size = constraints.constrain(newContentSize);
if (_contentSize == null || _contentSize != newContentSize) {
_contentSize = newContentSize;
if (onContentSizeChanged != null)
onContentSizeChanged(newContentSize);
}
}
void paint(PaintingContext context, Offset offset) {
layoutText(constraints);
bool needsClipping = (_contentSize.width > size.width);
if (needsClipping) {
context.canvas.save();
context.canvas.clipRect(offset & size);
}
textPainter.paint(context.canvas, offset - _scrollOffset);
if (_showCursor) {
Rect cursorRect = new Rect.fromLTWH(
textPainter.size.width + _kCursorGap,
_kCursorHeightOffset,
_kCursorWidth,
size.height - 2.0 * _kCursorHeightOffset
);
context.canvas.drawRect(
cursorRect.shift(offset - _scrollOffset),
new Paint()..color = _cursorColor
);
}
if (needsClipping)
context.canvas.restore();
}
}