multiple selection in table views
parent
c7242b8516
commit
89efe27ab5
|
@ -20,13 +20,15 @@ ARTICLE: "ui.gadgets.tables.selection" "Table row selection"
|
||||||
$nl
|
$nl
|
||||||
"A few slots in the table gadget concern row selection:"
|
"A few slots in the table gadget concern row selection:"
|
||||||
{ $table
|
{ $table
|
||||||
{ { $slot "selected-value" } { " - if set to a model, the currently selected row's value, as determined by a " { $link row-value } " call to the renderer, is stored in this model. See " { $link "models" } "." } }
|
{ { $slot "selected-values" } { " - if set to a model, an array of the currently selected rows' values, as determined by a " { $link row-value } " call to the renderer, is stored in this model. See " { $link "models" } "." } }
|
||||||
{ { $slot "selected-index" } " - the index of the currently selected row." }
|
{ { $slot "selected-indices" } " - the indices of the currently selected rows." }
|
||||||
{ { $slot "selection-required?" } { " - if set to a true value, the table ensures that some row is always selected, if the model is non-empty. If set to " { $link f } ", a state where nothing is selected is permitted to occur. The default is " { $link f } "." } }
|
{ { $slot "selection-required?" } { " - if set to a true value, the table ensures that some row is always selected, if the model is non-empty. If set to " { $link f } ", a state where nothing is selected is permitted to occur. The default is " { $link f } "." } }
|
||||||
|
{ { $slot "multiple-selection?" } { " - if set to a true value, users are allowed to select more than one value." } }
|
||||||
|
|
||||||
}
|
}
|
||||||
"Some words for row selection:"
|
"Some words for row selection:"
|
||||||
{ $subsection selected-row }
|
{ $subsection selected-rows }
|
||||||
{ $subsection (selected-row) } ;
|
{ $subsection (selected-rows) } ;
|
||||||
|
|
||||||
ARTICLE: "ui.gadgets.tables.actions" "Table row actions"
|
ARTICLE: "ui.gadgets.tables.actions" "Table row actions"
|
||||||
"When the user double-clicks on a row, or presses " { $command table "row" row-action } " while a row is selected, optional action and hook quotations are invoked. The action receives the row value and the hook receives the table gadget itself. These quotations are stored in the " { $slot "action" } " and " { $snippet "hook" } " slots of a table, respectively."
|
"When the user double-clicks on a row, or presses " { $command table "row" row-action } " while a row is selected, optional action and hook quotations are invoked. The action receives the row value and the hook receives the table gadget itself. These quotations are stored in the " { $slot "action" } " and " { $snippet "hook" } " slots of a table, respectively."
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
! Copyright (C) 2008, 2009 Slava Pestov.
|
! Copyright (C) 2008, 2009 Slava Pestov.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: accessors arrays colors colors.constants fry kernel math
|
USING: accessors arrays colors colors.constants fry kernel math
|
||||||
math.functions math.rectangles math.order math.vectors namespaces
|
math.functions math.ranges math.rectangles math.order math.vectors models.arrow
|
||||||
opengl sequences ui.gadgets ui.gadgets.scrollers ui.gadgets.status-bar
|
namespaces opengl sequences ui.gadgets ui.gadgets.scrollers
|
||||||
ui.gadgets.worlds ui.gestures ui.render ui.pens.solid ui.text
|
ui.gadgets.status-bar ui.gadgets.worlds ui.gestures ui.render ui.pens.solid
|
||||||
ui.commands ui.images ui.gadgets.menus ui.gadgets.line-support
|
ui.text ui.commands ui.images ui.gadgets.menus ui.gadgets.line-support
|
||||||
math.rectangles models math.ranges sequences combinators
|
math.rectangles models math.ranges sequences combinators
|
||||||
combinators.short-circuit fonts locals strings ;
|
combinators.short-circuit fonts locals strings vectors ;
|
||||||
IN: ui.gadgets.tables
|
IN: ui.gadgets.tables
|
||||||
|
|
||||||
! Row rendererer protocol
|
! Row rendererer protocol
|
||||||
|
@ -41,16 +41,33 @@ focus-border-color
|
||||||
{ mouse-color initial: COLOR: black }
|
{ mouse-color initial: COLOR: black }
|
||||||
column-line-color
|
column-line-color
|
||||||
selection-required?
|
selection-required?
|
||||||
selected-index selected-value
|
selected-indices selected-values
|
||||||
mouse-index
|
mouse-index
|
||||||
{ takes-focus? initial: t }
|
{ takes-focus? initial: t }
|
||||||
focused? ;
|
focused?
|
||||||
|
multiple-selection? ;
|
||||||
|
|
||||||
|
IN: accessors
|
||||||
|
GENERIC: selected-value>> ( table -- n )
|
||||||
|
GENERIC: selected-index>> ( table -- n )
|
||||||
|
GENERIC: (>>selected-index) ( n table -- )
|
||||||
|
GENERIC: (>>selected-value) ( val table -- )
|
||||||
|
: >>selected-index ( table n -- table ) over (>>selected-index) ;
|
||||||
|
: >>selected-value ( table val -- table ) over (>>selected-value) ;
|
||||||
|
|
||||||
|
M: table selected-value>> selected-values>> [ [ peek ] [ f ] if* ] <arrow> ;
|
||||||
|
M: table (>>selected-value) [ [ 1vector ] <arrow> ] dip (>>selected-values) ;
|
||||||
|
M: table selected-index>> selected-indices>> [ peek ] [ f ] if* ;
|
||||||
|
M: table (>>selected-index) [ 1vector ] dip (>>selected-indices) ;
|
||||||
|
|
||||||
|
IN: ui.gadgets.tables
|
||||||
|
: push-selected-index ( table n -- table ) over selected-indices>> push ;
|
||||||
|
|
||||||
: new-table ( rows renderer class -- table )
|
: new-table ( rows renderer class -- table )
|
||||||
new-line-gadget
|
new-line-gadget
|
||||||
swap >>renderer
|
swap >>renderer
|
||||||
swap >>model
|
swap >>model
|
||||||
f <model> >>selected-value
|
f <model> >>selected-values
|
||||||
sans-serif-font >>font
|
sans-serif-font >>font
|
||||||
focus-border-color >>focus-border-color
|
focus-border-color >>focus-border-color
|
||||||
transparent >>column-line-color ; inline
|
transparent >>column-line-color ; inline
|
||||||
|
@ -131,12 +148,12 @@ M: table layout*
|
||||||
: row-bounds ( table row -- loc dim )
|
: row-bounds ( table row -- loc dim )
|
||||||
row-rect rect-bounds ; inline
|
row-rect rect-bounds ; inline
|
||||||
|
|
||||||
: draw-selected-row ( table -- )
|
: draw-selected-rows ( table -- )
|
||||||
{
|
{
|
||||||
{ [ dup selected-index>> not ] [ drop ] }
|
{ [ dup selected-indices>> not ] [ drop ] }
|
||||||
[
|
[
|
||||||
[ ] [ selected-index>> ] [ selection-color>> gl-color ] tri
|
[ selected-indices>> ] [ selection-color>> gl-color ] [ ] tri
|
||||||
row-bounds gl-fill-rect
|
[ swap row-bounds gl-fill-rect ] curry each
|
||||||
]
|
]
|
||||||
} cond ;
|
} cond ;
|
||||||
|
|
||||||
|
@ -189,10 +206,10 @@ M: table layout*
|
||||||
dup renderer>> column-alignment
|
dup renderer>> column-alignment
|
||||||
[ ] [ column-widths>> length 0 <repetition> ] ?if ;
|
[ ] [ column-widths>> length 0 <repetition> ] ?if ;
|
||||||
|
|
||||||
:: row-font ( row index table -- font )
|
:: row-font ( row ind table -- font )
|
||||||
table font>> clone
|
table font>> clone
|
||||||
row table renderer>> row-color [ >>foreground ] when*
|
row table renderer>> row-color [ >>foreground ] when*
|
||||||
index table selected-index>> = [ table selection-color>> >>background ] when ;
|
ind table selected-indices>> index [ table selection-color>> >>background ] when ;
|
||||||
|
|
||||||
: draw-columns ( columns widths alignment font gap -- )
|
: draw-columns ( columns widths alignment font gap -- )
|
||||||
'[ [ _ ] 3dip _ draw-column ] 3each ;
|
'[ [ _ ] 3dip _ draw-column ] 3each ;
|
||||||
|
@ -213,7 +230,7 @@ M: table draw-gadget*
|
||||||
dup control-value empty? [ drop ] [
|
dup control-value empty? [ drop ] [
|
||||||
dup line-height \ line-height [
|
dup line-height \ line-height [
|
||||||
{
|
{
|
||||||
[ draw-selected-row ]
|
[ draw-selected-rows ]
|
||||||
[ draw-lines ]
|
[ draw-lines ]
|
||||||
[ draw-column-lines ]
|
[ draw-column-lines ]
|
||||||
[ draw-focused-row ]
|
[ draw-focused-row ]
|
||||||
|
@ -236,17 +253,19 @@ M: table pref-dim*
|
||||||
|
|
||||||
PRIVATE>
|
PRIVATE>
|
||||||
|
|
||||||
: (selected-row) ( table -- value/f ? )
|
: (selected-rows) ( table -- {row} )
|
||||||
[ selected-index>> ] keep nth-row ;
|
[ selected-indices>> ] keep
|
||||||
|
[ nth-row [ 1array ] [ drop { } ] if ] curry map concat ;
|
||||||
|
|
||||||
: selected-row ( table -- value/f ? )
|
: selected-rows ( table -- {value} )
|
||||||
[ (selected-row) ] keep
|
[ (selected-rows) ] [ renderer>> ] bi [ row-value ] curry map ;
|
||||||
swap [ renderer>> row-value t ] [ 2drop f f ] if ;
|
|
||||||
|
: selected-row ( table -- value ? ) selected-rows [ f f ] [ peek t ] if-empty ;
|
||||||
|
|
||||||
<PRIVATE
|
<PRIVATE
|
||||||
|
|
||||||
: update-selected-value ( table -- )
|
: update-selected-values ( table -- )
|
||||||
[ selected-row drop ] [ selected-value>> ] bi set-model ;
|
[ selected-rows ] [ selected-values>> ] bi set-model ;
|
||||||
|
|
||||||
: show-row-summary ( table n -- )
|
: show-row-summary ( table n -- )
|
||||||
over nth-row
|
over nth-row
|
||||||
|
@ -260,54 +279,68 @@ PRIVATE>
|
||||||
: find-row-index ( value table -- n/f )
|
: find-row-index ( value table -- n/f )
|
||||||
[ model>> value>> ] [ renderer>> '[ _ row-value ] map index ] bi ;
|
[ model>> value>> ] [ renderer>> '[ _ row-value ] map index ] bi ;
|
||||||
|
|
||||||
: initial-selected-index ( table -- n/f )
|
: initial-selected-indices ( table -- n/f )
|
||||||
{
|
{
|
||||||
[ model>> value>> empty? not ]
|
[ model>> value>> empty? not ]
|
||||||
[ selection-required?>> ]
|
[ selection-required?>> ]
|
||||||
[ drop 0 ]
|
[ drop V{ 0 } ]
|
||||||
} 1&& ;
|
} 1&& ;
|
||||||
|
|
||||||
: (update-selected-index) ( table -- n/f )
|
: (update-selected-indices) ( table -- {n}/f )
|
||||||
[ selected-value>> value>> ] keep over
|
[ selected-values>> value>> ] keep
|
||||||
[ find-row-index ] [ 2drop f ] if ;
|
[ find-row-index ] curry map [ ] filter [ f ] when-empty ;
|
||||||
|
|
||||||
: update-selected-index ( table -- n/f )
|
: update-selected-indices ( table -- {n}/f )
|
||||||
{
|
{
|
||||||
[ (update-selected-index) ]
|
[ (update-selected-indices) ]
|
||||||
[ initial-selected-index ]
|
[ initial-selected-indices ]
|
||||||
} 1|| ;
|
} 1|| ;
|
||||||
|
|
||||||
M: table model-changed
|
M: table model-changed
|
||||||
nip dup update-selected-index {
|
nip dup update-selected-indices {
|
||||||
[ >>selected-index f >>mouse-index drop ]
|
[ >>selected-indices f >>mouse-index drop ]
|
||||||
[ show-row-summary ]
|
[ peek show-row-summary ]
|
||||||
[ drop update-selected-value ]
|
[ drop update-selected-values ]
|
||||||
[ drop relayout ]
|
[ drop relayout ]
|
||||||
} 2cleave ;
|
} 2cleave ;
|
||||||
|
|
||||||
: thin-row-rect ( table row -- rect )
|
: thin-row-rect ( table row -- rect )
|
||||||
row-rect [ { 0 1 } v* ] change-dim ;
|
row-rect [ { 0 1 } v* ] change-dim ;
|
||||||
|
|
||||||
|
: scroll-to-row ( table n -- )
|
||||||
|
dup [ [ thin-row-rect ] [ drop ] 2bi scroll>rect ] [ 2drop ] if ;
|
||||||
|
|
||||||
|
: add-selected-row ( table n -- )
|
||||||
|
[ scroll-to-row ]
|
||||||
|
[ push-selected-index relayout-1 ] 2bi ;
|
||||||
|
|
||||||
: (select-row) ( table n -- )
|
: (select-row) ( table n -- )
|
||||||
[ dup [ [ thin-row-rect ] [ drop ] 2bi scroll>rect ] [ 2drop ] if ]
|
[ scroll-to-row ]
|
||||||
[ >>selected-index relayout-1 ]
|
[ >>selected-index relayout-1 ]
|
||||||
2bi ;
|
2bi ;
|
||||||
|
|
||||||
: mouse-row ( table -- n )
|
: mouse-row ( table -- n )
|
||||||
[ hand-rel second ] keep y>line ;
|
[ hand-rel second ] keep y>line ;
|
||||||
|
|
||||||
: if-mouse-row ( table true: ( table mouse-index -- ) false: ( table -- ) -- )
|
: if-mouse-row ( table true: ( mouse-index table -- ) false: ( table -- ) -- )
|
||||||
[ [ mouse-row ] keep 2dup valid-line? ]
|
[ [ mouse-row ] keep 2dup valid-line? ]
|
||||||
[ ] [ '[ nip @ ] ] tri* if ; inline
|
[ ] [ '[ nip @ ] ] tri* if ; inline
|
||||||
|
|
||||||
: table-button-down ( table -- )
|
: (table-button-down) ( quot table -- )
|
||||||
dup takes-focus?>> [ dup request-focus ] when
|
dup takes-focus?>> [ dup request-focus ] when swap
|
||||||
[ swap [ >>mouse-index ] [ (select-row) ] bi ] [ drop ] if-mouse-row ;
|
'[ swap [ >>mouse-index ] _ bi ] [ drop ] if-mouse-row ; inline
|
||||||
|
|
||||||
|
: table-button-down ( table -- ) [ (select-row) ] swap (table-button-down) ;
|
||||||
|
: continued-button-down ( table -- ) dup multiple-selection?>> [ [ add-selected-row ] swap (table-button-down) ] [ table-button-down ] if ;
|
||||||
|
: thru-button-down ( table -- ) dup multiple-selection?>> [
|
||||||
|
[ over selected-index>> (a,b] over
|
||||||
|
[ swap push-selected-index drop ] curry each continued-button-down ]
|
||||||
|
swap (table-button-down) ] [ table-button-down ] if ;
|
||||||
|
|
||||||
PRIVATE>
|
PRIVATE>
|
||||||
|
|
||||||
: row-action ( table -- )
|
: row-action ( table -- )
|
||||||
dup selected-row
|
dup [ selected-rows peek ]
|
||||||
[ swap [ action>> call( value -- ) ] [ dup hook>> call( table -- ) ] bi ]
|
[ swap [ action>> call( value -- ) ] [ dup hook>> call( table -- ) ] bi ]
|
||||||
[ 2drop ]
|
[ 2drop ]
|
||||||
if ;
|
if ;
|
||||||
|
@ -319,14 +352,14 @@ PRIVATE>
|
||||||
<PRIVATE
|
<PRIVATE
|
||||||
|
|
||||||
: table-button-up ( table -- )
|
: table-button-up ( table -- )
|
||||||
dup row-action? [ row-action ] [ update-selected-value ] if ;
|
dup row-action? [ row-action ] [ update-selected-values ] if ;
|
||||||
|
|
||||||
PRIVATE>
|
PRIVATE>
|
||||||
|
|
||||||
: select-row ( table n -- )
|
: select-row ( table n -- )
|
||||||
over validate-line
|
over validate-line
|
||||||
[ (select-row) ]
|
[ (select-row) ]
|
||||||
[ drop update-selected-value ]
|
[ drop update-selected-values ]
|
||||||
[ show-row-summary ]
|
[ show-row-summary ]
|
||||||
2tri ;
|
2tri ;
|
||||||
|
|
||||||
|
@ -385,6 +418,8 @@ table "sundry" f {
|
||||||
{ mouse-enter show-mouse-help }
|
{ mouse-enter show-mouse-help }
|
||||||
{ mouse-leave hide-mouse-help }
|
{ mouse-leave hide-mouse-help }
|
||||||
{ motion show-mouse-help }
|
{ motion show-mouse-help }
|
||||||
|
{ T{ button-down f { A+ } 1 } continued-button-down }
|
||||||
|
{ T{ button-down f { S+ } 1 } thru-button-down }
|
||||||
{ T{ button-down } table-button-down }
|
{ T{ button-down } table-button-down }
|
||||||
{ T{ button-up } table-button-up }
|
{ T{ button-up } table-button-up }
|
||||||
{ gain-focus focus-table }
|
{ gain-focus focus-table }
|
||||||
|
|
|
@ -60,7 +60,7 @@ M: frp-table row-color color-quot>> [ call( a -- b ) ] [ drop f ] if* ;
|
||||||
|
|
||||||
: <frp-table> ( model -- table )
|
: <frp-table> ( model -- table )
|
||||||
frp-table new-line-gadget dup >>renderer swap >>model
|
frp-table new-line-gadget dup >>renderer swap >>model
|
||||||
f basic-model new-model >>selected-value sans-serif-font >>font
|
f basic-model new-model >>selected-values sans-serif-font >>font
|
||||||
focus-border-color >>focus-border-color
|
focus-border-color >>focus-border-color
|
||||||
transparent >>column-line-color ;
|
transparent >>column-line-color ;
|
||||||
: <frp-table*> ( -- table ) f <model> <frp-table> ;
|
: <frp-table*> ( -- table ) f <model> <frp-table> ;
|
||||||
|
@ -74,7 +74,7 @@ TUPLE: layout gadget width ; C: <layout> layout
|
||||||
|
|
||||||
GENERIC: output-model ( gadget -- model )
|
GENERIC: output-model ( gadget -- model )
|
||||||
M: gadget output-model model>> ;
|
M: gadget output-model model>> ;
|
||||||
M: frp-table output-model selected-value>> ;
|
M: table output-model dup multiple-selection?>> [ selected-values>> ] [ selected-value>> ] if ;
|
||||||
M: model-field output-model field-model>> ;
|
M: model-field output-model field-model>> ;
|
||||||
M: scroller output-model viewport>> children>> first output-model ;
|
M: scroller output-model viewport>> children>> first output-model ;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue