Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/lib/editor_autocomplete.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class AutoCompleteEditor extends StatefulWidget {

class _AutoCompleteEditorState extends State<AutoCompleteEditor> {

final CodeLineEditingController _controller = CodeLineEditingController();
final CodeLineEditingController _controller = CodeLineEditingController(contextMenuDelegate: ContextMenuDelegateImpl());

@override
void initState() {
Expand Down
71 changes: 71 additions & 0 deletions example/lib/menu.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class ContextMenuControllerImpl implements SelectionToolbarController {
required LayerLink layerLink,
required ValueNotifier<bool> visibility,
}) {
if(controller.contextMenuDelegate != null && !kIsAndroid && !kIsIOS){
controller.menuController.open(position: anchors.secondaryAnchor);
return;
}
showMenu(
context: context,
position: RelativeRect.fromSize(anchors.primaryAnchor & const Size(150, double.infinity),
Expand Down Expand Up @@ -62,4 +66,71 @@ class ContextMenuControllerImpl implements SelectionToolbarController {
);
}

}

class ContextMenuDelegateImpl implements ContextMenuDelegate{
@override
List<Widget> buildMenuItems({required CodeLineEditingController controller, required BuildContext context}) {
return [
Padding(
padding: const EdgeInsets.all(6.0),
child: Column(children: [

_buildRightMenuItem(context:context, text: 'Cut', onPressed: () {controller.cut();}),
_buildRightMenuItem(context:context, text: 'Copy', onPressed: () {controller.copy();}),
_buildRightMenuItem(context:context, text: 'Paste', onPressed: (){ controller.paste();}),
_buildSubMenu(context: context, text: 'Sub Menu',onPressed: (){}, menuChildren: [_buildRightMenuItem(context:context, text: 'Select All', onPressed: (){ controller.selectAll();})])

],),
)
];
}

Widget _buildRightMenuItem({
required BuildContext context,
required String text,
VoidCallback? onPressed,
bool enabled = true,
}){
final Color textColor = Theme.of(context).brightness == Brightness.light ? const Color.fromRGBO(0, 0, 0, 0.85) : const Color.fromRGBO(255, 255, 255, 0.85);
return MenuItemButton(
style: enabled ? null : Theme.of(context).menuButtonTheme.style?.copyWith(foregroundColor: WidgetStatePropertyAll(textColor.withOpacity(0.5))),
onPressed: enabled ? onPressed : null,
child: SizedBox(
height: 24,
// width: 160,
child: Align(
alignment: Alignment.centerLeft,
child: Text(
text,
strutStyle: const StrutStyle(
fontSize: 11,
leading: 0,
height: 1.1,
// 1.1更居中
forceStrutHeight: true, // 关键属性 强制改为文字高度
),
overflow: TextOverflow.ellipsis,
),),
),
);
}

Widget _buildSubMenu({
required BuildContext context,
required String text,
VoidCallback? onPressed,
bool enabled = true,
required List<Widget> menuChildren,
}) {
return SubmenuButton(
style: Theme.of(context).menuButtonTheme.style?.copyWith(
padding: WidgetStateProperty.all<EdgeInsetsGeometry>(
const EdgeInsets.only(left: 0.0, right: 10.0),
)),
menuChildren: enabled ? menuChildren : [],
child: Text(text),
);
}

}
19 changes: 19 additions & 0 deletions lib/src/_code_line.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@ class _CodeLineEditingControllerImpl extends ValueNotifier<CodeLineEditingValue>
late int _preEditLineIndex;
CodeLineEditingValue? _preValue;
GlobalKey? _editorKey;
@override
final MenuController menuController = MenuController();
@override
final ContextMenuDelegate? contextMenuDelegate;

_CodeLineEditingControllerImpl({
required CodeLines codeLines,
required this.options,
this.spanBuilder,
this.contextMenuDelegate,
}) : super(CodeLineEditingValue(codeLines: codeLines)) {
_cache = _CodeLineEditingCache(this);
_preEditLineIndex = -1;
Expand Down Expand Up @@ -2500,4 +2505,18 @@ class _CodeLineEditingControllerDelegate implements CodeLineEditingController {
_delegate.undo();
}

@override
ContextMenuDelegate? get contextMenuDelegate => delegate.contextMenuDelegate;

@override
MenuController get menuController => delegate.menuController;

}

abstract class ContextMenuDelegate {
List<Widget> buildMenuItems({
required CodeLineEditingController controller,
required BuildContext context,
});

}
33 changes: 20 additions & 13 deletions lib/src/_code_selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete
_onMobileLongPressedStart(details.globalPosition);
_autoScrollWhenDragging();
} else {
widget.selectionOverlayController.showToolbar(context, details.globalPosition);
widget.selectionOverlayController.showToolbar(context, details.globalPosition,details.localPosition);
}
widget.selectionOverlayController.showHandle(context);
},
onLongPressEnd: (details) {
if (_longPressOnSelection != true) {
widget.selectionOverlayController.showToolbar(context, details.globalPosition);
widget.selectionOverlayController.showToolbar(context, details.globalPosition,details.localPosition);
}
_dragPosition = null;
_longPressOnSelection = false;
Expand Down Expand Up @@ -155,7 +155,13 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete
_pointerTapPosition = null;
},
behavior: widget.behavior ?? HitTestBehavior.translucent,
child: widget.child,
child: MenuAnchor(
consumeOutsideTap: true,
anchorTapClosesMenu: true,
controller: widget.controller.menuController,
menuChildren: widget.controller.contextMenuDelegate == null ? [] : widget.controller.contextMenuDelegate!.buildMenuItems(controller: widget.controller, context: context),
child: widget.child,
),
),
);
}
Expand All @@ -181,7 +187,7 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete
kDoubleTapTimeout.inMilliseconds && _pointerTapPosition != null && _pointerTapPosition!.isSamePosition(position)) {
_onDoubleTap(position);
widget.selectionOverlayController.showHandle(context);
widget.selectionOverlayController.showToolbar(context, position);
widget.selectionOverlayController.showToolbar(context, position ,null);
} else {
_pointerTapTimestamp = now;
_pointerTapPosition = position;
Expand Down Expand Up @@ -302,7 +308,7 @@ class _CodeSelectionGestureDetectorState extends State<_CodeSelectionGestureDete
return;
}
widget.controller.clearComposing();
widget.selectionOverlayController.showToolbar(context, details.globalPosition);
widget.selectionOverlayController.showToolbar(context, details.globalPosition,details.localPosition);
}

