Skip to content

Commit 0f2df38

Browse files
authored
Merge branch 'master' into fix-error-badge
2 parents e7f2495 + 55c61f4 commit 0f2df38

4 files changed

Lines changed: 311 additions & 16 deletions

File tree

packages/devtools_app/lib/src/shared/ui/hover.dart

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,21 @@ import 'package:provider/provider.dart';
1414
import 'common_widgets.dart';
1515
import 'utils.dart';
1616

17-
const _maxHoverCardHeight = 250.0;
17+
const _maxHoverCardContentHeight = 250.0;
18+
const _hoverCardTitleHeight = 24.0;
19+
const _hoverCardDividerHeight = 16.0;
20+
21+
/// Returns the total maximum height of the [HoverCard] including content,
22+
/// title (if present), divider, vertical padding, and borders.
23+
double _totalMaxHoverCardHeight({
24+
required bool hasTitle,
25+
double maxCardContentHeight = _maxHoverCardContentHeight,
26+
}) {
27+
return maxCardContentHeight +
28+
(hasTitle ? _hoverCardTitleHeight + _hoverCardDividerHeight : 0.0) +
29+
(denseSpacing * 2) +
30+
(hoverCardBorderSize * 2);
31+
}
1832

1933
TextStyle get _hoverTitleTextStyle => fixBlurryText(
2034
const TextStyle(
@@ -142,9 +156,9 @@ class HoverCard {
142156
required Offset position,
143157
required HoverCardController hoverCardController,
144158
String? title,
145-
double? maxCardHeight,
159+
double? maxCardContentHeight,
146160
}) {
147-
maxCardHeight ??= _maxHoverCardHeight;
161+
maxCardContentHeight ??= _maxHoverCardContentHeight;
148162
final overlayState = Overlay.of(context);
149163
final theme = Theme.of(context);
150164
final colorScheme = theme.colorScheme;
@@ -179,18 +193,24 @@ class HoverCard {
179193
if (title != null) ...[
180194
SizedBox(
181195
width: width,
196+
height: _hoverCardTitleHeight,
182197
child: Text(
183198
title,
184199
overflow: TextOverflow.ellipsis,
185200
style: _hoverTitleTextStyle,
186201
textAlign: TextAlign.center,
187202
),
188203
),
189-
Divider(color: theme.focusColor),
204+
Divider(
205+
color: theme.focusColor,
206+
height: _hoverCardDividerHeight,
207+
),
190208
],
191209
SingleChildScrollView(
192210
child: Container(
193-
constraints: BoxConstraints(maxHeight: maxCardHeight!),
211+
constraints: BoxConstraints(
212+
maxHeight: maxCardContentHeight!,
213+
),
194214
child: contents,
195215
),
196216
),
@@ -215,14 +235,44 @@ class HoverCard {
215235
context: context,
216236
contents: contents,
217237
width: width,
218-
position: Offset(
219-
math.max(0, event.position.dx - (width / 2.0)),
220-
event.position.dy + _hoverYOffset,
238+
position: _calculateCardPositionFromPointerEvent(
239+
context,
240+
event,
241+
width,
242+
title: title,
221243
),
222244
title: title,
223245
hoverCardController: hoverCardController,
224246
);
225247

248+
static Offset _calculateCardPositionFromPointerEvent(
249+
BuildContext context,
250+
PointerHoverEvent event,
251+
double width, {
252+
String? title,
253+
}) {
254+
final overlayBox =
255+
Overlay.of(context).context.findRenderObject() as RenderBox;
256+
final overlaySize = overlayBox.size;
257+
final localPosition = overlayBox.globalToLocal(event.position);
258+
259+
final maxX = math.max(
260+
_hoverMargin,
261+
overlaySize.width - _hoverMargin - width,
262+
);
263+
final x = (localPosition.dx - (width / 2.0)).clamp(_hoverMargin, maxX);
264+
265+
final maxY = math.max(
266+
_hoverMargin,
267+
overlaySize.height -
268+
_hoverMargin -
269+
_totalMaxHoverCardHeight(hasTitle: title != null),
270+
);
271+
final y = (localPosition.dy + _hoverYOffset).clamp(_hoverMargin, maxY);
272+
273+
return Offset(x, y);
274+
}
275+
226276
late OverlayEntry _overlayEntry;
227277

228278
bool _isRemoved = false;
@@ -510,7 +560,10 @@ class _HoverCardTooltipState extends State<HoverCardTooltip> {
510560
title: hoverCardData.title,
511561
contents: hoverCardData.contents,
512562
width: hoverCardData.width,
513-
position: _calculateTooltipPosition(hoverCardData.width),
563+
position: _calculateCardPosition(
564+
hoverCardData.width,
565+
title: hoverCardData.title,
566+
),
514567
hoverCardController: _hoverCardController,
515568
),
516569
);
@@ -537,13 +590,21 @@ class _HoverCardTooltipState extends State<HoverCardTooltip> {
537590
return completer;
538591
}
539592

540-
Offset _calculateTooltipPosition(double width) {
593+
Offset _calculateCardPosition(double width, {String? title}) {
541594
final overlayBox =
542595
Overlay.of(context).context.findRenderObject() as RenderBox;
543596
final box = context.findRenderObject() as RenderBox;
544597

545-
final maxX = overlayBox.size.width - _hoverMargin - width;
546-
final maxY = overlayBox.size.height - _hoverMargin;
598+
final maxX = math.max(
599+
_hoverMargin,
600+
overlayBox.size.width - _hoverMargin - width,
601+
);
602+
final maxY = math.max(
603+
_hoverMargin,
604+
overlayBox.size.height -
605+
_hoverMargin -
606+
_totalMaxHoverCardHeight(hasTitle: title != null),
607+
);
547608

548609
final offset = box.localToGlobal(
549610
box.size.bottomCenter(Offset.zero).translate(-width / 2, _hoverYOffset),

packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ TODO: Remove this section if there are not any updates.
2828
- Fixed an issue where clicking a widget row after collapsing a subtree with the left arrow key unexpectedly re-expanded the subtree. [#9810](https://github.com/flutter/devtools/pull/9810)
2929
- Fixed an issue where collapsing the Inspector widget tree to a single row with the left arrow key caused a loading spinner to appear instead of showing the root node. [#9810](https://github.com/flutter/devtools/pull/9810)
3030
TODO: Remove this section if there are not any updates.
31+
- Fixed an issue where hover tooltips in the widget tree were being clipped by the window boundaries. [#9823](https://github.com/flutter/devtools/pull/9823)
3132

3233
## Performance updates
3334

packages/devtools_app/test/shared/eval_integration_test.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ void main() {
7070
expect(instance2.classRef!.name, '_Future');
7171
},
7272
timeout: const Timeout.factor(2),
73-
// TODO(https://github.com/flutter/devtools/issues/6998): if this flake
73+
// TODO(https://github.com/flutter/devtools/issues/9484): if this flake
7474
// is addressed, we can unskip this for the Flutter customer tests.
7575
tags: skipForCustomerTestsTag,
7676
);
@@ -99,7 +99,7 @@ void main() {
9999
expect(instance.valueAsString, '42');
100100
},
101101
timeout: const Timeout.factor(2),
102-
// TODO(https://github.com/flutter/devtools/issues/6998): if this flake
102+
// TODO(https://github.com/flutter/devtools/issues/9484): if this flake
103103
// is addressed, we can unskip this for the Flutter customer tests.
104104
tags: skipForCustomerTestsTag,
105105
);
@@ -151,10 +151,12 @@ void main() {
151151
expect(error.valueAsString, 'foo');
152152
},
153153
timeout: const Timeout.factor(2),
154-
// TODO(https://github.com/flutter/devtools/issues/6998): if this flake
154+
// TODO(https://github.com/flutter/devtools/issues/9484): if this flake
155155
// is addressed, we can unskip this for the Flutter customer tests.
156156
tags: skipForCustomerTestsTag,
157157
);
158-
});
158+
// TODO(https://github.com/flutter/devtools/issues/9484): if this flake
159+
// is addressed, we can remove the retry.
160+
}, retry: 3);
159161
});
160162
}

0 commit comments

Comments
 (0)