From 160bc464735549076f855f5056b71e123b5c374b Mon Sep 17 00:00:00 2001 From: palexdev Date: Tue, 2 Nov 2021 18:10:18 +0100 Subject: [PATCH] :boom: Huge Update [Part 2] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disclaimer: I recently switched to Linux for production because I was tired of Bugdows but because they use different line endings IntelliJ is showing me that all files are changed, also the ones with identical content. I re-normalized the project and added a .gitattributes file. I'm not sure how GitHub will visualize this commit, if it's messed sorry in advance... but don't worry, as always all changes are listed here 😉 :arrow_up: Upgraded VirtualizedFX to version 11.2.1 Demo :construction: Temporarily "disabled" or non-functional some showcases :white_check_mark: Added new tests MaterialFX Beans Package :sparkles: Added convenience properties for Java's functions :sparkles: Added convenience property to represent a NumberRange :sparkles: Added many new beans :recycle: NumberRange: implemented hashCode, equals and toString, added two new methods to convert a range on integers to a List or a Set :truck: Renamed RipplePosition ti PositionBean and moved to this package Collections Package :sparkles: TransformableList is a new kind of ObservableList that combines JavaFX's FilteredList and SortedList functionalities into one :sparkles: TransformableListWrapper is an ObservableList which wraps both the source list and the transformable list in the same class. This makes using TransformableLists less verbose as modifications to the source list can be made directly from this wrapper Controls Package :fire: Removed AbstractMFXNotificationPane :fire: Removed MFXNotification :fire: Removed SimpleMFXNotificationPane :sparkles: Added a new cell to contain notifications :sparkles: FilterPane, a new control that allows to build Predicate filters interactively :sparkles: MFXNotificationCenter, a new control that allows to display multiple notifications. It is basically an icon that opens a popup which contains not only the list of notifications but also controls to manage them :sparkles: MFXPopup, extension of PopupControl to easily set the popup's content and position it by using HPos and VPos enumerations. It also introduces a hover functionality :sparkles: MFXSimpleNotification, a simple implementation of INotification Effects Package :sparkles: ConsumerTransition, an implementation of Transition that uses a consumer to perform some action when the interpolate method is called :sparkles: Interpolators, a new enumerator that offers some new interpolators for JavaFX's animations Enums Package :recycle: Moved all MaterialFX enumerators to this top level package :sparkles: ChainMode, a new enumerator mainly used by PredicateUtils to chain two predicates :sparkles: NotificationCounterStyle, a new enumerator to specify MFXNotificationCenter's counter style :sparkles: NotificationPos, a new enumerator to specify at which position a notification system should place the notification :sparkles: NotificationState, a new enumerator to represent the read state of a notification Factories Package :recycle: Moved all MaterialFX factories to this top level package :sparkles: InsetsFactory, a new factory tp build JavaFX's Insets objects Filter Package :boom: The filter API has been completely remade and now it's super flexible, super useful, super amazin haha. I won't describe it here as there are a LOT of new classes and concepts to be described so I recommend you to read AbstractFilter, FilterBean and BiPredicateBean documentations, usage examples can be also found in the demo (not yet at time of writing) and in the documentation of MFXFilterPane :construction: MFXFilterDialog has been completely commented, will be reworked for the new API Font Package :sparkles: Added new resources Notifications Package :boom: The notification API has been completely remade. Now there are to notification systems, one is very similar to the old one but it is limited to one notification at a time at a given position. This restriction helper to keep the system simple and efficient. To show multiple notifications at one time I recommend the usage of MFXNotificationCenterSystem which uses a MFXNotificationCenter to show the notifications. Or, you could implement you own notification system since the notification API now offers some base classes to build on top. AbstractMFXNotificationSystem and INotificationSystem specify the base features all notification systems should have, INotification specifies the base features all notifications should have Skin Package No notable change aside from new skins for the new controls and minor changes due to classes renamed/moved Utils Package :sparkles: FunctionalStringConverter, a functional alternative to JavaFX's StringConverter :sparkles: ReusableScheduledExecutor, a wrapper class to make a ScheduledExecutorService reusable. To stop/restart a ScheduledExecutorService it's needed to keep a reference to the ScheduledFuture task but this often result in boilerplate code, this wrapper fixes this :sparkles: EnumStringConverter, an implementation of JavaFX's StringConverter to work with enumerators :sparkles: Added a new method to ExecutionUtils :sparkles: FXCollectors, a class that contains some new collectors for JavaFX's observable collections :sparkles: PredicateUtils, utils for Predicates :sparkles: StringUtils, added a new method to convert an elapsed time in seconds to a String :recycle: AnimationUtils, added some new methods to PauseTransitionBuilder and KeyFrames classes :bug: ExceptionUtils, fixed getStackTraceString method as StringWriters are not reusable Resources :sparkles: Added new CSS files for new controls :recycle: MFXColors.css, added a new color Signed-off-by: Alessadro Parisi Signed-off-by: palexdev --- .gitattributes | 34 + .github/workflows/gradle.yml | 0 .gitignore | 0 .run/MaterialFX [build].run.xml | 0 .run/MaterialFX [clean].run.xml | 0 .run/MaterialFX [jlinkZip].run.xml | 0 ...rialFX [materialfx_uploadArchives].run.xml | 0 .run/MaterialFX [run].run.xml | 0 .run/MaterialFX [testrun].run.xml | 0 LICENSE | 0 README.md | 0 ROADMAP.md | 0 build.gradle | 0 demo/build.gradle | 2 +- demo/libs/scenicview.jar | Bin .../github/palexdev/materialfx/demo/Demo.java | 0 .../demo/MFXDemoResourcesLoader.java | 0 .../palexdev/materialfx/demo/TestDemo.java | 0 .../controllers/ComboBoxesDemoController.java | 0 .../DatePickersDemoController.java | 0 .../demo/controllers/DemoController.java | 0 .../demo/controllers/DialogsController.java | 30 +- .../FontResourcesDemoController.java | 0 .../demo/controllers/InfoController.java | 0 .../controllers/LabelsDemoController.java | 0 .../controllers/ListViewsDemoController.java | 0 .../controllers/NotificationsController.java | 36 +- .../ProgressBarsDemoController.java | 2 +- .../ProgressSpinnersDemoController.java | 0 .../controllers/ScrollPaneDemoController.java | 0 .../controllers/SlidersDemoController.java | 0 .../controllers/StepperDemoController.java | 0 .../controllers/TableViewsDemoController.java | 0 .../controllers/TextFieldsDemoController.java | 0 .../demo/controllers/TogglesController.java | 0 .../controllers/TreeviewsDemoController.java | 0 .../demo/model/FilterablePerson.java | 9 +- .../materialfx/demo/model/Machine.java | 10 +- .../materialfx/demo/model/Person.java | 0 .../materialfx/demo/model/SimplePerson.java | 0 demo/src/main/java/module-info.java | 0 .../palexdev/materialfx/demo/ButtonsDemo.fxml | 0 .../materialfx/demo/CheckBoxesDemo.fxml | 0 .../materialfx/demo/ComboBoxesDemo.fxml | 0 .../materialfx/demo/DatePickersDemo.fxml | 0 .../github/palexdev/materialfx/demo/Demo.fxml | 0 .../palexdev/materialfx/demo/DialogsDemo.fxml | 0 .../materialfx/demo/FontResourcesDemo.fxml | 0 .../palexdev/materialfx/demo/InfoDialog.fxml | 0 .../palexdev/materialfx/demo/LabelsDemo.fxml | 0 .../materialfx/demo/ListViewsDemo.fxml | 0 .../materialfx/demo/NotificationsDemo.fxml | 0 .../materialfx/demo/ProgressBarsDemo.fxml | 0 .../materialfx/demo/ProgressSpinnersDemo.fxml | 0 .../materialfx/demo/RadioButtonsDemo.fxml | 0 .../materialfx/demo/ScrollPanesDemo.fxml | 0 .../palexdev/materialfx/demo/SlidersDemo.fxml | 0 .../palexdev/materialfx/demo/StepperDemo.fxml | 0 .../materialfx/demo/TableViewsDemo.fxml | 0 .../materialfx/demo/TextFieldsDemo.fxml | 0 .../materialfx/demo/ToggleButtonsDemo.fxml | 0 .../materialfx/demo/TreeViewsDemo.fxml | 0 .../palexdev/materialfx/demo/assets/logo.png | Bin .../materialfx/demo/assets/welcome1.wav | Bin .../materialfx/demo/assets/welcome2.wav | Bin .../materialfx/demo/css/ButtonsDemo.css | 0 .../materialfx/demo/css/CheckBoxesDemo.css | 0 .../materialfx/demo/css/ComboBoxesDemo.css | 0 .../palexdev/materialfx/demo/css/Common.css | 0 .../materialfx/demo/css/CustomDatePicker.css | 0 .../materialfx/demo/css/DatePickersDemo.css | 0 .../palexdev/materialfx/demo/css/Demo.css | 0 .../materialfx/demo/css/InfoDialog.css | 0 .../materialfx/demo/css/ListViewsDemo.css | 0 .../materialfx/demo/css/MFXColors.css | 0 .../materialfx/demo/css/ProgressBarDemo.css | 0 .../demo/css/ProgressSpinnersDemo.css | 0 .../materialfx/demo/css/RadioButtonsDemo.css | 0 .../materialfx/demo/css/ScrollPanesDemo.css | 0 .../materialfx/demo/css/SlidersDemo.css | 0 .../materialfx/demo/css/StepperDemo.css | 0 .../palexdev/materialfx/demo/css/TestDemo.css | 0 .../materialfx/demo/css/TextFieldsDemo.css | 0 .../materialfx/demo/css/ToggleButtonsDemo.css | 0 .../demo/fonts/Comfortaa/Comfortaa-Bold.ttf | Bin .../demo/fonts/Comfortaa/Comfortaa-Light.ttf | Bin .../demo/fonts/Comfortaa/Comfortaa-Medium.ttf | Bin .../fonts/Comfortaa/Comfortaa-Regular.ttf | Bin .../fonts/Comfortaa/Comfortaa-SemiBold.ttf | Bin .../Comfortaa/Comfortaa-VariableFont_wght.ttf | Bin .../demo/fonts/OpenSans/OpenSans-Bold.ttf | Bin .../fonts/OpenSans/OpenSans-BoldItalic.ttf | Bin .../fonts/OpenSans/OpenSans-ExtraBold.ttf | Bin .../OpenSans/OpenSans-ExtraBoldItalic.ttf | Bin .../demo/fonts/OpenSans/OpenSans-Italic.ttf | Bin .../demo/fonts/OpenSans/OpenSans-Light.ttf | Bin .../fonts/OpenSans/OpenSans-LightItalic.ttf | Bin .../demo/fonts/OpenSans/OpenSans-Regular.ttf | Bin .../demo/fonts/OpenSans/OpenSans-SemiBold.ttf | Bin .../OpenSans/OpenSans-SemiBoldItalic.ttf | Bin .../demo/fonts/Roboto/Roboto-Black.ttf | Bin .../demo/fonts/Roboto/Roboto-BlackItalic.ttf | Bin .../demo/fonts/Roboto/Roboto-Bold.ttf | Bin .../demo/fonts/Roboto/Roboto-BoldItalic.ttf | Bin .../demo/fonts/Roboto/Roboto-Italic.ttf | Bin .../demo/fonts/Roboto/Roboto-Light.ttf | Bin .../demo/fonts/Roboto/Roboto-LightItalic.ttf | Bin .../demo/fonts/Roboto/Roboto-Medium.ttf | Bin .../demo/fonts/Roboto/Roboto-MediumItalic.ttf | Bin .../demo/fonts/Roboto/Roboto-Regular.ttf | Bin .../demo/fonts/Roboto/Roboto-Thin.ttf | Bin .../demo/fonts/Roboto/Roboto-ThinItalic.ttf | Bin demo/src/main/resources/logo.ico | Bin demo/src/test/java/Launcher.java | 3 +- demo/src/test/java/NotificationsTest.java | 84 ++ demo/src/test/java/PopupTest.java | 73 ++ .../java/binding/BindingManagerTests.java | 0 .../collections/TransformableListTest.java | 69 ++ demo/src/test/java/combobox/ComboBoxTest.java | 0 .../properties/SynchronizedBooleanTests.java | 0 .../properties/SynchronizedDoubleTests.java | 0 .../properties/SynchronizedFloatTests.java | 0 .../properties/SynchronizedIntegerTests.java | 0 .../properties/SynchronizedLongTests.java | 0 .../properties/SynchronizedObjectTests.java | 0 .../properties/SynchronizedStringTests.java | 0 .../selection/SingleSelectionModelTests.java | 0 .../test/java/treeview/NumberUtilsTests.java | 0 .../src/test/java/treeview/TreeViewTests.java | 0 gradle/wrapper/gradle-wrapper.jar | Bin gradle/wrapper/gradle-wrapper.properties | 0 gradlew | 0 gradlew.bat | 0 materialfx/build.gradle | 4 +- materialfx/gradle.properties | 0 .../materialfx/MFXResourcesLoader.java | 0 .../materialfx/beans/AnimationsData.java | 0 .../materialfx/beans/BiPredicateBean.java | 42 + .../materialfx/beans/CustomBounds.java | 98 +++ .../palexdev/materialfx/beans/FilterBean.java | 104 +++ .../materialfx/beans/MFXLoaderBean.java | 0 .../materialfx/beans/MFXSnapshotWrapper.java | 0 .../materialfx/beans/NumberRange.java | 41 +- .../materialfx/beans/PopupPositionBean.java | 121 +++ .../materialfx/beans/PositionBean.java | 86 +++ .../beans/TransitionPositionBean.java | 85 +++ .../beans/properties/NumberRangeProperty.java | 62 ++ .../properties/base/ResettableProperty.java | 0 .../properties/base/SynchronizedProperty.java | 0 .../functional/BiConsumerProperty.java | 14 + .../functional/BiFunctionProperty.java | 15 + .../functional/BiPredicateProperty.java | 14 + .../functional/ConsumerProperty.java | 13 + .../functional/FunctionProperty.java | 14 + .../functional/PredicateProperty.java | 13 + .../functional/SupplierProperty.java | 13 + .../resettable/ResettableBooleanProperty.java | 0 .../resettable/ResettableDoubleProperty.java | 0 .../resettable/ResettableFloatProperty.java | 0 .../resettable/ResettableIntegerProperty.java | 0 .../resettable/ResettableLongProperty.java | 0 .../resettable/ResettableObjectProperty.java | 0 .../resettable/ResettableStringProperty.java | 0 .../synced/SynchronizedBooleanProperty.java | 0 .../synced/SynchronizedDoubleProperty.java | 0 .../synced/SynchronizedFloatProperty.java | 0 .../synced/SynchronizedIntegerProperty.java | 0 .../synced/SynchronizedLongProperty.java | 0 .../synced/SynchronizedObjectProperty.java | 0 .../synced/SynchronizedStringProperty.java | 0 .../bindings/BidirectionalBindingHelper.java | 0 .../materialfx/bindings/BindingHelper.java | 0 .../materialfx/bindings/BindingManager.java | 0 .../bindings/BooleanListBinding.java | 0 .../materialfx/collections/ChangeHelper.java | 35 + .../materialfx/collections/CircularQueue.java | 0 .../collections/GenericAddRemoveChange.java | 156 ++++ .../collections/ObservableStack.java | 0 .../collections/TransformableList.java | 269 +++++++ .../collections/TransformableListWrapper.java | 168 ++++ .../materialfx/controls/MFXButton.java | 6 +- .../materialfx/controls/MFXCheckListView.java | 0 .../materialfx/controls/MFXCheckTreeItem.java | 0 .../materialfx/controls/MFXCheckTreeView.java | 0 .../materialfx/controls/MFXCheckbox.java | 0 .../controls/MFXCircleToggleNode.java | 2 +- .../materialfx/controls/MFXComboBox.java | 6 +- .../materialfx/controls/MFXContextMenu.java | 4 +- .../controls/MFXContextMenuItem.java | 0 .../materialfx/controls/MFXDatePicker.java | 12 +- .../materialfx/controls/MFXDialog.java | 0 .../controls/MFXExceptionDialog.java | 2 +- .../controls/MFXFilterComboBox.java | 0 .../materialfx/controls/MFXFilterPane.java | 240 ++++++ .../materialfx/controls/MFXHLoader.java | 4 +- .../materialfx/controls/MFXIconWrapper.java | 8 +- .../materialfx/controls/MFXLabel.java | 2 +- .../materialfx/controls/MFXListView.java | 0 .../materialfx/controls/MFXNotification.java | 194 ----- .../controls/MFXNotificationCenter.java | 721 ++++++++++++++++++ .../materialfx/controls/MFXPasswordField.java | 3 +- .../materialfx/controls/MFXPopup.java | 357 +++++++++ .../materialfx/controls/MFXProgressBar.java | 0 .../controls/MFXProgressSpinner.java | 0 .../materialfx/controls/MFXRadioButton.java | 0 .../controls/MFXRectangleToggleNode.java | 2 +- .../materialfx/controls/MFXScrollPane.java | 0 .../controls/MFXSimpleNotification.java | 147 ++++ .../materialfx/controls/MFXSlider.java | 8 +- .../materialfx/controls/MFXStageDialog.java | 6 +- .../materialfx/controls/MFXStepper.java | 2 +- .../materialfx/controls/MFXStepperToggle.java | 4 +- .../materialfx/controls/MFXTableRow.java | 6 +- .../controls/MFXTableSortModel.java | 2 +- .../materialfx/controls/MFXTableView.java | 0 .../materialfx/controls/MFXTextField.java | 4 +- .../materialfx/controls/MFXToggleButton.java | 0 .../materialfx/controls/MFXTooltip.java | 0 .../materialfx/controls/MFXTreeItem.java | 0 .../materialfx/controls/MFXTreeView.java | 0 .../materialfx/controls/MFXVLoader.java | 4 +- .../controls/SimpleMFXNotificationPane.java | 235 ------ .../controls/base/AbstractMFXDialog.java | 4 +- .../controls/base/AbstractMFXListView.java | 0 .../base/AbstractMFXNotificationPane.java | 88 --- .../controls/base/AbstractMFXToggleNode.java | 0 .../controls/base/AbstractMFXTreeCell.java | 0 .../controls/base/AbstractMFXTreeItem.java | 0 .../materialfx/controls/base/IListView.java | 0 .../controls/cell/MFXCheckListCell.java | 4 +- .../controls/cell/MFXCheckTreeCell.java | 0 .../materialfx/controls/cell/MFXDateCell.java | 0 .../materialfx/controls/cell/MFXListCell.java | 4 +- .../controls/cell/MFXNotificationCell.java | 224 ++++++ .../controls/cell/MFXSimpleTreeCell.java | 0 .../controls/cell/MFXTableColumn.java | 2 +- .../controls/cell/MFXTableRowCell.java | 0 .../cell/base/AbstractMFXListCell.java | 4 +- .../controls/legacy/MFXLegacyComboBox.java | 2 +- .../controls/legacy/MFXLegacyListCell.java | 4 +- .../controls/legacy/MFXLegacyListView.java | 0 .../controls/legacy/MFXLegacyTableRow.java | 4 +- .../controls/legacy/MFXLegacyTableView.java | 0 .../effects/ConsumerTransition.java | 138 ++++ .../materialfx/effects/DepthLevel.java | 0 .../materialfx/effects/Interpolators.java | 101 +++ .../materialfx/effects/MFXDepthManager.java | 0 .../materialfx/effects/MFXScrimEffect.java | 0 .../ripple/MFXCircleRippleGenerator.java | 19 +- .../effects/ripple/RippleClipType.java | 0 .../effects/ripple/RippleGenerator.java | 4 +- .../effects/ripple/RipplePosition.java | 74 -- .../base/AbstractMFXRippleGenerator.java | 4 +- .../effects/ripple/base/IRipple.java | 0 .../effects/ripple/base/IRippleGenerator.java | 10 +- .../{controls => }/enums/ButtonType.java | 2 +- .../palexdev/materialfx/enums/ChainMode.java | 22 + .../{controls => }/enums/DialogType.java | 2 +- .../enums/LoaderCacheLevel.java | 2 +- .../enums/NotificationCounterStyle.java | 10 + .../materialfx/enums/NotificationPos.java | 30 + .../materialfx/enums/NotificationState.java | 8 + .../{controls => }/enums/SliderEnums.java | 13 +- .../{controls => }/enums/SortState.java | 5 +- .../enums/StepperToggleState.java | 4 +- .../{controls => }/enums/Styles.java | 2 +- .../{controls => }/enums/TextPosition.java | 2 +- .../materialfx/factories/InsetsFactory.java | 53 ++ .../factories/MFXAnimationFactory.java | 2 +- .../factories/MFXDialogFactory.java | 6 +- .../factories/MFXStageDialogFactory.java | 4 +- .../factories/RippleClipTypeFactory.java | 2 +- .../materialfx/filter/BooleanFilter.java | 51 ++ .../materialfx/filter/DoubleFilter.java | 59 ++ .../materialfx/filter/EnumFilter.java | 66 ++ .../materialfx/filter/EvaluationMode.java | 23 - .../materialfx/filter/FloatFilter.java | 59 ++ .../materialfx/filter/IFilterable.java | 27 - .../materialfx/filter/IntegerFilter.java | 59 ++ .../materialfx/filter/LongFilter.java | 59 ++ .../materialfx/filter/MFXEvaluationBox.java | 195 ----- .../materialfx/filter/MFXFilterDialog.java | 56 +- .../materialfx/filter/StringFilter.java | 81 ++ .../filter/base/AbstractFilter.java | 246 ++++++ .../materialfx/filter/base/NumberFilter.java | 18 + .../palexdev/materialfx/font/FontHandler.java | 0 .../materialfx/font/FontResources.java | 184 ++--- .../palexdev/materialfx/font/MFXFontIcon.java | 0 .../MFXNotificationCenterSystem.java | 342 +++++++++ .../notifications/MFXNotificationSystem.java | 295 +++++++ .../notifications/NotificationPos.java | 24 - .../notifications/NotificationsManager.java | 128 ---- .../notifications/PositionManager.java | 235 ------ .../base/AbstractMFXNotificationSystem.java | 268 +++++++ .../notifications/base/INotification.java | 67 ++ .../base/INotificationSystem.java | 26 + .../selection/ComboBoxSelectionModel.java | 8 +- .../selection/MultipleSelectionManager.java | 0 .../selection/MultipleSelectionModel.java | 4 + .../selection/SingleSelectionManager.java | 0 .../selection/SingleSelectionModel.java | 7 +- .../selection/TableSelectionModel.java | 0 .../materialfx/selection/TreeCheckModel.java | 0 .../selection/TreeSelectionModel.java | 0 .../base/AbstractMultipleSelectionModel.java | 4 + .../base/AbstractSingleSelectionModel.java | 4 + .../base/IMultipleSelectionModel.java | 0 .../selection/base/ISingleSelectionModel.java | 0 .../selection/base/ITableSelectionModel.java | 0 .../selection/base/ITreeCheckModel.java | 0 .../selection/base/ITreeSelectionModel.java | 0 .../materialfx/skins/MFXButtonSkin.java | 0 .../skins/MFXCheckTreeItemSkin.java | 0 .../materialfx/skins/MFXCheckboxSkin.java | 10 +- .../skins/MFXCircleToggleNodeSkin.java | 6 +- .../materialfx/skins/MFXComboBoxSkin.java | 8 +- .../skins/MFXContextMenuItemSkin.java | 0 .../materialfx/skins/MFXDateCellSkin.java | 6 +- .../skins/MFXDatePickerContent.java | 10 +- .../skins/MFXFilterComboBoxSkin.java | 8 +- .../materialfx/skins/MFXFilterPaneSkin.java | 342 +++++++++ .../materialfx/skins/MFXLabelSkin.java | 4 +- .../materialfx/skins/MFXListViewSkin.java | 2 +- .../skins/MFXNotificationCenterSkin.java | 213 ++++++ .../skins/MFXPasswordFieldSkin.java | 0 .../materialfx/skins/MFXPopupSkin.java | 125 +++ .../materialfx/skins/MFXProgressBarSkin.java | 0 .../skins/MFXProgressSpinnerSkin.java | 0 .../materialfx/skins/MFXRadioButtonSkin.java | 8 +- .../skins/MFXRectangleToggleNodeSkin.java | 4 +- .../materialfx/skins/MFXScrollPaneSkin.java | 0 .../materialfx/skins/MFXSliderSkin.java | 6 +- .../materialfx/skins/MFXStepperSkin.java | 4 +- .../skins/MFXStepperToggleSkin.java | 6 +- .../materialfx/skins/MFXTableColumnSkin.java | 0 .../materialfx/skins/MFXTableRowCellSkin.java | 0 .../materialfx/skins/MFXTableViewSkin.java | 28 +- .../materialfx/skins/MFXTextFieldSkin.java | 2 +- .../materialfx/skins/MFXToggleButtonSkin.java | 8 +- .../materialfx/skins/MFXTreeItemSkin.java | 2 +- .../skins/legacy/MFXLegacyComboBoxSkin.java | 2 +- .../skins/legacy/MFXLegacyListViewSkin.java | 2 +- .../skins/legacy/MFXLegacyTableViewSkin.java | 0 .../materialfx/utils/AnimationUtils.java | 33 +- .../materialfx/utils/BindingUtils.java | 0 .../palexdev/materialfx/utils/ColorUtils.java | 0 .../materialfx/utils/DialogUtils.java | 4 +- .../materialfx/utils/DragResizer.java | 0 .../materialfx/utils/EnumStringConverter.java | 42 + .../materialfx/utils/ExceptionUtils.java | 2 +- .../materialfx/utils/ExecutionUtils.java | 35 + .../materialfx/utils/FXCollectors.java | 32 + .../palexdev/materialfx/utils/LabelUtils.java | 0 .../materialfx/utils/ListChangeProcessor.java | 0 .../materialfx/utils/LoaderUtils.java | 0 .../palexdev/materialfx/utils/NodeUtils.java | 0 .../materialfx/utils/NumberUtils.java | 0 .../materialfx/utils/PredicateUtils.java | 21 + .../materialfx/utils/RandomInstance.java | 0 .../materialfx/utils/ScrollUtils.java | 2 +- .../materialfx/utils/StringUtils.java | 23 + .../materialfx/utils/ToggleButtonsUtil.java | 0 .../materialfx/utils/TreeItemIterator.java | 0 .../materialfx/utils/TreeItemStream.java | 0 .../others/FunctionalStringConverter.java | 13 + .../others/ReusableScheduledExecutor.java | 70 ++ .../materialfx/utils/others/TriConsumer.java | 0 .../validation/MFXDialogValidator.java | 4 +- .../validation/MFXPriorityValidator.java | 0 .../validation/base/AbstractMFXValidator.java | 0 .../validation/base/IMFXValidator.java | 0 .../materialfx/validation/base/Validated.java | 0 materialfx/src/main/java/module-info.java | 7 +- .../github/palexdev/materialfx/css/Fonts.css | 0 .../palexdev/materialfx/css/MFXButton.css | 0 .../palexdev/materialfx/css/MFXCheckBox.css | 0 .../materialfx/css/MFXCheckListCell.css | 0 .../materialfx/css/MFXCheckListView.css | 0 .../materialfx/css/MFXCheckTreeCell.css | 0 .../materialfx/css/MFXCircleToggleNode.css | 0 .../palexdev/materialfx/css/MFXColors.css | 1 + .../materialfx/css/MFXComboBoxStyle1.css | 0 .../materialfx/css/MFXComboBoxStyle2.css | 0 .../materialfx/css/MFXComboBoxStyle3.css | 0 .../materialfx/css/MFXContextMenu.css | 0 .../materialfx/css/MFXContextMenuItem.css | 0 .../palexdev/materialfx/css/MFXDatePicker.css | 0 .../materialfx/css/MFXDatePickerContent.css | 0 .../palexdev/materialfx/css/MFXDialog.css | 0 .../materialfx/css/MFXEvaluationBox.css | 0 .../materialfx/css/MFXFilterComboBox.css | 0 .../materialfx/css/MFXFilterDialog.css | 0 .../palexdev/materialfx/css/MFXFilterPane.css | 172 +++++ .../materialfx/css/MFXLabelStyle1.css | 0 .../materialfx/css/MFXLabelStyle2.css | 0 .../materialfx/css/MFXLabelStyle3.css | 0 .../palexdev/materialfx/css/MFXListCell.css | 0 .../palexdev/materialfx/css/MFXListView.css | 0 .../materialfx/css/MFXNotification.css | 0 .../materialfx/css/MFXNotificationCenter.css | 88 +++ .../materialfx/css/MFXPasswordField.css | 0 .../materialfx/css/MFXProgressBar.css | 0 .../materialfx/css/MFXProgressSpinner.css | 0 .../materialfx/css/MFXRadioButton.css | 0 .../materialfx/css/MFXRectangleToggleNode.css | 0 .../palexdev/materialfx/css/MFXScrollPane.css | 0 .../palexdev/materialfx/css/MFXSlider.css | 0 .../palexdev/materialfx/css/MFXStepper.css | 0 .../materialfx/css/MFXStepperToggle.css | 0 .../materialfx/css/MFXTableColumn.css | 0 .../palexdev/materialfx/css/MFXTableRow.css | 0 .../materialfx/css/MFXTableRowCell.css | 0 .../palexdev/materialfx/css/MFXTableView.css | 0 .../palexdev/materialfx/css/MFXTextField.css | 0 .../materialfx/css/MFXToggleButton.css | 0 .../palexdev/materialfx/css/MFXTreeCell.css | 0 .../palexdev/materialfx/css/MFXTreeItem.css | 0 .../palexdev/materialfx/css/MFXTreeView.css | 0 .../materialfx/css/legacy/MFXComboBox.css | 0 .../css/legacy/MFXLegacyListCell.css | 0 .../css/legacy/MFXLegacyListView.css | 0 .../materialfx/css/legacy/MFXTableRow.css | 0 .../materialfx/css/legacy/MFXTableView.css | 0 .../fonts/Comfortaa/Comfortaa-Bold.ttf | Bin .../fonts/Comfortaa/Comfortaa-Light.ttf | Bin .../fonts/Comfortaa/Comfortaa-Medium.ttf | Bin .../fonts/Comfortaa/Comfortaa-Regular.ttf | Bin .../fonts/Comfortaa/Comfortaa-SemiBold.ttf | Bin .../Comfortaa/Comfortaa-VariableFont_wght.ttf | Bin .../materialfx/fonts/MFXResources.ttf | Bin 18400 -> 20080 bytes .../fonts/OpenSans/OpenSans-Bold.ttf | Bin .../fonts/OpenSans/OpenSans-BoldItalic.ttf | Bin .../fonts/OpenSans/OpenSans-ExtraBold.ttf | Bin .../OpenSans/OpenSans-ExtraBoldItalic.ttf | Bin .../fonts/OpenSans/OpenSans-Italic.ttf | Bin .../fonts/OpenSans/OpenSans-Light.ttf | Bin .../fonts/OpenSans/OpenSans-LightItalic.ttf | Bin .../fonts/OpenSans/OpenSans-Regular.ttf | Bin .../fonts/OpenSans/OpenSans-SemiBold.ttf | Bin .../OpenSans/OpenSans-SemiBoldItalic.ttf | Bin .../materialfx/fonts/Roboto/Roboto-Black.ttf | Bin .../fonts/Roboto/Roboto-BlackItalic.ttf | Bin .../materialfx/fonts/Roboto/Roboto-Bold.ttf | Bin .../fonts/Roboto/Roboto-BoldItalic.ttf | Bin .../materialfx/fonts/Roboto/Roboto-Italic.ttf | Bin .../materialfx/fonts/Roboto/Roboto-Light.ttf | Bin .../fonts/Roboto/Roboto-LightItalic.ttf | Bin .../materialfx/fonts/Roboto/Roboto-Medium.ttf | Bin .../fonts/Roboto/Roboto-MediumItalic.ttf | Bin .../fonts/Roboto/Roboto-Regular.ttf | Bin .../materialfx/fonts/Roboto/Roboto-Thin.ttf | Bin .../fonts/Roboto/Roboto-ThinItalic.ttf | Bin settings.gradle | 0 453 files changed, 6920 insertions(+), 1589 deletions(-) create mode 100644 .gitattributes mode change 100644 => 100755 .github/workflows/gradle.yml mode change 100644 => 100755 .gitignore mode change 100644 => 100755 .run/MaterialFX [build].run.xml mode change 100644 => 100755 .run/MaterialFX [clean].run.xml mode change 100644 => 100755 .run/MaterialFX [jlinkZip].run.xml mode change 100644 => 100755 .run/MaterialFX [materialfx_uploadArchives].run.xml mode change 100644 => 100755 .run/MaterialFX [run].run.xml mode change 100644 => 100755 .run/MaterialFX [testrun].run.xml mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md mode change 100644 => 100755 ROADMAP.md mode change 100644 => 100755 build.gradle mode change 100644 => 100755 demo/build.gradle mode change 100644 => 100755 demo/libs/scenicview.jar mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/Demo.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/MFXDemoResourcesLoader.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/TestDemo.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ComboBoxesDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DatePickersDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DialogsController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/FontResourcesDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/InfoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/LabelsDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ListViewsDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/NotificationsController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressBarsDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressSpinnersDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ScrollPaneDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/SlidersDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/StepperDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TableViewsDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TextFieldsDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TogglesController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TreeviewsDemoController.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/model/FilterablePerson.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/model/Machine.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/model/Person.java mode change 100644 => 100755 demo/src/main/java/io/github/palexdev/materialfx/demo/model/SimplePerson.java mode change 100644 => 100755 demo/src/main/java/module-info.java mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/ButtonsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/CheckBoxesDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/ComboBoxesDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/DatePickersDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/Demo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/DialogsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/FontResourcesDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/InfoDialog.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/LabelsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/ListViewsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/NotificationsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/ProgressBarsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/ProgressSpinnersDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/RadioButtonsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/ScrollPanesDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/SlidersDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/StepperDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/TableViewsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/TextFieldsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/ToggleButtonsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/TreeViewsDemo.fxml mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/logo.png mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/welcome1.wav mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/welcome2.wav mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ButtonsDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/CheckBoxesDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ComboBoxesDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/Common.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/CustomDatePicker.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/DatePickersDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/Demo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/InfoDialog.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ListViewsDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/MFXColors.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ProgressBarDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ProgressSpinnersDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/RadioButtonsDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ScrollPanesDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/SlidersDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/StepperDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/TestDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/TextFieldsDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ToggleButtonsDemo.css mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Bold.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Light.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Medium.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Regular.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-SemiBold.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-VariableFont_wght.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Bold.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-BoldItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-ExtraBold.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Italic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Light.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-LightItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Regular.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-SemiBold.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-SemiBoldItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Black.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-BlackItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Bold.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-BoldItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Italic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Light.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-LightItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Medium.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-MediumItalic.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Regular.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Thin.ttf mode change 100644 => 100755 demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-ThinItalic.ttf mode change 100644 => 100755 demo/src/main/resources/logo.ico mode change 100644 => 100755 demo/src/test/java/Launcher.java create mode 100755 demo/src/test/java/NotificationsTest.java create mode 100755 demo/src/test/java/PopupTest.java mode change 100644 => 100755 demo/src/test/java/binding/BindingManagerTests.java create mode 100755 demo/src/test/java/collections/TransformableListTest.java mode change 100644 => 100755 demo/src/test/java/combobox/ComboBoxTest.java mode change 100644 => 100755 demo/src/test/java/properties/SynchronizedBooleanTests.java mode change 100644 => 100755 demo/src/test/java/properties/SynchronizedDoubleTests.java mode change 100644 => 100755 demo/src/test/java/properties/SynchronizedFloatTests.java mode change 100644 => 100755 demo/src/test/java/properties/SynchronizedIntegerTests.java mode change 100644 => 100755 demo/src/test/java/properties/SynchronizedLongTests.java mode change 100644 => 100755 demo/src/test/java/properties/SynchronizedObjectTests.java mode change 100644 => 100755 demo/src/test/java/properties/SynchronizedStringTests.java mode change 100644 => 100755 demo/src/test/java/selection/SingleSelectionModelTests.java mode change 100644 => 100755 demo/src/test/java/treeview/NumberUtilsTests.java mode change 100644 => 100755 demo/src/test/java/treeview/TreeViewTests.java mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.jar mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.properties mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat mode change 100644 => 100755 materialfx/build.gradle mode change 100644 => 100755 materialfx/gradle.properties mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/MFXResourcesLoader.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/AnimationsData.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/BiPredicateBean.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/CustomBounds.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXLoaderBean.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXSnapshotWrapper.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/NumberRange.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/PopupPositionBean.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/PositionBean.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/TransitionPositionBean.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/NumberRangeProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/base/ResettableProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/base/SynchronizedProperty.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiConsumerProperty.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiFunctionProperty.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiPredicateProperty.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/ConsumerProperty.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/FunctionProperty.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/PredicateProperty.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/SupplierProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableBooleanProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableDoubleProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableFloatProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableIntegerProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableLongProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableObjectProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableStringProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedBooleanProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedDoubleProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedFloatProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedIntegerProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedLongProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedObjectProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedStringProperty.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BidirectionalBindingHelper.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BindingHelper.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BindingManager.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BooleanListBinding.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/collections/ChangeHelper.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/collections/CircularQueue.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/collections/GenericAddRemoveChange.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/collections/ObservableStack.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableList.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableListWrapper.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXButton.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckListView.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckTreeItem.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckTreeView.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckbox.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCircleToggleNode.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXContextMenu.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXContextMenuItem.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXDatePicker.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXDialog.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXExceptionDialog.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterComboBox.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterPane.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXHLoader.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXIconWrapper.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXListView.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotification.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotificationCenter.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPasswordField.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPopup.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressBar.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressSpinner.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRadioButton.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRectangleToggleNode.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXScrollPane.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSimpleNotification.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSlider.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStageDialog.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepper.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepperToggle.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableRow.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableSortModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableView.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTextField.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXToggleButton.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTooltip.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTreeItem.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTreeView.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXVLoader.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/controls/SimpleMFXNotificationPane.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXDialog.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXListView.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXNotificationPane.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXToggleNode.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXTreeCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXTreeItem.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/IListView.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckListCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckTreeCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXDateCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXListCell.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXNotificationCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXSimpleTreeCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumn.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableRowCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/base/AbstractMFXListCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyComboBox.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListCell.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListView.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableRow.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableView.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ConsumerTransition.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/DepthLevel.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/Interpolators.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/MFXDepthManager.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/MFXScrimEffect.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/MFXCircleRippleGenerator.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleClipType.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleGenerator.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RipplePosition.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/AbstractMFXRippleGenerator.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRipple.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRippleGenerator.java rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/ButtonType.java (93%) mode change 100644 => 100755 create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/enums/ChainMode.java rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/DialogType.java (94%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/LoaderCacheLevel.java (97%) mode change 100644 => 100755 create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationCounterStyle.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationPos.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationState.java rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/SliderEnums.java (72%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/SortState.java (92%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/StepperToggleState.java (88%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/Styles.java (97%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/enums/TextPosition.java (93%) mode change 100644 => 100755 create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/factories/InsetsFactory.java rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/factories/MFXAnimationFactory.java (99%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/factories/MFXDialogFactory.java (98%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/factories/MFXStageDialogFactory.java (96%) mode change 100644 => 100755 rename materialfx/src/main/java/io/github/palexdev/materialfx/{controls => }/factories/RippleClipTypeFactory.java (98%) mode change 100644 => 100755 create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/BooleanFilter.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/DoubleFilter.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/EnumFilter.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/filter/EvaluationMode.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/FloatFilter.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/filter/IFilterable.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/IntegerFilter.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/LongFilter.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXEvaluationBox.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXFilterDialog.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/StringFilter.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/NumberFilter.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/font/FontHandler.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/font/FontResources.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/font/MFXFontIcon.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationCenterSystem.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationSystem.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationPos.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationsManager.java delete mode 100644 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/PositionManager.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/AbstractMFXNotificationSystem.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotification.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotificationSystem.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboBoxSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionManager.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionManager.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/TableSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeCheckModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractMultipleSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractSingleSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/IMultipleSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ISingleSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITableSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITreeCheckModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITreeSelectionModel.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXButtonSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckTreeItemSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckboxSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCircleToggleNodeSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXContextMenuItemSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDateCellSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDatePickerContent.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterComboBoxSkin.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterPaneSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXLabelSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXListViewSkin.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXNotificationCenterSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXPasswordFieldSkin.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXPopupSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressBarSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressSpinnerSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRadioButtonSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRectangleToggleNodeSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXScrollPaneSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXSliderSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperToggleSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableColumnSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableRowCellSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTextFieldSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXToggleButtonSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTreeItemSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyComboBoxSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyListViewSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyTableViewSkin.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/AnimationUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/BindingUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/ColorUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/DialogUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/DragResizer.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/EnumStringConverter.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExceptionUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExecutionUtils.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/FXCollectors.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/LabelUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/ListChangeProcessor.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/LoaderUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/NodeUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/NumberUtils.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/PredicateUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/RandomInstance.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/ScrollUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/StringUtils.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/ToggleButtonsUtil.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/TreeItemIterator.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/TreeItemStream.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/FunctionalStringConverter.java create mode 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/ReusableScheduledExecutor.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/TriConsumer.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXDialogValidator.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXPriorityValidator.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/AbstractMFXValidator.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/IMFXValidator.java mode change 100644 => 100755 materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/Validated.java mode change 100644 => 100755 materialfx/src/main/java/module-info.java mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/Fonts.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXButton.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckBox.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckListCell.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckListView.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckTreeCell.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCircleToggleNode.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXColors.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle1.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle2.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle3.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXContextMenu.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXContextMenuItem.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDatePicker.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDatePickerContent.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDialog.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXEvaluationBox.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterComboBox.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterDialog.css create mode 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterPane.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle1.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle2.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle3.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXListCell.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXListView.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXNotification.css create mode 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXNotificationCenter.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXPasswordField.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXProgressBar.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXProgressSpinner.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXRadioButton.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXRectangleToggleNode.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXScrollPane.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXSlider.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXStepper.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXStepperToggle.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableColumn.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableRow.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableRowCell.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableView.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTextField.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXToggleButton.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeCell.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeItem.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeView.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXComboBox.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXLegacyListCell.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXLegacyListView.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXTableRow.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXTableView.css mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Bold.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Light.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Medium.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Regular.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-SemiBold.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-VariableFont_wght.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/MFXResources.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-Bold.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-BoldItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-ExtraBold.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-Italic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-Light.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-LightItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-Regular.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-SemiBold.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/OpenSans/OpenSans-SemiBoldItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-Black.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-BlackItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-Bold.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-BoldItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-Italic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-Light.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-LightItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-Medium.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-MediumItalic.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-Regular.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-Thin.ttf mode change 100644 => 100755 materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Roboto/Roboto-ThinItalic.ttf mode change 100644 => 100755 settings.gradle diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..f6b1c4ce --- /dev/null +++ b/.gitattributes @@ -0,0 +1,34 @@ +# Java sources +*.java text diff=java +*.kt text diff=java +*.groovy text diff=java +*.scala text diff=java +*.gradle text diff=java +*.gradle.kts text diff=java + +# These files are text and should be normalized (Convert crlf => lf) +*.css text diff=css +*.scss text diff=css +*.sass text +*.df text +*.htm text diff=html +*.html text diff=html +*.js text +*.jsp text +*.jspf text +*.jspx text +*.properties text +*.tld text +*.tag text +*.tagx text +*.xml text + +# These files are binary and should be left untouched +# (binary is a macro for -text -diff) +*.class binary +*.dll binary +*.ear binary +*.jar binary +*.so binary +*.war binary +*.jks binary \ No newline at end of file diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/.run/MaterialFX [build].run.xml b/.run/MaterialFX [build].run.xml old mode 100644 new mode 100755 diff --git a/.run/MaterialFX [clean].run.xml b/.run/MaterialFX [clean].run.xml old mode 100644 new mode 100755 diff --git a/.run/MaterialFX [jlinkZip].run.xml b/.run/MaterialFX [jlinkZip].run.xml old mode 100644 new mode 100755 diff --git a/.run/MaterialFX [materialfx_uploadArchives].run.xml b/.run/MaterialFX [materialfx_uploadArchives].run.xml old mode 100644 new mode 100755 diff --git a/.run/MaterialFX [run].run.xml b/.run/MaterialFX [run].run.xml old mode 100644 new mode 100755 diff --git a/.run/MaterialFX [testrun].run.xml b/.run/MaterialFX [testrun].run.xml old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/ROADMAP.md b/ROADMAP.md old mode 100644 new mode 100755 diff --git a/build.gradle b/build.gradle old mode 100644 new mode 100755 diff --git a/demo/build.gradle b/demo/build.gradle old mode 100644 new mode 100755 index 922bcd73..12c9521d --- a/demo/build.gradle +++ b/demo/build.gradle @@ -24,7 +24,7 @@ dependencies { implementation 'org.kordamp.ikonli:ikonli-core:12.2.0' implementation 'org.kordamp.ikonli:ikonli-javafx:12.2.0' implementation 'org.kordamp.ikonli:ikonli-fontawesome5-pack:12.2.0' - implementation 'io.github.palexdev:virtualizedfx:11.1.3' + implementation 'io.github.palexdev:virtualizedfx:11.2.1' implementation project(':materialfx') } diff --git a/demo/libs/scenicview.jar b/demo/libs/scenicview.jar old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/Demo.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/Demo.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/MFXDemoResourcesLoader.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/MFXDemoResourcesLoader.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/TestDemo.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/TestDemo.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ComboBoxesDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ComboBoxesDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DatePickersDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DatePickersDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DialogsController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DialogsController.java old mode 100644 new mode 100755 index 5537917f..85dc9a9c --- a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DialogsController.java +++ b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/DialogsController.java @@ -19,17 +19,13 @@ package io.github.palexdev.materialfx.demo.controllers; import io.github.palexdev.materialfx.controls.MFXButton; -import io.github.palexdev.materialfx.controls.MFXNotification; import io.github.palexdev.materialfx.controls.MFXStageDialog; -import io.github.palexdev.materialfx.controls.SimpleMFXNotificationPane; import io.github.palexdev.materialfx.controls.base.AbstractMFXDialog; -import io.github.palexdev.materialfx.controls.enums.ButtonType; -import io.github.palexdev.materialfx.controls.enums.DialogType; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; -import io.github.palexdev.materialfx.controls.factories.MFXDialogFactory; import io.github.palexdev.materialfx.effects.DepthLevel; -import io.github.palexdev.materialfx.notifications.NotificationPos; -import io.github.palexdev.materialfx.notifications.NotificationsManager; +import io.github.palexdev.materialfx.enums.ButtonType; +import io.github.palexdev.materialfx.enums.DialogType; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXDialogFactory; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.Initializable; @@ -37,9 +33,7 @@ import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; -import javafx.scene.layout.Region; import javafx.stage.Modality; -import javafx.util.Duration; import java.net.URL; import java.util.ResourceBundle; @@ -270,9 +264,10 @@ public class DialogsController implements Initializable { action3.setDepthLevel(DepthLevel.LEVEL1); close.setDepthLevel(DepthLevel.LEVEL1); - action1.setOnAction(event -> NotificationsManager.send(NotificationPos.BOTTOM_RIGHT, createNotification("Action 1 Performed"))); + // TODO remake +/* action1.setOnAction(event -> NotificationsManager.send(NotificationPos.BOTTOM_RIGHT, createNotification("Action 1 Performed"))); action2.setOnAction(event -> NotificationsManager.send(NotificationPos.BOTTOM_RIGHT, createNotification("Action 2 Performed"))); - action3.setOnAction(event -> NotificationsManager.send(NotificationPos.BOTTOM_RIGHT, createNotification("Action 3 Performed"))); + action3.setOnAction(event -> NotificationsManager.send(NotificationPos.BOTTOM_RIGHT, createNotification("Action 3 Performed")));*/ dialog.addCloseButton(close); HBox box = new HBox(20, action1, action2, action3, close); @@ -280,15 +275,4 @@ public class DialogsController implements Initializable { box.setPadding(new Insets(20, 5, 20, 5)); return box; } - - private MFXNotification createNotification(String text) { - Region notificationPane = new SimpleMFXNotificationPane( - "Dialogs Actions Test", - "", - text - ); - MFXNotification notification = new MFXNotification(notificationPane, true, true); - notification.setHideAfterDuration(Duration.seconds(3)); - return notification; - } } diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/FontResourcesDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/FontResourcesDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/InfoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/InfoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/LabelsDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/LabelsDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ListViewsDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ListViewsDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/NotificationsController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/NotificationsController.java old mode 100644 new mode 100755 index bacca117..3c87258b --- a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/NotificationsController.java +++ b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/NotificationsController.java @@ -18,19 +18,8 @@ package io.github.palexdev.materialfx.demo.controllers; -import io.github.palexdev.materialfx.controls.MFXDialog; -import io.github.palexdev.materialfx.controls.MFXNotification; -import io.github.palexdev.materialfx.controls.SimpleMFXNotificationPane; -import io.github.palexdev.materialfx.controls.base.AbstractMFXDialog; -import io.github.palexdev.materialfx.controls.enums.DialogType; -import io.github.palexdev.materialfx.controls.factories.MFXDialogFactory; -import io.github.palexdev.materialfx.notifications.NotificationPos; -import io.github.palexdev.materialfx.notifications.NotificationsManager; +import io.github.palexdev.materialfx.enums.NotificationPos; import javafx.fxml.FXML; -import javafx.scene.layout.Region; -import javafx.scene.paint.Color; -import javafx.util.Duration; -import org.kordamp.ikonli.javafx.FontIcon; import java.util.Random; @@ -83,27 +72,10 @@ public class NotificationsController { } private void showNotification(NotificationPos pos) { - MFXNotification notification = buildNotification(); - NotificationsManager.send(pos, notification); + // TODO remake } - private MFXNotification buildNotification() { - Region template = getRandomTemplate(); - MFXNotification notification = new MFXNotification(template, true, true); - notification.setHideAfterDuration(Duration.seconds(3)); - - if (template instanceof SimpleMFXNotificationPane) { - SimpleMFXNotificationPane pane = (SimpleMFXNotificationPane) template; - pane.setCloseHandler(closeEvent -> notification.hideNotification()); - } else { - MFXDialog dialog = (MFXDialog) template; - dialog.setCloseHandler(closeEvent -> notification.hideNotification()); - } - - return notification; - } - - private Region getRandomTemplate() { +/* private Region getRandomTemplate() { final int rand = random.nextInt(4); switch (rand) { @@ -144,5 +116,5 @@ public class NotificationsController { default: return null; } - } + }*/ } diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressBarsDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressBarsDemoController.java old mode 100644 new mode 100755 index faa89b6b..e762d712 --- a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressBarsDemoController.java +++ b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressBarsDemoController.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.demo.controllers; import io.github.palexdev.materialfx.beans.NumberRange; import io.github.palexdev.materialfx.controls.MFXProgressBar; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.utils.AnimationUtils; import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; import javafx.animation.Animation; diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressSpinnersDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ProgressSpinnersDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ScrollPaneDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/ScrollPaneDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/SlidersDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/SlidersDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/StepperDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/StepperDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TableViewsDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TableViewsDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TextFieldsDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TextFieldsDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TogglesController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TogglesController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TreeviewsDemoController.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/controllers/TreeviewsDemoController.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/model/FilterablePerson.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/model/FilterablePerson.java old mode 100644 new mode 100755 index c598f4eb..324251f2 --- a/demo/src/main/java/io/github/palexdev/materialfx/demo/model/FilterablePerson.java +++ b/demo/src/main/java/io/github/palexdev/materialfx/demo/model/FilterablePerson.java @@ -18,13 +18,13 @@ package io.github.palexdev.materialfx.demo.model; -import io.github.palexdev.materialfx.filter.IFilterable; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -public class FilterablePerson implements IFilterable { +// TODO remove? +public class FilterablePerson { private final StringProperty firstName = new SimpleStringProperty(); private final StringProperty lastName = new SimpleStringProperty(); private final StringProperty address = new SimpleStringProperty(); @@ -85,11 +85,6 @@ public class FilterablePerson implements IFilterable { this.age.set(age); } - @Override - public String toFilterString() { - return getFirstName() + getLastName() + getAddress() + getAge(); - } - @Override public String toString() { return getFirstName() + " " + getLastName(); diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/model/Machine.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/model/Machine.java old mode 100644 new mode 100755 index 9799f153..30bbfe4a --- a/demo/src/main/java/io/github/palexdev/materialfx/demo/model/Machine.java +++ b/demo/src/main/java/io/github/palexdev/materialfx/demo/model/Machine.java @@ -18,13 +18,14 @@ package io.github.palexdev.materialfx.demo.model; -import io.github.palexdev.materialfx.filter.IFilterable; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -public class Machine implements IFilterable { + +// TODO review? +public class Machine { public enum State { ONLINE, OFFLINE @@ -89,9 +90,4 @@ public class Machine implements IFilterable { public void setState(State state) { this.state.set(state); } - - @Override - public String toFilterString() { - return getName() + " " + getIp() + " " + getOwner() + " " + getState().name(); - } } diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/model/Person.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/model/Person.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/io/github/palexdev/materialfx/demo/model/SimplePerson.java b/demo/src/main/java/io/github/palexdev/materialfx/demo/model/SimplePerson.java old mode 100644 new mode 100755 diff --git a/demo/src/main/java/module-info.java b/demo/src/main/java/module-info.java old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/ButtonsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/ButtonsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/CheckBoxesDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/CheckBoxesDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/ComboBoxesDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/ComboBoxesDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/DatePickersDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/DatePickersDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/Demo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/Demo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/DialogsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/DialogsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/FontResourcesDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/FontResourcesDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/InfoDialog.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/InfoDialog.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/LabelsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/LabelsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/ListViewsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/ListViewsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/NotificationsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/NotificationsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/ProgressBarsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/ProgressBarsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/ProgressSpinnersDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/ProgressSpinnersDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/RadioButtonsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/RadioButtonsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/ScrollPanesDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/ScrollPanesDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/SlidersDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/SlidersDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/StepperDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/StepperDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/TableViewsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/TableViewsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/TextFieldsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/TextFieldsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/ToggleButtonsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/ToggleButtonsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/TreeViewsDemo.fxml b/demo/src/main/resources/io/github/palexdev/materialfx/demo/TreeViewsDemo.fxml old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/logo.png b/demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/logo.png old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/welcome1.wav b/demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/welcome1.wav old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/welcome2.wav b/demo/src/main/resources/io/github/palexdev/materialfx/demo/assets/welcome2.wav old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ButtonsDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ButtonsDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/CheckBoxesDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/CheckBoxesDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ComboBoxesDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ComboBoxesDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/Common.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/Common.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/CustomDatePicker.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/CustomDatePicker.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/DatePickersDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/DatePickersDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/Demo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/Demo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/InfoDialog.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/InfoDialog.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ListViewsDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ListViewsDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/MFXColors.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/MFXColors.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ProgressBarDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ProgressBarDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ProgressSpinnersDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ProgressSpinnersDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/RadioButtonsDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/RadioButtonsDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ScrollPanesDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ScrollPanesDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/SlidersDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/SlidersDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/StepperDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/StepperDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/TestDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/TestDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/TextFieldsDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/TextFieldsDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ToggleButtonsDemo.css b/demo/src/main/resources/io/github/palexdev/materialfx/demo/css/ToggleButtonsDemo.css old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Bold.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Bold.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Light.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Light.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Medium.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Medium.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Regular.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-Regular.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-SemiBold.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-SemiBold.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-VariableFont_wght.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Comfortaa/Comfortaa-VariableFont_wght.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Bold.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Bold.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-BoldItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-BoldItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-ExtraBold.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-ExtraBold.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Italic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Italic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Light.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Light.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-LightItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-LightItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Regular.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-Regular.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-SemiBold.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-SemiBold.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-SemiBoldItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/OpenSans/OpenSans-SemiBoldItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Black.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Black.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-BlackItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-BlackItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Bold.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Bold.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-BoldItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-BoldItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Italic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Italic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Light.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Light.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-LightItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-LightItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Medium.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Medium.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-MediumItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-MediumItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Regular.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Regular.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Thin.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-Thin.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-ThinItalic.ttf b/demo/src/main/resources/io/github/palexdev/materialfx/demo/fonts/Roboto/Roboto-ThinItalic.ttf old mode 100644 new mode 100755 diff --git a/demo/src/main/resources/logo.ico b/demo/src/main/resources/logo.ico old mode 100644 new mode 100755 diff --git a/demo/src/test/java/Launcher.java b/demo/src/test/java/Launcher.java old mode 100644 new mode 100755 index 8c9ed24a..b38a9f21 --- a/demo/src/test/java/Launcher.java +++ b/demo/src/test/java/Launcher.java @@ -1,9 +1,8 @@ -import combobox.ComboBoxTest; import javafx.application.Application; public class Launcher { public static void main(String[] args) { - Application.launch(ComboBoxTest.class, args); + Application.launch(NotificationsTest.class, args); } } diff --git a/demo/src/test/java/NotificationsTest.java b/demo/src/test/java/NotificationsTest.java new file mode 100755 index 00000000..e3b34c1d --- /dev/null +++ b/demo/src/test/java/NotificationsTest.java @@ -0,0 +1,84 @@ +import io.github.palexdev.materialfx.controls.MFXLabel; +import io.github.palexdev.materialfx.controls.MFXNotificationCenter; +import io.github.palexdev.materialfx.enums.NotificationPos; +import io.github.palexdev.materialfx.font.MFXFontIcon; +import io.github.palexdev.materialfx.notifications.MFXNotificationCenterSystem; +import io.github.palexdev.materialfx.notifications.MFXNotificationSystem; +import io.github.palexdev.materialfx.controls.MFXSimpleNotification; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.utils.ColorUtils; +import io.github.palexdev.materialfx.utils.RandomInstance; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import javafx.stage.Stage; +import org.scenicview.ScenicView; + +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; + +public class NotificationsTest extends Application { + + @Override + public void start(Stage primaryStage) throws Exception { + StackPane stackPane = new StackPane(); + + MFXNotificationCenter notificationCenter = new MFXNotificationCenter(); + IntStream.range(0, 100).forEach(i -> notificationCenter.getNotifications().add(createDummyNotification())); + stackPane.getChildren().add(notificationCenter); + + MFXNotificationCenterSystem.instance() + .initOwner(primaryStage) + .setOpenOnNew(false) + .setCloseAutomatically(true) + .setPosition(NotificationPos.TOP_RIGHT); + MFXNotificationSystem.instance() + .initOwner(primaryStage) + .setPosition(NotificationPos.TOP_RIGHT); + stackPane.addEventFilter(KeyEvent.KEY_PRESSED, event -> { + switch (event.getCode()) { + case A -> MFXNotificationCenterSystem.instance().publish(createDummyNotification()); + case C -> notificationCenter.stopNotificationsUpdater(); + case S -> notificationCenter.startNotificationsUpdater(60, TimeUnit.SECONDS); + case T -> MFXNotificationSystem.instance().publish(createDummyNotification()); + case P -> MFXNotificationCenterSystem.instance().delaySetPosition(NotificationPos.TOP_LEFT); + } + }); + + Scene scene = new Scene(stackPane, 800, 600); + primaryStage.setScene(scene); + primaryStage.show(); + + ScenicView.show(scene); + } + + private INotification createDummyNotification() { + MFXLabel label = new MFXLabel("Random Label n." + RandomInstance.random.nextInt()); + label.setLeadingIcon(MFXFontIcon.getRandomIcon(32, ColorUtils.getRandomColor())); + label.setAlignment(Pos.CENTER_LEFT); + label.setLineColor(Color.TRANSPARENT); + label.setUnfocusedLineColor(Color.TRANSPARENT); + label.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(label, Priority.ALWAYS); + + MFXLabel time = new MFXLabel(); + time.setAlignment(Pos.CENTER_RIGHT); + time.setLineColor(Color.TRANSPARENT); + time.setUnfocusedLineColor(Color.TRANSPARENT); + + HBox box = new HBox(label, time); + box.setMinSize(450, 100); + box.setStyle("-fx-background-color: white"); + box.setAlignment(Pos.CENTER_LEFT); + MFXSimpleNotification notification = new MFXSimpleNotification(box); + notification.setOnUpdateElapsed((longElapsed, stringElapsed) -> Platform.runLater(() -> time.setText(stringElapsed))); + time.setText(notification.getTimeToStringConverter().apply(notification.getElapsedTime())); + return notification; + } +} diff --git a/demo/src/test/java/PopupTest.java b/demo/src/test/java/PopupTest.java new file mode 100755 index 00000000..acb59511 --- /dev/null +++ b/demo/src/test/java/PopupTest.java @@ -0,0 +1,73 @@ +import io.github.palexdev.materialfx.controls.MFXButton; +import io.github.palexdev.materialfx.controls.MFXLabel; +import io.github.palexdev.materialfx.controls.MFXPopup; +import io.github.palexdev.materialfx.enums.ButtonType; +import io.github.palexdev.materialfx.effects.DepthLevel; +import io.github.palexdev.materialfx.font.MFXFontIcon; +import io.github.palexdev.materialfx.controls.MFXSimpleNotification; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.utils.ColorUtils; +import io.github.palexdev.materialfx.utils.RandomInstance; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.geometry.HPos; +import javafx.geometry.Pos; +import javafx.geometry.VPos; +import javafx.scene.Scene; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.StackPane; +import javafx.scene.paint.Color; +import javafx.stage.Stage; + +public class PopupTest extends Application { + + @Override + public void start(Stage primaryStage) throws Exception { + StackPane stackPane = new StackPane(); + + MFXButton button = new MFXButton("SHOW"); + button.setPrefSize(180, 36); + button.setButtonType(ButtonType.RAISED); + button.setDepthLevel(DepthLevel.LEVEL1); + + button.setOnAction(event -> { + Region content = createDummyNotification().getContent(); + MFXPopup popup = new MFXPopup(content); + popup.show(button, HPos.LEFT, VPos.BOTTOM, -0, -0); + }); + + stackPane.getChildren().add(button); + Scene scene = new Scene(stackPane, 800, 800); + primaryStage.setScene(scene); + primaryStage.show(); + } + + private INotification createDummyNotification() { + MFXLabel label = new MFXLabel("Random Label n." + RandomInstance.random.nextInt()); + label.setLeadingIcon(MFXFontIcon.getRandomIcon(32, ColorUtils.getRandomColor())); + label.setAlignment(Pos.CENTER_LEFT); + label.setLineColor(Color.TRANSPARENT); + label.setUnfocusedLineColor(Color.TRANSPARENT); + label.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(label, Priority.ALWAYS); + + MFXLabel time = new MFXLabel(); + time.setAlignment(Pos.CENTER_RIGHT); + time.setLineColor(Color.TRANSPARENT); + time.setUnfocusedLineColor(Color.TRANSPARENT); + + HBox box = new HBox(label, time); + box.setMinSize(450, 100); + box.setStyle("-fx-background-color: white"); + box.setAlignment(Pos.CENTER_LEFT); + MFXSimpleNotification notification = new MFXSimpleNotification(box); + notification.setOnUpdateElapsed((longElapsed, stringElapsed) -> Platform.runLater(() -> time.setText(stringElapsed))); + time.setText(notification.getTimeToStringConverter().apply(notification.getElapsedTime())); + box.setStyle("" + + "-fx-background-color: transparent;\n" + + "-fx-border-color: red"); + return notification; + } +} diff --git a/demo/src/test/java/binding/BindingManagerTests.java b/demo/src/test/java/binding/BindingManagerTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/collections/TransformableListTest.java b/demo/src/test/java/collections/TransformableListTest.java new file mode 100755 index 00000000..c758d4bc --- /dev/null +++ b/demo/src/test/java/collections/TransformableListTest.java @@ -0,0 +1,69 @@ +package collections; + +import io.github.palexdev.materialfx.collections.TransformableList; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; +import javafx.collections.transformation.SortedList; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.testfx.framework.junit5.ApplicationExtension; + +import java.util.Comparator; + +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(ApplicationExtension.class) +public class TransformableListTest { + private final ObservableList source = FXCollections.observableArrayList("A", "B", "C", "D", "E"); + + @Test + public void sortTest1() { + TransformableList transformed = new TransformableList<>(source); + transformed.setComparator(Comparator.reverseOrder(), true); + + assertEquals(transformed.get(4), "A"); + assertEquals(transformed.indexOf("E"), 0); + assertEquals(transformed.viewToSource(0), 4); + assertEquals(transformed.sourceToView(0), 4); + } + + @Test + public void sortAndFilterTest1() { + TransformableList transformed = new TransformableList<>(source); + transformed.setComparator(Comparator.reverseOrder(), true); + transformed.setPredicate(s -> s.equals("A") || s.equals("C") || s.equals("E")); + + assertThrows(IndexOutOfBoundsException.class, () -> transformed.get(4)); + assertEquals(transformed.get(1), "C"); + assertEquals(transformed.indexOf("E"), 0); + assertEquals(transformed.viewToSource(1), 2); + assertEquals(transformed.sourceToView(1), -1); + } + + @Test + public void testJavaFX1() { + SortedList sorted = new SortedList<>(source); + sorted.setComparator(Comparator.reverseOrder()); + + assertEquals(sorted.get(4), "A"); + assertEquals(sorted.indexOf("E"), 0); + assertEquals(sorted.getSourceIndex(0), 4); + assertEquals(sorted.getViewIndex(0), 4); + } + + @Test + public void testJavaFX2() { + SortedList sorted = new SortedList<>(source); + sorted.setComparator(Comparator.reverseOrder()); + + FilteredList filtered = new FilteredList<>(sorted); + filtered.setPredicate(s -> s.equals("A") || s.equals("C") || s.equals("E")); + + assertThrows(IndexOutOfBoundsException.class, () -> filtered.get(4)); + assertEquals(filtered.get(1), "C"); + assertEquals(filtered.indexOf("E"), 0); + assertEquals(filtered.getSourceIndex(1), 2); + assertTrue(filtered.getViewIndex(1) < 0); + } +} diff --git a/demo/src/test/java/combobox/ComboBoxTest.java b/demo/src/test/java/combobox/ComboBoxTest.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/properties/SynchronizedBooleanTests.java b/demo/src/test/java/properties/SynchronizedBooleanTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/properties/SynchronizedDoubleTests.java b/demo/src/test/java/properties/SynchronizedDoubleTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/properties/SynchronizedFloatTests.java b/demo/src/test/java/properties/SynchronizedFloatTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/properties/SynchronizedIntegerTests.java b/demo/src/test/java/properties/SynchronizedIntegerTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/properties/SynchronizedLongTests.java b/demo/src/test/java/properties/SynchronizedLongTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/properties/SynchronizedObjectTests.java b/demo/src/test/java/properties/SynchronizedObjectTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/properties/SynchronizedStringTests.java b/demo/src/test/java/properties/SynchronizedStringTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/selection/SingleSelectionModelTests.java b/demo/src/test/java/selection/SingleSelectionModelTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/treeview/NumberUtilsTests.java b/demo/src/test/java/treeview/NumberUtilsTests.java old mode 100644 new mode 100755 diff --git a/demo/src/test/java/treeview/TreeViewTests.java b/demo/src/test/java/treeview/TreeViewTests.java old mode 100644 new mode 100755 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar old mode 100644 new mode 100755 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties old mode 100644 new mode 100755 diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 diff --git a/materialfx/build.gradle b/materialfx/build.gradle old mode 100644 new mode 100755 index 647d2d88..1886a7d4 --- a/materialfx/build.gradle +++ b/materialfx/build.gradle @@ -23,7 +23,7 @@ dependencies { testImplementation('junit:junit:4.13.2') implementation 'com.vanniktech:gradle-maven-publish-plugin:0.18.0' - implementation 'io.github.palexdev:virtualizedfx:11.1.3' + implementation 'io.github.palexdev:virtualizedfx:11.2.1' } javadoc { @@ -70,7 +70,7 @@ jar { shadowJar { mergeServiceFiles() dependencies { - include(dependency('io.github.palexdev:virtualizedfx:11.1.3')) + include(dependency('io.github.palexdev:virtualizedfx:11.2.1')) } } diff --git a/materialfx/gradle.properties b/materialfx/gradle.properties old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/MFXResourcesLoader.java b/materialfx/src/main/java/io/github/palexdev/materialfx/MFXResourcesLoader.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/AnimationsData.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/AnimationsData.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/BiPredicateBean.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/BiPredicateBean.java new file mode 100755 index 00000000..939dcc04 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/BiPredicateBean.java @@ -0,0 +1,42 @@ +package io.github.palexdev.materialfx.beans; + +import java.util.function.BiPredicate; + +/** + * A simple bean that wraps a {@link BiPredicate} and s String that represents + * the name for the predicate. + * + * @param the type of the first argument to the predicate + * @param the type of the second argument the predicate + */ +public class BiPredicateBean { + //================================================================================ + // Properties + //================================================================================ + private final String name; + private final BiPredicate predicate; + + //================================================================================ + // Constructors + //================================================================================ + public BiPredicateBean(String name, BiPredicate predicate) { + this.name = name; + this.predicate = predicate; + } + + //================================================================================ + // Getters + //================================================================================ + public String name() { + return name; + } + + public BiPredicate predicate() { + return predicate; + } + + @Override + public String toString() { + return name; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/CustomBounds.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/CustomBounds.java new file mode 100755 index 00000000..7388951a --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/CustomBounds.java @@ -0,0 +1,98 @@ +package io.github.palexdev.materialfx.beans; + +import io.github.palexdev.materialfx.notifications.MFXNotificationCenterSystem; +import javafx.geometry.BoundingBox; +import javafx.geometry.Bounds; + +/** + * JavaFX allows you to create custom {@code Bounds} objects, see {@link BoundingBox}, the thing is + * that it automatically computes the max X/Y/Z values. This can be quite unfortunate in some rare + * cases because maybe you need some kind of special bounds, this bean is specifically for those + * cases, it allows creating custom bounds. + *

+ * An example of that is in the {@link MFXNotificationCenterSystem} class, there custom bounds + * are created to take into account the coordinates of the bell icon and the entire width/height of the + * notification center. Like I said tough, cases like that are quite rare. + */ +public class CustomBounds { + //================================================================================ + // Properties + //================================================================================ + private final double minX; + private final double minY; + private final double minZ; + private final double maxX; + private final double maxY; + private final double maxZ; + private final double width; + private final double height; + + //================================================================================ + // Constructors + //================================================================================ + public CustomBounds(double minX, double minY, double maxX, double maxY, double width, double height) { + this(minX, minY, 0, maxX, maxY, 0, width, height); + } + + public CustomBounds(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, double width, double height) { + this.minX = minX; + this.minY = minY; + this.minZ = minZ; + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; + this.width = width; + this.height = height; + } + + //================================================================================ + // Static Methods + //================================================================================ + public static CustomBounds from(Bounds bounds) { + return new CustomBounds( + bounds.getMinX(), + bounds.getMinY(), + bounds.getMinZ(), + bounds.getMaxX(), + bounds.getMaxY(), + bounds.getMaxY(), + bounds.getWidth(), + bounds.getHeight() + ); + } + + //================================================================================ + // Getters/Setters + //================================================================================ + public double getMinX() { + return minX; + } + + public double getMinY() { + return minY; + } + + public double getMinZ() { + return minZ; + } + + public double getMaxX() { + return maxX; + } + + public double getMaxY() { + return maxY; + } + + public double getMaxZ() { + return maxZ; + } + + public double getWidth() { + return width; + } + + public double getHeight() { + return height; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java new file mode 100755 index 00000000..97963d2d --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/FilterBean.java @@ -0,0 +1,104 @@ +package io.github.palexdev.materialfx.beans; + +import io.github.palexdev.materialfx.enums.ChainMode; +import io.github.palexdev.materialfx.filter.base.AbstractFilter; + +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +/** + * A simple bean that has all the necessary information to produce a {@link Predicate} + * for a given T object type. + *

+ * It wraps the following data: + *

- A String which is the query + *

- An object of type {@link AbstractFilter}, which is effectively responsible for producing the {@link Predicate} + *

- A {@link BiPredicateBean}, which is used by {@link AbstractFilter}, see {@link AbstractFilter#predicateFor(String)} or {@link AbstractFilter#predicateFor(String, BiPredicate)} + *

- A {@link ChainMode} enumeration to specify how this filter should be combined with other filters + * + * @param the type of objects to filter + * @param the type of objects on which the {@link BiPredicate} operates + */ +public class FilterBean { + //================================================================================ + // Properties + //================================================================================ + private final String query; + private final AbstractFilter filter; + private final BiPredicateBean predicateBean; + private ChainMode mode; + + //================================================================================ + // Constructors + //================================================================================ + public FilterBean(String query, AbstractFilter filter, BiPredicateBean predicateBean) { + this(query, filter, predicateBean, ChainMode.OR); + } + + public FilterBean(String query, AbstractFilter filter, BiPredicateBean predicateBean, ChainMode mode) { + this.query = query; + this.filter = filter; + this.predicateBean = predicateBean; + this.mode = mode; + } + + //================================================================================ + // Methods + //================================================================================ + + /** + * Calls {@link AbstractFilter#predicateFor(String)} with the query specified by this bean. + */ + public Predicate predicate() { + return filter.predicateFor(query); + } + + /** + * @return the query, see {@link AbstractFilter} documentation for more info about the query + */ + public String getQuery() { + return query; + } + + /** + * @return the {@link AbstractFilter} specified by this bean + */ + public AbstractFilter getFilter() { + return filter; + } + + /** + * Delegate for {@link AbstractFilter#name()}. + */ + public String getFilterName() { + return filter.name(); + } + + /** + * @return the {@link BiPredicateBean} specified by this bean + */ + public BiPredicateBean getPredicateBean() { + return predicateBean; + } + + /** + * Delegate for {@link BiPredicateBean#name()}. + */ + public String getPredicateName() { + return predicateBean.name(); + } + + /** + * @return the {@link ChainMode} enumeration that specifies how this filter should be chained with other filters. + */ + public ChainMode getMode() { + return mode; + } + + /** + * Sets the chain mode to the specified one. + */ + public void setMode(ChainMode mode) { + this.mode = mode; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXLoaderBean.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXLoaderBean.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXSnapshotWrapper.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/MFXSnapshotWrapper.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/NumberRange.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/NumberRange.java old mode 100644 new mode 100755 index aa485e92..606902f0 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/NumberRange.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/NumberRange.java @@ -18,7 +18,8 @@ package io.github.palexdev.materialfx.beans; -import java.util.List; +import java.util.*; +import java.util.stream.IntStream; /** * Simple bean to represent a range of values from min to max. @@ -43,14 +44,38 @@ public class NumberRange { //================================================================================ // Methods //================================================================================ + + /** + * @return the lower bound + */ public T getMin() { return min; } + /** + * @return the upper bound + */ public T getMax() { return max; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + NumberRange that = (NumberRange) o; + return Objects.equals(min, that.min) && Objects.equals(max, that.max); + } + + @Override + public int hashCode() { + return Objects.hash(min, max); + } + + @Override + public String toString() { + return "Min[" + min + "], Max[" + max + "]"; + } //================================================================================ // Static Methods //================================================================================ @@ -124,4 +149,18 @@ public class NumberRange { public static boolean inRangeOf(long val, List> ranges) { return ranges.stream().anyMatch(range -> inRangeOf(val, range)); } + + /** + * Expands a range of integers to a List of integers. + */ + public static List expandRange(NumberRange range) { + return IntStream.rangeClosed(range.getMin(), range.getMax()).collect(ArrayList::new, ArrayList::add, ArrayList::addAll); + } + + /** + * Expands a range of integers to a Set of integers. + */ + public static Set expandRangeToSet(NumberRange range) { + return IntStream.rangeClosed(range.getMin(), range.getMax()).collect(HashSet::new, HashSet::add, HashSet::addAll); + } } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/PopupPositionBean.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/PopupPositionBean.java new file mode 100755 index 00000000..aa8f7e41 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/PopupPositionBean.java @@ -0,0 +1,121 @@ +package io.github.palexdev.materialfx.beans; + +import io.github.palexdev.materialfx.controls.MFXPopup; +import javafx.geometry.Bounds; +import javafx.geometry.HPos; +import javafx.geometry.VPos; +import javafx.scene.Node; + +/** + * A useful bean which gives info about a {@link MFXPopup}'s position and owner. + *

+ * The purpose of this bean is to provide a way to communicate between the popup and its skin. + * The precise location of a popup cannot be computed when the show methods are called because the content + * has not been laid out yet, thus its sizes/bounds are 0. This changes when the skin is created, at that moment + * all info about the content are available so this bean is necessary to properly reposition and animate the popup. + */ +public class PopupPositionBean { + //================================================================================ + // Properties + //================================================================================ + private final Node owner; + private final Bounds ownerBounds; + private final PositionBean positionBean; + private final HPos hPos; + private final VPos vPos; + private final double xOffset; + private final double yOffset; + + //================================================================================ + // Constructors + //================================================================================ + public PopupPositionBean(Node owner, PositionBean positionBean, HPos hPos, VPos vPos, double xOffset, double yOffset) { + this.owner = owner; + this.ownerBounds = owner.getLayoutBounds(); + this.positionBean = positionBean; + this.hPos = hPos; + this.vPos = vPos; + this.xOffset = xOffset; + this.yOffset = yOffset; + } + + /** + * @return the popup's owner + */ + public Node getOwner() { + return owner; + } + + /** + * @return the popup owner's bounds + */ + public Bounds getOwnerBounds() { + return ownerBounds; + } + + /** + * @return the popup owner's width + */ + public double getOwnerWidth() { + return ownerBounds.getWidth(); + } + + /** + * @return the popup owner's height + */ + public double getOwnerHeight() { + return ownerBounds.getHeight(); + } + + /** + * You should NOT rely on these coordinates since as of now + * they do not take into account the translations made by the skin. + * + * @return the initial computed coordinates of the popup + */ + public PositionBean getPositionBean() { + return positionBean; + } + + /** + * Delegate for {@link #getPositionBean()}.getX(). + */ + public double getX() { + return positionBean.getX(); + } + + /** + * Delegate for {@link #getPositionBean()}.getY(). + */ + public double getY() { + return positionBean.getY(); + } + + /** + * @return the specified {@link HPos} + */ + public HPos getHPos() { + return hPos; + } + + /** + * @return the specified {@link VPos} + */ + public VPos getVPos() { + return vPos; + } + + /** + * @return the specified x offset + */ + public double getXOffset() { + return xOffset; + } + + /** + * @return the specified y offset + */ + public double getYOffset() { + return yOffset; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/PositionBean.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/PositionBean.java new file mode 100755 index 00000000..a70f7b23 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/PositionBean.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2021 Parisi Alessandro + * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). + * + * MaterialFX is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MaterialFX is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with MaterialFX. If not, see . + */ + +package io.github.palexdev.materialfx.beans; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + +/** + * Simple bean that keeps track of two coordinates, x and y. + *

+ * Both are JavaFX properties to allow dynamic uses. + */ +public class PositionBean { + //================================================================================ + // Properties + //================================================================================ + private final DoubleProperty x = new SimpleDoubleProperty(0); + private final DoubleProperty y = new SimpleDoubleProperty(0); + + //================================================================================ + // Constructors + //================================================================================ + public PositionBean() { + } + + public PositionBean(double x, double y) { + setX(x); + setY(y); + } + + //================================================================================ + // Static Methods + //================================================================================ + public static PositionBean of(double x, double y) { + return new PositionBean(x, y); + } + + //================================================================================ + // Methods + //================================================================================ + public double getX() { + return x.get(); + } + + /** + * The x coordinate property. + */ + public DoubleProperty xProperty() { + return x; + } + + public void setX(double xPosition) { + this.x.set(xPosition); + } + + public double getY() { + return y.get(); + } + + /** + * The y coordinate property + */ + public DoubleProperty yProperty() { + return y; + } + + public void setY(double yPosition) { + this.y.set(yPosition); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/TransitionPositionBean.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/TransitionPositionBean.java new file mode 100755 index 00000000..07b314e9 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/TransitionPositionBean.java @@ -0,0 +1,85 @@ +package io.github.palexdev.materialfx.beans; + +import javafx.animation.Transition; + +// TODO documentation +/** + * This is an extension of {@link PositionBean} to be used + * with {@link Transition}s that start from a point P(x, y) and + * end at a point P1(endX, endY). + *

+ * A very basic example: + *

+ * Let's say I want to move a point P from (x, y) to the left + * (x1, y) with an animation. The transition would probably look like this: + *

+ * {@code
+ *     double startX = ...;
+ *     double startY = ...;
+ *     double endX = ...;
+ *     double endY = startY; // The y coordinate doesn't change so it is equal to the start one
+ *     TransitionPositionBean position = TransitionPositionBean.of(startX, startY, endX, endY);
+ *     Transition move = new Transition() {
+ *             @Override
+ *             protected void interpolate(double frac) {
+ *                 p.setX(x - position.deltaX() * frac);
+ *             }
+ *      }
+ * }
+ * 
+ */ +public class TransitionPositionBean extends PositionBean { + //================================================================================ + // Properties + //================================================================================ + private final double endX; + private final double endY; + + //================================================================================ + // Constructors + //================================================================================ + public TransitionPositionBean(double x, double y, double endX, double endY) { + super(x, y); + this.endX = endX; + this.endY = endY; + } + + //================================================================================ + // Static Methods + //================================================================================ + public static TransitionPositionBean of(double x, double y, double endX, double endY) { + return new TransitionPositionBean(x, y, endX, endY); + } + + //================================================================================ + // Getters/Setters + //================================================================================ + + /** + * @return the end x coordinate + */ + public double getEndX() { + return endX; + } + + /** + * @return the end y coordinate + */ + public double getEndY() { + return endY; + } + + /** + * @return the difference between the star x and end x coordinates + */ + public double deltaX() { + return getX() - getEndX(); + } + + /** + * @return the difference between the start y and end y coordinates + */ + public double deltaY() { + return getY() - getEndY(); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/NumberRangeProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/NumberRangeProperty.java new file mode 100755 index 00000000..896bd44d --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/NumberRangeProperty.java @@ -0,0 +1,62 @@ +package io.github.palexdev.materialfx.beans.properties; + +import io.github.palexdev.materialfx.beans.NumberRange; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link NumberRange}. + * + * @param the range's number type + */ +public class NumberRangeProperty extends SimpleObjectProperty> { + + + //================================================================================ + // Methods + //================================================================================ + + /** + * Convenience method to get the range's lower bound. + * Null if the range is null. + */ + public T getMin() { + return get() == null ? null : get().getMin(); + } + + /** + * Convenience method to get the range's upper bound. + * Null if the range is null. + */ + public T getMax() { + return get() == null ? null : get().getMin(); + } + + /** + * Convenience method to set a range with both min and max equal. + */ + public void setRange(T value) { + set(NumberRange.of(value)); + } + + /** + * Convenience method to set a range with the given min and max values. + */ + public void setRange(T min, T max) { + set(NumberRange.of(min, max)); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + /** + * Overridden to check equality between ranges and return in case ranges are the same. + */ + @Override + public void set(NumberRange newValue) { + NumberRange oldValue = get(); + if (newValue.equals(oldValue)) return; + super.set(newValue); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/base/ResettableProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/base/ResettableProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/base/SynchronizedProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/base/SynchronizedProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiConsumerProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiConsumerProperty.java new file mode 100755 index 00000000..15f24ebe --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiConsumerProperty.java @@ -0,0 +1,14 @@ +package io.github.palexdev.materialfx.beans.properties.functional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.function.BiConsumer; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link BiConsumer}. + * + * @param the consumer's first argument + * @param the consumer's second argument + */ +public class BiConsumerProperty extends SimpleObjectProperty> {} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiFunctionProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiFunctionProperty.java new file mode 100755 index 00000000..4f6d2c49 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiFunctionProperty.java @@ -0,0 +1,15 @@ +package io.github.palexdev.materialfx.beans.properties.functional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.function.BiFunction; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link BiFunction}. + * + * @param the function's first argument + * @param the function's second argument + * @param the function's return type + */ +public class BiFunctionProperty extends SimpleObjectProperty> {} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiPredicateProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiPredicateProperty.java new file mode 100755 index 00000000..2f06708e --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/BiPredicateProperty.java @@ -0,0 +1,14 @@ +package io.github.palexdev.materialfx.beans.properties.functional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.function.BiPredicate; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link BiPredicate}. + * + * @param the predicate's first argument + * @param the predicate's second argument + */ +public class BiPredicateProperty extends SimpleObjectProperty> {} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/ConsumerProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/ConsumerProperty.java new file mode 100755 index 00000000..60c7d646 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/ConsumerProperty.java @@ -0,0 +1,13 @@ +package io.github.palexdev.materialfx.beans.properties.functional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.function.Consumer; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link Consumer}. + * + * @param the consumer's input type + */ +public class ConsumerProperty extends SimpleObjectProperty> {} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/FunctionProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/FunctionProperty.java new file mode 100755 index 00000000..faa004ab --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/FunctionProperty.java @@ -0,0 +1,14 @@ +package io.github.palexdev.materialfx.beans.properties.functional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.function.Function; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link Function}. + * + * @param the function's input type + * @param the function's return type + */ +public class FunctionProperty extends SimpleObjectProperty> {} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/PredicateProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/PredicateProperty.java new file mode 100755 index 00000000..5da3f9c1 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/PredicateProperty.java @@ -0,0 +1,13 @@ +package io.github.palexdev.materialfx.beans.properties.functional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.function.Predicate; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link Predicate}. + * + * @param the predicate's input type + */ +public class PredicateProperty extends SimpleObjectProperty> {} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/SupplierProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/SupplierProperty.java new file mode 100755 index 00000000..86c51509 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/functional/SupplierProperty.java @@ -0,0 +1,13 @@ +package io.github.palexdev.materialfx.beans.properties.functional; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.util.function.Supplier; + +/** + * Simply an {@link ObjectProperty} that wraps a {@link Supplier}. + * + * @param the supplier's return type + */ +public class SupplierProperty extends SimpleObjectProperty> {} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableBooleanProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableBooleanProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableDoubleProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableDoubleProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableFloatProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableFloatProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableIntegerProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableIntegerProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableLongProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableLongProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableObjectProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableObjectProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableStringProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/resettable/ResettableStringProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedBooleanProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedBooleanProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedDoubleProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedDoubleProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedFloatProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedFloatProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedIntegerProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedIntegerProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedLongProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedLongProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedObjectProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedObjectProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedStringProperty.java b/materialfx/src/main/java/io/github/palexdev/materialfx/beans/properties/synced/SynchronizedStringProperty.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BidirectionalBindingHelper.java b/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BidirectionalBindingHelper.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BindingHelper.java b/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BindingHelper.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BindingManager.java b/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BindingManager.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BooleanListBinding.java b/materialfx/src/main/java/io/github/palexdev/materialfx/bindings/BooleanListBinding.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/collections/ChangeHelper.java b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/ChangeHelper.java new file mode 100755 index 00000000..8779e8df --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/ChangeHelper.java @@ -0,0 +1,35 @@ +package io.github.palexdev.materialfx.collections; + +import java.util.Arrays; +import java.util.List; + +class ChangeHelper { + ChangeHelper() {} + + public static String addRemoveChangeToString(int from, int to, List list, List removed) { + StringBuilder sb = new StringBuilder(); + if (removed.isEmpty()) { + sb.append(list.subList(from, to)); + sb.append(" added at ").append(from); + } else { + sb.append(removed); + if (from == to) { + sb.append(" removed at ").append(from); + } else { + sb.append(" replaced by "); + sb.append(list.subList(from, to)); + sb.append(" at ").append(from); + } + } + + return sb.toString(); + } + + public static String permChangeToString(int[] permutation) { + return "permutated by " + Arrays.toString(permutation); + } + + public static String updateChangeToString(int from, int to) { + return "updated at range [" + from + ", " + to + ")"; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/collections/CircularQueue.java b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/CircularQueue.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/collections/GenericAddRemoveChange.java b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/GenericAddRemoveChange.java new file mode 100755 index 00000000..adb5dbcc --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/GenericAddRemoveChange.java @@ -0,0 +1,156 @@ +package io.github.palexdev.materialfx.collections; + +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; + +import java.util.Collections; +import java.util.List; + +abstract class NonIterableChange extends ListChangeListener.Change { + private final int from; + private final int to; + private boolean invalid = true; + private static final int[] EMPTY_PERM = new int[0]; + + protected NonIterableChange(int from, int to, ObservableList list) { + super(list); + this.from = from; + this.to = to; + } + + public int getFrom() { + checkState(); + return from; + } + + public int getTo() { + checkState(); + return to; + } + + protected int[] getPermutation() { + checkState(); + return EMPTY_PERM; + } + + public boolean next() { + if (invalid) { + invalid = false; + return true; + } else { + return false; + } + } + + public void reset() { + invalid = true; + } + + public void checkState() { + if (invalid) { + throw new IllegalStateException("Invalid Change state: next() must be called before inspecting the Change."); + } + } + + public String toString() { + boolean oldInvalid = invalid; + invalid = false; + String ret; + if (wasPermutated()) { + ret = ChangeHelper.permChangeToString(getPermutation()); + } else if (wasUpdated()) { + ret = ChangeHelper.updateChangeToString(from, to); + } else { + ret = ChangeHelper.addRemoveChangeToString(from, to, getList(), getRemoved()); + } + + invalid = oldInvalid; + return "{ " + ret + " }"; + } + + public static class SimpleUpdateChange extends NonIterableChange { + public SimpleUpdateChange(int position, ObservableList list) { + this(position, position + 1, list); + } + + public SimpleUpdateChange(int from, int to, ObservableList list) { + super(from, to, list); + } + + public List getRemoved() { + return Collections.emptyList(); + } + + public boolean wasUpdated() { + return true; + } + } + + public static class SimplePermutationChange extends NonIterableChange { + private final int[] permutation; + + public SimplePermutationChange(int from, int to, int[] permutation, ObservableList list) { + super(from, to, list); + this.permutation = permutation; + } + + public List getRemoved() { + checkState(); + return Collections.emptyList(); + } + + protected int[] getPermutation() { + checkState(); + return permutation; + } + } + + public static class SimpleAddChange extends NonIterableChange { + public SimpleAddChange(int from, int to, ObservableList list) { + super(from, to, list); + } + + public boolean wasRemoved() { + checkState(); + return false; + } + + public List getRemoved() { + checkState(); + return Collections.emptyList(); + } + } + + public static class SimpleRemovedChange extends NonIterableChange { + private final List removed; + + public SimpleRemovedChange(int from, int to, E removed, ObservableList list) { + super(from, to, list); + this.removed = Collections.singletonList(removed); + } + + public boolean wasRemoved() { + checkState(); + return true; + } + + public List getRemoved() { + checkState(); + return removed; + } + } + + public static class GenericAddRemoveChange extends NonIterableChange { + private final List removed; + + public GenericAddRemoveChange(int from, int to, List removed, ObservableList list) { + super(from, to, list); + this.removed = removed; + } + + public List getRemoved() { + checkState(); + return removed; + } + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/collections/ObservableStack.java b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/ObservableStack.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableList.java b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableList.java new file mode 100755 index 00000000..cfe66fa6 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableList.java @@ -0,0 +1,269 @@ +package io.github.palexdev.materialfx.collections; + +import io.github.palexdev.materialfx.collections.NonIterableChange.GenericAddRemoveChange; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.collections.transformation.FilteredList; +import javafx.collections.transformation.SortedList; +import javafx.collections.transformation.TransformationList; + +import java.util.*; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * A {@code TransformableList} is a particular type of List which wraps another + * List called "source" and allows manipulations such as: filter and sort, retaining + * the original items' index. + *

+ * Extends {@link TransformationList}, it's basically the same thing of a {@link FilteredList} + * and a {@link SortedList} but combined into one. + *

+ * A more detailed (and hopefully more clear) explanation about the "indexes retention mentioned above": + *

+ * Think of this List as a View for the source list. The underlying data provided by the source is + * not guaranteed to be what the user sees but the items' properties are maintained. + * Let's see a brief example: + *

+ * {@code
+ *     // Let's say I have this ObservableList
+ *     ObservableList source = FXCollections.observableArrayList("A", "B", "C"):
+ *
+ *     // Now let's say I want to sort this list in reverse order (CBA) and that
+ *     // for some reason I still want A to be the element at index 0, B-1 and C-2
+ *     // This is exactly the purpose of the TransformableList...
+ *     TransformableList transformed = new TransformableList<>(source);
+ *     transformed.setSorter(Comparator.reverseOrder());
+ *
+ *     // Now that the order is (CBA) let's see how the list behaves:
+ *     transformed.get(0); // Returns C
+ *     transformed.indexOf("C"); // Returns 2, the index is retrieved in the source list
+ *     transformed.viewToSource(0); // Returns 2, it maps an index of the transformed list to the index of the source list, at 0 we have C which is at index 2 in the source list
+ *     transformed.sourceToView(0); // Also returns 2, it maps an index of the source list to the index of the transformed list, at 0 we have C which is at index 2 in the transformed list
+ *
+ *     // To better see its behavior try to sort and filter the list at the same time.
+ *     // You'll notice that sometimes sourceToView will return a negative index because the item is not in the transformed list (after a filter operation)
+ * }
+ * 
+ * + * Check {@link #computeIndexes()} documentation to see how indexes are calculated. + *

+ * IMPORTANT: If using a reversed comparator please use {@link #setComparator(Comparator, boolean)} with 'true' as argument, + * as {@link #setComparator(Comparator)} will always assume it is a natural order comparator. This is needed to make {@link #sourceToView(int)} + * properly work as it uses a binary search algorithm to find the right index. + * + * @param the items' type + */ +public class TransformableList extends TransformationList { + //================================================================================ + // Constructors + //================================================================================ + private final List indexes = new ArrayList<>(); + private boolean reversed = false; + + private final ObjectProperty> predicate = new SimpleObjectProperty<>() { + @Override + protected void invalidated() { + update(); + } + }; + + private final ObjectProperty> comparator = new SimpleObjectProperty<>() { + @Override + protected void invalidated() { + update(); + } + }; + + //================================================================================ + // Constructors + //================================================================================ + public TransformableList(ObservableList source) { + this(source, null); + } + + public TransformableList(ObservableList source, Predicate predicate) { + this(source, predicate, null); + } + + public TransformableList(ObservableList source, Predicate predicate, Comparator comparator) { + super(source); + setPredicate(predicate); + setComparator(comparator); + } + + //================================================================================ + // Methods + //================================================================================ + + /** + * Calls {@link #getSourceIndex(int)}, just with a different name to be more clear. + *

+ * Maps an index of the transformed list, to the index of the source list. + */ + public int viewToSource(int index) { + return getSourceIndex(index); + } + + /** + * Calls {@link #getViewIndex(int)}, just with a different name to be more clear. + *

+ * Maps an index of the source list, to the index of the transformed list. + */ + public int sourceToView(int index) { + return getViewIndex(index); + } + + /** + * Responsible for updating the transformed indexes when the + * predicate or the comparator change. + */ + private void update() { + indexes.clear(); + indexes.addAll(computeIndexes()); + if (this.hasListeners()) { + this.fireChange(new GenericAddRemoveChange<>(0, size(), new ArrayList<>(this), this)); + } + } + + /** + * Core method of TransformableLists. This is responsible for computing + * the transformed indexes by creating a {@link SortedMap} and mapping every index from 0 to source size + * to its item. Before mapping, items are filtered with the given predicate, {@link #predicateProperty()}. + * Before returning, the map's entry set is sorted by its values with the given comparator, {@link #comparatorProperty()}. + * Finally, returns the map's key set, this set contains the transformed indexes, filtered and sorted. + */ + private Collection computeIndexes() { + Predicate filter = this.getPredicate(); + Comparator sorter = this.getComparator(); + SortedMap sourceMap; + if (filter != null) { + sourceMap = IntStream.range(0, getSource().size()) + .filter((index) -> filter.test(getSource().get(index))) + .collect(TreeMap::new, (map, index) -> map.put(index, getSource().get(index)), TreeMap::putAll); + } else { + sourceMap = IntStream.range(0, getSource().size()) + .collect(TreeMap::new, (map, index) -> map.put(index, getSource().get(index)), TreeMap::putAll); + } + + return sorter != null ? sourceMap.entrySet().stream() + .sorted((o1, o2) -> sorter.compare(o1.getValue(), o2.getValue())) + .map(Map.Entry::getKey) + .collect(Collectors.toList()) : sourceMap.keySet(); + } + + public Predicate getPredicate() { + return this.predicate.get(); + } + + /** + * Specifies the predicate used to filter the source list. + */ + public ObjectProperty> predicateProperty() { + return this.predicate; + } + + public void setPredicate(Predicate predicate) { + this.predicate.set(predicate); + } + + public Comparator getComparator() { + return this.comparator.get(); + } + + /** + * Specifies the comparator used to sort the source list. + * + * @see #setComparator(Comparator, boolean) + */ + public ObjectProperty> comparatorProperty() { + return this.comparator; + } + + public void setComparator(Comparator comparator) { + this.reversed = false; + this.comparator.set(comparator); + } + + /** + * This method is NECESSARY if using a reversed comparator, + * a special flag is set to true and {@link #sourceToView(int)} behaves accordingly. + */ + public void setComparator(Comparator sorter, boolean reversed) { + this.reversed = reversed; + this.comparator.set(sorter); + } + + /** + * Specifies if a reversed comparator is being used. + */ + public boolean isReversed() { + return reversed; + } + + /** + * Communicates to the transformed list, specifically to {@link #getViewIndex(int)}, + * if the list is sorted in reversed order. + */ + public void setReversed(boolean reversed) { + this.reversed = reversed; + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + /** + * {@inheritDoc} + *

+ * Calls {@link #update()}. + */ + @Override + protected void sourceChanged(ListChangeListener.Change c) { + beginChange(); + update(); + endChange(); + } + + /** + * @return the number of items in the transformable list + */ + @Override + public int size() { + return indexes.size(); + } + + /** + * Retrieves and return the item at the given index in the transformable list. + * This means transformations due to {@link #predicateProperty()} or {@link #comparatorProperty()} + * are taken into account. + */ + @Override + public T get(int index) { + if (index > size()) { + throw new IndexOutOfBoundsException(index); + } else { + return getSource().get(indexes.get(index)); + } + } + + @Override + public int getSourceIndex(int index) { + if (index > size()) { + throw new IndexOutOfBoundsException(index); + } else { + return indexes.get(index); + } + } + + @Override + public int getViewIndex(int index) { + int viewIndex = reversed ? + Collections.binarySearch(indexes, index, Collections.reverseOrder()) : + Collections.binarySearch(indexes, index); + return viewIndex < 0 ? -1 : viewIndex; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableListWrapper.java b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableListWrapper.java new file mode 100755 index 00000000..4ab96b70 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/collections/TransformableListWrapper.java @@ -0,0 +1,168 @@ +package io.github.palexdev.materialfx.collections; + +import javafx.beans.InvalidationListener; +import javafx.beans.property.ObjectProperty; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; + +import java.util.*; +import java.util.function.Predicate; + +@SuppressWarnings({"unchecked", "NullableProblems"}) +public class TransformableListWrapper extends AbstractList implements ObservableList { + private final ObservableList source; + private final TransformableList transformableList; + + public TransformableListWrapper(ObservableList source) { + this.source = source; + this.transformableList = new TransformableList<>(source); + } + + @Override + public void addListener(ListChangeListener listener) { + transformableList.addListener(listener); + } + + @Override + public void removeListener(ListChangeListener listener) { + transformableList.removeListener(listener); + } + + @Override + public boolean add(T t) { + return source.add(t); + } + + @Override + public T set(int index, T element) { + return source.set(index, element); + } + + @Override + public void add(int index, T element) { + source.add(index, element); + } + + @Override + public T remove(int index) { + return source.remove(index); + } + + @Override + public int indexOf(Object o) { + return transformableList.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return transformableList.lastIndexOf(o); + } + + @Override + public void clear() { + source.clear(); + } + + @Override + public boolean addAll(int index, Collection c) { + return source.addAll(index, c); + } + + @Override + public boolean addAll(T... elements) { + return source.addAll(elements); + } + + @Override + public boolean setAll(T... elements) { + return source.setAll(elements); + } + + @Override + public boolean setAll(Collection col) { + return source.setAll(col); + } + + @Override + public boolean removeAll(T... elements) { + return source.removeAll(elements); + } + + @Override + public boolean retainAll(T... elements) { + return source.retainAll(elements); + } + + @Override + public void remove(int from, int to) { + source.remove(from, to); + } + + @Override + public void addListener(InvalidationListener listener) { + transformableList.addListener(listener); + } + + @Override + public void removeListener(InvalidationListener listener) { + transformableList.removeListener(listener); + } + + @Override + public T get(int index) { + return transformableList.get(index); + } + + @Override + public int size() { + return transformableList.size(); + } + + public ObservableList getSource() { + return transformableList.getSource(); + } + + public int viewToSource(int index) { + return transformableList.viewToSource(index); + } + + public int sourceToView(int index) { + return transformableList.sourceToView(index); + } + + public Predicate getPredicate() { + return transformableList.getPredicate(); + } + + public ObjectProperty> predicateProperty() { + return transformableList.predicateProperty(); + } + + public void setPredicate(Predicate predicate) { + transformableList.setPredicate(predicate); + } + + public Comparator getComparator() { + return transformableList.getComparator(); + } + + public ObjectProperty> comparatorProperty() { + return transformableList.comparatorProperty(); + } + + public void setComparator(Comparator comparator) { + transformableList.setComparator(comparator); + } + + public void setComparator(Comparator sorter, boolean reversed) { + transformableList.setComparator(sorter, reversed); + } + + public boolean isReversed() { + return transformableList.isReversed(); + } + + public void setReversed(boolean reversed) { + transformableList.setReversed(reversed); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXButton.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXButton.java old mode 100644 new mode 100755 index 216f9c3d..321496ce --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXButton.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXButton.java @@ -19,10 +19,10 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; -import io.github.palexdev.materialfx.controls.enums.ButtonType; +import io.github.palexdev.materialfx.enums.ButtonType; import io.github.palexdev.materialfx.effects.DepthLevel; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.skins.MFXButtonSkin; import javafx.beans.property.*; import javafx.css.*; @@ -119,7 +119,7 @@ public class MFXButton extends Button { setRippleColor(Color.rgb(190, 190, 190)); setRippleRadius(25); setComputeRadiusMultiplier(true); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> PositionBean.of(event.getX(), event.getY())); } public boolean isComputeRadiusMultiplier() { diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckListView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckListView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckTreeItem.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckTreeItem.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckTreeView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckTreeView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckbox.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCheckbox.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCircleToggleNode.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCircleToggleNode.java old mode 100644 new mode 100755 index 3cfd89e1..de138444 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCircleToggleNode.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXCircleToggleNode.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.controls.base.AbstractMFXToggleNode; -import io.github.palexdev.materialfx.controls.enums.TextPosition; +import io.github.palexdev.materialfx.enums.TextPosition; import io.github.palexdev.materialfx.skins.MFXCircleToggleNodeSkin; import javafx.css.*; import javafx.scene.Node; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java old mode 100644 new mode 100755 index f1b67961..4227856a --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.beans.MFXSnapshotWrapper; -import io.github.palexdev.materialfx.controls.enums.DialogType; +import io.github.palexdev.materialfx.enums.DialogType; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.selection.ComboBoxSelectionModel; import io.github.palexdev.materialfx.skins.MFXComboBoxSkin; @@ -41,7 +41,7 @@ import javafx.scene.paint.Paint; import java.util.List; import java.util.function.Supplier; -import static io.github.palexdev.materialfx.controls.enums.Styles.ComboBoxStyles; +import static io.github.palexdev.materialfx.enums.Styles.ComboBoxStyles; /** * This is the implementation of a combo box following Google's material design guidelines in JavaFX. @@ -229,7 +229,7 @@ public class MFXComboBox extends Control implements Validated null); rippleGenerator.setRadiusMultiplier(1.7); rippleGenerator.setRippleColor(Color.rgb(98, 0, 238, 0.3)); - rippleGenerator.setRipplePositionFunction(event -> { - RipplePosition ripplePosition = new RipplePosition(); - ripplePosition.setXPosition(calendar.getBoundsInParent().getCenterX()); - ripplePosition.setYPosition(calendar.getBoundsInParent().getCenterY()); - return ripplePosition; - }); + rippleGenerator.setRipplePositionFunction(event -> PositionBean.of( + calendar.getBoundsInParent().getCenterX(), + calendar.getBoundsInParent().getCenterY() + )); getChildren().add(0, rippleGenerator); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXDialog.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXDialog.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXExceptionDialog.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXExceptionDialog.java old mode 100644 new mode 100755 index 3cfb90ac..d1f33bd0 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXExceptionDialog.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXExceptionDialog.java @@ -18,7 +18,7 @@ package io.github.palexdev.materialfx.controls; -import io.github.palexdev.materialfx.controls.enums.ButtonType; +import io.github.palexdev.materialfx.enums.ButtonType; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.ExceptionUtils; import io.github.palexdev.materialfx.utils.NodeUtils; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterComboBox.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterComboBox.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterPane.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterPane.java new file mode 100755 index 00000000..b5bc3172 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXFilterPane.java @@ -0,0 +1,240 @@ +package io.github.palexdev.materialfx.controls; + +import io.github.palexdev.materialfx.MFXResourcesLoader; +import io.github.palexdev.materialfx.enums.ChainMode; +import io.github.palexdev.materialfx.filter.base.AbstractFilter; +import io.github.palexdev.materialfx.beans.FilterBean; +import io.github.palexdev.materialfx.skins.MFXFilterPaneSkin; +import io.github.palexdev.materialfx.utils.PredicateUtils; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.event.EventHandler; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; +import javafx.scene.input.MouseEvent; + +import java.util.function.Predicate; + +/** + * This control allows to produce a {@link Predicate} for a given object type + * interactively, meaning that the filter is assembled from the user choices. + * To produce a filter the user must choose the object's field, input/choose a query + * and a way to evaluate the object's field against the query. + *

+ * From now on all code examples to better understand the functionalities of this control + * will use these POJO classes: + *
+ * {@code
+ *      public enum Gender {
+ *          MALE, FEMALE
+ *      }
+ *
+ *      public class Person {
+ *          private final String name;
+ *          private final int age;
+ *          private final Gender gender;
+ *          private final City city;
+ *
+ *          public Person(String name, int age, Gender gender, City city) {
+ *              this.name = name;
+ *              this.age = age;
+ *              this.gender = gender;
+ *              this.city = city;
+ *          }
+ *
+ *          public String name() {
+ *              return name;
+ *          }
+ *
+ *          public int age() {
+ *              return age;
+ *          }
+ *
+ *          public Gender gender() {
+ *              return gender;
+ *          }
+ *
+ *          public City city() {
+ *              return city;
+ *          }
+ *      }
+ *
+ *      public class City {
+ *          private final String name;
+ *          private final long population;
+ *
+ *          public City(String name, long population) {
+ *              this.name = name;
+ *              this.population = population;
+ *          }
+ *
+ *          public String name() {
+ *              return name;
+ *          }
+ *
+ *          public long population() {
+ *              return population;
+ *          }
+ *      }
+ * }
+ * 
+ *

+ * To specify on which fields to operate the filters must be added like this: + *
+ * {@code
+ *      MFXFilterPane fp = new MFXFilterPane<>();
+ *      AbstractFilter nameFilter = new StringFilter<>("Name", Person::name)
+ *      AbstractFilter ageFilter = new IntegerFilter<>("Age", Person:.age);
+ *
+ *      // MFXFilterPane is so powerful and versatile that you can also filter by nested objects, something like this for example...
+ *      AbstractFilter populationFilter = new LongFilter<>("City Population", person -> person.city().population());
+ *
+ *      // It even works for enumerators...
+ *      AbstractFilter> genderFilter = new EnumFilter<>("Gender", Person::gender, Gender.class); // Note that the type is necessary
+ *
+ *      // Finally...
+ *      fp.getFilters().addAll(nameFilter, ageFilter, populationFilter, genderFilter);
+ * }
+ * 
+ * + *

+ * When a filter is created through the add button, a {@link FilterBean} is created and added to a list + * which holds the "active filters", {@link #getActiveFilters()}. + *

+ * Note that the list is not unmodifiable, potentially, you could even add your own custom filters, the UI will be updated anyway. + *

+ * As you can read in the {@link FilterBean} documentation, they can be chained according to the specified {@link FilterBean#getMode()}, + * this is also interactive, meaning that when you build more than one filter, a node will appear between them, that node specifies + * the {@link ChainMode}, by clicking on it, you can switch between modes. + *

+ * Once filters you have finished you can produce a filter by calling {@link #filter()}. + *

+ * The control also offers to icons that are intended to produce a filter or reset the control, + * to set their behavior use {@link #setOnFilter(EventHandler)} and {@link #setOnReset(EventHandler)}. + * + * @param + */ +public class MFXFilterPane extends Control { + //================================================================================ + // Properties + //================================================================================ + private final String STYLE_CLASS = "mfx-filter-pane"; + private final String STYLESHEET = MFXResourcesLoader.load("css/MFXFilterPane.css"); + private final StringProperty headerText = new SimpleStringProperty("Filters"); + private final ObservableList> filters = FXCollections.observableArrayList(); + private final ObservableList> activeFilters = FXCollections.observableArrayList(); + + private EventHandler onFilter = event -> {}; + private EventHandler onReset = event -> {}; + + //================================================================================ + // Constructors + //================================================================================ + public MFXFilterPane() { + initialize(); + } + + //================================================================================ + // Methods + //================================================================================ + private void initialize() { + getStyleClass().add(STYLE_CLASS); + getStylesheets().add(STYLESHEET); + } + + /** + * Builds a predicate from the list of built filters (active filters). + *

+ * The {@link FilterBean} are chained by using {@link PredicateUtils#chain(Predicate, Predicate, ChainMode)}. + *

+ * If the list is empty by default a predicate that always returns true is built. + */ + public Predicate filter() { + Predicate filter = null; + ChainMode mode = null; + + for (FilterBean activeFilter : activeFilters) { + if (filter == null) { + filter = activeFilter.predicate(); + mode = activeFilter.getMode(); + continue; + } + + filter = PredicateUtils.chain(filter, activeFilter.predicate(), mode); + mode = activeFilter.getMode(); + } + + return filter != null ? filter : t -> true; + } + + //================================================================================ + // Getters/Setters + //================================================================================ + public String getHeaderText() { + return headerText.get(); + } + + /** + * Specifies the text of the header. + */ + public StringProperty headerTextProperty() { + return headerText; + } + + public void setHeaderText(String headerText) { + this.headerText.set(headerText); + } + + /** + * @return the list of {@link AbstractFilter}s. Each of them + * represents an object's field o which the filter operates + */ + public ObservableList> getFilters() { + return filters; + } + + /** + * @return the list of built filters + */ + public ObservableList> getActiveFilters() { + return activeFilters; + } + + /** + * @return the action invoked when clicking on the filter icon + */ + public EventHandler getOnFilter() { + return onFilter; + } + + /** + * Sets the action to perform when the filter icon is clicked. + */ + public void setOnFilter(EventHandler onFilter) { + this.onFilter = onFilter; + } + + /** + * @return the action invoked when clicking on the reset icon + */ + public EventHandler getOnReset() { + return onReset; + } + + /** + * Sets the action to perform when the reset icon is clicked. + */ + public void setOnReset(EventHandler onReset) { + this.onReset = onReset; + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected Skin createDefaultSkin() { + return new MFXFilterPaneSkin<>(this); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXHLoader.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXHLoader.java old mode 100644 new mode 100755 index cf1ff679..7dac8925 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXHLoader.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXHLoader.java @@ -19,8 +19,8 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.beans.MFXLoaderBean; -import io.github.palexdev.materialfx.controls.enums.LoaderCacheLevel; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.enums.LoaderCacheLevel; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.utils.LoaderUtils; import io.github.palexdev.materialfx.utils.ToggleButtonsUtil; import javafx.application.Platform; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXIconWrapper.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXIconWrapper.java old mode 100644 new mode 100755 index 55942d91..7705a967 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXIconWrapper.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXIconWrapper.java @@ -19,7 +19,7 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.effects.ripple.base.IRippleGenerator; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; @@ -63,6 +63,8 @@ public class MFXIconWrapper extends StackPane { setSize(size); } + // TODO add constructor with MFXFontIcon description and replace everywhere + //================================================================================ // Methods //================================================================================ @@ -87,7 +89,7 @@ public class MFXIconWrapper extends StackPane { */ public MFXIconWrapper defaultRippleGeneratorBehavior() { addRippleGenerator(); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> PositionBean.of(event.getX(), event.getY())); addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { if (event.getButton() == MouseButton.PRIMARY) { rippleGenerator.generateRipple(event); @@ -103,7 +105,7 @@ public class MFXIconWrapper extends StackPane { * @see IRippleGenerator * @see MFXCircleRippleGenerator */ - public MFXIconWrapper rippleGeneratorBehavior(Function positionFunction) { + public MFXIconWrapper rippleGeneratorBehavior(Function positionFunction) { addRippleGenerator(); rippleGenerator.setRipplePositionFunction(positionFunction); addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java old mode 100644 new mode 100755 index 5c0b1ec8..e9f28203 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXLabel.java @@ -34,7 +34,7 @@ import javafx.scene.text.Font; import java.util.List; -import static io.github.palexdev.materialfx.controls.enums.Styles.LabelStyles; +import static io.github.palexdev.materialfx.enums.Styles.LabelStyles; /** * This is the implementation of a label following Google's material design guidelines in JavaFX. diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXListView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXListView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotification.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotification.java deleted file mode 100644 index 7a6f3267..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotification.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.controls; - -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; -import javafx.animation.Animation; -import javafx.animation.PauseTransition; -import javafx.animation.Timeline; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.scene.layout.Region; -import javafx.stage.Popup; -import javafx.stage.Window; -import javafx.util.Duration; - -/** - * This is the implementation of a popup notification in JavaFX. - *

- * Extends {@code Popup}, provides animations for showing and closing and allows to - * close automatically the notification after some specified time. - */ -public class MFXNotification extends Popup { - //================================================================================ - // Properties - //================================================================================ - private Region content; - private boolean animate = false; - private final BooleanProperty hideAfter = new SimpleBooleanProperty(false); - - private Timeline inAnimation; - private Timeline outAnimation; - private PauseTransition hideAfterTransition; - - //================================================================================ - // Constructors - //================================================================================ - public MFXNotification(Region content) { - setAutoFix(false); - this.content = content; - this.getContent().add(content); - initialize(); - } - - public MFXNotification(Region content, boolean animate) { - this(content); - this.animate = animate; - } - - public MFXNotification(Region content, boolean animate, boolean hideAfter) { - this(content, animate); - this.hideAfter.set(hideAfter); - } - - //================================================================================ - // Methods - //================================================================================ - private void initialize() { - this.inAnimation = MFXAnimationFactory.FADE_IN.build(content, 600); - this.outAnimation = MFXAnimationFactory.FADE_OUT.build(content, 600); - this.hideAfterTransition = new PauseTransition(Duration.seconds(4)); - - this.hideAfter.addListener((observable, oldValue, newValue) -> { - if (newValue) { - addMouseHandlers(); - } else { - removeMouseHandlers(); - } - }); - } - - /** - * Closes the notification, plays out animation if requested. - *

- * Note: this method should be used rather than Popup's hide() method - */ - public void hideNotification() { - if (animate) { - outAnimation.setOnFinished(event -> super.hide()); - outAnimation.play(); - } else { - super.hide(); - } - } - - /** - * If the notification is set to hide automatically this method is called. - *

- * Adds MouseEntered and MouseExited handlers to stop/restart the - * close countdown when mouse is on/off the notification content. - */ - private void addMouseHandlers() { - this.content.setOnMouseEntered(event -> { - outAnimation.stop(); - hideAfterTransition.stop(); - this.content.setOpacity(1.0); - }); - this.content.setOnMouseExited(event -> { - if (hideAfterTransition.getStatus().equals(Animation.Status.STOPPED)) { - hideAfterTransition.playFromStart(); - } - }); - } - - /** - * If the notification is set to not hide automatically this method is called. - * Removes the handlers for MouseEntered and MouseExited - */ - private void removeMouseHandlers() { - this.content.setOnMouseEntered(null); - this.content.setOnMouseExited(null); - } - - /** - * Returns the notification's content - */ - public Region getNotificationContent() { - return content; - } - - /** - * Sets the notification's content and re-initializes the object. - */ - public void setContent(Region content) { - this.content = content; - this.getContent().add(content); - initialize(); - } - - public void setAnimate(boolean animate) { - this.animate = animate; - } - - public void setHideAfter(boolean hideAfter) { - this.hideAfter.set(hideAfter); - } - - public void setHideAfterDuration(Duration hideAfterDuration) { - this.hideAfterTransition.setDuration(hideAfterDuration); - } - - public void setInAnimation(Timeline inAnimation) { - this.inAnimation = inAnimation; - } - - public void setOutAnimation(Timeline outAnimation) { - this.outAnimation = outAnimation; - } - - //================================================================================ - // Override Methods - //================================================================================ - - /** - * Shows the notification on screen, plays in animation if requested, - * starts the close countdown if it's set to hide automatically. - * - * @param ownerWindow The owner of the popup. This must not be null. - * @param anchorX The x position of the popup anchor in screen coordinates - * @param anchorY The y position of the popup anchor in screen coordinates - * @throws NullPointerException if content is null - */ - @Override - public void show(Window ownerWindow, double anchorX, double anchorY) { - if (content == null) { - throw new NullPointerException("Notification content is null!"); - } - - if (animate) { - inAnimation.play(); - } - super.show(ownerWindow, anchorX, anchorY); - - if (hideAfter.get()) { - hideAfterTransition.setOnFinished(event -> hideNotification()); - hideAfterTransition.play(); - } - } -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotificationCenter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotificationCenter.java new file mode 100755 index 00000000..82ad9f21 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXNotificationCenter.java @@ -0,0 +1,721 @@ +package io.github.palexdev.materialfx.controls; + +import io.github.palexdev.materialfx.MFXResourcesLoader; +import io.github.palexdev.materialfx.beans.properties.functional.FunctionProperty; +import io.github.palexdev.materialfx.collections.TransformableListWrapper; +import io.github.palexdev.materialfx.controls.cell.MFXNotificationCell; +import io.github.palexdev.materialfx.enums.NotificationCounterStyle; +import io.github.palexdev.materialfx.enums.NotificationState; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.selection.MultipleSelectionModel; +import io.github.palexdev.materialfx.skins.MFXNotificationCenterSkin; +import io.github.palexdev.materialfx.utils.ExecutionUtils; +import io.github.palexdev.materialfx.utils.ListChangeProcessor; +import io.github.palexdev.materialfx.utils.others.ReusableScheduledExecutor; +import io.github.palexdev.virtualizedfx.beans.NumberRange; +import io.github.palexdev.virtualizedfx.flow.simple.SimpleVirtualFlow; +import io.github.palexdev.virtualizedfx.utils.ListChangeHelper; +import io.github.palexdev.virtualizedfx.utils.ListChangeHelper.Change; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.LongBinding; +import javafx.beans.property.*; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.event.EventHandler; +import javafx.geometry.Orientation; +import javafx.scene.Node; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; +import javafx.scene.input.MouseEvent; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.IntStream; + +import static io.github.palexdev.materialfx.enums.NotificationCounterStyle.NUMBER; + +/** + * A quite complex but easy to use implementation of a modern notification center. + *

+ * For the notifications it uses {@link TransformableListWrapper} as list implementation, this allows + * not only basic operations such additions, removals and replacements, but also filter and sort operations. + *

+ * It's composed by an icon and a popup that contains the list of notifications. + *

+ * A complete list of the features the notification center offers: + *

- Uses a virtual flow to show the notifications and have high performance + *

- Uses {@link MFXNotificationCell} as cells to contain the notifications, those special + * cells perfectly integrate with the selection mode feature of the notification center to show a checkbox when needed + *

- Has a {@link MultipleSelectionModel} to keep track of the selected notifications + *

- Has a property that keeps track of the number of unread notifications + *

- Has two styles for the unread counter: as a DOT, or as a dot with the NUMBER + *

- Allows to change the header's text + *

- Allows to toggle a "Do not disturb" mode + *

- Has a property that specifies whether the popup is showing or not + *

- Has a property that specifies whether the mouse is on the popup (it's bound, cannot be set, nor unbound) + *

- Allows to specify the space between the bell icon and the popup + *

- Allows to specify the popup's size. Must be greater than 0 and should always be larger than the bell's icon + *

- Has a context menu that opens when right-clicking on the virtual flow, by default it contains + * items to perform selection, filter and sort actions. It can also be disabled by setting a null factory, {@link #contextMenuFactoryProperty()} + *

- Has a flag to specify whether the notification center is animated or not + *

- Has a flag to specify whether visible notifications should be set as READ when the popup is shown + *

- Has a flag to specify whether notifications should be set as READ when they are dismissed + *

- Allows specifying the action to perform when the bell icon is pressed, by default inverts the value of the {@link #showingProperty()} + * to inform the popup that it should open/hide + *

Has an executor that runs every 60 seconds (by default, can be changed) that updates all the notifications. + * By update, I mean that {@link INotification#updateElapsed()} is called. The service can be stopped and started + * whenever desired, by default it is always started. + *

+ * As you can see it as a LOT to offer, and to be honest it's not everything I wanted to implement, but I decided to + * restrain myself for now, as adding any other feature would add more and more complexity. + */ +public class MFXNotificationCenter extends Control { + //================================================================================ + // Properties + //================================================================================ + private final String STYLE_CLASS = "mfx-notification-center"; + private final String STYLESHEET = MFXResourcesLoader.load("css/MFXNotificationCenter.css"); + + private final TransformableListWrapper notifications = new TransformableListWrapper<>(FXCollections.observableArrayList()); + + private final SimpleVirtualFlow virtualFlow; + private final MultipleSelectionModel selectionModel = new MultipleSelectionModel<>(notifications); + + private final BooleanProperty selectionMode = new SimpleBooleanProperty(false); + private final ReadOnlyLongWrapper unreadCount = new ReadOnlyLongWrapper(0); + private final LongBinding unreadCountBinding; + + private final ObjectProperty counterStyle = new SimpleObjectProperty<>(NUMBER); + private final StringProperty headerTextProperty = new SimpleStringProperty("Notifications"); + private final BooleanProperty doNotDisturb = new SimpleBooleanProperty(false); + private final BooleanProperty showing = new SimpleBooleanProperty(false); + + private final BooleanProperty popupHover = new SimpleBooleanProperty(false) { + @Override + public void unbind() {} + }; + private final DoubleProperty popupSpacing = new SimpleDoubleProperty(10); + private final DoubleProperty popupWidth = new SimpleDoubleProperty(450); + private final DoubleProperty popupHeight = new SimpleDoubleProperty(550); + + private MFXContextMenu contextMenu; + private final FunctionProperty contextMenuFactory = new FunctionProperty<>() { + @Override + public void set(Function newValue) { + if (contextMenu != null) { + contextMenu.dispose(); + contextMenu = null; + } + if (newValue != null) { + contextMenu = newValue.apply(virtualFlow); + } + super.set(newValue); + } + }; + + private boolean animated = true; + private boolean markAsReadOnShow = false; + private boolean markAsReadOnDismiss = false; + + private EventHandler onIconClicked = event -> setShowing(!isShowing()); + + private final ReusableScheduledExecutor notificationsUpdater; + + //================================================================================ + // Constructors + //================================================================================ + public MFXNotificationCenter() { + virtualFlow = SimpleVirtualFlow.Builder.create( + notifications, + notification -> new MFXNotificationCell(this, notification), + Orientation.VERTICAL + ); + + unreadCountBinding = Bindings.createLongBinding(() -> + notifications.stream() + .filter(notification -> notification.getState() == NotificationState.UNREAD) + .count(), + notifications + ); + + notificationsUpdater = new ReusableScheduledExecutor(Executors.newScheduledThreadPool( + 1, + r -> { + Thread thread = new Thread(r); + thread.setDaemon(true); + return thread; + } + )); + initialize(); + } + + //================================================================================ + // Methods + //================================================================================ + private void initialize() { + getStyleClass().add(STYLE_CLASS); + getStylesheets().add(STYLESHEET); + setPrefSize(400, 550); + defaultContextMenu(); + + unreadCount.bind(unreadCountBinding); + notifications.addListener((ListChangeListener) change -> { + if (!selectionModel.getSelection().isEmpty()) { + if (change.getList().isEmpty()) { + selectionModel.clearSelection(); + } else { + Change c = ListChangeHelper.processChange(change, NumberRange.of(0, Integer.MAX_VALUE)); + ListChangeProcessor updater = new ListChangeProcessor(selectionModel.getSelection().keySet()); + c.processReplacement((changed, removed) -> selectionModel.replaceSelection(changed.toArray(new Integer[0]))); + c.processAddition((from, to, added) -> { + updater.computeAddition(added.size(), from); + selectionModel.replaceSelection(updater.getIndexes().toArray(new Integer[0])); + }); + c.processRemoval((from, to, removed) -> { + updater.computeRemoval(removed, from); + selectionModel.replaceSelection(updater.getIndexes().toArray(new Integer[0])); + }); + } + } + }); + + notifications.predicateProperty().addListener(invalidated -> { + setSelectionMode(false); + selectionModel.clearSelection(); + }); + notifications.comparatorProperty().addListener(invalidated -> { + setSelectionMode(false); + selectionModel.clearSelection(); + }); + + showing.addListener((observable, oldValue, newValue) -> { + if (newValue && markAsReadOnShow) markVisibleNotificationsAs(NotificationState.READ); + }); + + startNotificationsUpdater(60, TimeUnit.SECONDS); + } + + /** + * Responsible for building and setting the default context menu. + */ + protected void defaultContextMenu() { + setContextMenuFactory(owner -> { + MFXContextMenuItem selectAll = new MFXContextMenuItem("Select All"); + selectAll.setAction(event -> { + if (notifications.isEmpty()) return; + NumberRange indexes = NumberRange.of(0, notifications.size() - 1); + selectionModel.replaceSelection(NumberRange.expandRange(indexes).toArray(Integer[]::new)); + } + ); + + MFXContextMenuItem selectRead = new MFXContextMenuItem("Select Read"); + selectRead.setAction(event -> { + if (notifications.isEmpty()) return; + Integer[] indexes = IntStream.range(0, notifications.size()) + .filter(i -> notifications.get(i).getState() == NotificationState.READ) + .boxed() + .toArray(Integer[]::new); + selectionModel.replaceSelection(indexes); + }); + + MFXContextMenuItem selectUnread = new MFXContextMenuItem("Select Unread"); + selectUnread.setAction(event -> { + if (notifications.isEmpty()) return; + Integer[] indexes = IntStream.range(0, notifications.size()) + .filter(i -> notifications.get(i).getState() == NotificationState.UNREAD) + .boxed() + .toArray(Integer[]::new); + selectionModel.replaceSelection(indexes); + }); + + MFXContextMenuItem clearSelection = new MFXContextMenuItem("Clear Selection"); + clearSelection.setAction(event -> selectionModel.clearSelection()); + + MFXContextMenuItem sortByState = new MFXContextMenuItem("Sort By State"); + sortByState.setAction(event -> notifications.setComparator(Comparator.comparing(INotification::getState))); + + MFXContextMenuItem sortByTime = new MFXContextMenuItem("Sort By Time"); + sortByTime.setAction(event -> notifications.setComparator(Comparator.comparing(INotification::getTime))); + + MFXContextMenuItem reverseSort = new MFXContextMenuItem("Reverse Sort"); + reverseSort.setAction(event -> { + if (notifications.getComparator() == null) return; + Comparator comparator = notifications.getComparator(); + notifications.setComparator(comparator.reversed()); + }); + + MFXContextMenuItem filterRead = new MFXContextMenuItem("Filter By Read"); + filterRead.setAction(event -> notifications.setPredicate(notification -> notification.getState() == NotificationState.READ)); + + MFXContextMenuItem filterUnread = new MFXContextMenuItem("Filter By Unread"); + filterUnread.setAction(event -> notifications.setPredicate(notification -> notification.getState() == NotificationState.UNREAD)); + + MFXContextMenuItem clearFilter = new MFXContextMenuItem("Clear Filter"); + clearFilter.setAction(event -> notifications.setPredicate(null)); + + MFXContextMenuItem clearSort = new MFXContextMenuItem("Clear Sort"); + clearSort.setAction(event -> notifications.setComparator(null)); + + + MFXContextMenu contextMenu = MFXContextMenu.Builder.build(owner) + .addMenuItem(selectAll) + .addMenuItem(selectRead) + .addMenuItem(selectUnread) + .addMenuItem(clearSelection) + .addSeparator() + .addMenuItem(sortByState) + .addMenuItem(sortByTime) + .addMenuItem(reverseSort) + .addSeparator() + .addMenuItem(filterRead) + .addMenuItem(filterUnread) + .addSeparator() + .addMenuItem(clearSort) + .addMenuItem(clearFilter) + .installAndGet(); + + ExecutionUtils.executeWhen( + getStylesheets(), + () -> { + String base = contextMenu.getUserAgentStylesheet(); // TODO change if making THAT change + List stylesheets = new ArrayList<>(List.of(base)); + stylesheets.addAll(getStylesheets()); + contextMenu.getStylesheets().setAll(stylesheets); + }, + true, + () -> true, + false + ); + return contextMenu; + }); + } + + /** + * Starts the notifications updater service to run the update task + * periodically, according to the given period and time unit. + * + * @see INotification#updateElapsed() + */ + public void startNotificationsUpdater(long period, TimeUnit timeUnit) { + notificationsUpdater.scheduleAtFixedRate( + () -> notifications.forEach(INotification::updateElapsed), + 0, + period, + timeUnit + ); + } + + /** + * Immediately stops the notifications updater service. + */ + public void stopNotificationsUpdater() { + notificationsUpdater.cancelNow(); + } + + /** + * Sets all the given notifications' state to the given state. + *

+ * At the end recomputes the number of unread notifications. + */ + public void markNotificationsAs(NotificationState state, INotification... notifications) { + for (INotification notification : notifications) { + notification.setNotificationState(state); + } + unreadCountBinding.invalidate(); + } + + /** + * Sets all the visible notifications' state to the given state. + */ + public void markVisibleNotificationsAs(NotificationState state) { + markNotificationsAs( + state, + getCells().values().stream() + .map(MFXNotificationCell::getNotification) + .toArray(INotification[]::new) + ); + } + + /** + * Sets all the selected notifications' state to the given state. + */ + public void markSelectedNotificationsAs(NotificationState state) { + markNotificationsAs(state, selectionModel.getSelection().values().toArray(INotification[]::new)); + } + + /** + * Sets all the notifications' state to the given state. + */ + public void markAllNotificationsAs(NotificationState state) { + markNotificationsAs(state, notifications.toArray(INotification[]::new)); + } + + /** + * Sets all the given notifications' state to READ, then removes them from the notifications list. + */ + public void dismiss(INotification... notifications) { + if (markAsReadOnDismiss) { + markNotificationsAs(NotificationState.READ, notifications); + } + this.notifications.removeAll(notifications); + } + + /** + * Sets all the visible notifications' state to READ, then removes them from the notifications list. + */ + public void dismissVisible() { + dismiss(getCells().values().stream().map(MFXNotificationCell::getNotification).toArray(INotification[]::new)); + } + + /** + * Sets all the selected notifications' state to READ, then removes them from the notifications list. + */ + public void dismissSelected() { + dismiss(getSelectionModel().getSelection().values().toArray(INotification[]::new)); + } + + /** + * Sets all the notifications' state to READ, then removes them from the notifications list. + */ + public void dismissAll() { + dismiss(notifications.toArray(INotification[]::new)); + } + + //================================================================================ + // Getters/Setters + //================================================================================ + + /** + * @return the list of notifications + */ + public TransformableListWrapper getNotifications() { + return notifications; + } + + /** + * @return the selection model instance used to keep track of selected notifications + */ + public MultipleSelectionModel getSelectionModel() { + return selectionModel; + } + + public boolean isSelectionMode() { + return selectionMode.get(); + } + + /** + * Specifies if the notification center is in selection mode. + *

+ * By default this mode triggers {@link MFXNotificationCell} to show a checkbox for selection + */ + public BooleanProperty selectionModeProperty() { + return selectionMode; + } + + public void setSelectionMode(boolean selectionMode) { + this.selectionMode.set(selectionMode); + } + + public long getUnreadCount() { + return unreadCount.get(); + } + + /** + * Specifies the number of unread notifications. + */ + public ReadOnlyLongProperty unreadCountProperty() { + return unreadCount.getReadOnlyProperty(); + } + + public NotificationCounterStyle getCounterStyle() { + return counterStyle.get(); + } + + /** + * Specifies the style of the unread counter. + */ + public ObjectProperty counterStyleProperty() { + return counterStyle; + } + + public void setCounterStyle(NotificationCounterStyle counterStyle) { + this.counterStyle.set(counterStyle); + } + + public String getHeaderTextProperty() { + return headerTextProperty.get(); + } + + /** + * Specifies the header's text. + */ + public StringProperty headerTextPropertyProperty() { + return headerTextProperty; + } + + public void setHeaderTextProperty(String headerTextProperty) { + this.headerTextProperty.set(headerTextProperty); + } + + public boolean isDoNotDisturb() { + return doNotDisturb.get(); + } + + /** + * Specifies if the notification center is in "Do not disturb" mode. + */ + public BooleanProperty doNotDisturbProperty() { + return doNotDisturb; + } + + public void setDoNotDisturb(boolean doNotDisturb) { + this.doNotDisturb.set(doNotDisturb); + } + + public boolean isShowing() { + return showing.get(); + } + + /** + * Specifies if the popup is shown/hidden. + *

+ * Can also be used to control the popup. + */ + public BooleanProperty showingProperty() { + return showing; + } + + public void setShowing(boolean showing) { + this.showing.set(showing); + } + + public boolean isPopupHover() { + return popupHover.get(); + } + + /** + * Specifies if the mouse is on the popup. + *

+ * Despite being a Read-Write property, it is bound to the popup's hover property + * and cannot be unbound. Attempts to set this will always fail with an exception. + */ + public BooleanProperty popupHoverProperty() { + return popupHover; + } + + public double getPopupSpacing() { + return popupSpacing.get(); + } + + /** + * Specifies the space between the bell icon and the popup + */ + public DoubleProperty popupSpacingProperty() { + return popupSpacing; + } + + public void setPopupSpacing(double popupSpacing) { + this.popupSpacing.set(popupSpacing); + } + + public double getPopupWidth() { + return popupWidth.get(); + } + + /** + * Specifies the popups' width. + */ + public DoubleProperty popupWidthProperty() { + return popupWidth; + } + + public void setPopupWidth(double popupWidth) { + this.popupWidth.set(popupWidth); + } + + public double getPopupHeight() { + return popupHeight.get(); + } + + /** + * Specifies the popup's height. + */ + public DoubleProperty popupHeightProperty() { + return popupHeight; + } + + public void setPopupHeight(double popupHeight) { + this.popupHeight.set(popupHeight); + } + + public Function getContextMenuFactory() { + return contextMenuFactory.get(); + } + + /** + * Specifies the function used to produce a {@link MFXContextMenu}. + *

+ * Setting this to null will remove the context menu. + */ + public FunctionProperty contextMenuFactoryProperty() { + return contextMenuFactory; + } + + public void setContextMenuFactory(Function contextMenuFactory) { + this.contextMenuFactory.set(contextMenuFactory); + } + + /** + * Specifies whether the notification center is animated. + */ + public boolean isAnimated() { + return animated; + } + + public void setAnimated(boolean animated) { + this.animated = animated; + } + + /** + * Specifies whether visible notification should be marked as read when the popup is shown. + */ + public boolean isMarkAsReadOnShow() { + return markAsReadOnShow; + } + + public void setMarkAsReadOnShow(boolean markAsReadOnShow) { + this.markAsReadOnShow = markAsReadOnShow; + } + + /** + * Specifies whether dismissed notifications should be set as READ. + *

+ * For this to work use one of the dismiss methods offered by the control. + */ + public boolean isMarkAsReadOnDismiss() { + return markAsReadOnDismiss; + } + + public void setMarkAsReadOnDismiss(boolean markAsReadOnDismiss) { + this.markAsReadOnDismiss = markAsReadOnDismiss; + } + + /** + * Specifies the action to perform when the bell icon is clicked. + */ + public EventHandler getOnIconClicked() { + return onIconClicked; + } + + public void setOnIconClicked(EventHandler onIconClicked) { + this.onIconClicked = onIconClicked; + } + + //================================================================================ + // Delegate Methods + //================================================================================ + + /** + * Delegate method for {@link SimpleVirtualFlow#getCell(int)}. + */ + public MFXNotificationCell getCell(int index) { + return virtualFlow.getCell(index); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#getCells()}. + */ + public Map getCells() { + return virtualFlow.getCells(); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#scrollBy(double)}. + */ + public void scrollBy(double pixels) { + virtualFlow.scrollBy(pixels); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#scrollTo(int)}. + */ + public void scrollTo(int index) { + virtualFlow.scrollTo(index); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#scrollToFirst()}. + */ + public void scrollToFirst() { + virtualFlow.scrollToFirst(); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#scrollToLast()}. + */ + public void scrollToLast() { + virtualFlow.scrollToLast(); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#scrollToPixel(double)}. + */ + public void scrollToPixel(double pixel) { + virtualFlow.scrollToPixel(pixel); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#setHSpeed(double, double)}. + */ + public void setHSpeed(double unit, double block) { + virtualFlow.setHSpeed(unit, block); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#setVSpeed(double, double)}. + */ + public void setVSpeed(double unit, double block) { + virtualFlow.setVSpeed(unit, block); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#getVerticalPosition()}. + */ + public double getVerticalPosition() { + return virtualFlow.getVerticalPosition(); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#getHorizontalPosition()}. + */ + public double getHorizontalPosition() { + return virtualFlow.getHorizontalPosition(); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#setCellFactory(Function)}. + */ + public void setCellFactory(Function cellFactory) { + virtualFlow.setCellFactory(cellFactory); + } + + /** + * Delegate method for {@link SimpleVirtualFlow#features()}. + */ + public SimpleVirtualFlow.Features features() { + return virtualFlow.features(); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected Skin createDefaultSkin() { + return new MFXNotificationCenterSkin(this, virtualFlow); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPasswordField.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPasswordField.java old mode 100644 new mode 100755 index 7e0625d4..865fd378 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPasswordField.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPasswordField.java @@ -52,7 +52,6 @@ import javafx.scene.paint.Color; *

* Side notes: *

- the context menu is redefined in the skin since some methods are private in the skin. - *

- see {@link #enableContextMenuTextSelectionFix(boolean)}. */ public class MFXPasswordField extends MFXTextField { //================================================================================ @@ -128,7 +127,7 @@ public class MFXPasswordField extends MFXTextField { */ @Override protected void defaultContextMenu() { - setMFXContextMenu(MFXContextMenu.Builder.build(this).install()); + setMFXContextMenu(MFXContextMenu.Builder.build(this).installAndGet()); } public String getPassword() { diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPopup.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPopup.java new file mode 100755 index 00000000..a4f1d377 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXPopup.java @@ -0,0 +1,357 @@ +package io.github.palexdev.materialfx.controls; + +import io.github.palexdev.materialfx.beans.PopupPositionBean; +import io.github.palexdev.materialfx.beans.PositionBean; +import io.github.palexdev.materialfx.effects.Interpolators; +import io.github.palexdev.materialfx.skins.MFXPopupSkin; +import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; +import io.github.palexdev.materialfx.utils.AnimationUtils.TimelineBuilder; +import javafx.animation.Animation; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.css.PseudoClass; +import javafx.event.Event; +import javafx.event.EventHandler; +import javafx.event.EventType; +import javafx.geometry.HPos; +import javafx.geometry.Point2D; +import javafx.geometry.VPos; +import javafx.scene.Node; +import javafx.scene.control.PopupControl; +import javafx.scene.control.Skin; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.StackPane; +import javafx.scene.transform.Scale; +import javafx.stage.Window; + +import java.util.function.BiFunction; + +/** + * Custom and better implementation of a {@link PopupControl}. + *

+ * Setting the popup's content is now easier, it is animated (can be disabled), the animation + * can be changed but the most important features are the hover property and PseudoClass ("popup-hover" in css) + * that specifies when the mouse is on the content, and the new show methods that make use of {@link HPos} + * and {@link VPos} to compute the position for you, no more x and y computation, leave it to {@code MFXPopup}. + *

+ * Of course if needed JavaFX's methods are still available. + *

+ * Also allows to reposition the popup on demand by calling {@link #reposition()} and also + * offers a new {@link EventType}. + */ +public class MFXPopup extends PopupControl { + //================================================================================ + // Properties + //================================================================================ + private PopupPositionBean position; + private final ObjectProperty content = new SimpleObjectProperty<>() { + @Override + public void set(Node newValue) { + Node oldValue = get(); + if (oldValue != null) { + oldValue.removeEventFilter(MouseEvent.MOUSE_ENTERED, entered); + oldValue.removeEventFilter(MouseEvent.MOUSE_EXITED, exited); + } + newValue.addEventFilter(MouseEvent.MOUSE_ENTERED, entered); + newValue.addEventFilter(MouseEvent.MOUSE_EXITED, exited); + super.set(newValue); + } + }; + private BiFunction animationProvider; + private boolean animated = true; + + private final PseudoClass HOVER_PSEUDO_CLASS = PseudoClass.getPseudoClass("popup-hover"); + private final BooleanProperty hover = new SimpleBooleanProperty(false); + private final EventHandler entered = event -> setHover(true); + private final EventHandler exited = event -> setHover(false); + + //================================================================================ + // Constructors + //================================================================================ + public MFXPopup() { + animationProvider = (node, scale) -> TimelineBuilder.build() + .show(150, node) + .add(KeyFrames.of(150, + scale.xProperty(), 1, Interpolators.INTERPOLATOR_V2 + )) + .add(KeyFrames.of(200, + scale.yProperty(), 1, Interpolators.INTERPOLATOR_V2 + + )) + .getAnimation(); + initialize(); + } + + public MFXPopup(Node content) { + setContent(content); + animationProvider = (node, scale) -> TimelineBuilder.build() + .show(150, node) + .add(KeyFrames.of(150, + scale.xProperty(), 1, Interpolators.INTERPOLATOR_V2 + )) + .add(KeyFrames.of(200, + scale.yProperty(), 1, Interpolators.INTERPOLATOR_V2 + + )) + .getAnimation(); + initialize(); + } + + //================================================================================ + // Methods + //================================================================================ + private void initialize() { + setAutoFix(false); + setAutoHide(true); + setHideOnEscape(true); + + hover.addListener(invalidated -> pseudoClassStateChanged(HOVER_PSEUDO_CLASS, hover.get())); + } + + /** + * Shows the popup at the BOTTOM_RIGHT of the specified node. + *

+ * Calls {@link #show(Node, HPos, VPos, double, double)}. + */ + public void show(Node node) { + show(node, HPos.RIGHT, VPos.BOTTOM, 0, 0); + } + + /** + * Shows the popup at the given positions. + *

+ * Calls {@link #show(Node, HPos, VPos, double, double)}. + */ + public void show(Node node, HPos hPos, VPos vPos) { + show(node, hPos, vPos, 0, 0); + } + + /** + * Shows the popup at the given positions, then shifts the computed coordinates + * by the given offsets. + *

+ * Once the position is computed, it is stored in a {@link PopupPositionBean} alongside other + * useful info. These info are important because before the popup is actually shown, its skin + * is created. The {@link MFXPopupSkin} uses these info to properly position and animate the popup. + * This is needed because before creating the skin the content is not laid out so its sizes/bounds are 0 + * and the "real" coordinates cannot be computed. For this reason, the coordinates stored in the + * position bean are not reliable, because they do not take into account the adjustments applied + * by the skin. (as of now, maybe will be improved in the future) + */ + public void show(Node node, HPos hPos, VPos vPos, double xOffset, double yOffset) { + if (node.getScene() == null || node.getScene().getWindow() == null) { + throw new IllegalStateException("Cannot show the popup. The node must be attached to a scene/window!"); + } + + Window window = node.getScene().getWindow(); + PositionBean position = computePosition(node, window, hPos, vPos); + this.position = new PopupPositionBean(node, position, hPos, vPos, xOffset, yOffset); + show(window, position.getX(), position.getY()); + } + + // TODO add show Window + + /** + * Repositions the popup by recomputing the position from + * the previous stored info. + *

+ * This should be called when the owner's position changes. + * + * @see #show(Node, HPos, VPos, double, double) + * @see PopupPositionBean + */ + public void reposition() { + if (!isShowing() || position == null) return; + position = computeReposition(); + double containerW = getContent().prefWidth(-1); + double containerH = getContent().prefHeight(-1); + HPos hPos = position.getHPos(); + VPos vPos = position.getVPos(); + double xOffset = position.getXOffset(); + double yOffset = position.getYOffset(); + + double tx = 0; + double ty = 0; + switch (hPos) { + case CENTER: { + tx = -(Math.abs(containerW - position.getOwnerWidth()) / 2) + xOffset; + break; + } + case LEFT: { + tx = -containerW + xOffset; + break; + } + case RIGHT: { + tx = xOffset; + break; + } + } + switch (vPos) { + case BOTTOM: { + ty = yOffset; + break; + } + case CENTER: { + ty = -(Math.abs(containerH - position.getOwnerHeight()) / 2) + yOffset; + break; + } + case TOP: { + ty = -containerH + yOffset; + break; + } + } + + setX(position.getX() + tx); + setY(position.getY() + ty); + } + + /** + * Computes the initial (x, y) coordinates for the given parameters. + * These will be "refined" in the skin. + */ + private PositionBean computePosition(Node node, Window window, HPos hPos, VPos vPos) { + Point2D origin = node.localToScene(0, 0); + + double nodeWidth = node.prefWidth(-1); + double nodeHeight = node.prefHeight(-1); + double x = window.getX() + origin.getX() + node.getScene().getX() + (hPos == HPos.LEFT ? nodeWidth : 0); + double y = window.getY() + origin.getY() + node.getScene().getY() + (vPos == VPos.BOTTOM ? nodeHeight : 0); + return PositionBean.of(x, y); + } + + /** + * Used to compute the new position of the popup when repositioning. + */ + private PopupPositionBean computeReposition() { + Node node = position.getOwner(); + Window window = node.getScene().getWindow(); + HPos hPos = position.getHPos(); + VPos vPos = position.getVPos(); + PositionBean positionBean = computePosition(node, window, hPos, vPos); + return new PopupPositionBean(node, positionBean, hPos, vPos, position.getXOffset(), position.getYOffset()); + } + + //================================================================================ + // Getters/Setters + //================================================================================ + + /** + * @return the instance of the {@link PopupPositionBean} computed when showing + * or repositioning the popup. Note that it will return null if the popup is not showing. + */ + public PopupPositionBean getPosition() { + return position; + } + + public Node getContent() { + return content.get(); + } + + /** + * Specifies the popup's content. + *

+ * As of now changing the content while the popup is shown won't have any effect. + * For it to work, the popup must be closed and reopened again. + * As of now, there's no plan to improve this because such use case would introduce + * an unnecessary layer of complexity and in my opinion it's also a discouraged practice to change + * the popup's content while open. It would be better to use a container Pane and change its content. + *

+ * This is a property because when the content changes it's needed to add the necessary handlers to it + * to make the "hover" feature work. + *

+ * The content cannot be null. + */ + public ObjectProperty contentProperty() { + return content; + } + + public void setContent(Node content) { + this.content.set(content); + } + + /** + * @return the function used by the skin to produce the popup's animation + */ + public BiFunction getAnimationProvider() { + return animationProvider; + } + + /** + * Sets the function used by the skin to produce the popup's animation. + *

+ * The input parameters are the popup's container (it's a {@link StackPane}, and + * the {@link Scale} transform applied to the container. + */ + public void setAnimationProvider(BiFunction animationProvider) { + this.animationProvider = animationProvider; + } + + /** + * Specifies whether tha popup's is animated. + */ + public boolean isAnimated() { + return animated; + } + + public void setAnimated(boolean animated) { + this.animated = animated; + } + + public boolean isHover() { + return hover.get(); + } + + /** + * Specifies if the mouse is on the popup's content. + */ + public BooleanProperty hoverProperty() { + return hover; + } + + public void setHover(boolean hover) { + this.hover.set(hover); + } + + //================================================================================ + // Override Methods + //================================================================================ + + /** + * {@inheritDoc} + *

+ * Overridden to set the stored {@link PopupPositionBean} to null. + */ + @Override + public void hide() { + position = null; + super.hide(); + } + + @Override + protected Skin createDefaultSkin() { + return new MFXPopupSkin(this); + } + + //================================================================================ + // Events + //================================================================================ + + /** + * Events class for {@link MFXPopup}s. + *

+ * Introduces a new event type: "REPOSITION_EVENT". It can be used to inform a popup that it should + * reposition. The typical use of this event is in case of Control/Skin or in general MVC pattern. + * If you don't have a reference to the popup, fire this event and capture it in the class that has the popup's reference + * then call, {@link #reposition()}. + */ + public static class MFXPopupEvent extends Event { + + public static final EventType REPOSITION_EVENT = new EventType<>(ANY, "Reposition Event"); + + public MFXPopupEvent(EventType eventType) { + super(eventType); + } + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressBar.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressBar.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressSpinner.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXProgressSpinner.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRadioButton.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRadioButton.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRectangleToggleNode.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRectangleToggleNode.java old mode 100644 new mode 100755 index cacfde16..dc83461c --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRectangleToggleNode.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXRectangleToggleNode.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.controls.base.AbstractMFXToggleNode; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; import io.github.palexdev.materialfx.effects.ripple.RippleClipType; import io.github.palexdev.materialfx.skins.MFXRectangleToggleNodeSkin; import javafx.beans.property.ObjectProperty; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXScrollPane.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXScrollPane.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSimpleNotification.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSimpleNotification.java new file mode 100755 index 00000000..09f3a7f2 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSimpleNotification.java @@ -0,0 +1,147 @@ +package io.github.palexdev.materialfx.controls; + +import io.github.palexdev.materialfx.enums.NotificationState; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.utils.StringUtils; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Region; + +import java.time.Instant; +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * Simple implementation of {@link INotification}. + *

+ * By default the {@link INotification#getTimeToStringConverter()} function is set to use {@link StringUtils#timeToHumanReadable(long)}. + * By default the {@link INotification#setOnUpdateElapsed(BiConsumer)} function is set to do nothing. + *

+ * Offers a Builder to build a notification with fluent design. + */ +public class MFXSimpleNotification implements INotification { + //================================================================================ + // Properties + //================================================================================ + private Region content; + + private final ObjectProperty state = new SimpleObjectProperty<>(NotificationState.UNREAD); + private final long createdTime; + private Function timeToStringConverter = StringUtils::timeToHumanReadable; + private BiConsumer onUpdate = (elapsedLong, elapsedString) -> {}; + + //================================================================================ + // Constructors + //================================================================================ + protected MFXSimpleNotification() { + this(new AnchorPane()); + } + + public MFXSimpleNotification(Region content) { + createdTime = Instant.now().getEpochSecond(); + if (content == null) { + throw new IllegalArgumentException("Content cannot be null!"); + } + this.content = content; + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + @Override + public Region getContent() { + return content; + } + + protected void setContent(Region content) { + this.content = content; + } + + @Override + public NotificationState getState() { + return state.get(); + } + + @Override + public ObjectProperty notificationStateProperty() { + return state; + } + + @Override + public void setNotificationState(NotificationState state) { + this.state.set(state); + } + + @Override + public long getTime() { + return createdTime; + } + + @Override + public long getElapsedTime() { + return Instant.now().getEpochSecond() - createdTime; + } + + @Override + public Function getTimeToStringConverter() { + return timeToStringConverter; + } + + @Override + public void setTimeToStringConverter(Function converter) { + this.timeToStringConverter = converter; + } + + @Override + public void updateElapsed() { + long elapsedTime = getElapsedTime(); + onUpdate.accept(elapsedTime, timeToStringConverter.apply(elapsedTime)); + } + + @Override + public void setOnUpdateElapsed(BiConsumer elapsedConsumer) { + this.onUpdate = elapsedConsumer; + } + + //================================================================================ + // Builder + //================================================================================ + public static class Builder { + private final MFXSimpleNotification notification = new MFXSimpleNotification(); + + protected Builder() {} + + public static Builder build() { + return new Builder(); + } + + public Builder setContent(Region content) { + if (content == null) { + throw new IllegalArgumentException("Content cannot be null!"); + } + notification.setContent(content); + return this; + } + + public Builder setState(NotificationState state) { + notification.setNotificationState(state); + return this; + } + + public Builder setTimeToStringConverter(Function converter) { + notification.setTimeToStringConverter(converter); + return this; + } + + public Builder setOnUpdateElapsed(BiConsumer elapsedConsumer) { + notification.setOnUpdateElapsed(elapsedConsumer); + return this; + } + + public MFXSimpleNotification get() { + return notification; + } + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSlider.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSlider.java old mode 100644 new mode 100755 index 75c44ba3..19159fe8 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSlider.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXSlider.java @@ -20,10 +20,10 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.beans.NumberRange; -import io.github.palexdev.materialfx.controls.enums.SliderEnums.SliderMode; -import io.github.palexdev.materialfx.controls.enums.SliderEnums.SliderPopupSide; +import io.github.palexdev.materialfx.enums.SliderEnums.SliderMode; +import io.github.palexdev.materialfx.enums.SliderEnums.SliderPopupSide; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.skins.MFXSliderSkin; import io.github.palexdev.materialfx.utils.NodeUtils; @@ -264,7 +264,7 @@ public class MFXSlider extends Control { rippleGenerator.setMouseTransparent(true); rippleGenerator.setRadiusMultiplier(2.5); rippleGenerator.setRippleRadius(6); - rippleGenerator.setRipplePositionFunction(mouseEvent -> new RipplePosition(stackPane.getWidth() / 2, stackPane.getHeight() / 2)); + rippleGenerator.setRipplePositionFunction(mouseEvent -> new PositionBean(stackPane.getWidth() / 2, stackPane.getHeight() / 2)); stackPane.addEventFilter(MouseEvent.MOUSE_PRESSED, rippleGenerator::generateRipple); stackPane.getChildren().add(rippleGenerator); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStageDialog.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStageDialog.java old mode 100644 new mode 100755 index dc558410..e52d565b --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStageDialog.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStageDialog.java @@ -19,9 +19,9 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.controls.base.AbstractMFXDialog; -import io.github.palexdev.materialfx.controls.enums.DialogType; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; -import io.github.palexdev.materialfx.controls.factories.MFXStageDialogFactory; +import io.github.palexdev.materialfx.enums.DialogType; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXStageDialogFactory; import io.github.palexdev.materialfx.effects.MFXScrimEffect; import io.github.palexdev.materialfx.utils.AnimationUtils; import javafx.animation.KeyFrame; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepper.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepper.java old mode 100644 new mode 100755 index b6086963..9da9a413 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepper.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepper.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.controls.MFXStepperToggle.MFXStepperToggleEvent; -import io.github.palexdev.materialfx.controls.enums.StepperToggleState; +import io.github.palexdev.materialfx.enums.StepperToggleState; import io.github.palexdev.materialfx.skins.MFXStepperSkin; import io.github.palexdev.materialfx.utils.NodeUtils; import io.github.palexdev.materialfx.validation.base.AbstractMFXValidator; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepperToggle.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepperToggle.java old mode 100644 new mode 100755 index 79209c98..30ff5049 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepperToggle.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXStepperToggle.java @@ -19,8 +19,8 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; -import io.github.palexdev.materialfx.controls.enums.StepperToggleState; -import io.github.palexdev.materialfx.controls.enums.TextPosition; +import io.github.palexdev.materialfx.enums.StepperToggleState; +import io.github.palexdev.materialfx.enums.TextPosition; import io.github.palexdev.materialfx.skins.MFXStepperSkin; import io.github.palexdev.materialfx.skins.MFXStepperToggleSkin; import io.github.palexdev.materialfx.validation.MFXDialogValidator; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableRow.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableRow.java old mode 100644 new mode 100755 index 0e801eb7..c365a85a --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableRow.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableRow.java @@ -19,10 +19,10 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; import io.github.palexdev.materialfx.effects.ripple.RippleClipType; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.css.PseudoClass; @@ -89,7 +89,7 @@ public class MFXTableRow extends HBox { rippleGenerator.setClipSupplier(() -> new RippleClipTypeFactory(RippleClipType.RECTANGLE).setOffsetW(10).build(this)); rippleGenerator.setComputeRadiusMultiplier(true); rippleGenerator.setManaged(false); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> new PositionBean(event.getX(), event.getY())); rippleGenerator.setTranslateX(-5); rippleGenerator.rippleRadiusProperty().bind(widthProperty().divide(2.0)); addEventFilter(MouseEvent.MOUSE_PRESSED, rippleGenerator::generateRipple); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableSortModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableSortModel.java old mode 100644 new mode 100755 index f1d17cf5..7bcefd86 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableSortModel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableSortModel.java @@ -19,7 +19,7 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.controls.cell.MFXTableColumn; -import io.github.palexdev.materialfx.controls.enums.SortState; +import io.github.palexdev.materialfx.enums.SortState; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.ListChangeListener; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTableView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTextField.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTextField.java old mode 100644 new mode 100755 index 594ca047..cac61219 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTextField.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXTextField.java @@ -19,7 +19,7 @@ package io.github.palexdev.materialfx.controls; import io.github.palexdev.materialfx.MFXResourcesLoader; -import io.github.palexdev.materialfx.controls.enums.DialogType; +import io.github.palexdev.materialfx.enums.DialogType; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.skins.MFXTextFieldSkin; import io.github.palexdev.materialfx.utils.ColorUtils; @@ -262,7 +262,7 @@ public class MFXTextField extends TextField implements Validated. - */ - -package io.github.palexdev.materialfx.controls; - -import io.github.palexdev.materialfx.controls.base.AbstractMFXNotificationPane; -import io.github.palexdev.materialfx.font.MFXFontIcon; -import io.github.palexdev.materialfx.utils.NodeUtils; -import javafx.event.EventHandler; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import javafx.scene.paint.Color; - -/** - * This class extends {@code AbstractMFXNotificationPane} and it serves as an - * example of a basic pane for a {@code MFXNotification}. - */ -public class SimpleMFXNotificationPane extends AbstractMFXNotificationPane { - //================================================================================ - // Properties - //================================================================================ - private final StackPane headerNode; - private final Label headerLabel; - private final Label titleLabel; - private final MFXScrollPane contentScroll; - private final Label contentLabel; - - private final MFXButton closeButton; - private final MFXButton okButton; - private final HBox buttonsBox; - - private EventHandler closeHandler; - - //================================================================================ - // Constructors - //================================================================================ - public SimpleMFXNotificationPane(String header, String title, String content) { - this(null, header, title, content); - } - - public SimpleMFXNotificationPane(Node icon, String header, String title, String content) { - // Header - headerNode = new StackPane(); - headerLabel = new Label(); - headerLabel.textProperty().bind(headerProperty); - headerLabel.getStyleClass().add("header-label"); - headerLabel.setGraphic(icon); - headerLabel.setGraphicTextGap(7); - headerLabel.setPadding(new Insets(15, 15, 0, 15)); - headerProperty.set(header); - - closeButton = new MFXButton(""); - closeButton.setPrefSize(18, 18); - closeButton.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); - MFXFontIcon xIcon = new MFXFontIcon("mfx-x-circle", 14); - closeButton.setGraphic(xIcon); - closeButton.setRippleRadius(12); - closeButton.setRippleColor(Color.rgb(255, 0, 0, 0.1)); - - NodeUtils.makeRegionCircular(closeButton); - - headerNode.getChildren().addAll(headerLabel, closeButton); - StackPane.setMargin(headerLabel, new Insets(0, 0, 10, 0)); - StackPane.setAlignment(headerLabel, Pos.CENTER_LEFT); - StackPane.setAlignment(closeButton, Pos.TOP_RIGHT); - StackPane.setMargin(closeButton, new Insets(6, 6, 8, 8)); - - // Title - titleLabel = new Label(); - titleLabel.textProperty().bind(titleProperty); - titleLabel.getStyleClass().add("title-label"); - titleLabel.setPadding(new Insets(0, 0, 0, 15)); - titleProperty.set(title); - - // Content - contentScroll = new MFXScrollPane(); - contentScroll.setFitToWidth(true); - contentScroll.setPrefSize(200, 200); - - contentLabel = new Label(); - contentLabel.textProperty().bind(contentProperty); - contentLabel.getStyleClass().add("content-label"); - contentLabel.setWrapText(true); - contentProperty.set(content); - - contentScroll.setContent(contentLabel); - contentScroll.setPadding(new Insets(5, 10, 5, 10)); - VBox.setMargin(contentScroll, new Insets(5, 10, 5, 10)); - - // Buttons - buttonsBox = new HBox(); - buttonsBox.getStyleClass().add("buttons-box"); - buttonsBox.setAlignment(Pos.CENTER_RIGHT); - buttonsBox.setSpacing(20); - okButton = new MFXButton("OK"); - okButton.setPrefWidth(50); - buttonsBox.getChildren().add(okButton); - VBox.setMargin(buttonsBox, new Insets(2, 10, 2, 0)); - - getChildren().addAll(headerNode, titleLabel, contentScroll, buttonsBox); - initialize(); - } - - //================================================================================ - // Methods - //================================================================================ - private void initialize() { - getStyleClass().add(STYLE_CLASS); - setPrefSize(360, 160); - setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); - } - - /** - * Adds the specified button the the HBox at the bottom of the VBox. - */ - public void addButton(Button button) { - this.buttonsBox.getChildren().add(button); - } - - /** - * Adds the specified button to the HBox at the bottom of the VBox at the specified index. - */ - public void addButton(int index, Button button) { - try { - this.buttonsBox.getChildren().add(index, button); - } catch (IndexOutOfBoundsException ex) { - throw new IndexOutOfBoundsException("Could not add button at index:" + index + - ", list size is:" + this.buttonsBox.getChildren().size()); - } - } - - /** - * Since this class has no references to {@code MFXNotification} because they are two distinct and separate concepts, - * the close button action must be set after instantiating a {@code MFXNotification}. - */ - public void setCloseHandler(EventHandler closeHandler) { - if (this.closeHandler != null) { - this.closeButton.removeEventHandler(MouseEvent.MOUSE_PRESSED, this.closeHandler); - } - - this.closeHandler = closeHandler; - this.closeButton.addEventHandler(MouseEvent.MOUSE_PRESSED, closeHandler); - } - - public StackPane getHeaderNode() { - return headerNode; - } - - public Label getHeaderLabel() { - return headerLabel; - } - - public Label getTitleLabel() { - return titleLabel; - } - - public MFXScrollPane getContentScroll() { - return contentScroll; - } - - public Label getContentLabel() { - return contentLabel; - } - - public MFXButton getCloseButton() { - return closeButton; - } - - public MFXButton getOkButton() { - return okButton; - } - - public HBox getButtonsBox() { - return buttonsBox; - } - - /* - * Unused code. - * Before using the scroll pane for the content label the header had an extra button, - * an expand button similar to Android's notifications, that button was set to be visible - * only if the content was truncated and on click the prefHeight was incremented by the specified value with - * a Transition, however the problem with this approach was the PositionManager system because as you can see in the following code, - * if the content was still truncated at the end of the transition the method was executed again and again until the isTruncated property - * was false. The PositionManager had two extra methods, repositionNotifications and buildRepositionAnimation with the expandValue as parameter, - * the reposition method had to be recalled every time too with the same frequency as the expandNotificationMethod but as you can see this class - * has no references to PositionManager because of course they are two distinct and separate concepts. - * - * I don't want to delete this code because I still believe it can be implemented in some way, but in the end I opted for a scroll pane - * because it was way easier. - */ - /* - public void expandNotification(double expandValue) { - final double currHeight = getPrefHeight(); - Transition expand = new Transition() { - { - setCycleDuration(Duration.millis(0.1)); - } - - @Override - protected void interpolate(double frac) { - setPrefHeight(currHeight + (expandValue * frac)); - } - }; - expand.setOnFinished(event -> { - if (isTruncated.get()) { - expandNotification(expandValue); - } - }); - expand.play(); - } - */ -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXDialog.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXDialog.java old mode 100644 new mode 100755 index 469c11bb..46fdf8d4 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXDialog.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXDialog.java @@ -20,8 +20,8 @@ package io.github.palexdev.materialfx.controls.base; import io.github.palexdev.materialfx.controls.MFXButton; import io.github.palexdev.materialfx.controls.MFXDialog; -import io.github.palexdev.materialfx.controls.enums.DialogType; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.enums.DialogType; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.effects.MFXScrimEffect; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.animation.ParallelTransition; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXListView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXListView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXNotificationPane.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXNotificationPane.java deleted file mode 100644 index 163be3fe..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXNotificationPane.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.controls.base; - -import io.github.palexdev.materialfx.MFXResourcesLoader; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; -import javafx.scene.layout.VBox; - -/** - * Base class for a material notification content pane. - *

- * Extends {@code VBox} and redefines the style class to "mfx-notification" for usage in CSS. - */ -public abstract class AbstractMFXNotificationPane extends VBox { - //================================================================================ - // Properties - //================================================================================ - protected final String STYLE_CLASS = "mfx-notification"; - protected final String STYLESHEET = MFXResourcesLoader.load("css/MFXNotification.css"); - - protected final StringProperty headerProperty = new SimpleStringProperty(""); - protected final StringProperty titleProperty = new SimpleStringProperty(""); - protected final StringProperty contentProperty = new SimpleStringProperty(""); - - //================================================================================ - // Methods - //================================================================================ - public String getHeaderProperty() { - return headerProperty.get(); - } - - public StringProperty headerPropertyProperty() { - return headerProperty; - } - - public void setHeaderProperty(String headerProperty) { - this.headerProperty.set(headerProperty); - } - - public String getTitleProperty() { - return titleProperty.get(); - } - - public StringProperty titlePropertyProperty() { - return titleProperty; - } - - public void setTitleProperty(String titleProperty) { - this.titleProperty.set(titleProperty); - } - - public String getContentProperty() { - return contentProperty.get(); - } - - public StringProperty contentPropertyProperty() { - return contentProperty; - } - - public void setContentProperty(String contentProperty) { - this.contentProperty.set(contentProperty); - } - - //================================================================================ - // Override Methods - //================================================================================ - @Override - public String getUserAgentStylesheet() { - return STYLESHEET; - } -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXToggleNode.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXToggleNode.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXTreeCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXTreeCell.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXTreeItem.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/AbstractMFXTreeItem.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/IListView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/base/IListView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckListCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckListCell.java old mode 100644 new mode 100755 index 6f4f53cc..c9b5db49 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckListCell.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckListCell.java @@ -19,11 +19,11 @@ package io.github.palexdev.materialfx.controls.cell; import io.github.palexdev.materialfx.MFXResourcesLoader; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.controls.MFXCheckListView; import io.github.palexdev.materialfx.controls.MFXCheckbox; import io.github.palexdev.materialfx.controls.cell.base.AbstractMFXListCell; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.beans.binding.Bindings; import javafx.scene.Node; @@ -90,7 +90,7 @@ public class MFXCheckListCell extends AbstractMFXListCell { */ protected void setupRippleGenerator() { rippleGenerator.setManaged(false); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> PositionBean.of(event.getX(), event.getY())); rippleGenerator.rippleRadiusProperty().bind(widthProperty().divide(2.0)); addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { if (NodeUtils.inHierarchy(event, checkbox)) { diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckTreeCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXCheckTreeCell.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXDateCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXDateCell.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXListCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXListCell.java old mode 100644 new mode 100755 index 00b86de3..854a2ae5 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXListCell.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXListCell.java @@ -22,7 +22,7 @@ import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.controls.MFXListView; import io.github.palexdev.materialfx.controls.cell.base.AbstractMFXListCell; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import javafx.scene.Node; import javafx.scene.control.Label; import javafx.scene.input.MouseButton; @@ -83,7 +83,7 @@ public class MFXListCell extends AbstractMFXListCell { */ protected void setupRippleGenerator() { rippleGenerator.setManaged(false); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> PositionBean.of(event.getX(), event.getY())); rippleGenerator.rippleRadiusProperty().bind(widthProperty().divide(2.0)); addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { if (event.getButton() == MouseButton.PRIMARY) { diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXNotificationCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXNotificationCell.java new file mode 100755 index 00000000..36fd2227 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXNotificationCell.java @@ -0,0 +1,224 @@ +package io.github.palexdev.materialfx.controls.cell; + +import io.github.palexdev.materialfx.controls.MFXCheckbox; +import io.github.palexdev.materialfx.controls.MFXNotificationCenter; +import io.github.palexdev.materialfx.effects.Interpolators; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; +import io.github.palexdev.materialfx.utils.AnimationUtils.ParallelBuilder; +import io.github.palexdev.virtualizedfx.cell.Cell; +import javafx.beans.binding.Bindings; +import javafx.beans.property.*; +import javafx.css.PseudoClass; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import javafx.scene.shape.Rectangle; + +/** + * Implementation of a {@link Cell} for usage with {@link MFXNotificationCenter}. + *

+ * Includes a checkbox to allow selecting notifications. + */ +public class MFXNotificationCell extends HBox implements Cell { + //================================================================================ + // Properties + //================================================================================ + private final String STYLE_CLASS = "mfx-notification-cell"; + private final MFXNotificationCenter notificationCenter; + private final ReadOnlyObjectWrapper notification = new ReadOnlyObjectWrapper<>(); + private final ReadOnlyIntegerWrapper index = new ReadOnlyIntegerWrapper(); + private final ReadOnlyBooleanWrapper selected = new ReadOnlyBooleanWrapper(); + + protected final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected"); + protected final StackPane container; + protected final MFXCheckbox checkbox; + + //================================================================================ + // Constructors + //================================================================================ + public MFXNotificationCell(MFXNotificationCenter notificationCenter, INotification notification) { + this.notificationCenter = notificationCenter; + setNotification(notification); + + setPrefHeight(65); + setMaxHeight(USE_PREF_SIZE); + setAlignment(Pos.CENTER_LEFT); + + checkbox = new MFXCheckbox(""); + checkbox.setId("check"); + checkbox.setMarkType("mfx-variant7-mark"); + + container = new StackPane(checkbox); + container.setMinWidth(USE_PREF_SIZE); + container.setPrefWidth(0); + container.setMaxWidth(USE_PREF_SIZE); + + Rectangle clip = new Rectangle(); + clip.widthProperty().bind(container.widthProperty()); + clip.heightProperty().bind(container.heightProperty()); + container.setClip(clip); + + initialize(); + } + + //================================================================================ + // Methods + //================================================================================ + + /** + * Adds the style class, calls {@link #setBehavior()} then {@link #render(INotification)} + * for the first time. + */ + private void initialize() { + getStyleClass().add(STYLE_CLASS); + setBehavior(); + render(getNotification()); + } + + /** + * Sets the following behaviors: + *

+ * - Binds the selected property to the notification center' selection model (checks for index).

+ * - Updates the selected PseudoClass state when selected property changes.

+ * - Adds a listener to the checkbox' selection state to call {@link #updateSelection(boolean)}.

+ * - Adds a listener to the notification center's {@link MFXNotificationCenter#selectionModeProperty()} to call {@link #expand(boolean)}. + */ + protected void setBehavior() { + selected.addListener(invalidated -> pseudoClassStateChanged(SELECTED_PSEUDO_CLASS, selected.get())); + selected.bind(Bindings.createBooleanBinding(() -> { + boolean contained = notificationCenter.getSelectionModel().getSelection().containsKey(getIndex()); + checkbox.setSelected(contained); + return contained; + }, notificationCenter.getSelectionModel().selectionProperty(), index)); + + checkbox.selectedProperty().addListener((observable, oldValue, newValue) -> updateSelection(newValue)); + notificationCenter.selectionModeProperty().addListener((observable, oldValue, newValue) -> expand(newValue)); + } + + /** + * Responsible for rendering the cell's content. + */ + protected void render(INotification notification) { + if (notificationCenter.isSelectionMode()) { + checkbox.setOpacity(1.0); + checkbox.setPrefWidth(45); + } + getChildren().setAll(container, notification.getContent()); + } + + /** + * Responsible for updating the selection state according to the checkbox' state. + *

+ * If checked is true then the cell should be selected, otherwise it is deselected. + */ + protected void updateSelection(boolean checked) { + int index = getIndex(); + if (checked) { + notificationCenter.getSelectionModel().selectIndex(index); + } else { + notificationCenter.getSelectionModel().deselectIndex(index); + } + } + + /** + * Responsible for showing/hiding the checkbox. + */ + protected void expand(boolean selectionMode) { + double width = selectionMode ? 45 : 0; + double opacity = selectionMode ? 1 : 0; + if (notificationCenter.isAnimated()) { + ParallelBuilder.build() + .add( + KeyFrames.of(150, checkbox.opacityProperty(), opacity, Interpolators.EASE_OUT), + KeyFrames.of(250, container.prefWidthProperty(), width, Interpolators.EASE_OUT_SINE) + ).getAnimation().play(); + } else { + container.setPrefWidth(width); + checkbox.setOpacity(opacity); + } + if (!selectionMode) { + notificationCenter.getSelectionModel().clearSelection(); + } + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + @Override + public Node getNode() { + return this; + } + + /** + * Updates the notification property of the cell, then calls {@link #render(INotification)}. + *

+ * This is called after {@link #updateIndex(int)}. + */ + @Override + public void updateItem(INotification notification) { + setNotification(notification); + render(notification); + } + + /** + * Updates the index property of the cell. + *

+ * This is called before {@link #updateItem(INotification)}. + */ + @Override + public void updateIndex(int index) { + setIndex(index); + } + + //================================================================================ + // Getters/Setters + //================================================================================ + + public INotification getNotification() { + return this.notification.get(); + } + + /** + * Specifies the current shown notification (in other words the cell's content). + */ + public ReadOnlyObjectProperty notificationProperty() { + return this.notification.getReadOnlyProperty(); + } + + protected void setNotification(INotification notification) { + this.notification.set(notification); + } + + public int getIndex() { + return this.index.get(); + } + + /** + * Specifies the cell's index. + */ + protected ReadOnlyIntegerProperty indexProperty() { + return this.index.getReadOnlyProperty(); + } + + protected void setIndex(int index) { + this.index.set(index); + } + + public boolean isSelected() { + return this.selected.get(); + } + + /** + * Specifies the selection state of the cell. + */ + public ReadOnlyBooleanProperty selectedProperty() { + return this.selected.getReadOnlyProperty(); + } + + protected void setSelected(boolean selected) { + this.selected.set(selected); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXSimpleTreeCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXSimpleTreeCell.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumn.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumn.java old mode 100644 new mode 100755 index fd40cb96..24b935da --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumn.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableColumn.java @@ -21,7 +21,7 @@ package io.github.palexdev.materialfx.controls.cell; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.controls.MFXIconWrapper; import io.github.palexdev.materialfx.controls.MFXTableView; -import io.github.palexdev.materialfx.controls.enums.SortState; +import io.github.palexdev.materialfx.enums.SortState; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.skins.MFXTableColumnSkin; import io.github.palexdev.materialfx.skins.MFXTableViewSkin; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableRowCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXTableRowCell.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/base/AbstractMFXListCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/base/AbstractMFXListCell.java old mode 100644 new mode 100755 index 95ac1509..9d19894a --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/base/AbstractMFXListCell.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/base/AbstractMFXListCell.java @@ -166,7 +166,7 @@ public abstract class AbstractMFXListCell extends HBox implements Cell { } /** - * Index property of the cell. + * Specifies the cell's index. */ public ReadOnlyIntegerProperty indexProperty() { return index.getReadOnlyProperty(); @@ -181,7 +181,7 @@ public abstract class AbstractMFXListCell extends HBox implements Cell { } /** - * The selection state property of the cell. + * Specifies the selection state of the cell. */ public ReadOnlyBooleanProperty selectedProperty() { return selected.getReadOnlyProperty(); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyComboBox.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyComboBox.java old mode 100644 new mode 100755 index 5df45540..62aa0d49 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyComboBox.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyComboBox.java @@ -21,7 +21,7 @@ package io.github.palexdev.materialfx.controls.legacy; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.beans.MFXSnapshotWrapper; import io.github.palexdev.materialfx.controls.MFXComboBox; -import io.github.palexdev.materialfx.controls.enums.DialogType; +import io.github.palexdev.materialfx.enums.DialogType; import io.github.palexdev.materialfx.skins.legacy.MFXLegacyComboBoxSkin; import io.github.palexdev.materialfx.utils.NodeUtils; import io.github.palexdev.materialfx.validation.MFXDialogValidator; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListCell.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListCell.java old mode 100644 new mode 100755 index 7458744f..c92f97f2 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListCell.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListCell.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.controls.legacy; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.css.*; import javafx.geometry.Insets; @@ -127,7 +127,7 @@ public class MFXLegacyListCell extends ListCell { protected void setupRippleGenerator() { rippleGenerator.setRippleColor(Color.rgb(50, 150, 255)); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> PositionBean.of(event.getX(), event.getY())); addEventFilter(MouseEvent.MOUSE_PRESSED, rippleGenerator::generateRipple); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyListView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableRow.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableRow.java old mode 100644 new mode 100755 index f14792c4..d1df17ea --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableRow.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableRow.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.controls.legacy; import io.github.palexdev.materialfx.MFXResourcesLoader; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.css.*; import javafx.geometry.Insets; @@ -68,7 +68,7 @@ public class MFXLegacyTableRow extends TableRow { private void setupRippleGenerator() { rippleGenerator.setRippleColor(Color.rgb(50, 150, 255)); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> PositionBean.of(event.getX(), event.getY())); addEventFilter(MouseEvent.MOUSE_PRESSED, rippleGenerator::generateRipple); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableView.java b/materialfx/src/main/java/io/github/palexdev/materialfx/controls/legacy/MFXLegacyTableView.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ConsumerTransition.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ConsumerTransition.java new file mode 100755 index 00000000..16e3bb40 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ConsumerTransition.java @@ -0,0 +1,138 @@ +package io.github.palexdev.materialfx.effects; + +import javafx.animation.Interpolator; +import javafx.animation.Transition; +import javafx.util.Duration; + +import java.util.function.Consumer; + +/** + * A simple implementation of {@link Transition} that allows to specify + * what to do when the {@link #interpolate(double)} method is called by using + * a {@link Consumer}. + */ +public class ConsumerTransition extends Transition { + //================================================================================ + // Properties + //================================================================================ + private Consumer interpolateConsumer; + + //================================================================================ + // Methods + //================================================================================ + + /** + * Sets the transition duration. + */ + public ConsumerTransition setDuration(Duration duration) { + this.setCycleDuration(duration); + return this; + } + + /** + * Sets the transition duration in milliseconds. + */ + public ConsumerTransition setDuration(double millis) { + this.setCycleDuration(Duration.millis(millis)); + return this; + } + + /** + * Sets the consumer used by the {@link #interpolate(double)} method. + */ + public ConsumerTransition setInterpolateConsumer(Consumer interpolateConsumer) { + this.interpolateConsumer = interpolateConsumer; + return this; + } + + /** + * Sets the transition's interpolator. + */ + public ConsumerTransition setInterpolatorFluent(Interpolator interpolator) { + this.setInterpolator(interpolator); + return this; + } + + /** + * Sets the transition's delay. + */ + public ConsumerTransition setDelayFluent(Duration duration) { + this.setDelay(duration); + return this; + } + + /** + * Calls {@link #setInterpolateConsumer(Consumer)} and then starts the animation. + */ + public void playWithConsumer(Consumer interpolateConsumer) { + setInterpolateConsumer(interpolateConsumer); + this.play(); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + /** + * {@inheritDoc} + *

+ * Implementation to make use of a {@link Consumer}. + */ + @Override + protected void interpolate(double frac) { + this.interpolateConsumer.accept(frac); + } + + //================================================================================ + // Static Methods + //================================================================================ + + /** + * Creates a new {@code ConsumerTransition} with the given consumer. + */ + public static ConsumerTransition of(Consumer interpolateConsumer) { + return (new ConsumerTransition()).setInterpolateConsumer(interpolateConsumer); + } + + /** + * Creates a new {@code ConsumerTransition} with the given consumer and duration. + */ + public static ConsumerTransition of(Consumer interpolateConsumer, Duration duration) { + return (new ConsumerTransition()).setInterpolateConsumer(interpolateConsumer).setDuration(duration); + } + + /** + * Creates a new {@code ConsumerTransition} with the given consumer and duration in milliseconds. + */ + public static ConsumerTransition of(Consumer interpolateConsumer, double duration) { + return (new ConsumerTransition()).setInterpolateConsumer(interpolateConsumer).setDuration(duration); + } + + /** + * Creates a new {@code ConsumerTransition} with the given consumer, duration and interpolator. + */ + public static ConsumerTransition of(Consumer interpolateConsumer, Duration duration, Interpolator interpolator) { + return (new ConsumerTransition()).setInterpolateConsumer(interpolateConsumer).setDuration(duration).setInterpolatorFluent(interpolator); + } + + /** + * Creates a new {@code ConsumerTransition} with the given consumer, duration in milliseconds and interpolator. + */ + public static ConsumerTransition of(Consumer interpolateConsumer, double duration, Interpolator interpolator) { + return (new ConsumerTransition()).setInterpolateConsumer(interpolateConsumer).setDuration(duration).setInterpolatorFluent(interpolator); + } + + /** + * Creates a new {@code ConsumerTransition} with the given consumer, duration and interpolator. + */ + public static ConsumerTransition of(Consumer interpolateConsumer, Duration duration, Interpolators interpolator) { + return (new ConsumerTransition()).setInterpolateConsumer(interpolateConsumer).setDuration(duration).setInterpolatorFluent(interpolator.toInterpolator()); + } + + /** + * Creates a new {@code ConsumerTransition} with the given consumer, duration in milliseconds and interpolator. + */ + public static ConsumerTransition of(Consumer interpolateConsumer, double duration, Interpolators interpolator) { + return (new ConsumerTransition()).setInterpolateConsumer(interpolateConsumer).setDuration(duration).setInterpolatorFluent(interpolator.toInterpolator()); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/DepthLevel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/DepthLevel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/Interpolators.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/Interpolators.java new file mode 100755 index 00000000..9c66a948 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/Interpolators.java @@ -0,0 +1,101 @@ +package io.github.palexdev.materialfx.effects; + +import javafx.animation.Interpolator; + +import java.util.function.Function; + +/** + * Enumerator that offers some new {@link Interpolator}s for JavaFX's animations. + */ +public enum Interpolators { + INTERPOLATOR_V1(null) { + public Interpolator toInterpolator() { + return Interpolator.SPLINE(0.25D, 0.1D, 0.25D, 1.0D); + } + }, + INTERPOLATOR_V2(null) { + public Interpolator toInterpolator() { + return Interpolator.SPLINE(0.0825D, 0.3025D, 0.0875D, 0.9975D); + } + }, + LINEAR((t) -> t) { + public Interpolator toInterpolator() { + return new Interpolator() { + protected double curve(double t) { + return getCurve().apply(t); + } + }; + } + }, + EASE_IN((t) -> t * t * t) { + public Interpolator toInterpolator() { + return new Interpolator() { + protected double curve(double t) { + return getCurve().apply(t); + } + }; + } + }, + EASE_IN_SINE((t) -> 1.0D - Math.cos(t * 3.141592653589793D / 2.0D)) { + public Interpolator toInterpolator() { + return new Interpolator() { + protected double curve(double t) { + return getCurve().apply(t); + } + }; + } + }, + EASE_OUT((t) -> 1.0D - (1.0D - t) * (1.0D - t) * (1.0D - t)) { + public Interpolator toInterpolator() { + return new Interpolator() { + protected double curve(double t) { + return getCurve().apply(t); + } + }; + } + }, + EASE_OUT_SINE((t) -> { + return Math.sin(t * 3.141592653589793D / 2.0D); + }) { + public Interpolator toInterpolator() { + return new Interpolator() { + protected double curve(double t) { + return getCurve().apply(t); + } + }; + } + }, + EASE_IN_OUT((t) -> t < 0.5D ? 4.0D * t * t * t : 1.0D - Math.pow(-2.0D * t + 2.0D, 3.0D) / 2.0D) { + public Interpolator toInterpolator() { + return new Interpolator() { + protected double curve(double t) { + return getCurve().apply(t); + } + }; + } + }, + EASE_IN_OUT_SINE((t) -> -(Math.cos(3.141592653589793D * t) - 1.0D) / 2.0D) { + public Interpolator toInterpolator() { + return new Interpolator() { + protected double curve(double t) { + return getCurve().apply(t); + } + }; + } + }; + + private final Function curve; + + Interpolators(Function curve) { + this.curve = curve; + } + + /** + * Converts a Function to a JavaFX's {@link Interpolator}. + */ + public abstract Interpolator toInterpolator(); + + public Function getCurve() { + return this.curve; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/MFXDepthManager.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/MFXDepthManager.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/MFXScrimEffect.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/MFXScrimEffect.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/MFXCircleRippleGenerator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/MFXCircleRippleGenerator.java old mode 100644 new mode 100755 index 2bca45f9..09ce45d2 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/MFXCircleRippleGenerator.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/MFXCircleRippleGenerator.java @@ -18,8 +18,9 @@ package io.github.palexdev.materialfx.effects.ripple; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.beans.PositionBean; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; import io.github.palexdev.materialfx.effects.DepthLevel; import io.github.palexdev.materialfx.effects.MFXDepthManager; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator.CircleRipple; @@ -123,12 +124,12 @@ public class MFXCircleRippleGenerator extends AbstractMFXRippleGenerator new RipplePosition()); + setRipplePositionFunction(event -> new PositionBean()); } @Override - public Function getRipplePositionFunction() { + public Function getRipplePositionFunction() { return positionFunction; } @Override - public void setRipplePositionFunction(Function positionFunction) { + public void setRipplePositionFunction(Function positionFunction) { super.positionFunction = positionFunction; } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleClipType.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleClipType.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleGenerator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleGenerator.java old mode 100644 new mode 100755 index 760191f0..63986eaa --- a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleGenerator.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RippleGenerator.java @@ -18,8 +18,8 @@ package io.github.palexdev.materialfx.effects.ripple; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; import io.github.palexdev.materialfx.effects.DepthLevel; import javafx.animation.*; import javafx.beans.property.ObjectProperty; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RipplePosition.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RipplePosition.java deleted file mode 100644 index 4b1e8512..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/RipplePosition.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.effects.ripple; - -import io.github.palexdev.materialfx.effects.ripple.base.IRippleGenerator; -import io.github.palexdev.materialfx.skins.MFXToggleButtonSkin; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.SimpleDoubleProperty; - -import java.util.function.Function; - -/** - * Simple bean to wrap the coordinates of generated ripples. - *

- * This is used by the ripple generator's position function as the return type, - * {@link IRippleGenerator#setRipplePositionFunction(Function)}. - *

- * Note that both the positions are JavaFX properties, this allows to change the ripple position during - * its animation, an example can be seen in the {@link MFXToggleButtonSkin} - *

- * In {@link MFXCircleRippleGenerator} the ripple center properties are already bound to these values. - */ -public class RipplePosition { - private final DoubleProperty xPosition = new SimpleDoubleProperty(0); - private final DoubleProperty yPosition = new SimpleDoubleProperty(0); - - public RipplePosition() { - } - - public RipplePosition(double xPosition, double yPosition) { - setXPosition(xPosition); - setYPosition(yPosition); - } - - public double getXPosition() { - return xPosition.get(); - } - - public DoubleProperty xPositionProperty() { - return xPosition; - } - - public void setXPosition(double xPosition) { - this.xPosition.set(xPosition); - } - - public double getYPosition() { - return yPosition.get(); - } - - public DoubleProperty yPositionProperty() { - return yPosition; - } - - public void setYPosition(double yPosition) { - this.yPosition.set(yPosition); - } -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/AbstractMFXRippleGenerator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/AbstractMFXRippleGenerator.java old mode 100644 new mode 100755 index f9056f7a..1721efa6 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/AbstractMFXRippleGenerator.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/AbstractMFXRippleGenerator.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.effects.ripple.base; import io.github.palexdev.materialfx.collections.ObservableStack; import io.github.palexdev.materialfx.effects.DepthLevel; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.skins.MFXCheckboxSkin; import javafx.animation.Animation; import javafx.beans.property.*; @@ -60,7 +60,7 @@ public abstract class AbstractMFXRippleGenerator extends Regi protected final Region region; protected Supplier clipSupplier; protected Supplier rippleSupplier; - protected Function positionFunction; + protected Function positionFunction; protected final BooleanProperty animateBackground = new SimpleBooleanProperty(true); protected final BooleanProperty animateShadow = new SimpleBooleanProperty(false); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRipple.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRipple.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRippleGenerator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRippleGenerator.java old mode 100644 new mode 100755 index 60f94b36..f456d129 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRippleGenerator.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/effects/ripple/base/IRippleGenerator.java @@ -18,8 +18,8 @@ package io.github.palexdev.materialfx.effects.ripple.base; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.beans.PositionBean; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Region; import javafx.scene.shape.Shape; @@ -68,7 +68,7 @@ public interface IRippleGenerator { /** * @return the current generator's position function */ - Function getRipplePositionFunction(); + Function getRipplePositionFunction(); /** * Sets the generator's ripple position function to the specified one. @@ -76,9 +76,9 @@ public interface IRippleGenerator { * This {@link Function} is responsible for computing the ripple's x and y * coordinates before the animation is played. The function takes a MouseEvent as the input * (since in most controls the coordinates are the x and y coordinates of the mouse event) - * and returns a {@link RipplePosition} bean. + * and returns a {@link PositionBean} bean. */ - void setRipplePositionFunction(Function positionFunction); + void setRipplePositionFunction(Function positionFunction); /** * Every ripple generator should have a default ripple supplier. diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/ButtonType.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/ButtonType.java old mode 100644 new mode 100755 similarity index 93% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/ButtonType.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/ButtonType.java index c6ed9e7b..ceef7e5a --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/ButtonType.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/ButtonType.java @@ -16,7 +16,7 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; public enum ButtonType { FLAT, diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/enums/ChainMode.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/ChainMode.java new file mode 100755 index 00000000..6a103090 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/ChainMode.java @@ -0,0 +1,22 @@ +package io.github.palexdev.materialfx.enums; + +/** + * Enumeration to specify how two predicates should be chained. + * Also specify how a ChainMode enumeration should be represented in UI. + */ +public enum ChainMode { + AND("&"), + OR("or"); + + public static boolean useAlternativeAnd = false; + private final String text; + + ChainMode(String text) { + this.text = text; + } + + public String text() { + return this == AND && useAlternativeAnd ? "and" : this.text; + } + +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/DialogType.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/DialogType.java old mode 100644 new mode 100755 similarity index 94% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/DialogType.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/DialogType.java index 420152ab..5a859f06 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/DialogType.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/DialogType.java @@ -16,7 +16,7 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; public enum DialogType { ERROR, diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/LoaderCacheLevel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/LoaderCacheLevel.java old mode 100644 new mode 100755 similarity index 97% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/LoaderCacheLevel.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/LoaderCacheLevel.java index 77afd229..bbd00ad4 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/LoaderCacheLevel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/LoaderCacheLevel.java @@ -16,7 +16,7 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; import io.github.palexdev.materialfx.controls.MFXHLoader; import io.github.palexdev.materialfx.controls.MFXVLoader; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationCounterStyle.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationCounterStyle.java new file mode 100755 index 00000000..abf0a3be --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationCounterStyle.java @@ -0,0 +1,10 @@ +package io.github.palexdev.materialfx.enums; + +import io.github.palexdev.materialfx.controls.MFXNotificationCenter; + +/** + * Enumeration to specify the style of a {@link MFXNotificationCenter}'s counter. + */ +public enum NotificationCounterStyle { + DOT, NUMBER +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationPos.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationPos.java new file mode 100755 index 00000000..5ccae29b --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationPos.java @@ -0,0 +1,30 @@ +package io.github.palexdev.materialfx.enums; + +import io.github.palexdev.materialfx.notifications.MFXNotificationCenterSystem; +import io.github.palexdev.materialfx.notifications.MFXNotificationSystem; + +/** + * Enumeration to specify where a notification has to be shown. + *

+ * Used by {@link MFXNotificationCenterSystem} and {@link MFXNotificationSystem}. + */ +public enum NotificationPos { + TOP_CENTER, + TOP_LEFT, + TOP_RIGHT, + BOTTOM_CENTER, + BOTTOM_LEFT, + BOTTOM_RIGHT; + + public boolean isTop() { + return this == TOP_LEFT || this == TOP_CENTER || this == TOP_RIGHT; + } + + public boolean isCenter() { + return this == TOP_CENTER || this == BOTTOM_CENTER; + } + + public boolean isRight() { + return this == TOP_RIGHT || this == BOTTOM_RIGHT; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationState.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationState.java new file mode 100755 index 00000000..f2c749ac --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/NotificationState.java @@ -0,0 +1,8 @@ +package io.github.palexdev.materialfx.enums; + +/** + * Enumeration to represent the read state of a notification. + */ +public enum NotificationState { + READ, UNREAD; +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/SliderEnums.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/SliderEnums.java old mode 100644 new mode 100755 similarity index 72% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/SliderEnums.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/SliderEnums.java index 2f2e9102..a5f83780 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/SliderEnums.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/SliderEnums.java @@ -16,16 +16,27 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; +import io.github.palexdev.materialfx.controls.MFXSlider; + +/** + * Class that contains some enumerators to be used with {@link MFXSlider}. + */ public class SliderEnums { private SliderEnums() {} + /** + * Enumeration to specify the snap behavior of {@link MFXSlider}. + */ public enum SliderMode { DEFAULT, SNAP_TO_TICKS } + /** + * Enumeration to specify on which side to show the {@link MFXSlider}'s popup. + */ public enum SliderPopupSide { DEFAULT, OTHER_SIDE } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/SortState.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/SortState.java old mode 100644 new mode 100755 similarity index 92% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/SortState.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/SortState.java index 1b05d8a0..3d57eddc --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/SortState.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/SortState.java @@ -16,8 +16,11 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; +/** + * Enumerations to represent sorting. + */ public enum SortState { ASCENDING, DESCENDING, diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/StepperToggleState.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/StepperToggleState.java old mode 100644 new mode 100755 similarity index 88% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/StepperToggleState.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/StepperToggleState.java index 72b540a4..39f1b4a3 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/StepperToggleState.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/StepperToggleState.java @@ -16,12 +16,12 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; import io.github.palexdev.materialfx.controls.MFXStepperToggle; /** - * Enumerator to represent the state of a {@link MFXStepperToggle} + * Enumerator to represent the states of a {@link MFXStepperToggle} */ public enum StepperToggleState { SELECTED, diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/Styles.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/Styles.java old mode 100644 new mode 100755 similarity index 97% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/Styles.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/Styles.java index 279d095a..0faedc7e --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/Styles.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/Styles.java @@ -16,7 +16,7 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; /** * This class contains various enumerators used in MaterialFX controls which diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/TextPosition.java b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/TextPosition.java old mode 100644 new mode 100755 similarity index 93% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/TextPosition.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/enums/TextPosition.java index 94360945..61c9c005 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/enums/TextPosition.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/enums/TextPosition.java @@ -16,7 +16,7 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.enums; +package io.github.palexdev.materialfx.enums; public enum TextPosition { TOP, diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/factories/InsetsFactory.java b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/InsetsFactory.java new file mode 100755 index 00000000..ce129059 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/InsetsFactory.java @@ -0,0 +1,53 @@ +package io.github.palexdev.materialfx.factories; + +import javafx.geometry.Insets; + +/** + * Convenience class to build {@link Insets} objects. + */ +public class InsetsFactory { + + //================================================================================ + // Constructors + //================================================================================ + private InsetsFactory() {} + + //================================================================================ + // Static Methods + //================================================================================ + public static Insets all(double topRightBottomLeft) { + return new Insets(topRightBottomLeft); + } + + public static Insets none() { + return Insets.EMPTY; + } + + public static Insets top(double top) { + return new Insets(top, 0, 0, 0); + } + + public static Insets right(double right) { + return new Insets(0, right, 0, 0); + } + + public static Insets bottom(double bottom) { + return new Insets(0, 0, bottom, 0); + } + + public static Insets left(double left) { + return new Insets(0, 0, 0, left); + } + + public static Insets of(double top, double right) { + return new Insets(top, right, 0, 0); + } + + public static Insets of(double top, double right, double bottom) { + return new Insets(top, right, bottom, 0); + } + + public static Insets of(double top, double right, double bottom, double left) { + return new Insets(top, right, bottom, left); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXAnimationFactory.java b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXAnimationFactory.java old mode 100644 new mode 100755 similarity index 99% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXAnimationFactory.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXAnimationFactory.java index 478d6432..2e3a6739 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXAnimationFactory.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXAnimationFactory.java @@ -16,7 +16,7 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.factories; +package io.github.palexdev.materialfx.factories; import javafx.animation.Interpolator; import javafx.animation.KeyFrame; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXDialogFactory.java b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXDialogFactory.java old mode 100644 new mode 100755 similarity index 98% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXDialogFactory.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXDialogFactory.java index 771a4e17..15f68022 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXDialogFactory.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXDialogFactory.java @@ -16,13 +16,13 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.factories; +package io.github.palexdev.materialfx.factories; import io.github.palexdev.materialfx.controls.MFXButton; import io.github.palexdev.materialfx.controls.MFXDialog; import io.github.palexdev.materialfx.controls.base.AbstractMFXDialog; -import io.github.palexdev.materialfx.controls.enums.ButtonType; -import io.github.palexdev.materialfx.controls.enums.DialogType; +import io.github.palexdev.materialfx.enums.ButtonType; +import io.github.palexdev.materialfx.enums.DialogType; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.geometry.Insets; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXStageDialogFactory.java b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXStageDialogFactory.java old mode 100644 new mode 100755 similarity index 96% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXStageDialogFactory.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXStageDialogFactory.java index 86010b4c..2fb21ae4 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/MFXStageDialogFactory.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/MFXStageDialogFactory.java @@ -16,10 +16,10 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.factories; +package io.github.palexdev.materialfx.factories; import io.github.palexdev.materialfx.controls.base.AbstractMFXDialog; -import io.github.palexdev.materialfx.controls.enums.DialogType; +import io.github.palexdev.materialfx.enums.DialogType; import javafx.scene.Scene; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/RippleClipTypeFactory.java b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/RippleClipTypeFactory.java old mode 100644 new mode 100755 similarity index 98% rename from materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/RippleClipTypeFactory.java rename to materialfx/src/main/java/io/github/palexdev/materialfx/factories/RippleClipTypeFactory.java index ef878499..048e3552 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/controls/factories/RippleClipTypeFactory.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/factories/RippleClipTypeFactory.java @@ -16,7 +16,7 @@ * along with MaterialFX. If not, see . */ -package io.github.palexdev.materialfx.controls.factories; +package io.github.palexdev.materialfx.factories; import io.github.palexdev.materialfx.effects.ripple.RippleClipType; import javafx.scene.layout.Region; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/BooleanFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/BooleanFilter.java new file mode 100755 index 00000000..448849d3 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/BooleanFilter.java @@ -0,0 +1,51 @@ +package io.github.palexdev.materialfx.filter; + +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.filter.base.AbstractFilter; +import io.github.palexdev.materialfx.utils.FXCollectors; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; +import javafx.util.converter.BooleanStringConverter; + +import java.util.Collections; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Extension of {@link AbstractFilter} for boolean fields. + *

+ * Offers the following default {@link BiPredicateBean}s: + *

- "is": checks for booleans equality + *

- "is not": checks for booleans inequality + */ +public class BooleanFilter extends AbstractFilter { + + //================================================================================ + // Constructors + //================================================================================ + public BooleanFilter(String name, Function extractor) { + this(name, extractor, new BooleanStringConverter()); + } + + public BooleanFilter(String name, Function extractor, StringConverter converter) { + super(name, extractor, converter); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected ObservableList> defaultPredicates() { + return Stream.>of( + new BiPredicateBean<>("is", Boolean::equals), + new BiPredicateBean<>("is not", (aBoolean, aBoolean2) -> !aBoolean.equals(aBoolean2)) + ).collect(FXCollectors.toList()); + } + + @SafeVarargs + @Override + protected final BooleanFilter extend(BiPredicateBean... predicateBeans) { + Collections.addAll(super.predicates, predicateBeans); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/DoubleFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/DoubleFilter.java new file mode 100755 index 00000000..a3253201 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/DoubleFilter.java @@ -0,0 +1,59 @@ +package io.github.palexdev.materialfx.filter; + +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.filter.base.NumberFilter; +import io.github.palexdev.materialfx.utils.FXCollectors; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; +import javafx.util.converter.DoubleStringConverter; + +import java.util.Collections; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Extension of {@link NumberFilter} for double fields. + *

+ * Offers the following default {@link BiPredicateBean}s: + *

- "is": checks for doubles equality + *

- "is not": checks for doubles inequality + *

- "greater than": checks if a double is greater than another double + *

- "greater or equal to": checks if a double is greater or equal to another double + *

- "lesser than": checks if a double is lesser than another double + *

- "lesser or equal to": checks if a double is lesser or equal to another double + */ +public class DoubleFilter extends NumberFilter { + + //================================================================================ + // Constructors + //================================================================================ + public DoubleFilter(String name, Function extractor) { + this(name, extractor, new DoubleStringConverter()); + } + + public DoubleFilter(String name, Function extractor, StringConverter converter) { + super(name, extractor, converter); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected ObservableList> defaultPredicates() { + return Stream.>of( + new BiPredicateBean<>("is", Double::equals), + new BiPredicateBean<>("is not", (aDouble, aDouble2) -> !aDouble.equals(aDouble2)), + new BiPredicateBean<>("greater than", (aDouble, aDouble2) -> aDouble > aDouble2), + new BiPredicateBean<>("greater or equal to", (aDouble, aDouble2) -> aDouble >= aDouble2), + new BiPredicateBean<>("lesser than", (aDouble, aDouble2) -> aDouble < aDouble2), + new BiPredicateBean<>("lesser or equal to", (aDouble, aDouble2) -> aDouble <= aDouble2) + ).collect(FXCollectors.toList()); + } + + @SafeVarargs + @Override + protected final DoubleFilter extend(BiPredicateBean... predicateBeans) { + Collections.addAll(super.predicates, predicateBeans); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/EnumFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/EnumFilter.java new file mode 100755 index 00000000..18817480 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/EnumFilter.java @@ -0,0 +1,66 @@ +package io.github.palexdev.materialfx.filter; + +import io.github.palexdev.materialfx.filter.base.AbstractFilter; +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.utils.EnumStringConverter; +import io.github.palexdev.materialfx.utils.FXCollectors; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; + +import java.util.Collections; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Extension of {@link AbstractFilter} for {@link Enum} fields. + *

+ * Offers the following default {@link BiPredicateBean}s: + *

- "is": checks for enums equality + *

- "is not": checks for enums inequality + *

+ * This filter is special because to extract the enumerations of a given E enum, it's + * needed to also pass the type to the constructor. This is necessary for the {@link EnumStringConverter}. + */ +public class EnumFilter> extends AbstractFilter { + //================================================================================ + // Properties + //================================================================================ + private final Class enumType; + + //================================================================================ + // Constructors + //================================================================================ + public EnumFilter(String name, Function extractor, Class enumType) { + this(name, extractor, enumType, new EnumStringConverter<>(enumType)); + } + + public EnumFilter(String name, Function extractor, Class enumType, StringConverter converter) { + super(name, extractor, converter); + this.enumType = enumType; + } + + //================================================================================ + // Getters + //================================================================================ + public Class getEnumType() { + return enumType; + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected ObservableList> defaultPredicates() { + return Stream.>of( + new BiPredicateBean<>("is", Enum::equals), + new BiPredicateBean<>("is not", (anEnum, anEnum2) -> !anEnum.equals(anEnum2)) + ).collect(FXCollectors.toList()); + } + + @SafeVarargs + @Override + protected final EnumFilter extend(BiPredicateBean... predicateBeans) { + Collections.addAll(super.predicates, predicateBeans); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/EvaluationMode.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/EvaluationMode.java deleted file mode 100644 index 166d8a18..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/EvaluationMode.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.filter; - -public enum EvaluationMode { - AND, OR -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/FloatFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/FloatFilter.java new file mode 100755 index 00000000..43bb95e3 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/FloatFilter.java @@ -0,0 +1,59 @@ +package io.github.palexdev.materialfx.filter; + +import io.github.palexdev.materialfx.filter.base.NumberFilter; +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.utils.FXCollectors; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; +import javafx.util.converter.FloatStringConverter; + +import java.util.Collections; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Extension of {@link NumberFilter} for float fields. + *

+ * Offers the following default {@link BiPredicateBean}s: + *

- "is": checks for floats equality + *

- "is not": checks for floats inequality + *

- "greater than": checks if a float is greater than another float + *

- "greater or equal to": checks if a float is greater or equal to another float + *

- "lesser than": checks if a float is lesser than another float + *

- "lesser or equal to": checks if a float is lesser or equal to another float + */ +public class FloatFilter extends NumberFilter { + + //================================================================================ + // Constructors + //================================================================================ + public FloatFilter(String name, Function extractor) { + this(name, extractor, new FloatStringConverter()); + } + + public FloatFilter(String name, Function extractor, StringConverter converter) { + super(name, extractor, converter); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected ObservableList> defaultPredicates() { + return Stream.>of( + new BiPredicateBean<>("is", Float::equals), + new BiPredicateBean<>("is not", (aFloat, aFloat2) -> !aFloat.equals(aFloat2)), + new BiPredicateBean<>("greater than", (aFloat, aFloat2) -> aFloat > aFloat2), + new BiPredicateBean<>("greater or equal to", (aFloat, aFloat2) -> aFloat >= aFloat2), + new BiPredicateBean<>("lesser than", (aFloat, aFloat2) -> aFloat < aFloat2), + new BiPredicateBean<>("lesser or equal to", (aFloat, aFloat2) -> aFloat <= aFloat2) + ).collect(FXCollectors.toList()); + } + + @SafeVarargs + @Override + protected final FloatFilter extend(BiPredicateBean... predicateBeans) { + Collections.addAll(super.predicates, predicateBeans); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/IFilterable.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/IFilterable.java deleted file mode 100644 index b5b8986f..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/IFilterable.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.filter; - -/** - * This interface allows filtering a {@link io.github.palexdev.materialfx.controls.MFXTableView} without - * using an object {@code toString()} method but rather using a specific method. - */ -public interface IFilterable { - String toFilterString(); -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/IntegerFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/IntegerFilter.java new file mode 100755 index 00000000..86841ec0 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/IntegerFilter.java @@ -0,0 +1,59 @@ +package io.github.palexdev.materialfx.filter; + +import io.github.palexdev.materialfx.filter.base.NumberFilter; +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.utils.FXCollectors; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; +import javafx.util.converter.IntegerStringConverter; + +import java.util.Collections; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Extension of {@link NumberFilter} for integer fields. + *

+ * Offers the following default {@link BiPredicateBean}s: + *

- "is": checks for integers equality + *

- "is not": checks for integers inequality + *

- "greater than": checks if a integer is greater than another integer + *

- "greater or equal to": checks if a integer is greater or equal to another integer + *

- "lesser than": checks if a integer is lesser than another integer + *

- "lesser or equal to": checks if a integer is lesser or equal to another integer + */ +public class IntegerFilter extends NumberFilter { + + //================================================================================ + // Constructors + //================================================================================ + public IntegerFilter(String name, Function extractor) { + this(name, extractor, new IntegerStringConverter()); + } + + public IntegerFilter(String name, Function extractor, StringConverter converter) { + super(name, extractor, converter); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected ObservableList> defaultPredicates() { + return Stream.>of( + new BiPredicateBean<>("is", Integer::equals), + new BiPredicateBean<>("is not", (anInteger, anInteger2) -> !anInteger.equals(anInteger2)), + new BiPredicateBean<>("greater than", (anInteger, anInteger2) -> anInteger > anInteger2), + new BiPredicateBean<>("greater or equal to", (anInteger, anInteger2) -> anInteger >= anInteger2), + new BiPredicateBean<>("lesser than", (anInteger, anInteger2) -> anInteger < anInteger2), + new BiPredicateBean<>("lesser or equal to", (anInteger, anInteger2) -> anInteger <= anInteger2) + ).collect(FXCollectors.toList()); + } + + @SafeVarargs + @Override + protected final IntegerFilter extend(BiPredicateBean... predicateBeans) { + Collections.addAll(super.predicates, predicateBeans); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/LongFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/LongFilter.java new file mode 100755 index 00000000..4042625f --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/LongFilter.java @@ -0,0 +1,59 @@ +package io.github.palexdev.materialfx.filter; + +import io.github.palexdev.materialfx.filter.base.NumberFilter; +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.utils.FXCollectors; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; +import javafx.util.converter.LongStringConverter; + +import java.util.Collections; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Extension of {@link NumberFilter} for long fields. + *

+ * Offers the following default {@link BiPredicateBean}s: + *

- "is": checks for longs equality + *

- "is not": checks for longs inequality + *

- "greater than": checks if a long is greater than another long + *

- "greater or equal to": checks if a long is greater or equal to another long + *

- "lesser than": checks if a long is lesser than another long + *

- "lesser or equal to": checks if a long is lesser or equal to another long + */ +public class LongFilter extends NumberFilter { + + //================================================================================ + // Constructors + //================================================================================ + public LongFilter(String name, Function extractor) { + this(name, extractor, new LongStringConverter()); + } + + public LongFilter(String name, Function extractor, StringConverter converter) { + super(name, extractor, converter); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected ObservableList> defaultPredicates() { + return Stream.>of( + new BiPredicateBean<>("is", Long::equals), + new BiPredicateBean<>("is not", (aLong, aLong2) -> !aLong.equals(aLong2)), + new BiPredicateBean<>("greater than", (aLong, aLong2) -> aLong > aLong2), + new BiPredicateBean<>("greater or equal to", (aLong, aLong2) -> aLong >= aLong2), + new BiPredicateBean<>("lesser than", (aLong, aLong2) -> aLong < aLong2), + new BiPredicateBean<>("lesser or equal to", (aLong, aLong2) -> aLong <= aLong2) + ).collect(FXCollectors.toList()); + } + + @SafeVarargs + @Override + protected final LongFilter extend(BiPredicateBean... predicateBeans) { + Collections.addAll(super.predicates, predicateBeans); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXEvaluationBox.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXEvaluationBox.java deleted file mode 100644 index 0b172361..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXEvaluationBox.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.filter; - -import io.github.palexdev.materialfx.MFXResourcesLoader; -import io.github.palexdev.materialfx.controls.MFXComboBox; -import io.github.palexdev.materialfx.controls.MFXTextField; -import io.github.palexdev.materialfx.controls.enums.Styles; -import io.github.palexdev.materialfx.font.MFXFontIcon; -import io.github.palexdev.materialfx.utils.StringUtils; -import javafx.beans.binding.Bindings; -import javafx.collections.FXCollections; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.paint.Color; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.BiPredicate; - -/** - * This little control provides a graphical way of evaluating a condition on - * a given string with a specific predicate. The computed boolean can also be chained with - * other conditions as an AND or an OR, specified by {@link EvaluationMode}. - *

- * The control is made of: - *

- An icon that should be used by the control's parent to remove it from the children list - *

- A text field that provides one of the strings to test - *

- A combo box that contains the predicate to apply - *

- * An usage example would be: - *

- * Let's say I have a string {@code s1 = AbcdE} and a string {@code s2 = "cde"} provided by the text field. - *

- * If the selected predicate is "Contains" then {@link #test(String)} will check if s1 contains s2 and will return false. - *

- * If the selected predicate is "Contains Ignore Case" then {@link #test(String)} will check if s1 contains s2 ignoring case and will return true. - * - *

- * N.B: Since "Contains Any" and "Contains All" are advanced functions the field text is cleared when one of those functions is selected - * in the combo box and a prompt text that shows a small example on how to format the string is set. - * - * @see BiPredicate - */ -public class MFXEvaluationBox extends HBox { - //================================================================================ - // Properties - //================================================================================ - private final String STYLE_CLASS = "mfx/evaluation-box"; - private final String STYLESHEET = MFXResourcesLoader.load("css/MFXEvaluationBox.css"); - - private final EvaluationMode mode; - private final Map> biPredicates = new LinkedHashMap<>(); - private final MFXFontIcon removeIcon; - private final MFXTextField inputField; - private final MFXComboBox predicatesCombo; - - //================================================================================ - // Constructor - //================================================================================ - public MFXEvaluationBox(EvaluationMode mode) { - setPrefWidth(600); - setAlignment(Pos.CENTER_LEFT); - setSpacing(20); - setPadding(new Insets(15, 10, 15, 10)); - - this.mode = mode; - - Label modeLabel = new Label(mode.name()); - modeLabel.setId("modeLabel"); - modeLabel.setPrefSize(40, 40); - modeLabel.setMaxHeight(Double.MAX_VALUE); - modeLabel.setPadding(new Insets(3)); - modeLabel.setAlignment(Pos.CENTER); - - HBox box = new HBox(5); - box.setAlignment(Pos.CENTER); - - Label predicateLabel = new Label("Evaluation Predicate:"); - predicatesCombo = new MFXComboBox<>(); - predicatesCombo.setComboStyle(Styles.ComboBoxStyles.STYLE2); - predicatesCombo.setPrefSize(180, 27); - predicatesCombo.setMaxSize(USE_PREF_SIZE, USE_PREF_SIZE); - - inputField = new MFXTextField(); - inputField.setPromptText("Input String..."); - inputField.setAnimateLines(false); - inputField.setLineColor(Color.web("#4d4d4d")); - inputField.setLineStrokeWidth(1); - inputField.setMaxWidth(Double.MAX_VALUE); - HBox.setHgrow(inputField, Priority.ALWAYS); - HBox.setMargin(inputField, new Insets(0, 10, 2, 0)); - inputField.getStylesheets().add(STYLESHEET); - - removeIcon = new MFXFontIcon("mfx-x-circle", 16, Color.web("#4D4D4D")); - removeIcon.colorProperty().bind(Bindings.createObjectBinding( - () -> removeIcon.isHover() ? Color.web("#EF6E6B") : Color.web("#4D4D4D"), - removeIcon.hoverProperty() - )); - - box.getChildren().addAll(predicateLabel, predicatesCombo); - getChildren().addAll(removeIcon, modeLabel, box, inputField); - - initialize(); - } - - //================================================================================ - // Methods - //================================================================================ - private void initialize() { - getStyleClass().add(STYLE_CLASS); - - biPredicates.put("Contains", String::contains); - biPredicates.put("Contains Ignore Case", StringUtils::containsIgnoreCase); - biPredicates.put("Contains Any", StringUtils::containsAny); - biPredicates.put("Contains All", StringUtils::containsAll); - biPredicates.put("Starts With", String::startsWith); - biPredicates.put("Start With Ignore Case", StringUtils::startsWithIgnoreCase); - biPredicates.put("Ends With", String::endsWith); - biPredicates.put("Ends With Ignore Case", StringUtils::endsWithIgnoreCase); - biPredicates.put("Equals", String::equals); - biPredicates.put("Equals Ignore Case", String::equalsIgnoreCase); - - predicatesCombo.selectedValueProperty().addListener((observable, oldValue, newValue) -> { - if (newValue.equals("Contains Any") || newValue.equals("Contains All")) { - inputField.setPromptText("Eg. \"A, B, C, DEF GHI, E, F...\""); - inputField.clear(); - } else { - inputField.setPromptText(""); - } - }); - - predicatesCombo.setItems(FXCollections.observableArrayList(biPredicates.keySet())); - predicatesCombo.getSelectionModel().selectFirst(); - } - - /** - * Applies the selected predicate (provided by the combo box) to the given - * string and the text provided by the text field. - */ - public Boolean test(String testString) { - if (getPredicate() != null) { - return biPredicates.get(getPredicate()).test(testString, inputField.getText()); - } - return false; - } - - /** - * @return the evaluation mode of this control - */ - public EvaluationMode getMode() { - return mode; - } - - /** - * @return the currently selected predicate - */ - public String getPredicate() { - return predicatesCombo.getSelectedValue(); - } - - /** - * @return the remove icon instance - */ - public MFXFontIcon getRemoveIcon() { - return removeIcon; - } - - //================================================================================ - // Override Methods - //================================================================================ - @Override - public String getUserAgentStylesheet() { - return STYLESHEET; - } -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXFilterDialog.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXFilterDialog.java old mode 100644 new mode 100755 index 036ed604..ff582d77 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXFilterDialog.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/MFXFilterDialog.java @@ -18,35 +18,14 @@ package io.github.palexdev.materialfx.filter; -import io.github.palexdev.materialfx.MFXResourcesLoader; -import io.github.palexdev.materialfx.controls.*; -import io.github.palexdev.materialfx.controls.cell.MFXListCell; -import io.github.palexdev.materialfx.controls.enums.Styles; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; -import io.github.palexdev.materialfx.effects.DepthLevel; -import io.github.palexdev.materialfx.effects.ripple.RippleClipType; -import io.github.palexdev.materialfx.font.MFXFontIcon; -import javafx.beans.binding.Bindings; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.event.Event; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.input.MouseEvent; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.StackPane; -import javafx.scene.paint.Color; - -import java.util.List; -import java.util.stream.Collectors; - +// TODO remake? /** * This dialog provides a graphical way of filtering a given list of T items based * on the conditions specified by the added evaluation boxes. * * @see MFXEvaluationBox */ +/* public class MFXFilterDialog extends MFXDialog { //================================================================================ // Properties @@ -154,9 +133,11 @@ public class MFXFilterDialog extends MFXDialog { setBehavior(); } - /** + */ +/** * Sets the buttons behavior - */ + *//* + private void setBehavior() { addEventFilter(MouseEvent.MOUSE_PRESSED, event -> requestFocus()); @@ -165,7 +146,8 @@ public class MFXFilterDialog extends MFXDialog { clear.setOnAction(event -> evaluationBoxes.clear()); } - /** + */ +/** * Filters the given list and returns an observable filtered list. *

* Calls {@link #filter(String)} on each item for filtering. @@ -173,7 +155,8 @@ public class MFXFilterDialog extends MFXDialog { * N.B: The evaluation is done by calling the item's toString method or, if the item implements {@link IFilterable}, * by calling {@link IFilterable#toFilterString()}. If the toString method is not overridden * or does not contain any useful information for filtering it won't work. - */ + *//* + public ObservableList filter(List list) { return list.stream() .filter(item -> { @@ -187,9 +170,11 @@ public class MFXFilterDialog extends MFXDialog { .collect(Collectors.toCollection(FXCollections::observableArrayList)); } - /** + */ +/** * Tests all the evaluation boxes conditions on the given string. - */ + *//* + private boolean filter(String filterString) { Boolean expression = null; for (MFXEvaluationBox box : evaluationBoxes) { @@ -210,9 +195,11 @@ public class MFXFilterDialog extends MFXDialog { return expression != null ? expression : false; } - /** + */ +/** * Adds a new {@link MFXEvaluationBox} with the specified {@link EvaluationMode} to the dialog. - */ + *//* + private void addFilterBox(EvaluationMode mode) { MFXEvaluationBox evaluationBox = new MFXEvaluationBox(mode); HBox.setHgrow(evaluationBox, Priority.ALWAYS); @@ -220,9 +207,11 @@ public class MFXFilterDialog extends MFXDialog { evaluationBoxes.add(evaluationBox); } - /** + */ +/** * @return the filter button instance - */ + *//* + public MFXButton getFilterButton() { return filterButton; } @@ -245,3 +234,4 @@ public class MFXFilterDialog extends MFXDialog { closeIcon.resizeRelocate(ciX, ciY, ciSize, ciSize); } } +*/ diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/StringFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/StringFilter.java new file mode 100755 index 00000000..40f8ebb9 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/StringFilter.java @@ -0,0 +1,81 @@ +package io.github.palexdev.materialfx.filter; + +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.filter.base.AbstractFilter; +import io.github.palexdev.materialfx.utils.FXCollectors; +import io.github.palexdev.materialfx.utils.StringUtils; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; + +import java.util.Collections; +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * Extension of {@link AbstractFilter} for String fields. + *

+ * Offers the following default {@link BiPredicateBean}s: + *

- "contains": checks if a String is contained in another String + *

- "contains ignore case": checks if a String is contained in another String, case insensitive + *

- "contains any": checks if any of the given words are contained in a String. Words are specified as a + * single String split by ", ". Like this: "A, B, C, DEF GHI, E, F" + *

- "contains all": checks if all the given words are contained in a String. Words are specified as a + * single String split by ", ". Like this: "A, B, C, DEF GHI, E, F" + *

- "ends with": checks if a String ends with another String + *

- "ends with ignore case": checks if a String ends with another String, case insensitive + *

- "starts with": checks if a String starts with another String + *

- "starts with ignore case": checks if a String starts with another String, case insensitive + *

- "equals": checks for Strings equality + *

- "equals ignore case": checks for Strings equality, case insensitive + *

- "is not equal to": checks for Strings inequality + */ +public class StringFilter extends AbstractFilter { + + //================================================================================ + // Constructors + //================================================================================ + public StringFilter(String name, Function extractor) { + this(name, extractor, new StringConverter<>() { + @Override + public String toString(String object) { + return object; + } + + @Override + public String fromString(String string) { + return string; + } + }); + } + + public StringFilter(String name, Function extractor, StringConverter converter) { + super(name, extractor, converter); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected ObservableList> defaultPredicates() { + return Stream.>of( + new BiPredicateBean<>("contains", String::contains), + new BiPredicateBean<>("contains ignore case", StringUtils::containsIgnoreCase), + new BiPredicateBean<>("contains any", StringUtils::containsAny), + new BiPredicateBean<>("contains all", StringUtils::containsAll), + new BiPredicateBean<>("ends with", String::endsWith), + new BiPredicateBean<>("ends with ignore case", StringUtils::endsWithIgnoreCase), + new BiPredicateBean<>("equals", String::equals), + new BiPredicateBean<>("equals ignore case", String::equalsIgnoreCase), + new BiPredicateBean<>("is not equal to", (aString, aString2) -> !aString.equals(aString2)), + new BiPredicateBean<>("starts with", String::startsWith), + new BiPredicateBean<>("starts with ignore case", StringUtils::startsWithIgnoreCase) + ).collect(FXCollectors.toList()); + } + + @SafeVarargs + @Override + protected final StringFilter extend(BiPredicateBean... predicateBeans) { + Collections.addAll(super.predicates, predicateBeans); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java new file mode 100755 index 00000000..1bb6b9f4 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/AbstractFilter.java @@ -0,0 +1,246 @@ +package io.github.palexdev.materialfx.filter.base; + +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.controls.MFXFilterPane; +import io.github.palexdev.materialfx.enums.ChainMode; +import io.github.palexdev.materialfx.beans.FilterBean; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.collections.ObservableList; +import javafx.util.StringConverter; + +import java.util.function.BiPredicate; +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Base class for all filters. + *

+ * A filter is a class capable of operating on a given T object type for + * a given U field of that object. + *

+ * In other words, it is capable of extracting a field U from an object T (this is the extractor function) + * and producing a {@link Predicate} given a certain input (also called query) and it's a String. + *

+ * To make the filter system flexible and yet highly specialized, every implementation must specify a + * {@link StringConverter} which is used to convert the query to an object of type U. + *

+ * At this point we have all the basic elements to describe how the {@link Predicate} is predicate is produced. + * Every implementation of this base class has some predefined {@link BiPredicate} which operate on U objects. + * The query is converted to an object of type U, and the extractor gets the U field from a T object, both U + * objects are fed to the {@link BiPredicate}. In code: + *
+ * {@code
+ *      // We have the query...
+ *      String query = ...;
+ *      U convertedQuery = converter.fromString(query);
+ *
+ *      // We can build a Predicate by doing this...
+ *      Predicate predicate = t -> biPredicate.test(extractor.apply(t), convertedQuery);
+ * }
+ * 
+ *

+ * Filters are intended to be used with UI controls, they provide an interactive way to build a {@link Predicate} + * and filter a collection with generics, however you can also use them without an UI, however some other + * aspects needs to be discussed because they are strictly related to UI usage: + *

Every filter has a name, see {@link MFXFilterPane} documentation for an example + *

{@link BiPredicate}s are wrapped in a {@link BiPredicateBean} + *

The BiPredicate to use is "selected" with an index property (ideal for comboboxes), see {@link #predicateFor(String)}. + * + * @param the type of objects to filter + * @param the objects' field on which to operate + */ +public abstract class AbstractFilter { + //================================================================================ + // Properties + //================================================================================ + private final String name; + private final Function extractor; + protected final ObservableList> predicates; + protected final IntegerProperty selectedPredicateIndex = new SimpleIntegerProperty(-1); + protected final StringConverter converter; + + //================================================================================ + // Constructors + //================================================================================ + public AbstractFilter(String name, Function extractor, StringConverter converter) { + this.name = name; + this.extractor = extractor; + this.converter = converter; + this.predicates = defaultPredicates(); + } + + //================================================================================ + // Abstract Methods + //================================================================================ + + /** + * Every implementation of {@link AbstractFilter} must define some default {@link BiPredicate}s. + */ + protected abstract ObservableList> defaultPredicates(); + + /** + * Allows to add some extra {@link BiPredicateBean}s alongside the default ones. + */ + protected abstract AbstractFilter extend(BiPredicateBean... predicateBeans); + + //================================================================================ + // Methods + //================================================================================ + + /** + * Converts a given input String to an object of type U using + * the {@link StringConverter} specified by this filter. + */ + public U getValue(String input) { + return getConverter().fromString(input); + } + + /** + * Produces a {@link Predicate} from the given input. + *

+ * First checks if a {@link BiPredicate} is selected by checking + * the selected index property, see {@link #checkIndex()}. + *

+ * Then converts the input to an object of type U by using {@link #getValue(String)}, + * and then returns a Predicate that applies the selected BiPredicate to the extracted U field of T + * and the converted U input. + *

+ * In code: + *
+     * {@code
+     *      return t -> biPredicate.test(extractor.apply(t), convertedQuery);
+     * }
+     * 
+ */ + public Predicate predicateFor(String input) { + checkIndex(); + int index = getSelectedPredicateIndex(); + U convertedInput = getValue(input); + return t -> predicates.get(index).predicate().test(extractor.apply(t), convertedInput); + } + + // TODO can be used but warn + /** + * Produces a {@link Predicate} from the given input and {@link BiPredicate}. + *

+ * First converts the input to an object of type U by using {@link #getValue(String)}, + * and then returns a Predicate that applies the given BiPredicate to the extracted U field of T + * and the converted U input. + *

+ * In code: + *
+     * {@code
+     *      return t -> biPredicate.test(extractor.apply(t), convertedQuery);
+     * }
+     * 
+ *

+ * WARN: to be honest this method should have been removed but I wanted to keep it + * since it adds some flexibility to the filter system. Note that using this method may lead + * to inconsistencies in UI controls since the given argument is not a {@link BiPredicateBean}, + * which means that it won't be added to the predicates list of this filter, and the selected predicate index + * property won't be updated. This also means that any other method that relies on that index will fail. + */ + public Predicate predicateFor(String input, BiPredicate biPredicate) { + U convertedInput = getValue(input); + return t -> biPredicate.test(extractor.apply(t), convertedInput); + } + + /** + * Converts this filter to a {@link FilterBean} from the given input. + *

+ * Checks for the selected BiPredicate, see {@link #checkIndex()}. + */ + public FilterBean toFilterBean(String input) { + checkIndex(); + int index = getSelectedPredicateIndex(); + BiPredicateBean bean = predicates.get(index); + return new FilterBean<>(input, this, bean); + } + + /** + * Converts this filter to a {@link FilterBean} from the given input and {@link ChainMode}. + *

+ * Checks for the selected BiPredicate, see {@link #checkIndex()}. + */ + public FilterBean toFilterBean(String input, ChainMode mode) { + checkIndex(); + int index = getSelectedPredicateIndex(); + BiPredicateBean bean = predicates.get(index); + return new FilterBean<>(input, this, bean, mode); + } + + /** + * Converts this filter to a {@link FilterBean} from the given input, {@link BiPredicateBean} and {@link ChainMode}. + */ + public FilterBean toFilterBean(String input, BiPredicateBean bean, ChainMode mode) { + return new FilterBean<>(input, this, bean, mode); + } + + /** + * Used in methods which rely on a selected {@link BiPredicateBean}. + * + * @throws IllegalStateException if the selected index is not valid + */ + private void checkIndex() throws IllegalStateException{ + int index = getSelectedPredicateIndex(); + if (index < 0) { + throw new IllegalStateException("No predicate selected for filter: " + name); + } + } + + //================================================================================ + // Getters/Setters + //================================================================================ + + /** + * @return the filter's name + */ + public String name() { + return name; + } + + /** + * @return the function used to extract a field of type U from an object of type T + */ + public Function getExtractor() { + return extractor; + } + + /** + * @return the list of usable {@link BiPredicate}s, each wrapped in a {@link BiPredicateBean} + */ + public ObservableList> getPredicates() { + return predicates; + } + + public int getSelectedPredicateIndex() { + return selectedPredicateIndex.get(); + } + + /** + * Used to specify the selected {@link BiPredicateBean}. + */ + public IntegerProperty selectedPredicateIndexProperty() { + return selectedPredicateIndex; + } + + public void setSelectedPredicateIndex(int selectedPredicateIndex) { + this.selectedPredicateIndex.set(selectedPredicateIndex); + } + + /** + * @return the {@link StringConverter} used to convert the input String to an object of type U + */ + public StringConverter getConverter() { + return converter; + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + public String toString() { + return name; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/NumberFilter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/NumberFilter.java new file mode 100755 index 00000000..98348003 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/filter/base/NumberFilter.java @@ -0,0 +1,18 @@ +package io.github.palexdev.materialfx.filter.base; + +import javafx.util.StringConverter; + +import java.util.function.Function; + +/** + * Extension of {@link AbstractFilter}, still abstract, limits the U parameter to {@link Number}s. + */ +public abstract class NumberFilter extends AbstractFilter { + + //================================================================================ + // Constructors + //================================================================================ + public NumberFilter(String name, Function extractor, StringConverter converter) { + super(name, extractor, converter); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/font/FontHandler.java b/materialfx/src/main/java/io/github/palexdev/materialfx/font/FontHandler.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/font/FontResources.java b/materialfx/src/main/java/io/github/palexdev/materialfx/font/FontResources.java old mode 100644 new mode 100755 index 61680d88..c4146397 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/font/FontResources.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/font/FontResources.java @@ -19,7 +19,7 @@ package io.github.palexdev.materialfx.font; /** - * Enumerator class for MaterialFX font resources. (Count: 95) + * Enumerator class for MaterialFX font resources. (Count: 101) */ public enum FontResources { ANGLE_DOWN("mfx-angle-down", '\uE900'), @@ -29,94 +29,100 @@ public enum FontResources { ARROW_BACK("mfx-arrow-back", '\uE904'), ARROW_FORWARD("mfx-arrow-forward", '\uE905'), BACK("mfx-back", '\uE906'), - CALENDAR_BLACK("mfx-calendar-black", '\uE907'), - CALENDAR_SEMI_BLACK("mfx-calendar-semi-black", '\uE908'), - CALENDAR_WHITE("mfx-calendar-white", '\uE909'), - CARET_DOWN("mfx-caret-down", '\uE90A'), - CARET_LEFT("mfx-caret-left", '\uE90B'), - CARET_RIGHT("mfx-caret-right", '\uE90C'), - CARET_UP("mfx-caret-up", '\uE90D'), - CASPIAN_MARK("mfx-caspian-mark", '\uE90E'), - CHART_PIE("mfx-chart-pie", '\uE90F'), - CHECK_CIRCLE("mfx-check-circle", '\uE910'), - CHEVRON_DOWN("mfx-chevron-down", '\uE911'), - CHEVRON_LEFT("mfx-chevron-left", '\uE912'), - CHEVRON_RIGHT("mfx-chevron-right", '\uE913'), - CHEVRON_UP("mfx-chevron-up", '\uE914'), - CIRCLE("mfx-circle", '\uE915'), - CONTENT_COPY("mfx-content-copy", '\uE916'), - CONTENT_CUT("mfx-content-cut", '\uE917'), - CONTENT_PASTE("mfx-content-paste", '\uE918'), - DASHBOARD("mfx-dashboard", '\uE919'), - DEBUG("mfx-debug", '\uE91A'), - DELETE("mfx-delete", '\uE91B'), - DELETE_ALT("mfx-delete-alt", '\uE91C'), - EXCLAMATION_CIRCLE("mfx-exclamation-circle", '\uE91D'), - EXCLAMATION_TRIANGLE("mfx-exclamation-triangle", '\uE91E'), - EXPAND("mfx-expand", '\uE91F'), - EYE("mfx-eye", '\uE920'), - EYE_SLASH("mfx-eye-slash", '\uE921'), - FILE("mfx-file", '\uE922'), - FILTER("mfx-filter", '\uE923'), - FILTER_ALT("mfx-filter-alt", '\uE924'), - FILTER_ALT_CLEAR("mfx-filter-alt-clear", '\uE925'), - FIRST_PAGE("mfx-first-page", '\uE926'), - FIT("mfx-fit", '\uE927'), - FOLDER("mfx-folder", '\uE928'), - GEAR("mfx-gear", '\uE929'), - GOOGLE("mfx-google", '\uE92A'), - GOOGLE_DRAWING("mfx-google-drawing", '\uE92B'), - GOOGLE_DRIVE("mfx-google-drive", '\uE92C'), - GOOGLE_FORMS("mfx-google-forms", '\uE92D'), - GOOGLE_FUSION_TABLES("mfx-google-fusion-tables", '\uE92E'), - GOOGLE_PRESENTATION("mfx-google-presentation", '\uE92F'), - GOOGLE_SCRIPT("mfx-google-script", '\uE930'), - GOOGLE_SITES("mfx-google-sites", '\uE931'), - HOME("mfx-home", '\uE932'), - IMAGE("mfx-image", '\uE933'), - INFO("mfx-info", '\uE934'), - INFO_CIRCLE("mfx-info-circle", '\uE935'), - LAST_PAGE("mfx-last-page", '\uE936'), - LEVEL_UP("mfx-level-up", '\uE937'), - LOCK("mfx-lock", '\uE938'), - LOCK_OPEN("mfx-lock-open", '\uE939'), - MAP("mfx-map", '\uE93A'), - MINUS("mfx-minus", '\uE93B'), - MINUS_CIRCLE("mfx-minus-circle", '\uE93C'), - MODENA_MARK("mfx-modena-mark", '\uE93D'), - MUSIC("mfx-music", '\uE93E'), - NEXT("mfx-next", '\uE93F'), - REDO("mfx-redo", '\uE940'), - RESTORE("mfx-restore", '\uE941'), - SEARCH("mfx-search", '\uE942'), - SEARCH_PLUS("mfx-search-plus", '\uE943'), - SELECT_ALL("mfx-select-all", '\uE944'), - SHORTCUT("mfx-shortcut", '\uE945'), - SLIDERS("mfx-sliders", '\uE946'), - SPREADSHEET("mfx-spreadsheet", '\uE947'), - STEP_BACKWARD("mfx-step-backward", '\uE948'), - STEP_FORWARD("mfx-step-forward", '\uE949'), - SYNC("mfx-sync", '\uE94A'), - SYNC_LIGHT("mfx-sync-light", '\uE94B'), - UNDO("mfx-undo", '\uE94C'), - USER("mfx-user", '\uE94D'), - USERS("mfx-users", '\uE94E'), - VARIANT10_MARK("mfx-variant10-mark", '\uE94F'), - VARIANT11_MARK("mfx-variant11-mark", '\uE950'), - VARIANT12_MARK("mfx-variant12-mark", '\uE951'), - VARIANT3_MARK("mfx-variant3-mark", '\uE952'), - VARIANT4_MARK("mfx-variant4-mark", '\uE953'), - VARIANT5_MARK("mfx-variant5-mark", '\uE954'), - VARIANT6_MARK("mfx-variant6-mark", '\uE955'), - VARIANT7_MARK("mfx-variant7-mark", '\uE956'), - VARIANT8_MARK("mfx-variant8-mark", '\uE957'), - VARIANT9_MARK("mfx-variant9-mark", '\uE958'), - VIDEO("mfx-video", '\uE959'), - X("mfx-x", '\uE95A'), - X_ALT("mfx-x-alt", '\uE95B'), - X_CIRCLE("mfx-x-circle", '\uE95C'), - X_CIRCLE_LIGHT("mfx-x-circle-light", '\uE95D'), - X_LIGHT("mfx-x-light", '\uE95E'), + BELL("mfx-bell", '\uE907'), + BELL_ALT("mfx-bell-alt", '\uE908'), + CALENDAR_BLACK("mfx-calendar-black", '\uE909'), + CALENDAR_SEMI_BLACK("mfx-calendar-semi-black", '\uE90A'), + CALENDAR_WHITE("mfx-calendar-white", '\uE90B'), + CARET_DOWN("mfx-caret-down", '\uE90C'), + CARET_LEFT("mfx-caret-left", '\uE90D'), + CARET_RIGHT("mfx-caret-right", '\uE90E'), + CARET_UP("mfx-caret-up", '\uE90F'), + CASPIAN_MARK("mfx-caspian-mark", '\uE910'), + CHART_PIE("mfx-chart-pie", '\uE911'), + CHECK_CIRCLE("mfx-check-circle", '\uE912'), + CHECK_CIRCLE_EMPTY("mfx-check-circle-empty", '\uE913'), + CHEVRON_DOWN("mfx-chevron-down", '\uE914'), + CHEVRON_LEFT("mfx-chevron-left", '\uE915'), + CHEVRON_RIGHT("mfx-chevron-right", '\uE916'), + CHEVRON_UP("mfx-chevron-up", '\uE917'), + CIRCLE("mfx-circle", '\uE918'), + CIRCLE_EMPTY("mfx-circle-empty", '\uE919'), + CONTENT_COPY("mfx-content-copy", '\uE91A'), + CONTENT_CUT("mfx-content-cut", '\uE91B'), + CONTENT_PASTE("mfx-content-paste", '\uE91C'), + DASHBOARD("mfx-dashboard", '\uE91D'), + DEBUG("mfx-debug", '\uE91E'), + DELETE("mfx-delete", '\uE91F'), + DELETE_ALT("mfx-delete-alt", '\uE920'), + EXCLAMATION_CIRCLE("mfx-exclamation-circle", '\uE921'), + EXCLAMATION_TRIANGLE("mfx-exclamation-triangle", '\uE922'), + EXPAND("mfx-expand", '\uE923'), + EYE("mfx-eye", '\uE924'), + EYE_SLASH("mfx-eye-slash", '\uE925'), + FILE("mfx-file", '\uE926'), + FILTER("mfx-filter", '\uE927'), + FILTER_ALT("mfx-filter-alt", '\uE928'), + FILTER_ALT_CLEAR("mfx-filter-alt-clear", '\uE929'), + FIRST_PAGE("mfx-first-page", '\uE92A'), + FIT("mfx-fit", '\uE92B'), + FOLDER("mfx-folder", '\uE92C'), + GEAR("mfx-gear", '\uE92D'), + GOOGLE("mfx-google", '\uE92E'), + GOOGLE_DRAWING("mfx-google-drawing", '\uE92F'), + GOOGLE_DRIVE("mfx-google-drive", '\uE930'), + GOOGLE_FORMS("mfx-google-forms", '\uE931'), + GOOGLE_FUSION_TABLES("mfx-google-fusion-tables", '\uE932'), + GOOGLE_PRESENTATION("mfx-google-presentation", '\uE933'), + GOOGLE_SCRIPT("mfx-google-script", '\uE934'), + GOOGLE_SITES("mfx-google-sites", '\uE935'), + HOME("mfx-home", '\uE936'), + IMAGE("mfx-image", '\uE937'), + INFO("mfx-info", '\uE938'), + INFO_CIRCLE("mfx-info-circle", '\uE939'), + LAST_PAGE("mfx-last-page", '\uE93A'), + LEVEL_UP("mfx-level-up", '\uE93B'), + LOCK("mfx-lock", '\uE93C'), + LOCK_OPEN("mfx-lock-open", '\uE93D'), + MAP("mfx-map", '\uE93E'), + MINUS("mfx-minus", '\uE93F'), + MINUS_CIRCLE("mfx-minus-circle", '\uE940'), + MODENA_MARK("mfx-modena-mark", '\uE941'), + MUSIC("mfx-music", '\uE942'), + NEXT("mfx-next", '\uE943'), + REDO("mfx-redo", '\uE944'), + RESTORE("mfx-restore", '\uE945'), + SEARCH("mfx-search", '\uE946'), + SEARCH_PLUS("mfx-search-plus", '\uE947'), + SELECT_ALL("mfx-select-all", '\uE948'), + SHORTCUT("mfx-shortcut", '\uE949'), + SLIDERS("mfx-sliders", '\uE94A'), + SPREADSHEET("mfx-spreadsheet", '\uE94B'), + STEP_BACKWARD("mfx-step-backward", '\uE94C'), + STEP_FORWARD("mfx-step-forward", '\uE94D'), + SYNC("mfx-sync", '\uE94E'), + SYNC_LIGHT("mfx-sync-light", '\uE94F'), + UNDO("mfx-undo", '\uE950'), + USER("mfx-user", '\uE951'), + USERS("mfx-users", '\uE952'), + VARIANT10_MARK("mfx-variant10-mark", '\uE953'), + VARIANT11_MARK("mfx-variant11-mark", '\uE954'), + VARIANT12_MARK("mfx-variant12-mark", '\uE955'), + VARIANT13_MARK("mfx-variant13-mark", '\uE956'), + VARIANT14_MARK("mfx-variant14-mark", '\uE957'), + VARIANT3_MARK("mfx-variant3-mark", '\uE958'), + VARIANT4_MARK("mfx-variant4-mark", '\uE959'), + VARIANT5_MARK("mfx-variant5-mark", '\uE95A'), + VARIANT6_MARK("mfx-variant6-mark", '\uE95B'), + VARIANT7_MARK("mfx-variant7-mark", '\uE95C'), + VARIANT8_MARK("mfx-variant8-mark", '\uE95D'), + VARIANT9_MARK("mfx-variant9-mark", '\uE95E'), + VIDEO("mfx-video", '\uE95F'), + X("mfx-x", '\uE960'), + X_ALT("mfx-x-alt", '\uE961'), + X_CIRCLE("mfx-x-circle", '\uE962'), + X_CIRCLE_LIGHT("mfx-x-circle-light", '\uE963'), + X_LIGHT("mfx-x-light", '\uE964') ; public static FontResources findByDescription(String description) { diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/font/MFXFontIcon.java b/materialfx/src/main/java/io/github/palexdev/materialfx/font/MFXFontIcon.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationCenterSystem.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationCenterSystem.java new file mode 100755 index 00000000..730dbbc1 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationCenterSystem.java @@ -0,0 +1,342 @@ +package io.github.palexdev.materialfx.notifications; + +import io.github.palexdev.materialfx.beans.CustomBounds; +import io.github.palexdev.materialfx.beans.PositionBean; +import io.github.palexdev.materialfx.beans.TransitionPositionBean; +import io.github.palexdev.materialfx.controls.MFXNotificationCenter; +import io.github.palexdev.materialfx.effects.ConsumerTransition; +import io.github.palexdev.materialfx.effects.Interpolators; +import io.github.palexdev.materialfx.enums.NotificationPos; +import io.github.palexdev.materialfx.notifications.base.AbstractMFXNotificationSystem; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.notifications.base.INotificationSystem; +import io.github.palexdev.materialfx.utils.AnimationUtils.ParallelBuilder; +import io.github.palexdev.materialfx.utils.AnimationUtils.PauseBuilder; +import io.github.palexdev.materialfx.utils.AnimationUtils.TimelineBuilder; +import io.github.palexdev.materialfx.utils.ExecutionUtils; +import javafx.animation.PauseTransition; +import javafx.geometry.Bounds; +import javafx.geometry.Rectangle2D; +import javafx.scene.input.MouseEvent; +import javafx.stage.Window; +import javafx.stage.WindowEvent; + +/** + * Implementation of an {@link AbstractMFXNotificationSystem} which makes use of a {@link MFXNotificationCenter} + * to show the notifications. + */ +public class MFXNotificationCenterSystem extends AbstractMFXNotificationSystem { + //================================================================================ + // Instance + //================================================================================ + private final static MFXNotificationCenterSystem instance = new MFXNotificationCenterSystem(); + + public static MFXNotificationCenterSystem instance() { + return instance; + } + + //================================================================================ + // Properties + //================================================================================ + private final MFXNotificationCenter center; + private boolean openOnNew = true; + + //================================================================================ + // Constructors + //================================================================================ + private MFXNotificationCenterSystem() { + super(); + center = new MFXNotificationCenter(); + center.setOnIconClicked(event -> { + if (!isShowing() && !center.getNotifications().isEmpty()) { + show(); + } else { + close(); + } + }); + + center.popupHoverProperty().addListener((observable, oldValue, newValue) -> { + if (newValue) { + closeAfterTransition.stop(); + } else if (closeAutomatically) { + closeAfterTransition.playFromStart(); + } + }); + center.addEventFilter(MouseEvent.MOUSE_ENTERED, event -> closeAfterTransition.stop()); + center.addEventFilter(MouseEvent.MOUSE_EXITED, event -> { + if (closeAutomatically) closeAfterTransition.playFromStart(); + }); + + popup.setContent(center); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + /** + * {@inheritDoc} + *

+ * This method must be called before the notification system can be used. + *

+ * Also calls {@link #dispose()} before initializing. + */ + @Override + public MFXNotificationCenterSystem initOwner(Window owner) { + dispose(); + super.owner = owner; + owner.addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, onClose); + center.setOpacity(0.0); + if (!dummyStage.isShowing()) dummyStage.show(); + popup.show(dummyStage); + return this; + } + + /** + * Initializes the popup's position for the specified {@link NotificationPos}. + */ + @Override + protected void init() { + PositionBean positionBean = computePosition(); + popup.setX(positionBean.getX()); + popup.setY(positionBean.getY()); + init = true; // TODO remove? + } + + /** + * If the notification system is closing, exits and {@link #scheduleReopen(INotification)} is called. + *

+ * Adds the notification to the {@link MFXNotificationCenter} then if the notification system is set + * to close automatically starts the close {@link PauseTransition}. + *

+ * If the notification center is in "Do not disturb mode" exits immediately otherwise + * shows the popup (the content is still hidden tough so it's not really open), then shown + * the bell icon and if {@link #isOpenOnNew()} is true, {@link #show()} is called. + * + * @throws IllegalStateException if the notification system has not been initialized + */ + @Override + public INotificationSystem publish(INotification notification) { + if (notification == null) return this; + + if (owner == null) { + throw new IllegalStateException("The NotificationSystem has not been initialized!"); + } else if (isClosing()) { + scheduleReopen(notification); + } else { + center.getNotifications().add(notification); + if (closeAutomatically) { + closeAfterTransition.playFromStart(); + } + + if (!isShowing() && !center.isDoNotDisturb()) { + init(); + popup.show(dummyStage); + + if (animated) { + TimelineBuilder.build().show(250, center).getAnimation().play(); + } else { + center.setOpacity(1.0); + } + if (openOnNew) { + show(); + } + } + } + return this; + } + + /** + * Sets the showing property to true, computes the popup position as a {@link TransitionPositionBean}, + * then positions the popup (animated or not), and tells the notification center to open. + */ + @Override + protected void show() { + showing.set(true); + TransitionPositionBean positionBean = computePosition(); + double x = positionBean.getX(); + double y = positionBean.getY(); + double deltaX = positionBean.deltaX(); + double deltaY = positionBean.deltaY(); + + if (animated) { + ParallelBuilder.build() + .add(ConsumerTransition.of(frac -> popup.setX(x - deltaX * frac), 250, Interpolators.INTERPOLATOR_V2)) + .add(ConsumerTransition.of(frac -> popup.setY(y - deltaY * frac), 250, Interpolators.INTERPOLATOR_V2)) + .setOnFinished(event -> center.setShowing(true)) + .getAnimation() + .play(); + } else { + popup.setX(x - deltaX); + popup.setY(y - deltaY); + center.setShowing(true); + } + } + + /** + * Sets the closing property to true, immediately closes the notification center, + * computes the popup's position as a {@link TransitionPositionBean} and then sets the popup's + * coordinates (animated or not). + * At the end always hides the popup, and resets the showing/closing properties. + */ + @Override + protected void close() { + closing.set(true); + center.setShowing(false); + + TransitionPositionBean positionBean = computePosition(); + double x = popup.getX(); + double y = popup.getY(); + double deltaX = positionBean.deltaX(); + double deltaY = positionBean.deltaY(); + + if (animated) { + ParallelBuilder.build() + .setDelay(100) + .hide(400, center) + .add(ConsumerTransition.of(frac -> popup.setX(x + deltaX * frac), 250, Interpolators.INTERPOLATOR_V2)) + .add(ConsumerTransition.of(frac -> popup.setY(y + deltaY * frac), 250, Interpolators.INTERPOLATOR_V2)) + .setOnFinished(event -> { + popup.hide(); + closing.reset(); + showing.reset(); + }) + .getAnimation().play(); + } else { + PauseBuilder.build().setDuration(30).setOnFinished((event) -> { + popup.setX(x + deltaX); + popup.setY(y + deltaY); + center.setOpacity(0); + popup.hide(); + showing.reset(); + closing.reset(); + }).getAnimation().play(); + } + } + + /** + * Adds a one-time listener to the closing property so that when it becomes + * false the notification that could not be shown will be sent to {@link #publish(INotification)} again. + */ + @Override + protected void scheduleReopen(INotification notification) { + ExecutionUtils.executeWhen( + closing, + (oldValue, newValue) -> publish(notification), + false, + (oldValue, newValue) -> !newValue, + true + ); + } + + /** + * Computes the position of the popup as a {@link TransitionPositionBean} to be used in animations too. + */ + @Override + protected TransitionPositionBean computePosition() { + double x; + double y; + double endX; + double endY; + + Rectangle2D screenBounds = screen.getVisualBounds(); + CustomBounds centerBounds = getBounds(); + double counterWidth = centerBounds.getMaxX() - centerBounds.getMinX(); + + if (position.isTop()) { + y = screenBounds.getMinY() + spacing.getTop(); + endY = y; + } else { + y = screenBounds.getMaxY() - centerBounds.getMaxY() - spacing.getBottom(); + endY = screenBounds.getMaxY() - centerBounds.getHeight() - spacing.getBottom(); + } + + if (position.isCenter()) { + x = (screenBounds.getMaxX() / 2) - (counterWidth / 2); + endX = x; + } else if (position.isRight()) { + x = screenBounds.getMaxX() - counterWidth - spacing.getRight(); + endX = screenBounds.getMaxX() - centerBounds.getMaxX() - spacing.getRight(); + } else { + x = screenBounds.getMinX() + spacing.getLeft(); + endX = centerBounds.getMinX() + spacing.getLeft(); + } + return TransitionPositionBean.of(x, y, endX, endY); + } + + @Override + public INotificationSystem dispose() { + if (super.owner != null) { + super.owner.removeEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, onClose); + super.owner = null; + } + if (dummyStage.isShowing()) { + dummyStage.close(); + } + return this; + } + + //================================================================================ + // Methods + //================================================================================ + + /** + * Computes the bounds of the notification center. + * Custom bounds are needed since we need to take into account the bell icon AND the popup. + */ + private CustomBounds getBounds() { + Bounds bounds = center.getLayoutBounds(); + double width = center.getPopupWidth(); + double height = bounds.getHeight() + center.getPopupHeight() + center.getPopupSpacing(); + double minX = (width / 2) - (bounds.getWidth() / 2); + double maxX = minX + bounds.getWidth(); + return new CustomBounds( + minX, + bounds.getMinY(), + maxX, + bounds.getMaxY(), + width, + height + ); + } + + //================================================================================ + // Getters/Setters + //================================================================================ + + /** + * Returns the instance of the notification center used by this notification system. + *

+ * WARN: do not mess around too much with it since the notification system is highly + * dependant on the notification center. For this reason I also warn you that + * this method could be deprecated and removed in the future, maybe replaced by delegates methods + * to expose only a few features. + */ + public MFXNotificationCenter getCenter() { + return center; + } + + /** + * {@inheritDoc} + *

+ * Overridden to also enable/disable the notification center's animations. + */ + @Override + public AbstractMFXNotificationSystem setAnimated(boolean animated) { + this.animated = animated; + center.setAnimated(animated); + return this; + } + + /** + * Specifies if the notification center should be opened when a new notification is sent. + */ + public boolean isOpenOnNew() { + return openOnNew; + } + + public MFXNotificationCenterSystem setOpenOnNew(boolean openOnNew) { + this.openOnNew = openOnNew; + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationSystem.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationSystem.java new file mode 100755 index 00000000..185217eb --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/MFXNotificationSystem.java @@ -0,0 +1,295 @@ +package io.github.palexdev.materialfx.notifications; + +import io.github.palexdev.materialfx.beans.CustomBounds; +import io.github.palexdev.materialfx.beans.PositionBean; +import io.github.palexdev.materialfx.beans.TransitionPositionBean; +import io.github.palexdev.materialfx.collections.CircularQueue; +import io.github.palexdev.materialfx.effects.ConsumerTransition; +import io.github.palexdev.materialfx.effects.Interpolators; +import io.github.palexdev.materialfx.enums.NotificationPos; +import io.github.palexdev.materialfx.notifications.base.AbstractMFXNotificationSystem; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.notifications.base.INotificationSystem; +import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; +import io.github.palexdev.materialfx.utils.AnimationUtils.ParallelBuilder; +import io.github.palexdev.materialfx.utils.AnimationUtils.PauseBuilder; +import io.github.palexdev.materialfx.utils.AnimationUtils.TimelineBuilder; +import io.github.palexdev.materialfx.utils.ExecutionUtils; +import javafx.animation.PauseTransition; +import javafx.geometry.Bounds; +import javafx.geometry.Rectangle2D; +import javafx.scene.Group; +import javafx.stage.Window; +import javafx.stage.WindowEvent; +import javafx.util.Duration; + +import java.util.ArrayList; +import java.util.List; + +/** + * Simple implementation of an {@link AbstractMFXNotificationSystem} which makes use of + * a {@link CircularQueue} to keep an history of the shown notifications (by default max size is 100), + * and a list to keep a reference to queued notifications that can't be shown at the moment of {@link #publish(INotification)} + * and that will be sent to {@link #scheduleReopen(INotification)} instead. + */ +public class MFXNotificationSystem extends AbstractMFXNotificationSystem { + //================================================================================ + // Instance + //================================================================================ + private static final MFXNotificationSystem instance = new MFXNotificationSystem(); + + public static MFXNotificationSystem instance() { + return instance; + } + + //================================================================================ + // Properties + //================================================================================ + private final CircularQueue notifications = new CircularQueue<>(100); + private final List queued = new ArrayList<>(); + private final Group notificationContainer; + + //================================================================================ + // Constructors + //================================================================================ + private MFXNotificationSystem() { + super(); + notificationContainer = new Group(); + notificationContainer.setOpacity(0.0); + + popup.setContent(notificationContainer); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + /** + * {@inheritDoc} + *

+ * This method must be called before the notification system can be used. + *

+ * Also calls {@link #dispose()} before initializing. + */ + @Override + public MFXNotificationSystem initOwner(Window owner) { + dispose(); + super.owner = owner; + owner.addEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, onClose); + popup.show(dummyStage); + return this; + } + + /** + * Initializes the popup's position for the specified {@link NotificationPos}. + */ + @Override + protected void init() { + PositionBean position = computePosition(); + popup.show(dummyStage, position.getX(), position.getY()); + init = true; // TODO remove? + } + + /** + * If the notification system is showing/closing, exits and {@link #scheduleReopen(INotification)} is called. + *

+ * Adds the notification to the notifications queue then if the notification system is set + * to close automatically starts the close {@link PauseTransition}. + *

+ * Shows the popup (the content is still hidden tough so it's not really open), then forces + * the notification container to compute its bounds (should not be necessary though), shown the content + * and calls {@link #show()}. + * + * @throws IllegalStateException if the notification system has not been initialized + */ + @Override + public MFXNotificationSystem publish(INotification notification) { + if (notification == null) return this; + + if (owner == null) { + throw new IllegalStateException("The NotificationSystem has not been initialized!"); + } else if (isClosing() || isShowing()) { + scheduleReopen(notification); + } else { + notifications.add(notification); + if (closeAutomatically) { + closeAfterTransition.playFromStart(); + } + + if (!isShowing()) { + init(); + popup.show(dummyStage); + + notificationContainer.getChildren().setAll(notification.getContent()); + notificationContainer.applyCss(); + notificationContainer.layout(); + + //popup.setY(screen.getBounds().getWidth()); + if (animated) { + TimelineBuilder.build().show(400, notificationContainer).getAnimation().play(); + } else { + notificationContainer.setOpacity(1.0); + } + show(); + } + } + return this; + } + + /** + * Sets the showing property to true, computes the popup position as a {@link TransitionPositionBean}, + * then positions the popup (animated or not). + */ + @Override + protected void show() { + showing.set(true); + TransitionPositionBean positionBean = computePosition(); + double x = positionBean.getX(); + double y = positionBean.getY(); + double deltaX = positionBean.deltaX(); + double deltaY = positionBean.deltaY(); + + if (animated) { + ParallelBuilder.build() + .add(ConsumerTransition.of(frac -> popup.setY(y - deltaY * frac), Duration.millis(400), Interpolators.INTERPOLATOR_V2.toInterpolator())) + .add(KeyFrames.of(1, event -> popup.setX(x - deltaX))) + .getAnimation().play(); + } else { + popup.setX(x - deltaX); + popup.setY(y - deltaY); + } + } + + /** + * Sets the closing property to true and hides the notification. + * At the end always hides the popup, and resets the showing/closing properties. + */ + @Override + protected void close() { + closing.set(true); + if (animated) { + TimelineBuilder.build() + .hide(400, notificationContainer) + .setOnFinished(event -> { + popup.hide(); + showing.reset(); + closing.reset(); + }) + .getAnimation() + .play(); + } else { + PauseBuilder.build().setDuration(30).setOnFinished(event -> { + notificationContainer.setOpacity(0); + popup.hide(); + showing.reset(); + closing.reset(); + }).getAnimation().play(); + } + } + + /** + * Adds the notification to the queued notifications list, then adds a one-time listener to the closing property + * so that when it becomes false a notification is removed from the queue and then + * sent to {@link #publish(INotification)} again. + */ + @Override + protected void scheduleReopen(INotification notification) { + queued.add(notification); + ExecutionUtils.executeWhen( + closing, + (oldValue, newValue) -> { + if (!queued.isEmpty()) { + PauseBuilder.build() + .setDuration(300) + .setOnFinished(event -> publish(queued.remove(0))) + .getAnimation().play(); + } + }, + false, + (oldValue, newValue) -> !newValue, + true + ); + } + + /** + * Computes the position of the popup as a {@link TransitionPositionBean} to be used in animations too. + */ + @Override + protected TransitionPositionBean computePosition() { + double x; + double y; + double endX; + double endY; + + Rectangle2D screenBounds = screen.getVisualBounds(); + Bounds containerBounds = notificationContainer.getLayoutBounds(); + + if (position.isTop()) { + y = -containerBounds.getMaxY() - spacing.getTop(); + endY = screenBounds.getMinY() + spacing.getTop(); + } else { + y = screenBounds.getMaxY() + spacing.getBottom(); + endY = screenBounds.getMaxY() - containerBounds.getMaxY() - spacing.getBottom(); + } + + if (position.isCenter()) { + x = (screenBounds.getMaxX() / 2) - (containerBounds.getMaxX() / 2); + endX = x; + } else if (position.isRight()) { + x = screenBounds.getMaxX() + spacing.getRight(); + endX = screenBounds.getMaxX() - containerBounds.getMaxX() - spacing.getRight(); + } else { + x = -containerBounds.getMaxX() - spacing.getLeft(); + endX = screenBounds.getMinX() + spacing.getLeft(); + } + return TransitionPositionBean.of(x, y, endX, endY); + } + + @Override + public INotificationSystem dispose() { + if (super.owner != null) { + super.owner.removeEventHandler(WindowEvent.WINDOW_CLOSE_REQUEST, onClose); + super.owner = null; + } + return this; + } + + //================================================================================ + // Methods + //================================================================================ + + /** + * Computes the bounds of the notification container. + * These bounds always have the maxY 0. + */ + private CustomBounds getBounds() { + Bounds bounds = notificationContainer.getBoundsInParent(); + return new CustomBounds( + bounds.getMinX(), + bounds.getMinY(), + bounds.getMaxX(), + 0, + bounds.getWidth(), + bounds.getHeight() + ); + } + + //================================================================================ + // Getters/Setters + //================================================================================ + + /** + * Returns the list of shown notifications. + */ + public CircularQueue history() { + return notifications; + } + + /** + * Delegate to {@link CircularQueue#setSize(int)}. + */ + public MFXNotificationSystem setHistoryLimit(int size) { + notifications.setSize(size); + return this; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationPos.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationPos.java deleted file mode 100644 index 324ff521..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationPos.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.notifications; - -public enum NotificationPos { - TOP_LEFT, TOP_CENTER, TOP_RIGHT, - BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationsManager.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationsManager.java deleted file mode 100644 index 5d589746..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/NotificationsManager.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.notifications; - -import io.github.palexdev.materialfx.collections.CircularQueue; -import io.github.palexdev.materialfx.controls.MFXNotification; -import javafx.geometry.Rectangle2D; -import javafx.stage.Screen; -import javafx.stage.Window; - -import java.util.HashMap; -import java.util.Map; - -/** - * This class is a notification system, its job is to manage the incoming notifications - * by sending them to the correct position. It also keeps track of the sent notifications - * by storing them in a {@link CircularQueue} with the default size of 20. - */ -public class NotificationsManager { - //================================================================================ - // Properties - //================================================================================ - private static final Rectangle2D screenBounds; - private static final Window window; - private static final Map notifications = new HashMap<>(); - private static final CircularQueue notificationsHistory = new CircularQueue<>(20); - - //================================================================================ - // Init - //================================================================================ - static { - screenBounds = Screen.getPrimary().getVisualBounds(); - window = getWindow(); - } - - //================================================================================ - // Methods - //================================================================================ - - /** - * Sends a {@code MFXNotification} to the designated {@code PositionManager} - * - * @param pos The notifications' position on screen - * @param notification The notification - */ - public static void send(NotificationPos pos, MFXNotification notification) { - notifications.computeIfAbsent(pos, notificationPos -> new PositionManager(screenBounds, window, notificationPos)); - notifications.get(pos).show(notification); - notificationsHistory.add(notification); - } - - /** - * Sends a {@code MFXNotification} to the designated {@code PositionManager} with the specified spacing. - * - * @param pos The notifications' position on screen - * @param notification The notification - * @param spacing The number of pixels between each shown notification and from screen's left and right borders - */ - public static void send(NotificationPos pos, MFXNotification notification, double spacing) { - notifications.computeIfAbsent(pos, notificationPos -> new PositionManager(screenBounds, window, notificationPos)); - notifications.get(pos).setSpacing(spacing).show(notification); - notificationsHistory.add(notification); - } - - /** - * Sends a {@code MFXNotification} to the designated {@code PositionManager} with the specified limit. - * - * @param pos The notifications' position on screen - * @param notification The notification - * @param limit The maximum number of notifications to show, if limit is exceeded they will be queued - */ - public static void send(NotificationPos pos, MFXNotification notification, int limit) { - notifications.computeIfAbsent(pos, notificationPos -> new PositionManager(screenBounds, window, notificationPos)); - notifications.get(pos).setLimit(limit).show(notification); - notificationsHistory.add(notification); - } - - /** - * Sends a {@code MFXNotification} to the designated {@code PositionManager} with the specified spacing and limit. - * - * @param pos The notifications' position on screen - * @param notification The notification - * @param spacing The number of pixels between each shown notification and from screen's left and right borders - * @param limit The maximum number of notifications to show, if limit is exceeded they will be queued - */ - public static void send(NotificationPos pos, MFXNotification notification, double spacing, int limit) { - notifications.computeIfAbsent(pos, notificationPos -> new PositionManager(screenBounds, window, notificationPos)); - notifications.get(pos).setSpacing(spacing).setLimit(limit).show(notification); - notificationsHistory.add(notification); - } - - public static PositionManager getPositionManager(NotificationPos pos) { - return notifications.get(pos); - } - - public CircularQueue getNotificationsHistory() { - return notificationsHistory; - } - - public static void setHistoryLimit(int size) { - notificationsHistory.setSize(size); - } - - private static Window getWindow() { - for (Window w : Window.getWindows()) { - if (w.isFocused()) { - return w; - } - } - return null; - } -} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/PositionManager.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/PositionManager.java deleted file mode 100644 index 9ddfdf7f..00000000 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/PositionManager.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2021 Parisi Alessandro - * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX). - * - * MaterialFX is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * MaterialFX is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with MaterialFX. If not, see . - */ - -package io.github.palexdev.materialfx.notifications; - -import io.github.palexdev.materialfx.controls.MFXNotification; -import javafx.animation.Interpolator; -import javafx.animation.Transition; -import javafx.application.Platform; -import javafx.concurrent.Task; -import javafx.geometry.Rectangle2D; -import javafx.stage.Window; -import javafx.util.Duration; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.*; - -/** - * Support class for the {@code NotificationManager}. - *

- * Each {@code PositionManager} is responsible for showing the incoming notifications according to its position ({@link #pos}), - * and according to its limit ({@link #limit}), which by default is 3. Each notification is distant from each other and from - * the left and right borders according to the {@link #spacing} property which by default is 15. - *

- * To simulate the behavior of a queue, a {@link ThreadPoolExecutor} and a {@link Semaphore} are used, - * each notification show is committed to a JavaFX's {@link Task} and before any other operation a permit is acquired - * from the semaphore. The semaphore has a number of permits equals to the {@link #limit} property of this class, - * when the limit is reached and there are no more permits available all other sent notifications are queued and - * waiting for a semaphore {@code release()}. The semaphore is released every time a notification is being hidden. - */ -public class PositionManager { - //================================================================================ - // Properties - //================================================================================ - private final ThreadPoolExecutor service; - private final Semaphore semaphore; - private final Rectangle2D screenBounds; - private final Window owner; - - private final List notifications = new ArrayList<>(); - private double spacing = 15; - private int limit = 3; - - private final NotificationPos pos; - private double anchorX; - private double anchorY; - - //================================================================================ - // Constructors - //================================================================================ - public PositionManager(Rectangle2D screenBounds, Window owner, NotificationPos pos) { - this.service = new ThreadPoolExecutor( - 1, - 2, - 2, - TimeUnit.SECONDS, - new LinkedBlockingDeque<>(), - runnable -> { - Thread t = Executors.defaultThreadFactory().newThread(runnable); - t.setName("MFXNotificationsThread - " + pos.name()); - t.setDaemon(true); - return t; - } - ); - this.service.allowCoreThreadTimeOut(true); - this.semaphore = new Semaphore(limit); - - this.screenBounds = screenBounds; - this.owner = owner; - this.pos = pos; - } - - //================================================================================ - // Methods - //================================================================================ - - /** - * Shows the specified notification on screen. - *

- * The show mechanism uses a {@link ThreadPoolExecutor} with JavaFX's {@code Tasks} and - * a {@link Semaphore} to make threads wait when the notifications limit is reached, - * in a sense it simulates the operation of a queue. - *

- * After the new notification has been added to the list, all others notifications are repositioned, - * then anchorX and anchorY are calculated according to the {@link #pos} property. - *

- * After that the notification's show method is called on the JavaFX's thread with the specified owner and anchors. - * On hidden the notification is removed from the list and the semaphore is released. - *

- * On failed task, logs the exception. - * - * @param newNotification The notification to show - * @see Task - */ - public void show(MFXNotification newNotification) { - Task showTask = new Task<>() { - @Override - protected Void call() throws Exception { - semaphore.acquire(); - - notifications.add(newNotification); - repositionNotifications(newNotification); - - newNotification.setOnHidden(event -> { - notifications.remove(newNotification); - semaphore.release(); - }); - computePosition(newNotification); - Platform.runLater(() -> newNotification.show(owner, anchorX, anchorY)); - - return null; - } - }; - showTask.setOnFailed(event -> { - if (showTask.getException() != null) { - showTask.getException().printStackTrace(); - } - }); - service.submit(showTask); - } - - public PositionManager setSpacing(double spacing) { - this.spacing = spacing; - return this; - } - - public PositionManager setLimit(int limit) { - this.limit = limit; - this.semaphore.release(limit); - return this; - } - - /** - * Repositions every notification in the list, except the most recent one, with a {@code Transition} animation. - */ - private void repositionNotifications(MFXNotification newNotification) { - for (int i = 0; i < notifications.indexOf(newNotification); i++) { - MFXNotification oldNotification = notifications.get(i); - buildRepositionAnimation(newNotification, oldNotification).play(); - } - } - - /** - * Builds the repositioning animation. - *

- * The new anchorY is calculated using the current value and the new notification's content prefHeight. - * Note: this works only if the notification's content has it's pref height set - * - * @param newNotification The new notification - * @param oldNotification The already showing notification - * @return The animation - */ - private Transition buildRepositionAnimation(MFXNotification newNotification, MFXNotification oldNotification) { - final double notificationHeight = newNotification.getNotificationContent().getPrefHeight(); - final double oldAnchorY = oldNotification.getAnchorY(); - - switch (pos) { - case BOTTOM_LEFT: - case BOTTOM_CENTER: - case BOTTOM_RIGHT: - return new Transition() { - { - setCycleDuration(Duration.millis(350)); - setInterpolator(Interpolator.EASE_BOTH); - } - - @Override - protected void interpolate(double frac) { - final double newAnchorY = (oldAnchorY - notificationHeight) - (spacing * frac); - oldNotification.setAnchorY(newAnchorY); - } - }; - default: - return new Transition() { - { - setCycleDuration(Duration.millis(350)); - setInterpolator(Interpolator.EASE_BOTH); - } - - @Override - protected void interpolate(double frac) { - final double newAnchorY = (oldAnchorY + notificationHeight) + (spacing * frac); - oldNotification.setAnchorY(newAnchorY); - } - }; - } - } - - /** - * Computes the notification coordinates according to the {@link #pos} property. - */ - private void computePosition(MFXNotification notification) { - switch (pos) { - case TOP_LEFT: - case TOP_CENTER: - case TOP_RIGHT: - anchorY = spacing; - break; - case BOTTOM_LEFT: - case BOTTOM_CENTER: - case BOTTOM_RIGHT: - anchorY = screenBounds.getHeight() - notification.getNotificationContent().getPrefHeight() - spacing; - break; - } - - switch (pos) { - case TOP_LEFT: - case BOTTOM_LEFT: - anchorX = spacing; - break; - case TOP_RIGHT: - case BOTTOM_RIGHT: - anchorX = screenBounds.getWidth() - notification.getNotificationContent().getPrefWidth() - spacing; - break; - default: - anchorX = (screenBounds.getWidth() / 2) - (notification.getNotificationContent().getPrefWidth() / 2); - } - } -} \ No newline at end of file diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/AbstractMFXNotificationSystem.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/AbstractMFXNotificationSystem.java new file mode 100755 index 00000000..71c150b2 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/AbstractMFXNotificationSystem.java @@ -0,0 +1,268 @@ +package io.github.palexdev.materialfx.notifications.base; + +import io.github.palexdev.materialfx.beans.TransitionPositionBean; +import io.github.palexdev.materialfx.beans.properties.resettable.ResettableBooleanProperty; +import io.github.palexdev.materialfx.controls.MFXPopup; +import io.github.palexdev.materialfx.enums.NotificationPos; +import io.github.palexdev.materialfx.factories.InsetsFactory; +import io.github.palexdev.materialfx.utils.AnimationUtils.PauseBuilder; +import io.github.palexdev.materialfx.utils.ExecutionUtils; +import javafx.animation.PauseTransition; +import javafx.event.EventHandler; +import javafx.geometry.Insets; +import javafx.stage.*; +import javafx.util.Duration; + +/** + * Base class to define a notification system. + *

+ * A notification system has the following info and features: + *

- The {@link Screen} on which to show the notification + *

- The {@link Window} on which the notification system's stage depends (more on that later) + *

- A {@link MFXPopup} which contains the notification + *

- The {@link NotificationPos} to compute the shown notifications' position + *

- Allows to specify some extra spacing between the screen's borders and the notification + *

- By default is animated but it can also be disabled + *

- By default notifications will close automatically after 3 seconds (by default) + *

+ * To fix issue #80 and similar, the notification system do not uses the focused window anymore but + * it has its own "dummy" stage. It is a UTILITY stage, so that no icon appear in the taskbar, and its opacity is 0. + * While this is a great improvement over the old design there's also a downside. + * When the JavaFX's primary stage is closed the app won't close because the "dummy" stage is still open, + * to fix this a notification system must be initialized with an owner window, so that when owner is closed + * the "dummy" stage is closed too. + *

+ * Any notification system ideally must implement the following behaviors: + *

- publish: the method that accepts and manages new notifications + *

- show: ideally called by the publish method, serves to specify how to show the new notification + *

- close: serves to specify how a notification should be closed + *

- scheduleReopen: this method specifies how the notification system behaves when + * a new notification is published but it already is in a showing/closing state. Ideally this method + * should instruct the notification system to ignore the new notification and recall publish as soon as the current + * notification is being closed. + *

- computePosition: computes the position of the notification as a {@link TransitionPositionBean} for use + * with animations too. (for non animated systems just subtract the deltas from their respective coordinates) + *

+ * Side note on the close method: it's highly recommended to also close the popup since it is not transparent + * and mouse won't work through. (may block OS windows) + *

+ * Side notes on the scheduleReopen mechanism: this base class offers two {@link ResettableBooleanProperty} to + * specify that the notification is showing/closing a notification. Show and hide methods should set these properties + * to true as the first operation, and then reset them once the notification is closed (see implementations source code for examples). + * The scheduleReopen should instruct the system to call publish as soon as the closing property becomes false. + *

+ * Last note: notification systems ideally should be singletons. + */ +public abstract class AbstractMFXNotificationSystem implements INotificationSystem { + //================================================================================ + // Properties + //================================================================================ + protected Screen screen = Screen.getPrimary(); + protected Window owner; + protected final Stage dummyStage; + protected final EventHandler onClose; + protected final MFXPopup popup; + protected NotificationPos position; + protected Insets spacing; + + protected boolean animated = true; + protected boolean closeAutomatically = true; + protected Duration closeAfter = Duration.seconds(3); + protected final PauseTransition closeAfterTransition; + + protected final ResettableBooleanProperty showing = new ResettableBooleanProperty(false, false); + protected final ResettableBooleanProperty closing = new ResettableBooleanProperty(false, false); + protected boolean init = false; + + //================================================================================ + // Constructors + //================================================================================ + protected AbstractMFXNotificationSystem() { + position = NotificationPos.BOTTOM_RIGHT; + spacing = InsetsFactory.all(15); + + dummyStage = new Stage(); + dummyStage.initStyle(StageStyle.UTILITY); + dummyStage.setOpacity(0.0); + dummyStage.show(); + onClose = event -> dummyStage.close(); + + popup = new MFXPopup(); + popup.setAnimated(false); + + closeAfterTransition = PauseBuilder.build() + .setDelay(100) + .setDuration(closeAfter) + .setOnFinished(event -> close()) + .getAnimation(); + + closing.setFireChangeOnReset(true); + } + + //================================================================================ + // Abstract Methods + //================================================================================ + + /** + * Shows a notification by manipulating the popup's coordinates and content. + */ + protected abstract void show(); + + /** + * Closes a notification by manipulating the popup's coordinates and content. + *

+ * The popup should be closed as well! + */ + protected abstract void close(); + + /** + * Instructs the notification system to shown the specified notification when possible. + */ + protected abstract void scheduleReopen(INotification notification); + + /** + * Responsible for computing the popup's coordinates. + */ + protected abstract TransitionPositionBean computePosition(); + + //================================================================================ + // Methods + //================================================================================ + + /** + * Default implementation is empty. + */ + protected void init() {} + + //================================================================================ + // Getters/Setters + //================================================================================ + + /** + * @return the screen on which to show the notifications + */ + public Screen getScreen() { + return screen; + } + + /** + * Sets the screen on which to show the notifications. + */ + public AbstractMFXNotificationSystem setScreen(Screen screen) { + this.screen = screen; + return this; + } + + /** + * @return the position at which notifications will be shown + */ + public NotificationPos getPosition() { + return position; + } + + /** + * Sets the position at which notifications will be shown. + */ + public AbstractMFXNotificationSystem setPosition(NotificationPos position) { + this.position = position; + return this; + } + + /** + * Safer version of {@link #setPosition(NotificationPos)}. If the notification system is currently showing + * it's not a good idea to change the position as the close method could then misbehave, this method + * changes the position as soon as the notification system has been closed. If it's already closed then + * the position is set immediately. + */ + public AbstractMFXNotificationSystem delaySetPosition(NotificationPos position) { + if (isShowing()) { + ExecutionUtils.executeWhen( + closing, + (oldValue, newValue) -> setPosition(position), + false, + (oldValue, newValue) -> !newValue, + true + ); + } else { + setPosition(position); + } + return this; + } + + /** + * @return the Insets object that specifies the spacing between notifications and the screen borders + */ + public Insets getSpacing() { + return spacing; + } + + /** + * Sets the Insets object that specifies the spacing between notifications and the screen borders. + */ + public AbstractMFXNotificationSystem setSpacing(Insets spacing) { + this.spacing = spacing; + return this; + } + + /** + * @return whether the notification system is animated + */ + public boolean isAnimated() { + return animated; + } + + /** + * Enables/Disables animations. + */ + public AbstractMFXNotificationSystem setAnimated(boolean animated) { + this.animated = animated; + return this; + } + + /** + * @return whether notifications should close automatically + */ + public boolean isCloseAutomatically() { + return closeAutomatically; + } + + /** + * Enables/Disables notifications automatic close. + */ + public AbstractMFXNotificationSystem setCloseAutomatically(boolean closeAutomatically) { + this.closeAutomatically = closeAutomatically; + return this; + } + + /** + * @return the duration of time after which the notifications are automatically closed + * if {@link #isCloseAutomatically()} is true + */ + public Duration getCloseAfter() { + return closeAfter; + } + + /** + * Sets the duration of time after which the notifications are automatically closed + * if {@link #isCloseAutomatically()} is true + */ + public AbstractMFXNotificationSystem setCloseAfter(Duration closeAfter) { + this.closeAfter = closeAfter; + closeAfterTransition.setDuration(closeAfter); + return this; + } + + /** + * @return whether the notification system is showing a notification + */ + public boolean isShowing() { + return showing.get(); + } + + /** + * @return whether the notification system is closing + */ + public boolean isClosing() { + return closing.get(); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotification.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotification.java new file mode 100755 index 00000000..cc017694 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotification.java @@ -0,0 +1,67 @@ +package io.github.palexdev.materialfx.notifications.base; + +import io.github.palexdev.materialfx.enums.NotificationState; +import javafx.beans.property.ObjectProperty; +import javafx.scene.layout.Region; + +import java.util.function.BiConsumer; +import java.util.function.Function; + +/** + * Interface which specifies the features of a notification rather than its content. + *

+ * Base features of a notification are: + *

- the content, specified as a generic {@link Region} + *

- the read state property, {@link NotificationState} + *

- a way to tell when the notification was created, how much time has passed since creation, + * a way to convert the time from a long value to a String, a way to tell that the elapsed time should change + * and an action to run when this happens + */ +public interface INotification { + + /** + * @return the notification's content + */ + Region getContent(); + + NotificationState getState(); + + /** + * Specifies the notification's read state. + */ + ObjectProperty notificationStateProperty(); + + void setNotificationState(NotificationState state); + + /** + * @return the created time as a long value, the number of seconds from the Java epoch + */ + long getTime(); + + /** + * @return the difference between the current number of seconds from the Java epoch and the created time + */ + long getElapsedTime(); + + /** + * @return the function used to convert a time in seconds to String + */ + Function getTimeToStringConverter(); + + /** + * Sets the function used to convert a time in seconds to String. + */ + void setTimeToStringConverter(Function converter); + + /** + * Should be called by a periodic task to inform "someone" that the elapsed time should be updated + */ + void updateElapsed(); + + /** + * This action is automatically called by {@link #updateElapsed()}, use this to inform "someone" that + * the elapsed time should be updated. The action is a {@link BiConsumer} and the inputs are the elapsed seconds + * as a long value and the elapsed seconds converted to a String by using the {@link #getTimeToStringConverter()}. + */ + void setOnUpdateElapsed(BiConsumer elapsedConsumer); +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotificationSystem.java b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotificationSystem.java new file mode 100755 index 00000000..1dcb2fd2 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/notifications/base/INotificationSystem.java @@ -0,0 +1,26 @@ +package io.github.palexdev.materialfx.notifications.base; + +import javafx.stage.Window; + +/** + * Defines the public API of every notification system. + */ +public interface INotificationSystem { + + /** + * A notification system should be initialized to honor the behavior of a owner Window. + * (for example if the owner closes that the notification system closes too) + */ + INotificationSystem initOwner(Window owner); + + /** + * Method to send a new notification to be shown, it's up to an implementation + * to decide how to manage and show it. + */ + INotificationSystem publish(INotification notification); + + /** + * Closes and disposes the notification system if not needed anymore. + */ + INotificationSystem dispose(); +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboBoxSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboBoxSelectionModel.java old mode 100644 new mode 100755 index 41b213c5..9863e93f --- a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboBoxSelectionModel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/ComboBoxSelectionModel.java @@ -18,7 +18,7 @@ package io.github.palexdev.materialfx.selection; -import javafx.beans.value.ObservableValue; +import javafx.beans.property.ObjectProperty; import javafx.collections.ObservableList; /** @@ -29,7 +29,11 @@ public class ComboBoxSelectionModel extends SingleSelectionModel { //================================================================================ // Constructors //================================================================================ - public ComboBoxSelectionModel(ObservableValue> items) { + public ComboBoxSelectionModel(ObservableList items) { + super(items); + } + + public ComboBoxSelectionModel(ObjectProperty> items) { super(items); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionManager.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionManager.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionModel.java old mode 100644 new mode 100755 index 9a2edc28..c935fc97 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionModel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/MultipleSelectionModel.java @@ -39,6 +39,10 @@ public class MultipleSelectionModel extends AbstractMultipleSelectionModel //================================================================================ // Constructors //================================================================================ + public MultipleSelectionModel(ObservableList items) { + super(items); + } + public MultipleSelectionModel(ObjectProperty> items) { super(items); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionManager.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionManager.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionModel.java old mode 100644 new mode 100755 index 1fa92c83..bc83cc75 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionModel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/SingleSelectionModel.java @@ -21,6 +21,7 @@ package io.github.palexdev.materialfx.selection; import io.github.palexdev.materialfx.selection.base.AbstractSingleSelectionModel; import io.github.palexdev.materialfx.selection.base.ISingleSelectionModel; import io.github.palexdev.materialfx.utils.others.TriConsumer; +import javafx.beans.property.ObjectProperty; import javafx.beans.property.Property; import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.ReadOnlyObjectProperty; @@ -40,7 +41,11 @@ public class SingleSelectionModel extends AbstractSingleSelectionModel { //================================================================================ // Constructors //================================================================================ - public SingleSelectionModel(ObservableValue> items) { + public SingleSelectionModel(ObservableList items) { + super(items); + } + + public SingleSelectionModel(ObjectProperty> items) { super(items); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/TableSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/TableSelectionModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeCheckModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeCheckModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/TreeSelectionModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractMultipleSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractMultipleSelectionModel.java old mode 100644 new mode 100755 index 3200642e..4176d7a7 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractMultipleSelectionModel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractMultipleSelectionModel.java @@ -44,6 +44,10 @@ public abstract class AbstractMultipleSelectionModel implements IMultipleSele //================================================================================ // Constructors //================================================================================ + protected AbstractMultipleSelectionModel(ObservableList items) { + this.items.set(items); + } + protected AbstractMultipleSelectionModel(ObservableValue> items) { this.items.bind(items); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractSingleSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractSingleSelectionModel.java old mode 100644 new mode 100755 index 361af32c..087bc0b8 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractSingleSelectionModel.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/AbstractSingleSelectionModel.java @@ -44,6 +44,10 @@ public abstract class AbstractSingleSelectionModel implements ISingleSelectio //================================================================================ // Constructors //================================================================================ + protected AbstractSingleSelectionModel(ObservableList items) { + this.items.set(items); + } + protected AbstractSingleSelectionModel(ObservableValue> items) { this.items.bind(items); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/IMultipleSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/IMultipleSelectionModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ISingleSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ISingleSelectionModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITableSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITableSelectionModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITreeCheckModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITreeCheckModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITreeSelectionModel.java b/materialfx/src/main/java/io/github/palexdev/materialfx/selection/base/ITreeSelectionModel.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXButtonSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXButtonSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckTreeItemSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckTreeItemSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckboxSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckboxSkin.java old mode 100644 new mode 100755 index 93337ee0..ea2a5fc6 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckboxSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCheckboxSkin.java @@ -21,7 +21,7 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.MFXCheckbox; import io.github.palexdev.materialfx.controls.MFXIconWrapper; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.geometry.Insets; @@ -68,9 +68,9 @@ public class MFXCheckboxSkin extends SkinBase { rippleGenerator.setCheckBounds(false); rippleGenerator.setClipSupplier(() -> null); rippleGenerator.setRipplePositionFunction(event -> { - RipplePosition position = new RipplePosition(); - position.setXPosition(Math.min(event.getX(), rippleContainer.getWidth())); - position.setYPosition(Math.min(event.getY(), rippleContainer.getHeight())); + PositionBean position = new PositionBean(); + position.setX(Math.min(event.getX(), rippleContainer.getWidth())); + position.setY(Math.min(event.getY(), rippleContainer.getHeight())); return position; }); rippleGenerator.setRippleRadius(16); @@ -144,7 +144,7 @@ public class MFXCheckboxSkin extends SkinBase { * then the center of the ripple is set to the width and/or height of container */ checkBox.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> { - if (!event, checkBox)) { + if (!NodeUtils.inHierarchy(event, checkBox)) { return; } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCircleToggleNodeSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCircleToggleNodeSkin.java old mode 100644 new mode 100755 index 6d4d35d4..797c7e81 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCircleToggleNodeSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXCircleToggleNodeSkin.java @@ -20,9 +20,9 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.MFXCircleToggleNode; import io.github.palexdev.materialfx.controls.MFXLabel; -import io.github.palexdev.materialfx.controls.enums.TextPosition; +import io.github.palexdev.materialfx.enums.TextPosition; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.utils.LabelUtils; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.beans.binding.Bindings; @@ -112,7 +112,7 @@ public class MFXCircleToggleNodeSkin extends SkinBase { )); return clip; }); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> new PositionBean(event.getX(), event.getY())); rippleGenerator.rippleRadiusProperty().bind(circle.radiusProperty().add(5)); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java old mode 100644 new mode 100755 index 60c5577a..2e987f5b --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXComboBoxSkin.java @@ -24,10 +24,10 @@ import io.github.palexdev.materialfx.controls.MFXIconWrapper; import io.github.palexdev.materialfx.controls.MFXLabel; import io.github.palexdev.materialfx.controls.MFXListView; import io.github.palexdev.materialfx.controls.cell.MFXListCell; -import io.github.palexdev.materialfx.controls.enums.Styles; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.enums.Styles; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.selection.ComboBoxSelectionModel; import io.github.palexdev.materialfx.utils.AnimationUtils; @@ -364,7 +364,7 @@ public class MFXComboBoxSkin extends SkinBase> { */ private void iconBehavior() { icon.rippleGeneratorBehavior(event -> - new RipplePosition(icon.getWidth() / 2, icon.getHeight() / 2) + new PositionBean(icon.getWidth() / 2, icon.getHeight() / 2) ); MFXCircleRippleGenerator rg = icon.getRippleGenerator(); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXContextMenuItemSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXContextMenuItemSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDateCellSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDateCellSkin.java old mode 100644 new mode 100755 index 4867ec0d..ce624947 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDateCellSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDateCellSkin.java @@ -19,10 +19,10 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.cell.MFXDateCell; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; import io.github.palexdev.materialfx.effects.ripple.RippleClipType; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import javafx.scene.control.skin.DateCellSkin; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; @@ -47,7 +47,7 @@ public class MFXDateCellSkin extends DateCellSkin { rippleGenerator = new MFXCircleRippleGenerator(dateCell); rippleGenerator.setClipSupplier(() -> new RippleClipTypeFactory(RippleClipType.ROUNDED_RECTANGLE).setArcs(15).build(dateCell)); rippleGenerator.setRippleColor(Color.rgb(220, 220, 220, 0.6)); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> new PositionBean(event.getX(), event.getY())); dateCell.addEventFilter(MouseEvent.MOUSE_PRESSED, rippleGenerator::generateRipple); updateChildren(); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDatePickerContent.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDatePickerContent.java old mode 100644 new mode 100755 index cdf9df74..d49ca1f6 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDatePickerContent.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXDatePickerContent.java @@ -26,7 +26,7 @@ import io.github.palexdev.materialfx.controls.MFXScrollPane; import io.github.palexdev.materialfx.controls.MFXTextField; import io.github.palexdev.materialfx.controls.cell.MFXDateCell; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.*; import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; @@ -489,7 +489,7 @@ public class MFXDatePickerContent extends VBox { private void buildButtons() { MFXFontIcon chevronDown = new MFXFontIcon("mfx-chevron-down", 13); yearsButton = new MFXIconWrapper(chevronDown, 20).rippleGeneratorBehavior(event -> - new RipplePosition(yearsButton.getWidth() / 2, yearsButton.getHeight() / 2) + new PositionBean(yearsButton.getWidth() / 2, yearsButton.getHeight() / 2) ); yearsButton.getStyleClass().add("years-button"); NodeUtils.makeRegionCircular(yearsButton); @@ -501,7 +501,7 @@ public class MFXDatePickerContent extends VBox { MFXFontIcon chevronLeft = new MFXFontIcon("mfx-chevron-left", 13); monthBackButton = new MFXIconWrapper(chevronLeft, 20).rippleGeneratorBehavior(event -> - new RipplePosition(monthBackButton.getWidth() / 2, monthBackButton.getHeight() / 2) + new PositionBean(monthBackButton.getWidth() / 2, monthBackButton.getHeight() / 2) ); monthBackButton.getStyleClass().add("month-back-button"); NodeUtils.makeRegionCircular(monthBackButton); @@ -509,7 +509,7 @@ public class MFXDatePickerContent extends VBox { MFXFontIcon chevronRight = new MFXFontIcon("mfx-chevron-right", 13); monthForwardButton = new MFXIconWrapper(chevronRight, 20).rippleGeneratorBehavior(event -> - new RipplePosition(monthForwardButton.getWidth() / 2, monthForwardButton.getHeight() / 2) + new PositionBean(monthForwardButton.getWidth() / 2, monthForwardButton.getHeight() / 2) ); monthForwardButton.getStyleClass().add("month-forward-button"); NodeUtils.makeRegionCircular(monthForwardButton); @@ -517,7 +517,7 @@ public class MFXDatePickerContent extends VBox { MFXFontIcon calendar = new MFXFontIcon("mfx-calendar-semi-black", 17); inputButton = new MFXIconWrapper(calendar, 35).rippleGeneratorBehavior(event -> - new RipplePosition(inputButton.getWidth() / 2, inputButton.getHeight() / 2) + new PositionBean(inputButton.getWidth() / 2, inputButton.getHeight() / 2) ); inputButton.getStyleClass().add("change-input-button"); Tooltip tooltip = new Tooltip("Switches between mouse input and keyboard input"); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterComboBoxSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterComboBoxSkin.java old mode 100644 new mode 100755 index ce48dc8d..7660e756 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterComboBoxSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterComboBoxSkin.java @@ -21,10 +21,10 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.beans.MFXSnapshotWrapper; import io.github.palexdev.materialfx.controls.*; import io.github.palexdev.materialfx.controls.cell.MFXListCell; -import io.github.palexdev.materialfx.controls.enums.Styles; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.enums.Styles; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.selection.ComboBoxSelectionModel; import io.github.palexdev.materialfx.utils.AnimationUtils; @@ -379,7 +379,7 @@ public class MFXFilterComboBoxSkin extends SkinBase> { */ private void iconBehavior() { icon.rippleGeneratorBehavior(event -> - new RipplePosition(icon.getWidth() / 2, icon.getHeight() / 2) + new PositionBean(icon.getWidth() / 2, icon.getHeight() / 2) ); MFXCircleRippleGenerator rg = icon.getRippleGenerator(); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterPaneSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterPaneSkin.java new file mode 100755 index 00000000..d9b9bf02 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXFilterPaneSkin.java @@ -0,0 +1,342 @@ +package io.github.palexdev.materialfx.skins; + +import io.github.palexdev.materialfx.controls.*; +import io.github.palexdev.materialfx.factories.InsetsFactory; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.effects.ripple.RippleClipType; +import io.github.palexdev.materialfx.filter.BooleanFilter; +import io.github.palexdev.materialfx.enums.ChainMode; +import io.github.palexdev.materialfx.filter.EnumFilter; +import io.github.palexdev.materialfx.filter.base.AbstractFilter; +import io.github.palexdev.materialfx.filter.base.NumberFilter; +import io.github.palexdev.materialfx.beans.BiPredicateBean; +import io.github.palexdev.materialfx.beans.FilterBean; +import io.github.palexdev.materialfx.font.MFXFontIcon; +import io.github.palexdev.materialfx.utils.NodeUtils; +import javafx.beans.InvalidationListener; +import javafx.beans.property.ListProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Orientation; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.control.SkinBase; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.*; +import javafx.scene.text.Text; +import javafx.stage.Modality; + +/** + * This is the skin associated with every {@link MFXFilterPane}. + *

+ * The control is made of four parts: + *

- The header which contains a label, and two icons to confirm the filter or reset the filter pane + *

- The filter builder which contains the necessary controls to produce active filters + *

- A label which acts as a separator + *

- A {@link FlowPane} to show the currently built active filters + */ +public class MFXFilterPaneSkin extends SkinBase> { + //================================================================================ + // Properties + //================================================================================ + private final VBox container; + private final Region filterBuilder; + private final FlowPane activeFiltersPane; + + private final MFXExceptionDialog exceptionDialog = new MFXExceptionDialog(); + private final MFXStageDialog errorDialog = new MFXStageDialog(exceptionDialog); + private final StringProperty query = new SimpleStringProperty(); + + //================================================================================ + // Constructors + //================================================================================ + public MFXFilterPaneSkin(MFXFilterPane filterPane) { + super(filterPane); + + // TODO review exception dialog + exceptionDialog.setPrefSize(600, 500); + errorDialog.setModality(Modality.WINDOW_MODAL); + + Region header = buildHeader(); + + Label filtersLabel = new Label("Active filters"); + filtersLabel.getStyleClass().add("header-label"); + VBox.setMargin(filtersLabel, InsetsFactory.top(15)); + + filterBuilder = buildFilterBuilder(); + activeFiltersPane = buildActiveFilters(); + + container = new VBox(10, header, filterBuilder, filtersLabel, activeFiltersPane); + getChildren().setAll(container); + addListeners(); + } + + //================================================================================ + // Methods + //================================================================================ + private void addListeners() { + MFXFilterPane filterPane = getSkinnable(); + filterPane.getActiveFilters().addListener((InvalidationListener) invalidated -> updateFilters()); + } + + /** + * For each filter in the {@link MFXFilterPane#getActiveFilters()} list builds + * a node that represents the filter. Filters are spaced by another node + * which represents how to filters are chained, by clicking on this icon the + * chain mode can be changed., + * + * @see #buildFilter(FilterBean) + * @see #buildAndOrIcon(FilterBean) + */ + protected void updateFilters() { + MFXFilterPane filterPane = getSkinnable(); + ObservableList> filters = filterPane.getActiveFilters(); + ObservableList children = FXCollections.observableArrayList(); + + for (int i = 0; i < filters.size(); i++) { + int previous = i - 1; + FilterBean filter; + if (previous >= 0) { + filter = filters.get(previous); + children.add(buildAndOrIcon(filter)); + } + + filter = filters.get(i); + children.add(buildFilter(filter)); + } + + activeFiltersPane.getChildren().setAll(children); + } + + /** + * Builds a node that represents the given {@link FilterBean}. + *

+ * It is composed by: + *

- A label that shows the object's data type/name + *

- A label that shows which function is used to compare the input with the object's field value + *

- A label that shows which is the input + *

- An icon to remove the filter + */ + protected Region buildFilter(FilterBean filter) { + Label filterLabel = new Label(filter.getFilterName()); + Label functionLabel = new Label(filter.getPredicateName()); + Label queryLabel = new Label(filter.getQuery()); + functionLabel.getStyleClass().add("function-text"); + MFXFontIcon remove = new MFXFontIcon("mfx-x-alt", 12); + remove.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> getSkinnable().getActiveFilters().remove(filter)); + HBox.setMargin(remove, InsetsFactory.top(2)); + + HBox container = new HBox(15, filterLabel, functionLabel, queryLabel, remove); + container.getStyleClass().add("active-filter"); + container.setAlignment(Pos.CENTER); + return container; + } + + /** + * Builds an icon that represents how two {@link FilterBean}s should be chained. + * Clicking on the icon switches the chain mode. + */ + protected Node buildAndOrIcon(FilterBean filter) { + Text modeText = new Text(filter.getMode().text()); + modeText.getStyleClass().add("and-or-text"); + modeText.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> { + if (filter.getMode() == ChainMode.AND) { + filter.setMode(ChainMode.OR); + modeText.setText(ChainMode.OR.text()); + } else { + filter.setMode(ChainMode.AND); + modeText.setText(ChainMode.AND.text()); + } + }); + return modeText; + } + + /** + * Builds the header. + */ + protected Region buildHeader() { + MFXFilterPane filterPane = getSkinnable(); + + Label headerLabel = new Label(); + headerLabel.getStyleClass().add("header-label"); + headerLabel.textProperty().bind(filterPane.headerTextProperty()); + headerLabel.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(headerLabel, Priority.ALWAYS); + + MFXIconWrapper filter = new MFXIconWrapper(new MFXFontIcon("mfx-variant7-mark", 16), 28).defaultRippleGeneratorBehavior(); + MFXIconWrapper reset = new MFXIconWrapper(new MFXFontIcon("mfx-undo", 16), 28).defaultRippleGeneratorBehavior(); + + filter.setId("filterIcon"); + reset.setId("resetIcon"); + + NodeUtils.makeRegionCircular(filter); + NodeUtils.makeRegionCircular(reset); + + filter.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> filterPane.getOnFilter().handle(event)); // TODO action + reset.addEventHandler(MouseEvent.MOUSE_CLICKED, this::reset); + + HBox box = new HBox(5, headerLabel, filter, reset); + box.setAlignment(Pos.CENTER_LEFT); + box.getStyleClass().add("header"); + return box; + } + + /** + * Builds the filter builder region. + */ + protected Region buildFilterBuilder() { + MFXFilterPane filterPane = getSkinnable(); + + ListProperty> predicates = new SimpleListProperty<>(FXCollections.observableArrayList()); + + MFXTextField searchField = new MFXTextField(); + searchField.setPromptText("Type in your filter value..."); + searchField.textProperty().bindBidirectional(query); + + MFXComboBox enumsCombo = new MFXComboBox<>(); + enumsCombo.selectedValueProperty().addListener((observable, oldValue, newValue) -> setQuery(newValue.toString())); + enumsCombo.setManaged(false); + enumsCombo.setVisible(false); + + MFXComboBox booleansCombo = new MFXComboBox<>(FXCollections.observableArrayList(true, false)); + booleansCombo.selectedValueProperty().addListener((observable, oldValue, newValue) -> setQuery(newValue.toString())); + booleansCombo.setManaged(false); + booleansCombo.setVisible(false); + + MFXComboBox> filterCombo = new MFXComboBox<>(filterPane.getFilters()); + filterCombo.getSelectionModel().selectFirst(); + filterCombo.getStyleClass().add("filter-combo"); + filterCombo.selectedValueProperty().addListener((observable, oldValue, newValue) -> { + setQuery(""); + predicates.setAll(newValue.getPredicates()); + + if (newValue instanceof EnumFilter) { + EnumFilter enumFilter = (EnumFilter) filterCombo.getSelectedValue(); + enumsCombo.setItems(FXCollections.observableArrayList(enumFilter.getEnumType().getEnumConstants())); + enumsCombo.setVisible(true); + booleansCombo.setVisible(false); + searchField.setVisible(false); + } else if (newValue instanceof BooleanFilter) { + booleansCombo.setVisible(true); + enumsCombo.setVisible(false); + searchField.setVisible(false); + } else { + enumsCombo.setVisible(false); + booleansCombo.setVisible(false); + searchField.setVisible(true); + } + }); + + // TODO FIX COMBO BOX ICON EMPTY LIST + // TODO FIX SELECTION + MFXComboBox> predicatesCombo = new MFXComboBox<>(predicates); + predicatesCombo.getStyleClass().add("predicates-combo"); + + MFXButton addButton = new MFXButton("Add filter"); + addButton.setOnAction(event -> { + if (filterCombo.getSelectionModel().getSelectedItem() != null + && predicatesCombo.getSelectionModel().getSelectedItem() != null + && !searchField.getText().isEmpty() + ) { + AbstractFilter selected = filterCombo.getSelectedValue(); + selected.setSelectedPredicateIndex(predicatesCombo.getSelectionModel().getSelectedIndex()); + FilterBean predicate = selected.toFilterBean(getQuery()); + + if (queryValidation(selected)) { + filterPane.getActiveFilters().add(predicate); + }; + } + }); + addButton.getRippleGenerator().setClipSupplier(() -> new RippleClipTypeFactory(RippleClipType.ROUNDED_RECTANGLE).setArcs(30).build(addButton)); + + HBox container = new HBox(10, filterCombo, predicatesCombo, searchField, enumsCombo, booleansCombo, addButton) { + @Override + protected void layoutChildren() { + super.layoutChildren(); + + double w = searchField.getBoundsInParent().getWidth(); + double h = searchField.getBoundsInParent().getHeight(); + double x = searchField.getBoundsInParent().getMinX(); + double y = searchField.getBoundsInParent().getMinY(); + enumsCombo.resizeRelocate(x, y, w, h); + booleansCombo.resizeRelocate(x, y, w, h); + } + }; + container.setAlignment(Pos.CENTER_LEFT); + return container; + } + + /** + * Builds tha active filters flow pane. + */ + protected FlowPane buildActiveFilters() { + MFXFilterPane filterPane = getSkinnable(); + FlowPane flowPane = new FlowPane(Orientation.HORIZONTAL, 10, 10); + flowPane.setAlignment(Pos.TOP_LEFT); + flowPane.prefWrapLengthProperty().bind(filterPane.widthProperty()); + flowPane.setPadding(InsetsFactory.bottom(7)); + return flowPane; + } + + /** + * Validates the given query. This is needed for Numbers since the input is a + * String and there's no guarantee that the typed text represents a number. + *

+ * Returns true if the input is valid otherwise shows an {@link MFXExceptionDialog} and returns false. + */ + protected boolean queryValidation(AbstractFilter filter) { + String type = ""; + String name = ""; + + try { + if (filter instanceof NumberFilter) { + NumberFilter numberFilter = (NumberFilter) filter; + type = "Number"; + name = numberFilter.name(); + Number parsed = numberFilter.getValue(getQuery()); + } + return true; + } catch (Exception ex) { + String title = "Attempted to parse " + name + " of type: " + type; + exceptionDialog.setTitle(title); + exceptionDialog.setException(ex); + errorDialog.show(); + return false; + } + } + + /** + * Resets the filter pane. + */ + protected void reset(MouseEvent event) { + MFXFilterPane filterPane = getSkinnable(); + setQuery(""); + filterPane.getActiveFilters().clear(); + filterPane.getOnReset().handle(event); + } + + public String getQuery() { + return query.get(); + } + + public void setQuery(String query) { + this.query.set(query); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { + return getSkinnable().prefWidth(-1); + } + + @Override + protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { + return getSkinnable().prefHeight(-1); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXLabelSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXLabelSkin.java old mode 100644 new mode 100755 index 7a8b8f35..168a4b07 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXLabelSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXLabelSkin.java @@ -20,8 +20,8 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.MFXLabel; import io.github.palexdev.materialfx.controls.MFXTextField; -import io.github.palexdev.materialfx.controls.enums.Styles; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.enums.Styles; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.utils.LabelUtils; import javafx.animation.ScaleTransition; import javafx.beans.binding.Bindings; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXListViewSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXListViewSkin.java old mode 100644 new mode 100755 index ba92f823..1f2b6fdc --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXListViewSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXListViewSkin.java @@ -19,7 +19,7 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.base.AbstractMFXListView; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.effects.MFXDepthManager; import io.github.palexdev.materialfx.utils.AnimationUtils; import io.github.palexdev.virtualizedfx.flow.simple.SimpleVirtualFlow; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXNotificationCenterSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXNotificationCenterSkin.java new file mode 100755 index 00000000..28a0d444 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXNotificationCenterSkin.java @@ -0,0 +1,213 @@ +package io.github.palexdev.materialfx.skins; + +import io.github.palexdev.materialfx.controls.*; +import io.github.palexdev.materialfx.controls.MFXPopup.MFXPopupEvent; +import io.github.palexdev.materialfx.controls.cell.MFXNotificationCell; +import io.github.palexdev.materialfx.factories.InsetsFactory; +import io.github.palexdev.materialfx.enums.NotificationCounterStyle; +import io.github.palexdev.materialfx.enums.NotificationState; +import io.github.palexdev.materialfx.font.MFXFontIcon; +import io.github.palexdev.materialfx.notifications.base.INotification; +import io.github.palexdev.materialfx.utils.NodeUtils; +import io.github.palexdev.virtualizedfx.flow.simple.SimpleVirtualFlow; +import javafx.beans.binding.Bindings; +import javafx.css.Styleable; +import javafx.geometry.HPos; +import javafx.geometry.Pos; +import javafx.geometry.VPos; +import javafx.scene.control.ContentDisplay; +import javafx.scene.control.SkinBase; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.*; +import javafx.scene.text.Text; + +/** + * This is the skin associated with every {@link MFXNotificationCenter}. + *

+ * It is composed by an icon, which is a bell, that opens a {@link MFXPopup} to show the notification center. + *

+ * As of now there's a bug that I can't fix because of JavaFX internal API, if the popup is open and the + * icon has been clicked again the popup won't open but will stay open. I'll see what I can do... // TODO fix + */ +public class MFXNotificationCenterSkin extends SkinBase { + //================================================================================ + // Properties + //================================================================================ + private final MFXIconWrapper bellWrapped; + private final NotificationsCounter counter; + private final MFXPopup popup; + + //================================================================================ + // Constructors + //================================================================================ + public MFXNotificationCenterSkin(MFXNotificationCenter notificationCenter, SimpleVirtualFlow virtualFlow) { + super(notificationCenter); + + MFXFontIcon bell = new MFXFontIcon("mfx-bell-alt", 36); + bellWrapped = new MFXIconWrapper(bell, 56); + bellWrapped.getStyleClass().add("notifications-icon"); + + counter = new NotificationsCounter(); + counter.setManaged(false); + + MFXLabel headerLabel = new MFXLabel(); + headerLabel.textProperty().bind(notificationCenter.headerTextPropertyProperty()); + headerLabel.setAlignment(Pos.CENTER_LEFT); + headerLabel.setMaxWidth(Double.MAX_VALUE); + HBox.setHgrow(headerLabel, Priority.ALWAYS); + + MFXToggleButton dndToggle = new MFXToggleButton("Do not disturb"); + dndToggle.setContentDisplay(ContentDisplay.RIGHT); + dndToggle.setGraphicTextGap(15); + notificationCenter.doNotDisturbProperty().bindBidirectional(dndToggle.selectedProperty()); + + HBox header = new HBox(headerLabel, dndToggle); + header.getStyleClass().add("header"); + header.setAlignment(Pos.CENTER_LEFT); + + MFXIconWrapper select = new MFXIconWrapper(new MFXFontIcon("mfx-variant13-mark", 24), 36).defaultRippleGeneratorBehavior(); + MFXIconWrapper markAsRead = new MFXIconWrapper(new MFXFontIcon("mfx-eye", 20), 36).defaultRippleGeneratorBehavior(); + MFXIconWrapper markAsUnread = new MFXIconWrapper(new MFXFontIcon("mfx-eye-slash", 20), 36).defaultRippleGeneratorBehavior(); + MFXIconWrapper dismiss = new MFXIconWrapper(new MFXFontIcon("mfx-delete", 20), 36).defaultRippleGeneratorBehavior(); + + select.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> notificationCenter.setSelectionMode(!notificationCenter.isSelectionMode())); + markAsRead.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> notificationCenter.markSelectedNotificationsAs(NotificationState.READ)); + markAsUnread.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> notificationCenter.markSelectedNotificationsAs(NotificationState.UNREAD)); + dismiss.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> notificationCenter.dismissSelected()); + + NodeUtils.makeRegionCircular(select); + NodeUtils.makeRegionCircular(markAsRead); + NodeUtils.makeRegionCircular(markAsUnread); + NodeUtils.makeRegionCircular(dismiss); + + HBox actions = new HBox(50, select, markAsRead, markAsUnread, dismiss); + actions.getStyleClass().add("actions"); + actions.setAlignment(Pos.CENTER); + + BorderPane borderPane = new BorderPane(); + borderPane.setTop(header); + borderPane.setCenter(virtualFlow); + borderPane.setBottom(actions); + borderPane.getStyleClass().add("notifications-container"); + VBox.setVgrow(borderPane, Priority.ALWAYS); + + VBox popupContent = new VBox(borderPane); + popupContent.setAlignment(Pos.TOP_CENTER); + popupContent.paddingProperty().bind(Bindings.createObjectBinding( + () -> InsetsFactory.top(notificationCenter.getPopupSpacing()), + notificationCenter.popupSpacingProperty() + )); + popupContent.setMinHeight(Region.USE_PREF_SIZE); + popupContent.setMaxHeight(Region.USE_PREF_SIZE); + popupContent.prefWidthProperty().bind(notificationCenter.popupWidthProperty()); + popupContent.prefHeightProperty().bind(notificationCenter.popupHeightProperty()); + + popup = new MFXPopup(popupContent) { + @Override + public Styleable getStyleableParent() { + return MFXNotificationCenterSkin.this.getSkinnable(); + } + }; + popup.setAnimated(false); + popup.setConsumeAutoHidingEvents(false); // TODO can't fix as of now, JavaFX 17.0.1 + popup.getStyleClass().addAll(getSkinnable().getStyleClass()); + + getChildren().setAll(bellWrapped, counter); + addListeners(); + } + + //================================================================================ + // Methods + //================================================================================ + private void addListeners() { + MFXNotificationCenter notificationCenter = getSkinnable(); + + popup.showingProperty().addListener((observable, oldValue, newValue) -> { + if (!newValue && notificationCenter.isShowing()) notificationCenter.setShowing(false); + }); + bellWrapped.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { + bellWrapped.requestFocus(); + notificationCenter.getOnIconClicked().handle(event); + }); + notificationCenter.showingProperty().addListener((observable, oldValue, newValue) -> managePopup(newValue)); + notificationCenter.addEventFilter(MFXPopupEvent.REPOSITION_EVENT, event -> popup.reposition()); + notificationCenter.popupHoverProperty().bind(popup.hoverProperty()); + } + + /** + * Shows/Hides the popup. + */ + protected void managePopup(boolean showing) { + if (!showing) { + popup.hide(); + return; + } + popup.show(bellWrapped, HPos.CENTER, VPos.BOTTOM); + } + + //================================================================================ + // Overridden Methods + //================================================================================ + @Override + protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) { + return bellWrapped.prefWidth(-1); + } + + @Override + protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { + return bellWrapped.prefHeight(-1); + } + + @Override + protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) { + super.layoutChildren(contentX, contentY, contentWidth, contentHeight); + + // That one time I really need math, I don't understand how it works, but it works :) + double bellCenterX = bellWrapped.getBoundsInParent().getCenterX(); + double bellCenterY = bellWrapped.getBoundsInParent().getCenterY(); + double radius = bellWrapped.getSize() / 2; + double angle = 45; + double angleToRadians = Math.PI / 180; + double size = counter.getSize(); + double counterX = bellCenterX + radius * Math.cos(angle * angleToRadians) - (size / 2); + double counterY = bellCenterY - radius * Math.sin(angle * angleToRadians) - (size / 2); + counter.resizeRelocate(counterX, counterY, size, size); + } + + /** + * To keep things clean and organized the {@link MFXNotificationCenter}'s counter has been + * written to a separate class. + */ + private class NotificationsCounter extends MFXIconWrapper { + + public NotificationsCounter() { + MFXNotificationCenter notificationCenter = getSkinnable(); + + Text counterText = new Text(); + counterText.getStyleClass().add("text"); + + counterText.textProperty().addListener(invalidated -> { + double padding = notificationCenter.getCounterStyle() == NotificationCounterStyle.DOT ? 3 : 7; + double textW = counterText.prefWidth(-1); + double textH = counterText.prefHeight(-1); + double size = textW > textH ? snapSizeX(textW + padding) : snapSizeY(textH + padding); + setSize(size); + notificationCenter.requestLayout(); + requestLayout(); + }); + counterText.visibleProperty().bind(Bindings.createBooleanBinding( + () -> notificationCenter.getCounterStyle() == NotificationCounterStyle.NUMBER, + notificationCenter.counterStyleProperty() + )); + counterText.textProperty().bind(notificationCenter.unreadCountProperty().asString()); + counterText.textProperty().bind(Bindings.createStringBinding( + () -> notificationCenter.getCounterStyle() == NotificationCounterStyle.NUMBER ? Long.toString(notificationCenter.getUnreadCount()) : "", + notificationCenter.unreadCountProperty(), notificationCenter.counterStyleProperty() + )); + + getStyleClass().add("counter"); + visibleProperty().bind(notificationCenter.unreadCountProperty().greaterThan(0)); + setIcon(counterText); + } + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXPasswordFieldSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXPasswordFieldSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXPopupSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXPopupSkin.java new file mode 100755 index 00000000..44bd5ffe --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXPopupSkin.java @@ -0,0 +1,125 @@ +package io.github.palexdev.materialfx.skins; + +import io.github.palexdev.materialfx.beans.PopupPositionBean; +import io.github.palexdev.materialfx.controls.MFXPopup; +import javafx.animation.Animation; +import javafx.geometry.HPos; +import javafx.geometry.VPos; +import javafx.scene.Node; +import javafx.scene.control.Skin; +import javafx.scene.layout.StackPane; +import javafx.scene.transform.Scale; + +/** + * This is the skin associated with every {@link MFXPopup}. + *

+ * The popup's content is shown in a container (a {@link StackPane}). + */ +public class MFXPopupSkin implements Skin { + //================================================================================ + // Properties + //================================================================================ + private MFXPopup popup; + private final StackPane container; + private final Scale scale; + + private Animation animation; + + //================================================================================ + // Constructors + //================================================================================ + public MFXPopupSkin(MFXPopup popup) { + this.popup = popup; + + container = new StackPane(popup.getContent()); + scale = new Scale(0.1, 0.1, 0, 0); + container.getTransforms().add(scale); + init(); + + if (popup.isAnimated()) { + animation = popup.getAnimationProvider().apply(container, scale); + animation.play(); + } else { + scale.setX(1); + scale.setY(1); + container.setOpacity(1); + } + } + + //================================================================================ + // Methods + //================================================================================ + + /** + * Positions the popup. + */ + protected void init() { + container.setOpacity(0.0); + + PopupPositionBean position = popup.getPosition(); + if (position == null) return; + + double containerW = container.prefWidth(-1); + double containerH = container.prefHeight(-1); + HPos hPos = position.getHPos(); + VPos vPos = position.getVPos(); + double xOffset = position.getXOffset(); + double yOffset = position.getYOffset(); + + double tx = 0; + double ty = 0; + double px = hPos == HPos.RIGHT ? xOffset : containerW + xOffset; + double py = vPos == VPos.BOTTOM ? yOffset : containerH + yOffset; + + switch (hPos) { + case CENTER: { + tx = -(Math.abs(containerW - position.getOwnerWidth()) / 2) + xOffset; + break; + } + case LEFT: { + tx = -containerW + xOffset; + break; + } + case RIGHT: { + tx = xOffset; + break; + } + } + switch (vPos) { + case BOTTOM: { + ty = yOffset; + break; + } + case CENTER: { + ty = -(Math.abs(containerH - position.getOwnerHeight()) / 2) + yOffset; + break; + } + case TOP: { + ty = -containerH + yOffset; + break; + } + } + + scale.setPivotX(px); + scale.setPivotY(py); + container.setTranslateX(tx); + container.setTranslateY(ty); + } + + @Override + public MFXPopup getSkinnable() { + return popup; + } + + @Override + public Node getNode() { + return container; + } + + @Override + public void dispose() { + animation.stop(); + animation = null; + popup = null; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressBarSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressBarSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressSpinnerSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXProgressSpinnerSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRadioButtonSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRadioButtonSkin.java old mode 100644 new mode 100755 index 640bf20d..341b1454 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRadioButtonSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRadioButtonSkin.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.MFXRadioButton; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.utils.AnimationUtils; import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; import io.github.palexdev.materialfx.utils.ColorUtils; @@ -78,9 +78,9 @@ public class MFXRadioButtonSkin extends RadioButtonSkin { rippleGenerator.setAnimationSpeed(2); rippleGenerator.setClipSupplier(() -> null); rippleGenerator.setRipplePositionFunction(event -> { - RipplePosition position = new RipplePosition(); - position.setXPosition(dot.getBoundsInParent().getCenterX()); - position.setYPosition(dot.getBoundsInParent().getCenterY()); + PositionBean position = new PositionBean(); + position.setX(dot.getBoundsInParent().getCenterX()); + position.setY(dot.getBoundsInParent().getCenterY()); return position; }); rippleGenerator.setRippleRadius(radius); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRectangleToggleNodeSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRectangleToggleNodeSkin.java old mode 100644 new mode 100755 index 9d2cb1c4..ae426408 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRectangleToggleNodeSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXRectangleToggleNodeSkin.java @@ -21,7 +21,7 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.MFXLabel; import io.github.palexdev.materialfx.controls.MFXRectangleToggleNode; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.utils.LabelUtils; import io.github.palexdev.materialfx.utils.NodeUtils; import javafx.event.Event; @@ -90,7 +90,7 @@ public class MFXRectangleToggleNodeSkin extends SkinBase rippleGenerator.setAnimateBackground(false); rippleGenerator.setClipSupplier(() -> toggleNode.getRippleClipTypeFactory().build(container)); - rippleGenerator.setRipplePositionFunction(event -> new RipplePosition(event.getX(), event.getY())); + rippleGenerator.setRipplePositionFunction(event -> new PositionBean(event.getX(), event.getY())); rippleGenerator.rippleRadiusProperty().bind(toggleNode.widthProperty().divide(2.0)); } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXScrollPaneSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXScrollPaneSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXSliderSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXSliderSkin.java old mode 100644 new mode 100755 index 2c8d9de2..2d88f7d5 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXSliderSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXSliderSkin.java @@ -20,9 +20,9 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.beans.NumberRange; import io.github.palexdev.materialfx.controls.MFXSlider; -import io.github.palexdev.materialfx.controls.enums.SliderEnums.SliderMode; -import io.github.palexdev.materialfx.controls.enums.SliderEnums.SliderPopupSide; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.enums.SliderEnums.SliderMode; +import io.github.palexdev.materialfx.enums.SliderEnums.SliderPopupSide; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.AnimationUtils; import io.github.palexdev.materialfx.utils.AnimationUtils.PauseBuilder; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperSkin.java old mode 100644 new mode 100755 index 035757b0..29bdabd9 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperSkin.java @@ -23,8 +23,8 @@ import io.github.palexdev.materialfx.controls.MFXStepper; import io.github.palexdev.materialfx.controls.MFXStepper.MFXStepperEvent; import io.github.palexdev.materialfx.controls.MFXStepperToggle; import io.github.palexdev.materialfx.controls.MFXStepperToggle.MFXStepperToggleEvent; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; -import io.github.palexdev.materialfx.controls.factories.RippleClipTypeFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.RippleClipTypeFactory; import io.github.palexdev.materialfx.effects.ripple.RippleClipType; import io.github.palexdev.materialfx.utils.AnimationUtils; import io.github.palexdev.materialfx.utils.NodeUtils; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperToggleSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperToggleSkin.java old mode 100644 new mode 100755 index 09559de0..634b17ff --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperToggleSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXStepperToggleSkin.java @@ -22,9 +22,9 @@ import io.github.palexdev.materialfx.controls.MFXIconWrapper; import io.github.palexdev.materialfx.controls.MFXLabel; import io.github.palexdev.materialfx.controls.MFXStageDialog; import io.github.palexdev.materialfx.controls.MFXStepperToggle; -import io.github.palexdev.materialfx.controls.enums.DialogType; -import io.github.palexdev.materialfx.controls.enums.StepperToggleState; -import io.github.palexdev.materialfx.controls.enums.TextPosition; +import io.github.palexdev.materialfx.enums.DialogType; +import io.github.palexdev.materialfx.enums.StepperToggleState; +import io.github.palexdev.materialfx.enums.TextPosition; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.DialogUtils; import io.github.palexdev.materialfx.utils.LabelUtils; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableColumnSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableColumnSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableRowCellSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableRowCellSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java old mode 100644 new mode 100755 index 5eb4a4a2..29f8525b --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTableViewSkin.java @@ -22,11 +22,9 @@ import io.github.palexdev.materialfx.controls.*; import io.github.palexdev.materialfx.controls.MFXTableView.MFXTableViewEvent; import io.github.palexdev.materialfx.controls.cell.MFXTableColumn; import io.github.palexdev.materialfx.controls.cell.MFXTableRowCell; -import io.github.palexdev.materialfx.controls.enums.SortState; -import io.github.palexdev.materialfx.controls.enums.Styles; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; -import io.github.palexdev.materialfx.filter.IFilterable; -import io.github.palexdev.materialfx.filter.MFXFilterDialog; +import io.github.palexdev.materialfx.enums.SortState; +import io.github.palexdev.materialfx.enums.Styles; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.selection.TableSelectionModel; import io.github.palexdev.materialfx.selection.base.ITableSelectionModel; @@ -61,7 +59,6 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; -import javafx.stage.Modality; import javafx.util.Duration; import javafx.util.Pair; @@ -70,6 +67,7 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +// TODO review /** * This is the implementation of the {@code Skin} associated with every {@link MFXTableView}. *

@@ -125,8 +123,8 @@ public class MFXTableViewSkin extends SkinBase> { private SortedList sortedList; private SortedList filteredList; - private final MFXFilterDialog filterDialog; - private final MFXStageDialog filterStageDialog; + //private final MFXFilterDialog filterDialog; + //private final MFXStageDialog filterStageDialog; private final BooleanProperty tableFiltered = new SimpleBooleanProperty(false); //================================================================================ @@ -178,12 +176,12 @@ public class MFXTableViewSkin extends SkinBase> { pgcBox = buildPaginationControls(); - filterDialog = new MFXFilterDialog<>(); +/* filterDialog = new MFXFilterDialog<>(); filterDialog.getFilterButton().setOnAction(event -> filterTable()); filterStageDialog = new MFXStageDialog(filterDialog); filterStageDialog.setOwner(tableView.getScene() != null ? tableView.getScene().getWindow() : null); filterStageDialog.setCenterInOwner(true); - filterStageDialog.setModality(Modality.WINDOW_MODAL); + filterStageDialog.setModality(Modality.WINDOW_MODAL);*/ container.getChildren().setAll(header, columnsBox, rowsBox, pgcBox); getChildren().setAll(container); @@ -233,7 +231,7 @@ public class MFXTableViewSkin extends SkinBase> { } }); - NodeUtils.waitForScene(tableView, () -> filterStageDialog.setOwner(tableView.getScene().getWindow()), true, false); + //NodeUtils.waitForScene(tableView, () -> filterStageDialog.setOwner(tableView.getScene().getWindow()), true, false); tableView.getItems().addListener((InvalidationListener) listInvalidated -> reset(false)); tableView.itemsProperty().addListener(propertyInvalidated -> { @@ -428,7 +426,7 @@ public class MFXTableViewSkin extends SkinBase> { ); filterIcon.disableProperty().bind(tableFiltered.or(listEmpty)); clearFilterIcon.disableProperty().bind(tableFiltered.not().or(listEmpty)); - filterIcon.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> filterStageDialog.show()); + //filterIcon.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> filterStageDialog.show()); clearFilterIcon.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> { if (tableFiltered.get()) { tableFiltered.set(false); @@ -600,12 +598,12 @@ public class MFXTableViewSkin extends SkinBase> { * N.B: if the toString method is not overridden or does not contain any useful information for filtering it won't work. */ protected void filterTable() { - ObservableList list = filterDialog.filter(sortedList); +/* ObservableList list = filterDialog.filter(sortedList); filteredList = new SortedList<>(list); filteredList.comparatorProperty().bind(sortedList.comparatorProperty()); tableFiltered.set(true); buildRows(); - filterStageDialog.close(); + filterStageDialog.close();*/ } /** @@ -661,7 +659,7 @@ public class MFXTableViewSkin extends SkinBase> { .addSeparator() .addMenuItem(lockSize) .addMenuItem(unlockSize) - .install(); + .installAndGet(); } /** diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTextFieldSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTextFieldSkin.java old mode 100644 new mode 100755 index 75ef9b63..bd90a7fd --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTextFieldSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTextFieldSkin.java @@ -20,7 +20,7 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.MFXIconWrapper; import io.github.palexdev.materialfx.controls.MFXTextField; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.LabelUtils; import io.github.palexdev.materialfx.validation.MFXDialogValidator; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXToggleButtonSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXToggleButtonSkin.java old mode 100644 new mode 100755 index 2ee7d2c2..228c7c1f --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXToggleButtonSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXToggleButtonSkin.java @@ -22,7 +22,7 @@ import io.github.palexdev.materialfx.controls.MFXToggleButton; import io.github.palexdev.materialfx.effects.DepthLevel; import io.github.palexdev.materialfx.effects.MFXDepthManager; import io.github.palexdev.materialfx.effects.ripple.MFXCircleRippleGenerator; -import io.github.palexdev.materialfx.effects.ripple.RipplePosition; +import io.github.palexdev.materialfx.beans.PositionBean; import io.github.palexdev.materialfx.utils.AnimationUtils; import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; import io.github.palexdev.materialfx.utils.NodeUtils; @@ -144,12 +144,12 @@ public class MFXToggleButtonSkin extends ToggleButtonSkin { rippleGenerator.setClipSupplier(() -> null); rippleGenerator.setRippleColor(toggleButton.isSelected() ? toggleButton.getUnToggleLineColor() : toggleButton.getToggleLineColor()); rippleGenerator.setRipplePositionFunction(mouseEvent -> { - RipplePosition position = new RipplePosition(); - position.xPositionProperty().bind(Bindings.createDoubleBinding( + PositionBean position = new PositionBean(); + position.xProperty().bind(Bindings.createDoubleBinding( () -> circle.getBoundsInParent().getCenterX(), circle.boundsInParentProperty() )); - position.yPositionProperty().bind(Bindings.createDoubleBinding( + position.yProperty().bind(Bindings.createDoubleBinding( () -> circle.localToParent(circle.getLayoutBounds()).getCenterY(), circle.layoutBoundsProperty() )); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTreeItemSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTreeItemSkin.java old mode 100644 new mode 100755 index 8bbab588..51f063bc --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTreeItemSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTreeItemSkin.java @@ -21,7 +21,7 @@ package io.github.palexdev.materialfx.skins; import io.github.palexdev.materialfx.controls.MFXTreeItem; import io.github.palexdev.materialfx.controls.base.AbstractMFXTreeCell; import io.github.palexdev.materialfx.controls.base.AbstractMFXTreeItem; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.selection.TreeSelectionModel; import io.github.palexdev.materialfx.utils.AnimationUtils; import io.github.palexdev.materialfx.utils.AnimationUtils.KeyFrames; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyComboBoxSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyComboBoxSkin.java old mode 100644 new mode 100755 index 16bdcb25..e9d0e4ac --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyComboBoxSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyComboBoxSkin.java @@ -19,7 +19,7 @@ package io.github.palexdev.materialfx.skins.legacy; import io.github.palexdev.materialfx.controls.MFXIconWrapper; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.controls.legacy.MFXLegacyComboBox; import io.github.palexdev.materialfx.font.MFXFontIcon; import io.github.palexdev.materialfx.utils.LabelUtils; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyListViewSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyListViewSkin.java old mode 100644 new mode 100755 index a4204cb8..b3ac951a --- a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyListViewSkin.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyListViewSkin.java @@ -18,7 +18,7 @@ package io.github.palexdev.materialfx.skins.legacy; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import io.github.palexdev.materialfx.controls.legacy.MFXLegacyListView; import io.github.palexdev.materialfx.effects.MFXDepthManager; import io.github.palexdev.materialfx.utils.AnimationUtils; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyTableViewSkin.java b/materialfx/src/main/java/io/github/palexdev/materialfx/skins/legacy/MFXLegacyTableViewSkin.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/AnimationUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/AnimationUtils.java old mode 100644 new mode 100755 index fb0c9c74..b2703b8c --- a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/AnimationUtils.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/AnimationUtils.java @@ -19,7 +19,8 @@ package io.github.palexdev.materialfx.utils; import io.github.palexdev.materialfx.beans.AnimationsData; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.effects.Interpolators; import javafx.animation.*; import javafx.animation.Animation.Status; import javafx.beans.binding.BooleanExpression; @@ -145,6 +146,10 @@ public class AnimationUtils { return animation.getStatus() == Status.PAUSED; } + public static boolean isStopped(Animation animation) { + return animation.getStatus() == Status.STOPPED; + } + //================================================================================ // Builders //================================================================================ @@ -705,6 +710,16 @@ public class AnimationUtils { // Methods //================================================================================ + public AnimationUtils.PauseBuilder setDelay(Duration duration) { + pauseTransition.setDelay(duration); + return this; + } + + public AnimationUtils.PauseBuilder setDelay(double millis) { + pauseTransition.setDelay(Duration.millis(millis)); + return this; + } + /** * Sets the pause transition duration. */ @@ -859,5 +874,21 @@ public class AnimationUtils { public static KeyFrame of(double millis, WritableValue writableValue, T endValue, Interpolator interpolator) { return of(Duration.millis(millis), writableValue, endValue, interpolator); } + + /** + * Returns a new KeyFrame with the given duration and builds a new KeyValue for it + * with the given writable property, endValue and interpolator. + */ + public static KeyFrame of(Duration duration, WritableValue writableValue, T endValue, Interpolators interpolator) { + return of(duration, new KeyValue(writableValue, endValue, interpolator.toInterpolator())); + } + + /** + * Calls {@link #of(Duration, WritableValue, Object, Interpolators)} by converting the given millis value + * with {@link Duration#millis(double)}. + */ + public static KeyFrame of(double millis, WritableValue writableValue, T endValue, Interpolators interpolator) { + return of(Duration.millis(millis), writableValue, endValue, interpolator.toInterpolator()); + } } } diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/BindingUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/BindingUtils.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ColorUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ColorUtils.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/DialogUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/DialogUtils.java old mode 100644 new mode 100755 index ea49f38c..35d31635 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/DialogUtils.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/DialogUtils.java @@ -21,8 +21,8 @@ package io.github.palexdev.materialfx.utils; import io.github.palexdev.materialfx.controls.MFXDialog; import io.github.palexdev.materialfx.controls.MFXExceptionDialog; import io.github.palexdev.materialfx.controls.MFXStageDialog; -import io.github.palexdev.materialfx.controls.enums.DialogType; -import io.github.palexdev.materialfx.controls.factories.MFXDialogFactory; +import io.github.palexdev.materialfx.enums.DialogType; +import io.github.palexdev.materialfx.factories.MFXDialogFactory; import javafx.stage.Modality; import javafx.stage.Window; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/DragResizer.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/DragResizer.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/EnumStringConverter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/EnumStringConverter.java new file mode 100755 index 00000000..78558fb9 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/EnumStringConverter.java @@ -0,0 +1,42 @@ +package io.github.palexdev.materialfx.utils; + +import javafx.util.StringConverter; + +/** + * Implementation of {@link StringConverter} to work with a generic {@link Enum}. + *

+ * For this to work, it's necessary to specify the enumerator class, see {@link Enum#valueOf(Class, String)}. + */ +public class EnumStringConverter> extends StringConverter { + //================================================================================ + // Properties + //================================================================================ + private final Class type; + + //================================================================================ + // Constructors + //================================================================================ + public EnumStringConverter(Class type) { + this.type = type; + } + + //================================================================================ + // Overridden Methods + //================================================================================ + + /** + * Calls toString() on the given enumeration. + */ + @Override + public String toString(E e) { + return e.toString(); + } + + /** + * Uses {@link Enum#valueOf(Class, String)} to convert the given String to an enumeration. + */ + @Override + public E fromString(String string) { + return E.valueOf(type, string); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExceptionUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExceptionUtils.java old mode 100644 new mode 100755 index 6782d7d9..d9b156d4 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExceptionUtils.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExceptionUtils.java @@ -25,7 +25,6 @@ import java.io.StringWriter; * Little utils class to convert a throwable stack trace to a String. */ public class ExceptionUtils { - private static final StringWriter sw = new StringWriter(); private ExceptionUtils() {} @@ -34,6 +33,7 @@ public class ExceptionUtils { * by using a {@link StringWriter} and a {@link PrintWriter}. */ public static String getStackTraceString(Throwable ex) { + StringWriter sw = new StringWriter(); sw.flush(); ex.printStackTrace(new PrintWriter(sw)); return sw.toString(); diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExecutionUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExecutionUtils.java old mode 100644 new mode 100755 index 9d53de6c..e1cc3046 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExecutionUtils.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ExecutionUtils.java @@ -19,6 +19,8 @@ package io.github.palexdev.materialfx.utils; import javafx.application.Platform; +import javafx.beans.InvalidationListener; +import javafx.beans.Observable; import javafx.beans.binding.BooleanExpression; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; @@ -30,6 +32,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.Supplier; /** * Utils class to help with concurrency and callables. @@ -160,6 +163,38 @@ public class ExecutionUtils { }); } + /** + * Executes the given action when the given {@link Observable} changes. + *

+ * If executeNow is true the action is immediately executed. + *

+ * Adds a listener to the observable and executes the given action every time the observable changes and the + * execution condition is met or just once if the isOneShot parameter is true. + * + * @param observable the observable to listen to + * @param action the action to execute when the observable changes + * @param executeNow to specify if the given action should be immediately executed + * @param executionCondition to specify on what conditions the action should be executed + * @param isOneShot to specify if the added listener should be removed after the first time the observable changes + */ + public static void executeWhen(Observable observable, Runnable action, boolean executeNow, Supplier executionCondition, boolean isOneShot) { + if (executeNow) { + action.run(); + } + + observable.addListener(new InvalidationListener() { + @Override + public void invalidated(Observable observable) { + if (executionCondition.get()) { + action.run(); + if (isOneShot) { + observable.removeListener(this); + } + } + } + }); + } + /** * Executes the given action if the given expression and the executeNow parameter are true. *

diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/FXCollectors.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/FXCollectors.java new file mode 100755 index 00000000..3cfc55c8 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/FXCollectors.java @@ -0,0 +1,32 @@ +package io.github.palexdev.materialfx.utils; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.collections.ObservableSet; + +import java.util.stream.Collector; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Convenience class that offers some methods useful on combination with Java {@link Stream} + * to collect to JavaFX's collections. + */ +public class FXCollectors { + + private FXCollectors() {} + + /** + * @return a collector that returns an {@link ObservableSet} + */ + public static Collector> toSet() { + return Collectors.collectingAndThen(Collectors.toSet(), FXCollections::observableSet); + } + + /** + * @return a collector that returns an {@link ObservableList} + */ + public static Collector> toList() { + return Collectors.collectingAndThen(Collectors.toList(), FXCollections::observableArrayList); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/LabelUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/LabelUtils.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ListChangeProcessor.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ListChangeProcessor.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/LoaderUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/LoaderUtils.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/NodeUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/NodeUtils.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/NumberUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/NumberUtils.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/PredicateUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/PredicateUtils.java new file mode 100755 index 00000000..3f05b28f --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/PredicateUtils.java @@ -0,0 +1,21 @@ +package io.github.palexdev.materialfx.utils; + +import io.github.palexdev.materialfx.enums.ChainMode; + +import java.util.function.Predicate; + +/** + * Convenience methods for predicates. + */ +public class PredicateUtils { + + private PredicateUtils() {} + + /** + * @return a new predicate that is the combination of the original predicate + * with the given one according to the specified {@link ChainMode}. + */ + public static Predicate chain(Predicate original, Predicate other, ChainMode mode) { + return mode == ChainMode.AND ? original.and(other) : original.or(other); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/RandomInstance.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/RandomInstance.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ScrollUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ScrollUtils.java old mode 100644 new mode 100755 index 331e080f..944e36da --- a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ScrollUtils.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ScrollUtils.java @@ -18,7 +18,7 @@ package io.github.palexdev.materialfx.utils; -import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory; +import io.github.palexdev.materialfx.factories.MFXAnimationFactory; import javafx.animation.Animation; import javafx.animation.Animation.Status; import javafx.animation.KeyFrame; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/StringUtils.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/StringUtils.java old mode 100644 new mode 100755 index 736f99c0..b4dd28d2 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/StringUtils.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/StringUtils.java @@ -167,6 +167,29 @@ public class StringUtils { return inputStringList.containsAll(wordsList); } + /** + * A useful method to convert a given elapsed time in seconds to a + * String. + *

+ *

- "Just now" if elapsed is less than 60 seconds + *

- minutes + " minutes ago" if the elapsed seconds is greater than 60 seconds + *

- hours + " minutes ago" if the elapsed minutes are greater than 60 minutes + *

- days + " days ago" if the elapsed hours are greater than 24 + */ + public static String timeToHumanReadable(long elapsedSeconds) { + if (elapsedSeconds < 60) { + return "Just now"; + } else { + long minutes = elapsedSeconds / 60; + if (minutes < 60) { + return minutes + " min ago"; + } else { + long hours = minutes / 60; + return hours < 24 ? hours + " hours ago" : hours / 24 + " days ago"; + } + } + } + /** * Generates a random alphabetic string of given length */ diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ToggleButtonsUtil.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/ToggleButtonsUtil.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/TreeItemIterator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/TreeItemIterator.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/TreeItemStream.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/TreeItemStream.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/FunctionalStringConverter.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/FunctionalStringConverter.java new file mode 100755 index 00000000..81942c26 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/FunctionalStringConverter.java @@ -0,0 +1,13 @@ +package io.github.palexdev.materialfx.utils.others; + +/** + * A functional alternative to {@link javafx.util.StringConverter}. + */ +@FunctionalInterface +public interface FunctionalStringConverter { + T fromString(String s); + + default String toString(T t) { + throw new UnsupportedOperationException(); + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/ReusableScheduledExecutor.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/ReusableScheduledExecutor.java new file mode 100755 index 00000000..bcaaf6f4 --- /dev/null +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/ReusableScheduledExecutor.java @@ -0,0 +1,70 @@ +package io.github.palexdev.materialfx.utils.others; + +import java.util.concurrent.Callable; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * This class wraps a {@link ScheduledExecutorService} to make it reusable by keeping + * a reference to the {@link ScheduledFuture}. + */ +public class ReusableScheduledExecutor { + //================================================================================ + // Properties + //================================================================================ + private final ScheduledExecutorService service; + private ScheduledFuture task; + + //================================================================================ + // Constructors + //================================================================================ + public ReusableScheduledExecutor(ScheduledExecutorService service) { + this.service = service; + } + + //================================================================================ + // Delegate Methods + //================================================================================ + + /** + * Cancels the task by calling {@link ScheduledFuture#cancel(boolean)} with false as argument. + */ + public void cancel() { + task.cancel(false); + } + + /** + * Cancels the task by calling {@link ScheduledFuture#cancel(boolean)} with true as argument. + */ + public void cancelNow() { + task.cancel(true); + } + + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + task = service.schedule(command, delay, unit); + return task; + } + + public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { + task = service.schedule(callable, delay, unit); + return (ScheduledFuture) task; + } + + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + task = service.scheduleAtFixedRate(command, initialDelay, period, unit); + return task; + } + + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + task = service.scheduleWithFixedDelay(command, initialDelay, delay, unit); + return task; + } + + //================================================================================ + // Getter/Setters + //================================================================================ + public ScheduledExecutorService getService() { + return service; + } +} diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/TriConsumer.java b/materialfx/src/main/java/io/github/palexdev/materialfx/utils/others/TriConsumer.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXDialogValidator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXDialogValidator.java old mode 100644 new mode 100755 index d6f7e06f..a053ec20 --- a/materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXDialogValidator.java +++ b/materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXDialogValidator.java @@ -19,8 +19,8 @@ package io.github.palexdev.materialfx.validation; import io.github.palexdev.materialfx.controls.MFXStageDialog; -import io.github.palexdev.materialfx.controls.enums.DialogType; -import io.github.palexdev.materialfx.controls.factories.MFXDialogFactory; +import io.github.palexdev.materialfx.enums.DialogType; +import io.github.palexdev.materialfx.factories.MFXDialogFactory; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXPriorityValidator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/validation/MFXPriorityValidator.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/AbstractMFXValidator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/AbstractMFXValidator.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/IMFXValidator.java b/materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/IMFXValidator.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/Validated.java b/materialfx/src/main/java/io/github/palexdev/materialfx/validation/base/Validated.java old mode 100644 new mode 100755 diff --git a/materialfx/src/main/java/module-info.java b/materialfx/src/main/java/module-info.java old mode 100644 new mode 100755 index 2c9389ce..acbebbed --- a/materialfx/src/main/java/module-info.java +++ b/materialfx/src/main/java/module-info.java @@ -9,6 +9,7 @@ module MaterialFX { exports io.github.palexdev.materialfx; exports io.github.palexdev.materialfx.beans; exports io.github.palexdev.materialfx.beans.properties.base; + exports io.github.palexdev.materialfx.beans.properties.functional; exports io.github.palexdev.materialfx.beans.properties.resettable; exports io.github.palexdev.materialfx.beans.properties.synced; exports io.github.palexdev.materialfx.bindings; @@ -16,15 +17,17 @@ module MaterialFX { exports io.github.palexdev.materialfx.controls; exports io.github.palexdev.materialfx.controls.base; exports io.github.palexdev.materialfx.controls.cell; - exports io.github.palexdev.materialfx.controls.enums; - exports io.github.palexdev.materialfx.controls.factories; exports io.github.palexdev.materialfx.controls.legacy; exports io.github.palexdev.materialfx.effects; exports io.github.palexdev.materialfx.effects.ripple; exports io.github.palexdev.materialfx.effects.ripple.base; + exports io.github.palexdev.materialfx.enums; + exports io.github.palexdev.materialfx.factories; exports io.github.palexdev.materialfx.filter; + exports io.github.palexdev.materialfx.filter.base; exports io.github.palexdev.materialfx.font; exports io.github.palexdev.materialfx.notifications; + exports io.github.palexdev.materialfx.notifications.base; exports io.github.palexdev.materialfx.selection; exports io.github.palexdev.materialfx.selection.base; exports io.github.palexdev.materialfx.skins; diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/Fonts.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/Fonts.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXButton.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXButton.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckBox.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckBox.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckListCell.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckListCell.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckListView.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckListView.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckTreeCell.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCheckTreeCell.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCircleToggleNode.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXCircleToggleNode.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXColors.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXColors.css old mode 100644 new mode 100755 index 6afd20c0..a0da8355 --- a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXColors.css +++ b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXColors.css @@ -20,6 +20,7 @@ -mfx-blue: #2196f3; -mfx-charcoal: #445055; -mfx-green: #4caf50; + -mfx-onyx: #353935; -mfx-purple: #673AB7; -mfx-red: #EF6E6B; } diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle1.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle1.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle2.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle2.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle3.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXComboBoxStyle3.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXContextMenu.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXContextMenu.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXContextMenuItem.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXContextMenuItem.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDatePicker.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDatePicker.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDatePickerContent.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDatePickerContent.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDialog.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXDialog.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXEvaluationBox.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXEvaluationBox.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterComboBox.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterComboBox.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterDialog.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterDialog.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterPane.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterPane.css new file mode 100755 index 00000000..3d0d8b4e --- /dev/null +++ b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXFilterPane.css @@ -0,0 +1,172 @@ +@import "MFXColors.css"; +@import "Fonts.css"; + +.mfx-filter-pane { + -mfx-main: #7A0ED9; + -mfx-main-light: #B47BC2; + -mfx-main-lighter: #F5F2F7; + -mfx-gray: #6b6b6b; + + -fx-background-color: white; + -fx-background-radius: 10; + -fx-padding: 7 14 7 14; +} + +.mfx-filter-pane .header { + -fx-padding: 0 0 7 0; +} + +.mfx-filter-pane .header .header-label { + -fx-font-family: "Open Sans SemiBold"; + -fx-font-size: 14; + -fx-text-fill: -mfx-gray; + -fx-font-smoothing-type: gray; + -fx-padding: 5; +} + +.mfx-filter-pane .header #filterIcon .mfx-ripple-generator { + -mfx-ripple-radius: 20; + -mfx-ripple-color: derive(-mfx-main, 120%); +} + +.mfx-filter-pane .header #resetIcon .mfx-ripple-generator { + -mfx-ripple-radius: 20; + -mfx-ripple-color: derive(-mfx-red, 60%); +} + +.mfx-filter-pane .header #filterIcon .mfx-font-icon, +.mfx-filter-pane .header #resetIcon .mfx-font-icon { + -mfx-color: -mfx-gray; +} + +.mfx-filter-pane .header #filterIcon:hover { + -fx-background-color: derive(-mfx-main, 150%); +} + +.mfx-filter-pane .header #resetIcon:hover { + -fx-background-color: derive(-mfx-red, 90%); +} + +.mfx-filter-pane .header #filterIcon:hover .mfx-font-icon { + -mfx-color: -mfx-main; +} + +.mfx-filter-pane .header #resetIcon:hover .mfx-font-icon { + -mfx-color: -mfx-red +} + +.mfx-filter-pane .mfx-combo-box .focused-line, +.mfx-filter-pane .mfx-combo-box .unfocused-line { + -fx-stroke: transparent; +} + +.mfx-filter-pane .mfx-combo-box { + -mfx-animate-lines: false; + + -fx-background-color: -mfx-main-lighter; + -fx-background-radius: 30; + -fx-border-color: lightgray; + -fx-border-width: 0.5; + -fx-border-radius: 30; + -fx-padding: 0 3 0 5; /* TODO FIX */ +} + +.mfx-filter-pane .filter-combo { + -fx-min-height: 36; + -fx-min-width: 120; +} + +.mfx-filter-pane .predicates-combo { + -fx-min-height: 36; + -fx-min-width: 180; +} + +.mfx-filter-pane .mfx-combo-box:focused { + -fx-background-color: -mfx-main; +} + +.mfx-filter-pane .mfx-combo-box .mfx-label { + -mfx-font-family: "Open Sans SemiBold"; + -mfx-text-fill: -mfx-charcoal; +} + +.mfx-filter-pane .mfx-combo-box:focused .mfx-label { + -mfx-text-fill: white; +} + +.mfx-filter-pane .mfx-combo-box .mfx-icon-wrapper .mfx-font-icon { + -mfx-color: gray; +} + +.mfx-filter-pane .mfx-combo-box:focused .mfx-icon-wrapper .mfx-font-icon { + -mfx-color: white; +} + +.mfx-filter-pane .mfx-combo-box .mfx-icon-wrapper .mfx-ripple-generator { + -mfx-ripple-color: -mfx-main-lighter; +} + +/* TODO fix */ +.mfx-filter-pane .mfx-combo-box .mfx-list-view { + -fx-background-color: red; +} + +.mfx-filter-pane .mfx-combo-box .mfx-list-view .mfx-list-cell:selected { + -fx-background-color: transparent; +} + +.mfx-filter-pane .mfx-text-field { + -fx-min-width: 180; + -fx-min-height: 36; + -mfx-animate-lines: false; + -fx-background-color: transparent; + -fx-border-color: lightgray; + -fx-border-width: 0.7; + -fx-border-radius: 100%; + -fx-padding: 7 8 7 8; +} + +.mfx-filter-pane .mfx-text-field .focused-line, +.mfx-filter-pane .mfx-text-field .unfocused-line { + -fx-stroke: transparent; +} + +.mfx-filter-pane .mfx-button { + -fx-pref-width: 135; + -fx-pref-height: 36; + -fx-background-color: #7915D9; + -fx-background-radius: 30; + -fx-text-fill: white; + -fx-font-weight: bold; +} + +.mfx-filter-pane .mfx-button .mfx-ripple-generator { + -mfx-ripple-color: rgba(250, 250, 250, 0.6); + -mfx-ripple-radius: 45; +} + +.mfx-filter-pane .active-filter { + -fx-min-height: 30; + -fx-background-color: #B379C1; + -fx-background-radius: 30; + -fx-padding: 0 20 0 20; +} + +.mfx-filter-pane .active-filter .mfx-font-icon { + -mfx-color: white; +} + +.mfx-filter-pane .active-filter .label { + -fx-font-family: "Open Sans Regular"; + -fx-text-fill: white; +} + +.mfx-filter-pane .active-filter .function-text { + -fx-font-family: "Open Sans Bold"; +} + +.mfx-filter-pane .and-or-text { + -fx-font-family: "Open Sans Bold"; + -fx-font-size: 14; + -fx-fill: -mfx-gray; +} \ No newline at end of file diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle1.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle1.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle2.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle2.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle3.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXLabelStyle3.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXListCell.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXListCell.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXListView.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXListView.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXNotification.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXNotification.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXNotificationCenter.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXNotificationCenter.css new file mode 100755 index 00000000..0d4125fe --- /dev/null +++ b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXNotificationCenter.css @@ -0,0 +1,88 @@ +@import "MFXColors.css"; +@import "Fonts.css"; + +.mfx-notification-center { + -mfx-main: #7A0ED9; + -fx-background-color: transparent; +} + +.mfx-notification-center .notifications-icon { + -fx-background-color: white; + -fx-background-radius: 100%; + -fx-border-color: lightgray; + -fx-border-radius: 100%; +} + +.mfx-notification-center .counter { + -fx-background-color: -mfx-main; + -fx-background-radius: 100%; +} + +.mfx-notification-center .counter .text { + -fx-fill: white; + -fx-font-family: "Open Sans Bold"; + -fx-font-smoothing-type: gray; +} + +.mfx-notification-center .header { + -fx-border-color: transparent transparent lightgray transparent; + -fx-border-width: 0.7; + -fx-padding: 5 0 5 0; +} + +.mfx-notification-center .header .mfx-label { + -mfx-line-color: transparent; + -mfx-unfocused-line-color: transparent; + -mfx-animate-lines: false; + + -mfx-font-family: "Open Sans SemiBold"; + -mfx-font-size: 14; + -mfx-text-fill: -mfx-onyx; +} + +.mfx-notification-center .header .mfx-toggle-button { + -mfx-toggle-color: -mfx-main; + -mfx-untoggle-line-color: derive(-mfx-onyx, 30%); + + -fx-font-family: "Open Sans SemiBold"; + -fx-font-size: 12; + -fx-text-fill: -mfx-onyx; + -fx-font-smoothing-type: gray; +} + +.mfx-notification-center .notifications-container { + -fx-background-color: white; + -fx-background-radius: 5; + -fx-border-color: lightgray; + -fx-border-radius: 5; + -fx-border-width: 0.7; + -fx-padding: 5 1 1 1; +} + +.mfx-notification-center .notifications-container .virtual-flow .mfx-notification-cell #check { + -mfx-checked-color: -mfx-main; + -mfx-unchecked-color: -mfx-onyx; +} + +.mfx-notification-center .notifications-container .virtual-flow .mfx-notification-cell #check .ripple-container .mfx-ripple-generator { + -mfx-ripple-color: derive(-mfx-main, 125%); +} + +.mfx-notification-center .actions { + -fx-border-color: lightgray transparent transparent transparent; + -fx-border-width: 0.7; + -fx-padding: 10; +} + +.mfx-notification-center .actions .mfx-font-icon { + -mfx-color: -mfx-onyx; +} + +.mfx-notification-center .notifications-container .actions .mfx-icon-wrapper .mfx-ripple-generator { + -mfx-ripple-radius: 24; + -mfx-ripple-color: derive(-mfx-main, 150%) +} + +.mfx-context-menu .mfx-context-menu-item:hover { + -fx-background-color: derive(#7A0ED9, 150%); +} diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXPasswordField.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXPasswordField.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXProgressBar.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXProgressBar.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXProgressSpinner.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXProgressSpinner.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXRadioButton.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXRadioButton.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXRectangleToggleNode.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXRectangleToggleNode.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXScrollPane.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXScrollPane.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXSlider.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXSlider.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXStepper.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXStepper.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXStepperToggle.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXStepperToggle.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableColumn.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableColumn.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableRow.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableRow.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableRowCell.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableRowCell.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableView.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTableView.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTextField.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTextField.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXToggleButton.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXToggleButton.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeCell.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeCell.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeItem.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeItem.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeView.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/MFXTreeView.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXComboBox.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXComboBox.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXLegacyListCell.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXLegacyListCell.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXLegacyListView.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXLegacyListView.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXTableRow.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXTableRow.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXTableView.css b/materialfx/src/main/resources/io/github/palexdev/materialfx/css/legacy/MFXTableView.css old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Bold.ttf b/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Bold.ttf old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Light.ttf b/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Light.ttf old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Medium.ttf b/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Medium.ttf old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Regular.ttf b/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-Regular.ttf old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-SemiBold.ttf b/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-SemiBold.ttf old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-VariableFont_wght.ttf b/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/Comfortaa/Comfortaa-VariableFont_wght.ttf old mode 100644 new mode 100755 diff --git a/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/MFXResources.ttf b/materialfx/src/main/resources/io/github/palexdev/materialfx/fonts/MFXResources.ttf old mode 100644 new mode 100755 index 47a418739c3cae9e9a9e8f5a4e00b8a7395df943..f1afd55110595a5335a9e35fd4ce26c68b9c5cd7 GIT binary patch delta 2186 zcmai0Yiu0V6~2#|xwA9-nw{6acXro1v&-6EXT7@ah&f74KJbrTalsWyk zFA>5?puagc`^+hr!$5npIJfZZ@ptk5zXQF5(5N+kZ1!kz`@3a?#(o9+jd@@wFPpCe zeFf;Q`IC!FzZ_5f8R#2u=9Pt~9)Do=*xB!{A~fzDc<7fqrx!c6Q?J?ioRGo-3t}ednm6kpk_FM4jW_D!x6pVU|2j3PY9p13YscfZ zTd9m_>SW3%b|ooFc8SgLdVL(1t>p^?wf@OuQob)yC?xKaTgl{Pe{JBxvgI@7nB&A` z6D;M>2dGKYw269=iylPt2o-`jpR*kp^;%;W80QXQx8VZOUo}$LFw@wC*)%-!%J56$ z{%XVBMsJ%x1hiqYT-%Ej4&k;JEzb>5RUupM=E<|c;ZkWhIMO}D@#%oSH&7#D+7+x{d2q0 zSJ>4p8`8*f$+nwjG!V*HtNERwK-6s7c4>K}IHmBsYMLsURKC<{%RYkE%#Wp&D6Cv z4EbC;#9LrOuyf3Ngs`Axuu*k!qvjAaH#76R1MT^lnYlaHQ)6QbR;HD)7RJV=Iz)So zpX^~8+x*88JbM`X9ZdKTWAxI!Dmv)GJVZipM) z8yq5kg2LQ~jzfw=xwShaHN?zI*EG&xFH%A56>DjO`b_p!?t zd-R~{6Ist2WyjeOiD2HK9L|*vjVD!~#7jY*BiMMTP{T3h510}%xNFW*BMA|5n34x3 z&c&oKCOpOj6MK3-t4S>%uPY)=Jve*$q9aN^)gRgBDIZWGmtN^IR_!Y9FgyI#7OuUxavNee z?)8R;a%YzbTZjV(ElB`p;o_<(z&sQJ4B(E{TzCv>0P`y{WHbTidmtCy3yU-8@A+@7ah zLPbf?88_A3@d)L0MsvEJr4Xx##^FTWs!~xA@hIoIKWNl3p_~wt=)u9kgOrc(RFTZ6 z6nvCtA>kb?P}VXBa}6##mM{Z;UduRV4)<_jIi~j~)kH~8V-nc!p2!Pe5i7(3dB4$j zcJB!;An}}DuGPvK50RW8$M-xvAjn`8#C)>3V;WOfSh{XOq+=02UAMLYi>IW~c&_16 zrt&_JogN&VRxlwr7~0y^k%wD{@pW>AzRkVGz0cj` zqx^P$AOD%q6n-y!!J=%GEwML6L2Qa|iU0DYrH7;i=@)Xh{G$99|F;81U^Vbk;FDl) za5VTr@U_tS(2ekc@M8F?5>#fCGs@?Y^O0-nfcmNWl~&bOwU6}2^i_ix1IG7_pBOjI zY4g3|=((5>>x+F9ABmriUrOvtTu&ZM{wB4U=F$h#E19?@SWRo%dd_;)`Y^jadnEg# Y>}%Q2a;y2Su5kN*#}n(H?%Blu1sp(zAOHXW delta 478 zcmew`hw(u_V?6^S0|Ns$LjwadgMojrz7f9=TRTu>4-h9L=Oz}2hh2Kgz`!U2z@9N~5~DX`+-4ufK&H)+tP40czvX+uxVcsE zi_Yd&M`;cj`E`f-m=3#tRL7E*uvN*uye3`vFCBj;@HFSjI)OG z6_*6pI_@;?E8HJ=^myucX7JqL`N8{$&xLOR-w}QT{y6?s{MQ651Re?62zCh>3Hb;$ z30)D^5#A(xMI=b1OXQr$15pprWnwB~x5UH58zgkhB&JB5l4OvaC*>fuLYhhXh)jsg q3YiPCT(SzXKC%U}OXQg3wB#b>isaVG`^mpkxCM^O