void _extendSelection(Offset offset, _SelectionChangedCause cause) {
Expand Down Expand Up @@ -417,7 +423,7 @@ abstract class _SelectionOverlayController {

void hideHandle();

void showToolbar(BuildContext context, Offset position);
void showToolbar(BuildContext context, Offset position, Offset? localPosition);

void hideToolbar();

Expand Down Expand Up @@ -451,12 +457,13 @@ class _DesktopSelectionOverlayController implements _SelectionOverlayController
}

@override
void showToolbar(BuildContext context, Offset? position) {
void showToolbar(BuildContext context, Offset? position ,Offset? localPosition ) {
if (position == null) {
return;
}
onShowToolbar(context, TextSelectionToolbarAnchors(
primaryAnchor: position
primaryAnchor: position,
secondaryAnchor: localPosition
), null);
}

Expand Down Expand Up @@ -558,7 +565,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController {
}

@override
void showToolbar(BuildContext context, Offset globalPosition) {
void showToolbar(BuildContext context, Offset globalPosition, Offset? localPosition) {
globalPosition = _clampPosition(globalPosition);
final Rect editingRegion = Rect.fromPoints(
ensureRender.localToGlobal(Offset.zero),
Expand Down Expand Up @@ -696,7 +703,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController {
if (position == null) {
return;
}
showToolbar(_context, position);
showToolbar(_context, position, null);
},
onSelectionHandleDragStart: _handleStartHandleDragStart,
onSelectionHandleDragUpdate: (details) {
Expand Down Expand Up @@ -728,7 +735,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController {
if (position == null) {
return;
}
showToolbar(_context, position);
showToolbar(_context, position, null);
},
onSelectionHandleDragStart: _handleEndHandleDragStart,
onSelectionHandleDragUpdate: (details) {
Expand Down Expand Up @@ -822,7 +829,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController {
void _handleStartHandleDragEnd(DragEndDetails details) {
_startHandleDragging = false;
toolbarVisibility.value = true;
showToolbar(_context, _startHandleDragLastPosition);
showToolbar(_context, _startHandleDragLastPosition, null);
}

void _handleEndHandleDragStart(DragStartDetails details) {
Expand Down Expand Up @@ -901,7 +908,7 @@ class _MobileSelectionOverlayController implements _SelectionOverlayController {
void _handleEndHandleDragEnd(DragEndDetails details) {
_endHandleDragging = false;
toolbarVisibility.value = true;
showToolbar(_context, _endHandleDragLastPosition);
showToolbar(_context, _endHandleDragLastPosition, null);
}

void _autoScrollWhenStartHandleDragging() {
Expand Down
7 changes: 7 additions & 0 deletions lib/src/code_line.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ abstract class CodeLineEditingController extends ValueNotifier<CodeLineEditingVa
CodeLines codeLines = _kInitialCodeLines,
CodeLineOptions options = const CodeLineOptions(),
CodeLineSpanBuilder? spanBuilder,
ContextMenuDelegate? contextMenuDelegate,
}) => _CodeLineEditingControllerImpl(
codeLines: codeLines,
options: options,
spanBuilder: spanBuilder,
contextMenuDelegate: contextMenuDelegate
);

/// Creates a controller for a given text.
Expand Down Expand Up @@ -373,6 +375,11 @@ abstract class CodeLineEditingController extends ValueNotifier<CodeLineEditingVa
required TextSpan textSpan,
required TextStyle style,
});

/// for context menu ,only support desktop
MenuController get menuController;
/// for context menu ,only support desktop
ContextMenuDelegate? get contextMenuDelegate;
}

/// A delegate controller for an editor field.
Expand Down
45 changes: 45 additions & 0 deletions lib/src/code_shortcuts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ enum CodeShortcutType {
replace,
save,
esc,
execute,
executeNewTab,
executeScript,
format
}

abstract class CodeShortcutsActivatorsBuilder {
Expand Down Expand Up @@ -218,6 +222,19 @@ class CodeShortcutSaveIntent extends Intent {
class CodeShortcutEscIntent extends Intent {
const CodeShortcutEscIntent();
}
class CodeShortcutExecuteIntent extends Intent {
const CodeShortcutExecuteIntent();
}
class CodeShortcutExecuteNewTabIntent extends Intent {
const CodeShortcutExecuteNewTabIntent();
}
class CodeShortcutExecuteScriptIntent extends Intent {
const CodeShortcutExecuteScriptIntent();
}
class CodeShortcutFormatIntent extends Intent {
const CodeShortcutFormatIntent();
}


const Map<CodeShortcutType, Intent> kCodeShortcutIntents = {
CodeShortcutType.selectAll: CodeShortcutSelectAllIntent(),
Expand Down Expand Up @@ -270,6 +287,10 @@ const Map<CodeShortcutType, Intent> kCodeShortcutIntents = {
CodeShortcutType.replace: CodeShortcutReplaceIntent(),
CodeShortcutType.save: CodeShortcutSaveIntent(),
CodeShortcutType.esc: CodeShortcutEscIntent(),
CodeShortcutType.execute: CodeShortcutExecuteIntent(),
CodeShortcutType.executeNewTab: CodeShortcutExecuteNewTabIntent(),
CodeShortcutType.executeScript: CodeShortcutExecuteScriptIntent(),
CodeShortcutType.format: CodeShortcutFormatIntent(),
};

const Map<CodeShortcutType, List<ShortcutActivator>> _kDefaultMacCodeShortcutsActivators = {
Expand Down Expand Up @@ -434,6 +455,18 @@ const Map<CodeShortcutType, List<ShortcutActivator>> _kDefaultMacCodeShortcutsAc
CodeShortcutType.esc: [
SingleActivator(LogicalKeyboardKey.escape)
],
CodeShortcutType.execute: [
SingleActivator(LogicalKeyboardKey.enter,meta: true)
],
CodeShortcutType.executeNewTab: [
SingleActivator(LogicalKeyboardKey.backslash,meta: true)
],
CodeShortcutType.executeScript: [
SingleActivator(LogicalKeyboardKey.keyX,alt: true)
],
CodeShortcutType.format: [
SingleActivator(LogicalKeyboardKey.keyF,meta: true,shift: true)
],
};

const Map<CodeShortcutType, List<ShortcutActivator>> _kDefaultCommonCodeShortcutsActivators = {
Expand Down Expand Up @@ -594,4 +627,16 @@ const Map<CodeShortcutType, List<ShortcutActivator>> _kDefaultCommonCodeShortcut
CodeShortcutType.esc: [
SingleActivator(LogicalKeyboardKey.escape)
],
CodeShortcutType.execute: [
SingleActivator(LogicalKeyboardKey.enter,control: true)
],
CodeShortcutType.executeNewTab: [
SingleActivator(LogicalKeyboardKey.backslash,control: true)
],
CodeShortcutType.executeScript: [
SingleActivator(LogicalKeyboardKey.keyX,alt: true)
],
CodeShortcutType.format: [
SingleActivator(LogicalKeyboardKey.keyF,control: true,shift: true)
],
};