How to create a more complex list/dropdown from code?

I tried to create a more complex dropdown and listview from code using ItemRenderer (and dataSource), but unfortunately there are no examples of how it can be done from code alone.

Something like that doesn’t work

		var comboBox: DropDown = new DropDown();
		var itemRender:ItemRenderer = new ItemRenderer();
		itemRender.addChild(new Bitmap(bitmapdata));
		comboBox.itemRenderer = itemRender;

I tried adding bitmaps directly since my target is OpenFL

How can create a listview (and dropdown) , from code , with more complex elements in it (including separate images, buttons, labels, backgrounds)?

Here are two examples of what I’m trying to do with listview:
I ) The image shows:

  1. custom border
  2. images
  3. labels / text
  4. bitmap images
  5. buttons
  6. clickable text / links
  7. and 8) different image backgrounds for odd and even rows in the list

II ) The below image show similar elements - labels, images, etc. ( each row contains labels, clickable images )

About the dropdown, how can change elements from the source ?
Here is example with custom arrow and custom scrollbar image and different background ( image)
for even/odd rows
hxuidropdown

itemRender.addChild(new Bitmap(bitmapdata));

I think you should add an Image Component instead


var image = new Image();
            image.id = "image";
            image.percentWidth = 100;
            image.verticalAlign = "center";
            itemRenderer.addComponent(image);

you will be then be able the bitmapdata as a ressource to the image;

Now for the custom design , you can modfity plenty ust by modifying the css you can look here,
haxeui-core/dropdowns.css at master · haxeui/haxeui-core · GitHub.

The dropdown seems to use a listview, you can have different styles.colors for odd and even rows haxeui-core/listview.css at master · haxeui/haxeui-core · GitHub

Try to play with the css :slight_smile:

1 Like

i mean, theres alot going on there, but nothing that doesnt look possible. Do you have reference images to play with?

Btw, you might want to check out the “kenney theme” (GitHub - haxeui/haxeui-theme-kenney)

Its a complete theme replacement using bitmaps (well, pngs). You can see it in action here: Main

Cheers,
Ian

Also, i dont know how this is supposed to work, i mean, you can add anything you want to an item renderer (from an openfl perspective), but haxeui isnt going to “magically” know it should be use inside the item renderer

It might help to look at the component explorer (Component Explorer - HaxeUI) there are maybe examples there that could help you

EDIT: i just realised thats basically exactly waht @rationaldecay said :slight_smile:

Maybe I couldn’t explain what I was trying to achieve. Sorry about that.
So my question is how can I use ItemRenderer and dataSource to add more complex items?
I could not find any examples how to do it from the code . The only example from the component explorer was using xml.
At example for listview

<listview id="lv2" width="200" height="150" selectedIndex="1">
                        <item-renderer layoutName="horizontal" width="100%">
                            <checkbox id="complete" />
                            <label width="100%" id="item" verticalAlign="center" />
                            <image id="image" />
                        </item-renderer>

For Itemrender here is added empty checkbox, label, image . Only the id is set . Is this is the only way to add elements ? Should be Haxeui items with Id ( not bitmap at example)
This id is then used to add items ?

<data>
                           <item complete="false" item="Item 1" image="haxeui-core/styles/default/haxeui_tiny.png" />
                           <item complete="true" item="Item 2" image="haxeui-core/styles/default/haxeui_tiny.png" />

How can the same be done from code?

The second question is about the background for the even/odd rows in the list. Is it possible to change it and set it as new bitmap image ?

So my question is how can I use ItemRenderer and dataSource to add more complex items?

You certainly can, the xml based item renderers are basically “helpers” they let you quickly and easily create fairly complex renderers where the data is linked by id, but you can, of course, create a 100% custom item renderer class and do “everything” yourself (that is, you can link any data to any ui element, etc). There isnt an example of this is the explorer, but i think it should be added, as it is, ofc, a very useful part of the item rendering system. Ill add a note to add an example to the explorere :+1:

By-the-way, one thing to be aware of is that there is no separation between “code” and “xml” in haxeui. It may seem that way, but its not the case, the haxeui macros take xml and turn it into haxe code. So the question “can it be done from code” is moot, haxeui itself is doing this all from code (there is no such thing as “xml” after it has been parsed and the haxe code has been built from it). If you would like to see the haxe code it generates, create an xml example and do dump=pretty and you’ll see what code haxeui generates from the xml (i mention this because there seems to be some misconception that when you use xml, you are using some other part of haxeui that doesnt apply to code - thats not the case… its all haxe code)

The second question is about the background for the even/odd rows in the list. Is it possible to change it and set it as new bitmap image ?

Sure, this is just css, as @rationaldecay mentioned, check out the listview css for hints, but basically its:

.listview .even {
    ...
}

