layouting

210 views
Skip to first unread message

John Asmuth

unread,
Apr 17, 2012, 8:33:44 AM4/17/12
to go-...@googlegroups.com
Next step is to create a simple layouter. Iron Man's pull request mods for buttons was setting the button's size and location manually, but I'm not a big fan.

The way java swing does it (and please don't feel like I want to copy java swing, but it does have a working layout manager) is each component has a preferred, minimum and maximum size. The layouter works with that information, and information that it (and only it) has about where in the space that component should go. Using information from all its children and the amount of screen space it's given, it will then place each component.

So for the button example, we might want to create the equivalent of swing's FlowLayout, a layouter that just adds components from left to right and sizes them however they prefer. We'd also need to work out what kind of messages need to be sent to manage this.

Laurent Le Goff

unread,
Apr 17, 2012, 9:37:50 AM4/17/12
to go-...@googlegroups.com
Sorry,
I think more a Box model:
    - with box that can contain other box and layout vertically other horizontally and other following a flow
    - box with fix size
    ...
I think css except that it is often a puzzle to make complex layout.

More generally I think that the layout and the style (color, font...) should be separated from the application design (but not necessary), this permit to target different platform changing the style of the application or to delegate the design to someone else. For this we have to be able to tag some box (as we have className in css):
   box.Tag("Tool Bar");
   box.Tag("Menu");
   box.Tag("Form");

This permit to have a higher level representation of structure of the application, and next to apply some specific layout depending of tags.
...
Laurent

Laurent Le Goff

unread,
Apr 17, 2012, 9:43:50 AM4/17/12
to go-...@googlegroups.com

http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html 


On Tuesday, April 17, 2012 2:33:44 PM UTC+2, John Asmuth wrote:

André Moraes

unread,
Apr 17, 2012, 9:44:16 AM4/17/12
to go-...@googlegroups.com
I think that something similar to what is made in browsers would work.

Most of the time, with just a few CSS the programmer can made their interface work in a 22 inch screen and on a 7 inch smartphone.

Also, instead of using fixed units using relative ones allow the screen to adapt without much work from the programmer.

John Asmuth

unread,
Apr 17, 2012, 10:00:13 AM4/17/12
to go-...@googlegroups.com
Since we're using vector graphics, I don't know if the fixed/relative issue will come up. A Block just has to take care of drawing itself. The images it sends back on the compositor will be (as in, this code is yet to be written) scaled to fit in the area the foundation wants to put it in.

John Asmuth

unread,
Apr 17, 2012, 10:04:55 AM4/17/12
to go-...@googlegroups.com
Just a heads up - I am a bit hostile towards css. I find it extremely confusing and frustrating. That isn't to say we couldn't come up with something similar that made more sense, it's just that I have my doubts.

John Asmuth

unread,
Apr 17, 2012, 3:56:32 PM4/17/12
to go-...@googlegroups.com
One issue that I think is a bit more pressing than the method use to place blocks (css, something else, whatever), is how the block and the foundation it rests upon should communicate the relavent information and instructions.

I really want to have all communication happen using the Block's channels (and we can feel free to add more as is appropriate). I want to have very little, if possible, done through method calls. They pause the execution of the parent, and that's bad(tm). I also want to have very little done through shared memory, for obvious reasons.

The question, then, is what information needs to go between the block and the foundation, and how should it be sent.

I think it's probably necessary for a foundation to keep its own information about the area owned by a particular block. It's possible that the Compositing channel would need to have both the *Block and the image, so the compositor can make a more informed decision about where to paste the image, rather than trusting what it gets (like it does now).

To have a block tell its foundation sizing and placement hints, we could give the foundation a chan struct { b *Block; MinSize, PreferredSize, MaxSize Coord } - a placement hints channel. The block could also accept messages on a GiveMeAHint channel. Ok, I like this :)

Feedback?

John Asmuth

unread,
Apr 18, 2012, 11:42:47 AM4/18/12
to go-...@googlegroups.com
Some fun updates - I've added layouts.Flow (as well as a layouts package). very simple, and you can see how to use it in uiktest.

Laurent Le Goff

unread,
Apr 18, 2012, 5:20:54 PM4/18/12
to go-...@googlegroups.com
Thanks John,
I launch your test, it works :)
just a link  to show some thought about a Window with a 2 buttons (this is a fake code):


--
You received this message because you are subscribed to the Google Groups "go-uik" group.
To view this discussion on the web visit https://groups.google.com/d/msg/go-uik/-/brJqGmvAZ-gJ.
To post to this group, send email to go-...@googlegroups.com.
To unsubscribe from this group, send email to go-uik+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/go-uik?hl=en.

John Asmuth

unread,
Apr 18, 2012, 5:37:41 PM4/18/12
to go-...@googlegroups.com
Cool. In general, I like the idea of suggesting what the programmer's code might look like - what you've got certainly seems easy to work with.

Check out the latest version of go.uik. I have a way to subscribe to events, but it's a bit more tedious (and more general). I added commentary to uiktest.go.

- John

Laurent Le Goff

unread,
Apr 18, 2012, 6:10:16 PM4/18/12
to go-...@googlegroups.com
Interesting,
comments help to understand, thanks.
I continue to work on "what the code should be if I open a window with 2 buttons":

I'm not sure on layout things, i have to think deeper on it to have something intuitive, simple and that works well.

Sorry, I don't comment your code because I'm not totally synchronized with all your works....

Cheers
- Laurent

Anthony Starks

unread,
Apr 18, 2012, 7:14:09 PM4/18/12
to go-...@googlegroups.com
Here's a  higher level view, after moving all the housekeeping into functions:

func main() {
w, f, err := topbox("GoUI", 480, 320)
if err != nil {
fmt.Println(err)
return
}
bsize := geom.Coord{100, 50}
b1 := button(bsize, "Hi", "clicked!")
b2 := button(bsize, "there", "BAM")
cb := widgets.NewCheckbox(geom.Coord{50, 50})
f.PlaceBlock(&b1.Block)
f.PlaceBlock(&b2.Block)
f.PlaceBlock(&cb.Block)
w.Show()
shutdown(w)

John Asmuth

unread,
Apr 18, 2012, 9:05:29 PM4/18/12
to go-...@googlegroups.com
The reason I'm trying to use a mostly channel-based interface rather than a function- and method-based interface is because functions block, and if they don't block then they can have their executions reordered. If you take safeguards against either of these things happening, then you're really just wrapping a channel operation under the hood!

For the moment, at least, I really want all communication between blocks, foundations etc, to happen on non-blocking channels.

There are three major ways to have non-blocking channels. At least three that I'm thinking about right now.

1) Infinitely buffered channels: there is a goroutine gobetween keeping track of everything.

2) Drop-channels: a channel with a finite buffer, but when the buffer is full a send is simply ignored rather than blocked.

The idea is that some components might stall out for whatever reason, and we don't want to have that become a memory leak. If they somehow eventually wake up, then emptying the current buffer will enable them to get no messages.

3) Stacked channels: a channel that combines all unreceived sends into a single message.

An example of this is the message sent by a block to its parent to composite the buffer. The parent only really needs to know about the most recent buffer, so sending a buffer should cause the buffer already in there to be dropped. Another example is the Redraw channel, which informs a block that some portion of its buffer needs to be redrawn. The sends are combined into a single message that describes the union of all the previous messages, so the block redraws only once.


The result of having things work like this is that the api looks like a list of channels instead of a set of functions. It's less efficient than method calls, especially when a goroutine switch is required. Fortunately this is a UI kit, and performance faster than a certain mark is pointless: a human won't be able to tell the difference after a while.

What a human *can* notice is when a hitch in one component brings down the whole UI. That is what we're trying to avoid here. The goal is to make it so that a properly written component cannot be adversely affected by another component unless it's a child or a parent. Siblings can't affect each other as long as the parent is written properly.


One thing that's getting me down a bit here is the lack of generics. I'd really like to have typed channels, but that means a lot of specialty code. Might be better to just require type assertions. Anyone have an opinion on that?
- John

