function radarEquationCalculator
% radarEquationCalculator Estimate maximum range, peak power and SNR of a
% radar system
%   radarEquationCalculator launches the radar equation calculator app. The
%   app allows the user to calculate target range, peak transmit power, or
%   SNR level using the radar equations. The app supports calculations for
%   both monostatic and bistatic configurations.

% Copyright 2012-2013 The MathWorks, Inc.

% Construct UI components
GUI_WIDTH = 370;
GUI_HEIGHT = 510;
EDIT_ALIGN = 'Left';
RSZ_HEIGHT = 160;    % Resize height for detection settings

DBLRTARROW = getString(message('phased:apps:radareqapp:DoubleRightArrow'));
DBLLTARROW = getString(message('phased:apps:radareqapp:DoubleLeftArrow'));

% Units factors used to convert input values to default units of the app
Units.Wavelength = 1;
Units.Pulsewidth = 1e-6;    %us
Units.Rcs = 1;  % Used as a flag. 1: m^2  2: dBsm
Units.Power = 1e3;  % Default units set to kW
Units.RangeTx = 1e3; % Default units set to km
Units.RangeRx = 1e3;

% Units factors used to convert result values to units set on app
Units.ResultRange = 1/1000; % Convert to km by default
Units.ResultPower = 1/1e3;  % Convert to kW by default

% Turn on Web Figures in MATLAB Online
try
appsOBDScopeGuard = matlab.ui.internal.EnableAppsOnByDefaultScopeGuard;
    
hGui = figure( ...
    'Name', getString(message('phased:apps:radareqapp:RadarEqApp')), ...
    'Visible', 'off', ...
    'Toolbar', 'none', ...
    'Menubar', 'none', ...
    'NumberTitle', 'off', ...
    'DockControl', 'off', ...
    'Resize', 'off', ...
    'IntegerHandle', 'off', ...    
    'Units', 'pixels', ...
    'Position', [300, 300, GUI_WIDTH, GUI_HEIGHT], ...
    'Tag', 'RadarEqApp');

% Color reference for UI controls
BKGND_COLOR = get(hGui,'DefaultUIControlBackgroundColor');
EDIT_COLOR = 'white';
% Set main gui background color to default
set(hGui, 'Color', BKGND_COLOR);

% Menu structure
hFileMenu = uimenu(hGui,'Label', getString(message('phased:apps:radareqapp:File')), ...
    'Tag', 'FileMenu');
uimenu(hFileMenu, 'Label', getString(message('phased:apps:radareqapp:GenReport')), ...
    'Tag', 'GenReport', 'Callback', @gen_report_Callback);
uimenu(hFileMenu, 'Label', getString(message('phased:apps:radareqapp:GenMatlabCode')), ...
    'Tag', 'GenMCode', 'Callback', @gen_mcode_Callback);
uimenu(hFileMenu, 'Label', getString(message('phased:apps:radareqapp:Close')), ...
    'Separator', 'on', 'Tag', 'CloseMenu', 'Callback', @close_Callback);
hHelpMenu = uimenu(hGui, 'Label', getString(message('phased:apps:radareqapp:Help')), ...
    'Tag', 'HelpMenu');
uimenu(hHelpMenu, 'Label', getString(message('phased:apps:radareqapp:RadarEqAppHelp')), ...
    'Tag', 'RadEqAppHelp', 'Callback', @radareqapp_help_Callback);
uimenu(hHelpMenu, 'Label',getString(message('phased:apps:radareqapp:PhASTHelp')) , ...
    'Tag', 'PASTHelp', 'Callback', @phased_help_Callback);
uimenu(hHelpMenu, 'Label', getString(message('phased:apps:radareqapp:RadarEqAppAbout')), ...
    'Separator', 'on', 'Tag', 'AboutMenu', 'Callback', @about_Callback);

%------------------------------------------------------------------------%
% Radar Equation Setting UI components
%------------------------------------------------------------------------%
hCalcpanel = uipanel(...
    'Parent', hGui, ...
    'FontSize', 10, ...
    'BorderType', 'none', ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'CalcPanel');

hCalctxt = uicontrol(...
    'Parent', hCalcpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:Parameter')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'ParmCalculateLabel', ...
    'BackgroundColor', BKGND_COLOR);

calc_parms = {getString(message('phased:apps:radareqapp:Range')), ...
    getString(message('phased:apps:radareqapp:PeakPower')), ...
    getString(message('phased:apps:radareqapp:Snr'))};

hCalcpopup = uicontrol(...
    'Parent', hCalcpanel, ...
    'Style', 'popupmenu', ...
    'String', calc_parms, ...
    'Enable', 'on', ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'CalculatePopup', ...
    'BackgroundColor', 'White', ...
    'Callback', @calc_popup_Callback);

% +----------% Layout manager for calculation option panel ------------------%
hLmanCalc = siglayout.gridbaglayout(hCalcpanel, 'VerticalGap', 5, 'HorizontalGap', 5);
hLmanCalc.add(hCalctxt, 1, 1, 'MinimumHeight', 20, 'MinimumWidth',169, 'TopInset', 4, 'LeftInset', 8);
hLmanCalc.add(hCalcpopup, 1, 2, 'MinimumWidth', 150, 'LeftInset', 10);
hLmanCalc.HorizontalWeights = [0.5 1];
hLmanCalc.clean();
hLmanCalc.update();

% Main panel
hParmpanel = uipanel(...
    'Parent', hGui, ...
    'Title', getString(message('phased:apps:radareqapp:RadarSettings')), ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'ParamPanel');

% Dummy panel to hold common parameter.
hCommonParmpanel = uipanel(...
    'Parent', hParmpanel, ...
    'Tag', 'CommonParmPanel', ...
    'BorderType', 'none', ...
    'BorderWidth', 0, ...
    'BackgroundColor', BKGND_COLOR);

% Dummy panel for Power ans SNR ui controls
hPowSnrpanel = uipanel(...
    'Parent', hParmpanel, ...
    'Tag', 'PowSnrPanel', ...
    'BorderType', 'none', ...
    'BorderWidth', 0, ...
    'BackgroundColor', BKGND_COLOR);
% +---
hPeakpowtxt = uicontrol(...
    'Parent', hPowSnrpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:PeakPower')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'PeakPowerLabel', ...
    'BackgroundColor', BKGND_COLOR);

hTgtRngTx = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:Range')) ':'], ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'TgtRangeTxLabel', ...
    'BackgroundColor', BKGND_COLOR);

hTgtRngRx = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:TgtRangeRx')) ':'], ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'TgtRangeRxLabel', ...
    'BackgroundColor', BKGND_COLOR);

hSnrtxt = uicontrol(...
    'Parent', hPowSnrpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:Snr')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'SnrLabel', ...
    'BackgroundColor', BKGND_COLOR);

hWavelentxt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:WaveLen')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'WaveLengthLabel', ...
    'BackgroundColor', BKGND_COLOR);

hPwidthtxt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:PulseWidth')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'PulseWidthLabel', ...
    'BackgroundColor', BKGND_COLOR);

hTxGaintxt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:Gain')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'TxGainLabel', ...
    'BackgroundColor', BKGND_COLOR);

hRxGaintxt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:RxGain')) ':'], ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'RxGainLabel', ...
    'BackgroundColor', BKGND_COLOR);

hRcstxt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:Rcs')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'RcsLabel', ...
    'BackgroundColor', BKGND_COLOR);

hSyslosstxt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:SysLoss')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'SysLossLabel', ...
    'BackgroundColor', BKGND_COLOR);

hNoisetemptxt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:SysTemp')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'NoiseTemp', ...
    'BackgroundColor', BKGND_COLOR);

% Parameter Edit boxes

hWavelenedt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:WavelenDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'WaveLengthEdit', ...
    'Callback', @wavelen_Callback);
setappdata(hWavelenedt, 'wavelen', get(hWavelenedt, 'String'));

hPwidthedt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:PwidthDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'PulseWidthEdit', ...
    'Callback', @pwidth_Callback);
setappdata(hPwidthedt, 'pwidth', get(hPwidthedt, 'String'));

hSyslossedt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:SyslossDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'SysLossEdit', ...
    'Callback', @sysloss_Callback);
setappdata(hSyslossedt, 'sysloss', get(hSyslossedt, 'String'));

hNoisetempedt = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:NoiseTempDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'NoiseTempEdit', ...
    'Callback', @noisetemp_Callback);
setappdata(hNoisetempedt, 'noisetemp', get(hNoisetempedt, 'String'));

hRcsedt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:RcsDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'RcsEdit', ...
    'Callback', @rcs_Callback);
setappdata(hRcsedt, 'rcs', get(hRcsedt, 'String'));

% +----- Radar config params ---+
hTgtRngTxedt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:RangeDefault')), ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'TgtRangeTxEdit', ...
    'Callback', @tgtrangetx_Callback);
setappdata(hTgtRngTxedt, 'tgtrangetx', get(hTgtRngTxedt, 'String'));

