% Some setup for metapost
\startMPinclusions 

% Use metaobj for drawing objects
input metaobj; 

% Set some defaults for pretty pictures
setObjectDefaultOption("Box")("framewidth")(.75mm);
setObjectDefaultOption("Circle")("framewidth")(.75mm);
setObjectDefaultOption("Circle")("circmargin")(3mm);
setObjectDefaultOption("Mux")("framewidth")(.75mm);
%ahlength := 1.5mm;
ahangle := 60;

setCurveDefaultOption("linewidth",.75mm);
% Add a nodesep that's equal to the linewidth, since the linewidth isn't
% included in the bounding box for line cutoff.
setCurveDefaultOption("nodesep",curve_linewidth_default);


% Define a register.
% |v| is either a picture, a string or an object given by its number which
% will be contained inside the register. Supports the same options as Box,
% plus:
%   reflect    Reflect the register vertically, so input is right and output
%              is left. (default: false)
%   labels     Show labels for the input and output ports. (default: false)
vardef newReg@#(expr v) text options=
  ExecuteOptions(@#)(options);
  assignObj(@#,"Reg");
  StandardInterface;
  
  % We contain a box (that contains the passed object in turn)
  SubObject(box,obj(newobjstring_));
  newBox.obj(@#box)(v) options;
 
  % Some points for ports
  ObjPoint ck,d,out;

  ObjCode StandardEquations,
    % Align our bounding box with the enclosed box
    "obj(@#box).c = @#c",
    "obj(@#box).se = @#se",
    "obj(@#box).nw = @#nw",
    % Put the clock, data and output ports at the right spots
    if OptionValue@#("reflect"):
      "xpart @#out = xpart @#w",
      "xpart @#d = xpart @#ck = xpart @#e",
    else:
      "xpart @#out = xpart @#e",
      "xpart @#d = xpart @#ck = xpart @#w",
    fi
    "ypart @#out = ypart midpoint(@#n, @#s)",
    "ypart @#d = ypart (@#sw * .25 + @#nw * .75)",
    "ypart @#ck = ypart (@#sw * .75 + @#nw * .25)";

  StandardTies;
enddef;

% Draw a register
def drawReg(suffix reg)=
  save clkwh, refl;
  % Draw the box
  drawObj(obj(reg.box));

  % Fill refl with 1 or -1, to invert coordinates when reflected.
  if OptionValue.reg("reflect"):
    refl = -1;
  else:
    refl = 1;
  fi;

  % Calculate (half of) the height and width of the triangle
  clkwh = ypart((reg.n - reg.s)) * .1;
  % Draw the "clock" triangle
  draw ((0, clkwh) -- (refl * clkwh, 0) -- (0, -clkwh)) shifted reg.ck;

  % Draw input and output labels
  if OptionValue.reg("labels"):
    if OptionValue.reg("reflect"):
      label.lft(\sometxt{D}, reg.d);
      label.rt(\sometxt{O}, reg.out);
    else:
      label.rt(\sometxt{D}, reg.d);
      label.lft(\sometxt{O}, reg.out);
    fi;
  fi
enddef;

% Bounding path for a register
def BpathReg(suffix n)=BpathObj(obj(n.box)) enddef;

% Define options
define_global_boolean_option("reflect");
define_global_boolean_option("labels");
setObjectDefaultOption("Reg")("reflect")(false);
setObjectDefaultOption("Reg")("labels")(false);

% Define a Multiplexer.
vardef newMux@# text options=
  ExecuteOptions(@#)(options);
  assignObj(@#,"Mux");
  StandardInterface;
  % Add ports
  ObjPoint inpa, inpb, out, sel;
 
  ObjCode MinimumStandardEquations,
    % Make it a parallel trapezium
    "xpart(@#ne - @#nw) = xpart(@#se - @#sw)",
    "ypart(@#ne - @#nw) = -1 * ypart(@#se - @#sw)",
    % Use a 22.5 degree angle for the sides
    "ypart(@#nw) - ypart(@#ne) = xpart(@#ne-@#nw) / 2",
    % With a specific width and height
    "@#e-@#w = (" & decimal OptionValue@#("width") & ", 0mm)",
    "@#n-@#s = (0mm, " & decimal OptionValue@#("height") & ")",
    % And space the input ports evenly
    "@#inpa = midpoint(@#nw, @#w)",
    "@#inpb = midpoint(@#w, @#sw)",
    "@#out = @#e", 
    "@#sel = @#n"; 

  StandardTies;
enddef;

% Draw a multiplexer
def drawMux(suffix mux)=
  draw mux.n -- mux.s;
  % Use our bounding path to draw
  drawFramedOrFilledObject_(mux);
enddef;

% Bounding path for a multiplexer
def BpathMux(suffix n)=StandardBpath(n) enddef;

% Define options
define_local_numeric_option("width");
define_local_numeric_option("height");
setObjectDefaultOption("Mux")("width")(5mm);
setObjectDefaultOption("Mux")("height")(15mm);
setObjectDefaultOption("Mux")("framed")(true);
% Overidden above
%setObjectDefaultOption("Mux")("framewidth")(.5bp);
setObjectDefaultOption("Mux")("framecolor")(black);
setObjectDefaultOption("Mux")("framestyle")("");
setObjectDefaultOption("Mux")("shadow")(false);
setObjectDefaultOption("Mux")("shadowcolor")(black);
setObjectDefaultOption("Mux")("filled")(false);
setObjectDefaultOption("Mux")("fillcolor")(black);


def midpoint(expr a, b) = ((a + b) / 2) enddef;

\stopMPinclusions

% Make \overrightarrow "unexpanded", to make it work within metapost.
% http://www.ntg.nl/pipermail/ntg-context/2009/043620.html. Will be fixed in
% context.
\let\normaloverrightarrow\overrightarrow                                                                                                                     
\unexpanded\def\overrightarrow{\normaloverrightarrow} 

% vim: set sw=2 sts=2 expandtab:
