Quoting Ian Ward (2012-10-19 01:50:27)
> On Tue, Oct 16, 2012 at 11:51 AM, Patrick Totzke
> <[email protected]> wrote:
> > Quoting Ian Ward (2012-10-14 15:18:05)
> >> On Sat, Oct 13, 2012 at 12:42 PM, Patrick Totzke
> >> <[email protected]> wrote:
> >> > Quoting Ian Ward (2012-10-13 14:47:04)
> >> >> On Fri, Oct 12, 2012 at 6:23 PM, Patrick Totzke 
> >> >> <[email protected]> wrote:
> >> > What does Pile do if there is too little space for its entire content?
> >
> > question remains..
> 
> At the moment I believe it only trims canvases at the bottom end.
> I've recently updated Columns so that it tries to keep the column in
> focus visible (see the new horizontal example in the tutorial:
> http://urwid.readthedocs.org/en/latest/tutorial/index.html#horizontal-menu

This could be helpful for building variable width tree widgets. Will look into 
that.

> ) so it might be better to make Pile do the same thing.  I don't know
> how many people are using Pile that way though.

If Pile could keep the focus on screen and thus display more widgets that fit 
on the screen
then it would not be all too different from ListBox would it?
I think this is a good idea. It would certainly relax the need for this 
ueber-widget ListBox :)

> >> >> Here's another idea: do the decoration in a ListWalker subclass that
> >> >> takes a tree walker object which only implements tree operations (not
> >> >> a superclass or subclass of ListWalker).  This way we can mix and
> >> >> match different types of trees and different decorations.
> >> >
> >> > I don't like this idea to be honest. Its not much different from
> >> > making TreeBox a WidgetWrap'ed ListBox, adding some padding to the left 
> >> > in each line.
> >> > In fact, *this* would be the easy way to come up with a Widget for 
> >> > displaying TreeWalker.
> >> > Maybe I'll build this as a short term solution. But its not pretty.
> >> > I'd like to keep the Walkers semantical objects only: no decorations, no 
> >> > info on folding.
> >> > In my opinion these Walkers form some topology that one can explore by 
> >> > means of a TreeBox-Widget
> >> > that defines the way one sees and moves in the structure. </metaphermode>
> >
> > OK I added a widget to my POC repository that does exactly this.
> > check out https://github.com/pazz/urwidtrees
> > But we should be aware that this can only be a short term solution
> > as this means that the screen width and indentation level imply a fixed!
> > tree-depth one can display. In the long run I think a "TreeBox"
> > that generalizes ListBox, scrolling in two dimensions is inevitable!
> >
> >> Maybe I explained that poorly.
> >>
> >> ListBox: knows about scrolling and selection for vertically stacked
> >> widgets (implements widget API)
> >> BaseTreeWalker: provides vertically stacked widget view of a tree of
> >> widgets (implements list walker API)
> > ..called ListWalkerAdapter in my code.
> >
> >> WidgetTree: provides tree of widgets (implents new tree API
> >> get_parent, get_sibling, etc)
> > Called TreeWalker in my code.
> 
> No that's not quite what I was getting at.  Your ListWalkerAdapter
> points to *another* list walker.  I was suggesting having a
> BaseTreeWalker that would use the new "tree" API in a non-list-walker
> WidgetTree.  i.e. WidgetTree wouldn't implement the list walker API
> (get_next, get_prev, ..) but it would keep the methods related to
> traversing a tree.

Not sure if i get your point here:
You suggest one would use a LixtBox that works on a "BaseTreeWalker", that 
subclasses ListWalker.
BaseTreeWalker gets its data from a "WidgetTree", a walker like object that 
implements my
tree-walker api (which happens to be a superset of the list-walker api).

So in a way, BaseTreeWalker translates a Tree-Walker to a List-Walker, adding 
some decoration.
This is exactly what I'm doing. My "ListWalkerAdapter" uses a "TreeWalker" 
object to implement the
List walker API, by adding decoration.
What was missing in your description was some Widget that can not only display
a given ListWalkerAdapter(TreeWalker()), but also trigger focus movement based 
on the tree
structure. This is what's called "TreeBox" in my code. It wraps ListBox and 
overwrites keypress().


