bit pattern paint

This commit is contained in:
nakst 2022-01-01 14:22:19 +00:00
parent cac419f971
commit ea8b6cbd13
4 changed files with 115 additions and 13 deletions

View File

@ -12,6 +12,7 @@
#define THEME_PAINT_CUSTOM (3)
#define THEME_PAINT_OVERWRITE (4)
#define THEME_PAINT_RADIAL_GRADIENT (5)
#define THEME_PAINT_BIT_PATTERN (6)
#define THEME_LAYER_MODE_BACKGROUND (0)
#define THEME_LAYER_MODE_SHADOW (1)
@ -102,6 +103,11 @@ typedef struct ThemePaintSolid {
uint32_t color;
} ThemePaintSolid;
typedef struct ThemePaintBitPattern {
uint8_t rows[8]; // 8x8 bit pattern.
uint32_t colors[2];
} ThemePaintBitPattern;
typedef struct ThemeGradientStop {
uint32_t color;
int8_t position;
@ -269,6 +275,7 @@ typedef struct ThemePaintData {
union {
const ThemePaintSolid *solid;
const ThemePaintLinearGradient *linearGradient;
const ThemePaintBitPattern *bitPattern;
const ThemePaintCustom *custom;
};
} ThemePaintData;
@ -435,6 +442,15 @@ void ThemeFillRectangle(EsPainter *painter, EsRectangle bounds, ThemePaintData p
uint32_t *b = bits + x + y * width;
do { *b = color; x++, b++; } while (x < bounds.r);
}
} else if (paint.type == THEME_PAINT_BIT_PATTERN) {
for (int y = bounds.t; y < bounds.b; y++) {
uint8_t row = paint.bitPattern->rows[y & 7];
for (int x = bounds.l; x < bounds.r; x++) {
uint32_t *b = bits + x + y * width;
*b = paint.bitPattern->colors[(row >> (x & 7)) & 1];
}
}
}
}
@ -486,6 +502,10 @@ void ThemeFillCorner(EsPainter *painter, EsRectangle bounds, int cx, int cy,
if (mainPaint.type == THEME_PAINT_SOLID || mainPaint.type == THEME_PAINT_OVERWRITE) {
mainColor = mainPaint.solid->color;
} else if (mainPaint.type == THEME_PAINT_BIT_PATTERN) {
uintptr_t tx = ((i >> STYLE_CORNER_OVERSAMPLING) + bounds.l) & 7;
uintptr_t ty = ((j >> STYLE_CORNER_OVERSAMPLING) + bounds.t) & 7;
mainColor = mainPaint.bitPattern->colors[(mainPaint.bitPattern->rows[ty] >> tx) & 1];
} else if (mainPaint.type == THEME_PAINT_LINEAR_GRADIENT) {
mainColor = mainGradient->colors[ClampInteger(0, GRADIENT_CACHE_COUNT - 1,
(((j >> STYLE_CORNER_OVERSAMPLING) - mainGradient->oy + bounds.t) * mainGradient->dy
@ -742,6 +762,8 @@ void ThemeDrawBox(EsPainter *painter, EsRectangle rect, EsBuffer *data, float sc
if (mainPaint.type == 0) {
} else if (mainPaint.type == THEME_PAINT_SOLID || mainPaint.type == THEME_PAINT_OVERWRITE) {
mainPaint.solid = (const ThemePaintSolid *) EsBufferRead(data, sizeof(ThemePaintSolid));
} else if (mainPaint.type == THEME_PAINT_BIT_PATTERN) {
mainPaint.bitPattern = (const ThemePaintBitPattern *) EsBufferRead(data, sizeof(ThemePaintBitPattern));
} else if (mainPaint.type == THEME_PAINT_LINEAR_GRADIENT) {
mainPaint.linearGradient = (const ThemePaintLinearGradient *) EsBufferRead(data, sizeof(ThemePaintLinearGradient));
GradientCacheSetup(&mainGradient, mainPaint.linearGradient, width, height, data);

View File

@ -883,29 +883,23 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_CURSOR) {
SYSCALL_BUFFER(argument1, imageWidth * imageHeight * 4, 1, false);
KMutexAcquire(&windowManager.mutex);
Window *window;
bool ignore = false;
if (_window.type == KERNEL_OBJECT_EMBEDDED_WINDOW) {
EmbeddedWindow *embeddedWindow = (EmbeddedWindow *) _window.object;
window = embeddedWindow->container;
if (!window || !window->hoveringOverEmbed || embeddedWindow->owner != currentProcess) {
KMutexRelease(&windowManager.mutex);
SYSCALL_RETURN(ES_SUCCESS, false);
}
ignore = !window || !window->hoveringOverEmbed || embeddedWindow->owner != currentProcess;
} else {
window = (Window *) _window.object;
if (window->hoveringOverEmbed) {
KMutexRelease(&windowManager.mutex);
SYSCALL_RETURN(ES_SUCCESS, false);
}
ignore = window->hoveringOverEmbed;
}
bool changedCursor = false;
bool different = argument1 != windowManager.cursorID || windowManager.cursorShadow != !!(argument3 & (1 << 30));
if (!window->closed && different && !windowManager.eyedropping && (windowManager.hoverWindow == window || !windowManager.hoverWindow)) {
if (!ignore && !window->closed && different && !windowManager.eyedropping && (windowManager.hoverWindow == window || !windowManager.hoverWindow)) {
windowManager.cursorID = argument1;
windowManager.cursorImageOffsetX = (int8_t) ((argument2 >> 0) & 0xFF) - CURSOR_PADDING_L;
windowManager.cursorImageOffsetY = (int8_t) ((argument2 >> 8) & 0xFF) - CURSOR_PADDING_T;

Binary file not shown.

View File

@ -245,6 +245,10 @@ struct Canvas : UIElement {
bool previewStateActive;
};
struct PatternEditor : UIElement {
uint8_t rows[8];
};
struct Prototype : UIElement {
};
@ -272,6 +276,7 @@ enum PropertyType : uint8_t {
PROP_INT,
PROP_OBJECT,
PROP_FLOAT,
PROP_U64,
};
struct Property {
@ -281,6 +286,7 @@ struct Property {
union {
int32_t integer;
uint64_t u64;
uint64_t object;
float floating;
};
@ -302,6 +308,7 @@ enum ObjectType : uint8_t {
OBJ_PAINT_OVERWRITE = 0x60,
OBJ_PAINT_LINEAR_GRADIENT,
OBJ_PAINT_RADIAL_GRADIENT,
OBJ_PAINT_BIT_PATTERN,
OBJ_LAYER_BOX = 0x80,
OBJ_LAYER_METRICS,
@ -381,6 +388,7 @@ ObjectTypeString cObjectTypeStrings[] = {
ADD_STRING(OBJ_VAR_CONTOUR_STYLE),
ADD_STRING(OBJ_PAINT_OVERWRITE),
ADD_STRING(OBJ_PAINT_LINEAR_GRADIENT),
ADD_STRING(OBJ_PAINT_BIT_PATTERN),
ADD_STRING(OBJ_PAINT_RADIAL_GRADIENT),
ADD_STRING(OBJ_LAYER_BOX),
ADD_STRING(OBJ_LAYER_METRICS),
@ -538,6 +546,11 @@ int32_t PropertyFindOrInheritReadInt32(Object *object, const char *cName, int32_
return property ? property->integer : defaultValue;
}
uint64_t PropertyFindOrInheritReadU64(Object *object, const char *cName, uint64_t defaultValue = 0) {
Property *property = PropertyFindOrInherit(object, cName, PROP_U64);
return property ? property->u64 : defaultValue;
}
float PropertyFindOrInheritReadFloat(Object *object, const char *cName, float defaultValue = 0) {
Property *property = PropertyFindOrInherit(object, cName, PROP_FLOAT);
return property ? property->floating : defaultValue;
@ -903,6 +916,7 @@ void TextStyleRemoveDuplicates(void *cp) {
if (object->properties[pi].type != other->properties[pj].type) break;
if (object->properties[pi].type == PROP_INT && object->properties[pi].integer != other->properties[pj].integer ) break;
if (object->properties[pi].type == PROP_COLOR && object->properties[pi].integer != other->properties[pj].integer ) break;
if (object->properties[pi].type == PROP_U64 && object->properties[pi].u64 != other->properties[pj].u64 ) break;
if (object->properties[pi].type == PROP_OBJECT && object->properties[pi].object != other->properties[pj].object ) break;
if (object->properties[pi].type == PROP_FLOAT && object->properties[pi].floating != other->properties[pj].floating) break;
@ -953,6 +967,7 @@ enum InspectorElementType {
INSPECTOR_ADD_ARRAY_ITEM,
INSPECTOR_SWAP_ARRAY_ITEMS,
INSPECTOR_DELETE_ARRAY_ITEM,
INSPECTOR_PATTERN_EDITOR,
};
struct InspectorBindingData {
@ -1053,6 +1068,12 @@ void InspectorUpdateSingleElement(InspectorBindingData *data) {
UI_FREE(button->label);
button->label = UIStringCopy(string, (button->labelBytes = -1));
UIElementRefresh(&button->e);
} else if (data->elementType == INSPECTOR_PATTERN_EDITOR) {
PatternEditor *editor = (PatternEditor *) data->element;
Property *property = PropertyFind(ObjectFind(data->objectID, false), data->cPropertyName, PROP_U64);
if (property) memcpy(editor->rows, &property->u64, sizeof(uint64_t));
else memset(editor->rows, 0, sizeof(uint64_t));
UIElementRefresh(editor);
} else if (data->elementType == INSPECTOR_ADD_ARRAY_ITEM || data->elementType == INSPECTOR_SWAP_ARRAY_ITEMS
|| data->elementType == INSPECTOR_DELETE_ARRAY_ITEM) {
} else {
@ -1306,6 +1327,44 @@ int InspectorBoundMessage(UIElement *element, UIMessage message, int di, void *d
return 0;
}
int PatternEditorMessage(UIElement *element, UIMessage message, int di, void *dp) {
PatternEditor *editor = (PatternEditor *) element;
const int zoom = 20;
bool leftDraw = (message == UI_MSG_MOUSE_DRAG && element->window->pressedButton == 1) || message == UI_MSG_LEFT_DOWN;
bool rightDraw = (message == UI_MSG_MOUSE_DRAG && element->window->pressedButton == 3) || message == UI_MSG_RIGHT_DOWN;
if (message == UI_MSG_GET_WIDTH || message == UI_MSG_GET_HEIGHT) {
return 8 * zoom;
} else if (message == UI_MSG_PAINT) {
for (int32_t y = 0; y < 8; y++) {
for (int32_t x = 0; x < 8; x++) {
UIRectangle tile = UI_RECT_4(element->bounds.l + zoom * x, element->bounds.l + zoom * (x + 1),
element->bounds.t + zoom * y, element->bounds.t + zoom * (y + 1));
UIDrawBorder((UIPainter *) dp, tile, 0xFF000000, UI_RECT_1(1));
if ((editor->rows[y] >> x) & 1) UIDrawInvert((UIPainter *) dp, tile);
}
}
} else if (leftDraw || rightDraw) {
int32_t x = (element->window->cursorX - element->bounds.l) / zoom;
int32_t y = (element->window->cursorY - element->bounds.t) / zoom;
if (leftDraw && x >= 0 && x < 8 && y >= 0 && y < 8) editor->rows[y] |= 1 << x;
if (rightDraw && x >= 0 && x < 8 && y >= 0 && y < 8) editor->rows[y] &= ~(1 << x);
UIElementRepaint(element, nullptr);
InspectorBindingData *data = (InspectorBindingData *) element->cp;
Step step = {};
step.type = STEP_MODIFY_PROPERTY;
step.objectID = data->objectID;
strcpy(step.property.cName, data->cPropertyName);
step.property.type = PROP_U64;
memcpy(&step.property.u64, editor->rows, sizeof(uint64_t));
DocumentApplyStep(step);
}
return 0;
}
InspectorBindingData *InspectorBind(UIElement *element, uint64_t objectID, const char *cPropertyName, InspectorElementType elementType,
int32_t choiceValue = 0, const char *cEnablePropertyName = nullptr) {
InspectorBindingData *data = (InspectorBindingData *) calloc(1, sizeof(InspectorBindingData));
@ -1586,7 +1645,8 @@ void InspectorPopulate() {
bool inheritWithAnimation = object->type == OBJ_VAR_TEXT_STYLE
|| object->type == OBJ_LAYER_BOX || object->type == OBJ_LAYER_TEXT || object->type == OBJ_LAYER_PATH
|| object->type == OBJ_PAINT_OVERWRITE || object->type == OBJ_PAINT_LINEAR_GRADIENT || object->type == OBJ_PAINT_RADIAL_GRADIENT
|| object->type == OBJ_PAINT_OVERWRITE || object->type == OBJ_PAINT_BIT_PATTERN
|| object->type == OBJ_PAINT_LINEAR_GRADIENT || object->type == OBJ_PAINT_RADIAL_GRADIENT
|| object->type == OBJ_VAR_CONTOUR_STYLE;
bool inheritWithoutAnimation = object->type == OBJ_STYLE || object->type == OBJ_LAYER_METRICS;
@ -1882,6 +1942,14 @@ void InspectorPopulate() {
InspectorBind(&UIButtonCreate(0, 0, "Add layer", -1)->e, object->id, "layers_count", INSPECTOR_ADD_ARRAY_ITEM);
} else if (object->type == OBJ_PAINT_OVERWRITE) {
InspectorAddLink(object, "Color:", "color");
} else if (object->type == OBJ_PAINT_BIT_PATTERN) {
InspectorBind(UIElementCreate(sizeof(PatternEditor), 0, 0, PatternEditorMessage, "Pattern editor"), object->id, "pattern", INSPECTOR_PATTERN_EDITOR);
UILabelCreate(0, 0, "Color off:", -1);
InspectorBind(&UIColorPickerCreate(&UIPanelCreate(0, 0)->e, UI_COLOR_PICKER_HAS_OPACITY)->e, object->id, "color0", INSPECTOR_COLOR_PICKER);
InspectorBind(&UITextboxCreate(0, 0)->e, object->id, "color0", INSPECTOR_COLOR_TEXTBOX);
UILabelCreate(0, 0, "Color on:", -1);
InspectorBind(&UIColorPickerCreate(&UIPanelCreate(0, 0)->e, UI_COLOR_PICKER_HAS_OPACITY)->e, object->id, "color1", INSPECTOR_COLOR_PICKER);
InspectorBind(&UITextboxCreate(0, 0)->e, object->id, "color1", INSPECTOR_COLOR_TEXTBOX);
} else if (object->type == OBJ_PAINT_LINEAR_GRADIENT || object->type == OBJ_PAINT_RADIAL_GRADIENT) {
if (object->type == OBJ_PAINT_LINEAR_GRADIENT) {
InspectorAddFloat(object, "Transform X:", "transformX");
@ -2074,6 +2142,8 @@ uint32_t GraphGetColorFromProperty(Property *property) {
return 0;
} else if (property->type == PROP_OBJECT) {
return GraphGetColor(ObjectFind(property->object, true));
} else if (property->type == PROP_COLOR) {
return (uint32_t) property->integer;
} else {
return 0;
}
@ -2286,6 +2356,17 @@ int8_t ExportPaint(Object *parentObject, const char *cPropertyNameInParent, Expo
} else if (object->type == OBJ_PAINT_OVERWRITE) {
ExportPaint(object, "color", data, depth + 1);
return THEME_PAINT_OVERWRITE;
} else if (object->type == OBJ_PAINT_BIT_PATTERN) {
if (data) {
ThemePaintBitPattern bitPattern = {};
ExportColor(data, bitPattern, colors[0], object, "color0");
ExportColor(data, bitPattern, colors[1], object, "color1");
uint64_t pattern = PropertyFindOrInheritReadU64(object, "pattern");
memcpy(bitPattern.rows, &pattern, sizeof(uint64_t));
ExportWrite(data, &bitPattern, sizeof(bitPattern));
}
return THEME_PAINT_BIT_PATTERN;
} else if (object->type == OBJ_PAINT_LINEAR_GRADIENT) {
if (data) {
ThemePaintLinearGradient paint = {};
@ -2763,7 +2844,7 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) {
} else if (object->type == OBJ_LAYER_BOX || object->type == OBJ_LAYER_GROUP
|| object->type == OBJ_LAYER_TEXT || object->type == OBJ_LAYER_PATH) {
CanvasDrawLayer(object, bounds, painter);
} else if (object->type == OBJ_PAINT_LINEAR_GRADIENT || object->type == OBJ_PAINT_RADIAL_GRADIENT) {
} else if (object->type == OBJ_PAINT_LINEAR_GRADIENT || object->type == OBJ_PAINT_RADIAL_GRADIENT || object->type == OBJ_PAINT_BIT_PATTERN) {
CanvasDrawColorSwatch(object, bounds, painter);
} else if (object->type == OBJ_VAR_COLOR || object->type == OBJ_MOD_COLOR) {
CanvasDrawColorSwatch(object, bounds, painter);
@ -3155,6 +3236,9 @@ void ObjectAddCommandInternal(void *cp) {
object.properties.Free();
return;
}
} else if (object.type == OBJ_PAINT_BIT_PATTERN) {
p = { .type = PROP_COLOR, .integer = (int32_t) 0xFFFFFFFF }; strcpy(p.cName, "color0"); object.properties.Add(p);
p = { .type = PROP_COLOR, .integer = (int32_t) 0xFF000000 }; strcpy(p.cName, "color1"); object.properties.Add(p);
}
ObjectAddInternal(object);
@ -3195,6 +3279,7 @@ void ObjectAddCommand(void *cp) {
UIMenuAddItem(menu, 0, "Contour style", -1, invoke, (void *) (uintptr_t) OBJ_VAR_CONTOUR_STYLE);
UIMenuAddItem(menu, 0, "Metrics", -1, invoke, (void *) (uintptr_t) OBJ_LAYER_METRICS);
UIMenuAddItem(menu, 0, "Overwrite paint", -1, invoke, (void *) (uintptr_t) OBJ_PAINT_OVERWRITE);
UIMenuAddItem(menu, 0, "Bit pattern paint", -1, invoke, (void *) (uintptr_t) OBJ_PAINT_BIT_PATTERN);
UIMenuAddItem(menu, 0, "Linear gradient", -1, invoke, (void *) (uintptr_t) OBJ_PAINT_LINEAR_GRADIENT);
UIMenuAddItem(menu, 0, "Radial gradient", -1, invoke, (void *) (uintptr_t) OBJ_PAINT_RADIAL_GRADIENT);
UIMenuAddItem(menu, 0, "Box layer", -1, invoke, (void *) (uintptr_t) OBJ_LAYER_BOX);
@ -3631,6 +3716,7 @@ void ExportJSON() {
if (property->type == PROP_COLOR) fprintf(f, "\"#%.8X\"", (uint32_t) property->integer);
if (property->type == PROP_INT) fprintf(f, "%d", property->integer);
if (property->type == PROP_OBJECT) fprintf(f, "\"@%ld\"", property->object);
if (property->type == PROP_U64) fprintf(f, "\"%ld\"", property->object);
if (property->type == PROP_FLOAT) fprintf(f, "%f", property->floating);
fprintf(f, "%s\n", i < object->properties.Length() - 1 ? "," : "");
}