From ab6fe85c50b91793619e2427e5250f55ca11af99 Mon Sep 17 00:00:00 2001 From: Naotsugu Kobayashi Date: Fri, 2 Feb 2024 20:24:10 +0900 Subject: [PATCH] Add CaretSelection --- .../mammb/code/editor/ui/model/Selection.java | 23 +---- .../code/editor/ui/model/SelectionDraw.java | 90 +++++++++++++++++++ .../code/editor/ui/model/impl/CaretLine.java | 6 ++ .../editor/ui/model/impl/CaretSelection.java | 75 ++++++++++++++++ .../editor/ui/model/impl/CaretSelections.java | 58 ++++++++++++ .../editor/ui/model/impl/SelectionImpl.java | 42 --------- .../editor/ui/model/impl/SubSelection.java | 32 ++++++- 7 files changed, 262 insertions(+), 64 deletions(-) create mode 100644 modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/SelectionDraw.java create mode 100644 modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelection.java create mode 100644 modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelections.java diff --git a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/Selection.java b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/Selection.java index 44e37a9b..173b0412 100644 --- a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/Selection.java +++ b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/Selection.java @@ -16,15 +16,13 @@ package com.mammb.code.editor.ui.model; import com.mammb.code.editor.model.buffer.Metrics; -import com.mammb.code.editor.model.layout.TextRun; import com.mammb.code.editor.model.text.OffsetPoint; -import javafx.scene.canvas.GraphicsContext; /** * Selection. * @author Naotsugu Kobayashi */ -public interface Selection { +public interface Selection extends SelectionDraw { /** * Start select. @@ -79,15 +77,6 @@ public interface Selection { */ boolean isDragging(); - /** - * Draw the selection. - * @param gc the graphics context - * @param run the text run - * @param offsetY the position y - * @param left the left position of run(margin included) - */ - void draw(GraphicsContext gc, TextRun run, double offsetY, double left); - /** * Select all. * @param metrics the metrics @@ -105,10 +94,7 @@ default long length() { return started() ? max().offset() - min().offset() : 0; } - /** - * Get the min select offset. - * @return the min select offset - */ + @Override default OffsetPoint min() { if (startOffset() == null && endOffset() == null) { return null; @@ -121,10 +107,7 @@ default OffsetPoint min() { } } - /** - * Get the max select offset. - * @return the max select offset - */ + @Override default OffsetPoint max() { if (startOffset() == null && endOffset() == null) { return null; diff --git a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/SelectionDraw.java b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/SelectionDraw.java new file mode 100644 index 00000000..ea578203 --- /dev/null +++ b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/SelectionDraw.java @@ -0,0 +1,90 @@ +/* + * Copyright 2023-2024 the original author or authors. + * + * 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 + * + * https://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. + */ +package com.mammb.code.editor.ui.model; + +import com.mammb.code.editor.javafx.layout.FxFonts; +import com.mammb.code.editor.model.layout.TextRun; +import com.mammb.code.editor.model.text.OffsetPoint; +import javafx.scene.canvas.GraphicsContext; +import javafx.scene.paint.Color; +import java.util.Objects; + +/** + * SelectionDraw. + * @author Naotsugu Kobayashi + */ +public interface SelectionDraw { + + /** The color. */ + Color color = new Color(0.6784314F, 0.84705883F, 0.9019608F, 0.3); + + /** + * Get the min select offset. + * @return the min select offset + */ + OffsetPoint min(); + + /** + * Get the max select offset. + * @return the max select offset + */ + OffsetPoint max(); + + + /** + * Draw the selection. + * @param gc the graphics context + * @param run the text run + * @param offsetY the position y + * @param left the left position of run(margin included) + */ + default void draw(GraphicsContext gc, TextRun run, double offsetY, double left) { + + final OffsetPoint min = min(); + final OffsetPoint max = max(); + + if (min == null || Objects.equals(min, max)) { + return; + } + + long runStart = run.offset(); + long runEnd = runStart + run.length(); + + if (max().offset() >= runStart && min().offset() < runEnd) { + + final String text = run.text(); + + if (runEnd <= max().offset() && + ((text.length() == 1 && text.charAt(0) == '\n') || + (text.length() == 2 && text.charAt(0) == '\r' && text.charAt(1) == '\n'))) { + + gc.setFill(color); + gc.fillRect(run.layout().x() + left, offsetY, FxFonts.uppercaseLetterWidth(gc.getFont()), run.textLine().leadingHeight()); + + } else { + + double x1 = run.offsetToX().apply(Math.toIntExact(Math.max(min().offset(), runStart) - runStart)); + double x2 = run.offsetToX().apply(Math.toIntExact(Math.min(max().offset(), runEnd) - runStart)); + + gc.setFill(color); + gc.fillRect(x1 + left, offsetY, x2 - x1, run.textLine().leadingHeight()); + + } + } + + } + +} diff --git a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretLine.java b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretLine.java index 5ebaa436..7d0fee38 100644 --- a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretLine.java +++ b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretLine.java @@ -15,6 +15,7 @@ */ package com.mammb.code.editor.ui.model.impl; +import com.mammb.code.editor.model.text.OffsetPoint; import com.mammb.code.editor.ui.model.LayoutLine; import javafx.scene.canvas.GraphicsContext; import java.util.Objects; @@ -195,6 +196,11 @@ public CaretLine cloneAt(long offset) { } + OffsetPoint point() { + return (line == null) ? null : line.offsetPoint(bar.offset()); + } + + LayoutLine getLine() { return line; } diff --git a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelection.java b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelection.java new file mode 100644 index 00000000..09e4b9be --- /dev/null +++ b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelection.java @@ -0,0 +1,75 @@ +/* + * Copyright 2023-2024 the original author or authors. + * + * 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 + * + * https://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. + */ +package com.mammb.code.editor.ui.model.impl; + +import com.mammb.code.editor.model.text.OffsetPoint; +import com.mammb.code.editor.ui.model.SelectionDraw; + +/** + * CaretSelection. + * @author Naotsugu Kobayashi + */ +public class CaretSelection implements SelectionDraw { + + /** The selection open offset. */ + private final OffsetPoint start; + + /** The selection close offset caret. */ + private final CaretLine caretLine; + + + /** + * Constructor. + * @param caretLine the caret + */ + public CaretSelection(CaretLine caretLine) { + if (caretLine == null) { + this.start = null; + this.caretLine = null; + } else { + this.start = caretLine.point(); + this.caretLine = caretLine; + } + } + + + public boolean isInvalid() { + return start == null || caretLine.getLine() == null; + } + + + @Override + public OffsetPoint min() { + if (isInvalid()) { + return null; + } + return (start.offset() <= caretLine.getBar().offset()) + ? start + : caretLine.point(); + } + + + @Override + public OffsetPoint max() { + if (isInvalid()) { + return null; + } + return (start.offset() <= caretLine.getBar().offset()) + ? caretLine.point() + : start; + } + +} diff --git a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelections.java b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelections.java new file mode 100644 index 00000000..0f178bab --- /dev/null +++ b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/CaretSelections.java @@ -0,0 +1,58 @@ +/* + * Copyright 2023-2024 the original author or authors. + * + * 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 + * + * https://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. + */ +package com.mammb.code.editor.ui.model.impl; + +import com.mammb.code.editor.model.layout.TextRun; +import javafx.scene.canvas.GraphicsContext; +import java.util.List; +import java.util.stream.Collectors; + +/** + * CaretSelections. + * @author Naotsugu Kobayashi + */ +public class CaretSelections { + + private final List carets; + + + public CaretSelections(List carets) { + this.carets = carets; + } + + + public static CaretSelections of(List caretLines) { + return new CaretSelections(caretLines.stream() + .map(CaretSelection::new) + .collect(Collectors.toList())); + } + + public void draw(GraphicsContext gc, TextRun run, double offsetY, double left) { + carets.removeIf(CaretSelection::isInvalid); + carets.forEach(c -> c.draw(gc, run, offsetY, left)); + } + + + public void clear() { + carets.clear(); + } + + + private void ensureValid() { + carets.removeIf(CaretSelection::isInvalid); + } + +} diff --git a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SelectionImpl.java b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SelectionImpl.java index 2e705865..67839f5c 100644 --- a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SelectionImpl.java +++ b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SelectionImpl.java @@ -15,12 +15,8 @@ */ package com.mammb.code.editor.ui.model.impl; -import com.mammb.code.editor.javafx.layout.FxFonts; -import com.mammb.code.editor.model.layout.TextRun; import com.mammb.code.editor.model.text.OffsetPoint; import com.mammb.code.editor.ui.model.Selection; -import javafx.scene.canvas.GraphicsContext; -import javafx.scene.paint.Color; /** * SelectionImpl. @@ -37,10 +33,6 @@ public class SelectionImpl implements Selection { /** The selection dragging. */ private boolean dragging = false; - /** The color. */ - private Color color = new Color(0.6784314F, 0.84705883F, 0.9019608F, 0.3); - - @Override public void start(OffsetPoint offset) { start = end = offset; @@ -89,38 +81,4 @@ public boolean started() { return start != null; } - @Override - public void draw(GraphicsContext gc, TextRun run, double top, double left) { - - if (!started()) { - return; - } - - long runStart = run.offset(); - long runEnd = runStart + run.length(); - - if (max().offset() >= runStart && min().offset() < runEnd) { - - final String text = run.text(); - - if (runEnd <= max().offset() && - ((text.length() == 1 && text.charAt(0) == '\n') || - (text.length() == 2 && text.charAt(0) == '\r' && text.charAt(1) == '\n'))) { - - gc.setFill(color); - gc.fillRect(run.layout().x() + left, top, FxFonts.uppercaseLetterWidth(gc.getFont()), run.textLine().leadingHeight()); - - } else { - - double x1 = run.offsetToX().apply(Math.toIntExact(Math.max(min().offset(), runStart) - runStart)); - double x2 = run.offsetToX().apply(Math.toIntExact(Math.min(max().offset(), runEnd) - runStart)); - - gc.setFill(color); - gc.fillRect(x1 + left, top, x2 - x1, run.textLine().leadingHeight()); - - } - } - - } - } diff --git a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SubSelection.java b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SubSelection.java index 9559adae..b542a806 100644 --- a/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SubSelection.java +++ b/modules/ui-model/src/main/java/com/mammb/code/editor/ui/model/impl/SubSelection.java @@ -15,7 +15,10 @@ */ package com.mammb.code.editor.ui.model.impl; +import com.mammb.code.editor.model.text.OffsetPoint; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; /** * SubSelection. @@ -23,10 +26,35 @@ */ public class SubSelection { - private List moonRefs; + record Pair(OffsetPoint point, CaretLine caretLine) { } + + private final List pairs; + public SubSelection(List moonRefs) { - this.moonRefs = moonRefs; + this.pairs = moonRefs.stream() + .map(SubSelection::pairOf) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + + public void clear() { + pairs.clear(); + } + + + private void ensureScope() { + pairs.removeIf(p -> p.caretLine().getLine() == null); + } + + + private static Pair pairOf(CaretLine caretLine) { + if (caretLine == null) { + return null; + } + OffsetPoint p = caretLine.point(); + return (p == null) ? null : new Pair(p, caretLine); } }