Skip to content

Commit

Permalink
Add Calendar functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
IzN432 committed Oct 21, 2024
1 parent 6ff43f9 commit 2192843
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 59 deletions.
215 changes: 206 additions & 9 deletions src/main/java/keycontacts/ui/CalendarView.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
package keycontacts.ui;

import javafx.fxml.FXML;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.Node;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

/**
* The calendar view
Expand All @@ -12,23 +20,212 @@ public class CalendarView extends UiPart<Region> {
private static final String FXML = "Calendar.fxml";

private static final int NUM_ROWS = 7;
private static final int NUM_COLS = 24;
private static final int NUM_MINUTES = 24 * 60;

@SuppressWarnings("unchecked")
private final List<TimeBlock>[] timeBlocks = (ArrayList<TimeBlock>[]) new ArrayList[NUM_ROWS];

private final List<HBox> dayHBoxes = new ArrayList<>();

@FXML
private VBox grid;

@FXML
private HBox mon;

@FXML
private HBox tue;

@FXML
private GridPane grid;
private HBox wed;

@FXML
private HBox thu;

@FXML
private HBox fri;

@FXML
private HBox sat;

@FXML
private HBox sun;

public CalendarView() {
super(FXML);
addHBoxes();
generateGrid();
update();

}

public void update() {
private void addHBoxes() {
dayHBoxes.add(mon);
dayHBoxes.add(tue);
dayHBoxes.add(wed);
dayHBoxes.add(thu);
dayHBoxes.add(fri);
dayHBoxes.add(sat);
dayHBoxes.add(sun);
}

private void generateGrid() {
for (int i = 0; i < NUM_ROWS; i++) {
for (int j = 0; j < NUM_COLS; j++) {
Pane pane = new Pane();
pane.setStyle("-fx-background-color: white; -fx-border-color: black; -fx-border-width: 1;");
grid.add(pane, j, i);
timeBlocks[i] = new ArrayList<>();
}
}

private void createBlock(int day, LocalTime startTime, LocalTime endTime, Color color) {
assert endTime.isAfter(startTime);

TimeBlock timeBlock = new TimeBlock(startTime, endTime);

List<TimeBlock> currentDayBlocks = timeBlocks[day];

TimeBlock previousTimeBlock = new TimeBlock(0, 0);
for (int i = 0; i <= currentDayBlocks.size(); i++) {
if (i == currentDayBlocks.size()) {
// attach
dayHBoxes.get(day).getChildren().add(i * 2,
timeBlock.createPadding(previousTimeBlock));
dayHBoxes.get(day).getChildren().add(i * 2 + 1,
timeBlock.createBlock(color));
currentDayBlocks.add(i, timeBlock);

return;
}

TimeBlock currentTimeBlock = currentDayBlocks.get(i);
assert !currentTimeBlock.isIntersecting(timeBlock);
if (currentTimeBlock.isAfter(timeBlock)) {
// attach
dayHBoxes.get(day).getChildren().add(i * 2,
timeBlock.createPadding(previousTimeBlock));
dayHBoxes.get(day).getChildren().add(i * 2 + 1,
timeBlock.createBlock(color));
currentDayBlocks.add(i, timeBlock);

// fix padding
currentTimeBlock.subtractPaddingWidth(timeBlock.getTotalWidth());

return;
}
previousTimeBlock = currentTimeBlock;
}
}

public void update() {
createBlock(0, LocalTime.of(1, 0, 0), LocalTime.of(1, 30, 0),
Color.BLUE);
createBlock(0, LocalTime.of(3, 0, 0), LocalTime.of(3, 30, 0),
Color.BLUE);
createBlock(0, LocalTime.of(2, 0, 0), LocalTime.of(2, 30, 0),
Color.RED);
}

class TimeBlock {

private final int startTimeMinutes;
private final int endTimeMinutes;

private Rectangle block;
private Rectangle padding;

private int paddingWidth;
private int blockWidth;

public TimeBlock(LocalTime startTime, LocalTime endTime) {
this(startTime.getHour() * 60 + startTime.getMinute(), endTime.getHour() * 60 + endTime.getMinute());
}

private TimeBlock(int startTimeMinutes, int endTimeMinutes) {
this.startTimeMinutes = startTimeMinutes;
this.endTimeMinutes = endTimeMinutes;
}

/**
* Returns the duration of the time block
*/
public int getDuration() {
return endTimeMinutes - startTimeMinutes;
}

/**
* Returns the distance between this time block and the other
*/
public int getDistance(TimeBlock other) {
if (isIntersecting(other)) {
return 0;
}

if (isAfter(other)) {
return startTimeMinutes - other.endTimeMinutes;
}

return other.startTimeMinutes - endTimeMinutes;
}