Then you can do anything you want there, haxeui sets a background color, but you could set a background image, slice-9, etc, etc.

To convert

<data>
                           <item complete="false" item="Item 1" image="haxeui-core/styles/default/haxeui_tiny.png" />
                           <item complete="true" item="Item 2" image="haxeui-core/styles/default/haxeui_tiny.png" />

to code

lv2.dataSource.add ({complete : false, item: "Item 1", image:"haxeui-core/styles/default/haxeui_tiny.png"}); 

the values in the dynamic object will replace the variable value of the corresponding instance of the class.
So for example, it will do image.value = “haxeui-core/styles/default/haxeui_tiny.png”;

After reading the rerssource property,
you can here instead of
image:“haxeui-core/styles/default/haxeui_tiny.png”
you could have put
image:bitmapdata

Thank you for the example.
Maybe I miss something obvious , but as example for that
lv2.dataSource.add ({complete : false, item: "Item 1", image:"...haxeui_tiny.png"});
we have :

  1. complete is checkbox type;
  2. item is label;
  3. image is image;
    So maybe I first need to set new ItemRenderer() , with those values , but how ?
    The other thing is how to set in itemRender elements which not have id ( at example Bitmap, not Image) ?
    And last question could be how to add containers in ItemRender ( Vbox, Hbox , etc) if want to create complex rows which should include elements on fixed position ( at example above image of lock, chip followed by text/label)

Let’s make a full example

// you  create the item renderer
var itemRender:ItemRenderer = new ItemRenderer();
var image = new Image();
            image.id = "image_id";
            itemRenderer.addComponent(image);

// You add your bitmapdata

lv2.dataSource.add ({image_id: mybitmapdata}); 

Here as you were able to put the bitmap data. You cannot put directly non haxe-ui components in the ItemRenderer. That 's why you use an image where you can easily set the bitmapdata;

You can easily put containers

// you  create the item renderer
var itemRender:ItemRenderer = new ItemRenderer();
var vbox = new VBox();
itemRenderer.addComponent(vbox);

var image = new Image();
            image.id = "image1_id";
           vbox.addComponent(image);
var image = new Image();
            image.id = "image2_id";
            vbox.itemRenderer.addComponent(image);

// You add your bitmapdata

lv2.dataSource.add ({image_id1: mybitmapdata, image_id2: mybitmapdata}); 

Just use the itemrenderer as a normal haxeui component, you can add containers inside of it, haxeui will will find the ids indicated in the dynamic objects.

I you copy this in the haxeui builder, you see that I was able to put a vbox.

 <listview id="lv2" width="200" height="150" selectedIndex="1">
                        <item-renderer layoutName="horizontal" width="100%">
                            <vbox>
                            <checkbox id="complete" />
                            <label width="100%" id="item" verticalAlign="center" />
                            </vbox>
                            <image id="image" />
                        </item-renderer>
                        <data>
                            <item complete="false" item="Item 1" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="true" item="Item 2" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="true" item="Item 3" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="false" item="Item 4" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="true" item="Item 5" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="true" item="Item 6" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="false" item="Item 7" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="true" item="Item 8" image="haxeui-core/styles/default/haxeui_tiny.png" />
                            <item complete="false" item="Item 9" image="haxeui-core/styles/default/haxeui_tiny.png" />
                        </data>
                    </listview>
1 Like

Thank you again!
That’s really help me.
Unfortunately after load my bitmapdata it’s not shown with lv2.dataSource.add ({image_id: mybitmapdata});
Maybe because datasource exptected type Image and I put BitmapData type.
As I understand ItemRender exptected only HaxeUI components, so it’s not possible to add directly Sprite or Bitmap ( something like itemRender.addChild(sprite) it’s not possible)

No, you shouldn’t put BitmapData, leave Image :slight_smile: Like you said haxeui expects haxeui components.
Then you should be able to put
lv2.dataSource.add ({image_id: mybitmapdata});
If it doesn’t work post the part of your code.

Thank you!
There is itemRenderer.addChild(..), but I’m not sure how I can use it . Maybe is available only because is DisplayObject and could not be render in the listview.

Like I said, you must use an Image ( and then add the bitmapdata to the image), so you mustn’t use addChild, which is openfl, but not haxeui. Try to post your code, and I’ll try to correct it :slight_smile:

2 Likes

Thank you again for your time!
I will try to create a a little bit more complex Itemrender using only HaxeUI components .
If anything goes wrong I will post here .

So as @rationaldecay points out (thanks! :slight_smile: ), addChild isnt the right call to use, you must use addComponent since that means that where you add it (in this case probably an item renderer) will know about it, otherwise its just some unsolicited openfl sprite / bitmap / display object.

So you could do something like this:

