Flash required to explore WidSets
The newest version of the Flash Player is required to explore WidSets. Please download and install the free Flash Player from the icon below.
After installation, refresh this page »
vertical alignment behaving badly
vertical alignment behaving badly
I have a situation where I have a scrollable list of items where each item is supposed to have an image on the left side, vertically centered, and text on the right side. So for example if there's 100 pixels worth of text vertically, an if the image is 50 pixels in height, the image should be positioned so that its top edge is 25 pixels from the top edge of the item. The text is split in two parts: a headline with a larger font and then a multi-line description.
I'm trying to accomplish this as follows:
A Flow for each item in the list. Each item Flow in turn has two children: a Picture and a Flow for the text. And the text flow in turn has a Label for a headline and then a Text for a description text.
These are then stacked inside a flow, which is in a Scrollable. Everything is working pretty much as expected except the vertical alignment of the Picture. The picture always aligns vertically to the top no matter what alignment I specify in the stylesheet.
The top-level Flow for the item, the Picture as well as the Flow for the text all have alignment set as RuleName { align: left vcenter; } but the vertical alignment doesn't seem to work at all.
Any ideas? Need more info?
The code is as follows:
// create item flow
Flow item = new Flow(getStyle("ListItemFlow"));
item.setPreferredWidth(-100);
item.setFlags(VISIBLE | FOCUSABLE | LINEFEED);
item.setData(itemData);
item.setAction(CMD_OPEN);
// add image (if specified)
Image image = getImage("item_icon.png");
Picture pic = new Picture(getStyle("ListItemImage"), image);
pic.setFlags(VISIBLE);
item.add(pic);
// create text flow
Flow textFlow = new Flow(getStyle("ListTextFlow"));
textFlow.setFlags(VISIBLE);
// create label for headline
Label headlineLabel = new Label(getStyle("ListItemHeadline"), headline);
headlineLabel.setFlags(VISIBLE | LINEFEED);
textFlow.add(headlineLabel);
// create text for description
Text descriptionText = new Text(getStyle("ListItemDescription"), description);
descriptionText.setFlags(VISIBLE | LINEFEED);
textFlow.add(descriptionText);
item.add(textFlow);
The relevant styles are like this:
ListItemFlow {
background: vgradient rgb(30,60,110) rgb(10,40,90);
border: 1 1 1 1;
border-type: rectangle rgb(0,20,60);
padding: 2 2 2 2;
align: left vcenter;
focused {
background: vgradient rgb(70,100,150) rgb(40,70,120);
border-type: rectangle rgb(255,0,00);
}
}
ListItemImage {
align: left vcenter;
}
ListTextFlow {
align: left vcenter;
}
ListItemHeadline {
color: rgb(255,255,255);
font: proportional medium;
align: left vcenter;
}
ListItemDescription {
color: rgb(255,255,255);
font: proportional small;
align: left vcenter;
}
Re:vertical alignment behaving badly
Hi Peppe!
This is a little bit tricky one. Since the components doesn't inherit the size of the parent component automatically, and since the text (I suppose) is generated dynamically so you can't give a static height to your picture component, you have to calculate the component size every time you create one and give the height to your picture component.
Something like this:
// add image (if specified)
Image image = getImage("item_icon.png");
Picture pic = new Picture(getStyle("ListItemImage"), image);
pic.setFlags(VISIBLE);
item.add(pic);
.
.
.
// create text for description
Text descriptionText = new Text(getStyle("ListItemDescription"), description);
descriptionText.setFlags(VISIBLE | LINEFEED);
textFlow.add(descriptionText);
//new code
Shell tmpShell = new Shell(textFlow);
tmpShell.computeLayout();
int w, int h = textFlow.getSize();
pic.setPreferredHeight(h);
Hopefully you'll get it working!
BR Pekka
Re:vertical alignment behaving badly
Ok, so I read your post a bit too fast.
You can just give your picture component a static height of 100: pic.setPreferredHeight(100). And that should do the trick.
Re:vertical alignment behaving badly
| PekkaT wrote: Ok, so I read your post a bit too fast. You can just give your picture component a static height of 100: pic.setPreferredHeight(100). And that should do the trick. |
But hold on a second! Let's simplify this a bit.. If you have a container (a Flow) that contains inside it two components side by side, let's call them A and B, and let's say A is 50 pixels high and B is 100 pixels high, then shouldn't A and B be aligned vertically centered inside the container Flow if the style says align: left vcenter? If not, then what does vcenter alignment even do?
From what I see, the parent container should be sized dynamically according to the children's size (in this case the max height comes from B and is 100). Since the parent container is now 100 pixels in height and contains A and B side by side, B is filling up the parent 100% but A is only taking up 50% of the height. Since CSS alignment says vcenter, A should be positioned with equal margin above and below it - in other words, A should be at y=25. With align: top, you'd think y=0 and with align: bottom it would be y=50.
That certainly seems to be what one would assume based on the CSS rules and the API! Can you explain why that's not actually happening? I mean you said children don't inherit the parent's size. But I don't see how that's relevant. What's relevant is parent's being sized from the children! I don't even want the children's size to be inherited. :)
And in any case, programatically setting size is not really a possibility since the text inside one of the child components in the Flow is dynamic and there's no way to know how it will wrap and thus how high it will be until the it's actually laid out inside the UI component tree. And that's all being handled by the UI framework.
Could it be that alignments don't work unless dimensions are set explicitly for a component?
Peppe
Re:vertical alignment behaving badly
I'm afraid you've misunderstood something about CSS of widgets. You write "align: hcenter vcenter" not to place the component at the center of its parent, but to place its children at the its center. In another word, the alignment constraints only affect the children's position. So, if you want to judge the position of a component, rewrite the stylesheet for its parent, but not itself.
As for your widget, you can use a "frame" Flow to contain the Picture, which is made the same height with the text Flow and has a vcenter alignment. I 'm sure you know how to realize it.
Re:vertical alignment behaving badly
| yaiba wrote: I'm afraid you've misunderstood something about CSS of widgets. You write "align: hcenter vcenter" not to place the component at the center of its parent, but to place its children at the its center. In another word, the alignment constraints only affect the children's position. So, if you want to judge the position of a component, rewrite the stylesheet for its parent, but not itself. As for your widget, you can use a "frame" Flow to contain the Picture, which is made the same height with the text Flow and has a vcenter alignment. I 'm sure you know how to realize it. |
I think you need to read my post(s) again because I'm not confused about what the CSS does. I fully realize it is a rule for a parent for how to align the children. That's why you'll see me state several times that the alignment for the *CONTAINER* (the container of the child elements, i.e. the parent) is "left, vcenter".
Please check the original source code (including CSS) that I provided and you'll see the alignment for the parent.
Peppe
Re:vertical alignment behaving badly
I'm surprised that there's been so much confusion over this. The situation is actually quite simple despite my slighter more complex real-world case. The problem case is simply:
A Flow that has two children. One with a fixed height and one that has a height that depends on its text content. The width of both is always constant. What I want is for both the first and the second to be vertically centered inside the parent Flow. I assumed it would be done simply by setting align: left vcenter (or hcenter vcenter) for the parent. But that doesn't seem to do anything but rather just results in both children being top-aligned.
Does this happen because the parent Flow doesn't have an explicitly set height? Or what's going on?
EDIT: I just found this from the API docs for the Flow class: "If vertical alignment is other than TOP it is recommended to have Flow that has explicit height (i.e. Component.setPreferredWidth(int) has been set with != 0 value."
That's what I was afraid of.. Could the cases when the height has to be explicit be clarified? Also, there seems to be a typo in the docs as that should be setPreferredHeight - not Width.
Peppe
Re:vertical alignment behaving badly
I must confess I hadn't read your post so carefully. But I really had checked through your script word by word and I think I had understood what you want to do and known where the problem is.
You have a Flow("item") with 100% width and dynamic height, and "left vcenter" alignment. When you add a Picture("pic") into "item", the height of "item" is set to the same of "pic". At this moment, "pic" is VCENTERed, though with no blank above or below it. Then you add a text Flow("textFlow") into "item", the height of "item" is most likely changed to the same of "texFlow" if "textFlow" is higher than "pic". Although "item" has become higher, the relative position of "pic" has not been changed so that it's not VCENTERed any more. Even if you recalculate the layout, things will not get any better due to the order of the components. You got it?
In order to realize a dynamic position judgement, you should change the order of position determination. As said in my last post, you can create a Flow for the Picture with a VCENTER alignment. When you have put "textFlow" into "item", call Shell.computeLayout() to get every single position and length calculated. After that, you can set the height of the picture Flow to the same of "item" and repaint it by using Component.repaint(true) and flushScreen(false). Finally, you will get the picture vertically centered as you want. It's a bit annoying, but far from difficult. Don't you think so?
Sorry for not having given detailed solution in my last post.
Re:vertical alignment behaving badly
test.he
class Test {
void startWidget() {
setMinimizedView(createView("min", null));
}
Shell openWidget() {
Flow frame = new Flow(getStyle("frame"));
Flow imageFrame = new Flow(getStyle("imageFrame"));
Flow textFrame = new Flow(getStyle("textFrame"));
{
Image icon = getImage("icon.png");
imageFrame.add(new Picture(getStyle("image"), icon));
frame.add(imageFrame);
Text text = new Text(getStyle("text"), "");
while(true) {
text.appendText("abcdefghijklmnopqrstuvwxyz");
if(random(5) == 0) {
break;
}
}
textFrame.add(text);
frame.add(textFrame);
}
Shell shell = new Shell(frame);
shell.computeLayout();
int frameWidth, int frameHeight = frame.getSize();
int imageFrameWidth, int imageFrameHeight = imageFrame.getSize();
textFrame.setPreferredWidth(frameWidth - imageFrameWidth);
shell.computeLayout();
frameWidth, frameHeight = frame.getSize();
imageFrame.setPreferredHeight(frameHeight);
return shell;
}
boolean keyAction(Component focused, int op, int key) {
if(op == KEY_PRESSED) {
popShell(focused.getShell());
}
return true;
}
}
widget.xml
<?xml version="1.0" encoding="utf-8"?>
<widget spec_version="2.0">
<info>
<name>Test</name>
<author>yaiba</author>
<version>0.0</version>
<shortdescription>Test</shortdescription>
</info>
<resources>
<code src="test.he"/>
<img src="icon.png"/>
<stylesheet><![CDATA[
min {
align: hcenter vcenter;
background: solid yellow;
color: navy;
font: bold;
}
max {
background: solid white;
height: 100%;
width: 100%;
}
frame {
background: solid white;
width: 100%;
}
imageFrame {
align: hcenter vcenter;
}
textFrame {
width: 100%;
}
text {
color: black;
width: 100%;
}
]]></stylesheet>
</resources>
<layout minimizedheight="30sp">
<view id="min">
<label class="min">Test</label>
</view>
</layout>
</widget>
BTW: It's essential to give a definite(absolute or relative) width for children components, which I have neglected before about your script.
Re:vertical alignment behaving badly
Thanks for the respones. I understand what you're saying now. I think the problem is that the exact algorithm and order of things in the layout engine is a bit unclear. I think especially since the style is defined with a CSS-like syntax and similar box-model, there's somewhat of an assumption that the layout works in a similar way.
I mean basically, what I want to do is somwhat similar to:
<table width="100%">
<tr>
<td valign="middle" width="30%"><img src="x.png"></td>
<td valign="middle" width="70%">text text text</td>
</tr>
</table>
And the CSS syntax in WidSets sortof leads you to believe that it would be possible. Yet it's not, and the reason is mainly due to the order of calculations in the layout engine.
Perhaps this could be explained more in the documentation? Another source of confusion - no doubt - is the way relative sizes (percentages) work. In HTML/CSS they are relative to the parent element size. In WidSets, that doesn't seem to be the case and the documentation seems a bit unclear about this too. In fact it's not clear to me whether it is relative to parent element but subject to some layout order issue, or whether it is relative to screen size. Which one is it, by the way? :)
Thanks again for you answer!
Peppe
PS. You have a broken link to the API reference in the forum webpage. It goes to /Apidocs instead of /apidocs
1
2
