diff --git a/src/goryachev/rich/RichTextArea.java b/src/goryachev/rich/RichTextArea.java index 7d12b56d..ba210ca5 100644 --- a/src/goryachev/rich/RichTextArea.java +++ b/src/goryachev/rich/RichTextArea.java @@ -52,6 +52,7 @@ import javafx.scene.AccessibleRole; import javafx.scene.control.Control; import javafx.util.Duration; +import goryachev.rich.model.EditableRichTextModel; import goryachev.rich.model.StyleAttrs; import goryachev.rich.model.StyleInfo; import goryachev.rich.model.StyledTextModel; @@ -60,11 +61,9 @@ /** * Styled Text Area. * - * TODO line spacing property - * TODO content padding property - * TODO set size to content property + * TODO fit height property + * TODO fit width property * TODO highlight current line property - * TODO line count r/o property * * TODO add methods corresponding to the remaining Action tags */ @@ -123,11 +122,28 @@ public enum Cmd { private DoubleProperty lineSpacing; private BooleanProperty highlightCurrentLine; + /** + * Creates an editable instance with default configuration parameters, + * using an in-memory model {@link EditableRichTextModel}. + */ public RichTextArea() { - this(Config.defaultConfig()); + this(new EditableRichTextModel()); + } + + /** + * Creates an instance with default configuration parameters, using the specified model. + * @param model styled text model + */ + public RichTextArea(StyledTextModel model) { + this(Config.defaultConfig(), model); } - public RichTextArea(Config c) { + /** + * Creates an instance with the specified configuration parameters and model. + * @param c configuration parameters + * @param m styled text model + */ + public RichTextArea(Config c, StyledTextModel m) { this.config = c; caretBlinkPeriod = new ReadOnlyObjectWrapper<>(this, "caretBlinkPeriod", Duration.millis(config.caretBlinkPeriod)); @@ -139,6 +155,10 @@ public RichTextArea(Config c) { // TODO move to main stylesheet // TODO focus border around content area, not the whole thing? getStylesheets().add(Util.getResourceURL(getClass(), "RichTextArea.css")); + + if (m != null) { + setModel(m); + } } @Override @@ -163,17 +183,20 @@ public ObjectProperty modelProperty() { * then this variable indicates whether the text should wrap onto * another line. */ - // TODO perhaps all other properties need to be styleable properties? + // TODO perhaps all other properties also need to be styleable? private StyleableBooleanProperty wrapText = new StyleableBooleanProperty(false) { - @Override public Object getBean() { + @Override + public Object getBean() { return RichTextArea.this; } - @Override public String getName() { + @Override + public String getName() { return "wrapText"; } - @Override public CssMetaData getCssMetaData() { + @Override + public CssMetaData getCssMetaData() { return StyleableProperties.WRAP_TEXT; } }; diff --git a/src/goryachev/rich/RichTextAreaBehavior.java b/src/goryachev/rich/RichTextAreaBehavior.java index 417bc63a..03b19c8b 100644 --- a/src/goryachev/rich/RichTextAreaBehavior.java +++ b/src/goryachev/rich/RichTextAreaBehavior.java @@ -549,91 +549,6 @@ protected void moveCharacter(boolean moveRight, boolean extendSelection) { control.moveCaret(p, extendSelection); } } - - @Deprecated // FIX remove - protected void moveWord(boolean moveRight, boolean extendSelection) { - // TODO -// TextPos caret = control.getCaretPosition(); -// if (caret == null) { -// return; -// } -// -// clearPhantomX(); -// -// if(!extendSelection) { -// TextPos ca = control.getCaretPosition(); -// TextPos an = control.getAnchorPosition(); -// int d = ca.compareTo(an); -// // jump over selection if it exists -// if (d < 0) { -// control.moveCaret(moveRight ? an : ca, extendSelection); -// return; -// } else if(d > 0) { -// control.moveCaret(moveRight ? ca : an, extendSelection); -// return; -// } -// } -// -// TextPos p = moveWord2(caret, moveRight); -// if (p != null) { -// control.moveCaret(p, extendSelection); -// } - } - - @Deprecated // FIX remove - protected TextPos moveWord2(TextPos start, boolean moveRight) { - if (isRTL()) { - moveRight = !moveRight; - } - - TextCell cell = vflow().getCell(start.index()); - int cix = start.offset(); - if (moveRight) { - cix++; - if (cix > cell.getTextLength()) { - int line = cell.getIndex() + 1; - TextPos p; - if (line < control.getParagraphCount()) { - // next line - p = new TextPos(line, 0); - } else { - // end of last paragraph w/o newline - p = new TextPos(cell.getIndex(), cell.getTextLength()); - } - return p; - } - } else { - if (start.offset() == 0) { - int line = cell.getIndex() - 1; - if (line >= 0) { - // prev line - TextCell prevCell = vflow().getCell(line); - cix = prevCell.getTextLength(); - return new TextPos(line, cix); - } - return null; - } - } - - // using default locale, same as TextInputControl.backward() for example - BreakIterator br = BreakIterator.getCharacterInstance(); - String text = getPlainText(cell.getIndex()); - br.setText(text); - int off = start.offset(); - try { - int ix = moveRight ? br.following(off) : br.preceding(off); - if (ix == BreakIterator.DONE) { - System.err.println(" --- SHOULD NOT HAPPEN: BreakIterator.DONE off=" + off); // FIX - return null; - } - return new TextPos(start.index(), ix); - } catch(Exception e) { - // TODO need to use a logger! - System.err.println("offset=" + off + " text=[" + text + "]"); - e.printStackTrace(); - return null; - } - } protected TextPos nextCharacterVisually(TextPos start, boolean moveRight) { if (isRTL()) { diff --git a/src/goryachev/rich/util/InputMap2.java b/src/goryachev/rich/util/InputMap2.java index e455801d..747f8c47 100644 --- a/src/goryachev/rich/util/InputMap2.java +++ b/src/goryachev/rich/util/InputMap2.java @@ -30,8 +30,8 @@ import javafx.scene.input.KeyCode; /** - * Input Map maps KeyBindings(2) to Action IDs (any object but Runnable or FxAction, typically an enum) and - * Action IDs to the actual actions (Runnable, FxAction, or lambda). + * Input Map maps KeyBindings(2) to function tags (any object except Runnable), + * followed by mapping from tags to the actual Runnable function. * * The input map may not be limited to a keyboard event, so looking up an action from an Action ID for a * built-in functionality such as copy, paste, etc. is also permitted. @@ -47,19 +47,19 @@ * - maps action ids to methods in the behavior */ public class InputMap2 { - // keyBinding2 -> Runnable (FIX: Action tag) - // Action -> Runnable + // keyBinding2 -> tag + // tag -> Runnable private final HashMap map = new HashMap<>(); public InputMap2() { } - /** adds a mapping: actionTag -> function */ - public void add(Object actionTag, Runnable function) { - map.put(actionTag, function); + /** adds a mapping: tag -> function */ + public void add(Object tag, Runnable function) { + map.put(tag, function); } - /** adds a mapping: keyBinding -> actionTag */ + /** adds a mapping: keyBinding -> tag */ public void add(Object actionTag, KeyCode code, KCondition... modifiers) { // TODO check for nulls KeyBinding2 k = KeyBinding2.of(code, modifiers); @@ -97,11 +97,7 @@ public Runnable getFunction(Object k) { } return null; } - - // TODO this should return FxAction which app developer can enable/disable - /* - public FxAction getAction(Object tag) { - // map can hold Actions as well - } - */ + + // TODO restore function for tag + // TODO restore key binding for tag }