function y = dsp_cgpref(action)
% DSP_CGPREF DSP Blockset code generation preference editor.
%
% See also DSPBLKS, RTW.

% Author: D. Orofino
% Copyright 1995-2000 The MathWorks, Inc.
% $Revision: 1.7 $ $Date: 2000/05/05 20:16:22 $

% xxx To do:
%   - implement param value serialization
%   - implement "fixup" to remove CR's from function declarations
%     when they are "short enough"
%   - Check for duplicates when new entries added
%      (both s-fcn and attribs)
%   - Find/search facility on Block Name and S-Fcn
%   - Provide sorting option for S-Fcn list (by Block Name)

if nargin<1,
   action='init';
end

switch action
case 'init'
   Init;
   
case 'SFcnListCB'
   SFcnListCB;
case 'InlinePopupCB'
   InlinePopupCB;
case 'AttribListCB'
   AttribListCB;
case 'AttribOnCB'
   AttribOnOffCB('on');
case 'AttribOffCB'
   AttribOnOffCB('off');
   
case 'OpenFileCB'
   OpenFileCB;
case 'SaveDataCB'
   SaveDataCB;
case 'SaveAsCB'
   SaveAsCB;
case 'SaveDataIfOpen'
   SaveDataIfOpen;
case 'QuitGUICB'
   QuitGUICB;
   
case 'HelpTopicsCB'
   HelpTopicsCB;
case 'HelpWhatsThisBDown'
   HelpWhatsThisBDown;
case 'HelpWhatsThisCB'
   HelpWhatsThisCB;
case 'HelpGeneral'
   HelpGeneral;
   
case 'AdvMenuOptCB'
   AdvMenuOptCB;
   
case 'AdvSFcnDnCB'
   AdvSFcnUpDnCB('dn');
case 'AdvSFcnUpCB'
   AdvSFcnUpDnCB('up');
case 'AdvSFcnAddCB'
   AdvSFcnAddCB;
case 'AdvSFcnDeleteCB'
   AdvSFcnDeleteCB;
case 'AdvSFcnEditCB'
   AdvSFcnAllCB('SFcnName');
case 'AdvBlockNameEditCB'
   AdvSFcnAllCB('BlkName');
   
case 'AdvAttribUpCB'
   AdvAttribUpDnCB('up');
case 'AdvAttribDnCB'
   AdvAttribUpDnCB('dn');
case 'AdvAttribAddCB'
   AdvAttribAddCB;
case 'AdvAttribDeleteCB'
   AdvAttribDeleteCB;
case 'AdvAttribInfoCB'
   AdvAttribAllCB('Info');
case 'AdvAttribParamCB'
   AdvAttribAllCB('Param');
case 'AdvAttribDTypeCB'
   AdvAttribAllCB('DType');   

otherwise
   warning(['Unrecognized action: ' action]);
end

return


% --------------------------------------------------------------
function Init
% INIT Create GUI and initialize with user preferences.

% Only allow one instance of the GUI to run at a time:
hfig = FindOpenGUI;
if ~isempty(hfig),
   figure(hfig);  % bring existing GUI window forward
   return;
end

% Setup basic GUI data:
%
% Set "fixed" number of port-properties for attributes list:
ud.numPortProps = 4;            % xxx hard coded number of port props
ud.handles  = CreateBasicGUI;   % creates invisible GUI
ud.dirty    = 0;                % GUI is not dirty yet
ud.prefs    = [];               % for now...
ud.fileName = 'dsp_cgopts.mat';
hfig = ud.handles.fig;
set(hfig,'UserData',ud);        % Store data into figure

% Open default data file:
LoadFile(hfig,ud.fileName);

return

% --------------------------------------------------------------
function SaveDataIfOpen
% SaveDataIfOpen Save data in GUI if it is open.
%    This is called by the code-gen system, in order to "flush"
%    any unsaved changes to disk before proceeding.

% If GUI found, save data:
hfig = FindOpenGUI;
if ~isempty(hfig),
   SaveData(hfig);
end
return

% --------------------------------------------------------------
function SaveAs(hfig)
% SaveAs

ud = get(hfig,'UserData');
[f,p] = uiputfile('*.mat', 'Save Preference File');

if f==0,
   return % cancel
end

ud.fileName = [p f];
[p,f,x] = fileparts(ud.fileName);
if isempty(x),
   ud.fileName = [ud.fileName '.mat'];
end
set(hfig,'UserData',ud);

SaveData(hfig);


% --------------------------------------------------------------
function OpenFile(hfig)
% OpenFile Load data file

ud = get(hfig,'UserData');
if ud.dirty,
   % Give user opportunity to cancel or save:
   buttonName = questdlg(['Save changes to ' ud.fileName '?'], ...
      'Open Preference File', 'Yes','No','Cancel','Cancel');
   switch buttonName
   case 'Yes'
      SaveData(hfig);
   case 'No'
      % Do nothing
   otherwise  % Cancel
      return
   end
end

% Select new file name:
[f,p] = uigetfile('*.mat','Load Preference File');
if f==0,
   return   % cancel button was hit
end
fileName = [p f];
LoadFile(hfig, fileName);


% --------------------------------------------------------------
function LoadFile(hfig, fileName)

% Load preferences file:
[prefs,errMsg] = LoadUserPrefs(fileName);

ud = get(hfig,'UserData');
ud.prefs = prefs;
ud.dirty = 0;  % GUI is not dirty
set(hfig,'UserData',ud);  % Store data into figure

% Reset selected S-Fcn:
SetSFcnSetting(hfig,1);

if isempty(errMsg),
   % Update filename:
   ud.fileName = fileName;
   set(hfig,'UserData',ud);
end

UpdateGUI(hfig);
set(hfig,'vis','on');  % Show GUI to user

if ~isempty(errMsg),
   ErrorGUI(errMsg);
end


% --------------------------------------------------------------
function SaveData(hfig)
% SaveData Save current options in data file
%  regardless of dirty state

% Save the data
ud = get(hfig,'UserData');
opts = ud.prefs;

% Protect the save function from read-only files, etc:
try
   save(ud.fileName,'opts');
catch
   % Save failed
   ErrorGUI(lasterr);
   return;
end

% Reset dirty status of GUI
ud.dirty = 0;
set(hfig,'UserData',ud);

% Update title bar and save-controls to indicate dirty status
UpdateGUIName(hfig);

return

% --------------------------------------------------------------
function SaveAsCB
% SaveAsCB Save As callback

SaveAs(gcbf);
return

% --------------------------------------------------------------
function OpenFileCB
% OpenFileCB Load datafile callback

OpenFile(gcbf);
return


% --------------------------------------------------------------
function SaveDataCB
% SaveCB Save datafile callback

SaveData(gcbf);
return


% --------------------------------------------------------------
function QuitGUICB
% QuitGUICB Quit GUI callback function.

ExitGUI(gcbf);
return


% --------------------------------------------------------------
function ExitGUI(hfig)
% QuitGUI Quit the GUI.
%   Double-check if GUI is dirty.

% Remove delete fcn, or we'll get a double-callback
props = {'DeleteFcn','CloseRequestFcn'};
origFcns = get(hfig,props);
set(hfig,props,{'',''});

ud = get(hfig,'UserData');
if ud.dirty,
   fileName = 'dsp_cgopts';
   buttonName = questdlg(['Save changes to ' fileName '?'], ...
      'Save Preferences','Yes','No','Cancel','Save & Quit');
   
   switch buttonName
   case 'Yes'
      SaveData(hfig);
   case 'No'
      % Do nothing
   otherwise  % Cancel
      % Restore delete/close fcns:
      set(hfig,props,origFcns);
      return
   end
end

delete(hfig);
return


% --------------------------------------------------------------
function err = CheckPrefsStruct(s)
% CheckPrefsStruct Returns an empty string if preference
%   structure is valid, or an error msg otherwise.

% Check for required fields:
prefs = s.opts;
errMsg = 'Invalid user preference file.';
err = '';

if ~isfield(s,'opts'),
   err = errMsg;
   return
