function varargout = tangoplayer(varargin)
%TANGOPLAYER MATLAB code file for tangoplayer.fig
%      TANGOPLAYER, by itself, creates a new TANGOPLAYER or raises the existing
%      singleton*.
%
%      H = TANGOPLAYER returns the handle to a new TANGOPLAYER or the handle to
%      the existing singleton*.
%
%      TANGOPLAYER('Property','Value',...) creates a new TANGOPLAYER using the
%      given property value pairs. Unrecognized properties are passed via
%      varargin to tangoplayer_OpeningFcn.  This calling syntax produces a
%      warning when there is an existing singleton*.
%
%      TANGOPLAYER('CALLBACK') and TANGOPLAYER('CALLBACK',hObject,...) call the
%      local function named CALLBACK in TANGOPLAYER.M with the given input
%      arguments.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help tangoplayer

% Last Modified by GUIDE v2.5 28-Oct-2016 00:06:50

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @tangoplayer_OpeningFcn, ...
                   'gui_OutputFcn',  @tangoplayer_OutputFcn, ...
                   'gui_LayoutFcn',  [], ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
   gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before tangoplayer is made visible.
function tangoplayer_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   unrecognized PropertyName/PropertyValue pairs from the
%            command line (see VARARGIN)

% Choose default command line output for tangoplayer
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes tangoplayer wait for user response (see UIRESUME)
% uiwait(handles.figure1);

% === Begin Custom Code ===
ctm = uicontextmenu;                                    % context menu
topmenu = uimenu('Parent',ctm,'Label','Draw');          % add top menu
uimenu('Parent',topmenu,'Label','Line', ...             % draw line sub menu
    'Callback',@ctm_line_Callback);     
uimenu('Parent',topmenu,'Label','Rectangle', ...        % draw rect sub menu
    'Callback',@ctm_rect_Callback);
uimenu('Parent',topmenu,'Label','Circle', ...           % draw circle sub menu
    'Callback',@ctm_circle_Callback);
handles.ctm = ctm;                                      % add ctm to handles
guidata(hObject,handles)                                % update handles

logo = imread('splash.png');                            % logo image
axes(handles.viewer)                                    % get axes
hImage = imshow(logo);                                  % show image
set(hImage,'uicontextmenu',ctm)                         % add context menu
% === End Custom Code ===