Thanks John,
To unsubscribe from this group, send email to go-uik+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/go-uik?hl=en.

--
You received this message because you are subscribed to the Google Groups "go-uik" group.
To post to this group, send email to go-...@googlegroups.com.
To unsubscribe from this group, send email to go-uik+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/go-uik?hl=en.

--
You received this message because you are subscribed to the Google Groups "go-uik" group.
To post to this group, send email to go-...@googlegroups.com.
To unsubscribe from this group, send email to go-uik+unsubscribe@googlegroups.com.

Robert Bloomquist

unread,
Apr 19, 2012, 12:11:10 AM4/19/12
to go-...@googlegroups.com
I mentioned this in another thread on golang-nuts, but I think it's worth repeating here.  If you haven't yet, I highly recommend reading http://doc.cat-v.org/bell_labs/concurrent_window_system/ which provides a design of a concurrent windowing system similar to the one we're designing here.  In addition, the Plan 9 window manager, rio, is designed in a similar fashion, so its source code may provide some insights.  The source code (written in C) can be found here:   http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/rio/ 

Also, I would prefer to just do channels of a defined interface, rather than requiring type assertions, but I'm not sure what you have in mind.  Can you give a specific example?

John Asmuth

unread,
Apr 19, 2012, 8:27:26 AM4/19/12
to go-...@googlegroups.com


On Thursday, April 19, 2012 12:11:10 AM UTC-4, Robert Bloomquist wrote:
I mentioned this in another thread on golang-nuts, but I think it's worth repeating here.  If you haven't yet, I highly recommend reading http://doc.cat-v.org/bell_labs/concurrent_window_system/ which provides a design of a concurrent windowing system similar to the one we're designing here.  In addition, the Plan 9 window manager, rio, is designed in a similar fashion, so its source code may provide some insights.  The source code (written in C) can be found here:   http://plan9.bell-labs.com/sources/plan9/sys/src/cmd/rio/ 

I have read it.
 
Also, I would prefer to just do channels of a defined interface, rather than requiring type assertions, but I'm not sure what you have in mind.  Can you give a specific example?

Having one chan interface{} that requires a type switch vs many chans of concrete types is much more efficient in running. Each channel takes up (a small amount of) memory, lengthens the struct definition (in a good way) and requires more code to set up (not so bad).

Robert Bloomquist

unread,
Apr 19, 2012, 2:22:19 PM4/19/12
to go-...@googlegroups.com
I understand your point, but what I meant was, where in the design of uik are you thinking about applying this?  Are you talking about having each control message a different type, and using type switches to decode them?  Or some other application that I'm missing?

John Asmuth

unread,
Apr 19, 2012, 2:48:58 PM4/19/12
to go-...@googlegroups.com
It's already the case that there is a single event channel that queues everything up and keeps it all in order. Right now these events are taken off that channel, type switched, and then fed to the correct typed channels that will be select{}ed upon. I'm thinking of letting the component code do that type switch.

This way we can sneak control messages in there to. For example, the label has a special channel .SetLabelData that gets select{}ed on along with the event channels it's monitoring.

One big problem I'm discovering is that doing it this way makes it difficult to provide a default set of functionality to new blocks. For instance, the Foundation type has a method .HandleEvents(), which does some basic stuff for forwarding events down to its children and compositing buffers from children. If the specialized type wants to intercept any of these messages, it cannot call .HandleEvents(). Instead it has to more or less reimplement the whole thing. I provide helper methods for each event type to aid this a bit, but it's still a big minus.

If the events come in a stream of interface{}, the specialization code can type assert it, handle some kinds of events and call the foundation's .HandleEvent(e) method in the default case. Writing this out has made it clear to me how essential this is to having the API be easy to extend :)

--
You received this message because you are subscribed to the Google Groups "go-uik" group.
To view this discussion on the web visit https://groups.google.com/d/msg/go-uik/-/_UUqeaUv7pcJ.

To post to this group, send email to go-...@googlegroups.com.
To unsubscribe from this group, send email to go-uik+un...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages