Skip to content

Commit 63b78c4

Browse files
committed
fixes to BaseInternalDialog for resizing and adjusting the close button position
1 parent 78c0f01 commit 63b78c4

File tree

1 file changed

+103
-83
lines changed

1 file changed

+103
-83
lines changed

widgets/+wt/+abstract/BaseInternalDialog.m

Lines changed: 103 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
% window. The dialog's lifecycle is tied to the app that launched it.
88
%
99
% This enables compatibility with web apps.
10+
%
11+
% The dialog may flicker when resizing the figure if
12+
% AutoResizeChildren is on. Disabling this is recommended.
1013

1114
% ** This is a prototype component that may change in the future.
1215

@@ -132,7 +135,7 @@
132135
MinimumSize (1,2) double {mustBePositive} = [30 20];
133136

134137
% Buffer border space required on each side when sizing in figure
135-
Buffer (1,1) double {mustBeNonnegative} = 0
138+
% Buffer (1,1) double {mustBeNonnegative} = 0
136139

137140
end %properties
138141

@@ -181,10 +184,12 @@
181184
function obj = BaseInternalDialog(fig, varargin)
182185

183186
arguments
184-
fig matlab.ui.Figure
187+
% Figure parent - Create a figure if not provided
188+
fig (1,1) matlab.ui.Figure = uifigure("AutoResizeChildren","off");
185189
end
186190

187-
arguments(Repeating)
191+
arguments (Repeating)
192+
% Property-value pairs
188193
varargin
189194
end
190195

@@ -209,15 +214,6 @@
209214
% Update the modal image positioning
210215
obj.updateModalImage();
211216

212-
% Listen to resizing of OuterPanel
213-
% (non needed until we make the dialog resizable by user)
214-
% obj.OuterPanel.ResizeFcn = @(~,~)onOuterPanelResize(obj);
215-
216-
% Position over figure by default
217-
if isscalar(obj.Figure) && isvalid(obj.Figure)
218-
obj.positionOver(obj.Figure)
219-
end
220-
221217
end %function
222218

223219
end %methods
@@ -247,58 +243,28 @@ function positionOver(obj, refComp)
247243

248244
% Reference component size and position
249245
refPos = getpixelposition(refComp, true);
250-
refSize = refPos(3:4);
246+
% refSize = refPos(3:4);
251247

252248
% Lower left corner depends if it's a figure
253249
if isa(refComp, "matlab.ui.Figure")
254-
refCornerA = [1 1];
250+
% refCornerA = [1 1];
251+
refPos(1:2) = [1 1];
255252
else
256-
refCornerA = refPos(1:2);
253+
% refCornerA = refPos(1:2);
257254
end
258255

259-
% Dialog size
260-
dlgPos = getpixelposition(obj);
261-
dlgSize = dlgPos(3:4);
262-
263-
% Does it fit entirely within the reference component?
264-
if all(refSize >= dlgSize)
265-
% Yes - center it over the component
266-
267-
% Calculate lower-left corner
268-
dlgPos = floor((refSize - dlgSize) / 2) + refCornerA;
269-
270-
else
271-
% NO - position within the figure
272-
273-
% Get the corners of the figure (bottom left and top right)
274-
figPos = getpixelposition(obj.Parent);
275-
figSize = figPos(3:4);
276-
277-
% Start with dialog position in lower-left of widget
278-
dlgPos = refCornerA;
279-
dlgCornerB = dlgPos + dlgSize;
280-
281-
% Move left and down as needed to fit in figure
282-
adj = figSize - dlgCornerB;
283-
adj(adj>0) = 0;
284-
dlgPos = max(dlgPos + adj, [1 1]);
285-
dlgCornerB = dlgPos + dlgSize;
286-
287-
% If it doesn't fit in the figure, shrink it
288-
adj = figSize - dlgCornerB;
289-
adj(adj>0) = 0;
290-
dlgSize = dlgSize + adj;
256+
% Dialog position
257+
posNew = obj.Position;
291258

292-
end %if
293-
294-
% Disable warning
295-
warnState = warning('off','MATLAB:ui:components:noPositionSetWhenInLayoutContainer');
259+
% Calculate the dialog position
260+
% Request to center over refPos
261+
posNew = calculatePositionWithinBounds(obj, posNew, refPos);
296262

297-
% Set final position
298-
obj.Position = [dlgPos dlgSize];
299-
300-
% Restore warning
301-
warning(warnState)
263+
% Update dialog position
264+
if ~isequal(obj.Position, posNew)
265+
fprintf(" Change position: posOld = %f posNew = %f\n", obj.Position, posNew);
266+
obj.Position = posNew;
267+
end
302268

303269
end %function
304270

@@ -497,9 +463,16 @@ function setup(obj)
497463
obj.TitleFontStyledComponents = [obj.OuterPanel];
498464
obj.FontStyledComponents = [obj.DialogButtons];
499465

466+
% Listen to resizing of OuterPanel
467+
% This enables the close button to stay in the correct spot
468+
obj.OuterPanel.ResizeFcn = @(~,~)onOuterPanelResize(obj);
469+
500470
% Ensure it fits in the figure
501471
obj.resizeToFitFigure();
502472

473+
% Reposition the close button
474+
repositionCloseButton(obj)
475+
503476
end %function
504477

505478

@@ -513,7 +486,10 @@ function update(obj)
513486
end
514487