hTgtRngRxedt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:RangeDefault')), ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'TgtRangeRxEdit', ...
    'Callback', @tgtrangerx_Callback);
setappdata(hTgtRngRxedt, 'tgtrangerx', get(hTgtRngRxedt, 'String'));


hTxGainedt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:GainDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'TxGainEdit', ...
    'Callback', @txgain_Callback);
setappdata(hTxGainedt, 'txgain', get(hTxGainedt, 'String'));

hRxGainedt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:GainDefault')), ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'RxGainEdit', ...
    'Callback', @rxgain_Callback);
setappdata(hRxGainedt, 'rxgain', get(hRxGainedt, 'String'));

hPeakpowedt = uicontrol(...
    'Parent', hPowSnrpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:PeakPowDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'PeakPowerEdit', ...
    'Callback', @peakpower_Callback);
setappdata(hPeakpowedt, 'peakpower', get(hPeakpowedt, 'String'));

hSnredt = uicontrol(...
    'Parent', hPowSnrpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:SnrDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'SnrEdit', ...
    'Callback', @snr_Callback);
setappdata(hSnredt, 'snr', get(hTgtRngRxedt, 'String'));

hSnrDetbtn = uicontrol(...
    'Parent', hPowSnrpanel, ...
    'Style', 'pushbutton', ...
    'String', DBLRTARROW, ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tooltip', getString(message('phased:apps:radareqapp:SnrBtnToolTip')), ...
    'Tag', 'SnrDetPushBtn', ...
    'Callback', @snr_det_btn_Callback);

hRadarConfigtxt = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:RadarConfig')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'Tag', 'RadarConfigTxt', ...
    'BackgroundColor', BKGND_COLOR);

config_cases = {getString(message('phased:apps:radareqapp:Monostatic')), ...
    getString(message('phased:apps:radareqapp:Bistatic'))};

hRadarConfigpopup = uicontrol(...
    'Parent', hParmpanel, ...
    'Style', 'popup', ...
    'String', config_cases, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'RadarConfigPopup', ...
    'Callback', @radar_config_Callback);

% Panel to group radar configuration related ui controls
hRadConfigPanel = uipanel(...
    'Parent', hParmpanel, ...
    'Tag', 'RadarConfigPanel', ...
    'BorderType', 'none', ...
    'BorderWidth', 0, ...
    'BackgroundColor', BKGND_COLOR);

%---------------------------------------------------%
% Units UI controls                                 %
%---------------------------------------------------%
wavelen_units = {getString(message('phased:apps:radareqapp:meter')), ...
    getString(message('phased:apps:radareqapp:cmeter')), ...
    getString(message('phased:apps:radareqapp:mmeter'))};

hWavelenunit = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'popup', ...
    'String', wavelen_units, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'WavelengthUnit', ...
    'Callback', @wavelen_unit_Callback);

pwidth_units = {getString(message('phased:apps:radareqapp:usec')), ...
    getString(message('phased:apps:radareqapp:msec')), ...
    getString(message('phased:apps:radareqapp:sec'))};

hPwidthunit = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'popup', ...
    'String', pwidth_units, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'PulseWidthUnit', ...
    'Callback', @pulsewidth_unit_Callback);

hSyslossunit = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'text', ...
    'String', getString(message('phased:apps:radareqapp:decibel')), ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'HorizontalAlignment', 'Left', ...
    'Tag', 'SysLossUnit');

hNoiseTempunit = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'text', ...
    'String', getString(message('phased:apps:radareqapp:kelvin')), ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'HorizontalAlignment', 'Left', ...
    'Tag', 'NoiseTempUnit');

rcs_units = {getString(message('phased:apps:radareqapp:sqm')), ...
    getString(message('phased:apps:radareqapp:dbsm'))};

hRcsunit = uicontrol(...
    'Parent', hCommonParmpanel, ...
    'Style', 'popup', ...
    'String', rcs_units, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'RcsUnit', ...
    'Callback', @rcs_unit_Callback);


hTxGainunit = uicontrol(...
    'Parent', hRadConfigPanel, ...
    'Style', 'text', ...
    'String', getString(message('phased:apps:radareqapp:decibel')), ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'HorizontalAlignment', 'Left', ...
    'Tag', 'TxGainUnit');

hRxGainunit = uicontrol(...
    'Parent', hRadConfigPanel, ...
    'Style', 'text', ...
    'String', 'dB', ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'HorizontalAlignment', 'Left', ...
    'Tag', 'RxGainUnit');

range_units = {getString(message('phased:apps:radareqapp:meter')), ...
    getString(message('phased:apps:radareqapp:kmeter')), ...
    getString(message('phased:apps:radareqapp:miles')), ...
    getString(message('phased:apps:radareqapp:nautmi'))};

hTgtRngTxunit = uicontrol(...
    'Parent', hRadConfigPanel, ...
    'Style', 'popup', ...
    'Visible', 'off', ...
    'String', range_units, ...
    'Value', 2, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'TgtRngTxUnit', ...
    'Callback', @range_tx_unit_Callback);

hTgtRngRxunit = uicontrol(...
    'Parent', hRadConfigPanel, ...
    'Style', 'popup', ...
    'Visible', 'off', ...
    'String', range_units, ...
    'Value', 2, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'TgtRngRxUnit', ...
    'Callback', @range_rx_unit_Callback);

power_units = {getString(message('phased:apps:radareqapp:mwatt')), ...
    getString(message('phased:apps:radareqapp:kwatt')), ...
    getString(message('phased:apps:radareqapp:watt')), ...
    getString(message('phased:apps:radareqapp:dbw'))};

hPeakpowerunit = uicontrol(...
    'Parent', hPowSnrpanel, ...
    'Style', 'popup', ...
    'String', power_units, ...
    'Value', 2, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'PeakPowerUnit', ...
    'Callback', @power_unit_Callback);

hSnrunit = uicontrol(...
    'Parent', hPowSnrpanel, ...
    'Style', 'text', ...
    'String', getString(message('phased:apps:radareqapp:decibel')), ...
    'Visible', 'on', ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'HorizontalAlignment', 'Left', ...
    'Tag', 'SnrUnit');

% +------- Constants for layout ------+
EDIT_WIDTH = 85;
EDIT_HEIGHT = 25;
TEXT_HEIGHT = 25;
SNRBTN_HEIGHT = 25;
if ismac
    UNIT_WIDTH = 75;
else
    UNIT_WIDTH = 60;
end
UNIT_HEIGHT = 25;
if isunix
    % In unix, the unit popups need some top inset to align with text box.
    UNIT_INSET = 1;
elseif ispc
    UNIT_INSET = 0;
end
% +--------------------------------------------------------------+
% +-------- Layout mgr for common parameter ---------------------+
% +--------------------------------------------------------------+
hLmanCommParm = siglayout.gridbaglayout(hCommonParmpanel, ...
    'VerticalGap', 6, 'HorizontalGap', 5);
hLmanCommParm.add(hWavelentxt, 1, 1,'Fill', 'Horizontal', ...
    'TopInset', 5, 'LeftInset', 2);
hLmanCommParm.add(hPwidthtxt, 2, 1, 'Fill', 'Horizontal', ...
    'TopInset', 0, 'LeftInset', 2);
hLmanCommParm.add(hSyslosstxt, 3, 1, 'Fill', 'Horizontal', ...
    'TopInset', 0, 'LeftInset', 2);
hLmanCommParm.add(hNoisetemptxt, 4, 1, 'Fill', 'Horizontal', ...
    'TopInset', 0, 'LeftInset', 2);
hLmanCommParm.add(hRcstxt, 5, 1, 'Fill', 'Horizontal', ...
    'TopInset', 0, 'LeftInset', 2);
hLmanCommParm.add(hWavelenedt, 1, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT);
hLmanCommParm.add(hPwidthedt, 2, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT);
hLmanCommParm.add(hSyslossedt, 3, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT);
hLmanCommParm.add(hNoisetempedt, 4, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT);
hLmanCommParm.add(hRcsedt, 5, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT);

hLmanCommParm.add(hWavelenunit, 1, 3, 'MinimumWidth', UNIT_WIDTH, ...
    'MinimumHeight', UNIT_HEIGHT, 'TopInset', UNIT_INSET);
hLmanCommParm.add(hPwidthunit, 2, 3, 'MinimumWidth', UNIT_WIDTH, ...
    'MinimumHeight', UNIT_HEIGHT, 'TopInset', UNIT_INSET);
hLmanCommParm.add(hSyslossunit, 3, 3, 'MinimumWidth', UNIT_WIDTH, ...
    'TopInset', 5);
hLmanCommParm.add(hNoiseTempunit, 4, 3, 'MinimumWidth', UNIT_WIDTH, ...
    'TopInset', 5);
hLmanCommParm.add(hRcsunit, 5, 3, 'MinimumWidth', UNIT_WIDTH, ...
    'MinimumHeight', UNIT_HEIGHT, 'TopInset', UNIT_INSET);