/**
* Returns true if the given time block starts at or after this time block's end
*/
public boolean isAfter(TimeBlock other) {
return startTimeMinutes >= other.startTimeMinutes;
}

/**
* Returns true if the given time block intersects with this time block
*/
public boolean isIntersecting(TimeBlock other) {
return startTimeMinutes <= other.endTimeMinutes && other.startTimeMinutes <= endTimeMinutes;
}

/**
* Subtracts {@code width} from the padding width
*/
public void subtractPaddingWidth(int width) {
this.paddingWidth -= width;
updatePaddingBinding();
}

/**
* Updates the binding to the new padding width
*/
private void updatePaddingBinding() {
this.padding.widthProperty().bind(grid.widthProperty().multiply((double) paddingWidth / NUM_MINUTES));
this.padding.heightProperty().bind(grid.heightProperty().divide(NUM_ROWS));
}

/**
* Updates the binding to the new block width
*/
private void updateBlockBinding() {
this.block.widthProperty().bind(grid.widthProperty().multiply((double) blockWidth / NUM_MINUTES));
this.block.heightProperty().bind(grid.heightProperty().divide(NUM_ROWS));
}

/**
* Returns the total width this block takes, including padding
*/
public int getTotalWidth() {
return paddingWidth + blockWidth;
}

public Node createPadding(TimeBlock previousTimeBlock) {
this.paddingWidth = getDistance(previousTimeBlock);
this.padding = new Rectangle();
this.padding.setStyle("-fx-opacity: 0");
updatePaddingBinding();
return this.padding;
}

public Node createBlock(Color color) {
this.blockWidth = getDuration();
this.block = new Rectangle();
this.block.setFill(color);
updateBlockBinding();
return this.block;
}
}
}


66 changes: 16 additions & 50 deletions src/main/resources/view/Calendar.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>

<VBox prefHeight="800.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/23.0.1" xmlns:fx="http://javafx.com/fxml/1">
<VBox prefHeight="800.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
<HBox>

<VBox prefWidth="50.0" HBox.hgrow="NEVER" />
Expand Down Expand Up @@ -76,7 +73,21 @@
</VBox>

</HBox>
<StackPane prefHeight="150.0" prefWidth="200.0" styleClass="calendar" VBox.vgrow="ALWAYS">
<StackPane styleClass="calendar" VBox.vgrow="ALWAYS">
<HBox layoutX="10.0" layoutY="10.0">
<VBox prefWidth="50.0" styleClass="day-container" HBox.hgrow="NEVER" />
<VBox fx:id="grid" HBox.hgrow="ALWAYS">
<children>
<HBox fx:id="mon" prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox fx:id="tue" layoutX="10.0" layoutY="10.0" prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox fx:id="wed" layoutX="10.0" layoutY="110.0" prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox fx:id="thu" layoutX="10.0" layoutY="210.0" prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox fx:id="fri" layoutX="10.0" layoutY="310.0" prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox fx:id="sat" layoutX="10.0" layoutY="410.0" prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
<HBox fx:id="sun" layoutX="10.0" layoutY="510.0" prefHeight="100.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
</children>
</VBox>
</HBox>
<HBox prefHeight="100.0" prefWidth="200.0">
<VBox prefWidth="50.0" styleClass="day-container" HBox.hgrow="NEVER">
<AnchorPane prefHeight="200.0" prefWidth="200.0">
Expand Down Expand Up @@ -151,51 +162,6 @@
<Pane layoutX="10.0" layoutY="330.0" prefWidth="200.0" styleClass="horizontal-space" VBox.vgrow="ALWAYS" />
<Pane layoutX="10.0" layoutY="343.0" prefWidth="200.0" styleClass="horizontal-space" VBox.vgrow="ALWAYS" />
</VBox>
<HBox layoutX="10.0" layoutY="10.0">
<VBox prefWidth="50.0" styleClass="day-container" HBox.hgrow="NEVER" />
<VBox HBox.hgrow="ALWAYS">
<children>
<GridPane fx:id="grid" gridLinesVisible="true" VBox.vgrow="ALWAYS">
<rowConstraints>
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
<RowConstraints minHeight="10.0" vgrow="ALWAYS" />
</rowConstraints>
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
<ColumnConstraints hgrow="ALWAYS" />
</columnConstraints>
</GridPane>
</children>
</VBox>
</HBox>

</StackPane>
</VBox>

0 comments on commit 2192843

Please sign in to comment.