end
prefs = s.opts;
fields = {'Inline','SFcnName','BlkName','Options'};
for i=1:length(fields),
   if ~isfield(prefs, fields{i}),
      err = errMsg;
      return;
   end
end


% --------------------------------------------------------------
function [prefs,errMsg] = LoadUserPrefs(fileName)
% LoadUserPrefs Load user preferences from MAT file

prefs = [];
errMsg = '';

% Load preference file:
if ~exist(fileName,'file'),
   errMsg = 'File not found.';
   return;
end
s = load(fileName);
errMsg = CheckPrefsStruct(s);
if isempty(errMsg),
   prefs = s.opts;
end

return

% --------------------------------------------------------------
function hfig = FindOpenGUI
% FingOpenGUI
%
% Check if an instance of the preference editor GUI is already open.
% If another instance is found, return figure handle.
% If it is not, return empty.

% Find open GUI:
prop = 'ShowHiddenHandles';
oldState = get(0,prop); set(0,prop,'on');
hfig = findobj('type','figure','tag',mfilename);
set(0,prop,oldState);

return


% --------------------------------------------------------------
function err = ErrorGUI(msg)
% ErrorGUI Create standard modal error dialog
%          and return an error status.

warndlg(msg, ...
   'Code Generation Preference Editor','modal');
err=1;  % Non-zero error status


% --------------------------------------------------------------
function UpdateInlinePanel(hfig)
% UpdateInlinePanel Update the Inline popup.

% Update inline popup
ud = get(hfig,'UserData');
hPop = ud.handles.InlinePopup;

% Determine which s-fcn we're examining:
sfcnIdx = GetSFcnSetting(hfig);

if sfcnIdx == 0,
   % No s-fcns in database
   set(hPop,'value',1,'enable','off');
   
else
   
   % Update inline popup accordingly:
   inlinePref = ud.prefs(sfcnIdx).Inline;
   allPopups = get(hPop,'string');
   idx = strmatch(inlinePref,allPopups,'exact');
   
   % Update value cache to be the same as the current value
   ud.lastInlinePopupIdx = idx;
   set(hfig,'UserData',ud);
   
   % Check for invalid setting:
   if isempty(idx),
      err = ['Invalid setting for inline parameter in database: ' inlinePref];
      ErrorGUI(err);
      return;
   end
   set(hPop,'value',idx,'enable','on');
end

return


% --------------------------------------------------------------
function InlinePopupCB
% InlinePopupCB Inline popup control callback.

hfig = gcbf;

% If the current inline-popup selection was clicked on again, do nothing:
if ~InlinePopupNewSelection(hfig),
   return;
end

ud = get(hfig,'UserData');

% Get current popup string
hPop = ud.handles.InlinePopup;
newIdx = get(hPop,'value');
allStrs = get(hPop,'string');
newStr = deblank(allStrs(newIdx,:));

% Determine which s-fcn we're changing:
sfcnIdx = GetSFcnSetting(hfig);

% Update preference for this s-fcn and store prefs:
ud.prefs(sfcnIdx).Inline = newStr;
set(hfig,'UserData',ud);  % Update userdata

SettingsChanged(hfig);  % Mark dirty status of GUI
EnableAttribs(hfig);  % enable/disable inline panel

return


% --------------------------------------------------------------
function hasChanged = InlinePopupNewSelection(hfig)
% InlineNewSelection Returns true if current Inline Popup
%   selection differs from the last recorded selection.  If so,
%   updates last recorded selection to be the current selection.

% Create cache of last selection value, if needed:
ud = get(hfig,'UserData');

% Test if selection has changed
hPop = ud.handles.InlinePopup;
inlineIdx = get(hPop,'value');
hasChanged = (inlineIdx ~= ud.lastInlinePopupIdx);
if hasChanged,
   % Update last selection cache:
   ud.lastInlinePopupIdx = inlineIdx;
   set(hfig,'UserData',ud);
end
return


% --------------------------------------------------------------
function SFcnListCB
% SFcnListCB S-Function listbox item callback.
%   Update the attributes and inline panels.

hfig = gcbf;

% If the current s-fcn was clicked on again, do nothing:
if ~SFcnNewSelection(hfig),
   return;
end

UpdateAdvPanel(hfig);
UpdateInlinePanel(hfig);
UpdateAttribPanel(hfig, 'first');

return

% --------------------------------------------------------------
function hasChanged = SFcnNewSelection(hfig)
% SFcnNewSelection Returns true if current S-function list
%   selection differs from the last recorded selection.  If so,
%   updates last recorded selection to be the current selection.

% Create cache of last selection value, if needed:
ud = get(hfig,'UserData');

% Test if selection has changed
sfcnIdx = GetSFcnSetting(hfig);
hasChanged = (sfcnIdx ~= ud.lastSFcnIdx);
if hasChanged,
   % Update last selection cache:
   ud.lastSFcnIdx = sfcnIdx;
   set(hfig,'UserData',ud);
end
return


% --------------------------------------------------------------
function h = AttribListCB
% AttribListCB Attribute listbox item callback.
%   Toggle the current setting if a double-click occurred.

hfig = gcbf;
% If double-click, toggle state:
selectionType = get(hfig,'SelectionType');
if strcmp(selectionType, 'open'),
   changeAttribState(hfig,'toggle');
end

UpdateAdvAttribPanel(hfig);

return

% --------------------------------------------------------------
function attribIdx = GetAttribSelectionIdx(hfig)
% GetAttribSelectionIdx Get index of currently selected attribute
%
% NOTE: This is not the "graphical" row of the listbox,
% but the database index of the corresponding listbox attribute.
% If the currently selected row is a blank line, a demarcation, etc.,
% the option index is set to empty.

% Could be a vector if multiple selections
ud = get(hfig,'UserData');
v = get(ud.handles.AttribList,'value');
s = get(ud.handles.AttribList,'string');

% account for first port-prop string, plus
% blank separator line plus block param string

attribIdx = []; % preset to invalid state

for j=1:length(v),
   i = v(j);
   if (i>1) & (i<=ud.numPortProps+1),
      % In port props
      attribIdx(end+1) = i-1;
   elseif (i > ud.numPortProps+3),   %% hard coded number 4
      % In block params
      attribIdx(end+1) = i-3;        %% hard coded number 4
   else
      % Invalid index - remove from list
   end
end

return


% --------------------------------------------------------------
function allOptions = GetAttribSettings(hfig)
% GetAttribSettings Return the attribute settings as a vector,
%  and the index of the currently selected option.

ud = get(hfig,'UserData');
hAttrib = ud.handles.AttribList;

% Get state from listbox attribute string
% and convert to a string matrix:\
listStr = char(get(hAttrib,'string'));

% If the list only contains "title" lines, skip:
if size(listStr,1)>3,
   listStr([1 (2:3)+ud.numPortProps ],:)='';
   
   % Determine status of all options (on=1, off=0)
   % 2nd char of each listbox string is the status,
   %   and is either a space or an "X"
   allOptions = ~isspace(listStr(:,2));
else
   allOptions = [];
end

return


% --------------------------------------------------------------
function SetAttribSettings(hfig, allOptions)
% SetAttribSettings Set all attribute settings ("X" and " ")
%   in the list from the vector allOptions.

ud = get(hfig,'UserData');
hAttrib = ud.handles.AttribList;

% Get state from listbox attribute string
% and convert to a string matrix:\
listStr = char(get(hAttrib,'string'));

% Convert status of each option to a space or X, as appropriate:
strs = [' ';'X'];
newStatus = strs(allOptions+1);

% Put this into the listbox text.
% 2nd char of each listbox string is the status,
%   and is either a space or an "X"
listStr(2:ud.numPortProps+1,  2) = newStatus(1:ud.numPortProps);
listStr(ud.numPortProps+4:end,2) = newStatus(ud.numPortProps+1:end);

set(hAttrib,'string',listStr);

return


% --------------------------------------------------------------
function AttribOnOffCB(state)
% AttribOnCB Attribute On/Off pushbutton callback

changeAttribState(gcbf,state);
return


% --------------------------------------------------------------
function changeAttribState(hfig,method)
% changeAttribState Change the value of the current
%   attribute field in the list box.
%
% method is one of the following strings:
%   'toggle' = toggle the current value in the list box (only one)
%   'on'     = turn on current attrib (could be multiple)
%   'off'    = turn off current attrib (could be multiple)

