% 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;