Skip to content

Commit

Permalink
wip color picker
Browse files Browse the repository at this point in the history
  • Loading branch information
ArthurHeitmann committed Nov 2, 2024
1 parent f7608e6 commit b205024
Show file tree
Hide file tree
Showing 12 changed files with 781 additions and 163 deletions.
10 changes: 7 additions & 3 deletions lib/stateManagement/openFiles/types/xml/sync/syncServer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ bool _startupCompleted() {
}

void startSyncServer() async {
final server = await HttpServer.bind("localhost", wsPort);
server.transform(WebSocketTransformer()).listen(_handleWebSocket);
serverStartTime = DateTime.now();
try {
final server = await HttpServer.bind("localhost", wsPort);
server.transform(WebSocketTransformer()).listen(_handleWebSocket);
serverStartTime = DateTime.now();
} catch (e) {
print("Failed to start local server. Maybe already running");
}
}
4 changes: 2 additions & 2 deletions lib/stateManagement/preferencesData.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class PreferencesData extends OpenFileData {
SavableProp<String>? lastWwiseProjectDir;
SavableProp<Map>? lastWwiseProjectSettings;
SavableProp<List>? lastHierarchyFiles;
// SavableProp<List<String>>? lastOpenedFiles;
SavableProp<int>? lastColorPickerMode;

PreferencesData._()
: prefsFuture = SharedPreferences.getInstance(),
Expand Down Expand Up @@ -149,7 +149,7 @@ class PreferencesData extends OpenFileData {
lastWwiseProjectDir = SavableProp<String>("lastWwiseProjectDir", _prefs!, "");
lastWwiseProjectSettings = SavableProp("lastWwiseProjectSettings", _prefs!, {});
lastHierarchyFiles = SavableProp("lastHierarchyFiles", _prefs!, []);
// lastOpenedFiles = SavableProp("lastOpenedFiles", _prefs!, []);
lastColorPickerMode = SavableProp("lastColorPickerMode", _prefs!, 0);

await super.load();
_loadingState = LoadingState.loaded;
Expand Down
319 changes: 319 additions & 0 deletions lib/widgets/filesView/types/effect/ColorPicker.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@

import 'dart:math';

import 'package:flutter/material.dart';

import '../../../../stateManagement/Property.dart';
import '../../../../utils/utils.dart';
import '../../../misc/ChangeNotifierWidget.dart';
import 'RgbColorModeFields.dart';

class ColorPicker extends ChangeNotifierWidget {
final VectorProp rgb;
final bool showTextFields;

ColorPicker({super.key, required this.rgb, required this.showTextFields}) : super(notifier: rgb);

@override
State<ColorPicker> createState() => _ColorPickerState();
}

class _ColorPickerState extends ChangeNotifierState<ColorPicker> {
late final double svAreaHeight;
double desiredHue = 0.0;
double desiredSaturation = 0.0;

@override
void initState() {
super.initState();
svAreaHeight = 200 - 25 - (widget.showTextFields ? 40 : 0);
}

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
height: svAreaHeight,
child: GestureDetector(
onPanStart: (details) => onSvDrag(details.localPosition),
onPanUpdate: (details) => onSvDrag(details.localPosition),
child: CustomPaint(
painter: _SvPainter(widget.rgb, desiredHue, desiredSaturation),
),
),
),
GestureDetector(
onPanStart: (details) => onHueDrag(details.localPosition),
onPanUpdate: (details) => onHueDrag(details.localPosition),
child: Container(
height: 25,
padding: const EdgeInsets.symmetric(vertical: 2),
child: CustomPaint(
painter: _HuePainter(widget.rgb, desiredHue),
),
),
),
if (widget.showTextFields)
Padding(
padding: const EdgeInsets.all(4.0),
child: RgbColorModeFields(rgb: widget.rgb),
),
],
);
}