% Get current selection
attribIdx = GetAttribSelectionIdx(hfig);
if isempty(attribIdx), return; end

% Determine status of all options (on=1, off=0)
allOptions = GetAttribSettings(hfig);

% Empty list?
if isempty(allOptions), return; end

oldVal = allOptions(attribIdx);
numSel = length(attribIdx);
multipleSel = (numSel>1);

switch method
case 'off'
   newVal = zeros(size(oldVal));
case 'on'
   newVal = ones(size(oldVal));
case 'toggle'
   newVal = 1-oldVal;
otherwise
   ErrorGUI('Invalid method string passed.');   
end

% If no changes were actually made, leave:
if isequal(oldVal, newVal),
   return;
end

allOptions(attribIdx) = newVal;
SetAttribSettings(hfig, allOptions);

% Update ud.prefs database entries.
% NOTE: Need this to work for multiple selections
%
ud = get(hfig,'UserData');
sfcnIdx = GetSFcnSetting(hfig);
for i=1:length(attribIdx),
   ud.prefs(sfcnIdx).Options(attribIdx(i)).value = newVal(i);
end
set(hfig,'UserData',ud);  % Update userdata

SettingsChanged(hfig);  % Mark dirty status of GUI

return


% --------------------------------------------------------------
function SettingsChanged(hfig)
% SettingsChanged Update GUI to reflect "dirty" status of GUI
%   - Update title bar to indicate dirty status
%   - Enable File->Save menu

ud = get(hfig,'UserData');
ud.dirty = 1;
set(hfig,'UserData',ud);

% Update title bar to indicate dirty status
UpdateGUIName(hfig);

return


% --------------------------------------------------------------
function UpdateGUIName(hfig)
% UpdateGUIName

ud = get(hfig,'UserData');
mainName = 'Code Generation Preference Editor';

% Get filename without extension:
[p,f,x] = fileparts(ud.fileName);
fileName = [f x];
if ~isempty(p) & ~strcmp(lower(pwd),lower(p)),
   fileName = [p filesep fileName];
end

if ud.dirty,
   dirtyChar = ' *';
   enaDirty = 'on';
else
   dirtyChar = '';
   enaDirty = 'off';
end

% Update GUI name:
fullName = [mainName ' - [' fileName dirtyChar ']'];
set(hfig, 'name',fullName);

% Update save button enable state, but not the menu item:
set(ud.handles.SaveButton,'enable',enaDirty);

return


% --------------------------------------------------------------
function h = UpdateGUI(hfig)
% UpdateGUI  Update GUI fields with preference data

UpdateGUIName(hfig);
UpdateSFcnList(hfig);
UpdateInlinePanel(hfig);
UpdateAttribPanel(hfig,'first');  % must come after inline panel
UpdateAdvPanel(hfig);

return


% --------------------------------------------------------------
function h = UpdateSFcnList(hfig)
% UpdateSFcnList Update the S-Function/Block name list box

ud = get(hfig,'UserData');
prefs = ud.prefs;
sfcnList = CreateSFcnList(prefs);
selectIdx = get(ud.handles.SFcnList,'value');

set(ud.handles.SFcnList, ...
   'string', sfcnList, ...
   'value', selectIdx);

% Initialize the "last listbox value" cache, so we know when
% the user has really made a change:
%
% Note that this will re-initialize to "selectIdx" every time
% this function is called ... we want this behavior:
ud.lastSFcnIdx = selectIdx;
set(hfig,'UserData',ud);

if isempty(sfcnList),
   % Disable sfcn edit boxes
   ena='off';
else
   ena='on';
end
set([ud.handles.Adv.SFcnName ud.handles.Adv.BlkName],'Enable',ena);

return


% --------------------------------------------------------------
function sfcnList = CreateSFcnList(prefs)
% CreateSFcnList Create a new S-function/Block name listbox string
%    based on the current user preferences.  The text is returned
%    as a cell-array of strings, one entry per row in the list box.

% Spec of each text line for listbox:
%   First 11 chars = S-function name
%   One space
%   Rest of line = Block name

sfcnList = {};
for i=1:length(prefs),
   % Get SFcnName, and pad/truncate to 11 chars
   sfcn = prefs(i).SFcnName;
   sfcnLen = length(sfcn);
   if sfcnLen>11,
      sfcn = sfcn(1:11);
   elseif sfcnLen<11,
      sfcn = [sfcn ones(1,11-sfcnLen).*' '];
   end
   % Append Block name
   blk = prefs(i).BlkName;
   sfcnList{i} = [sfcn ' ' blk];
end
return


% --------------------------------------------------------------
function h = UpdateAttribPanel(hfig,selIdxMode)
% UpdateAttribPanel Update the entire Attrib "panel".
%   This include the Attributes list box,
%   the listbox selection, and the attrib toggle button.
%
% selIdxMode determines the listbox entry to highlight:
%   'first'
%   'last'
%   'maintain'
%   'prev'
%   'next'

ud = get(hfig,'UserData');
prefs = ud.prefs;

% If this list is same as present list, do not
% change value (and thereby change attrib selection):
newAttribList = CreateAttribList(hfig, prefs);
oldAttribList = get(ud.handles.AttribList,'string');
newLast       = length(newAttribList);
currVal       = get(ud.handles.AttribList,'value');

switch selIdxMode
case 'first'
   value = 2;  % first "actual" attrib list entry
case 'last'
   value = newLast;
case 'prev'
   value = currVal-1;
case 'next'
   value = currVal+1;   
case 'maintain'
   % Don't allow value to exceed new limit.
   % We may have just deleted the last entry from the
   % database, but we haven't yet updated the list box
   value = min(currVal, newLast);
end

% Ignore any row/col differences, but update
%   if any other changes are found:
%if ~isequal(oldAttribList(:), newAttribList(:)),
   set(ud.handles.AttribList, ...
      'string', newAttribList, ...
      'value',value);
%end

% Don't move into conditional --- value selection could have
% changes, and thus the enable-states of many options.
EnableAttribs(hfig);
UpdateAdvAttribPanel(hfig);

return


% --------------------------------------------------------------
function attribList = CreateAttribList(hfig, prefs)
% CreateAttribList Create a new Attrib listbox string based on the
%    current user preferences, and the currently selected s-function.
%    The text is returned as a cell-array of strings, one entry per
%    row in the list box.

% Spec of each text line for listbox:
%   First  chars = "[ ]"
%   One space
%   Rest of line = name of attribute

% Get currently selected s-function
sfcnIdx = GetSFcnSetting(hfig);
attribList = {};

if sfcnIdx == 0,
   prefInfo = {};
   prefValues = {};
else
   prefInfo   = {prefs(sfcnIdx).Options.info};
   prefValues = {prefs(sfcnIdx).Options.value};
end

ud = get(hfig,'UserData');
local_numPortProps = ud.numPortProps;

if sfcnIdx == 0,
   local_numPortProps=0;  % no sfcns, then no port props!
end
numBlockParams = max(0, length(prefValues) - local_numPortProps);

j = 0;

% Port properties:
%
attribList{end+1} = '    --- Port Properties  ---';
for i=1:local_numPortProps,
   j=j+1;
   check='[ ] ';
   if prefValues{j}, check(2)='X'; end
   attribList{end+1} = [check prefInfo{j}];
end

% Block parameters:
%
attribList{end+1} = '    ';
attribList{end+1} = '    --- Block Parameters ---';
for i=1:numBlockParams,
   j=j+1;
   check='[ ] ';
   if prefValues{j}, check(2)='X'; end
   attribList{end+1} = [check prefInfo{j}];
end

return


% --------------------------------------------------------------
function EnableAttribs(hfig)
% EnableAttribs Set the enable state of the Attrib list box
%   and associated push buttons, according to the inline popup.

ud = get(hfig,'UserData');
state = get(ud.handles.InlinePopup,'value');
isAlways = (state == 1);
isAdv = isAdvGUIOn(ud.handles.fig);

