Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

width attribute taken .. from where? #374

Open
K3nn3th2 opened this issue Oct 2, 2019 · 9 comments
Open

width attribute taken .. from where? #374

K3nn3th2 opened this issue Oct 2, 2019 · 9 comments

Comments

@K3nn3th2
Copy link

K3nn3th2 commented Oct 2, 2019

hey folks,

ive made a list view and am having trouble with the width of the list widets.
the structure looks like this:

ScrollArea:
    Container: includeContainer
        Include:
            pass

The items in the Include's "objects" list look like this (shorter version of code for explaining):

ListItem(Container):
    constraints=[
        hbox(thingOne, thingTwo),
        thingOne.width == 0.5 * width,
        thingTwo.width == 0.3 * width,
        ]
    Label: thingOne:
        text = 'something'
    Label: thingTwo:
        text = 'something'

The result looks good, proportion wise.
But the list Include's items (The List Items) are far broader than the window of the scrollView, i have to scroll to the right to see the rest of the labels.
i presume instead of using the width of the Container which the Include is in (includeContainer) some value is used as a width reference which i do not understand. initially i believed it to be the window size, but it seems to be even larger than that.

any ideas?

i have a feeling i have missed something essential about the constraints system..

thanks!

@K3nn3th2 K3nn3th2 changed the title width attribute taken of windo width? width attribute taken .. from where? Oct 2, 2019
@MatthieuDartiailh
Copy link
Member

I tried to reproduce using the following:

from enaml.widgets.api import Window, Container, ScrollArea, Field
from enaml.layout.api import hbox
from enaml.core.api import Include

enamldef Item(Container):

    #constraints = [hbox(l1, l2), 3*l1.width == 5*l2.width]
    constraints = [hbox(l1, l2), l1.width == 0.5*width, l2.width == 0.3*width]
    Field: l1:
        text = "Test"
    Field: l2:
        text = "Done"

enamldef Main(Window):

    Container:
        ScrollArea:
            Container:
                Include:
                    objects = [Item() for i in range(10)]

But I cannot reproduce the behavior you see. However the first set of constraints appears to give something better behaved. If you can provide a reproduction example I will try to investigate more.

However, I would suggest you to link the width of your two label to one another rather than to the surrounding container (whose size is solved based on its inner components) and if you want them to take the full width of the ScrollArea you may to set the hug_width attribute to 'ignore'.

@K3nn3th2
Copy link
Author

K3nn3th2 commented Oct 3, 2019

thanks for the quick reply!

i modified your example and added some stuff to demonstrate.
should i add hug_width to all of the labels ?
the thing is i am dynamically generating the list items and would like them to have a 'grid' look when inserted into the list.
so the width of each row's 'name' label should be the same, and the same goes for the other labels and the progressBar.

from enaml.widgets.api import Window, ProgressBar, Container, PushButton, ScrollArea, Label, Field
from enaml.layout.api import hbox, align
from enaml.core.api import Include

enamldef Item(Container):

    constraints = [
            hbox(name, source,  status, progressDL, progress_label, seperator, max_label, mb),
            name.width == 0.3 * width,
            source.width == 0.05 * width,
            status.width == 0.05 * width,
            progressDL.width == 0.45 * width,
            max_label.width == 0.05 * width,
            align('width', progress_label, max_label),
                ]
    Label: name:
        text = 'LOOOOONG NAME AND DESCRIPTION'
    Label: source:
        text = 'SHORTER NAME'
        align = 'right'
    Label: status:
        text = 'STATUS'
        align = 'right'
    ProgressBar: progressDL:
        maximum = 100
        hug_width = 'ignore'
        value = 50
    Label: progress_label:
        text = '50'
        align = 'right'
    Label: seperator:
        text = ' / '
    Label: max_label:
        text = '100'
        align = 'left'
    Label: mb:
        text= 'MB'

enamldef Main(Window):

    Container:
        constraints = [
            hbox(cont, scroll),
            scroll.width == 0.8 * width,
        ]
        Container: cont:
            Label:
                text = 'sample text'
        ScrollArea: scroll:
            Container:
                Include:
                    objects = [Item() for i in range(10)]

@K3nn3th2
Copy link
Author

K3nn3th2 commented Oct 6, 2019

