1 USING: help.syntax help.markup kernel math classes classes.tuple
2 calendar sequences growable ;
6 { $class-description "A mutable cell holding a single value. When the value is changed, a sequence of connected objects are notified. Models have the following slots:"
8 { "value" { "the value of the model. Use " { $link set-model } " to change the value." } }
9 { "connections" { "a sequence of objects implementing the " { $link model-changed } " generic word, to be notified when the model's value changes." } }
10 { "dependencies" { "a sequence of models which should have this model added to their sequence of connections when activated." } }
11 { "ref" { "a reference count tracking the number of models which depend on this one." } }
12 { "locked?" { "a slot set by " { $link with-locked-model } " to ensure that the model doesn't get changed recursively" } }
14 "Other classes may inherit from " { $link model } "."
18 { $values { "value" object } { "model" "a new " { $link model } } }
19 { $description "Creates a new model with an initial value." } ;
22 { $values { "dep" model } { "model" model } }
23 { $description "Registers a dependency. When " { $snippet "model" } " is activated, it will be added to " { $snippet "dep" } "'s connections and notified when " { $snippet "dep" } " changes." }
24 { $notes "This word should not be called directly unless you are implementing your own model class." } ;
26 { add-dependency remove-dependency activate-model deactivate-model } related-words
28 HELP: remove-dependency
29 { $values { "dep" model } { "model" model } }
30 { $description "Unregisters a dependency." }
31 { $notes "This word should not be called directly unless you are implementing your own model class." } ;
34 { $values { "model" model } }
35 { $contract "Called after a model has been activated." } ;
37 { model-activated activate-model deactivate-model } related-words
40 { $values { "model" model } }
41 { $description "Increments the reference count of the model. If it was previously zero, this model is added as a connection to all models registered as dependencies by " { $link add-dependency } "." }
42 { $warning "Calls to " { $link activate-model } " and " { $link deactivate-model } " should be balanced to keep the reference counting consistent, otherwise " { $link model-changed } " might be called at the wrong time or not at all." } ;
44 HELP: deactivate-model
45 { $values { "model" model } }
46 { $description "Decrements the reference count of the model. If it reaches zero, this model is removed as a connection from all models registered as dependencies by " { $link add-dependency } "." }
47 { $warning "Calls to " { $link activate-model } " and " { $link deactivate-model } " should be balanced to keep the reference counting consistent, otherwise " { $link model-changed } " might be called at the wrong time or not at all." } ;
50 { $values { "model" model } { "value" object } }
51 { $description "Activate and immediately deactivate the model, forcing recomputation of its value, which is returned. If the model is already activated, no dependencies are recalculated. Useful when using models outside of gadget context or for testing." } ;
54 { $values { "model" model } { "observer" object } }
55 { $contract "Called to notify observers of a model that the model value has changed as a result of a call to " { $link set-model } ". Observers can be registered with " { $link add-connection } "." } ;
57 { add-connection remove-connection model-changed } related-words
60 { $values { "observer" object } { "model" model } }
61 { $contract "Registers an object interested in being notified of changes to the model's value. When the value is changed as a result of a call to " { $link set-model } ", the " { $link model-changed } " word is called on the observer." } ;
63 HELP: remove-connection
64 { $values { "observer" object } { "model" model } }
65 { $contract "Unregisters an object no longer interested in being notified of changes to the model's value." } ;
68 { $values { "model" model } }
69 { $description "Notifies the model that its " { $slot "value" } " slot has been updated by " { $link set-model } "." } ;
72 { $values { "value" object } { "model" model } }
73 { $description "Changes the value of a model, calls " { $link update-model } " to notify it, then calls " { $link model-changed } " on all observers registered with " { $link add-connection } "." } ;
76 { $values { "value" object } { "model" model } }
77 { $description "Similar to " { $link set-model } ", but only sets the value if the new value is different." } ;
79 { set-model ?set-model change-model change-model* (change-model) push-model pop-model } related-words
82 { $values { "model" model } { "quot" { $quotation ( ..a obj -- ..b newobj ) } } }
83 { $description "Applies the quotation to the current value of the model to yield a new value, then changes the value of the model to the new value, and calls " { $link model-changed } " on all observers registered with " { $link add-connection } "." } ;
86 { $values { "model" model } { "quot" { $quotation ( ..a obj -- ..b ) } } }
87 { $description "Applies the quotation to the current value of the model and calls " { $link model-changed } " on all observers registered with " { $link add-connection } " without actually changing the value of the model. This is useful for notifying observers of operations that mutate a value, as in " { $link push-model } " and " { $link pop-model } "." } ;
90 { $values { "model" model } { "quot" { $quotation ( ..a obj -- ..b newobj ) } } }
91 { $description "Applies the quotation to the current value of the model to yield a new value, then changes the value of the model to the new value without notifying any observers registered with " { $link add-connection } "." }
92 { $notes "There are very few reasons for user code to call this word. Instead, call " { $link change-model } ", which notifies observers." } ;
95 { $values { "value" object } { "model" model } }
96 { $description { $link push } "es " { $snippet "value" } " onto the " { $link growable } " sequence stored as the value of " { $snippet "model" } " and calls " { $link model-changed } " on all observers registered for the model with " { $link add-connection } "." } ;
99 { $values { "model" model } { "value" object } }
100 { $description { $link pop } "s the topmost " { $snippet "value" } " off of the " { $link growable } " sequence stored as the value of " { $snippet "model" } " and calls " { $link model-changed } " on all observers registered for the model with " { $link add-connection } "." } ;
103 { $values { "model" model } { "value" object } }
104 { $contract "Outputs the current value of a range model." } ;
106 HELP: range-page-value
107 { $values { "model" model } { "value" object } }
108 { $contract "Outputs the page size of a range model." } ;
110 HELP: range-min-value
111 { $values { "model" model } { "value" object } }
112 { $contract "Outputs the minimum value of a range model." } ;
114 HELP: range-max-value
115 { $values { "model" model } { "value" object } }
116 { $contract "Outputs the maximum value of a range model." } ;
118 HELP: range-max-value*
119 { $values { "model" model } { "value" object } }
120 { $contract "Outputs the slider position for a range model. Since the bottom of the slider cannot exceed the maximum value, this is equal to the maximum value minus the page size." } ;
122 HELP: set-range-value
123 { $values { "value" object } { "model" model } }
124 { $description "Sets the current value of a range model." }
125 { $side-effects "model" } ;
127 HELP: set-range-page-value
128 { $values { "value" object } { "model" model } }
129 { $description "Sets the page size of a range model." }
130 { $side-effects "model" } ;
132 HELP: set-range-min-value
133 { $values { "value" object } { "model" model } }
134 { $description "Sets the minimum value of a range model." }
135 { $side-effects "model" } ;
137 HELP: set-range-max-value
138 { $values { "value" object } { "model" model } }
139 { $description "Sets the maximum value of a range model." }
140 { $side-effects "model" } ;
142 ARTICLE: "models" "Models"
143 "The " { $vocab-link "models" } " vocabulary provides basic support for dataflow programming. A model is an observable value. Changing a model's value notifies other objects which depend on the model automatically, and models may depend on each other's values."
145 "The class of models:"
146 { $subsections model }
148 { $subsections <model> }
149 "Adding and removing connections:"
154 "Generic word called on model connections when the model value changes:"
155 { $subsections model-changed }
156 "When using models which are not associated with controls (or when unit testing controls), you must activate and deactivate models manually:"
167 ARTICLE: "models-impl" "Implementing models"
168 "New types of models can be defined, for example see " { $vocab-link "models.arrow" } "."
170 "Models can execute hooks when activated:"
171 { $subsections model-activated }
172 "To avoid recursive updating and do proper notifications, you should set the model values via:"
173 { $subsections set-model }
174 "Models are notified when their values are changed:"
175 { $subsections update-model } ;