%% fxpicture.sty
%%
%% Line styles for LaTeX's picture environment, on top of pict2e.
%%
%% Written by Claude AI (Anthropic), with direction from CodeCogs Ltd.
%% A working implementation: https://fxeditor.codecogs.com
%%
%% Copyright (C) 2026 CodeCogs Ltd.
%%
%% This work may be distributed and/or modified under the conditions of the LaTeX Project
%% Public License, either version 1.3c of this license or (at your option) any later version.
%% The latest version of this license is in https://www.latex-project.org/lppl.txt
%%
%% This work has the LPPL maintenance status `maintained'. The Current Maintainer of this
%% work is CodeCogs Ltd. This work consists of the files fxpicture.sty and fxpicture-doc.tex,
%% and the derived file fxpicture-doc.pdf.
%%
%%   \usepackage{fxpicture}            % loads pict2e; options are passed to it
%%
%%   \linestyle{solid}                 % the default
%%   \linestyle{dashed}                % on 3pt, off 3pt
%%   \linestyle{dotted}                % on one line width, off 2pt
%%   \linestyle{dashdot}               % on 3pt, off 2pt, on one line width, off 2pt
%%   \dashpattern{<on>}{<off>}         % a dash pattern of your own, eg \dashpattern{3pt}{2pt}
%%
%% Both are ordinary declarations, like \linethickness: they last to the end of the group, and
%% apply to every line pict2e strokes - \line, \vector's shaft, \Line, \polyline, \polygon,
%% \circle, \oval, \arc, \qbezier, \cbezier and \strokepath. Filled shapes (\circle*, \polygon*,
%% \arc*, arrowheads) are not dashed.
%%
%%   {\linestyle{dashed}
%%     \put(10,10){\line(1,0){40}}
%%     \put(10,20){\oval(40,10)}
%%     \put(10,30){\qbezier(0,0)(20,15)(40,0)}
%%   }
%%
%% The lengths of \dashpattern are lengths (3pt, 1mm), or bare numbers as multiples of
%% \unitlength as it is when \dashpattern is given. The pattern starts afresh at the beginning
%% of each path. The named styles follow TikZ's (dashed, dotted, dash dot), so a picture and a
%% TikZ drawing side by side match; dotted and dashdot dots are as long as the line is thick,
%% whatever \linethickness is when the line is drawn.
%%
%% Works with each of pict2e's drivers (pdftex, luatex, xetex, dvips, dvipdfm).
%%
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{fxpicture}[2026/10/15 v1.0 Line styles for the picture environment]

\DeclareOption*{\PassOptionsToPackage{\CurrentOption}{pict2e}}
\ProcessOptions\relax
\RequirePackage{pict2e}[2020/09/30]

% The dash operator of the output: PostScript for dvips, PDF otherwise. pict2e has already set
% its user space to points (\pIIe@scale@PTtoBP), so the lengths are written in pt.
\ifnum\pIIe@mode=\@ne
  \def\fxp@setdash@op{setdash}
\else
  \def\fxp@setdash@op{d}
\fi

% \fxp@dash expands, inside pict2e's \edef, to the dash operator of the current style, or to
% nothing for solid lines - so a picture without \linestyle comes out exactly as pict2e makes it.
\let\fxp@dash\@empty
\def\fxp@w{\strip@pt\@wholewidth}

\@namedef{fxp@style@solid}{\let\fxp@dash\@empty}
\@namedef{fxp@style@dashed}{%
  \def\fxp@dash{ [3 3] 0 \fxp@setdash@op}}
\@namedef{fxp@style@dotted}{%
  \def\fxp@dash{ [\fxp@w\space 2] 0 \fxp@setdash@op}}
\@namedef{fxp@style@dashdot}{%
  \def\fxp@dash{ [3 2 \fxp@w\space 2] 0 \fxp@setdash@op}}

\DeclareRobustCommand*\linestyle[1]{%
  \@ifundefined{fxp@style@#1}%
    {\PackageError{fxpicture}{Unknown line style `#1'}%
       {The line styles are solid, dashed, dotted and dashdot;\MessageBreak
        \protect\dashpattern{on}{off} makes one of your own.}}%
    {\@nameuse{fxp@style@#1}}%
  \ignorespaces}

\DeclareRobustCommand*\dashpattern[2]{%
  \@defaultunitsset\@tempdima{#1}\unitlength
  \@defaultunitsset\@tempdimb{#2}\unitlength
  \ifdim\@tempdima<\z@ \fxp@baddash \else
  \ifdim\@tempdimb<\z@ \fxp@baddash \else
  \ifdim\dimexpr\@tempdima+\@tempdimb\relax=\z@ \fxp@baddash \else
    \edef\fxp@dash{ [\strip@pt\@tempdima\space\strip@pt\@tempdimb] 0 \noexpand\fxp@setdash@op}%
  \fi\fi\fi
  \ignorespaces}
\def\fxp@baddash{%
  \PackageError{fxpicture}{Bad \protect\dashpattern}%
    {Its lengths can't be negative, nor both zero.}}

% pict2e strokes every path through \pIIe@drawGraph; this is pict2e's own (v0.4b, 2020) with
% \fxp@dash after the line join, in the branch that strokes. With no driver (pict2e's
% `original' option) pict2e draws nothing of its own, and there is nothing to dash.
\ifnum\pIIe@mode>\z@
  \def\fxp@drawGraph@pIIe{%
      \edef\x{\pIIe@debug@comment\space
              \pIIe@scale@PTtoBP}%
      \if@tempswa
        \edef\y{\pIIe@fill@op}%
      \else
        \edef\x{\x\space
          \strip@pt\@wholewidth\space\pIIe@setlinewidth@op
          \pIIe@linecap\pIIe@linejoin\space}%
        \edef\y{\pIIe@stroke@op}%
      \fi
      \expandafter\pIIe@code\expandafter{%
        \expandafter\x\the\pIIe@GRAPH\space\y}%
      \global\pIIe@GRAPH{}\xdef\pIIe@CPx{}\xdef\pIIe@CPy{}%
    \endgroup}
  \ifx\pIIe@drawGraph\fxp@drawGraph@pIIe\else
    \PackageWarningNoLine{fxpicture}{%
      This pict2e's \string\pIIe@drawGraph\space is not the one\MessageBreak
      fxpicture was written for; line styles may not work}%
  \fi
  \def\pIIe@drawGraph{%
      \edef\x{\pIIe@debug@comment\space
              \pIIe@scale@PTtoBP}%
      \if@tempswa
        \edef\y{\pIIe@fill@op}%
      \else
        \edef\x{\x\space
          \strip@pt\@wholewidth\space\pIIe@setlinewidth@op
          \pIIe@linecap\pIIe@linejoin\fxp@dash\space}%
        \edef\y{\pIIe@stroke@op}%
      \fi
      \expandafter\pIIe@code\expandafter{%
        \expandafter\x\the\pIIe@GRAPH\space\y}%
      \global\pIIe@GRAPH{}\xdef\pIIe@CPx{}\xdef\pIIe@CPy{}%
    \endgroup}
\fi

% pict2e's arrows (\vector, \Vector, \polyvector) are one filled outline, shaft and head
% together. With a line style, the outline is drawn without the shaft - its back corners are the
% only points at x=0, in both the LaTeX and the PSTricks arrowheads - and the shaft is stroked
% on its own, from the tail to half way into the head, under the head. Solid arrows are pict2e's
% own. \ltxarrows and \pstarrows still choose the arrowhead.
\ifnum\pIIe@mode>\z@
  \let\fxp@vector@orig\pIIe@vector
  \def\ltxarrows{\let\fxp@vector@orig\pIIe@vector@ltx}
  \def\pstarrows{\let\fxp@vector@orig\pIIe@vector@pst}
  \def\pIIe@vector{%
    \ifx\fxp@dash\@empty \fxp@vector@orig \else \fxp@dashedvector \fi}
  \def\fxp@dashedvector{%
    \edef\fxp@concat{\the\pIIe@GRAPH}%
    \let\fxp@lineto\pIIe@lineto
    \let\pIIe@lineto\fxp@headlineto
    \fxp@vector@orig
    \let\pIIe@lineto\fxp@lineto
    \ifdim\@xdim>\z@
      \edef\fxp@head{\the\pIIe@GRAPH}%
      \global\pIIe@GRAPH\expandafter{\fxp@concat}%
      \@tempdimc\@xdim \advance\@tempdimc\@linelen \divide\@tempdimc\tw@
      \pIIe@moveto\z@\z@ \pIIe@lineto\@tempdimc\z@
      \pIIe@strokeGraph
      \global\pIIe@GRAPH\expandafter{\fxp@head}%
    \fi}
  \def\fxp@headlineto#1#2{\ifdim#1=\z@ \else \fxp@lineto{#1}{#2}\fi}
\fi

\endinput
