Code covered by the BSD License  

Highlights from
Yet Another Calendar

image thumbnail
from Yet Another Calendar by Thomas Montagnon
A new calendar date picker using nested functions

uical(sDate,lang)
function res = uical(sDate,lang)
% UICAL - Calendar date picker
%
%   Version : 1.1
%   Created : 10/08/2007
%   Modified: 14/08/2007
%   Author  : Thomas Montagnon (The MathWorks France)
%
%   RES = UICAL() displays the calendar in English with the today's date
%   selected. RES is the serial date number corresponding to the date the user
%   selected.
%
%   RES = UICAL(SDATE) displays the calendar in English with SDATE date
%   selected. SDATE can be either a serial date number or a 3-elements vector
%   containing year, month and day in this order.
%
%   RES = UICAL(SDATE,LANG) displays the calendar in the language specified by
%   LANG with SDATE date selected.
%   Default available languages are English and French but you can easily add
%   your own by editing the SET_LANGUAGES nested function at the bottom of this
%   file.
%
%   
%   Customization Tips:
%   You can customize the colors of the calendar by editing the "Colors" section
%   at the begining of the main function. See comments there for more details.
%
%
%   Examples:
%
%     myDate = uical()
%
%     myDate = uical(now+7)
%
%     myDate = uical([1980 7 24],'fr')
%
%   See also CALENDAR.
%


% ------------------------------------------------------------------------------
% --- INITIALIZATIONS                                                        ---
% ------------------------------------------------------------------------------

% Colors
figColor     = get(0,'DefaultUicontrolBackgroundColor'); % Figure background color
colorNoDay   = [0.95  0.95  0.95]; % Background color of the cells that are not days of the selected month
colorDayB    = [1.00  1.00  1.00]; % Background color of the cells that are day of the selected month
colorDayF    = [0.00  0.00  0.00]; % Foreground color of the cells that are day of the selected month
colorDayNB   = [0.30  0.30  0.30]; % Background color of the column headers
colorDayNF   = [1.00  1.00  1.00]; % Foreground color of the column headers
colorSelDayB = [0.70  0.00  0.00]; % Background color of the selected day
colorSelDayF = [1.00  1.00  1.00]; % Foreground color of the selected day

% Default input arguments
sDateDef = now;
langDef  = 'en';

% Use default values if input does not exist
switch nargin
  case 0
    sDate = sDateDef;
    lang  = langDef;
  case 1
    lang = langDef;
end

% Check input argument validity
if ~isnumeric(sDate)
  error('MYCAL:DateFormat:WrongClass','First input must be numeric');
end
switch numel(sDate)
  case 1
    sDate = datevec(sDate);
  case 3
    if sDate(1) < 0
      error('MYCAL:DateFormat:WrongYearVal','First element of the first input must be a valid year number');
    end
    if (sDate(2) > 12) && (sDate(2) < 1)
      error('MYCAL:DateFormat:WrongMonthVal','Second element of the first input must be a valid month number');
    end
    if (sDate(3) > 31) && (sDate(3) < 1)
      error('MYCAL:DateFormat:WrongDayVal','Third element of the first input must be a valid day number');
    end
  otherwise
    error('MYCAL:DateFormat:WrongVal','First input must be a numeric scalar or a 3-elements vector');
end
  

% Language dependent strings
set_language(lang);

% Initializes output
res = sDate(1:3);

% Dimensions
dayH   = 24;
dayW   = 30;
ctrlH  = 20;
figH   = 7 * (dayH - 1) + ctrlH;
figW   = 7 * (dayW-1);
ctrlYW = 60;
ctrlMW = 80;
ctrlCW = figW - ctrlYW - ctrlMW;

daysNy = figH - ctrlH - dayH + 1;


% ------------------------------------------------------------------------------
% --- UICONTROL CREATION                                                     ---
% ------------------------------------------------------------------------------


% Create figure
handles.FgCal = figure( ...
  'Visible', 'off', ...
  'Tag', 'FgCal', ...
  'Name', '', ...
  'Units', 'pixels', ...
  'Position', [50 50 figW figH], ...
  'Toolbar', 'none', ...
  'MenuBar', 'none', ...
  'NumberTitle', 'off', ...
  'Color', figColor, ...
  'CloseRequestFcn',@FgCal_CloseRequestFcn,...
  'WindowStyle','modal');

% Move the GUI to the center of the screen
movegui(handles.FgCal,'center')

% Columns Headers containing initials of the week days
for dayNidx=1:7
  
  daysNx = (dayNidx - 1) * (dayW - 1);
  
  handles.EdDayN(dayNidx) = uicontrol( ...
    'Parent', handles.FgCal, ...
    'Tag', 'EdDay', ...
    'Style', 'edit', ...
    'Units', 'pixels', ...
    'Position', [daysNx daysNy dayW dayH], ...
    'ForegroundColor', colorDayNF, ...
    'BackgroundColor', colorDayNB, ...
    'String', daysN{dayNidx}, ...
    'HorizontalAlignment', 'center', ...
    'Enable','inactive');
  
end

% Days UI controls
for dayIdx=1:42
  
  % X and Y Positions
  [i,j] = ind2sub([6,7],dayIdx);
  
  dayX = (j - 1) * (dayW - 1);
  dayY = (dayH - 1) * 6 - i * (dayH - 1);
  
  handles.EdDay(dayIdx) = uicontrol( ...
    'Parent', handles.FgCal, ...
    'Tag', 'EdDay', ...
    'Style', 'edit', ...
    'Units', 'pixels', ...
    'Position', [dayX dayY dayW dayH], ...
    'BackgroundColor', colorDayB, ...
    'ForegroundColor', colorDayF, ...
    'String', '', ...
    'HorizontalAlignment', 'center', ...
    'Enable','inactive');
  
