Skip to content

Commit

Permalink
Gutter customization (#167)
Browse files Browse the repository at this point in the history
* WIP

* small rearrangements

* margin adjustments, example added

* variable replaced with getter

* example 03 restored

* ignores removed

* example 4 moved to example 3

* checkbox color changed to transparent white from grey

* GutterStyle renamed instead of creating new file

* GutterStyle.none added

* padding changed

* ignores inlined

* import fixes

* example adjustments

* Code style (#159)

Co-authored-by: Yestay Tastanov <[email protected]>
Co-authored-by: Alexey Inkin <[email protected]>
  • Loading branch information
3 people authored Jan 27, 2023
1 parent 512f229 commit a71e934
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 54 deletions.
43 changes: 41 additions & 2 deletions example/lib/03.change_language_theme/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import 'widgets/dropdown_selector.dart';
const _defaultLanguage = 'java';
const _defaultTheme = 'monokai-sublime';

const toggleButtonColor = Color.fromARGB(124, 255, 255, 255);
const toggleButtonActiveColor = Colors.white;

class HomeScreen extends StatefulWidget {
@override
State<HomeScreen> createState() => _HomeScreenState();
Expand All @@ -17,6 +20,11 @@ class HomeScreen extends StatefulWidget {
class _HomeScreenState extends State<HomeScreen> {
String _language = _defaultLanguage;
String _theme = _defaultTheme;

bool _showNumbers = true;
bool _showErrors = true;
bool _showFoldingHandles = true;

final _codeFieldFocusNode = FocusNode();
late final _codeController = CodeController(
language: builtinLanguages[_language],
Expand All @@ -31,6 +39,33 @@ class _HomeScreenState extends State<HomeScreen> {
appBar: AppBar(
title: const Text('Code Editor by Akvelon'),
actions: [
//
IconButton(
color: _showNumbers ? toggleButtonActiveColor : toggleButtonColor,
onPressed: () => setState(() {
_showNumbers = !_showNumbers;
}),
icon: const Icon(Icons.numbers),
),

IconButton(
color: _showErrors ? toggleButtonActiveColor : toggleButtonColor,
onPressed: () => setState(() {
_showErrors = !_showErrors;
}),
icon: const Icon(Icons.cancel),
),

IconButton(
color: _showFoldingHandles
? toggleButtonActiveColor
: toggleButtonColor,
onPressed: () => setState(() {
_showFoldingHandles = !_showFoldingHandles;
}),
icon: const Icon(Icons.chevron_right),
),
const SizedBox(width: 20),
DropdownSelector(
onChanged: _setLanguage,
icon: Icons.code,
Expand All @@ -44,6 +79,7 @@ class _HomeScreenState extends State<HomeScreen> {
value: _theme,
values: themeList,
),
const SizedBox(width: 20),
],
),
body: ListView(
Expand All @@ -54,10 +90,13 @@ class _HomeScreenState extends State<HomeScreen> {
focusNode: _codeFieldFocusNode,
controller: _codeController,
textStyle: const TextStyle(fontFamily: 'SourceCode'),
lineNumberStyle: const LineNumberStyle(
textStyle: TextStyle(
gutterStyle: GutterStyle(
textStyle: const TextStyle(
color: Colors.purple,
),
showLineNumbers: _showNumbers,
showErrors: _showErrors,
showFoldingHandles: _showFoldingHandles,
),
),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/flutter_code_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export 'src/folding/foldable_block_type.dart';
export 'src/folding/invalid_foldable_block.dart';
export 'src/folding/parsers/highlight.dart';

export 'src/line_numbers/line_number_style.dart';
export 'src/line_numbers/gutter_style.dart';

export 'src/named_sections/named_section.dart';
export 'src/named_sections/parsers/abstract.dart';
Expand Down
46 changes: 28 additions & 18 deletions lib/src/code_field/code_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:linked_scroll_controller/linked_scroll_controller.dart';

import '../code_theme/code_theme.dart';
import '../gutter/gutter.dart';
import '../line_numbers/line_number_style.dart';
import '../line_numbers/gutter_style.dart';
import '../sizes.dart';
import '../wip/autocomplete/popup.dart';
import 'actions/comment_uncomment.dart';
Expand Down Expand Up @@ -106,8 +106,8 @@ class CodeField extends StatefulWidget {
/// language highlight, themeing and modifiers.
final CodeController controller;

/// A LineNumberStyle instance to tweak the line number column styling
final LineNumberStyle lineNumberStyle;
@Deprecated('Use gutterStyle instead')
final GutterStyle lineNumberStyle;

/// {@macro flutter.widgets.textField.cursorColor}
final Color? cursorColor;
Expand All @@ -132,7 +132,11 @@ class CodeField extends StatefulWidget {
final Decoration? decoration;
final TextSelectionThemeData? textSelectionTheme;
final FocusNode? focusNode;
final bool lineNumbers;

@Deprecated('Use gutterStyle instead')
final bool? lineNumbers;

final GutterStyle gutterStyle;

const CodeField({
super.key,
Expand All @@ -145,16 +149,23 @@ class CodeField extends StatefulWidget {
this.decoration,
this.textStyle,
this.padding = EdgeInsets.zero,
this.lineNumberStyle = const LineNumberStyle(),
GutterStyle? gutterStyle,
this.enabled,
this.readOnly = false,
this.cursorColor,
this.textSelectionTheme,
this.lineNumberBuilder,
this.focusNode,
this.onChanged,
this.lineNumbers = true,
});
@Deprecated('Use gutterStyle instead') this.lineNumbers,
@Deprecated('Use gutterStyle instead')
this.lineNumberStyle = const GutterStyle(),
}) : assert(
gutterStyle == null || lineNumbers == null,
'Can not provide gutterStyle and lineNumbers at the same time. '
'Please use gutterStyle and provide necessary columns to show/hide'),
gutterStyle = gutterStyle ??
((lineNumbers == false) ? GutterStyle.none : lineNumberStyle);

@override
State<CodeField> createState() => _CodeFieldState();
Expand Down Expand Up @@ -310,26 +321,25 @@ class _CodeFieldState extends State<CodeField> {
textStyle = defaultTextStyle.merge(widget.textStyle);

final lineNumberSize = textStyle.fontSize;
final lineNumberColor = widget.lineNumberStyle.textStyle?.color ??
textStyle.color?.withOpacity(.5);
final lineNumberColor =
widget.gutterStyle.textStyle?.color ?? textStyle.color?.withOpacity(.5);

final lineNumberTextStyle =
(widget.lineNumberStyle.textStyle ?? textStyle).copyWith(
(widget.gutterStyle.textStyle ?? textStyle).copyWith(
color: lineNumberColor,
fontFamily: textStyle.fontFamily,
fontSize: lineNumberSize,
);

final lineNumberStyle = widget.lineNumberStyle.copyWith(
final gutterStyle = widget.gutterStyle.copyWith(
textStyle: lineNumberTextStyle,
);

Widget? numberCol;

if (widget.lineNumbers) {
numberCol = GutterWidget(
Widget? gutter;
if (gutterStyle.showGutter) {
gutter = GutterWidget(
codeController: widget.controller,
style: lineNumberStyle,
style: gutterStyle,
);
}

Expand Down Expand Up @@ -376,11 +386,11 @@ class _CodeFieldState extends State<CodeField> {
decoration: widget.decoration,
color: backgroundCol,
key: _codeFieldKey,
padding: !widget.lineNumbers ? const EdgeInsets.only(left: 8) : null,
padding: const EdgeInsets.only(left: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.lineNumbers && numberCol != null) numberCol,
if (gutter != null) gutter,
Expanded(
child: Stack(
children: [
Expand Down
78 changes: 54 additions & 24 deletions lib/src/gutter/gutter.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';

import '../code_field/code_controller.dart';
import '../line_numbers/line_number_style.dart';
import '../line_numbers/gutter_style.dart';
import 'error.dart';
import 'fold_toggle.dart';

Expand All @@ -19,7 +19,7 @@ class GutterWidget extends StatelessWidget {
});

final CodeController codeController;
final LineNumberStyle style;
final GutterStyle style;

@override
Widget build(BuildContext context) {
Expand All @@ -32,39 +32,69 @@ class GutterWidget extends StatelessWidget {
Widget _buildOnChange(BuildContext context, Widget? child) {
final code = codeController.code;

final tableRows = [
for (final i in code.hiddenLineRanges.visibleLineNumbers)
TableRow(
children: [
Text(
'${i + 1}',
style: style.textStyle,
textAlign: style.textAlign,
),
const SizedBox(),
const SizedBox(),
],
),
];

_fillIssues(tableRows);
_fillFoldToggles(tableRows);
final gutterWidth = style.width -
(style.showErrors ? 0 : _issueColumnWidth) -
(style.showFoldingHandles ? 0 : _foldingColumnWidth);

final issueColumnWidth = style.showErrors ? _issueColumnWidth : 0.0;
final foldingColumnWidth =
style.showFoldingHandles ? _foldingColumnWidth : 0.0;

final tableRows = List.generate(
code.hiddenLineRanges.visibleLineNumbers.length,
// ignore: prefer_const_constructors
(i) => TableRow(
// ignore: prefer_const_literals_to_create_immutables
children: [
const SizedBox(),
const SizedBox(),
const SizedBox(),
],
),
);

_fillLineNumbers(tableRows);

if (style.showErrors) {
_fillIssues(tableRows);
}
if (style.showFoldingHandles) {
_fillFoldToggles(tableRows);
}

return Container(
padding: EdgeInsets.only(top: 12, bottom: 12, right: style.margin),
width: style.width,
width: style.showLineNumbers ? gutterWidth : null,
child: Table(
columnWidths: const {
_lineNumberColumn: FlexColumnWidth(),
_issueColumn: FixedColumnWidth(_issueColumnWidth),
_foldingColumn: FixedColumnWidth(_foldingColumnWidth),
columnWidths: {
_lineNumberColumn: const FlexColumnWidth(),
_issueColumn: FixedColumnWidth(issueColumnWidth),
_foldingColumn: FixedColumnWidth(foldingColumnWidth),
},
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: tableRows,
),
);
}

void _fillLineNumbers(List<TableRow> tableRows) {
final code = codeController.code;

for (final i in code.hiddenLineRanges.visibleLineNumbers) {
final lineIndex = _lineIndexToTableRowIndex(i);

if (lineIndex == null) {
continue;
}

tableRows[lineIndex].children![_lineNumberColumn] = Text(
style.showLineNumbers ? '${i + 1}' : ' ',
style: style.textStyle,
textAlign: style.textAlign,
);
}
}

void _fillIssues(List<TableRow> tableRows) {
final code = codeController.code;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';

// TODO(alexeyinkin): Rename to GutterStyle when we break compatibility.
class LineNumberStyle {
class GutterStyle {
/// Width of the line number column.
final double width;

Expand All @@ -18,28 +17,55 @@ class LineNumberStyle {
/// half the opacity.
final TextStyle? textStyle;

/// Background of the line number column
/// Background of the line number column.
final Color? background;

/// Central horizontal margin between the numbers and the code.
final double margin;

const LineNumberStyle({
this.width = 80.0,
this.textAlign = TextAlign.right,
/// Whether to show line numbers column.
final bool showLineNumbers;

/// Whether to show errors column.
final bool showErrors;

/// Whether to show folding handles column.
final bool showFoldingHandles;

/// Whether there is any column to show in gutter.
bool get showGutter => showLineNumbers || showErrors || showFoldingHandles;

const GutterStyle({
this.margin = 10.0,
this.textStyle,
this.textAlign = TextAlign.right,
this.showErrors = true,
this.showFoldingHandles = true,
this.showLineNumbers = true,
this.width = 80.0,
this.background,
this.textStyle,
});

LineNumberStyle copyWith({
static const GutterStyle none = GutterStyle(
showErrors: false,
showFoldingHandles: false,
showLineNumbers: false,
);

GutterStyle copyWith({
TextStyle? textStyle,
}) =>
LineNumberStyle(
GutterStyle(
width: width,
textAlign: textAlign,
textStyle: textStyle ?? this.textStyle,
background: background,
margin: margin,
showErrors: showErrors,
showFoldingHandles: showFoldingHandles,
showLineNumbers: showLineNumbers,
);
}

@Deprecated('Renamed to GutterStyle')
typedef LineNumberStyle = GutterStyle;

0 comments on commit a71e934

Please sign in to comment.