% --- Outputs from this function are returned to the command line.
function varargout = tangoplayer_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on slider movement.
function startSlider_Callback(hObject, eventdata, handles)
% hObject    handle to startSlider (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider

% === Begin Custom Code ===
if ismember('v',fieldnames(handles))                    % if VideoReader object exists
    v = handles.v;                                      % retrieve it
else                                                    % if not
    set(handles.startBox,'String', ...                  % show warning
        'Video not loaded...');                 
    return;                                             % do nothing else
end
duration =  v.Duration;                                 % get duration
fps = v.FrameRate;                                      % get frame rate
stepSize = 1/(duration*fps);                            % 1 step = 1 frame
set(hObject,'SliderStep',[stepSize, 10*stepSize]);      % slider step sizes 

curVal = get(hObject,'Value');                          % get current value
minVal = get(hObject,'Min');                            % get minimum value
maxVal = get(hObject,'Max');                            % get maximum value
pos = (curVal - minVal)/(maxVal - minVal);              % get slider position
startTime = duration*pos;                               % compute start time
if pos == 1                                             % if last frame
    startTime = startTime - 1/fps;                      % use previous frame
end
set(handles.startBox,'String', ...                      % update box text 
    sprintf('%.4f',startTime));
set(handles.timeBox,'String',sprintf('%.4f',startTime));% update box text

v.CurrentTime = startTime;                              % update current time
f = readFrame(v);                                       % get the frame
axes(handles.viewer)                                    % get axes
hImage = imshow(f);                                     % show the frame
ctm = handles.ctm;                                      % get context menu
set(hImage,'uicontextmenu',ctm)                         % add context menu

handles.t = startTime;                                  % update t
handles.k = floor(startTime * fps);                     % update k
guidata(hObject,handles)                                % update handles
% === End Custom Code ===

% --- Executes during object creation, after setting all properties.
function startSlider_CreateFcn(hObject, eventdata, handles)
% hObject    handle to startSlider (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function speedSlider_Callback(hObject, eventdata, handles)
% hObject    handle to speedSlider (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'Value') returns position of slider
%        get(hObject,'Min') and get(hObject,'Max') to determine range of slider

% === Begin Custom Code ===
set(handles.speedBox,'String','1/1');                   % reset box text
set(hObject,'SliderStep',[0.1, 0.2]);                   % slider step sizes
curVal = get(hObject,'Value');                          % get current value
curVal = ceil(curVal*10);                               % first decial as integer
if curVal == 0                                          % if zero
    curVal = 1;                                         % change to 1
    set(hObject,'Value',curVal/10);                     % adjust slider
end

set(handles.speedBox,'String',['1/' num2str(curVal)]);  % update box text
% === End Custom Code ===

% --- Executes during object creation, after setting all properties.
function speedSlider_CreateFcn(hObject, eventdata, handles)
% hObject    handle to speedSlider (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: slider controls usually have a light gray background.
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on button press in playBtn.
function playBtn_Callback(hObject, eventdata, handles)
% hObject    handle to playBtn (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of playBtn

% === Begin Custom Code ===
if ismember('v',fieldnames(handles))                    % if VideoReader object exists
    v = handles.v;                                      % retrieve it
    s = handles.s;                                      % get frames
    set(handles.startSlider,'Enable','off');            % disable Start Time slider
    set(handles.startBox,'Enable','off');               % disable Start Time edit box
else
    set(handles.filenameBox,'String','File not chosen') % show warning
    return                                              % do nothing else
end

fps = v.FrameRate;                                      % get frame rate
speed =  str2num(get(handles.speedBox,'String'));       % get speed
startTime = handles.t;                                  % get start time
startFrame = handles.k;                                 % get start frame

if startFrame == 0                                      % if invalid frame
    if startTime == 0                                   % if start at beginning
        startFrame = 1;                                 % set to the first frame
    else
        startFrame = floor(startTime * fps);            % compute starting frame
    end
end

% ***  Begin Reuse Example Code ***
set(handles.timeBox,'String',sprintf('%.4f',startTime)) % update box text
hImage = imshow(s(startFrame).cdata, ...                % create hande and
    'Parent',handles.viewer);                           % show the first frame
ctm = handles.ctm;                                      % get context menu
set(hImage,'uicontextmenu',ctm)                         % add context menu

for k = startFrame + 1:length(s)                        % for each remaining frame
    if get(hObject,'Value')                             % if button is down
        set(hImage,'CData',s(k).cdata);                 % update underlying data
        pause(1/(fps*speed));                           % pause for specified speed
    % ***  End Reuse Example Code ***
    
        set(hObject,'String','Pause');                  % change to "pause"
        t = k/fps;                                      % current time
        set(handles.timeBox,'String',sprintf('%.4f',t)) % update box text
        handles.t = t;                                  % update t
        handles.k = k;                                  % update k
        guidata(hObject,handles)                        % update handles
    else                                                % if button is up
        break                                           % break the loop
    end
end

set(hObject,'String','Play');                           % change to "play"
set(hObject,'Value',false);                             % make button up

if k == length(s)                                       % if loop finished
    handles.fin = true;                                 % update fin
    guidata(hObject,handles)                            % update handles
end

if handles.fin                                          % if loop finished
    handles.k = startFrame;                             % reset k
else                                                    % if not
    t = handles.t;                                      % get current time
    set(handles.startBox,'String',sprintf('%.4f',t))    % update start time
end

set(handles.startSlider,'Enable','on');                 % enable Start Time slider
set(handles.startBox,'Enable','on');                    % enable Start Time edit box
handles.fin = false;                                    % reset fin
guidata(hObject,handles)                                % update handles
% === End Custom Code ===

function timeBox_Callback(hObject, eventdata, handles)
% hObject    handle to timeBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of timeBox as text
%        str2double(get(hObject,'String')) returns contents of timeBox as a double

% --- Executes during object creation, after setting all properties.
function timeBox_CreateFcn(hObject, eventdata, handles)
% hObject    handle to timeBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function startBox_Callback(hObject, eventdata, handles)
% hObject    handle to startBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of startBox as text
%        str2double(get(hObject,'String')) returns contents of startBox as a double

% === Begin Custom Code ===
if ismember('v',fieldnames(handles))                    % if VideoReader Object exists
    v = handles.v;                                      % retrieve it
else                                                    % if not
    set(handles.startBox,'String', ...                  % show warning
        'Video not loaded...');   
    return;                                             % do nothing else
end

duration =  v.Duration;                                 % get duration
fps = v.FrameRate;                                      % get frame rate
startTime = str2double(get(hObject,'String'));          % get box text
if startTime >= duration                                % if wrong start time
    startTime = 0;                                      % set to zero
    set(hObject,'String',sprintf('%.4f',startTime));    % update box text
end
set(handles.timeBox,'String',sprintf('%.4f',startTime));% update box text

v.CurrentTime = startTime;                              % update current time
f = readFrame(v);                                       % get the frame
axes(handles.viewer)                                    % get axes
hImage = imshow(f);                                     % show the frame
ctm = handles.ctm;                                      % get context menu
set(hImage,'uicontextmenu',ctm)                         % add context menu

handles.t = startTime;                                  % update t
handles.k = floor(startTime * fps);                     % update k
guidata(hObject,handles)                                % update handles
% === End Custom Code ===

% --- Executes during object creation, after setting all properties.
function startBox_CreateFcn(hObject, eventdata, handles)
% hObject    handle to startBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function speedBox_Callback(hObject, eventdata, handles)
% hObject    handle to speedBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of speedBox as text
%        str2double(get(hObject,'String')) returns contents of speedBox as a double

% === Begin Custom Code ===
speed = str2num(get(hObject,'String'));                 % text in the box 
if speed > 1                                            % if more than 1
    set(hObject,'String','1/1');                        % update the box
end
% === End Custom Code ===

% --- Executes during object creation, after setting all properties.
function speedBox_CreateFcn(hObject, eventdata, handles)
% hObject    handle to speedBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

function filenameBox_Callback(hObject, eventdata, handles)
% hObject    handle to filenameBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of filenameBox as text
%        str2double(get(hObject,'String')) returns contents of filenameBox as a double

% --- Executes during object creation, after setting all properties.
function filenameBox_CreateFcn(hObject, eventdata, handles)
% hObject    handle to filenameBox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in chooseBtn.
function chooseBtn_Callback(hObject, eventdata, handles)
% hObject    handle to chooseBtn (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% === Begin Custom Code ===
msg = 'Choose your video file...';                      % dialog message
[filename, pathname] = uigetfile( ...                   % open file selection dialog
{'*.mov;*.mp4;','Video Files (*.mov,*.mp4,)';           % show .mov or .mp4 files
   '*.*',  'All Files (*.*)'},msg);                     % or all files
boxtext = get(handles.filenameBox,'String');            % text in filename box
if ~ischar(filename) && ...                             % if dialog was canceled
        isempty(strfind(boxtext,'.mp4'))                % and no filename
    set(handles.filenameBox,'String','File not chosen');% update filenameBox
    return                                              % do nothing else
end
if ~ischar(filename) && ...                             % if dialog was canceled
        ~isempty(strfind(boxtext,'.mp4')) && ...        % but has filename
        ismember('v',fieldnames(handles))               % and videoReader object
    return                                              % do nothing else
end

filename = [pathname filename];                         % get full file path
set(handles.filenameBox,'String',filename);             % update filenameBox
    
if ismember('orient',fieldnames(handles))               % if rotate set
    rotate = handles.orient;                            % get its value
else                                                    % if not
    rotate = 0;                                         % set to zero
end

% ***  Begin Reuse Example Code ***
wb = waitbar(0,'Loading the file...');                  % show progress bar
v = VideoReader(filename);                              % create VideoReader object
w = v.Width;                                            % get width 
h = v.Height;                                           % get height
d = v.Duration;                                         % get duration
s = struct('cdata',zeros(h,w,3,'uint8'),'colormap',[]); % struct to hold frames
k = 1;                                                  % initialize counter
while hasFrame(v)                                       % while object has frame
    if rotate == 0                                      % if no rotation
        s(k).cdata = readFrame(v);                      % read the frame
    else                                                % otherwise
        f = readFrame(v);                               % get the frame
        s(k).cdata = imrotate(f,rotate);                % rotate it
    end
    k = k + 1;                                          % increment counter
    waitbar(v.CurrentTime/d)                            % update progress bar
end
v.CurrentTime = 0;                                      % back to the beginning
f = readFrame(v);                                       % get the frame
close(wb)                                               % close progress bar
axes(handles.viewer)                                    % get axes
hImage = imshow(imrotate(f,rotate));                    % show the frame
% ***  End Reuse Example Code ***

ctm = handles.ctm;                                      % get context menu
set(hImage,'uicontextmenu',ctm)                         % add context menu
set(handles.startBox,'String',sprintf('%.4f',0));       % update startbox

% share the loaded data across the GUI app with handles
handles.v = v;                                          % add v to handles
handles.s = s;                                          % add s to handles
handles.t = 0;                                          % add t to handles
handles.k = 0;                                          % add k to handle
handles.fin = false;                                    % add fin to handle
guidata(hObject,handles)                                % update handles
% === End Custom Code ===

% --------------------------------------------------------------------
function ctm_line_Callback(hObject, eventdata, handles)
% hObject    handle to ctm_line (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
imline;                                                 % add line

% --------------------------------------------------------------------
function ctm_rect_Callback(hObject, eventdata, handles)
% hObject    handle to ctm_rect (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
imrect;                                                 % add rectagnle

% --------------------------------------------------------------------
function ctm_circle_Callback(hObject, eventdata, handles)
% hObject    handle to ctm_circle (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
imellipse;                                              % add ellipse

% --- Executes when user attempts to close tangoplayer.
function tangoplayer_CloseRequestFcn(hObject, eventdata, handles)
% hObject    handle to tangoplayer (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: delete(hObject) closes the figure
if get(handles.playBtn,'Value')                         % if button is down
    errordlg('Pause the video before closing the window')  % show error message
else
    delete(hObject)
end


% --- Executes on selection change in rotateMenu.
function rotateMenu_Callback(hObject, eventdata, handles)
% hObject    handle to rotateMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns rotateMenu contents as cell array
%        contents{get(hObject,'Value')} returns selected item from rotateMenu
 switch get(hObject,'Value')                            % get selected value
     case 1                                             % 0 degree
         handles.orient = 0;                            % rotate = 0
     case 2                                             % 90 degrees
         handles.orient = 90;                           % rotate = 90
     case 3                                             % 180 degrees
         handles.orient = 180;                          % rotate = 180
     case 4                                             % 270 degrees
         handles.orient = 270;                          % rotate = 270
 end
 guidata(hObject,handles)                                % update handles

% --- Executes during object creation, after setting all properties.
function rotateMenu_CreateFcn(hObject, eventdata, handles)
% hObject    handle to rotateMenu (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