hLmanCommParm.HorizontalWeights = [ 1 0.009 0];

% +-------------------------------------------------------+
% Layout for power and snr uicontrols on a dummy  panel --+
% +-------------------------------------------------------+
hLmanPowSnr = siglayout.gridbaglayout(hPowSnrpanel, 'VerticalGap', 5, ...
    'HorizontalGap', 6);
layout_power(1);
layout_snr(2);
hLmanPowSnr.HorizontalWeights = [0 0 1 0];
%---------------------------------------------------%
% Layout manager: Parameter panel                   %
%---------------------------------------------------%
GUTTER = 10;
hLmanParm = siglayout.gridbaglayout(hParmpanel, ...
    'VerticalGap', 5,...
    'HorizontalGap', 5);
hLmanParm.add(hCommonParmpanel,1, 1, 'MinimumHeight', 6*TEXT_HEIGHT, ...
    'MinimumWidth', GUI_WIDTH - GUTTER, 'TopInset', 12, 'Anchor', 'NorthWest');
hLmanParm.add(hRadConfigPanel, 2, 1, 'MinimumWidth', GUI_WIDTH - GUTTER, ...
    'MinimumHeight', 6.5*TEXT_HEIGHT, 'Anchor', 'NorthWest', 'TopInset', -8);
hLmanParm.add(hPowSnrpanel, 3, 1, 'MinimumHeight', 2.6*TEXT_HEIGHT, ...
    'MinimumWidth', GUI_WIDTH - GUTTER, 'Anchor', 'NorthEast', 'TopInset', -5);
hLmanParm.VerticalWeights = [0 0 1];
clean(hLmanParm);   % Remove any excess spacing

% -------------- Layout radarconfig panel --------------------%
% Radar configuration layout handled in the helper function
render_radarconf(4, 3);
% Draw lines bounding the radar config components. 
% TopLine (combination of two lines with slightly different shade)
topwhitepos = 0.975;
topblackpos = topwhitepos - 0.003;
rtedgepos = 0.97;
hLineWT = annotation(hRadConfigPanel,'line', 'Position', [0.015 topwhitepos rtedgepos 0], ...
    'Color', [0.2 0.2 0.2]);   % Manually positioned
hLineBT = annotation(hRadConfigPanel,'line', 'Position', [0.015 topblackpos rtedgepos 0], ...
    'Color',[1 1 1] , 'LineWidth', 0.5);   % Manually positioned

bottomwhitepos = 0.965;
bottomblackpos = bottomwhitepos - 0.003;
% Bottom line
hLineWB = annotation(hPowSnrpanel,'line', 'Position', [0.015 bottomwhitepos rtedgepos 0], ...
    'Color',  [0 0 0]);   % Manually positioned
hLineBB = annotation(hPowSnrpanel,'line', 'Position', [0.015 bottomblackpos rtedgepos 0], ...
    'Color',[1 1 1], 'LineWidth', 0.5);   % Manually positioned

%+----------------------------------------------------------------------+%
%                         Result panel                                   %
%+----------------------------------------------------------------------+%
hResultpanel = uipanel(...
    'Parent', hGui, ...
    'FontSize', 10, ...
    'Tag', 'ResultPanel', ...
    'BorderType', 'none', ...
    'BackgroundColor', BKGND_COLOR);

hResultParmtxt = uicontrol(...
    'Parent', hResultpanel, ...
    'Style', 'text', ...
    'FontSize', 10, ...
    'Visible', 'off', ...
    'HorizontalAlignment', 'Left', ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'ResultParmTxt');

hResulttxt = uicontrol(...
    'Parent', hResultpanel, ...
    'Style', 'text', ...
    'FontSize', 10, ...
    'Visible', 'off', ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'ResultTxt');

hResultPowerunit = uicontrol(...
    'Parent', hResultpanel, ...
    'Style', 'popup', ...
    'String', power_units, ...
    'Value', 2, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'ResultPowerUnit', ...
    'Callback', @result_power_unit_Callback);

hResultSnrunit = uicontrol(...
    'Parent', hResultpanel, ...
    'Style', 'text', ...
    'String', getString(message('phased:apps:radareqapp:decibel')), ...
    'FontSize', 10, ...
    'BackgroundColor', BKGND_COLOR, ...
    'HorizontalAlignment', 'Left', ...
    'Tag', 'ResultSnrUnit');

hResultRangeunit = uicontrol(...
    'Parent', hResultpanel, ...
    'Style', 'popup', ...
    'String', range_units, ...
    'Value', 2, ...
    'FontSize', 10, ...
    'BackgroundColor', 'White', ...
    'Tag', 'ResultRangeUnit', ...
    'Callback', @result_range_unit_Callback);

% +-------------------------------+ Layout for Result panel  -------|
% +-------------------------------+
INSET = 20;
hLmanResult = siglayout.gridbaglayout(hResultpanel, 'VerticalGap', 5, ...
    'HorizontalGap', 5);
hLmanResult.add(hResultParmtxt, 1, 1, 'Fill', 'Horizontal', ...
    'LeftInset', 6);
set(hResultParmtxt, 'Visible', 'on');
hLmanResult.add(hResulttxt, 1, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'Anchor', 'Northwest', 'TopInset', 5);
set(hResulttxt, 'Visible', 'on');
hLmanResult.add(hResultRangeunit, 1, 3);
hLmanResult.add(uicontrol('Style', 'text', 'Visible', 'off'), 1, 4, ...
    'MinimumWidth', 0.25);     % Dummy component to push unit to left.
hLmanResult.HorizontalWeights = [1 0 0 0];
% Rest of dynamic layout management is handled in render_result()

%-------------------------------------------------------------------------%
% Detection settings layout ui controls
%-------------------------------------------------------------------------%
hSnrDetpanel = uipanel( ...
    'Title', getString(message('phased:apps:radareqapp:DetSettings')), ...
    'TitlePosition', 'lefttop', ...
    'Visible', 'off', ...
    'FontSize', 10, ...
    'BorderType', 'none', ...
    'BorderWidth', 0, ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'SnrDetPanel');

hProbDetlbl = uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:ProbDetection')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'ProbDetLabel');

hProbFalbl = uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:ProbFalseAlarm')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'ProbFaLabel');

hNumPulselbl = uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:NumSamples')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'NumSampleLabel');

hSwerlingNumlbl= uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'text', ...
    'String', [getString(message('phased:apps:radareqapp:SwerlingNum')) ':'], ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'left', ...
    'BackgroundColor', BKGND_COLOR, ...
    'Tag', 'SwerlingNumLabel');

% Edit inputs
hProbDetedt = uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'edit', ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'ProbDetEdit', ...
    'Callback', @pd_Callback);

hProbFaedt = uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'edit', ...
    'String', getString(message('phased:apps:radareqapp:ProbFaDefault')), ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'ProbFaEdit', ...
    'Callback', @pfa_Callback);
setappdata(hProbFaedt, 'probfa', get(hProbFaedt, 'String'));

hNumPulseedt = uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'edit', ...
    'String', '1', ...
    'FontSize', 10, ...
    'HorizontalAlignment', EDIT_ALIGN, ...
    'BackgroundColor', EDIT_COLOR, ...
    'Tag', 'NumPulseEdit', ...
    'Callback', @numpulse_Callback);
setappdata(hNumPulseedt, 'numpulse', get(hNumPulseedt, 'String'));

hSwerlingNumpopup = uicontrol(...
    'Parent', hSnrDetpanel, ...
    'Style', 'popupmenu', ...
    'String', {'0','1','2','3','4' }, ...
    'FontSize', 10, ...
    'HorizontalAlignment', 'right', ...
    'BackgroundColor', 'White', ...
    'Tag', 'SwerlingNumpopup', ...
    'Callback', @swerling_num_Callback);

%-------------------------------------------------------------------------%
% Layout for detection setting panel
%-------------------------------------------------------------------------%
hLmanSnrDet = siglayout.gridbaglayout(hSnrDetpanel, 'HorizontalGap', 5, ...
    'VerticalGap', 5);
hLmanSnrDet.add(hProbDetlbl, 1, 1, 'Fill', 'Horizontal', 'TopInset', 20, 'LeftInset', 7);
PfaLabelWidth = 183;
hLmanSnrDet.add(hProbFalbl, 2, 1, 'MinimumWidth', PfaLabelWidth, 'TopInset', 5, ...
    'Anchor', 'West', 'LeftInset', 7);
hLmanSnrDet.add(hNumPulselbl, 3, 1, 'Fill', 'Horizontal', 'TopInset', 5, 'LeftInset', 7);
hLmanSnrDet.add(hSwerlingNumlbl, 4, 1, 'Fill', 'Horizontal', 'TopInset', 5, 'LeftInset', 7);

hLmanSnrDet.add(hProbDetedt, 1, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT, ...
    'TopInset', 15, 'Anchor', 'West');
hLmanSnrDet.add(hProbFaedt, 2, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT, ...
    'Anchor', 'West');