end

% Listbox containing the list of months
handles.PuMonth = uicontrol( ...
  'Parent', handles.FgCal, ...
  'Tag', 'PuMonth', ...
  'Style', 'popupmenu', ...
  'Units', 'pixels', ...
  'Position', [ctrlYW-2 figH-ctrlH+1 ctrlMW+2 ctrlH], ...
  'BackgroundColor', [1 1 1], ...
  'String', monthsN, ...
  'Value', res(2), ...
  'Callback',@set_cal);

% Edit control which enables you to enter a year number
handles.EdYear = uicontrol( ...
  'Parent', handles.FgCal, ...
  'Tag', 'EdYear', ...
  'Style', 'edit', ...
  'Units', 'pixels', ...
  'Position', [0 figH-ctrlH ctrlYW-1 ctrlH+1], ...
  'BackgroundColor', [1 1 1], ...
  'String', res(1), ...
  'Callback',@set_cal);

% Selection button
handles.PbChoose = uicontrol( ...
  'Parent', handles.FgCal, ...
  'Tag', 'PbChoose', ...
  'Style', 'pushbutton', ...
  'Units', 'pixels', ...
  'Position', [ctrlYW+ctrlMW figH-ctrlH+1 ctrlCW ctrlH], ...
  'String', 'OK', ...
  'Callback','uiresume');

% Display calendar for the default date
set_cal();

% Make the calendar visible
set(handles.FgCal,'Visible','on')

% Wait for user action
uiwait(handles.FgCal);

% Convert date to serial date number
res = datenum(res);

% Close the calendar figure
delete(handles.FgCal);


% ------------------------------------------------------------------------------
% --- CALLBACKS                                                              ---
% ------------------------------------------------------------------------------


%-------------------------------------------------------------------------------
  function FgCal_CloseRequestFcn(varargin)
    % Callback executed when the user click on the close button of the figure.
    % This means he wants to cancel date selection so function returns the
    % intial date (the one used when we opened the calendar)
    
    % Set the output to the intial date value
    res = sDate(1:3);
    
    % End execution of the window
    uiresume;
    
  end


%-------------------------------------------------------------------------------
  function EdDay_ButtonDownFcn(varargin)
    % Callback executed when the user click on day.
    % Updates the RES variable containing the currently selected date and then
    % update the calendar.
    
    res(1) = str2double(get(handles.EdYear,'String'));
    res(2) = get(handles.PuMonth,'Value');
    res(3) = str2double(get(varargin{1},'String')); % Number of the selected day
    
    set_cal();
    
  end


%-------------------------------------------------------------------------------
  function set_cal(varargin)
    % Displays the calendar according to the selected date stored in RES

    % Get selected Year and Month
    year   = str2double(get(handles.EdYear,'String'));
    res(2) = get(handles.PuMonth,'value');
    
    % Check Year value (keep previous value if the new one is wrong)
    if ~isnan(year)
      res(1) = abs(round(year)); % ensure year is a positive integer
    end
    set(handles.EdYear,'String',res(1))

    % Get the matrix of the calendar for selected month and year then convert it
    % into a cell array
    c = calendar(res(1),res(2));
    v = mat2cell(c,ones(1,6),ones(1,7));

    % Cell array of indices used to index the vector of handles
    i = mat2cell((1:42)',ones(1,42),1);

    % Set String property for all cells of the calendar
    cellfun(@(i,x) set(handles.EdDay(i),'string',x),i,v(:))

    % Change properties of the "non-day" cells of the calendar
    set(handles.EdDay(c==0), ...
      'ButtonDownFcn'  , '', ...
      'BackgroundColor', colorNoDay, ...
      'string'         , '')
    
    % Change the properties of the calendar's cells containing existing days
    set(handles.EdDay(c~=0), ...
      'ButtonDownFcn'  , @EdDay_ButtonDownFcn, ...
      'BackgroundColor', colorDayB, ...
      'ForegroundColor', colorDayF, ...
      'FontWeight'     ,'normal')

    % Highlight the selected day
    set(handles.EdDay(c==res(3)), ...
      'BackgroundColor', colorSelDayB, ...
      'ForegroundColor', colorSelDayF, ...
      'FontWeight'     ,'bold')
    
    % Update the name of the figure to reflect the selected day
    set(handles.FgCal,'Name',sprintf('%u/%u/%u',fliplr(res)))

    % Give focus to the "OK" button
    uicontrol(handles.PbChoose);
    
  end


%-------------------------------------------------------------------------------
  function set_language(lang)
    % Sets language dependent strings used in the calendar
    % You can add languages by adding cases below.
    
    switch lang
      
      case 'en'
        
        daysN   = {'S','M','T','W','T','F','S'}; % First day is always Sunday
        monthsN = {'January','February','March','April','May','June',...
          'July','August','September','October','November','December'};
        
      case 'fr'
        
        daysN   = {'D','L','M','M','J','V','S'};
        monthsN = {'Janvier','Fvrier','Mars','Avril','Mai','Juin',...
          'Juillet','Aot','Septembre','Octobre','Novembre','Dcembre'};
      
      otherwise
        
        % If language is not recognized then use the English strings
        
        daysN   = {'S','M','T','W','T','F','S'};
        monthsN = {'January','February','March','April','May','June',...
          'July','August','September','October','November','December'};
        
    end
    
  end

end

Contact us at files@mathworks.com