I created a custom dialog with my own panes and controls in it. But the dialog has a white border default which I want to remove. Here is an example with a single image:
I tried using ScenicView but couldn't find a way to catch the dialog layer and modify it:
public class MainView extends View {
Image img = new Image("https://i.stack.imgur.com/7bI1Y.jpg", 300, 500, true, true);
public MainView(String name) {
super(name);
Button b = new Button("Pop");
b.setOnAction(e -> {
Dialog<Void> dialog = new Dialog<>();
dialog.setOnShown(e2 -> {
Parent parent = getParent();
Pane p = (Pane) parent.lookup(".dialog");
p.setPadding(new Insets(0));
});
dialog.setGraphic(new ImageView(img));
dialog.showAndWait();
});
setCenter(b);
}
}
Best i got was removing the flowpane child to remove some of the lower part
dialog.setOnShown(e2 -> {
Parent parent = getParent();
Pane p = (Pane) parent.lookup(".dialog");
p.getChildren().removeIf(c -> (c instanceof FlowPane));
System.out.println(p.getChildren());
});
Removing the VBox moves the dialog which i don't want to do and changing its padding also dose nothing.
As you can see with ScenicView, the Dialog has the dialog style class.
One easy way to modify the dialog style is via css. Just add a css file to your view, and set:
.dialog {
-fx-background-color: transparent;
}
That will set the background transparent, instead of the default white color.
If you want to remove the borders instead, then you can play with padding. As you can also see with ScenicView, the dialog has a VBox with style class container for the content in the center, and the flow pane for the buttons at the bottom, with style class dialog-button-bar.
Before anything, just use the setContent method to add the image instead of the setGraphic one:
dialog.setContent(new ImageView(img));
And this will be required to remove all the borders, and let the image take the whole dialog:
.dialog,
.dialog > .container,
.dialog > .dialog-button-bar {
-fx-padding: 0;
}
Related
I'm building a Vaadin 8 app ( first one for me ). I am using the designer to generate the UI. I've added several buttons to the dashboard which should fire a function when clicked. For some reason nothing fires when the image is clicked. Below is all the code that is involved. Can anyone see what I'm doing wrong?
This is the code from the .html file:
<vaadin-horizontal-layout responsive width-full margin>
**<vaadin-image icon="theme://images/properties.png" style-name="my-image-button" responsive alt="" _id="imagePropertyInfo"></vaadin-image>**
<vaadin-image icon="theme://images/occupants.png" responsive alt="" _id="imageOccupants"></vaadin-image>
<vaadin-image icon="theme://images/vendors.png" responsive alt="" _id="imageVendors"></vaadin-image>
</vaadin-horizontal-layout>
Here is the scss
.my-image-button
{
cursor: pointer;
}
Here is the code from the Dashboard UI
public DashboardHomeView( OnCallUI onCallUI )
{
this.onCallUI = onCallUI;
// Make it disabled until a property is selected
**imagePropertyInfo.setEnabled( false );
imagePropertyInfo.setStyleName( "my-image-button" );**
fetchPropertyBasicInfo();
}
protected void fetchPropertyBasicInfo()
{
List<PropertyProfileBasic> listOfPropertyProfiles = new ArrayList<PropertyProfileBasic>( OnCallUI.myStarService.fetchAllPropertyProfileBasicInformation() );
comboBoxGeneric.setCaption( "Select a Property" );
comboBoxGeneric.setItemCaptionGenerator( aProperty -> aProperty.toString() );
comboBoxGeneric.setItems( listOfPropertyProfiles );
comboBoxGeneric.addValueChangeListener( event -> fetchOccupantBasicInfo( event ) );
comboBoxGeneric.focus();
}
protected void fetchOccupantBasicInfo( ValueChangeEvent<PropertyProfileBasic> event )
{
// Fetch all the occupants for the selected property
if( event.getValue().getPropertyNo() != null )
{
// Fetch a list of occupant basic info for the selected property
List<OccupantProfileBasic> listOfOccupantProfiles = new ArrayList<OccupantProfileBasic>( OnCallUI.myStarService.fetchOccupantProfileBasicByPropertyNo( event.getValue().getPropertyNo() ) );
// Clear the existing grid et al
gridContainer.removeAllComponents();
// Add the occupant grid
occupantGrid = new OccupantProfileBasicGrid( listOfOccupantProfiles );
// Show the grid
gridContainer.addComponents( new Label( "Occupants" ), occupantGrid );
// Set the dashboard buttons to enabled now a property is selected
**imagePropertyInfo.setEnabled( true );
// Add the property info button
imagePropertyInfo.addClickListener( e -> fetchPropertyInformation() );**
}
}
protected void fetchPropertyInformation()
{
Notification.show( "Yo!", "You clicked!", Notification.Type.HUMANIZED_MESSAGE );
}
I assume you are using GridLayout. I am recommending another approach. Use Button, and set the button style to be borderless (apparently you want something like that. The icon of the button can be image from your theme, using ThemeResource. "Pseudo code" is something like this:
ThemeResource icon = new ThemeResource("/images/properties.png");
Button imagePropertyInfo = new Button(icon);
imagePropertyInfo.setStyleName(ValoTheme.BUTTON_BORDERLESS);
imagePropertyInfo.addClickListener( e -> fetchPropertyInformation() );
Note also, JavaDoc of Image component says.
"public Registration addClickListener(MouseEvents.ClickListener listener)
Add a click listener to the component. The listener is called whenever the user clicks inside the component. Depending on the content the event may be blocked and in that case no event is fired."
I think it does not like your way of setting image with theme, without using Resource.
If you want to remove the focus highlight of the button, it should be possible via this CSS rule:
.v-button-link:after {
content: none;
}
Also it is worth of mentioning that Image is not Focusable, while Button is. This means that even that Image can have click listener, it is not reached by keyboard navigation, Button is Focusable and is reached by tabbing etc. So using Button instead of Image makes your application more accessible.
If I set the ExtendedDescription text for a DefaultOption clicking the option opens a view where the text is displayed in an HBox and is centered there. I would like to customize the HBox area where the text is: align the text not only to center, color the text or bold/italicise parts of it, add a small image maybe...
I didn't see any API to access anything relating to customization except for maybe OptionEditor but when I try to call editorFactoryProperty() the optional is always empty. Am I supposed to create one myself and set it? What is the process for that?
So far there is no API for the Extended View.
If you check it with ScenicView, you can see that the view nodes have custom style classes applied though, so you will be able to use lookups on runtime to get a hold of the BorderPane (id: extended-pane), the HBox at the top (id: extended-top), the one at the center (id: extended-center), and its Text child (styleClass: extended-text).
Something like this should work:
viewProperty().addListener((obs, ov, nv) -> {
if (nv != null && nv.getName().startsWith("Extended_View_Gender")) {
BorderPane pane = (BorderPane) nv.lookup(".extended-pane");
if (pane != null) {
Text text = (Text) pane.lookup(".extended-text");
text.setStyle("-fx-fill: red");
}
}
});
I have a Settings View with a styled AppBar and when I open a full screen dialog from that View, the AppBar styling follows the global swatch specified.
THEN, when I close the dialog box, the Settings View AppBar retains the dialog styling (it should have a white background, but it's green which is the swatch that is specified for the application).
Further Clarification:
The View is a page for Settings and then when you click each setting a dialog pops up with the content set to StackPanes that contain information for that specific setting.
I have tried to add a method that stylizes the AppBar on Dialog close, hide, and hidden event handlers:
public void initView(SettingView viewType) {
View pane = null;
try {
switch (viewType) {
case PASSWORD_CHANGE:
pane = getPasswordPane();
break;
case PROFILE_CHANGE:
pane = getProfilePane();
break;
case BANK_CHANGE:
pane = getBankPane();
break;
case NOTIFICATION_CHANGE:
pane = getNotificationPane();
break;
}
} catch (IOException e) {
System.out.println("IOException: " + e);
}
//this.settingsContainer = new Dialog(true);
this.settingsContainer.setContent(pane);
MobileApplication.getInstance().removeLayerFactory("$$$DropdownButtonSkin$$$");
Platform.runLater(new Runnable() {
#Override
public void run() { //None of these change the appbar styling
settingsContainer.setOnShowing(e -> { setAppBar("Settings");});
settingsContainer.setOnShown(e -> { setAppBar("Settings");});
settingsContainer.setOnHiding(e -> { setAppBar("Settings");});
settingsContainer.setOnHidden(e -> { setAppBar("Settings");});
//When closing the appbar the color remains to the swatch instead of the customized background
settingsContainer.setOnCloseRequest(e -> { setAppBar("Settings");});
settingsContainer.showAndWait();
}
});
}
public AppBar setAppBar(String name) {
Button menu = MaterialDesignIcon.MENU.button();
menu.setStyle("-fx-text-fill:darkgreen;");
menu.setOnMouseClicked(e -> {
MobileApplication.getInstance().showLayer(Appstar.MENU_LAYER);
});
AppBar appBar = MobileApplication.getInstance().getAppBar();
appBar.clear();
appBar.setNavIcon(menu);
appBar.setTitleText(name);
appBar.setVisible(true);
appBar.setBackground(new Background(new BackgroundFill(Color.WHITE, new CornerRadii(0), new Insets(0, 0, 0, 0))));
return appBar;
}
Considering that you want the same app-bar color on all views (i.e. white in all the views), the easiest way to solve this is to use CSS.
You can set the color of the AppBar on a full-screen dialog by using the custom style-class for the AppBar on a full-screen dialog i.e. dialog-fullscreen along with the base style-class app-bar. Therefore, you can use something like this:
.app-bar.dialog-fullscreen {
-fx-background-color: green; // OR -primary-swatch-500;
}
For setting the overall app-bar color to white, you can simply use:
.app-bar {
-fx-background-color: white;
}
If I create a settings pane and add new DefaultOption(...) to it with an icon and text then the controller on the right takes more space than it needs and trims the text in the middle.
Option<BooleanProperty> antiAliasingOption = new DefaultOption<>(MaterialDesignIcon.BLUR_OFF.graphic(),
"Anti-aliasing", "Toggle anti-Aliasing", null, new SimpleBooleanProperty(), true);
You can see that there's a lot of space (red line) for the toggle button which is not used and the text is cut off. I want the controls to be justified to the right like in a border pane where the center takes all unallocated space.
If you use Scenic View to inspect the Settings control, you will find that for every Option there is an HBox that contains a left HBox for the icon, a central VBox for the text and a right HBox for the editor.
All these containers have style classes, so an easy way to modify any of them on runtime is by using lookups.
As for the right HBox, you can look for the secondary-graphic and then set the preferred width:
public BasicView(String name) {
super(name);
Option<BooleanProperty> antiAliasingOption = new DefaultOption<>(MaterialDesignIcon.BLUR_OFF.graphic(),
"Anti-aliasing", "Toggle anti-Aliasing", null, new SimpleBooleanProperty(), true);
SettingsPane settings = new SettingsPane(FXCollections.<Option>observableArrayList(antiAliasingOption));
settings.setSearchBoxVisible(false);
setCenter(settings);
setOnShown(e -> {
HBox rightBox = (HBox) settings.lookup(".secondary-graphic");
rightBox.setPrefWidth(60);
});
}
Another option is to override the default styling within your css file:
.settings-pane .options-grid > .option-row > .secondary-graphic {
-fx-pref-width: 60;
}
I've the this Shadow Element/root in this example http://jsfiddle.net/fyf6thte/8/ working perfectly with JavaScript, interested to have similar one with DART, so I wrote the below code (using the same html and css file), but I could not see the button it looks theshadow.innerHTML = '<button id="d">click</button>'is not working
the full code is:
import 'dart:html';
void main() {
var thehost = document.querySelector('#host1');
document.registerElement(fonixDiv.tag, fonixDiv);
thehost.append(new fonixDiv());
}
class fonixDiv extends HtmlElement {
static final tag = 'fonix-div';
var shadow;
bool disabled;
factory fonixDiv() => new Element.tag(tag);
fonixDiv.created() : super.created() {
shadow = this.createShadowRoot();
shadow.host.innerHTML = '<button id="d">click</button>';
shadow.host.onClick.listen((e){
this.host.dataset.disabled='true'; // set Attribute to the custom element
});
shadow.children.d.onClick.listen((e){
this.text = "you clicked me :(";
// or shadow.children[0].textContent="Shadow DOM content changed";
this.disabled=true;
// alert("All: button, text and host should be change");
});
}
#override
void attached() {
super.attached();
this.disabled=disabled;
}
}
I'm not sure about the accuracy of the balance of the code, I can check it only after I see the button.
any help.
The error is correct: in Dart 'this' is not bound contextually as in JS and instead we have lexical scoping;
in your dart code you are actually changing the text content of the custom element and not of the target of the event (the button in the shadow root). So basically you have a custom element, you set the text content on it but you also have a shadow root created inside of that same DOM node and it shadows everything else you put inside that custom element and that is why you do not see it and continue to see the shadow root's content - this is how shadow root works by design.
To fix it you need to update the text content (and the disabled property) on the button (for example e.target.text = ...).
Hope this helps.
Seems like the .host should be removed from this line
shadow.host.innerHTML = '<button id="d">click</button>';
shadow.innerHTML = '<button id="d">click</button>';
The jsfiddle doesn't have it and it seems weird. I think with .host you add it basically to this and therefore as child not as content.
I think the main issue is: Use innerHtml instead of innerHTML.
There are a few additional minor things you need to fix:
Remove 'host', as Gunter says, you want to set the innerHtml of the shadow.
Instead of shadow.children.d.onClick, do shadow.querySelector('#d').onClick.
Also, do dataset['disabled'] instead of dataset.disabled.