> Your ListWalkerAdapter would then subclass BaseTreeWalker to implement
> the particular decoration you want. 
I agree that one will want to subclass "ListWalkerAdapter" (what you called 
"BaseTreeWalker")
to implement different or more complicated decorations.
Note that if you do not want any decoration - just display a DF-flattened tree 
as List -
you can simply not wrap the TreeWalker and directly put it into a ListBox.
This is because the ListWalker API is a subset of the TreeWalker API.
If you want no decorations but keep the ability to move focus based on the tree 
structure,
you'd stick a TreeWalker into a TreeBox. This will then omit the adapter that 
introduces the
decoration.
I think we're basically saying the same thing up to isomorphism :)

> >> Subclasses of BaseTreeWalker could implement any decoration they like,
> >> and implement folding with the widgets they return if they so choose.
> >
> > agreed (for now)
> >
> >> I believe that folding is tied closely to the decoration.  It might
> >> have a clickable [+] for example
> >
> > definitely. folding and decoration should be handeled in the same class:
> > in the Widget that displays a TreeWalker.
> > In my code this is TreeBox (via its ListWalkerAdapter).

I will do that next. stay tuned.

> >> >> Horizontal scrolling means the widgets in the ListBox would have to be
> >> >> fixed widgets not flow widgets.
> >> >
> >> > Yes, agreed: this is problematic. Maybe there should be some complement 
> >> > method of
> >> > `pack` (that if i understand correctly computes the most compact way one 
> >> > can display the widget),
> >> > namely one method that returns the size of the widget if one gives it as 
> >> > much horizontal
> >> > space as it wants. For Text for instance, this would return the maximal 
> >> > length of any contained
> >> > text line. One had to ensure that all basic widgets return a finite 
> >> > value here. then this would
> >> > propagate to higher level containers.
> >>
> >> Text already does :-)
> >>
> >>   >>> Text('Hello World').pack()
> >>   (11, 1)
> >>   >>> Text('Hello World').pack((10,))
> >>   (5, 2)
> >
> > Well, I meant something that gives you the horizontal space needed if you 
> > provide
> > the vertical space. Something like
> >
> >   >>> Text('Hello World').vpack()
> >   11
> >   >>> Text('Hello\nWorld!').vpack()
> >   6
> 
> What's the difference between that and this?
> 
> >>> Text('Hello World').pack()[0]
> 11
> >>> Text('Hello\nWorld!').pack()[0]
> 6
> 
> If you actually mean to calculate the minimum columns required given a
> number of rows with *any* wrapping, that's not supported by text
> layouts at the moment, but it could be added if there was a need for
> it.

You are right, it's he same thing.
So if all Widgets can do this, then it should not be so difficult to introduce 
horizontal
scrolling? simply pack() flow widgets to display them side by side..

