summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex')
-rw-r--r--Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex451
1 files changed, 451 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex
new file mode 100644
index 00000000000..e80d3ac06bb
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/pgf/modules/pgfmoduleoo.code.tex
@@ -0,0 +1,451 @@
+% Copyright 2006 by Till Tantau
+%
+% This file may be distributed and/or modified
+%
+% 1. under the LaTeX Project Public License and/or
+% 2. under the GNU Public License.
+%
+% See the file doc/generic/pgf/licenses/LICENSE for more details.
+
+\ProvidesFileRCS $Header: /cvsroot/pgf/pgf/generic/pgf/modules/pgfmoduleoo.code.tex,v 1.8 2010/02/22 22:49:21 tantau Exp $
+
+
+
+% Support of object-oriented programming in TeX.
+
+
+% The oo support works as follows:
+%
+% The main supported concepts are classes, objects, methods,
+% attributes and signal/slots. A class defines a set of methods, which are,
+% in the end, just normal TeX macros. Once a class has been created,
+% it can be instantiated by calling the \pgfoonew command, resulting
+% in a new object. Objects are local to their group. Given an object,
+% you can send it a message, resulting in the method code of the
+% object's method to be executed. While an object exists, it has a set
+% of attributes whose values can change over time. Attributes values
+% are not local to TeX groups, rather their life-cycle is the same as
+% the object's (which, however, is local to the group in which the
+% object was declared).
+%
+% The implementation is as follows: There is an ID counter that is
+% increased each time an object is created. This counter is local to
+% the group, which means that when a group ends the counter will
+% revert to the previous value, allowing objects to the reused in
+% subsequent groups.
+%
+% A method is just a normal \TeX macro, but to call it you write
+% \objecthandle.methodname(parameters). The \objecthandle is a macro
+% that is created when you say \pgfoonew. The special object
+% \pgfoothis is the current object.
+%
+% Attributes are stored globally in internal TeX macros whose name is
+% composed of the object number and the attribute name.
+
+
+
+
+% Declares a class
+%
+% #1 = class name
+% #2 = methods
+%
+% Description:
+%
+% This command declares a class for futurue use. Inside #2, the macro
+% \method can be used to declare a method. The \method macro takes a
+% method name, parameters (methods are normal TeX macros, after all)
+% and body.
+
+\long\def\pgfooclass#1#2{%
+ \def\pgfoo@classname{#1}%
+ \let\pgfoo@origmethod=\method%
+ \let\pgfoo@origattribute=\attribute%
+ \let\method=\pgfoo@declaremethod%
+ \let\attribute=\pgfoo@declareattribute%
+ \let\pgfoo@attribute@collection=\pgfutil@empty%
+ \let\pgfoo@attribute@collection@gc=\pgfutil@empty%
+ #2%
+ % Attribute initializer:
+ \expandafter\let\csname pgfooY\pgfoo@classname.@pgfooinit\endcsname\pgfoo@attribute@collection%
+ \expandafter\let\csname pgfooY\pgfoo@classname.@pgfoogc\endcsname\pgfoo@attribute@collection@gc%
+ % Always persent methods:
+ \expandafter\let\csname pgfooY\pgfoo@classname.get handle\endcsname\pgfoo@obj%
+ \expandafter\let\csname pgfooY\pgfoo@classname.get id\endcsname\pgfoo@id%
+ \let\method=\pgfoo@origmethod%
+ \let\attribute=\pgfoo@origattribute%
+}
+
+
+
+% Declare a method
+%
+% Description:
+%
+% Defines a method. To use/invoke this method for an object \object,
+% you write \object.methodname(parameters). This will cause the method
+% body to be invoked with the argument "(parameters)".
+%
+% To define the method \method should be directly followed by the
+% method name and, then, by (, followed by a parameter pattern,
+% followed by ), followed by the message body. Spaces are allowed only
+% after "\method" and after the closing ).
+%
+% Example:
+%
+% \pgfooclass{MyPlot}{
+%
+% \attribute x=0;
+% \attribute y=0;
+%
+% \method MyPlot() {
+% }
+%
+% \method getX(#1) {
+% \pgfooget{x}{#1}
+% }
+%
+% \method setPoint(#1,#2) {
+% \pgfooset{x}{#1}
+% \pgfooset{y}{#2}
+% }
+% }
+
+\def\pgfoo@declaremethod#1(#2)#3{%
+ \expandafter\long\expandafter\def\csname pgfooY\pgfoo@classname.#1\endcsname(#2){#3}%
+}
+
+
+% Declare an attribute
+%
+% #1 = attribute name
+% #2 = optional default value
+%
+% Description:
+%
+% Declares the attribute #1 for the current class. If the attribute
+% name is followed by =, the text following the equal sign is the
+% default value.
+
+\def\pgfoo@declareattribute#1;{%
+ \pgfutil@in@{ =}{#1}%
+ \ifpgfutil@in@%
+ \pgfoo@declareunpackspace#1;%
+ \else%
+ \pgfutil@in@={#1}%
+ \ifpgfutil@in@%
+ \pgfoo@declareunpack#1;%
+ \else%
+ \expandafter\def\expandafter\pgfoo@attribute@collection\expandafter{\pgfoo@attribute@collection\pgfoolet{#1}\pgfutil@empty}%
+ \expandafter\def\expandafter\pgfoo@attribute@collection@gc\expandafter{\pgfoo@attribute@collection@gc\pgfoolet{#1}\relax}%
+ \fi%
+ \fi%
+}
+\def\pgfoo@declareunpack#1=#2;{%
+ \expandafter\def\expandafter\pgfoo@attribute@collection\expandafter{\pgfoo@attribute@collection\pgfooset{#1}{#2}}%
+ \expandafter\def\expandafter\pgfoo@attribute@collection@gc\expandafter{\pgfoo@attribute@collection@gc\pgfoolet{#1}\relax}%
+}
+\def\pgfoo@declareunpackspace#1 =#2;{%
+ \expandafter\def\expandafter\pgfoo@attribute@collection\expandafter{\pgfoo@attribute@collection\pgfooset{#1}{#2}}%
+ \expandafter\def\expandafter\pgfoo@attribute@collection@gc\expandafter{\pgfoo@attribute@collection@gc\pgfoolet{#1}\relax}%
+}
+
+
+\newcount\pgfoo@objectcount
+\newcount\pgfoothis@count
+
+% The attribute value method
+%
+% #1 = attr
+%
+% This method inserts the current value of the given attribute for the
+% current object.
+
+\def\pgfoovalueof#1{%
+ \csname pgfooX\the\pgfoothis@count @#1\endcsname%
+}
+
+
+% The attribute get method
+%
+% #1 = attr
+% #2 = macro
+%
+% This method makes the macro equal to the current value of the
+% attribute for the current object.
+
+\def\pgfooget#1#2{%
+ \expandafter\let\expandafter#2\csname pgfooX\the\pgfoothis@count @#1\endcsname%
+}
+
+
+% The attribute set method
+%
+% #1 = attr
+% #2 = value
+%
+% This method sets the given attribute for the current object to the
+% given value.
+
+\long\def\pgfooset#1#2{%
+ \expandafter\gdef\csname pgfooX\the\pgfoothis@count @#1\endcsname{#2}%
+}
+
+
+% The attribute set method (expanded version)
+%
+% #1 = attr
+% #2 = value
+%
+% This method sets the given attribute for the current object to the
+% expanded version of the given value.
+
+\long\def\pgfooeset#1#2{%
+ \expandafter\xdef\csname pgfooX\the\pgfoothis@count @#1\endcsname{#2}%
+}
+
+
+% The attribute let method
+%
+% #1 = attr
+% #2 = value
+%
+% This method sets the given attribute for the current object to the
+% given value using \let.
+
+\def\pgfoolet#1#2{%
+ \expandafter\global\expandafter\let\csname pgfooX\the\pgfoothis@count @#1\endcsname#2%
+}
+
+
+% Add something to an attribute at the end
+%
+% #1 = attr
+% #2 = code
+%
+% This method adds the give code to the attr at the end.
+
+\def\pgfooappend#1#2{%
+ \expandafter\expandafter\expandafter\def%
+ \expandafter\expandafter\expandafter\pgf@oo@temp\expandafter\expandafter\expandafter{\csname pgfooX\the\pgfoothis@count @#1\endcsname#2}%
+ \expandafter\global\expandafter\let\csname pgfooX\the\pgfoothis@count @#1\endcsname\pgf@oo@temp%
+}
+
+
+% Add something to an attribute at the beginning
+%
+% #1 = attr
+% #2 = code
+%
+% This method adds the give code to the attr at the beginning.
+
+\def\pgfooprefix#1#2{%
+ \pgfooget{#1}\pgf@oo@temp%
+ \def\pgf@oo@@temp{#2}%
+ \expandafter\expandafter\expandafter\def%
+ \expandafter\expandafter\expandafter\pgf@oo@temp%
+ \expandafter\expandafter\expandafter{\expandafter\pgf@oo@@temp\pgf@oo@temp}%
+ \pgfoolet{#1}\pgf@oo@temp%
+}
+
+
+
+% Instantiate an object
+%
+% Possible syntax:
+%
+% 1) \pgfoonew new <class name>(<constructor parameters)
+% 2) \pgfoonew \<objectname>=new <class name>(<constructor parameters)
+% 3) \pgfoonew{attribute}=new <class name>(<constructor parameters)
+%
+% Description:
+%
+% Creates an object. After the object has been created, the method
+% called <class name> (the constructor) is invoked. If the
+% \<objectname>= part is present, the macro is assigned to the newly
+% created object.
+
+\def\pgfoonew{%
+ \pgfutil@ifnextchar n{%
+ \pgfoo@new\pgfoo@dummy=%
+ }{%
+ \pgfutil@ifnextchar\bgroup{%
+ \pgfoo@new@attribute%
+ }{%
+ \pgfoo@new%
+ }%
+ }%
+}
+\def\pgfoo@new#1=new #2(#3){%
+ \expandafter\ifx\csname pgfooY#2.get id\endcsname\relax%
+ \PackageError{pgfoo}{Unknown class '#2'}{}%
+ \else%
+ \advance\pgfoo@objectcount by 1\relax%
+ \edef\pgfoolastobj{\noexpand\pgfoo@caller{\the\pgfoo@objectcount}}%
+ \expandafter\gdef\csname pgfooX\the\pgfoo@objectcount @class\endcsname{#2}%
+ \let#1\pgfoolastobj%
+ {%
+ \pgfoothis@count\pgfoo@objectcount%
+ \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.@pgfooinit\endcsname%
+ }%
+ \pgfoolastobj.#2(#3)%
+ \aftergroup\pgfoogc% cleanup after group
+ \fi%
+}
+\def\pgfoo@new@attribute#1=new #2(#3){%
+ \pgfoo@new\pgf@oo@temp=new #2(#3)%
+ \pgfoolet{#1}\pgf@oo@temp%
+}
+
+
+\def\pgfoo@caller#1.#2(#3){%
+ \def\pgf@marshal{%
+ \pgfoothis@count=#1\relax%
+ \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.#2\endcsname(#3)%
+ }%
+ \expandafter\pgf@marshal\expandafter\pgfoothis@count\the\pgfoothis@count\relax%
+}
+\let\pgfoo@orig@caller=\pgfoo@caller
+
+% The special "this" object
+
+\def\pgfoothis.#1(#2){%
+ \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.#1\endcsname(#2)%
+}
+
+
+
+
+
+% Get the object id
+%
+% #1 = macro to store the id
+%
+% Description:
+%
+% This special method allows you to access the object id. You can then
+% use \pgfoocall to call a method using this id. This is mainly useful
+% when you wish to store the id for a longer time.
+
+\def\pgfoo@id(#1){%
+ \edef#1{\the\pgfoothis@count}%
+}
+
+% Yields the object with the given id
+%
+% #1 = id
+%
+% Description:
+%
+% Given an object id, \pgfooobj{<id>} will yield the object having
+% this id.
+
+\def\pgfooobj#1{%
+ \pgfoo@caller{#1}%
+}
+
+
+% Get the object
+%
+% #1 = macro to store the object
+%
+% Description:
+%
+% This special method allows you to get a new handle to a given
+% object. If \obj is an object, you could normally just say
+% \let#1=\obj. However, if \obj happens to be \pgfoothis, then you may
+% wish to get a handle to the object itself, not to the special macro
+% \pgfoothis. In this case you can say \obj.get handle(#1).
+
+\def\pgfoo@obj(#1){%
+ \edef#1{\noexpand\pgfoo@caller{\the\pgfoothis@count}}%
+}
+
+
+
+% The garbage collector
+%
+% Description:
+%
+% This method frees space ocupied by unused objects. Garbage are
+% objects that have been destroyed because of the end of the scope in
+% which they were created. In this case, however, the memory used by
+% this object is not immediately reused because the attributes of the
+% object are actually stored in global variables. When the garbage
+% collector is called, it will set all these global variables to
+% \relax, thereby ensuring that no memory is needed for them.
+
+\def\pgfoogc{%
+ {%
+ % We do this in a group...
+ \pgfoothis@count\pgfoo@objectcount% this is temporary...
+ \let\pgfoo@next=\pgfoo@dogc%
+ \pgfoo@next%
+ }%
+}
+\def\pgfoo@dogc{%
+ \advance\pgfoothis@count by 1\relax%
+ \expandafter\ifx\csname pgfooX\the\pgfoothis@count @class\endcsname\relax%
+ \let\pgfoo@next=\relax%
+ \else%
+ % Cleanup this object:
+ % The following is the fast version of \pgfooobj{\the\pgfoo@objectcount}.@pgfoogc:
+ \csname pgfooY\csname pgfooX\the\pgfoothis@count @class\endcsname.@pgfoogc\endcsname%
+ \expandafter\global\expandafter\let\csname pgfooX\the\pgfoothis@count @class\endcsname\relax%
+ \fi%
+ \pgfoo@next%
+}
+
+
+
+
+%
+%
+% Signal class
+%
+%
+
+\pgfooclass{signal}
+{
+ %
+ % This class implements signals.
+ %
+ % After you have created a signal object, you can call
+ % connect to connect a slot. Then, whenever the emit method is
+ % called, all connected methods get called.
+
+ % Attribute
+ \attribute emitter;
+ % Collects the objects that should be called.
+
+ % Constructor
+ \method signal() {}
+
+ % Connect a slot (method) #2 of object #1
+ \method connect(#1,#2) {%
+ {%
+ #1.get id(\pgf@tempid)%
+ % Save in emmiter
+ \pgfooget{emitter}\pgf@temp%
+ \let\pgfoo@signal@call=\relax% avoid expansion
+ \edef\pgf@temp{\pgf@temp\pgfoo@signal@call{\pgf@tempid}{#2}}%
+ \pgfoolet{emitter}\pgf@temp%
+ }%
+ }
+
+ \def\pgfoo@signal@call#1#2{%
+ \def\pgf@temp{\pgfooobj{#1}.#2}%
+ \expandafter\pgf@temp\expandafter(\pgfoo@signal@args)%
+ }
+
+ % Emit a signal
+ \method emit(#1) {%
+ \def\pgfoo@signal@args{#1}%
+ \pgfoovalueof{emitter}
+ }
+}
+
+
+
+
+\endinput