hLmanSnrDet.add(hNumPulseedt, 3, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'MinimumHeight', EDIT_HEIGHT, ...
    'Anchor', 'West');
hLmanSnrDet.add(hSwerlingNumpopup, 4, 2, 'MinimumWidth', EDIT_WIDTH, ...
    'Anchor', 'Northwest');
hLmanSnrDet.HorizontalWeights = [0 1];

%-------------------------------------------------------------------------%
% Layout manager for main figure
%-------------------------------------------------------------------------%
hLmanGui = siglayout.gridbaglayout(hGui, 'VerticalGap' , 5, 'HorizontalGap', 5);
hLmanGui.add(hCalcpanel, 1, 1, 'MinimumWidth', GUI_WIDTH-GUTTER, ...
    'MinimumHeight', 30, ...
    'Anchor', 'NorthWest');
hLmanGui.add(hParmpanel, 2, 1, 'Fill', 'Vertical', ...
    'MinimumWidth', GUI_WIDTH - GUTTER, ...
    'MinimumHeight', 430, ...
    'Anchor', 'NorthWest');
hLmanGui.add(hResultpanel, 3, 1, 'MinimumWidth', GUI_WIDTH - GUTTER, ...
    'MinimumHeight', 40, ...
    'Anchor', 'Northwest');
hLmanGui.VerticalWeights = [0 1 0];
hLmanGui.clean();
hLmanGui.update();

%-------------------------------------------------------------------------%
% GUI Initialization
%-------------------------------------------------------------------------%
% Parameter initialization
calc_type = get(hCalcpopup, 'Value');
config_type = get(hRadarConfigpopup, 'Value');
render_radarconfig_ui(calc_type, config_type);
render_power_snr(calc_type);
calculation_Callback();  % Initial setup
movegui(hGui, 'center');
set(hGui, 'Visible', 'on', 'HandleVisibility', 'off');

% Workaround layout issue in MATLAB Online Web-Figures
drawnow;
hGui.Position(4) = GUI_HEIGHT+1;
drawnow;

if ispc
    % In windows, all the uicontrols in the GUI shift down when the GUI is
    % resized for the first time. This happens only once. As a workaround
    % for this behavior of the layout, the gui is manually resized and back
    % again.
    resize_gui('on', RSZ_HEIGHT);
    resize_gui('off', RSZ_HEIGHT);
end

% Clean up Web Figures in MATLAB Online
delete(appsOBDScopeGuard);
catch
    delete(appsOBDScopeGuard);
end

