%
% CoDi: Commutative Diagrams for TeX
% Copyright (c) 2015-2024 Paolo Brasolin <[email protected]>
% SPDX-License-Identifier: MIT
%
% This file is part of CoDi 1.1.2, released on 2024/04/22 under MIT license.
%

% μανδύας • (mandýas)
%   1. cloak
%   2. mantle
%   3. dolman

% Mandias defines the aesthetics aspect of the user level functionality,
% together with some baseline configuration.

\usetikzlibrary[calc]

% \usetikzlibrary[decorations.pathreplacing]
% \usetikzlibrary{decorations.pathmorphing}
% \usetikzlibrary[decorations.markings]
% \usetikzlibrary[arrows.meta]
\usetikzlibrary[positioning]

\pgfqkeys{/codi}{
%==[ universal styles ]=========================================================
 every diagram/.append style={},
 every layout/.append style={
   /codi/every object/.append style={shape=codi baseline centered rectangle},
   square,
 },
 every object/.append style={},
 every arrow/.append style={
   >=stealth,
 },
 every label/.append style={
   auto,
   inner sep=0.5ex,
   font=\everymath\expandafter{\the\everymath\scriptstyle}
 },
%==[ arrow styles ]=============================================================
 /codi/arrows/.cd,
   crossing over/clearance/.initial=0.5ex,
   crossing over/color/.initial=white,
   crossing over/.style={
     /tikz/preaction={
       -,
       draw=\pgfkeysvalueof{/codi/arrows/crossing over/color},
       line width=\pgfkeysvalueof{/codi/arrows/crossing over/clearance},
     },
   },
   shove/.style={
     /tikz/transform canvas={
       /tikz/shift={($(\tikztostart)!#1!-90:(\tikztotarget)-(\tikztostart)$)}
     }
   },
   slide/.style={
     /tikz/transform canvas={
       /tikz/shift={($(\tikztostart)!#1!0:(\tikztotarget)-(\tikztostart)$)}
     }
   },
%==[ label styles ]=============================================================
 /codi/labels/.cd,
   mid/.style={
     /tikz/fill=white,
     /tikz/shape=circle,
     /tikz/anchor=center,
     /tikz/inner sep=.25ex
   },
%=[ objects styles ]============================================================
 /codi/objects/.cd,
   % TODO: reflect on these styles
   % tetragonal/.style 2 args={
   %   /tikz/node distance=#2 and #1
   % },
   % square/.style={
   %   /codi/objects/rectangular={#1}{#1}
   % },
   % golden/.style={
   %   /codi/objects/rectangular={#1}{0.618*#1}
   % },
   % % comb/.style={
   % %   /codi/objects/rectangular={#1}{sqrt(3/4)*#1},
   % % },
   % % comb/.default=4em,
   % square/.default=4em,
   % golden/.default=4em,
%=[ lattice styles ]============================================================
 /codi/layouts/.cd,
   hexagonal/.code args={#1side #2 angle #3}{
     \pgfkeys{/codi/layouts/#1hexagonal=side {#2} angle {#3}},
   },
   horizontal hexagonal/.style args={side #1 angle #2}{
     /codi/layouts/tetragonal=base {#1} height {tan(#2)*#1*0.5},
     /tikz/every odd row/.append style={/tikz/xshift=(#1)*0.5},
   },
   vertical hexagonal/.style args={side #1 angle #2}{
     /codi/layouts/tetragonal=base {tan(#2)*#1*0.5} height {#1},
     /tikz/every odd column/.append style={/tikz/yshift=-1*(#1)*0.5},
   },
   hexagonal/.default=horizontal side 4.5em angle 60,
   %
   tetragonal/.style args={base #1 height #2}{
     /tikz/column sep={{#1},between origins},
     /tikz/row sep={{#2},between origins},
   },
   tetragonal/.default=base 4.5em height 2.8em,
   %
   square/.style={
     /codi/layouts/tetragonal=base {#1} height {#1},
   },
   golden/.style={
     /codi/layouts/tetragonal=base {#1} height {0.618*#1},
   },
   square/.default=4.5em,
   golden/.default=4.5em,
%=[ diagram styles ]============================================================
 /codi/diagrams/.cd,
   grid/.style 2 args={
     /tikz/x={#1},
     /tikz/y={#2},
     /tikz/on grid,
   },
   metric/.style 2 args={
     % NOTE: {1 and 1}{1} is infty-norm, unit circle is unit square
     % NOTE: {2}{0.5} is 1-norm, circle of radius 2 is rhombus circumscribing base hexagon
     /tikz/node distance={#1},
     % TODO: implement control to allow for explicit units on single factor specs
     /tikz/above left/.code={\tikz@lib@place@handle@{##1}{south east}{-1}{1}{north west}{#2}},
     /tikz/above right/.code={\tikz@lib@place@handle@{##1}{south west}{1}{1}{north east}{#2}},
     /tikz/below left/.code={\tikz@lib@place@handle@{##1}{north east}{-1}{-1}{south west}{#2}},
     /tikz/below right/.code={\tikz@lib@place@handle@{##1}{north west}{1}{-1}{south east}{#2}},
   },
   %
   hexagonal/.code args={#1side #2 angle #3}{
     \pgfkeys{/codi/diagrams/#1hexagonal=side #2 angle #3}
   },
   horizontal hexagonal/.style args={side #1 angle #2}{
     /codi/every layout/.append style={/codi/layouts/hexagonal=horizontal side {#1} angle {#2}},
     /codi/diagrams/grid={#1*0.5}{#1*tan(#2)*0.5},
     /codi/diagrams/metric={2}{0.5},
   },
   vertical hexagonal/.style args={side #1 angle #2}{
     /codi/every layout/.append style={/codi/layouts/hexagonal=vertical side {#1} angle {#2}},
     /codi/diagrams/grid={#1*tan(#2)*0.5}{#1*0.5},
     /codi/diagrams/metric={2}{0.5},
   },
   hexagonal/.default=horizontal side 4.5em angle 60,
   %
   tetragonal/.style args={base #1 height #2}{
     /codi/every layout/.append style={/codi/layouts/tetragonal=base {#1} height {#2}},
     /codi/diagrams/grid={#1}{#2},
     /codi/diagrams/metric={1 and 1}{1},
   },
   tetragonal/.default=base 4.5em height 2.8em,
   %
   square/.style={
     /codi/every layout/.append style={/codi/layouts/square=#1},
     /codi/diagrams/tetragonal=base {#1} height {#1},
   },
   golden/.style={
     /codi/every layout/.append style={/codi/layouts/golden=#1},
     /codi/diagrams/tetragonal=base {#1} height {0.618*#1},
   },
   square/.default=4.5em,
   golden/.default=4.5em,
}

%==[ baseline centered rectangle shape ]========================================

% The math formula axis height is recovered and stored as a pgf function.

% NOTE: the LuaTeX version is needed just by ConTeXt
\pgfutil@ifluatex
 \directlua{tex.enableprimitives('kD', {'Umathaxis'})}
 \pgfmathdeclarefunction{kD_math_formula_axis_height}{0}{%
   \begingroup%
     $\relax$% update fontdimens
     % See TeX by Topic §23.5 for details.
     \pgfmathreturn\the\kDUmathaxis\textstyle%
   \endgroup}
\else% if using (pdf)tex
 \pgfmathdeclarefunction{kD_math_formula_axis_height}{0}{%
   \begingroup%
     $\relax$% update fontdimens
     % See TeX by Topic §23.5 for details.
     \pgfmathreturn\the\fontdimen22\textfont2%
   \endgroup}
\fi

\pgfqkeys{/codi/baseline centered rectangle}{
 center raise/.initial=kD_math_formula_axis_height
}

% Then the shape is defined by inheritance.

\pgfdeclareshape{codi baseline centered rectangle} {
 % Inherit the rectangle shape.
 \inheritsavedanchors[from={rectangle}]
 \inheritanchor[from={rectangle}]{base}
 \inheritanchor[from={rectangle}]{north}
 \inheritanchor[from={rectangle}]{south}
 \inheritanchor[from={rectangle}]{base west}
 \inheritanchor[from={rectangle}]{north west}
 \inheritanchor[from={rectangle}]{south west}
 \inheritanchor[from={rectangle}]{base east}
 \inheritanchor[from={rectangle}]{north east}
 \inheritanchor[from={rectangle}]{south east}
 \inheritanchor[from={rectangle}]{mid}
 \inheritanchor[from={rectangle}]{mid west}
 \inheritanchor[from={rectangle}]{mid east}
 \inheritbackgroundpath[from={rectangle}]
 % Redefine west, center and east anchors
 % setting their y coordinates to center raise.
 \anchor{center}{\pgf@anchor@rectangle@center\pgfmathsetlength\pgf@y%
   {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}}
 \anchor{west}{\pgf@anchor@rectangle@west\pgfmathsetlength\pgf@y%
   {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}}
 \anchor{east}{\pgf@anchor@rectangle@east\pgfmathsetlength\pgf@y%
   {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}}
 % Save the original anchors as alternate "real" versions.
 \anchor{real center}{\pgf@anchor@rectangle@center}
 \anchor{real west}{\pgf@anchor@rectangle@west}
 \anchor{real east}{\pgf@anchor@rectangle@east}
 % Redefine the border anchor calculation.
 \anchorborder{%
   % (x,y) = target
   % let tempdima = center raise
   \pgfmathsetlength\pgfutil@tempdima%
     {\pgfkeysvalueof{/codi/baseline centered rectangle/center raise}}%
   % let b = (x,y) = target
   \pgf@xb=\pgf@x%
   \pgf@yb=\pgf@y%
   % let (x,y) = south west
   \southwest%
   % let a = (x,y) = south west
   \pgf@xa=\pgf@x%
   \pgf@ya=\pgf@y%
   % let (x,y) = north east
   \northeast%
   % let (x,y) = (x,y) - a = north east - south west = (width, height)
   \advance\pgf@x by-\pgf@xa%
   \advance\pgf@y by-\pgf@ya%
   % let c = (x,y)/2 = (width, height)/2 = (width/2, height/2)
   \pgf@xc=.5\pgf@x%
   \pgf@yc=.5\pgf@y%
   % let a = a + c = south west + (width/2, height/2) = center
   \advance\pgf@xa by\pgf@xc%
   \advance\pgf@ya by\pgf@yc%
   % if by = target y > 0
   \ifdim\pgf@yb>0pt%
     % let (x,y) = north east
     \northeast%
     % let cy = y = north east y
     \pgf@yc=\pgf@y%
     % let cy = cy - center raise = north east y - center raise
     \advance\pgf@yc by-\pgfutil@tempdima%
   \else%
     % let (x,y) = south west
     \southwest%
     % let cy = y = - south west y
     \pgf@yc=-\pgf@y%
     % let cy = cy + center raise = - south west y + center raise
     \advance\pgf@yc by\pgfutil@tempdima%
   \fi
   \edef\pgf@marshal{%
     % calculate the intersection of the half line from the origin
     \noexpand\pgfpointborderrectangle
     % passing through target
     {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}
     % and the rectangle centered on the origin
     % whose upper right corner is
     % (width/2, +north east y - center raise) if target y > 0
     % (width/2, -south west y + center raise) if target y < 0
     {\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
   }%
   % let (x,y) = the intersection
   \pgf@process{\pgf@marshal}%
   % let x = x + ax = width/2 + center x
   \advance\pgf@x by\pgf@xa%
   % let y = y + tempdima = ±(ne/sw y - center raise) + center raise
   \advance\pgf@y by\pgfutil@tempdima%
   % that is, y = + north east y                    if target y > 0
   %          y = - south west y + 2 * center raise if target y < 0
   %
   % NOTE: in essence, we're just compensating for the redefinition
   % of ne/sw anchors that shifted them by cr below the real center.
   %                ┏━━━━━━┯━━━━━━┓  ╮╮
   %                ┃      │      ┃  ││ + ney - cr
   %            ╭╭  ┠──────┼──────┨ ╮│╯               y > 0
   % - swy + cr │╰╭ ┣━━━━━━┿━━━━━━┫ ╯╯ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
   %            ╰ ╰ ┗━━━━━━┷━━━━━━┛                   y < 0
 }%
}%

%==[ prompter ]=================================================================

% This key is meant for visual assistance with the node labeling automation.

\pgfqkeys{/codi}{
 prompter label/.style={
   /tikz/.cd,
   inner sep=0sp,
   font=\ttfamily\bfseries\tiny,
   line width=1pt,
   draw=violet,
   fill=violet,
   text=white,
   overlay,
   label anchor/.style={tikz@label@post/.append style={anchor=##1}},
   label anchor=north east,
   label position=south east
 },
 prompter pinner/.style={
   /tikz/draw=violet,
   /tikz/line width=1sp,
   /tikz/label={[/codi/prompter label]:#1},
 },
 prompter/.style={/bapto/output/.forward to=/codi/prompter pinner}
}