% Clear the workspace and the screen
sca;
close all;
clear;

% Here we call some default settings for setting up Psychtoolbox
PsychDefaultSetup(2);

% Get the screen numbers
screens = Screen('Screens');

% Draw to the external screen if avaliable
screenNumber = max(screens);

% Define black and white
white = WhiteIndex(screenNumber);
black = BlackIndex(screenNumber);
grey = white / 2;

% Open an on screen window
[window, windowRect] = PsychImaging('OpenWindow', screenNumber, black);

% Get the size of the on screen window
[screenXpixels, screenYpixels] = Screen('WindowSize', window);

% Change the blend function to draw an antialiased stimuli
Screen('BlendFunction', window, 'GL_SRC_ALPHA', 'GL_ONE_MINUS_SRC_ALPHA');

% Query the frame duration
ifi = Screen('GetFlipInterval', window);

% Hide the standard computer as we will be rendering our own
HideCursor;

% Get the centre coordinate of the window
[xCenter, yCenter] = RectCenter(windowRect);

% Make a base Rect a proportion of the screen
dim = round(screenYpixels / 5);
baseRect = [0 0 dim dim];

% Define red and blue
blue = [0 0 1];
red = [1 0 0];

% Here we set the initial position of the mouse to be in the centre of the
% screen
SetMouse(xCenter, yCenter, window);

% We now set the squares initial position to the centre of the screen
sx = xCenter;
sy = yCenter;

% Center the rectangle on screen position
centeredRect = CenterRectOnPointd(baseRect, sx, sy);
topLeft = [centeredRect(1) centeredRect(2)]';
bottomRight = [centeredRect(3) centeredRect(4)]';

% Diameter of the dots showing the top left and bottom right corners
cornerDim = 40;

% Minimum size of the rect
minDim = 60;

% Signal not to draw the rings around the corner dots
drawTopLeftRing = 0;
drawBottomRightRing = 0;

% Set the previous ring drawing cue to zero
drawTopLeftRingPrevious = 0;
drawBottomRightRingPrevious = 0;

% Signal the the person is not holding down the mouse button
leftPressed = 0;
rightPressed = 0;

% Offset cue to allow nice dragging effect
topLeftOffsetSet = 0;
bottomRightOffsetSet = 0;

% Sync us and get a time stamp
vbl = Screen('Flip', window);
waitframes = 1;

% Maximum priority level
topPriorityLevel = MaxPriority(window);
Priority(topPriorityLevel);

% Loop the animation until a key is pressed
while ~KbCheck

    % Cache the previous centered rect: we revert to this if the user trys
    % to turn the rectangle inside out
    previousCentredRect = centeredRect;

    % Get the current position of the mouse
    [mx, my, buttons] = GetMouse(window);

    % Offsets between the cursor and the two control points
    offsetTopLeft = topLeft' - [mx my];
    offsetBottomRight = bottomRight' - [mx my];

    % Calculate the screen distance in pixels bewteen the mouse cursor and
    % each of the corners
    distTopLeft = EuclidDist([mx, my], topLeft');
    distBottomRight = EuclidDist([mx, my], bottomRight');

    % Calculations for the top left corner
    if distTopLeft <= cornerDim / 2 || leftPressed == 1

        % If the mouse is in the circle color it red
        topLeftColor = red;

        % If the button is pressed draw a ring around the circle
        if sum(buttons) > 0
            drawTopLeftRing = 1;
        else
            drawTopLeftRing = 0;
        end

        % If we are drawing a ring both this frame and last then move the
        % coordinates of the corner that is being clicked
        if drawTopLeftRingPrevious == 1 && drawTopLeftRing == 1

            % We are pressing and holding the mouse button, so we cache the
            % offset between the mouse cursor and the centre of the pressed
            % circle
            if topLeftOffsetSet == 0
                theOffset = offsetTopLeft;
                topLeftOffsetSet = 1;
            end

            % Update corner coordinates
            centeredRect(1:2) = [mx , my] + theOffset;

            % Signal the person is depressing the mouse button on the top
            % left corner
            leftPressed = 1;

        else

            % Signal the person is not depressing the mouse button on the
            % top left corner
            leftPressed = 0;
            topLeftOffsetSet = 0;

        end

        % Cache this value for the next frame
        drawTopLeftRingPrevious = drawTopLeftRing;

    else

        % If the mouse is not in the circle color it blue
        topLeftColor = blue;

    end

    % Calculations for the bottom right corner
    if distBottomRight <= cornerDim / 2 || rightPressed == 1

        % If the mouse is in the circle color it red
        bottomRightColor = red;

        % If the button is pressed draw a ring around the circle
        if sum(buttons) > 0
            drawBottomRightRing = 1;
        else
            drawBottomRightRing = 0;
        end

        % If we are drawing a ring both this frame and last then move the
        % coordinates of the coorner that is being clicked
        if drawBottomRightRingPrevious == 1 && drawBottomRightRing == 1

            % We are pressing and holding the mouse button, so we cache the
            % offset between the mouse cursor and the centre of the pressed
            % circle
            if bottomRightOffsetSet == 0
                theOffset = offsetBottomRight;
                bottomRightOffsetSet = 1;
            end

            % Update corner coordinates
            centeredRect(3:4) = [mx, my] + theOffset;

            % Signal the person is depressing the mouse button on the
            % bottom right
            rightPressed = 1;

        else
            % Signal the person is not depressing the mouse button on the
            % bottom right corner
            rightPressed = 0;
            bottomRightOffsetSet = 0;

        end

        % Cache this value for the next frame
        drawBottomRightRingPrevious = drawBottomRightRing;

    else

        % If the mouse is not in the circle color it blue
        bottomRightColor = blue;

    end

    % Here we gauard against the user trying to turn the rectangle inside
    % out - this will break the drawing code
    if (centeredRect(3) - centeredRect(1)) < minDim || ...
            (centeredRect(4) - centeredRect(2)) < minDim
        centeredRect = previousCentredRect;
    end

    % Coordinates of the movable corners on this frame
    topLeft = [centeredRect(1) centeredRect(2)]';
    bottomRight = [centeredRect(3) centeredRect(4)]';

    % Make the matrices we need for the corner dots
    cornerCoords = [topLeft bottomRight];
    cornerColors = [topLeftColor' bottomRightColor'];

    % Draw the rect to the screen
    Screen('FillRect', window, grey, centeredRect);

    % Draw the appropriate ring of the corner is clicked
    if drawTopLeftRing == 1
        Screen('DrawDots', window, topLeft', cornerDim * 1.2, white, [], 2);
    end

    if drawBottomRightRing == 1
        Screen('DrawDots', window, bottomRight', cornerDim * 1.2, white, [], 2);
    end

    % Draw the position of the active corners
    Screen('DrawDots', window, cornerCoords, cornerDim, cornerColors, [], 2);

    % Draw a white dot where the mouse cursor is
    Screen('DrawDots', window, [mx my], 10, white, [], 2);

    % Flip to the screen
    vbl  = Screen('Flip', window, vbl + (waitframes - 0.5) * ifi);

end

% Clear the screen
sca;


% Simple function to calculate 2D euclidean distance
function dist = EuclidDist(p1, p2)

    dist = sqrt(sum((p1 - p2).^2));

end