-
Notifications
You must be signed in to change notification settings - Fork 30
Description
Hi,
thanks for the great libraries. I have been trying for a couple of days to add and remove widgets in the docking workspace, but the best that I had is the code below. So my problems are:
-
adding or removing widgets always resets the layout
-
at some point when removing and adding widgets I get errors like:
Exception has occurred.
ArgumentError (Invalid argument(s): DockingParentArea cannot have disposed child) -
there are no example of how to add widgets dynamically (like with a + button or something), but when I try to use addItemOn() sometimes the layout root is null or disappeared, and addItemOnRoot() which seemed ideal doesn't seem to work at all.
I simply want to add a new tab on the right of the workspace when I add a new widget, I will dock it after. I could really use some help please, I've been stuck on this for 2-3 days. Thanks
import 'package:flutter/material.dart';
import 'package:docking/docking.dart';
import 'nav_bar.dart';
class DesktopWorkspace extends StatefulWidget {
const DesktopWorkspace({super.key});
@override
State<DesktopWorkspace> createState() => _DesktopWorkspaceState();
}
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
//// Layout and Widget Management, manages the docking layout and widget list (add/remove functionality)
/////////////////////////////////////////////////////////////////////////////////
class _DesktopWorkspaceState extends State<DesktopWorkspace> {
late DockingLayout _layout; // The docking layout structure
int _widgetCounter = 3; // Counter for generating unique widget IDs
// List of tab items, each representing a widget in the tabbed area
final List<DockingItem> _tabItems = [
DockingItem(
id: 'chart_1',
name: 'Chart 1',
widget: const PlaceholderWidget('Chart'),
),
DockingItem(
id: 'dom_2',
name: 'DOM Ladder 2',
widget: const PlaceholderWidget('DOM'),
),
];
// Initialize the layout with a tabbed area
@override
void initState() {
super.initState();
_layout = DockingLayout(
root: DockingTabs(_tabItems), // Use DockingTabs for tabbed layout
);
}
// Add a new widget to the tabbed area
void _addWidget(String type) {
setState(() {
_widgetCounter++;
final newId = '${type.toLowerCase()}_$_widgetCounter';
final newName = '$type $_widgetCounter';
final newItem = DockingItem(
id: newId,
name: newName,
widget: PlaceholderWidget(newName),
);
_tabItems.add(newItem);
_layout = DockingLayout(root: DockingTabs([..._tabItems]));
});
}
// Remove a widget from the tabbed area by ID
void _removeWidget(String id) {
setState(() {
_tabItems.removeWhere((item) => item.id == id);
_layout = DockingLayout(
root: DockingTabs(_tabItems.isNotEmpty ? [..._tabItems] : []),
);
});
}
///////////////////////////////////////////////////////////////////////////////////////
/// Build Method, combines the navigation bar and themed docking area
///////////////////////////////////////////////////////////////////////////////////////
@override
Widget build(BuildContext context) {
// Get theme data from the dedicated theme section
final (tabTheme, dividerTheme) = _buildTheme();
return Row(
children: [
// Navigation bar for adding/removing widgets
LeftNavBar(
onAddWidget: _addWidget,
onRemoveWidget: _removeWidget,
),
// Main docking area with themed tabs and dividers
Expanded(
child: TabbedViewTheme(
data: tabTheme,
child: MultiSplitViewTheme(
data: dividerTheme,
child: Docking(
layout: _layout,
onItemSelection: (item) {
print('Selected: ${item.name}');
},
onItemClose: (item) {
print('Closed: ${item.name}');
},
),
),
),
),
],
);
}
///////////////////////////////////////////////////////////////////////////////////////
/// Theme Setup
///////////////////////////////////////////////////////////////////////////////////////
(TabbedViewThemeData, MultiSplitViewThemeData) _buildTheme() {
// Tab Theme (TabbedViewThemeData)
final tabTheme = TabbedViewThemeData();
// Tabs Bar: The container holding all tabs
tabTheme.tabsArea
..border = const Border(bottom: BorderSide(color: Colors.transparent, width: 0)) // No bottom border
..middleGap = 0; // No gap between tabs
// Tab Appearance
const borderRadius = BorderRadius.only(
topLeft: Radius.circular(3),
topRight: Radius.circular(3),
);
tabTheme.tab
..normalButtonColor = const Color.fromARGB(255, 225, 225, 225) // Unselected tab background
..padding = const EdgeInsets.symmetric(horizontal: 12, vertical: 4) // Tab size
..textStyle = const TextStyle(fontSize: 10, color: Colors.white) // Tab text (affects dragged tab)
..decoration = const BoxDecoration(
color: Color.fromARGB(255, 25, 25, 25), // Unselected tab background (affects dragged tab)
borderRadius: borderRadius,
)
..selectedStatus.decoration = const BoxDecoration(
color: Color.fromARGB(255, 34, 34, 34), // Selected tab background
border: Border(
bottom: BorderSide(color: Color.fromARGB(0, 0, 195, 255), width: 1), // Blue underline for selected tab
),
borderRadius: borderRadius,
)
;
// Divider Theme (MultiSplitViewThemeData)
final dividerTheme = MultiSplitViewThemeData(
dividerThickness: 3,
dividerPainter: DividerPainters.grooved1(
backgroundColor: const Color.fromARGB(0, 85, 140, 186), // Transparent background
color: Colors.transparent, // Transparent divider
highlightedColor: Colors.blue, // Blue when dragged
),
);
return (tabTheme, dividerTheme);
}
}