var renderer = new ItemRenderer();
var hbox = new HBox();
var image = new Image();
image.id = "some_image_id";
hbox.addComponent(image);
renderer.addComponent(hbox);

myList.itemRenderer = render;
myList.dataSource.add({some_image_id: myBitmapData});

note that you can build this code, pretty much exactly, by using haxeui xml :wink:

How to show the text (from Label ) in ListView ? Currently showing [object Label] (openfl / html5)
image

Here is my source code:

var roomName:Label = new Label();
roomName.id = "roomName";
var roomPoints:Label = new Label();
roomPoints.id = "roomPoints";

var itemRender:ItemRenderer = new ItemRenderer();
itemRender.height = 78;
itemRender.addComponent(roomName);
itemRender.addComponent(roomPoints);

commonList = new ListView();
commonList.width = 635;
commonList.height = 555;
commonList.itemRenderer = itemRender;
		
var rname = new Label();
rname.text = "Room_name";
var rpoints = new Label();
rpoints.text = "500 K";

commonList.dataSource.add({roomName:rname, roomChips:rchips });
commonList.dataSource.add({roomName:rname, roomChips:rchips });
commonList.dataSource.add({roomName:rname, roomChips:rchips });

Another question: How to control the selected color ? At the moment of selecting a row, the text [object Label] turns white. I want to remove this ie. not color the text at all (and maybe stop selection altogether)

OK, so you are adding the label to the data source, where as you should be adding the data to the data source:

commonList.dataSource.add({roomName: "room1" ... });
commonList.dataSource.add({roomName: "room2" ... });
commonList.dataSource.add({roomName: "room3" ... });

http://haxeui.org/builder/?wbkpvg

I still don’t understand something:
What is the purpose of ItemRenderer then ?
My understanding was that: we first init the components which we want to add to a listview using the itemrender.
After that we add these components via dataSource. Obviously this is a wrong assumption.
But then how I will control the label properties ? What if I want each row to have different size and color for the label text ?
And why to use ItemRenderer when all data is string, int or other standard type.
Obviously I could use css for set even/odd row ( not each row differently), but why to use addComponent(…).

So an item renderer is exactly that, it is a renderer of an item (ie, a bit of data). So you define an item renderer with its sub components, then that renderer gets cloned and its data get set for each item in a data source. So if you have a component in the renderer called “bob” and a field in the data called “bob” then the .value of the component “bob” will be set to the value that is present in the data source.

example: Builder - HaxeUI

So with that example, the item renderer is cloned for each item in the data source and each cloned item renderer has its data set (the data would be each item in the data source). This then looks for components from the fields in the data that was set and and calls their “.value”

So, with the default item renderer (ItemRenderer) its not really possible to control all properties of a sub component, i think eventually it will be possible, but i have to think about how to do it properly, however, you can always create your own item renderer (by sub classing ItemRenderer) and do anything you want there, for example:

import haxe.ui.core.ItemRenderer;
import haxe.ui.util.Color;

@:xml('
<item-renderer width="100%" layoutName="horizontal">
    <checkbox id="isComplete" verticalAlign="center" />
    <label id="someText" verticalAlign="center" width="100%" />
    <slider id="someValue" verticalAlign="center" />
    <switch id="isOn" verticalAlign="center" />
</item-renderer>
')
class MyCustomItemRenderer extends ItemRenderer {
    public override function onDataChanged(data:Dynamic) {
        super.onDataChanged(data);
        if (data != null && data.theRowColor != null) {
            this.backgroundColor = Color.fromString(data.theRowColor);
        }
    }
}
<listview width="300">
    <my-custom-item-renderer />
    <data>
        <item isComplete="false" someText="Item 1" someValue="10" isOn="false" theRowColor="red" />
        <item isComplete="true" someText="Item 2" someValue="22" isOn="true" theRowColor="green" />
        <item isComplete="true" someText="Item 3" someValue="88" isOn="true" theRowColor="blue" />
        <item isComplete="true" someText="Item 4" someValue="55" isOn="false" theRowColor="yellow" />
        <item isComplete="false" someText="Item 5" someValue="12" isOn="false" theRowColor="#ff00ff" />
        <item isComplete="true" someText="Item 6" someValue="70" isOn="true" theRowColor="#667799" />
        <item isComplete="false" someText="Item 7" someValue="100" isOn="false" theRowColor="#99aabb" />
    </data>    
</listview>

image

Obviously im using alot of xml here, but the same thing is perfectly possible with just using haxe code also. :slight_smile:

Hope that helps?

Cheers,
Ian

I’ll do some test. One more question. How to set data/item from the source code on the listview ?

<data>
        <item .... />
       <item .... />
</data>

My understanding was to use commonList.dataSource.add(...) for that , but it’s obviously wrong.