can you confirm the strange behaviour?

@MatthieuDartiailh
Copy link
Member

I can reproduce and explain what is happening.

First you must realize that size of outer containers is not fixed but determined by the solver based on the size of the inner components (this is even more true in a sense inside a ScrollArea that can accept any size). As a consequence, when you refer to the container width you mostly link your different components to one another. A second important points is that enaml will not by default shrink a widget below its size hint. As a consequence when you ask source.width == 0.05 * width, the solver actually will enlarge the container to make it work (and it means the overall width is 20 times the width of your source widget which mostly explains the width you are seeing).

The grid like behavior you want requires to have constraints beyond each item. This is possible in enaml (although poorly documented) by specifying that the layout of your container should be shared with its parent. This is not done by default for performance reasons (it is better to solve many small systems than a gigantic one...), however for your case it is the right solution (assuming you have to keep the intermediate Item widget otherwise you could manage the objects in the Include in a more granular and simply use a grid for the layout. The example below show you how to use the shared_layout feature. This would be a cool example and the documentation could be improved if you feel up to it feel free to start a PR in that direction.

from enaml.widgets.api import Window, ProgressBar, Container, PushButton, ScrollArea, Label, Field
from enaml.layout.api import hbox, align, grid, vbox
from enaml.core.api import Include

enamldef Item(Container):

    share_layout = True
    constraints = [hbox(name, source,  status, progressDL, progress_label, seperator, max_label, mb)]

    Label: name:
        text = 'LOOOOONG NAME AND DESCRIPTION'
    Label: source:
        text = 'SHORTER NAME'
        align = 'right'
    Label: status:
        text = 'STATUS'
        align = 'right'
    ProgressBar: progressDL:
        maximum = 100
        hug_width = 'ignore'
        value = 50
    Label: progress_label:
        text = '50'
        align = 'right'
    Label: seperator:
        text = ' / '
    Label: max_label:
        text = '100'
        align = 'left'
    Label: mb:
        text= 'MB'

enamldef Main(Window):

    Container:
        constraints = [
            hbox(cont, scroll)
        ]
        Container: cont:
            Label:
                text = 'sample text'
        ScrollArea: scroll:
            Container:
                layout_constraints => ():
                    cs = []
                    if not inc.objects:
                        return[]

                    ref = self.children[0].visible_widgets()
                    for i in self.children[1:-1]:
                        for j, w in enumerate(i.visible_widgets()):
                            cs.append(ref[j].width == w.width)
                    return [vbox(*self.children[:-1])] + cs

                Include: inc:
                    objects = [Item() for i in range(10)]

As a side note I would advise against using 4 labels for your progress summary, it is over complicated, you need only one whose you update the text.

@K3nn3th2
Copy link
Author

K3nn3th2 commented Oct 7, 2019

thanks for the detailed explanation and the code!

however, its not quite clear to me how to achieve the grid-like look.
I believe i need to keep the intermediate item for reference of progress as each one represents a file transfer. Or would you have any idea how to do this otherwise?

adding your code fits all the widgets nicely into the parent container, but every entry with a different string has a different label width.
i would need a mixture of both of our code snippets functionality-wise..
how could i achieve a uniform width of the labels throughout the rows?
would it be possible to have a responsive feel to it?

@MatthieuDartiailh
Copy link
Member

I am not sure to follow your issue. Adapting the code to generate different names I get the following which to me looks like a grid. If you have a closer look at the code I posted you will notice that I enforce equal width across the rows in the layout_constraints function.
image

@MatthieuDartiailh
Copy link
Member

@K3nn3th2 is your issue fixed, now ?

@K3nn3th2
Copy link
Author

its mostly fixed now, yes.
i still have an issue with the label widths. when the 'STATUS' label in your example is updated to STATUSNEW for example, the 'tes' label will be moved to the left. Or when a '50' label gets changed to '100', the same thing happens with all of the widgets left of the label. it would be nice to set fixed widths in which the text should be displayed.

what is the best way to achieve this?

@MatthieuDartiailh
Copy link
Member

If you truly want to block the width in this way either pad the text in the columns that should be fix or enforce a constant width using the constraints. The first option seems sub-optimal but will be more flexible than the second.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants