diff options
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.tex | 451 |
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 |