% Disable attributes (list box & buttons) if the "inline code"
% option is set to "always" (e.g., never make a fcn call).
%
% However, if the Advanced GUI is turned on, allow these to
% still be enabled.
if isAlways & ~isAdv,
   ena = 'off';  % disable attribs
else
   ena = 'on';   % enable attribs
end
set([ud.handles.AttribList ud.handles.ButtonOn ud.handles.ButtonOff], ...
   'enable',ena);

return


% --------------------------------------------------------------
function sfcnIdx = GetSFcnSetting(hfig)
% GetSFcnSettings Return index of currently selected
%    S-Function in listbox.
ud = get(hfig,'UserData');
if isempty(ud.prefs),
   sfcnIdx = 0;
else
   sfcnIdx = get(ud.handles.SFcnList, 'value');
end
return


% --------------------------------------------------------------
function SetSFcnSetting(hfig,newIdx)
ud = get(hfig,'UserData');
set(ud.handles.SFcnList,'value',newIdx);
return


% --------------------------------------------------------------
function HelpWhatsThisBDown
% HelpWhatsThisBDown Button-down function called from the
%   menu-based "What's This?" function

hfig = gcbf;
hOver = overobj('uicontrol');  % handle to object under pointer

% Restore pointer icon quickly:
setptr(hfig,'arrow');

% Shut off button-down functions for uicontrols and the figure:
hChildren = findobj(hfig,'type','uicontrol');
set(hChildren, ...
   'ButtonDownFcn','', ...
   'Enable','on');
set(hfig,'WindowButtonDownFcn','');

% Restore GUI enable states:
UpdateGUI(hfig);

% Dispatch to context help if a uicontrol was selected.
% If it was the figure, bail out (no help):
if strcmp(get(hOver,'type'),'uicontrol'),
   hc = get(hOver,'uicontextmenu');
   hm = get(hc,'children');  % menu pointed to by context menu
   tag = get(hm,'tag');
   HelpGeneral(tag);
end

% --------------------------------------------------------------
function HelpWhatsThisCB
% HelpWhatsThisCB Get "What's This?" help
%   This mimics the context-menu help selection, but allows
%   cursor-selection of the help topic

% NOTE: Enabling context-help "destroys" the enable-state
%  of all uicontrols in the GUI.  When the callback completes,
%  we must restore the enable states.

hfig = gcbf;

% Change pointer icon:
setptr(hfig,'help');

% Install button-down functions on all uicontrols,
%  plus the figure itself:
hChildren = findobj(hfig,'type','uicontrol');
bdfcn = [mfilename '(''HelpWhatsThisBDown'');'];
set(hChildren, ...
   'Enable','inactive', ...
   'ButtonDownFcn',bdfcn);
set(hfig, ...
   'WindowButtonDownFcn',bdfcn);


% --------------------------------------------------------------
function HelpTopicsCB
% HelpTopicsCB Get reference-page help on
%    Code Generation Preferences Editor

web(dspbhelp('CodeGenerationPreferenceEditor'));
return


% --------------------------------------------------------------
function HelpGeneral(tag)
% HelpGeneral

hfig = gcbf;
hco = gcbo;

if nargin<1,
   tag = get(hco,'tag');
end
title = ['Help: ' tag];

switch tag
case 'Function Partition List'
   msg = {'';
      'Function Partitioning options control the number of functions';
      'generated for the selected S-Function.  Turning on a partition-'
      'ing option enables the code generator to create a separate';
      'function for each unique value of the partitioning option';
      'as encountered in the model.';
      '';
      'For example, if the Real/Complex Ports option is turned on,';
      'separate functions are generated for the S-Function.  If the';
      'block is only used with real data in the current model, only';
      'the real-valued version of the function is generated.  If the';
      'option is not turned on, a single version of the function is';
      'generated that handles both real and complex data.'};
case 'Function Partition On/Off'
   msg = {'';
      'Turns on and off selected Function Partition options.';
      'Multiple selections may be altered at one time.'};
case 'S-Function List'
   msg = {'';
      'Code generation parameters are displayed for the';
      'selected S-Function.  Each S-Function in the list is';
      'used in the implementation of one library block in the';
      'DSP Blockset.';
      '';
      'Not every library block in the DSP Blockset is ';
      'implemented using an S-Function, however, so you';
      'wiil not find every library block in the list.'};
case 'Save Button'
   msg = {'';
      'Saves all changes made to the';
      'code-generation preferences.'};
case 'Close Button'
   msg = {'';
      'Closes the code-generation preferences GUI.  If';
      'unsaved changes exist, you will be prompted to';
      'save all changes before closing.'};
   
case 'Add S-Function'
   msg = {'';
      'Add a new S-Function to the code generation';
      'preferences database.'};
case 'Delete S-Function'
   msg = {'';
      'Delete selected S-Function from the code generation';
      'preferences database.';
      '';
      'WARNING: You cannot undo this operation!'};
case 'Move S-Function'
   msg = {'';
      'Move selected S-Function up or down in the';
      'preferences list.'};
   
case 'Modify S-Function Name'
   msg = {'';
      'Modifies the name of the selected S-Function.';
      '';
      'WARNING: The S-Function name in the database must';
      'match the name of the corresponding S-Function in';
      'the Blockset!'};
case 'Modify Block Name'
   msg = {'';
      'Modifies the name of the block corresponding to the';
      'selected S-Function.  This name is used in the above';
      'S-Fcn list as a reference for the user, and is used';
      'as part of the comment placed into the generated code.'};
   
case 'Add Function Partition Option'
   msg = {'';
      'Add a new Function Partition option to the code';
      'generation preferences database.'};
case 'Delete Function Partition Option'
   msg = {'';
      'Delete selected Function Partition option from the';
      'code generation preferences database.';
      '';
      'WARNING: You cannot undo this operation!'};
case 'Move Function Partition Option'
   msg = {'';
      'Move selected Function Partition option up or down';
      'in the preferences list.'};
case 'Modify Function Partition Info'
   msg = {'';
      'Modifies the description of the C-code variable corresponding';
      'to the selected Function Partition option.  This description';
      'is only used in the Preferences GUI as information to the user.'};
case 'Modify Function Partition Param'
   msg = {'';
      'Modifies the name of the C-code variable corresponding';
      'to the selected Function Partition option.  This parameter';
      'name will be used in the generated code.'};
case 'Modify Function Partition DType'
   msg = {'';
      'Modifies the name of the C-code data type corresponding';
      'to the selected Function Partition option.  This data type';
      'will be used in the generated code when declaring this';
      'partition argument.'};
case 'Code Inlining Control'
   % Inline Popup
   % Describe overall behavior
   general = {'';
      'Code for the selected S-Function is either inlined';
      'into the main body of generated code, or replaced';
      'with a function call, according to the setting of';
      'this pop-up control.';
      ''};
   
   % Describe current setting
   ud = get(hfig,'UserData');
   
   % Get current popup string
   hPop = ud.handles.InlinePopup;
   newIdx = get(hPop,'value');
   allStrs = get(hPop,'string');
   newStr = deblank(allStrs(newIdx,:));
   
   switch newStr
   case 'Always'
      msg = {'';
         'Current selection: "Always"';
         'Always inline the code for the selected library block.';
         'No function calls will be generated, even if 2 or more';
         'instances of the selected library block share a common';
         'set of attributes.'};
   case 'Never'
      msg = {'';
         'Current selection: "Never"';
         'Always generate a call to a library function for each';
         'instance of the selected library block.  Multiple';
         'functions may be generated for this block according';
         'to the Function Partition options.'};
   case 'If Unique'
      msg = {'';
         'Current selection: "If Unique"';
         'Inline the code for each instance of the selected library';
         'block that has a unique set of attributes as determined';
         'by the Function Partition options.  If 2 or more instances';
         'share a common set of attributes, a call to a library';
         'function will be generated.'};
   otherwise
      msg = {''
         'Unknown inline-option selected.'};
   end
   msg = cat(1,general,msg);
   
otherwise
   msg = {'';'No help available for selected control.'};
end

% Put up message box for help:
%
hmsg = msgbox(msg,title, 'help','modal');
CenterFigOnFig(hfig, hmsg);


