alter style definition in vaadin - css

I have code that will hide components dynamically; it uses [component].addStyleName("name") to add a style to a component, and that style is defined to hide the component.
I have a page which will have a large number of components; I can put them in an array and do this, but I'm hoping for a different way. I would like to assign all those components their own style - something like "costPanel" - and then use server-side vaadin code to alter the definition of the style "costPanel" at runtime.
The Page.Styles class in Vaadin has no methods for obtaining existing styles nor altering ones that are there -- the only methods are for adding them.
Is this possible in Vaadin, even if I have to do something on the client side for it?

This is perhaps best suited as a comment, but it does not really fit in there.
Not trying to be patronising, but it sounds like you're trying in a very complicated way to reinvent the wheel. component.setVisible(false) will do exactly what you need, as in the component will not take up any space since it won't actually exist in the DOM itself. Take a look at the example below:
Code:
public class LayoutWithInvisibleComponents extends VerticalLayout {
private int index = 0;
public LayoutWithInvisibleComponents() {
// add a visibility toggling button
addComponent(new Button("Toggle next", event -> {
Component component = getComponent(++index);
if (component instanceof Button) {
// just toggle the next one if it's a button
component.setVisible(!component.isVisible());
}
if (index == getComponentCount() - 1) {
// reset counter
index = 0;
}
}));
// add some invisible dummy buttons
for (int i = 0; i < 5; i++) {
Button button = new Button("Button " + i);
button.setVisible(false);
addComponent(button);
}
// and add a visual delimiter
Panel rightPanel = new Panel(new Label("---------- some visual delimiter ----------"));
rightPanel.setSizeFull();
addComponent(rightPanel);
}
}
Result:
Is there anything else I'm missing?

This also would make a better comment, but doesn't fit well enough there.
The following is from the Book of Vaadin:
Beware that invisible beings can leave footprints. The containing layout cell that holds the invisible
component will not go away, but will show in the layout as extra empty space. Also expand ratios
work just like if the component was visible - it is the layout cell that expands, not the component.
The phrase "show in the layout as extra empty space" convinced me that there would be blank, open, background-colored space where my component was supposed to be. I don't remember if I tried it, but I might have and had some other error that caused me to conclude my assumption was correct, and that the setting was for making it un-rendered but with the space still visible.
Vaadin has much better documentation than most of the industry, but in this case I got the meaning crossed up. In succeeding paragraphs they even have additional explanation that does say what I learned through this question, but the part quoted here seemed to contradict it.

Related

I'm wondering about custom attributes, CSS attribute selector & repaint

So a little disclaimer: I am completely and utterly self taught. Bear over with me if I'm being a clown.
Anyways, I am currently working on a some platform and in need for a dropdown functionality. That's simple right? Just use HTML5 select tag. However option tags can't be styled :>
So onwards to build my own. The HTML5 select tag uses keyboard input (up/down/enter) for those with disabilities, and I thought I would implement that too. That did present a problem though: The :hover selector collided with my custom attribute, which I use to style keyboard selected items (&[data-selected=true] to be precise).
So onwards to implement my own :hover. And this is where my bewilderment starts.
const handleChildMouseOver = () => {
const items = Array.from(listItem.current?.children!); // The wonders of typescript XD
for (const item of items) {
if (item === event.target) {
item.setAttribute("data-selected", "true");
} else {
item.removeAttribute("data-selected"); // I'm removing the attribute, rather than toggling it, because I got components with 3 states: On, off, and default.
}
}
}
(...)
<ul css={css.list} /*emotion prop*/ data-toggled={toggled} /*parent state*/ onMouseOver={handleChildMouseOver}>
{children} // parent prop
</ul>
So it works as intended, which is fine. But I recall from my pre-react days that you should never manipulate the DOM in loops, as it causes repaints on every iteration. However when I look at the Dev Tools performance profiler, I barely see any "Paints", 8 or so, even when I'm switching hover targets like a madman. What I do see is one million "Composite layer". Oh, and as a bonus React doesn't re-render. Which is fine right? 'Cause I'm not really changing the state of anything, just adding some CSS.
So my question boils down to: Am I being bonkers or smart?
N.B.: I would love to share the actual component, but seeing as this is my first post on stackoverflow, I've got no clue how you do those fancy script tag. Well github is involved somehow, I know that much 🤔

