From bb4b9fe1193f554458b4472c25522a0f6a9690ba Mon Sep 17 00:00:00 2001 From: Guy Luz Date: Mon, 21 Jul 2025 02:22:18 +0300 Subject: [PATCH 1/3] Example to include navigation node buttons --- example/lib/main.dart | 32 ++++++++++++++++++++++++++++++- lib/src/models/mind_map_data.dart | 11 ++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index eafa53c..1c7b4f2 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -94,6 +94,9 @@ class _TestScreenState extends State { 'πŸƒ 첫리프', () => _focusToNode(CameraFocus.firstLeaf, null), ), + // Forward/Backward focus buttons + _buildButton('⬅️ 이전', _focusPreviousNode), + _buildButton('λ‹€μŒ ➑️', _focusNextNode), ], ), ), @@ -171,7 +174,7 @@ class _TestScreenState extends State { levelSpacing: 120, nodeMargin: 15, ), - cameraFocus: CameraFocus.fitAll, + cameraFocus: currentFocus, focusNodeId: targetNodeId, focusAnimation: const Duration( milliseconds: 1000, @@ -256,4 +259,31 @@ class _TestScreenState extends State { return '🌳 μ „μ²΄νŠΈλ¦¬'; } } + + void _focusNextNode() { + final flatNodes = mindMapData.flatten(); + if (flatNodes.isEmpty) return; + int currentIdx = flatNodes.indexWhere((n) => n.id == targetNodeId); + int nextIdx = (currentIdx + 1) % flatNodes.length; + final nextNode = flatNodes[nextIdx]; + setState(() { + currentFocus = CameraFocus.custom; + targetNodeId = nextNode.id; + lastAction = 'λ‹€μŒ λ…Έλ“œλ‘œ 이동: ${nextNode.title}'; + }); + } + + void _focusPreviousNode() { + final flatNodes = mindMapData.flatten(); + if (flatNodes.isEmpty) return; + int currentIdx = flatNodes.indexWhere((n) => n.id == targetNodeId); + int prevIdx = (currentIdx - 1); + if (prevIdx < 0) prevIdx = flatNodes.length - 1; + final prevNode = flatNodes[prevIdx]; + setState(() { + currentFocus = CameraFocus.custom; + targetNodeId = prevNode.id; + lastAction = '이전 λ…Έλ“œλ‘œ 이동: ${prevNode.title}'; + }); + } } diff --git a/lib/src/models/mind_map_data.dart b/lib/src/models/mind_map_data.dart index 20985d6..ccb45bb 100644 --- a/lib/src/models/mind_map_data.dart +++ b/lib/src/models/mind_map_data.dart @@ -107,6 +107,15 @@ class MindMapData { @override String toString() { - return 'MindMapData(id: $id, title: $title, children: ${children.length})'; + return 'MindMapData(id: $id, title: $title, children: [36m${children.length} [0m)'; + } + + /// Returns a flat list of all nodes in pre-order traversal (self, then children) + List flatten() { + List result = [this]; + for (final child in children) { + result.addAll(child.flatten()); + } + return result; } } From 74616cebd3df75e366d0ef28954b1e37dd155f49 Mon Sep 17 00:00:00 2001 From: Guy Luz Date: Mon, 21 Jul 2025 02:34:15 +0300 Subject: [PATCH 2/3] Added selection border color to focused nodes --- lib/src/widgets/mind_map_widget.dart | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/src/widgets/mind_map_widget.dart b/lib/src/widgets/mind_map_widget.dart index 7c7ae90..51c1f30 100644 --- a/lib/src/widgets/mind_map_widget.dart +++ b/lib/src/widgets/mind_map_widget.dart @@ -1,13 +1,14 @@ +import 'dart:math' as math; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'dart:math' as math; -import '../models/mind_map_data.dart'; -import '../models/mind_map_style.dart'; -import '../models/mind_map_node.dart'; +import '../enums/camera_focus.dart'; import '../enums/mind_map_layout.dart'; import '../enums/node_shape.dart'; -import '../enums/camera_focus.dart'; +import '../models/mind_map_data.dart'; +import '../models/mind_map_node.dart'; +import '../models/mind_map_style.dart'; // import '../enums/mind_map_type.dart'; import '../painters/mind_map_painter.dart'; import '../painters/node_painter.dart'; @@ -1647,6 +1648,8 @@ class _MindMapWidgetState extends State /// κ°œλ³„ λ…Έλ“œ μœ„μ ― λΉŒλ“œ / Build individual node widget Widget _buildNodeWidget(MindMapNode node) { final isSelected = _selectedNodeId == node.id; + final isFocused = + widget.focusNodeId != null && widget.focusNodeId == node.id; final actualSize = widget.style.getActualNodeSize( node.title, @@ -1747,7 +1750,11 @@ class _MindMapWidgetState extends State final textColor = node.textColor ?? widget.style.defaultTextStyle.color; final borderColor = node.borderColor ?? - (isSelected ? widget.style.selectionBorderColor : Colors.white); + ((isFocused || isSelected) + ? widget.style.selectionBorderColor + : Colors.white); + final borderWidth = + (isFocused || isSelected) ? widget.style.selectionBorderWidth : 2.0; return Positioned( key: ValueKey('positioned_${node.id}'), @@ -1785,8 +1792,7 @@ class _MindMapWidgetState extends State shape: widget.style.nodeShape, fillColor: nodeColor, borderColor: borderColor, - borderWidth: - isSelected ? widget.style.selectionBorderWidth : 2.0, + borderWidth: borderWidth, shadowEnabled: widget.style.enableNodeShadow, shadowColor: widget.style.nodeShadowColor, shadowBlurRadius: widget.style.nodeShadowBlurRadius, From 922766a51ecddcb1032ac267df6933046fb2c8a1 Mon Sep 17 00:00:00 2001 From: Guy Luz Date: Mon, 21 Jul 2025 03:06:59 +0300 Subject: [PATCH 3/3] Fix bug where borderColor was stronger than selectionBorderColor --- example/lib/main.dart | 3 ++- lib/src/widgets/mind_map_widget.dart | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 1c7b4f2..8adc4c8 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -39,8 +39,9 @@ class _TestScreenState extends State { MindMapData( id: 'node1', title: 'πŸ“ λ…Έλ“œ1', + borderColor: Colors.green, children: [ - MindMapData(id: 'sub1', title: 'μ„œλΈŒ1'), + MindMapData(id: 'sub1', title: 'μ„œλΈŒ1', borderColor: Colors.purple), MindMapData(id: 'sub2', title: 'μ„œλΈŒ2'), ], ), diff --git a/lib/src/widgets/mind_map_widget.dart b/lib/src/widgets/mind_map_widget.dart index 51c1f30..0ef3a72 100644 --- a/lib/src/widgets/mind_map_widget.dart +++ b/lib/src/widgets/mind_map_widget.dart @@ -1749,10 +1749,9 @@ class _MindMapWidgetState extends State final nodeColor = node.color; final textColor = node.textColor ?? widget.style.defaultTextStyle.color; final borderColor = - node.borderColor ?? - ((isFocused || isSelected) + (isFocused || isSelected) ? widget.style.selectionBorderColor - : Colors.white); + : (node.borderColor ?? Colors.white); final borderWidth = (isFocused || isSelected) ? widget.style.selectionBorderWidth : 2.0;