adding packages

This commit is contained in:
2026-01-15 14:38:46 -08:00
parent ef86e3ab6a
commit 6869cf47e5
5253 changed files with 726695 additions and 34 deletions
@@ -0,0 +1,276 @@
import 'package:flutter/material.dart';
import 'src/controller.dart';
import 'src/drag_bar.dart';
import 'src/window.dart';
import 'src/window_group.dart';
export 'src/controller.dart';
export 'src/theme.dart';
export 'src/window.dart';
class GoldenLayout extends StatefulWidget {
final WindowController controller;
final Size popupSize;
final WindowCollection collection;
final WindowTab Function() onAddTab;
final Function() onCloseTab;
const GoldenLayout({
Key key,
@required this.controller,
this.collection,
this.popupSize = const Size(450, 300),
this.onAddTab,
this.onCloseTab,
}) : super(key: key);
@override
_GoldenLayoutState createState() => _GoldenLayoutState();
}
class _GoldenLayoutState extends State<GoldenLayout> {
WindowController _controller;
@override
void initState() {
_controller = widget?.controller ?? WindowController();
if (widget?.collection != null) {
_controller.base = widget.collection;
}
super.initState();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, dimens) {
if (_controller.fullScreen != null) {
return RenderWindowGroup(
onAddTab: widget.onAddTab,
onCancel: (val) {
_controller.addToBase(val);
},
isDragging: _isDragging,
onDraggingChanged: (val) {
if (mounted) {
setState(() {
_isDragging = val;
});
}
},
popUpSize: widget.popupSize,
minimize: true,
group: _controller.fullScreen,
onFullScreen: () {
if (mounted) {
setState(() {
_controller.exitFullScreen();
});
}
},
onClose: !_controller.fullScreen.canClose
? null
: () {
if (mounted) {
setState(() {
_controller.exitFullScreen(true);
});
}
},
update: () {
if (mounted) setState(() {});
},
);
}
return _renderItem(
_controller.base,
index: 0,
size: Size(dimens.maxWidth, dimens.maxHeight),
onChanged: (val) {
if (mounted) {
setState(() {
_controller.base = val;
});
}
},
onClose: (val) {
if (mounted) {
setState(() {
_controller.base = null;
});
}
},
);
});
}
Widget _renderItem(
WindowCollection item, {
@required int index,
@required Size size,
@required ValueChanged<WindowCollection> onChanged,
@required ValueChanged<WindowCollection> onClose,
}) {
if (item is WindowColumn) {
return Column(
children: [
for (var i = 0; i < item.children.length; i++) ...[
Flexible(
flex: (size.height * item.children[i].flex).round(),
child: LayoutBuilder(
builder: (context, dimens) => _renderItem(
item.children[i],
index: i,
size: Size(dimens.maxWidth, dimens.maxHeight),
onChanged: (val) {
if (mounted) {
setState(() {
item.children[i] = val;
});
}
},
onClose: (val) {
if (mounted) {
setState(() {
item.children.remove(val);
});
}
if (item.children.isEmpty) {
onClose(item);
}
},
),
),
),
if (i != item.children.length - 1)
GestureDetector(
onVerticalDragUpdate: (val) {
final _current = size.height * item.children[i].flex;
final _height = val.delta.dy + _current;
if (mounted) {
setState(() {
item.children[i].flex = _height / size.height;
});
}
},
child: HorizontalDragBar(),
),
],
],
);
}
if (item is WindowRow) {
return Row(
children: [
for (var i = 0; i < item.children.length; i++) ...[
Flexible(
flex: (size.width * item.children[i].flex).round(),
child: LayoutBuilder(
builder: (context, dimens) => _renderItem(
item.children[i],
index: i,
size: Size(dimens.maxWidth, dimens.maxHeight),
onChanged: (val) {
if (mounted) {
setState(() {
item.children[i] = val;
});
}
},
onClose: (val) {
if (mounted) {
setState(() {
item.children.remove(val);
});
}
if (item.children.isEmpty) {
onClose(item);
}
},
),
),
),
if (i != item.children.length - 1)
GestureDetector(
onHorizontalDragUpdate: (val) {
final _current = size.width * item.children[i].flex;
final _width = val.delta.dx + _current;
if (mounted) {
setState(() {
item.children[i].flex = _width / size.width;
});
}
},
child: VerticalDragBar(),
),
],
],
);
}
if (item is WindowGroup) {
return RenderWindowGroup(
onAddTab: widget.onAddTab,
onCancel: (val) {
_controller.addToBase(val);
},
onDraggingChanged: (val) {
if (mounted) {
setState(() {
_isDragging = val;
});
}
},
isDragging: _isDragging,
popUpSize: widget.popupSize,
group: item,
onFullScreen: () {
if (mounted) {
setState(() {
_controller.enterFullScreen(item, onClose);
});
}
},
onClose: !item.canClose
? null
: () {
if (mounted) {
setState(() {
item.close();
});
}
if (item.tabs.isEmpty) {
onClose(item);
}
},
update: () {
if (mounted) setState(() {});
},
onModify: (context, tab, pos, [index]) {
final _group = WindowGroup()..addTab(tab);
switch (pos) {
case WindowPos.top:
onChanged(WindowColumn([_group, item]));
break;
case WindowPos.left:
onChanged(WindowRow([_group, item]));
break;
case WindowPos.bottom:
onChanged(WindowColumn([item, _group]));
break;
case WindowPos.right:
onChanged(WindowRow([item, _group]));
break;
case WindowPos.tab:
item.addTab(tab, index);
onChanged(item);
break;
}
if (mounted) setState(() {});
},
);
}
return Container();
}
bool _isDragging = false;
}
@@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import 'dotted_border.dart';
import 'window.dart';
class WindowAcceptRegion extends StatefulWidget {
const WindowAcceptRegion({
Key key,
this.onAccept,
this.top,
this.left,
this.right,
this.bottom,
this.size,
}) : super(key: key);
final void Function(WindowTab) onAccept;
final double top, left, right, bottom;
final Size size;
@override
_WindowAcceptRegionState createState() => _WindowAcceptRegionState();
}
class _WindowAcceptRegionState extends State<WindowAcceptRegion> {
bool accepting = false;
@override
Widget build(BuildContext context) {
return SizedBox.fromSize(
size: widget?.size,
child: LayoutBuilder(
builder: (context, dimens) => Stack(
fit: StackFit.expand,
children: [
IgnorePointer(
child: DashedRect(
color: accepting ? Colors.white : Colors.transparent,
shadowColor:
accepting ? Colors.grey.shade300 : Colors.transparent,
strokeWidth: 2.0,
gap: 5.0,
),
),
Positioned.fill(
left: widget?.left ?? 0,
right: widget?.right ?? 0,
top: widget?.top ?? 0,
bottom: widget?.bottom ?? 0,
child: Container(
child: DragTarget<WindowTab>(
builder: (context, accepted, rejected) => Container(),
onAccept: (val) {
if (mounted) {
setState(() {
accepting = false;
});
}
if (widget.onAccept != null) widget.onAccept(val);
},
onWillAccept: (val) {
if (mounted) {
setState(() {
accepting = true;
});
}
return true;
},
onLeave: (_) {
if (mounted) {
setState(() {
accepting = false;
});
}
},
),
),
),
],
),
),
);
}
}
@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'window.dart';
class WindowController extends ChangeNotifier {
WindowGroup _fullScreenGroup;
WindowGroup get fullScreen => _fullScreenGroup;
void Function(WindowGroup) _closeWindow;
void enterFullScreen(WindowGroup val, void Function(WindowGroup) onClose) {
_fullScreenGroup = val;
_closeWindow = onClose;
notifyListeners();
}
void exitFullScreen([bool close = false]) {
if (close) {
_closeWindow(_fullScreenGroup);
}
_fullScreenGroup = null;
notifyListeners();
}
WindowCollection base = WindowColumn([]);
void addToBase(WindowTab tab) {
if (base == null) {
base = WindowColumn([WindowGroup(tab)]);
} else {
_addTab(base, tab);
}
notifyListeners();
}
bool _addTab(WindowCollection item, WindowTab tab) {
if (item is WindowGroup) {
item.addTab(tab);
item.update();
return true;
}
if (item is WindowColumn) {
for (final child in item.children) {
if (_addTab(child, tab)) {
child.update();
return true;
}
}
}
if (item is WindowRow) {
for (final child in item.children) {
if (_addTab(child, tab)) {
child.update();
return true;
}
}
}
return false;
}
}
@@ -0,0 +1,127 @@
import 'package:flutter/material.dart';
import 'dart:math' as math;
class DashedRect extends StatelessWidget {
final Color color, shadowColor;
final double strokeWidth;
final double gap;
DashedRect({
this.color = Colors.black,
this.shadowColor = Colors.transparent,
this.strokeWidth = 1.0,
this.gap = 5.0,
});
@override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: EdgeInsets.all(strokeWidth / 2),
child: CustomPaint(
painter: DashRectPainter(
color: color,
strokeWidth: strokeWidth,
gap: gap,
shadowColor: shadowColor,
),
),
),
);
}
}
class DashRectPainter extends CustomPainter {
double strokeWidth;
Color color, shadowColor;
double gap;
DashRectPainter({
this.strokeWidth = 5.0,
this.color = Colors.red,
this.shadowColor = Colors.transparent,
this.gap = 5.0,
});
@override
void paint(Canvas canvas, Size size) {
var dashedPaint = Paint()
..color = color
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
var x = size.width;
var y = size.height;
var _topPath = getDashedPath(
a: math.Point(0, 0),
b: math.Point(x, 0),
gap: gap,
);
var _rightPath = getDashedPath(
a: math.Point(x, 0),
b: math.Point(x, y),
gap: gap,
);
var _bottomPath = getDashedPath(
a: math.Point(0, y),
b: math.Point(x, y),
gap: gap,
);
var _leftPath = getDashedPath(
a: math.Point(0, 0),
b: math.Point(0.001, y),
gap: gap,
);
canvas.drawPath(_topPath, dashedPaint..color = shadowColor);
canvas.drawPath(_rightPath, dashedPaint..color = shadowColor);
canvas.drawPath(_bottomPath, dashedPaint..color = shadowColor);
canvas.drawPath(_leftPath, dashedPaint..color = shadowColor);
canvas.drawPath(_topPath, dashedPaint);
canvas.drawPath(_rightPath, dashedPaint);
canvas.drawPath(_bottomPath, dashedPaint);
canvas.drawPath(_leftPath, dashedPaint);
}
Path getDashedPath({
@required math.Point<double> a,
@required math.Point<double> b,
@required num gap,
}) {
var size = Size(b.x - a.x, b.y - a.y);
var path = Path();
path.moveTo(a.x, a.y);
var shouldDraw = true;
var currentPoint = math.Point(a.x, a.y);
num radians = math.atan(size.height / size.width);
num dx = math.cos(radians) * gap < 0
? math.cos(radians) * gap * -1
: math.cos(radians) * gap;
num dy = math.sin(radians) * gap < 0
? math.sin(radians) * gap * -1
: math.sin(radians) * gap;
while (currentPoint.x <= b.x && currentPoint.y <= b.y) {
shouldDraw
? path.lineTo(currentPoint.x, currentPoint.y)
: path.moveTo(currentPoint.x, currentPoint.y);
shouldDraw = !shouldDraw;
currentPoint = math.Point(
currentPoint.x + dx,
currentPoint.y + dy,
);
}
return path;
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
@@ -0,0 +1,75 @@
import 'package:flutter/material.dart';
class HorizontalDragBar extends StatefulWidget {
const HorizontalDragBar({
Key key,
}) : super(key: key);
@override
_HorizontalDragBarState createState() => _HorizontalDragBarState();
}
class _HorizontalDragBarState extends State<HorizontalDragBar> {
bool _onHover = false;
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (_) {
if (mounted) {
setState(() {
_onHover = true;
});
}
},
onExit: (_) {
if (mounted) {
setState(() {
_onHover = false;
});
}
},
child: Divider(
height: 8,
color: _onHover ? Colors.grey : Colors.black,
thickness: 8,
),
);
}
}
class VerticalDragBar extends StatefulWidget {
const VerticalDragBar({
Key key,
}) : super(key: key);
@override
_VerticalDragBarState createState() => _VerticalDragBarState();
}
class _VerticalDragBarState extends State<VerticalDragBar> {
bool _onHover = false;
@override
Widget build(BuildContext context) {
return MouseRegion(
onEnter: (_) {
if (mounted) {
setState(() {
_onHover = true;
});
}
},
onExit: (_) {
if (mounted) {
setState(() {
_onHover = false;
});
}
},
child: VerticalDivider(
width: 8,
color: _onHover ? Colors.grey : Colors.black,
thickness: 8,
),
);
}
}
@@ -0,0 +1,138 @@
// code from: https://github.com/matthew-carroll/flutter_ui_challenge_feature_discovery
// TODO: Use https://github.com/matthew-carroll/fluttery/blob/master/lib/src/layout_overlays.dart
import 'package:flutter/material.dart';
class AnchoredOverlay extends StatelessWidget {
final bool showOverlay;
final Widget Function(BuildContext, Offset anchor) overlayBuilder;
final Widget child;
AnchoredOverlay({
this.showOverlay,
this.overlayBuilder,
this.child,
});
@override
Widget build(BuildContext context) {
return Container(
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return OverlayBuilder(
showOverlay: showOverlay,
overlayBuilder: (BuildContext overlayContext) {
var box = context.findRenderObject() as RenderBox;
final center =
box.size.center(box.localToGlobal(const Offset(0.0, 0.0)));
return overlayBuilder(overlayContext, center);
},
child: child,
);
}),
);
}
}
class OverlayBuilder extends StatefulWidget {
final bool showOverlay;
final Widget Function(BuildContext) overlayBuilder;
final Widget child;
OverlayBuilder({
this.showOverlay = false,
this.overlayBuilder,
this.child,
});
@override
_OverlayBuilderState createState() => _OverlayBuilderState();
}
class _OverlayBuilderState extends State<OverlayBuilder> {
OverlayEntry overlayEntry;
@override
void initState() {
super.initState();
if (widget.showOverlay) {
WidgetsBinding.instance.addPostFrameCallback((_) => showOverlay());
}
}
@override
void didUpdateWidget(OverlayBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
}
@override
void reassemble() {
super.reassemble();
WidgetsBinding.instance.addPostFrameCallback((_) => syncWidgetAndOverlay());
}
@override
void dispose() {
if (isShowingOverlay()) {
hideOverlay();
}
super.dispose();
}
bool isShowingOverlay() => overlayEntry != null;
void showOverlay() {
overlayEntry = OverlayEntry(
builder: widget.overlayBuilder,
);
addToOverlay(overlayEntry);
}
void addToOverlay(OverlayEntry entry) async {
print('addToOverlay');
Overlay.of(context).insert(entry);
}
void hideOverlay() {
print('hideOverlay');
overlayEntry.remove();
overlayEntry = null;
}
void syncWidgetAndOverlay() {
if (isShowingOverlay() && !widget.showOverlay) {
hideOverlay();
} else if (!isShowingOverlay() && widget.showOverlay) {
showOverlay();
}
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
class PositionedOverlay extends StatelessWidget {
final Offset position;
final Widget child;
PositionedOverlay({
this.position,
this.child,
});
@override
Widget build(BuildContext context) {
return Positioned(
top: position.dy,
left: position.dx,
child: FractionalTranslation(
translation: const Offset(-0.5, -0.5),
child: child,
),
);
}
}
@@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
class GoldenLayoutThemeData {
final Color tabSelectedBackgroundColor;
Color tabBackgroundColor;
Color backgroundColor;
final Color draggableBarsHoveredColor;
final Color tabIconColor;
GoldenLayoutThemeData({
this.tabSelectedBackgroundColor = Colors.grey,
this.backgroundColor,
this.draggableBarsHoveredColor = Colors.grey,
this.tabIconColor = Colors.white,
this.tabBackgroundColor,
}) {
tabBackgroundColor ??= Colors.grey.shade700;
backgroundColor ??= Colors.grey.shade800;
}
}
class GoldenLayoutTheme extends InheritedWidget {
GoldenLayoutTheme({
Key key,
@required this.child,
@required this.data,
}) : super(key: key, child: child);
final GoldenLayoutThemeData data;
@override
final Widget child;
GoldenLayoutThemeData get theme => data ?? GoldenLayoutThemeData();
static GoldenLayoutTheme of(BuildContext context) {
return (context.dependOnInheritedWidgetOfExactType<GoldenLayoutTheme>());
}
@override
bool updateShouldNotify(GoldenLayoutTheme oldWidget) {
return data != oldWidget.data;
}
}
@@ -0,0 +1,82 @@
import 'package:flutter/material.dart';
abstract class WindowCollection extends ChangeNotifier {
double flex = 1;
void update() {
notifyListeners();
}
}
class WindowTab {
final String id;
final Widget Function(BuildContext, bool selected, int index) title;
final Widget child;
final bool canClose;
final Function() onClose;
WindowTab(
{@required this.id,
@required this.title,
this.child,
this.canClose = true,
this.onClose});
}
class WindowRow extends WindowCollection {
final List<WindowCollection> children;
WindowRow(this.children);
}
class WindowColumn extends WindowCollection {
final List<WindowCollection> children;
WindowColumn(this.children);
}
class WindowGroup extends WindowCollection {
WindowGroup([WindowTab tab, bool closeable = true]) {
if (tab != null) _tabs.add(tab);
canClose = closeable;
}
bool canClose = true;
final List<WindowTab> _tabs = [];
List<WindowTab> get tabs => _tabs;
int _activeTab = 0;
int get activeTabIndex => _activeTab;
void selectTab(int index) {
_activeTab = index;
notifyListeners();
}
void init(List<WindowTab> tabs) {
_tabs.addAll(tabs);
notifyListeners();
}
void addTab(WindowTab tab, [int index]) {
if (index != null) {
_tabs.insert(index, tab);
_activeTab = index;
} else {
_tabs.add(tab);
_activeTab = _tabs.length - 1;
}
notifyListeners();
}
void removeTab(WindowTab tab) {
_tabs.remove(tab);
if (_activeTab > _tabs.length - 1) {
_activeTab = _tabs.length - 1;
}
notifyListeners();
}
void close() {
if (!canClose) return;
_tabs.clear();
notifyListeners();
}
}
@@ -0,0 +1,322 @@
import 'package:flutter/material.dart';
import 'border_accept.dart';
import 'dotted_border.dart';
import 'theme.dart';
import 'window.dart';
enum WindowPos { top, left, bottom, right, tab }
class RenderWindowGroup extends StatefulWidget {
final WindowGroup group;
final VoidCallback onFullScreen, onClose, update;
final bool minimize;
final Size popUpSize;
final bool isDragging;
final void Function(WindowTab) onCancel;
final ValueChanged<bool> onDraggingChanged;
final void Function(BuildContext, WindowTab, WindowPos, [int index]) onModify;
final WindowTab Function() onAddTab;
const RenderWindowGroup({
Key key,
this.group,
this.onFullScreen,
this.onClose,
this.minimize = false,
this.update,
@required this.onCancel,
@required this.popUpSize,
@required this.onDraggingChanged,
@required this.isDragging,
this.onModify,
@required this.onAddTab,
}) : super(key: key);
@override
_RenderWindowGroupState createState() => _RenderWindowGroupState();
}
class _RenderWindowGroupState extends State<RenderWindowGroup> {
int accepting;
WindowTab _draggingTab;
@override
void initState() {
widget.group.addListener(() {
if (mounted) {
setState(() {});
}
});
super.initState();
}
@override
Widget build(BuildContext context) {
final _theme =
GoldenLayoutTheme.of(context)?.theme ?? GoldenLayoutThemeData();
return Column(
children: [
Container(
color: _theme?.backgroundColor,
height: 32,
child: Row(
children: [
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(width: 4),
for (var i = 0; i < widget.group.tabs.length; i++)
Draggable<WindowTab>(
data: widget.group.tabs[i],
dragAnchor: DragAnchor.child,
onDragStarted: () {
_draggingTab = widget.group.tabs[i];
widget.group.removeTab(_draggingTab);
widget.update();
if (widget.group.tabs.isEmpty) {
widget.onClose?.call();
}
widget.onDraggingChanged(true);
},
onDragCompleted: () {
widget.onDraggingChanged(false);
_draggingTab = null;
},
onDragEnd: (_) {
widget.onDraggingChanged(false);
_draggingTab = null;
},
onDraggableCanceled: (_, __) {
widget.onDraggingChanged(false);
widget.onCancel(_draggingTab);
_draggingTab = null;
},
feedback: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Material(
elevation: 8,
color: Colors.red,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(5),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: widget.group.tabs[i]
.title(context, false, i),
),
),
SizedBox.fromSize(
size: widget.popUpSize,
child:
Material(elevation: 8, child: Container()),
),
],
),
child: DragTarget<WindowTab>(
onLeave: (_) {
if (mounted) {
setState(() {
accepting = null;
});
}
},
onWillAccept: (val) {
if (mounted) {
setState(() {
accepting = i;
});
}
return true;
},
onAccept: (val) {
widget.onModify(
context, val, WindowPos.tab, accepting);
if (mounted) {
setState(() {
accepting = null;
});
}
},
builder: (context, accepted, rejected) {
final selected = i == widget.group.activeTabIndex;
return InkWell(
onTap: () {
widget.group.selectTab(i);
widget.update();
},
child: Container(
decoration: BoxDecoration(
color: selected
? _theme?.tabSelectedBackgroundColor ??
Colors.grey.shade600
: _theme?.backgroundColor,
borderRadius: selected
? BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(5),
)
: null,
),
height: double.infinity,
margin: EdgeInsets.only(
top: 4,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
if (accepting != i)
Container(
child: widget.group.tabs[i]
.title(context, false, i),
),
if (accepting == i)
Container(
width: 100,
height: double.infinity,
child: DashedRect(
color: Colors.white,
shadowColor: Colors.grey.shade300,
strokeWidth: 2.0,
gap: 5.0,
),
),
if (widget.group.tabs[i].canClose &&
selected) ...[
Container(width: 4),
InkWell(
child: Icon(
Icons.close,
size: 18,
color: _theme?.tabIconColor ??
Colors.white,
),
onTap: () {
widget.group.tabs[i].onClose
?.call();
widget.group.removeTab(
widget.group.tabs[i]);
widget.update();
if (widget.group.tabs.isEmpty) {
widget.onClose?.call();
}
},
),
],
if (!selected &&
i + 1 != widget.group.activeTabIndex)
VerticalDivider(
indent: 4,
width: 1,
thickness: 1,
color: Colors.grey.shade500,
),
],
),
),
);
},
),
),
if (widget.onAddTab != null)
IconButton(
iconSize: 20,
icon: Icon(
Icons.add,
color: Colors.white,
),
onPressed: () =>
widget.group.addTab(widget.onAddTab())),
if (widget.isDragging)
WindowAcceptRegion(
size: Size(100, 32),
onAccept: (val) {
widget.group.addTab(val);
widget.update();
},
),
],
),
),
),
IconButton(
color: _theme?.tabIconColor ?? Colors.white,
iconSize: 18,
icon: Icon(widget.minimize ? Icons.minimize : Icons.fullscreen),
onPressed: widget.onFullScreen,
),
if (widget.onClose != null)
IconButton(
color: _theme?.tabIconColor ?? Colors.white,
iconSize: 18,
icon: Icon(Icons.close),
onPressed: widget.onClose,
),
],
),
),
Expanded(
child: LayoutBuilder(
builder: (context, dimens) => Stack(
children: [
Positioned.fill(
child: widget.group.tabs.isEmpty
? Container()
: widget.group.tabs[widget.group.activeTabIndex].child ??
Container(),
),
Positioned(
top: 0,
width: dimens.maxWidth,
height: dimens.minHeight * 0.5,
child: WindowAcceptRegion(
onAccept: (val) =>
widget.onModify(context, val, WindowPos.top),
),
),
Positioned(
bottom: 0,
width: dimens.maxWidth,
height: dimens.minHeight * 0.5,
child: WindowAcceptRegion(
onAccept: (val) =>
widget.onModify(context, val, WindowPos.bottom),
),
),
Positioned(
right: 0,
width: dimens.maxWidth * 0.5,
height: dimens.minHeight,
child: WindowAcceptRegion(
left: dimens.maxWidth * 0.2,
onAccept: (val) =>
widget.onModify(context, val, WindowPos.right),
),
),
Positioned(
left: 0,
width: dimens.maxWidth * 0.5,
height: dimens.minHeight,
child: WindowAcceptRegion(
right: dimens.maxWidth * 0.2,
onAccept: (val) =>
widget.onModify(context, val, WindowPos.left),
),
),
],
),
),
),
],
);
}
}