How do I overlay two Xamarin Forms layouts such that both can receive touch inputs?

(I posted this initially on the Xamarin Forums, but then decided I might get a faster answer here?)
TL;DR: Some layouts will count a tap on a transparent background, others won't. Setting InputTransparent on a container sets it for all of its children, and I feel like children should be able to override the parent. I need to create elements that overlay another element and pass taps through a transparent region but still have tappable buttons. When I try this with a Grid, it doesn't work. I don't want to go back to AbsoluteLayouts. I'm mostly working in iOS right now, I'm not quite sure if it's a problem in Android yet. Windows Phone/UWP isn't on the table.
Longer version:
I'm rewriting some layouts that worked OK in an older Xamarin Forms (1.3 I think). We recently upgraded to 2.1, and it wreaked havoc on the layout code's bad decisions. I'm tasked with updating the layouts to behave themselves. While I recognize 2.2 has been released, I just tried an upgrade and everything I'm typing seems true in that version as well, so it's not a 2.1 vs. 2.2 issue, or at least if some improvements are made they aren't helping me.
It's a mapping application, so the centerpiece of all layouts is an expensive, temperamental OpenGL element. This element very much does not like to be reparented, so I've adopted a layout sort of like this imaginary XAML:
<ContentPage>
<CustomLayout>
<OurHeaderControl />
<TheMapControl />
<OurFooterControl />
<MapOverlay />
</CustomLayout>
</ContentPage
The purpose of "MapOverlay" is to implement our workflows by adding Xamarin elements on top of the header/footer areas and/or the map. For example, one layout adds a list of directions to the bottom above the footer, so it has less room for the map to appear. The custom layout understands this and lays out the map after the overlay so it can ask for the correct map bounds.
In this layout, I cannot tap on anything the MapOverlay is over. I can make it InputTransparent and tap those things, but then all of its children are also not tappable. This was not true in the old layouts.
Here's the only differences I see between the old layouts and the new:
The old layouts were a complicated mess of AbsoluteLayouts. It looked something like this, I didn't write it:
<ContentPage>
<AbsoluteLayout> // "main layout"
<AbsoluteLayout> // "map layout"
<Map /> // An AbsoluteLayout containing the OpenGL view.
</AbsoluteLayout>
<AbsoluteLayout> // "child layout"
<SubPage /> // An AbsoluteLayout
</AbsoluteLayout>
</AbsoluteLayout>
</ContentPage>
The main layout contains AbsoluteLayouts to constrain the child views. One child view is itself an AbsoluteLayout that contains the Map and a handful of other elements associated with it. The other child is the overlay, which is always an AbsoluteLayout that contains the elements relevant to that overlay. These layouts all reference each other in cycles and update each other as layout events change. It's a fascinating ping-ponging that eventually settles down. Usually. Sometimes things just disapper. Obviously there's a reason I'm rewriting it.
But I can click on what I need to click on at every layer, and I don't get that.
So, let's talk about what I need to work, and maybe figure out if it's a bug why it's not working, or if it's a coincidence that it worked with other layouts. Here's a non-XAML page layout that demonstrates, my project's got its roots in the days when you couldn't use XAML in shared libraries:
I need to be able to tap both buttons in this UI and have them respond.
public class MyPage : ContentPage {
public MyPage() {
var mainLayout = new AbsoluteLayout();
// Two buttons will be overlaid.
var overlaidButton = new Button() {
Text = "Overlaid",
Command = new Command((o) => DisplayAlert("Upper!", "Overlaid button.", "Ah."))
};
mainLayout.Children.Add(overlaidButton, new Rectangle(0.25, 0.25, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize), AbsoluteLayoutFlags.PositionProportional);
// The top overlay layout will be a grid.
var overlay = new Grid() {
RowDefinitions = { new RowDefinition() { Height = new GridLength(1.0, GridUnitType.Star) } },
ColumnDefinitions = {
new ColumnDefinition() { Width = new GridLength(1.0, GridUnitType.Star) },
new ColumnDefinition() { Width = new GridLength(1.0, GridUnitType.Star) },
},
BackgroundColor = Color.Transparent
};
var overlayingButton = new Button() {
Text = "Overlaying",
Command = new Command((o) => DisplayAlert("Upper!", "Overlaying button.", "Ah."))
};
overlay.Children.Add(overlayingButton, 0, 1);
mainLayout.Children.Add(overlay, new Rectangle(0, 0, 1.0, 1.0), AbsoluteLayoutFlags.All);
// This pair of property sets makes the overlaid button clickable, but not the overlaying!
// overlay.InputTransparent = true;
// upperOverlayButton.InputTransparent = false;
Content = mainLayout;
}
}
This only lets me tap the "overlaying" button even when I change the Grid to an AbsoluteLayout.
I'm stumped. It took me 2 weeks to debug the initial layouts and come up with a new solution. I really don't want to disassemble all of our layouts and put everything in one big AbsoluteLayout or a custom layout. In WPF, there were two kinds of transparent: "transparent background" meant the background could still hit test, and "null background" meant the background would not hit test. Is there some way to overlay layouts in Xamarin like this?
Or, more appropriate, why is the convoluted nest of numerous AbsoluteLayouts in our old layouts working like I need it to, but this much simpler layout isn't?
updates
Here's some additional information I remembered:
This behavior is iOS specific. On Android, both the example code and our code work.
I'm not the first person to have this problem: On StackOverflow. On Xamarin's Forums.
In general it seems as if the behavior with iOS in regards to how InputTransparent is being handled in a Grid compared to the other two platforms. I'm not particularly certain whether I'd quantify the current behavior as a bug at this time, but I understand that it's frustrating to run into a disparity in platform behavior.
There is a fix of sorts for your situation, though, if I'm understanding it correctly. It appears similar a similar report was filed before and behavior regarding iOS was mentioned via this SO link. The question is posed in the scope of a non-Forms iOS app, but the logic can be applied here.
By using a custom renderer (let's use a CustomGrid as an example), you can specifically implement the iOS implementation of the Grid to follow the aforementioned link's manner of finding underlying views:
CustomGrid.cs (PCL):
public class CustomGrid : Grid
{
public CustomGrid() { }
}
CustomGrid.cs (iOS):
[assembly: ExportRenderer(typeof(CustomGrid), typeof(CustomGridRenderer))]
public class CustomGridRenderer : ViewRenderer
{
public override UIKit.UIView HitTest(CoreGraphics.CGPoint point, UIKit.UIEvent uievent)
{
UIView hitView = base.HitTest(point, uievent);
if (hitView == this)
{
return null;
}
return hitView;
}
}
In this manner you should not explicitly set InputTransparent for iOS, and any taps on the Grid itself are sent through to anything below. Since Android works with InputTransparent, though, in this particular case you can wrap that inside a Device.OnPlatform statement and skip implementing the Android custom renderer if you don't want to:
Device.OnPlatform(Android: () =>
{
overlay.InputTransparent = true
});
Using your above code modified to use the CustomGrid and iOS renderer, I'm able to tap both buttons.

Adding new stylesheet parameters for custom Qt widgets

I would like to add stylesheet options for a custom widget I have developed. We have extended the QPushButton to be a different colour and to flash when it is depressed. This has been done by adding a new property, background color down. And we set this in code. But I would like to set this instead using a Qt stylesheet entry, something like
QFlashingButton
{
background-color-down: yellow;
flashing-interval: 5;
}
I can see one way to do this, read out the stylesheet info using the stylesheet() method, then parse it for parameters relevant to my widget and set them. But I am wondering if there is some way to access the code Qt have themselves for processing stylesheets. At first sight of their code this seems perhaps not to be publically available.
As long as the parameter you want to control in the stylesheet is a QProperty, you can set it in the stylesheet using the syntax: qproperty-<PROPERTY_NAME>: <PROPERTY_VALUE>
I don't think property names can actually have dashes in them, so assuming your QProperties on your custom widget are actually backgroundColorDown and flashingInterval, then your stylesheet would look like:
QFlashingButton
{
qproperty-backgroundColorDown: yellow;
qproperty-flashingInterval: 5;
}

Inconsistent style of disabled components in ExtJS

I have an ExtJS form that uses hbox-layout containers to create sentences that contain form inputs and there is a requirement to disable the form under certain conditions. The hbox-layout containers have a series of radio, text, checkbox, and textfield components. You can see an example on jsfiddle.
This is an answered question here on SO that doesn't fully work for me because if you disable something that isn't a field (like the text component I'm using) the disable style is different - it appears to mask the component instead of just graying out the text. When nested components are disabled, the mask gradients stack. Examples of this scenario are illustrated on this jsfiddle.
Is there a way to override how text handles its styling when it becomes disabled? I think that may be the easiest solution.
You'll have to handpick each style fix, but yes that's completely possible. Just addCls to give a hook for your CSS...
For example, using the following CSS:
.my-disabled-ct text {
opacity: .3;
}
You can give a similar disabled look both to fields and text items with the following code:
var rootCt = Ext.getCmp('lotsOfItems');
rootCt.query('field').forEach(function(field) {
field.disable();
});
rootCt.query('container').forEach(function(ct) {
ct.addCls('my-disabled-ct');
});
You should probably avoid using disable on field since Ext put a mask over them then (though you could probably hide it with CSS).
You could add the class and target the CSS directly to text items however, why not? In this case, you would query for 'text' and use addCls on them, with this kind of CSS:
text.my-disabled-cls {opacity: .3;}
That goes without saying that you'll restore your components look to "not disabled" by removing the CSS class with the same query and the removeCls method.

Interleave row/column colors in a GridView

Suppose you have a GridView with a few columns like:
| Foo | Bar | Total |
and you use a style sheet to make the alternating rows different colors, say light blue and white.
Is there a good way to make a particular column alternate in a different color? For example, I might want the Total column to alternate in medium and light red to bring attention to it in a large grid.
BTW, I know you can programmatically change the color of a cell. I'd like to stick to CSS if it all possible, however, so all my style stuff is in one place. I also don't see an easy way to tell if I'm in an alternating row when I'm inside the event handler.
If you're using jQuery, you can do it pretty easily.
$("table#myTable col:odd").css("background-color:#ffe");
the :odd selector is not available in most current browsers, but jQuery gives it to us today.
For rows, you can do it with the built-in AlternatingRowStyle element.
Edit: found a good resource for some different ways of doing this: http://css-discuss.incutio.com/?page=StylingColumns
In addition to Ben's suggestion, Matt Berseth also has quite a nice demo of how to do rollover highlighting of columns as well using the GridViewControlExtender which is quite nice:
http://mattberseth2.com/demo/Default.aspx?Name=GridViewControlExtender+II+-+Header+Cell+MouseOver+Styles+and+a+Few+More+Live+Examples&Filter=All
There's also a ton of other stuff on how to enhance your GridView on his site as well:
http://mattberseth.com/blog/gridview/
Quite a few of the examples use the ASP.NET Ajax and Ajax Control Toolkit bits, but they're not too hard to port to lightweight jQuery equivalents.
going off on 2 tangents here...
P.S. "also don't see an easy way to tell if I'm in an alternating row when I'm inside the event handler."
Row.RowState == RowState.Alternating
Also, you can always set the CssClass on the appropriate cells in ASP.NET, and then define that class in your css.
I found this when searching for the same question regarding the WPF ListView's GridView. There, the answer is to use a StyleSelector like this one described by Bea Costa:
public class ListViewItemStyleSelector : StyleSelector
{
private int i = 0;
public override Style SelectStyle(object item, DependencyObject container)
{
// makes sure the first item always gets the first style, even when restyling
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(container);
if (item == ic.Items[0])
{
i = 0;
}
string styleKey;
if (i % 2 == 0)
{
styleKey = “ListViewItemStyle1″;
}
else
{
styleKey = “ListViewItemStyle2″;
}
i++;
return (Style)(ic.FindResource(styleKey));
}
}
There are a few nits to pick to get this to work really well, which are all described in her blog post.
One thing that connot be helped, is that this only works for rows. Columns seem to always have to use the CellTemplate/Style.

Resources