void onHueDrag(Offset pos) {
var renderBox = context.findRenderObject() as RenderBox;
var size = renderBox.size;
var hue = clamp(pos.dx / size.width, 0.0, 0.999);
var sat = _rgbToSaturation(widget.rgb.map((e) => e.value.toDouble()).toList());
var val = _rgbToValue(widget.rgb.map((e) => e.value.toDouble()).toList());
var rgb = _hsvToRgb(hue, sat, val);
var oldRgb = widget.rgb.map((e) => e.value.toDouble()).toList();
var brightness = _scaleFactor(oldRgb);
for (var i = 0; i < 3; i++) {
widget.rgb[i].value = rgb[i] * brightness;
}
desiredHue = hue;
setState(() {});
}

void onSvDrag(Offset pos) {
var renderBox = context.findRenderObject() as RenderBox;
var size = renderBox.size;
var sat = clamp(pos.dx / size.width, 0.0, 1.0);
var val = 1.0 - clamp(pos.dy / svAreaHeight, 0.0, 1.0);
var hue = _rgbToHue(widget.rgb.map((e) => e.value.toDouble()).toList());
var oldRgb = widget.rgb.map((e) => e.value.toDouble()).toList();
hue = _hueOrDesired(hue, _rgbToSaturation(oldRgb), _rgbToValue(oldRgb), desiredHue);
var rgb = _hsvToRgb(hue, sat, val);
var brightness = _scaleFactor(oldRgb);
var newTempBrightness = rgb.reduce(max);
var brightnessFactor = brightness > 1 && val > 0.9 && newTempBrightness > 0 ? brightness / newTempBrightness : 1;
for (var i = 0; i < 3; i++) {
widget.rgb[i].value = rgb[i] * brightnessFactor;
}
desiredSaturation = sat;
setState(() {});
}
}

