From 35f361a7e451fe39bb47d3606386c44d7e8ae9bc Mon Sep 17 00:00:00 2001 From: nakst <> Date: Sun, 3 Oct 2021 21:14:18 +0100 Subject: [PATCH] designer2 export --- desktop/theme.cpp | 279 ++++++++--------- {apps => ports/bochs}/bochs.ini | 0 res/Theme Source.dat | Bin 52967 -> 53162 bytes res/Theme.dat | Bin 29496 -> 30364 bytes util/designer/designer.c | 14 +- util/designer2.cpp | 530 ++++++++++++++++++++++++-------- 6 files changed, 534 insertions(+), 289 deletions(-) rename {apps => ports/bochs}/bochs.ini (100%) diff --git a/desktop/theme.cpp b/desktop/theme.cpp index 5a33f7c..8610940 100644 --- a/desktop/theme.cpp +++ b/desktop/theme.cpp @@ -133,7 +133,7 @@ typedef struct ThemePaintCustom { #endif typedef struct ThemeLayerBox { - Rectangle8 borders; + Rectangle8 borders, offset; Corners8 corners; int8_t flags, mainPaintType, borderPaintType; uint8_t _unused0; @@ -180,7 +180,9 @@ typedef struct ThemeLayerPath { } ThemeLayerPath; typedef struct ThemeLayer { - uint32_t sequenceDataOffset; + uint32_t overrideListOffset; + uint16_t overrideCount; + uint16_t _unused; Rectangle8 offset; // (dpx) Rectangle8 position; // (percent) int8_t mode, type; @@ -210,20 +212,12 @@ typedef union ThemeVariant { } ThemeVariant; typedef struct ThemeOverride { + uint16_t state, duration; uint16_t offset; - uint8_t type, layer; + uint8_t type, _unused; ThemeVariant data; } ThemeOverride; -typedef struct ThemeSequenceHeader { - uint16_t state; // Low 4 bits are the primary state. - uint16_t overrideCount; - uint16_t duration; - uint8_t isLastSequence; - uint8_t _unused; - // Followed by overrides. -} ThemeSequenceHeader; - typedef struct ThemeStyle { // A list of uint32_t, giving offsets to ThemeLayer. First is the metrics layer. // **This must be the first field in the structure; see the end of Export in util/designer2.cpp.** @@ -714,24 +708,24 @@ void GradientCacheSetup(GradientCache *cache, const ThemePaintLinearGradient *gr void ThemeDrawBox(EsPainter *painter, EsRectangle rect, EsBuffer *data, float scale, const ThemeLayer *layer, EsRectangle opaqueRegion, int childType) { - int width = THEME_RECT_WIDTH(rect), height = THEME_RECT_HEIGHT(rect); - if (width <= 0 || height <= 0) return; - const ThemeLayerBox *box = (const ThemeLayerBox *) EsBufferRead(data, sizeof(ThemeLayerBox)); if (!box) return; - if ((box->flags & THEME_LAYER_BOX_SHADOW_HIDING) && layer->offset.l == 0 && layer->offset.r == 0 && layer->offset.t == 0 && layer->offset.b == 0) { + if ((box->flags & THEME_LAYER_BOX_SHADOW_HIDING) && layer->offset.l == 0 && layer->offset.r == 0 && layer->offset.t == 0 && layer->offset.b == 0 + && box->offset.l == 0 && box->offset.r == 0 && box->offset.t == 0 && box->offset.b == 0 + && THEME_RECT_VALID(opaqueRegion)) { return; } - bool isBlurred = box->flags & THEME_LAYER_BOX_IS_BLURRED; + rect.l += box->offset.l * scale; + rect.r += box->offset.r * scale; + rect.t += box->offset.t * scale; + rect.b += box->offset.b * scale; -#if 0 - if (scale == 1 && isBlurred) { - width--, rect.r--; - height--, rect.b--; - } -#endif + int width = THEME_RECT_WIDTH(rect), height = THEME_RECT_HEIGHT(rect); + if (width <= 0 || height <= 0) return; + + bool isBlurred = box->flags & THEME_LAYER_BOX_IS_BLURRED; ThemePaintData mainPaint, borderPaint; GradientCache mainGradient, borderGradient; @@ -1409,72 +1403,65 @@ void _ThemeAnimationBuildAddProperties(ThemeAnimation *animation, UIStyle *style const ThemeLayer *layer = (const ThemeLayer *) (theming.system.in + layerList[i]); EsBuffer layerData = theming.system; - layerData.position = layer->sequenceDataOffset; + layerData.position = layer->overrideListOffset; - while (layerData.position) { - const ThemeSequenceHeader *sequenceHeader = (const ThemeSequenceHeader *) EsBufferRead(&layerData, sizeof(ThemeSequenceHeader)); + for (uintptr_t i = 0; i < layer->overrideCount; i++) { + const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); - if (THEME_STATE_CHECK(sequenceHeader->state, stateFlags) && sequenceHeader->duration) { - for (uintptr_t j = 0; j < sequenceHeader->overrideCount; j++) { - const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); - uintptr_t key = themeOverride->offset + layerCumulativeDataOffset; - EsAssert(key <= (uintptr_t) style->layerDataByteCount - sizeof(ThemeVariant)); - - uintptr_t point; - bool alreadyInList; - - // Find where the property is/should be in the animation list. - - ES_MACRO_SEARCH(animation->properties.Length(), { - uintptr_t item = animation->properties[index].offset; - result = key < item ? -1 : key > item ? 1 : 0; - }, point, alreadyInList); - - bool beforeEnter = (sequenceHeader->state & THEME_STATE_BEFORE_ENTER) != 0; - - if (alreadyInList) { - // Update the duration, if the property is already in the list. - // Prioritise before enter sequence durations. - - if (!animation->properties[point].beforeEnter || beforeEnter) { - animation->properties[point].duration = sequenceHeader->duration * api.global->animationTimeMultiplier; - animation->properties[point].beforeEnter = beforeEnter; - } - } else { - // Add the property to the list. - - if (point < animation->properties.Length()) EsAssert(key < animation->properties[point].offset); - if (point > 0) EsAssert(key > animation->properties[point - 1].offset); - - ThemeAnimatingProperty property = {}; - property.offset = key; - property.type = themeOverride->type; - property.duration = sequenceHeader->duration * api.global->animationTimeMultiplier; - property.beforeEnter = beforeEnter; - - if (themeOverride->type == THEME_OVERRIDE_I8) { - EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 1); - property.from.i8 = *(int8_t *) (oldLayerData + key); - } else if (themeOverride->type == THEME_OVERRIDE_I16) { - EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 2); - property.from.i16 = *(int16_t *) (oldLayerData + key); - } else if (themeOverride->type == THEME_OVERRIDE_F32) { - EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 4); - property.from.f32 = *(float *) (oldLayerData + key); - } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { - EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 4); - property.from.u32 = *(uint32_t *) (oldLayerData + key); - } - - animation->properties.Insert(property, point); - } - } - } else { - EsBufferRead(&layerData, sizeof(ThemeOverride) * sequenceHeader->overrideCount); + if (!THEME_STATE_CHECK(themeOverride->state, stateFlags) || !themeOverride->duration) { + continue; } - if (sequenceHeader->isLastSequence) { - break; + uintptr_t key = themeOverride->offset + layerCumulativeDataOffset; + EsAssert(key <= (uintptr_t) style->layerDataByteCount - sizeof(ThemeVariant)); + + uintptr_t point; + bool alreadyInList; + + // Find where the property is/should be in the animation list. + + ES_MACRO_SEARCH(animation->properties.Length(), { + uintptr_t item = animation->properties[index].offset; + result = key < item ? -1 : key > item ? 1 : 0; + }, point, alreadyInList); + + bool beforeEnter = (themeOverride->state & THEME_STATE_BEFORE_ENTER) != 0; + + if (alreadyInList) { + // Update the duration, if the property is already in the list. + // Prioritise before enter sequence durations. + + if (!animation->properties[point].beforeEnter || beforeEnter) { + animation->properties[point].duration = themeOverride->duration * api.global->animationTimeMultiplier; + animation->properties[point].beforeEnter = beforeEnter; + } + } else { + // Add the property to the list. + + if (point < animation->properties.Length()) EsAssert(key < animation->properties[point].offset); + if (point > 0) EsAssert(key > animation->properties[point - 1].offset); + + ThemeAnimatingProperty property = {}; + property.offset = key; + property.type = themeOverride->type; + property.duration = themeOverride->duration * api.global->animationTimeMultiplier; + property.beforeEnter = beforeEnter; + + if (themeOverride->type == THEME_OVERRIDE_I8) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 1); + property.from.i8 = *(int8_t *) (oldLayerData + key); + } else if (themeOverride->type == THEME_OVERRIDE_I16) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 2); + property.from.i16 = *(int16_t *) (oldLayerData + key); + } else if (themeOverride->type == THEME_OVERRIDE_F32) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 4); + property.from.f32 = *(float *) (oldLayerData + key); + } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { + EsAssert(themeOverride->offset <= (uintptr_t) layer->dataByteCount - 4); + property.from.u32 = *(uint32_t *) (oldLayerData + key); + } + + animation->properties.Insert(property, point); } } @@ -1683,59 +1670,43 @@ UIStyle *ThemeStyleInitialise(UIStyleKey key) { } } - layerData.position = layer->sequenceDataOffset; + layerData.position = layer->overrideListOffset; - while (layerData.position) { - const ThemeSequenceHeader *sequenceHeader = (const ThemeSequenceHeader *) EsBufferRead(&layerData, sizeof(ThemeSequenceHeader)); + for (uintptr_t i = 0; i < layer->overrideCount; i++) { + const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); - if (!sequenceHeader) { - EsPrint("Broken sequence list.\n"); + if (!themeOverride) { + EsPrint("Broken override list.\n"); return nullptr; } - if (THEME_STATE_CHECK(sequenceHeader->state, key.stateFlags)) { - for (uintptr_t j = 0; j < sequenceHeader->overrideCount; j++) { - const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); - - if (!themeOverride) { - EsPrint("Broken override list.\n"); - return nullptr; - } - - if (themeOverride->offset >= layer->dataByteCount) { - EsPrint("Broken override list.\n"); - return nullptr; - } - - bool valid; - - if (themeOverride->type == THEME_OVERRIDE_I8) { - valid = themeOverride->offset + 1 <= layer->dataByteCount; - } else if (themeOverride->type == THEME_OVERRIDE_I16) { - valid = themeOverride->offset + 2 <= layer->dataByteCount; - } else if (themeOverride->type == THEME_OVERRIDE_F32) { - valid = themeOverride->offset + 4 <= layer->dataByteCount; - } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { - valid = themeOverride->offset + 4 <= layer->dataByteCount; - } else { - EsPrint("Unsupported override type.\n"); - return nullptr; - } - - if (!valid) { - EsPrint("Broken override list.\n"); - return nullptr; - } - } - } else { - if (!EsBufferRead(&layerData, sizeof(ThemeOverride) * sequenceHeader->overrideCount)) { - EsPrint("Broken sequence list.\n"); - return nullptr; - } + if (!THEME_STATE_CHECK(themeOverride->state, key.stateFlags)) { + continue; } - if (sequenceHeader->isLastSequence) { - break; + if (themeOverride->offset >= layer->dataByteCount) { + EsPrint("Broken override list.\n"); + return nullptr; + } + + bool valid; + + if (themeOverride->type == THEME_OVERRIDE_I8) { + valid = themeOverride->offset + 1 <= layer->dataByteCount; + } else if (themeOverride->type == THEME_OVERRIDE_I16) { + valid = themeOverride->offset + 2 <= layer->dataByteCount; + } else if (themeOverride->type == THEME_OVERRIDE_F32) { + valid = themeOverride->offset + 4 <= layer->dataByteCount; + } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { + valid = themeOverride->offset + 4 <= layer->dataByteCount; + } else { + EsPrint("Unsupported override type.\n"); + return nullptr; + } + + if (!valid) { + EsPrint("Broken override list.\n"); + return nullptr; } } } @@ -1768,38 +1739,30 @@ UIStyle *ThemeStyleInitialise(UIStyleKey key) { layerData.position = *offset; const uint8_t *data = (const uint8_t *) EsBufferRead(&layerData, layer->dataByteCount); EsMemoryCopy(baseData + layerDataByteCount, data, layer->dataByteCount); - layerData.position = layer->sequenceDataOffset; + layerData.position = layer->overrideListOffset; - while (layerData.position) { - const ThemeSequenceHeader *sequenceHeader = (const ThemeSequenceHeader *) EsBufferRead(&layerData, sizeof(ThemeSequenceHeader)); + for (uintptr_t i = 0; i < layer->overrideCount; i++) { + const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); - style->observedStyleStateMask |= 0x10000 << (sequenceHeader->state & THEME_PRIMARY_STATE_MASK); - style->observedStyleStateMask |= sequenceHeader->state & ~THEME_PRIMARY_STATE_MASK; + style->observedStyleStateMask |= 0x10000 << (themeOverride->state & THEME_PRIMARY_STATE_MASK); + style->observedStyleStateMask |= themeOverride->state & ~THEME_PRIMARY_STATE_MASK; - if (THEME_STATE_CHECK(sequenceHeader->state, key.stateFlags)) { - for (uintptr_t j = 0; j < sequenceHeader->overrideCount; j++) { - const ThemeOverride *themeOverride = (const ThemeOverride *) EsBufferRead(&layerData, sizeof(ThemeOverride)); - - ThemeVariant overrideValue = themeOverride->data; - - if (themeOverride->type == THEME_OVERRIDE_I8) { - *(int8_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.i8; - } else if (themeOverride->type == THEME_OVERRIDE_I16) { - *(int16_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.i16; - } else if (themeOverride->type == THEME_OVERRIDE_F32) { - *(float *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.f32; - } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { - *(uint32_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.u32; - } else { - EsAssert(false); - } - } - } else { - EsBufferRead(&layerData, sizeof(ThemeOverride) * sequenceHeader->overrideCount); + if (!THEME_STATE_CHECK(themeOverride->state, key.stateFlags)) { + continue; } - if (sequenceHeader->isLastSequence) { - break; + ThemeVariant overrideValue = themeOverride->data; + + if (themeOverride->type == THEME_OVERRIDE_I8) { + *(int8_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.i8; + } else if (themeOverride->type == THEME_OVERRIDE_I16) { + *(int16_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.i16; + } else if (themeOverride->type == THEME_OVERRIDE_F32) { + *(float *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.f32; + } else if (themeOverride->type == THEME_OVERRIDE_COLOR) { + *(uint32_t *) (baseData + layerDataByteCount + themeOverride->offset) = overrideValue.u32; + } else { + EsAssert(false); } } diff --git a/apps/bochs.ini b/ports/bochs/bochs.ini similarity index 100% rename from apps/bochs.ini rename to ports/bochs/bochs.ini diff --git a/res/Theme Source.dat b/res/Theme Source.dat index f28ff3cf2846ce6021917c13a1108f4bd427405b..1e94a6d46af2803d1c258252a4285e7d76c56fcb 100644 GIT binary patch delta 115 zcmV-(0F3|Vodc?$0|gcU002#~1;PgeZh=jPv&#p31p^v_0h5s)7?W@`1hZxhX%Yc| zv)ms+D*=qN9!seUv%y#QWs|_U{{c;t;hZv)@VgX~Z+d(IZj&LEIkULEK?4B`v--f6 V2a~VJ7Y9#tXcqf!fV1Jq1_rK%E{*^I delta 293 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.data.buffer + layer->exportOffset); entry->dataByteCount = export->buffer.data.byteCount - layer->exportOffset; +#if 0 entry->sequenceDataOffset = arrlenu(layer->sequences) ? export->buffer.data.byteCount : 0; +#endif Layer *previousLayer = selected.layer; selected.layer = layer; // HACK! +#if 0 // Write out the sequences. for (uintptr_t j = 0; j < arrlenu(layer->sequences); j++) { @@ -1521,6 +1524,7 @@ void StyleSetOp(RfState *state, RfItem *item, void *pointer) { ThemeSequenceHeader *header = (ThemeSequenceHeader *) ((uint8_t *) export->buffer.data.buffer + headerOffset); header->overrideCount = overrideCount; } +#endif selected.layer = previousLayer; @@ -2132,6 +2136,10 @@ void ActionExportDesigner2(void *cp) { ObjectAddIntegerProperty(&object, "corners1", box->corners.tr); ObjectAddIntegerProperty(&object, "corners2", box->corners.bl); ObjectAddIntegerProperty(&object, "corners3", box->corners.br); + ObjectAddIntegerProperty(&object, "offset0", 0); + ObjectAddIntegerProperty(&object, "offset1", 0); + ObjectAddIntegerProperty(&object, "offset2", 0); + ObjectAddIntegerProperty(&object, "offset3", 0); ObjectAddIntegerProperty(&object, "isBlurred", box->blurred); ObjectAddIntegerProperty(&object, "autoCorners", box->autoCorners); ObjectAddIntegerProperty(&object, "autoBorders", box->autoBorders); @@ -2217,7 +2225,7 @@ void ActionExportDesigner2(void *cp) { textStyle = object; metrics.type = OBJ_LAYER_METRICS, metrics.id = ++objectIDAllocator; - ObjectAddIntegerProperty(&metrics, "clipEnabled", m->clipEnabled); + ObjectAddIntegerProperty(&metrics, "clipEnabled", m->clipEnabled == CLIP_MODE_ENABLED); ObjectAddIntegerProperty(&metrics, "wrapText", m->wrapText); ObjectAddIntegerProperty(&metrics, "ellipsis", m->ellipsis); ObjectAddIntegerProperty(&metrics, "insets0", m->insets.l); @@ -2326,6 +2334,10 @@ void ActionExportDesigner2(void *cp) { } } + if (object.type == OBJ_VAR_TEXT_STYLE) { + textStyle.id = previousOverrideID; + } + if (addToLayerGroup) { sprintf(cPropertyName, "layers_%d_layer", layerCount); ObjectAddObjectProperty(&layerGroup, cPropertyName, previousOverrideID); diff --git a/util/designer2.cpp b/util/designer2.cpp index 73b55d4..8c1dc04 100644 --- a/util/designer2.cpp +++ b/util/designer2.cpp @@ -16,8 +16,7 @@ // x86_64-w64-mingw32-gcc -O3 -o bin/designer2.exe -D UI_WINDOWS util/designer2.cpp -DUNICODE -lgdi32 -luser32 -lkernel32 -Wl,--subsystem,windows -fno-exceptions -fno-rtti // TODO Needed to replace the old designer: -// Exporting sequences. -// Calculating additional metric rectangles (paintOutsets, opaqueInsets and approximateBorders). +// Calculating opaqueInsets. // Prototyping display: previewing state transitions. // TODO Additional features: @@ -338,6 +337,35 @@ struct ExportOffset { uint64_t objectID; uintptr_t offset; char cPropertyName[PROPERTY_NAME_SIZE]; + uint8_t overrideType; +}; + +struct ObjectTypeString { + ObjectType type; + const char *string; +}; + +ObjectTypeString cObjectTypeStrings[] = { +#define ADD_STRING(x) { x, #x } + ADD_STRING(OBJ_NONE), + ADD_STRING(OBJ_STYLE), + ADD_STRING(OBJ_COMMENT), + ADD_STRING(OBJ_INSTANCE), + ADD_STRING(OBJ_VAR_COLOR), + ADD_STRING(OBJ_VAR_INT), + ADD_STRING(OBJ_VAR_TEXT_STYLE), + ADD_STRING(OBJ_VAR_CONTOUR_STYLE), + ADD_STRING(OBJ_PAINT_OVERWRITE), + ADD_STRING(OBJ_PAINT_LINEAR_GRADIENT), + ADD_STRING(OBJ_PAINT_RADIAL_GRADIENT), + ADD_STRING(OBJ_LAYER_BOX), + ADD_STRING(OBJ_LAYER_METRICS), + ADD_STRING(OBJ_LAYER_TEXT), + ADD_STRING(OBJ_LAYER_GROUP), + ADD_STRING(OBJ_LAYER_PATH), + ADD_STRING(OBJ_MOD_COLOR), + ADD_STRING(OBJ_MOD_MULTIPLY), +#undef ADD_STRING }; Array undoStack; @@ -379,6 +407,17 @@ ExportOffset *ExportOffsetFindObject(uint64_t id) { return nullptr; } +ExportOffset *ExportOffsetFindProperty(uint64_t objectID, const char *cPropertyName) { + for (uintptr_t i = 0; i < exportOffsets.Length(); i++) { + if (exportOffsets[i].objectID == objectID + && 0 == strcmp(exportOffsets[i].cPropertyName, cPropertyName)) { + return &exportOffsets[i]; + } + } + + return nullptr; +} + void ObjectSetSelected(uint64_t id, bool removeSelectedFlagFromPreviousSelection = true) { if (selectedObjectID && removeSelectedFlagFromPreviousSelection) { Object *object = ObjectFind(selectedObjectID); @@ -507,8 +546,6 @@ void DocumentSave(void *) { } void DocumentLoad() { - // TODO Check names are zero-terminated. - #ifdef OS_ESSENCE EsBuffer buffer = {}; buffer.out = (uint8_t *) EsFileStoreReadAll(fileStore, &buffer.bytes); @@ -527,11 +564,17 @@ void DocumentLoad() { for (uintptr_t i = 0; i < objectCount; i++) { Object object = {}; fread(&object, 1, sizeof(Object), f); + object.cName[OBJECT_NAME_SIZE - 1] = 0; uint32_t propertyCount = 0; fread(&propertyCount, 1, sizeof(uint32_t), f); object.properties.InsertMany(0, propertyCount); fread(object.properties.array, 1, sizeof(Property) * propertyCount, f); object.flags &= ~OBJECT_IS_SELECTED; + + for (uintptr_t i = 0; i < propertyCount; i++) { + object.properties[i].cName[PROPERTY_NAME_SIZE - 1] = 0; + } + objects.Add(object); } @@ -1404,34 +1447,34 @@ void InspectorPopulate() { if (inheritWithAnimation || inheritWithoutAnimation) { InspectorAddLink(object, "Inherit from:", "_parent"); - UILabelCreate(0, 0, "Primary state:", -1); - UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_HORIZONTAL); - InspectorAddRadioSwitch(object, "Idle", "_primaryState", THEME_PRIMARY_STATE_IDLE); - InspectorAddRadioSwitch(object, "Hovered", "_primaryState", THEME_PRIMARY_STATE_HOVERED); - InspectorAddRadioSwitch(object, "Pressed", "_primaryState", THEME_PRIMARY_STATE_PRESSED); - InspectorAddRadioSwitch(object, "Disabled", "_primaryState", THEME_PRIMARY_STATE_DISABLED); - InspectorAddRadioSwitch(object, "Inactive", "_primaryState", THEME_PRIMARY_STATE_INACTIVE); - InspectorBind(&UIButtonCreate(0, UI_BUTTON_SMALL, "X", 1)->e, object->id, "_primaryState", INSPECTOR_REMOVE_BUTTON); - UIParentPop(); - - UILabelCreate(0, 0, "State bits:", -1); - UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_EXPAND)->gap = -5; - UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_HORIZONTAL)->gap = 8; - InspectorAddMaskBitToggle(object, cStateBitStrings[0], "_stateBits", THEME_STATE_FOCUSED); - InspectorAddMaskBitToggle(object, cStateBitStrings[1], "_stateBits", THEME_STATE_CHECKED); - InspectorAddMaskBitToggle(object, cStateBitStrings[2], "_stateBits", THEME_STATE_INDETERMINATE); - InspectorAddMaskBitToggle(object, cStateBitStrings[3], "_stateBits", THEME_STATE_DEFAULT_BUTTON); - InspectorAddMaskBitToggle(object, cStateBitStrings[4], "_stateBits", THEME_STATE_SELECTED); - UIParentPop(); - UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_HORIZONTAL)->gap = 8; - InspectorAddMaskBitToggle(object, cStateBitStrings[5], "_stateBits", THEME_STATE_FOCUSED_ITEM); - InspectorAddMaskBitToggle(object, cStateBitStrings[6], "_stateBits", THEME_STATE_LIST_FOCUSED); - InspectorAddMaskBitToggle(object, cStateBitStrings[7], "_stateBits", THEME_STATE_BEFORE_ENTER); - InspectorAddMaskBitToggle(object, cStateBitStrings[8], "_stateBits", THEME_STATE_AFTER_EXIT); - UIParentPop(); - UIParentPop(); - if (inheritWithAnimation) { + UILabelCreate(0, 0, "Primary state:", -1); + UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_HORIZONTAL); + InspectorAddRadioSwitch(object, "Idle", "_primaryState", THEME_PRIMARY_STATE_IDLE); + InspectorAddRadioSwitch(object, "Hovered", "_primaryState", THEME_PRIMARY_STATE_HOVERED); + InspectorAddRadioSwitch(object, "Pressed", "_primaryState", THEME_PRIMARY_STATE_PRESSED); + InspectorAddRadioSwitch(object, "Disabled", "_primaryState", THEME_PRIMARY_STATE_DISABLED); + InspectorAddRadioSwitch(object, "Inactive", "_primaryState", THEME_PRIMARY_STATE_INACTIVE); + InspectorBind(&UIButtonCreate(0, UI_BUTTON_SMALL, "X", 1)->e, object->id, "_primaryState", INSPECTOR_REMOVE_BUTTON); + UIParentPop(); + + UILabelCreate(0, 0, "State bits:", -1); + UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_EXPAND)->gap = -5; + UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_HORIZONTAL)->gap = 8; + InspectorAddMaskBitToggle(object, cStateBitStrings[0], "_stateBits", THEME_STATE_FOCUSED); + InspectorAddMaskBitToggle(object, cStateBitStrings[1], "_stateBits", THEME_STATE_CHECKED); + InspectorAddMaskBitToggle(object, cStateBitStrings[2], "_stateBits", THEME_STATE_INDETERMINATE); + InspectorAddMaskBitToggle(object, cStateBitStrings[3], "_stateBits", THEME_STATE_DEFAULT_BUTTON); + InspectorAddMaskBitToggle(object, cStateBitStrings[4], "_stateBits", THEME_STATE_SELECTED); + UIParentPop(); + UIPanelCreate(0, UI_ELEMENT_PARENT_PUSH | UI_PANEL_HORIZONTAL)->gap = 8; + InspectorAddMaskBitToggle(object, cStateBitStrings[5], "_stateBits", THEME_STATE_FOCUSED_ITEM); + InspectorAddMaskBitToggle(object, cStateBitStrings[6], "_stateBits", THEME_STATE_LIST_FOCUSED); + InspectorAddMaskBitToggle(object, cStateBitStrings[7], "_stateBits", THEME_STATE_BEFORE_ENTER); + InspectorAddMaskBitToggle(object, cStateBitStrings[8], "_stateBits", THEME_STATE_AFTER_EXIT); + UIParentPop(); + UIParentPop(); + UILabelCreate(0, 0, "Transition duration:", -1); InspectorAddInteger(object, nullptr, "_duration"); } @@ -1856,19 +1899,101 @@ uint32_t GraphGetColorFromProperty(Property *property) { ////////////////////////////////////////////////////////////// -void ExportGradientStopArray(Object *object, EsBuffer *data, size_t stopCount) { +struct ExportContext { + EsBuffer *baseData; + EsBuffer *overrideData; + uintptr_t overrideOffset; +}; + +ThemeVariant PropertyToThemeVariant(Property *property, uint8_t type) { + ThemeVariant value = {}; + + if (type == THEME_OVERRIDE_COLOR) { + value.u32 = GraphGetColorFromProperty(property); + } else if (type == THEME_OVERRIDE_I8) { + value.i8 = GraphGetIntegerFromProperty(property); + } else if (type == THEME_OVERRIDE_I16) { + value.i16 = GraphGetIntegerFromProperty(property); + } else if (type == THEME_OVERRIDE_F32) { + value.f32 = property && property->type == PROP_FLOAT ? property->floating : 0; + } else { + assert(false); + } + + return value; +} + +ThemeVariant ExportValue(ExportContext *data, uintptr_t additionalOffset, Object *object, const char *cPropertyName, uint8_t type) { + uintptr_t depth = 0; + ThemeVariant value = {}; + + if (data->overrideData) { + Array themeOverrides = {}; + + while (object && (depth++ < 100)) { + Property *property = PropertyFind(object, cPropertyName); + + if (property) { + uint16_t state = PropertyReadInt32(object, "_primaryState") | PropertyReadInt32(object, "_stateBits"); + value = PropertyToThemeVariant(property, type); + + if (state) { + ThemeOverride themeOverride = {}; + themeOverride.state = state; + themeOverride.duration = GraphGetIntegerFromProperty(PropertyFind(object, "_duration")); + themeOverride.offset = data->overrideOffset + (data->baseData ? data->baseData->position : 0) + additionalOffset; + themeOverride.type = type; + themeOverride.data = value; + themeOverrides.Insert(themeOverride, 0); + } else { + break; + } + } + + // Go to the inheritance parent object. + property = PropertyFind(object, "_parent", PROP_OBJECT); + object = ObjectFind(property ? property->object : 0); + } + + EsBufferWrite(data->overrideData, &themeOverrides[0], themeOverrides.Length() * sizeof(ThemeOverride)); + themeOverrides.Free(); + } else { + value = PropertyToThemeVariant(PropertyFindOrInherit(object, cPropertyName), type); + } + + return value; +} + +#define ExportColor(data, structure, field, object, cPropertyName) \ + structure.field = ExportValue(data, ((uint8_t *) &structure.field - (uint8_t *) &structure), object, cPropertyName, THEME_OVERRIDE_COLOR).u32 +#define ExportI8(data, structure, field, object, cPropertyName) \ + structure.field = ExportValue(data, ((uint8_t *) &structure.field - (uint8_t *) &structure), object, cPropertyName, THEME_OVERRIDE_I8).i8 +#define ExportI16(data, structure, field, object, cPropertyName) \ + structure.field = ExportValue(data, ((uint8_t *) &structure.field - (uint8_t *) &structure), object, cPropertyName, THEME_OVERRIDE_I16).i16 +#define ExportF32(data, structure, field, object, cPropertyName) \ + structure.field = ExportValue(data, ((uint8_t *) &structure.field - (uint8_t *) &structure), object, cPropertyName, THEME_OVERRIDE_F32).f32 + +void ExportWrite(ExportContext *context, const void *buffer, size_t bytes) { + if (context->baseData) { + EsBufferWrite(context->baseData, buffer, bytes); + } +} + +void ExportGradientStopArray(Object *object, ExportContext *data, size_t stopCount) { for (uintptr_t i = 0; i < stopCount; i++) { char cPropertyName[PROPERTY_NAME_SIZE]; ThemeGradientStop stop = {}; sprintf(cPropertyName, "stops_%d_color", (int32_t) i); - stop.color = GraphGetColor(PropertyFindOrInheritReadObject(object, cPropertyName)); + ExportColor(data, stop, color, object, cPropertyName); sprintf(cPropertyName, "stops_%d_position", (int32_t) i); - stop.position = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, cPropertyName, PROP_INT)); - EsBufferWrite(data, &stop, sizeof(stop)); + ExportI8(data, stop, position, object, cPropertyName); + ExportWrite(data, &stop, sizeof(stop)); } } -int8_t ExportPaint(Object *object, EsBuffer *data, int depth = 0) { +int8_t ExportPaint(Object *parentObject, const char *cPropertyNameInParent, ExportContext *data, int depth = 0) { + Object *object = PropertyFindOrInheritReadObject(parentObject, cPropertyNameInParent); + if (!object || depth == 100) { return 0; } @@ -1876,25 +2001,25 @@ int8_t ExportPaint(Object *object, EsBuffer *data, int depth = 0) { if (object->type == OBJ_VAR_COLOR || object->type == OBJ_MOD_COLOR) { if (data) { ThemePaintSolid solid = {}; - solid.color = GraphGetColor(object); - EsBufferWrite(data, &solid, sizeof(solid)); + ExportColor(data, solid, color, parentObject, cPropertyNameInParent); + ExportWrite(data, &solid, sizeof(solid)); } return THEME_PAINT_SOLID; } else if (object->type == OBJ_PAINT_OVERWRITE) { - ExportPaint(PropertyFindOrInheritReadObject(object, "color"), data, depth + 1); + ExportPaint(object, "color", data, depth + 1); return THEME_PAINT_OVERWRITE; } else if (object->type == OBJ_PAINT_LINEAR_GRADIENT) { if (data) { ThemePaintLinearGradient paint = {}; - paint.transform[0] = PropertyFindOrInheritReadFloat(object, "transformX"); - paint.transform[1] = PropertyFindOrInheritReadFloat(object, "transformY"); - paint.transform[2] = PropertyFindOrInheritReadFloat(object, "transformStart"); + ExportF32(data, paint, transform[0], object, "transformX"); + ExportF32(data, paint, transform[1], object, "transformY"); + ExportF32(data, paint, transform[2], object, "transformStart"); paint.stopCount = PropertyFindOrInheritReadInt32(object, "stops_count"); paint.useGammaInterpolation = !!PropertyFindOrInheritReadInt32(object, "useGammaInterpolation"); paint.useSystemColor = !!PropertyFindOrInheritReadInt32(object, "useSystemColor"); paint.repeatMode = PropertyFindOrInheritReadInt32(object, "repeatMode"); - EsBufferWrite(data, &paint, sizeof(paint)); + ExportWrite(data, &paint, sizeof(paint)); ExportGradientStopArray(object, data, paint.stopCount); } @@ -1902,16 +2027,16 @@ int8_t ExportPaint(Object *object, EsBuffer *data, int depth = 0) { } else if (object->type == OBJ_PAINT_RADIAL_GRADIENT) { if (data) { ThemePaintRadialGradient paint = {}; - paint.transform[0] = PropertyFindOrInheritReadFloat(object, "transform0"); - paint.transform[1] = PropertyFindOrInheritReadFloat(object, "transform1"); - paint.transform[2] = PropertyFindOrInheritReadFloat(object, "transform2"); - paint.transform[3] = PropertyFindOrInheritReadFloat(object, "transform3"); - paint.transform[4] = PropertyFindOrInheritReadFloat(object, "transform4"); - paint.transform[5] = PropertyFindOrInheritReadFloat(object, "transform5"); + ExportF32(data, paint, transform[0], object, "transform0"); + ExportF32(data, paint, transform[1], object, "transform1"); + ExportF32(data, paint, transform[2], object, "transform2"); + ExportF32(data, paint, transform[3], object, "transform3"); + ExportF32(data, paint, transform[4], object, "transform4"); + ExportF32(data, paint, transform[5], object, "transform5"); paint.stopCount = PropertyFindOrInheritReadInt32(object, "stops_count"); paint.useGammaInterpolation = !!PropertyFindOrInheritReadInt32(object, "useGammaInterpolation"); paint.repeatMode = PropertyFindOrInheritReadInt32(object, "repeatMode"); - EsBufferWrite(data, &paint, sizeof(paint)); + ExportWrite(data, &paint, sizeof(paint)); ExportGradientStopArray(object, data, paint.stopCount); } @@ -1921,49 +2046,50 @@ int8_t ExportPaint(Object *object, EsBuffer *data, int depth = 0) { } } -void ExportLayerBox(Object *object, EsBuffer *data) { - Property *mainPaint = PropertyFindOrInherit(object, "mainPaint", PROP_OBJECT); - Property *borderPaint = PropertyFindOrInherit(object, "borderPaint", PROP_OBJECT); +void ExportLayerBox(Object *object, ExportContext *data) { ThemeLayerBox box = {}; - box.mainPaintType = ExportPaint(ObjectFind(mainPaint ? mainPaint->object : 0), nullptr); - box.borderPaintType = ExportPaint(ObjectFind(borderPaint ? borderPaint->object : 0), nullptr); - box.borders.l = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders0")); - box.borders.r = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders1")); - box.borders.t = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders2")); - box.borders.b = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "borders3")); - box.corners.tl = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners0")); - box.corners.tr = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners1")); - box.corners.bl = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners2")); - box.corners.br = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "corners3")); + box.mainPaintType = ExportPaint(object, "mainPaint", nullptr); + box.borderPaintType = ExportPaint(object, "borderPaint", nullptr); + ExportI8(data, box, borders.l, object, "borders0"); + ExportI8(data, box, borders.r, object, "borders1"); + ExportI8(data, box, borders.t, object, "borders2"); + ExportI8(data, box, borders.b, object, "borders3"); + ExportI8(data, box, corners.tl, object, "corners0"); + ExportI8(data, box, corners.tr, object, "corners1"); + ExportI8(data, box, corners.bl, object, "corners2"); + ExportI8(data, box, corners.br, object, "corners3"); + ExportI8(data, box, offset.l, object, "offset0"); + ExportI8(data, box, offset.r, object, "offset1"); + ExportI8(data, box, offset.t, object, "offset2"); + ExportI8(data, box, offset.b, object, "offset3"); if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "isBlurred" ))) box.flags |= THEME_LAYER_BOX_IS_BLURRED; if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "autoCorners" ))) box.flags |= THEME_LAYER_BOX_AUTO_CORNERS; if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "autoBorders" ))) box.flags |= THEME_LAYER_BOX_AUTO_BORDERS; if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "shadowHiding"))) box.flags |= THEME_LAYER_BOX_SHADOW_HIDING; - EsBufferWrite(data, &box, sizeof(box)); - ExportPaint(ObjectFind(mainPaint ? mainPaint->object : 0), data); - ExportPaint(ObjectFind(borderPaint ? borderPaint->object : 0), data); + ExportWrite(data, &box, sizeof(box)); + ExportPaint(object, "mainPaint", data); + ExportPaint(object, "borderPaint", data); } -void ExportLayerPath(Object *object, EsBuffer *data) { +void ExportLayerPath(Object *object, ExportContext *data) { Property *pointCount = PropertyFindOrInherit(object, "points_count", PROP_INT); Property *fillCount = PropertyFindOrInherit(object, "fills_count", PROP_INT); ThemeLayerPath path = {}; if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "pathFillEvenOdd"))) path.flags |= THEME_LAYER_PATH_FILL_EVEN_ODD; if (GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "pathClosed"))) path.flags |= THEME_LAYER_PATH_CLOSED; - path.alpha = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "alpha")); + ExportI16(data, path, alpha, object, "alpha"); path.pointCount = pointCount ? pointCount->integer : 0; path.fillCount = fillCount ? fillCount->integer : 0; - EsBufferWrite(data, &path, sizeof(path)); + ExportWrite(data, &path, sizeof(path)); for (uintptr_t i = 0; i < path.pointCount; i++) { char cPropertyName[PROPERTY_NAME_SIZE]; - float zero = 0.0f; - Property *property; + ThemeVariant value; #define LAYER_PATH_WRITE_POINT(x) \ sprintf(cPropertyName, "points_%d_" #x, (int32_t) i); \ - property = PropertyFindOrInherit(object, cPropertyName, PROP_FLOAT); \ - EsBufferWrite(data, property ? &property->floating : &zero, sizeof(float)); + value = ExportValue(data, 0, object, cPropertyName, THEME_OVERRIDE_F32); \ + ExportWrite(data, &value.f32, sizeof(float)); LAYER_PATH_WRITE_POINT(x0); LAYER_PATH_WRITE_POINT(y0); LAYER_PATH_WRITE_POINT(x1); @@ -1977,8 +2103,7 @@ void ExportLayerPath(Object *object, EsBuffer *data) { ThemeLayerPathFill fill = {}; sprintf(cPropertyName, "fills_%d_paint", (int32_t) i); - Object *paint = PropertyFindOrInheritReadObject(object, cPropertyName); - fill.paintAndFillType |= ExportPaint(paint, nullptr); + fill.paintAndFillType |= ExportPaint(object, cPropertyName, nullptr); sprintf(cPropertyName, "fills_%d_mode", (int32_t) i); Object *mode = PropertyFindOrInheritReadObject(object, cPropertyName); @@ -1991,27 +2116,36 @@ void ExportLayerPath(Object *object, EsBuffer *data) { fill.paintAndFillType |= THEME_PATH_FILL_SOLID; } - EsBufferWrite(data, &fill, sizeof(fill)); - ExportPaint(paint, data); + ExportWrite(data, &fill, sizeof(fill)); + + sprintf(cPropertyName, "fills_%d_paint", (int32_t) i); + ExportPaint(object, cPropertyName, data); if (mode && mode->type == OBJ_VAR_CONTOUR_STYLE) { ThemeLayerPathFillContour contour = {}; - contour.miterLimit = PropertyFindOrInheritReadFloat(mode, "miterLimit"); - contour.internalWidth = PropertyFindOrInheritReadInt32(mode, "internalWidth"); - contour.externalWidth = PropertyFindOrInheritReadInt32(mode, "externalWidth"); + ExportF32(data, contour, miterLimit, mode, "miterLimit"); + ExportI8(data, contour, internalWidth, mode, "internalWidth"); + ExportI8(data, contour, externalWidth, mode, "externalWidth"); contour.mode = PropertyFindOrInheritReadInt32(mode, "joinMode") | (PropertyFindOrInheritReadInt32(mode, "capMode") << 2) | (PropertyFindOrInheritReadInt32(mode, "integerWidthsOnly") ? 0x80 : 0); - EsBufferWrite(data, &contour, sizeof(contour)); + ExportWrite(data, &contour, sizeof(contour)); } } } -void ExportPaintAsLayerBox(Object *object, EsBuffer *data) { +void ExportPaintAsLayerBox(Object *object, ExportContext *data) { + Object parentObject = {}; + Property property = {}; + property.type = PROP_OBJECT; + property.cName[0] = '.'; + property.object = object->id; + parentObject.properties.Add(property); ThemeLayerBox box = {}; - box.mainPaintType = ExportPaint(object, nullptr); - EsBufferWrite(data, &box, sizeof(box)); - ExportPaint(object, data); + box.mainPaintType = ExportPaint(&parentObject, ".", nullptr); + ExportWrite(data, &box, sizeof(box)); + ExportPaint(&parentObject, ".", data); + parentObject.properties.Free(); } ////////////////////////////////////////////////////////////// @@ -2076,7 +2210,7 @@ void CanvasDrawLayerFromData(UIPainter *painter, UIRectangle bounds, EsBuffer da data.bytes = data.position; data.position = 0; - ThemeDrawLayer(&themePainter, bounds, &data, canvas->zoom, UI_RECT_1(0) /* TODO opaqueRegion */); + ThemeDrawLayer(&themePainter, bounds, &data, canvas->zoom, UI_RECT_1(0)); } void CanvasDrawColorSwatch(Object *object, UIRectangle bounds, UIPainter *painter) { @@ -2088,9 +2222,10 @@ void CanvasDrawColorSwatch(Object *object, UIRectangle bounds, UIPainter *painte uint8_t buffer[4096]; EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) }; + ExportContext context = { .baseData = &data }; ThemeLayer layer = { .position = { .r = 100, .b = 100 }, .type = THEME_LAYER_BOX }; - EsBufferWrite(&data, &layer, sizeof(layer)); - ExportPaintAsLayerBox(object, &data); + ExportWrite(&context, &layer, sizeof(layer)); + ExportPaintAsLayerBox(object, &context); CanvasDrawLayerFromData(painter, bounds, data); } @@ -2100,16 +2235,12 @@ void CanvasDrawLayer(Object *object, UIRectangle bounds, UIPainter *painter, int } if (object->type == OBJ_LAYER_BOX) { - bounds.l += GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "offset0")) * canvas->zoom; - bounds.r += GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "offset1")) * canvas->zoom; - bounds.t += GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "offset2")) * canvas->zoom; - bounds.b += GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "offset3")) * canvas->zoom; - uint8_t buffer[4096]; EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) }; + ExportContext context = { .baseData = &data }; ThemeLayer layer = { .position = { .r = 100, .b = 100 }, .type = THEME_LAYER_BOX }; - EsBufferWrite(&data, &layer, sizeof(layer)); - ExportLayerBox(object, &data); + ExportWrite(&context, &layer, sizeof(layer)); + ExportLayerBox(object, &context); CanvasDrawLayerFromData(painter, bounds, data); } else if (object->type == OBJ_LAYER_TEXT) { #ifdef OS_ESSENCE @@ -2136,9 +2267,10 @@ void CanvasDrawLayer(Object *object, UIRectangle bounds, UIPainter *painter, int } else if (object->type == OBJ_LAYER_PATH) { uint8_t buffer[4096]; EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) }; + ExportContext context = { .baseData = &data }; ThemeLayer layer = { .position = { .r = 100, .b = 100 }, .type = THEME_LAYER_PATH }; - EsBufferWrite(&data, &layer, sizeof(layer)); - ExportLayerPath(object, &data); + ExportWrite(&context, &layer, sizeof(layer)); + ExportLayerPath(object, &context); CanvasDrawLayerFromData(painter, bounds, data); } else if (object->type == OBJ_LAYER_GROUP) { int32_t layerCount = PropertyReadInt32(object, "layers_count"); @@ -2315,7 +2447,7 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) { UIDrawString(painter, indicator, "?", -1, 0xFF000000, UI_ALIGN_CENTER, nullptr); } - bounds = UIRectangleAdd(bounds, UI_RECT_1I(3)); + bounds = UIRectangleAdd(bounds, UI_RECT_1I(5)); } if (selectedObjectID == object->id && canvas->resizing) { @@ -2762,25 +2894,101 @@ void ObjectDuplicateCommand(void *) { ////////////////////////////////////////////////////////////// Rectangle8 ExportCalculatePaintOutsets(Object *object) { - return {}; // TODO; + Rectangle8 paintOutsets = {}; + + int32_t layerCount = PropertyReadInt32(object, "layers_count"); + if (layerCount < 0) layerCount = 0; + if (layerCount > 100) layerCount = 100; + + for (int32_t i = 0; i < layerCount; i++) { + char cPropertyName[PROPERTY_NAME_SIZE]; + sprintf(cPropertyName, "layers_%d_layer", i); + Property *layerProperty = PropertyFind(object, cPropertyName, PROP_OBJECT); + Object *layerObject = ObjectFind(layerProperty ? layerProperty->object : 0); + if (!layerObject) continue; + +#define LAYER_READ_INT32(x) sprintf(cPropertyName, "layers_%d_" #x, i); int8_t x = PropertyReadInt32(object, cPropertyName) + LAYER_READ_INT32(offset0); + LAYER_READ_INT32(offset1); + LAYER_READ_INT32(offset2); + LAYER_READ_INT32(offset3); + LAYER_READ_INT32(position0); + LAYER_READ_INT32(position1); + LAYER_READ_INT32(position2); + LAYER_READ_INT32(position3); +#undef LAYER_READ_INT32 + + if (layerObject->type == OBJ_LAYER_BOX) { + Object *object = layerObject; + int depth = 0; + + while (object && (depth++ < 100)) { + int32_t boxOffset0 = PropertyReadInt32(object, "offset0"); + int32_t boxOffset1 = PropertyReadInt32(object, "offset1"); + int32_t boxOffset2 = PropertyReadInt32(object, "offset2"); + int32_t boxOffset3 = PropertyReadInt32(object, "offset3"); + if (boxOffset0 < offset0) offset0 = boxOffset0; + if (boxOffset1 > offset1) offset1 = boxOffset1; + if (boxOffset2 < offset2) offset2 = boxOffset2; + if (boxOffset3 > offset3) offset3 = boxOffset3; + Property *property = PropertyFind(object, "_parent", PROP_OBJECT); + object = ObjectFind(property ? property->object : 0); + } + } + + if (position0 == 0 && -offset0 > paintOutsets.l) paintOutsets.l = -offset0; + if (position1 == 100 && offset1 > paintOutsets.r) paintOutsets.r = offset1; + if (position2 == 0 && -offset2 > paintOutsets.t) paintOutsets.t = -offset2; + if (position3 == 100 && offset3 > paintOutsets.b) paintOutsets.b = offset3; + } + + return paintOutsets; } Rectangle8 ExportCalculateOpaqueInsets(Object *object) { - return {}; // TODO; + return { 0x7F, 0x7F, 0x7F, 0x7F }; // TODO; } Rectangle8 ExportCalculateApproximateBorders(Object *object) { - return {}; // TODO; + int32_t layerCount = PropertyReadInt32(object, "layers_count"); + if (layerCount < 0) layerCount = 0; + if (layerCount > 100) layerCount = 100; + + for (int32_t i = 0; i < layerCount; i++) { + char cPropertyName[PROPERTY_NAME_SIZE]; + sprintf(cPropertyName, "layers_%d_layer", i); + Property *layerProperty = PropertyFind(object, cPropertyName, PROP_OBJECT); + Object *layerObject = ObjectFind(layerProperty ? layerProperty->object : 0); + if (!layerObject) continue; + +#define LAYER_READ_INT32(x) sprintf(cPropertyName, "layers_%d_" #x, i); int8_t x = PropertyReadInt32(object, cPropertyName) + LAYER_READ_INT32(position0); + LAYER_READ_INT32(position1); + LAYER_READ_INT32(position2); + LAYER_READ_INT32(position3); + LAYER_READ_INT32(mode); +#undef LAYER_READ_INT32 + + if (layerObject->type == OBJ_LAYER_BOX && position0 == 0 && position1 == 100 && position2 == 0 && position3 == 100 + && !PropertyReadInt32(layerObject, "shadowHiding") && !PropertyReadInt32(layerObject, "isBlurred") + && mode == THEME_LAYER_MODE_BACKGROUND && PropertyFind(layerObject, "borderPaint")) { + return { + (int8_t) PropertyReadInt32(layerObject, "borders0"), + (int8_t) PropertyReadInt32(layerObject, "borders1"), + (int8_t) PropertyReadInt32(layerObject, "borders2"), + (int8_t) PropertyReadInt32(layerObject, "borders3"), + }; + } + } + + return {}; } #ifndef OS_ESSENCE void Export() { DocumentLoad(); - // TODO Output the new styles.header. - // TODO Export conditional objects into sequences. - - // TODO Exporting modified integers and colors. + // TODO Exporting modified integers and colors as constants. // TODO Recursively exporting nested groups. // TODO Handling styles that don't have metrics/textStyle. @@ -2910,9 +3118,9 @@ void Export() { exportOffset.offset = ftell(output); exportOffsets.Add(exportOffset); - ThemeLayer layer = {}; - layer.type = THEME_LAYER_METRICS; - layer.dataByteCount = sizeof(ThemeLayer) + sizeof(ThemeMetrics); + uint8_t overrideDataBuffer[4096]; + EsBuffer overrideData = { .out = overrideDataBuffer, .bytes = sizeof(overrideDataBuffer) }; + ExportContext context = { .overrideData = &overrideData, .overrideOffset = sizeof(ThemeLayer) }; ThemeMetrics _metrics = {}; @@ -2945,17 +3153,33 @@ void Export() { | (verticalTextAlign == 1 ? ES_TEXT_V_TOP : verticalTextAlign == 3 ? ES_TEXT_V_BOTTOM : ES_TEXT_V_CENTER); _metrics.fontFamily = PropertyFindOrInheritReadInt32(textStyle, "fontFamily"); - _metrics.fontWeight = GraphGetIntegerFromProperty(PropertyFind(textStyle, "fontWeight")); - _metrics.textSize = GraphGetIntegerFromProperty(PropertyFindOrInherit(textStyle, "textSize")); - _metrics.iconSize = GraphGetIntegerFromProperty(PropertyFindOrInherit(textStyle, "iconSize")); _metrics.isItalic = PropertyFindOrInheritReadInt32(textStyle, "isItalic"); - _metrics.textColor = GraphGetColorFromProperty(PropertyFindOrInherit(textStyle, "textColor")); - _metrics.selectedBackground = GraphGetColorFromProperty(PropertyFindOrInherit(textStyle, "selectedBackground")); - _metrics.selectedText = GraphGetColorFromProperty(PropertyFindOrInherit(textStyle, "selectedText")); - _metrics.iconColor = GraphGetColorFromProperty(PropertyFindOrInherit(textStyle, "iconColor")); + ExportI8(&context, _metrics, fontWeight, textStyle, "fontWeight"); + ExportI16(&context, _metrics, textSize, textStyle, "textSize"); + ExportI16(&context, _metrics, iconSize, textStyle, "iconSize"); + ExportColor(&context, _metrics, textColor, textStyle, "textColor"); + ExportColor(&context, _metrics, selectedBackground, textStyle, "selectedBackground"); + ExportColor(&context, _metrics, selectedText, textStyle, "selectedText"); + ExportColor(&context, _metrics, iconColor, textStyle, "iconColor"); + ThemeLayer layer = {}; + layer.type = THEME_LAYER_METRICS; + layer.dataByteCount = sizeof(ThemeLayer) + sizeof(ThemeMetrics); + layer.overrideCount = overrideData.position / sizeof(ThemeOverride); + layer.overrideListOffset = layer.dataByteCount + ftell(output); fwrite(&layer, 1, sizeof(layer), output); + +#if 0 + for (uintptr_t i = 0; i < objects.Length(); i++) { + if (objects[i].type == OBJ_STYLE && PropertyFindOrInheritReadObject(&objects[i], "textStyle") == textStyle) { + fprintf(stderr, "%s %d %d\n", objects[i].cName, layer.overrideCount, layer.overrideListOffset); + } + } +#endif + fwrite(&_metrics, 1, sizeof(_metrics), output); + fwrite(overrideData.out, 1, overrideData.position, output); + assert(!overrideData.error); } else { assert(false); // TODO. } @@ -2988,36 +3212,39 @@ void Export() { LAYER_READ_INT32(position3); #undef LAYER_READ_INT32 - uint8_t buffer[4096]; - EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) }; + uint8_t baseDataBuffer[4096]; + uint8_t overrideDataBuffer[4096]; + EsBuffer baseData = { .out = baseDataBuffer, .bytes = sizeof(baseDataBuffer) }; + EsBuffer overrideData = { .out = overrideDataBuffer, .bytes = sizeof(overrideDataBuffer) }; + ExportContext context = { .baseData = &baseData, .overrideData = &overrideData, .overrideOffset = sizeof(ThemeLayer) }; ThemeLayer layer = {}; layer.position = { position0, position1, position2, position3 }; layer.offset = { offset0, offset1, offset2, offset3 }; if (layerObject->type == OBJ_LAYER_PATH) { layer.type = THEME_LAYER_PATH; - ExportLayerPath(layerObject, &data); + ExportLayerPath(layerObject, &context); } else if (layerObject->type == OBJ_LAYER_BOX) { layer.type = THEME_LAYER_BOX; - layer.offset.l += GraphGetIntegerFromProperty(PropertyFindOrInherit(layerObject, "offset0")); - layer.offset.r += GraphGetIntegerFromProperty(PropertyFindOrInherit(layerObject, "offset1")); - layer.offset.t += GraphGetIntegerFromProperty(PropertyFindOrInherit(layerObject, "offset2")); - layer.offset.b += GraphGetIntegerFromProperty(PropertyFindOrInherit(layerObject, "offset3")); - ExportLayerBox(layerObject, &data); + ExportLayerBox(layerObject, &context); } else if (layerObject->type == OBJ_LAYER_TEXT) { layer.type = THEME_LAYER_TEXT; ThemeLayerText text = {}; - text.blur = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "blur")); - text.color = GraphGetColorFromProperty(PropertyFindOrInherit(object, "color")); - EsBufferWrite(&data, &text, sizeof(text)); + ExportI8(&context, text, blur, object, "blur"); + ExportColor(&context, text, color, object, "color"); + ExportWrite(&context, &text, sizeof(text)); } else { assert(false); } - layer.dataByteCount = data.position + sizeof(layer); + layer.dataByteCount = baseData.position + sizeof(layer); + layer.overrideCount = overrideData.position / sizeof(ThemeOverride); + layer.overrideListOffset = layer.dataByteCount + ftell(output); fwrite(&layer, 1, sizeof(layer), output); - fwrite(data.out, 1, data.position, output); - assert(!data.error); + fwrite(baseData.out, 1, baseData.position, output); + fwrite(overrideData.out, 1, overrideData.position, output); + assert(!baseData.error); + assert(!overrideData.error); } } } @@ -3075,6 +3302,47 @@ void Export() { fwrite(&exportOffset, 1, sizeof(exportOffset), output); writeOffset += sizeof(ThemeStyle); } + + DocumentFree(); + fclose(output); + exportOffsets.Free(); +} + +void ExportJSON() { + DocumentLoad(); + FILE *f = fopen("bin/designer2.json", "wb"); + fprintf(f, "{\n\t\"version\": 1,\n\t\"objectIDAllocator\": %ld,\n", objectIDAllocator); + + for (uintptr_t i = 0; i < objects.Length(); i++) { + Object *object = &objects[i]; + const char *type = "??"; + + for (uintptr_t i = 0; i < sizeof(cObjectTypeStrings) / sizeof(cObjectTypeStrings[0]); i++) { + if (cObjectTypeStrings[i].type == object->type) { + type = cObjectTypeStrings[i].string; + break; + } + } + + fprintf(f, "\t\"%ld\": {\n\t\t\"Flags\": %d,\n\t\t\"Type\": \"%s\",\n\t\t\"Name\": \"%s\",\n", + object->id, object->flags, type, object->cName); + + for (uintptr_t i = 0; i < object->properties.Length(); i++) { + Property *property = &object->properties[i]; + fprintf(f, "\t\t\"%s\": ", property->cName); + 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_FLOAT) fprintf(f, "%f", property->floating); + fprintf(f, "%s\n", i < object->properties.Length() - 1 ? "," : ""); + } + + fprintf(f, "\t}%s\n", i < objects.Length() - 1 ? "," : ""); + } + + fprintf(f, "}\n"); + fclose(f); + DocumentFree(); } #endif @@ -3108,6 +3376,8 @@ int main(int argc, char **argv) { if (argc == 2) { if (0 == strcmp(argv[1], "export")) { Export(); + } else if (0 == strcmp(argv[1], "json")) { + ExportJSON(); } else { fprintf(stderr, "Error: Unknown action '%s'.\n", argv[1]); return 1; @@ -3161,7 +3431,7 @@ int main(int argc, char **argv) { UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_LETTER('Y'), 1 /* ctrl */, 0, 0, DocumentRedoStep, 0)); UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_LETTER('D'), 1 /* ctrl */, 0, 0, ObjectDuplicateCommand, 0)); UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_FKEY(2), 0, 0, 0, CanvasSwitchView, 0)); - UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_FKEY(1), 0, 0, 0, CanvasZoom100, 0)); + UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_DIGIT('1'), 1 /* ctrl */, 0, 0, CanvasZoom100, 0)); UIWindowRegisterShortcut(window, UI_SHORTCUT(UI_KEYCODE_DELETE, 0, 0, 0, ObjectDeleteCommand, 0)); #ifdef OS_ESSENCE