Sounding Out the View Tree

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
33 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Sounding Out the View Tree

Travis Griggs-4
I would be curious about VisualWorks programmers' reactions to the following:

http://objology.blogspot.com/2011/10/sounding-out-view-tree.html

--
Travis Griggs
Objologist
Simplicity is the Ultimate Sophistication -- Leonardo da Vinci


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

andre

I would be curious about VisualWorks programmers' reactions to the following:

http://objology.blogspot.com/2011/10/sounding-out-view-tree.html


Although the code examples look nice, IMO it's making things even more complicated. 

Why not just use a simple IdentityDictionary (or an API that fakes it), nested by sub builders? I am all for a straight API with a minimum set of methods that fit 90% of all common use cases, for example

self widgetAt: #id do: [ :w | ... ].
self widgetAt: #id in: #subcanvas do: [ :w | ... ].

A powerful query system seems smart, but is really not needed here. Logic like "all widgets in the lower half of the window" is pretty useless. A UI is designed for a specific purpose and the application knows about that design in every detail. Identifying widgets by name is just fine and sufficient. If dynamically separating widgets in groups and collections was of any importance, it would have been incorporated into the application and UI from the beginning (composites, subcanvases, collections of widget names, etc):

#( input1 input2 input3 ) do:
[ :id | self widgetAt: id do: [ :w | ... ]].


Please keep it simple!

Andre





_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Gregory Bourassa-3
In reply to this post by Travis Griggs-4
Travis,

Well,  there certainly is a need to tidy these patterns up.

Did you consider XPath queries as a model, as an alternative to
jQuery?   They have a nice, generalized,  declarative syntax which could
be applied to a UI component tree.    Without putting nearly as much
thought into it as you have, the following mapping springs to mind:

/ = topComponent

//* = any component

//TypeName = any component of type TypeName

