showDefineBitFieldsDialog function
- BuildContext context, {
- required String signalName,
- required int width,
- List<
BitFieldDef> ? existingDefs,
Show a dialog to define named bit-field slices on a signal.
Returns the parsed BitFieldDef list, or null if cancelled/empty.
Implementation
Future<List<BitFieldDef>?> showDefineBitFieldsDialog(
BuildContext context, {
required String signalName,
required int width,
List<BitFieldDef>? existingDefs,
}) async {
final maxBit = width - 1;
// Pre-fill with existing definitions if re-editing; append a trailing
// newline and place the cursor at the end so the user can immediately
// type additional fields without accidentally replacing existing ones.
final hasExisting = existingDefs != null && existingDefs.isNotEmpty;
String formatField(BitFieldDef field) => field.high == field.low
? '${field.name} ${field.high}'
: '${field.name} ${field.high}:${field.low}';
final initialText = hasExisting
? '${existingDefs.map(formatField).join('\n')}\n'
: 'field0 $maxBit:0';
final controller = TextEditingController(text: initialText);
if (hasExisting) {
// Cursor at the end (after trailing newline) — ready for a new field.
controller.selection = TextSelection.collapsed(
offset: controller.text.length,
);
} else {
// First time: select all default text for easy replacement.
controller.selection = TextSelection(
baseOffset: 0,
extentOffset: controller.text.length,
);
}
final result = await showDialog<String>(
context: context,
barrierColor: Colors.black26,
builder: (ctx) => AlertDialog(
title: Text(
'$signalName [$width bits] — Define Fields',
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
),
content: SizedBox(
width: 320,
child: TextField(
controller: controller,
autofocus: true,
maxLines: 8,
minLines: 3,
style: const TextStyle(fontFamily: 'monospace', fontSize: 13),
decoration: InputDecoration(
labelText: 'One field per line: name high:low',
hintText: 'exponent $maxBit:${maxBit - 10}\n'
'mantissa ${maxBit - 11}:0',
isDense: true,
border: const OutlineInputBorder(),
),
),
),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(ctx).pop(controller.text),
child: const Text('OK'),
),
],
),
);
if (result == null || result.trim().isEmpty) {
return null;
}
final fields = BitFieldUtils.parseBitFieldDefs(result, maxBit);
return fields.isEmpty ? null : fields;
}