%-------------------------------------------------------------------------%
% Callback functions
%-------------------------------------------------------------------------%
    function calculation_Callback(~, ~)
        % Main callback: Handles the calculation of parameters using
        % radareq functions.
        calc_type = get(hCalcpopup, 'Value');
        config_type = get(hRadarConfigpopup, 'Value');
        if ~(Units.Power == 4)
            Pt = str2double(get(hPeakpowedt, 'String'))*Units.Power;
        elseif (Units.Power == 4)
            Pt = db2pow(str2double(get(hPeakpowedt, 'String')));
        end
        rangetx = str2double(get(hTgtRngTxedt, 'String'))*Units.RangeTx;
        rangerx = str2double(get(hTgtRngRxedt, 'String'))*Units.RangeRx;
        SNR = str2double(get(hSnredt, 'String'));
        wavelen = str2double(get(hWavelenedt, 'String'))*Units.Wavelength;
        pwidth = str2double(get(hPwidthedt, 'String'))*Units.Pulsewidth;
        txgain = str2double(get(hTxGainedt, 'String'));
        rxgain = str2double(get(hRxGainedt, 'String'));
        
        if config_type == 1 % Monostatic
            gain = txgain;
            tgtrange = rangetx;
        elseif config_type == 2 % Bistatic
            gain = [txgain rxgain];
            tgtrange = [rangetx rangerx];
        end
        
        radxsec = str2double(get(hRcsedt, 'String'));   % Default unit sq.m
        if get(hRcsunit, 'Value') == 2   % Check for RCS units
            radxsec = db2pow(radxsec);
        end
        sysloss = str2double(get(hSyslossedt, 'String'));
        noisetemp = str2double(get(hNoisetempedt, 'String'));
        
        % Calculation logic rawresult : results in default units
        switch calc_type
            case 1 % Target range
                rawresult = radareqrng(wavelen, SNR, Pt, pwidth, ...
                    'rcs', radxsec, 'gain', gain, 'loss', sysloss, 'Ts', noisetemp);
                result = rawresult * Units.ResultRange;
            case 2 % Peak power
                rawresult = radareqpow(wavelen, tgtrange, SNR, pwidth, ...
                    'rcs', radxsec, 'gain', gain, 'loss', sysloss','Ts', noisetemp);
                if ~(Units.ResultPower == 4)    % Not dBW
                    result = rawresult * Units.ResultPower;
                elseif (Units.ResultPower == 4)
                    result = pow2db(rawresult);
                end
                
            case 3 % SNR
                rawresult = radareqsnr(wavelen, tgtrange, Pt, pwidth, ...
                    'rcs', radxsec, 'gain', gain, 'loss', sysloss, 'Ts', noisetemp);
                result = rawresult;
        end % Switch case
        
        % Save result value as guidata, to be used by get_parm_struct()
        guidata(hGui, rawresult);
        render_result(calc_type, config_type, result);  % Render result
    end % calculation callback

    function calc_popup_Callback(~,~)
        % Callback for main calculation popup
        calc_type = get(hCalcpopup, 'Value');
        config_type = get(hRadarConfigpopup, 'Value');
        render_radarconfig_ui(calc_type, config_type);
        render_power_snr(calc_type);
        calculation_Callback();
    end

    function wavelen_Callback(hObject, eventdata)
        wavelen = str2double(get(hWavelenedt, 'String'));
        try
            validateattributes(wavelen, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'nonzero', 'positive', 'nonempty'});
        catch errObj
            holetxt = get(hWavelentxt, 'String');  % This string has : at the end.
            errordlg(getString(message('phased:apps:radareqapp:NzPosNumErr', ...
                holetxt(1:end-1))), 'Invalid Input', 'modal');
            set(hWavelenedt, 'String', getappdata(hWavelenedt, 'wavelen'));
            return;
        end
        setappdata(hWavelenedt, 'wavelen', get(hWavelenedt, 'String'));
        calculation_Callback();
    end

    function pwidth_Callback(hObject, eventdata)
        pwidth = str2double(get(hPwidthedt, 'String'));
        try
            validateattributes(pwidth, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'nonzero', 'positive', 'nonempty'});
        catch errObj
            holetxt = get(hPwidthtxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NzPosNumErr', ...
                holetxt(1:end-1))),'Invalid Input', 'modal');
            set(hPwidthedt, 'String', getappdata(hPwidthedt, 'pwidth'));
            return;
        end
        setappdata(hPwidthedt, 'pwidth', get(hPwidthedt, 'String'));
        calculation_Callback();
    end

    function sysloss_Callback(hObject, eventdata) %#ok<*INUSD>
        sysloss = str2double(get(hSyslossedt, 'String'));
        try
            validateattributes(sysloss, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'nonempty', 'real'});
        catch errObj %#ok<*NASGU>
            holetxt = get(hSyslosstxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NumericErr', ...
                holetxt(1:end-1))), 'Invalid Input', 'modal');
            set(hSyslossedt, 'String', getappdata(hSyslossedt, 'sysloss'));
            return;
        end
        setappdata(hSyslossedt, 'sysloss', get(hSyslossedt, 'String'));
        calculation_Callback();
    end

    function noisetemp_Callback(hObject, eventdata)
        % Noisetemp callback
        noisetemp = str2double(get(hNoisetempedt, 'String'));
        try
            validateattributes(noisetemp, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'positive', 'nonempty'});
        catch errObj
            holetxt = get(hNoisetemptxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NzPosNumErr', ...
                holetxt(1:end-1))), 'Invalid Input', 'modal');
            set(hNoisetempedt, 'String', getappdata(hNoisetempedt, 'noisetemp'));
            return;
        end
        setappdata(hNoisetempedt, 'noisetemp', get(hNoisetempedt, 'String'));
        calculation_Callback();
    end

    function rcs_Callback(hObject, eventdata)
        % Target cross section callback
        tgtrcs = str2double(get(hRcsedt, 'String'));
        if (get(hRcsunit, 'Value') == 2)
            rcs_validate_option = {'scalar', 'finite', 'nonnan', 'nonempty'};
            err_msg_id = 'phased:apps:radareqapp:NumericErr';
        else
            rcs_validate_option = {'scalar', 'finite', 'nonnan', 'positive', 'nonzero', 'nonempty'};
            err_msg_id = 'phased:apps:radareqapp:NzPosNumErr';
        end
        try
            validateattributes(tgtrcs, {'numeric'}, rcs_validate_option);
        catch errObj
            holetxt = get(hRcstxt, 'String');
            errordlg(getString(message(err_msg_id, ...
                holetxt(1:end-1))), 'Invalid Input', 'modal');
            set(hRcsedt, 'String', getappdata(hRcsedt, 'rcs'));
            return;
        end
        % Check if the rcs value is <= 3000 when unit is dbsm
        if (get(hRcsunit, 'Value') == 2) && isinf(db2pow(tgtrcs))
            holetxt = get(hRcstxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:dBErr', ...
                holetxt(1:end-1), 3000, 'dbsm')),'Invalid Input', 'modal');
            set(hRcsunit, 'Value', 1);   % Reset it back to m^2
            return;
        end            
        
        setappdata(hRcsedt, 'rcs', get(hRcsedt, 'String'));
        calculation_Callback();
    end

    function txgain_Callback(hObject, eventdata)
        % Validate and call calculation for gain parameters
        
        txgain = str2double(get(hTxGainedt, 'String'));
        try
            validateattributes(txgain, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'nonempty', 'real'});
        catch errObj %#ok<NASGU>
            holetxt = get(hTxGaintxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NumericErr', ...
                holetxt(1:end-1))),'Invalid Input', 'modal');
            set(hTxGainedt, 'String', getappdata(hTxGainedt, 'txgain'));
            return;
        end
        setappdata(hTxGainedt, 'txgain', get(hTxGainedt, 'String'));
        calculation_Callback();
    end

    function rxgain_Callback(hObject, eventdata) %#ok<*INUSD>
        % Validate and call calculation for gain parameters
        
        rxgain = str2double(get(hRxGainedt, 'String'));
        try
            validateattributes(rxgain, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'nonempty', 'real'});
        catch errObj
            holetxt = get(hRxGaintxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NumericErr', ...
                holetxt(1:end-1))),'Invalid Input', 'modal');
            set(hRxGainedt, 'String', getappdata(hRxGainedt, 'rxgain'));
            return;
        end
        setappdata(hRxGainedt, 'rxgain', get(hRxGainedt, 'String'));
        calculation_Callback();
    end

    function tgtrangetx_Callback(hObject, eventdata)
        % Validate and call calculation for range parameter
        tgtrangetx = str2double(get(hTgtRngTxedt, 'String'));
        try
            validateattributes(tgtrangetx, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'positive', 'nonzero'});
        catch errObj
            holetxt = get(hTgtRngTx, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NzPosNumErr', ...
                holetxt(1:end-1))), 'Invalid Input', 'modal')
            set(hTgtRngTxedt, 'String', getappdata(hTgtRngTxedt, 'tgtrangetx'));
            return;
        end
        setappdata(hTgtRngTxedt, 'tgtrangetx', get(hTgtRngTxedt, 'String'));
        calculation_Callback();
    end

    function tgtrangerx_Callback(hObject, eventdata)
        % Validate and call calculation for range parameter
        tgtrangerx = str2double(get(hTgtRngRxedt, 'String'));
        try
            validateattributes(tgtrangerx, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'positive', 'nonzero'});
        catch errObj
            holetxt = get(hTgtRngRx, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NzPosNumErr', ...
                holetxt(1:end-1))), 'Invalid Input', 'modal')
            set(hTgtRngRxedt, 'String', getappdata(hTgtRngRxedt, 'tgtrangerx'));
            return;
        end
        setappdata(hTgtRngRxedt, 'tgtrangerx', get(hTgtRngRxedt, 'String'));
        calculation_Callback();
    end

    function snr_Callback(hObject, eventdata)
        % Validate and call calculation for snr parameter
        snr = str2double(get(hSnredt, 'String'));
        try
            validateattributes(snr, {'numeric'}, ...
                {'scalar', 'finite',  'nonnan', 'nonempty', 'real'});
        catch errObj
            holetxt = get(hSnrtxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NumericErr', ...
                holetxt(1:end-1))),'Invalid Input', 'modal');
            set(hSnredt, 'String', getappdata(hSnredt, 'snr'));
            return;
        end
        setappdata(hSnredt, 'snr', get(hSnredt, 'String'));
        %populate_pdpfa();
        calculation_Callback();
    end

    function peakpower_Callback(hObject, eventdata)
        % Validate and call calculation for power parameter
        peakpower = str2double(get(hPeakpowedt, 'String'));
        try
            validateattributes(peakpower, {'numeric'}, ...
                {'scalar', 'finite', 'nonnan', 'positive', 'nonzero'});
        catch errObj
            holetxt = get(hPeakpowtxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NzPosNumErr', ...
                holetxt(1:end-1))),'Invalid Input', 'modal');
            set(hPeakpowedt, 'String', getappdata(hPeakpowedt, 'peakpower'));
            return;
        end
        % Check if the input results in infinite power when unit is dbW
        if (Units.Power == 4) && isinf(db2pow(peakpower))        
            holetxt = get(hPeakpowtxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:dBErr', ...
                holetxt(1:end-1), 3000, 'dbW')),'Invalid Input', 'modal');
            set(hPeakpowedt, 'String', getappdata(hPeakpowedt, 'peakpower'));
            return;
        end
        setappdata(hPeakpowedt, 'peakpower', get(hPeakpowedt, 'String'));        
        calculation_Callback();
    end

    function radar_config_Callback(hObject, eventdata)
        % Callback for radar config popup
        calc_type = get(hCalcpopup, 'Value');
        config_type = get(hRadarConfigpopup, 'Value');
        render_radarconfig_ui(calc_type, config_type);
        calculation_Callback(); % Update result
    end

    function snr_det_btn_Callback(hObject, eventdata)
        btn_label = get(hSnrDetbtn, 'String');
        if strcmp(btn_label, DBLRTARROW)
            % Change string
            set(hSnrDetbtn, 'String', DBLLTARROW);
            set(hSnredt, 'Enable', 'off');
            switch_snrdetpanel('on');
            % Populate Pd and Pfa editbox using values from rocsnr()
            populate_pdpfa();
        elseif strcmp(btn_label, DBLLTARROW)
            switch_snrdetpanel('off');
            drawnow();
            % Change String
            set(hSnrDetbtn, 'String', DBLRTARROW);
            set(hSnredt, 'Enable', 'on');
        end
    end

    function gen_report_Callback(~, ~)
        % Generate report and open save dialog
        rparms = get_parm_struct();
        genradareqreport(rparms);
    end

    function gen_mcode_Callback(~, ~)
        rparms = get_parm_struct();
        genradareqmcode(rparms);
    end

    function close_Callback(~, ~)
        close(hGui);
    end

    function radareqapp_help_Callback(~,~)        
        helpview([docroot, '\phased\helptargets.map'],  'radar_app');
    end

    function phased_help_Callback(~, ~)
        % Launch phased array system toolbox documentation
        helpview([docroot, '\phased\helptargets.map'],  'phased_doc');
    end

    function about_Callback(~,~)
        aboutphasedtbx;
    end        

% -------------------- Detection setting callbacks -----------------------%
    function pd_Callback(hObject, eventdata)
        % Prob of detection edit box callback Validate and call calculation
        % for gain parameter
        pd = str2double(get(hProbDetedt, 'String'));
        try
            validateattributes(pd, {'numeric'}, ...
                {'scalar', 'nonnan', 'positive', '>=', 0.1, '<=', 0.99});
        catch errObj
            holetxt = get(hProbDetlbl, 'String');
            errordlg(getString(message('phased:apps:radareqapp:ProbDetErr', ...
                holetxt(1:end-1), num2str(0.1), num2str(0.99))), 'Invalid Input', 'modal');
            set(hProbDetedt, 'String', getappdata(hProbDetedt, 'probdet'));
            return;
        end
        setappdata(hProbDetedt, 'probdet', get(hProbDetedt, 'String'));
        update_snr_Callback();
        calculation_Callback();
    end

    function pfa_Callback(Object, eventdata)
        % Prob of false alarm edit box callback
        pfa = str2double(get(hProbFaedt, 'String'));
        try
            validateattributes(pfa, {'numeric'}, ...
                {'scalar', 'nonnan', 'positive', 'nonzero', '<', 1, '>=', 1e-20});
        catch errObj
            holetxt = get(hProbFalbl, 'String');
            errordlg(getString(message('phased:apps:radareqapp:ProbFaErr', ...
                holetxt(1:end-1), num2str(1e-20), 1)), 'Invalid Input', 'modal');
            set(hProbFaedt, 'String', getappdata(hProbFaedt, 'probfa'));
            return;
        end
        % Make sure Pd is <= 0.99
        if (str2double(get(hProbDetedt, 'String')) > 0.99)
            holetxt = get(hProbDetlbl, 'String');
            errordlg(getString(message('phased:apps:radareqapp:ProbDetErr', ...
                holetxt(1:end-1), num2str(0.1), num2str(0.99))), 'Invalid Input', 'modal');
            set(hProbFaedt, 'String', getappdata(hProbFaedt, 'probfa'));
            return;
        end
        setappdata(hProbFaedt, 'probfa', get(hProbFaedt, 'String'));
        update_snr_Callback();
        calculation_Callback();
    end

    function numpulse_Callback(hObject, eventdata)
        % Number of pulses callback
        numpulse = str2double(get(hNumPulseedt, 'String'));
        try
            validateattributes(numpulse, {'numeric'}, ...
                {'scalar', 'nonnan', 'positive', 'nonzero', 'integer'});
        catch errObj
            holetxt = get(hNumPulselbl, 'String');
            errordlg(getString(message('phased:apps:radareqapp:NzPosIntErr', ...
                holetxt(1:end-1))), 'Invalid Input', 'modal');
            set(hNumPulseedt, 'String', getappdata(hNumPulseedt, 'numpulse'));
            return;
        end
        % Make sure Pd is <= 0.99
        if (str2double(get(hProbDetedt, 'String')) > 0.99)
            holetxt = get(hProbDetlbl, 'String');
            errordlg(getString(message('phased:apps:radareqapp:ProbDetErr', ...
                holetxt(1:end-1), num2str(0.1), num2str(0.99))), 'Invalid Input', 'modal');
            set(hProbFaedt, 'String', getappdata(hProbFaedt, 'probfa'));
            return;
        end
        setappdata(hNumPulseedt, 'numpulse', get(hNumPulseedt, 'String'));
        update_snr_Callback();
        calculation_Callback();
    end

    function swerling_num_Callback(hObject, eventdata)
        % Swerling number popup callback
        update_snr_Callback();
        calculation_Callback();
    end