class _HuePainter extends CustomPainter {
final VectorProp rgb;
final double desiredHue;
double lastHue = -1;

_HuePainter(this.rgb, this.desiredHue);

@override
void paint(Canvas canvas, Size size) {
const colors = [
(0, Color.fromARGB(255, 255, 0, 0)),
(60, Color.fromARGB(255, 255, 255, 0)),
(120, Color.fromARGB(255, 0, 255, 0)),
(180, Color.fromARGB(255, 0, 255, 255)),
(240, Color.fromARGB(255, 0, 0, 255)),
(300, Color.fromARGB(255, 255, 0, 255)),
(360, Color.fromARGB(255, 255, 0, 0)),
];

const barHeight = 10.0;
var centerRect = Rect.fromLTWH(0, (size.height - barHeight) / 2, size.width, barHeight);

var gradientPaint = Paint()
..shader = LinearGradient(
colors: colors.map((e) => e.$2).toList(),
stops: colors.map((e) => e.$1 / 360).toList(),
).createShader(centerRect);

canvas.drawRect(centerRect, gradientPaint);

var hue = _getHue();
var rgbHue = _hueToRgb(hue).map((e) => (e * 255).round()).toList();
var radius = size.height / 2 - 2;
var circleOffset = Offset(hue * size.width, size.height / 2);
canvas.drawCircle(
circleOffset,
radius + 2,
Paint()..color = Colors.white
);
canvas.drawCircle(
circleOffset,
radius,
Paint()..color = Color.fromARGB(255, rgbHue[0], rgbHue[1], rgbHue[2])
);


lastHue = hue;
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => _getHue() != lastHue;

double _getHue() {
var rgb = this.rgb.map((e) => e.value.toDouble()).toList();
var hue = _hueOrDesired(_rgbToHue(rgb), _rgbToSaturation(rgb), _rgbToValue(rgb), desiredHue);
return hue;
}
}

class _SvPainter extends CustomPainter {
final VectorProp rgb;
final double desiredHue;
final double desiredSaturation;
String lastValue = "";

_SvPainter(this.rgb, this.desiredHue, this.desiredSaturation);

@override
void paint(Canvas canvas, Size size) {
var rgb = this.rgb.map((e) => e.value.toDouble()).toList();
var scale = _scaleFactor(rgb);
rgb = rgb.map((e) => e / scale).toList();
var hue = _hueOrDesired(_rgbToHue(rgb), _rgbToSaturation(rgb), _rgbToValue(rgb), desiredHue);
var hueRgb = _hueToRgb(hue).map((e) => (e * 255).round()).toList();
var rect = Rect.fromLTWH(0, 0, size.width, size.height);
var whiteHueGradient = LinearGradient(
colors: [
Colors.white,
Color.fromARGB(255, hueRgb[0], hueRgb[1], hueRgb[2]),
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
).createShader(rect);
var blackMaskGradient = LinearGradient(
colors: [
Colors.white,
Colors.black,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
).createShader(rect);

canvas.drawRect(
rect,
Paint()
..shader = whiteHueGradient
);
canvas.drawRect(
rect,
Paint()
..shader = blackMaskGradient
..blendMode = BlendMode.multiply
);

var value = _rgbToValue(rgb);
var saturation = _saturationOrDesired(_rgbToSaturation(rgb), value, desiredSaturation);
var circleOffset = Offset(saturation * size.width, (1 - value) * size.height);
var radius = 10.5;
canvas.drawCircle(
circleOffset,
radius,
Paint()..color = Colors.white
);
var rgb255 = rgb.map((e) => (e * 255).round()).toList();
canvas.drawCircle(
circleOffset,
radius - 2,
Paint()..color = Color.fromARGB(255, rgb255[0], rgb255[1], rgb255[2])
);

lastValue = this.rgb.toString();
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => rgb.toString() != lastValue;
}

double _rgbToHue(List<double> rgb) {
var scale = _scaleFactor(rgb);
rgb = rgb.map((e) => e / scale).toList();
var maxVal = rgb.reduce(max);
var minVal = rgb.reduce(min);
var delta = maxVal - minVal;
if (delta == 0) {
return 0;
}
var hue = 0.0;
if (maxVal == rgb[0]) {
hue = (rgb[1] - rgb[2]) / delta;
} else if (maxVal == rgb[1]) {
hue = 2 + (rgb[2] - rgb[0]) / delta;
} else {
hue = 4 + (rgb[0] - rgb[1]) / delta;
}
hue *= 60;
if (hue < 0) {
hue += 360;
}
return hue / 360;
}

double _rgbToSaturation(List<double> rgb) {
var maxVal = rgb.reduce(max);
var minVal = rgb.reduce(min);
if (maxVal == 0) {
return 0;
}
return (maxVal - minVal) / maxVal;
}

double _rgbToValue(List<double> rgb) {
var scale = _scaleFactor(rgb);
return rgb.reduce(max) / scale;
}

List<double> _hueToRgb(double h) {
var kr = (5 + h * 6) % 6;
var kg = (3 + h * 6) % 6;
var kb = (1 + h * 6) % 6;

var r = 1.0 - max(min(min(kr, 4-kr), 1), 0);
var g = 1.0 - max(min(min(kg, 4-kg), 1), 0);
var b = 1.0 - max(min(min(kb, 4-kb), 1), 0);

return [r, g, b];
}

List<double> _hsvToRgb(double h, double s, double v) {
double r, g, b;

var i = (h * 6).floor();
double f = h * 6 - i;
double p = v * (1 - s);
double q = v * (1 - f * s);
double t = v * (1 - (1 - f) * s);

switch(i % 6){
case 0: r = v; g = t; b = p; break;
case 1: r = q; g = v; b = p; break;
case 2: r = p; g = v; b = t; break;
case 3: r = p; g = q; b = v; break;
case 4: r = t; g = p; b = v; break;
case 5: r = v; g = p; b = q; break;
default: r = 0; g = 0; b = 0; break;
}

return [r, g, b];
}

double _hueOrDesired(double hue, double sat, double val, double desiredHue) {
if (hue == 0 && desiredHue != 0 && (sat == 0 || val == 0)) {
return desiredHue;
}
return hue;
}

double _saturationOrDesired(double sat, double val, double desiredSaturation) {
if (sat == 0 && desiredSaturation != 0 && val == 0) {
return desiredSaturation;
}
return sat;
}

double _scaleFactor(Iterable<double> rgb) {
var maxVal = rgb.reduce(max);
return max(maxVal, 1.0);
}
Loading

0 comments on commit b205024

Please sign in to comment.