Home   Archive   Permalink



Can a VID list style contain a field?

I want to make a form for entering data into a list, and the size of the list is not known until run time. I am wondering if the 'list' style can contain a field for data entry, and how I would go about using it. In the contrived demo below, if I type a couple characters into any field, the program crashes. Even if it did not crash, I don't see how I would get my hands on the field values. The 'count' and 'index' items are available only (it seems) in the 'supply' function which is executed when building the list and not in any post-building processing. Maybe it can't be done; maybe a 'list' is just for 'listing.' But if it can, and anyone knows how, I would be grateful for some direction. Thank you.
    
R E B O L [
     Title: 'Test a list with a field'
]
    
;; This is the data that will go on the list.
;; It is a simple demo, a contrived example to have something
;; to work with. It is a list of names, plus 'nicknames'
;; that we hope to change in a window with a list.
    
NAMES: [
     ['Andrew Anderson' 'Andy']
     ['Betty Barber' 'Bets']
     ['Charles Carlson' 'Chuck']
     ['David Davidson' 'Dave']
     ['Edward Edwards' 'Ed']
     ['Francis Frankenstein' 'Frank']
]
    
SUPPLY-START: 0
    
view center-face layout [
     across
     banner 'Test of list with field'
     return
     space 0
     text snow black 200 'Full name' center bold
     text snow black 150 'Nickname' center bold
     return
     LST: list 350x400 [
         origin 0
         space 0x0
         across
         text 200 bold
         field 150 bold ;;; Can I put a field here and what do I do with it?
     ] supply [    
         count: count + SUPPLY-START
         face/color: ivory
         face/text: none
         face/font/color: black
         if even? count [face/color: ivory - 50.50.50]
         if none? NAME-BLOCK: pick NAMES count [exit]
         face/text: pick NAME-BLOCK index
     ]
     slider 20x400 [
         SUPPLY-START: (length? NAMES) * value
         show LST
     ]
]


posted by:   Steven White       7-Nov-2016/12:45:35-8:00



My inclination would be to say this is very, very difficult to pull off. Each list item is actually the SAME block of faces (let's call them 'cast faces') shown at multiple offsets simultaneously (let's call them 'rows' and we'll call the display of the cast faces at each row an 'impression'). The height of each row is fixed (based on the row layout spec) as is the number of rows based on container height / row height.
    
Initially the impression on every row is composed with variations of the cast faces determined by the SUPPLY function. Some events trigger a refresh of a row's impression (usually dependent on offset), other events can trigger the refresh of every row. (you can see this by adding PRINT [AS-PAIR COUNT INDEX FACE/STYLE] to the end of your SUPPLY block).
    
What's happening in your example is that you are able to focus on the field, but then each keypress forces the refresh of all the rows. As the cast faces are used to create each new impression, the SUPPLY function alters their content and the field's edit functions get all confused.
    
A simpler approach would be to have a separate panel to edit each of your fields and just use the list to select which field you are editing. You can do this by attaching actions to each of the cast faces that populate and focus the panel.
    
     LST: list 350x400 [
         across origin 0 space 0
         text 200 bold [probe face/data]
         text 150 bold [probe face/data]
     ] supply [
         ; ... your supply function, and: ...
         face/data: name-block/1
     ]

posted by:   Chris       10-Nov-2016/23:35:26-8:00



Or just simply:
    
     face/data: name-block
    
Then replace PROBE with POPULATE EDIT PANEL. FACE/DATA in the functions will be the same block from your data block.

posted by:   Chris       10-Nov-2016/23:39:13-8:00



Or better put, replace:
    
     probe face/data
    
With:
    
     populate-edit-panel face/data
    
    
Lists contain much sleight of hand so as to be performant. They are that, but it makes them complex. Far better to keep their utility as conservative as possible.

posted by:   Chris       10-Nov-2016/23:44:22-8:00



Or, maybe an alternative representation might be to make a subpanel with a column of fields, where the entire face containing the fields can be scrolled with slider. The slider would be in the main face, not the sub panel.
    
It could look like a list, yet every field is unique, so on could set & get the values. I imagine this could be composed on startup, with the number of fields as needed. They might be identified with a variable name, or just by the position in the order of calling all data of the fields of the subpanel.
    
Some other ideas might be gleaned from:    
http://rebol2.blogspot.com.au/2013/08/the-worlds-smallest-spreadsheet-program.html


posted by:   Neutron       12-Nov-2016/0:03:24-8:00



Steve, take a look at http://business-programming.com/business_programming.html#section-16.21
    
Read the section titled '16.21.2 Creating Home Made Multi Column Data Grids'

posted by:   Nick       12-Nov-2016/3:20:31-8:00



The section of the tutorial at that link also demonstrates how to accomplish your goal, using the list style. The final example, as well as several simpler examples show how it can be done. I've always just used simpler styles, such as a 'text style, instead of a 'field style, and attached a 'request-text action to each instance of any text I want to edit. Check out the examples and the explanations which lead up to this code, in the section linked above:
    
R E B O L [title: "List Widget Example"]
    
x: copy [] random/seed now/time ; generate 5000 rows of random data:
repeat i 5000 [
     append/only x reduce [random "asdfqwertyiop" form random 1000 form i]
] y: copy x
Alert help-txt: {Be sure to try the following features: 1) Resize the GUI
     window to see the list automatically adjust to fit 2) Click column
     headers to sort by field 3) Use the arrow keys and page-up/page-down
     keys to scroll 4) Use the Insert, Delete and "M" keys to add, remove
     and move rows (by default, at the currently highlighted row) 5) Click
     the small "r" header button in the top right corner to reset the list
     back to its original values 6) Click any individual data cell to edit
     the selected value.}