% --------------------------------------------------------------
function CenterFigOnFig(hfig,hmsg)
% CenterFigOnFig Center hMsg figure on top of hFig figure

set(hfig,'units','pix');
figPos = get(hfig,'pos');
figCtr = [figPos(1)+figPos(3)/2 figPos(2)+figPos(4)/2];

set(hmsg,'units','pix');
msgPos = get(hmsg,'position');
msgCtr = [msgPos(1)+msgPos(3)/2 msgPos(2)+msgPos(4)/2];

movePos = figCtr - msgCtr;

new_msgPos = msgPos;
new_msgPos(1:2) = msgPos(1:2) + movePos;
set(hmsg,'Position',new_msgPos);

return


% --------------------------------------------------------------
function AdvMenuOptCB
% AdvMenuOptCB Toggle Advanced GUI status

ShowAdvGUI(gcbf, ~isAdvGUIOn(gcbf));


% --------------------------------------------------------------
function isOn = isAdvGUIOn(hfig)
% isAdvGUIOn Determines if the Advanced GUI is turned on

ud = get(hfig,'UserData');
hAdv = ud.handles.AdvMenu;
isOn = strcmp(get(hAdv,'checked'),'on');


% --------------------------------------------------------------
function ShowAdvGUI(hfig, turnOn)
% ShowAdvGUI
% turnOn: 0=turn off, 1=turn on

ud = get(hfig,'UserData');
h  = ud.handles;

% Update check on "Advanced" menu item:
if turnOn,
   ch='on';
else
   ch='off';
end
set(h.AdvMenu,'checked',ch);

pos = get(hfig,'pos');
YdimOff  = 230;
YdimOn   = 340;
dYdim    = YdimOn-YdimOff;
dY       = 82;

if turnOn,
   % Enlarge GUI
   pos(4) = YdimOn;
   pos(2) = pos(2)-dYdim;
   set(hfig,'pos',pos);
   
   % Move basic GUI elements up
   for i=1:length(h.AllBasic),
      p=get(h.AllBasic(i),'pos');
      p(2) = p(2) + dY;
      set(h.AllBasic(i),'pos',p);
   end
   
   % Make Adv GUI elements visible
   set(h.AllAdv,'vis','on');
   
else
   % Shrink GUI
   pos(4) = YdimOff;
   pos(2) = pos(2)+dYdim;
   set(hfig,'pos',pos);
   
   % Move basic GUI elements down
   for i=1:length(h.AllBasic),
      p = get(h.AllBasic(i),'pos');
      p(2) = p(2) - dY;
      set(h.AllBasic(i),'pos',p);
   end
   
   % Make Adv GUI elements invisible
   set(h.AllAdv,'vis','off');
end

% Update in case attribs enable/disable themselves, etc.
UpdateGUI(h.fig);


% --------------------------------------------------------------
function UpdateAdvAttribButtons(hfig)
% Update the Up/Down/Delete buttons in the Advanced Attrib panel

