|
6 | 6 | #include <scratchcpp/istagehandler.h> |
7 | 7 | #include <scratchcpp/value.h> |
8 | 8 | #include <scratchcpp/compilerconstant.h> |
| 9 | +#include <scratchcpp/stringptr.h> |
| 10 | +#include <scratchcpp/string_pool.h> |
9 | 11 |
|
10 | 12 | #include "penblocks.h" |
11 | 13 | #include "penlayer.h" |
|
15 | 17 | using namespace scratchcpprender; |
16 | 18 | using namespace libscratchcpp; |
17 | 19 |
|
| 20 | +inline QColor pen_convert_from_numeric_color(long color) |
| 21 | +{ |
| 22 | + return QColor::fromRgba(static_cast<QRgb>(color)); |
| 23 | +} |
| 24 | + |
| 25 | +static void pen_convert_color(const ValueData *color, QColor &dst) |
| 26 | +{ |
| 27 | + StringPtr *str = string_pool_new(); |
| 28 | + |
| 29 | + if (value_isString(color)) { |
| 30 | + value_toStringPtr(color, str); |
| 31 | + |
| 32 | + if (str->size > 0 && str->data[0] == u'#') { |
| 33 | + if (str->size <= 7) // #RRGGBB |
| 34 | + { |
| 35 | + dst = QColor::fromString(str->data); |
| 36 | + |
| 37 | + if (!dst.isValid()) |
| 38 | + dst = Qt::black; |
| 39 | + } else |
| 40 | + dst = Qt::black; |
| 41 | + } else |
| 42 | + dst = pen_convert_from_numeric_color(value_toLong(color)); |
| 43 | + } else |
| 44 | + dst = pen_convert_from_numeric_color(value_toLong(color)); |
| 45 | + |
| 46 | + string_pool_free(str); |
| 47 | +} |
| 48 | + |
18 | 49 | std::string PenBlocks::name() const |
19 | 50 | { |
20 | 51 | return "pen"; |
@@ -42,7 +73,32 @@ void PenBlocks::registerBlocks(IEngine *engine) |
42 | 73 | CompilerValue *PenBlocks::compileSetPenColorToColor(Compiler *compiler) |
43 | 74 | { |
44 | 75 | CompilerValue *color = compiler->addInput("COLOR"); |
45 | | - compiler->addTargetFunctionCall("pen_setPenColorToColor", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { color }); |
| 76 | + |
| 77 | + if (color->isConst()) { |
| 78 | + // Convert color constant at compile time |
| 79 | + const ValueData *value = &dynamic_cast<CompilerConstant *>(color)->value().data(); |
| 80 | + QColor converted; |
| 81 | + pen_convert_color(value, converted); |
| 82 | + |
| 83 | + QColor hsv = converted.toHsv(); |
| 84 | + CompilerValue *h = compiler->addConstValue((hsv.hue() / 360.0) * 100); |
| 85 | + CompilerValue *s = compiler->addConstValue(hsv.saturationF() * 100); |
| 86 | + CompilerValue *b = compiler->addConstValue(hsv.valueF() * 100); |
| 87 | + CompilerValue *transparency; |
| 88 | + |
| 89 | + if (converted.alpha() > 0) |
| 90 | + transparency = compiler->addConstValue(100 * (1 - converted.alpha() / 255.0)); |
| 91 | + else |
| 92 | + transparency = compiler->addConstValue(0); |
| 93 | + |
| 94 | + compiler->addTargetFunctionCall( |
| 95 | + "pen_setPenColorToHsbColor", |
| 96 | + Compiler::StaticType::Void, |
| 97 | + { Compiler::StaticType::Number, Compiler::StaticType::Number, Compiler::StaticType::Number, Compiler::StaticType::Number }, |
| 98 | + { h, s, b, transparency }); |
| 99 | + } else |
| 100 | + compiler->addTargetFunctionCall("pen_setPenColorToColor", Compiler::StaticType::Void, { Compiler::StaticType::Unknown }, { color }); |
| 101 | + |
46 | 102 | return nullptr; |
47 | 103 | } |
48 | 104 |
|
@@ -120,44 +176,37 @@ BLOCK_EXPORT void pen_set_pen_down(Target *target, bool down) |
120 | 176 | getTargetModel(target)->setPenDown(down); |
121 | 177 | } |
122 | 178 |
|
123 | | -BLOCK_EXPORT void pen_setPenColorToColor(Target *target, const ValueData *color) |
| 179 | +BLOCK_EXPORT void pen_setPenColorToHsbColor(Target *target, double h, double s, double b, double transparency) |
124 | 180 | { |
125 | 181 | TargetModel *model = getTargetModel(target); |
126 | 182 |
|
127 | | - std::string stringValue; |
128 | 183 | PenState &penState = model->penState(); |
129 | | - QColor newColor; |
130 | | - |
131 | | - if (value_isString(color)) |
132 | | - value_toString(color, &stringValue); |
| 184 | + penState.color = h; |
| 185 | + penState.saturation = s; |
| 186 | + penState.brightness = b; |
| 187 | + penState.transparency = transparency; |
133 | 188 |
|
134 | | - if (!stringValue.empty() && stringValue[0] == '#') { |
135 | | - bool valid = false; |
136 | | - |
137 | | - if (stringValue.size() <= 7) // #RRGGBB |
138 | | - { |
139 | | - newColor = QColor::fromString(stringValue); |
140 | | - valid = newColor.isValid(); |
141 | | - } |
| 189 | + penState.updateColor(); |
142 | 190 |
|
143 | | - if (!valid) |
144 | | - newColor = Qt::black; |
| 191 | + // Set the legacy "shade" value the same way Scratch 2 did. |
| 192 | + penState.shade = penState.brightness / 2; |
| 193 | +} |
145 | 194 |
|
146 | | - } else |
147 | | - newColor = QColor::fromRgba(static_cast<QRgb>(value_toLong(color))); |
| 195 | +BLOCK_EXPORT void pen_setPenColorToColor(Target *target, const ValueData *color) |
| 196 | +{ |
| 197 | + QColor converted; |
| 198 | + pen_convert_color(color, converted); |
148 | 199 |
|
149 | | - QColor hsv = newColor.toHsv(); |
150 | | - penState.color = (hsv.hue() / 360.0) * 100; |
151 | | - penState.saturation = hsv.saturationF() * 100; |
152 | | - penState.brightness = hsv.valueF() * 100; |
| 200 | + QColor hsv = converted.toHsv(); |
| 201 | + double h = (hsv.hue() / 360.0) * 100; |
| 202 | + double s = hsv.saturationF() * 100; |
| 203 | + double b = hsv.valueF() * 100; |
| 204 | + double transparency; |
153 | 205 |
|
154 | | - if (newColor.alpha() > 0) |
155 | | - penState.transparency = 100 * (1 - newColor.alpha() / 255.0); |
| 206 | + if (converted.alpha() > 0) |
| 207 | + transparency = 100 * (1 - converted.alpha() / 255.0); |
156 | 208 | else |
157 | | - penState.transparency = 0; |
158 | | - |
159 | | - penState.updateColor(); |
| 209 | + transparency = 0; |
160 | 210 |
|
161 | | - // Set the legacy "shade" value the same way Scratch 2 did. |
162 | | - penState.shade = penState.brightness / 2; |
| 211 | + pen_setPenColorToHsbColor(target, h, s, b, transparency); |
163 | 212 | } |
0 commit comments