mirror of
https://github.com/xpipe-io/xpipe.git
synced 2024-11-25 09:00:26 +00:00
Accessibility improvements
This commit is contained in:
parent
544597c267
commit
fcc47b9038
24 changed files with 112 additions and 24 deletions
|
@ -6,6 +6,7 @@ import io.xpipe.app.comp.storage.store.StoreViewState;
|
|||
import io.xpipe.app.fxcomps.SimpleComp;
|
||||
import io.xpipe.app.fxcomps.impl.IconButtonComp;
|
||||
import io.xpipe.app.fxcomps.impl.PrettyImageComp;
|
||||
import io.xpipe.app.fxcomps.util.PlatformThread;
|
||||
import io.xpipe.core.store.DataStore;
|
||||
import io.xpipe.core.store.ShellStore;
|
||||
import javafx.application.Platform;
|
||||
|
@ -13,6 +14,7 @@ import javafx.beans.property.*;
|
|||
import javafx.collections.SetChangeListener;
|
||||
import javafx.css.PseudoClass;
|
||||
import javafx.geometry.Point2D;
|
||||
import javafx.scene.AccessibleRole;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.TreeCell;
|
||||
import javafx.scene.control.TreeItem;
|
||||
|
@ -47,7 +49,7 @@ final class BrowserBookmarkList extends SimpleComp {
|
|||
return new StoreCell();
|
||||
});
|
||||
|
||||
model.getSelected().addListener((observable, oldValue, newValue) -> {
|
||||
PlatformThread.sync(model.getSelected()).addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue == null) {
|
||||
view.getSelectionModel().clearSelection();
|
||||
return;
|
||||
|
@ -95,6 +97,7 @@ final class BrowserBookmarkList extends SimpleComp {
|
|||
|
||||
private StoreCell() {
|
||||
disableProperty().bind(busy);
|
||||
setAccessibleRole(AccessibleRole.BUTTON);
|
||||
setGraphic(imageView);
|
||||
addEventHandler(DragEvent.DRAG_OVER, mouseEvent -> {
|
||||
if (getItem() == null) {
|
||||
|
@ -131,7 +134,8 @@ final class BrowserBookmarkList extends SimpleComp {
|
|||
})
|
||||
.apply(struc -> struc.get().setPrefWidth(25))
|
||||
.grow(false, true)
|
||||
.styleClass("expand-button");
|
||||
.styleClass("expand-button")
|
||||
.apply(struc -> struc.get().setFocusTraversable(false));
|
||||
|
||||
setDisclosureNode(button.createRegion());
|
||||
}
|
||||
|
@ -145,12 +149,16 @@ final class BrowserBookmarkList extends SimpleComp {
|
|||
// and cells are emptied on each change, leading to unnecessary changes
|
||||
// img.set(null);
|
||||
setGraphic(null);
|
||||
setFocusTraversable(false);
|
||||
setAccessibleText(null);
|
||||
} else {
|
||||
setText(item.getName());
|
||||
img.set(item.getEntry()
|
||||
.getProvider()
|
||||
.getDisplayIconFileName(item.getEntry().getStore()));
|
||||
setGraphic(imageView);
|
||||
setFocusTraversable(true);
|
||||
setAccessibleText(item.getName() + " " + item.getEntry().getProvider().getDisplayName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,7 +165,8 @@ public class BrowserComp extends SimpleComp {
|
|||
// Handle selection from model
|
||||
model.getSelected().addListener((observable, oldValue, newValue) -> {
|
||||
PlatformThread.runLaterIfNeeded(() -> {
|
||||
tabs.getSelectionModel().select(model.getOpenFileSystems().indexOf(newValue));
|
||||
var tab = tabs.getTabs().get(model.getOpenFileSystems().indexOf(newValue));
|
||||
tabs.getSelectionModel().select(tab);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -258,6 +259,7 @@ public class BrowserComp extends SimpleComp {
|
|||
new FancyTooltipAugment<>(new SimpleStringProperty(model.getName())).augment(label);
|
||||
GrowAugment.create(true, false).augment(new SimpleCompStructure<>(label));
|
||||
tab.setContent(new OpenFileSystemComp(model).createSimple());
|
||||
tab.setText(model.getName());
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import javafx.collections.ListChangeListener;
|
|||
import javafx.css.PseudoClass;
|
||||
import javafx.geometry.Bounds;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.AccessibleRole;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.skin.TableViewSkin;
|
||||
|
@ -100,10 +101,12 @@ final class BrowserFileListComp extends SimpleComp {
|
|||
modeCol.setSortable(false);
|
||||
|
||||
var table = new TableView<BrowserEntry>();
|
||||
table.setAccessibleText("Directory contents");
|
||||
table.setPlaceholder(new Region());
|
||||
table.getStyleClass().add(Styles.STRIPED);
|
||||
table.getColumns().setAll(filenameCol, sizeCol, modeCol, mtimeCol);
|
||||
table.getSortOrder().add(filenameCol);
|
||||
table.setFocusTraversable(true);
|
||||
table.setSortPolicy(param -> {
|
||||
var comp = table.getComparator();
|
||||
if (comp == null) {
|
||||
|
@ -229,6 +232,12 @@ final class BrowserFileListComp extends SimpleComp {
|
|||
|
||||
table.setRowFactory(param -> {
|
||||
TableRow<BrowserEntry> row = new TableRow<>();
|
||||
row.accessibleTextProperty().bind(Bindings.createStringBinding(() -> {
|
||||
return row.getItem() != null ? row.getItem().getFileName() : null;
|
||||
}, row.itemProperty()));
|
||||
row.focusTraversableProperty().bind(Bindings.createBooleanBinding(() -> {
|
||||
return row.getItem() != null;
|
||||
}, row.itemProperty()));
|
||||
new ContextMenuAugment<>(event -> {
|
||||
if (row.getItem() == null) {
|
||||
return event.getButton() == MouseButton.SECONDARY;
|
||||
|
@ -405,6 +414,11 @@ final class BrowserFileListComp extends SimpleComp {
|
|||
private final BooleanProperty updating = new SimpleBooleanProperty();
|
||||
|
||||
public FilenameCell(Property<BrowserEntry> editing) {
|
||||
accessibleTextProperty().bind(Bindings.createStringBinding(() -> {
|
||||
return getItem() != null ? getItem() : null;
|
||||
}, itemProperty()));
|
||||
setAccessibleRole(AccessibleRole.TEXT);
|
||||
|
||||
editing.addListener((observable, oldValue, newValue) -> {
|
||||
if (getTableRow().getItem() != null && getTableRow().getItem().equals(newValue)) {
|
||||
PlatformThread.runLaterIfNeeded(() -> textField.requestFocus());
|
||||
|
|
|
@ -86,7 +86,7 @@ public class BrowserFileListCompEntry {
|
|||
}
|
||||
|
||||
// Prevent dropping items onto themselves
|
||||
if (item != null && BrowserClipboard.currentDragClipboard.getEntries().contains(item)) {
|
||||
if (item != null && BrowserClipboard.currentDragClipboard.getEntries().contains(item.getRawFileEntry())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ public class BrowserNavBar extends SimpleComp {
|
|||
struc.get().setPromptText("Overview of " + model.getName());
|
||||
}).shortcut(new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN), s -> {
|
||||
s.get().requestFocus();
|
||||
});
|
||||
}).accessibleText("Current path");
|
||||
|
||||
var graphic = Bindings.createStringBinding(
|
||||
() -> {
|
||||
|
@ -87,6 +87,7 @@ public class BrowserNavBar extends SimpleComp {
|
|||
.createRegion();
|
||||
|
||||
var graphicButton = new Button(null, breadcrumbsGraphic);
|
||||
graphicButton.setAccessibleText("Directory options");
|
||||
graphicButton.getStyleClass().add(Styles.LEFT_PILL);
|
||||
graphicButton.getStyleClass().add("path-graphic-button");
|
||||
new ContextMenuAugment<>(
|
||||
|
|
|
@ -45,6 +45,7 @@ public class OpenFileSystemComp extends SimpleComp {
|
|||
var overview = new Button(null, new FontIcon("mdi2m-monitor"));
|
||||
overview.setOnAction(e -> model.cd(null));
|
||||
overview.disableProperty().bind(model.getInOverview());
|
||||
overview.setAccessibleText("System overview");
|
||||
|
||||
var backBtn = BrowserAction.byId("back").toButton(model, List.of());
|
||||
var forthBtn = BrowserAction.byId("forward").toButton(model, List.of());
|
||||
|
@ -56,6 +57,7 @@ public class OpenFileSystemComp extends SimpleComp {
|
|||
event -> event.getButton() == MouseButton.PRIMARY, () -> new BrowserContextMenu(model, null))
|
||||
.augment(new SimpleCompStructure<>(menuButton));
|
||||
menuButton.disableProperty().bind(model.getInOverview());
|
||||
menuButton.setAccessibleText("Directory options");
|
||||
|
||||
var filter = new BrowserFilterComp(model, model.getFilter()).createStructure();
|
||||
Shortcuts.addShortcut(filter.toggleButton(), new KeyCodeCombination(KeyCode.F, KeyCombination.SHORTCUT_DOWN));
|
||||
|
|
|
@ -36,6 +36,7 @@ public interface LeafAction extends BrowserAction {
|
|||
b.setGraphic(graphic);
|
||||
}
|
||||
b.setMnemonicParsing(false);
|
||||
b.setAccessibleText(getName(model, selected));
|
||||
|
||||
b.setDisable(!isActive(model, selected));
|
||||
model.getCurrentPath().addListener((observable, oldValue, newValue) -> {
|
||||
|
|
|
@ -34,6 +34,7 @@ public class BigIconButton extends ButtonComp {
|
|||
vbox.getChildren().add(label);
|
||||
|
||||
var b = new Button(null);
|
||||
b.accessibleTextProperty().bind(getName());
|
||||
b.setGraphic(vbox);
|
||||
b.setOnAction(e -> getListener().run());
|
||||
b.getStyleClass().add("big-icon-button-comp");
|
||||
|
|
|
@ -68,7 +68,7 @@ public class DataSourceTargetChoiceComp extends Comp<CompStructure<ComboBox<Node
|
|||
var addMoreLabel = new Label(AppI18n.get("addMore"), new FontIcon("mdmz-plus"));
|
||||
|
||||
var builder = new CustomComboBoxBuilder<DataSourceTarget>(
|
||||
selectedApplication, app -> createLabel(app), new Label(""), v -> true);
|
||||
selectedApplication, app -> createLabel(app), dataSourceTarget -> dataSourceTarget.getName().getValue(), new Label(""), v -> true);
|
||||
|
||||
// builder.addFilter((v, s) -> v.getName().getValue().toLowerCase().contains(s));
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public class DsProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>>> im
|
|||
|
||||
@Override
|
||||
public CompStructure<ComboBox<Node>> createBase() {
|
||||
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, createDefaultNode(), v -> true);
|
||||
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, dataSourceProvider -> dataSourceProvider.getDisplayName(), createDefaultNode(), v -> true);
|
||||
comboBox.add(null);
|
||||
comboBox.addSeparator();
|
||||
comboBox.addFilter((v, s) -> v.getDisplayName().toLowerCase().contains(s.toLowerCase()));
|
||||
|
|
|
@ -30,7 +30,7 @@ public class DsStorageGroupSelector extends SimpleComp {
|
|||
@Override
|
||||
protected ComboBox<Node> createSimple() {
|
||||
var comboBox = new CustomComboBoxBuilder<DataSourceCollection>(
|
||||
selected, DsStorageGroupSelector::createGraphic, createGraphic(null), v -> true);
|
||||
selected, DsStorageGroupSelector::createGraphic, dataSourceCollection -> dataSourceCollection.getName(), createGraphic(null), v -> true);
|
||||
|
||||
DataStorage.get().getSourceCollections().stream()
|
||||
.filter(dataSourceCollection ->
|
||||
|
|
|
@ -50,7 +50,7 @@ public class DsTypeChoiceComp extends Comp<CompStructure<StackPane>> {
|
|||
return;
|
||||
}
|
||||
|
||||
var builder = new CustomComboBoxBuilder<>(selectedType, app -> createLabel(app), new Label(""), v -> true);
|
||||
var builder = new CustomComboBoxBuilder<>(selectedType, app -> createLabel(app), dataSourceType -> dataSourceType.toString(), new Label(""), v -> true);
|
||||
builder.add(provider.getValue().getPrimaryType());
|
||||
|
||||
var list = Arrays.stream(DataSourceType.values())
|
||||
|
|
|
@ -49,7 +49,7 @@ public class DsStoreProviderChoiceComp extends Comp<CompStructure<ComboBox<Node>
|
|||
|
||||
@Override
|
||||
public CompStructure<ComboBox<Node>> createBase() {
|
||||
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, createDefaultNode(), v -> true);
|
||||
var comboBox = new CustomComboBoxBuilder<>(provider, this::createGraphic, dataStoreProvider -> dataStoreProvider.getDisplayName(), createDefaultNode(), v -> true);
|
||||
getProviders().stream()
|
||||
.filter(p -> AppPrefs.get().developerShowHiddenProviders().get() || p.shouldShow())
|
||||
.forEach(comboBox::add);
|
||||
|
|
|
@ -148,7 +148,11 @@ public class StoreEntryComp extends SimpleComp {
|
|||
GrowAugment.create(true, false).augment(new SimpleCompStructure<>(grid));
|
||||
button.getStyleClass().add("store-entry-comp");
|
||||
button.setMaxWidth(2000);
|
||||
button.setFocusTraversable(false);
|
||||
button.setFocusTraversable(true);
|
||||
button.accessibleTextProperty().bind(Bindings.createStringBinding(() -> {
|
||||
return entry.getName();
|
||||
}, entry.nameProperty()));
|
||||
button.accessibleHelpProperty().bind(entry.getInformation());
|
||||
button.setOnAction(event -> {
|
||||
event.consume();
|
||||
ThreadHelper.runFailableAsync(() -> {
|
||||
|
@ -214,6 +218,7 @@ public class StoreEntryComp extends SimpleComp {
|
|||
private Comp<?> createSettingsButton() {
|
||||
var settingsButton = new IconButtonComp("mdomz-settings");
|
||||
settingsButton.styleClass("settings");
|
||||
settingsButton.accessibleText("Settings");
|
||||
settingsButton.apply(new ContextMenuAugment<>(event -> event.getButton() == MouseButton.PRIMARY, () -> StoreEntryComp.this.createContextMenu()));
|
||||
settingsButton.apply(GrowAugment.create(false, true));
|
||||
settingsButton.apply(s -> {
|
||||
|
|
|
@ -36,6 +36,8 @@ public class StoreEntrySection extends Comp<CompStructure<VBox>> {
|
|||
section.getWrapper().toggleExpanded();
|
||||
})
|
||||
.apply(struc -> struc.get().setPrefWidth(40))
|
||||
.focusTraversable()
|
||||
.accessibleText("Expand")
|
||||
.disable(BindingsHelper.persist(
|
||||
Bindings.size(section.getChildren()).isEqualTo(0)))
|
||||
.grow(false, true).styleClass("expand-button");
|
||||
|
|
|
@ -59,6 +59,14 @@ public abstract class Comp<S extends CompStructure<?>> {
|
|||
return apply(struc -> VBox.setVgrow(struc.get(), Priority.ALWAYS));
|
||||
}
|
||||
|
||||
public Comp<S> focusTraversable() {
|
||||
return apply(struc -> struc.get().setFocusTraversable(true));
|
||||
}
|
||||
|
||||
public Comp<S> focusTraversable(boolean b) {
|
||||
return apply(struc -> struc.get().setFocusTraversable(b));
|
||||
}
|
||||
|
||||
public Comp<S> visible(ObservableValue<Boolean> o) {
|
||||
return apply(struc -> struc.get().visibleProperty().bind(o));
|
||||
}
|
||||
|
@ -90,6 +98,11 @@ public abstract class Comp<S extends CompStructure<?>> {
|
|||
return apply(struc -> struc.get().getStyleClass().add(styleClass));
|
||||
}
|
||||
|
||||
public Comp<S> accessibleText(String text) {
|
||||
return apply(struc -> struc.get().setAccessibleText(text));
|
||||
}
|
||||
|
||||
|
||||
public Comp<S> grow(boolean width, boolean height) {
|
||||
return apply(GrowAugment.create(width, height));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class CharsetChoiceComp extends SimpleComp {
|
|||
return new Label(streamCharset.getCharset().displayName()
|
||||
+ (streamCharset.hasByteOrderMark() ? " (BOM)" : ""));
|
||||
},
|
||||
new Label(AppI18n.get("app.none")),
|
||||
streamCharset -> streamCharset.getNames().get(0), new Label(AppI18n.get("app.none")),
|
||||
null);
|
||||
builder.addFilter((charset, filter) -> {
|
||||
return charset.getCharset().displayName().contains(filter);
|
||||
|
|
|
@ -59,8 +59,8 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
|||
|
||||
protected Region createGraphic(T s) {
|
||||
var provider = DataStoreProviders.byStore(s);
|
||||
var imgView =
|
||||
new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName(s)), 16, 16).createRegion();
|
||||
var imgView = new PrettyImageComp(new SimpleStringProperty(provider.getDisplayIconFileName(s)), 16, 16)
|
||||
.createRegion();
|
||||
|
||||
var name = DataStorage.get().getUsableStores().stream()
|
||||
.filter(e -> e.equals(s))
|
||||
|
@ -77,6 +77,14 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
|||
return new Label(name, imgView);
|
||||
}
|
||||
|
||||
private String toName(DataStore store) {
|
||||
if (mode == Mode.PROXY && store instanceof ShellStore && ShellStore.isLocal(store.asNeeded())) {
|
||||
return AppI18n.get("none");
|
||||
}
|
||||
|
||||
return XPipeDaemon.getInstance().getStoreName(store).orElse("?");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Region createSimple() {
|
||||
|
@ -88,6 +96,7 @@ public class DataStoreChoiceComp<T extends DataStore> extends SimpleComp {
|
|||
.findFirst()
|
||||
.orElseThrow()
|
||||
.createRegion(),
|
||||
t -> toName(t),
|
||||
new Label(AppI18n.get("none")),
|
||||
n -> true);
|
||||
comboBox.setSelectedDisplay(t -> createGraphic(t));
|
||||
|
|
|
@ -60,7 +60,7 @@ public class FileSystemStoreChoiceComp extends SimpleComp {
|
|||
});
|
||||
|
||||
var comboBox =
|
||||
new CustomComboBoxBuilder<FileSystemStore>(fileSystemProperty, this::createGraphic, null, v -> true);
|
||||
new CustomComboBoxBuilder<FileSystemStore>(fileSystemProperty, this::createGraphic, store -> getName(store), null, v -> true);
|
||||
comboBox.setSelectedDisplay(this::createDisplayGraphic);
|
||||
DataStorage.get().getUsableStores().stream()
|
||||
.filter(e -> e instanceof FileSystemStore)
|
||||
|
|
|
@ -34,6 +34,7 @@ public class IconButtonComp extends Comp<CompStructure<JFXButton>> {
|
|||
var button = new JFXButton();
|
||||
|
||||
var fi = new FontIcon(icon.getValue());
|
||||
fi.setFocusTraversable(false);
|
||||
icon.addListener((c, o, n) -> {
|
||||
fi.setIconLiteral(n);
|
||||
});
|
||||
|
|
|
@ -107,6 +107,8 @@ public class OptionsComp extends Comp<CompStructure<Pane>> {
|
|||
}
|
||||
|
||||
if (compRegion != null) {
|
||||
compRegion.accessibleTextProperty().bind(name.textProperty());
|
||||
compRegion.accessibleHelpProperty().bind(description.textProperty());
|
||||
line.getChildren().add(compRegion);
|
||||
}
|
||||
|
||||
|
@ -132,6 +134,7 @@ public class OptionsComp extends Comp<CompStructure<Pane>> {
|
|||
line.getChildren().add(name);
|
||||
|
||||
if (compRegion != null) {
|
||||
compRegion.accessibleTextProperty().bind(name.textProperty());
|
||||
compRegions.add(compRegion);
|
||||
line.getChildren().add(compRegion);
|
||||
HBox.setHgrow(compRegion, Priority.ALWAYS);
|
||||
|
|
|
@ -95,6 +95,7 @@ public class SvgView {
|
|||
wv.setPageFill(Color.TRANSPARENT);
|
||||
wv.getEngine().setJavaScriptEnabled(false);
|
||||
wv.setContextMenuEnabled(false);
|
||||
wv.setFocusTraversable(false);
|
||||
|
||||
wv.getEngine().loadContent(getHtml(svgContent.getValue()));
|
||||
svgContent.addListener((c, o, n) -> {
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.dlsc.preferencesfx.formsfx.view.renderer.PreferencesFxGroupRenderer;
|
|||
import com.dlsc.preferencesfx.util.PreferencesFxUtils;
|
||||
import io.xpipe.app.core.AppFont;
|
||||
import io.xpipe.app.core.AppI18n;
|
||||
import io.xpipe.app.fxcomps.util.BindingsHelper;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.GridPane;
|
||||
|
@ -53,7 +54,7 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
if (nextRow > 1) {
|
||||
GridPane.setMargin(titleLabel, new Insets(SPACING * 3, 0, SPACING, 0));
|
||||
} else {
|
||||
GridPane.setMargin(titleLabel, new Insets(SPACING, 0, SPACING, 0));
|
||||
GridPane.setMargin(titleLabel, new Insets(SPACING, 0, SPACING, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,21 +78,37 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
c.getFieldLabel().setMaxHeight(AppFont.getPixelSize(1));
|
||||
grid.add(c.getFieldLabel(), 0, i + rowAmount, 2, 1);
|
||||
|
||||
var canFocus = BindingsHelper.persist(c.getNode().disabledProperty().not());
|
||||
|
||||
var descriptionLabel = new Label();
|
||||
descriptionLabel.setWrapText(true);
|
||||
descriptionLabel.disableProperty().bind(c.getFieldLabel().disabledProperty());
|
||||
descriptionLabel.opacityProperty().bind(c.getFieldLabel().opacityProperty().multiply(0.8));
|
||||
descriptionLabel.managedProperty().bind(c.getFieldLabel().managedProperty());
|
||||
descriptionLabel.visibleProperty().bind(c.getFieldLabel().visibleProperty());
|
||||
descriptionLabel
|
||||
.disableProperty()
|
||||
.bind(c.getFieldLabel().disabledProperty());
|
||||
descriptionLabel
|
||||
.opacityProperty()
|
||||
.bind(c.getFieldLabel()
|
||||
.opacityProperty()
|
||||
.multiply(0.8));
|
||||
descriptionLabel
|
||||
.managedProperty()
|
||||
.bind(c.getFieldLabel().managedProperty());
|
||||
descriptionLabel
|
||||
.visibleProperty()
|
||||
.bind(c.getFieldLabel().visibleProperty());
|
||||
descriptionLabel.setMaxHeight(USE_PREF_SIZE);
|
||||
if (AppI18n.getInstance().containsKey(descriptionKey)) {
|
||||
rowAmount++;
|
||||
descriptionLabel.textProperty().bind(AppI18n.observable(descriptionKey));
|
||||
descriptionLabel.focusTraversableProperty().bind(canFocus);
|
||||
grid.add(descriptionLabel, 0, i + rowAmount, 2, 1);
|
||||
}
|
||||
|
||||
rowAmount++;
|
||||
grid.add(c.getNode(), 0, i + rowAmount, 1, 1);
|
||||
|
||||
var node = c.getNode();
|
||||
c.getFieldLabel().focusTraversableProperty().bind(canFocus);
|
||||
grid.add(node, 0, i + rowAmount, 1, 1);
|
||||
|
||||
if (i == elements.size() - 1) {
|
||||
// additional styling for the last setting
|
||||
|
@ -101,7 +118,7 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
var offset = preferencesGroup.getTitle() != null ? 15 : 0;
|
||||
|
||||
GridPane.setMargin(descriptionLabel, new Insets(SPACING, 0, 0, offset));
|
||||
GridPane.setMargin(c.getNode(), new Insets(SPACING, 0, 0, offset));
|
||||
GridPane.setMargin(node, new Insets(SPACING, 0, 0, offset));
|
||||
|
||||
if (!((i == 0) && (nextRow > 0))) {
|
||||
GridPane.setMargin(c.getFieldLabel(), new Insets(SPACING * 3, 0, 0, offset));
|
||||
|
@ -110,7 +127,7 @@ public class CustomFormRenderer extends PreferencesFxFormRenderer {
|
|||
}
|
||||
|
||||
c.getFieldLabel().getStyleClass().add(styleClass.toString() + "-label");
|
||||
c.getNode().getStyleClass().add(styleClass.toString() + "-node");
|
||||
node.getStyleClass().add(styleClass.toString() + "-node");
|
||||
}
|
||||
|
||||
if (element instanceof NodeElement nodeElement) {
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.xpipe.app.util;
|
|||
import io.xpipe.app.fxcomps.impl.FilterComp;
|
||||
import io.xpipe.app.fxcomps.util.SimpleChangeListener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.Property;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
|
@ -25,6 +26,7 @@ public class CustomComboBoxBuilder<T> {
|
|||
|
||||
private final Property<T> selected;
|
||||
private final Function<T, Node> nodeFunction;
|
||||
private final Function<T, String> accessibleNameFunction;
|
||||
private Function<T, Node> selectedDisplayNodeFunction;
|
||||
private final Map<Node, T> nodeMap = new HashMap<>();
|
||||
private final Map<Node, Runnable> actionsMap = new HashMap<>();
|
||||
|
@ -39,10 +41,11 @@ public class CustomComboBoxBuilder<T> {
|
|||
private Function<T, Node> unknownNode;
|
||||
|
||||
public CustomComboBoxBuilder(
|
||||
Property<T> selected, Function<T, Node> nodeFunction, Node emptyNode, Predicate<T> veto) {
|
||||
Property<T> selected, Function<T, Node> nodeFunction, Function<T, String> accessibleNameFunction, Node emptyNode, Predicate<T> veto) {
|
||||
this.selected = selected;
|
||||
this.nodeFunction = nodeFunction;
|
||||
this.selectedDisplayNodeFunction = nodeFunction;
|
||||
this.accessibleNameFunction = accessibleNameFunction;
|
||||
this.emptyNode = emptyNode;
|
||||
this.veto = veto;
|
||||
}
|
||||
|
@ -66,6 +69,7 @@ public class CustomComboBoxBuilder<T> {
|
|||
|
||||
public Node add(T val) {
|
||||
var node = nodeFunction.apply(val);
|
||||
node.setAccessibleText(accessibleNameFunction.apply(val));
|
||||
nodeMap.put(node, val);
|
||||
nodes.add(node);
|
||||
if (filterPredicate != null) {
|
||||
|
@ -86,6 +90,7 @@ public class CustomComboBoxBuilder<T> {
|
|||
var header = new Label(name);
|
||||
header.setAlignment(Pos.CENTER);
|
||||
var v = new VBox(spacer, header, new Separator(Orientation.HORIZONTAL));
|
||||
v.setAccessibleText(name);
|
||||
v.setAlignment(Pos.CENTER);
|
||||
nodes.add(v);
|
||||
disabledNodes.add(v);
|
||||
|
@ -105,6 +110,9 @@ public class CustomComboBoxBuilder<T> {
|
|||
|
||||
public ComboBox<Node> build() {
|
||||
var cb = new ComboBox<Node>();
|
||||
cb.accessibleTextProperty().bind(Bindings.createStringBinding(() -> {
|
||||
return selected.getValue() != null ? accessibleNameFunction.apply(selected.getValue()) : null;
|
||||
}, selected));
|
||||
cb.getItems().addAll(nodes);
|
||||
cb.setCellFactory((lv) -> {
|
||||
return new Cell();
|
||||
|
|
Loading…
Reference in a new issue