% Procedure:
%   Set enable for both Up and Down
%   Reset enable for Up if first entry selected
%   Reset enable for Dn if last entry selected
%   If multiple selections, disable both
%     set enable states
%   If multiple selections, and the first entry is in that selection
%     group, disable the delete button (not allowed to delete first
%     entry ... it's the cplx option)
%
% NOTE: If one entry, it is both the first AND the last.

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;

attribIdx = GetAttribSelectionIdx(hfig);

if isempty(attribIdx),
   isInval  = 1;
   multiple = 0;
   isAnyPortProp = 1;
else
   isInval  = 0;
   multiple = (length(attribIdx)>1);
   isAnyPortProp = any(attribIdx <= ud.numPortProps);
end

% ena = {upEna, downEna, deleteEna}
%
if isInval | multiple,
   % multiple (or invalid) selections
   ena = {'off','off','on'};
   if isAnyPortProp,
      ena{3}='off';  % cannot delete multiple port props
   end
else
   % single selection
   ena = {'on','on','on'};
   sfcnIdx  = GetSFcnSetting(hfig);
   if (sfcnIdx == 0)
      numAttribs = 0;
   else
      numAttribs = length(ud.prefs(sfcnIdx).Options);
   end
   isFirstBlockParam = (attribIdx == ud.numPortProps+1);
   if isFirstBlockParam, ena{1}='off'; end
   
   isLast  = (attribIdx == numAttribs);
   if isLast, ena{2}='off'; end
end

% Disallow moving and deleting port properties:
if isAnyPortProp,
   ena(1:3)={'off'};
end

set(h.Adv.AttribUp,'enable',ena{1});
set(h.Adv.AttribDn,'enable',ena{2});
set(h.Adv.AttribDelete,'enable',ena{3});

% If there are no S-Fcns in database,
% we cannot allow user to add attributes:
sfcnIdx = GetSFcnSetting(hfig);
if sfcnIdx == 0,
   addEna='off';
else
   addEna='on';
end
set(h.Adv.AttribAdd,'enable',addEna);


% --------------------------------------------------------------
function UpdateAdvSFcnButtons(hfig)
% Update the Up/Down buttons in the Advanced S-Function panel

% Procedure:
%   Set enable for both Up and Down
%   Reset enable for Up if first entry selected
%   Reset enable for Dn if last entry selected
%   set enable states
%
% NOTE: If one entry, it is both the first AND the last.

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;
sfcnIdx  = GetSFcnSetting(hfig);
numSFcns = length(ud.prefs);
isFirst  = (sfcnIdx <= 1);  % 0 or 1 s-fcns
isLast   = (sfcnIdx == numSFcns);

ena = {'on','on'};
if isFirst, ena{1}='off'; end
if isLast, ena{2}='off'; end
set(h.Adv.SFcnUp,'enable',ena{1});
set(h.Adv.SFcnDn,'enable',ena{2});

% If no s-fcns left, disable delete button:
if (numSFcns==0),
   set(h.Adv.SFcnDelete,'enable','off');
else
   set(h.Adv.SFcnDelete,'enable','on');
end


% --------------------------------------------------------------
function AdvSFcnAddCB
% AdvSFcnAddCB Add new S-Function database entry

hfig = gcbf;

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;

% Create new entry:
lastIdx = length(ud.prefs);

% Create new port property attrib fields:

% Currently these fields exist for every block
% even though a block may not be able, for instance,
% share IO buffers.

temp.SFcnName = 'New';
temp.BlkName  = 'Untitled';

% xxx hard coded number of port props

temp.Options(1).param='cplx';
temp.Options(1).value=1; % turn on split by default
temp.Options(1).info='Real/Complex';
temp.Options(1).dtype='int_T';

temp.Options(2).param='nSamps';
temp.Options(2).value=1; % turn off split by default
temp.Options(2).info='Samples per frame';
temp.Options(2).dtype='int_T';

temp.Options(3).param='nChans';
temp.Options(3).value=1; % turn off split by default
temp.Options(3).info='Number of channels';
temp.Options(3).dtype='int_T';

temp.Options(4).param='SharedIOBuffers';
temp.Options(4).value=1; % turn on split by default
temp.Options(4).info='Shared I/O Buffers';
temp.Options(4).dtype='int_T';

temp.Inline   = 'If Unique';

ud.prefs(end+1) = temp;

set(hfig,'UserData',ud);

% Update list box selection:
SetSFcnSetting(hfig,lastIdx+1);

SettingsChanged(hfig);  % Mark dirty status of GUI
UpdateGUI(hfig);


% --------------------------------------------------------------
function AdvSFcnDeleteCB
% AdvSFcnDeleteCB Add new S-Function database entry

hfig = gcbf;

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;
sfcnIdx = GetSFcnSetting(hfig);

% Delete current entry:
num = length(ud.prefs);
ud.prefs(sfcnIdx) = [];
set(hfig,'UserData',ud);

% Update list box selection:
% Select previous entry, or first if first was deleted:
SetSFcnSetting(hfig, min(sfcnIdx, num-1));

SettingsChanged(hfig);  % Mark dirty status of GUI
UpdateGUI(hfig);


% --------------------------------------------------------------
function AdvSFcnUpDnCB(dir)
% AdvSFcnUpDnCB Callback from Advanced S-Function Up/Down button

% Reorder the current S-Function list/database so that the
% current entry is placed AFTER the next entry.
%
% Change "current" S-Fcn selection to track moved entry

hfig = gcbf;

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;
sfcnIdx  = GetSFcnSetting(hfig);

% Swap entries:
if strcmp(dir,'up'),
   i1=sfcnIdx;
   i2=sfcnIdx-1;
else
   i1=sfcnIdx;
   i2=sfcnIdx+1;
end
temp = ud.prefs(i1);
ud.prefs(i1) = ud.prefs(i2);
ud.prefs(i2) = temp;

set(hfig,'UserData',ud);

% Update list box selection:
SetSFcnSetting(hfig,i2);
SettingsChanged(hfig);  % Mark dirty status of GUI
UpdateGUI(hfig);


% --------------------------------------------------------------
function AdvSFcnAllCB(fldSuffix)
% AdvSFcnAllCB Advanced S-Fcn Edit SFcnName/BlockName callback

hfig = gcbf;

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;
sfcnIdx  = GetSFcnSetting(hfig);

% Edit entry:
fldname = ['h.Adv.' fldSuffix ];
fld=eval(fldname);
str = get(fld,'string');
eval(['ud.prefs(sfcnIdx).' fldSuffix '= str;']);
set(hfig,'UserData',ud);

SettingsChanged(hfig);  % Mark dirty status of GUI
UpdateGUI(hfig);


% --------------------------------------------------------------
function UpdateAdvSFcnPanel(hfig)
% UpdateAdvSFcnPanel Update the "advanced" S-Fcn edit controls
%   with the currently-selected S-Function data

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;
sfcnIdx = GetSFcnSetting(hfig);

if (sfcnIdx == 0),
   SFcnName = '';
   BlkName = '';
else
   SFcnName = ud.prefs(sfcnIdx).SFcnName;
   BlkName  = ud.prefs(sfcnIdx).BlkName;
end

% Put into Advanced S-Fcn edit boxes:
set(h.Adv.SFcnName,'string',SFcnName);
set(h.Adv.BlkName,'string',BlkName);
   
UpdateAdvSFcnButtons(hfig);


% --------------------------------------------------------------
function UpdateAdvAttribPanel(hfig)
% UpdateAdvAttribPanel

% xxx
% By definition, port properties are not editable in the GUI.
% In any case, they only show up in the Advanced dialog, and
% if we want to disallow modifying these, set the flag accordingly:
%   0 = disallow editing of port properties
%   1 = permit editing of port properties
allowPortPropEdit = 0;

% Get currently selected s-function
ud = get(hfig,'UserData');
h  = ud.handles;

% Get current values:
sfcnIdx = GetSFcnSetting(hfig);
optionIdx = GetAttribSelectionIdx(hfig);

if isempty(optionIdx) | (sfcnIdx==0),
   invalIdx = 1;
   multiple = 0;
   isPortProp = 0;
else
   invalIdx = 0;
   multiple = (length(optionIdx)>1);
   isPortProp = ~allowPortPropEdit & any(optionIdx <= ud.numPortProps);
end

hAllEditAttrib = [h.Adv.AttribInfo, ...
      h.Adv.AttribParam, ...
      h.Adv.AttribDType];
hAllAttrib = [hAllEditAttrib];

if invalIdx | multiple,
   % If multiple Attrib entries selected, disable panel:
   if invalIdx,
      editStr = '';
      popStr = ' ';
   else
      editStr = '<Multiple>';
      popStr = editStr;
   end
   set(hAllEditAttrib, ...
      'string',editStr, ...
      'enable','off');
   
elseif isPortProp,
   % Disallow changes to port properties:
   set(hAllAttrib, 'enable','off');
   
else
   % enable in case previously disabled
   set(hAllAttrib,'enable','on');
end
UpdateAdvAttribButtons(hfig);

if ~multiple & ~invalIdx,
   % Update attrib advanced entries, if only one selected:
   
   if (sfcnIdx == 0),
      prefInfo   = '';
      prefParams = '';
      prefDType  = '';
   else
      prefs      = ud.prefs;
      prefInfo   = prefs(sfcnIdx).Options(optionIdx).info;
      prefParams = prefs(sfcnIdx).Options(optionIdx).param;
      prefDType  = prefs(sfcnIdx).Options(optionIdx).dtype;
   end
   
   % Put int Advanced Attrib edit boxes:
   set(h.Adv.AttribInfo,'string',prefInfo);
   set(h.Adv.AttribParam,'string',prefParams);
   set(h.Adv.AttribDType,'string',prefDType);
end


% --------------------------------------------------------------
function UpdateAdvPanel(hfig)

UpdateAdvSFcnPanel(hfig);
% UpdateAdvAttribPanel() automatically called by
% the function UpdateAttribPanel().


% --------------------------------------------------------------
function AdvAttribAddCB
% AdvAttribAddCB Add new Attrib database entry

hfig = gcbf;

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;
sfcnIdx  = GetSFcnSetting(hfig);

% Create new entry:
lastIdx = length(ud.prefs(sfcnIdx).Options);
temp = ud.prefs(sfcnIdx).Options(end);  % Copy one existing attrib
temp.param = 'newParam';
temp.value = 0;
temp.info = 'New attribute';
temp.dtype = 'int_T';

addIdx = lastIdx+1;
ud.prefs(sfcnIdx).Options(addIdx) = temp;
set(hfig,'UserData',ud);

% Update list box selection:
UpdateAttribPanel(hfig,'last');
UpdateAdvAttribPanel(hfig);
SettingsChanged(hfig);  % Mark dirty status of GUI


% --------------------------------------------------------------
function AdvAttribDeleteCB
% AdvAttribDeleteCB Delete current Attrib database entry

hfig = gcbf;

% Get current values:
ud = get(hfig,'UserData');
h  = ud.handles;
sfcnIdx  = GetSFcnSetting(hfig);
optionIdx = GetAttribSelectionIdx(hfig);
num2del = length(optionIdx);
if num2del == 0, return; end

% Delete entry:
num = length(ud.prefs(sfcnIdx).Options);
if num==1,
   err = ErrorGUI('Cannot remove last entry in database.');
   return
end
ud.prefs(sfcnIdx).Options(optionIdx)=[];
set(hfig,'UserData',ud);

% Update list box selection:
UpdateAttribPanel(hfig,'maintain');
UpdateAdvAttribPanel(hfig);
SettingsChanged(hfig);  % Mark dirty status of GUI


% --------------------------------------------------------------
function AdvAttribUpDnCB(dir)
% AdvAttribUpCB Callback from Advanced Attrib Down button

% dir = 'up', 'dn'
%
% Reorder the current Attrib list/database so that the
% current entry is placed AFTER the next entry.
%
% Change "current" Attrib selection to track moved entry

% Get current values:
hfig = gcbf;
sfcnIdx  = GetSFcnSetting(hfig);
optionIdx = GetAttribSelectionIdx(hfig);
if isempty(optionIdx), return; end

% Swap entries:
if strcmp(dir,'up'),
   i1=optionIdx;
   i2=optionIdx-1;
   listIdx='prev';
else
   i1=optionIdx;
   i2=optionIdx+1;
   listIdx='next';
end

ud = get(hfig,'UserData');
temp  = ud.prefs(sfcnIdx).Options(i1);
ud.prefs(sfcnIdx).Options(i1) = ud.prefs(sfcnIdx).Options(i2);
ud.prefs(sfcnIdx).Options(i2) = temp;
set(hfig,'UserData',ud);

% Update list box selection:
UpdateAttribPanel(hfig,listIdx);
UpdateAdvAttribPanel(hfig);
SettingsChanged(hfig);  % Mark dirty status of GUI


% --------------------------------------------------------------
function SetAttribListValue(hfig,idx)

ud = get(hfig,'UserData');
if idx <= ud.numPortProps,
   newIdx = idx+1;
else
   newIdx = idx+3;
end
set(ud.handles.AttribList,'value',newIdx);


% --------------------------------------------------------------
function AdvAttribAllCB(fieldSuffix)
% AdvAttribAllCB All advanced Attrib callbacks

hfig = gcbf;

% Get current values:
sfcnIdx  = GetSFcnSetting(hfig);
optionIdx = GetAttribSelectionIdx(hfig);
if isempty(optionIdx), return; end

ud = get(hfig,'UserData');
h  = ud.handles;

% Edit entry:
fldname = ['h.Adv.Attrib' fieldSuffix];
fld=eval(fldname);
dbField = lower(fieldSuffix);

str = get(fld,'string');
eval(['ud.prefs(sfcnIdx).Options(optionIdx).' dbField '=str;']);
set(hfig,'UserData',ud);

% Update list box selection:
UpdateAttribPanel(hfig,'maintain');  % keep same setting
UpdateAdvAttribPanel(hfig);

SettingsChanged(hfig);  % Mark dirty status of GUI


% --------------------------------------------------------------
function h = CreateBasicGUI
% dsp_cgpref
% Create the GUI window only, returning a structure of handles.
% No values are loaded into the GUI.

bgclr = get(0,'defaultfigurecolor');
y1 = -45;

% Determine position that will center GUI in middle of screen:
screenSiz = get(0,'ScreenSize');
screenSiz = screenSiz(3:4);
figSiz = [600 230];
orig = (screenSiz-figSiz)/2;
pos = [orig figSiz];

cbstr = [mfilename '(''QuitGUICB'');'];
h.fig = figure('Color',bgclr, ...
   'Position',pos, ...
   'Tag',mfilename, ...
   'HandleVisibility','off', ...
   'IntegerHandle','off', ...
   'NumberTitle','off', ...
   'Name','test name', ...
   'Resize','off', ...
   'DeleteFcn', cbstr, ...
   'CloseRequestFcn', cbstr, ...
   'Menu','None', ...
   'ToolBar','none', ...
   'vis','off');

% Static text label for S-Function list box:
str = {'','S-Fcn       Block Name'};
h.SFcnListText = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'FontName','Courier', ...
   'HorizontalAlignment','left', ...
   'Position',[19.5 192+y1 215.25 24], ...
   'String',str, ...
   'tag','Basic', ...
   'Style','text');

