]> gitweb.factorcode.org Git - factor.git/commitdiff
Merge branch 'master' of git://factorcode.org/git/factor
authorSam Anklesaria <sam@Tintin.local>
Tue, 28 Jul 2009 21:42:38 +0000 (16:42 -0500)
committerSam Anklesaria <sam@Tintin.local>
Tue, 28 Jul 2009 21:42:38 +0000 (16:42 -0500)
63 files changed:
basis/db/queries/queries.factor
basis/functors/functors.factor
basis/inverse/inverse.factor
basis/models/illusion/illusion.factor [new file with mode: 0644]
basis/models/illusion/summary.txt [new file with mode: 0644]
basis/ui/gadgets/tables/tables-docs.factor
basis/ui/gadgets/tables/tables.factor
core/vocabs/parser/parser.factor [changed mode: 0644->0755]
extra/closures/closures.factor [new file with mode: 0644]
extra/db/info/info.factor [new file with mode: 0644]
extra/drills/deployed/deploy.factor
extra/drills/deployed/deployed.factor
extra/drills/drills.factor
extra/file-trees/file-trees.factor
extra/fries/authors.txt [new file with mode: 0644]
extra/fries/fries.factor [new file with mode: 0644]
extra/fries/summary.txt [new file with mode: 0644]
extra/merger/deploy.factor
extra/merger/merger.factor
extra/monads/monads.factor
extra/persistency/authors.txt [new file with mode: 0644]
extra/persistency/persistency.factor [new file with mode: 0644]
extra/recipes/authors.txt [new file with mode: 0644]
extra/recipes/icons/back.tiff [new file with mode: 0644]
extra/recipes/icons/hate.tiff [new file with mode: 0644]
extra/recipes/icons/love.tiff [new file with mode: 0644]
extra/recipes/icons/more.tiff [new file with mode: 0644]
extra/recipes/icons/submit.tiff [new file with mode: 0644]
extra/recipes/recipes.factor [new file with mode: 0644]
extra/recipes/summary.txt [new file with mode: 0644]
extra/run-desc/run-desc.factor [new file with mode: 0644]
extra/sequences/extras/extras.factor [new file with mode: 0644]
extra/set-n/set-n.factor [new file with mode: 0644]
extra/str-fry/authors.txt [deleted file]
extra/str-fry/str-fry.factor [deleted file]
extra/str-fry/summary.txt [deleted file]
extra/sudokus/authors.txt [new file with mode: 0644]
extra/sudokus/sudokus.factor [new file with mode: 0644]
extra/sudokus/summary.txt [new file with mode: 0644]
extra/ui/frp/authors.txt [deleted file]
extra/ui/frp/frp-docs.factor [deleted file]
extra/ui/frp/frp.factor [deleted file]
extra/ui/frp/gadgets/authors.txt [new file with mode: 0644]
extra/ui/frp/gadgets/gadgets-docs.factor [new file with mode: 0644]
extra/ui/frp/gadgets/gadgets.factor [new file with mode: 0644]
extra/ui/frp/gadgets/summary.txt [new file with mode: 0644]
extra/ui/frp/layout/authors.txt [new file with mode: 0644]
extra/ui/frp/layout/layout-docs.factor [new file with mode: 0644]
extra/ui/frp/layout/layout.factor [new file with mode: 0644]
extra/ui/frp/layout/summary.txt [new file with mode: 0644]
extra/ui/frp/signals/authors.txt [new file with mode: 0644]
extra/ui/frp/signals/signals-docs.factor [new file with mode: 0644]
extra/ui/frp/signals/signals.factor [new file with mode: 0644]
extra/ui/frp/signals/summary.txt [new file with mode: 0644]
extra/ui/frp/signals/templates/templates.factor [new file with mode: 0644]
extra/ui/frp/summary.txt [deleted file]
extra/ui/gadgets/alerts/alerts.factor
extra/ui/gadgets/book-extras/book-extras.factor
extra/ui/gadgets/comboboxes/comboboxes.factor
unmaintained/modules/rpc/rpc.factor
unmaintained/modules/using/tests/tests.factor
unmaintained/modules/using/using-docs.factor
unmaintained/modules/using/using.factor

index c4aa47d383b3a1281ff091887449bb6e6ad39be6..d2674205b1f47eb87831e0bb8479c490129ce219 100755 (executable)
@@ -4,7 +4,7 @@ USING: accessors kernel math namespaces make sequences random
 strings math.parser math.intervals combinators math.bitwise
 nmake db db.tuples db.types classes words shuffle arrays
 destructors continuations db.tuples.private prettyprint
-db.private byte-arrays ;
+db.private byte-arrays strings.parser parser ;
 IN: db.queries
 
 GENERIC: where ( specs obj -- )
@@ -130,6 +130,10 @@ M: integer where ( spec obj -- ) object-where ;
 
 M: string where ( spec obj -- ) object-where ;
 
+TUPLE: pattern value ; C: <pattern> pattern
+SYNTAX: %" parse-string <pattern> parsed ;
+M: pattern where value>> over column-name>> 0% " LIKE " 0% bind# ;
+
 : filter-slots ( tuple specs -- specs' )
     [
         slot-name>> swap get-slot-named
index 51295159807cd5441e72b737ed06612fea5e106a..5f519aeecefe41ad70e489bafe35c84d9f963859 100644 (file)
@@ -1,11 +1,11 @@
 ! Copyright (C) 2008, 2009 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors arrays classes.mixin classes.parser classes.singleton
-classes.tuple classes.tuple.parser combinators effects effects.parser
-fry generic generic.parser generic.standard interpolate
-io.streams.string kernel lexer locals.parser locals.rewrite.closures
-locals.types make namespaces parser quotations sequences vocabs.parser
-words words.symbol ;
+USING: accessors arrays classes.mixin classes.parser
+classes.singleton classes.tuple classes.tuple.parser
+combinators effects.parser fry generic generic.parser
+generic.standard interpolate io.streams.string kernel lexer
+locals.parser locals.types macros make namespaces parser
+quotations sequences vocabs.parser words words.symbol ;
 IN: functors
 
 ! This is a hack
@@ -117,6 +117,11 @@ SYNTAX: `GENERIC:
     complete-effect parsed
     \ define-simple-generic* parsed ;
 
+SYNTAX: `MACRO:
+    scan-param parsed
+    parse-declared*
+    \ define-macro parsed ;
+
 SYNTAX: `inline [ word make-inline ] over push-all ;
 
 SYNTAX: `call-next-method T{ fake-call-next-method } parsed ;
@@ -152,6 +157,7 @@ DEFER: ;FUNCTOR delimiter
         { "SYNTAX:" POSTPONE: `SYNTAX: }
         { "SYMBOL:" POSTPONE: `SYMBOL: }
         { "inline" POSTPONE: `inline }
+        { "MACRO:" POSTPONE: `MACRO: }
         { "call-next-method" POSTPONE: `call-next-method }
     } ;
 
index cf97a0b2c8eebf78c0747e18639b6cab8efff03e..7a9e821b37740a2ce9a1fdd45a632f2ab7acb678 100755 (executable)
@@ -1,6 +1,6 @@
 ! Copyright (C) 2007, 2009 Daniel Ehrenberg.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors kernel words summary slots quotations
+USING: accessors kernel locals words summary slots quotations
 sequences assocs math arrays stack-checker effects
 continuations debugger classes.tuple namespaces make vectors
 bit-arrays byte-arrays strings sbufs math.functions macros
@@ -231,6 +231,18 @@ DEFER: __
 \ output>sequence 2 [ [undo] '[ dup _ assure-same-class _ input<sequence ] ] define-pop-inverse
 \ input<sequence 1 [ [undo] '[ _ { } output>sequence ] ] define-pop-inverse
 
+! conditionals
+
+:: undo-if-empty ( result a b -- seq )
+   a call( -- b ) result = [ { } ] [ result b [undo] call( a -- b ) ] if ;
+
+:: undo-if* ( result a b -- boolean )
+   b call( -- b ) result = [ f ] [ result a [undo] call( a -- b ) ] if ;
+
+\ if-empty 2 [ swap [ undo-if-empty ] 2curry ] define-pop-inverse
+
+\ if* 2 [ swap [ undo-if* ] 2curry ] define-pop-inverse
+
 ! Constructor inverse
 : deconstruct-pred ( class -- quot )
     "predicate" word-prop [ dupd call assure ] curry ;
@@ -283,4 +295,4 @@ M: no-match summary drop "Fall through in switch" ;
     reverse [ [ [undo] ] dip compose ] { } assoc>map
     recover-chain ;
 
-MACRO: switch ( quot-alist -- ) [switch] ;
+MACRO: switch ( quot-alist -- ) [switch] ;
\ No newline at end of file
diff --git a/basis/models/illusion/illusion.factor b/basis/models/illusion/illusion.factor
new file mode 100644 (file)
index 0000000..0016979
--- /dev/null
@@ -0,0 +1,15 @@
+USING: accessors models models.arrow inverse kernel ;
+IN: models.illusion
+
+TUPLE: illusion < arrow ;
+
+: <illusion> ( model quot -- illusion )
+    illusion new V{ } clone >>connections V{ } clone >>dependencies 0 >>ref
+    swap >>quot over >>model [ add-dependency ] keep ;
+
+: <activated-illusion> ( model quot -- illusion ) <illusion> dup activate-model ;
+
+: backtalk ( value object -- )
+   [ quot>> [undo] call( a -- b ) ] [ model>> ] bi set-model ;
+
+M: illusion update-model ( model -- ) [ [ value>> ] keep backtalk ] with-locked-model ;
\ No newline at end of file
diff --git a/basis/models/illusion/summary.txt b/basis/models/illusion/summary.txt
new file mode 100644 (file)
index 0000000..8ea7cf1
--- /dev/null
@@ -0,0 +1 @@
+Two Way Arrows
\ No newline at end of file
index c064a80ee4bb6649f8a60e287ac6725229801e73..4f016caa8a5217fcdaa3fa0e8a943acf97e4ccc9 100644 (file)
@@ -20,13 +20,15 @@ ARTICLE: "ui.gadgets.tables.selection" "Table row selection"
 $nl
 "A few slots in the table gadget concern row selection:"
 { $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-index" } " - the index of the currently selected row." }
+  { { $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-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 "multiple-selection?" } { " - if set to a true value, users are allowed to select more than one value." } }
+
 }
 "Some words for row selection:"
-{ $subsection selected-row }
-{ $subsection (selected-row) } ;
+{ $subsection selected-rows }
+{ $subsection (selected-rows) } ;
 
 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."
index 3beb0af79f946a75cbe630b046a982005c725a2a..353dd912701ee825e2d2a282bb61e2814b533e13 100644 (file)
@@ -1,12 +1,13 @@
 ! Copyright (C) 2008, 2009 Slava Pestov.
 ! See http://factorcode.org/license.txt for BSD license.
 USING: accessors arrays colors colors.constants fry kernel math
-math.functions math.rectangles math.order math.vectors namespaces
-opengl sequences ui.gadgets ui.gadgets.scrollers ui.gadgets.status-bar
-ui.gadgets.worlds ui.gestures ui.render ui.pens.solid ui.text
-ui.commands ui.images ui.gadgets.menus ui.gadgets.line-support
-models math.ranges combinators
-combinators.short-circuit fonts locals strings ;
+math.functions math.ranges math.rectangles math.order math.vectors
+models.illusion namespaces opengl sequences ui.gadgets
+ui.gadgets.scrollers ui.gadgets.status-bar ui.gadgets.worlds
+ui.gestures ui.render ui.pens.solid ui.text ui.commands ui.images
+ui.gadgets.menus ui.gadgets.line-support models
+combinators combinators.short-circuit
+fonts locals strings sorting ;
 IN: ui.gadgets.tables
 
 ! Row rendererer protocol
@@ -41,16 +42,37 @@ focus-border-color
 { mouse-color initial: COLOR: black }
 column-line-color
 selection-required?
-selected-index selected-value
+selected-indices selected-values
+selected-indices*
 mouse-index
 { takes-focus? initial: t }
-focused? ;
+focused?
+multiple-selection? ;
+
+: in>out ( array -- val/f ) [ f ] [ first ] if-empty ;
+: out>in ( val/f -- array ) [ 1array ] [ { } ] if* ;
+IN: accessors
+SLOT: selected-value
+SLOT: selected-index
+SLOT: selected-index*
+M: table selected-value>> selected-values>> [ in>out ] <illusion> ;
+M: table (>>selected-value) [ [ out>in ] <activated-illusion> ] dip (>>selected-values) ;
+M: table selected-index>> selected-indices>> in>out ;
+M: table (>>selected-index) [ out>in ] dip (>>selected-indices) ;
+M: table selected-index*>> selected-indices*>> [ in>out ] <illusion> ;
+M: table (>>selected-index*) [ [ out>in ] <activated-illusion> ] dip (>>selected-indices*) ;
+
+IN: ui.gadgets.tables
+: push-selected-index ( table n -- table ) 2dup swap selected-indices>> index
+   [ drop ] [ over selected-indices>> swap suffix natural-sort >>selected-indices ] if ;
 
 : new-table ( rows renderer class -- table )
     new-line-gadget
         swap >>renderer
         swap >>model
-        f <model> >>selected-value
+        { } >>selected-indices
+        { } <model> >>selected-values
+        { } <model> >>selected-indices*
         sans-serif-font >>font
         focus-border-color >>focus-border-color
         transparent >>column-line-color ; inline
@@ -131,12 +153,12 @@ M: table layout*
 : row-bounds ( table row -- loc dim )
     row-rect rect-bounds ; inline
 
-: draw-selected-row ( table -- )
+: draw-selected-rows ( table -- )
     {
-        { [ dup selected-index>> not ] [ drop ] }
+        { [ dup selected-indices>> empty? ] [ drop ] }
         [
-            [ ] [ selected-index>> ] [ selection-color>> gl-color ] tri
-            row-bounds gl-fill-rect
+            [ selected-indices>> ] [ selection-color>> gl-color ] [ ] tri
+            [ swap row-bounds gl-fill-rect ] curry each
         ]
     } cond ;
 
@@ -189,10 +211,10 @@ M: table layout*
     dup renderer>> column-alignment
     [ ] [ column-widths>> length 0 <repetition> ] ?if ;
 
-:: row-font ( row index table -- font )
+:: row-font ( row ind table -- font )
     table font>> clone
     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 -- )
     '[ [ _ ] 3dip _ draw-column ] 3each ;
@@ -213,7 +235,7 @@ M: table draw-gadget*
     dup control-value empty? [ drop ] [
         dup line-height \ line-height [
             {
-                [ draw-selected-row ]
+                [ draw-selected-rows ]
                 [ draw-lines ]
                 [ draw-column-lines ]
                 [ draw-focused-row ]
@@ -236,17 +258,22 @@ M: table pref-dim*
 
 PRIVATE>
 
-: (selected-row) ( table -- value/f ? )
-    [ selected-index>> ] keep nth-row ;
+: (selected-rows) ( table -- {row} )
+    [ selected-indices>> ] keep
+    [ nth-row [ 1array ] [ drop { } ] if ] curry map concat ;
 
-: selected-row ( table -- value/f ? )
-    [ (selected-row) ] keep
-    swap [ renderer>> row-value t ] [ 2drop f f ] if ;
+: selected-rows ( table -- {value} )
+    [ (selected-rows) ] [ renderer>> ] bi [ row-value ] curry map ;
+
+: multiple>single ( values -- value/f ? ) [ f f ] [ first t ] if-empty ;
+: (selected-row) ( table -- value/f ? ) (selected-rows) multiple>single ;
+: selected-row ( table -- value/f ? ) selected-rows multiple>single ;
 
 <PRIVATE
 
-: update-selected-value ( table -- )
-    [ selected-row drop ] [ selected-value>> ] bi set-model ;
+: update-selected-values ( table -- )
+    [ [ selected-rows ] [ selected-values>> ] bi set-model ]
+    [ [ selected-indices>> ] [ selected-indices*>> ] bi set-model ] bi ;
 
 : show-row-summary ( table n -- )
     over nth-row
@@ -260,49 +287,63 @@ PRIVATE>
 : find-row-index ( value table -- n/f )
     [ model>> value>> ] [ renderer>> '[ _ row-value ] map index ] bi ;
 
-: initial-selected-index ( table -- n/f )
+: initial-selected-indices ( table -- {n}/f )
     {
         [ model>> value>> empty? not ]
         [ selection-required?>> ]
-        [ drop 0 ]
+        [ drop { 0 } ]
     } 1&& ;
 
-: (update-selected-index) ( table -- n/f )
-    [ selected-value>> value>> ] keep over
-    [ find-row-index ] [ 2drop f ] if ;
+: (update-selected-indices) ( table -- {n}/f )
+    [ selected-values>> value>> ] keep
+    [ find-row-index ] curry map [ ] filter [ f ] when-empty ;
 
-: update-selected-index ( table -- n/f )
+: update-selected-indices ( table -- {n}/f )
     {
-        [ (update-selected-index) ]
-        [ initial-selected-index ]
+        [ (update-selected-indices) ]
+        [ initial-selected-indices ]
     } 1|| ;
 
 M: table model-changed
-    nip dup update-selected-index {
-        [ >>selected-index f >>mouse-index drop ]
-        [ show-row-summary ]
-        [ drop update-selected-value ]
+    nip dup update-selected-indices [ { } ] unless* {
+        [ >>selected-indices f >>mouse-index drop ]
+        [ [ f ] [ first ] if-empty show-row-summary ]
+        [ drop update-selected-values ]
         [ drop relayout ]
     } 2cleave ;
 
 : thin-row-rect ( table row -- rect )
     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 -- )
-    [ dup [ [ thin-row-rect ] [ drop ] 2bi scroll>rect ] [ 2drop ] if ]
+    [ scroll-to-row ]
     [ >>selected-index relayout-1 ]
     2bi ;
 
 : mouse-row ( table -- n )
     [ 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? ]
     [ ] [ '[ nip @ ] ] tri* if ; inline
 
-: table-button-down ( table -- )
-    dup takes-focus?>> [ dup request-focus ] when
-    [ swap [ >>mouse-index ] [ (select-row) ] bi ] [ drop ] if-mouse-row ;
+: (table-button-down) ( quot table -- )
+    dup takes-focus?>> [ dup request-focus ] when swap
+   '[ 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?>> [
+    [ 2dup over selected-index>> (a,b) swap
+      [ swap push-selected-index drop ] curry each add-selected-row ]
+    swap (table-button-down) ] [ table-button-down ] if ;
 
 PRIVATE>
 
@@ -319,7 +360,7 @@ PRIVATE>
 
 : table-button-up ( table -- )
     dup [ mouse-row ] keep valid-line? [
-        dup row-action? [ row-action ] [ update-selected-value ] if
+        dup row-action? [ row-action ] [ update-selected-values ] if
     ] [ drop ] if ;
 
 PRIVATE>
@@ -327,7 +368,7 @@ PRIVATE>
 : select-row ( table n -- )
     over validate-line
     [ (select-row) ]
-    [ drop update-selected-value ]
+    [ drop update-selected-values ]
     [ show-row-summary ]
     2tri ;
 
@@ -386,8 +427,11 @@ table "sundry" f {
     { mouse-enter show-mouse-help }
     { mouse-leave hide-mouse-help }
     { motion show-mouse-help }
-    { T{ button-down } table-button-down }
+    { T{ button-down f { S+ } 1 } thru-button-down }
+    { T{ button-down f { A+ } 1 } continued-button-down }
     { T{ button-up } table-button-up }
+    { T{ button-up f { S+ } } table-button-up }
+    { T{ button-down } table-button-down }
     { gain-focus focus-table }
     { lose-focus unfocus-table }
     { T{ drag } table-button-down }
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/extra/closures/closures.factor b/extra/closures/closures.factor
new file mode 100644 (file)
index 0000000..79fcf75
--- /dev/null
@@ -0,0 +1,13 @@
+USING: assocs io.pathnames fry namespaces namespaces.private kernel sequences parser hashtables ;
+IN: closures
+SYMBOL: |
+
+! Selective Binding
+: delayed-bind-with ( vars quot -- quot' ) '[ _ dup [ get ] map zip >hashtable [ _ bind ] curry ] ;
+SYNTAX: C[ | parse-until parse-quotation delayed-bind-with over push-all ;
+! Common ones
+SYNTAX: DIR[ parse-quotation { current-directory } swap delayed-bind-with over push-all ;
+
+! Namespace Binding
+: bind-to-namespace ( quot -- quot' ) '[ namespace [ _ bind ] curry ] ;
+SYNTAX: NS[ parse-quotation bind-to-namespace over push-all ;
\ No newline at end of file
diff --git a/extra/db/info/info.factor b/extra/db/info/info.factor
new file mode 100644 (file)
index 0000000..66409f2
--- /dev/null
@@ -0,0 +1,15 @@
+USING: accessors sequences generalizations io.encodings.utf8 db.postgresql parser combinators vocabs.parser db.sqlite
+io.files ;
+IN: db.info
+! having sensative (and likely to change) information directly in source code seems a bad idea
+: get-info ( -- lines ) current-vocab name>> "vocab:" "/dbinfo.txt" surround utf8 file-lines ;
+SYNTAX: get-psql-info <postgresql-db> get-info 5 firstn
+    {
+        [ >>host ]
+        [ >>port ]
+        [ >>username ]
+        [ [ f ] [ ] if-empty >>password ]
+        [ >>database ]
+    } spread parsed ;
+
+SYNTAX: get-sqlite-info get-info first <sqlite-db> parsed ;
\ No newline at end of file
index eaa0d3bb6949fce87143fa6ca32b8838bcec21bb..c1e93078f7f0533ae33b78cab90d75b48e74cfd6 100644 (file)
@@ -1,14 +1,14 @@
 USING: tools.deploy.config ;
 H{
-    { deploy-unicode? f }
+    { deploy-name "drills" }
+    { deploy-c-types? t }
+    { "stop-after-last-window?" t }
+    { deploy-unicode? t }
     { deploy-threads? t }
+    { deploy-reflection 6 }
+    { deploy-word-defs? t }
     { deploy-math? t }
-    { deploy-name "drills" }
     { deploy-ui? t }
-    { "stop-after-last-window?" t }
-    { deploy-word-props? f }
-    { deploy-c-types? f }
-    { deploy-io 2 }
-    { deploy-word-defs? f }
-    { deploy-reflection 1 }
+    { deploy-word-props? t }
+    { deploy-io 3 }
 }
index 43873c99bb089b145d5a203406b0849987969979..5681c73438e2fc238a03f61f587f68b8e7f352cd 100644 (file)
@@ -1,11 +1,11 @@
-USING: accessors arrays cocoa.dialogs combinators continuations
+USING: arrays cocoa.dialogs combinators continuations
 fry grouping io.encodings.utf8 io.files io.styles kernel math
 math.parser models models.arrow models.history namespaces random
 sequences splitting ui ui.gadgets.alerts ui.gadgets.book-extras
 ui.gadgets.books ui.gadgets.buttons ui.gadgets.frames
 ui.gadgets.grids ui.gadgets.labels ui.gadgets.tracks fonts
 wrap.strings system ;
-
+EXCLUDE: accessors => change-model ;
 IN: drills.deployed
 SYMBOLS: it startLength ;
 : big ( gadget -- gadget ) T{ font { name "sans-serif" } { size 30 } } >>font ;
index 9ee4e9b6ebc23636c1c63cc6e5fa97efd920a42f..1da1fcaa1d963268338e267ef8d983316294b81e 100644 (file)
@@ -1,16 +1,17 @@
-USING: accessors arrays cocoa.dialogs combinators continuations
+USING: arrays cocoa.dialogs combinators continuations
 fry grouping io.encodings.utf8 io.files io.styles kernel math
 math.parser models models.arrow models.history namespaces random
 sequences splitting ui ui.gadgets.alerts ui.gadgets.book-extras
 ui.gadgets.books ui.gadgets.buttons ui.gadgets.frames
 ui.gadgets.grids ui.gadgets.labels ui.gadgets.tracks fonts
 wrap.strings ;
+EXCLUDE: accessors => change-model ;
 
 IN: drills
 SYMBOLS: it startLength ;
 : big ( gadget -- gadget ) T{ font { name "sans-serif" } { size 30 } } >>font ;
 : card ( model quot -- button ) <arrow> <label-control> big [ next ] <book-btn> ;
-: op ( quot str -- gadget ) <label> big swap <book-bevel-btn> ;
+: op ( quot str -- gadget ) <label> big swap <book-border-btn> ;
 
 : show ( model -- gadget ) dup it set-global [ random ] <arrow>
    { [ [ first ] card ]
index eadfccdc4c0adfabb5372e49404786254749d329..adfb7d67de7b7f7e9d0decd747715d04c81ef3ab 100644 (file)
@@ -1,17 +1,26 @@
 USING: accessors arrays delegate delegate.protocols
-io.pathnames kernel locals namespaces prettyprint sequences
-ui.frp vectors ;
+io.pathnames kernel locals sequences
+vectors make strings ui.frp.signals ui.frp.gadgets
+sequences.extras ;
 IN: file-trees
 
-TUPLE: tree node children ;
+TUPLE: walkable-vector vector father ;
+CONSULT: sequence-protocol walkable-vector vector>> ;
+
+M: walkable-vector set-nth [ vector>> set-nth ] 3keep nip
+   father>> swap children>> vector>> push ;
+
+TUPLE: tree node comment children ;
 CONSULT: sequence-protocol tree children>> ;
 
-: <tree> ( start -- tree ) V{ } clone
-   [ tree boa dup children>> ] [ ".." swap tree boa ] bi swap push ;
+: file? ( tree -- ? ) children>> [ node>> ".." = not ] filter empty? ;
+
+: <dir-tree> ( {start,comment} -- tree ) first2 walkable-vector new vector new >>vector
+   [ tree boa dup children>> ] [ ".." -rot tree boa ] 2bi swap (>>father) ;
 
 DEFER: (tree-insert)
 
-: tree-insert ( path tree -- ) [ unclip <tree> ] [ children>> ] bi* (tree-insert) ;
+: tree-insert ( path tree -- ) [ unclip <dir-tree> ] [ children>> ] bi* (tree-insert) ;
 :: (tree-insert) ( path-rest path-head tree-children -- )
    tree-children [ node>> path-head node>> = ] find nip
    [ path-rest swap tree-insert ]
@@ -19,10 +28,22 @@ DEFER: (tree-insert)
       path-head tree-children push
       path-rest [ path-head tree-insert ] unless-empty
    ] if* ;
-: create-tree ( file-list -- tree ) [ path-components ] map
-   t <tree> [ [ tree-insert ] curry each ] keep ;
+
+: add-paths ( pathseq -- {{name,path}} )
+   "" [ [ "/" glue dup ] keep swap 2array , ] [ reduce drop ] f make ;
+
+: go-to-path ( path tree -- tree' ) over empty? [ nip ]
+   [ [ unclip ] [ children>> ] bi* swap [ swap node>> = ] curry find nip go-to-path ] if ;
+
+: find-root ( pathseq -- root ) dup flip
+   [ [ dupd = [ ] [ drop f ] if ] reduce1 ] find-last drop
+      [ first ] dip head-slice >string path-components ;
+
+: create-tree ( file-list -- tree ) [ find-root ]
+   [ [ path-components add-paths ] map { "/" "/" } <dir-tree> [ [ tree-insert ] curry each ] keep ] bi
+   go-to-path ;
 
 : <dir-table> ( tree-model -- table )
    <frp-list*> [ node>> 1array ] >>quot
-   [ selected-value>> <switch> ]
+   [ selected-value>> [ file? not ] <filter> swap <switch> ]
    [ swap >>model ] bi ;
\ No newline at end of file
diff --git a/extra/fries/authors.txt b/extra/fries/authors.txt
new file mode 100644 (file)
index 0000000..ce0899f
--- /dev/null
@@ -0,0 +1 @@
+Sam Anklesaria
\ No newline at end of file
diff --git a/extra/fries/fries.factor b/extra/fries/fries.factor
new file mode 100644 (file)
index 0000000..f67d0d7
--- /dev/null
@@ -0,0 +1,13 @@
+USING: arrays vectors combinators effects kernel math sequences splitting
+strings.parser parser fry sequences.extras ;
+IN: fries
+: str-fry ( str on -- quot ) split
+    [ unclip-last [ [ spin glue ] reduce-r ] 2curry ]
+    [ length 1 - 1 <effect> [ call-effect ] 2curry ] bi ;
+: gen-fry ( str on -- quot ) split
+    [ unclip-last [ [ spin 1array glue ] reduce-r ] 2curry ]
+    [ length 1 - 1 <effect> [ call-effect ] 2curry ] bi ;
+
+SYNTAX: i" parse-string rest "_" str-fry over push-all ;
+SYNTAX: i{ \ } parse-until >array { _ } gen-fry over push-all ;
+SYNTAX: iV{ \ } parse-until >vector V{ _ } gen-fry over push-all ;
diff --git a/extra/fries/summary.txt b/extra/fries/summary.txt
new file mode 100644 (file)
index 0000000..44e9456
--- /dev/null
@@ -0,0 +1 @@
+Generalized Frying
\ No newline at end of file
index adaab737c3dc00696a0c0656356fdb86302c84de..39a73eab82399b3ac83784c40b1b784de52179fa 100644 (file)
@@ -1,14 +1,14 @@
 USING: tools.deploy.config ;
 H{
-    { deploy-math? t }
-    { deploy-io 2 }
-    { deploy-unicode? t }
+    { deploy-name "Merger" }
     { deploy-c-types? f }
     { "stop-after-last-window?" t }
-    { deploy-ui? t }
-    { deploy-reflection 1 }
-    { deploy-name "Merger" }
-    { deploy-word-props? f }
+    { deploy-unicode? f }
     { deploy-threads? t }
+    { deploy-reflection 1 }
     { deploy-word-defs? f }
+    { deploy-math? t }
+    { deploy-ui? t }
+    { deploy-word-props? f }
+    { deploy-io 2 }
 }
index c4986bf47fb47bf436176f8cf0197d84d9e41bbf..ee9207e4caff4121d83fe92e08798862116cc801 100644 (file)
@@ -1,4 +1,5 @@
-USING: accessors arrays fry io.directories kernel models sequences sets ui
+USING: accessors arrays fry io.directories kernel
+models sequences sets ui
 ui.gadgets ui.gadgets.buttons ui.gadgets.labeled
 ui.gadgets.tracks ui.gadgets.labels ui.gadgets.glass
 math.rectangles cocoa.dialogs ;
index 6b35772596f92e59e06c18b8ff6055e19ab6720d..a859c36f2e22661c7c8b2dee311d7de787e43c00 100644 (file)
@@ -7,6 +7,8 @@ IN: monads
 
 ! Functors
 GENERIC# fmap 1 ( functor quot -- functor' )
+GENERIC# <$ 1 ( functor quot -- functor' )
+GENERIC# $> 1 ( functor quot -- functor' )
 
 ! Monads
 
@@ -22,6 +24,7 @@ M: monad return monad-of return ;
 M: monad fail   monad-of fail   ;
 
 : bind ( mvalue quot -- mvalue' ) swap >>= call( quot -- mvalue ) ;
+: bind* ( mvalue quot -- mvalue' ) '[ drop @ ] bind ;
 : >>   ( mvalue k -- mvalue' ) '[ drop _ ] bind ;
 
 :: lift-m2 ( m1 m2 f monad -- m3 )
diff --git a/extra/persistency/authors.txt b/extra/persistency/authors.txt
new file mode 100644 (file)
index 0000000..ce0899f
--- /dev/null
@@ -0,0 +1 @@
+Sam Anklesaria
\ No newline at end of file
diff --git a/extra/persistency/persistency.factor b/extra/persistency/persistency.factor
new file mode 100644 (file)
index 0000000..1604c66
--- /dev/null
@@ -0,0 +1,25 @@
+USING: accessors arrays byte-arrays calendar classes classes.tuple
+classes.tuple.parser combinators db db.tuples db.types kernel
+math sequences strings unicode.case urls words ;
+IN: persistency
+
+TUPLE: persistent id ;
+
+: add-types ( table -- table' ) [ dup array? [ [ first dup >upper ] [ second ] bi 3array ]
+        [ dup >upper FACTOR-BLOB 3array ] if
+    ] map { "id" "ID" +db-assigned-id+ } prefix ;
+
+: remove-types ( table -- table' ) [ dup array? [ first ] when ] map ;
+
+SYNTAX: STORED-TUPLE: parse-tuple-definition [ drop persistent ] dip [ remove-types define-tuple-class ]
+   [ nip [ dup name>> >upper ] [ add-types ] bi* define-persistent ] 3bi ;
+
+: define-db ( database class -- ) swap [ [ ensure-table ] with-db ] [ "database" set-word-prop ] 2bi ;
+
+: query>tuple ( tuple/query -- tuple ) dup query? [ tuple>> ] when ;
+: w/db ( query quot -- ) [ dup query>tuple class "database" word-prop ] dip with-db ; inline
+: get-tuples ( query -- tuples ) [ select-tuples ] w/db ;
+: get-tuple ( query -- tuple ) [ select-tuple ] w/db ;
+: store-tuple ( tuple -- ) [ insert-tuple ] w/db ;
+: modify-tuple ( tuple -- ) [ update-tuple ] w/db ;
+: remove-tuples ( tuple -- ) [ delete-tuples ] w/db ;
\ No newline at end of file
diff --git a/extra/recipes/authors.txt b/extra/recipes/authors.txt
new file mode 100644 (file)
index 0000000..ce0899f
--- /dev/null
@@ -0,0 +1 @@
+Sam Anklesaria
\ No newline at end of file
diff --git a/extra/recipes/icons/back.tiff b/extra/recipes/icons/back.tiff
new file mode 100644 (file)
index 0000000..27b8112
Binary files /dev/null and b/extra/recipes/icons/back.tiff differ
diff --git a/extra/recipes/icons/hate.tiff b/extra/recipes/icons/hate.tiff
new file mode 100644 (file)
index 0000000..d7d5f8e
Binary files /dev/null and b/extra/recipes/icons/hate.tiff differ
diff --git a/extra/recipes/icons/love.tiff b/extra/recipes/icons/love.tiff
new file mode 100644 (file)
index 0000000..ae2fa7b
Binary files /dev/null and b/extra/recipes/icons/love.tiff differ
diff --git a/extra/recipes/icons/more.tiff b/extra/recipes/icons/more.tiff
new file mode 100644 (file)
index 0000000..b4ec27b
Binary files /dev/null and b/extra/recipes/icons/more.tiff differ
diff --git a/extra/recipes/icons/submit.tiff b/extra/recipes/icons/submit.tiff
new file mode 100644 (file)
index 0000000..7c98267
Binary files /dev/null and b/extra/recipes/icons/submit.tiff differ
diff --git a/extra/recipes/recipes.factor b/extra/recipes/recipes.factor
new file mode 100644 (file)
index 0000000..528663d
--- /dev/null
@@ -0,0 +1,61 @@
+USING: accessors arrays colors.constants combinators db.queries
+db.info db.tuples db.types kernel locals math
+monads persistency sequences sequences.extras ui ui.frp.gadgets
+ui.frp.layout ui.frp.signals ui.gadgets.labels
+ui.gadgets.scrollers ui.pens.solid ;
+FROM: sets => prune ;
+IN: recipes
+
+STORED-TUPLE: recipe { title { VARCHAR 100 } } { votes INTEGER } { txt TEXT } { genre { VARCHAR 100 } } ;
+: <recipe> ( title genre text -- recipe ) recipe new swap >>txt swap >>genre swap >>title 0 >>votes ;
+get-psql-info recipe define-db
+: top-recipes ( offset search -- recipes ) <query> T{ recipe } rot >>title >>tuple
+    "votes" >>order 30 >>limit swap >>offset get-tuples ;
+: top-genres ( -- genres ) f f top-recipes [ genre>> ] map prune 4 (head-slice) ;
+
+: interface ( -- book ) [ 
+     [
+        [ $ TOOLBAR $ ] <hbox> COLOR: AliceBlue <solid> >>interior ,
+        [ "Genres:" <label> , <spacer> $ ALL $ $ GENRES $ ] <hbox>
+            { 5 0 } >>gap COLOR: gray <solid> >>interior ,
+        $ RECIPES $
+     ] <vbox> ,
+     [
+        [ "Title:" <label> , $ TITLE $ "Genre:" <label> , $ GENRE $ ] <hbox> ,
+        $ BODY $
+        $ BUTTON $
+     ] <vbox> ,
+  ] <frp-book*> { 350 245 } >>pref-dim ;
+  
+:: recipe-browser ( -- ) [ [
+    interface
+      <frp-table*> :> tbl
+      "okay" <frp-border-button> BUTTON -> :> ok
+      IMG-FRP-BTN: submit [ store-tuple ] >>value TOOLBAR -> :> submit
+      IMG-FRP-BTN: love 1 >>value TOOLBAR ->
+      IMG-FRP-BTN: hate -1 >>value -> 2array <merge> :> votes
+      IMG-FRP-BTN: back -> [ -30 ] <$
+      IMG-FRP-BTN: more -> [ 30 ] <$ 2array <merge> :> viewed
+      <spacer> <frp-field*> ->% 1 :> search
+      submit ok [ [ drop ] ] <$ 2array <merge> [ drop ] >>value :> quot
+      viewed 0 [ + ] <fold> search ok t <basic> "all" <frp-button> ALL ->
+      tbl selected-value>> votes [ [ + ] curry change-votes modify-tuple ] 2$>
+        4array <merge>
+        [ drop [ f ] [ "%" dup surround <pattern> ] if-empty top-recipes ] 3fmap :> updates
+      updates [ top-genres [ <frp-button> GENRES -> ] map <merge> ] bind*
+        [ text>> T{ recipe } swap >>genre get-tuples ] fmap
+      tbl swap updates 2array <merge> >>model
+        [ [ title>> ] [ genre>> ] bi 2array ] >>quot
+        { "Title" "Genre" } >>column-titles dup <scroller> RECIPES ,% 1 actions>>
+      submit [ "" dup dup <recipe> ] <$ 2array <merge>
+        { [ [ title>> ] fmap <frp-field> TITLE ->% .5 ]
+          [ [ genre>> ] fmap <frp-field> GENRE ->% .5 ]
+          [ [ txt>> ] fmap <frp-editor> BODY ->% 1 ]
+        } cleave
+        [ <recipe> ] 3fmap
+      [ [ 1 ] <$ ]
+      [ quot ok <updates> #1 [ call( recipe -- ) 0 ] 2fmap ] bi
+      2array <merge> 0 <basic> <switch> >>model
+   ] with-interface "recipes" open-window ] with-ui ;
+
+MAIN: recipe-browser
\ No newline at end of file
diff --git a/extra/recipes/summary.txt b/extra/recipes/summary.txt
new file mode 100644 (file)
index 0000000..98b1ece
--- /dev/null
@@ -0,0 +1 @@
+Database backed recipe sharing
\ No newline at end of file
diff --git a/extra/run-desc/run-desc.factor b/extra/run-desc/run-desc.factor
new file mode 100644 (file)
index 0000000..6acf66d
--- /dev/null
@@ -0,0 +1,3 @@
+USING: io io.encodings.utf8 io.launcher kernel sequences ;
+IN: run-desc
+: run-desc ( desc -- result ) utf8 [ contents [ but-last ] [ f ] if* ] with-process-reader ;
diff --git a/extra/sequences/extras/extras.factor b/extra/sequences/extras/extras.factor
new file mode 100644 (file)
index 0000000..37d1d94
--- /dev/null
@@ -0,0 +1,22 @@
+USING: arrays kernel locals math sequences ;
+IN: sequences.extras
+: reduce1 ( seq quot -- result ) [ unclip ] dip reduce ; inline
+
+:: reduce-r
+    ( list identity quot: ( obj1 obj2 -- obj ) -- result )
+    list empty?
+    [ identity ]
+    [ list rest identity quot reduce-r list first quot call ] if ;
+    inline recursive
+
+! Quot must have static stack effect, unlike "reduce"
+:: reduce* ( seq id quot -- result ) seq
+    [ id ]
+    [ unclip id swap quot call( prev elt -- next ) quot reduce* ] if-empty ; inline recursive
+
+:: combos ( list1 list2 -- result ) list2 [ [ 2array ] curry list1 swap map ] map concat ;
+: (head-slice) ( seq n -- seq' ) over length over < [ drop ] [ head-slice ] if ;
+: find-all ( seq quot -- elts ) [ [ length iota ] keep ] dip
+    [ dupd call( a -- ? ) [ 2array ] [ 2drop f ] if ] curry 2map [ ] filter ; inline
+
+: empty ( seq -- ) 0 swap shorten ;
\ No newline at end of file
diff --git a/extra/set-n/set-n.factor b/extra/set-n/set-n.factor
new file mode 100644 (file)
index 0000000..04731b0
--- /dev/null
@@ -0,0 +1,9 @@
+USING: accessors assocs fry generalizations kernel math
+namespaces parser sequences words ;
+IN: set-n
+: get* ( var n -- val ) namestack dup length rot - head assoc-stack ;
+
+: set* ( val var n -- ) 1 + namestack [ length swap - ] keep nth set-at ;
+
+! dynamic lambda
+SYNTAX: :| (:) dup in>> dup length [ spin '[ _ narray _ swap zip _ bind ] ] 2curry dip define-declared ;
\ No newline at end of file
diff --git a/extra/str-fry/authors.txt b/extra/str-fry/authors.txt
deleted file mode 100644 (file)
index ce0899f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Sam Anklesaria
\ No newline at end of file
diff --git a/extra/str-fry/str-fry.factor b/extra/str-fry/str-fry.factor
deleted file mode 100644 (file)
index bfe74f3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-USING: combinators effects kernel math sequences splitting
-strings.parser ;
-IN: str-fry
-: str-fry ( str -- quot ) "_" split
-    [ unclip [ [ rot glue ] reduce ] 2curry ]
-    [ length 1 - 1 <effect> [ call-effect ] 2curry ] bi ;
-SYNTAX: I" parse-string rest str-fry over push-all ;
\ No newline at end of file
diff --git a/extra/str-fry/summary.txt b/extra/str-fry/summary.txt
deleted file mode 100644 (file)
index 7755f5a..0000000
+++ /dev/null
@@ -1 +0,0 @@
-String Frying
\ No newline at end of file
diff --git a/extra/sudokus/authors.txt b/extra/sudokus/authors.txt
new file mode 100644 (file)
index 0000000..ce0899f
--- /dev/null
@@ -0,0 +1 @@
+Sam Anklesaria
\ No newline at end of file
diff --git a/extra/sudokus/sudokus.factor b/extra/sudokus/sudokus.factor
new file mode 100644 (file)
index 0000000..efc127f
--- /dev/null
@@ -0,0 +1,40 @@
+USING: accessors arrays combinators.short-circuit grouping kernel lists
+lists.lazy locals math math.functions math.parser math.ranges
+models.product monads random sequences sets ui ui.frp.gadgets
+ui.frp.layout ui.frp.signals ui.gadgets.alerts vectors fry
+ui.gadgets.labels memoize ;
+IN: sudokus
+
+: row ( index -- row ) 1 + 9 / ceiling ;
+: col ( index -- col ) 9 mod 1 + ;
+: sq ( index -- square ) [ row ] [ col ] bi [ 3 / ceiling ] bi@ 2array ;
+: near ( a pos -- ? ) { [ [ row ] bi@ = ] [ [ col ] bi@ = ] [ [ sq ] bi@ = ] } 2|| ;
+: nth-or-lower ( n seq -- elt ) [ length 1 - 2dup > [ nip ] [ drop ] if ] keep nth ;
+
+MEMO:: solutions ( puzzle random? -- solutions )
+    f puzzle random? [ indices [ f ] [ random? swap nth-or-lower ] if-empty ] [ index ] if
+    [ :> pos
+      1 9 [a,b] 80 iota [ pos near ] filter [ puzzle nth ] map prune diff
+      [ 1array puzzle pos cut-slice rest surround ] map >list [ random? solutions ] bind
+    ] [ puzzle list-monad return ] if* ;
+
+: solution ( puzzle random? -- solution ) dupd solutions dup +nil+ = [ drop "Unsolvable" alert* ] [ nip car ] if \ solutions reset-memoized ;
+: hint ( puzzle -- puzzle' ) [ [ f swap indices random dup ] [ f solution ] bi nth ] keep swapd >vector [ set-nth ] keep ;
+: create ( difficulty -- puzzle ) 81 [ f ] replicate
+    40 random solution [ [ dup length random f spin set-nth ] curry times ] keep ;
+
+: do-sudoku ( -- ) [ [
+        [
+            81 [ "" ] replicate <basic> <switch> [ [ <basic> ] map 9 group [ 3 group ] map 3 group
+               [ [ [ <spacer> [ [ <frp-field> ->% 2 [ string>number ] fmap ]
+                    map <spacer> ] map concat ] <hbox> , ] map concat <spacer> ] map concat <product>
+               [ "Difficulty:" <label> , "1" <basic> <frp-field> -> [ string>number 1 or 1 + 10 * ] fmap
+               "Generate" <frp-border-button> -> <updates> [ create ] fmap <spacer>
+               "Hint" <frp-border-button> -> "Solve" <frp-border-button> -> ] <hbox> ,
+               roll [ swap <updates> ] curry bi@
+               [ [ hint ] fmap ] [ [ f solution ] fmap ] bi* 3array <merge> [ [ [ number>string ] [ "" ] if* ] map ] fmap
+           ] bind
+        ] with-self , ] <vbox> { 280 220 } >>pref-dim
+    "Sudoku Sleuth" open-window ] with-ui ;
+
+MAIN: do-sudoku
\ No newline at end of file
diff --git a/extra/sudokus/summary.txt b/extra/sudokus/summary.txt
new file mode 100644 (file)
index 0000000..d66e7be
--- /dev/null
@@ -0,0 +1 @@
+graphical sudoku solver
\ No newline at end of file
diff --git a/extra/ui/frp/authors.txt b/extra/ui/frp/authors.txt
deleted file mode 100644 (file)
index 2300f69..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Sam Anklesaria
diff --git a/extra/ui/frp/frp-docs.factor b/extra/ui/frp/frp-docs.factor
deleted file mode 100644 (file)
index 479a56e..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-USING: help.markup help.syntax models monads sequences
-ui.gadgets.buttons ui.gadgets.tracks ;
-IN: ui.frp
-
-! Layout utilities
-
-HELP: ,
-{ $values { "uiitem" "a gadget or model" } }
-{ $description "Used in a series of gadgets created by a box, accumulating the gadget" } ;
-HELP: ->
-{ $values { "uiitem" "a gadget or model" } { "model" model } }
-{ $description "Like " { $link , } "but passes its model on for further use." } ;
-HELP: <hbox>
-{ $values { "gadgets" "a list of gadgets" } { "track" track } }
-{ $syntax "[ gadget , gadget , ... ] <hbox>" }
-{ $description "Creates an horizontal track containing the gadgets listed in the quotation" } ;
-HELP: <vbox>
-{ $values { "gadgets" "a list of gadgets" } { "track" track } }
-{ $syntax "[ gadget , gadget , ... ] <hbox>" }
-{ $description "Creates an vertical track containing the gadgets listed in the quotation" } ;
-
-! Gadgets
-HELP: <frp-button>
-{ $values { "text" "the button's label" } { "button" button } }
-{ $description "Creates an button whose model updates on clicks" } ;
-
-HELP: <merge>
-{ $values { "models" "a list of models" } { "model" merge-model } }
-{ $description "Creates a model that merges the updates of others" } ;
-
-HELP: <filter>
-{ $values { "model" model } { "quot" "quotation with stack effect ( a b -- c )" } { "filter-model" filter-model } }
-{ $description "Creates a model that uses the updates of another model when they satisfy a given predicate" } ;
-
-HELP: <fold>
-{ $values { "oldval" "starting value" } { "quot" "applied to update and previous values" } { "model" model } { "model'" model } }
-{ $description "Similar to " { $link reduce } " but works on models, applying a quotation to the previous and new values at each update" } ;
-
-HELP: <switch>
-{ $values { "signal1" model } { "signal2" model } { "signal'" model } }
-{ $description "Creates a model that starts with the behavior of model1 and switches to the behavior of model2 on its update" } ;
-
-ARTICLE: { "frp" "instances" } "FRP Instances"
-"Models are all functors, as " { $link fmap } " corresponds directly to the " { $link "models.arrow" } " vocabulary. "
-"Also, a gadget is a monad. Binding recieves a model and creates a new gadget." ;
-
diff --git a/extra/ui/frp/frp.factor b/extra/ui/frp/frp.factor
deleted file mode 100644 (file)
index 699d034..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-USING: accessors arrays colors fonts kernel models
-models.product monads sequences ui.gadgets ui.gadgets.buttons
-ui.gadgets.editors ui.gadgets.line-support ui.gadgets.tables
-ui.gadgets.tracks ui.render ui.gadgets.scrollers ;
-QUALIFIED: make
-IN: ui.frp
-
-! Gadgets
-: <frp-button> ( text -- button ) [ t swap set-control-value ] <border-button> f <model> >>model ;
-TUPLE: frp-table < table quot val-quot color-quot column-titles column-alignment ;
-M: frp-table column-titles column-titles>> ;
-M: frp-table column-alignment column-alignment>> ;
-M: frp-table row-columns quot>> [ call( a -- b ) ] [ drop f ] if* ;
-M: frp-table row-value val-quot>> [ call( a -- b ) ]  [ drop f ] if* ;
-M: frp-table row-color color-quot>> [ call( a -- b ) ]  [ drop f ] if* ;
-
-: <frp-table> ( model -- table )
-    frp-table new-line-gadget dup >>renderer [ ] >>quot swap >>model
-    f <model> >>selected-value sans-serif-font >>font
-    focus-border-color >>focus-border-color
-    transparent >>column-line-color [ ] >>val-quot ;
-: <frp-table*> ( -- table ) f <model> <frp-table> ;
-: <frp-list> ( model -- table ) <frp-table> [ 1array ] >>quot ;
-: <frp-list*> ( -- table ) f <model> <frp-list> ;
-
-: <frp-field> ( -- field ) f <model> <model-field> ;
-
-! Layout utilities
-
-GENERIC: output-model ( gadget -- model )
-M: gadget output-model model>> ;
-M: frp-table output-model selected-value>> ;
-M: model-field output-model field-model>> ;
-M: scroller output-model children>> first model>> ;
-
-GENERIC: , ( uiitem -- )
-M: gadget , make:, ;
-M: model , activate-model ;
-
-GENERIC: -> ( uiitem -- model )
-M: gadget -> dup make:, output-model ;
-M: model -> dup , ;
-M: table -> dup , selected-value>> ;
-
-: <box> ( gadgets type -- track )
-   [ { } make:make ] dip <track> swap [ f track-add ] each ; inline
-: <box*> ( gadgets type -- track ) [ <box> ] [ [ model>> ] map <product> ] bi >>model ; inline
-: <hbox> ( gadgets -- track ) horizontal <box> ; inline
-: <hbox*> ( gadgets -- track ) horizontal <box*> ; inline
-: <vbox> ( gadgets -- track ) vertical <box> ; inline
-: <vbox*> ( gadgets -- track ) vertical <box*> ; inline
-
-! !!! Model utilities
-TUPLE: multi-model < model ;
-: <multi-model> ( models kind -- model ) f swap new-model [ [ add-dependency ] curry each ] keep ;
-
-! Events- discrete model utilities
-
-TUPLE: merge-model < multi-model ;
-M: merge-model model-changed [ value>> ] dip set-model ;
-: <merge> ( models -- model ) merge-model <multi-model> ;
-
-TUPLE: filter-model < multi-model quot ;
-M: filter-model model-changed [ value>> ] dip [ quot>> call( val -- bool ) ] 2keep
-   [ set-model ] [ 2drop ] if ;
-: <filter> ( model quot -- filter-model ) [ 1array filter-model <multi-model> ] dip >>quot ;
-
-! Behaviors - continuous model utilities
-
-TUPLE: fold-model < multi-model oldval quot ;
-M: fold-model model-changed [ [ value>> ] [ [ oldval>> ] [ quot>> ] bi ] bi*
-   call( val oldval -- newval ) ] keep set-model ;
-: <fold> ( oldval quot model -- model' ) 1array fold-model <multi-model> swap >>quot
-   swap [ >>oldval ] [ >>value ] bi ;
-
-TUPLE: switch-model < multi-model original switcher on ;
-M: switch-model model-changed 2dup switcher>> =
-   [ over value>> [ [ value>> ] [ t >>on ] bi* set-model ] [ 2drop ] if ]
-   [ dup on>> [ 2drop ] [ [ value>> ] dip set-model ] if ] if ;
-M: switch-model model-activated [ original>> ] keep model-changed ;
-: <switch> ( signal1 signal2 -- signal' ) [ 2array switch-model <multi-model> ] 2keep
-   [ >>original ] [ >>switcher ] bi* ;
-
-TUPLE: mapped < model model quot ;
-
-: <mapped> ( model quot -- arrow )
-    f mapped new-model
-        swap >>quot
-        over >>model
-        [ add-dependency ] keep ;
-
-M: mapped model-changed
-    [ [ value>> ] [ quot>> ] bi* call( old -- new ) ] [ nip ] 2bi
-    set-model ;
-
-! Instances
-M: model fmap <mapped> ;
-
-SINGLETON: gadget-monad
-INSTANCE: gadget-monad monad
-INSTANCE: gadget monad
-M: gadget monad-of drop gadget-monad ;
-M: gadget-monad return drop <gadget> swap >>model ;
-M: gadget >>= output-model [ swap call( x -- y ) ] curry ; 
\ No newline at end of file
diff --git a/extra/ui/frp/gadgets/authors.txt b/extra/ui/frp/gadgets/authors.txt
new file mode 100644 (file)
index 0000000..2300f69
--- /dev/null
@@ -0,0 +1 @@
+Sam Anklesaria
diff --git a/extra/ui/frp/gadgets/gadgets-docs.factor b/extra/ui/frp/gadgets/gadgets-docs.factor
new file mode 100644 (file)
index 0000000..ee0c764
--- /dev/null
@@ -0,0 +1,71 @@
+USING: accessors help.markup help.syntax ui.gadgets.buttons
+ui.gadgets.editors ui.frp.gadgets models ui.gadgets ;
+IN: ui.frp.gadgets
+
+HELP: <frp-button>
+{ $values { "gadget" "the button's label" } { "button" button } }
+{ $description "Creates an button whose signal updates on clicks.  " } ;
+
+HELP: <frp-border-button>
+{ $values { "text" "the button's label" } { "button" button } }
+{ $description "Creates an button whose signal updates on clicks.  " } ;
+
+HELP: <frp-table>
+{ $values { "model" "values the table is to display" } { "table" frp-table } }
+{ $description "Creates an " { $link frp-table } } ;
+
+HELP: <frp-table*>
+{ $values { "table" frp-table } }
+{ $description "Creates an " { $link frp-table } " with no initial values to display" } ;
+
+HELP: <frp-list>
+{ $values { "column-model" "values the table is to display" } { "table" frp-table } }
+{ $description "Creates an " { $link frp-table } " with a val-quot that renders each element as its own row" } ;
+
+HELP: <frp-list*>
+{ $values { "table" frp-table } }
+{ $description "Creates an frp-list with no initial values to display" } ;
+
+HELP: indexed
+{ $values { "table" frp-table } }
+{ $description "Sets the output model of an frp-table to the selected-index, rather than the selected-value" } ;
+
+HELP: <frp-field>
+{ $values { "model" model } { "gadget" model-field } }
+{ $description "Creates a field with an initial value" } ;
+
+HELP: <frp-field*>
+{ $values { "field" model-field } }
+{ $description "Creates a field with an empty initial value" } ;
+
+HELP: <empty-field>
+{ $values { "model" model } { "field" model-field } }
+{ $description "Creates a field with an empty initial value that switches to another signal on its update" } ;
+
+HELP: <frp-editor>
+{ $values { "model" model } { "gadget" model-field } }
+{ $description "Creates an editor with an initial value" } ;
+
+HELP: <frp-editor*>
+{ $values { "editor" "an editor" } }
+{ $description "Creates a editor with an empty initial value" } ;
+
+HELP: <empty-editor>
+{ $values { "model" model } { "editor" "an editor" } }
+{ $description "Creates a field with an empty initial value that switches to another signal on its update" } ;
+
+HELP: <frp-action-field>
+{ $values { "field" action-field } }
+{ $description "Field that updates its model with its contents when the user hits the return key" } ;
+
+HELP: IMG-FRP-BTN:
+{ $syntax "IMAGE-BUTTON: filename" }
+{ $description "Creates a button using a tiff image named as specified found in the icons subdirectory of the vocabulary path" } ;
+
+HELP: IMG-BTN:
+{ $syntax "[ do-something ] IMAGE-BUTTON: filename" }
+{ $description "Creates a button using a tiff image named as specified found in the icons subdirectory of the vocabulary path, calling the specified quotation on click" } ;
+
+HELP: output-model
+{ $values { "gadget" gadget } { "model" model } }
+{ $description "Returns the model a gadget uses for output. Often the same as " { $link model>> } } ;
\ No newline at end of file
diff --git a/extra/ui/frp/gadgets/gadgets.factor b/extra/ui/frp/gadgets/gadgets.factor
new file mode 100644 (file)
index 0000000..59dfd98
--- /dev/null
@@ -0,0 +1,79 @@
+USING: accessors assocs arrays kernel models monads sequences
+ui.frp.signals ui.gadgets ui.gadgets.borders ui.gadgets.buttons
+ui.gadgets.buttons.private ui.gadgets.editors words images.loader
+ui.gadgets.scrollers ui.gadgets.tables ui.images vocabs.parser lexer ;
+IN: ui.frp.gadgets
+
+TUPLE: frp-button < button hook value ;
+: <frp-button> ( gadget -- button ) [
+      [ dup hook>> [ call( button -- ) ] [ drop ] if* ]
+      [ [ [ value>> ] [ ] bi or ] keep set-control-value ]
+      [ model>> f swap (>>value) ] tri
+   ] frp-button new-button f <basic> >>model ;
+: <frp-border-button> ( text -- button ) <frp-button> border-button-theme ;
+
+TUPLE: frp-table < table { quot initial: [ ] } { val-quot initial: [ ] } color-quot column-titles column-alignment actions ;
+M: frp-table column-titles column-titles>> ;
+M: frp-table column-alignment column-alignment>> ;
+M: frp-table row-columns quot>> [ call( a -- b ) ] [ drop f ] if* ;
+M: frp-table row-value val-quot>> [ call( a -- b ) ]  [ drop f ] if* ;
+M: frp-table row-color color-quot>> [ call( a -- b ) ]  [ drop f ] if* ;
+
+: new-frp-table ( model class -- table ) f swap new-table dup >>renderer
+   V{ } clone <basic> >>selected-values V{ } clone <basic> >>selected-indices*
+   f <basic> >>actions dup [ actions>> set-model ] curry >>action ;
+: <frp-table> ( model -- table ) frp-table new-frp-table ;
+: <frp-table*> ( -- table ) V{ } clone <model> <frp-table> ;
+: <frp-list> ( column-model -- table ) <frp-table> [ 1array ] >>quot ;
+: <frp-list*> ( -- table ) V{ } clone <model> <frp-list> ;
+: indexed ( table -- table ) f >>val-quot ;
+
+TUPLE: frp-field < field frp-model ;
+: init-field ( field -- field' ) [ [ ] [ "" ] if* ] change-value ;
+: <frp-field> ( model -- gadget ) frp-field new-field swap init-field >>frp-model ;
+M: frp-field graft*
+    [ [ frp-model>> value>> ] [ editor>> ] bi set-editor-string ]
+    [ dup editor>> model>> add-connection ]
+    [ dup frp-model>> add-connection ] tri ;
+M: frp-field ungraft*
+   [ dup editor>> model>> remove-connection ]
+   [ dup frp-model>> remove-connection ] bi ;
+M: frp-field model-changed 2dup frp-model>> =
+    [ [ value>> ] [ editor>> ] bi* set-editor-string ]
+    [ nip [ editor>> editor-string ] [ frp-model>> ] bi set-model ] if ;
+
+: <frp-field*> ( -- field ) "" <model> <frp-field> ;
+: <empty-field> ( model -- field ) "" <model> <switch> <frp-field> ;
+: <frp-editor> ( model -- gadget )
+    frp-field [ <multiline-editor> ] dip new-border dup gadget-child >>editor
+    field-theme swap init-field >>frp-model { 1 0 } >>align ;
+: <frp-editor*> ( -- editor ) "" <model> <frp-editor> ;
+: <empty-editor> ( model -- editor ) "" <model> <switch> <frp-editor> ;
+
+: <frp-action-field> ( -- field ) f <action-field> dup [ set-control-value ] curry >>quot
+    f <model> >>model ;
+
+: image-prep ( -- image ) scan current-vocab name>> "vocab:" "/icons/" surround ".tiff" surround <image-name> dup cached-image drop ;
+SYNTAX: IMG-FRP-BTN: image-prep [ <frp-button> ] curry over push-all ;
+
+SYNTAX: IMG-BTN: image-prep [ swap <button> ] curry over push-all ;
+
+GENERIC: output-model ( gadget -- model )
+M: gadget output-model model>> ;
+M: table output-model dup multiple-selection?>>
+   [ dup val-quot>> [ selected-values>> ] [ selected-indices*>> ] if ]
+   [ dup val-quot>> [ selected-value>> ] [ selected-index*>> ] if ] if ;
+M: frp-field output-model frp-model>> ;
+M: scroller output-model viewport>> children>> first output-model ;
+
+IN: accessors
+M: frp-button text>> children>> first text>> ;
+
+IN: ui.frp.gadgets
+
+SINGLETON: gadget-monad
+INSTANCE: gadget-monad monad
+INSTANCE: gadget monad
+M: gadget monad-of drop gadget-monad ;
+M: gadget-monad return drop <gadget> swap >>model ;
+M: gadget >>= output-model [ swap call( x -- y ) ] curry ; 
\ No newline at end of file
diff --git a/extra/ui/frp/gadgets/summary.txt b/extra/ui/frp/gadgets/summary.txt
new file mode 100644 (file)
index 0000000..b792b81
--- /dev/null
@@ -0,0 +1 @@
+Gadgets using signals as their models
\ No newline at end of file
diff --git a/extra/ui/frp/layout/authors.txt b/extra/ui/frp/layout/authors.txt
new file mode 100644 (file)
index 0000000..2300f69
--- /dev/null
@@ -0,0 +1 @@
+Sam Anklesaria
diff --git a/extra/ui/frp/layout/layout-docs.factor b/extra/ui/frp/layout/layout-docs.factor
new file mode 100644 (file)
index 0000000..2f475de
--- /dev/null
@@ -0,0 +1,53 @@
+USING: help.markup help.syntax models ui.gadgets.tracks ui.frp.layout ;
+IN: ui.frp.layout
+
+HELP: ,
+{ $values { "item" "a gadget or model" } }
+{ $description "Used in a series of gadgets created by a box, accumulating the gadget" } ;
+
+HELP: ,%
+{ $syntax "gadget ,% width" }
+{ $description "Like ',' but stretches the gadget to always fill a percent of the parent" } ;
+
+HELP: ->
+{ $values { "uiitem" "a gadget or model" } { "model" model } }
+{ $description "Like ',' but passes its model on for further use." } ;
+
+HELP: ->%
+{ $syntax "gadget ,% width" }
+{ $description "Like '->' but stretches the gadget to always fill a percent of the parent" } ;
+
+HELP: <spacer>
+{ $description "Grows to fill any empty space in a box" } ;
+
+HELP: <hbox>
+{ $values { "gadgets" "a list of gadgets" } { "track" track } }
+{ $syntax "[ gadget , gadget , ... ] <hbox>" }
+{ $description "Creates an horizontal track containing the gadgets listed in the quotation" } ;
+
+HELP: <vbox>
+{ $values { "gadgets" "a list of gadgets" } { "track" track } }
+{ $syntax "[ gadget , gadget , ... ] <hbox>" }
+{ $description "Creates an vertical track containing the gadgets listed in the quotation" } ;
+
+HELP: $
+{ $syntax "$ PLACEHOLDER-NAME $" }
+{ $description "Defines an insertion point in a template named PLACEHOLDER-NAME which can be used by calling its name" } ;
+
+HELP: with-interface
+{ $values { "quot" "quotation that builds a template and inserts into it" } }
+{ $description "Create templates, used with " { $link POSTPONE: $ } } ;
+
+ARTICLE: "ui.frp.layout" "GUI Layout"
+"Laying out GUIs works the same way as building lists with " { $vocab-link "make" }
+". Gadgets are layed out using " { $vocab-link "ui.gadgets.tracks" } " through " { $link <hbox> } " and " { $link <vbox> } ", which allow both fixed and percentage widths. "
+{ $link , } " and " { $link -> }  " add a signal or gadget to the gadget you're building. "
+"Also, books can be made with " { $link <frp-book> } ". "
+{ $link <spacer> } "s add flexable space between items. " $nl
+"Using " { $link with-interface } ", one can pre-build templates to add items to later: "
+"Like in the StringTemplate framework for java, placeholders are defined using $ PLACERHOLDER-NAME $ "
+"Using PLACEHOLDER-NAME again sets it as the current insertion point. "
+"For examples using normal layout, see the " { $vocab-link "sudokus" } " demo. "
+"For examples of templating, see " { $vocab-link "recipes" } " demo. " ;
+
+ABOUT: "ui.frp.layout"
\ No newline at end of file
diff --git a/extra/ui/frp/layout/layout.factor b/extra/ui/frp/layout/layout.factor
new file mode 100644 (file)
index 0000000..c3c32cd
--- /dev/null
@@ -0,0 +1,77 @@
+USING: accessors arrays fry kernel lexer make math.parser
+models monads namespaces parser sequences
+sequences.extras ui.frp.gadgets ui.frp.signals ui.gadgets
+ui.gadgets.books ui.gadgets.tracks words ;
+QUALIFIED: make
+IN: ui.frp.layout
+
+TUPLE: layout gadget size ; C: <layout> layout
+TUPLE: placeholder < gadget members ;
+: <placeholder> ( -- placeholder ) placeholder new V{ } clone >>members ;
+
+: (remove-members) ( placeholder members -- ) [ [ model? ] filter swap parent>> model>> [ remove-connection ] curry each ]
+    [ nip [ gadget? ] filter [ unparent ] each ] 2bi ;
+
+: remove-members ( placeholder -- ) dup members>> [ drop ] [ [ (remove-members) ] keep empty ] if-empty ;
+: add-member ( obj placeholder -- ) over layout? [ [ gadget>> ] dip ] when members>> push ;
+
+: , ( item -- ) make:, ;
+: make* ( quot -- list ) { } make ; inline
+
+! Just take the previous mentioned placeholder and use it
+! If there is no previously mentioned placeholder, we're probably making a box, and will create the placeholder ourselves
+DEFER: with-interface
+: insertion-quot ( quot -- quot' ) make:building get [ [ placeholder? ] find-last nip [ <placeholder> dup , ] unless*
+    swap '[ [ _ , @ ] with-interface ] ] when* ;
+
+SYNTAX: ,% scan string>number [ <layout> , ] curry over push-all ;
+SYNTAX: ->% scan string>number '[ [ _ <layout> , ] [ output-model ] bi ] over push-all ;
+
+GENERIC: -> ( uiitem -- model )
+M: gadget -> dup , output-model ;
+M: model -> dup , ;
+
+: <spacer> ( -- ) <gadget> 1 <layout> , ;
+
+: add-layout ( track layout -- track ) [ gadget>> ] [ size>> ] bi track-add ; inline
+: layouts ( sized? gadgets -- layouts ) [ [ gadget? ] [ layout? ] bi or ] filter swap
+   [ [ dup layout? [ f <layout> ] unless ] map ]
+   [ [ dup gadget? [ gadget>> ] unless ] map ] if ;
+: make-layout ( building sized? -- models layouts ) [ swap layouts ] curry
+   [ make* [ [ model? ] filter ] ] dip bi ; inline
+: <box> ( gadgets type -- track )
+   [ t make-layout ] dip <track>
+   swap [ add-layout ] each
+   swap [ <collection> >>model ] unless-empty ; inline
+: <hbox> ( gadgets -- track ) horizontal <box> ; inline
+: <vbox> ( gadgets -- track ) vertical <box> ; inline
+
+: make-book ( models gadgets model -- book ) <book> swap [ "No models in books" throw ] unless-empty ;
+: <frp-book> ( quot: ( -- model ) -- book ) f make-layout rot 0 >>value make-book ; inline
+: <frp-book*> ( quot -- book ) f make-layout f make-book ; inline
+
+SYNTAX: $ CREATE-WORD <placeholder>
+    [ [ , ] curry (( -- )) define-declared "$" expect ]
+    [ [ , ] curry ] bi over push-all ;
+
+: insert-gadget ( number parent gadget -- ) -rot [ but-last insert-nth ] change-children drop ;
+: insert-size ( number parent size -- ) -rot [ but-last insert-nth ] change-sizes drop ;
+: insertion-point ( gadget placeholder -- number parent gadget ) dup parent>> [ children>> index ] keep rot ;
+
+GENERIC# (insert-item) 1 ( item location -- )
+M: gadget (insert-item) dup parent>> track? [ [ f <layout> ] dip (insert-item) ]
+    [ insertion-point [ add-gadget ] keep insert-gadget ] if ;
+M: layout (insert-item) insertion-point [ add-layout ] keep [ gadget>> insert-gadget ] [ size>> insert-size ] 3bi ;
+M: model (insert-item) parent>> dup book? [ "No models in books" throw ]
+   [ dup model>> dup collection? [ nip swap add-connection ] [ drop [ 1array <collection> ] dip (>>model) ] if ] if ;
+: insert-item ( item location -- ) [ dup get [ drop ] [ remove-members ] if ] [ on ] [ ] tri
+    [ add-member ] 2keep (insert-item) ;
+
+: insert-items ( makelist -- ) t swap [ dup placeholder? [ nip ] [ over insert-item ] if ] each drop ;
+
+: with-interface ( quot -- ) make* [ insert-items ] with-scope ; inline
+
+M: model >>= [ swap insertion-quot <action> ] curry ;
+M: model fmap insertion-quot <mapped> ;
+M: model $> insertion-quot side-effect-model new-mapped-model ;
+M: model <$ insertion-quot quot-model new-mapped-model ;
\ No newline at end of file
diff --git a/extra/ui/frp/layout/summary.txt b/extra/ui/frp/layout/summary.txt
new file mode 100644 (file)
index 0000000..30b5ef5
--- /dev/null
@@ -0,0 +1 @@
+Syntax for easily building GUIs and using templates
\ No newline at end of file
diff --git a/extra/ui/frp/signals/authors.txt b/extra/ui/frp/signals/authors.txt
new file mode 100644 (file)
index 0000000..2300f69
--- /dev/null
@@ -0,0 +1 @@
+Sam Anklesaria
diff --git a/extra/ui/frp/signals/signals-docs.factor b/extra/ui/frp/signals/signals-docs.factor
new file mode 100644 (file)
index 0000000..397c1e2
--- /dev/null
@@ -0,0 +1,49 @@
+USING: help.markup help.syntax models models.arrow sequences ui.frp.signals monads ;
+IN: ui.frp.signals
+
+HELP: <merge>
+{ $values { "models" "a list of models" } { "signal" basic-model } }
+{ $description "Creates a signal that merges the updates of others" } ;
+
+HELP: <filter>
+{ $values { "model" model } { "quot" "quotation with stack effect ( a b -- c )" } { "filter-signal" filter-model } }
+{ $description "Creates a signal that uses the updates of another model only when they satisfy a given predicate" } ;
+
+HELP: <fold>
+{ $values { "oldval" "starting value" } { "quot" "applied to update and previous values" } { "model" model } { "signal" model } }
+{ $description "Similar to " { $link reduce } " but works on models, applying a quotation to the previous and new values at each update" } ;
+
+HELP: <switch>
+{ $values { "signal1" model } { "signal2" model } { "signal'" model } }
+{ $description "Creates a signal that starts with the behavior of signal2 and switches to the behavior of signal1 on its update" } ;
+
+HELP: <mapped>
+{ $values { "model" model } { "quot" "applied to model's value on updates" } { "signal" model } }
+{ $description "The signal version of an " { $link <arrow> } } ;
+
+HELP: $>
+{ $values { "model" model } { "quot" "applied to model's value on updates" } { "signal" model } }
+{ $description "Like " { $link <mapped> } ", but doesn't produce a new value" } ;
+
+HELP: <$
+{ $values { "model" model } { "quot" "applied to model's value on updates" } { "signal" model } }
+{ $description "Opposite of " { $link <$ } "- gives output, but takes no input" } ;
+
+HELP: frp-when
+{ $values { "model" model } { "quot" "called on the model if the quot yields true" } { "cond" "a quotation called on the model's value, yielding a boolean value"  } }
+{ $description "Calls quot when model updates if its value meets the condition set in cond" } ;
+
+HELP: with-self
+{ $values { "quot" "quotation that recieves its own return value" } { "model" model } }
+{ $description "Fixed points for signals: the quot reacts to the same signal to gives" } ;
+
+HELP: #1
+{ $values { "model" model } { "model'" model } }
+{ $description "Moves a signal to the top of its dependencies' connections, thus being notified before the others" } ;
+
+ARTICLE: "signals" "FRP Signals"
+"Unlike models, which always have a value, signals have discrete start and end times. "
+"They are the core of the frp library: program flow using frp is controlled entirely through manipulating and combining signals. "
+"The output signals of some gadgets (see " { $vocab-link "ui.frp.gadgets" } " ) can be manipulated and used as the input signals of others. " ;
+
+ABOUT: "signals"
\ No newline at end of file
diff --git a/extra/ui/frp/signals/signals.factor b/extra/ui/frp/signals/signals.factor
new file mode 100644 (file)
index 0000000..681ffaf
--- /dev/null
@@ -0,0 +1,105 @@
+USING: accessors arrays kernel models models.product monads
+sequences sequences.extras ;
+FROM: syntax => >> ;
+IN: ui.frp.signals
+
+TUPLE: multi-model < model important? ;
+GENERIC: (model-changed) ( model observer -- )
+: <multi-model> ( models kind -- model ) f swap new-model [ [ add-dependency ] curry each ] keep ;
+M: multi-model model-changed over value>> [ (model-changed) ] [ 2drop ] if ;
+M: multi-model model-activated dup dependencies>> [ value>> ] find nip
+   [ swap model-changed ] [ drop ] if* ;
+
+: #1 ( model -- model' ) t >>important? ;
+
+IN: models
+: notify-connections ( model -- )
+    dup connections>> dup [ dup multi-model? [ important?>> ] [ drop f ] if ] find-all
+    [ second tuck [ remove ] dip prefix ] each
+    [ model-changed ] with each ;
+IN: ui.frp.signals
+
+TUPLE: basic-model < multi-model ;
+M: basic-model (model-changed) [ value>> ] dip set-model ;
+: <merge> ( models -- signal ) basic-model <multi-model> ;
+: <2merge> ( model1 model2 -- signal ) 2array <merge> ;
+: <basic> ( value -- signal ) basic-model new-model ;
+
+TUPLE: filter-model < multi-model quot ;
+M: filter-model (model-changed) [ value>> ] dip 2dup quot>> call( a -- ? )
+   [ set-model ] [ 2drop ] if ;
+: <filter> ( model quot -- filter-signal ) [ 1array filter-model <multi-model> ] dip >>quot ;
+
+TUPLE: fold-model < multi-model quot base values ;
+M: fold-model (model-changed) 2dup base>> =
+    [ [ [ value>> ] [ [ values>> ] [ quot>> ] bi ] bi* swapd reduce* ] keep set-model ]
+    [ [ [ value>> ] [ values>> ] bi* push ]
+      [ [ [ value>> ] [ [ value>> ] [ quot>> ] bi ] bi* call( val oldval -- newval ) ] keep set-model ] 2bi
+    ] if ;
+M: fold-model model-activated drop ;
+: new-fold-model ( deps -- model ) fold-model <multi-model> V{ } clone >>values ;
+: <fold> ( model oldval quot -- signal ) rot 1array new-fold-model swap >>quot
+   swap >>value ;
+: <fold*> ( model oldmodel quot -- signal ) over [ [ 2array new-fold-model ] dip >>quot ]
+    dip [ >>base ] [ value>> >>value ] bi ;
+
+TUPLE: updater-model < multi-model values updates ;
+M: updater-model (model-changed) [ tuck updates>> =
+   [ [ values>> value>> ] keep set-model ]
+   [ drop ] if ] keep f swap (>>value) ;
+: <updates> ( values updates -- signal ) [ 2array updater-model <multi-model> ] 2keep
+   [ >>values ] [ >>updates ] bi* ;
+
+SYMBOL: switch
+TUPLE: switch-model < multi-model original switcher on ;
+M: switch-model (model-changed) 2dup switcher>> =
+   [ [ value>> ] dip over switch = [ nip [ original>> ] keep f >>on model-changed ] [ t >>on set-model ] if ]
+   [ dup on>> [ 2drop ] [ [ value>> ] dip over [ set-model ] [ 2drop ] if ] if ] if ;
+: <switch> ( signal1 signal2 -- signal' ) swap [ 2array switch-model <multi-model> ] 2keep
+   [ [ value>> >>value ] [ >>original ] bi ] [ >>switcher ] bi* ;
+M: switch-model model-activated [ original>> ] keep model-changed ;
+: >behavior ( event -- behavior ) t >>value ;
+
+TUPLE: mapped-model < multi-model model quot ;
+: new-mapped-model ( model quot class -- mapped-model ) [ over 1array ] dip
+   <multi-model> swap >>quot swap >>model ;
+: <mapped> ( model quot -- signal ) mapped-model new-mapped-model ;
+M: mapped-model (model-changed)
+    [ [ value>> ] [ quot>> ] bi* call( old -- new ) ] [ nip ] 2bi
+    set-model ;
+
+TUPLE: side-effect-model < mapped-model ;
+M: side-effect-model (model-changed) [ value>> ] dip [ quot>> call( old -- ) ] 2keep set-model ;
+
+TUPLE: quot-model < mapped-model ;
+M: quot-model (model-changed) nip [ quot>> call( -- b ) ] keep set-model ;
+
+TUPLE: action-value < basic-model parent ;
+: <action-value> ( parent value -- model ) action-value new-model swap >>parent ;
+M: action-value model-activated dup parent>> dup activate-model model-changed ; ! a fake dependency of sorts
+
+TUPLE: action < multi-model quot ;
+M: action (model-changed) [ [ value>> ] [ quot>> ] bi* call( a -- b ) ] keep value>>
+   [ swap add-connection ] 2keep model-changed ;
+: <action> ( model quot -- action-signal ) [ 1array action <multi-model> ] dip >>quot dup f <action-value> >>value value>> ;
+
+TUPLE: collection < multi-model ;
+: <collection> ( models -- product ) collection <multi-model> ;
+M: collection (model-changed)
+    nip
+    dup dependencies>> [ value>> ] all?
+    [ dup [ value>> ] product-value swap set-model ]
+    [ drop ] if ;
+M: collection model-activated dup (model-changed) ;
+
+! for side effects
+TUPLE: (frp-when) < multi-model quot cond ;
+: frp-when ( model quot cond -- model ) rot 1array (frp-when) <multi-model> swap >>cond swap >>quot ;
+M: (frp-when) (model-changed) [ quot>> ] 2keep
+    [ value>> ] [ cond>> ] bi* call( a -- ? ) [ call( model -- ) ] [ 2drop ] if ;
+
+! only used in construction
+: with-self ( quot: ( model -- model ) -- model ) [ f <basic> dup ] dip call swap [ add-dependency ] keep ; inline
+
+USE: ui.frp.signals.templates
+<< { "$>" "<$" "fmap" } [ fmaps ] each >>
\ No newline at end of file
diff --git a/extra/ui/frp/signals/summary.txt b/extra/ui/frp/signals/summary.txt
new file mode 100644 (file)
index 0000000..3b49d34
--- /dev/null
@@ -0,0 +1 @@
+Utilities for functional reactive programming in user interfaces
diff --git a/extra/ui/frp/signals/templates/templates.factor b/extra/ui/frp/signals/templates/templates.factor
new file mode 100644 (file)
index 0000000..bb08e03
--- /dev/null
@@ -0,0 +1,23 @@
+USING: kernel sequences functors fry macros generalizations ;
+IN: ui.frp.signals.templates
+FROM: ui.frp.signals => <collection> #1 ;
+FUNCTOR: fmaps ( W -- )
+W        IS ${W}
+w-n      DEFINES ${W}-n
+w-2      DEFINES 2${W}
+w-3      DEFINES 3${W}
+w-4      DEFINES 4${W}
+w-n*     DEFINES ${W}-n*
+w-2*     DEFINES 2${W}*
+w-3*     DEFINES 3${W}*
+w-4*     DEFINES 4${W}*
+WHERE
+MACRO: w-n ( int -- quot ) dup '[ [ _ narray <collection> ] dip [ _ firstn ] prepend W ] ;
+: w-2 ( a b quot -- mapped ) 2 w-n ; inline
+: w-3 ( a b c quot -- mapped ) 3 w-n ; inline
+: w-4 ( a b c d quot -- mapped ) 4 w-n ; inline
+MACRO: w-n* ( int -- quot ) dup '[ [ _ narray <collection> #1 ] dip [ _ firstn ] prepend W ] ;
+: w-2* ( a b quot -- mapped ) 2 w-n* ; inline
+: w-3* ( a b c quot -- mapped ) 3 w-n* ; inline
+: w-4* ( a b c d quot -- mapped ) 4 w-n* ; inline
+;FUNCTOR
\ No newline at end of file
diff --git a/extra/ui/frp/summary.txt b/extra/ui/frp/summary.txt
deleted file mode 100644 (file)
index 3b49d34..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Utilities for functional reactive programming in user interfaces
index 03d60957fa19a16e7221d9701d522ea550334c73..dc81aff15e56c5df5aab2f15ff206a9f18e03238 100644 (file)
@@ -1,4 +1,28 @@
-USING: accessors ui ui.gadgets ui.gadgets.labels ui.gadgets.buttons ui.gadgets.packs locals sequences fonts io.styles ;
+USING: accessors models monads macros generalizations kernel
+ui ui.frp.gadgets ui.frp.signals ui.frp.layout ui.gadgets
+ui.gadgets.labels ui.gadgets.editors ui.gadgets.buttons
+ui.gadgets.packs locals sequences fonts io.styles
+wrap.strings ;
+
 IN: ui.gadgets.alerts
-:: alert ( quot string -- ) <pile> { 10 10 } >>gap 1 >>align string <label> T{ font { name "sans-serif" } { size 18 } } >>font { 200 100 } >>pref-dim add-gadget 
-   "okay" [ close-window ] quot append <border-button> add-gadget "" open-window ;
\ No newline at end of file
+:: alert ( quot string -- ) <pile> { 10 10 } >>gap 1 >>align
+   string 22 wrap-lines <label> T{ font { name "sans-serif" } { size 18 } } >>font { 200 100 } >>pref-dim add-gadget 
+   "okay" [ close-window ] quot append <border-button> add-gadget "" open-window ;
+
+: alert* ( str -- ) [ ] swap alert ;
+
+:: ask-user ( string -- model' )
+   [ [let | lbl  [ string <label>  T{ font { name "sans-serif" } { size 14 } } >>font dup , ]
+            fldm [ <frp-field*> ->% 1 ]
+            btn  [ "okay" <frp-border-button> ] |
+         btn -> [ fldm swap <updates> ]
+                [ [ drop lbl close-window ] $> , ] bi
+   ] ] <vbox> { 161 86 } >>pref-dim "" open-window ;
+
+MACRO: ask-buttons ( buttons -- quot ) dup length [
+      [ swap
+         [ 22 wrap-lines <label> T{ font { name "sans-serif" } { size 18 } } >>font ,
+         [ [ <frp-border-button> [ close-window ] >>hook -> ] map ] <hbox> , ] <vbox>
+         "" open-window
+      ] dip firstn
+   ] 2curry ;
\ No newline at end of file
index 9e9474791986899c17f54ec8eece1bc666a97655..41e16e0f9f050a477669652cd86bbed5ff58fa8a 100644 (file)
@@ -5,8 +5,13 @@ IN: ui.gadgets.book-extras
 : |<< ( book -- ) 0 swap set-control-value ;
 : next ( book -- ) model>> [ 1 + ] change-model ;
 : prev ( book -- ) model>> [ 1 - ] change-model ;
-: (book-t) ( quot -- quot ) '[ : owner ( gadget -- book ) parent>> dup book? [ owner ] unless ; owner @ ] ;
+: owner ( gadget -- book ) parent>> dup book? [ owner ] unless ;
+: (book-t) ( quot -- quot ) '[ owner @ ] ;
 : <book-btn> ( label quot -- button ) (book-t) <button> ;
-: <book-bevel-btn> ( label quot -- button ) (book-t) <border-button> ;
-: >>> ( label -- button ) [ next ] <book-btn> ;
-: <<< ( label -- button ) [ prev ] <book-btn> ;
\ No newline at end of file
+: <book-border-btn> ( label quot -- button ) (book-t) <border-button> ;
+: >>> ( gadget -- ) owner next ;
+: <<< ( gadget -- ) owner prev ;
+: go-to ( gadget number -- ) swap owner model>> set-model ;
+
+: <forward-btn> ( label -- button ) [ >>> ] <button> ;
+: <backward-btn> ( label -- button ) [ <<< ] <button> ;
index b0dbe34d1665381a6cbf0c10cad9007b2ceb233d..eddd105e24794b8174a01e9cf8b6321479eced7e 100644 (file)
@@ -1,22 +1,21 @@
-USING: accessors arrays kernel math.rectangles models sequences
-ui.frp ui.gadgets ui.gadgets.glass ui.gadgets.labels
-ui.gadgets.tables ui.gestures ;
+USING: accessors arrays kernel math.rectangles sequences
+ui.frp.gadgets ui.frp.signals ui.gadgets ui.gadgets.glass
+ui.gadgets.labels ui.gadgets.tables ui.gestures ;
 IN: ui.gadgets.comboboxes
 
-TUPLE: combo-table < table spawner ;
+TUPLE: combo-table < frp-table spawner ;
 
-M: combo-table handle-gesture [ call-next-method ] 2keep swap
+M: combo-table handle-gesture [ call-next-method drop ] 2keep swap
    T{ button-up } = [
       [ spawner>> ]
-      [ selected-value>> value>> [ swap set-control-value ] [ drop ] if* ]
-      [ hide-glass ] tri drop t
-   ] [ drop ] if ;
+      [ selected-row [ swap set-control-value ] [ 2drop ] if ]
+      [ hide-glass ] tri
+   ] [ drop ] if ;
 
 TUPLE: combobox < label-control table ;
 combobox H{
    { T{ button-down } [ dup table>> over >>spawner <zero-rect> show-glass ] }
 } set-gestures
 
-: <combobox> ( options -- combobox ) [ first [ combobox new-label ] keep <model> >>model ] keep
-   [ 1array ] map <model> trivial-renderer combo-table new-table
-   >>table ;
\ No newline at end of file
+: <combobox> ( options -- combobox ) [ first [ combobox new-label ] keep <basic> >>model ] keep
+    <basic> combo-table new-frp-table [ 1array ] >>quot >>table ;
\ No newline at end of file
index 1c1217a71e0c0b9caaaf46e6654525ad3c6f179b..fe65c9cb37ef29ef396738d19a84cc2bad942a02 100644 (file)
@@ -1,10 +1,13 @@
 USING: accessors compiler.units combinators fry generalizations io
-io.encodings.binary io.sockets kernel namespaces
+io.encodings.binary io.sockets kernel
 parser sequences serialize vocabs vocabs.parser words ;
 IN: modules.rpc
 
 DEFER: get-words
 
+: with-in-vocab ( vocab quot -- vocab ) over
+  [ '[ _ set-current-vocab @ ] current-vocab name>> swap dip set-current-vocab ] dip vocab ; inline
+
 : remote-quot ( addrspec vocabspec effect str -- quot )
    '[ _ 5000 <inet> binary
       [
@@ -16,11 +19,8 @@ DEFER: get-words
       [ remote-quot ] 2keep create-in -rot define-declared word make-inline
    ] with-compilation-unit ;
 
-: with-in ( vocab quot -- vocab ) over
-   [ '[ _ set-in @ ] in get swap dip set-in ] dip vocab ; inline
-
 : remote-vocab ( addrspec vocabspec -- vocab )
    dup "-remote" append [ 
       [ (( -- words )) [ "get-words" remote-quot ] keep call-effect ] 2keep
       [ rot first2 swap define-remote ] 2curry each
-   ] with-in ;
\ No newline at end of file
+   ] with-in-vocab ;
\ No newline at end of file
index 894075acf8eafe12e8f65ea42b10582800a20f02..a0adca2646482fc36a6274168c55967775fd3d09 100644 (file)
@@ -1,4 +1,4 @@
-USING: modules.using ;
+QUALIFIED-WITH: modules.using m
 IN: modules.using.tests
-USING: tools.test localhost::modules.test-server ;
+m:USING: tools.test localhost::modules.test-server ;
 [ "hello world" ] [ rpc-hello ] unit-test
\ No newline at end of file
index c78e54652515e4bf082039847d6aefb0ac3f2c7d..15f99964d8fcff74406ffc5f731cb56af0f023c4 100644 (file)
@@ -1,4 +1,5 @@
-USING: modules.using modules.rpc-server help.syntax help.markup strings ;
+USING: modules.rpc-server help.syntax help.markup strings ;
+QUALIFIED-WITH: modules.using m
 IN: modules
 
 HELP: service
@@ -6,7 +7,7 @@ HELP: service
 { $description "Starts a server for requests for remote procedure calls." } ;
 
 ARTICLE: { "modules" "remote-loading" } "Using the remote-loading vocabulary"
-"If loaded, starts serving vocabularies, accessable through a " { $link POSTPONE: USING: } " form" ;
+"If loaded, starts serving vocabularies, accessable through a " { $link POSTPONE: m:USING: } " form" ;
 
 HELP: USING:
 { $syntax "USING: rpc-server::module fetch-sever::module { module qualified-name } { module => word ... } ... ;" }
index b0891aa391b8aa6734c9ddec241914cae6e72536..57bf3c67cde15907e1465189507f3660c9910576 100644 (file)
@@ -1,4 +1,4 @@
-USING: assocs kernel modules.remote-loading modules.rpc
+USING: accessors assocs kernel modules.remote-loading modules.rpc
 namespaces peg peg.ebnf peg-lexer sequences vocabs vocabs.parser
 strings ;
 IN: modules.using
@@ -9,9 +9,9 @@ IN: modules.using
 : >partial-vocab ( words assoc -- assoc )
     [ dupd at [ no-word-error ] unless* ] curry { } map>assoc ;
 
-: remote-load ( addr vocabspec -- voab ) [ "modules.remote-loading" remote-vocab (use+) ] dip get-vocab ;
+: remote-load ( addr vocabspec -- voab ) [ "modules.remote-loading" remote-vocab use-vocab ] dip get-vocab ;
 
-: load'em ( vocab words/? -- ) [ swap >partial-vocab ] when* use get push ;
+: load'em ( vocab words/? -- ) [ swap >partial-vocab ] when* manifest get qualified-vocabs>> push ;
 
 EBNF: modulize
 tokenpart = (!(':').)+ => [[ >string ]]
@@ -30,7 +30,7 @@ qualified = modspec sym => [[ first2 >qualified ]]
 unqualified = modspec => [[ vocab-words ]]
 words = ("=>" sym+ )? => [[ [ f ] [ second ] if-empty ]]
 long = "{" ( qualified | unqualified ) words "}" => [[ rest first2 load'em ignore ]]
-short = modspec => [[ use+ ignore ]]
+short = modspec => [[ use-vocab ignore ]]
 wordSpec = long | short
 using = wordSpec+ ";" => [[ drop ignore ]]
 ;ON-BNF
\ No newline at end of file