Files
PiliPlus/lib/common/widgets/disabled_icon.dart
My-Responsitories 7ee6d1e905 tweaks
2026-03-12 11:55:42 +08:00

167 lines
4.3 KiB
Dart

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class DisabledIcon extends SingleChildRenderObjectWidget {
const DisabledIcon({
super.key,
required Widget super.child,
this.disable = false,
this.color,
this.iconSize,
this.lineLengthScale = 0.9,
this.strokeCap = .butt,
});
final bool disable;
final Color? color;
final double? iconSize;
final StrokeCap strokeCap;
final double lineLengthScale;
Icon? get _icon => child is Icon ? child as Icon : null;
@override
RenderObject createRenderObject(BuildContext context) {
late final iconTheme = IconTheme.of(context);
final icon = _icon;
return RenderMaskedIcon(
disable: disable,
iconSize: iconSize ?? icon?.size ?? iconTheme.size ?? 24.0,
color: color ?? icon?.color ?? iconTheme.color!,
strokeCap: strokeCap,
lineLengthScale: lineLengthScale,
);
}
@override
void updateRenderObject(BuildContext context, RenderMaskedIcon renderObject) {
late final iconTheme = IconTheme.of(context);
final icon = _icon;
renderObject
..disable = disable
..iconSize = iconSize ?? icon?.size ?? iconTheme.size ?? 24.0
..color = color ?? icon?.color ?? iconTheme.color!
..strokeCap = strokeCap
..lineLengthScale = lineLengthScale;
}
}
class RenderMaskedIcon extends RenderProxyBox {
RenderMaskedIcon({
required bool disable,
required double iconSize,
required Color color,
required StrokeCap strokeCap,
required double lineLengthScale,
}) : _disable = disable,
_iconSize = iconSize,
_color = color,
_strokeCap = strokeCap,
_lineLengthScale = lineLengthScale;
bool _disable;
bool get disable => _disable;
set disable(bool value) {
if (_disable == value) return;
_disable = value;
markNeedsPaint();
}
double _iconSize;
double get iconSize => _iconSize;
set iconSize(double value) {
if (_iconSize == value) return;
_iconSize = value;
markNeedsPaint();
}
Color _color;
Color get color => _color;
set color(Color value) {
if (_color == value) return;
_color = value;
markNeedsPaint();
}
StrokeCap _strokeCap;
StrokeCap get strokeCap => _strokeCap;
set strokeCap(StrokeCap value) {
if (_strokeCap == value) return;
_strokeCap = value;
markNeedsPaint();
}
double _lineLengthScale;
double get lineLengthScale => _lineLengthScale;
set lineLengthScale(double value) {
if (_lineLengthScale == value) return;
_lineLengthScale = value;
markNeedsPaint();
}
@override
void paint(PaintingContext context, Offset offset) {
if (!disable) {
return super.paint(context, offset);
}
final canvas = context.canvas;
var rectOffset = offset;
Size size = this.size;
final exceedWidth = size.width > _iconSize;
final exceedHeight = size.height > _iconSize;
if (exceedWidth || exceedHeight) {
final dx = exceedWidth ? (size.width - _iconSize) / 2.0 : 0.0;
final dy = exceedHeight ? (size.height - _iconSize) / 2.0 : 0.0;
size = Size.square(_iconSize);
rectOffset += Offset(dx, dy);
} else if (size.width < _iconSize && size.height < _iconSize) {
size = Size.square(_iconSize);
}
final strokeWidth = size.width / 12;
var rect = rectOffset & size;
final sqrt2Width = strokeWidth * sqrt2; // rotate pi / 4
final path = Path.combine(
PathOperation.union,
Path() // bottom
..moveTo(rect.left, rect.bottom)
..lineTo(rect.left, rect.top + sqrt2Width)
..lineTo(rect.right - sqrt2Width, rect.bottom)
..close(),
Path() // top
..moveTo(rect.right, rect.top)
..lineTo(rect.right, rect.bottom - sqrt2Width)
..lineTo(rect.left + sqrt2Width, rect.top),
);
canvas
..save()
..clipPath(path, doAntiAlias: false);
super.paint(context, offset);
canvas.restore();
final linePaint = Paint()
..color = color
..strokeWidth = strokeWidth
..strokeCap = strokeCap;
final strokeOffset = strokeWidth * sqrt1_2 / 2;
rect = rect
.translate(-strokeOffset, strokeOffset)
.deflate(size.width * lineLengthScale);
canvas.drawLine(
rect.topLeft,
rect.bottomRight,
linePaint,
);
}
}