% List box for S-Function names:
cbstr = [mfilename '(''SFcnListCB'');'];
h.SFcnList = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',[1 1 1], ...
   'FontName','Courier', ...
   'Position',[15 88.5+y1 205 105.75], ...
   'String','test', ...
   'Style','listbox', ...
   'Callback', cbstr, ...
   'Max',1, ...  % allow single selection only
   'tag','Basic', ...
   'Value',1);

% Static text label for Function Attributes list box:
h.AttribListText = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'FontName','Courier', ...
   'HorizontalAlignment','left', ...
   'Position',[240 192+y1 135 24], ...
   'String',{'','Function Partitions'}, ...
   'tag','Basic', ...
   'Style','text');

% List box for Function Attributes
cbstr = [mfilename '(''AttribListCB'');'];
h.AttribList = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',[1 1 1], ...
   'FontName','Courier', ...
   'Position',[235 88.5+y1 205 105.75], ...
   'String','test', ...
   'Style','listbox', ...
   'callback', cbstr, ...
   'Max',2, ...  % allow multiple selection
   'tag','Basic', ...
   'Value',1);

% Button for Attrib Off:
cbstr = [mfilename '(''AttribOffCB'');'];
h.ButtonOff = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'ListboxTop',0, ...
   'Position',[380 196+y1 22 18], ...
   'String','Off', ...
   'Callback', cbstr, ...
   'tag','Basic', ...
   'Style','pushbutton');

% Button for Attrib On:
cbstr = [mfilename '(''AttribOnCB'');'];
h.ButtonOn = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'ListboxTop',0, ...
   'Position',[404 196+y1 22 18], ...
   'String','On', ...
   'Callback', cbstr, ...
   'tag','Basic', ...
   'Style','pushbutton');


% Static label: "Inline Code:"
h.InlinePopupText = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'ListboxTop',0, ...
   'HorizontalAlignment','right', ...
   'Position',[29+200 58+y1 55 16], ...
   'String','Inline Code:', ...
   'Style','text');

% Popup for "Inline Code:"
cbstr = [mfilename '(''InlinePopupCB'');'];
h.InlinePopup = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'ListboxTop',0, ...
   'backgr','w', ...
   'Position',[88+200 53+y1 92.25 24], ...
   'String','Always|Never|If Unique', ...
   'Style','popupmenu', ...
   'callback', cbstr, ...
   'Value',3);

xoff=5;
yoff=40;

% Frame around Save/Close buttons:
uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'position',[50+xoff 12+yoff+y1 82 29], ...
   'style','frame');

% Save Button
cbstr = [mfilename '(''SaveDataCB'');'];
h.SaveButton = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'ListboxTop',0, ...
   'Position',[54+xoff 16+yoff+y1 35 20], ...
   'String','Save', ...
   'Callback', cbstr, ...
   'Enable','off', ...
   'Style','pushbutton');

% Close Button
cbstr = [mfilename '(''QuitGUICB'');'];
h.CloseButton = uicontrol('Parent',h.fig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'ListboxTop',0, ...
   'Position',[92+xoff 16+yoff+y1 35 20], ...
   'String','Close', ...
   'Callback', cbstr, ...
   'Style','pushbutton');

% File menu:
mFile = uimenu('Parent',h.fig, ...
   'label','&File');

% File->Load submenu:
cbstr = [mfilename '(''OpenFileCB'');'];
h.LoadMenu = uimenu('Parent',mFile, ...
   'label','&Open...', ...
   'accel','O', ...
   'enable','on', ...
   'callback',cbstr);

% File->Save submenu:
cbstr = [mfilename '(''SaveDataCB'');'];
h.SaveMenu = uimenu('Parent',mFile, ...
   'label','&Save', ...
   'accel','S', ...
   'separator','on', ...
   'callback',cbstr);

% File->SaveAs submenu:
cbstr = [mfilename '(''SaveAsCB'');'];
h.SaveAsMenu = uimenu('Parent',mFile, ...
   'label','Save &As...', ...
   'callback',cbstr);

% File->Close menu:
cbstr = [mfilename '(''QuitGUICB'');'];
uimenu('Parent',mFile, ...
   'label','&Close', ...
   'separator','on', ...
   'callback',cbstr);

% Edit menu:
mEdit = uimenu('Parent',h.fig, ...
   'label','&Edit');

% Edit->Find menu:
uimenu('Parent',mEdit, ...
   'label','&Find');

% Edit->Advanced menu:
cbstr = [mfilename '(''AdvMenuOptCB'');'];
h.AdvMenu = uimenu('Parent',mEdit, ...
   'label','&Advanced', ...
   'checked','off', ...
   'callback',cbstr);

% Window menu:
% Setup to use standard winmenu management functionality
uimenu('Parent',h.fig, ...
   'label','&Window', ...
   'callback', winmenu('callback'), ...
   'tag', 'winmenu');
winmenu(h.fig);

% Help menu:
mHelp = uimenu('Parent',h.fig, ...
   'label','&Help');

% Help->About submenu:
cbstr = [mfilename '(''HelpTopicsCB'');'];
uimenu('Parent',mHelp, ...
   'label','&Help Topics', ...
   'callback',cbstr);

% Help->WhatThis submenu:
cbstr = [mfilename '(''HelpWhatsThisCB'');'];
uimenu('Parent',mHelp, ...
   'label','&What''s This?', ...
   'callback',cbstr);

% ------------ CONTEXT HELP: BASIC GUI -------------

