-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #171 from dlsc-software-consulting-gmbh/enhancment…
…-SearchTextField Enhanced SearchTextField to support search history
- Loading branch information
Showing
10 changed files
with
882 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
gemsfx/src/main/java/com/dlsc/gemsfx/CustomPopupControl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.dlsc.gemsfx; | ||
|
||
import javafx.css.PseudoClass; | ||
import javafx.geometry.NodeOrientation; | ||
import javafx.scene.Node; | ||
import javafx.scene.control.PopupControl; | ||
import javafx.stage.Screen; | ||
import javafx.stage.Window; | ||
|
||
/** | ||
* A custom popup control that extends PopupControl. | ||
* <p> | ||
* The popup can be displayed above or below the anchor node depending on the available space. | ||
*/ | ||
public class CustomPopupControl extends PopupControl { | ||
|
||
private static final PseudoClass ABOVE_PSEUDO_CLASS = PseudoClass.getPseudoClass("above"); | ||
private static final PseudoClass BELOW_PSEUDO_CLASS = PseudoClass.getPseudoClass("below"); | ||
|
||
public void show(Node node) { | ||
if (node.getScene() != null && node.getScene().getWindow() != null) { | ||
Window parent = node.getScene().getWindow(); | ||
getScene().setNodeOrientation(node.getEffectiveNodeOrientation()); | ||
if (node.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT) { | ||
setAnchorLocation(AnchorLocation.CONTENT_TOP_RIGHT); | ||
} else { | ||
setAnchorLocation(AnchorLocation.CONTENT_TOP_LEFT); | ||
} | ||
|
||
double nodeTopY = parent.getY() + node.localToScene(0.0D, 0.0D).getY() + node.getScene().getY(); | ||
|
||
double anchorX = parent.getX() + node.localToScene(0.0D, 0.0D).getX() + node.getScene().getX(); | ||
double anchorY = nodeTopY + node.getBoundsInParent().getHeight(); | ||
|
||
double bridgeHeight = bridge.getHeight(); | ||
double popupHeight = bridgeHeight == 0 ? getSkin().getNode().prefHeight(-1) : bridgeHeight; | ||
double screenHeight = Screen.getPrimary().getVisualBounds().getHeight(); | ||
|
||
boolean isShowAbove = anchorY + popupHeight > screenHeight; | ||
if (isShowAbove) { | ||
anchorY = nodeTopY - popupHeight; | ||
} | ||
this.pseudoClassStateChanged(ABOVE_PSEUDO_CLASS, isShowAbove); | ||
this.pseudoClassStateChanged(BELOW_PSEUDO_CLASS, !isShowAbove); | ||
|
||
show(node, anchorX, anchorY); | ||
} else { | ||
throw new IllegalStateException("Can not show popup. The node must be attached to a scene/window."); | ||
} | ||
} | ||
|
||
} |
106 changes: 106 additions & 0 deletions
106
gemsfx/src/main/java/com/dlsc/gemsfx/RemovableListCell.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package com.dlsc.gemsfx; | ||
|
||
import javafx.beans.property.ObjectProperty; | ||
import javafx.beans.property.SimpleObjectProperty; | ||
import javafx.geometry.Pos; | ||
import javafx.scene.control.Label; | ||
import javafx.scene.control.ListCell; | ||
import javafx.scene.control.ListView; | ||
import javafx.scene.input.MouseEvent; | ||
import javafx.scene.layout.HBox; | ||
import javafx.scene.layout.StackPane; | ||
import org.kordamp.ikonli.javafx.FontIcon; | ||
import org.kordamp.ikonli.materialdesign.MaterialDesign; | ||
|
||
import java.util.Objects; | ||
import java.util.function.BiConsumer; | ||
|
||
/** | ||
* A list cell that displays a remove button on the right side. The remove button is only | ||
* visible when the mouse hovers over the cell. When the remove button is clicked, the | ||
* onRemove callback is invoked. | ||
* | ||
* @param <T> the type of the list cell item | ||
*/ | ||
public class RemovableListCell<T> extends ListCell<T> { | ||
|
||
private final HBox containerBox; | ||
private final Label label; | ||
|
||
public RemovableListCell() { | ||
getStyleClass().add("removable-list-cell"); | ||
|
||
label = new Label(); | ||
|
||
StackPane removeBtn = new StackPane(new FontIcon(MaterialDesign.MDI_CLOSE)); | ||
removeBtn.getStyleClass().add("remove-button"); | ||
removeBtn.setOnMouseClicked(this::onRemoveAction); | ||
|
||
containerBox = new HBox(label, new Spacer(), removeBtn); | ||
containerBox.getStyleClass().add("container-box"); | ||
containerBox.setAlignment(Pos.CENTER_LEFT); | ||
} | ||
|
||
public RemovableListCell(BiConsumer<ListView<T>, T> onRemove) { | ||
this(); | ||
setOnRemove(onRemove); | ||
} | ||
|
||
@Override | ||
protected void updateItem(T item, boolean empty) { | ||
super.updateItem(item, empty); | ||
|
||
if (item == null || empty) { | ||
label.setText(null); | ||
|
||
setText(null); | ||
setGraphic(null); | ||
} else { | ||
label.setText(item.toString()); | ||
|
||
setText(null); | ||
setGraphic(containerBox); | ||
} | ||
} | ||
|
||
public void onRemoveAction(MouseEvent event) { | ||
if (getOnRemove() != null) { | ||
|
||
// clear selection if the item is selected | ||
if (isSelected()) { | ||
getListView().getSelectionModel().clearSelection(); | ||
} | ||
|
||
getOnRemove().accept(getListView(), getItem()); | ||
} | ||
} | ||
|
||
private ObjectProperty<BiConsumer<ListView<T>, T>> onRemove; | ||
|
||
/** | ||
* A callback that is invoked when the remove button is clicked. | ||
* | ||
* @return the onRemoveProperty | ||
*/ | ||
public final ObjectProperty<BiConsumer<ListView<T>, T>> onRemoveProperty() { | ||
if (onRemove == null) { | ||
onRemove = new SimpleObjectProperty<>(this, "onRemove"); | ||
} | ||
return onRemove; | ||
} | ||
|
||
public final BiConsumer<ListView<T>, T> getOnRemove() { | ||
return onRemove == null ? null : onRemoveProperty().get(); | ||
} | ||
|
||
public final void setOnRemove(BiConsumer<ListView<T>, T> onRemove) { | ||
onRemoveProperty().set(onRemove); | ||
} | ||
|
||
@Override | ||
public String getUserAgentStylesheet() { | ||
return Objects.requireNonNull(RemovableListCell.class.getResource("removable-list-cell.css")).toExternalForm(); | ||
} | ||
} | ||
|
||
|
Oops, something went wrong.