use of com.helospark.tactview.ui.javafx.uicomponents.canvasdraw.domain.TimelineUiCacheElement in project tactview by helospark.
the class TimelineCanvasOnDragOverHandler method onDrag.
public boolean onDrag(double x, double y, boolean finished, TimelineCanvasOnDragOverHandlerRequest request) {
TimelinePosition position = request.xPosition;
if ((dragRepository.currentEffectDragInformation() != null || dragRepository.currentlyDraggedClip() != null)) {
acceptTransferMode(request);
if (!pressedKeyRepository.isKeyDown(KeyCode.CONTROL)) {
selectElementOnMouseDrag();
}
if (dragRepository.currentlyDraggedClip() != null) {
if (!dragRepository.isResizing()) {
TimelinePosition newX = TimelinePosition.ofSeconds(position.getSeconds().doubleValue() - dragRepository.currentlyDraggedClip().getAnchorPointX());
String channelId = request.channel.map(a -> a.getId()).orElse(timelineAccessor.getChannels().get(0).getId());
Optional<TimelineClip> insertBeforeClip = getInsertBefore(request, channelId);
if (insertBeforeClip.isPresent()) {
if (dragRepository.getClipDragInformation().getHasMovedWithoutRevert()) {
// so revert works properly
timelineDragAndDropHandler.moveClip(channelId, true, newX);
}
timelineDragAndDropHandler.insertClipBefore(insertBeforeClip.get());
timelineAccessor.findClipById(dragRepository.getClipDragInformation().getClipIds().get(0)).map(a -> a.getInterval()).ifPresent(interval -> dragRepository.getClipDragInformation().setOriginalInterval(interval));
} else {
if (dragRepository.currentlyDraggedClip().shouldCopyClip()) {
copyCurrentClipOnDrag(dragRepository.currentlyDraggedClip().getClipIds(), channelId, newX);
} else {
timelineDragAndDropHandler.moveClip(channelId, finished, newX);
}
}
} else {
TimelinePosition newX = position;
TimelinePosition relativeMove = position.subtract(dragRepository.currentlyDraggedClip().getLastPosition());
timelineDragAndDropHandler.resizeClip(newX, finished, relativeMove);
}
dragRepository.currentlyDraggedClip().setLastPosition(position);
return true;
} else if (dragRepository.currentEffectDragInformation() != null) {
acceptTransferMode(request);
if (dragRepository.isResizing()) {
TimelinePosition newX = position;
timelineDragAndDropHandler.resizeEffect(newX, finished);
} else {
Optional<TimelineUiCacheElement> optionalElementUnderCursor = request.selectedElement;
TimelinePosition newX = TimelinePosition.ofSeconds(position.getSeconds().doubleValue() - dragRepository.currentEffectDragInformation().getAnchorPointX());
if (optionalElementUnderCursor.isPresent() && optionalElementUnderCursor.get().elementType == TimelineUiCacheType.CLIP && isClipIdDifferentThanClipUnderCursorAndSupported(optionalElementUnderCursor.get())) {
timelineDragAndDropHandler.moveEffectToDifferentParent(optionalElementUnderCursor.get().elementId, newX);
} else {
timelineDragAndDropHandler.moveEffect(newX, finished);
}
}
return true;
}
}
return false;
}
use of com.helospark.tactview.ui.javafx.uicomponents.canvasdraw.domain.TimelineUiCacheElement in project tactview by helospark.
the class TimelineCanvas method onMouseMoved.
private void onMouseMoved(double x, double y, MouseEvent event) {
Optional<TimelineUiCacheElement> optionalElement = findElementAt(x, y);
if (optionalElement.isPresent()) {
var element = optionalElement.get();
boolean isResizing = timelineCanvasElementClickHandler.isResizing(element, x);
if (isResizing) {
canvas.setCursor(Cursor.H_RESIZE);
} else {
canvas.setCursor(Cursor.HAND);
}
} else {
canvas.setCursor(null);
}
if (y < TIMELINE_TIMESCALE_HEIGHT) {
boolean success = false;
for (var marker : markerRepository.getMarkers().entrySet()) {
double markerPosition = timelineState.secondsToPixelsWithZoom(marker.getKey());
double mousePosition = x;
if (Math.abs(markerPosition - mousePosition) < 5) {
if (tooltip != null && marker.getKey().equals(lastMarkerShownPosition)) {
success = true;
break;
} else
closeTooltip();
tooltip = new Tooltip(marker.getValue().describe());
Point2D sceneCoordinates = canvas.localToScene(markerPosition, TIMELINE_TIMESCALE_HEIGHT);
tooltip.show(canvas, sceneCoordinates.getX(), sceneCoordinates.getY());
lastMarkerShownPosition = marker.getKey();
success = true;
break;
}
}
if (!success) {
closeTooltip();
}
} else {
closeTooltip();
}
}
use of com.helospark.tactview.ui.javafx.uicomponents.canvasdraw.domain.TimelineUiCacheElement in project tactview by helospark.
the class TimelineCanvas method create.
public BorderPane create(BorderPane timelineTitlesBorderPane) {
BorderPane centerPane = new BorderPane();
centerPane.getStyleClass().add("timeline-pane");
this.bottomBar = new ScrollBar();
bottomBar.getStyleClass().add("timeline-bottom-scroll-bar");
bottomBar.setMin(0);
bottomBar.setMax(100.0);
bottomBar.setUnitIncrement(100);
bottomBar.setBlockIncrement(100);
bottomBar.setVisibleAmount(500);
bottomBar.setValue(0.0);
bottomBar.valueProperty().addListener(e -> {
timelineState.setTranslate(bottomBar.getValue());
});
this.rightBar = new ScrollBar();
rightBar.setMin(0);
rightBar.setMax(100.0);
rightBar.setUnitIncrement(100);
rightBar.setBlockIncrement(100);
rightBar.setVisibleAmount(200);
rightBar.setValue(0.0);
rightBar.getStyleClass().add("timeline-right-scroll-bar");
rightBar.setOrientation(Orientation.VERTICAL);
this.canvas = new Canvas(600, 200);
this.graphics = canvas.getGraphicsContext2D();
Pane wrapperPane = new Pane();
wrapperPane.getChildren().add(canvas);
canvas.widthProperty().bind(wrapperPane.widthProperty());
canvas.heightProperty().bind(wrapperPane.heightProperty());
canvas.widthProperty().addListener(e -> redraw(true));
canvas.heightProperty().addListener(e -> redraw(true));
centerPane.setRight(rightBar);
centerPane.setBottom(bottomBar);
centerPane.setCenter(wrapperPane);
resultPane = new BorderPane();
resultPane.setLeft(timelineTitlesBorderPane);
resultPane.setCenter(centerPane);
timelineState.subscribe(type -> {
boolean fullRedraw = true;
if (type.getType().equals(UiTimelineChangeType.TIMELINE_POSITION) || type.getType().equals(UiTimelineChangeType.SPECIAL_LINE_POSITION)) {
fullRedraw = false;
}
this.redraw(fullRedraw);
});
messagingService.register(TimelinePatternChangedMessage.class, message -> {
Optional<TimelineClip> clip = timelineAccessor.findClipById(message.getComponentId());
Optional<Integer> channelIndex = timelineAccessor.findChannelIndexForClipId(message.getComponentId());
if (clip.isPresent() && channelIndex.isPresent() && isVisible(clip.get().getGlobalInterval(), channelIndex.get())) {
redraw(true);
}
});
canvas.setOnScroll(e -> {
if (e.isControlDown()) {
onZoom(e.getDeltaY(), new Point2D(e.getX(), e.getY()));
} else {
onScrollVertically(e);
}
});
rightBar.valueProperty().addListener(e -> {
double normalizedScroll = rightBar.getValue() / rightBar.getMax();
timelineState.setNormalizedVScroll(normalizedScroll);
});
canvas.setOnMouseMoved(event -> {
onMouseMoved(event.getX(), event.getY(), event);
if (!event.isPrimaryButtonDown()) {
dragRepository.clean();
timelineState.getMoveSpecialPointLineProperties().setEnabled(false);
selectionBox = null;
}
});
canvas.setOnMouseExited(event -> {
closeTooltip();
});
canvas.setOnMousePressed(event -> {
if (scene.getFocusOwner() instanceof Control) {
// remove focus from any control element
JavaFXUiMain.canvas.requestFocus();
}
double position = mapCanvasPixelToTime(event.getX());
double currentX = position;
Optional<TimelineUiCacheElement> optionalElement = findElementAt(event.getX(), event.getY());
if (event.getY() < TIMELINE_TIMESCALE_HEIGHT) {
TimelineCanvasTimelineHeaderClickHandlerRequest timelineCanvasTimelineHeaderClickHandlerRequest = TimelineCanvasTimelineHeaderClickHandlerRequest.builder().withEvent(event).withPosition(TimelinePosition.ofSeconds(position)).withParentWindow(canvas.getScene().getWindow()).build();
timelineCanvasTimelineHeaderClickHandler.onHeaderClick(timelineCanvasTimelineHeaderClickHandlerRequest);
} else if (event.isPrimaryButtonDown() && dragRepository.getInitialX() == -1 && optionalElement.isPresent()) {
timelineCanvasElementClickHandler.onElementClick(event, currentX, optionalElement.get());
} else {
double positionY = event.getY() + calculateScrolledY();
selectionBox = new CollisionRectangle(currentX, positionY, 0, 0);
}
});
canvas.setOnMouseDragged(event -> {
double x = event.getX();
double y = event.getY();
boolean isPrimaryButtonDown = event.isPrimaryButtonDown();
if (isPrimaryButtonDown) {
if (selectionBox != null) {
double positionX = mapCanvasPixelToTime(event.getX());
double canvasY = event.getY();
if (canvasY < TIMELINE_TIMESCALE_HEIGHT) {
canvasY = TIMELINE_TIMESCALE_HEIGHT;
}
double positionY = canvasY + calculateScrolledY();
selectionBox.width = (positionX - selectionBox.topLeftX);
selectionBox.height = (positionY - selectionBox.topLeftY);
recalculateSelectionModel();
} else {
TimelineCanvasOnDragOverHandlerRequest request = TimelineCanvasOnDragOverHandlerRequest.builder().withChannel(findChannelAtPosition(x, y)).withSelectedElement(findElementAt(x, y)).withXPosition(TimelinePosition.ofSeconds(mapCanvasPixelToTime(x))).withMouseEvent(event).build();
timelineCanvasOnDragOverHandler.onDrag(x, y, false, request);
}
scrollVerticallyWhenDraggingNearEdge(y);
scrollHorizontallyWhenDraggingNearEdge(x);
}
if (y < TIMELINE_TIMESCALE_HEIGHT && !dragRepository.isDraggingAnything() && selectionBox == null) {
uiTimelineManager.jumpAbsolute(BigDecimal.valueOf(mapCanvasPixelToTime(x)));
}
});
canvas.setOnMouseReleased(event -> {
if (!event.isStillSincePress()) {
TimelineCanvasOnDragOverHandlerRequest request = TimelineCanvasOnDragOverHandlerRequest.builder().withChannel(findChannelAtPosition(event.getX(), event.getY())).withSelectedElement(findElementAt(event.getX(), event.getY())).withXPosition(TimelinePosition.ofSeconds(mapCanvasPixelToTime(event.getX()))).withMouseEvent(event).build();
timelineCanvasOnDragOverHandler.onDrag(event.getX(), event.getY(), true, request);
}
disableToolsOnMouseRelease();
});
canvas.setOnDragDropped(event -> {
TimelineCanvasOnDragOverHandlerRequest request = TimelineCanvasOnDragOverHandlerRequest.builder().withChannel(findChannelAtPosition(event.getX(), event.getY())).withEvent(event).withSelectedElement(findElementAt(event.getX(), event.getY())).withXPosition(TimelinePosition.ofSeconds(mapCanvasPixelToTime(event.getX()))).build();
timelineCanvasOnDragOverHandler.onDrag(event.getX(), event.getY(), true, request);
disableToolsOnMouseRelease();
});
canvas.setOnMouseDragReleased(event -> {
disableToolsOnMouseRelease();
});
canvas.setOnDragExited(event -> {
disableToolsOnMouseRelease();
});
canvas.setOnDragOver(event -> {
TimelineCanvasOnDragOverHandlerRequest request = TimelineCanvasOnDragOverHandlerRequest.builder().withChannel(findChannelAtPosition(event.getX(), event.getY())).withEvent(event).withSelectedElement(findElementAt(event.getX(), event.getY())).withXPosition(TimelinePosition.ofSeconds(mapCanvasPixelToTime(event.getX()))).build();
timelineCanvasOnDragOverHandler.onDragOver(request);
});
canvas.setOnMouseClicked(event -> {
TimelineCanvasClickHandlerRequest request = TimelineCanvasClickHandlerRequest.builder().withChannelSelected(findChannelAtPosition(event.getX(), event.getY())).withEvent(event).withParentWindow(canvas.getScene().getWindow()).withSelectedElement(findElementAt(event.getX(), event.getY())).withXPosition(TimelinePosition.ofSeconds(mapCanvasPixelToTime(event.getX()))).build();
boolean shouldRedraw = timelineCanvasClickHandler.onClick(request);
if (shouldRedraw) {
redraw(true);
}
});
canvas.setOnContextMenuRequested(event -> {
Optional<TimelineUiCacheElement> optionalElement = findElementAt(event.getX(), event.getY());
TimelineCanvasContextMenuRequestedHandlerRequest request = TimelineCanvasContextMenuRequestedHandlerRequest.builder().withEvent(event).withParentWindow(canvas.getScene().getWindow()).withSelectedElement(optionalElement).build();
timelineCanvasContextMenuRequestedHandler.onContextMenuRequested(request);
});
return resultPane;
}
use of com.helospark.tactview.ui.javafx.uicomponents.canvasdraw.domain.TimelineUiCacheElement in project tactview by helospark.
the class TimelineCanvas method redrawInternal.
public void redrawInternal(boolean fullRedraw) {
LOGGER.trace("Canvas redraw requested, fullRedraw={}, time={}", fullRedraw, System.currentTimeMillis());
graphics.setLineWidth(1.0);
timelineState.setVisibleLength(TimelineLength.ofSeconds(mapCanvasPixelToTime(canvas.getWidth())));
double timelineWidth = timelineState.secondsToPixelsWithZoom(timelineAccessor.findEndPosition().add(TimelineLength.ofSeconds(10)));
timelineWidth -= canvas.getWidth();
if (timelineWidth < 1000) {
timelineWidth = 1000;
}
bottomBar.setMin(0);
bottomBar.setMax(timelineWidth);
clearCanvas();
double visibleAreaStartY = calculateScrolledY();
if (visibleAreaStartY < 0) {
visibleAreaStartY = 0;
}
TimelineInterval visibleInterval = TimelineInterval.fromDoubles(timelineState.getTranslateDouble(), timelineState.getTimelineLengthDouble() + timelineState.getTranslateDouble());
double channelStartY = TIMELINE_TIMESCALE_HEIGHT + CHANNEL_PADDING;
if (fullRedraw || previouslyCachedImage == null) {
List<TimelineUiCacheElement> newCachedElements = new ArrayList<>();
for (int i = 0; i < timelineAccessor.getChannels().size(); ++i) {
TimelineChannel currentChannel = timelineAccessor.getChannels().get(i);
NonIntersectingIntervalList<TimelineClip> clips = currentChannel.getAllClips().shallowCopy();
double clipHeight = calculateHeight(currentChannel);
if ((channelStartY + clipHeight) >= visibleAreaStartY && (channelStartY) <= visibleAreaStartY + canvas.getHeight()) {
for (var clip : clips) {
TimelineInterval interval = clip.getGlobalInterval();
double clipX = timelineState.secondsToPixelsWidthZoomAndTranslate(interval.getStartPosition());
double clipEndX = timelineState.secondsToPixelsWidthZoomAndTranslate(interval.getEndPosition());
double clipWidth = clipEndX - clipX;
double clipY = channelStartY - visibleAreaStartY;
boolean isPrimarySelectedClip = (selectedNodeRepository.getPrimarySelectedClip().map(a -> a.equals(clip.getId())).orElse(false));
boolean isSecondarySelectedClip = (selectedNodeRepository.getSelectedClipIds().stream().filter(a -> a.equals(clip.getId())).findAny().map(a -> true).orElse(false));
drawClip(visibleInterval, clip, visibleAreaStartY, clipY);
if (isPrimarySelectedClip) {
graphics.setFill(new Color(0.0, 1.0, 1.0, 0.3));
graphics.fillRoundRect(clipX, clipY, clipWidth, MIN_CHANNEL_HEIGHT, 4, 4);
} else if (isSecondarySelectedClip) {
graphics.setFill(new Color(0.0, 1.0, 1.0, 0.2));
graphics.fillRoundRect(clipX, clipY, clipWidth, MIN_CHANNEL_HEIGHT, 4, 4);
}
newCachedElements.add(new TimelineUiCacheElement(clip.getId(), TimelineUiCacheType.CLIP, new CollisionRectangle(clipX, clipY, clipWidth, MIN_CHANNEL_HEIGHT)));
List<NonIntersectingIntervalList<StatelessEffect>> effects = shallowCloneEffects(clip.getEffectChannels());
for (int j = 0; j < effects.size(); ++j) {
for (var effect : effects.get(j)) {
double effectX = timelineState.secondsToPixelsWidthZoomAndTranslate(effect.getGlobalInterval().getStartPosition());
double effectEndX = timelineState.secondsToPixelsWidthZoomAndTranslate(effect.getGlobalInterval().getEndPosition());
double effectY = clipY + MIN_CHANNEL_HEIGHT + EFFECT_HEIGHT * j;
if (effectEndX > clipEndX) {
effectEndX = clipEndX;
}
if (effectX < clipX) {
effectX = clipX;
}
double effectWidth = effectEndX - effectX;
double effectHeight = EFFECT_HEIGHT;
if (effectWidth < 0) {
continue;
}
boolean isPrimarySelectedEffect = (selectedNodeRepository.getPrimarySelectedEffect().map(a -> a.equals(effect.getId())).orElse(false));
boolean isSecondarySelectedEffect = (selectedNodeRepository.getSelectedEffectIds().stream().filter(a -> a.equals(effect.getId())).findAny().map(a -> true).orElse(false));
if (isPrimarySelectedEffect) {
graphics.setFill(new Color(0, 1, 1, 1));
} else if (isSecondarySelectedEffect) {
graphics.setFill(new Color(0, 0.8, 0.8, 1));
} else {
graphics.setFill(new Color(0, 0.5, 0.5, 1));
}
graphics.fillRoundRect(effectX, effectY, effectWidth, effectHeight - 1, 12, 12);
graphics.setFont(new Font(10.0));
graphics.setStroke(Color.WHITE);
graphics.setTextAlign(TextAlignment.LEFT);
graphics.save();
graphics.beginPath();
graphics.rect(effectX, effectY, effectWidth, effectHeight);
graphics.clip();
String name = Optional.ofNullable(nameToIdRepository.getNameForId(effect.getId())).orElse(effect.getId());
graphics.strokeText(name, effectX + 2, effectY + effectHeight / 2.0);
graphics.restore();
newCachedElements.add(new TimelineUiCacheElement(effect.getId(), TimelineUiCacheType.EFFECT, new CollisionRectangle(effectX, effectY, effectWidth, effectHeight)));
}
}
}
graphics.setStroke(Color.GRAY);
graphics.setLineWidth(0.8);
graphics.strokeLine(0, channelStartY + clipHeight + CHANNEL_PADDING - visibleAreaStartY, canvas.getWidth(), channelStartY + clipHeight + CHANNEL_PADDING - visibleAreaStartY);
}
double rowHeight = clipHeight + CHANNEL_PADDING * 2;
channelStartY += rowHeight;
VBox channelTitleVBox = (VBox) timelineState.getChannelTitlesAsNodes().get(i);
channelTitleVBox.setMinHeight(rowHeight);
channelTitleVBox.setMaxHeight(rowHeight);
channelTitleVBox.setPrefHeight(rowHeight);
}
rightBar.setMax(channelStartY);
drawTimelineTitles();
previouslyCachedImage = canvas.snapshot(new SnapshotParameters(), null);
cachedVisibleElements = newCachedElements;
} else {
graphics.drawImage(previouslyCachedImage, 0, 0);
}
drawSelectionBox();
drawLoopingLines();
drawChapterLines();
drawPlaybackLine();
drawSpecialPositionLine(visibleAreaStartY);
}
use of com.helospark.tactview.ui.javafx.uicomponents.canvasdraw.domain.TimelineUiCacheElement in project tactview by helospark.
the class TimelineCanvas method recalculateSelectionModel.
private void recalculateSelectionModel() {
if (selectionBox != null) {
List<TimelineUiCacheElement> selectedElements = new ArrayList<>();
CollisionRectangle rectangleInCanvasSpace = getSelectionRectangleInCanvasSpace(selectionBox);
for (var element : cachedVisibleElements) {
CollisionRectangle rectangle = element.rectangle;
if (rectangle.intersects(rectangleInCanvasSpace)) {
selectedElements.add(element);
}
}
selectedNodeRepository.clearAllSelectedItems();
for (var element : selectedElements) {
if (element.elementType.equals(TimelineUiCacheType.CLIP)) {
selectedNodeRepository.addSelectedClip(element.elementId);
} else if (element.elementType.equals(TimelineUiCacheType.EFFECT)) {
selectedNodeRepository.addSelectedEffect(element.elementId);
}
}
redraw(true);
}
}
Aggregations