function modfun(m,n,detail,gif)
    % modfun(m,n,detail) connects n points, z(j), equally spaced
    % around the complex unit circle, by n+1 straight lines.    
    % The j-th line connects z(j+1) to z(mod(j*m,n)+1).
    %
    % detail = 0 displays the final result.
    % detail = 1 displays each line.
    % detail = 2 pauses briefly after displaying each line.

    %    Copyright 2022 Cleve Moler

    if nargin < 2
        m = 102;
        n = 300;
    end
    if nargin < 3
        detail = 0;
    end
    if nargin < 4
        gif = [];
    end

    init_fig(detail,gif)
    z = exp(2i*pi*(0:n)/n);
    for j = 0:n
        zj = [z(j+1) z(mod(j*m,n)+1)];
        line(real(zj),imag(zj))
        paws(detail)
        if ~isempty(gif) && mod(j,5) == 0
            gif_frame
        end
    end 
    if ~isempty(gif)
        gif_frame(3)
        gif_frame('wrap')
    end
    % -------------------------------------------
    
    function init_fig(detail,gif)
        clf
        shg
        axis([-1 1 -1 1])
        axis square
        axis off
        if isempty(gif)
            pbutton(1,'-','m')
            ebutton(2,int2str(m),'m')
            pbutton(3,'+','m')
            wbutton(4,detail)
            pbutton(6,'-','n')
            ebutton(7,int2str(n),'n')
            pbutton(8,'+','n')
        else
            gif_frame(gif)
        end
    end

    function ebutton(p,s,t)
        uicontrol(Style = "edit", ...
            Units = 'normalized', ...
            Position = [p/10+(p>5)/20,0.03,0.08,0.05], ...
            String = s, ...
            Tag = t, ...
            FontSize = 12, ...
            FontWeight = 'Bold', ...
            Callback = @cb)
    end

    function pbutton(p,s,u)
        uicontrol(Style = "pushbutton", ...
            Units = 'normalized', ...
            Position = [p/10+(p>5)/20,0.03,0.08,0.05], ...
            String = s, ...
            UserData = u, ...
            FontSize = 12, ...
            FontWeight = 'Bold', ...
            Callback = @cb)
    end

    function wbutton(~,s)
        uicontrol(Style = "pushbutton", ...
            Units = 'normalized', ...
            Position = [0.475,0.03,0.08,0.05], ...
            String = s, ...
            FontSize = 12, ...
            FontWeight = 'Bold', ...
            Callback = @paws)
    end

    function cb(arg,~)
        mo = findobj('tag','m');
        m = str2double(mo.String);
        no = findobj('tag','n');
        n = str2double(no.String);
        as = arg.String;
        au = arg.UserData;
        minus = (length(as) == 1) && (as == '-');
        plus = (length(as) == 1) && (as == '+');
        if minus && au == 'm'
            m = m-1;
        elseif minus && au == 'n'
            n = n-1;
        elseif plus && au == 'm'
            m = m+1;
        elseif plus && au == 'n'
            n = n+1;
        end    
        mo.String = num2str(m);
        no.String = num2str(n);
        detail = get(findobj('callback',@paws),'string');
        modfun(m,n,detail)
    end

    function paws(arg,~)
        if nargin == 1
            switch arg
                case '0'
                case '1', drawnow
                case '2', pause(0.05)
            end
        else
            switch arg.String
                case '0', arg.String = '1';
                case '1', arg.String = '2';
                case '2', arg.String = '0';
            end
        end
    end
end