Skip to content

Commit

Permalink
Add CaretSelection
Browse files Browse the repository at this point in the history
  • Loading branch information
naotsugu committed Feb 2, 2024
1 parent 3848587 commit ab6fe85
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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());

}
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -195,6 +196,11 @@ public CaretLine cloneAt(long offset) {
}


OffsetPoint point() {
return (line == null) ? null : line.offsetPoint(bar.offset());
}


LayoutLine getLine() {
return line;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -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<CaretSelection> carets;


public CaretSelections(List<CaretSelection> carets) {
this.carets = carets;
}


public static CaretSelections of(List<CaretLine> 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);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -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());

}
}

}

}
Loading

0 comments on commit ab6fe85

Please sign in to comment.