feat: rotate (Shift+sag tik), StartupWMClass taskbar gruplama, dist guncelle
Some checks failed
Build Windows / build-windows (push) Has been cancelled

This commit is contained in:
Alhan
2026-07-27 20:41:14 +03:00
parent 35d3bc3749
commit 171476d30b
6 changed files with 179 additions and 34 deletions

View File

@@ -37,6 +37,7 @@ class _ImageCanvasState extends State<ImageCanvas> {
void _clamp() {
if (_vpSize.width <= 0 || _vpSize.height <= 0) return;
if (_angle != 0) return; // rotate varsa serbest pan
if (_isFilled) {
final double w = _vpSize.width * _sc;
final double h = _vpSize.height * _sc;
@@ -153,15 +154,23 @@ class _ImageCanvasState extends State<ImageCanvas> {
void _handleScroll(PointerScrollEvent e) {
if (_vpSize.width <= 0 || _vpSize.height <= 0) return;
final double vx = e.localPosition.dx;
final double vy = e.localPosition.dy;
final double vx = _angle == 0 ? e.localPosition.dx : _vpSize.width / 2;
final double vy = _angle == 0 ? e.localPosition.dy : _vpSize.height / 2;
final double cx = (vx - _tx) / _sc;
final double cy = (vy - _ty) / _sc;
const double factor = 1.1;
final double rawSc = _sc * (e.scrollDelta.dy < 0 ? factor : 1.0 / factor);
final double newSc = rawSc.clamp(1.0, 10.0);
_tx = _tx + cx * _sc - cx * newSc;
_ty = _ty + cy * _sc - cy * newSc;
if (_angle == 0) {
_tx = _tx + cx * _sc - cx * newSc;
_ty = _ty + cy * _sc - cy * newSc;
} else {
// Rotate'li zoom: viewport merkezini koru
final double dw = _vpSize.width * (newSc - _sc);
final double dh = _vpSize.height * (newSc - _sc);
_tx -= dw / 2;
_ty -= dh / 2;
}
_sc = newSc;
_clamp();
setState(() {});
@@ -235,32 +244,39 @@ class _ImageCanvasState extends State<ImageCanvas> {
_interactionMode = 'none';
}
// ── Color filters ──
// ── Combined color filter (saturation × contrast) ──
static const double _rLum = 0.2126;
static const double _gLum = 0.7152;
static const double _bLum = 0.0722;
ColorFilter _buildSaturationFilter() {
final s = _saturation;
final invS = 1.0 - s;
return ColorFilter.matrix(<double>[
invS * _rLum + s, invS * _gLum, invS * _bLum, 0, 0,
invS * _rLum, invS * _gLum + s, invS * _bLum, 0, 0,
invS * _rLum, invS * _gLum, invS * _bLum + s, 0, 0,
0, 0, 0, 1, 0,
]);
}
ColorFilter? _cachedFilter;
double _cachedSat = -1;
double _cachedCon = -1;
ColorFilter _buildContrastFilter() {
ColorFilter _buildCombinedFilter() {
if (_cachedFilter != null && _cachedSat == _saturation && _cachedCon == _contrast) {
return _cachedFilter!;
}
_cachedSat = _saturation;
_cachedCon = _contrast;
final s = _saturation;
final c = _contrast;
final t = (1.0 - c) / 2.0;
return ColorFilter.matrix(<double>[
c, 0, 0, 0, t,
0, c, 0, 0, t,
0, 0, c, 0, t,
0, 0, 0, 1, 0,
final invS = 1.0 - s;
final sR_R = invS * _rLum + s, sR_G = invS * _gLum, sR_B = invS * _bLum;
final sG_R = invS * _rLum, sG_G = invS * _gLum + s, sG_B = invS * _bLum;
final sB_R = invS * _rLum, sB_G = invS * _gLum, sB_B = invS * _bLum + s;
_cachedFilter = ColorFilter.matrix(<double>[
c * sR_R, c * sR_G, c * sR_B, 0, t,
c * sG_R, c * sG_G, c * sG_B, 0, t,
c * sB_R, c * sB_G, c * sB_B, 0, t,
0, 0, 0, 1, 0,
]);
return _cachedFilter!;
}
Widget _buildImage() {
@@ -284,6 +300,29 @@ class _ImageCanvasState extends State<ImageCanvas> {
final vpCenterY = _vpSize.height / 2;
final angleRad = _angle * math.pi / 180;
Widget imageContent = Builder(
builder: (context) {
final hasFilter = _saturation != 1.0 || _contrast != 1.0;
final image = _isFilled
? SizedBox.expand(child: _buildImage())
: Center(child: _buildImage());
return hasFilter
? ColorFiltered(colorFilter: _buildCombinedFilter(), child: image)
: image;
},
);
if (_angle != 0) {
imageContent = Transform(
alignment: Alignment.topLeft,
transform: Matrix4.identity()
..translate(vpCenterX, vpCenterY)
..rotateZ(angleRad)
..translate(-vpCenterX, -vpCenterY),
child: imageContent,
);
}
return SizedBox.expand(
child: Stack(
children: [
@@ -301,20 +340,9 @@ class _ImageCanvasState extends State<ImageCanvas> {
child: Transform(
alignment: Alignment.topLeft,
transform: Matrix4.identity()
..translate(vpCenterX, vpCenterY)
..rotateZ(angleRad)
..translate(-vpCenterX, -vpCenterY)
..translate(_tx, _ty)
..scale(_sc),
child: ColorFiltered(
colorFilter: _buildSaturationFilter(),
child: ColorFiltered(
colorFilter: _buildContrastFilter(),
child: _isFilled
? SizedBox.expand(child: _buildImage())
: Center(child: _buildImage()),
),
),
child: imageContent,
),
),
),