All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.calendarfx.util.ViewHelper Maven / Gradle / Ivy

There is a newer version: 8.5.0
Show newest version
/*
 *  Copyright (C) 2017 Dirk Lemmermann Software & Consulting (dlsc.com)
 *
 *  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
 *
 *          http://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.calendarfx.util;

import com.calendarfx.view.DateControl;
import com.calendarfx.view.DayView;
import com.calendarfx.view.DayViewBase;
import impl.com.calendarfx.view.DayViewScrollPane;
import javafx.collections.ObservableList;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.stage.Screen;
import org.controlsfx.control.PopOver.ArrowLocation;

import java.time.Instant;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

@SuppressWarnings("javadoc")
public final class ViewHelper {

    public static double getTimeLocation(DayViewBase view, LocalTime time) {
        return getTimeLocation(view, ZonedDateTime.of(view.getDate(), time, view.getZoneId()));
    }

    public static double getTimeLocation(DayViewBase view, LocalTime time, boolean prefHeight) {
        return getTimeLocation(view, ZonedDateTime.of(view.getDate(), time, view.getZoneId()), prefHeight);
    }

    public static double getTimeLocation(DayViewBase view, ZonedDateTime time) {
        return getTimeLocation(view, time, false);
    }

    public static double getTimeLocation(DayViewBase view, Instant instant) {
        return getTimeLocation(view, ZonedDateTime.ofInstant(instant, view.getZoneId()), false);
    }

    public static double getTimeLocation(DayViewBase view, ZonedDateTime zonedTime, boolean prefHeight) {
        if (view.isScrollingEnabled()) {
            final Instant scrollInstant = view.getScrollTime().toInstant();
            final double mpp = DayView.MILLIS_PER_HOUR / view.getHourHeight();
            final long millis = zonedTime.toInstant().toEpochMilli() - scrollInstant.toEpochMilli();
            return millis / mpp;
        }

        double availableHeight = view.getHeight();
        if (prefHeight) {
            availableHeight = view.prefHeight(-1);
        }

        long epochMilli = zonedTime.toInstant().toEpochMilli();

        switch (view.getEarlyLateHoursStrategy()) {
            case SHOW:
                ZonedDateTime startTime = view.getZonedDateTimeMin();
                ZonedDateTime endTime = view.getZonedDateTimeMax();

                long startMillis = startTime.toInstant().toEpochMilli();
                long endMillis = endTime.toInstant().toEpochMilli();

                double mpp = (endMillis - startMillis) / availableHeight;

                return ((int) ((epochMilli - startMillis) / mpp)) + .5;
            case HIDE:
                startTime = view.getZonedDateTimeStart();
                endTime = view.getZonedDateTimeEnd();

                if (zonedTime.isBefore(startTime)) {
                    return -1;
                }

                if (zonedTime.isAfter(endTime)) {
                    return availableHeight;
                }

                startMillis = startTime.toInstant().toEpochMilli();
                endMillis = endTime.toInstant().toEpochMilli();

                mpp = (endMillis - startMillis) / availableHeight;

                return ((int) ((epochMilli - startMillis) / mpp)) + .5;
            case SHOW_COMPRESSED:
                ZonedDateTime minTime = view.getZonedDateTimeMin();
                ZonedDateTime maxTime = view.getZonedDateTimeMax();

                startTime = view.getZonedDateTimeStart();
                endTime = view.getZonedDateTimeEnd();

                long earlyHours = ChronoUnit.HOURS.between(minTime, startTime);
                long lateHours = ChronoUnit.HOURS.between(endTime, maxTime) + 1;

                double hourHeightCompressed = view.getHourHeightCompressed();
                double earlyHeight = hourHeightCompressed * earlyHours;
                double lateHeight = hourHeightCompressed * lateHours;

                if (zonedTime.isBefore(startTime)) {
                    /*
                     * Early compressed hours.
                     */
                    startMillis = minTime.toInstant().toEpochMilli();
                    endMillis = startTime.toInstant().toEpochMilli();

                    mpp = (endMillis - startMillis) / earlyHeight;

                    return ((int) ((epochMilli - startMillis) / mpp)) + .5;
                } else if (zonedTime.isAfter(endTime)) {
                    /*
                     * Late compressed hours.
                     */
                    startMillis = endTime.toInstant().toEpochMilli();
                    endMillis = maxTime.toInstant().toEpochMilli();

                    mpp = (endMillis - startMillis) / lateHeight;

                    return ((int) ((epochMilli - startMillis) / mpp)) + (availableHeight - lateHeight) + .5;
                } else {
                    /*
                     * Regular hours.
                     */
                    startMillis = startTime.toInstant().toEpochMilli();
                    endMillis = endTime.toInstant().toEpochMilli();
                    mpp = (endMillis - startMillis) / (availableHeight - earlyHeight - lateHeight);

                    return earlyHeight + ((int) ((epochMilli - startMillis) / mpp)) + .5;
                }
            default:
                return 0;
        }
    }

    public static Instant getInstantAt(DayViewBase view, double y) {

        ZonedDateTime zonedDateTime = view.getZonedDateTimeStart();

        double availableHeight = view.getHeight();

        switch (view.getEarlyLateHoursStrategy()) {
            case SHOW:
                long startMillis = view.getZonedDateTimeMin().toInstant().toEpochMilli();
                long endMillis = view.getZonedDateTimeMax().toInstant().toEpochMilli();

                double mpp = (endMillis - startMillis) / availableHeight;

                long millis = (long) (mpp * y) + startMillis;

                return Instant.ofEpochMilli(millis);
            case HIDE:
                ZonedDateTime startTime = view.getZonedDateTimeStart();
                ZonedDateTime endTime = view.getZonedDateTimeEnd();

                startMillis = startTime.toInstant().toEpochMilli();
                endMillis = endTime.toInstant().toEpochMilli();

                mpp = (endMillis - startMillis) / availableHeight;

                millis = (long) (mpp * y) + startMillis;

                return Instant.ofEpochMilli(millis);
            case SHOW_COMPRESSED:
                startTime = view.getZonedDateTimeStart();
                endTime = view.getZonedDateTimeEnd();

                ZonedDateTime minTime = view.getZonedDateTimeMin();
                ZonedDateTime maxTime = view.getZonedDateTimeMax();

                long earlyHours = ChronoUnit.HOURS.between(minTime, startTime);
                long lateHours = ChronoUnit.HOURS.between(endTime, maxTime) + 1;

                double hourHeightCompressed = view.getHourHeightCompressed();
                double earlyHeight = hourHeightCompressed * earlyHours;
                double lateHeight = hourHeightCompressed * lateHours;

                if (y < earlyHeight) {
                    /*
                     * Early compressed hours.
                     */
                    startMillis = minTime.toInstant().toEpochMilli();
                    endMillis = startTime.toInstant().toEpochMilli();

                    mpp = (endMillis - startMillis) / earlyHeight;

                    millis = (long) (mpp * y) + startMillis;

                    return Instant.ofEpochMilli(millis);
                } else if (y > availableHeight - lateHeight) {
                    /*
                     * Late compressed hours.
                     */
                    startMillis = endTime.toInstant().toEpochMilli();
                    endMillis = maxTime.toInstant().toEpochMilli();

                    mpp = (endMillis - startMillis) / lateHeight;

                    millis = (long) (mpp * (y - (availableHeight - lateHeight))) + startMillis;

                    return Instant.ofEpochMilli(millis);
                } else {
                    /*
                     * Regular hours.
                     */
                    startMillis = startTime.toInstant().toEpochMilli();
                    endMillis = endTime.toInstant().toEpochMilli();

                    mpp = (endMillis - startMillis) / (availableHeight - earlyHeight - lateHeight);

                    millis = (long) (mpp * (y - earlyHeight)) + startMillis;

                    return Instant.ofEpochMilli(millis);
                }
            default:
                return zonedDateTime.toInstant();
        }
    }

    public static ArrowLocation findPopOverArrowLocation(Node view) {
        Bounds localBounds = view.getBoundsInLocal();
        Bounds entryBounds = view.localToScreen(localBounds);

        ObservableList screens = Screen.getScreensForRectangle(
                entryBounds.getMinX(), entryBounds.getMinY(),
                entryBounds.getWidth(), entryBounds.getHeight());

        if (screens.isEmpty()) {
            return null;

        }
        Rectangle2D screenBounds = screens.get(0).getVisualBounds();

        double spaceLeft = entryBounds.getMinX();
        double spaceRight = screenBounds.getWidth() - entryBounds.getMaxX();
        double spaceTop = entryBounds.getMinY();
        double spaceBottom = screenBounds.getHeight() - entryBounds.getMaxY();

        if (spaceLeft > spaceRight) {
            if (spaceTop > spaceBottom) {
                return ArrowLocation.RIGHT_BOTTOM;
            }
            return ArrowLocation.RIGHT_TOP;
        }

        if (spaceTop > spaceBottom) {
            return ArrowLocation.LEFT_BOTTOM;
        }

        return ArrowLocation.LEFT_TOP;
    }

    public static Point2D findPopOverArrowPosition(Node node, double screenY, double arrowSize, ArrowLocation arrowLocation) {

        Bounds entryBounds = node.localToScreen(node.getBoundsInLocal());

        double screenX;

        if (arrowLocation == ArrowLocation.LEFT_TOP || arrowLocation == ArrowLocation.LEFT_BOTTOM) {
            screenX = entryBounds.getMaxX();
        } else {
            screenX = entryBounds.getMinX() - arrowSize;
        }

        return new Point2D(screenX, screenY);
    }

    public static void scrollToRequestedTime(DateControl control, DayViewScrollPane scrollPane) {
        LocalTime requestedTime = control.getRequestedTime();
        if (requestedTime != null) {
            scrollPane.scrollToTime(requestedTime);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy