summaryrefslogtreecommitdiff
path: root/graphics/metapost/contrib/macros/metauml
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/metapost/contrib/macros/metauml
Initial commit
Diffstat (limited to 'graphics/metapost/contrib/macros/metauml')
-rw-r--r--graphics/metapost/contrib/macros/metauml/README19
-rw-r--r--graphics/metapost/contrib/macros/metauml/doc/metauml-manual-v0.2.6-19d34de3da75cbd9f814f0a9ec03b4e0861b1541.pdfbin0 -> 413691 bytes
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity.mp52
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity_diagrams.mp59
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/appetizer.mp203
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/boxes_vs_util.mp92
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/class.mp134
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_association.mp72
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization.mp94
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization2.mp31
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_diagrams.mp212
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_templates.mp29
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/component.mp61
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/group.mp51
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/how-links-work.mp38
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/instance.mp9
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/mptextmp.mp1
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/note.mp74
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/object_stack.mp46
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/package.mp93
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths.mp132
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths_man.mp143
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_info.mp86
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_stack.mp44
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/positioning.mp139
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/properties.mp58
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/state.mp55
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/statemachine_diagrams.mp78
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_activity.mp46
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class.mp156
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_feature_types.mp53
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_qual_assoc.mp53
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_templates.mp62
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_component.mp30
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_font.mp81
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_group.mp60
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_instance.mp35
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lars_issues.mp94
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lowlevel.mp66
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_note.mp39
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_package.mp54
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_paths.mp100
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture.mp273
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_stack.mp130
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_tex_rendering.mp43
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_positioning.mp195
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins.mp26
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins_global_defaults.mp29
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_state.mp73
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_usecase.mp185
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase.mp43
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase_diagrams.mp48
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.bib64
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.tex2072
-rw-r--r--graphics/metapost/contrib/macros/metauml/examples/manual/test-suite.tex82
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml.mp66
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_activity.mp229
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_base.mp171
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_behavioral_common.mp214
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_class.mp485
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_class_assoc.mp93
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_class_relations.mp172
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_component.mp186
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_component_relations.mp55
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_defaults.mp31
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_instance.mp186
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_links.mp86
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_note.mp140
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_package.mp176
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_package_relations.mp37
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_paths.mp173
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_skin_simple.mp28
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_state.mp201
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_stereotype.mp25
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_templates.mp132
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase.mp215
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase_clipart.mp158
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_commons.mp137
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_group.mp181
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_infrastructure.mp56
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_log.mp31
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_margins.mp21
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_object.mp233
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_picture.mp285
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_picture_stack.mp153
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_positioning.mp242
-rw-r--r--graphics/metapost/contrib/macros/metauml/inputs/util_shade.mp53
87 files changed, 10948 insertions, 0 deletions
diff --git a/graphics/metapost/contrib/macros/metauml/README b/graphics/metapost/contrib/macros/metauml/README
new file mode 100644
index 0000000000..f646504337
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/README
@@ -0,0 +1,19 @@
+MetaUML https://github.com/ogheorghies/MetaUML
+
+Version: 0.2.6
+Author : Ovidiu Gheorghies
+Date : February 02, 2019
+
+MetaUML is a MetaPost library for creating UML diagrams using a textual notation.
+It offers partial support for:
+- class diagrams
+- package diagrams
+- activity diagrams
+- use case diagrams
+- state machine diagrams
+
+This release contains the following directories:
+
+doc : PDF documentation
+examples : source code for the documentation
+inputs : the macros needed to use MetaUML \ No newline at end of file
diff --git a/graphics/metapost/contrib/macros/metauml/doc/metauml-manual-v0.2.6-19d34de3da75cbd9f814f0a9ec03b4e0861b1541.pdf b/graphics/metapost/contrib/macros/metauml/doc/metauml-manual-v0.2.6-19d34de3da75cbd9f814f0a9ec03b4e0861b1541.pdf
new file mode 100644
index 0000000000..30c8ae4f5f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/doc/metauml-manual-v0.2.6-19d34de3da75cbd9f814f0a9ec03b4e0861b1541.pdf
Binary files differ
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity.mp
new file mode 100644
index 0000000000..676d1996eb
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity.mp
@@ -0,0 +1,52 @@
+% Sample MetaUML figures.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+input metauml;
+
+beginfig(1);
+ Begin.b;
+ End.e;
+ FlowFinal.f;
+
+ leftToRight(20)(b, e, f);
+
+ drawObjects(b, e, f);
+endfig;
+
+beginfig(2);
+ Activity.A("Learn MetaUML -",
+ "the MetaPost UML library");
+ drawObject(A);
+endfig;
+
+beginfig(3);
+ Fork.forkA("h", 50);
+ Fork.forkB("v", 20);
+
+ leftToRight(10)(forkA, forkB);
+
+ drawObjects(forkA, forkB);
+endfig;
+
+beginfig(4);
+ Branch.testA;
+
+ drawObject(testA);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity_diagrams.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity_diagrams.mp
new file mode 100644
index 0000000000..0807619acd
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/activity_diagrams.mp
@@ -0,0 +1,59 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+% for f in `find . | grep '.*\.[1-9]'`; do echo $f; done
+
+input metauml;
+
+beginfig(1);
+ Begin.b;
+ Activity.eat("Eat something good", "from the kitchen");
+ Branch.enough;
+ Fork.fork("h", 50);
+ Activity.read("Read a book");
+ Activity.listen("Listen to music", "(and ignore it)");
+ Fork.join("h", 50);
+ End.e;
+
+ eat.n = b.s + (0,-20);
+ enough.n = eat.s + (0,-20);
+ fork.n = enough.s + (0, -20);
+
+ read.top = listen.top = fork.bottom - 30;
+ listen.left - read.right = 10;
+ b.midx = .5[listen.left, read.right];
+
+ join.n = (b.midx, listen.bottom - 20);
+ e.n = join.s + (0, -20);
+
+ drawObjects(b, eat, enough, fork, read, listen, join, e);
+
+ clink(transition)(b, eat);
+ clink(transition)(eat, enough);
+ link(transition)(pathStepX(enough.w, eat.w, -80));
+ clink(transition)(enough, fork);
+ clink(transition)(fork, read);
+ clink(transition)(fork, listen);
+ clink(transition)(read, join);
+ clink(transition)(listen, join);
+ clink(transition)(join, e);
+
+ item(iGuard)("still hungry")(obj.se = enough.w + (-20, 0));
+ item(iGuard)("had enough")(obj.nw = enough.s + (0, -4));
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/appetizer.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/appetizer.mp
new file mode 100644
index 0000000000..ed90dc77dc
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/appetizer.mp
@@ -0,0 +1,203 @@
+% Sample MetaUML figures.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ Class.Client("Client")()();
+
+ Class._Component("Component")()();
+ %("+Operation()", "+Add(Component)", "+Remove(Component)", "+GetChild(int)");
+ classStereotype._Component("<<interface>>");
+
+ Class.Leaf("Leaf")()("+Operation()");
+
+ Class.Composite("Composite")()();
+ %("+Operation()", "+Add(Component)", "+Remove(Component)", "+GetChild(int)");
+
+ leftToRight.top(30)(Client, _Component);
+ leftToRight.top(20)(Leaf, Composite);
+ .5[Leaf.ne, Composite.nw] = below(_Component.s, 45);
+
+ drawObjects(Client, _Component, Leaf, Composite);
+
+ link(associationUni)(pathHorizontal(Client.e, _Component.left));
+ link(inheritance)(pathStepY(Leaf.n, _Component.s, 20));
+ link(inheritance)(pathStepY(Composite.n, _Component.s, 20));
+
+ link(aggregationUni)(pathStepX(_Component.e, Composite.e, 55));
+endfig;
+
+beginfig(2);
+ Begin.b;
+ Activity.eat("Eat something good", "from the kitchen");
+ Branch.enough;
+ Fork.fork("h", 50);
+ Activity.read("Read a book");
+ Activity.listen("Listen to music", "(and ignore it)");
+ Fork.join("h", 50);
+ End.e;
+
+ leftToRight.top(10)(read, listen);
+ Group.readListen(read, listen);
+
+ leftToRight(30)(b, eat);
+ topToBottom(20)(eat, enough, fork, readListen, join, e);
+
+ drawObjects(b, eat, enough, fork, readListen, join, e);
+
+ clink(transition)(b, eat);
+ clink(transition)(eat, enough);
+ link(transition)(pathStepX(enough.e, eat.e, 80));
+ clink(transition)(enough, fork);
+ clink(transition)(fork, read);
+ clink(transition)(fork, listen);
+ clink(transition)(read, join);
+ clink(transition)(listen, join);
+ clink(transition)(join, e);
+
+ item(iGuard)("still hungry")(obj.sw = enough.e + (20, 0));
+ item(iGuard)("had enough")(obj.nw = enough.s + (0, -4));
+endfig;
+
+beginfig(3);
+ Actor.user("User");
+ Actor.db("Database");
+
+ Usecase.dbquery("Query database");
+ Usecase.auth("Authenticate user");
+ Usecase.authA("Authenticate by", "username, password");
+ Usecase.authB("Authenticate by", "smartcard");
+
+ leftToRight(30)(user.human, auth, dbquery, db.human);
+ leftToRight.top(30)(authA, authB);
+ .5[authA.ne, authB.nw] = below(auth.s, 20);
+
+ drawObjects(user, auth, dbquery, db, authA, authB);
+
+ clink(inheritance)(authA, auth);
+ clink(inheritance)(authB, auth);
+ clink(association)(auth, dbquery);
+ clink(association)(user.human, auth);
+ clink(association)(dbquery, db.human);
+endfig;
+
+beginfig(4);
+ save b, e, reading, processing, composite, exit, error, result, theEnd;
+
+ Begin.b;
+ State.reading("Reading commands")();
+ State.processing("Processing commands")();
+ End.e;
+
+ State.composite("Working")(b, reading, processing, e);
+ composite.info.left := composite.info.right := 10;
+ composite.info.drawNameLine := 1;
+
+ topToBottom(20)(b, reading, processing, e);
+ drawObject(composite);
+
+ clink(transition)(b, reading);
+ clink(transition)(reading, processing);
+ clink(transition)(processing, e);
+
+ ExitPoint.exit;
+ exit.c=(composite.right, reading.midy);
+ drawObject(exit);
+ item(iAssoc)("error")(obj.nw = exit.s);
+
+ clink(transition)(reading, exit);
+
+ State.error("Preparing error report")();
+ State.result("Writing result")();
+ End.theEnd;
+
+ topToBottom(20)(error, result, theEnd);
+ leftToRight(30)(exit, error);
+
+ drawObjects(error, result, theEnd);
+
+ clink(transition)(exit, error);
+ clink(transition)(error, result);
+ clink(transition)(result, theEnd);
+
+ link(transition)(rpathHorizontal(result.w, composite.right));
+endfig;
+
+
+beginfig(5);
+ save A, B;
+
+ Note.A("An important", "UML note");
+ Note.B("Another note");
+
+ leftToRight(20)(A, B);
+ drawObjects(A, B);
+
+ clink(dashedLink)(A, B);
+endfig;
+
+beginfig(6);
+ Class.A("A")()();
+ Class.B("B")()();
+
+ Package.pA("net.foo")();
+ Package.pB("net.foo.bar")(A, B);
+
+ leftToRight(20)(A, B);
+ leftToRight(50)(pA, pB);
+
+ drawObjects(A, B, pA, pB);
+
+ clink(nest)(pB, pA);
+endfig;
+
+beginfig(7);
+ save A;
+
+ Class.A("MyClass")
+ ("attr1: int", "attr2: int")
+ ("method1(): void",
+ "method2(): void");
+
+ A.nw = (0, 0); % optional, implied
+ drawObject(A);
+endfig;
+
+beginfig(8);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")()();
+
+ A.nw = (0,0);
+ B.w = A.e + (20, 0);
+
+ drawObjects(A, B);
+endfig;
+
+beginfig(9);
+ save A, B;
+
+ Class.A("A")()();
+ Class.B("B")()();
+ B.w = A.e + (20, 0);
+ drawObjects(A, B);
+ link(inheritance)(B.w -- A.e);
+endfig;
+end
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/boxes_vs_util.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/boxes_vs_util.mp
new file mode 100644
index 0000000000..985c9bb158
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/boxes_vs_util.mp
@@ -0,0 +1,92 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input boxes;
+input util_commons;
+input util_object;
+input util_picture;
+
+beginfig(1);
+ boxit.a ("yummy");
+ boxit.b ("cool");
+
+ a.nw = (0,0);
+ b.sw = a.se + (10,0);
+
+ drawboxed (a, b);
+ draw a.sw -- b.se dashed evenly withpen pencircle scaled 1.1;
+
+ boxit.c ("yummy");
+ boxit.d ("cool");
+
+ c.nw = (0,-20);
+ d.sw = c.se + (10,0);
+
+ drawunboxed (c, d);
+ draw c.sw -- d.se dashed evenly withpen pencircle scaled 1.1;
+endfig;
+
+beginfig(2);
+ save a, b, c, d;
+
+ Picture.a("yummy");
+ Picture.b("cool");
+ a.info.boxed := b.info.boxed := 1;
+
+ a.nw = (0,0);
+ b.sw = a.se + (10,0);
+
+ drawObjects(a, b);
+ draw a.sw -- b.se dashed evenly withpen pencircle scaled 1.1;
+
+ Picture.c("yummy");
+ Picture.d("cool");
+
+ c.nw = (0,-20);
+ d.sw = c.se + (10,0);
+
+ drawObjects(c, d);
+ draw c.sw -- d.se dashed evenly withpen pencircle scaled 1.1;
+endfig;
+
+beginfig(3);
+ save a, b, c, d;
+
+ iPict.ignoreNegativeBase := 1;
+
+ Picture.a("yummy");
+ Picture.b("cool");
+ a.info.boxed := b.info.boxed := 1;
+
+ a.nw = (0,0);
+ b.sw = a.se + (10,0);
+
+ drawObjects(a, b);
+ draw a.sw -- b.se dashed evenly withpen pencircle scaled 1.1;
+
+ Picture.c("yummy");
+ Picture.d("cool");
+
+ c.nw = (0,-20);
+ d.sw = c.se + (10,0);
+
+ drawObjects(c, d);
+ draw c.sw -- d.se dashed evenly withpen pencircle scaled 1.1;
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class.mp
new file mode 100644
index 0000000000..e5d03d3d43
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class.mp
@@ -0,0 +1,134 @@
+% Sample MetaUML figures.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+input metauml;
+
+beginfig(1);
+ Class.A("Point")
+ ("#x:int",
+ "#y:int")
+ ("+set(x:int, y:int)",
+ "+getX():int",
+ "+getY():int",
+ "-debug():void",
+ "test():void");
+ drawObject(A);
+endfig;
+
+beginfig(2);
+ save A, T;
+
+ Class.A("User")()();
+ Class_stereotypes.A("<<interface>>", "<<home>>");
+
+ drawObject(A);
+endfig;
+
+beginfig(3);
+ save A, T;
+
+ Class.A("Vector")()();
+ ClassTemplate.T("T", "size: int")(A);
+
+ drawObjects(A, T);
+endfig;
+
+beginfig(4);
+ link(association)( (0,0) -- (50,0) );
+endfig;
+
+beginfig(5);
+ link(associationUni)( (0,0) -- (50,0) );
+endfig;
+
+beginfig(6);
+ link(inheritance)( (0,0) -- (50,0) );
+endfig;
+
+beginfig(7);
+ link(aggregation)( (0,0) -- (50,0) );
+endfig;
+
+beginfig(8);
+ link(aggregationUni)( (0,0) -- (50,0) );
+endfig;
+
+beginfig(9);
+ link(composition)( (0,0) -- (50,0) );
+endfig;
+
+beginfig(10);
+ link(compositionUni)( (0,0) -- (50,0) );
+endfig;
+
+beginfig(11);
+ save A;
+ Interface.A("Observer")
+ ("+update(src:Object)");
+
+ drawObject(A);
+endfig;
+
+beginfig(12);
+ save A;
+ EClass.A(iAbstractClass)("Observable")
+ ("observers: Observer[0..*]")
+ ("+addObserver(o: Observer)",
+ "+notify()");
+
+ drawObject(A);
+endfig;
+
+beginfig(13)
+ save A;
+
+ Class.A("MyModel")()();
+ A.info.iName.top := 10;
+ A.info.iName.bottom := 10;
+ A.info.iAttributeStack.top := 0;
+ A.info.iAttributeStack.bottom := 0;
+ A.info.iMethodStack.top := 0;
+ A.info.iMethodStack.bottom := 0;
+
+ drawObject(A);
+endfig;
+
+beginfig(14)
+ save A, B;
+
+ EClass.A(iClassNameOnly)("MyModel")()();
+ ClassName.B("AnotherModel");
+ classStereotypes.B("<<smart>>");
+
+ topToBottom(20)(A, B);
+
+ drawObjects(A, B);
+endfig;
+
+beginfig(15);
+ save A;
+
+ Class.A("Point")
+ ("#x:int", "#y:int")
+ ("+toString():String");
+ Class_noVisibilityMarkers.A;
+
+ drawObject(A);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_association.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_association.mp
new file mode 100644
index 0000000000..2ff5037a8c
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_association.mp
@@ -0,0 +1,72 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ save P,B;
+
+ Class.P("Person")()();
+ Class.B("Bank")()();
+
+ P.nw = (0,0);
+ B.w = P.e + (50,0);
+
+ drawObjects(P, B);
+
+ drawRelation(association)(P.e -- B.w);
+
+ item.assocName(iAssoc)("works for")(assocName.s = .5[P.e,B.w]);
+
+ draw assocName.n -- (assocName.n + (20,20));
+ label.urt("association name" infont "tyxtt", assocName.n + (20,20));
+endfig;
+
+beginfig(2);
+ save P,C;
+
+ Class.P("Person")()();
+ Class.C("Company")()();
+
+ C.n = P.s + (0, -70);
+ drawObjects(P, C);
+
+ link(association)(P.s -- C.n);
+
+ item(iAssoc)("employee")(obj.nw = P.s);
+ item(iAssoc)("1..*")(obj.ne = P.s);
+
+ item(iAssoc)("employer")(obj.sw = C.n);
+ item(iAssoc)("0..*")(obj.se = C.n);
+
+ item(iAssoc)("works for")(obj.w = .5[P.s,C.n]);
+endfig;
+
+beginfig(3);
+ save F, O;
+
+ Class.F("Factory")()();
+ Class.O("Object")()();
+
+ O.n = F.s - (0, 50);
+ drawObjects(F, O);
+
+ clink(dependency)(F, O);
+ item(iStereo)("<<creates>>")(obj.w = .5[F.s,O.n])
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization.mp
new file mode 100644
index 0000000000..980915ea00
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization.mp
@@ -0,0 +1,94 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ iClass.foreColor := (.9, .9, 0);
+
+ Class.A("A")()();
+ Class.B("B")()();
+ Class.C("C")()();
+
+ B.w = A.e + (20,0);
+ C.n = .5[A.se, B.sw] + (0, -10);
+
+ drawObjects(A, B, C);
+endfig;
+
+beginfig(2);
+ save A, B, C;
+ iClass.foreColor := (.9, .9, 0);
+
+ Class.A("A")()();
+ Class.B("B")()();
+ Class.C("C")()();
+ C.info.foreColor := (.7, .7, .9);
+ C.info.borderColor := blue;
+ C.info.iName.iFont.scale := 2;
+
+ B.w = A.e + (20,0);
+ C.n = .5[A.se, B.sw] + (0, -10);
+
+ drawObjects(A, B, C);
+endfig;
+
+beginfig(3);
+ ClassInfoCopy.iHome(iClass);
+ iHome.foreColor := (0, .9, .9);
+
+ ClassInfo.iRemote;
+ iRemote.foreColor := (.9, .9, 0);
+ iRemote.borderColor := (0, 0, .9);
+
+ save A, B, C, D;
+
+ EClass.A(iHome)("UserHome")()();
+ EClass.B(iRemote)("UserRemote")()();
+ EClass.C(iHome)("CartHome")()();
+ EClass.D(iRemote)("CartRemote")()();
+
+
+ B.nw = A.ne + (20,0);
+ D.nw = C.ne + (20,0);
+ A.bottom - C.top = 10;
+ A.left = C.left;
+
+ drawObjects(A, B, C, D);
+endfig;
+
+beginfig(4);
+ iClass.foreColor := .9white;
+ save A;
+
+ Class.A("Foo")
+ ("a: int", "b: int")
+ ("foo()", "bar()", "gar()");
+ A.info.iName.iFont.name := metauml_defaultFontBold;
+ A.info.iName.iFont.scale := 1.2;
+
+ A.info.iAttributeStack.iPict.iFont.scale := 0.8;
+ A.info.iAttributeStack.top := 10;
+ A.info.iAttributeStack.spacing := 11;
+
+ A.info.iMethodStack.iPict.iFont.scale := 2;
+ A.info.iMethodStack.spacing := 17;
+ A.info.iMethodStack.bottom := 10;
+ drawObject(A);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization2.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization2.mp
new file mode 100644
index 0000000000..be45e95240
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_customization2.mp
@@ -0,0 +1,31 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ save Test;
+ Class.Test("TestClass")("attribute1: int","attribute2: double")
+ ("oneLongMethod(): void",
+ "anotherLongMethod(): void");
+
+ Test.nw = (0,0);
+ Class_draw.Test;
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_diagrams.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_diagrams.mp
new file mode 100644
index 0000000000..614cdbeca6
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_diagrams.mp
@@ -0,0 +1,212 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ Class.Count("Count")
+ ("#n: int")
+ ("+increase(): void",
+ "+get(): int");
+
+ %Count.nw = (0,0);
+ drawObject(Count);
+ %Class_draw.Count;
+endfig;
+
+beginfig(2);
+ Class.A("Point")
+ ("+x: int",
+ "+y: int") ();
+
+ Class.B("Circle")
+ ("radius: int")
+ ("+getRadius(): int",
+ "+setRadius(r: int):void");
+
+ A.nw = (0,0);
+ B.n = A.s - (0,45);
+ Class_draw.A;
+ Class_draw.B;
+
+ drawRelation(aggregationUni)(A.s -- B.n);
+endfig;
+
+beginfig(3);
+ Class.Test("Test")("a1","a2","a3")("aLongMethod():void");
+
+ Test.nw = (0,0);
+ Class_draw.Test;
+
+ dotlabel.ulft(btex nw etex, Test.nw);
+ dotlabel.top(btex n etex, Test.n);
+ dotlabel.urt(btex ne etex, Test.ne);
+ dotlabel.rt(btex e etex, Test.e);
+ dotlabel.lrt(btex se etex, Test.se);
+ dotlabel.bot(btex s etex, Test.s);
+ dotlabel.llft(btex sw etex, Test.sw);
+ dotlabel.lft(btex w etex, Test.w);
+
+ dotlabel.lft(btex c etex, Test.c);
+
+ draw Test.nw - (50,0) -- Test.ne + (10,0);
+ label.urt(btex top etex, Test.nw - (50,0));
+
+ draw Test.sw - (50,0) -- Test.se + (10,0);
+ label.lrt(btex bottom etex, Test.sw - (50,0));
+
+ draw Test.nw + (0,10) -- Test.sw - (0, 50);
+ label.bot(btex left etex, Test.sw - (0,50));
+
+ draw Test.ne + (0,10) -- Test.se - (0, 50);
+ label.bot(btex right etex, Test.se - (0,50));
+
+ drawarrow Test.nw - (25,0) -- Test.sw - (25,0);
+ label.lft(btex height etex, .5[Test.nw, Test.sw] - (25,0));
+
+ drawarrow Test.sw - (0,25) -- Test.se - (0,25);
+ label.bot(btex width etex, .5[Test.sw, Test.se] - (0,25));
+endfig;
+
+%newAssociationDescription.association;
+%newAssociationUniDescription.associationUni;
+%newInheritanceDescription.inheritance;
+%newAggregationDescription.aggregation;
+%newAggregationUniDescription.aggregationUni;
+%newCompositionDescription.composition;
+%newCompositionUniDescription.compositionUni;
+%newDashedLinkDescription.dashedLink;
+%newDependencyDescription.dependency;
+
+beginfig(4);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(association)(X.e -- Y.w);
+endfig;
+
+beginfig(5);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(associationUni)(X.e -- Y.w);
+endfig;
+
+beginfig(6);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(inheritance)(X.e -- Y.w);
+endfig;
+
+beginfig(7);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(aggregation)(X.e -- Y.w);
+endfig;
+
+beginfig(8);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(aggregationUni)(X.e -- Y.w);
+endfig;
+
+beginfig(9);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(composition)(X.e -- Y.w);
+endfig;
+
+beginfig(10);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(compositionUni)(X.e -- Y.w);
+endfig;
+
+beginfig(11);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(dependency)(X.e -- Y.w);
+endfig;
+
+beginfig(12);
+ save X, Y;
+ Class.X("X")()();
+ Class.Y("Y")()();
+
+ X.nw = (0,0);
+ Y.w = X.e + (50,0);
+ Class_draw.X;
+ Class_draw.Y;
+
+ drawRelation(realization)(X.e -- Y.w);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_templates.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_templates.mp
new file mode 100644
index 0000000000..bf89f9d3cd
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/class_templates.mp
@@ -0,0 +1,29 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ Class.V("Vector")("elements: T(n)")();
+ Template.T("T", "n: int");
+ Template_attachToClass.T(V);
+
+ drawObjects(V);
+ drawObjects(T);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/component.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/component.mp
new file mode 100644
index 0000000000..da46c9d346
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/component.mp
@@ -0,0 +1,61 @@
+input metauml;
+
+beginfig(1);
+ Component.C("Business Logic")();
+ drawObject(C);
+endfig;
+
+beginfig(2);
+ save A, B, C, BigC;
+
+ Class.A("A")()();
+ Package.B("B")();
+ Component.C("C")();
+
+ Component.BigC("Big Component")(A, B, C);
+
+ leftToRight(10)(A, B);
+ topToBottom(10)(A, C);
+
+ drawObject(BigC);
+endfig;
+
+beginfig(3);
+ save A, B;
+ Component.A("A")();
+ Component.B("B")();
+
+ leftToRight(80)(A, B);
+
+ drawObjects(A, B);
+
+ link(providedInterface)( A.e -- .5[A.e, B.w] );
+endfig;
+
+beginfig(4);
+ save A, B;
+ Component.A("A")();
+ Component.B("B")();
+
+ leftToRight(80)(A, B);
+
+ drawObjects(A, B);
+
+ link(requiredInterface)( B.w -- .5[A.e, B.w]);
+endfig;
+
+beginfig(5);
+ save A, B;
+ Component.A("A")();
+ Component.B("B")();
+
+ leftToRight(80)(A, B);
+
+ drawObjects(A, B);
+
+ link(providedInterface)( A.e -- .5[A.e, B.w] );
+ link(requiredInterface)( B.w -- .5[A.e, B.w] );
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/group.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/group.mp
new file mode 100644
index 0000000000..0e25e58ea6
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/group.mp
@@ -0,0 +1,51 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input boxes;
+input util_commons;
+input util_object;
+input util_picture;
+input util_margins;
+input util_group;
+
+beginfig(1);
+ iGroup.left:=20;
+ iGroup.right:=15;
+ iGroup.boxed:=1;
+ iPict.boxed:=1;
+
+ Picture.a("yummy");
+ Picture.b("cool");
+ Picture.c("fool");
+
+ a.nw = (0,0);
+ b.nw = (20,20);
+ c.nw = (15, 40);
+
+ Group.g(a, b, c);
+
+ drawObjects(g);
+endfig;
+
+beginfig(2);
+endfig;
+
+beginfig(3);
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/how-links-work.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/how-links-work.mp
new file mode 100644
index 0000000000..c8d8500358
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/how-links-work.mp
@@ -0,0 +1,38 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ drawRelation(aggregationUni)
+ ((0,0)--(40,0));
+endfig;
+
+
+beginfig(2);
+ path myPath;
+ myPath := (0,0) -- (100,0);
+ LinkStructure.ls(myPath,
+ aggregationUni.widthA,
+ aggregationUni.widthB);
+
+ describeLinkStructure(ls);
+ drawLinkStructure(ls)(aggregationUni);
+endfig;
+
+end
+
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/instance.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/instance.mp
new file mode 100644
index 0000000000..9417224306
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/instance.mp
@@ -0,0 +1,9 @@
+input metauml;
+
+beginfig(1);
+ Instance.order("o: Order")
+ ("name='book'", "{placed}", "{payed}");
+ drawObject(order);
+endfig;
+
+end \ No newline at end of file
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/mptextmp.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/mptextmp.mp
new file mode 100644
index 0000000000..3e16f83e56
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/mptextmp.mp
@@ -0,0 +1 @@
+btex But this is insane: $\sum_1^3 f(x) \over x$! etex
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/note.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/note.mp
new file mode 100644
index 0000000000..f04a5b5e4f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/note.mp
@@ -0,0 +1,74 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+input TEX;
+
+beginfig(1);
+ Note.A("This note", "has two lines.");
+ drawObject(A);
+endfig;
+
+beginfig(2);
+ save A, C;
+ Note.A("This is a class");
+ Class.C("Object")()();
+
+ A.sw = C.ne + (20, 20);
+
+ drawObjects(A, C);
+
+ clink(dashedLink)(A, C);
+endfig;
+
+beginfig(3);
+ save C;
+ Note.nA("This is the class name");
+ Note.nB("This is a key attribute");
+ Note.nC("This is a nice method");
+
+ Class.C("Object")("+id:int")
+ ("+clone()", "+serialize()");
+
+ topToBottom.left(10)(nA, nB, nC);
+ leftToRight(10)(C, nB);
+
+ drawObjects(C, nA, nB, nC);
+
+ clink(dashedLink)(C.namePict, nA);
+ clink(dashedLink)(C.attributeStack.pict[0], nB);
+ clink(dashedLink)(C.methodStack.pict[1], nC);
+endfig;
+
+beginfig(4);
+ save A;
+ Note.A("This class implements the formula:",
+ TEX("$\sum_1^n f(x)\cdot dx$"));
+ drawObjects(A);
+endfig;
+
+beginfig(5);
+ save A;
+ Note.A("Can you do it?",
+ TEX("$\sum_1^n f(x) \cdot dx " &
+ "\over \sum_1^m g(y) \cdot dy$"));
+ A.stack.info.spacing := 30;
+ A.stack.pict[1].info.ignoreNegativeBase := 0;
+ drawObjects(A);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/object_stack.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/object_stack.mp
new file mode 100644
index 0000000000..b9cd4d32b3
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/object_stack.mp
@@ -0,0 +1,46 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input boxes;
+input util_commons;
+input util_object;
+input util_picture;
+
+
+beginfig(1);
+ iPict.ignoreNegativeBase := 1;
+ iPict.boxed := 1;
+ Picture.a0("yummy");
+ Picture.a1("cool");
+ Picture.a2("fool");
+
+ a0.nw = (0,0);
+ setObjectJoin(pa.sw = pb.nw);
+
+ joinObjects(scantokens listArray(a)(3));
+ drawObjects(scantokens listArray(a)(3));
+
+endfig;
+
+beginfig(2);
+endfig;
+
+beginfig(3);
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/package.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/package.mp
new file mode 100644
index 0000000000..88653b5fee
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/package.mp
@@ -0,0 +1,93 @@
+input metauml;
+input metauml_package;
+input metauml_package_relations;
+
+beginfig(1);
+ Package.P("java.lang")();
+ drawObject(P);
+endfig;
+
+beginfig(2);
+ save P;
+ Package.P("An important", "package")();
+ drawObject(P);
+endfig;
+
+beginfig(3);
+ save P;
+ Package.P("java.lang")();
+ P.info.forceEmptyContent := 1;
+ drawObject(P);
+endfig;
+
+beginfig(4);
+ save P, A, B;
+ Class.A("A")()();
+ Class.B("B")()();
+ Package.P("net.metauml")(A, B);
+
+ leftToRight(10)(A, B);
+
+ drawObject(P);
+endfig;
+
+beginfig(5);
+ Package.X("X")();
+ Package.Y("Y")();
+
+ leftToRight(50)(X, Y);
+ drawObjects(X, Y);
+
+ link(nest)(X.e -- Y.w);
+endfig;
+
+beginfig(8);
+ Package.emptyPackage("")();
+
+ Package.nameOnlyPackage("java.sun.com")();
+
+ Class.oneClass("A class")()();
+ Package.oneClassPackage("One class package")(oneClass);
+
+ Instance.oneInstance("An instance")();
+ State.oneState("A state")();
+ Activity.oneActivity("An activity");
+ Package.multiPackage("Multipackage")(oneInstance, oneState, oneActivity);
+
+ Package.allPackage("This package contains them all")(emptyPackage, nameOnlyPackage,
+ oneClassPackage, multiPackage);
+
+ nameOnlyPackage.nw = emptyPackage.ne + (30, 0);
+ oneClassPackage.ne = emptyPackage.s - (0, 50);
+
+ multiPackage.top = oneClassPackage.top;
+ multiPackage.left = oneClassPackage.right + 20;
+
+ centered_align_top(oneState, oneActivity)(10, below(oneInstance.s, 20));
+
+ drawObjects(allPackage);
+endfig;
+
+beginfig(8);
+ Package.nameOnlyOnTopPackage("Name on top")();
+ nameOnlyOnTopPackage.info.forceEmptyContent := 1;
+ Package.nameOnlyInMiddlePackage("By default name", "is in the middle")();
+
+ Class.cl("A class")("Attribute")("Method");
+ Package.notEmptyPackage("Contains class")(cl);
+
+ nameOnlyInMiddlePackage.n = nameOnlyOnTopPackage.s - (0, 40);
+ notEmptyPackage.w = nameOnlyInMiddlePackage.e + (80, 0);
+ drawObjects(nameOnlyOnTopPackage, nameOnlyInMiddlePackage, notEmptyPackage);
+
+ %link(import)(pathStepX(notEmptyPackage.w, nameOnlyOnTopPackage.e, -30));
+ %link(import)(pathVertical(nameOnlyInMiddlePackage.ne - (10, 0), nameOnlyOnTopPackage.bottom));
+ %link(import)(notEmptyPackage.sw -- nameOnlyInMiddlePackage.ne);
+endfig;
+
+beginfig(8);
+ link(nest)((10,10)--(30,30));
+endfig;
+
+
+end \ No newline at end of file
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths.mp
new file mode 100644
index 0000000000..06ca576120
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths.mp
@@ -0,0 +1,132 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ pair za, zb;
+ za = (10,10);
+ zb = (10,-5);
+ path cool;
+ cool := za .. za+(20,10) ..
+ zb+(20,-20) ..
+ zb+(-10,-30) -- zb;
+ link(aggregationUni)(cool);
+endfig;
+
+beginfig(2);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")()();
+
+ B.sw = A.ne + (10,10);
+
+ drawObjects(A, B);
+
+ link(aggregationUni)
+ (rpathManhattanX(A.e, B.s));
+ link(inheritance)
+ (pathManhattanY(A.n, B.w));
+endfig;
+
+beginfig(3);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")()();
+
+ B.sw = A.ne + (10,10);
+
+ drawObjects(A, B);
+
+ stepX:=60;
+ link(aggregationUni)
+ (pathStepX(A.e, B.e, stepX));
+
+ stepY:=20;
+ link(inheritance)
+ (pathStepY(B.n, A.n, stepY));
+
+ pair X,Y;
+ X := A.se + (0,-30);
+ Y := X + (stepX, 0);
+ draw A.se -- X dashed evenly;
+ draw (xpart Y, ypart A.e) -- Y dashed evenly;
+ drawdblarrow X + (0,15) -- Y + (0,15);
+ label.top(btex stepX etex, .5[X,Y]);
+
+ pair X,Y;
+ X := B.n + (-70,-0);
+ Y := X + (0, stepY);
+
+ draw B.n -- X dashed evenly;
+ draw B.n + (0,stepY) -- Y dashed evenly;
+ drawdblarrow X + (15,0) -- Y + (15,0);
+ label.lft(btex stepY etex, .5[X,Y]);
+endfig;
+
+% horizontal, vertical
+beginfig(4);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")("b")();
+ Class.C("C")("foo: int")();
+
+ B.sw = A.se + (30,5);
+ C.sw = A.nw + (0, 30);
+
+ drawObjects(A, B, C);
+
+ untilX := B.left;
+ drawRelation(association)
+ (pathHorizontal(A.e, untilX));
+
+ draw B.nw -- B.sw + (0,-10) dashed evenly;
+ label.bot(btex untilX etex, B.sw + (0,-10));
+
+ untilY:= C.bottom;
+ drawRelation(association)(pathVertical(A.n, untilY));
+
+ draw C.sw -- C.sw + (-20,0) dashed evenly;
+ label.lft(btex untilY etex, C.sw + (-20,-0));
+
+endfig;
+
+beginfig(5);
+ save A,B;
+ Activity.A("A");
+ Activity.B("B");
+
+ B.nw = A.ne + (40,30);
+ drawObjects(A,B);
+
+ z = A.se + (30, -10);
+ link(transition)(pathCut(A, B)
+ (A.c -- z -- B.c));
+endfig;
+
+beginfig(6);
+ save A,B;
+ Class.A("A")()();
+ Class.B("B")()();
+
+ B.nw = A.ne + (20,30);
+ drawObjects(A,B);
+
+ clink(inheritance)(A, B);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths_man.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths_man.mp
new file mode 100644
index 0000000000..a6c502f147
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/paths_man.mp
@@ -0,0 +1,143 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ save A, B;
+ Class.A("A")("foo:int")("bar()");
+ Class.B("B")()();
+
+ A.nw = (0,0);
+ B.s = A.ne + (30,30);
+
+ Class_draw.A;
+ Class_draw.B;
+
+ drawRelation(aggregationUni)
+ (A.n ..(30,30)..B.w);
+ path cool;
+ cool := A.e .. A.e+(20,10) ..
+ B.s+(20,-40) .. B.s+(-10,-30)
+ -- B.s;
+ drawRelation(inheritance)(cool);
+endfig;
+
+beginfig(2);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")()();
+
+ A.nw = (0,0);
+ B.sw = A.ne + (10,10);
+
+ Class_draw.A;
+ Class_draw.B;
+
+ drawRelation(aggregationUni)
+ (pathManhattanX(A.e, B.s));
+ drawRelation(inheritance)
+ (pathManhattanY(A.n, B.w));
+endfig;
+
+beginfig(3);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")()();
+
+ A.nw = (0,0);
+ B.sw = A.ne + (10,10);
+
+ Class_draw.A;
+ Class_draw.B;
+
+ stepX:=60;
+ drawRelation(aggregationUni)
+ (pathStepX(A.e, B.e, stepX));
+
+ stepY:=20;
+ drawRelation(inheritance)
+ (pathStepY(B.n, A.n, stepY));
+
+ pair X,Y;
+ X := A.se + (0,-30);
+ Y := X + (stepX, 0);
+ draw A.se -- X dashed evenly;
+ draw (xpart Y, ypart A.e) -- Y dashed evenly;
+ drawdblarrow X + (0,15) -- Y + (0,15);
+ label.top(btex stepX etex, .5[X,Y]);
+
+ pair X,Y;
+ X := B.n + (-70,-0);
+ Y := X + (0, stepY);
+
+ draw B.n -- X dashed evenly;
+ draw B.n + (0,stepY) -- Y dashed evenly;
+ drawdblarrow X + (15,0) -- Y + (15,0);
+ label.lft(btex stepY etex, .5[X,Y]);
+endfig;
+
+beginfig(4);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")("a")();
+
+ A.nw = (0,0);
+ B.sw = A.se + (30,5);
+
+ Class_draw.A;
+ Class_draw.B;
+
+ untilX := B.left;
+ drawRelation(association)
+ (pathHorizontal(A.e, untilX));
+
+ draw B.nw -- B.sw + (0,-10) dashed evenly;
+ label.bot(btex untilX etex, B.sw + (0,-10));
+endfig;
+
+beginfig(5);
+ save A, B;
+ Class.A("A")()();
+ Class.B("B")("a")("foo()");
+
+ A.nw = (0,0);
+ B.sw = A.ne + (-20,20);
+
+ Class_draw.A;
+ Class_draw.B;
+
+ untilY:= B.bottom;
+ drawRelation(association)
+ (pathVertical(A.n, untilY));
+
+ draw B.sw -- B.sw + (-20,0) dashed evenly;
+ label.lft(btex untilY etex, B.sw + (-20,-0));
+endfig;
+
+beginfig(6);
+ save A,B;
+ Class.A("A")()();
+ Class.B("B")()();
+
+ B.nw = A.ne + (40,30);
+ drawObjects(A,B);
+
+ link(inheritance)(pathCut(A,B)(A.c -- B.c));
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_info.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_info.mp
new file mode 100644
index 0000000000..df3b10145f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_info.mp
@@ -0,0 +1,86 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input boxes;
+input util_commons;
+input util_object;
+input util_picture;
+input util_positioning;
+
+PictureInfoCopy.iBig(iPict);
+iBig.left := iBig.right := 20;
+iBig.top := 10;
+iBig.bottom := 1;
+iBig.boxed := 1;
+iBig.ignoreNegativeBase := 1;
+iBig.iFont.name := defaultfont;
+iBig.iFont.scale := 3;
+
+PictureInfoCopy.iSmall(iPict);
+iSmall.boxed := 1;
+iSmall.borderColor := green;
+
+beginfig(1);
+ EPicture.a(iBig)("yummy");
+ EPicture.b(iSmall)("cool");
+% you can still modify a.info
+% and b.info if you wish.
+
+ a.nw = (0,0);
+ b.nw = a.sw + (0,-10);
+
+ drawObjects(a, b)
+endfig;
+
+beginfig(2);
+ save a, b, c, myFixed;
+ PictureInfoCopy.myFixed(iPict);
+ myFixed.ignoreNegativeBase := 1;
+ myFixed.fixedWidth := 15;
+ myFixed.fixedHeight := 20;
+ myFixed.boxed := 1;
+
+ EPicture.a(myFixed)("a");
+ EPicture.b(myFixed)(".-.");
+ EPicture.c(myFixed)("toolong");
+
+ leftToRight.bottom(10)(a, b, c);
+
+ drawObjects(a, b, c);
+endfig;
+
+beginfig(3);
+ save a, b, c, myFixed;
+ PictureInfoCopy.myFixed(iPict);
+ myFixed.ignoreNegativeBase := 1;
+ myFixed.bottom := 4.5;
+ myFixed.valign := "bottom";
+ myFixed.halign := "center";
+ myFixed.fixedWidth := 25;
+ myFixed.fixedHeight := 15;
+ myFixed.boxed := 1;
+
+ EPicture.a(myFixed)("a");
+ EPicture.b(myFixed)("yum");
+ EPicture.c(myFixed)("b");
+
+ leftToRight.bottom(10)(a, b, c);
+
+ drawObjects(a, b, c);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_stack.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_stack.mp
new file mode 100644
index 0000000000..ee6e09104b
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/picture_stack.mp
@@ -0,0 +1,44 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input boxes;
+input util_commons;
+input util_object;
+input util_picture;
+input util_group;
+input util_picture_stack;
+
+beginfig(1);
+ iStack.boxed := 1;
+ iStack.iPict.boxed := 1;
+ PictureStack.myStack("foo",
+ "bar: int" infont "tyxtt",
+ "cool-man-centered" infont defaultfont,
+ "nice")("vcenter");
+
+ myStack.nw = (0,0);
+ drawObject(myStack);
+endfig;
+
+beginfig(2);
+endfig;
+
+beginfig(3);
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/positioning.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/positioning.mp
new file mode 100644
index 0000000000..f98de47182
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/positioning.mp
@@ -0,0 +1,139 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ Class.A("A")()();
+ Class.B("B")()();
+ Class.C("C")()();
+ Class.Base("Base")()();
+
+
+ A.ne = B.nw - (20,0);
+ B.ne = C.nw - (20,0);
+ Base.s = B.n + (0,20);
+
+ drawObjects(Base, A, B, C);
+endfig;
+
+beginfig(2);
+ save A, B, C, Base;
+
+ Class.A("A")()();
+ Class.B("B")()();
+ Class.C("C")()();
+ Class.Base("Base")()();
+
+ leftToRight(20)(A, B, C);
+ topToBottom(20)(Base, B);
+
+ drawObjects(Base, A, B, C);
+endfig;
+
+iPict.boxed := 1;
+spacing := 5;
+string strA, strB, strC;
+strA := "a";
+strB := "...";
+strC := "Cyan";
+
+beginfig(3);
+ save A, B, C, X, Y, Z;
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ leftToRight.top(spacing)(X, Y, Z);
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.top) -- (Z.right, X.top) dashed evenly withpen pencircle withcolor red;
+endfig;
+
+beginfig(4);
+ save A, B, C, X, Y, Z;
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ leftToRight.midy(spacing)(X, Y, Z);
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.midy) -- (Z.right, X.midy) dashed evenly withpen pencircle withcolor red;;
+endfig;
+
+beginfig(5);
+ save A, B, C, X, Y, Z;
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ leftToRight.bottom(spacing)(X, Y, Z);
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.bottom) -- (Z.right, X.bottom) dashed evenly withpen pencircle withcolor red;;
+endfig;
+
+beginfig(6);
+ save A, B, C, X, Y, Z;
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ topToBottom.left(spacing)(X, Y, Z);
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.top) -- (X.left, Z.bottom) dashed evenly withpen pencircle withcolor red;;
+endfig;
+
+beginfig(7);
+ save A, B, C, X, Y, Z;
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ topToBottom.midx(spacing)(X, Y, Z);
+
+ drawObjects(X, Y, Z);
+
+ draw (X.midx, X.top) -- (X.midx, Z.bottom) dashed evenly withpen pencircle withcolor red;;
+endfig;
+
+beginfig(8);
+ save A, B, C, X, Y, Z;
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ topToBottom.right(spacing)(X, Y, Z);
+
+ drawObjects(X, Y, Z);
+
+ draw (X.right, X.top) -- (X.right, Z.bottom) dashed evenly withpen pencircle withcolor red;;
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/properties.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/properties.mp
new file mode 100644
index 0000000000..94f71d772e
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/properties.mp
@@ -0,0 +1,58 @@
+% Sample MetaUML figures.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+input metauml;
+
+beginfig(1);
+ Class.Test("Test")("a1","a2","a3")("aLongMethod():void");
+
+ Test.nw = (0,0);
+ Class_draw.Test;
+
+ dotlabel.ulft(btex nw etex, Test.nw);
+ dotlabel.top(btex n etex, Test.n);
+ dotlabel.urt(btex ne etex, Test.ne);
+ dotlabel.rt(btex e etex, Test.e);
+ dotlabel.lrt(btex se etex, Test.se);
+ dotlabel.bot(btex s etex, Test.s);
+ dotlabel.llft(btex sw etex, Test.sw);
+ dotlabel.lft(btex w etex, Test.w);
+
+ dotlabel.lft(btex c etex, Test.c);
+
+ draw Test.nw - (50,0) -- Test.ne + (10,0);
+ label.urt(btex top etex, Test.nw - (50,0));
+
+ draw Test.sw - (50,0) -- Test.se + (10,0);
+ label.lrt(btex bottom etex, Test.sw - (50,0));
+
+ draw Test.nw + (0,10) -- Test.sw - (0, 50);
+ label.bot(btex left etex, Test.sw - (0,50));
+
+ draw Test.ne + (0,10) -- Test.se - (0, 50);
+ label.bot(btex right etex, Test.se - (0,50));
+
+ drawarrow Test.nw - (25,0) -- Test.sw - (25,0);
+ label.lft(btex height etex, .5[Test.nw, Test.sw] - (25,0));
+
+ drawarrow Test.sw - (0,25) -- Test.se - (0,25);
+ label.bot(btex width etex, .5[Test.sw, Test.se] - (0,25));
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/state.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/state.mp
new file mode 100644
index 0000000000..77c7691a9a
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/state.mp
@@ -0,0 +1,55 @@
+% Sample MetaUML figures.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+input metauml;
+
+beginfig(1);
+ State.s("Take order")();
+ drawObject(s);
+endfig;
+
+beginfig(2);
+ Begin.b;
+ End.e;
+ State.c("Component")();
+ State.composite("Composite")(b, e, c);
+
+ b.midx = e.midx = c.midx;
+ c.top = b.bottom - 20;
+ e.top = c.bottom - 20;
+
+ composite.info.drawNameLine := 1;
+ drawObject(composite);
+
+ link(transition)(b.s -- c.n);
+ link(transition)(c.s -- e.n);
+endfig;
+
+beginfig(3);
+ save s;
+ State.s("An interesting state",
+ "which is worth mentioning")();
+ stateTransitions.s(
+ "OnEntry / Open eyes",
+ "OnExit / Sleep well");
+ s.info.drawNameLine := 1;
+
+ drawObject(s);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/statemachine_diagrams.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/statemachine_diagrams.mp
new file mode 100644
index 0000000000..ff93a74dd5
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/statemachine_diagrams.mp
@@ -0,0 +1,78 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+% for f in `find . | grep '.*\.[1-9]'`; do echo $f; done
+
+input metauml;
+
+beginfig(1);
+ Begin.b;
+ State.on("On")();
+ State.off("Off")();
+ End.e;
+
+ setObjectJoin(pb.w = pa.e + (20,0));
+ joinObjects(b, on, off, e);
+ drawObjects(b, on, off, e);
+
+ clink(transition)(b, on);
+ clink(transition)(on, off);
+ clink(transition)(off, e);
+endfig;
+
+beginfig(2);
+ save b, reading, processing, e, exit;
+
+ Begin.b;
+ State.reading("Commands read")();
+ State.processing("Processing commands")();
+ End.e;
+ setObjectJoin(pb.n = pa.s + (0, -20));
+ joinObjects(b, reading, processing, e);
+
+ State.composite("Work")(b, reading, processing, e);
+ drawObject(composite);
+
+ clink(transition)(b, reading);
+ clink(transition)(reading, processing);
+ clink(transition)(processing, e);
+
+ ExitPoint.exit;
+ exit.c=(composite.right, reading.midy);
+ drawObject(exit);
+ item(iAssoc)("error")(obj.nw = exit.s);
+
+ clink(transition)(reading, exit);
+
+ State.error("Prepare error report")();
+ State.result("Display result")();
+ End.theEnd;
+
+ error.midx = result.midx = theEnd.midx = composite.right + 90;
+ error.midy = exit.midy;
+ result.midy = processing.midy;
+ theEnd.midy = e.midy;
+ drawObjects(error, result, theEnd);
+
+ clink(transition)(exit, error);
+ clink(transition)(error, result);
+ clink(transition)(result, theEnd);
+
+ link(transition)(rpathHorizontal(result.w, composite.right));
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_activity.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_activity.mp
new file mode 100644
index 0000000000..841bdb8a31
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_activity.mp
@@ -0,0 +1,46 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ Begin.b;
+ End.e;
+
+ e.n = (30,30);
+ drawObject(b);
+ show "Object b drawn";
+ drawObject(e);
+
+ link(associationUni)(pathCut(b,e)(b.c--e.c));
+endfig;
+
+beginfig(2);
+ EActivity.act(iActivity)("go to school", "while singing");
+ drawObject(act);
+
+ Branch.br;
+ br.nw = (50,50);
+ drawObject(br);
+
+ Fork.fork("h",30);
+ fork.nw = (30,70);
+ drawObject(fork);
+endfig;
+
+end
+
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class.mp
new file mode 100644
index 0000000000..94e1fdc130
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class.mp
@@ -0,0 +1,156 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(0);
+ show "Copying class info...";
+ ClassInfoCopy.foo(iClass);
+endfig;
+
+beginfig(1);
+ Class.A("A")()();
+ Class_setDebugMode.A;
+
+ A.nw=(0,0);
+ Class_draw.A;
+endfig;
+
+beginfig(2);
+ save B;
+ Class.B("B")("+ a:int")();
+ Class_setDebugMode.B;
+
+ B.nw=(0,0);
+ Class_draw.B;
+endfig;
+
+beginfig(3);
+ save C;
+ Class.C("C")("+ a-#~+:int", "- b-#~+:int", "- g-#~+:int", "~ c-#~+:int", "# g-#~+:double")();
+ Class_setDebugMode.C;
+
+ C.nw=(0,0);
+ Class_draw.C;
+endfig;
+
+beginfig(4);
+ save D;
+ Class.D("D")
+ ("+ a-#~+:int", "- b-#~+:int", "- g-#~+:int", "~ c-#~+:int", "# g-#~+:double")
+ ("+ a()-#~+:int", "- b()-#~+:int", "- g()-#~+:int", "~ c()-#~+:int", "# g()-#~+:double");
+ Class_setDebugMode.D;
+
+ D.nw=(0,0);
+ Class_draw.D;
+endfig;
+
+beginfig(5);
+ save P, Q;
+
+ Class.P("AAA")()();
+ Class_stereotypes.P("ooo", "home", "interface");
+ Class_setDebugMode.P;
+ P.nw=(0,0);
+ Class_draw.P;
+
+ Class.Q("AAA")()();
+ Class_stereotypes.Q("ooo", "home", "interface");
+ Q.nw=P.ne + (20,0);
+ Class_draw.Q;
+endfig;
+
+beginfig(6);
+ save A;
+
+ Class.A("User6")()();
+ Class_stereotypes.A("<<interface>>","<<home>>");
+ A.nw=(0,0);
+ drawObject(A);
+endfig;
+
+beginfig(7)
+ save A;
+ Class.A("User7")()();
+ A.info.iMethodStack.left := A.info.iMethodStack.right := 50;
+ A.info.iMethodStack.top := A.info.iMethodStack.bottom := 20;
+
+ drawObject(A);
+endfig;
+
+beginfig(8)
+ save inter;
+ EClass.inter(iInterface)("Observer")()("+update(src: Object)");
+ drawObjects(inter);
+endfig;
+
+beginfig(9)
+ save inter;
+ EInterface.inter(iInterface)("Observer")("+update(src: Object)");
+ drawObjects(inter);
+endfig;
+
+beginfig(10)
+ save inter;
+ Interface.inter("Observer")("+update(src: Object)");
+ drawObjects(inter);
+endfig;
+
+beginfig(11)
+ save A;
+ EClass.A(iAbstractClass)("AbstractClass")("[]{}")("+update(src: Object)");
+ drawObjects(A);
+endfig;
+
+beginfig(12)
+ save A;
+ AbstractClass.A("AbstractClass")("[]{}")("+update(src: Object)");
+ drawObjects(A);
+endfig;
+
+beginfig(13)
+ save A;
+ EClass.A(iClassNameOnly)("AClassWithNoCompartments")()();
+ drawObjects(A);
+endfig;
+
+beginfig(14)
+ save A;
+ ClassName.A("AnotherClass");
+ drawObjects(A);
+endfig;
+
+beginfig(15)
+ save A;
+ ClassName.A("AnotherClass");
+ classStereotypes.A("<<interface>>","<<remote>>");
+
+ drawObjects(A);
+endfig;
+
+beginfig(16);
+ save A, B, C;
+
+ Class.A("Foo")
+ ("+a: int", "-b: int", "#c: int", "d: int")
+ ("+x()", "-y()", "#z()", "t()");
+ Class_noVisibilityMarkers.A;
+
+ drawObjects(A);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_feature_types.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_feature_types.mp
new file mode 100644
index 0000000000..f35c0b7b68
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_feature_types.mp
@@ -0,0 +1,53 @@
+% Copyright 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+input metauml;
+
+beginfig(1);
+ if not metauml_private_isAbstract(abstract "foo"):
+ 1 = 2;
+ fi;
+
+ if metauml_private_isAbstract("@abstracp"):
+ 1 = 2;
+ fi;
+endfig;
+
+beginfig(2);
+ if not metauml_private_isStatic(static "bar"):
+ 1 = 2;
+ fi;
+
+ if metauml_private_isStatic("@statique"):
+ 1 = 2;
+ fi;
+endfig;
+
+beginfig(3);
+ Class.A("A")
+ ("+a:int+", static "+b:int")
+ ("+f+():int", static "+g+():int", abstract "+h():int");
+ Class_setDebugMode.A;
+ drawObjects(A);
+endfig;
+
+beginfig(4);
+ save A;
+ Class.A("A")
+ (static "-instanceCount:int")
+ (static "+getInstanceCount():int", abstract "+work()");
+ drawObjects(A);
+endfig;
+
+beginfig(5);
+ save A, B;
+ Class.A("A")()();
+ Class.B(abstract "B")()();
+ Class.C("C")()(abstract "foo()");
+
+ leftToRight(5)(A, B, C);
+
+ drawObjects(A, B, C);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_qual_assoc.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_qual_assoc.mp
new file mode 100644
index 0000000000..735bba19e0
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_qual_assoc.mp
@@ -0,0 +1,53 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ save P,qa;
+
+ Class.P("Person")()();
+ QualifiedAssociation.qa("accountNumber:int", "foo: id");
+
+ P.nw = (0,0);
+ qa.n = P.s;
+
+
+ P.info.iName.left := 35;
+ P.info.iName.right := 35;
+ drawObjects(P);
+
+ drawObject(qa);
+endfig;
+
+beginfig(2);
+ save P,qa;
+
+ Class.P("Person")()();
+ QualifiedAssociation.qa("accountNumber:int", "foo: id", "foolang");
+
+ P.nw = (0,0);
+ qa.w = P.e;
+
+ P.info.shade := 0;
+ P.info.iMethodStack.top := 20;
+ drawObjects(P);
+
+ drawObject(qa);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_templates.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_templates.mp
new file mode 100644
index 0000000000..c3fc50209c
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_class_templates.mp
@@ -0,0 +1,62 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ save P,template;
+
+ Class.P("Person")()();
+ Template.template("foo", "bar");
+
+ drawObjectAt(P)(P.nw=(0,0));
+
+ Template_attachToClass.template(P);
+ drawObject(template);
+endfig;
+
+beginfig(2);
+ save P,template;
+
+ Class.P("Person")()();
+ Template.template("foo: int");
+ Template_attachToClass.template(P);
+
+ drawObjectAt(P)(P.nw=(0,0));
+ drawObject(template);
+endfig;
+
+beginfig(3);
+ save CA, TA, CB, TB, CC, TC;
+ Class.CA("VeryVeryLongClassName")()();
+ ClassTemplate.TA("int foo")(CA);
+
+ Class.CB("Shortie")("abracadabra: long long int")();
+ ClassTemplate.TB("T")(CB);
+
+ Class.CC("Shortie")("abracadabra: long long int")();
+ ClassTemplate.TC("TrulyAmazingLongTypename")(CC);
+
+ CA.s = CB.n + (0,14);
+ CB.s = CC.n + (0,14);
+
+ drawObjects(CA, TA, CB, TB, CC, TC);
+endfig;
+
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_component.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_component.mp
new file mode 100644
index 0000000000..94d866c753
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_component.mp
@@ -0,0 +1,30 @@
+input metauml;
+input metauml_component;
+input metauml_component_relations;
+
+beginfig(1);
+ Class.classA("Class A")()();
+ Class.classB("Class B")()();
+
+ Component.compA("Component A")();
+ Component.compB("Component B")();
+ Component.compC("Component C")(compA, compB, classA, classB);
+
+ compB.w = compA.e + (40, 0);
+ classA.w = compB.e + (20, 0);
+ classB.w = classA.e + (20, 0);
+
+ drawObjects(compC);
+
+ path open;
+ open := compA.e .. compA.e + (20, 0);
+ path close;
+
+ close := compB.w .. compA.e + (20, 0);
+
+ link(requiredInterface)(open);
+
+ link(providedInterface)(close);
+endfig;
+
+end \ No newline at end of file
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_font.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_font.mp
new file mode 100644
index 0000000000..21e748a4f7
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_font.mp
@@ -0,0 +1,81 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+string theFont;
+
+beginfig(1);
+ theFont := "pcrr";
+
+ boxjoin(a.sw=b.nw);
+
+ boxit.ff(("Font name: ( ) " & theFont) infont theFont);
+ boxit.s0("<<stereotype>> text with guillemets. ><>><<" infont theFont );
+ boxit.s1("<<a>>, <<b>>, <<c>>" infont theFont);
+ boxit.s2("[g uard] text with square brackets []]." infont theFont);
+ boxit.s3("{c onstraint} text with curly brackets {}}." infont theFont);
+
+ drawboxed(ff, s0, s1, s2, s3);
+endfig;
+
+beginfig(2);
+ save ff,s,g,c;
+ theFont := "tyxbtt";
+
+ boxjoin(a.sw=b.nw);
+
+ boxit.ff(("Font name: ( ) " & theFont) infont theFont);
+ boxit.s0("<<stereotype>> text with guillemets. ><>><<" infont theFont );
+ boxit.s1("<<a>>, <<b>>, <<c>>" infont theFont);
+ boxit.s2("[g uard] text with square brackets []]." infont theFont);
+ boxit.s3("{c onstraint} text with curly brackets {}}." infont theFont);
+
+ drawboxed(ff, s0, s1, s2, s3);endfig;
+
+beginfig(3);
+ picture pA, pB, pC;
+ string sA, sB, sC;
+ sA := "assembleElementLocalMatrix(k: KeyType, mat: LocalMatrixType, a: AssembleAction)";
+ sB := "assembleElementLocalMatri(k: KeyType, mat: LocalMatrixType, a: AssembleAction)";
+ sC := "assembleElntLocalMatri(k: KeyType, mat: LocalMatrixType, a: AssembleAction)";
+
+ pA := sA infont "tyxbtt";
+ pB := sB infont "tyxbtt";
+ pC := sC infont "tyxbtt";
+
+ draw pA;
+ draw pB shifted (0,-20);
+ draw pC shifted (0,-40);
+endfig;
+
+beginfig(4);
+ save ff,s,g,c;
+ theFont := "ptmr8r";
+
+ boxjoin(a.sw=b.nw);
+ boxit.ff(("Font name: ( ) " & theFont) infont theFont);
+
+ boxit.s0("<<stereotype>> text with guillemets. ><>><<" infont theFont );
+ boxit.s1("<<a>>, <<b>>, <<c>>" infont theFont);
+ boxit.s2("[g uard] text with square brackets []]." infont theFont);
+ boxit.s3("{c onstraint} text with curly brackets {}}." infont theFont);
+
+ drawboxed(ff, s0, s1, s2, s3);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_group.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_group.mp
new file mode 100644
index 0000000000..17265c458b
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_group.mp
@@ -0,0 +1,60 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ save p,q,r,t,g;
+
+ EPicture.p(iPictBoxed)("p0");
+ EPicture.q(iPictBoxed)("p1");
+ p.se = q.nw;
+
+ string f;
+ f= enumToString(p,q)("");
+ show "f=" & f;
+
+ EGroup.g(iGroup)(p,q);
+ g.nw = (0,0);
+
+ drawObject(g);
+endfig;
+
+beginfig(2);
+ save g,h,p,gg;
+
+ Group.g();
+ g.info.boxed := 1;
+ g.nw = (30,30);
+ drawObject(g);
+
+ Picture.p("Test picture in group");
+ p.info.boxed := 1;
+ Group.h(p);
+ h.info.boxed := 1;
+ h.nw = (0,0);
+ drawObject(h);
+
+ Picture.v0("s"); v0.info.boxed := 1;
+ Picture.v1("s"); v1.info.boxed := 1;
+ v1.nw = v0.se + (10,10);
+ Group.gg(v0, v1); gg.info.boxed := 1;
+ gg.nw = (70,70);
+ drawObject(gg);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_instance.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_instance.mp
new file mode 100644
index 0000000000..d01ff8452e
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_instance.mp
@@ -0,0 +1,35 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Radu-George Radulescu
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ Instance.A(":Foo")("int: val1", "bool: val2");
+ Instance.B(":Bar")("very long text for testing purposes");
+ Instance.C("s: Student")("line1", "line2", "line3", "line4", "line5");
+ Instance.D("Example")("small");
+ Instance.E("g: Yummy")("{placed}", "{color=red}");
+
+ B.w = A.e + (20, 0);
+ C.n = A.s - (0, 20);
+ D.w = C.e + (20, 0);
+ E.w = D.e + (20, 0);
+
+ drawObjects(A, B, C, D, E);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lars_issues.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lars_issues.mp
new file mode 100644
index 0000000000..428d7b4144
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lars_issues.mp
@@ -0,0 +1,94 @@
+input metauml;
+
+numeric u;
+u = 1.3cm;
+
+beginfig(1);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Class.ElLocSysAcc("ElementLocalSystemAcceptor")
+()
+("+startElementAssebly()",
+ "+assembleElementLocalMatrix(k: KeyType, mat: LocalMatrixType, a: AssembleAction)",
+ "+assembleElementLocalRHS(k: KeyType, rhs: LocalRHSType, a: AssembleAction)",
+ "+endElementAssembly()");
+
+classStereotypes.ElLocSysAcc("<<interface>>");
+ClassTemplate.TEl("KeyType: typename")(ElLocSysAcc);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Class.FaceLocSysAcc("FaceLocalSystemAcceptor")
+ ()
+ ("+startFaceAssebly()",
+ "+assembleFaceLocalMatrix(k1: KeyType, k2: KeyType, mat: LocalMatrixType, a: AssembleAction)",
+ "+assembleFaceLocalRHS(k: KeyType, rhs: LocalRHSType, a: AssembleAction)",
+ "+endFaceAssembly()");
+
+ classStereotypes.FaceLocSysAcc("<<interface>>");
+ ClassTemplate.TFa("KeyType: typename")(FaceLocSysAcc);
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Class.SolProvider("SolutionProvider")
+ ()
+ ("+startSortBack()",
+ "+getLocalSolution(k: KeyType, sol: LocalSolutionType)",
+ "+endSortBack()");
+
+ classStereotypes.SolProvider("<<interface>>");
+ ClassTemplate.TSol("KeyType: typename")(SolProvider);
+
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ % now inherit from these for LapackMatrixSorter
+ Class.LapackMS("LapackMatrixSorter")
+ ("-indMan: IndexManager",
+ "-A: LaGenMatDouble&",
+ "-x: LaVectorDouble&",
+ "-b: LaVectorDouble&"
+ )
+ ("+startElementAssembly()");
+
+ ClassTemplate.TLap("KeyType: typename", "IndexManager: class")(LapackMS);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% where to draw these:
+FaceLocSysAcc.nw = ElLocSysAcc.ne + (1.5u, 0);
+SolProvider.nw = FaceLocSysAcc.ne + (1.5u, 0);
+LapackMS.n = FaceLocSysAcc.s + (0, -3u);
+
+drawObjects(ElLocSysAcc, TEl, FaceLocSysAcc, TFa,
+ SolProvider, TSol, LapackMS, TLap);
+
+% 50: how much should the path raise upwards before making a horizontal turn.
+link(inheritance)(pathStepY(LapackMS.n, FaceLocSysAcc.s, 50));
+link(inheritance)(pathStepY(LapackMS.n, SolProvider.s, 50));
+link(inheritance)(pathStepY(LapackMS.n, ElLocSysAcc.s, 50));
+
+endfig;
+
+beginfig(2);
+ Begin.b;
+ Activity.A("Activity A", "on line two");
+ Activity.B("Activity B");
+ End.e;
+
+ % or other positioning code...
+ setObjectJoin(pa.s = pb.n + (0,20));
+ joinObjects(b, A, B, e);
+
+ % important: first draw the activities
+ drawObjects(b, A, B, e);
+
+ % you can now draw the transitions
+ clink(transition)(b, A);
+ clink(transition)(A, B);
+ link(transition)(pathStepX(B.e, e.e, 30));
+
+ item(iGuard)("guard")(obj.sw = .5[b.s, A.n]);
+endfig;
+
+end;
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lowlevel.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lowlevel.mp
new file mode 100644
index 0000000000..952da34f48
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_lowlevel.mp
@@ -0,0 +1,66 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+input util_infrastructure;
+
+beginfig(1);
+ show "Lowlevel test";
+ %string foo;
+ %foo := var_instruction(numeric) x, y;
+ %show foo;
+ %foo := foo & ";";
+ %show foo;
+ attributes(foo);
+ _n_ := "foo";
+ %scantokens foo;
+ %string x;
+ %x := str(numeric);
+ var(numeric) x;
+
+ label.top("nothing shown (intentionally)", (0,0));
+endfig;
+
+vardef _foo@#=
+ attributes(@#);
+ var(string) @#a[];
+ @#a[0] := "fpp";
+ @#a[1] := "gqq";
+enddef;
+
+% _foo.b; % not working
+
+vardef _bar@#(text s)=
+ attributes(@#);
+ var(string) elements;
+ @#elements := enumToString(s)("");
+enddef;
+
+beginfig(2);
+ for f = scantokens "a, b, c":
+ show f;
+ endfor;
+ _bar.xx(a, b, c, d);
+ show xx.elements;
+ for f = scantokens xx.elements:
+ show f;
+ endfor;
+ label.top("nothing shown (intentionally)", (0,0));
+endfig;
+
+end
+
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_note.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_note.mp
new file mode 100644
index 0000000000..bf8c1aeb2f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_note.mp
@@ -0,0 +1,39 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml_note;
+input metauml_base;
+input metauml_paths;
+input metauml_links;
+input metauml_class_relations;
+
+beginfig(1);
+ Note.foo("This is the first line", "and this the second one.");
+ drawObject(foo);
+endfig;
+
+beginfig(2);
+ save foo;
+ Note.foo("Please disregard this note.");
+ Note.bar("Please take the other note", "very seriously.");
+
+ bar.s = foo.n + (10,20);
+ drawObjects(foo, bar);
+ clink(dashedLink)(foo, bar);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_package.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_package.mp
new file mode 100644
index 0000000000..6d4f97ea9f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_package.mp
@@ -0,0 +1,54 @@
+input metauml;
+input metauml_package;
+input metauml_package_relations;
+
+beginfig(1);
+ Package.emptyPackage("")();
+
+ Package.nameOnlyPackage("java.sun.com")();
+
+ Class.oneClass("A class")()();
+ Package.oneClassPackage("One class package")(oneClass);
+
+ Instance.oneInstance("An instance")();
+ State.oneState("A state")();
+ Activity.oneActivity("An activity");
+ Package.multiPackage("Multipackage")(oneInstance, oneState, oneActivity);
+
+ Package.allPackage("This package contains them all")(emptyPackage, nameOnlyPackage,
+ oneClassPackage, multiPackage);
+
+ nameOnlyPackage.nw = emptyPackage.ne + (30, 0);
+ oneClassPackage.ne = emptyPackage.s - (0, 50);
+
+ multiPackage.top = oneClassPackage.top;
+ multiPackage.left = oneClassPackage.right + 20;
+
+ centered_align_top(oneState, oneActivity)(10, below(oneInstance.s, 20));
+
+ drawObjects(allPackage);
+endfig;
+
+beginfig(2);
+ Package.nameOnlyOnTopPackage("Name on top")();
+ nameOnlyOnTopPackage.info.forceEmptyContent := 1;
+ Package.nameOnlyInMiddlePackage("By default, the name", "is in the middle")();
+
+ Class.cl("A class")("Attribute")("Method");
+ Package.notEmptyPackage("Contains class")(cl);
+
+ nameOnlyInMiddlePackage.n = nameOnlyOnTopPackage.s - (0, 40);
+ notEmptyPackage.w = nameOnlyInMiddlePackage.e + (80, 0);
+ drawObjects(nameOnlyOnTopPackage, nameOnlyInMiddlePackage, notEmptyPackage);
+
+ %link(import)(pathStepX(notEmptyPackage.w, nameOnlyOnTopPackage.e, -30));
+ %link(import)(pathVertical(nameOnlyInMiddlePackage.ne - (10, 0), nameOnlyOnTopPackage.bottom));
+ %link(import)(notEmptyPackage.sw -- nameOnlyInMiddlePackage.ne);
+endfig;
+
+beginfig(3);
+ link(nest)((10,10)--(30,30));
+endfig;
+
+
+end \ No newline at end of file
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_paths.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_paths.mp
new file mode 100644
index 0000000000..eedd11a9b0
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_paths.mp
@@ -0,0 +1,100 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+iPict.boxed := 1;
+
+beginfig(1);
+ iClass.shade := 3;
+ Class.F("Foo")("a: int","b: int")();
+ Class.B("Bar")()();
+
+ B.nw = F.ne + (20,-20);
+
+ drawObjects(B, F);
+
+ link(association)(B.nw -- F.ne);
+
+ draw objectBorder(B) withcolor red;
+ draw objectBorder(F) withcolor blue;
+
+ link(association)(pathCut(B,F)(B.c--F.c));
+endfig;
+
+beginfig(2);
+ save A, B;
+
+ Picture.A("A");
+ Picture.B("Blue");
+
+ B.sw = A.ne + (20,20);
+
+ drawObjects(A, B);
+
+ link(associationUni)(pathManhattanX(A.e, B));
+endfig;
+
+beginfig(3);
+ save A, B, C, D, O;
+
+ Picture.A("Alpha");
+ Picture.B("Beta");
+ Picture.C("Gamma");
+ Picture.D("Delta");
+ Picture.O("Omega");
+
+ A.c = O.c + (-50,50);
+ B.c = O.c + (50,50);
+ C.c = O.c + (-50,-50);
+ D.c = O.c + (50,-50);
+
+ drawObjects(O, A, B, C, D);
+
+ link(associationUni)(pathManhattanX(O, A));
+ link(associationUni)(pathManhattanX(O, B));
+ link(associationUni)(pathManhattanX(O, C));
+ link(associationUni)(pathManhattanX(O, D));
+endfig;
+
+beginfig(3);
+ show "";
+ show "";
+ show " FIGURE 3";
+
+ save A, B, C, D, O;
+
+ Picture.A("Alpha");
+ Picture.B("Beta");
+ Picture.C("Gamma");
+ Picture.D("Delta");
+ Picture.O("Omega");
+
+ A.c = O.c + (-50,50);
+ B.c = O.c + (50,50);
+ C.c = O.c + (-50,-50);
+ D.c = O.c + (50,-50);
+
+ drawObjects(O, A, B, C, D);
+
+ link(associationUni)(pathManhattanX(O, A));
+ link(associationUni)(pathManhattanX(O, B));
+ link(associationUni)(pathManhattanX(O, C));
+ link(associationUni)(pathManhattanX(O, D));
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture.mp
new file mode 100644
index 0000000000..7a56236e82
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture.mp
@@ -0,0 +1,273 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+string theFont;
+theFont := "tyxbtt";
+
+beginfig(1);
+ draw "xxx" infont defaultfont scaled defaultscale shifted (0,0);
+ draw "yyy" infont (iFont.name) scaled (iFont.scale) shifted (25, 0);
+
+ Picture.p("foo, bar, baz");
+ p.nw = (0,0);
+ drawObject(p);
+
+ Picture.q("qux, norf");
+ drawObjectAt(q)( q.nw = (30,30) );
+
+ FontInfo.foo("tyxbtt", 1);
+ PictureInfo.iNice(3,6,5,10)(foo);
+ iNice.boxed := 1;
+
+ EPicture.myPic(iNice)("Custom iPicture");
+ drawObjectAt(myPic)( myPic.nw = (70,0));
+endfig;
+
+beginfig(2);
+ save p, q, r, t;
+
+ Picture.p("foo");
+ Picture.q("bar");
+ p.nw = (10, 10);
+ q.nw = (20, 20);
+
+ drawObject(p);
+ drawObject(q);
+
+ drawObjects(p, q);
+
+ Picture.a0("root" infont defaultfont);
+ Picture.a1("toof");
+
+ a[0].nw = (30, 30);
+ a[1].nw = (50, 50);
+
+ drawObjects(scantokens listArray(a)(2));
+endfig;
+
+beginfig(3);
+ save p, q, r, t, u, pp;
+
+ bboxmargin := 0;
+
+ picture pp;
+ pp = "a" infont theFont;
+ Picture.p(pp);
+ Picture.q("foo" infont theFont);
+ Picture.r("bar" infont theFont);
+ Picture.t("baz");
+ Picture.u("norf" infont theFont);
+
+ p.nw = (0,0);
+ setObjectJoin(pa.left=pb.left; pa.bottom = pb.top + 1);
+ joinDrawObjects(p, q, r, t, u);
+
+ defaultdy:=0;
+ boxjoin(a.sw=b.nw; a.se=b.ne);
+ boxit.A0("foo1");
+ boxit.A1("bar1");
+ boxit.A2("baz2");
+ boxit.A3("norf2");
+ boxit.A4("..");
+ A0.nw=(50,0);
+ drawboxed(A0,A1,A2,A3,A4);
+
+ myy := 10;
+
+ bboxmargin := 0;
+
+ pair p;
+ p := (30,myy);
+ dotlabel.lrt(".", p);
+ picture x;
+ x := "f: int" infont theFont;
+ draw bbox(x) shifted p;
+ draw x shifted p;
+
+ pair q;
+ q := (70,myy);
+ dotlabel.lrt(".", q);
+ picture y;
+ y := "goofy: int" infont theFont;
+ draw bbox(y) shifted q;
+ draw y shifted q;
+
+ pair qq;
+ qq := (135,myy);
+ dotlabel.lrt(".", qq);
+ picture y;
+ y := "goot" infont theFont;
+ draw bbox(y) shifted qq;
+ draw y shifted qq;
+
+ draw (0,myy)--(150, myy) dashed evenly;
+
+ myyb := 30;
+ Picture.aa(btex goof etex);
+ aa.sw = (30, myyb);
+ Picture_draw.aa;
+
+ draw (0,myyb)--(100, myyb) dashed evenly;
+endfig;
+
+beginfig(4);
+ save a, b;
+ FontInfo.myFont(theFont, 1);
+ PictureInfo.myWay(0,0,0,0)(myFont);
+ myWay.boxed := 1;
+
+ EPicture.a0(myWay)("goof");
+ EPicture.a1(myWay)("Aoorian");
+ EPicture.a2(myWay)("fpp");
+ EPicture.a3(myWay)("f: int");
+ EPicture.a4(myWay)("aa()");
+
+ a0.nw = (0,0);
+ setObjectJoin(pa.bottom = pb.bottom; pa.right = pb.left - 10);
+ joinDrawObjects(scantokens listArray(a)(5));
+
+ draw a0.sw -- a4.se withcolor black dashed evenly;
+
+ myWay.ignoreNegativeBase := 1;
+ EPicture.b0(myWay)("foo");
+ EPicture.b1(myWay)("Bar baz");
+ EPicture.b2(myWay)("qux");
+ EPicture.b3(myWay)("f: int");
+ EPicture.b4(myWay)("aa()");
+
+ b0.nw = (0,-20);
+ setObjectJoin(pa.bottom = pb.bottom; pa.right = pb.left - 10);
+ joinDrawObjects(scantokens listArray(b)(5));
+
+ draw b0.sw -- b4.se withcolor black dashed evenly;
+endfig;
+
+beginfig(5);
+ truecorners := 1;
+ bboxmargin := 0;
+ save p;
+ picture basepict;
+ basepict := "<<foo>>" infont "tyxtt";
+
+ draw basepict;
+ draw bbox basepict;
+endfig;
+
+beginfig(6);
+ item.foo(iPictBoxed)("foo bar baz")(foo.nw = (0,0));
+ item.bar(iPict)("x: int")(bar.nw = (20,20));
+
+ aitem(iPictBoxed)("an anounymous item")(obj.nw = (40,10));
+endfig;
+
+beginfig(7);
+ save a, b, c, d, e, myFixed;
+ PictureInfoCopy.myFixed(iPict);
+ myFixed.ignoreNegativeBase := 1;
+ myFixed.fixedWidth := 20;
+ myFixed.boxed := 1;
+
+ EPicture.a(myFixed)("a");
+ EPicture.b(myFixed)("bar");
+ EPicture.c(myFixed)(".-.");
+ EPicture.d(myFixed)("baz");
+ EPicture.e(myFixed)("qux norf");
+
+ leftToRight.bottom(20)(a, b, c, d, e);
+
+ drawObjects(a, b, c, d, e);
+endfig;
+
+beginfig(8);
+ save a, b, c, d, e, myFixed;
+ PictureInfoCopy.myFixed(iPict);
+ myFixed.halign := "center";
+ myFixed.ignoreNegativeBase := 1;
+ myFixed.fixedWidth := 20;
+ myFixed.boxed := 1;
+
+ EPicture.a(myFixed)("a");
+ EPicture.b(myFixed)("bar");
+ EPicture.c(myFixed)(".-.");
+ EPicture.d(myFixed)("baz");
+ EPicture.e(myFixed)("qux norf");
+
+ leftToRight.bottom(20)(a, b, c, d, e);
+
+ drawObjects(a, b, c, d, e);
+endfig;
+
+beginfig(9);
+ save a, b, c, d, e, myFixed;
+ PictureInfoCopy.myFixed(iPict);
+ myFixed.halign := "center";
+ myFixed.ignoreNegativeBase := 1;
+ myFixed.fixedWidth := 20;
+ myFixed.fixedHeight := 30;
+ myFixed.boxed := 1;
+
+ EPicture.a(myFixed)("a");
+ EPicture.b(myFixed)("bar");
+ EPicture.c(myFixed)(".-.");
+ EPicture.d(myFixed)("baz");
+ EPicture.e(myFixed)("qux norf");
+
+ leftToRight.bottom(20)(a, b, c, d, e);
+
+ drawObjects(a, b, c, d, e);
+endfig;
+
+beginfig(10);
+ save a, b, c, d, e, myFixed;
+ PictureInfoCopy.myFixed(iPict);
+ myFixed.halign := "center";
+ myFixed.valign := "center";
+ myFixed.ignoreNegativeBase := 1;
+ myFixed.fixedWidth := 20;
+ myFixed.fixedHeight := 30;
+ myFixed.boxed := 1;
+
+ EPicture.a(myFixed)("a");
+ EPicture.b(myFixed)("bar");
+ EPicture.c(myFixed)(".-.");
+ EPicture.d(myFixed)("baz");
+ EPicture.e(myFixed)("qux norf");
+
+ leftToRight.bottom(20)(a, b, c, d, e);
+
+ drawObjects(a, b, c, d, e);
+endfig;
+
+beginfig(11);
+ save a, b, c;
+ Picture.a("goo");
+ a.info.textDecoration := "underline";
+
+ Picture.b("foo()");
+ b.info.textDecoration := "underline";
+
+ Picture.c("x");
+ c.info.textDecoration := "underline";
+
+ topToBottom(5)(a, b, c);
+
+ drawObjects(a, b, c);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_stack.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_stack.mp
new file mode 100644
index 0000000000..8ad4776fa4
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_stack.mp
@@ -0,0 +1,130 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+string theFont;
+theFont := "tyxtt";
+
+util_log_thresholdlevel := 100;
+
+beginfig(1);
+ PictureStackInfoCopy.stackWay(iStack);
+
+ EPictureStack.emptyStack(stackWay)()("vcenter");
+ emptyStack.nw=(10,10);
+ drawObject(emptyStack);
+endfig;
+
+beginfig(2);
+ PictureStack.myStack("foo")("vcenter");
+ myStack.nw = (0,0);
+ PictureStack_draw.myStack;
+endfig;
+
+beginfig(3);
+ PictureStack.myStackB("foo", "bar")("vcenter");
+ myStackB.nw = (0,0);
+ PictureStack_draw.myStackB;
+endfig;
+
+beginfig(4);
+ % 1
+ PictureStack.stack("item A", "item B long", "C")("vcenter");
+ stack.info.boxed := 1;
+ stack.info.iPict.boxed := 1; % this does nothing, it's too late
+
+ stack.nw = (0,0);
+ drawObject(stack);
+
+ % 2
+ PictureStack.stackb("item A", "item B long", "C")("vcenter");
+ stackb.info.boxed := 1;
+ stackb.pict[0].info.boxed := 1;
+ stackb.pict[2].info.boxed := 1;
+
+ stackb.nw = (100,0);
+ drawObject(stackb);
+
+ % 3
+ PictureStackInfoCopy.myInfo(iStack);
+ myInfo.boxed := 1;
+ myInfo.iPict.boxed := 1;
+ EPictureStack.stackc(myInfo)("item A", "item B long", "C")("vcenter");
+
+ stackc.nw = (200,0);
+ drawObject(stackc);
+endfig;
+
+beginfig(5);
+ vardef joinCallback= enddef;
+ PictureStack.custom("A.A", "B__________B", "C-----C")
+ ("joinCallback");
+
+ drawObject(custom);
+endfig;
+
+beginfig(6);
+ save custom;
+
+ pickup pencircle scaled 4pt;
+ drawdot origin;
+
+ vardef joinCallbackA=
+ setObjectJoin(pa.bottom = pb.top + index*10; pa.left = pb.left);
+ setObjectJoinFirst(pa.nw = (30,0));
+ enddef;
+
+ PictureStack.customA("go", "further", "and further", "and further still")
+ ("joinCallbackA");
+
+ vardef joinCallbackB=
+ setObjectJoin(pb.bottom = customA.pict[index].bottom; pb.midx = pa.midx);
+ setObjectJoinFirst(pa.bottom = customA.pict[index].bottom);
+ enddef;
+
+ PictureStack.customB(".", "..", "...", "....")
+ ("joinCallbackB");
+
+ drawObjects(customA, customB);
+endfig;
+
+beginfig(7);
+ save stackX;
+ save stylePA, stylePB;
+ save stylePictureStack;
+
+ PictureInfoCopy.stylePA(iPict);
+ stylePA.borderColor := green;
+ stylePA.boxed := 1;
+
+ PictureInfoCopy.stylePB(iPict);
+ stylePB.borderColor := red;
+ stylePB.boxed := 1;
+
+ PictureStackInfoCopy.stylePictureStack(iStack);
+
+ def styleSupplier(expr i)= if i mod 2 = 0: stylePA else: stylePB fi enddef;
+
+ stylePictureStack.childStyleSupplier := "styleSupplier";
+
+ EPictureStack.stackX(stylePictureStack)("a","b","c","d","e")("vcenter");
+
+ drawObjects(stackX);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_tex_rendering.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_tex_rendering.mp
new file mode 100644
index 0000000000..3c04129869
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_picture_tex_rendering.mp
@@ -0,0 +1,43 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+input TEX;
+
+beginfig(1);
+ PictureInfoCopy.myP(iPict);
+ myP.boxed := 1;
+ myP.ignoreNegativeBase := 1;
+
+ EPicture.p(myP)( TEX("Hello, world $x=7$") );
+
+ PictureStackInfoCopy.myPS(iStack);
+ myPS.boxed := 1;
+ myPS.iPict.boxed := 1;
+ myPS.iPict.ignoreNegativeBase := 1;
+
+ EPictureStack.ps(myPS)("Hello, world!",
+ TEX("This is cool: $x=y$."),
+ TEX("But this is insane: $\sum_1^3 f(x) \over x$!") ) ("vleft");
+
+ leftToRight(20)(p, ps);
+
+ drawObjects(p, ps);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_positioning.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_positioning.mp
new file mode 100644
index 0000000000..6603476771
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_positioning.mp
@@ -0,0 +1,195 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+iPict.boxed := 1;
+spacing := 5;
+string strA, strB, strC;
+strA := "a";
+strB := "...";
+strC := "XYZ";
+
+beginfig(1);
+ save A, B, C, X, Y, Z;
+
+ Picture.A(strA);
+ Picture.B(strB);
+ Picture.C(strC);
+
+ align(top, left, right)(spacing)("+")(A, B, C);
+
+ drawObjects(A, B, C);
+
+ draw (A.left, A.top) -- (C.right, A.top);
+
+ %%%%
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ leftToRight.top(spacing)(X, Y, Z);
+
+ X.top = A.bottom - 10;
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.top) -- (Z.right, X.top);
+endfig;
+
+beginfig(2);
+ save A, B, C, X, Y, Z;
+
+ Picture.A(strA);
+ Picture.B(strB);
+ Picture.C(strC);
+
+ align(midy, left, right)(spacing)("+")(A, B, C);
+
+ drawObjects(A, B, C);
+
+ draw (A.left, A.midy) -- (C.right, A.midy);
+
+ %%%%
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ leftToRight.midy(spacing)(X, Y, Z);
+
+ X.top = A.bottom - 10;
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.midy) -- (Z.right, X.midy);
+endfig;
+
+beginfig(3);
+ save A, B, C, X, Y, Z;
+
+ Picture.A(strA);
+ Picture.B(strB);
+ Picture.C(strC);
+
+ align(bottom, left, right)(spacing)("+")(A, B, C);
+
+ drawObjects(A, B, C);
+
+ draw (A.left, A.bottom) -- (C.right, A.bottom);
+
+ %%%%
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ leftToRight.bottom(spacing)(X, Y, Z);
+
+ X.top = A.bottom - 10;
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.bottom) -- (Z.right, X.bottom);
+endfig;
+
+beginfig(4);
+ save A, B, C, X, Y, Z;
+
+ Picture.A(strA);
+ Picture.B(strB);
+ Picture.C(strC);
+
+ align(left, top, bottom)(spacing)("-")(A, B, C);
+
+ drawObjects(A, B, C);
+
+ draw (A.left, A.top) -- (A.left, C.bottom);
+
+ %%%%
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ topToBottom.left(spacing)(X, Y, Z);
+
+ X.top = C.bottom - 10;
+
+ drawObjects(X, Y, Z);
+
+ draw (X.left, X.top) -- (X.left, Z.bottom);
+endfig;
+
+beginfig(5);
+ save A, B, C, X, Y, Z;
+
+ Picture.A(strA);
+ Picture.B(strB);
+ Picture.C(strC);
+
+ align(midx, top, bottom)(spacing)("-")(A, B, C);
+
+ drawObjects(A, B, C);
+
+ draw (A.midx, A.top) -- (A.midx, C.bottom);
+
+ %%%%
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ topToBottom.midx(spacing)(X, Y, Z);
+
+ X.top = C.bottom - 10;
+
+ drawObjects(X, Y, Z);
+
+ draw (X.midx, X.top) -- (X.midx, Z.bottom);
+endfig;
+
+beginfig(6);
+ save A, B, C, X, Y, Z;
+
+ Picture.A(strA);
+ Picture.B(strB);
+ Picture.C(strC);
+
+ align(right, top, bottom)(spacing)("-")(A, B, C);
+
+ drawObjects(A, B, C);
+
+ draw (A.right, A.top) -- (A.right, C.bottom);
+
+ %%%%
+
+ Picture.X(strA);
+ Picture.Y(strB);
+ Picture.Z(strC);
+
+ topToBottom.right(spacing)(X, Y, Z);
+
+ X.top = C.bottom - 10;
+
+ drawObjects(X, Y, Z);
+
+ draw (X.right, X.top) -- (X.right, Z.bottom);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins.mp
new file mode 100644
index 0000000000..750cee4e97
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins.mp
@@ -0,0 +1,26 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+input metauml_skin_simple;
+
+beginfig(1);
+ Class.HelloSkin("HelloSkin")("nice: int")("done(): void");
+ drawObject(HelloSkin);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins_global_defaults.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins_global_defaults.mp
new file mode 100644
index 0000000000..aaeffd043b
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_skins_global_defaults.mp
@@ -0,0 +1,29 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+string metauml_defaultFont, metauml_defaultFontLight;
+metauml_defaultFont := "cmr12";
+metauml_defaultFontLight := "cmr10";
+
+input metauml;
+
+beginfig(1);
+ Class.HelloSkinB("HelloSkinGlobal")("foo: int")("bar(): void");
+ drawObject(HelloSkinB);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_state.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_state.mp
new file mode 100644
index 0000000000..5420750749
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_state.mp
@@ -0,0 +1,73 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+beginfig(1);
+ EntryPoint.entry;
+ ExitPoint.exit;
+
+ entry.nw = (0,0);
+ exit.nw = (50,50);
+
+ drawObjects(entry, exit);
+ clink(transition)(entry, exit);
+endfig;
+
+beginfig(2);
+ EState.myState(iState)("The light is", "visibly on")();
+ drawObject(myState);
+
+ State.anotherState("Another nice state")();
+ anotherState.info.drawNameLine := 1;
+ drawObjectAt(anotherState)(anotherState.nw = (0,50));
+endfig;
+
+beginfig(3);
+ State.interesting("Interesting state")();
+ State_internalTransitions.interesting("OnEntry / doVeryHappy", "OnExit / doSomewhatSad");
+ interesting.info.drawNameLine := 1;
+
+ drawObject(interesting);
+endfig;
+
+beginfig(4);
+ Begin.b;
+ End.e;
+ State.sa("A state")();
+ State.sb("Another state")();
+ setObjectJoin(pb.w = pa.e + (40, 0));
+ joinObjects(b, sa, sb, e);
+
+ State.composite("Composite state")(b, e, sa, sb);
+ drawObject(composite);
+
+ clink(transition)(b, sa);
+ clink(transition)(sa, sb);
+ clink(transition)(sb, e);
+endfig;
+
+beginfig(5);
+endfig;
+
+beginfig(6);
+endfig;
+
+beginfig(7);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_usecase.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_usecase.mp
new file mode 100644
index 0000000000..32688814cf
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/test_usecase.mp
@@ -0,0 +1,185 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+input metauml;
+
+HumanInfoCopy.iDwarf(iHuman);
+iDwarf.width := 60;
+iDwarf.height := 20;
+iDwarf.foreColor := blue;
+iDwarf.shadeColor := .8blue;
+
+beginfig(1);
+ Human.h;
+ drawObject(h);
+ draw objectBox(h);
+
+ Human.h1;
+ h1.n = (35, 0);
+ h1.info.foreColor := red;
+ drawObject(h1);
+
+ Human.h2;
+ h2.info.height := 90;
+ h2.nw = (50,0);
+ drawObject(h2);
+ draw objectBox(h2);
+
+ EHuman.d(iDwarf);
+ drawObjectAt(d)(d.s = (10,-50));
+
+ EHuman.d2(iDwarf);
+ d2.info.shadeColor := red;
+ drawObjectAt(d2)(d2.s = (10,-80));
+endfig;
+
+beginfig(2);
+ save a,b;
+
+ Actor.a("foo");
+ drawObject(a);
+
+ Actor.b("Actor line one", "and line two");
+ Actor_setDebugMode.b;
+ b.n = (70,0);
+ drawObject(b);
+endfig;
+
+beginfig(3);
+ Usecase.u("foo");
+ drawObject(u);
+
+ draw objectBox(u) withpen pencircle scaled .1;
+
+ draw u.n withpen pencircle scaled 2 withcolor red;
+ draw u.s withpen pencircle scaled 2 withcolor red;
+ draw u.e withpen pencircle scaled 2 withcolor red;
+ draw u.w withpen pencircle scaled 2 withcolor red;
+
+ draw u.ulft withpen pencircle scaled 2 withcolor blue;
+ draw u.urt withpen pencircle scaled 2 withcolor blue;
+ draw u.llft withpen pencircle scaled 2 withcolor blue;
+ draw u.lrt withpen pencircle scaled 2 withcolor blue;
+
+ Usecase.login("Log in for an eagerly", "awaiting user", "which spans well into a very long 3rd line.");
+ login.s = (0, 5);
+ drawObject(login);
+
+ Usecase.t("Line 1 goo bar", "Line 2");
+ t.s = login.n + (0,10);
+ drawObject(t);
+
+ Usecase.q("Line 1 abcdefg hij", "abcde", "Line 3 abc def ghe jkl", "Line 4 x");
+ q.s = t.n + (0,10);
+ drawObject(q);
+
+endfig;
+
+beginfig(4);
+ Actor.userA("User A2", "line 2", "line 3 long long long");
+ % Any Actor object is made of two sub-objects: nameStack and human.
+ % Each individual picture in the nameStack can be configured individually.
+ %
+ % However, it is not possible to configure all the lines in the nameStack at
+ % once now, saying something like:
+ %
+ % userA.nameStack.info.iPict.iFont.scale := 3;
+ %
+ % This happens because the information above is copied into the Picture objects
+ % in the Actor constructor (and it is useless to modify it afterwards).
+ %
+ % If you do want to make such global modifications of the settings, see the
+ % next two examples.
+
+ userA.nameStack.pict[0].info.iFont.scale := 1.2;
+ userA.nameStack.pict[1].info.iFont.scale := .7;
+ userA.nameStack.info.borderColor := blue;
+ userA.nameStack.info.boxed := 1;
+ userA.nameStack.group.info.left := 30;
+ userA.nameStack.group.info.right := 5;
+ userA.human.info.foreColor := red;
+
+ drawObject(userA);
+ %draw objectBox(userA.nameStack);
+ %draw objectBox(userA.human);
+endfig;
+
+beginfig(5);
+ save userA;
+ % If you want to have preset a info for specific objects
+
+ ActorInfoCopy.iBig(iActor);
+
+ % ActorInfo contains info-s for two objects
+ % iNameStack: for the stack representing the actor's name
+ % iHuman: for the little human
+
+ iBig.iNameStack.iPict.iFont.scale := 3;
+ iBig.iNameStack.spacing := 25;
+ iBig.iHuman.height := 25;
+
+ EActor.userA(iBig)("User A", "Specifically configured");
+ drawObject(userA);
+endfig;
+
+beginfig(6);
+ save userA;
+
+ iActor.iNameStack.iPict.iFont.scale := 2;
+ iActor.iNameStack.spacing := 18;
+
+ Actor.userA("User A", "Globally configured");
+ drawObject(userA);
+endfig;
+
+beginfig(7);
+ save usecaseA;
+ Usecase.usecaseA("A highly customizable", "usecase. Foo bar!");
+ usecaseA.info.iNameStack.iPict.iFont.scale := .5;
+ drawObject(usecaseA);
+endfig;
+
+beginfig(8);
+ save usecaseA;
+ Usecase.usecaseA("A highly customizable", "usecase. Foo bar 2!");
+ usecaseA.info.iNameStack.iPict.iFont.scale := 1.1;
+ usecaseA.info.foreColor := red;
+ usecaseA.info.borderColor := blue;
+ usecaseA.info.iShade.background := green;
+ usecaseA.info.iShade.shift := 4;
+ drawObject(usecaseA);
+endfig;
+
+beginfig(9);
+ save usecaseA;
+ UsecaseInfoCopy.iMyUsecase(iUsecase);
+ iMyUsecase.iNameStack.iPict.iFont.scale := .6;
+ iMyUsecase.iNameStack.spacing := 5;
+ iMyUsecase.foreColor := green;
+ iMyUsecase.iShade.background := red;
+
+ EUsecase.usecaseA(iMyUsecase)("A highly ", " customizable usecase.");
+ EUsecase.usecaseB(iMyUsecase)("Another very ", " customizable usecase.");
+
+ usecaseB.info.iShade.background := green;
+
+ leftToRight(20)(usecaseA, usecaseB);
+ drawObjects(usecaseA, usecaseB);
+endfig;
+
+end
+
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase.mp
new file mode 100644
index 0000000000..ca8040f57b
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase.mp
@@ -0,0 +1,43 @@
+% Sample MetaUML figures.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+input metauml;
+
+beginfig(1);
+ Usecase.U("Authenticate user",
+ "by name, password");
+ drawObject(U);
+endfig;
+
+beginfig(2);
+ Actor.A("User");
+ drawObject(A);
+endfig;
+
+beginfig(3);
+ save A;
+
+ Actor.A("Administrator");
+ drawObject(A);
+ draw A.nw -- A.ne -- A.se -- A.sw -- cycle;
+ draw A.human.nw -- A.human.ne -- A.human.se -- A.human.sw -- cycle;
+
+endfig;
+
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase_diagrams.mp b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase_diagrams.mp
new file mode 100644
index 0000000000..110ca35c07
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/fig/usecase_diagrams.mp
@@ -0,0 +1,48 @@
+% Part of the MetaUML manual.
+% Copyright (C) 2005 Ovidiu Gheorghies
+%
+% This program is free software; you can redistribute it and/or
+% modify it under the terms of the GNU General Public License
+% as published by the Free Software Foundation; either version 2
+% of the License, or (at your option) any later version.
+%
+% This program is distributed in the hope that it will be useful,
+% but WITHOUT ANY WARRANTY; without even the implied warranty of
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+% GNU General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program; if not, write to the Free Software
+% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+% for f in `find . | grep '.*\.[1-9]'`; do echo $f; done
+
+input metauml;
+
+beginfig(1);
+ Actor.user("User");
+ Actor.db("Database");
+
+ Usecase.dbquery("Query database");
+ Usecase.auth("Authentification");
+ Usecase.authA("Authentification by", "username, password");
+ Usecase.authB("Authentification by", "smartcard");
+
+ auth.w = user.human.e + (30,0);
+ dbquery.s = auth.n + (0,30);
+ db.human.w = dbquery.e + (30,0);
+
+ authB.left - authA.right = 30;
+ authB.midy = authA.midy;
+ .5[authB.w, authA.e] = (auth.midx, auth.bottom - 50);
+
+ drawObjects(user, auth, dbquery, db, authA, authB);
+
+ clink(inheritance)(authA, auth);
+ clink(inheritance)(authB, auth);
+ clink(association)(auth, dbquery);
+ clink(association)(user.human, auth);
+ clink(association)(dbquery, db.human);
+endfig;
+
+end
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.bib b/graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.bib
new file mode 100644
index 0000000000..845db1968f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.bib
@@ -0,0 +1,64 @@
+@misc{metaobj,
+ author = "Denis Roegel",
+ title = "The {METAOBJ} tutorial and reference manual",
+ year = "2002",
+ url = "http://texdoc.net/texmf-dist/doc/metapost/metaobj/momanual.pdf"
+}
+@book{texbook,
+ author = "Donald E. Knuth",
+ title = "The {\TeX{}}book",
+ year = "1986",
+ publisher = "Addison-Wesley Publishing Company"
+}
+@book{latexbook,
+ author = "Leslie Lamport",
+ title = "{\LaTeX} a {D}ocument {P}reparation {S}ystem",
+ year = "1994",
+ publisher = "Addison-Wesley Publishing Company"
+}
+@misc{metapost,
+ author = "John D. Hobby",
+ title = "{METAPOST} {A} {U}ser's {M}anual",
+ year = "2018",
+ url = "http://www.tug.org/tutorials/mp/mpman.pdf"
+}
+@misc{umlsty,
+ author = "Ellef Fange Gjelstad",
+ title = "uml.sty, a package for writing {UML} diagrams in {LATEX}",
+ year = "2010",
+ url = "http://mirror.hmc.edu/ctan/graphics/pstricks/contrib/uml/uml.pdf"
+}
+
+@misc{pstumlsty,
+ author = "Maurice Diamantini",
+ title = "Interface utilisateur du package pst-uml",
+ year = "2006",
+ url = "http://mirrors.nxthost.com/ctan/graphics/pstricks/contrib/pst-uml/pst-uml-doc.pdf"
+}
+
+@misc{umldoc,
+ author = "Doug Palmer",
+ title = "The umldoc {UML} {D}ocumentation {P}ackage",
+ year = "1999",
+ url = "https://www.charvolant.org/elements/umldoc.pdf"
+}
+
+@misc{tikzuml,
+ author = "Nicolas Kielbasiewicz",
+ title = "The {T}ik{Z}-{UML} package",
+ year = "2016",
+ url = "http://perso.ensta-paristech.fr/~kielbasi/tikzuml/var/files/doc/tikzumlmanual.pdf"
+}
+
+@misc{svglatex,
+ author = "Johan B. C. Engelen",
+ title = "How to include an SVG image in LATEX",
+ url = "http://tug.ctan.org/info/svg-inkscape/InkscapePDFLaTeX.pdf"
+}
+
+@misc{umlomg,
+ publisher = "Object Management Group",
+ title = "{OMG}® {U}nified {M}odeling {L}anguage® ({OMG} {UML}®)",
+ year = "2017",
+ url = "https://www.omg.org/spec/UML/2.5.1/"
+}
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.tex b/graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.tex
new file mode 100644
index 0000000000..933130a33d
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/metauml-manual.tex
@@ -0,0 +1,2072 @@
+% MetaUML: Tutorial, Reference and Test Suite
+%
+% Copyright (c) 2005-2019 Ovidiu Gheorghies
+% Permission is granted to copy, distribute and/or modify this document
+% under the terms of the GNU Free Documentation License, Version 1.2
+% or any later version published by the Free Software Foundation;
+% with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+% A copy of the license is included in the section entitled "GNU
+% Free Documentation License".
+
+\documentclass{article}
+
+\usepackage[utf8]{inputenc}
+\usepackage[pdftex,colorlinks=true]{hyperref}
+\usepackage{multicol}
+\usepackage{multido}
+\usepackage[style=ieee]{biblatex}
+\addbibresource{metauml-manual.bib}
+
+\ifx\pdftexversion\undefined
+ \usepackage[dvips]{graphicx}
+\else
+ \usepackage[pdftex]{graphicx}
+ \DeclareGraphicsRule{*}{mps}{*}{}
+\fi
+
+\newcommand{\code}{\ttfamily}
+
+\setcounter{page}{1}
+
+\begin{document}
+
+MetaUML: A Manual and Test Suite
+
+\begin{quote}
+ Copyright \copyright 2005-2019 Ovidiu Gheorghie\c{s}.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+\end{quote}
+
+\pagebreak
+This page is intentionally left blank.
+
+\pagebreak
+\title{MetaUML: A Manual and Test Suite}
+
+\author{Ovidiu Gheorghie\c{s}}
+
+\maketitle
+
+\begin{abstract}
+MetaUML is a MetaPost \cite {metapost} library for creating UML \cite{umlomg} diagrams by means of a textual notation.
+While presenting the inner workings of MetaUML, this manual doubles as a step-by-step tutorial.
+More importantly, its source code contains many useful examples of diagrams, ranging from the very basic to the
+more advanced and customized.
+\end{abstract}
+
+\section{Introduction}
+
+Here is a quick MetaUML showcase:
+
+\begin{multicols}{2}
+\paragraph{A} Class Diagram\\
+\includegraphics[scale=.55]{fig/appetizer.1}
+\paragraph{B} Activity Diagram\\
+\includegraphics[scale=.55]{fig/appetizer.2}
+\paragraph{C} Notes\\
+\includegraphics[scale=.55]{fig/appetizer.5}
+\columnbreak
+\paragraph{D} Use Case Diagram\\
+\includegraphics[scale=.55]{fig/appetizer.3}
+\paragraph{E} State Machine Diagram\\
+\includegraphics[scale=.55]{fig/appetizer.4}
+\paragraph{F} Package Diagram\\
+\includegraphics[scale=.55]{fig/appetizer.6}
+\end{multicols}
+
+\pagebreak
+
+The code that generates these diagrams is quite straightforward, combining a natural object-oriented parlance
+with the power of MetaPost equation solving.
+
+For example, a UML class is drawn as follows:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("MyClass")
+ ("attr1: int", "attr2: int")
+ ("method1(): void",
+ "method2(): void");
+
+A.nw = (0, 0); % optional, implied
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/appetizer.7}
+\end{multicols}
+
+This code creates a visual object, referenced by its name {\code A}, of the MetaUML-defined type {\code Class}.
+Object {\code A} has the following content properties: a name
+({\code MyClass}), a list of attributes ({\code attr1}, {\code attr2})
+and a list of methods ({\code method1}, {\code method2}). To set the object's location, we assign a value to the
+so-called ``north-west'' point of the encompassing rectangle, {\code A.nw} --- a point which in actual fact references
+the upper-left corner.
+
+Every MetaUML visual object has the layout properties shown in figure \ref{fig:properties}.
+These properties may be used to set the location of any given object, either by assigning to them absolute values,
+or by linking them relatively to other objects via equations.
+
+\begin{figure}
+\centering
+\includegraphics{fig/properties.1}
+\caption{Layout properties of MetaUML objects. Here, a {\code Class} object is depicted.}
+\label{fig:properties}
+\end{figure}
+
+The following example demonstrates, respectively, the use of absolute and relative positioning for two classes, {\code A} and {\code B}.
+
+\begin{multicols}{2}
+\begin{verbatim}
+A.nw = (0,0);
+B.w = A.e + (20, 0);
+\end{verbatim}
+\columnbreak
+\includegraphics{fig/appetizer.8}
+\end{multicols}
+
+After the objects have been drawn, it becomes possible to attach links to them. In a class diagram, inheritance
+or association relations are meaningful links between classes, while in a state machine diagram, transitions between
+states can be used. Here is the general pattern used by MetaUML for drawing links:
+
+\begin{verbatim}
+link(<how-to-draw-information>)(<path-to-draw>);
+\end{verbatim}
+
+The ``how-to-draw-information'' is an object which defines the style of the line (e.g. solid, dashed) and the appearance
+of the heads (e.g. nothing, arrow, diamond). One such object, appropriately called {\code inheritance}, defines a solid
+line style and a white triangle head. The other parameter, the ``path-to-draw'', is simply a MetaPost path.
+
+For example, the following call draws an inheritance relation from class {\code B} to class {\code A}.
+
+\begin{verbatim}
+link(inheritance)(B.e -- A.w);
+\end{verbatim}
+
+The direction of the path is important, as MetaUML uses it to determine the
+type of adornment to attach to the link ends (if applicable). In our example, a white triangle,
+denoting inheritance, points towards the end of the path, that is towards class {\code A}.
+
+Let us sum up with a diagram typical for MetaUML use. Firstly, we define the objects that we want to include
+in our diagram. Secondly, we position these objects relative to each other. Thirdly, we draw the objects. Finally, we
+draw the links, by referencing the layout properties of the previously drawn objects. Note that in our example the
+positioning of {\code A} need not be set explicitly because ``floating'' objects are automatically positioned at
+{\code (0,0)} by their draw method.
+
+\begin{multicols}{2}
+
+\begin{verbatim}
+input metauml;
+
+beginfig(1);
+ Class.A("A")()(); % 1. Define the objects
+ Class.B("B")()();
+ B.w = A.e + (20, 0); % 2. Position the objects
+ drawObjects(A, B); % 3. Draw the objects
+ link(inheritance)(B.w -- A.e); % 4. Draw links between objects
+endfig;
+end
+\end{verbatim}
+\columnbreak
+\includegraphics{fig/appetizer.9}
+\end{multicols}
+
+As far as a user is concerned, this is all there is to MetaUML. With a reference describing how the
+UML elements are created, arbitrarily complex diagrams can be crafted.
+
+\section{Class Diagrams}
+
+A class is created as follows:
+
+\begin{verbatim}
+Class.<name>(<class-name>)
+ (<list-of-attributes>)
+ (<list-of-methods>);
+\end{verbatim}
+
+The suffix {\code <name>} specifies an identifier for the newly created {\code Class} object
+(which, of course, represents a UML class).
+The name of the UML class is a string given by {\code <class-name>};
+the attributes and methods are given as list of strings, {\code <list-of-attributes>} and {\code <list-of-methods>}
+respectively. The list of attributes and the list of methods may be void.
+
+An attribute or a method string may begin with a visibility marker: ``$+$'' for
+public, ``\#'' for protected, ``$-$'' for private, and ``\textasciitilde'' for package private.
+The default visibility is package private.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("Point")
+ ("#x:int", "#y:int")
+ ("+set(x:int, y:int)",
+ "+getX():int",
+ "+getY():int",
+ "-debug():void",
+ "test():void");
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\includegraphics{fig/class.1}
+\end{multicols}
+
+To disable showing the visibility markers, use {\code Class\_noVisibilityMarkers}, as shown below:
+
+\begin{multicols}{2}
+\begin{verbatim}
+ Class.A("Point")
+ ("#x:int", "#y:int")
+ ("+toString():String");
+ Class_noVisibilityMarkers.A;
+
+ drawObject(A);
+\end{verbatim}
+\columnbreak
+\includegraphics{fig/class.15}
+\end{multicols}
+
+\subsection{Stereotypes}
+
+After a class is created, but before it is drawn, its stereotypes may be specified by using {\code Class\_stereotypes}:
+
+\begin{verbatim}
+Class_stereotypes.<name>(<list-of-stereotypes>);
+\end{verbatim}
+
+Here, {\code <name>} is the object name of a previously created class and {\code <list-of-stereotypes>}
+is a comma-separated list of strings. Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("User")()();
+Class_stereotypes.A("<<interface>>","<<home>>");
+
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/class.2}
+\end{multicols}
+
+\subsection{Interfaces and Abstract Classes}
+
+At times it is preferred to write the name of an interface in an oblique font, rather than using the ``interface''
+stereotype. This can be easily achieved by using the macro {\code Interface}:
+
+\begin{verbatim}
+Interface.name(class-name)
+ (list-of-methods);
+\end{verbatim}
+
+Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Interface.A("Observer")
+ ("+update(src:Object)");
+
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/class.11}
+\end{multicols}
+
+Since internally {\code Interface} treated as a special kind of {\code Class}, the code above is equivalent to:
+\begin{verbatim}
+EClass.A(iInterface)("Observer")()
+ ("+update(src:Object)");
+\end{verbatim}
+
+Abstract classes can be drawn similarly using the {\code iAbstractClass} style:
+\begin{samepage}
+\begin{multicols}{2}
+\begin{verbatim}
+EClass.A(iAbstractClass)("Observable")
+ ("observers: Observer[0..*]")
+ ("+addObserver(o: Observer)",
+ "+notify()");
+
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/class.12}
+\end{multicols}
+\end{samepage}
+
+If you prefer, you can use equivalent construct:
+
+\begin{verbatim}
+AbstractClass.A("Observable")
+ ("observers: Observer[0..*]")
+ ("+addObserver(o: Observer)",
+ "+notify()");
+\end{verbatim}
+
+\subsection{Displaying Class Name Only}
+
+If you want the empty methods and attributes compartments in a class not being displayed, one way is to set the spacing
+at their top and the bottom to {\code 0}:
+\begin{samepage}
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("MyModel")()();
+A.info.iName.top := 10;
+A.info.iName.bottom := 10;
+A.info.iAttributeStack.top := 0;
+A.info.iAttributeStack.bottom := 0;
+A.info.iMethodStack.top := 0;
+A.info.iMethodStack.bottom := 0;
+
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/class.13}
+\end{multicols}
+\end{samepage}
+
+The same effect can be achieved by using the formatting information object {\code iClassNameOnly} or the {\code ClassName} macro:
+
+\begin{multicols}{2}
+\begin{verbatim}
+EClass.A(iClassNameOnly)("MyModel")()();
+ClassName.B("AnotherModel");
+Class_stereotypes.B("<<smart>>");
+
+topToBottom(20)(A, B);
+
+drawObjects(A, B);
+\end{verbatim}
+\columnbreak
+\hspace{2cm}\includegraphics{fig/class.14}
+\end{multicols}
+
+To customize the space around the class name globally, you can set the values of {\code iClassNameOnly.iName.top} and {\code iClassNameOnly.iName.bottom}. Individually, for a given object, say {\code B}, the attributes {\code B.info.iName.top} and {\code B.info.iName.bottom} can be used.
+
+\subsection{Objects (or Class Instances)}
+
+A UML object (or class instance) is created as follows:
+
+\begin{verbatim}
+Instance.name(object-name)
+ (list-of-attributes);
+\end{verbatim}
+
+The suffix {\code name} gives a name to the {\code Instance} object. The name of the object (given by {\code object-name}) is typeset underlined. The attributes are given as a comma-separated list of strings, {\code list-of-attributes}.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Instance.order("o: Order")
+ ("name='book'", "{placed}", "{payed}");
+drawObject(order);
+\end{verbatim}
+\columnbreak
+\hspace{2cm}\includegraphics{fig/instance.1}
+\end{multicols}
+
+
+\subsection{Parametrized Classes (Templates)}
+
+The most convenient way of typesetting a class template in MetaUML is to use the macro {\code ClassTemplate}.
+This macro creates a visual object which is appropriately positioned near the class object it adorns.
+
+\begin{verbatim}
+ClassTemplate.name(list-of-templates)
+ (class-object);
+\end{verbatim}
+
+The {\code name} is the name of the template object, {\code list-of-templates} is a comma-separated list of strings and the {\code class-object} is the name of a class object.
+
+Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("Vector")()();
+ClassTemplate.T("T", "size: int")(A);
+
+drawObjects(A, T);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/class.3}
+\end{multicols}
+
+The macro {\code Template} can also be used to create a template object, but this time the resulting
+object can be positioned freely.
+
+\begin{verbatim}
+Template.name(list-of-templates);
+\end{verbatim}
+
+Of course, it is possible to specify both stereotypes and template parameters for a given class.
+
+\subsection{Types of Links}
+
+In this section we enumerate the relations that can be drawn between classes by means
+of MetaUML macros. Suppose that we have the declared two points, {\code A} (on the left)
+and {\code B} (on the right):
+
+\begin{verbatim}
+pair A, B;
+A = (0,0);
+B = (50,0);
+\end{verbatim}
+
+\begin{tabular}{||l|c||}
+\hline
+{\code link(association)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.4} \\
+\hline
+{\code link(associationUni)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.5} \\
+\hline
+{\code link(inheritance)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.6} \\
+\hline
+{\code link(realization)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.12} \\
+\hline
+{\code link(aggregation)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.7} \\
+\hline
+{\code link(aggregationUni)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.8} \\
+\hline
+{\code link(composition)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.9} \\
+\hline
+{\code link(compositionUni)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.10} \\
+\hline
+{\code link(dependency)(X.e -- Y.w)} & \includegraphics{fig/class_diagrams.11} \\
+\hline
+\end{tabular}
+
+\subsection{Associations}
+In UML an association typically has two of association ends and may have a name specified for it.
+In turn, each association end may specify a multiplicity, a role, a visibility, an ordering.
+These entities are treated in MetaUML as pictures having specific drawing information
+(spacings, font).
+
+The first method of creating association ``items'' is by giving them explicit names.
+Having a name for an association item comes in handy when referring to its properties
+is later needed (see the non UML-compliant diagram below). The last parameter of the macro {\code item} is an equation which may use the item's name to perform positioning.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.P("Person")()();
+Class.C("Company")()();
+% drawing code ommited
+
+item.aName(iAssoc)("works for")
+ (aName.s = .5[P.w, C.w]);
+draw aName.n -- (aName.n + (20,20));
+label.urt("association name" infont "tyxtt",
+ aName.n + (20,20));
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics[scale=.8]{fig/class_association.1}
+\end{multicols}
+
+However, giving names to every association item may become an annoying burden
+(especially when there are many of them). Because of this, MetaUML also allows for
+``anonymous items''. In this case, the positioning is set by an equation
+which refers to the anonymous item as {\code obj}.
+
+\begin{multicols}{2}
+\begin{verbatim}
+% P and C defined as in the previous example
+
+item(iAssoc)("employee")(obj.nw = P.s);
+item(iAssoc)("1..*")(obj.ne = P.s);
+
+% other items are drawn similarly
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/class_association.2}
+\end{multicols}
+
+\subsection{Dependencies and Stereotypes}
+
+Stereotypes are frequently used with dependencies. Below is an example.
+\pagebreak
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.F("Factory")()();
+Class.O("Object")()();
+
+O.n = F.s - (0, 50);
+drawObjects(F, O);
+
+clink(dependency)(F, O);
+item(iStereo)("<<creates>>")(obj.w = .5[F.s,O.n])
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/class_association.3}
+\end{multicols}
+
+\section{Notes}
+
+A note is created as follows:
+
+\begin{verbatim}
+Note.name(list-of-lines);
+\end{verbatim}
+
+The suffix {\code name} is the name of the {\code Note} object. The contents of the note is given by a comma-separated
+list of strings, {\code list-of-lines}, gives the text contents of the note object, each string being drawn on its own
+line.
+
+Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Note.A("This note", "has two lines.");
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/note.1}
+\end{multicols}
+
+\subsection{Attaching notes to diagram elements}
+
+Notes can be attached to diagram elements by using a link of type {\code dashedLink}.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Note.A("This is a class");
+Class.C("Object")()();
+
+A.sw = C.ne + (20, 20);
+
+drawObject(A, C);
+
+clink(dashedLink)(A, C);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/note.2}
+\end{multicols}
+
+Now let us see a more complex example, which demontrates the ability of accessing sub-elements in a MetaUML diagram.
+\pagebreak
+
+\begin{multicols}{2}
+\begin{verbatim}
+Note.nA("This is the class name");
+Note.nB("This is a key attribute");
+Note.nC("This is a nice method");
+
+Class.C("Object")("+id:int")
+ ("+clone()", "+serialize()");
+
+topToBottom.left(10)(nA, nB, nC);
+leftToRight(10)(C, nB);
+
+drawObjects(C, nA, nB, nC);
+
+clink(dashedLink)(C.namePict, nA);
+clink(dashedLink)(C.attributeStack.pict[0], nB);
+clink(dashedLink)(C.methodStack.pict[1], nC);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/note.3}
+\end{multicols}
+
+Macros like {\code leftToRight} and {\code topToBottom} are presented in section \ref{section:positioning}.
+
+\subsection{Using mathematical formulae}
+
+MetaUML notes can contain mathematical formulae written in TeX \cite{texbook}. Regretably, LaTeX \cite{latexbook} support for formulae is {\bf not} available.
+Limited as it may be, this feature is considered experimental, as it is not always straightforward to use. In the example below, note that the MetaPost package {\code TEX} is imported.
+
+\begin{multicols}{2}
+\begin{verbatim}
+input metauml;
+input TEX;
+
+beginfig(1);
+ Note.A("This class implements the formula:",
+ TEX("$\sum_1^n f(x) \cdot dx$"));
+ drawObjects(A);
+endfig;
+
+end
+\end{verbatim}
+\columnbreak
+\hspace{0.5cm}\includegraphics{fig/note.4}
+\end{multicols}
+
+For taller formulae, you must be prepared to do some advanced stunts. Remark: {\code "aaa" \& "bbb"} is MetaPost's way to concatenate the strings into {\code "aaabbb"};
+the string containing the formula was split in two for layout reasons.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Note.A("Can you do it?",
+ TEX("$\sum_1^n f(x) \cdot dx " &
+ "\over \sum_1^m g(y) \cdot dy$"));
+A.stack.info.spacing := 30;
+A.stack.pict[1].info.ignoreNegativeBase := 0;
+
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/note.5}
+\end{multicols}
+
+Alas, this trick does not entirely solve the problem: a third line in the note would be badly aligned. Therefore,
+until MetaUML's {\code Note} class is upgraded to better support this scenario, you may want to limit yourself
+to two lines per note --- at least when tall formulae are involved.
+
+\section{Packages}
+
+MetaUML allows for the creation of packages in various forms. Firstly, we have the option of writing the package
+name in the middle of the main box. Secondly, we can write the name on the tiny box above the main box, leaving
+the main box empty. Lastly, we can write the package name as in the second case, but the main box can have an arbitrary
+contents: classes, other packages, or even other UML items.
+
+The macro that creates a package has the following synopsis:
+
+\begin{verbatim}
+Package.name(package-name)(subitems-list);
+\end{verbatim}
+
+The parameter {\code package-name} is a string or a list of comma-separated strings representing the package's name.
+The {\code subitems-list} parameter is used to specify the subitems (tipically classes or packages) of this package;
+its form is as a comma-separated list of objects, which can be void.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Package.P("java.lang")();
+drawObject(P);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/package.1}
+\end{multicols}
+
+Below is another example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Package.P("An important", "package")();
+drawObject(P);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/package.2}
+\end{multicols}
+
+If you wish to leave the main box empty, you can use the following code:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Package.P("java.lang")();
+P.info.forceEmptyContent := 1;
+drawObject(P);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/package.3}
+\end{multicols}
+
+The same effect as above can be achieved globally by doing:
+
+\begin{verbatim}
+iPackage.forceEmptyContent := 1;
+\end{verbatim}
+
+More information on MetaUML's way of managing global and per-object configuration data can be found in
+section \ref{section:infrastructure} and section \ref{section:customization}.
+
+Here is an example involving items contained in a package.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("A")()();
+Class.B("B")()();
+Package.P("net.metauml")(A, B);
+
+leftToRight(10)(A, B);
+
+drawObject(P);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/package.4}
+\end{multicols}
+
+\subsection{Types of Links}
+
+The nesting relation between packages is created by using the {\code nest} link information.
+
+\begin{tabular}{||l|c||}
+\hline
+{\code link(nest)(X.e -- Y.w)} & \includegraphics{fig/package.5} \\
+\hline
+\end{tabular}
+
+\section{Component Diagrams}
+
+A component is created by the macro {\code Component}:
+
+\begin{verbatim}
+Component.name(component-name)
+ (subitems-list)
+\end{verbatim}
+
+The parameter {\code component-name} is a string representing the component's name. The {\code subitems-list} parameter
+is used to specify the subitems of this component (possibly classes, packages or other components); its form is as a
+comma-separated list of objects, which can be void.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Component.C("Business Logic")();
+drawObject(C);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/component.1}
+\end{multicols}
+
+Here is an example involving subitems in a component:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("A")()();
+Package.B("B")();
+Component.C("C")();
+
+Component.BigC("Big Component")(A, B, C);
+
+leftToRight(10)(A, B);
+topToBottom(10)(A, C);
+
+drawObject(BigC);
+\end{verbatim}
+\columnbreak
+\hspace{3cm}\includegraphics{fig/component.2}
+\end{multicols}
+
+\subsection{Types of Links}
+
+\begin{tabular}{||l|c||}
+\hline
+{\code link(requiredInterface)( A.e -- .5[A.e, B.w] );} & \includegraphics{fig/component.3} \\
+\hline
+{\code link(providedInterface)( .5[A.e, B.w] -- B.w );} & \includegraphics{fig/component.4} \\
+\hline
+\end{tabular}
+
+\vspace{0.5cm}
+
+The {\code requiredInterface} and {\code providedInterface} visual constructs can be easily combined, as shown in the following example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Component.A("A")();
+Component.B("B")();
+
+leftToRight(80)(A, B);
+
+drawObjects(A, B);
+
+link(providedInterface)( A.e -- .5[A.e, B.w] );
+link(requiredInterface)( B.w -- .5[A.e, B.w] );
+\end{verbatim}
+\columnbreak
+\hspace{-1cm}\includegraphics{fig/component.5}
+\end{multicols}
+
+
+\section{Use Case Diagrams}
+
+\subsection{Use Cases}
+An use case is created by the macro {\code Usecase}:
+
+\begin{verbatim}
+Usecase.name(list-of-lines);
+\end{verbatim}
+
+The {\code list-of-lines} is a comma-separated list of strings. These strings are placed
+on top of each other, centered and surrounded by the appropriate visual UML notation.
+
+Here is an use case example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Usecase.U("Authenticate user",
+ "by name, password");
+drawObject(U);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/usecase.1}
+\end{multicols}
+
+\subsection{Actors}
+
+An actor is created by the macro {\code Actor}:
+
+\begin{verbatim}
+Actor.name(list-of-lines);
+\end{verbatim}
+
+Here, {\code list-of-lines} represents the actor's name. For convenience, the name may be
+given as a list of strings which are placed on top of each other, to provide support for
+the situations when the role is quite long. Otherwise, giving a single string
+as an argument to the Actor constructor is perfectly fine.
+
+Here is an actor example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Actor.A("User");
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/usecase.2}
+\end{multicols}
+
+Sometimes it may be preferable to draw diagram relations positioned relatively to
+the visual representation of an actor (the ``human'') rather than relatively to the whole
+actor object (which also includes the text). Because of that, MetaUML provides access
+to the ``human'' of every actor object {\code actor} by means of the sub-object {\code actor.human}.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Actor.A("Administrator");
+drawObject(A);
+draw objectBox(A);
+draw objectBox(A.human);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/usecase.3}
+\end{multicols}
+
+In MetaUML, {\code objectBox(X)} is equivalent to {\code X.nw -- X.ne -- X.se -- X.sw -- cycle} for every object {\code X}. {\code A.human} is considered a MetaUML object, so you can use expressions like {\code A.human.n} or {\code A.human.midx}.
+
+\subsection{Types of Links}
+
+Some of the types of links defined for class diagrams (such as inheritance, association etc.) can be used with similar semantics within use case diagrams.
+
+\section{Activity Diagrams}
+
+\subsection{Begin, End and Flow End}
+
+The begin and the end of an activity diagram can be marked by using the macros {\code Begin}
+and {\code End} or {\code FlowFinal}, respectively. The constructors of these visual objects take no parameters:
+
+\begin{verbatim}
+Begin.beginName;
+End.endName;
+\end{verbatim}
+
+Below is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Begin.b;
+End.e;
+FlowFinal.f;
+
+leftToRight(20)(b, e, f);
+
+drawObjects(b, e, f);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/activity.1}
+\end{multicols}
+
+\subsection{Activity}
+
+An activity is constructed as follows:
+\begin{verbatim}
+Activity.name(list-of-strings);
+\end{verbatim}
+
+The parameter {\code list-of-strings} is a comma-separated list of strings. These strings are
+centered on top of each other to allow for the accommodation of a longer activity description
+within a reasonable space.
+
+An example is given below:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Activity.A("Learn MetaUML -",
+ "the MetaPost UML library");
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/activity.2}
+\end{multicols}
+
+\subsection{Fork and Join}
+
+A fork or join is created by the macro:
+
+\begin{verbatim}
+Fork.name(type, length);
+\end{verbatim}
+
+The parameter {\code type} is a string and can be either of {\code "h"}, {\code "horiz"}, {\code "horizontal"}
+for horizontal bars, and either of {\code "v"}, {\code "vert"}, {\code "vertical"} for vertical bars.
+The {\code length} gives the bar's length.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Fork.forkA("h", 100);
+Fork.forkB("v", 20);
+
+leftToRight(10)(forkA, forkB);
+
+drawObject(forkA, forkB);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/activity.3}
+\end{multicols}
+
+\subsection{Branch}
+
+A branch is created by the macro:
+
+\begin{verbatim}
+Branch.name;
+\end{verbatim}
+
+Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Branch.testA;
+
+drawObject(testA);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/activity.4}
+\end{multicols}
+
+
+\subsection{Types of Links}
+
+In activity diagrams, transitions between activities are needed. They are typeset
+as in the example below. In section \ref{composite-states} such a transition
+is showed. This type of link is also used for state machine diagrams.
+
+\begin{verbatim}
+link(transition)( pointA -- pointB );
+\end{verbatim}
+
+\section{State Diagrams}
+
+The constructor of a state allows for aggregated sub-states:
+
+\begin{verbatim}
+State.name(state-name)(substates-list);
+\end{verbatim}
+
+The parameter {\code state-name} is a string or a list of comma-separated strings representing
+the state's name or description. The {\code substates-list} parameter is used to specify
+the substates of this state as a comma-separated list of objects; this list may be void.
+
+An example of a simple state:
+
+\begin{multicols}{2}
+\begin{verbatim}
+State.s("Take order")();
+drawObject(s);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/state.1}
+\end{multicols}
+
+
+\subsection{Composite States}
+\label{composite-states}
+
+A composite state is defined by enumerating at the end of its constructor the inner
+states. Interestingly enough, the composite state takes care of drawing the sub-states it
+contains. The transitions must be drawn after the composite state, as seen in the
+next example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Begin.b;
+End.e;
+State.c("Component")();
+State.composite("Composite")(b, e, c);
+
+b.midx = e.midx = c.midx;
+c.top = b.bottom - 20;
+e.top = c.bottom - 20;
+
+composite.info.drawNameLine := 1;
+drawObject(composite);
+
+link(transition)(b.s -- c.n);
+link(transition)(c.s -- e.n);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/state.2}
+\end{multicols}
+
+\subsection{Internal Transitions}
+
+Internal transitions can be specified by using the macro:
+\begin{verbatim}
+stateTransitions.name(list-transitions);
+\end{verbatim}
+
+Identifier {\code name} gives the state object whose internal transitions are being set,
+and parameter {\code list-transitions} is a comma-separated string list.
+
+
+An example is given below:
+
+\begin{multicols}{2}
+\begin{verbatim}
+State.s("An interesting state",
+ "which is worth mentioning")();
+stateTransitions.s(
+ "OnEntry / Open eyes",
+ "OnExit / Sleep well");
+s.info.drawNameLine := 1;
+
+drawObject(s);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/state.3}
+\end{multicols}
+
+\subsection{Special States}
+
+Similarly to the usage of {\code Begin} and {\code End} macros, one can define history states,
+exit/entry point states and terminate pseudo-states, by using the following constructors.
+
+\begin{verbatim}
+History.nameA;
+ExitPoint.nameB;
+EntryPoint.nameC;
+Terminate.nameD;
+\end{verbatim}
+
+\section{Drawing Paths}
+
+The {\code link} macro is powerful enough to draw relations following arbitrary paths:
+
+\begin{multicols}{2}
+\begin{verbatim}
+path cool;
+cool := A.e .. A.e+(20,10) ..
+ B.s+(20,-40) .. B.s+(-10,-30)
+ -- B.s;
+link(inheritance)(cool);
+
+link(aggregationUni)
+ (A.n ..(30,30)..B.w);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/paths.1}
+\end{multicols}
+
+Amusing as it may be, this feature gets old soon. When typesetting UML diagrams in good style, rectangular paths are usually preferred.
+It is for this kind of paths that MetaUML offers extensive support, by means of ``syntactic sugar'' constructs which
+are not only self-documenting, but reduce the amount of typing and thinking required.
+
+\subsection{Manhattan Paths}
+
+The ``Manhattan'' path macros generate a path between two points consisting of one
+horizontal and one vertical segment. The macro {\code pathManhattanX} generates first a
+horizontal segment, while the macro {\code pathManhattanY} generates first a
+vertical segment. In MetaUML it also matters the direction of a path, so you
+can choose to reverse it by using {\code rpathManhattanX} and {\code rpathManhattanY}
+(note the prefix ``{\code r}''):
+
+\begin{verbatim}
+pathManhattanX(A, B)
+pathManhattanY(A, B)
+
+rpathManhattanX(A, B)
+rpathManhattanY(A, B)
+\end{verbatim}
+
+\pagebreak
+Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("A")()();
+Class.B("B")()();
+
+B.sw = A.ne + (10,10);
+drawObjects(A, B);
+
+link(aggregationUni)
+ (rpathManhattanX(A.e, B.s));
+link(inheritance)
+ (pathManhattanY(A.n, B.w));
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/paths.2}
+\end{multicols}
+
+\subsection{Stair Step Paths}
+
+These path macros generate stair-like paths between two points.
+The ``stair'' can ``rise'' first in the direction of $Ox$ axis ({\code pathStepX})
+or in the direction of $Oy$ axis ({\code pathStepY}). How much should a step
+rise is given by an additional parameter, {\code delta}. Again, the macros
+prefixed with ``{\code r}'' reverse the direction of the path given by their
+unprefixed counterparts.
+
+\begin{verbatim}
+pathStepX(A, B, delta)
+pathStepY(A, B, delta)
+
+rpathStepX(A, B, delta)
+rpathStepY(A, B, delta)
+\end{verbatim}
+
+Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+stepX:=60;
+link(aggregationUni)
+ (pathStepX(A.e, B.e, stepX));
+
+stepY:=20;
+link(inheritance)
+ (pathStepY(B.n, A.n, stepY));
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/paths.3}
+\end{multicols}
+
+\subsection{Horizontal and Vertical Paths}
+
+There are times when drawing horizontal or vertical links is required,
+even when the objects are not properly aligned. To this aim, the following macros
+are useful:
+
+\begin{verbatim}
+pathHorizontal(pA, untilX)
+pathVertical(pA, untilY)
+
+rpathHorizontal(pA, untilX)
+rpathVertical(pA, untilY)
+\end{verbatim}
+
+A path created by {\code pathHorizonal} starts from the point {\code pA}
+and continues horizontally until coordinate {\code untilX} is reached. The macro
+{\code pathVertical} constructs the path dually, working vertically.
+The prefix ``{\code r}'' reverses the direction of the path.
+
+Usage example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+untilX := B.left;
+link(association)
+ (pathHorizontal(A.e, untilX));
+
+untilY:= C.bottom;
+link(association)
+ (pathVertical(A.n, untilY));
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/paths.4}
+\end{multicols}
+
+\subsection{Direct Paths}
+
+A direct path can be created with {\code directPath}. The call {\code directPath(A, B)}
+is equivalent to {\code A -{}- B}.
+
+\subsection{Paths between Objects}
+
+Using the constructs presented above, links between diagram objects are drawn easily like this:
+
+\begin{verbatim}
+link(transition)(directPath(objA.nw, objB.se));
+\end{verbatim}
+
+There are times however when this direct approach may yield unsatisfactory visual results,
+especially when the object's corners is round. To tackle these situations, MetaUML provides the macro
+{\code pathCut}, whose aim is to limit a given path exactly to the region outside the actual
+borders of the objects it connects. The macro's synopsis is:
+
+\begin{verbatim}
+pathCut(thePath)(objectA, objectB)
+\end{verbatim}
+
+Here, {\code thePath} is a given MetaPost path and {\code objectA} and {\code objectB}
+are two MetaUML objects. By contract, each MetaUML object of type, say, {\code X}
+defines a macro {\code X\_border} which returns the path that surrounds it. Because
+of that, {\code pathCut} can make the appropriate modifications to {\code thePath}.
+
+The following code demonstrates the benefits of the {\code pathCut} macro:
+
+\begin{multicols}{2}
+\begin{verbatim}
+z = A.se + (30, -10);
+link(transition)
+ (pathCut(A, B)(A.c--z--B.c));
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/paths.5}
+\end{multicols}
+
+\subsubsection{Direct Paths between Centers}
+
+At times is quicker to just draw direct paths between the center of two objects,
+minding of course the object margins. The macro which does this is {\code clink}:
+
+\begin{verbatim}
+clink(how-to-draw-information)(objA, objB);
+\end{verbatim}
+
+The parameter {\code how-to-draw-information} is the same as for the macro {\code link};
+{\code objA} and {\code objB} are two MetaUML objects.
+
+Below is an example which involves the inheritance relation:
+
+\begin{multicols}{2}
+\begin{verbatim}
+clink(inheritance)(A, B);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/paths.6}
+\end{multicols}
+
+\section{Arranging Diagram Items}
+\label{section:positioning}
+
+Using equations involving cardinal points, such as {\code A.nw = B.ne + (10,0)}, is
+good enough for achieving the desired results. However, programs are best to
+be written for human audience, rather than for compilers. It does become a bit
+tiresome to think all the time of cardinal points and figure out the
+direction of positive or negative offsets. Because of that, MetaUML offers
+syntactic sugar which allows for an easier understanding of the intent behind
+the positioning code.
+
+Suppose that we have three classes, {\code A}, {\code B}, {\code C} and their base class
+{\code Base}. We want the base class to be at the top, and the derived classes to be
+on a line below. This code will do:
+
+\begin{verbatim}
+A.ne = B.nw + (20,0);
+B.ne = C.nw + (20,0);
+Base.s = B.n + (0,-20);
+\end{verbatim}
+
+Unfortunately, writing code such as this makes it hard for fellow programmers to visualize
+its intent upon reading it. And ``fellow programmers`` include the author, five minutes later.
+
+Perhaps the next version of the code will drive home the point. The outcome is
+the same as before, but the layout is stated in a more human-friendly way. You might even
+infer by yourself that the numeric argument represents the distance between the objects.
+
+\begin{multicols}{2}
+\begin{verbatim}
+leftToRight(20)(A, B, C);
+topToBottom(20)(Base, B);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/positioning.2}
+\end{multicols}
+
+Below there are examples which show how these macros can be used. Suppose that we have the
+following definitions for objects {\code X}, {\code Y}, and {\code Z}; also, let's assume
+that {\code spacing} is a numeric variable set to {\code 5}.
+
+\begin{verbatim}
+Picture.X("a");
+Picture.Y("...");
+Picture.Z("Cyan");
+\end{verbatim}
+
+\begin{tabular}{||l|c||}
+\hline
+{\code leftToRight.top(spacing)(X, Y, Z);} & \includegraphics{fig/positioning.3} \\
+\hline
+{\code leftToRight.midy(spacing)(X, Y, Z);} & \includegraphics{fig/positioning.4} \\
+\hline
+{\code leftToRight.bottom(spacing)(X, Y, Z);} & \includegraphics{fig/positioning.5} \\
+\hline
+{\code topToBottom.left(spacing)(X, Y, Z);} & \includegraphics{fig/positioning.6} \\
+\hline
+{\code topToBottom.midx(spacing)(X, Y, Z);} & \includegraphics{fig/positioning.7} \\
+\hline
+{\code topToBottom.right(spacing)(X, Y, Z);} & \includegraphics{fig/positioning.8} \\
+\hline
+\end{tabular} \\
+
+To make things even easier, the following equivalent contructs are also allowed:
+
+\begin{verbatim}
+leftToRight.midy(spacing)(X, Y, Z);
+leftToRight(spacing)(X, Y, Z);
+\end{verbatim}
+
+\begin{verbatim}
+topToBottom.midx(spacing)(X, Y, Z);
+topToBottom(spacing)(X, Y, Z);
+\end{verbatim}
+
+If you want to specify that some objects have a given property equal, while the distance between them is given elsewhere, you can use the macro {\code same}.
+This macro accepts a variable number of parameters, but at least two. The following table gives the interpretation of the macro for a simple example.
+
+\begin{tabular}{||l|l||}
+\hline
+{\code same.top(X, Y, Z);} & {\code X.top = Y.top = Z.top;} \\
+\hline
+{\code same.midy(X, Y, Z);} & {\code X.midy = Y.midy = Z.midy;} \\
+\hline
+{\code same.bottom(X, Y, Z);} & {\code X.bottom = Y.bottom = Z.bottom;} \\
+\hline
+{\code same.left(X, Y, Z);} & {\code X.left = Y.left = Z.left;} \\
+\hline
+{\code same.midx(X, Y, Z);} & {\code X.midx = Y.midx = Z.midx;} \\
+\hline
+{\code same.right(X, Y, Z);} & {\code X.right = Y.right = Z.right;} \\
+\hline
+\end{tabular} \\
+
+Relative positions of two points can be declared more easily using the macros {\code below}, {\code above}, {\code atright}, {\code atleft}.
+Let us assume that {\code A} and {\code B} are two points (objects of type {\code pair} in MetaPost). The following constructs are equivalent:
+
+\begin{tabular}{||l|l||}
+\hline
+{\code B = A + (5,0);} & {\code B = atright(A, 5);} \\
+{\code B = A - (5,0);} & {\code B = atleft(A, 5);} \\
+{\code B = A + (0,5);} & {\code B = above(A, 5);} \\
+{\code B = A - (0,5);} & {\code B = below(A, 5);} \\
+\hline
+\end{tabular}
+
+
+\section{The MetaUML Infrastructure}
+\label{section:infrastructure}
+
+MetaPost is a macro language based on equation solving. Using it may seem quite
+tricky at first for a programmer accustomed to modern object-oriented languages.
+However, the great power of MetaPost consists in its versatility. Indeed, it is possible to write
+a system which mimics quite well object-oriented behavior. Along this line, METAOBJ
+\cite{metaobj} is a library worth mentioning: it provides a high-level objects
+infrastructure along with a battery of predefined objects.
+
+Surprisingly enough, MetaUML does not use METAOBJ. Instead, it uses a custom written,
+lightweight object-oriented infrastructure, provisionally called ``{\code util}''.
+METAOBJ's facilities, although impressive, were perceived by me as being a bit too much
+for what was initially intented as a quick way of getting some UML diagrams layed out.
+Inspired by METAOBJ, ``{\code util}'' was designed to fulfill with minimal effort
+the specific tasks needed to confortably position, allign or group visual objects
+which include text.
+
+Another library having some object-oriented traits is the {\code boxes}
+library, which comes with the standard MetaPost distribution. Early versions of
+MetaUML did use {\code boxes} as an infrastructure, but this approach had to be abandoned eventually.
+The main reason was that it was difficult to achieve good visual results when stacking texts
+(more on that further on). For all it's worth, it did not fit well with the way in which MetaUML's
+layout mechanism was shaping up at the time.
+
+\subsection{Motivation}
+
+Suppose that we want to typeset two texts with their bottom lines aligned, using {\code boxit}:
+
+\begin{multicols}{2}
+\begin{verbatim}
+boxit.a ("yummy");
+boxit.b ("cool");
+
+a.nw = (0,0); b.sw = a.se + (10,0);
+
+drawboxed (a, b); % or drawunboxed(a,b)
+draw a.sw -- b.se dashed evenly
+ withpen pencircle scaled 1.1;
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/boxes_vs_util.1}
+\end{multicols}
+
+Note that, despite supposedly having their bottom lines alligned,
+``yummy'' {\it looks} slightly higher than ``cool''. This would be unacceptable
+in a UML class diagram, when roles are placed at the ends of a horizontal association.
+Regardless of the default spacing being smaller in the {\code util} library,
+the very same unfortunate misalignment effect rears its ugly head:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Picture.a("yummy");
+Picture.b("cool");
+% comment next line for unboxed
+a.info.boxed := b.info.boxed := 1;
+
+b.sw = a.se + (10,0);
+
+drawObjects(a, b);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/boxes_vs_util.2}
+\end{multicols}
+
+However, the strong point of {\code util} is that we have a recourse to this problem:
+
+\begin{multicols}{2}
+\begin{verbatim}
+iPict.ignoreNegativeBase := 1;
+
+Picture.a("yummy");
+Picture.b("cool");
+% the rest the same as above
+drawObjects(a, b);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/boxes_vs_util.3}
+\end{multicols}
+
+\subsection{The Picture Macro}
+
+We have seen previously the line {\code iPict.ignoreNegativeBase := 1}.
+Who is {\code iPict} and what is it doing in our program? MetaUML
+aims at separating the ``business logic'' (what to draw) from the
+``interface'' (how to draw). In order to achieve this, it records the ``how to draw''
+information within the so-called {\code Info} structures. The object {\code iPict}
+is an instance of {\code PictureInfo} structure, which has the following properties
+(or attributes):
+\begin{verbatim}
+left, right, top, bottom
+ignoreNegativeBase
+boxed, borderColor
+\end{verbatim}
+
+The first four attributes specify how much space should be left around the
+actual item to be drawn. The marvelous effect of {\code ignoreNegativeBase}
+has just been shown (off), while the last two attributes control whether the border
+should be drawn (when {\code boxed=1}) and if drawn, in which color.
+
+There's one more thing: the font to typeset the text in. This is specified
+in a {\code FontInfo} structure which has two attributes: the font name
+and the font scale. This information is kept within the {\code PictureInfo} structure
+as a contained attribute {\code iFont}. Both {\code FontInfo} and {\code PictureInfo}
+have ``copy constructors'' which can be used to make copies. We have already
+the effect of these copy constructors at work, when we used:
+
+\begin{verbatim}
+Picture.a("yummy");
+a.info.boxed := 1;
+\end{verbatim}
+
+A copy of the default info for a picture, {\code iPict}, has been made within
+the object {\code a} and can be accessed as {\code a.info}. Having a copy of the
+info in each object may seem like an overkill, but it allows for a fine grained
+control of the drawing mode of each individual object. This feature comes in very
+handy when working with a large number of settings, as it is the case for MetaUML.
+
+Let us imagine for a moment that we have two types of text to write: one with a small font
+and a small margin and one with a big font and a big margin. We could in theory
+configure each individual object or set back and forth global parameters, but
+this is far for convenient. It is preferable to have two sets of settings and specify
+them explicitly when they are needed. The following code could be placed somewhere
+in a configuration file and loaded before any {\code beginfig} macro:
+\begin{verbatim}
+PictureInfoCopy.iBig(iPict);
+iBig.left := iBig.right := 20;
+iBig.top := 10;
+iBig.bottom := 1;
+iBig.boxed := 1;
+iBig.ignoreNegativeBase := 1;
+iBig.iFont.name := defaultfont;
+iBig.iFont.scale := 3;
+
+PictureInfoCopy.iSmall(iPict);
+iSmall.boxed := 1;
+iSmall.borderColor := green;
+\end{verbatim}
+
+Below is an usage example of these definitions. Note the name of the macro: {\code EPicture}.
+The prefix comes form ``explicit'' and it's used to acknowledge that the
+``how to draw'' information is given explicitly --- as a parameter,
+rather than defaulted to what's recorded in {\code iPict}, as with the {\code Picture} macro.
+Having predefined configurations yields short, convenient code.
+
+\begin{multicols}{2}
+\begin{verbatim}
+EPicture.a(iBig)("yummy");
+EPicture.b(iSmall)("cool");
+% you can still modify a.info, b.info
+
+b.sw = a.se + (10,0);
+
+drawObjects(a, b);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/picture_info.1}
+\end{multicols}
+
+\subsubsection{Fixed Sizes}
+
+By default, the size of a {\code Picture} object is set by its contents. However,
+it is possible to specify fixed dimensions both the width and the height, independently.
+This can be done by setting the {\code info}'s attributes {\code fixedWidth} and {\code fixedHeight} to values
+greater than 0. If any of these attributes is left to its default value, {\code -1}, then for the corresponding
+axis the dimension is set according to the dimension of the content. Nevertheless, the fixed dimensions are enforced, even though the contained object would have needed additional space.
+
+\begin{multicols}{2}
+\begin{verbatim}
+PictureInfoCopy.myFixed(iPict);
+myFixed.ignoreNegativeBase := 1;
+myFixed.fixedWidth := 15;
+myFixed.fixedHeight := 20;
+myFixed.boxed := 1;
+
+EPicture.a(myFixed)("a");
+EPicture.b(myFixed)(".-.");
+EPicture.c(myFixed)("toolong");
+
+leftToRight.bottom(10)(a, b, c);
+
+drawObjects(a, b, c);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/picture_info.2}
+\end{multicols}
+
+\subsubsection{Content alignment}
+
+When fixed dimensions are used, one most likely would prefer a centered alignement of the contents in the
+{\code Picture} box. This option can be expressed independently for each of the axes,
+by setting the {\code info}'s attributes {\code valign} and {\code halign} to descriptive string values.
+For horizontal alignement, {\code halign} can be set to {\code "left"} or {\code "center"}, and for
+vertical alignement, {\code valign} can be set to {\code "bottom} or {\code "center"}. The default
+values for these attributes are {\code "left"} and {\code "bottom"}, respectively.
+
+The next example uses horizontal centered alignement and a bottom alignement with a {\code 4.5} base offset, for
+vertical alignement. This vertical alignement gives a better visual result than the centered one, at
+least for the situations in which there are texts to be placed horizontally.
+
+\begin{multicols}{2}
+\begin{verbatim}
+PictureInfoCopy.myFixed(iPict);
+myFixed.ignoreNegativeBase := 1;
+myFixed.bottom := 4.5;
+myFixed.valign := "bottom";
+myFixed.halign := "center";
+myFixed.fixedWidth := 25;
+myFixed.fixedHeight := 15;
+myFixed.boxed := 1;
+
+EPicture.a(myFixed)("a");
+EPicture.b(myFixed)("yum");
+EPicture.c(myFixed)("b");
+
+leftToRight.bottom(10)(a, b, c);
+
+drawObjects(a, b, c);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/picture_info.3}
+\end{multicols}
+
+\subsection{Stacking Objects}
+
+It is possible to stack objects, much in the style of {\code setboxjoin}
+from {\code boxes} library.
+
+\begin{multicols}{2}
+\begin{verbatim}
+Picture.a0("yummy");
+Picture.a1("cool");
+Picture.a2("fool");
+
+setObjectJoin(pa.sw = pb.nw);
+joinObjects(scantokens listArray(a)(3));
+
+drawObjects(scantokens listArray(a)(3));
+% or drawObjects (a0, a1, a2);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/object_stack.1}
+\end{multicols}
+
+The {\code listArray} macro provides here a shortcut for writing
+{\code a0, a1, a2}. This macro is particularly useful for generic
+code which does not know beforehand the number of elements to be drawn.
+Having to write the {\code scantokens} keyword is admittedly a nuisance, but
+this is required.
+
+
+\subsection{The Group Macro}
+
+It is possible to group objects in MetaUML. This feature is the cornerstone
+of MetaUML, allowing for the easy development of complex objects, such as
+composite stats in state machine diagrams.
+
+Similarly to the macro {\code Picture}, the structure {\code GroupInfo}
+is used for specifying group properties; its default instantiation is
+{\code iGroup}. Furthermore, the macro {\code EGroup} explicitely sets the
+layout information.
+
+Here is an example:
+
+\begin{multicols}{2}
+\begin{verbatim}
+iGroup.left:=20;
+iGroup.right:=15;
+iGroup.boxed:=1;
+iPicture.boxed:=1;
+
+Picture.a("yummy");
+Picture.b("cool");
+Picture.c("fool");
+
+b.nw = a.nw + (20,20); % A
+c.nw = a.nw + (15, 40); % B
+
+Group.g(a, b, c);
+g.nw = (10,10); % C
+
+drawObject(g);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/group.1}
+\end{multicols}
+
+After some objects are grouped, they can only be drawn
+by invoking the {\code drawObject} macro on the group that aggregates them, and not individually.
+Conveniently, once the relative positioning of objects within a group is set (line A and B), the whole
+group can be ``moved'' do the desired position (line C), and all the contained objects will move along.
+
+\subsection{The PictureStack Macro}
+
+The {\code PictureStack} macro is a syntactic sugar for a set of pictures,
+stacked according to predefined equations and grouped together.
+
+\begin{multicols}{2}
+\begin{verbatim}
+iStack.boxed := 1;
+iStack.iPict.boxed := 1;
+PictureStack.myStack("foo",
+ "bar: int" infont "tyxtt",
+ "nicely-centered" infont defaultfont,
+ "nice")("vcenter");
+
+drawObject(myStack);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/picture_stack.1}
+\end{multicols}
+
+Note the last parameter of the macro {\code PictureStack}, here {\code vcenter}.
+It is used to generate appropriate equations based on a descriptive name.
+The spacing between individual picture objects is set by the field
+{\code iStack.spacing}. Currently, the following alignment names are
+defined: {\code vleft}, {\code vright}, {\code vcenter},
+{\code vleftbase}, {\code vrightbase}, {\code vcenterbase}. All these
+names refer to vertical alignment (the prefix ``{\code v}''); alignment can
+be at left, right or centered. The variants having the suffix ``{\code base}'' align
+the pictures so that {\code iStack.spacing} refer to the distance between the
+bottom lines of the pictures. The unsuffixed variants use {\code iStack.spacing} as
+the distance between one's bottom line and the next's top line.
+
+The ``{\code base}'' alignment is particularly useful for stacking text, since it
+offers better visual appearance when {\code iPict.ignoreNegativeBase} is set to {\code 1}.
+
+\section{Components Design}
+
+Each MetaUML component (e.g. {\code Picture}, {\code PictureStack}, {\code Class}) is
+designed according to an established pattern. This section gives more insight
+on this.
+
+In order to draw a component, MetaUML categorizes the required information as follows:
+\begin{itemize}
+\item what to draw, or what are the elements of a component.
+\item how to draw, or how are the elements positioned in relation to each other within the component
+\item where to draw
+\end{itemize}
+
+For example, in order to draw a picture object we must know, respectively:
+\begin{itemize}
+\item what is the text or the native picture that needs to be drawn
+\item what are the margins that should be left around the contents
+\item where is the picture to be drawn
+\end{itemize}
+
+Why do we bother with these questions? Why don't we just simply draw the picture
+component as soon as it was created and get it over with?
+That is, why doesn't the following code just work?
+
+\begin{verbatim}
+Picture.pict("foo");
+\end{verbatim}
+
+Well, although we have the answer to question 1 (what to draw),
+we still need to have question 3 answered. The code below becomes thus a
+necessity (actually, you are not forced to specify the positioning of an object,
+because its draw method positions it to {\code (0,0)} by default):
+
+\begin{verbatim}
+% question 1: what to draw
+Picture.pict("foo");
+
+% question 3: where to draw
+pict.nw = (10,10);
+
+% now we can draw
+drawObject(pict);
+\end{verbatim}
+
+How about question 2, how to draw? By default, this problem is addressed behind the
+scenes by the component. This means, for the Picture object, that a native picture is created
+from the given string, and around that picture certain margins are placed, by means of MetaPost equations.
+(The margins also come in handy when stacking Picture objects, so that the result doesn't look too cluttered.)
+If these equations were defined within the Picture constructor, then an
+usability problem would have appeared, because it wouldn't have been possible to modify the margins,
+as in the code below:
+
+\begin{verbatim}
+% question 1: what to draw
+Picture.pict("foo");
+
+% question 2: how to draw
+pict.info.left := 10;
+pict.info.boxed := 1;
+
+% question 3: where to draw
+pict.nw = (0,0);
+
+% now we can draw
+drawObject(pict);
+\end{verbatim}
+
+To allow for this type of code, the equations that define the layout of the {\code Picture} object (here, what the margins are)
+must be defined somewhere after the constructor. This is done by a macro called {\code Picture\_layout}.
+This macro defines all the equations which link the ``what to draw'' information to the ``how to draw''
+information (which in our case is taken from the {\code info} member, a copy of {\code iPict}).
+Nevertheless, notice that {\code Picture\_layouts} is not explicitly invoked. To the user's
+great relief, this is taken care of automatically within the {\code Picture\_draw} macro.
+
+There are times however, when explicitly invoking a macro like {\code Picture\_layout}
+becomes a necessity. This is because, by contract, it is only after the {\code layout}
+macro is invoked that the final dimensions (width, height) of an object are
+definitely and permanently known. Imagine that we have a component whose job is to
+surround in a red-filled rectangle some other objects. This component
+needs to know what the dimensions of the contained objects are, in order to be able to set
+its own dimensions. At drawing time, the contained objects must not have been drawn already,
+because the red rectangle of the container would overwrite them.
+Therefore, the whole pseudo-code would be:
+\begin{verbatim}
+Create objects o1, o2, ... ok;
+Create container c(o1, o2, ..., ok);
+Optional: modify info-s for o1, o2, ... ok;
+Optional: modify info for c;
+
+layout c, requiring layout of o1, o2, ... ok;
+establish where to draw c;
+draw red rectangle defined by c;
+draw components o1, o2, ...ok within c
+\end{verbatim}
+
+A natural conclusion is that an object must not be laid out more than once, because otherwise
+inconsistent or superfluous equations would arise. To enforce this, by contract,
+any object must keep record of whether its layout method has already been invoked,
+and if the answer is affirmative, subsequent invocations of the layout macro would
+do nothing. It is very important to mention that after the {\code layout} macro is
+invoked over an object, modifying the {\code info} member of that object has
+no subsequent effect, since the layout equations are declared and interpreted only once.
+
+\subsection{Notes on the Implementation of Links}
+
+MetaUML considers edges in diagram graphs as links. A link is composed of a path and the
+heads (possible none, one or two). For example, since an association has no heads, it suffices
+to draw along the path with a solid pen; however, an unidirectional aggregation has, in addition
+to a solid path, two heads: one is an arrow and the other is a diamond.
+
+The general algorithm for drawing a link is:
+
+\begin{verbatim}
+0. Reserve space for heads
+1. Draw the path (except for the heads)
+2. Draw head 1
+3. Draw head 2
+\end{verbatim}
+
+Each of the UML link types define how the drawing should be done, in each of the
+cases (1, 2 and 3). Consider the link type of unidirectional composition.
+Its ``class'' is declared as:
+
+\begin{verbatim}
+vardef CompositionUniInfo@# =
+ LinkInfo@#;
+
+ @#widthA = defaultRelationHeadWidth;
+ @#heightA = defaultRelationHeadHeight;
+ @#drawMethodA = "drawArrow";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawDiamondBlack";
+
+ @#drawMethod = "drawLine";
+enddef;
+\end{verbatim}
+
+Using this definition, the actual description is created like this:
+
+\begin{verbatim}
+CompositionUniInfo.compositionUni;
+\end{verbatim}
+
+As shown previously, is is the macro {\code link} which
+performs the actual drawing, using the link description information
+which is given as parameter (generally called {\code iLink}).
+For example, we can use:
+
+\begin{verbatim}
+link(aggregationUni)((0,0)--(40,0));
+\end{verbatim}
+
+%\begin{figure}
+%\centering
+%\includegraphics{fig/how-links-work.1}
+%\caption{An example of a picture stack.}
+%\label{fig:hlw}
+%\end{figure}
+
+Let us see now the inner workings of macro {\code link}. Its definition is:
+
+\begin{verbatim}
+vardef link(text iLink)(expr myPath)=
+ LinkStructure.ls(myPath,
+ iLink.widthA, iLink.widthB);
+ drawLinkStructure(ls)(iLink);
+enddef;
+\end{verbatim}
+
+\begin{figure}
+\centering
+\begin{tabular}{l|l}
+$AB$ & the path specified by the user \\
+$|AA'|$ & {\code iLink.widthA}\\
+$|BB'|$ & {\code iLink.widthB}
+\end{tabular}
+\includegraphics{fig/how-links-work.2}
+\caption{Details on how a link is drawn by MetaUML.}
+\label{fig:hlw2}
+\end{figure}
+
+First, space is reserved for heads, by ``shortening'' the given path {\code myPath}
+by {\code iLink.widthA} at the beginning and by {\code iLink.widthB} at the end.
+After that, the shortened path is drawn with the ``method''
+given by {\code iLink.drawMethod} and the heads with the ``methods''
+{\code iLink.drawMethodA} and {\code iLink.drawMethodB},
+respectively (figure \ref{fig:hlw2}).
+
+\subsection{Object Definitions: Easier {\code generic\_declare}}
+
+In MetaPost, if somebody wants to define something resembling a class in an object-oriented language,
+named, say, {\code Person}, he would do something like this:
+
+\begin{verbatim}
+vardef Person@#(expr _name, _age)=
+ % @# prefix can be seen as `this` pointer
+ string @#name;
+ numeric @#age;
+
+ @#name := _name;
+ @#age := _age;
+enddef;
+\end{verbatim}
+
+This allows for the creation of instances (or objects) of class {\code Person} by using
+declarations like:
+
+\begin{verbatim}
+Person.personA;
+Person.personB;
+\end{verbatim}
+
+ However, if one also wants to able able to create indexed arrays of persons, such as
+{\code Person.student0}, {\code Person.student1} etc., the definition of class
+{\code Person} must read:
+
+\begin{verbatim}
+vardef Person@#(expr _name, _age)=
+ _n_ := str @#;
+ generic_declare(string) _n.name;
+ generic_declare(numeric) _n.age;
+
+ @#name := _name;
+ @#age := _age;
+enddef;
+\end{verbatim}
+
+This construction is rather inelegant. MetaUML offers alternative macros to achieve
+the same effect, uncluttering the code by removing the need for the unaesthetic {\code \_n\_} and
+{\code \_n}.
+
+\begin{verbatim}
+vardef Person@#(expr _name, _age)=
+ attributes(@#);
+ var(string) name;
+ var(numeric) age;
+
+ @#name := _name;
+ @#age := _age;
+enddef;
+\end{verbatim}
+
+\section{Customization in MetaUML: Examples}
+\label{section:customization}
+
+We have seen that in MetaUML the ``how to draw'' information is memorized into the so-called
+``{\code Info}'' structures. For example, the default way in which a {\code Picture} object is
+to be drawn is recorded into an instance of {\code PictureInfo}, named {\code iPict}. In this section we
+present a case study involving the customization of {\code Class} objects. The customization of
+any other MetaUML objects works similarly. Here we cannot possibly present all the customization
+options for all kinds of MetaUML objects: this would take too long. Nevertheless, an interested reader can refer
+to the top of the appropriate MetaUML library file, where {\code Info} structures are defined.
+For example, class diagram related definitions are in {\code metauml\_class.mp}, activity diagram
+definitions are in {\code metauml\_activity.mp} etc.
+
+\subsection{Global settings}
+
+Let us assume that we do not particularly like the default foreground color of all classes, and wish
+to change it so something yellowish. In this scenario, one would most likely want to change
+the appropriate field in {\code iClass}:
+
+\begin{verbatim}
+iClass.foreColor := (.9, .9, 0);
+\end{verbatim}
+
+After this, we can obtain the following result:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("A")()();
+Class.B("B")()();
+Class.C("C")()();
+
+B.w = A.e + (20,0);
+C.n = .5[A.se, B.sw] + (0, -10);
+
+drawObjects(A, B, C);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/class_customization.1}
+\end{multicols}
+
+\subsection{Individual settings}
+
+To modify the settings of one particular {\code Class} objects, another strategy is more appropriate. How about having class
+{\code C} stand out with a light blue foreground color, a bigger font size for the class name and a blue border?
+
+\begin{multicols}{2}
+\begin{verbatim}
+iPict.foreColor := (.9, .9, 0);
+
+Class.A("A")()();
+Class.B("B")()();
+Class.C("C")()();
+C.info.foreColor := (.9, .7, .7);
+C.info.borderColor := green;
+C.info.iName.iFont.scale := 2;
+
+% positioning code ommited
+drawObjects(A, B, C);
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/class_customization.2}
+\end{multicols}
+
+As an aside, each {\code Class} object has an {\code info} member which is created as
+a copy of {\code iClass}; the actual drawing is performed using this copied
+information. Because of that, the {\code info} member can be safely modified after the object
+has been created, obtaining the expected results and not influencing other objects.
+
+Another thing worth mentioning is that the {\code ClassInfo} structure contains
+the {\code iName} member, which is an instance of {\code PictureInfo}. In our example we
+do not want to modify the spacings around the {\code Picture} object,
+but the characteristics of the font its contents is typeset into. To do that,
+we modify the {\code iName.iFont} member, which by default is a copy of {\code iFont}
+(an instance of {\code FontInfo}, defined in {\code util\_picture.mp}).
+If, for example, we want to change the font the class name is rendered into, we would set
+the attribute {\code iName.iFont.name} to a string representing a font name
+on our system (as used with the MetaPost {\code infont} operator).
+
+\subsection{Predefined settings}
+
+This usage scenario is perhaps more interesting. Suppose that we have two
+types of classes which we want to draw differently. Making the setting adjustments
+for each individual class object would soon become a nuisance. MetaUML's solution consists in the
+ability of using predefined ``how to draw'' {\code Info} objects. Let us create such objects:
+
+\begin{verbatim}
+ClassInfoCopy.iHome(iClass);
+iHome.foreColor := (0, .9, .9);
+
+ClassInfo.iRemote;
+iRemote.foreColor := (.9, .9, 0);
+iRemote.borderColor := green;
+\end{verbatim}
+
+Object {\code iHome} is a copy of {\code iClass} (as it might have been set at
+the time of the macro call). Object {\code iRemote} is created just as {\code iClass}
+is originally created. We can now use these {\code Info} objects to easily set the
+``how to draw'' information for classes. The result is depicted below,
+please note the ``{\code E}'' prefix in {\code EClass}:
+
+\begin{multicols}{2}
+\begin{verbatim}
+EClass.A(iHome)("UserHome")()();
+EClass.B(iRemote)("UserRemote")()();
+EClass.C(iHome)("CartHome")()();
+EClass.D(iRemote)("CartRemote")()();
+\end{verbatim}
+\columnbreak
+\hspace{1cm}\includegraphics{fig/class_customization.3}
+\end{multicols}
+
+\subsection{Extreme customization}
+
+When another font (or font size) is used, it may become necessary to change the space between the
+baselines of attributes and methods. Figure below is the result of the (unlikely) code:
+
+\begin{multicols}{2}
+\begin{verbatim}
+Class.A("Foo")
+ ("a: int", "b: int")
+ ("foo()", "bar()", "gar()");
+
+A.info.iName.iFont.name := metauml_defaultFontBold;
+A.info.iName.iFont.scale := 1.2;
+
+A.info.iAttributeStack.iPict.iFont.scale := 0.8;
+A.info.iAttributeStack.top := 10;
+A.info.iAttributeStack.spacing := 11;
+
+A.info.iMethodStack.iPict.iFont.scale := 2;
+A.info.iMethodStack.spacing := 17;
+A.info.iMethodStack.bottom := 10;
+
+drawObject(A);
+\end{verbatim}
+\columnbreak
+\hspace{4cm}\includegraphics{fig/class_customization.4}
+\end{multicols}
+
+\begin{verbatim}
+\end{verbatim}
+
+Both {\code iAttributeStack} and {\code iMethodStack} are instances of
+{\code PictureStackInfo}, which is used to control the display of {\code PictureStack} objects.
+%We can also customize the size and colors of the ``locks'' by setting {\code A.info.iLock}.
+
+As font names, you can choose from the globally defined {\code metauml\_defaultFont}, {\code metauml\_defaultFontOblique}, {\code metauml\_defaultFontBold}, {\code metauml\_defaultFontBoldOblique}, or any other name of a font that is available on your system.
+
+\section{Alternatives to MetaUML}
+
+No software package is perfect, and for this MetaUML is a prime example. Here is a list of packages that may also be used to create UML diagrams for LaTeX work:
+
+\begin{itemize}
+\item uml.sty \cite{umlsty}
+\item pst-uml \cite{pstumlsty}
+\item umldoc \cite{umldoc}
+\item TiKZ-UML \cite{tikzuml}
+\end{itemize}
+
+Do not ignore the possibility of creating your diagrams using a GUI program, and then exporting them into a LaTex-friendly open format such as SVG \cite{svglatex}.
+
+\pagebreak
+\input{test-suite}
+
+\pagebreak
+\section{References}
+\printbibliography[heading=none]
+
+\end{document}
diff --git a/graphics/metapost/contrib/macros/metauml/examples/manual/test-suite.tex b/graphics/metapost/contrib/macros/metauml/examples/manual/test-suite.tex
new file mode 100644
index 0000000000..b0aa9a6685
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/examples/manual/test-suite.tex
@@ -0,0 +1,82 @@
+% Part of the MetaUML manual
+% Copyright (c) 2005 Ovidiu Gheorghies
+%
+% Permission is granted to copy, distribute and/or modify this document
+% under the terms of the GNU Free Documentation License, Version 1.2
+% or any later version published by the Free Software Foundation;
+% with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+% A copy of the license is included in the section entitled "GNU
+% Free Documentation License".
+
+\newcommand{\metaumltest}[2]{Test #2 --- \\ \includegraphics{fig/test_#1.#2} \\ }
+\newcommand{\metaumltests}[2]{\multido{\iA=1+1}{#2}{\metaumltest{#1}{\iA}}}
+
+\section{Test Suite}
+
+\subsection{Low-level}
+ \metaumltests{lowlevel}{2}
+
+\subsection{Fonts}
+ \metaumltests{font}{3}
+
+\subsection{Util library}
+ \subsubsection{Picture tests}
+ \metaumltests{picture}{10}
+
+ \subsubsection{Picture tests - TeX rendering}
+ \metaumltests{picture_tex_rendering}{1}
+
+ \subsubsection{Group tests}
+ \metaumltests{group}{2}
+
+ \subsubsection{PictureStack tests}
+ \metaumltests{picture_stack}{7}
+
+ \subsubsection{Positioning tests}
+ \metaumltests{positioning}{6}
+
+\subsection{Class diagram}
+ \subsubsection{Class tests}
+ \metaumltests{class}{16}
+ \subsubsection{Class feature types tests}
+ \metaumltests{class_feature_types}{5}
+ \subsubsection{Class template tests}
+ \metaumltests{class_templates}{3}
+
+ \subsubsection{Qualified Association tests}
+ \metaumltests{class_qual_assoc}{2}
+
+\subsection{Package diagram}
+\subsubsection{Package tests}
+ \metaumltests{package}{2}
+
+\subsection{Component diagram}
+\subsubsection{Component tests}
+ \metaumltests{component}{1}
+
+\subsection{Paths}
+ \metaumltests{paths}{3}
+
+\subsection{Behavioral diagrams}
+ \subsubsection{Activity tests}
+ \metaumltests{activity}{2}
+
+ \subsubsection{State Machine tests}
+ \metaumltests{state}{5}
+
+ \subsubsection{Usecase tests}
+ \metaumltests{usecase}{9}
+
+\subsection{Miscelaneous}
+ \subsubsection{Notes}
+ \metaumltests{note}{2}
+ \subsubsection{Objects (Class Instances)}
+ \metaumltests{instance}{1}
+
+\subsection{User requests}
+ Test 1 --- \\ \includegraphics[scale=.2]{fig/test_lars_issues.1} \\
+ \metaumltest{lars_issues}{2}
+
+\subsection{Skins}
+ \metaumltests{skins}{1}
+ \metaumltests{skins_global_defaults}{1}
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml.mp
new file mode 100644
index 0000000000..95748cf767
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml.mp
@@ -0,0 +1,66 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_mp:
+ expandafter endinput
+fi;
+_metauml_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_infrastructure;
+inputonce util_object;
+inputonce util_commons;
+inputonce util_margins;
+inputonce util_picture;
+inputonce util_group;
+inputonce util_picture_stack;
+inputonce util_positioning;
+inputonce util_shade;
+
+inputonce metauml_base;
+
+inputonce metauml_links;
+inputonce metauml_paths;
+
+inputonce metauml_note;
+
+inputonce metauml_stereotype;
+
+inputonce metauml_class;
+inputonce metauml_instance;
+inputonce metauml_class_relations;
+inputonce metauml_class_assoc;
+
+inputonce metauml_package;
+inputonce metauml_package_relations;
+
+inputonce metauml_behavioral_common;
+inputonce metauml_activity;
+inputonce metauml_state;
+
+inputonce metauml_usecase_clipart;
+inputonce metauml_usecase;
+
+input metauml_behavioral_common;
+input metauml_activity;
+input metauml_state;
+
+input metauml_usecase_clipart;
+input metauml_usecase;
+
+input metauml_component;
+input metauml_component_relations;
+
+input metauml_templates;
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_activity.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_activity.mp
new file mode 100644
index 0000000000..79ac5042e2
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_activity.mp
@@ -0,0 +1,229 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_activity_mp:
+ expandafter endinput
+fi;
+_metauml_activity_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+vardef ActivityInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+
+ FontInfo.@#iFont(metauml_defaultFont, defaultscale);
+ @#iFont.ignoreNegativeBase := 1;
+
+ PictureInfo.@#iText (2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iStack (2, 2, 2, 2)(9)(@#iText);
+
+ @#iStack.iPict.ignoreNegativeBase := 1;
+
+ Margins.@#(2,2,2,2);
+
+ @#fat := 5;
+
+ ShadeInfo.@#iShade;
+ @#foreColor := .9white;
+ @#borderColor := black;
+enddef;
+
+vardef ActivityInfoCopy@#(text src)=
+ log "ActivityInfoCopy: Copying activity info";
+
+ attributes(@#);
+ var(color) foreColor, borderColor;
+
+ PictureStackInfoCopy.@#iStack (src.iStack);
+ MarginsCopy.@#(src);
+ @#fat := src.fat;
+
+ ShadeInfoCopy.@#iShade(src.iShade);
+
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+enddef;
+
+ActivityInfo.iActivity;
+
+vardef Activity@#(text contents)=
+ EActivity.@#(iActivity)(contents);
+enddef;
+
+vardef EActivity@#(text _info)(text contents)=
+ ObjectEquations(@#);
+ @#className := "Activity";
+
+ ActivityInfoCopy.@#info(_info);
+
+ numeric @#nLines; @#nLines := 0;
+ string @#lines[];
+ for l=contents:
+ @#lines[@#nLines] := l;
+ @#nLines := @#nLines + 1;
+ endfor;
+
+ EPictureStack.@#stack(@#info.iStack)(scantokens listArray(@#lines)(@#nLines))("vcenterbase");
+enddef;
+
+vardef Activity_layout@#=
+ if @#laidout = 1:
+ log "Activity " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+
+ PictureStack_layout.@#stack;
+
+ @#width = @#stack.width + @#info.left + @#info.right + 2 * @#info.fat;
+ @#height = @#stack.height + @#info.top + @#info.bottom;
+
+ @#c = @#stack.c;
+
+ pair @#urt, @#lrt, @#ulft, @#llft;
+
+ @#urt := @#ne - (@#info.fat, 0);
+ @#lrt := @#se - (@#info.fat, 0);
+ @#ulft := @#nw + (@#info.fat, 0);
+ @#llft := @#sw + (@#info.fat, 0);
+ fi;
+enddef;
+
+vardef Activity_draw@#=
+ Activity_layout@#;
+ objectEnsurePositioning.@#;
+
+ attributes(@#);
+ var(path) border;
+ @#border := @#ulft -- @#urt .. @#e .. @#lrt -- @#llft .. @#w .. cycle;
+
+ drawObjectShade(@#);
+ fill @#border withcolor @#info.foreColor;
+ draw @#border withcolor @#info.borderColor;
+
+ drawObject(@#stack);
+enddef;
+
+vardef Activity_border@#=
+ @#border
+enddef;
+
+
+vardef BranchInfo@#=
+ @#width := 10;
+ @#height := 10;
+
+ numeric @#shade;
+ color @#shadeColor, @#foreColor;
+ @#shade := .3;
+ @#shadeColor := .6white;
+ @#foreColor := white;
+enddef;
+
+BranchInfo.iBranch;
+
+vardef Branch@#=
+ ObjectEquations(@#);
+ @#className := "Branch";
+
+ @#width = iBranch.width;
+ @#height = iBranch.height;
+enddef;
+
+vardef Branch_layout@#=
+ % nothing to do
+enddef;
+
+vardef Branch_draw@#=
+ objectEnsurePositioning.@#;
+
+ path @#border;
+ @#border := @#n -- @#e -- @#s -- @#w -- cycle;
+
+ fill @#border shifted (iBranch.shade, -iBranch.shade) withcolor iBranch.shadeColor;
+ fill @#border withcolor iBranch.foreColor;
+ draw @#border;
+enddef;
+
+vardef Branch_border@#=
+ @#border
+enddef;
+
+vardef ForkInfo@#=
+ @#thickness := 3;
+
+ numeric @#shade;
+ color @#shadeColor, @#foreColor;
+ @#shade := .3;
+ @#shadeColor := .6white;
+ @#foreColor := black;
+enddef;
+
+ForkInfo.iFork;
+
+vardef Fork@#(expr orientation, length)=
+ ObjectEquations(@#);
+ @#className := "Fork";
+
+ if (orientation="h") or (orientation="horiz") or (orientation="horizontal"):
+ @#width = length;
+ @#height = iFork.thickness;
+ else:
+ @#height = length;
+ @#width = iFork.thickness;
+ fi;
+enddef;
+
+vardef Fork_layout@#=
+ % nothing to do
+enddef;
+
+vardef Fork_draw@#=
+ objectEnsurePositioning.@#;
+
+ path @#border;
+ @#border := @#nw -- @#ne -- @#se -- @#sw -- cycle;
+
+ fill @#border shifted (iFork.shade, -iFork.shade) withcolor iFork.shadeColor;
+ fill @#border withcolor iFork.foreColor;
+enddef;
+
+vardef Fork_border@#=
+ @#border
+enddef;
+
+defaultTransitionHeadWidth := 15;
+defaultTransitionHeadHeight := 5;
+
+vardef TransitionInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultTransitionHeadWidth;
+ @#heightB = defaultTransitionHeadHeight;
+ @#drawMethodB = "drawArrow";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+TransitionInfo.transition;
+
+FontInfo.guardFont(metauml_defaultFont, .7);
+PictureInfo.iGuard(2, 2, 2, 2)(guardFont);
+iGuard.ignoreNegativeBase := 1;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_base.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_base.mp
new file mode 100644
index 0000000000..22f73d3906
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_base.mp
@@ -0,0 +1,171 @@
+% Copyright 2006 2015 Ovidiu Gheorghies, Radu-George Radulescu
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_base_mp:
+ expandafter endinput
+fi;
+_metauml_base_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+
+vardef markPoint(text p)(text color) =
+ draw p withpen pencircle scaled 1 withcolor color;
+enddef;
+
+vardef drawLine(text pA)(text pB)(text base) =
+ draw pA--pB;
+enddef;
+
+vardef drawArrow(text pA)(text pB)(text base) =
+ numeric dx, dy;
+ dx = xpart(pB - pA);
+ dy = ypart(pB - pA);
+
+ numeric alfa;
+ alfa = angle(dx, dy);
+
+ pair pC, pD;
+ pC := (0, base/2);
+ pC := pC rotated (alfa) shifted pA;
+ pD := (0, base/2);
+ pD := pD rotated (180+alfa) shifted pA;
+
+ %fill pA--pC--pB--pD--cycle withcolor .8white;
+
+ draw pA--pB;
+ draw pB--pC;
+ draw pB--pD;
+enddef;
+
+vardef drawTriangle(text pA)(text pB)(text base) =
+ numeric dx, dy;
+ dx = xpart(pB - pA);
+ dy = ypart(pB - pA);
+
+ numeric alfa;
+ alfa = angle(dx, dy);
+ pair pC, pD;
+ pC := (0, base/2);
+ pC := pC rotated (alfa) shifted pA;
+ pD := (0, base/2);
+ pD := pD rotated (180+alfa) shifted pA;
+
+ fill pA--pC--pB--pD--cycle withcolor white;
+
+ draw pA--pC;% withcolor red;
+ draw pA--pD;% withcolor green;
+ draw pB--pC;% withcolor blue;
+ draw pB--pD;
+enddef;
+
+vardef drawDiamond(text pA)(text pB)(text height) =
+ numeric dx, dy;
+ dx = xpart(pB - pA);
+ dy = ypart(pB - pA);
+
+ numeric alfa;
+ alfa = angle(dx, dy);
+
+ numeric width;
+ width = _length(pA)(pB);
+
+ path diamond;
+ diamond = (0,0)--(width/2, height/2)--(width, 0)--(width/2, -height/2)--cycle;
+
+ fill diamond rotated alfa shifted pA withcolor white;
+ draw diamond rotated alfa shifted pA;
+enddef;
+
+vardef drawDiamondBlack(text pA)(text pB)(text height) =
+ numeric dx, dy;
+ dx = xpart(pB - pA);
+ dy = ypart(pB - pA);
+
+ numeric alfa;
+ alfa = angle(dx, dy);
+
+ numeric width;
+ width = _length(pA)(pB);
+
+ path diamond;
+ diamond = (0,0)--(width/2, height/2)--(width, 0)--(width/2, -height/2)--cycle;
+
+ fill diamond rotated alfa shifted pA;
+enddef;
+
+vardef drawCrossedCircle(text pA)(text pB)(text height) =
+ numeric dx, dy;
+ dx = xpart(pB - pA);
+ dy = ypart(pB - pA);
+
+ numeric alfa;
+ alfa = angle(dx, dy);
+
+ numeric width;
+ width = _length(pA)(pB);
+
+ pair pC, pD;
+ pC := (width/2, height/2 + 1);
+ pC := pC rotated (alfa) shifted pA;
+ pD := (width/2, -height/2 - 1);
+ pD := pD rotated (alfa) shifted pA;
+
+ fill pA..pB..pA -- cycle withcolor white;
+
+ draw pA -- pB;
+ draw pC -- pD;
+ draw pA .. pB .. pA;
+enddef;
+
+vardef drawSemiCircle(text pA)(text pB)(text height) =
+ numeric dx, dy;
+ dx = xpart(pB - pA);
+ dy = ypart(pB - pA);
+
+ numeric alfa;
+ alfa = angle(dx, dy);
+
+ numeric width;
+ width = _length(pA)(pB);
+
+ pair pC, pD;
+ pC := (width/2 + 5, height/2 + 1);
+ pC := pC rotated (alfa) shifted pB;
+ pD := (width/2 + 5, -height/2 - 1);
+ pD := pD rotated (alfa) shifted pB;
+
+ draw pC .. pA .. pD;
+enddef;
+
+vardef drawCircle(text pA)(text pB)(text height) =
+ fill pA..pB..pA -- cycle withcolor white;
+
+ draw pA .. pB .. pA;
+enddef;
+
+vardef drawLine(expr my_path) =
+ draw my_path;
+enddef;
+
+vardef drawLineDashed(expr my_path) =
+ draw my_path dashed evenly;
+enddef;
+
+vardef drawNothing(text pA)(text pB)(text base) =
+enddef;
+
+def shorterLineEndPoint(text pA)(text pB)(text delta) =
+ (xpart(pA) + _dx(pA)(pB)*(1 - delta/_length(pA)(pB)), ypart(pA) + _dy(pA)(pB) * (1 - delta/_length(pA)(pB)) )
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_behavioral_common.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_behavioral_common.mp
new file mode 100644
index 0000000000..190980eb69
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_behavioral_common.mp
@@ -0,0 +1,214 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_behavioral_common_mp:
+ expandafter endinput
+fi;
+_metauml_behavioral_common_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+
+vardef SpecialStateInfo@#=
+ numeric @#diameter;
+ color @#discColor;
+
+ numeric @#shade;
+ color @#shadeColor, @#foreColor;
+
+ @#diameter := 0.4cm;
+ @#discColor := black;
+ @#foreColor := black;
+
+ ShadeInfo.@#iShade;
+enddef;
+
+vardef SpecialStateInfoCopy@#(text src)=
+ SpecialStateInfo.@#;
+ ShadeInfo_copy.@#iShade(src.iShade);
+
+ @#diameter := src.diameter;
+ @#discColor := src.discColor;
+ @#foreColor := src.foreColor;
+enddef;
+
+%%%%%%%%%%%%%%%%%%
+% BEGIN %
+%%%%%%%%%%%%%%%%%%
+
+SpecialStateInfo.iBegin;
+
+vardef Begin@#=
+ ObjectEquations(@#);
+ @#className := "Begin";
+
+ SpecialStateInfoCopy.@#info(iBegin);
+enddef;
+
+vardef Begin_layout@#=
+ if @#laidout = 1:
+ log "Begin " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+
+ @#width = @#info.diameter;
+ @#height = @#info.diameter;
+ fi;
+enddef;
+
+vardef Begin_draw@#=
+ Begin_layout@#;
+ objectEnsurePositioning.@#;
+
+ path @#border;
+ @#border := @#n..@#e..@#s..@#w..cycle;
+
+ drawObjectShade(@#);
+
+ fill @#border withcolor @#info.discColor;
+ draw @#border withcolor @#info.foreColor;
+enddef;
+
+vardef Begin_border@#=
+ @#border
+enddef;
+
+%%%%%%%%%%%%%%%%%%
+% END %
+%%%%%%%%%%%%%%%%%%
+
+SpecialStateInfo.iEnd;
+iEnd.innerSpacing := 2;
+iEnd.discColor := white;
+
+vardef End@#=
+ ObjectEquations(@#);
+ @#className := "End";
+ SpecialStateInfoCopy.@#info(iEnd);
+ @#info.innerSpacing := iEnd.innerSpacing;
+enddef;
+
+vardef End_layout@#=
+ Begin_layout@#;
+enddef;
+
+vardef End_draw@#=
+ Begin_draw.@#;
+
+ path @#innerDisc;
+ @#innerDisc := @#n - (0, @#info.innerSpacing) ..
+ @#e - (@#info.innerSpacing, 0) ..
+ @#s + (0, @#info.innerSpacing) ..
+ @#w + (@#info.innerSpacing, 0) ..cycle;
+
+ fill @#innerDisc withcolor @#info.foreColor;
+enddef;
+
+vardef End_border@#=
+ @#border
+enddef;
+
+%%%%%%%%%%%%%%%%%%
+% ENTRY POINT %
+%%%%%%%%%%%%%%%%%%
+
+SpecialStateInfo.iEntryPoint;
+iEntryPoint.discColor := white;
+iEntryPoint.innerSpacing := 2;
+
+vardef EntryPoint@#=
+ ObjectEquations(@#);
+ @#className := "EntryPoint";
+ SpecialStateInfoCopy.@#info(iEntryPoint);
+ @#info.innerSpacing := iEntryPoint.innerSpacing;
+enddef;
+
+vardef EntryPoint_layout@#=
+ Begin_layout@#;
+enddef;
+
+vardef EntryPoint_draw@#=
+ Begin_draw.@#;
+enddef;
+
+vardef EntryPoint_border@#=
+ @#border
+enddef;
+
+%%%%%%%%%%%%%%%%%%
+% EXIT POINT %
+%%%%%%%%%%%%%%%%%%
+
+SpecialStateInfo.iExitPoint;
+iExitPoint.discColor := white;
+iExitPoint.innerSpacing := 2;
+
+vardef ExitPoint@#=
+ ObjectEquations(@#);
+ @#className := "ExitPoint";
+ SpecialStateInfoCopy.@#info(iExitPoint);
+ @#info.innerSpacing := iExitPoint.innerSpacing;
+ @#info.iShade.shift := 0;
+enddef;
+
+vardef ExitPoint_layout@#=
+ Begin_layout@#;
+enddef;
+
+vardef ExitPoint_draw@#=
+ Begin_draw.@#;
+
+ _n_ := str @#;
+ generic_declare(pair) _n.urt, _n.lrt, _n.llft, _n.ulft;
+
+ @#urt := @#c + @#info.diameter/2 * (sind(45), cosd(45));
+ @#lrt := @#c + @#info.diameter/2 * (sind(135), cosd(135));
+ @#llft := @#c + @#info.diameter/2 * (sind(225), cosd(225));
+ @#ulft := @#c + @#info.diameter/2 * (sind(315), cosd(315));
+
+ draw @#urt -- @#llft;
+ draw @#ulft -- @#lrt;
+enddef;
+
+vardef ExitPoint_border@#=
+ @#border
+enddef;
+
+%%%%%%%%%%%%%%%%%%
+% FlowFinal %
+%%%%%%%%%%%%%%%%%%
+
+SpecialStateInfo.iFlowFinal;
+iFlowFinal.discColor := white;
+iFlowFinal.innerSpacing := 2;
+
+vardef FlowFinal@#=
+ ObjectEquations(@#);
+ @#className := "FlowFinal";
+ SpecialStateInfoCopy.@#info(iFlowFinal);
+ @#info.innerSpacing := iFlowFinal.innerSpacing;
+ %@#info.iShade.shift := 0;
+enddef;
+
+vardef FlowFinal_layout@#=
+ Begin_layout@#;
+enddef;
+
+vardef FlowFinal_draw@#=
+ ExitPoint_draw@#
+enddef;
+
+vardef FlowFinal_border@#=
+ @#border
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_class.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_class.mp
new file mode 100644
index 0000000000..c3ac333b21
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_class.mp
@@ -0,0 +1,485 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_class_mp:
+ expandafter endinput
+fi;
+_metauml_class_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+inputonce util_picture;
+inputonce util_picture_stack;
+inputonce util_shade;
+
+string visibilityPublic, visibilityProtected, visibilityPrivate, visibilityPackage;
+visibilityPublic:="+";
+visibilityProtected:="#";
+visibilityPrivate:="-";
+visibilityPackage:="~";
+
+string metauml_private_abstractMarker, metauml_private_staticMarker;
+metauml_private_abstractMarker := "@abstract";
+metauml_private_staticMarker := "@static";
+
+def abstract expr methodName= metauml_private_abstractMarker&methodName enddef;
+def static expr featureName= metauml_private_staticMarker&featureName enddef;
+
+def metauml_private_isAbstract(expr name) = (substring (0, 9) of name = metauml_private_abstractMarker) enddef;
+def metauml_private_isStatic(expr name) = (substring (0, 7) of name = metauml_private_staticMarker) enddef;
+def metauml_private_stripStatic(expr name) = substring (7,infinity) of name enddef;
+def metauml_private_stripAbstract(expr name) = substring (9,infinity) of name enddef;
+
+vardef ClassInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(string) featureVisibilityMode;
+
+ FontInfo.@#nameFont(metauml_defaultFont, defaultscale);
+ FontInfo.@#featureFont (metauml_defaultFont, defaultscale);
+ FontInfo.@#stereotypeFont(metauml_defaultFont, .7);
+
+ ShadeInfo.@#iShade;
+
+ @#featureVisibilityMode := "individual"; % "none", "grouped"
+
+ @#foreColor := .9white;
+ @#borderColor := black;
+
+ PictureInfo.@#iName (2, 2, 1, 3)(@#nameFont);
+ @#iName.ignoreNegativeBase := 1;
+
+ PictureInfoCopy.@#iNameAbstract(@#iName);
+ @#iNameAbstract.iFont.name := metauml_defaultFontOblique;
+
+ PictureInfo.@#iStereotype(2, 2, 2, 2)(@#stereotypeFont);
+ @#iStereotypeStack.iPict.ignoreNegativeBase := 1;
+
+ PictureStackInfo.@#iStereotypeStack(2, 2, 1, 1)(5.5)(@#iStereotype);
+
+ PictureInfo.@#iFeature (2, 2, 1.25, 0)(@#featureFont);
+
+ PictureInfoCopy.@#iFeatureAbstract (@#iFeature);
+ @#iFeatureAbstract.iFont.name := metauml_defaultFontOblique;
+
+ PictureInfoCopy.@#iFeatureStatic (@#iFeature);
+ @#iFeatureStatic.textDecoration := "underline";
+
+ PictureStackInfo.@#iFeatureStack (2, 2, 2.5, 2)(10.5)(@#iFeature);
+ PictureStackInfoCopy.@#iAttributeStack(@#iFeatureStack);
+ PictureStackInfoCopy.@#iMethodStack(@#iFeatureStack);
+
+ @#iFeatureStack.iPict.bottom := 2;
+ @#iFeatureStack.iPict.ignoreNegativeBase := 1;
+
+ PictureStackInfoCopy.@#iAttributeVisibilityStack (@#iFeatureStack);
+ PictureStackInfoCopy.@#iMethodVisibilityStack (@#iFeatureStack);
+
+ @#iAttributeVisibilityStack.right := 0;
+ @#iMethodVisibilityStack.right := 0;
+enddef;
+
+vardef ClassInfoCopy@#(text src)=
+ log "ClassInfoCopy: Copying class";
+
+ attributes(@#);
+ var(numeric) featureVisibilitySpacing, visibilityWidth, visibilityHeight;
+ var(color) foreColor, borderColor;
+ var(string) featureVisibilityMode;
+
+ FontInfoCopy.@#nameFont(src.nameFont);
+ FontInfoCopy.@#featureFont(src.featureFont);
+ FontInfoCopy.@#stereotypeFont(src.stereotypeFont);
+
+ ShadeInfoCopy.@#iShade(src.iShade);
+
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+
+ PictureInfoCopy.@#iName (src.iName);
+ PictureInfoCopy.@#iNameAbstract (src.iNameAbstract);
+
+ PictureInfoCopy.@#iStereotype(src.iStereotype);
+ PictureInfoCopy.@#iFeature (src.iFeature);
+ PictureInfoCopy.@#iFeatureAbstract (src.iFeatureAbstract);
+ PictureInfoCopy.@#iFeatureStatic (src.iFeatureStatic);
+
+ PictureStackInfoCopy.@#iStereotypeStack(src.iStereotypeStack);
+ PictureStackInfoCopy.@#iFeatureStack (src.iFeatureStack);
+ PictureStackInfoCopy.@#iAttributeStack (src.iAttributeStack);
+ PictureStackInfoCopy.@#iMethodStack (src.iMethodStack);
+ PictureStackInfoCopy.@#iAttributeVisibilityStack (src.iAttributeVisibilityStack);
+ PictureStackInfoCopy.@#iMethodVisibilityStack (src.iMethodVisibilityStack);
+
+ @#featureVisibilityMode := src.featureVisibilityMode;
+enddef;
+
+ClassInfo.iClass;
+
+ClassInfoCopy.iClassNameOnly(iClass);
+iClassNameOnly.iName.top := 10;
+iClassNameOnly.iName.bottom := 10;
+iClassNameOnly.iAttributeStack.top := 0;
+iClassNameOnly.iAttributeStack.bottom := 0;
+iClassNameOnly.iMethodStack.top := 0;
+iClassNameOnly.iMethodStack.bottom := 0;
+
+ClassInfoCopy.iInterface(iClass);
+iInterface.iAttributeStack.top := 0;
+iInterface.iAttributeStack.bottom := 0;
+iInterface.iName.iFont.name := metauml_defaultFontOblique;
+
+ClassInfoCopy.iAbstractClass(iClass);
+iAbstractClass.iName.iFont.name := metauml_defaultFontOblique;
+
+%
+% CLASS
+%
+vardef defClass@#(expr pname) =
+ ObjectEquations(@#);
+ @#className := "Class";
+
+ string @#name;
+ boolean @#isAbstract;
+
+ @#isAbstract := metauml_private_isAbstract(pname);
+ if @#isAbstract:
+ @#name = metauml_private_stripAbstract(pname);
+ else:
+ @#name = pname;
+ fi
+
+ numeric @#nStereotypes;
+ string @#stereotypes[];
+
+ string @#attributes[];
+ string @#attributesVisibility[];
+ boolean @#attributesIsStatic[];
+
+ string @#methods[];
+ string @#methodsVisibility[];
+ boolean @#methodsIsStatic[];
+ boolean @#methodsIsAbstract[];
+
+ numeric @#nAttrs;
+ numeric @#nMethods;
+ numeric @#nStereotypes;
+
+ @#nStereotypes := 0;
+ @#nAttrs := 0;
+ @#nMethods := 0;
+enddef;
+
+vardef addAttribute@#(expr pcontent) =
+ string visibility;
+ string attribute;
+
+ attribute := pcontent;
+
+ @#attributesIsStatic[@#nAttrs] := metauml_private_isStatic(attribute);
+ if @#attributesIsStatic[@#nAttrs]:
+ attribute := metauml_private_stripStatic(attribute);
+ fi
+
+ visibility := substring(0,1) of attribute;
+ if (not (visibility = visibilityPublic)) and
+ (not (visibility = visibilityPrivate)) and
+ (not (visibility = visibilityProtected)) and
+ (not (visibility = visibilityPackage)):
+
+ @#.attributes[@#.nAttrs] := attribute;
+ @#.attributesVisibility[@#.nAttrs] := visibilityPackage;
+ else:
+ save from;
+ from := 1;
+ if (substring(1,2) of attribute) = " ": from := 2; fi;
+
+ @#.attributes[@#.nAttrs] := substring(from, infinity) of attribute;
+ @#.attributesVisibility[@#.nAttrs] := visibility;
+ fi;
+
+ @#.nAttrs := @#.nAttrs + 1;
+enddef;
+
+vardef addMethod@#(expr pcontent) =
+ string visibility;
+ string method;
+
+ method := pcontent;
+
+ @#methodsIsStatic[@#nMethods] := metauml_private_isStatic(method);
+ if @#methodsIsStatic[@#nMethods]:
+ method := metauml_private_stripStatic(method);
+ fi
+
+ @#methodsIsAbstract[@#nMethods] := metauml_private_isAbstract(method);
+ if @#methodsIsAbstract[@#nMethods]:
+ method := metauml_private_stripAbstract(method);
+ @#isAbstract := true;
+ fi
+
+ visibility := substring(0,1) of method;
+ if (not (visibility = visibilityPublic)) and
+ (not (visibility = visibilityPrivate)) and
+ (not (visibility = visibilityProtected)) and
+ (not (visibility = visibilityPackage)):
+
+ @#.methods[@#.nMethods] := method;
+ @#.methodsVisibility[@#.nMethods] := visibilityPackage;
+ else:
+ save from;
+ from := 1;
+ if (substring(1,2) of method) = " ": from := 2; fi;
+
+ @#.methods[@#.nMethods] := substring(from, infinity) of method;
+ @#.methodsVisibility[@#.nMethods] := visibility;
+ fi;
+
+ @#.nMethods := @#.nMethods + 1;
+enddef;
+
+vardef classStereotype@#(expr pcontent) =
+ show "Macro classStereotype is deprecated, use Class_stereotypes instead.";
+ Class_stereotypes.@#(pcontent);
+enddef;
+
+vardef classStereotypes@#(text stereotypes)=
+ show "Macro classStereotypes is deprecated, use Class_stereotypes instead.";
+ Class_stereotypes.@#(stereotypes);
+enddef;
+
+vardef EClass@#(text _info)(expr name)(text attributes)(text methods)=
+ log "EClass begin: " & str @#;
+
+ defClass@#(name);
+
+ log "Copying class info";
+ ClassInfoCopy.@#info(_info);
+
+ for a=attributes:
+ log "Adding attribute ", a;
+ addAttribute@#(a);
+ endfor;
+ for m=methods:
+ log "Adding method ", m;
+ addMethod@#(m);
+ endfor;
+enddef;
+
+vardef Class@#(expr name)(text attributes)(text methods)=
+ EClass@#(iClass)(name)(attributes)(methods);
+enddef;
+
+vardef Interface@#(expr name)(text methods)=
+ EClass@#(iInterface)(name)()(methods);
+enddef;
+
+vardef EInterface@#(text _info)(expr name)(text methods)=
+ EClass@#(_info)(name)()(methods);
+enddef;
+
+vardef ClassName@#(expr name)=
+ EClass@#(iClassNameOnly)(name)()();
+enddef;
+
+vardef EClassName@#(text _info)(expr name)=
+ EClass@#(_info)(name)()();
+enddef;
+
+vardef AbstractClass@#(expr name)(text attributes)(text methods)=
+ EClass@#(iAbstractClass)(name)(attributes)(methods);
+enddef;
+
+vardef EAbstractClass@#(text _info)(expr name)(text methods)=
+ EClass@#(_info)(name)()(methods);
+enddef;
+
+vardef Class_border@#=
+ objectBox(@#)
+enddef;
+
+vardef Class_noVisibilityMarkers@#=
+ @#info.featureVisibilityMode := "none";
+enddef;
+
+vardef Class_layout@# =
+ if @#laidout = 1:
+ log "Class " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Class layout: " & (str @#);
+
+ EPictureStack.@#stereotypeStack(@#info.iStereotypeStack)
+ (scantokens listArray(@#stereotypes)(@#nStereotypes))("vcenterbase");
+
+ if (@#isAbstract):
+ EPicture.@#namePict(@#info.iNameAbstract)(@#name);
+ else:
+ EPicture.@#namePict(@#info.iName)(@#name);
+ fi;
+
+ layoutObjects(@#stereotypeStack, @#namePict);
+
+ % Define attributes
+
+ def metauml_private_attributeStyleSupplier(expr i)=
+ if @#attributesIsStatic[i]: @#info.iFeatureStatic
+ else: @#info.iFeature
+ fi
+ enddef;
+
+ @#info.iAttributeStack.childStyleSupplier := "metauml_private_attributeStyleSupplier";
+
+ EPictureStack.@#attributeStack(@#info.iAttributeStack)
+ (scantokens listArray(@#attributes)(@#nAttrs))("vleftbase");
+
+ if @#info.featureVisibilityMode = "individual":
+ vardef joinCallbackAttributesVisibility@#=
+ setObjectJoin(pb.bottom = @#.attributeStack.pict[index].bottom; pb.midx = pa.midx);
+ setObjectJoinFirst(pa.bottom = @#.attributeStack.pict[index].bottom);
+ enddef;
+
+ EPictureStack.@#attributeVisibilityStack(@#info.iAttributeVisibilityStack)
+ (scantokens listArray(@#attributesVisibility)(@#nAttrs))
+ ("joinCallbackAttributesVisibility." & (str @#));
+ elseif @#info.featureVisibilityMode = "none":
+ EPicture.@#attributeVisibilityStack(iPictNoMargins)("");
+ else:
+ show "Unknown feature visibility mode", @#featureVisibilityMode;
+ 1=2;
+ fi;
+
+ % Define methods
+
+ def metauml_private_methodStyleSupplier(expr i)=
+ if @#methodsIsStatic[i]: @#info.iFeatureStatic
+ elseif @#methodsIsAbstract[i]: @#info.iFeatureAbstract
+ else: @#info.iFeature
+ fi
+ enddef;
+
+ @#info.iMethodStack.childStyleSupplier := "metauml_private_methodStyleSupplier";
+
+ EPictureStack.@#methodStack(@#info.iMethodStack)
+ (scantokens listArray(@#methods)(@#nMethods))("vleftbase");
+
+ if @#info.featureVisibilityMode = "individual":
+ vardef joinCallbackMethodsVisibility@#=
+ setObjectJoin(pb.bottom = @#.methodStack.pict[index].bottom; pb.midx = pa.midx);
+ setObjectJoinFirst(pa.bottom = @#.methodStack.pict[index].bottom);
+ enddef;
+
+ EPictureStack.@#methodVisibilityStack(@#info.iMethodVisibilityStack)
+ (scantokens listArray(@#methodsVisibility)(@#nMethods))
+ ("joinCallbackMethodsVisibility." & (str @#));
+ elseif @#info.featureVisibilityMode = "none":
+ EPicture.@#methodVisibilityStack(iPictNoMargins)("");
+ else:
+ show "Unknown feature visibility mode", @#featureVisibilityMode;
+ 1=2;
+ fi;
+
+ % Integrate components
+ show layoutObjects(@#attributeStack, @#methodStack);
+ layoutObjects(@#attributeStack, @#methodStack);
+
+ @#attributeStack.left = @#methodStack.left;
+ @#methodStack.top = @#attributeStack.bottom;
+
+ layoutObjects(@#attributeVisibilityStack, @#methodVisibilityStack);
+
+ @#attributeVisibilityStack.midx = @#methodVisibilityStack.midx;
+
+ if (@#.nMethods = 0) or (@#info.featureVisibilityMode="none"):
+ @#methodVisibilityStack.top = @#methodStack.top;
+ fi;
+ if (@#.nAttrs = 0) or (@#info.featureVisibilityMode="none"):
+ @#attributeVisibilityStack.top = @#attributeStack.top;
+ fi;
+
+ EGroup.@#visibilityStacks(iGroupNoMargins)(@#attributeVisibilityStack, @#methodVisibilityStack);
+
+ EGroup.@#featureStacks(iGroupNoMargins)(@#attributeStack, @#methodStack);
+
+ layoutObjects(@#visibilityStacks, @#featureStacks);
+
+ @#visibilityStacks.right = @#featureStacks.left;
+
+ EGroup.@#featureGroup(iGroupNoMargins)(@#visibilityStacks, @#featureStacks);
+
+ topToBottom(0)(@#stereotypeStack, @#namePict, @#featureGroup);
+
+ EGroup.@#all(iGroupNoMargins)(@#stereotypeStack, @#namePict, @#featureGroup);
+
+ layoutObjects(@#all);
+
+ @#.nw = @#all.nw;
+ @#.se = @#all.se;
+
+ log "Class layout for " & (str @#) & " done...";
+ fi;
+enddef;
+
+vardef Class_paintSkin@# =
+ log "Painting class skin...";
+ nameAttributeY := @#attributeStack.top;
+ attributeMethodY := @#methodStack.top;
+
+ drawObjectShade(@#);
+
+ fill Class_border.@# withcolor @#info.foreColor;
+ draw Class_border.@# withcolor @#info.borderColor;
+
+ draw (xpart @#nw, nameAttributeY)--(xpart @#se, nameAttributeY) withcolor @#info.borderColor;
+ draw (xpart @#nw, attributeMethodY)--(xpart @#se, attributeMethodY) withcolor @#info.borderColor;
+enddef;
+
+vardef Class_draw@#=
+ log "Class_draw begin " & @#;
+ Class_layout.@#;
+ objectEnsurePositioning.@#;
+ Class_paintSkin.@#;
+
+ drawObjects(@#all);
+ log "Class_draw end " & @#;
+enddef;
+
+vardef Class_setDebugMode@#=
+ @#.info.iName.boxed := 1;
+
+ @#.info.iFeature.boxed := 1;
+ @#.info.iFeatureStatic.boxed := 1;
+ @#.info.iFeatureAbstract.boxed := 1;
+
+ @#.info.iStereotypeStack.boxed := 1;
+ @#.info.iStereotypeStack.iPict.boxed := 1;
+ @#.info.iAttributeStack.boxed := 1;
+ @#.info.iAttributeStack.iPict.boxed := 1;
+ @#.info.iMethodStack.boxed := 1;
+ @#.info.iMethodStack.iPict.boxed := 1;
+
+ @#.info.iAttributeVisibilityStack.boxed := 1;
+ @#.info.iAttributeVisibilityStack.iPict.boxed := 1;
+ @#.info.iMethodVisibilityStack.boxed := 1;
+ @#.info.iMethodVisibilityStack.iPict.boxed := 1;
+enddef;
+
+vardef Class_stereotypes@#(text _stereotypes)=
+ for stereotype = _stereotypes:
+ @#stereotypes[@#nStereotypes] := stereotype;
+ @#nStereotypes := @#nStereotypes + 1;
+ endfor;
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_class_assoc.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_class_assoc.mp
new file mode 100644
index 0000000000..720117fc90
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_class_assoc.mp
@@ -0,0 +1,93 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_class_assoc_mp:
+ expandafter endinput
+fi;
+_metauml_class_assoc_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+inputonce metauml_defaults;
+
+FontInfo.assocFont(metauml_defaultFont, .7);
+PictureInfo.iAssoc(2, 2, 2, 2)(assocFont);
+iAssoc.ignoreNegativeBase := 1;
+
+vardef QualifiedAssociationInfo@#=
+ color @#background;
+ color @#borderColor;
+ numeric @#borderScale;
+
+ @#background := .9white;
+ @#borderColor := black;
+ @#borderScale := .5;
+
+ FontInfo.@#iFont(metauml_defaultFont, .9);
+ PictureInfo.@#iPict(2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iStack(2, 2, 1, 1)(7)(@#iPict);
+
+ @#iStack.iPict.ignoreNegativeBase := 1;
+enddef;
+
+vardef QualifiedAssociationInfoCopy@#(text src)=
+ color @#background;
+ color @#borderColor;
+ numeric @#borderScale;
+
+ @#background := src.background;
+ @#borderColor := src.borderColor;
+ @#borderScale := src.borderScale;
+
+ FontInfoCopy.@#iFont(src.iFont);
+ PictureInfoCopy.@#iPict(src.iPict);
+ PictureStackInfoCopy.@#iStack(src.iStack);
+enddef;
+
+QualifiedAssociationInfo.iQualifiedAssociation;
+
+%
+% QualifiedAssociation
+%
+vardef EQualifiedAssociation@#(text _info)(text qualifiedAssociations) =
+ ObjectEquations(@#);
+ @#className := "QualifiedAssociation";
+
+ QualifiedAssociationInfoCopy.@#info(_info);
+
+ EPictureStack.@#elementsStack(@#info.iStack)(qualifiedAssociations)("vleftbase");
+
+ @#nw = @#elementsStack.nw;
+ @#se = @#elementsStack.se;
+enddef;
+
+vardef QualifiedAssociation@#(text qualifiedAssociations)=
+ EQualifiedAssociation@#(iQualifiedAssociation)(qualifiedAssociations);
+enddef;
+
+vardef QualifiedAssociation_paintSkin@# =
+ log "Painting qualifiedAssociation skin...";
+
+ fill objectBox(@#) withcolor @#info.background;
+
+ draw objectBox(@#)
+ withpen pencircle scaled @#info.borderScale withcolor @#info.borderColor;
+enddef;
+
+vardef QualifiedAssociation_draw@# =
+ PictureStack_layout.@#elementsStack;
+
+ QualifiedAssociation_paintSkin.@#;
+ drawObject(@#elementsStack);
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_class_relations.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_class_relations.mp
new file mode 100644
index 0000000000..0379aceeca
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_class_relations.mp
@@ -0,0 +1,172 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_class_relations_mp:
+ expandafter endinput
+fi;
+_metauml_class_relations_mp:=1;
+
+defaultRelationHeadWidth := 25;
+defaultRelationHeadHeight := 10;
+
+vardef AssociationInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = 0;
+ @#heightB = 0;
+ @#drawMethodB = "drawNothing";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef AssociationUniInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawArrow";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef InheritanceInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawTriangle";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef AggregationInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawDiamond";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef AggregationUniInfo@# =
+ LinkInfo@#;
+
+ @#widthA = defaultRelationHeadWidth;
+ @#heightA = defaultRelationHeadHeight;
+ @#drawMethodA = "drawArrow";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawDiamond";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef CompositionInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawDiamondBlack";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef CompositionUniInfo@# =
+ LinkInfo@#;
+
+ @#widthA = defaultRelationHeadWidth;
+ @#heightA = defaultRelationHeadHeight;
+ @#drawMethodA = "drawArrow";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawDiamondBlack";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef DashedLinkInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = 0;
+ @#heightB = 0;
+ @#drawMethodB = "drawNothing";
+
+ @#drawMethod = "drawLineDashed";
+enddef;
+
+vardef DependencyInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawArrow";
+
+ @#drawMethod = "drawLineDashed";
+enddef;
+
+vardef RealizationInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawTriangle";
+
+ @#drawMethod = "drawLineDashed";
+enddef;
+
+AssociationInfo.association;
+AssociationUniInfo.associationUni;
+InheritanceInfo.inheritance;
+AggregationInfo.aggregation;
+AggregationUniInfo.aggregationUni;
+CompositionInfo.composition;
+CompositionUniInfo.compositionUni;
+DashedLinkInfo.dashedLink;
+DependencyInfo.dependency;
+RealizationInfo.realization;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Deprecated, kept to support code using the older API.
+% Using the generic formulation involving link, e.g.
+% link(association)(A.n--B.s) is preferable.
+% link and clink are defined in metauml_links
+%
+vardef drawRelation(text iLink)(expr myPath)=
+ link(iLink)(myPath);
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_component.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_component.mp
new file mode 100644
index 0000000000..c124f77110
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_component.mp
@@ -0,0 +1,186 @@
+% Copyright 2006 2015 Radu-George Radulescu, Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_component_mp:
+ expandafter endinput
+fi;
+_metauml_component_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+vardef ComponentInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(numeric) minimumNameContentsDifference;
+
+ FontInfo.@#iFont(metauml_defaultFont, defaultscale);
+ @#iFont.ignoreNegativeBase := 1;
+
+ PictureInfo.@#iText (2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iNameStack (2, 2, 2, 2)(9)(@#iText);
+ @#iNameStack.iPict.ignoreNegativeBase := 1;
+
+ Margins.@#(2,2,2,2);
+
+ ShadeInfo.@#iShade;
+ @#foreColor := .9white;
+ @#borderColor := black;
+
+ @#minimumNameContentsDifference := 20;
+
+ GroupInfo.@#iContentsGroup(2, 2, 10, 2);
+enddef;
+
+vardef ComponentInfoCopy@#(text src)=
+ log "ComponentInfoCopy: Copying component info";
+
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(numeric) minimumNameContentsDifference;
+
+ PictureStackInfoCopy.@#iNameStack (src.iNameStack);
+ MarginsCopy.@#(src);
+
+ ShadeInfoCopy.@#iShade(src.iShade);
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+
+ @#minimumNameContentsDifference := src.minimumNameContentsDifference;
+
+ GroupInfoCopy.@#iContentsGroup(src.iContentsGroup);
+enddef;
+
+ComponentInfo.iComponent;
+
+vardef Component@#(text contents)(text _subItems)=
+ EComponent.@#(iComponent)(contents)(_subItems);
+enddef;
+
+vardef EComponent@#(text _info)(text contents)(text _subItems)=
+ ObjectEquations(@#);
+ @#className := "Component";
+
+ ComponentInfoCopy.@#info(_info);
+
+ numeric @#nLines; @#nLines := 0;
+ string @#lines[];
+ numeric @#nSubItems; @#nSubItems := 0;
+
+ for l=contents:
+ @#lines[@#nLines] := l;
+ @#nLines := @#nLines + 1;
+ endfor;
+
+ for s=_subItems:
+ @#nSubItems := @#nSubItems + 1;
+ endfor;
+
+ EGroup.@#subItems(@#info.iContentsGroup)(_subItems);
+
+ EPictureStack.@#nameStack(@#info.iNameStack)(scantokens listArray(@#lines)(@#nLines))("vcenterbase");
+enddef;
+
+vardef Component_layout@#=
+ if @#laidout = 1:
+ log "Component '" & (str @#) & "' has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Component layout: '" & (str @#) & "'";
+
+ log "Component name layout '" & (str @#) & "'...";
+ PictureStack_layout.@#nameStack;
+ log "SubItems for component layout '" & (str @#) & "'...";
+ Group_layout.@#subItems;
+
+ log "All elements in component '" & (str @#) & "' successfully layed out, integrating...";
+
+
+ if @#subItems.width < @#nameStack.width + @#info.minimumNameContentsDifference:
+ @#contentWidth = @#nameStack.width + @#info.minimumNameContentsDifference;
+ else:
+ @#contentWidth = lmax(@#nameStack.width, @#subItems.width);
+ fi;
+
+ @#width = @#contentWidth + @#info.left + @#info.right + 15;
+
+ if @#nSubItems = 0:
+ @#height = @#info.top + @#info.bottom + @#subItems.height + 15;
+ @#nameStack.n = @#n - (0, 7);
+ else:
+ @#height = @#info.top + @#info.bottom + @#subItems.height + 30;
+ @#nameStack.n = @#n + (0, @#info.top) - (0, 5);
+ fi;
+
+ @#subItems.n = @#n + (0, -((@#height - @#subItems.height)/2)) - (0, 5);
+
+ log "Component layout for " & (str @#) & " ended.";
+ fi;
+enddef;
+
+vardef Component_draw@#=
+ Component_layout.@#;
+ objectEnsurePositioning.@#;
+
+ attributes(@#);
+ var(path) border;
+
+ @#border := @#ne -- @#nw -- @#sw -- @#se -- cycle;
+
+ drawObjectShade(@#);
+
+ fill @#border withcolor @#info.foreColor;
+ draw @#border withcolor @#info.borderColor;
+
+ drawComponentVisualStereotype(@#ne);
+
+ drawObject(@#nameStack);
+ drawObject(@#subItems);
+
+enddef;
+
+vardef drawComponentVisualStereotype(text ne)=
+ % lud = left-up-down of the top-right rectangle; luu = left-up-up of the top-right rectangle etc.
+ pair lud, luu, ru, rd, ldd, ldu, lmd, lmu;
+ % urectld = upper rectangle left-down, lrectru = lower rectangle right-up
+ pair urectld, urectlu, urectru, urectrd, lrectld, lrectlu, lrectru, lrectrd;
+ lud = ne - (14, 5 );
+ luu = lud + (0, 2 );
+ ru = luu + (8, 0 );
+ rd = ru - (0, 14);
+ ldd = rd - (8, 0 );
+ ldu = ldd + (0, 2 );
+ lmd = ldu + (0, 3 );
+ lmu = lud - (0, 3 );
+
+ urectld = lmu - (3, 0);
+ urectlu = lud - (3, 0);
+ urectru = lud + (3, 0);
+ urectrd = lmu + (3, 0);
+
+ lrectld = ldu - (3, 0);
+ lrectlu = lmd - (3, 0);
+ lrectru = lmd + (3, 0);
+ lrectrd = ldu + (3, 0);
+
+ draw lud -- luu -- ru -- rd -- ldd -- ldu;
+ draw lmd -- lmu;
+ draw urectld -- urectlu -- urectru -- urectrd -- urectld;
+ draw lrectld -- lrectlu -- lrectru -- lrectrd -- lrectld;
+enddef;
+
+vardef Component_border@#=
+ @#border
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_component_relations.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_component_relations.mp
new file mode 100644
index 0000000000..e6800a2acb
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_component_relations.mp
@@ -0,0 +1,55 @@
+% Copyright 2006 2015 Radu-George Radulescu, Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_component_relations_mp:
+ expandafter endinput
+fi;
+_metauml_component_relations_mp:=1;
+
+defaultRelationHeadWidth := 25;
+defaultRelationHeadHeight := 10;
+requiredInterfaceHeadWidth := 5;
+requiredInterfaceHeadHeight := 15;
+
+vardef requiredInterfaceInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = requiredInterfaceHeadWidth;
+ @#heightB = requiredInterfaceHeadHeight;
+ @#drawMethodB = "drawSemiCircle";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+vardef providedInterfaceInfo@# =
+ LinkInfo@#;
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawCircle";
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+requiredInterfaceInfo.requiredInterface;
+providedInterfaceInfo.providedInterface;
+
+vardef drawRelation(text iLink)(expr myPath)=
+ link(iLink)(myPath);
+enddef;
+
+vardef drawLine(expr my_path) =
+ draw my_path;
+enddef;
+
+vardef drawNothing(text pA)(text pB)(text base) =
+enddef;
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_defaults.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_defaults.mp
new file mode 100644
index 0000000000..228df4c48c
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_defaults.mp
@@ -0,0 +1,31 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_defaults_mp:
+ expandafter endinput
+fi;
+_metauml_defaults_mp:=1;
+
+% txbtt
+
+if not known metauml_defaultFont:
+ string metauml_defaultFont;
+ metauml_defaultFont := "ptmr8r";
+fi;
+
+if not known metauml_defaultFontOblique:
+ string metauml_defaultFontOblique;
+ metauml_defaultFontOblique := "ptmro8r";
+fi;
+
+if not known metauml_defaultFontBold:
+ string metauml_defaultFontBold;
+ metauml_defaultFontBold := "ptmb8r";
+fi;
+
+if not known metauml_defaultFontBoldOblique:
+ string metauml_defaultFontBoldOblique;
+ metauml_defaultFontBoldOblique := "ptmbo8r";
+fi;
+
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_instance.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_instance.mp
new file mode 100644
index 0000000000..543920eb49
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_instance.mp
@@ -0,0 +1,186 @@
+% Copyright 2005 2015 Radu-George Radulescu
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_instance_mp:
+ expandafter endinput
+fi;
+_metauml_instance_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+inputonce util_picture;
+inputonce util_picture_stack;
+inputonce util_shade;
+
+vardef InstanceInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+
+ FontInfo.@#nameFont(metauml_defaultFont, defaultscale);
+
+ FontInfo.@#attributeFont(metauml_defaultFont, defaultscale);
+
+ ShadeInfo.@#iShade;
+
+ @#foreColor := .9white;
+ @#borderColor := black;
+
+ PictureInfo.@#iName (2, 2, 1, 3)(@#nameFont);
+
+ PictureInfo.@#iAttribute (2, 2, 1.25, 0)(@#attributeFont);
+
+ PictureStackInfo.@#iAttributeStack (2, 2, 2.5, 2)(10.5)(@#iAttribute); % 8.5
+ @#iAttributeStack.iPict.bottom := 2;
+
+ @#iName.ignoreNegativeBase := 1;
+ @#iAttributeStack.iPict.ignoreNegativeBase := 1;
+enddef;
+
+vardef InstanceInfoCopy@#(text src)=
+ log "InstanceInfoCopy: Copying Instance";
+
+ attributes(@#);
+ var(color) foreColor, borderColor;
+
+ FontInfoCopy.@#nameFont(src.nameFont);
+
+ FontInfoCopy.@#attributeFont(src.attributeFont);
+
+ ShadeInfoCopy.@#iShade(src.iShade);
+
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+
+ PictureInfoCopy.@#iName (src.iName);
+
+ PictureInfoCopy.@#iAttribute (src.iAttribute);
+ PictureStackInfoCopy.@#iAttributeStack (src.iAttributeStack);
+
+enddef;
+
+InstanceInfo.iInstance;
+
+%
+% Instance
+%
+vardef defInstance@#(expr pname) =
+ ObjectEquations(@#);
+ @#className := "Instance";
+
+ string @#name;
+ @#name = pname;
+
+ string @#attributes[];
+ numeric @#nAttrs;
+ @#nAttrs := 0;
+enddef;
+
+vardef Instance_addAttribute@#(expr pcontent) =
+
+ @#.attributes[@#.nAttrs] := pcontent;
+ @#.nAttrs := @#.nAttrs + 1;
+
+enddef;
+
+vardef EInstance@#(text _info)(expr name)(text attributes)=
+ log "EInstance begin";
+ defInstance@#(name);
+
+ log "Copying Instance info";
+ InstanceInfoCopy.@#info(_info);
+
+ for a = attributes:
+ log "Adding attribute ", a;
+ Instance_addAttribute@#(a);
+ endfor;
+enddef;
+
+vardef Instance@#(expr name)(text attributes)=
+ EInstance@#(iInstance)(name)(attributes);
+enddef;
+
+vardef Instance_border@#=
+ objectBox(@#)
+enddef;
+
+vardef Instance_layout@# =
+ if @#laidout = 1:
+ log "Instance " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Instance layout: " & (str @#);
+
+ @#maxFeatureWidth := 0;
+
+ EPicture.@#namePict(@#info.iName)(@#name);
+ EPictureStack.@#attributeStack(@#info.iAttributeStack)
+ (scantokens listArray(@#attributes)(@#nAttrs))("vleftbase");
+
+ layoutObjects(@#namePict, @#attributeStack);
+
+ @#maxFeatureWidth := lmax(@#namePict.width, @#attributeStack.width) + 1;
+
+ @#namePict.midx = @#midx;
+
+ @#namePict.top = @#top - 1;
+ @#attributeStack.top = @#namePict.bottom - 1;
+
+ @#attributeStack.left = @#left;
+
+ @#width = @#maxFeatureWidth;
+ @#bottom = @#attributeStack.bottom;
+
+ log "Layout done...";
+ fi;
+enddef;
+
+vardef Instance_drawFeatures@#=
+ log "Drawing name";
+ drawObject(@#namePict);
+ log "Underlining name";
+ pair A, B;
+ A := @#namePict.se + (-@#namePict.info.left, @#namePict.info.bottom-1);
+ B := @#namePict.sw + (@#namePict.info.right, @#namePict.info.bottom-1);
+ draw A--B;
+ log "Drawing attribute stack";
+ drawObject(@#attributeStack);
+
+enddef;
+
+vardef Instance_paintSkin@# =
+ log "Painting Instance skin...";
+
+ drawObjectShade(@#);
+
+ fill Instance_border.@# withcolor @#info.foreColor;
+ draw Instance_border.@# withcolor @#info.borderColor;
+
+ draw (xpart @#nw, @#attributeStack.top)--(xpart @#se, @#attributeStack.top) withcolor @#info.borderColor;
+enddef;
+
+vardef Instance_draw@#=
+ log "draw Instance begin...";
+ Instance_layout.@#;
+ objectEnsurePositioning.@#;
+ Instance_paintSkin.@#;
+ Instance_drawFeatures.@#;
+enddef;
+
+vardef Instance_setDebugMode@#=
+ @#.info.iName.boxed := 1;
+ @#.info.iAttributeStack.boxed := 1;
+ @#.info.iAttributeStack.iPict.boxed := 1;
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_links.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_links.mp
new file mode 100644
index 0000000000..06a9dbabba
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_links.mp
@@ -0,0 +1,86 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+% A LinkStructure is used to compute the relevant elements
+% of a link, such as what is the main path of the link and
+% where the link ends are to be drawn.
+%
+% For example, for a unidirectional aggregation between points
+% A and B one must reserve some space for one diamond to the left and one arrow
+% to the right, and draw the continous line on a segment shorter than AB.
+%
+
+if known _metauml_links_mp:
+ expandafter endinput
+fi;
+_metauml_links_mp:=1;
+
+vardef LinkStructure@#(expr my_path, widthA, widthB) =
+ pair @#pointA, @#pointB, @#pointAc, @#pointBc;
+ path @#circleA, @#circleB;
+ numeric @#timeA, @#timeB;
+ path @#actualPath;
+
+ @#pointA = point 0 of my_path;
+ @#pointB = point infinity of my_path;
+
+ @#circleA = fullcircle scaled widthA shifted @#pointA;
+ @#circleB = fullcircle scaled widthB shifted @#pointB;
+
+ @#timeA = xpart (my_path intersectiontimes @#circleA);
+ @#timeB = xpart (my_path intersectiontimes @#circleB);
+ @#pointAc = point @#timeA of my_path;
+ @#pointBc = point @#timeB of my_path;
+
+ @#actualPath = subpath (@#timeA, @#timeB) of my_path;
+enddef;
+
+% Used for visual debugging purposes
+%
+vardef describeLinkStructure(text linkStruct)=
+ %draw linkStruct.pointA -- linkStruct.pointB withpen pencircle scaled 2 withcolor green;
+
+ draw linkStruct.circleA;
+ draw linkStruct.circleB;
+
+ dotlabel.lft("A", linkStruct.pointA);
+ dotlabel.rt ("B", linkStruct.pointB);
+
+ dotlabel.urt("A1", linkStruct.pointAc);
+ dotlabel.ulft("B1", linkStruct.pointBc);
+
+ draw linkStruct.actualPath withcolor red;
+enddef;
+
+% Draws the path using graphical elements specified by iLink
+% using the landmark points computed in the LinkStructure
+% linkStruct.
+%
+vardef drawLinkStructure(text linkStruct)(text iLink) =
+ scantokens(iLink.drawMethod)(linkStruct.actualPath);
+
+ scantokens(iLink.drawMethodA)(linkStruct.pointAc)(linkStruct.pointA)(iLink.heightA);
+ scantokens(iLink.drawMethodB)(linkStruct.pointBc)(linkStruct.pointB)(iLink.heightB);
+enddef;
+
+vardef LinkInfo@# =
+ numeric @#widthA, @#heightA;
+ string @#drawMethodA;
+
+ numeric @#widthB, @#heightB;
+ string @#drawMethodB;
+
+ string @#drawMethod;
+enddef;
+
+% Draws a link using the given path as support.
+%
+vardef link(text iLink)(expr myPath)=
+ LinkStructure.ls(myPath, iLink.widthA, iLink.widthB);
+ drawLinkStructure(ls)(iLink);
+enddef;
+
+% Draws a direct link between the center of the objects.
+vardef clink(text iLink)(suffix objectA, objectB)=
+ link(iLink)(pathCut(objectA, objectB)(objectA.c--objectB.c));
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_note.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_note.mp
new file mode 100644
index 0000000000..083b686f65
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_note.mp
@@ -0,0 +1,140 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_note_mp:
+ expandafter endinput
+fi;
+_metauml_note_mp:=1;
+
+% def metauml_note_debug text txt=log txt enddef;
+def metauml_note_debug text txt= enddef;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+inputonce util_object;
+inputonce util_picture_stack;
+inputonce util_shade;
+inputonce util_margins;
+
+vardef NoteInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(numeric) horizontalFolding, verticalFolding;
+
+ FontInfo.@#iFont(metauml_defaultFont, defaultscale);
+ @#iFont.ignoreNegativeBase := 1;
+
+ PictureInfo.@#iText (2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iStack (0, 0, 0, 0)(9)(@#iText);
+
+ @#iStack.iPict.ignoreNegativeBase := 1;
+
+ ShadeInfo.@#iShade;
+ Margins.@#(2,2,2,2);
+
+ @#foreColor := .9white;
+ @#borderColor := black;
+ @#horizontalFolding := 10;
+ @#verticalFolding := 10;
+enddef;
+
+vardef NoteInfoCopy@#(text src)=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+
+ log "NoteInfoCopy: Copying usecase info";
+
+ PictureStackInfoCopy.@#iStack (src.iStack);
+ MarginsCopy.@#(src);
+ ShadeInfoCopy.@#iShade(src.iShade);
+
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+ @#horizontalFolding := src.horizontalFolding;
+ @#verticalFolding := src.verticalFolding;
+enddef;
+
+NoteInfo.iNote;
+
+vardef Note@#(text contents)=
+ ENote.@#(iNote)(contents);
+enddef;
+
+vardef ENote@#(text _info)(text contents)=
+ ObjectEquations(@#);
+ @#className := "Note";
+
+ NoteInfoCopy.@#info(_info);
+
+ %% The following code cannot work when pictures are given in the contents argument, such as in:
+ %% ENote.myNote(iNote)("This is a formula", TEX("$a=b$"));
+ %%
+ %numeric @#nLines; @#nLines := 0;
+ %string @#lines[];
+ %for l=contents:
+ % @#lines[@#nLines] := l;
+ % @#nLines := @#nLines + 1;
+ %endfor;
+ %
+ %EPictureStack.@#stack(@#info.iStack)(scantokens listArray(@#lines)(@#nLines))("vleftbase");
+
+ EPictureStack.@#stack(@#info.iStack)(contents)("vleftbase");
+enddef;
+
+vardef Note_layout@#=
+ if @#laidout = 1:
+ log "Note " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Note layout: " & (str @#);
+
+ PictureStack_layout.@#stack;
+
+ @#width = @#stack.width + @#info.left + @#info.right + @#info.horizontalFolding;
+ @#height = @#stack.height + @#info.top + @#info.bottom;
+
+ @#top = @#stack.top + @#info.top;
+ @#left = @#stack.left - @#info.left;
+ fi;
+enddef;
+
+vardef Note_draw@#=
+ Note_layout@#;
+ objectEnsurePositioning.@#;
+
+ attributes(@#);
+ var(path) border, corner;
+
+ @#border := @#nw -- (@#ne - (@#info.horizontalFolding, 0)) --
+ (@#ne - (0, @#info.verticalFolding) ) -- @#se -- @#sw -- cycle;
+
+ @#corner := (@#ne - (@#info.horizontalFolding, 0)) --
+ (@#ne - (@#info.horizontalFolding, @#info.verticalFolding)) --
+ (@#ne - (0, @#info.verticalFolding));
+
+ drawObjectShade(@#);
+
+ fill Note_border.@# withcolor @#info.foreColor;
+ draw Note_border.@# withcolor @#info.borderColor;
+
+ draw @#corner withcolor @#info.borderColor;
+ drawObject(@#stack);
+enddef;
+
+vardef Note_border@#=
+ @#border
+enddef;
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_package.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_package.mp
new file mode 100644
index 0000000000..2e76c41fd1
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_package.mp
@@ -0,0 +1,176 @@
+% Copyright 2006 2015 Radu-George Radulescu, Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_package_mp:
+ expandafter endinput
+fi;
+_metauml_package_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+vardef PackageInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(numeric) forceEmptyContent;
+ var(numeric) minimumNameContentsDifference;
+
+ FontInfo.@#iFont(metauml_defaultFont, defaultscale);
+ @#iFont.ignoreNegativeBase := 1;
+
+ PictureInfo.@#iText (2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iNameStack (2, 2, 2, 2)(9)(@#iText);
+ @#iNameStack.iPict.ignoreNegativeBase := 1;
+
+ Margins.@#(2,2,2,2);
+
+ ShadeInfo.@#iShade;
+ @#foreColor := .9white;
+ @#borderColor := black;
+
+ @#forceEmptyContent := 0;
+
+ @#minimumNameContentsDifference := 20;
+
+ GroupInfo.@#iContentsGroup(2, 2, 10, 2);
+enddef;
+
+vardef PackageInfoCopy@#(text src)=
+ log "PackageInfoCopy: Copying package info";
+
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(numeric) forceEmptyContent;
+ var(numeric) minimumNameContentsDifference;
+
+ PictureStackInfoCopy.@#iNameStack (src.iNameStack);
+ MarginsCopy.@#(src);
+
+ ShadeInfoCopy.@#iShade(src.iShade);
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+
+ @#forceEmptyContent := src.forceEmptyContent;
+
+ @#minimumNameContentsDifference := src.minimumNameContentsDifference;
+
+ GroupInfoCopy.@#iContentsGroup(src.iContentsGroup);
+enddef;
+
+PackageInfo.iPackage;
+
+vardef Package@#(text contents)(text _subItems)=
+ EPackage.@#(iPackage)(contents)(_subItems);
+enddef;
+
+vardef EPackage@#(text _info)(text contents)(text _subItems)=
+ ObjectEquations(@#);
+ @#className := "Package";
+
+ PackageInfoCopy.@#info(_info);
+
+ numeric @#nLines; @#nLines := 0;
+ string @#lines[];
+% numeric @#nSubItems; @#nSubItems := 0;
+ numeric @#nameInCenter; @#nameInCenter := 0;
+
+ for l=contents:
+ @#lines[@#nLines] := l;
+ @#nLines := @#nLines + 1;
+ endfor;
+
+% for s=_subItems:
+% @#nSubItems := @#nSubItems + 1;
+% endfor;
+
+ EGroup.@#subItems(@#info.iContentsGroup)(_subItems);
+
+ EPictureStack.@#nameStack(@#info.iNameStack)(scantokens listArray(@#lines)(@#nLines))("vcenterbase");
+enddef;
+
+vardef Package_layout@#=
+ if @#laidout = 1:
+ log "Package '" & (str @#) & "' has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Package layout: '" & (str @#) & "'";
+
+ log "Package name layout '" & (str @#) & "'...";
+ PictureStack_layout.@#nameStack;
+ log "SubItems for package layout '" & (str @#) & "'...";
+ Group_layout.@#subItems;
+
+ log "All elements in package '" & (str @#) & "' successfully layed out, integrating...";
+
+ if @#subItems.nObjects = 0:
+ if @#info.forceEmptyContent = 0:
+ @#nameInCenter := 1;
+ fi;
+ fi;
+
+ if @#subItems.width < @#nameStack.width + @#info.minimumNameContentsDifference:
+ @#contentWidth = @#nameStack.width + @#info.minimumNameContentsDifference;
+ else:
+ @#contentWidth = lmax(@#nameStack.width, @#subItems.width);
+ fi;
+
+ if @#nameInCenter = 1:
+ @#height = @#info.top + @#info.bottom + @#nameStack.height;
+ @#width = @#info.left + @#info.right + @#nameStack.width;
+ @#nameStack.sw = @#sw + (@#info.left, @#info.bottom);
+ else:
+ @#nameStack.sw = @#nw;
+ @#width = @#contentWidth + @#info.left + @#info.right;
+ @#height = @#info.top + @#info.bottom + @#subItems.height;
+ fi;
+
+ @#subItems.n = @#n + (0, -((@#height - @#subItems.height)/2));
+
+ log "Package layout for " & (str @#) & " ended.";
+ fi;
+enddef;
+
+vardef Package_draw@#=
+ Package_layout.@#;
+ objectEnsurePositioning.@#;
+
+ attributes(@#);
+ var(path) border, nameStackBorder, emptyNameBorder;
+
+ @#border := @#ne -- @#nw -- @#sw -- @#se -- cycle;
+ @#nameStackBorder := @#nameStack.ne -- @#nameStack.nw -- @#nameStack.sw -- @#nameStack.se -- cycle;
+ @#emptyNameBorder := @#nw -- @#nw + (0, 10) -- @#n + (0, 10) -- @#n -- cycle;
+
+ drawObjectShade(@#);
+
+ fill @#border withcolor @#info.foreColor;
+ draw @#border withcolor @#info.borderColor;
+ if @#nameInCenter = 0:
+ fill @#nameStackBorder withcolor @#info.foreColor;
+ draw @#nameStackBorder withcolor @#info.borderColor;
+ else:
+ fill @#emptyNameBorder withcolor @#info.foreColor;
+ draw @#emptyNameBorder withcolor @#info.borderColor;
+ fi;
+
+
+ drawObject(@#nameStack);
+ drawObject(@#subItems);
+
+enddef;
+
+vardef Package_border@#=
+ @#border
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_package_relations.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_package_relations.mp
new file mode 100644
index 0000000000..87f1cc4dd1
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_package_relations.mp
@@ -0,0 +1,37 @@
+% Copyright 2006 2015 Radu-George Radulescu
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_package_relations_mp:
+ expandafter endinput
+fi;
+_metauml_package_relations_mp:=1;
+
+defaultRelationHeadWidth := 25;
+defaultRelationHeadHeight := 10;
+
+vardef NestInfo@# =
+ LinkInfo@#;
+
+ @#widthA = 0;
+ @#heightA = 0;
+ @#drawMethodA = "drawNothing";
+
+ @#widthB = defaultRelationHeadWidth;
+ @#heightB = defaultRelationHeadHeight;
+ @#drawMethodB = "drawCrossedCircle";
+
+ @#drawMethod = "drawLine";
+enddef;
+
+NestInfo.nest;
+
+vardef drawRelation(text iLink)(expr myPath)=
+ link(iLink)(myPath);
+enddef;
+
+vardef drawLine(expr my_path) =
+ draw my_path;
+enddef;
+
+vardef drawNothing(text pA)(text pB)(text base) =
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_paths.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_paths.mp
new file mode 100644
index 0000000000..d93832fd0f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_paths.mp
@@ -0,0 +1,173 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_paths_mp:
+ expandafter endinput
+fi;
+_metauml_paths_mp:=1;
+
+def pathDirect(expr pA,pB) =
+ pA--pB
+enddef;
+
+vardef pathManhattanX(text twoParams) =
+ pair pointA__, pointB__;
+ string paramA_str__, paramB_str__;
+ boolean paramA_isObject__, paramB_isObject__;
+
+ paramA_isObject__ := true;
+ paramB_isObject__ := true;
+
+ boolean isFirstParam__;
+ isFirstParam__ := true;
+
+ %string twoParams;
+ %twoParams := "";
+
+ %twoParams := str paramA & ", " & str paramB;
+ %%includeonce% show "the two params are: " & twoParams;
+
+ forsuffixes param__ = twoParams:
+
+ if isFirstParam__:
+ isFirstParam__ := false;
+ paramA_str__ := str param__;
+ %includeonce% show "paramA_str__ <-- " & paramA_str__;
+
+ if not known (scantokens (paramA_str__ & ".className")):
+ %includeonce% show "paramA is not an object";
+ paramA_isObject__ := false;
+ fi;
+ else:
+ paramB_str__ := str param__;
+ %includeonce% show "paramB_str__ <-- " & paramB_str__;
+
+ if not known (scantokens (paramB_str__ & ".className")):
+ %includeonce% show "paramB is not an object";
+ paramB_isObject__ := false;
+ fi;
+ fi;
+ endfor;
+
+ %includeonce% show paramA_str__;
+ %includeonce% show paramA_isObject__;
+
+ %includeonce% show paramB_str__;
+ %includeonce% show paramB_isObject__;
+
+ string stringPath__;
+ stringPath__ := "(0,0)--(50,50)";
+
+ if (not paramA_isObject__) and (not paramB_isObject__):
+ %includeonce% show "Both are points!";
+
+
+ stringPath__ := paramA_str__ & "--(xpart " & paramB_str__ & ", ypart " & paramA_str__ & ") -- " & paramB_str__;
+ %includeonce% show stringPath__;
+ else:
+ pair refPointA__, refPointB__;
+ if paramA_isObject__:
+ refPointA__ := scantokens (paramA_str__ & ".c");
+ else:
+ refPointA__ := scantokens paramA_str__;
+ fi;
+ if paramB_isObject__:
+ refPointB__ := scantokens (paramB_str__ & ".c");
+ else:
+ refPointB__ := scantokens paramB_str__;
+ fi;
+
+ %includeonce% show "Reference point A: ";
+ %includeonce% show refPointA__;
+ %includeonce% show "Reference point B: ";
+ %includeonce% show refPointB__;
+
+ numeric dx__, dy__;
+ dx__ := xpart refPointB__ - xpart refPointA__;
+ dy__ := ypart refPointB__ - ypart refPointA__;
+
+ string addornmentA__;
+ addornmentA__ := "";
+ string addornmentB__;
+ addornmentB__ := "";
+
+ if (paramA_isObject__):
+ if (dx__ > 0):
+ addornmentA__ := ".e";
+ else:
+ addornmentA__ := ".w";
+ fi;
+ fi;
+
+ if (paramB_isObject__):
+ if (dy__ > 0):
+ addornmentB__ := ".s";
+ else:
+ addornmentB__ := ".n";
+ fi;
+ fi;
+ stringPath__ := "pathManhattanX(" & paramA_str__ & addornmentA__ & ", " & paramB_str__ & addornmentB__ & ")";
+
+ %includeonce% show stringPath;
+ %includeonce% show "-------------------> recursive call";
+ fi;
+
+ scantokens stringPath__
+enddef;
+
+vardef rpathManhattanX(text twoParams) =
+ reverse pathManhattanX(twoParams)
+enddef;
+
+vardef pathManhattanY(expr pA,pB) =
+ pA--(xpart(pA), ypart(pB))--pB
+enddef;
+
+vardef rpathManhattanY(expr pA,pB) =
+ pB--(xpart(pA), ypart(pB))--pA
+enddef;
+
+vardef pathStepX(expr pA,pB, deltax) =
+ pA--(pA+(deltax, 0))--(((xpart pA)+deltax), ypart(pB))--pB
+enddef;
+
+vardef rpathStepX(expr pA,pB, deltax) =
+ pB--(((xpart pA)+deltax), ypart(pB))--(pA+(deltax, 0))--pA
+enddef;
+
+vardef pathStepY(expr pA,pB, deltay) =
+ pA--(pA+(0, deltay))--(xpart(pB), ((ypart pA)+deltay))--pB
+enddef;
+
+vardef rpathStepY(expr pA,pB, deltay) =
+ pB--(xpart(pB), ((ypart pA)+deltay))--(pA+(0, deltay))--pA
+enddef;
+
+vardef pathHorizontal(expr pA, untilX) =
+ pA--(untilX,ypart(pA))
+enddef;
+
+vardef rpathHorizontal(expr pA, untilX) =
+ (untilX,ypart(pA))--pA
+enddef;
+
+vardef pathVertical(expr pA, untilY) =
+ pA--(xpart(pA), untilY)
+enddef;
+
+vardef rpathVertical(expr pA, untilY) =
+ (xpart(pA), untilY)--pA
+enddef;
+
+% Cuts path thePath so that it won't intersect the objects
+% objectA and objectB. The border of the objects is obtained
+% by invoking the method "_border".
+%
+vardef pathCut(suffix objectA, objectB)(expr thePath)=
+ save timeA, timeB;
+
+ timeA = xpart (thePath intersectiontimes objectBorder(objectA));
+ timeB = xpart (thePath intersectiontimes objectBorder(objectB));
+
+ subpath (timeA, timeB) of thePath
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_skin_simple.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_skin_simple.mp
new file mode 100644
index 0000000000..3225eb8fc3
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_skin_simple.mp
@@ -0,0 +1,28 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+%% Usage of skins
+%%
+%% Skins are configuration files that, in geneal, customize the settings of
+%% MetaUML *Info objects. You most likely want to include the skin file after
+%% all other MetaUML files have been included:
+%%
+%% input metauml
+%% input metauml_skin_simple
+%%
+%% % normal usage of MetaUML follows here
+%%
+%% More advanced skin files might customize fonts for specific elements
+%% (eg for Class and Note), and also colors (eg foreground, shade, line etc.)
+
+if known _metauml_skin_simple_mp:
+ expandafter endinput
+fi;
+_metauml_skin_simple_mp:=1;
+
+iClass.foreColor := blue;
+iClass.iName.iFont.name := "cmr12";
+iClass.iAttributeStack.iPict.iFont.name := "cmr10";
+iClass.iMethodStack.iPict.iFont.name := "cmr10";
+
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_state.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_state.mp
new file mode 100644
index 0000000000..08b5d3be24
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_state.mp
@@ -0,0 +1,201 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_state_mp:
+ expandafter endinput
+fi;
+_metauml_state_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+vardef StateInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(numeric) round;
+
+ FontInfo.@#iFont(metauml_defaultFont, defaultscale);
+ @#iFont.ignoreNegativeBase := 1;
+
+ PictureInfo.@#iText (2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iStack (2, 2, 2, 2)(9)(@#iText);
+
+ @#iStack.iPict.ignoreNegativeBase := 1;
+
+ Margins.@#(2,2,0,6);
+
+ GroupInfo.@#iGroupSubstates(2, 2, 4, 2);
+
+ @#round := 5;
+ @#drawNameLine := 0;
+
+ ShadeInfo.@#iShade;
+ @#foreColor := .9white;
+ @#borderColor := black;
+enddef;
+
+vardef StateInfoCopy@#(text src)=
+ log "StateInfoCopy: Copying state info";
+ attributes(@#);
+ var(color) foreColor, borderColor;
+ var(numeric) round;
+
+ PictureStackInfoCopy.@#iStack (src.iStack);
+ MarginsCopy.@#(src);
+ @#round := src.round;
+ @#drawNameLine := src.drawNameLine;
+
+ GroupInfoCopy.@#iGroupSubstates(src.iGroupSubstates);
+
+ ShadeInfoCopy.@#iShade(src.iShade);
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+enddef;
+
+StateInfo.iState;
+
+vardef State@#(text contents)(text _substates)=
+ EState.@#(iState)(contents)(_substates);
+enddef;
+
+vardef EState@#(text _info)(text contents)(text _substates)=
+ ObjectEquations(@#);
+ @#className := "State";
+
+ StateInfoCopy.@#info(_info);
+
+ numeric @#nLines; @#nLines := 0;
+ string @#lines[];
+
+ numeric @#nInternalTransitions; @#nInternalTransitions := 0;
+ string @#internalTransitions[];
+
+ for l=contents:
+ @#lines[@#nLines] := l;
+ @#nLines := @#nLines + 1;
+ endfor;
+
+ EGroup.@#substates(@#info.iGroupSubstates)(_substates);
+ %@#substates.info.boxed := 1;
+
+ EPictureStack.@#stack(@#info.iStack)(scantokens listArray(@#lines)(@#nLines))("vcenterbase");
+enddef;
+
+vardef stateTransitions@#(text transitions)=
+ State_internalTransitions@#(transitions);
+enddef;
+
+vardef State_internalTransitions@#(text transitions)=
+ for transition=transitions:
+ @#internalTransitions[@#nInternalTransitions] := transition;
+ @#nInternalTransitions := @#nInternalTransitions + 1;
+ endfor;
+enddef;
+
+vardef State_layout@#=
+ if @#laidout = 1:
+ log "State '" & (str @#) & "' has already been layed out";
+ else:
+ @#laidout := 1;
+ log "State layout: '" & (str @#) & "'";
+
+ EPictureStack.@#internalTransitionsStack(@#info.iStack)
+ (scantokens listArray(@#internalTransitions)(@#nInternalTransitions))("vleftbase");
+
+ log "State name layout '" & (str @#) & "'...";
+ PictureStack_layout.@#stack;
+ log "Internal transitions layout '" & (str @#) & "'...";
+ PictureStack_layout.@#internalTransitionsStack;
+ log "Substates layout '" & (str @#) & "'...";
+ Group_layout.@#substates;
+
+ log "All elements in state '" & (str @#) & "' successfully layed out, integrating...";
+
+% @#internalTransitionsStack.info.boxed := 1;
+
+ @#contentWidth = lmax(@#stack.width, @#internalTransitionsStack.width, @#substates.width);
+
+ @#width = @#contentWidth + @#info.left + @#info.right + 2 * @#info.round;
+ @#height = @#stack.height + @#info.top + @#info.bottom +
+ @#internalTransitionsStack.height + @#substates.height;
+
+ @#stack.n = @#n + (0, -@#info.top);
+ @#substates.n = @#stack.s;
+
+ @#internalTransitionsStack.sw = @#sw + (@#info.round, @#info.round);
+
+ attributes(@#);
+ var(pair) urt, lrt, ulft, llft;
+ var(pair) urta, lrta, ulfta, llfta;
+ var(pair) urtb, lrtb, ulftb, llftb;
+
+ @#urta := @#ne - (@#info.round, 0);
+ @#urtb := @#ne - (0, @#info.round);
+
+ @#lrta := @#se + (0, @#info.round);
+ @#lrtb := @#se - (@#info.round, 0);
+
+ @#ulfta := @#nw - (0, @#info.round);
+ @#ulftb := @#nw + (@#info.round, 0);
+
+ @#llfta := @#sw + (@#info.round, 0);
+ @#llftb := @#sw + (0, @#info.round);
+
+ @#urt := @#ne - (@#info.round, @#info.round) + @#info.round * (sind(45),cosd(45));
+ @#lrt := @#se + (-@#info.round, @#info.round) + @#info.round * (sind(135),cosd(135));
+ @#llft := @#sw + (@#info.round, @#info.round) + @#info.round * (sind(225),cosd(225));
+ @#ulft := @#nw + (@#info.round, -@#info.round) + @#info.round * (sind(315),cosd(315));
+
+ var(pair) nameLineLeft, nameLineRight;
+ ypart @#nameLineLeft = ypart @#nameLineRight = @#stack.bottom;
+ xpart @#nameLineLeft = xpart @#nw;
+ xpart @#nameLineRight = xpart @#ne;
+
+ log "State layout for " & (str @#) & " ended.";
+ fi;
+enddef;
+
+vardef State_draw@#=
+ State_layout.@#;
+ objectEnsurePositioning.@#;
+
+ attributes(@#);
+ var(path) border;
+
+ @#border := @#urta .. @#urt .. @#urtb -- %
+ @#lrta .. @#lrt .. @#lrtb -- %
+ @#llfta .. @#llft .. @#llftb -- %
+ @#ulfta .. @#ulft .. @#ulftb -- cycle;
+
+ %fill @#border shifted (@#info.shade, -@#info.shade) withcolor .7white;
+ drawObjectShade(@#);
+
+ fill @#border withcolor @#info.foreColor;
+ draw @#border withcolor @#info.borderColor;
+
+
+ drawObject(@#internalTransitionsStack);
+ drawObject(@#stack);
+ drawObject(@#substates);
+
+ if @#info.drawNameLine = 1:
+ draw @#nameLineLeft -- @#nameLineRight;
+ fi;
+enddef;
+
+vardef State_border@#=
+ @#border
+enddef;
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_stereotype.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_stereotype.mp
new file mode 100644
index 0000000000..9251c30833
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_stereotype.mp
@@ -0,0 +1,25 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_stereotype_mp:
+ expandafter endinput
+fi;
+_metauml_stereotype_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+
+FontInfo.assocFont(metauml_defaultFont, .7);
+PictureInfo.iStereo(2, 2, 2, 2)(assocFont);
+iStereo.ignoreNegativeBase := 1;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_templates.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_templates.mp
new file mode 100644
index 0000000000..940377bc20
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_templates.mp
@@ -0,0 +1,132 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_templates_mp:
+ expandafter endinput
+fi;
+_metauml_templates_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+vardef TemplateInfo@#=
+ color @#background;
+ color @#borderColor;
+ numeric @#borderScale;
+
+ @#background := .9white;
+ @#borderColor := black;
+ @#borderScale := 1;
+
+ FontInfo.@#iFont(metauml_defaultFont, .9);
+ PictureInfo.@#iPict(2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iStack(2, 2, 1, 1)(7)(@#iPict);
+
+ @#iStack.iPict.ignoreNegativeBase := 1;
+enddef;
+
+vardef TemplateInfoCopy@#(text src)=
+ color @#background;
+ color @#borderColor;
+ numeric @#borderScale;
+
+ @#background := src.background;
+ @#borderColor := src.borderColor;
+ @#borderScale := src.borderScale;
+
+ FontInfoCopy.@#iFont(src.iFont);
+ PictureInfoCopy.@#iPict(src.iPict);
+ PictureStackInfoCopy.@#iStack(src.iStack);
+enddef;
+
+TemplateInfo.iTemplate;
+
+%
+% Template
+%
+vardef ETemplate@#(text _info)(text templates) =
+ ObjectEquations(@#);
+ @#className := "Template";
+
+ TemplateInfoCopy.@#info(_info);
+
+ EPictureStack.@#elementsStack(@#info.iStack)(templates)("vleftbase");
+
+ @#nw = @#elementsStack.nw;
+ @#se = @#elementsStack.se;
+enddef;
+
+vardef Template@#(text templates) =
+ ETemplate@#(iTemplate)(templates);
+enddef;
+
+vardef EClassTemplate@#(text _info)(text templates)(text theClass)=
+ ETemplate.@#(_info)(templates);
+ Template_attachToClass.@#(theClass);
+enddef;
+
+vardef ClassTemplate@#(text templates)(text theClass)=
+ EClassTemplate.@#(iTemplate)(templates)(theClass);
+enddef;
+
+vardef Template_layout@#=
+ if @#laidout = 1:
+ log "Template " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Template layout: " & (str @#);
+ PictureStack_layout.@#elementsStack;
+ fi;
+enddef;
+
+vardef Template_paintSkin@# =
+ log "Painting template skin...";
+
+ fill objectBox(@#) withcolor @#info.background;
+
+ draw objectBox(@#) dashed evenly scaled .8
+ withpen pencircle scaled @#info.borderScale withcolor @#info.borderColor;
+enddef;
+
+vardef Template_draw@# =
+ Template_layout.@#;
+
+ Template_paintSkin.@#;
+ drawObject(@#elementsStack);
+enddef;
+
+vardef Template_attachToClass@#(text theClass)=
+ Template_layout.@#;
+ Class_layout.theClass;
+
+ log "--- Attaching template " & (str @#) & " to class " & (str theClass);
+
+ save __nItems, __nameToRight;
+
+ __nItems := @#elementsStack.nItems;
+ __nameToRight := theClass.right - theClass.namePict.right;
+
+ @#elementsStack.pict[__nItems-1].midy = theClass.top;
+
+ if __nameToRight > @#width/2:
+ @#midx = theClass.right;
+ log "X";
+ else:
+ @#midx = theClass.right + (@#width/2 - __nameToRight) + 2;
+ log "Y";
+ fi;
+
+ %@#elementsStack.pict[__nItems-1].info.boxed:=1;
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase.mp
new file mode 100644
index 0000000000..f9c666abf3
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase.mp
@@ -0,0 +1,215 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _metauml_usecase_mp:
+ expandafter endinput
+fi;
+_metauml_usecase_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce metauml_defaults;
+inputonce util_log;
+
+vardef ActorInfo@#=
+ FontInfo.@#iFont(metauml_defaultFont, defaultscale);
+ @#iFont.ignoreNegativeBase := 1;
+
+ PictureInfo.@#iName (2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iNameStack (1pt, 1pt, 1pt, 1pt)(9)(@#iName);
+
+ @#iNameStack.iPict.ignoreNegativeBase := 1;
+
+ HumanInfo.@#iHuman(25, 35, .3, .35, .5, 1, 1);
+enddef;
+
+vardef ActorInfoCopy@#(text src)=
+ log "ActorInfoCopy: Copying actor info";
+
+ PictureStackInfoCopy.@#iNameStack (src.iNameStack);
+
+ HumanInfoCopy.@#iHuman(src.iHuman);
+enddef;
+
+ActorInfo.iActor;
+
+vardef Actor@#(text contents)=
+ EActor.@#(iActor)(contents);
+enddef;
+
+vardef EActor@#(text _info)(text contents)=
+ ObjectEquations(@#);
+ @#className := "Actor";
+
+ ActorInfoCopy.@#info(_info);
+
+ numeric @#nLines; @#nLines := 0;
+ string @#lines[];
+ for l=contents:
+ @#lines[@#nLines] := l;
+ @#nLines := @#nLines + 1;
+ endfor;
+ EHuman.@#human(@#info.iHuman);
+ EPictureStack.@#nameStack(@#info.iNameStack)(scantokens listArray(@#lines)(@#nLines))("vcenterbase");
+enddef;
+
+vardef Actor_setDebugMode@#=
+ @#.nameStack.info.boxed := 1;
+enddef;
+
+vardef Actor_layout@#=
+ if @#laidout = 1:
+ log "Actor " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Actor layout: " & (str @#);
+ Human_layout.@#human;
+ PictureStack_layout.@#nameStack;
+
+ @#width = max(@#nameStack.width)(@#human.width);
+ @#height = @#nameStack.height + @#human.height;
+
+ @#n = @#human.n;
+ @#nameStack.n=@#human.s;
+ @#s = @#nameStack.s;
+ fi;
+enddef;
+
+vardef Actor_draw@#=
+ Actor_layout.@#;
+
+ objectEnsurePositioning.@#;
+
+ drawObjects(@#nameStack, @#human);
+enddef;
+
+vardef Actor_border@#=
+ objectBox(@#);
+enddef;
+
+vardef UsecaseInfo@#=
+ attributes(@#);
+ var(color) foreColor, borderColor;
+
+ FontInfo.@#iFont(metauml_defaultFont, defaultscale);
+ @#iFont.ignoreNegativeBase := 1;
+
+ PictureInfo.@#iName (2, 2, 2, 2)(@#iFont);
+ PictureStackInfo.@#iNameStack (0, 0, 0, 0)(9)(@#iName);
+
+ @#iNameStack.iPict.ignoreNegativeBase := 1;
+
+ Margins.@#(2,2,2,2);
+
+ @#hFatRatio := .1;
+ @#vFatRatio := .15;
+
+ ShadeInfo.@#iShade;
+ @#foreColor := .9white;
+ @#borderColor := black;
+enddef;
+
+vardef UsecaseInfoCopy@#(text src)=
+ log "UsecaseInfoCopy: Copying usecase info";
+ attributes(@#);
+ var(color) foreColor, borderColor;
+
+ PictureStackInfoCopy.@#iNameStack (src.iNameStack);
+ MarginsCopy.@#(src);
+ @#hFatRatio := src.hFatRatio;
+ @#vFatRatio := src.vFatRatio;
+
+ ShadeInfoCopy.@#iShade(src.iShade);
+ @#foreColor := src.foreColor;
+ @#borderColor := src.borderColor;
+enddef;
+
+UsecaseInfo.iUsecase;
+
+vardef Usecase@#(text contents)=
+ EUsecase.@#(iUsecase)(contents);
+enddef;
+
+vardef EUsecase@#(text _info)(text contents)=
+ ObjectEquations(@#);
+ @#className := "Usecase";
+
+ UsecaseInfoCopy.@#info(_info);
+
+ attributes(@#);
+ var(numeric) nLines;
+ @#nLines := 0;
+
+ string @#lines[];
+ for l=contents:
+ @#lines[@#nLines] := l;
+ @#nLines := @#nLines + 1;
+ endfor;
+enddef;
+
+vardef Usecase_layout@#=
+ if @#laidout = 1:
+ log "Usecase " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+
+ EPictureStack.@#nameStack(@#info.iNameStack)(scantokens listArray(@#lines)(@#nLines))("vcenterbase");
+ PictureStack_layout.@#nameStack;
+
+ numeric @#vFat, @#hFat;
+
+ @#hFat = 0;
+ @#vFat = 10;
+
+ @#width = @#nameStack.width + @#info.left + @#info.right + 2 * @#hFat;
+ @#height = @#nameStack.height + @#info.top + @#info.bottom + 2 * @#vFat;
+
+ log "UC w,h";
+ log @#hFat;
+ log @#vFat;
+ log @#nameStack.width;
+ log @#nameStack.height;
+ log @#width;
+ log @#height;
+
+ @#c = @#nameStack.c;
+ fi;
+enddef;
+
+vardef Usecase_draw@#=
+ Usecase_layout@#;
+
+ pair @#urt, @#lrt, @#ulft, @#llft;
+
+ @#urt = @#nameStack.ne;
+ @#lrt = @#nameStack.se;
+ @#ulft = @#nameStack.nw;
+ @#llft = @#nameStack.sw;
+
+ objectEnsurePositioning.@#;
+
+ path @#border;
+ %@#border := @#w .. @#ulft .. @#n .. @#urt .. @#e .. @#lrt .. @#s .. @#llft .. cycle;
+ @#border := @#w .. @#n .. @#e .. @#s .. cycle;
+
+ drawObjectShade(@#);
+
+ fill Usecase_border.@# withcolor @#info.foreColor;
+ draw Usecase_border.@# withcolor @#info.borderColor;
+
+ drawObject(@#nameStack);
+enddef;
+
+vardef Usecase_border@#=
+ @#border
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase_clipart.mp b/graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase_clipart.mp
new file mode 100644
index 0000000000..3344454bc4
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/metauml_usecase_clipart.mp
@@ -0,0 +1,158 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+%%
+%% This file contains various drawings which can be used in
+%% UML usecase diagrams
+%%
+
+if known _metauml_usecase_clipart_mp:
+ expandafter endinput
+fi;
+_metauml_usecase_clipart_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+
+vardef HumanInfo@#(expr _width, _height, _yHeadRatio, _yBodyRatio, _yHandsRatio, _xHandsRatio, _xLegsRatio)=
+ attributes(@#);
+
+ var(numeric) width, height, yHeadRatio, yBodyRatio,
+ yHandsRatio, xHandsRatio, xLegsRatip;
+ var(color) foreColor, shadeColor;
+ var(numeric) shade;
+
+ @#width := _width;
+ @#height := _height;
+ @#yHeadRatio := _yHeadRatio;
+ @#yBodyRatio := _yBodyRatio;
+ @#yHandsRatio := _yHandsRatio;
+ @#xHandsRatio := _xHandsRatio;
+ @#xLegsRatio := _xLegsRatio;
+
+ @#foreColor := black;
+ @#shadeColor := .7white;
+ @#shade := .5;
+
+ Margins.@#(2,2,1,0);
+enddef;
+
+vardef HumanInfoCopy@#(text src)=
+ HumanInfo@#(src.width, src.height, src.yHeadRatio, src.yBodyRatio, src.yHandsRatio, src.xHandsRatio, src.xLegsRatio);
+
+ _n_ := str @#;
+ var(color) foreColor, shadeColor;
+ var(numeric) shade;
+
+ @#foreColor := src.foreColor;
+ @#shadeColor := src.shadeColor;
+ @#shade := src.shade;
+
+ MarginsCopy.@#(src);
+enddef;
+
+HumanInfo.iHuman(25, 25, .3, .35, .55, 1, 1);
+
+vardef EHuman@#(text _info)=
+ ObjectEquations(@#);
+ @#className := "Human";
+
+ var(path) pHead, pBody, pHands, pLegs;
+
+ HumanInfoCopy.@#info(_info);
+enddef;
+
+vardef Human@#=
+ EHuman@#(iHuman);
+enddef;
+
+vardef Human_layout@#=
+ if @#laidout = 1:
+ log "Human " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+ log "Human layout: " & (str @#);
+
+ attributes(@#);
+
+ @#height = @#info.height;
+ @#width = @#info.width;
+
+ log "(W, H) MUST BE SET. Their values are: " & (decimal @#height) &" "& (decimal @#width);
+
+ var(numeric) actualHeight, actualWidth;
+ @#actualHeight = @#height - @#info.top - @#info.bottom;
+ @#actualWidth = @#width - @#info.left - @#info.right;
+
+ % HEAD
+ var(pair) headS, headE, headW;
+
+ ypart @#headW = ypart @#headE;
+ .5[@#n - (0, @#info.top), @#headS] = .5[@#headE, @#headW];
+ (ypart @#n - @#info.top) - (ypart @#headS) =
+ (xpart @#headE) - (xpart @#headW) =
+ @#actualHeight * @#info.yHeadRatio;
+ (xpart @#headS) = (xpart @#n);
+
+ % BODY
+ var(pair) bodyS;
+ xpart @#bodyS = xpart @#headS;
+ ypart @#headS - ypart @#bodyS = @#actualHeight * @#info.yBodyRatio;
+
+ % HANDS
+ var(pair) handsW, handsE;
+ ypart @#handsW = ypart @#handsE = ypart @#n - (@#actualHeight * @#info.yHandsRatio);
+ .5[xpart @#handsE, xpart @#handsW] = @#midx;
+ xpart @#handsE - xpart @#handsW = @#actualWidth * @#info.xHandsRatio;
+
+ % LEGS
+ var(pair) footW, footE;
+ ypart @#footW = ypart @#footE = ypart @#s + @#info.bottom;
+ .5[xpart @#footW, xpart @#footE] = @#midx;
+ xpart @#footE - xpart @#footW = @#actualWidth * @#info.xLegsRatio;
+
+ log "Human layout completed";
+ fi;
+enddef;
+
+vardef Human_draw@#=
+ log "Drawing human";
+
+ Human_layout.@#;
+ objectEnsurePositioning.@#;
+
+ % all coordinates must be set to known values in order to compute the paths
+ @#pHead := (@#n - (0, @#info.top)) .. @#headE .. @#headS .. @#headW .. cycle;
+ @#pBody := @#headS -- @#bodyS;
+ @#pHands := @#handsW -- @#handsE;
+ @#pLegs := @#footW -- @#bodyS -- @#footE;
+
+ attributes(@#);
+ var(pair) shadeShift;
+ @#shadeShift = (@#info.shade, -@#info.shade);
+
+ draw @#pHead shifted @#shadeShift withcolor @#info.shadeColor;
+ draw @#pBody shifted @#shadeShift withcolor @#info.shadeColor;
+ draw @#pHands shifted @#shadeShift withcolor @#info.shadeColor;
+ draw @#pLegs shifted @#shadeShift withcolor @#info.shadeColor;
+
+ draw @#pHead withcolor @#info.foreColor;
+ draw @#pBody withcolor @#info.foreColor;
+ draw @#pHands withcolor @#info.foreColor;
+ draw @#pLegs withcolor @#info.foreColor;
+enddef;
+
+vardef Human_border@#=
+ objectBox(@#)
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_commons.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_commons.mp
new file mode 100644
index 0000000000..3ff7f06e83
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_commons.mp
@@ -0,0 +1,137 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_commons_mp:
+ expandafter endinput
+fi;
+_util_commons_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+
+vardef lmax(text items)=
+ log "finding lmax of items " & str items;
+ save current, nItems;
+ numeric current, nItems;
+ nItems := 0;
+ current:= 0;
+
+ for item = items:
+ log nItems;
+ log item;
+
+ if nItems = 0:
+ current := item;
+ else:
+ current := max(current)(item);
+ fi;
+ nItems := nItems + 1;
+ endfor;
+
+ current
+enddef;
+
+vardef lmin(text items)=
+ save current, nItems;
+ numeric current, nItems;
+ nItems := 0;
+ current:= 0;
+
+ for item = items:
+ if nItems = 0:
+ current := item;
+ else:
+ current := min(current)(item);
+ fi;
+ nItems := nItems + 1;
+ endfor;
+
+ current
+enddef;
+
+def _max(text a)(text b)=
+ if (a > b): a%
+ else:b%
+ fi;
+enddef;
+
+def _min(text a)(text b)=
+ if (a < b): a%
+ else:b%
+ fi;
+enddef;
+
+vardef ensurePict(text pictOrText)(expr font, scale) =
+ save p; picture p;
+ if picture pictOrText: p=pictOrText
+ else: p = pictOrText infont font scaled scale
+ fi;
+ p
+enddef;
+
+def pictHeight(text obj) =
+ (ypart (urcorner obj) - ypart (llcorner obj))
+enddef;
+
+def pictWidth(text obj) =
+ (xpart (urcorner obj) - xpart (llcorner obj))
+enddef;
+
+vardef listArray(text array)(text nElements)=
+ save objEnum;
+ string objEnum;
+ objEnum := "";
+
+ for i = 0 upto nElements-1:
+ if i>0:
+ objEnum := objEnum & ", ";
+ fi;
+ objEnum := objEnum & (str array) & (decimal i);
+ endfor;
+
+ objEnum
+enddef;
+
+vardef enumToString(text enumeration)(expr prefix)=
+ save ret, firstVar;
+ string ret;
+ ret := "";
+
+ numeric firstVar;
+ firstVar := 1;
+
+ forsuffixes v = enumeration:
+ if firstVar = 0:
+ ret := ret & ",";
+ else:
+ firstVar := 0;
+ fi;
+
+ ret := ret & prefix & (str v);
+ endfor;
+
+ ret
+enddef;
+
+def _dx(text pA)(text pB) =
+ (xpart(pB)-xpart(pA))
+enddef;
+
+def _dy(text pA, pB) =
+ (ypart(pB)-ypart(pA))
+enddef;
+
+def _length(text pA)(text pB) =
+ sqrt (_dx(pA)(pB)*_dx(pA)(pB) + _dy(pA)(pB)*_dy(pA)(pB))
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_group.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_group.mp
new file mode 100644
index 0000000000..7dad82ba02
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_group.mp
@@ -0,0 +1,181 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_group_mp:
+ expandafter endinput
+fi;
+_util_group_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_object;
+inputonce util_commons;
+inputonce util_margins;
+inputonce util_log;
+
+vardef GroupInfo@#(expr pleft, pright, ptop, pbottom)=
+ attributes(@#);
+ var(color) borderColor;
+ var(numeric) boxed;
+
+ @#boxed := 0;
+ @#borderColor := red;
+
+ Margins.@#(pleft, pright, ptop, pbottom);
+enddef;
+
+vardef GroupInfoCopy@#(text src)=
+ GroupInfo@#(src.left, src.right, src.top, src.bottom);
+
+ @#boxed := src.boxed;
+ @#borderColor := src.borderColor;
+
+enddef;
+
+GroupInfo.iGroup(2, 2, 2, 2);
+GroupInfo.iGroupNoMargins(0, 0, 0, 0);
+
+GroupInfoCopy.iGroupBoxed(iGroup);
+iGroupBoxed.boxed := 1;
+
+vardef EGroup@#(text groupInfo)(text objects)=
+ ObjectEquations(@#);
+ @#className := "Group";
+
+ var(numeric) minx, maxx, miny, maxy;
+ var(numeric) nObjects;
+ var(string) objectsAsString;
+
+ GroupInfoCopy.@#info(groupInfo);
+
+ @#objectsAsString := enumToString(objects)("");
+ log @#objectsAsString;
+
+ @#nObjects := 0;
+ if @#objectsAsString <> "":
+ forsuffixes obj = scantokens @#objectsAsString:
+ @#nObjects := @#nObjects + 1;
+ endfor;
+ fi;
+
+enddef;
+
+vardef Group@#(text objects)=
+ EGroup@#(iGroup)(objects);
+enddef;
+
+vardef Group_layout@#=
+ if @#laidout = 0:
+ log "Needing layout for group " & (str @#);
+ @#laidout := 1;
+
+ log "Calling layout for objects in group '" & (str @#) & "' .";
+ log " Objects are: '" & @#objectsAsString & "'.";
+
+ if (@#objectsAsString = ""):
+ log "Empty layout begin";
+ @#width = @#info.left + @#info.right;
+ @#height = @#info.top + @#info.bottom;
+ log "Empty layout end";
+ else:
+ log "Layout with content";
+ layoutObjects(scantokens @#objectsAsString);
+ log "All objects in group '" & (str @#) & "' are now laid out.";
+
+ % As already tested, @#objectsAsString must be <> "".
+ % See page 53, User's manual for MetaPost
+ % "if some of the suffixes are empty, the loop gets
+ % executed, with the loop index parameter set to
+ % the empty suffix" (!)
+
+ log "Group_layout: finding min/max x/y of objects:" & @#objectsAsString;
+
+ __objectIndex := 0;
+ forsuffixes obj__ = scantokens @#objectsAsString:
+ if __objectIndex = 0:
+ log "Group_layout: first object " & str obj__ & ", initial minx, maxx, miny, maxy follow.";
+ @#minx := obj__.left;
+ @#maxx := obj__.right;
+ @#miny := obj__.bottom;
+ @#maxy := obj__.top;
+
+ log @#minx;
+ log @#maxx;
+ log @#miny;
+ log @#maxy;
+ __objectIndex := __objectIndex + 1;
+ else:
+ log "Group_layout: current object " & str obj__;
+
+ log "comparing minx";
+ log @#minx;
+ log obj__.left;
+ @#minx := min(@#minx, obj__.left);
+
+ log "comparing maxx";
+ log @#maxx;
+ log obj__.right;
+ @#maxx := max(@#maxx, obj__.right);
+
+ log "comparing miny";
+ log @#miny;
+ log obj__.bottom;
+ @#miny := min(@#miny, obj__.bottom);
+
+ log "comparing maxy";
+ log @#maxy;
+ log obj__.top;
+ @#maxy := max(@#maxy, obj__.top);
+
+ __objectIndex := __objectIndex + 1;
+ fi;
+ endfor;
+ log "Group_layout: finding min/max x/y: done.";
+ log @#minx;
+ log @#maxx;
+ log @#miny;
+ log @#maxy;
+
+ log "Group_layout: about to set nw, se";
+ log @#nw;
+ log @#se;
+
+ @#nw = (@#minx - @#info.left, @#maxy + @#info.top);
+ @#se = (@#maxx + @#info.right, @#miny - @#info.bottom);
+
+ log "Done performing actual layout for group " & str @#;
+ fi;
+ else:
+ log "NOT needing layout for group " & (str @#);
+ fi;
+enddef;
+
+vardef Group_draw@#=
+ log "Drawing group....";
+ Group_layout@#;
+ objectEnsurePositioning.@#;
+
+ if @#objectsAsString <> "":
+ drawObjects(scantokens @#objectsAsString);
+ fi;
+
+ if (@#info.boxed = 1):
+ draw objectBox(@#) withcolor @#info.borderColor;
+ fi;
+enddef;
+
+vardef Group_border@#=
+ objectBox(@#)
+enddef;
+
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_infrastructure.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_infrastructure.mp
new file mode 100644
index 0000000000..8e6c2ed05d
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_infrastructure.mp
@@ -0,0 +1,56 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_infrastructure_mp:
+ expandafter endinput
+fi;
+_util_infrastructure_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+
+vardef attributes(text objectName)=
+ _n_ := str objectName
+enddef;
+
+vardef variables_ext text variables=
+ save ret, firstVar;
+ string ret;
+ ret := "";
+
+ numeric firstVar;
+ firstVar := 1;
+
+ forsuffixes v = variables:
+ if firstVar = 0:
+ ret := ret & ",";
+ else:
+ firstVar := 0;
+ fi;
+
+ ret := ret & " _n." & (str v);
+ endfor;
+
+ ret
+enddef;
+
+vardef var(text type) text variables =
+ save _variables;
+ string _variables;
+ _variables := variables_ext variables;
+
+ generic_declare(type) scantokens _variables;
+enddef;
+
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_log.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_log.mp
new file mode 100644
index 0000000000..61c86ec8d6
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_log.mp
@@ -0,0 +1,31 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+%%% if known _util_log_mp:
+%%% expandafter endinput
+%%% fi;
+_util_log_mp:=1;
+
+util_loglevel_PARANOIA:=1;
+util_loglevel_DEBUG:=2;
+util_loglevel_RELEASE:=3;
+util_loglevel_SILENT:=4;
+
+util_log_thresholdlevel := util_loglevel_DEBUG;
+util_log_defaultlevel := util_loglevel_RELEASE;
+
+def elog(expr loglevel) text txt=
+ if (loglevel <= util_log_thresholdlevel):
+ %includeonce% show txt
+ else:
+ % do nothing
+ fi;
+enddef;
+
+def log text txt=
+ if (util_log_defaultlevel <= util_log_thresholdlevel):
+ show txt
+ else:
+ % do nothing
+ fi;
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_margins.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_margins.mp
new file mode 100644
index 0000000000..7b014ee9e7
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_margins.mp
@@ -0,0 +1,21 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_margins_mp:
+ expandafter endinput
+fi;
+_util_margins_mp:=1;
+
+vardef Margins@#(expr pleft, pright, ptop, pbottom)=
+ attributes(@#);
+ var(numeric) left, right, top, bottom;
+
+ @#left := pleft;
+ @#right := pright;
+ @#top := ptop;
+ @#bottom := pbottom;
+enddef;
+
+vardef MarginsCopy@#(text src)=
+ Margins@#(src.left, src.right, src.top, src.bottom);
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_object.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_object.mp
new file mode 100644
index 0000000000..fbc569dd6f
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_object.mp
@@ -0,0 +1,233 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_object_mp:
+ expandafter endinput
+fi;
+_util_object_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_infrastructure;
+inputonce util_log;
+
+def ObjectEquations(suffix $)=
+ attributes($);
+ var(pair) n, ne, e, se, s, sw, w, nw, c;
+ var(pair) dim;
+ var(numeric) width, height;
+
+ var(numeric) left, right;
+ var(numeric) top, bottom;
+ var(numeric) midx, midy;
+
+ var(picture) pict;
+ var(string) className;
+
+ var(numeric) laidout, drawn;
+
+ $.laidout := 0;
+ $.drawn := 0;
+
+ $.left = xpart $.nw = xpart $.sw;
+ $.right = xpart $.ne = xpart $.se;
+
+ $.top = ypart $.ne = ypart $.nw;
+ $.bottom = ypart $.se = ypart $.sw;
+
+ $.w = .5[$.nw,$.sw];
+ $.s = .5[$.sw,$.se];
+ $.e = .5[$.ne,$.se];
+ $.n = .5[$.ne,$.nw];
+
+ $.c = .5[$.nw, $.se];
+
+ $.width = $.right - $.left;
+ $.height = $.top - $.bottom;
+
+ $.midx = xpart($.c);
+ $.midy = ypart($.c);
+
+ xpart $.dim = $.width;
+ ypart $.dim = $.height;
+
+ $.className := "Object";
+enddef;
+
+def objectBox(text obj)=
+ obj.nw -- obj.ne -- obj.se -- obj.sw -- cycle
+enddef;
+
+vardef objectBorder(suffix @#)=
+ save methodName;
+ string methodName;
+ methodName := @#className & "_border";
+ log "objectBorder: invoking " & methodName & " arg=" & str @#;
+
+ scantokens (methodName).@#
+enddef;
+
+vardef Object_toString(text obj)=
+ save ret; string ret;
+ ret := "Generic object";
+ ret
+enddef;
+
+vardef toString(suffix @#)=
+ scantokens (@#className & "_toString").@#
+enddef;
+
+vardef layoutObject(suffix @#)=
+ save methodName;
+ string methodName;
+ methodName := @#className & "_layout";
+ log "layoutObject: invoking " & methodName & " arg=" & str @#;
+
+ scantokens (methodName).@#;
+enddef;
+
+vardef drawObject(suffix @#)=
+ save methodName;
+ string methodName;
+ methodName := @#className & "_draw";
+ log "drawObject: invoking " & methodName & " arg=" & str @#;
+
+ scantokens (methodName).@#;
+enddef;
+
+vardef drawObjectShade(suffix @#)=
+ fill objectBorder(@#) shifted
+ (@#.info.iShade.shift, -@#.info.iShade.shift) withcolor @#.info.iShade.background;
+enddef;
+
+vardef objectEnsurePositioning@#=
+ if unknown (xpart @#nw):
+ log "*** WARNING: DEFAULTING OBJECT'S (" & (str @#) & ") x TO 0";
+ xpart @#nw = 0;
+ fi;
+ if unknown (ypart @#nw):
+ log "*** WARNING: DEFAULTING OBJECT'S (" & (str @#) & ") y TO 0";
+ ypart @#nw = 0;
+ fi;
+enddef;
+
+vardef drawObjectAt(suffix @#)(text eq)=
+ eq;
+ drawObject(@#);
+enddef;
+
+vardef layoutObjects(text objects)=
+ log "layoutObjects: begin";
+ forsuffixes o = objects:
+ if (str o) <> "":
+ layoutObject(o);
+ fi;
+ endfor;
+ log "layoutObjects: end";
+enddef;
+
+vardef drawObjects(text objects)=
+ % This needs to be done first in order to allow for equations which define
+ % relative positioning to be appropiately solved. Otherwise, for example,
+ % object0 may be positioned somewhere by default, and object1 also, leading
+ % to inconsitent equations. Inconsistency would have been caused by the fact that the
+ % positioning equations become meaningful only after object layout is performed
+ % --- but that would have been too late, since the positioning would have been
+ % done already to inappropriate values.
+ %
+ layoutObjects(objects);
+
+ forsuffixes o = objects:
+ if (str o) <> "":
+ drawObject(o);
+ fi;
+ endfor;
+enddef;
+
+%%
+%% Joins the given pictures according to the equation given
+%% by the pictureDoJoin macro. Note: the pictureDoJoin macro
+%% can be conveniently set by calling setPicutureJoin macro.
+%%
+%% Usage example:
+%% joinObjects (p, q, r);
+%%
+def joinObjects(text pictures)=
+ log "joinObjects: call started.";
+
+ save _index;
+ _index := 0;
+ forsuffixes p=pictures:
+ exitif (str p) = "";
+ if _index=0:
+ log " joinObjects: calling join for first object.";
+ log _index;
+ log p;
+ objectDoJoinFirst(p)(_index);
+ else:
+ log " joinObjects: calling join for next object.";
+ log _index;
+ log p;
+ objectDoJoin(previousPic, p)(_index);
+ fi;
+
+ _index := _index + 1;
+ def previousPic=p enddef;
+ endfor;
+
+ log "joinObjects: call ended."
+enddef;
+
+%%
+%% Sets the macro pictureDoJoin, which is used by joinObjects to join
+%% one picture into another.
+%%
+%% The pictureDoJoin macro has two arguments: pa and pb.
+%% pa represents the first picture and pb the second picture.
+%% The second picture is positioned relatively to pa as specified
+%% by the given equation.
+%%
+%% Usage examples:
+%%
+%% % place the second picture at the bottom of the first
+%% setPictureJoin(pa.sw = pb.nw);
+%%
+%% % place the second picture at the right of the first
+%% setPictureJoin(pa.ne = pb.nw);
+%%
+def setObjectJoin(text eq)=
+ def objectDoJoin(suffix pa, pb)(expr index)=eq; enddef;
+ def objectDoJoinFirst(suffix pa)(expr index)= log " objectDoJoinFirst: NOP"; enddef;
+enddef;
+
+def setObjectJoinFirst(text eq)=
+ def objectDoJoinFirst(suffix pa)(expr index)=eq; enddef;
+enddef;
+
+%%
+%% A shortcut for setting the join equation and actually performing the join.
+%
+def joinObjectsEq(text objects)(text eq)=
+ setObjectJoin(eq);
+ joinObjects(objects);
+enddef;
+
+
+%%
+%% Joins the pictures and draws them. A shorthand for
+%% the corresponding two macro invocations.
+%%
+def joinDrawObjects(text pictures)=
+ joinObjects(pictures);
+ drawObjects(pictures);
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_picture.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_picture.mp
new file mode 100644
index 0000000000..85ce68f7d4
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_picture.mp
@@ -0,0 +1,285 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_picture_mp:
+ expandafter endinput
+fi;
+_util_picture_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+inputonce util_margins;
+
+if not known _n_cur_:input boxes;fi;
+
+vardef FontInfo@#(expr tname, tscale)=
+ attributes(@#);
+ var(string) className;
+ var(string) name;
+ var(numeric) scale;
+
+ @#className := "FontInfo";
+
+ @#name := tname;
+ @#scale := tscale;
+enddef;
+
+vardef FontInfoCopy@#(text fontInfo)=
+ FontInfo@#(fontInfo.name, fontInfo.scale);
+ @#ignoreNegativeBase := fontInfo.ignoreNegativeBase;
+enddef;
+
+vardef FontInfo_toString@#=
+ save ret; string ret;
+ ret := "FontInfo(" & (str @#) & "): {" & (@#name) & ", " & (decimal @#scale) & "}";
+ ret
+enddef;
+
+log "()()() Creating iFont";
+FontInfo.iFont(defaultfont, defaultscale);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% PICTURE %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+vardef PictureInfo@#(expr pleft, pright, ptop, pbottom)(text pfont)=
+ attributes(@#);
+ var(string) className;
+ @#className := "PictureInfo";
+
+ var(color) borderColor;
+ var(numeric) boxed;
+
+ %% Used to set the base of a text to the natural base of the letters.
+ %% If set to '1', 'y' and 'a' will have the same base line, the tail
+ %% of 'y' being rendered below that line
+ %%
+ var(numeric) ignoreNegativeBase;
+
+ %% If these attributes are set to -1, the height and width of the
+ %% Picture object is deduced from the dimensions of the contained
+ %% object (picture or text). If one of these parameters is set to
+ %% a positive value, then the given value is used, regardless of the
+ %% size of the contents.
+ %%
+ var(numeric) fixedWidth, fixedHeight;
+
+ %% Controls how the contents of the picture is to be aligned relatively
+ %% to the picture margins. Can be one of "left", "centered", and defaults to
+ %% "left". The "centered" setting is useful for Picture-s whose fixedWidth
+ %% is set to a given value.
+ %%
+ var(string) halign, valign;
+
+ var(string) textDecoration;
+
+ @#boxed := 0;
+ @#borderColor := blue;
+
+ @#ignoreNegativeBase := 0;
+
+ @#fixedWidth := -1;
+ @#fixedHeight := -1;
+
+ @#halign := "left";
+ @#valign := "bottom";
+
+ @#textDecoration := "none";
+
+ Margins.@#(pleft, pright, ptop, pbottom);
+
+ FontInfoCopy.@#iFont(pfont);
+enddef;
+
+vardef PictureInfoCopy@#(text src)=
+ PictureInfo@#(src.left, src.right, src.top, src.bottom)(src.iFont);
+
+ @#boxed := src.boxed;
+ @#borderColor := src.borderColor;
+ @#ignoreNegativeBase := src.ignoreNegativeBase;
+ @#textDecoration := src.textDecoration;
+
+ @#fixedWidth := src.fixedWidth;
+ @#fixedHeight := src.fixedHeight;
+
+ @#halign := src.halign;
+ @#valign := src.valign;
+enddef;
+
+vardef PictureInfo_toString@#=
+ save ret; string ret;
+ ret := "PictureInfo(" & (str @#) & "): {" & (decimal @#left) & ", " & (decimal @#right) & ", " & (decimal @#top) & ", " & (decimal @#bottom) & "}" & " boxed: " & (decimal @#boxed);
+ ret := ret & " Font: " & toString(@#iFont);
+ ret
+enddef;
+
+PictureInfo.iPict(2, 2, 2, 2)(iFont);
+PictureInfo.iPictNoMargins(0, 0, 0, 0)(iFont);
+
+PictureInfoCopy.iPictBoxed(iPict);
+iPictBoxed.boxed := 1;
+
+%%
+%% Contructs a Picture object by wrapping around the
+%% low-level picture thePict.
+%%
+vardef EPicture@#(text iPict)(expr thePict) =
+ ObjectEquations(@#);
+ @#className := "Picture";
+
+ var(pair) contentShift;
+ var(picture) pict;
+ var(numeric) negativeBase;
+ var(string) contentAsString;
+ var(picture) contentAsPicture;
+
+ PictureInfoCopy.@#info(iPict);
+
+ if string thePict:
+ log "Picture " & (str @#) & " is a text";
+ @#contentAsString := thePict;
+ log @#contentAsString;
+ elseif picture thePict:
+ log "Picture " & (str @#) & " is a native pict";
+ @#contentAsPicture := thePict;
+ log @#contentAsPicture;
+ else:
+ log "Picture " & (str @#) & " [error]";
+ fi;
+
+enddef;
+
+%%
+%% Contructs a Picture object by wrapping around the
+%% low-level picture thePict.
+%%
+vardef Picture@#(expr thePict) =
+ EPicture@#(iPict)(thePict);
+enddef;
+
+%%
+%% Lays out the Picture.
+%%
+vardef Picture_layout@# =
+ if @#laidout = 1:
+ log "Picture " & str @# & " already laid out.";
+ else:
+ log "Laying out " & (str @#);
+
+ @#laidout := 1;
+
+ if known @#contentAsPicture:
+ log "Content is known to be a picture";
+ @#pict = @#contentAsPicture;
+ elseif known @#contentAsString:
+ log "Content is known to be a string: " & @#contentAsString;
+ @#pict = @#contentAsString infont @#info.iFont.name scaled @#info.iFont.scale;
+ else:
+ log "Show unknown parameter type in picture layout";
+ 2 = 3; % force an error
+ fi;
+
+ @#negativeBase = ypart llcorner @#pict;
+
+ if @#info.ignoreNegativeBase = 0:
+ negativeBaseAdjustement__ := 0;
+ else:
+ negativeBaseAdjustement__ := @#negativeBase;
+ fi;
+
+ if @#info.fixedWidth = -1:
+ @#width = pictWidth(@#pict) + @#info.left + @#info.right;
+ else:
+ @#width = @#info.fixedWidth;
+ fi;
+
+ if @#info.fixedHeight = -1:
+ @#height = pictHeight(@#pict) + @#info.top + @#info.bottom + negativeBaseAdjustement__;
+ else:
+ @#height = @#info.fixedHeight;
+ fi;
+
+ if @#info.halign = "left":
+ xdelta__ := @#info.left;
+ elseif @#info.halign = "center":
+ xdelta__ := (@#width-pictWidth(@#pict))/2;
+ else:
+ 2 = 3; % throw exception illegal value for @#info.halign
+ fi;
+
+ if @#info.valign = "bottom":
+ ydelta__ := @#info.bottom - @#negativeBase + negativeBaseAdjustement__;
+ elseif @#info.valign = "center":
+ ydelta__ := (@#height-pictHeight(@#pict))/2 - @#negativeBase + negativeBaseAdjustement__;
+ else:
+ 2 = 3; % throw exception illegal value for @#info.valign
+ fi;
+
+ @#contentShift = @#sw + (xdelta__, ydelta__);
+ fi;
+enddef;
+
+%%
+%% Draws the Picture.
+%%
+vardef Picture_draw@# =
+ Picture_layout@#;
+ objectEnsurePositioning.@#;
+
+ draw @#pict shifted @#contentShift;
+
+ if (@#info.textDecoration = "underline"):
+ save ydelta, height;
+ height := pictHeight(@#pict) - @#negativeBase;
+
+ ydelta := @#info.bottom - @#negativeBase - 0.8;
+
+ draw @#sw + (@#info.left, ydelta) -- @#se + (-@#info.right, ydelta) withcolor black withpen pencircle scaled 0.2bp;
+ fi;
+
+ if (@#info.boxed = 1):
+ draw objectBox(@#) withcolor @#info.borderColor;
+ fi;
+enddef;
+
+vardef Picture_border@#=
+ objectBox(@#)
+enddef;
+
+vardef aitem(text pictInfo)(text thePict)(text equation)=
+ save obj;
+ EPicture.obj(pictInfo)(thePict);
+ equation;
+ drawObject(obj);
+enddef;
+
+vardef item@#(text iPict)(text thePict)(text equation)=
+ save itemName;
+ string itemName;
+ itemName := str @#;
+
+ log "Creating an item with name: '" & itemName & "'";
+
+ if itemName = "":
+ log "Name is empty, creating an anonymous item!";
+ aitem(iPict)(thePict)(equation);
+ else:
+ EPicture@#(iPict)(thePict);
+ equation;
+ drawObject(@#);
+ fi;
+enddef;
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_picture_stack.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_picture_stack.mp
new file mode 100644
index 0000000000..edade327ef
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_picture_stack.mp
@@ -0,0 +1,153 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_picture_stack_mp:
+ expandafter endinput
+fi;
+_util_picture_stack_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_picture;
+inputonce util_commons;
+inputonce util_group;
+
+inputonce util_log;
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% %
+% PICTURE STACK %
+% %
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Style for a stack of child pictures with the given margins, spacing between children, and a common child style.
+%% If child style supplier @#childStyleSupplier is set, it takes precedence over the common child style.
+%% The child style supplier must be the name of a macro taking a child index as an argument and returning a child style.
+vardef PictureStackInfo@#(expr marginLeft, marginRight, marginTop, marginBottom)(text _spacing)(text _childStyle)=
+ attributes(@#);
+ var(numeric) boxed;
+ var(color) borderColor;
+ var(numeric) spacing;
+ var(string) childStyleSupplier;
+
+ Margins@#(marginLeft, marginRight, marginTop, marginBottom);
+
+ @#spacing := _spacing;
+
+ @#boxed := 0;
+ @#borderColor := green;
+
+ @#childStyleSupplier := "";
+
+ PictureInfoCopy.@#iPict(_childStyle);
+enddef;
+
+vardef PictureStackInfoCopy@#(text src)=
+ PictureStackInfo@#(src.left, src.right, src.top, src.bottom)(src.spacing)(src.iPict);
+
+ @#childStyleSupplier := src.childStyleSupplier;
+ @#boxed := src.boxed;
+ @#borderColor := src.borderColor;
+enddef;
+
+PictureStackInfo.iStack(2, 2, 2, 2)(2)(iPict);
+
+vardef EPictureStack@#(text pictStackInfo)(text thePictures)(text how)=
+ ObjectEquations(@#);
+ @#className := "PictureStack";
+
+ PictureStackInfoCopy.@#info(pictStackInfo);
+
+ attributes(@#);
+ var(numeric) nItems;
+ var(numeric) minx, miny, maxx, maxy;
+ var(string) picturesAsString;
+ %var(text) joinMethod;
+
+ string @#joinMethod;
+
+ %@#joinMethod := str how;
+ for l=how:
+ @#joinMethod := l;
+ endfor;
+
+ @#nItems := 0;
+ for p=thePictures:
+ if (@#info.childStyleSupplier <> ""):
+ EPicture.@#pict[@#nItems](scantokens (@#info.childStyleSupplier)(@#nItems))(p);
+ else:
+ EPicture.@#pict[@#nItems](@#info.iPict)(p);
+ fi;
+ @#nItems := @#nItems + 1;
+ endfor;
+
+ @#picturesAsString := listArray(@#pict)(@#nItems);
+
+ EGroup.@#group(@#info)(scantokens @#picturesAsString);
+
+ @#nw = @#group.nw;
+ @#se = @#group.se;
+enddef;
+
+vardef PictureStack@#(text thePictures)(text how)=
+ EPictureStack@#(iStack)(thePictures)(how);
+enddef;
+
+vardef PictureStack_layout@#=
+ if @#laidout = 1:
+ log "PictureStack " & (str @#) & " has already been layed out";
+ else:
+ @#laidout := 1;
+
+ layoutObjects(scantokens @#picturesAsString);
+
+ if @#joinMethod = "vleft":
+ setObjectJoin(pa.left=pb.left; pa.bottom = pb.top + @#info.spacing);
+ elseif @#joinMethod = "vcenter":
+ setObjectJoin(pa.midx=pb.midx; pa.bottom = pb.top + @#info.spacing);
+ elseif @#joinMethod = "vright":
+ setObjectJoin(pa.right=pb.right; pa.bottom = pb.top + @#info.spacing);
+ elseif @#joinMethod = "vleftbase":
+ setObjectJoin(pa.left=pb.left; pa.bottom = pb.bottom + @#info.spacing);
+ elseif @#joinMethod = "vcenterbase":
+ setObjectJoin(pa.midx=pb.midx; pa.bottom = pb.bottom + @#info.spacing);
+ elseif @#joinMethod = "vrightbase":
+ setObjectJoin(pa.right=pb.right; pa.bottom = pb.bottom + @#info.spacing);
+ else:
+ setObjectJoin(pa.c = pb.c); % By default, stack objects on top of each other.
+ scantokens @#joinMethod;
+ fi;
+
+ joinObjects(scantokens @#picturesAsString);
+
+ Group_layout.@#group;
+ fi;
+enddef;
+
+vardef PictureStack_draw@#=
+ PictureStack_layout.@#;
+ objectEnsurePositioning.@#;
+
+ for i=0 upto @#nItems-1:
+ Picture_draw.@#pict[i];
+ endfor;
+
+ if (@#info.boxed = 1):
+ draw objectBox(@#) withcolor @#info.borderColor;
+ fi;
+enddef;
+
+vardef PictureStack_border@#=
+ objectBox(@#)
+enddef;
+
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_positioning.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_positioning.mp
new file mode 100644
index 0000000000..9f32a0a54e
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_positioning.mp
@@ -0,0 +1,242 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_positioning_mp:
+ expandafter endinput
+fi;
+_util_positioning_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+
+%% Gives a point which is below the given @point with the given @value.
+%%
+def below(expr point, value) =
+ (point - (0, value))
+enddef;
+
+%% Gives a point which is above the given @point with the given @value.
+%%
+def above(expr point, value) =
+ (point + (0, value))
+enddef;
+
+%% Gives a point which is at the right of the given @point with the given @value.
+%%
+def atright(expr point, value) =
+ (point + (value, 0))
+enddef;
+
+%% Gives a point which is at the left of the given @point with the given @value.
+%%
+def atleft(expr point, value) =
+ (point - (value, 0))
+enddef;
+
+%% Positions the given objects so that they:
+%% * have their tops aligned
+%% * the distance between the objects is @distance
+%% * the center of gravity of the objects (taken on the top line) is at @middlePoint
+%%
+%% @distance
+%% |---------------------------|
+%% | |
+%% | @middlePoint |
+%% __________|_____________._____________|____________ the same top
+%% [objectA] | [objectB]
+%%
+vardef centered_align_top(suffix objectA, objectB)(expr distance, middlePoint)=
+ log middlePoint;
+ objectA.top = objectB.top;
+ objectB.left - objectA.right = distance;
+ middlePoint = .5[objectB.nw, objectA.ne];
+enddef;
+
+%% Deprecated, kept for backward compatibility (align is misspelled).
+%%
+vardef centered_allign_top(suffix objectA, objectB)(expr distance, middlePoint)=
+ log middlePoint;
+ objectA.top = objectB.top;
+ objectB.left - objectA.right = distance;
+ middlePoint = .5[objectB.nw, objectA.ne];
+enddef;
+
+%% theString means here not a sequence of characters but
+%% the horizontal or vertical line on which objects are placed.
+%% For example, if theString is top, then the objects are
+%% "hanging" on a horizontal line, like freshly washed
+%% clothes on a string.
+
+vardef align(suffix theString, extremityNew, extremityOld)
+ (text distanceBetweenObjects)(expr sign)(text objects)=
+ string objectsAsString__;
+ objectsAsString__ := enumToString(objects)("");
+
+ log "Aligning '" & objectsAsString__ & "' at " & str theString;
+ log sign;
+
+ if (objectsAsString__ = ""):
+ log "Nothing to do, bailing out.";
+ else:
+ string previousObject__;
+ previousObject__ := "";
+ objectIndex__ := 0;
+
+ forsuffixes obj = objects:
+ log "object: " & str obj;
+ if objectIndex__ = 0:
+ objectIndex__ := objectIndex__ + 1;
+ previousObject__ := str obj;
+ else:
+ objectIndex__ := objectIndex__ + 1;
+
+ log str theString;
+ log str extremityOld;
+ log str extremityNew;
+ log distanceBetweenObjects;
+
+ string eqA__, eqB__;
+ eqA__ := previousObject__ & "." & str theString & " = " & str obj & "." & str theString;
+
+ if (sign = "+"):
+ eqB__ := previousObject__ & "." & str extremityOld & " + " & (str distanceBetweenObjects) & " = " & str obj & "." & str extremityNew;
+ %eqB__ := previousObject__ & "." & str extremityOld & " + distanceBetweenObjects = " & str obj & "." & str extremityNew;
+ else:
+ eqB__ := previousObject__ & "." & str extremityOld & " - " & (str distanceBetweenObjects) & " = " & str obj & "." & str extremityNew;
+ fi;
+
+ log eqA__, eqB__;
+ scantokens eqA__;
+ scantokens eqB__;
+
+ previousObject__ := str obj;
+ fi;
+ endfor;
+ fi;
+enddef;
+
+vardef leftToRight@#(text distanceBetweenObjects)(text objects)=
+ if str @# = "":
+ log "String is empty, aligning to midy";
+ align(midy, left, right)(distanceBetweenObjects)("+")(objects);
+ else:
+ align(@#, left, right)(distanceBetweenObjects)("+")(objects);
+ fi;
+enddef;
+
+vardef rightToLeft@#(text distanceBetweenObjects)(text objects)=
+ if str @# = "":
+ log "String is empty, aligning to midy";
+ align(midy, right, left)(distanceBetweenObjects)("-")(objects);
+ else:
+ align(@#, right, left)(distanceBetweenObjects)("-")(objects);
+ fi;
+enddef;
+
+vardef topToBottom@#(text distanceBetweenObjects)(text objects)=
+ if str @# = "":
+ log "String is empty, aligning to midx";
+ align(midx, top, bottom)(distanceBetweenObjects)("-")(objects);
+ else:
+ align(@#, top, bottom)(distanceBetweenObjects)("-")(objects);
+ fi;
+enddef;
+
+vardef bottomToTop@#(text distanceBetweenObjects)(text objects)=
+ if str @# = "":
+ log "String is empty, aligning to midx";
+ align(midx, bottom, top)(distanceBetweenObjects)("+")(objects);
+ else:
+ align(@#, bottom, top)(distanceBetweenObjects)("+")(objects);
+ fi;
+enddef;
+
+%%
+%% Defines an equation which sets the given prefix to be equal for all the given objects.
+%% For example:
+%%
+%% same.top(a, b, c);
+%%
+%% is equivalent to
+%% a.top = b.top = c.top;
+%%
+vardef same@#(text objects)=
+ log "begin macro: same@#(text objects)=";
+
+ string equation__, property__;
+ equation__ := "";
+ property__ := str @#;
+
+ objectIndex__ := 0;
+ forsuffixes obj = objects:
+ log "object: " & str obj;
+
+ if objectIndex__ = 0:
+ objectIndex__ := objectIndex__ + 1;
+ equation__ := equation__ & str obj & "." & property__;
+ else:
+ objectIndex__ := objectIndex__ + 1;
+ equation__ := equation__ & "=" & str obj & "." & property__;
+ fi;
+ endfor;
+
+ equation__ := equation__ & ";";
+
+ log "Equation is: '" & equation__ & "'";
+
+ if objectIndex__ <= 1:
+ log "One or no objects, nothing to do!";
+ else:
+ scantokens equation__;
+ fi;
+enddef;
+
+%% this macro is NOT usable (yet)
+vardef leftToRightCentered@#(expr distanceBetweenObjects, middlePoint)(text objects)=
+ string objectsAsString__;
+ objectsAsString__ := enumToString(objects)("");
+
+ if (objectsAsString__ = ""):
+ log "Nothing to do, bailing out.";
+ else:
+ log "ASDFGHJ";
+ leftToRight@#(distanceBetweenObjects)(objects);
+
+ string firstObject__, lastObject__;
+ objectIndex__ := 0;
+ forsuffixes obj = objects:
+ if objectIndex__ = 0:
+ objectIndex__ := objectIndex__ + 1;
+ firstObject__ := str obj;
+ else:
+ objectIndex__ := objectIndex__ + 1;
+ lastObject__ := str obj;
+ fi;
+ endfor;
+
+ log "___";
+ .5[authA.nw,authB.ne] = middlePoint;
+ log "___";
+
+ string eqCenter__;
+ eqCenter__ := ".5[" & firstObject__ & ".nw," & lastObject__ & ".ne] = middlePoint";
+
+ log eqCenter__;
+ log middlePoint;
+
+ log "XXX";
+ scantokens eqCenter__;
+ log "XXX";
+ fi;
+enddef;
diff --git a/graphics/metapost/contrib/macros/metauml/inputs/util_shade.mp b/graphics/metapost/contrib/macros/metauml/inputs/util_shade.mp
new file mode 100644
index 0000000000..b5231164b9
--- /dev/null
+++ b/graphics/metapost/contrib/macros/metauml/inputs/util_shade.mp
@@ -0,0 +1,53 @@
+% Copyright 2005 2015 Ovidiu Gheorghies
+% Licensed under the Apache License, Version 2.0.
+
+if known _util_shade_mp:
+ expandafter endinput
+fi;
+_util_shade_mp:=1;
+
+% Sadly, this copy of the macro is needed to prevent multiple file loads being shown by MetaPost.
+% The guard values (such as _metauml_mp) do ensure that the file isn't loaded multiple times,
+% but this macro makes sure that MetaPost won't try to load the file and display a message for that.
+def inputonce text libraryFile=
+ if not known scantokens ("_" & str libraryFile & "_mp"):
+ %includeonce% show "Loading " & str libraryFile;
+ scantokens ("input " & str libraryFile);
+ else:
+ %includeonce% show str libraryFile & " already loaded.";
+ fi;
+enddef;
+
+inputonce util_log;
+
+vardef ShadeInfo@#=
+ _n_ := str @#;
+ generic_declare(numeric) _n.shift;
+ generic_declare(color) _n.background;
+
+ @#shift := 1;
+ @#background := .7white;
+enddef;
+
+vardef ShadeInfoCopy@#(text src)=
+ ShadeInfo.@#;
+ ShadeInfo_copy@#(src);
+enddef;
+
+vardef ShadeInfo_copy@#(text src)=
+ @#shift := src.shift;
+ @#background := src.background;
+enddef;
+
+vardef ShadeInfo_toString@#=
+ save @#ret;
+ string @#ret;
+ @#ret := "Shade (shift: " & (decimal @#shift) & " back: (" &
+ (decimal redpart @#background) & ", " &
+ (decimal greenpart @#background) & ", " &
+ (decimal bluepart @#background) & ")";
+
+ @#ret
+enddef;
+
+