515488
% Ensure it fits in the figure
516-
obj.resizeToFitFigure();
489+
% This is only needed if AutoResizeChildren is on
490+
if obj.Figure.AutoResizeChildren
491+
obj.resizeToFitFigure();
492+
end
517493

518494
end %function
519495

@@ -585,45 +561,86 @@ function resizeToFitFigure(obj)
585561
obj.updateModalImage();
586562

587563
% Get the current positioning
588-
posD = obj.Position;
589-
szRequest = obj.Size;
590-
posLowerLeft = posD(1:2);
564+
posNew = obj.Position;
565+
% posLowerLeft = posOld(1:2);
566+
567+
% Calculate the dialog size
568+
szDlg = calculateDialogSize(obj);
569+
posNew(3:4) = szDlg;
570+
571+
% Calculate the dialog position
572+
if obj.SetupFinished
573+
posNew = calculatePositionWithinBounds(obj, posNew);
574+
else
575+
% Try to center over figure by default
576+
posFig = getpixelposition(obj.Figure);
577+
posFig(1:2) = 1;
578+
posNew = calculatePositionWithinBounds(obj, posNew, posFig);
579+
end
580+
581+
% Update dialog position
582+
if ~isequal(obj.Position, posNew)
583+
obj.Position = posNew;
584+
end
585+
586+
end %function
587+
588+
589+
function szDlg = calculateDialogSize(obj)
590+
% Calculate the dialog size to use, given the set Size and
591+
% figure constraints
591592

592593
% Get figure size
593594
posFig = getpixelposition(obj.Figure);
594-
szFig = posFig(3:4);
595-
maxSize = szFig - (2 * obj.Buffer);
596595

597-
% Size is the smaller of requested size and figure size with
598-
% buffer space
599-
szDlg = min(szRequest, maxSize);
596+
% Calculate allowed dialog size
597+
szDlg = max( min(obj.Size, posFig(3:4)), obj.MinimumSize);
598+
599+
end %function
600+
600601

601-
% Restrict a minimum size also
602-
szDlg = max(szDlg, obj.MinimumSize);
602+
function posOut = calculatePositionWithinBounds(obj, posIn, posCenter)
603+
% Confirm and verify the position is within the figure bounds
603604

604-
% Calculate fit within figure
605-
posUpperRight = posLowerLeft + szDlg;
606-
if any(posUpperRight > szFig)
607-
posAdjust = szFig - posUpperRight;
608-
posLowerLeft = posLowerLeft + posAdjust;
605+
arguments
606+
obj (1,1) wt.abstract.BaseInternalDialog
607+
posIn (1,4) double {mustBeFinite} %requested [x,y,w,h] location
608+
posCenter (1,4) double = nan(1,4) %optional - center over this [x,y,w,h]
609609
end
610610

611-
% Don't go below 1
612-
posLowerLeft = max(posLowerLeft, 1);
611+
% Default output
612+
posOut = posIn;
613613

614-
% Update dialog position
615-
posNew = [posLowerLeft szDlg];
616-
set(obj,"Position",posNew);
614+
% Get figure size
615+
figPos = getpixelposition(obj.Figure);
616+
figSize = figPos(3:4);
617617

618-
% Reposition the close button
619-
obj.repositionCloseButton();
618+
% Center over a component? (optional posCenter)
619+
if ~any(ismissing(posCenter))
620+
centerPoint = floor(posCenter(1:2) + posCenter(3:4)/2);
621+
posOut(1:2) = floor(centerPoint - posOut(3:4)/2);
622+
end
623+
624+
% Ensure upper right corner is within the figure
625+
dlgUpperRight = posOut(1:2) + posOut(3:4) - [1 1];
626+
if any(dlgUpperRight > figSize)
627+
dlgAdjust = dlgUpperRight - figSize;
628+
dlgAdjust(dlgAdjust < 0) = 0;
629+
posOut(1:2) = posOut(1:2) - dlgAdjust;
630+
end
631+
632+
% Ensure lower left corner is within the figure
633+
posOut(1:2) = max(posOut(1:2), [1 1]);
620634

621635
end %function
622636

623637

624638
function repositionCloseButton(obj)
625639
% Called at end of resize
626640

641+
% Get current position
642+
oldPos = obj.CloseButton.Position;
643+
627644
% Outer panel inner/outer position
628645
outerPos = obj.OuterPanel.OuterPosition;
629646
wO = outerPos(3);
@@ -642,9 +659,12 @@ function repositionCloseButton(obj)
642659
yB = hO - 2*wBorder - hB - 1;
643660
wB = hB;
644661
xB = wO - 2*wBorder - wB - 1;
662+
newPos = floor([xB yB wB hB]);
645663

646664
% Move the close button
647-
set(obj.CloseButton,"Position",[xB yB wB hB]);
665+
if ~isequal(oldPos, newPos)
666+
obj.CloseButton.Position = newPos;
667+
end
648668

649669
end %function
650670

@@ -750,11 +770,11 @@ function onFigureResized(obj,~)
750770
end %function
751771

752772

753-
function onOuterPanelResize(~)
773+
function onOuterPanelResize(obj)
754774
% Triggered when the dialog window is resized
755775

756-
% Ensure it fits in the figure
757-
%obj.resizeToFitFigure();
776+
% Reposition the close button
777+
repositionCloseButton(obj)
758778

759779
end %function
760780

0 commit comments

Comments
 (0)