*/* = the parent-child relationship (we could ignore wrappers on our way
down)

TypeName[@id='Name']  = a specific type and its ID matching 'Name' (i.e.
those widget names in the UI editor)

*[@id='Name'] = any type whose ID matches 'Name'

../   =  the upward path step in the tree

./ = the path starting with "me"

and so on.

Here is a silly example:

'../*[@id="CancelButton"]'

That would get you the widget named "CancelButton" which is your sibling
in the tree.

This way, the search criterion is very easy to read in your source code
(though it has the slight disadvantage of being a string which the
search engine must first parse into objects).   You can either search
from the top of the view tree,   or from the current component (sender).

If you observe that the / and @ symbols are syntactic sugar for the
"axes" which include "parent",  "sibling",  "attribute" and so on,  
which could also be explicitly used in the XPath syntax,   you would get
pretty much complete expressive control over which items (in relation to
the sender) you are trying to locate.

Regards.

Gregory Bourassa


On 10/06/11 23:39, Travis Griggs wrote:

> I would be curious about VisualWorks programmers' reactions to the
> following:
>
> http://objology.blogspot.com/2011/10/sounding-out-view-tree.html
>
> --
> Travis Griggs
> Objologist
> Simplicity is the Ultimate Sophistication -- Leonardo da Vinci
>

-----------------------------------------
Key Technology, Inc. Disclaimer Notice - The information and attachment(s) contained in this communication are intended for the addressee only, and may be confidential and/or legally privileged. If you have received this communication in error, please contact the sender immediately, and delete this communication from any computer or network system. Any interception, review, printing, copying, re-transmission, dissemination, or other use of, or taking of any action upon this information by persons or entities other than the intended recipient is strictly prohibited by law and may subject them to criminal or civil liability. Key Technology, Inc. is not liable for the improper and/or incomplete transmission of the information contained in this communication or for any delay in its receipt.


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Dave Stevenson-3
In reply to this post by Travis Griggs-4
Attachment componentNamed.st contains a few methods I wrote to find a widget by name in the view tree:
    #name -> SpecWrapper, VisualPart
    #componentNamed: -> SpecWrapper, Wrapper, CompositePart, VisualComponent, ScheduledWindow, ApplicationModel
   
This allows my appModel to simply do:
    self componentNamed: #widgetID

This particular implementation has the weakness of answering only the first encountered component with the specified name (see CompositePart>>componentNamed:). An improvement might add an alternate selector to answer all components with that name (#componentsNamed:).

But the point is, I don't want to have to create a Query directly in my client code and then start it searching. I'd much rather just send a message to the appModel. Behind the scenes, if aQuery is constructed, I don't care so much. But I've shown that a few methods added to the existing view classes can handle the traversal of the tree without a separate traversal object.
 
Dave Stevenson
[hidden email]



From: Travis Griggs <[hidden email]>
To: VWNC NC <[hidden email]>
Sent: Fri, October 7, 2011 1:39:18 AM
Subject: [vwnc] Sounding Out the View Tree

I would be curious about VisualWorks programmers' reactions to the following:

http://objology.blogspot.com/2011/10/sounding-out-view-tree.html

--
Travis Griggs
Objologist
Simplicity is the Ultimate Sophistication -- Leonardo da Vinci

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc

componentNamed.st (3K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Travis Griggs-4
On Oct 7, 2011, at 8:30 AM, Dave Stevenson wrote:

Attachment componentNamed.st contains a few methods I wrote to find a widget by name in the view tree:
    #name -> SpecWrapper, VisualPart
    #componentNamed: -> SpecWrapper, Wrapper, CompositePart, VisualComponent, ScheduledWindow, ApplicationModel
    
This allows my appModel to simply do:
    self componentNamed: #widgetID

This particular implementation has the weakness of answering only the first encountered component with the specified name (see CompositePart>>componentNamed:). An improvement might add an alternate selector to answer all components with that name (#componentsNamed:).

But the point is, I don't want to have to create a Query directly in my client code and then start it searching. I'd much rather just send a message to the appModel. Behind the scenes, if aQuery is constructed, I don't care so much. But I've shown that a few methods added to the existing view classes can handle the traversal of the tree without a separate traversal object.

If you were trying to approximate the jQuery/CSS notion of Id with the Spec name, then matching the first one is the right thing to do.

This is a nice utility Dave, 8 extension methods. You're currently going to miss PartPort children and SimpleTextSelectionStatus, but if you change your code to use childrenDo:, that'll solve that problem for you.

I think we have different goals, with some overlap.

You are interested in finding methods by one means only: id. I wanted to be able to find them by principles similar to what is found in CSS, which include id. If I follow the approach you did, I'll add another 8 methods to implement componentsTyped:. And if I want to do tagging (css classes), which is very useful in jQuery/Web UIs, I'll add another 8 methods to implement componentsTagged:. And maybe it'd be better to just add a componentsSatisfying: aBlock do: bBlock. I can pivot those 24 methods to use that, and end up with 8 methods for the componentsSatisfying:do: and then helper sugar in 3x3 spots, which gets me back to 17.

I wanted to use the same mechanism to go up the tree as well though. Not just down. So now you get to multiply that 17 x 2 if you want to have similar named API.

And I wanted to be able to stack them.

I also wanted to be able to do more interesting matches. I liked that I could generally do batch sorts of things like

(self ? #(#cancel #maybe #ok)) enable

And I didn't want to be tied to SpecWrapper. Part of the whole game here, is that we'd like to figure out a way to decouple the process of assembling UIs from specs from their actual realization.

Maybe there's another way to put what I was/am after here. I've done what you've done here. I've done it lots of times. We've tried to add some useful generic patterns (like childrenDo:) to the base. But the basic problem is that every single time I have a new and interesting way that I want to interact with the view tree, I have to write a method that looks awfully familiar. If I'm going down, it looks something like

doSomethingInteresting
self doTheInterestingThingForMe.
self childrenDo: [:each | each doSomethingInteresting]

And if I'm going upwards it looks something like

doSomethingInteresting
self doTheInterestingThingForMe.
self parent ifNotNil: #doSomethingInteresting

It's great and all, but it gets old. After 20 years, I've done enough of them. Want to add a #layout method so that normal views can get at their layout? You know the drill. Want to have a #bottomComponent, or a #topComponent, or #isOpen, or #flushCoordinateCache, or.. you get the picture. For some of these you really want to follow the pattern, because subclasses can do interesting things. But for a lot of them, you're just making another recursive tree traverser by yet another name. 

What I was really after was an algebra for generalized access to the tree. I find it cool in a meta sort of way, that I don't need topComponent any more, I can just write

(self ?? [true]) last

It should have about the same efficiency as well (or close) .

Sure #topComponent is more clear, and maybe I'd write a helper just for that. But we can do just about any sort of tree processing we want without having to repeat the mechanics of tree traversal all over the place.

And you could still write componentNamed: in the 3 top level places as

componentNamed: anID
^(self ? #id) first

--
Travis Griggs
Objologist
Light travels faster than sound. This is why some people appear bright until you hear them speak...





_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Claus Kick
In reply to this post by Travis Griggs-4
>This allows my appModel to simply do:
>    self componentNamed: #widgetID

Sounds like it is done in VS(E), VA and some of the javascript libraries.

Honestly, I always liked this approach way better than anything else. You look for a GUI-Element in the tree and do not need to know where it is.
If you have a large tree of GUI components, you can always expose often-needed ones directly via getters.
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Ladislav Lenart
In reply to this post by Travis Griggs-4
Hello Travis.

Just my 2cents...

I like your Query approach very much. I would call the package
WidgetQuery instead of WidgetPath. I dislike #? and #?? shorthands
and the rest of the suggested "syntactic sugar". I prefer
readability over reduction in character count. Furthemore I would
constantly confuse the meaning of the two question mark selectors. I
would call them #childQuery: and #parentQuery: instead.

But when I look at the sample examples on your blog post I think the
encapsulation is still broken. I have to know the Wrapper internals
to get the job done:
* show/hide? => SpecWrapper
* layout? => BoundedWrapper
* #takeKeyboardFocus? => WidgetWrapper
* #invalidate? => BorderDecorator
* ...

I suggest to introduce "implicit tag names" for all these
capabilities (such as #layout). With these the programmer no longer
has to know anything about the internal Wrapper hierarchy. This
would enable you to change the Wrapper implementation (like
eliminating most of the wrappers ;-) )...


Ladislav Lenart


----- PŮVODNÍ ZPRÁVA -----
Od: "Travis Griggs" <[hidden email]>
Komu: "VWNC NC" <[hidden email]>
Předmět: Re: [vwnc] Sounding Out the View Tree
Datum: 8.10.2011 - 1:55:30

> On Oct 7, 2011, at 8:30 AM, Dave Stevenson wrote:
>
> > Attachment componentNamed.st contains a few
> > methods I wrote to find a widget by name in the
> > view tree:
> > >     #name -> SpecWrapper, VisualPart
> >     #componentNamed: -> SpecWrapper, Wrapper,
> >     CompositePart, VisualComponent,
> >     ScheduledWindow, ApplicationModel
> >     >    
> > This allows my appModel to simply do:
> >     self componentNamed: #widgetID
> >
> > This particular implementation has the weakness
> > of answering only the first encountered
> > component with the specified name (see
> > CompositePart>>componentNamed:). An improvement
> > might add an alternate selector to answer all
> > components with that name (#componentsNamed:).
> > >
> > But the point is, I don't want to have to create
> > a Query directly in my client code and then
> > start it searching. I'd much rather just send a
> > message to the appModel. Behind the scenes, if
> > aQuery is constructed, I don't care so much. But
> > I've shown that a few methods added to the
> > existing view classes can handle the traversal
> > of the tree without a separate traversal object.
> >
> If you were trying to approximate the jQuery/CSS
> notion of Id with the Spec name, then matching the
> first one is the right thing to do.
>
> This is a nice utility Dave, 8 extension methods.
> You're currently going to miss PartPort children
> and SimpleTextSelectionStatus, but if you change
> your code to use childrenDo:, that'll solve that
> problem for you.
>
> I think we have different goals, with some
> overlap.
>
> You are interested in finding methods by one means
> only: id. I wanted to be able to find them by
> principles similar to what is found in CSS, which
> include id. If I follow the approach you did, I'll
> add another 8 methods to implement
> componentsTyped:. And if I want to do tagging (css
> classes), which is very useful in jQuery/Web UIs,
> I'll add another 8 methods to implement
> componentsTagged:. And maybe it'd be better to
> just add a componentsSatisfying: aBlock do:
> bBlock. I can pivot those 24 methods to use that,
> and end up with 8 methods for the
> componentsSatisfying:do: and then helper sugar in
> 3x3 spots, which gets me back to 17.
>
> I wanted to use the same mechanism to go up the
> tree as well though. Not just down. So now you get
> to multiply that 17 x 2 if you want to have
> similar named API.
>
> And I wanted to be able to stack them.
>
> I also wanted to be able to do more interesting
> matches. I liked that I could generally do batch
> sorts of things like
>
> (self ? #(#cancel #maybe #ok)) enable
>
> And I didn't want to be tied to SpecWrapper. Part
> of the whole game here, is that we'd like to
> figure out a way to decouple the process of
> assembling UIs from specs from their actual
> realization.
>
> Maybe there's another way to put what I was/am
> after here. I've done what you've done here. I've
> done it lots of times. We've tried to add some
> useful generic patterns (like childrenDo:) to the
> base. But the basic problem is that every single
> time I have a new and interesting way that I want
> to interact with the view tree, I have to write a
> method that looks awfully familiar. If I'm going
> down, it looks something like
>
> doSomethingInteresting
> self doTheInterestingThingForMe.
> self childrenDo: [:each | each
> doSomethingInteresting]
>
> And if I'm going upwards it looks something like
>
> doSomethingInteresting
> self doTheInterestingThingForMe.
> self parent ifNotNil: #doSomethingInteresting
>
> It's great and all, but it gets old. After 20
> years, I've done enough of them. Want to add a
> #layout method so that normal views can get at
> their layout? You know the drill. Want to have a
> #bottomComponent, or a #topComponent, or #isOpen,
> or #flushCoordinateCache, or.. you get the
> picture. For some of these you really want to
> follow the pattern, because subclasses can do
> interesting things. But for a lot of them, you're
> just making another recursive tree traverser by
> yet another name.
>
> What I was really after was an algebra for
> generalized access to the tree. I find it cool in
> a meta sort of way, that I don't need topComponent
> any more, I can just write
>
> (self ?? [true]) last
>
> It should have about the same efficiency as well
> (or close) .
>
> Sure #topComponent is more clear, and maybe I'd
> write a helper just for that. But we can do just
> about any sort of tree processing we want without
> having to repeat the mechanics of tree traversal
> all over the place.
>
> And you could still write componentNamed: in the 3
> top level places as
>
> componentNamed: anID
> ^(self ? #id) first
>
> --
> Travis Griggs
> Objologist
> Light travels faster than sound. This is why some
> people appear bright until you hear them speak...
>
>
>
>
>


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

andre
In reply to this post by Travis Griggs-4


> componentNamed: anID
> ^(self ? #id) first


Sorry, but proposals like this frighten the hell out of me, because  
for me it feels like a move backwards. That's way too much overkill  
for a GUI framework that is supposed to be simple and straightforward  
and efficient. Apart from the smart logic behind it (no question, I  
like it), what is this supposed to be good for in practice?

I see the point that tree traversal could be generalized, but I  
wouldn't do it only for the mere handfull of methods that a GUI needs.  
I suspect that the reason for so many traversal things already being  
there is just bad and redundant design.

I might be missing something, but according to my current experience,  
there is only one chain needed in upwards direction for events  
(input), and one downwards for display. It would certainly be more  
rewarding to try and eliminate all other needs for traversal by  
cleaning up the framework, instead of adding to the overall complexity  
with a general query system.

I also doubt that it could be effcient enough for higher framerates  
(frequent updates).

The user interfaces I've done so far are really complex, involving  
real-time animation in deeply nested scrollable components that  
display thousands of immediately editable items, dozens of nested  
tabs, heavy use of dynamical disablement, etc. I don't see where such  
a query system could have helped me to make things easier or better in  
any way.

Smalltalk is so tempting in that it always suggests us to think about  
how many cool things we could do instead of forcing us to rethink and  
improve our immature ad-hoc designs in order to make them work with a  
strict, clean and minimal framework.

Andre

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

andre
In reply to this post by Travis Griggs-4
Admittedly the wording in my last post was a bit exaggerated. The  
point I was trying to make is that it is worth questioning whether we  
need more "intelligence" to help us deal with the current complexity,  
or whether is is more desirable to reduce and/or hide that complexity  
instead.

Since a couple years I am using a simple API to control visibility and  
enablement of widgets. The application model implements the following  
methods (examples):

widgetsDisabled
        "Answer a Set of widget names that are supposed to be disabled
         according to the current state of the application."

        disabled := super widgetsDisabled.
        self canPaste
                ifFalse:[ disabled add: #doPaste ].
        self canCommit
                ifFalse:[ disabled add: #OK ].
        self selectedProduct isOptedForMaintenance
                ifFalse:[ disabled addAll: self widgetsForMaintenance ].
        ^disabled

widgetsHidden
        "Answer a Set of widget names that are supposed to be hidden
         according to the current state of the application."

        hidden := super widgetsHidden.
        self selectedCustomer isEligibleForUpgrades
                ifFalse:[ hidden addAll: self widgetsForUpgrade ].
        ^hidden

updateVisibility
        "... straightforward code that uses the above to change widget states  
by #id"

Each time the application changes something that affects visibility or  
enablement, I just send #updateVisibility to the app. The general  
#updateAll message also invokes this, so everything is always up to  
date. The advantages of this approach compared to sending messages to  
individual widgets are:

1. Only a single place is reponsible.
2. Declarative and descriptive code, easy to understand, maintain and  
extend.
3. Various #canDelete, #canCommit, #canDoWhatever methods are self-
explanatory, inheritance-friendly and contain domain-specific code only.
4. No need to deal with Wrapper in customer code.

This scheme could be easily enhanced by adding  
#widgetsContinouslyAccepted, #widgetsWhatever. It should not be too  
difficult to come up with equivalent hooks hat accept arguments (e.g.  
layouts).

The point I am trying to make is: I strongly doubt there are actually  
that many use cases that would justify adding a query type of API. It  
seems more rewarding to me to just identify the most common  
application-level uses (merely a dozen, I would guess) and provide  
declarative hooks similar to the above that are easy to understand and  
maintain. This way Wrapper and its quirks could be kept out of custom  
code entirely.

Andre

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

andre
In reply to this post by Travis Griggs-4
Ouch, I missed to declare #hidden and #disabled as temporaries in my  
examples:


widgetsDisabled
        "Answer a Set of widget names that are supposed to be disabled
         according to the current state of the application."
        | disabled |
        disabled := super widgetsDisabled.
        self canPaste
                ifFalse:[ disabled add: #doPaste ].
        self canCommit
                ifFalse:[ disabled add: #OK ].
        self selectedProduct isOptedForMaintenance
                ifFalse:[ disabled addAll: self widgetsForMaintenance ].
        ^disabled

widgetsHidden
        "Answer a Set of widget names that are supposed to be hidden
         according to the current state of the application."
        | hidden |
        hidden := super widgetsHidden.
        self selectedCustomer isEligibleForUpgrades
                ifFalse:[ hidden addAll: self widgetsForUpgrade ].
        ^hidden
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

jarober
In reply to this post by andre
Actually, let me throw this out there: Menus have a hook for defining an enablement state message.  Why not do something similar for the widget set?

On Oct 9, 2011, at 5:01 AM, andre wrote:

> Admittedly the wording in my last post was a bit exaggerated. The  
> point I was trying to make is that it is worth questioning whether we  
> need more "intelligence" to help us deal with the current complexity,  
> or whether is is more desirable to reduce and/or hide that complexity  
> instead.
>
> Since a couple years I am using a simple API to control visibility and  
> enablement of widgets. The application model implements the following  
> methods (examples):
>
> widgetsDisabled
> "Answer a Set of widget names that are supposed to be disabled
> according to the current state of the application."
>
> disabled := super widgetsDisabled.
> self canPaste
> ifFalse:[ disabled add: #doPaste ].
> self canCommit
> ifFalse:[ disabled add: #OK ].
> self selectedProduct isOptedForMaintenance
> ifFalse:[ disabled addAll: self widgetsForMaintenance ].
> ^disabled
>
> widgetsHidden
> "Answer a Set of widget names that are supposed to be hidden
> according to the current state of the application."
>
> hidden := super widgetsHidden.
> self selectedCustomer isEligibleForUpgrades
> ifFalse:[ hidden addAll: self widgetsForUpgrade ].
> ^hidden
>
> updateVisibility
> "... straightforward code that uses the above to change widget states  
> by #id"
>
> Each time the application changes something that affects visibility or  
> enablement, I just send #updateVisibility to the app. The general  
> #updateAll message also invokes this, so everything is always up to  
> date. The advantages of this approach compared to sending messages to  
> individual widgets are:
>
> 1. Only a single place is reponsible.
> 2. Declarative and descriptive code, easy to understand, maintain and  
> extend.
> 3. Various #canDelete, #canCommit, #canDoWhatever methods are self-
> explanatory, inheritance-friendly and contain domain-specific code only.
> 4. No need to deal with Wrapper in customer code.
>
> This scheme could be easily enhanced by adding  
> #widgetsContinouslyAccepted, #widgetsWhatever. It should not be too  
> difficult to come up with equivalent hooks hat accept arguments (e.g.  
> layouts).
>
> The point I am trying to make is: I strongly doubt there are actually  
> that many use cases that would justify adding a query type of API. It  
> seems more rewarding to me to just identify the most common  
> application-level uses (merely a dozen, I would guess) and provide  
> declarative hooks similar to the above that are easy to understand and  
> maintain. This way Wrapper and its quirks could be kept out of custom  
> code entirely.
>
> Andre
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc

James Robertson
http://www.jarober.com
[hidden email]




_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

andre

Am 09.10.2011 um 18:12 schrieb James Robertson:

> Actually, let me throw this out there: Menus have a hook for  
> defining an enablement state message.  Why not do something similar  
> for the widget set?

It won't work that way round. One widget is usually not tied to a  
single application state. There may be multiple application states  
that enabled/disable a widget. To cope with this, we would end up with  
lots of methods like #isInputAEnabled, #isInputBEnabled and such, each  
of which query the same application state again and again (which is  
potentially expensive).

The nice thing with the proposed #widgetsDisabled / #widgetsHidden  
scheme is that the application state needs to be queried only once and  
all widgets react to it at once.

It is also more easy to understand and maintain, because the entire  
"business logic" of the UI is found in a single method source. I  
always found this to be very natural and comfortable.

It was much different if all state dependencies were cluttered across  
a large number of widgets. Even more so as this information is hidden  
in the UI painter's GUI or lengthy specs.

Andre


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

jarober
The same thing goes for menu items; in the apps I've been involved with, the same state triggers multiple menu item states.  The simplest way to deal with that is to give those menu items the same state check method.


On Oct 9, 2011, at 3:46 PM, andre wrote:

>
> Am 09.10.2011 um 18:12 schrieb James Robertson:
>
>> Actually, let me throw this out there: Menus have a hook for defining an enablement state message.  Why not do something similar for the widget set?
>
> It won't work that way round. One widget is usually not tied to a single application state. There may be multiple application states that enabled/disable a widget. To cope with this, we would end up with lots of methods like #isInputAEnabled, #isInputBEnabled and such, each of which query the same application state again and again (which is potentially expensive).
>
> The nice thing with the proposed #widgetsDisabled / #widgetsHidden scheme is that the application state needs to be queried only once and all widgets react to it at once.
>
> It is also more easy to understand and maintain, because the entire "business logic" of the UI is found in a single method source. I always found this to be very natural and comfortable.
>
> It was much different if all state dependencies were cluttered across a large number of widgets. Even more so as this information is hidden in the UI painter's GUI or lengthy specs.
>
> Andre
>
>

James Robertson
http://www.jarober.com
[hidden email]




_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

andre


> The same thing goes for menu items; in the apps I've been involved  
> with, the same state triggers multiple menu item states.  The  
> simplest way to deal with that is to give those menu items the same  
> state check method.

Sure, in theory that works, but mapping widgets to states (1) is more  
complex and less maintainable than mapping states to widgets (2):

(1)
Widget A -> State1
Widget B -> State2
Widget C -> State1, State2, State3 (requires an artificial state  
checker method)
Widget D -> State1, State2 (ditto)
Widget E -> State3

(2)
State1 -> #( A B C D )
State2 -> #( C D )
State3 -> #( C E )

For basic widgets like a "delete" button, a simple checker like  
#canDelete is fine. Also most menu items map to a single action only  
(and usually there is a relatively small number of menu items anyway).  
It's much different with forms that use a wide variety of widgets that  
depend on more than one state each. You might perhaps think this is  
uncommon, but it is not. I have it in almost every UI.

The most important point however is that (2) is driven by business  
logic, telling the UI to behave accordingly, whereas (1) is widget-
driven: widgets have to know in advance the state(s) they are tied to.  
That's asking for trouble. In (1), if the business logic changes, I  
have to review a single self-explanatory method. In (2) I always end  
up looking into the UI builder examining individual widgets, adding  
artificial checker methods, etc.

Business-driven declarative code is far superior compared to widget-
driven hard wired stuff. Because it's not the widget that knows about  
my business - it's the app that knows. Dynamic enablement and  
visibility is not a property of the widget. It belongs to the behavior  
of the application!

I am following this principle since a couple of years now, and it has  
proven to be very successful for me. Keeping all business logic away  
from the immediate UI definition really pays.

Andre

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Steven Kelly
In reply to this post by jarober
It's not so easy for widgets, because a widget is displayed all the
time, whereas a menu is displayed on demand. It's thus easy for the menu
itself to check whether it should be enabled, just before it is
displayed. But a widget needs an application to explicitly tell it when
the answer to the enablement message has changed, or then some
dependency or event mechanism.

> -----Original Message-----
> From: [hidden email] [mailto:[hidden email]] On
> Behalf Of James Robertson
> Sent: 9. lokakuuta 2011 19:12
> To: VWNC NC
> Subject: Re: [vwnc] Sounding Out the View Tree
>
> Actually, let me throw this out there: Menus have a hook for defining
> an enablement state message.  Why not do something similar for the
> widget set?
>
> On Oct 9, 2011, at 5:01 AM, andre wrote:
>
> > Admittedly the wording in my last post was a bit exaggerated. The
> > point I was trying to make is that it is worth questioning whether
we
> > need more "intelligence" to help us deal with the current
complexity,
> > or whether is is more desirable to reduce and/or hide that
complexity
> > instead.
> >
> > Since a couple years I am using a simple API to control visibility
> and
> > enablement of widgets. The application model implements the
following

> > methods (examples):
> >
> > widgetsDisabled
> > "Answer a Set of widget names that are supposed to be
> disabled
> > according to the current state of the application."
> >
> > disabled := super widgetsDisabled.
> > self canPaste
> > ifFalse:[ disabled add: #doPaste ].
> > self canCommit
> > ifFalse:[ disabled add: #OK ].
> > self selectedProduct isOptedForMaintenance
> > ifFalse:[ disabled addAll: self
> widgetsForMaintenance ].
> > ^disabled
> >
> > widgetsHidden
> > "Answer a Set of widget names that are supposed to be hidden
> > according to the current state of the application."
> >
> > hidden := super widgetsHidden.
> > self selectedCustomer isEligibleForUpgrades
> > ifFalse:[ hidden addAll: self widgetsForUpgrade
> ].
> > ^hidden
> >
> > updateVisibility
> > "... straightforward code that uses the above to change
> widget states
> > by #id"
> >
> > Each time the application changes something that affects visibility
> or
> > enablement, I just send #updateVisibility to the app. The general
> > #updateAll message also invokes this, so everything is always up to
> > date. The advantages of this approach compared to sending messages
to
> > individual widgets are:
> >
> > 1. Only a single place is reponsible.
> > 2. Declarative and descriptive code, easy to understand, maintain
and
> > extend.
> > 3. Various #canDelete, #canCommit, #canDoWhatever methods are self-
> > explanatory, inheritance-friendly and contain domain-specific code
> only.
> > 4. No need to deal with Wrapper in customer code.
> >
> > This scheme could be easily enhanced by adding
> > #widgetsContinouslyAccepted, #widgetsWhatever. It should not be too
> > difficult to come up with equivalent hooks hat accept arguments
(e.g.
> > layouts).
> >
> > The point I am trying to make is: I strongly doubt there are
actually
> > that many use cases that would justify adding a query type of API.
It
> > seems more rewarding to me to just identify the most common
> > application-level uses (merely a dozen, I would guess) and provide
> > declarative hooks similar to the above that are easy to understand
> and
> > maintain. This way Wrapper and its quirks could be kept out of
custom

> > code entirely.
> >
> > Andre
> >
> > _______________________________________________
> > vwnc mailing list
> > [hidden email]
> > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
> James Robertson
> http://www.jarober.com
> [hidden email]
>
>
>
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

jarober
doh, never mind then.  Why I didn't think of that is beyond me :)

On Oct 10, 2011, at 6:30 AM, Steven Kelly wrote:

> It's not so easy for widgets, because a widget is displayed all the
> time, whereas a menu is displayed on demand. It's thus easy for the menu
> itself to check whether it should be enabled, just before it is
> displayed. But a widget needs an application to explicitly tell it when
> the answer to the enablement message has changed, or then some
> dependency or event mechanism.
>
>> -----Original Message-----
>> From: [hidden email] [mailto:[hidden email]] On
>> Behalf Of James Robertson
>> Sent: 9. lokakuuta 2011 19:12
>> To: VWNC NC
>> Subject: Re: [vwnc] Sounding Out the View Tree
>>
>> Actually, let me throw this out there: Menus have a hook for defining
>> an enablement state message.  Why not do something similar for the
>> widget set?
>>
>> On Oct 9, 2011, at 5:01 AM, andre wrote:
>>
>>> Admittedly the wording in my last post was a bit exaggerated. The
>>> point I was trying to make is that it is worth questioning whether
> we
>>> need more "intelligence" to help us deal with the current
> complexity,
>>> or whether is is more desirable to reduce and/or hide that
> complexity
>>> instead.
>>>
>>> Since a couple years I am using a simple API to control visibility
>> and
>>> enablement of widgets. The application model implements the
> following
>>> methods (examples):
>>>
>>> widgetsDisabled
>>> "Answer a Set of widget names that are supposed to be
>> disabled
>>> according to the current state of the application."
>>>
>>> disabled := super widgetsDisabled.
>>> self canPaste
>>> ifFalse:[ disabled add: #doPaste ].
>>> self canCommit
>>> ifFalse:[ disabled add: #OK ].
>>> self selectedProduct isOptedForMaintenance
>>> ifFalse:[ disabled addAll: self
>> widgetsForMaintenance ].
>>> ^disabled
>>>
>>> widgetsHidden
>>> "Answer a Set of widget names that are supposed to be hidden
>>> according to the current state of the application."
>>>
>>> hidden := super widgetsHidden.
>>> self selectedCustomer isEligibleForUpgrades
>>> ifFalse:[ hidden addAll: self widgetsForUpgrade
>> ].
>>> ^hidden
>>>
>>> updateVisibility
>>> "... straightforward code that uses the above to change
>> widget states
>>> by #id"
>>>
>>> Each time the application changes something that affects visibility
>> or
>>> enablement, I just send #updateVisibility to the app. The general
>>> #updateAll message also invokes this, so everything is always up to
>>> date. The advantages of this approach compared to sending messages
> to
>>> individual widgets are:
>>>
>>> 1. Only a single place is reponsible.
>>> 2. Declarative and descriptive code, easy to understand, maintain
> and
>>> extend.
>>> 3. Various #canDelete, #canCommit, #canDoWhatever methods are self-
>>> explanatory, inheritance-friendly and contain domain-specific code
>> only.
>>> 4. No need to deal with Wrapper in customer code.
>>>
>>> This scheme could be easily enhanced by adding
>>> #widgetsContinouslyAccepted, #widgetsWhatever. It should not be too
>>> difficult to come up with equivalent hooks hat accept arguments
> (e.g.
>>> layouts).
>>>
>>> The point I am trying to make is: I strongly doubt there are
> actually
>>> that many use cases that would justify adding a query type of API.
> It
>>> seems more rewarding to me to just identify the most common
>>> application-level uses (merely a dozen, I would guess) and provide
>>> declarative hooks similar to the above that are easy to understand
>> and
>>> maintain. This way Wrapper and its quirks could be kept out of
> custom
>>> code entirely.
>>>
>>> Andre
>>>
>>> _______________________________________________
>>> vwnc mailing list
>>> [hidden email]
>>> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>>
>> James Robertson
>> http://www.jarober.com
>> [hidden email]
>>
>>
>>
>>
>> _______________________________________________
>> vwnc mailing list
>> [hidden email]
>> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc

James Robertson
http://www.jarober.com
[hidden email]



_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Dave Stevenson-3
In reply to this post by andre
One other thought:

Suppose a subCanvas is reused multiple times in the same UI. How can I get to widget #foo in subCanvas #A as opposed to the similarly named widget in subCanvas #B?

Perhaps we need a way to identify widgets not only by id, but by parentage as well:

    self componentAt: #(#A #foo)
 
Dave Stevenson
[hidden email]

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Travis Griggs-4
In reply to this post by Steven Kelly

On Oct 10, 2011, at 3:30 AM, Steven Kelly wrote:

It's not so easy for widgets, because a widget is displayed all the
time, whereas a menu is displayed on demand. It's thus easy for the menu
itself to check whether it should be enabled, just before it is
displayed. But a widget needs an application to explicitly tell it when
the answer to the enablement message has changed, or then some
dependency or event mechanism.

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On
Behalf Of James Robertson
Sent: 9. lokakuuta 2011 19:12
To: VWNC NC
Subject: Re: [vwnc] Sounding Out the View Tree

Actually, let me throw this out there: Menus have a hook for defining
an enablement state message.  Why not do something similar for the
widget set?

Yeah, what Steven said.

--
Travis Griggs
Objologist
"The project was so plagued by politics and ego that when the engineers requested technical oversight, our manager hired a psychologist instead." -- Ron Avitzur


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Gregory Bourassa-3
In reply to this post by Dave Stevenson-3
Dave,

That's why I suggested an XPath syntax.  :-)    Seems no one is interested in that, though.

I would let you crawl multi-directionally in the tree, and through attribute relations as well as parentage relations or type relations.

Gregory Bourassa


On 10/10/11 07:41, Dave Stevenson wrote:
One other thought:

Suppose a subCanvas is reused multiple times in the same UI. How can I get to widget #foo in subCanvas #A as opposed to the similarly named widget in subCanvas #B?

Perhaps we need a way to identify widgets not only by id, but by parentage as well:

    self componentAt: #(#A #foo)
 
Dave Stevenson
[hidden email]

-----------------------------------------
Key Technology, Inc. Disclaimer Notice - The information and attachment(s) contained in this communication are intended for the addressee only, and may be confidential and/or legally privileged. If you have received this communication in error, please contact the sender immediately, and delete this communication from any computer or network system. Any interception, review, printing, copying, re-transmission, dissemination, or other use of, or taking of any action upon this information by persons or entities other than the intended recipient is strictly prohibited by law and may subject them to criminal or civil liability. Key Technology, Inc. is not liable for the improper and/or incomplete transmission of the information contained in this communication or for any delay in its receipt.



_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: Sounding Out the View Tree

Travis Griggs-4
In reply to this post by Dave Stevenson-3

On Oct 10, 2011, at 7:41 AM, Dave Stevenson wrote:

One other thought:

Suppose a subCanvas is reused multiple times in the same UI. How can I get to widget #foo in subCanvas #A as opposed to the similarly named widget in subCanvas #B?

Perhaps we need a way to identify widgets not only by id, but by parentage as well:

    self componentAt: #(#A #foo)

Don't you have this already?

(self componentAt: #A) componentAt: #foo

I'm getting it as

self ? #A ? #foo

I didn't show this in the lengthy article I wrote, but the ClassCreationDialog rewrite I did to use this, had exactly that pattern in it, quite a bit actually.

--
Travis Griggs
Objologist
My Other Machine runs OSX. But then... so does this one.




_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
12