% -------------------- Unit UI callbacks ---------------------------------%
    function wavelen_unit_Callback(hObject, eventdata)
        % Callback for wavelength unit popup in parameter panel
        switch get(hObject, 'Value')
            case 1  % m
                Units.Wavelength = 1;
            case 2  % cm to m
                Units.Wavelength = unitsratio('m', 'cm');
            case 3  % mm to m
                Units.Wavelength = unitsratio('m', 'mm');
        end
        calculation_Callback();   % Update calculation
    end

    function pulsewidth_unit_Callback(hObject, eventdata)
        % Callback for pulse width unit popup in parameter panel
        switch get(hObject, 'Value')
            case 1  % us
                Units.Pulsewidth = 1e-6;
            case 2  % ms
                Units.Pulsewidth = 1e-3;
            case 3  % s
                Units.Pulsewidth = 1;
        end
        calculation_Callback();   % Update calculation
    end

    function rcs_unit_Callback(hObject, eventdata)
        % Callback for rcs unit popup in parameter panel 
        % The db2pow conversion is handled in calculation_Callback.
        % Check if RCS is < 3000 when unit is set to dB. 
        % db2pow returns finite value for input < 3000
        tgtrcsunit_value = get(hRcsunit, 'Value');
        tgtrcs = str2double(get(hRcsedt, 'String'));
        if (tgtrcsunit_value == 2)
            rcs_validate_option = {'scalar', 'finite', 'nonnan', 'nonempty'};
            err_msg_id = 'phased:apps:radareqapp:NumericErr';
        else
            rcs_validate_option = {'scalar', 'finite', 'nonnan', 'positive', 'nonzero', 'nonempty'};
            err_msg_id = 'phased:apps:radareqapp:NzPosNumErr';
        end
        try
            validateattributes(tgtrcs, {'numeric'}, rcs_validate_option);
        catch errObj
            holetxt = get(hRcstxt, 'String');
            errordlg(getString(message(err_msg_id, ...
                holetxt(1:end-1))), 'Invalid Input', 'modal');
            set(hRcsunit, 'Value', 3-tgtrcsunit_value);  % toggle back if error
            return;
        end
        
        if (tgtrcsunit_value == 2) && isinf(db2pow(str2double(get(hRcsedt, 'String'))))
            holetxt = get(hRcstxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:dBErr', ...
                holetxt(1:end-1), 3000, 'dbsm')),'Invalid Input', 'modal');
            set(hRcsunit, 'Value', 1);   % Reset it back to m^2
        end            
        calculation_Callback();   % Update calculation
    end

    function power_unit_Callback(hObject, eventdata)
        % Callback for power unit popup in parameter panel
        switch get(hObject, 'Value')
            case 1  % MW
                Units.Power = 1e6;
            case 2  % kW
                Units.Power = 1e3;
            case 3  % W
                Units.Power = 1;
            case 4  % dbW
                Units.Power = 4;    % Is isn't a factor. '4' is used as a flag for dBW
        end
        % Check if the in input is too high with dbW is chosen as unit
        % db2pow() requires input < 3000 to give finite output        
        if (Units.Power == 4) && isinf(db2pow(str2double(get(hPeakpowedt, 'String'))))
            holetxt = get(hPeakpowtxt, 'String');
            errordlg(getString(message('phased:apps:radareqapp:dBErr', ...
                holetxt(1:end-1), 3000, 'dbW')),'Invalid Input', 'modal');            
            % Reset unit to default value
            set(hPeakpowerunit, 'Value', 2);
            Units.Power = 1e3;
        end        
        calculation_Callback();   % Update calculation
    end

    function range_tx_unit_Callback(hObject, eventdata)
        % Callback for range unit popup in the result panel
        switch get(hObject, 'Value')
            case 1  % m
                Units.RangeTx = 1;
            case 2  % km
                Units.RangeTx = unitsratio('m', 'km');
            case 3  % mi
                Units.RangeTx = unitsratio('m', 'mi');
            case 4  % nm
                Units.RangeTx = unitsratio('m', 'nm');
        end
        calculation_Callback();   % Update calculation
    end

    function range_rx_unit_Callback(hObject, eventdata)
        % Callback for range unit popup in the result panel The conversion
        % factors are based of radareqpow.m file
        switch get(hObject, 'Value')
            case 1  % m
                Units.RangeRx = 1;
            case 2  % km to m
                Units.RangeRx = unitsratio('m', 'km');
            case 3  % mi to m
                Units.RangeRx = unitsratio('m', 'mi');
            case 4  % nmi to m
                Units.RangeRx = unitsratio('m', 'nm');
        end
        calculation_Callback();   % Update calculation
    end

    function result_range_unit_Callback(hObject, eventdata)
        % Callback for range unit popup in the result panel The conversion
        % factors are based of radareqpow.m file Convert from m to km, mi,
        % nmi
        switch get(hObject, 'Value')
            case 1  % m
                Units.ResultRange = 1;
            case 2  % m to km
                Units.ResultRange = unitsratio('km', 'm');
            case 3  % m to mi
                Units.ResultRange = unitsratio('mi', 'm');
            case 4  % m to nmi
                Units.ResultRange = unitsratio('nm', 'm');
        end
        calculation_Callback();   % Update calculation
    end

    function result_power_unit_Callback(hObject, eventdata)
        % Callback for power unit popup in parameter panel Convert from
        % Watts to MW or kW or W
        switch get(hObject, 'Value')
            case 1  % MW
                Units.ResultPower = 1/1e6;
            case 2  % kW
                Units.ResultPower = 1/1e3;
            case 3  % W
                Units.ResultPower = 1;
            case 4  % dBW
                Units.ResultPower = 4;  % This is used as a flag for dBW case
        end
        calculation_Callback();   % Update calculation
    end

