Dynamically Managing the Layout of Controls
Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller
Dynamically Managing the Layout of Controls
Having just realised that I wasted a week building a table object, I thought I'd post here and ask if anyone has any suggestions for layout management.
Basically, I am building card elements dynamically, and the number of them can vary. I want to find some high-level way of controllilng their layout (including on re-sizing) without specifying the location of individual controls.
I can't find anything about this on the use-list. So, without knowing of any better solution I'm currently looking at doing something like the layout management using in Java's AWT.
Any suggestions/pointers?
Basically, I am building card elements dynamically, and the number of them can vary. I want to find some high-level way of controllilng their layout (including on re-sizing) without specifying the location of individual controls.
I can't find anything about this on the use-list. So, without knowing of any better solution I'm currently looking at doing something like the layout management using in Java's AWT.
Any suggestions/pointers?
Hi Bernard,
This is just a guess, but would it be possible for you to make a template group with all controls you need and copy or clone this group as many times as you need to display your table?
You can copy your template group into a "main" group with a vertical (and if necessary a horizontal) scrollbar. To make this as smooth as possible, follow these steps.
1) lock screen
2) copy template group into other "main" group
3) remember vscroll and hscroll
4) set vscroll and hscroll of main group to 0
5) position all "subgroups" relative to card size
6) set vscroll and hscroll to previous values
When you resize the stack, do step 3 up to and including 6.
Best,
Mark
This is just a guess, but would it be possible for you to make a template group with all controls you need and copy or clone this group as many times as you need to display your table?
You can copy your template group into a "main" group with a vertical (and if necessary a horizontal) scrollbar. To make this as smooth as possible, follow these steps.
1) lock screen
2) copy template group into other "main" group
3) remember vscroll and hscroll
4) set vscroll and hscroll of main group to 0
5) position all "subgroups" relative to card size
6) set vscroll and hscroll to previous values
When you resize the stack, do step 3 up to and including 6.
Best,
Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode
-
- Livecode Opensource Backer
Re: Dynamically Managing the Layout of Controls
If I post the code for this I already have somewhere public, would you agree to share any improvement you make? A good layout system would be a great addition to the language.Bernard wrote: I'm currently looking at doing something like the layout management using in Java's AWT.
Marielle
Hi Mark
Thanks for the suggestion. This might well help with one part of the layout. However, what I'm trying to think through is the idea of a more generic layout manager. In my mind, I think I need some way to set a property on a card, its groups, and their controls such that the groups and controls would lay themselves out in specific patterns.would it be possible for you to make a template group with all controls you need and copy or clone this group as many times as you need
-
- Livecode Opensource Backer
Good timing, next week I had planned to spend the time to clean out my reusable libraries. I should have something in a state good enough to share publicly (and for others to build upon) by middle of next week.Bernard wrote:Of course, that is only fair.
In the meantime, feel free to browser some I have about laying out options usually provided in most layout agents like java awt.
-
- VIP Livecode Opensource Backer
- Posts: 10055
- Joined: Sat Apr 08, 2006 7:05 am
- Contact:
Hi Richard, I'm not sure if the Geometry Manager will do what I want. I did have a look at it, and it appears to me that it is for controlling layout of objects visually within the IDE. I'm looking into the automatic layout of controls based on externally created data represented in cards and controls.FourthWorld wrote:See Rev's Geometry Manager.Bernard wrote:In my mind, I think I need some way to set a property on a card, its groups, and their controls such that the groups and controls would lay themselves out in specific patterns.
Unfortunately the chapter in the Rev 2.7 docs about the Geometry Manager is still empty, and the information on geometry management is fairly sparse even in the documentation from earlier versions of Rev. Also, I've been wary of even going down that path because I have read many complaints about the GM being broken.
Or are you suggesting that I dig into the internals of the GM to see how runrev are managing layouts?
Bernard, you didn't reply my question "why?" but I am sure that making a general solution for your problem is not recommendable. Instead, just make a script that creates and manages controls that the data fit in.
Mark
Mark
The biggest LiveCode group on Facebook: https://www.facebook.com/groups/livecode.developers
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode
The book "Programming LiveCode for the Real Beginner"! Get it here! http://tinyurl.com/book-livecode
Sorry Mark, I just missed your question. Basically, I have a rev app that is the presentation tier of a "web app". I would like the app to be "skinnable", and the skin would not only affect things like colours, fonts, etc. but also layout. As the number of fields and controls is variable, I'm hoping to find a generic solution.
I hope that makes it a bit clearer.
Since you say it is not recommended, I'm starting to think it is a difficult furrow to plough. I will reconsider it. Thanks for the warning
I hope that makes it a bit clearer.
Since you say it is not recommended, I'm starting to think it is a difficult furrow to plough. I will reconsider it. Thanks for the warning

-
- Livecode Opensource Backer
Got distracted by too many things. Here is a draft for a function for laying out elements (objects or groups) according to a box model.
Still need to test it, etc. but early feedback on the logic would be appreciated.
Still need to test it, etc. but early feedback on the logic would be appreciated.
Code: Select all
/* ____________________________________________________________
|
| Layout
|________________________________________________________
|
| @Author: Marielle Lange
| @Company: Widged.com
| @Date: January 16, 2007
| @Version: 0.1
| @Changes since last version: n/a
| @License: Creative Commons Attribution 2.5 License http://creativecommons.org/licenses/by/2.5/
|________________________________________________________
|
| @Dependency: -
|________________________________________________________ */
/*
Description:
Place one group exactly after another
*/
#######################################################
#######################################################
###
### API data
###
#######################################################
#######################################################
/*
_ _ _ box _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
! Margin !
! __ list _____________________________ !
! | padding | !
! | --- object ------------------- | !
! | ' ' | !
! | ' ' | !
! | ' ' | !
! | '------------------------------- | !
! | --- object ------------------- | !
! | ' ' | !
! | ' ' | !
! | ' ' | !
! | '------------------------------- | !
! | --- object ------------------- | !
! | ' ' | !
! | ' ' | !
! | ' ' | !
! | '------------------------------- | !
! |_____________________________________| !
!_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _!
--- box ------------------------
box_layout: table | proportional | grid -- taken from squeak,
-- not sure what this means
box_rectangle: left,top,right,bottom
box_dimensions: width,height
box_topleft: x,y
--- list ------------------------
list_objectsRef: list of the objects to lay out
list_direction: topToBottom | leftToRight
list_margins: n | n,n | n,n,n,n
list_hAlignment: top | bottom | middle
list_vAlignment: left |Â right |Â center
list_hResizing: shrinkWrap | spaceFill
list_vResizing: shrinkWrap
--- object ------------------------
object_paddings: n | n,n | n,n,n,n
*/
#### Box ######################################
/* ____________________________________________________________
|
| box_layout
|
*/
getProp box_layout
put the box_layout of me into tValue
put layout.force(tValue) into tValue
return tValue
end box_layout
/* ____________________________________________________________
|
| box_rectangle
|
*/
setProp box_rectangle pRect
put rectangle.force(pRect) into tRect
----
put abs(item 1 of tRect - item 3 of tRect) into tWidth
put abs(item 2 of tRect - item 4 of tRect) into tHeight
set the box_dimensions of me to tWidth,tHeight
----
put item 1 of tRect into tLeft
put item 2 of tRect into tTop
set the box_topleft of me to tLeft,tTop
----
return tValue
end box_rectangle
---
getProp box_rectangle
put the box_rectangle of me into tValue
return tValue
end box_rectangle
/* ____________________________________________________________
|
| box_dimensions
|
*/
setProp box_dimensions pDimension
----
put twoIntegers.force(pDimension) into tDimension
---
put item 1 of tDimension into tWidth
put item 2 of tDimension into tHeight
--
put the box_topleft of me into tTopleft
put item 1 of tTopLeft into tLeft
put item 2 of tTopLeft into tTop
--
put rectangle.FromDimensionAndTopLeft(tLeft,tTop,tWidth,tHeight) into tRect
set the box_rectangle of me to tRect
----
return tValue
end box_dimensions
----
getProp box_dimensions
put the box_dimensions of me into tValue
put twoIntegers.force(tValue) into tValue
return tValue
end box_dimensions
/* ____________________________________________________________
|
| box_topleft
|
*/
setProp box_topleft pTopleft
----
put twoIntegers.force(pTopleft) into tTopLeft
----
put item 1 of tTopLeft into tLeft
put item 2 of tTopLeft into tTop
--
put the box_dimensions of me into tDimension
put item 1 of tDimension into tWidth
put item 2 of tDimension into tHeight
--
put rectangle.FromDimensionAndTopLeft(tLeft,tTop,tWidth,tHeight) into tRect
set the box_rectangle of me to tRect
----
return tValue
end box_topleft
----
getProp box_topleft
put the box_dimensions of me into tValue
put dimension.force(tValue) into tValue
return tValue
end box_topleft
#### List ######################################
/* ____________________________________________________________
|
| list_objectsRef
|
*/
getProp list_objectsRef
put the list_objectsRef of me into tValue
return tValue
end list_objectsRef
/* ____________________________________________________________
|
| list_direction
|
*/
getProp list_direction
put the list_direction of me into tValue
put direction.force(tValue) into tValue
return tValue
end list_direction
/* ____________________________________________________________
|
| list_margins
|
*/
getProp list_margins
put the list_margins of me into tValue
put fourIntegers.force(tValue) into tValue
return tValue
end list_margins
/* ____________________________________________________________
|
| list_hResizing
|
*/
getProp list_hResizing
put the list_hResizing of me into tValue
put resizing.force(tValue) into tValue
return tValue
end list_hResizing
/* ____________________________________________________________
|
| list_vResizing
|
*/
getProp list_vResizing
put the list_hResizing of me into tValue
put resizing.force(tValue) into tValue
return tValue
end list_vResizing
#### Objects ######################################
/* ____________________________________________________________
|
| object_paddings
|
*/
getProp object_paddings
put the object_paddings of me into tValue
put fourIntegers.force(tValue) into tValue
return tValue
end object_paddings
###################################################################################
###################################################################################
###
### Indirect Properties
###
###################################################################################
###################################################################################
/* ____________________________________________________________
|
| box.left/top/right/bottom/center
|
*/
function box.left
return (item 1 of the box_rectangle of me)
end box.left
-----
function box.right
return (item 3 of the box_rectangle of me)
end box.right
----
function box.top
return (item 2 of the box_rectangle of me)
end box.top
----
function box.bottom
return (item 4 of the box_rectangle of me)
end box.bottom
#########
function box.center
put round(box.right()+box.left())/2 into tValue
return tValue
end box.center
----
function box.middle
put round(box.top()+box.bottom())/2 into tValue
return tValue
end box.middle
----
function box.loc
put box.center,box.middle into tValue
return tValue
end box.loc
/* ____________________________________________________________
|
| list.left/top/right/bottom/center
|
*/
function list.left
put item 1 of the list_margins of me into tMargin
put box.left() + tMargin into tValue
return tValue
end list.left
-----
function list.right
put item 3 of the list_margins of me into tMargin
put box.right() - tMargin into tValue
return tValue
end list.right
----
function list.top
put item 3 of the list_margins of me into tMargin
put box.top() + tMargin into tValue
return tValue
end list.top
----
function list.bottom
put item 4 of the list_margins of me into tMargin
put box.bottom() - tMargin into tValue
return tValue
end list.bottom
#######
function list.center
put round(list.right()+list.left())/2 into tValue
return tValue
end list.center
----
function list.middle
put round(list.top()+list.bottom())/2 into tValue
return tValue
end list.middle
---
function list.width
put abs(list.left()-list.righ()) into tValue
return tValue
end list.width
---
function list.height
put abs(list.left()-list.righ()) into tValue
return tValue
end list.height
----
function list.loc
put list.center,list.middle into tValue
return tValue
end list.loc
/* ____________________________________________________________
|
| firstOrLastObject.left/top/right
|
*/
function firstOrLastObject.left
put item 1 of the object_paddings of me into tPadding
put list.left() + tPadding into tValue
return tValue
end firstOrLastObject.left
-----
function firstOrLastObject.top
put item 3 of the object_paddings of me into tPadding
put list.top() + tPadding into tValue
return tValue
end firstOrLastObject.top
-----
function firstOrLastObject.right
put item 3 of the object_paddings of me into tPadding
put list.right() - tPadding into tValue
return tValue
end firstOrLastObject.right
----
function firstOrLastObject.bottom
put item 4 of the object_paddings of me into tPadding
put list.bottom() - tPadding into tValue
return tValue
end firstOrLastObject.bottom
#############
function firstOrLastObject.center
put round(firstOrLastObject.right()+firstOrLastObject.left())/2 into tValue
return tValue
end firstOrLastObject.center
----
function firstOrLastObject.middle
put round(firstOrLastObject.top()+firstOrLastObject.bottom())/2 into tValue
return tValue
end firstOrLastObject.middle
###################################################################################
###################################################################################
###
### Processing
###
###################################################################################
###################################################################################
/* ____________________________________________________________
|
| objectList.layout
|
| Note: Resizing is being ignored for now
*/
on objectList.layout
----
put the box_layout of me into tLayout
--
put the list_objectsRef of me into tLstObjects
put the list_direction of me into tDirection
put the list_hAlignment of me into thAlignment
put the list_vAlignment of me into tvAlignment
-- put the list_hResizing of me into thResizing
-- put the list_vRezizing of me into tvResizing
----
put the object_paddings of me into tPaddings
---
put firstOrLastObject.top() into tTop
put firstOrLastObject.left() into tLeft
---
repeat with x = 1 to the number of lines in tLstObjects
put (line x of tLstObjects) into tCtlRef
if objectRef.validate(tCtlRef) is false then
-- TBD could add some warning message
next repeat
end if
---
switch tDirection
case "topToBottom"
object.hAlign tCtlRef, thAlignement
set the top of tCtlRef to tTop
add item 4 of tPaddings + item 2 of tPaddings to tTop
break
case "leftToRight"
object.vAlign tCtlRef, tvAlignement
set the left of tCtlRef to tLeft
add item 3 of tPaddings + item 1 of tPaddings to tLeft
break
end switch
end repeat
end objectList.layout
/* ____________________________________________________________
|
| object.hAlign
|
*/
on object.hAlign tCtlRef, pAlign
switch pAlign
case "left"
set the left of tCtlRef to firstOrLastObject.left()
break
case "right"
set the right of tCtlRef to firstOrLastObject.right()
break
case "center"
put the loc of tCtlRef into tLoc
put firstOrLastObject.center() into tCenter
put tCenter into item 1 of tLoc
set the loc of tCtlRef to tLoc
break
end switch
end object.hAlign
/* ____________________________________________________________
|
| object.vAlign
|
*/
on object.vAlign tCtlRef, pAlign
switch pAlign
case "top"
set the top of tCtlRef to firstOrLastObject.top()
break
case "bottom"
set the bottom of tCtlRef to firstOrLastObject.bottom()
break
case "middle"
put the loc of tCtlRef into tLoc
put firstOrLastObject.middle() into tMiddle
put tMiddle into item 2 of tLoc
set the loc of tCtlRef to tLoc
break
end switch
end object.vAlign
#######################################################
#######################################################
###
### Dependencies
###
#######################################################
#######################################################
### container - card reference ##################
/* ____________________________________________________________
|
| card.ref
|
*/
function card.ref
put the container_ref of me into tRef
if not exists(tRef) then
return empty -- TBD: something more sensible
end if
put word -6 to -1 of the long id of tRef into tCardRef
return tCardRef
end card.ref
### rectangle ###################################
/* ____________________________________________________________
|
| rectangle.FromDimensionAndTopLeft
|
*/
function rectangle.FromDimensionAndTopLeft pLeft, pTop, pWidth, pHeight
----
put integer.force(pLeft) into tLeft
put integer.force(pTop) into tTop
put integer.force(pWidth) into tWidth
put integer.force(pHeight) into tHeight
----
put tLeft, tTop, tLeft+tWidth, tTop+tHeight into tRect
----
return tRect
end rectangle.FromDimensionAndTopLeft
### Data Validation ############################
/* ____________________________________________________________
|
| objectRef.validate
|
*/
function objectRef.validate tRef
if exists(tRef) then return true
return false
end objectRef.validate
/* ____________________________________________________________
|
| integer.force
|
*/
function integer.force pValue
if pValue is not an integer then return 0
return pValue
end integer.force
/* ____________________________________________________________
|
| rectangle.force
|
*/
function rectangle.force pRect
put pRect into tRect
put integer.force(item 1 of tRect), integer.force(item 2 of tRect), integer.force(item 3 of tRect), integer.force(item 4 of tRect) into tRect
return tRect
end rectangle.force
/* ____________________________________________________________
|
| fourIntegers.force
|
*/
function fourIntegers.force pLstItems
----
put the number of items of pLstItems into tNbItems
-----
put pLstItems into tLstItems
if tNbItems = 1 then
put item 1 of tLstItems into item 2 of tLstItems
put item 1 of tLstItems into item 3 of tLstItems
put item 1 of tLstItems into item 4 of tLstItems
else if tNbItems=2 then
put item 2 of tLstItems into item 3 of tLstItems
put item 2 of tLstItems into item 4 of tLstItems
put item 1 of tLstItems into item 2 of tLstItems
end if
put integer.force(item 1 of tLstItems), integer.force(item 2 of tLstItems), integer.force(item 3 of tLstItems), integer.force(item 4 of tLstItems) into tLstItems
----
return tLstItems
----
end fourIntegers.force
/* ____________________________________________________________
|
| twoIntegers.force
|
*/
function twoIntegers.force pItems
----
put pLstItems into tLstItems
put integer.force(item 1 of tLstItems), integer.force(item 2 of tLstItems) into tLstItems
return tLstItems
----
end twoIntegers.force
/* ____________________________________________________________
|
| layout.force
|
*/
function layout.force pLayout
if pLayout is not among the items of "table,proportional,grid" then
return "table"
end if
return pLayout
end layout.force
/* ____________________________________________________________
|
| direction.force
|
*/
function direction.force pDirection
if pDirection is not among the items of "leftToRight,topToBottom" then
return "topToBottom"
end if
return pDirection
end direction.force
/* ____________________________________________________________
|
| hAlign.force
|
*/
function hAlign.force pAlign
if pAlign is not among the items of "left,center,right" then
return "left"
end if
return pAlign
end hAlign.force
/* ____________________________________________________________
|
| vAlign.force
|
*/
function vAlign.force pAlign
if pAlign is not among the items of "top,bottom,middle" then
return "top"
end if
return pAlign
end vAlign.force
/* ____________________________________________________________
|
| resizing.force
|
*/
function resizing.force pResizing
if pResizing is not among the items of "shrinkWrap,spaceFill" then
return "spaceFill"
end if
return pResizing
end resizing.force
-
- Livecode Opensource Backer
This didn't cross my mind eitherBernard wrote:It never crossed my mind to have a look at what they were doing with layouts in Squeak).

I have a pile of papers on automatic layout generation... unfortunately, I won't have the time to go through it this month.
Marielle
Last edited by marielle on Wed Jan 17, 2007 1:06 pm, edited 1 time in total.
I didn't know that. That sounds very depressing. The whole dabbleDB project (http://dabbledb.com/) was built on Squeak - it won the Under the Radar competition last year (http://undertheradarblog.com/2006/03/03 ... winner-is/).Their mailing list suggest that their founding members are now leaving the community
The main developer (Avi Bryant) of DabbleDB said that it would not have been possible to build it on any platform other than Smalltalk. And the whole thing runs inside Squeak.