sort-column: func [field] [
     either sort-order: not sort-order [
         sort/compare x func [a b] [(at a field) > (at b field)]
     ] [
         sort/compare x func [a b] [(at a field) < (at b field)]
     ]    
     show li
]
key-scroll: func [scroll-amount] [
     s-pos: s-pos + scroll-amount
     if s-pos > (length? x) [s-pos: length? x]
     if s-pos < 0 [s-pos: 0]
     sl/data: s-pos / (length? x)    
     show li show sl
]
resize-grid: func [percentage] [
     gui-size: system/view/screen-face/pane/1/size ; - 10x0
     list-size/1: list-size/1 * percentage
     list-size/2: gui-size/2 - 95
     t-size: round (list-size/1 / 3)
     sl-size: as-pair 16 list-size/2
     unview/only gui view/options center-face layout gui-block [resize]
]
resize-fit: does [
     gui-size: system/view/screen-face/pane/1/size
     resize-grid (gui-size/1 / list-size/1 - .1)
]
insert-event-func [either event/type = 'resize [resize-fit none] [event]]
gui-size: system/view/screen-face/size - 0x50
list-size: gui-size - 60x95
sl-size: as-pair 16 list-size/2
t-size: round (list-size/1 / 3)
s-pos: 0 sort-order: true ovr-cnt: none svv/vid-face/color: white
view/options center-face gui: layout gui-block: [
     size gui-size across
     btn "Smaller" [resize-grid .75]
     btn "Bigger" [resize-grid 1.3333]
     btn "Fit" [resize-fit]
     btn #"^~" "Remove" [attempt [
         indx: to-integer request-text/title/default "Row to remove:"
             form to-integer ovr-cnt
         if indx = 0 [return]
         if true <> request rejoin ["Remove: " pick x indx "?"] [return]
         remove (at x indx) show li
     ]]
     insert-btn: btn "Add" [attempt [
         indx: to-integer request-text/title/default "Add values at row #:"
             form to-integer ovr-cnt
         if indx = 0 [return]
         new-values: reduce [
             request-text request-text (form ((length? x) + 1))
         ]
         insert/only (at x indx) new-values show li
     ]]
     btn #"m" "Move" [
         old-indx: to-integer request-text/title/default "Move from row #:"
             form to-integer ovr-cnt
         new-indx: to-integer request-text/title "Move to row #:"
         if ((new-indx = 0) or (old-indx = 0)) [return]
         if true <> request rejoin ["Move: " pick x old-indx "?"] [return]
         move/to (at x old-indx) new-indx show li
     ]
     btn "Save" [save to-file request-file/save x]
     btn "Load" [y: copy x: copy load request-file/only show li]
     btn "Read Me" [alert help-txt]
     btn "View Data" [editor x]
     return space 0x0
     style header button as-pair t-size 20 black white bold
     header "Random Text" [sort-column 1]
     header "Random Number" [sort-column 2]
     header "Unique Key" [sort-column 3]
     button black "r" 17x20 [if true = request "Reset?"[x: copy y show li]]
     return
     li: list list-size [
         style cell text t-size feel [
             over: func [f o] [
                 if (o and (ovr-cnt <> f/data)) [ovr-cnt: f/data show li]
             ]
             engage: func [f a e] [
                 if a = 'up [
                     f/text: request-text/default f/text show li
                 ]
             ]
         ]            
         across space 0x0
         col1: cell blue
         col2: cell
         col3: cell red
     ] supply [
         either even? count [face/color: white] [face/color: 240.240.255]
         count: count + s-pos
         if none? q: pick x count [face/text: copy "" exit]
         if ovr-cnt = count [face/color: 200.200.255]
         face/data: count
         face/text: pick q index
     ]
     sl: scroller sl-size [s-pos: (length? x) * value show li]
     key keycode [up] [key-scroll -1]
     key keycode [down] [key-scroll 1]
     key keycode [page-up] [key-scroll -20]
     key keycode [page-down] [key-scroll 20]
     key keycode [insert] [do-face insert-btn 1]
] [resize]

posted by:   Nick       12-Nov-2016/5:11:03-8:00



I made a more easily usable implementation of a version of the code example above:
    
R E B O L [title: "Data Grid Lib Example"]
headers: ["Column1" "Column2"]    
x: data: [
     ["Item 01-01" "Item 02-01"]
     ["Item 01-02" "Item 02-02"]
     ["Item 01-03" "Item 02-03"]
     ["Item 01-04" "Item 02-04"]
     ["Item 01-05" "Item 02-05"]
]
do http://re-bol.com/gridlib.r

posted by:   Nick       12-Nov-2016/5:22:30-8:00



To answer your question more specifically, replace this line in your example above:
    
field 150 bold ;;; Can I put a field here and what do I do with it?
    
with this:
    
text 150 bold [
     face/text: request-text/default face/text
     show face focus face unfocus face
]    
    
There are several examples at the link above which demonstrate that technique. In the big example which I pasted above, it's found in 'feel block of the 'cell style.

posted by:   Nick       12-Nov-2016/7:27:59-8:00



There's a lot more in that section of the tutorial which explains how to access the data in an editable grid (search for "editor second second get in (list-widget-label) 'subfunc"), save/load the entire table add/delete rows, etc., which should answer all your questions.

posted by:   Nick       12-Nov-2016/10:02:32-8:00