% --------------------- Helper functions ---------------------------------%
    function render_result(calc_type, config_type, result)
        % Renders the result panel and its contents
        range_label = {getString(message('phased:apps:radareqapp:Range')), ...
            getString(message('phased:apps:radareqapp:ResultGeomRange'))};
        set(hResulttxt, 'String', num2str(result, 4));
        switch calc_type
            case 1  % Range
                set(hResultParmtxt, 'String', [range_label{config_type} ':']);
                set(hResultRangeunit, 'Visible', 'on');
                set(hResultPowerunit, 'Visible', 'off');
                set(hResultSnrunit, 'Visible', 'off');
                hLmanResult.remove(1,3);
                hLmanResult.add(hResultRangeunit, 1, 3, ...
                    'MinimumWidth', 0.95*UNIT_WIDTH,  'MinimumHeight', 30, ...
                    'TopInset', 0.75,'Anchor', 'Northwest');
                drawnow();
            case 2  % Power
                set(hResultParmtxt, 'String', [calc_parms{calc_type} ':']);
                set(hResultRangeunit, 'Visible', 'off');
                set(hResultPowerunit, 'Visible', 'on');
                set(hResultSnrunit, 'Visible', 'off');
                hLmanResult.remove(1,3);
                hLmanResult.add(hResultPowerunit, 1, 3, ...
                    'MinimumWidth',0.95*UNIT_WIDTH, 'MinimumHeight', 30, ...
                    'TopInset',0.75);
                drawnow();
            case 3  % SNR
                set(hResultParmtxt,'String', [calc_parms{calc_type} ':']);
                set(hResultRangeunit, 'Visible', 'off');
                set(hResultPowerunit, 'Visible', 'off');
                set(hResultSnrunit, 'Visible', 'on');
                hLmanResult.remove(1,3);
                hLmanResult.add(hResultSnrunit, 1, 3, ...
                    'MinimumWidth', 0.95*UNIT_WIDTH, 'MinimumHeight', 30, ...
                    'TopInset', 5);
                drawnow();
        end
    end

    function render_radarconfig_ui(calc_type, config_type)
        if calc_type == 1 && config_type == 1
            render_radarconf(4, 3);
            % Range, Monostatic Show only gain
            set(hTxGaintxt, 'String', [getString(message('phased:apps:radareqapp:Gain')) ':']);
            toggle_key = {'on', 'on', ...
                'off', 'off', 'off', ...
                'off', 'off', 'off', ...
                'off', 'off', 'off'};
            toggle_radarconfig_ui(toggle_key);
        elseif calc_type == 1 && config_type == 2
            % Range, Bistatic
            render_radarconf(3, 4);
            set(hTxGaintxt, 'String', [getString(message('phased:apps:radareqapp:TxGain')) ':']);
            toggle_key = {'on', 'on', ...
                'on', 'on', 'on', ...
                'off', 'off', 'off', ...
                'off', 'off', 'off'};
            toggle_radarconfig_ui(toggle_key);
        elseif (calc_type == 2 || calc_type == 3) && config_type == 1
            render_radarconf(4, 3);
            % Power or SNR, Monostatic
            set(hTxGaintxt, 'String', [getString(message('phased:apps:radareqapp:Gain')) ':']);
            set(hTgtRngTx, 'String', [getString(message('phased:apps:radareqapp:Range')) ':']);
            toggle_key = {'on', 'on', ...
                'off', 'off', 'off', ...
                'on', 'on', 'on', ...
                'off', 'off', 'off'};
            toggle_radarconfig_ui(toggle_key);
        elseif (calc_type == 2 || calc_type == 3) && config_type == 2
            render_radarconf(4, 3);
            % Power or SNR, Bistatic
            set(hTxGaintxt, 'String', [getString(message('phased:apps:radareqapp:TxGain')) ':']);
            set(hTgtRngRx, 'String', [getString(message('phased:apps:radareqapp:TgtRangeRx')) ':']);
            set(hTgtRngTx, 'String', [getString(message('phased:apps:radareqapp:TgtRangeTx')) ':']);
            toggle_key = {'on', 'on', ...
                'on', 'on', 'on', ...
                'on', 'on', 'on', ...
                'on', 'on', 'on'};
            toggle_radarconfig_ui(toggle_key);
        end
    end

    function toggle_radarconfig_ui(toggle_key)
        % Toggles visibility of radar config ui components
        set(hTxGainedt, 'Visible', toggle_key{1});
        set(hTxGaintxt, 'Visible', toggle_key{2});
        set(hRxGainedt, 'Visible', toggle_key{3});
        set(hRxGaintxt, 'Visible', toggle_key{4});
        set(hRxGainunit, 'Visible', toggle_key{5});
        set(hTgtRngTx, 'Visible', toggle_key{6});
        set(hTgtRngTxedt, 'Visible', toggle_key{7});
        set(hTgtRngTxunit, 'Visible', toggle_key{8});
        set(hTgtRngRx, 'Visible', toggle_key{9});
        set(hTgtRngRxedt, 'Visible', toggle_key{10});
        set(hTgtRngRxunit, 'Visible', toggle_key{11});
    end

    function render_power_snr(calc_type)
        % Manages dynamic rendering of Power and SNR related ui controls.
        if calc_type == 1 % Range
            % Show both power and snr ui controls
            toggle_key = {'on', 'on', 'on', ...
                'on', 'on', 'on', 'on'};
            toggle_power_snr(toggle_key);
            swap_power_snr_pos(1, 2);
        elseif calc_type == 2  % Power
            % Hide peak power uicontrols when Peak Power chosen for calc            
            % Toggle visibility
            swap_power_snr_pos(2, 1);   % Reposition
            % Visibility
            toggle_key = {'off', 'off', 'off', ...
                'on', 'on', 'on', 'on'};
            toggle_power_snr(toggle_key);
        elseif calc_type == 3   % SNR
            % Hide SNR uicontrols when SNR is chosen for calculation 
            btn_label = get(hSnrDetbtn, 'String');
            % If detection setting was open, close it too.
            if strcmp(btn_label, DBLLTARROW)  % If detection setting was open
                switch_snrdetpanel('off');
                set(hSnredt, 'Enable', 'on');
                set(hSnrDetbtn, 'String', DBLRTARROW);
            end
            swap_power_snr_pos(1, 2);
            toggle_key = {'on', 'on', 'on', ...
                'off', 'off', 'off', 'off'};
            toggle_power_snr(toggle_key);
        end
    end

    function swap_power_snr_pos(power_pos, snr_pos)
        % Swaps position of power ans snr uicontrols
        remove_pow_lm();
        remove_snr_lm();
        layout_snr(snr_pos);
        %%drawnow();
        layout_power(power_pos);
        hLmanPowSnr.HorizontalWeights = [1 1 0 0];
        hLmanPowSnr.update();        
    end

    function remove_pow_lm()
        % Remove Power uicontrols from LM
        hLmanPowSnr.remove(hPeakpowtxt);
        hLmanPowSnr.remove(hPeakpowedt);
        hLmanPowSnr.remove(hPeakpowerunit);        
    end

    function remove_snr_lm()
        % Remove from LM
        hLmanPowSnr.remove(hSnrtxt);
        hLmanPowSnr.remove(hSnredt);
        hLmanPowSnr.remove(hSnrunit);
        hLmanPowSnr.remove(hSnrDetbtn);        
    end

    function layout_power(pos)
        % Layout power ui controls at row pos
        hLmanPowSnr.add(hPeakpowtxt, pos, 1:2, 'Fill', 'Horizontal', ...
            'TopInset', 5, 'Anchor', 'NorthWest');
        % 'MinimumHeight', TEXT_HEIGHT);
        hLmanPowSnr.add(hPeakpowedt, pos, 3, 'MinimumWidth', EDIT_WIDTH, ...
            'MinimumHeight', EDIT_HEIGHT, 'Anchor', 'North' );
        hLmanPowSnr.add(hPeakpowerunit, pos, 4, 'MinimumWidth', 0.95*UNIT_WIDTH, ...
            'MinimumHeight', UNIT_HEIGHT, 'TopInset', 0.95*UNIT_INSET);
        hLmanPowSnr.update();
        %drawnow();
    end

    function layout_snr(pos)
        % Layout snr ui controls at row pos
        hLmanPowSnr.add(hSnrtxt, pos, 1, 'MinimumWidth', 35, ...
            'TopInset', 5, 'Anchor', 'NorthWest');
        hLmanPowSnr.add(hSnrDetbtn, pos, 2,'Anchor', 'Northwest',...
            'MinimumWidth', 35, 'MinimumHeight', SNRBTN_HEIGHT, 'LeftInset', -70);
        hLmanPowSnr.add(hSnredt, pos, 3, 'MinimumWidth', EDIT_WIDTH, ...
            'MinimumHeight', EDIT_HEIGHT, 'Anchor', 'Northeast');
        hLmanPowSnr.add(hSnrunit, pos, 4, 'MinimumWidth', 0.95*UNIT_WIDTH , ...
            'TopInset', 5);
        hLmanPowSnr.update();
    end

    function toggle_power_snr(toggle_key)
        % Makes power and snr related ui controls visible or invisible
        % according to the toggle_key
        set(hPeakpowtxt, 'Visible', toggle_key{1});
        set(hPeakpowedt, 'Visible', toggle_key{2});
        set(hPeakpowerunit, 'Visible', toggle_key{3});
        
        set(hSnrtxt, 'Visible', toggle_key{4});
        set(hSnredt, 'Visible', toggle_key{5});
        set(hSnrDetbtn, 'Visible', toggle_key{6});
        set(hSnrunit, 'Visible', toggle_key{7});
    end

    function resize_gui(size_state, rszlen)
        % Resize the main GUI figure when SNR detection assistant button is
        % pressed. size_state: Is a string set to 'on' or 'off'. When set
        % to 'on' the size is increased and vice versa when set to 'off'.
        % rszlen: The resize height value
        if strcmp(size_state, 'on')
            set(hGui, 'Position', get(hGui, 'Position') + [0 -rszlen 0 rszlen]);
        elseif strcmp(size_state, 'off')
            set(hGui, 'Position', get(hGui, 'Position') + [0 rszlen 0 -rszlen]);
        end
        drawnow();
    end

    function populate_pdpfa()
        % Populate Pd edit box using SNR value and Pfa ( set to 1e-5 by
        % default). This function is called when user sets the SNR edit
        % box.
        SNRdB = str2double(get(hSnredt, 'String'));
        num_pulses = str2double(get(hNumPulseedt, 'String'));
        tgt_case = get(hSwerlingNumpopup, 'Value');
        pfa = str2double(get(hProbFaedt,'String'));
        pd = get_pdpfa(SNRdB, pfa, num_pulses, tgt_case);
        % Round off to two decimal places, shnidman limits Pd <= 0.99
        %pd = round(pd*100)/100; 
        set(hProbDetedt, 'String', num2str(pd));
        set(hProbFaedt, 'String', num2str(pfa, 3));
        setappdata(hSnredt, 'probfa', get(hProbFaedt, 'String'));
        setappdata(hProbDetedt, 'probdet', get(hProbDetedt, 'String'));
        setappdata(hProbFaedt, 'probfa', get(hProbFaedt, 'String'));
    end

    function update_snr_Callback()
        Pfa = str2double(get(hProbFaedt, 'String'));
        Pd = str2double(get(hProbDetedt,'String'));
        N = str2double(get(hNumPulseedt, 'String'));
        
        swerling_num = get(hSwerlingNumpopup, 'Value') - 1;
        try
            SNRdB = shnidman(Pd, Pfa, N, swerling_num);
        catch errObj
            oldPfa = get(hProbFaedt, 'String');
            oldPd = get(hProbDetedt, 'String');
            oldN = get(hNumPulseedt, 'String');
            oldSwerling = get(hSwerlingNumpopup, 'Value') - 1;
            errordlg(errObj.message, 'Invalid Input', 'modal');
            set(hProbFaedt, 'String', oldPfa);
            set(hProbDetedt, 'String', oldPd);
            set(hNumPulseedt, 'String', oldN);
            set(hSwerlingNumpopup, 'Value', oldSwerling);
            return;
        end
        % Round off to two decimal places to match with rocsnr results
        %SNRdB = round((SNRdB)*10)/10; 
        set(hSnredt, 'String', num2str(SNRdB));
        setappdata(hSnredt, 'snr', get(hSnredt, 'String'));
    end

    function [pd, pfa] = get_pdpfa(SNRdB, pfa, num_pulses, tgt_case)
        % Returns probability of detection for given SNR and Pfa using the
        % builtin function rocsnr() Signal type dictionary
        signaltype = {'NonfluctuatingNoncoherent', ...
            'Swerling1', ...
            'Swerling2', ...
            'Swerling3', ...
            'Swerling4'};
        
        % Get Pd using rocsnr for giving SNR, keep Pfa max
        [pd, pfa] = rocsnr(SNRdB, 'NumPulses', num_pulses, ...
             'MaxPfa', pfa, 'MinPfa', pfa/10, 'SignalType', signaltype{tgt_case}, 'NumPoints', 1);            
    end

    function switch_snrdetpanel(state)
        % Handles all the actions required when showing or hiding the
        % detection setting panel
        if strcmp(state, 'on')
            switch_lines('off');
            drawnow();
            % Resize GUI
            resize_gui('on', RSZ_HEIGHT);
            switch_lines('on');
            drawnow();
            % Display SnrDet panel
            hLmanParm.add(hSnrDetpanel, 4, 1, 'MinimumWidth', GUI_WIDTH - 20, ...
                'MinimumHeight', RSZ_HEIGHT-10, 'Anchor', 'Northwest', 'LeftInset', -5);
            set(hSnrDetpanel, 'Visible', 'on');
        elseif strcmp(state, 'off')
            switch_lines('off');
            % Hide SnrDet panel
            set(hSnrDetpanel, 'Visible', 'off');
            hLmanParm.remove(hSnrDetpanel);
            drawnow();
            % Resize GUI
            resize_gui('off', RSZ_HEIGHT);
            switch_lines('on');
            drawnow();
        end
    end

    function switch_lines(state)
        % Switch visibility of two horizontal lines
        set(hLineWB, 'Visible', state);
        set(hLineBB, 'Visible', state);
        set(hLineWT, 'Visible', state);
        set(hLineBT, 'Visible', state);
    end

    function radarparm = get_parm_struct()
        % Create radarparm structure to hold all parameters in the GUI
        radarparm.calc_type = get(hCalcpopup, 'Value');
        radarparm.config_type = get(hRadarConfigpopup, 'Value');
        radarparm.wavelen = str2double(get(hWavelenedt, 'String'))*Units.Wavelength;
        radarparm.pwidth = str2double(get(hPwidthedt, 'String'))*Units.Pulsewidth;
        radarparm.sysloss = str2double(get(hSyslossedt, 'String'));
        radarparm.noisetemp = str2double(get(hNoisetempedt, 'String'));
        radarparm.txgain = str2double(get(hTxGainedt, 'String'));
        radarparm.rxgain = str2double(get(hRxGainedt, 'String'));
        radarparm.radxsec = str2double(get(hRcsedt, 'String'));
        if get(hRcsunit, 'Value') == 2   % Unit specified as dBsm
            radarparm.radxsec = db2pow(radarparm.radxsec);
        end        
        radarparm.Pt = str2double(get(hPeakpowedt, 'String'))*Units.Power;
        if (Units.Power == 4)
            % Power unit was dbW
            % Use db2pow after reverting multiplication by factor
            radarparm.Pt = db2pow(radarparm.Pt/Units.Power); 
        end
        radarparm.rangetx = str2double(get(hTgtRngTxedt, 'String'))*Units.RangeTx;
        radarparm.rangerx = str2double(get(hTgtRngRxedt, 'String'))*Units.RangeRx;
        radarparm.SNR = str2double(get(hSnredt, 'String'));
        radarparm.result = guidata(hGui);
        
        radarparm.Pd = str2double(get(hProbDetedt, 'String'));
        radarparm.Pfa = str2double(get(hProbFaedt, 'String'));
        radarparm.numpulse = str2double(get(hNumPulseedt, 'String'));
        radarparm.swerlingcase = get(hSwerlingNumpopup, 'Value') - 1;
        
        if strcmp(get(hSnrDetbtn, 'String'), DBLRTARROW)
            radarparm.detection = 0;    % OFF
        elseif strcmp(get(hSnrDetbtn, 'String'), DBLLTARROW)
            radarparm.detection = 1;    % ON
        end
    end

    function render_radarconf(pos1, pos2)
        % Renders radar configuration group pos1 : Position of TgtRangeTx
        % controls pos2 : Receiver gain controls. These two controls need
        % to switch place when bistatic config is selected for range
        % calculation.
        hLmanRadConfig = siglayout.gridbaglayout(hRadConfigPanel, ...
            'VerticalGap', 5, 'HorizontalGap', 5);
        hLmanRadConfig.add(hRadarConfigtxt, 1, 1,'Fill', 'Horizontal','TopInset', 5, 'LeftInset', 2);
        hLmanRadConfig.add(hTxGaintxt, 2, 1, 'Fill', 'Horizontal', 'TopInset', 5, 'LeftInset', 2);
        hLmanRadConfig.add(hRxGaintxt, pos1, 1, 'Fill', 'Horizontal', 'TopInset', 5, 'LeftInset', 2);
        hLmanRadConfig.add(hTgtRngTx, pos2, 1, 'Fill', 'Horizontal', 'TopInset', 5, 'LeftInset', 2);
        hLmanRadConfig.add(hTgtRngRx, 5, 1, 'Fill', 'Horizontal', 'TopInset', 5, 'LeftInset', 2);
        
        hLmanRadConfig.add(hRadarConfigpopup, 1, 2:3, 'Fill', 'Horizontal');
        
        hLmanRadConfig.add(hTxGainedt, 2, 2, 'MinimumWidth', EDIT_WIDTH, ...
            'MinimumHeight', 25);
        hLmanRadConfig.add(hRxGainedt, pos1, 2, 'MinimumWidth', EDIT_WIDTH, ...
            'MinimumHeight', 25);
        hLmanRadConfig.add(hTgtRngTxedt, pos2, 2, 'MinimumWidth', EDIT_WIDTH, ...
            'MinimumHeight', 25);
        hLmanRadConfig.add(hTgtRngRxedt, 5, 2, 'MinimumWidth', EDIT_WIDTH, ...
            'MinimumHeight', 25);
        
        hLmanRadConfig.add(hTxGainunit, 2, 3, 'MinimumWidth', UNIT_WIDTH, ...
            'TopInset', 5);
        hLmanRadConfig.add(hRxGainunit, pos1, 3, 'MinimumWidth', UNIT_WIDTH, ...
            'TopInset', 5);
        
        hLmanRadConfig.add(hTgtRngTxunit, pos2, 3, 'MinimumWidth', UNIT_WIDTH, ...
            'MinimumHeight', UNIT_HEIGHT, ...
            'TopInset', UNIT_INSET);
        
        hLmanRadConfig.add(hTgtRngRxunit, 5, 3, 'MinimumWidth', UNIT_WIDTH, ...
            'MinimumHeight', UNIT_HEIGHT, ...
            'TopInset', UNIT_INSET);
        hLmanRadConfig.HorizontalWeights = [1 0 0];
        drawnow();
    end
end
% [EOF]