% Create context menu to S-Function list:
cbstr = [mfilename '(''HelpGeneral'');'];
hc = uicontextmenu('parent',h.fig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag', 'S-Function List', 'callback',cbstr);
set([h.SFcnList h.SFcnListText],'uicontextmenu',hc);

% Create context menu to Save button:
hc = uicontextmenu('parent',h.fig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Save Button', 'callback',cbstr);
set(h.SaveButton,'uicontextmenu',hc);

% Create context menu to Close button:
hc = uicontextmenu('parent',h.fig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Close Button', 'callback',cbstr);
set(h.CloseButton,'uicontextmenu',hc);

% Create context menu to Attrib list:
hc = uicontextmenu('parent',h.fig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag', 'Function Partition List', 'callback',cbstr);
set([h.AttribList h.AttribListText],'uicontextmenu',hc);

% Create context menu to Attrib on/off buttons:
hc = uicontextmenu('parent',h.fig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag', 'Function Partition On/Off', 'callback',cbstr);
set([h.ButtonOn h.ButtonOff],'uicontextmenu',hc);

% Create context menu to Inline popup:
hc = uicontextmenu('parent',h.fig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag', 'Code Inlining Control', 'callback',cbstr);
set([h.InlinePopup h.InlinePopupText],'uicontextmenu',hc);

% Create advanced GUI:
h.Adv = CreateAdvGUI(h.fig);

% flat vector of "basic" and "advanced" GUI handles
h.AllBasic = findobj(h.fig,'tag','Basic');
h.AllAdv   = findobj(h.fig,'tag','Adv');

% Quick fix for Adv GUI elements:
for i=1:length(h.AllAdv),
   p=get(h.AllAdv(i),'pos');
   p(2)=p(2)-130;
   set(h.AllAdv(i),'pos',p);
end
set(h.AllAdv,'vis','off');

return


% -------------------------------------------------------------------------
function h = CreateAdvGUI(hfig)
% CreateAdvGUI Create dsp_cgpref "Advanced" GUI

bgclr = get(0,'defaultfigurecolor');
y2 = 115;

% S-Function name:
h.SFcnNameText = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'Position',[9 88.5+y2 60 16], ...
   'String','S-Fcn Name:', ...
   'BackgroundColor',bgclr, ...
   'horiz','right', ...
   'tag','Adv', ...
   'Style','text');

cbstr = [mfilename '(''AdvSFcnEditCB'');'];
h.SFcnName = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',[1 1 1], ...
   'Position',[73 90.5+y2 130 16], ...
   'String','the S-Fcn name', ...
   'horiz','left', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','edit');


% Library block name:
h.BlkNameText = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'Position',[9 68.5+y2 60 16], ...
   'String','Block Name:', ...
   'BackgroundColor',bgclr, ...
   'horiz','right', ...
   'tag','Adv', ...
   'Style','text');

cbstr = [mfilename '(''AdvBlockNameEditCB'');'];
h.BlkName = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',[1 1 1], ...
   'Position',[73 70.5+y2 130 16], ...
   'String','the Block name', ...
   'horiz','left', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','edit');

% Add Button
cbstr = [mfilename '(''AdvSFcnAddCB'');'];
h.SFcnAdd = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[35 115.5+y2 35 20], ...
   'String','Add', ...
   'Callback', cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');

% Delete Button
cbstr = [mfilename '(''AdvSFcnDeleteCB'');'];
h.SFcnDelete = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[73 115.5+y2 35 20], ...
   'String','Delete', ...
   'Callback', cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');

% Up Button
cbstr = [mfilename '(''AdvSFcnUpCB'');'];
h.SFcnUp = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[111 115.5+y2  35 20], ...
   'String','Up', ...
   'Callback', cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');

% Down Button
cbstr = [mfilename '(''AdvSFcnDnCB'');'];
h.SFcnDn = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[149 115.5+y2  35 20], ...
   'String','Down', ...
   'Callback', cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');


% ---

x1=220-12;

% Info:
h.AttribInfoText = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'Position',[15+x1 88.5+y2 60 16], ...
   'String','Info:', ...
   'BackgroundColor',bgclr, ...
   'horiz','right', ...
   'tag','Adv', ...
   'Style','text');

cbstr = [mfilename '(''AdvAttribInfoCB'');'];
h.AttribInfo = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',[1 1 1], ...
   'Position',[15+64+x1 88.5+y2+2 130 16], ...
   'String','the Info', ...
   'horiz','left', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','edit');

% Param:
h.AttribParamText = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'Position',[15+x1 68.5+y2 60 16], ...
   'String','Param:', ...
   'BackgroundColor',bgclr, ...
   'horiz','right', ...
   'tag','Adv', ...
   'Style','text');

cbstr = [mfilename '(''AdvAttribParamCB'');'];
h.AttribParam = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',[1 1 1], ...
   'Position',[15+64+x1 68.5+y2+2 130 16], ...
   'String','the Param', ...
   'horiz','left', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','edit');

% DType:
h.AttribDTypeText = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'Position',[15+x1 88.5+y2-40 60 16], ...
   'String','DType:', ...
   'BackgroundColor',bgclr, ...
   'horiz','right', ...
   'tag','Adv', ...
   'Style','text');

cbstr = [mfilename '(''AdvAttribDTypeCB'');'];
h.AttribDType = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',[1 1 1], ...
   'Position',[15+64+x1 88.5+y2-40+2 130 16], ...
   'String','the DType', ...
   'horiz','left', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','edit');

% Add Button
cbstr = [mfilename '(''AdvAttribAddCB'');'];
h.AttribAdd = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[51+x1 115.5+y2 35 20], ...
   'String','Add', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');

% Delete Button
cbstr = [mfilename '(''AdvAttribDeleteCB'');'];
h.AttribDelete = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[89+x1 115.5+y2 35 20], ...
   'String','Delete', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');

% Up Button
cbstr = [mfilename '(''AdvAttribUpCB'');'];
h.AttribUp = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[127+x1 115.5+y2  35 20], ...
   'String','Up', ...
   'Callback', cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');

% Down Button
cbstr = [mfilename '(''AdvAttribDnCB'');'];
h.AttribDn = uicontrol('Parent',hfig, ...
   'Units','points', ...
   'BackgroundColor',bgclr, ...
   'Position',[165+x1 115.5+y2  35 20], ...
   'String','Down', ...
   'callback',cbstr, ...
   'tag','Adv', ...
   'Style','pushbutton');

% ------------ CONTEXT HELP: ADVANCED GUI -------------

% Create context menu to Adv S-Fcn Add button:
cbstr = [mfilename '(''HelpGeneral'');'];
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Add S-Function', 'callback',cbstr);
set(h.SFcnAdd,'uicontextmenu',hc);

% Create context menu to Adv S-Fcn Delete button:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Delete S-Function', 'callback',cbstr);
set(h.SFcnDelete,'uicontextmenu',hc);

% Create context menu to Adv S-Fcn Up/Down button:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Move S-Function', 'callback',cbstr);
set([h.SFcnUp h.SFcnDn],'uicontextmenu',hc);

% Create context menu to Adv S-Fcn Name:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Modify S-Function Name', 'callback',cbstr);
set([h.SFcnName h.SFcnNameText],'uicontextmenu',hc);

% Create context menu to Adv S-Fcn Block Name:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Modify Block Name', 'callback',cbstr);
set([h.BlkName h.BlkNameText],'uicontextmenu',hc);

% Create context menu to Adv Attrib Add button:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Add Function Partition Option', 'callback',cbstr);
set(h.AttribAdd,'uicontextmenu',hc);

% Create context menu to Adv Attrib Delete button:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Delete Function Partition Option', 'callback',cbstr);
set(h.AttribDelete,'uicontextmenu',hc);

% Create context menu to Adv Attrib Up/Down button:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Move Function Partition Option', 'callback',cbstr);
set([h.AttribUp h.AttribDn],'uicontextmenu',hc);

% Create context menu to Adv Attrib Info:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Modify Function Partition Info', 'callback',cbstr);
set([h.AttribInfoText h.AttribInfo],'uicontextmenu',hc);

% Create context menu to Adv Attrib Param:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Modify Function Partition Param', 'callback',cbstr);
set([h.AttribParamText h.AttribParam],'uicontextmenu',hc);

% Create context menu to Adv Attrib DType:
hc = uicontextmenu('parent',hfig);
uimenu('parent',hc,'label','&What''s This?', ...
   'tag','Modify Function Partition DType', 'callback',cbstr);
set([h.AttribDTypeText h.AttribDType],'uicontextmenu',hc);


% -------------------------------------------------------------------------

% [EOF] dsp_cgpref.m