> > Lets get to the nitty gritty :)
> >> >> > - set_focus_valign this is to position the visible area around the 
> >> >> > focussed widget.
> >> >> >   It needs to be overwritten for TreeBox as the visible area is now 
> >> >> > two dimensional.
> >> >> >   Whats the difference to `shift_focus` and why does the latter need 
> >> >> > to know the size
> >> >> >   of the whole TreeBox?
> >> >>
> >> >> One acts immediately and the other does the next time one of the
> >> >> normal widget APIs gets the "current" size.  Remember widgets
> >> >> don't have a size:
> >> >> http://urwid.readthedocs.org/en/latest/manual/widgets.html#custom-widgets
> >> >
> >> > I agree with the concept that a Widget itself has no size and can be 
> >> > rendered
> >> > on a Canvas in different sizes. This means that whenever you want to 
> >> > `render`,
> >> > you need to provide a size, OK.
> >> > But i fail to see why one would ever need that size while reacting to 
> >> > input.
> >> > I get some input, i make some internal changes, if these trigger changes 
> >> > that need to be made
> >> > visible, then i trigger a 'modified' signal (or sth similar) and this in 
> >> > turn
> >> > will result in the Mainloop re-rendering this Widget and *then* will 
> >> > provide the necessary
> >> > dimension to `render`. Maybe I'm not seeing something obvious here but 
> >> > `keypress` itself should
> >> > not need that parameter right?
> >>
> >> One case where it is needed is in an Edit widget where the text is
> >> wrapped.  keypress(down/up) needs to know how the text is wrapped to
> >> figure out what the new cursor position is.  ListBox also needs to
> >> know the size to figure out how and when update the scrolling position
> >> in response to up/down/page up/page down.
> >
> > Edit: I see that if you press key down/up in a Edit, then the next cursor 
> > position
> > depends on the way the Widget *is* currently rendered, because this is what 
> > the user bases
> > his keypress on: he wants to move to the word that is currently displayes 
> > in direction X.
> > But this information you can get by remembering the last size given to 
> > render().
> > (if the widget wasn't rendered before that input was pointless).
> 
> I don't like the requirement that a widget must have been rendered
> once before accepting keyboard input works.  Also in the (admittedly
> silly) case where a single Edit widget was rendered two different
> sizes it wouldn't work.  A less silly case is a widget that was just
> scrolled in to view by a keypress -- you would have to render it in
> the middle of processing input, somehow.
> 
> > ListBox: I do not understand why keypress is so complicated in ListBox:
> > Sure, the visible part needs to be determined and this depends on the focus.
> > But you only really need to update this visible area when it is rendered.
> > So Im my opinion, keypress yould simply update the focus position
> > and all the complicated update-visible-part stuff should go into render(),
> > which already knows the size.
> >
> > All in all it is good practice to keep the API as clean as possible 
> > reagrding
> > accepted parameters: for a user of the API it is hard to grasp why keypress 
> > should
> > depend in any way on the size or colour of the widget in question.
> 
> I don't see how we can remove the size parameter from keypress without
> requiring that every widget is rendered in advance.  And that can't
> even be done in general.

Note that you are talking implementation details whereas I was
stating oddities in the API. Still:

I see that there are some complications with widgets like Edit that maintain a 
cursor
position when they are displayed multiple times on a screen. If one could
switch focus to the widget that was rendered first one would move the cursor
depending on the stored size of the other widget, because this touched the 
stored size last.
But is this even possible? would the widget not be re-rendered when focussed?

How could/would one want to delegate a keypress to a not yet rendered Widget?
This seems *so* artificial..

> I wrote ListBox so that it would behave like "less" when nothing in it
> is selectable, like "gedit" if it's full of Edit widgets, and like a
> web browser with focus moving between fields when there is a mix.
> Some selectable widgets can put the cursor anywhere, some can't.  Some
> widgets might be larger than the ListBox itself, but scrolling should
> still work.  When you resize the ListBox the focus position should
> stay approximately where it was before resizing.  All of these
> considerations taken together make for the mess of exceptions and
> corner cases you see in ListBox.keypress().

I must say I like your earlier Idea to "pimp" Pile to work on arbitrary
many widgets. This would keep things simple and one could subclass it
to implement the stated features of ListBox if required.
Of course ListBox as it is now must be complicated considering all those 
features.
Lets see how we can decompose it into smaller and maintainable classes.

> If you have any ideas about how those could be separated out cleanly
> (especially so they could be modified or extended by the user) I'm
> interested to hear them.

ListBox.keypress and kids:
  https://github.com/wardi/urwid/blob/master/urwid/listbox.py#L1015 and 
  https://github.com/wardi/urwid/blob/master/urwid/listbox.py#L1039 up until 
L1087
  seems to be duplicated code in _keypress_up and _keypress_down.
  Some of it also seems to be present in _keypress_pageup/down.
  I'm not sure what it does exactly, but its certainly a good candidate for a 
helper method.
  Maybe you also want a ListBox._make_focus_visible() and just call this in 
render()
  before doing anything else.

Cheers,
/p

Attachment: signature.asc
Description: signature

_______________________________________________
Urwid mailing list
[email protected]
http://lists.excess.org/mailman/listinfo/urwid

Reply via email to