designer2 non-animated export

This commit is contained in:
nakst 2021-10-02 20:59:34 +01:00
parent 91e674a7f3
commit b702c77c05
13 changed files with 541 additions and 188 deletions

View File

@ -2397,10 +2397,11 @@ void DesktopSetup() {
// Load the theme bitmap.
if (!desktop.setupDesktopUIComplete) {
size_t cursorsBitmapBytes;
const void *cursorsBitmap = EsBundleFind(&bundleDesktop, EsLiteral("Cursors.png"), &cursorsBitmapBytes);
EsHandle handle = EsMemoryOpen(ES_THEME_CURSORS_WIDTH * ES_THEME_CURSORS_HEIGHT * 4, EsLiteral(ES_THEME_CURSORS_NAME), ES_FLAGS_DEFAULT);
void *destination = EsObjectMap(handle, 0, ES_THEME_CURSORS_WIDTH * ES_THEME_CURSORS_HEIGHT * 4, ES_MAP_OBJECT_READ_WRITE);
LoadImage(theming.system.in + theming.system.bytes - theming.header->bitmapBytes, theming.header->bitmapBytes,
destination, ES_THEME_CURSORS_WIDTH, ES_THEME_CURSORS_HEIGHT, true);
LoadImage(cursorsBitmap, cursorsBitmapBytes, destination, ES_THEME_CURSORS_WIDTH, ES_THEME_CURSORS_HEIGHT, true);
EsObjectUnmap(destination);
EsHandleClose(handle);
}

View File

@ -6177,7 +6177,6 @@ EsThemeMetrics EsElementGetMetrics(EsElement *element) {
#define RECTANGLE_8_TO_ES_RECTANGLE(x) { (int32_t) (x).l, (int32_t) (x).r, (int32_t) (x).t, (int32_t) (x).b }
m.insets = RECTANGLE_8_TO_ES_RECTANGLE(metrics->insets);
m.clipInsets = RECTANGLE_8_TO_ES_RECTANGLE(metrics->clipInsets);
m.globalOffset = RECTANGLE_8_TO_ES_RECTANGLE(metrics->globalOffset);
m.clipEnabled = metrics->clipEnabled;
m.cursor = metrics->cursor;
m.preferredWidth = metrics->preferredWidth;
@ -6199,7 +6198,6 @@ EsThemeMetrics EsElementGetMetrics(EsElement *element) {
m.fontWeight = metrics->fontWeight;
m.iconSize = metrics->iconSize;
m.isItalic = metrics->isItalic;
m.ellipsis = metrics->ellipsis;
return m;
}

View File

@ -593,35 +593,29 @@ define ES_CELL_V_CENTER (ES_CELL_V_TOP | ES_CELL_V_BOTTOM)
// Mask bits for EsThemeMetrics:
define ES_THEME_METRICS_INSETS (1 << 0)
define ES_THEME_METRICS_CLIP_INSETS (1 << 1)
define ES_THEME_METRICS_GLOBAL_OFFSET (1 << 2)
define ES_THEME_METRICS_CLIP_ENABLED (1 << 3)
define ES_THEME_METRICS_CURSOR (1 << 4)
define ES_THEME_METRICS_ENTRANCE_TRANSITION (1 << 5)
define ES_THEME_METRICS_EXIT_TRANSITION (1 << 6)
define ES_THEME_METRICS_ENTRANCE_DURATION (1 << 7)
define ES_THEME_METRICS_EXIT_DURATION (1 << 8)
define ES_THEME_METRICS_PREFERRED_WIDTH (1 << 9)
define ES_THEME_METRICS_PREFERRED_HEIGHT (1 << 10)
define ES_THEME_METRICS_MINIMUM_WIDTH (1 << 11)
define ES_THEME_METRICS_MINIMUM_HEIGHT (1 << 12)
define ES_THEME_METRICS_MAXIMUM_WIDTH (1 << 13)
define ES_THEME_METRICS_MAXIMUM_HEIGHT (1 << 14)
define ES_THEME_METRICS_GAP_MAJOR (1 << 15)
define ES_THEME_METRICS_GAP_MINOR (1 << 16)
define ES_THEME_METRICS_GAP_WRAP (1 << 17)
define ES_THEME_METRICS_CLIP_ENABLED (1 << 2)
define ES_THEME_METRICS_CURSOR (1 << 3)
define ES_THEME_METRICS_PREFERRED_WIDTH (1 << 4)
define ES_THEME_METRICS_PREFERRED_HEIGHT (1 << 5)
define ES_THEME_METRICS_MINIMUM_WIDTH (1 << 6)
define ES_THEME_METRICS_MINIMUM_HEIGHT (1 << 7)
define ES_THEME_METRICS_MAXIMUM_WIDTH (1 << 8)
define ES_THEME_METRICS_MAXIMUM_HEIGHT (1 << 9)
define ES_THEME_METRICS_GAP_MAJOR (1 << 10)
define ES_THEME_METRICS_GAP_MINOR (1 << 11)
define ES_THEME_METRICS_GAP_WRAP (1 << 12)
define ES_THEME_METRICS_GAP_ALL (ES_THEME_METRICS_GAP_MAJOR | ES_THEME_METRICS_GAP_MINOR | ES_THEME_METRICS_GAP_WRAP)
define ES_THEME_METRICS_TEXT_COLOR (1 << 18)
define ES_THEME_METRICS_SELECTED_BACKGROUND (1 << 19)
define ES_THEME_METRICS_SELECTED_TEXT (1 << 20)
define ES_THEME_METRICS_ICON_COLOR (1 << 21)
define ES_THEME_METRICS_TEXT_ALIGN (1 << 22)
define ES_THEME_METRICS_TEXT_SIZE (1 << 23)
define ES_THEME_METRICS_FONT_FAMILY (1 << 24)
define ES_THEME_METRICS_FONT_WEIGHT (1 << 25)
define ES_THEME_METRICS_ICON_SIZE (1 << 26)
define ES_THEME_METRICS_IS_ITALIC (1 << 27)
define ES_THEME_METRICS_ELLIPSIS (1 << 28)
define ES_THEME_METRICS_LAYOUT_VERTICAL (1 << 29)
define ES_THEME_METRICS_TEXT_COLOR (1 << 13)
define ES_THEME_METRICS_SELECTED_BACKGROUND (1 << 14)
define ES_THEME_METRICS_SELECTED_TEXT (1 << 15)
define ES_THEME_METRICS_ICON_COLOR (1 << 16)
define ES_THEME_METRICS_TEXT_ALIGN (1 << 17)
define ES_THEME_METRICS_TEXT_SIZE (1 << 18)
define ES_THEME_METRICS_FONT_FAMILY (1 << 19)
define ES_THEME_METRICS_FONT_WEIGHT (1 << 20)
define ES_THEME_METRICS_ICON_SIZE (1 << 21)
define ES_THEME_METRICS_IS_ITALIC (1 << 22)
define ES_THEME_METRICS_LAYOUT_VERTICAL (1 << 23)
define ES_WINDOW_MOVE_MAXIMISED (1 << 0)
define ES_WINDOW_MOVE_ADJUST_TO_FIT_SCREEN (1 << 1)
@ -1310,7 +1304,6 @@ struct EsPanelBand {
struct EsThemeMetrics {
uint64_t mask;
EsRectangle insets, clipInsets;
EsRectangle globalOffset;
int clipEnabled, cursor;
int preferredWidth, preferredHeight;
int minimumWidth, minimumHeight;
@ -1318,7 +1311,7 @@ struct EsThemeMetrics {
int gapMajor, gapMinor, gapWrap;
uint32_t textColor, selectedBackground, selectedText, iconColor;
int textAlign, textSize, fontFamily, fontWeight, iconSize;
bool isItalic, ellipsis, layoutVertical;
bool isItalic, layoutVertical;
};
struct EsThemeAppearance {

View File

@ -14,10 +14,6 @@
#define THEME_LAYER_MODE_CONTENT (2)
#define THEME_LAYER_MODE_OVERLAY (3)
#define THEME_FONT_FAMILY_SANS (0)
#define THEME_FONT_FAMILY_SERIF (1)
#define THEME_FONT_FAMILY_MONO (2)
#define THEME_OVERRIDE_I8 (1)
#define THEME_OVERRIDE_I16 (2)
#define THEME_OVERRIDE_F32 (3)
@ -159,12 +155,6 @@ typedef struct ThemeLayerIcon {
Rectangle16 image;
} ThemeLayerIcon;
typedef struct ThemeLayerImage {
uint16_t alpha;
uint16_t _unused0;
Rectangle16 image, contentRegion;
} ThemeLayerImage;
typedef struct ThemeLayerPathFillContour {
float miterLimit;
uint8_t internalWidth, externalWidth;
@ -200,9 +190,8 @@ typedef struct ThemeLayer {
typedef struct ThemeMetrics {
Rectangle16 insets, clipInsets;
Rectangle16 globalOffset;
uint8_t clipEnabled, cursor;
uint16_t fontFamily;
uint16_t fontFamily; // TODO This needs to be validated when loading.
int16_t preferredWidth, preferredHeight;
int16_t minimumWidth, minimumHeight;
int16_t maximumWidth, maximumHeight;
@ -210,7 +199,7 @@ typedef struct ThemeMetrics {
uint32_t textColor, selectedBackground, selectedText, iconColor;
int8_t textAlign, fontWeight;
int16_t textSize, iconSize;
bool isItalic, ellipsis, layoutVertical;
bool isItalic, layoutVertical;
} ThemeMetrics;
typedef union ThemeVariant {
@ -236,7 +225,10 @@ typedef struct ThemeSequenceHeader {
} ThemeSequenceHeader;
typedef struct ThemeStyle {
uint32_t layerListOffset; // A list of uint32_t, giving offsets to ThemeLayer. First is the metrics layer.
// 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.**
uint32_t layerListOffset;
uint16_t id;
uint8_t layerCount;
uint8_t _unused1;
@ -245,17 +237,14 @@ typedef struct ThemeStyle {
typedef struct ThemeConstant {
uint64_t hash;
uint32_t valueOffset;
uint32_t valueByteCount;
char cValue[12];
bool scale;
} ThemeConstant;
typedef struct ThemeHeader {
uint32_t signature;
uint32_t styleCount, constantCount;
uint32_t bitmapBytes;
// Followed by array of ThemeStyles and then an array of ThemeConstants.
// The bitmap is at the end of the theme file.
} ThemeHeader;
typedef struct BasicFontKerningEntry {
@ -1253,17 +1242,19 @@ const void *GetConstant(const char *cKey, size_t *byteCount, bool *scale) {
}
if (constant->hash == hash) {
data.position = constant->valueOffset;
const void *value = EsBufferRead(&data, (constant->valueByteCount + 3) & ~3);
size_t _byteCount = 0;
if (!value) {
EsPrint("Broken theme constant value.\n");
return 0;
for (uintptr_t i = 0; i < sizeof(constant->cValue); i++) {
if (constant->cValue[i] == 0) {
break;
} else {
_byteCount++;
}
}
*byteCount = constant->valueByteCount;
*byteCount = _byteCount;
*scale = constant->scale;
return value;
return constant->cValue;
}
}
@ -1280,30 +1271,6 @@ int GetConstantNumber(const char *cKey) {
return integer;
}
EsRectangle GetConstantRectangle(const char *cKey) {
size_t byteCount;
bool scale = false;
char *value = (char *) GetConstant(cKey, &byteCount, &scale);
if (!value) return {};
EsRectangle rectangle;
rectangle.l = EsCRTstrtol(value, &value, 10);
if (*value == ',') value++;
rectangle.r = EsCRTstrtol(value, &value, 10);
if (*value == ',') value++;
rectangle.t = EsCRTstrtol(value, &value, 10);
if (*value == ',') value++;
rectangle.b = EsCRTstrtol(value, &value, 10);
if (scale) {
rectangle.l *= theming.scale;
rectangle.r *= theming.scale;
rectangle.t *= theming.scale;
rectangle.b *= theming.scale;
}
return rectangle;
}
const char *GetConstantString(const char *cKey) {
size_t byteCount;
bool scale;
@ -1317,9 +1284,7 @@ bool ThemeInitialise() {
const ThemeHeader *header = (const ThemeHeader *) EsBufferRead(&data, sizeof(ThemeHeader));
if (!header || header->signature != THEME_HEADER_SIGNATURE
|| !header->styleCount || !EsBufferRead(&data, sizeof(ThemeStyle))
|| data.bytes < header->bitmapBytes) {
if (!header || header->signature != THEME_HEADER_SIGNATURE || !header->styleCount || !EsBufferRead(&data, sizeof(ThemeStyle))) {
return false;
}
@ -1550,7 +1515,6 @@ void ThemeStylePrepare(UIStyle *style, UIStyleKey key) {
#define ES_RECTANGLE_TO_RECTANGLE_8(x) { (int8_t) (x).l, (int8_t) (x).r, (int8_t) (x).t, (int8_t) (x).b }
if (customMetrics->mask & ES_THEME_METRICS_INSETS) style->metrics->insets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->insets);
if (customMetrics->mask & ES_THEME_METRICS_CLIP_INSETS) style->metrics->clipInsets = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->clipInsets);
if (customMetrics->mask & ES_THEME_METRICS_GLOBAL_OFFSET) style->metrics->globalOffset = ES_RECTANGLE_TO_RECTANGLE_8(customMetrics->globalOffset);
if (customMetrics->mask & ES_THEME_METRICS_CLIP_ENABLED) style->metrics->clipEnabled = customMetrics->clipEnabled;
if (customMetrics->mask & ES_THEME_METRICS_CURSOR) style->metrics->cursor = customMetrics->cursor;
if (customMetrics->mask & ES_THEME_METRICS_PREFERRED_WIDTH) style->metrics->preferredWidth = customMetrics->preferredWidth;
@ -1572,7 +1536,6 @@ void ThemeStylePrepare(UIStyle *style, UIStyleKey key) {
if (customMetrics->mask & ES_THEME_METRICS_FONT_WEIGHT) style->metrics->fontWeight = customMetrics->fontWeight;
if (customMetrics->mask & ES_THEME_METRICS_ICON_SIZE) style->metrics->iconSize = customMetrics->iconSize;
if (customMetrics->mask & ES_THEME_METRICS_IS_ITALIC) style->metrics->isItalic = customMetrics->isItalic;
if (customMetrics->mask & ES_THEME_METRICS_ELLIPSIS) style->metrics->ellipsis = customMetrics->ellipsis;
if (customMetrics->mask & ES_THEME_METRICS_LAYOUT_VERTICAL) style->metrics->layoutVertical = customMetrics->layoutVertical;
}
@ -1585,7 +1548,6 @@ void ThemeStylePrepare(UIStyle *style, UIStyleKey key) {
int16_t *scale16[] = {
&style->metrics->insets.l, &style->metrics->insets.r, &style->metrics->insets.t, &style->metrics->insets.b,
&style->metrics->clipInsets.l, &style->metrics->clipInsets.r, &style->metrics->clipInsets.t, &style->metrics->clipInsets.b,
&style->metrics->globalOffset.l, &style->metrics->globalOffset.r, &style->metrics->globalOffset.t, &style->metrics->globalOffset.b,
&style->metrics->gapMajor, &style->metrics->gapMinor, &style->metrics->gapWrap,
&style->metrics->preferredWidth, &style->metrics->preferredHeight,
&style->metrics->minimumWidth, &style->metrics->minimumHeight,
@ -1689,7 +1651,7 @@ UIStyle *ThemeStyleInitialise(UIStyleKey key) {
}
if (layer->dataByteCount < sizeof(ThemeLayer)) {
EsPrint("Broken layer data byte count.\n");
EsPrint("Broken layer data byte count (%d; %d).\n", layer->dataByteCount, *offset);
return nullptr;
}
@ -1933,7 +1895,7 @@ void UIStyle::PaintTextLayers(EsPainter *painter, EsTextPlan *plan, EsRectangle
void UIStyle::PaintText(EsPainter *painter, EsElement *element, EsRectangle rectangle,
const char *text, size_t textBytes, uint32_t iconID, uint32_t flags, EsTextSelection *selectionProperties) {
EsRectangle bounds = EsRectangleAdd(Translate(EsRectangleAddBorder(rectangle, insets), painter->offsetX, painter->offsetY), RECT16_TO_RECT(metrics->globalOffset));
EsRectangle bounds = Translate(EsRectangleAddBorder(rectangle, insets), painter->offsetX, painter->offsetY);
EsRectangle textBounds = bounds;
EsRectangle oldClip = painter->clip;
EsRectangleClip(painter->clip, bounds, &painter->clip);
@ -2055,10 +2017,10 @@ void UIStyle::PaintLayers(EsPainter *painter, EsRectangle location, int childTyp
}
EsRectangle bounds;
bounds.l = _bounds.l + (int) (scale * layer->offset.l) + THEME_RECT_WIDTH(_bounds) * layer->position.l / 100 + metrics->globalOffset.l;
bounds.r = _bounds.l + (int) (scale * layer->offset.r) + THEME_RECT_WIDTH(_bounds) * layer->position.r / 100 + metrics->globalOffset.r;
bounds.t = _bounds.t + (int) (scale * layer->offset.t) + THEME_RECT_HEIGHT(_bounds) * layer->position.t / 100 + metrics->globalOffset.t;
bounds.b = _bounds.t + (int) (scale * layer->offset.b) + THEME_RECT_HEIGHT(_bounds) * layer->position.b / 100 + metrics->globalOffset.b;
bounds.l = _bounds.l + (int) (scale * layer->offset.l) + THEME_RECT_WIDTH(_bounds) * layer->position.l / 100;
bounds.r = _bounds.l + (int) (scale * layer->offset.r) + THEME_RECT_WIDTH(_bounds) * layer->position.r / 100;
bounds.t = _bounds.t + (int) (scale * layer->offset.t) + THEME_RECT_HEIGHT(_bounds) * layer->position.t / 100;
bounds.b = _bounds.t + (int) (scale * layer->offset.b) + THEME_RECT_HEIGHT(_bounds) * layer->position.b / 100;
if (layer->mode == whichLayers && THEME_RECT_WIDTH(bounds) > 0 && THEME_RECT_HEIGHT(bounds) > 0
&& THEME_RECT_VALID(EsRectangleIntersection(bounds, painter->clip))) {

Binary file not shown.

BIN
res/Theme.dat Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1191,7 +1191,7 @@ void DoCommand(const char *l) {
CallSystem("bin/config_editor");
} else if (0 == strcmp(l, "designer")) {
BuildUtilities();
CallSystem("bin/designer \"res/Theme Source.dat\" \"res/Themes/Theme.dat\" \"res/Cursors.png\" \"desktop/styles.header\"");
CallSystem("bin/designer \"res/Theme Source.dat\" \"res/Theme.dat\" \"desktop/styles.header\"");
} else if (0 == strcmp(l, "designer2")) {
BuildUtilities();
CallSystem("bin/designer2");

View File

@ -575,9 +575,10 @@ void BuildDesktop(Application *application) {
}
}
ADD_BUNDLE_INPUT("res/Themes/Theme.dat", "Theme.dat", 16);
ADD_BUNDLE_INPUT("res/Themes/elementary Icons.dat", "Icons.dat", 16);
ADD_BUNDLE_INPUT("res/Themes/elementary Icons License.txt", "Icons License.txt", 16);
ADD_BUNDLE_INPUT("res/Theme.dat", "Theme.dat", 16);
ADD_BUNDLE_INPUT("res/elementary Icons.dat", "Icons.dat", 16);
ADD_BUNDLE_INPUT("res/elementary Icons License.txt", "Icons License.txt", 16);
ADD_BUNDLE_INPUT("res/Cursors.png", "Cursors.png", 16);
ADD_BUNDLE_INPUT("bin/Desktop.no_symbols", "$Executables/x86_64", 0x1000);
MakeBundle("root/" SYSTEM_FOLDER_NAME "/Desktop.esx", application->bundleInputFiles, arrlenu(application->bundleInputFiles), 0);

View File

@ -239,7 +239,7 @@ ModContext selected = MOD_CONTEXT(NULL, NULL, NULL, NULL);
char temporaryOverride[4096];
char *filePath, *exportPath, *embedBitmapPath, *stylesPath;
char *filePath, *exportPath, *stylesPath;
void ModApply(ModData *mod);
@ -1286,7 +1286,6 @@ void LayerMetricsOp(RfState *state, RfItem *item, void *pointer) {
metrics.gapMajor = layer->gaps.major;
metrics.gapMinor = layer->gaps.minor;
metrics.gapWrap = layer->gaps.wrap;
EXPORT_RECTANGLE16_FIELD(LayerMetrics, layer, ThemeMetrics, metrics, globalOffset, globalOffset);
int fontFamily = inherit ? inherit->fontFamily : layer->fontFamily;
metrics.fontFamily = fontFamily == FONT_FAMILY_SANS ? 0xFFFF : fontFamily == FONT_FAMILY_SERIF ? 0xFFFE : 0xFFFD;
@ -1359,27 +1358,12 @@ void StyleSetOp(RfState *state, RfItem *item, void *pointer) {
ExportState *export = (ExportState *) state;
StyleSet *styleSet = (StyleSet *) pointer;
// Load the cursors image.
size_t bitmapBytes = 0;
char *bitmap = NULL;
if (embedBitmapPath) {
bitmap = LoadFile(embedBitmapPath, &bitmapBytes);
if (!bitmap) {
printf("Error: Could not load the embedded bitmap!\n");
return;
}
}
// Write the header.
ThemeHeader header = { 0 };
header.signature = THEME_HEADER_SIGNATURE;
header.styleCount = arrlenu(styleSet->styles);
header.constantCount = arrlenu(styleSet->constants);
header.bitmapBytes = bitmapBytes;
state->access(state, &header, sizeof(header));
assert((export->buffer.data.byteCount & 3) == 0);
@ -1433,30 +1417,18 @@ void StyleSetOp(RfState *state, RfItem *item, void *pointer) {
// Write the list of constants.
uint32_t constantListOffset = export->buffer.data.byteCount;
for (uintptr_t i = 0; i < header.constantCount; i++) {
Constant *constant = styleSet->constants[i];
ThemeConstant entry = { 0 };
assert(constant->value.byteCount + 1 < sizeof(entry.cValue));
entry.hash = CalculateCRC64(constant->key.buffer, constant->key.byteCount, 0);
entry.scale = constant->scale;
memcpy(entry.cValue, constant->value.buffer, constant->value.byteCount);
entry.cValue[constant->value.byteCount] = 0;
state->access(state, &entry, sizeof(entry));
assert((export->buffer.data.byteCount & 3) == 0);
}
for (uintptr_t i = 0; i < header.constantCount; i++) {
Constant *constant = styleSet->constants[i];
ThemeConstant *entry = (ThemeConstant *) ((uint8_t *) export->buffer.data.buffer + constantListOffset) + i;
entry->valueOffset = export->buffer.data.byteCount;
entry->valueByteCount = constant->value.byteCount + 1;
entry->scale = constant->scale;
state->access(state, constant->value.buffer, constant->value.byteCount);
uint8_t terminate = 0;
state->access(state, &terminate, 1);
uint32_t pad = 0;
state->access(state, &pad, 4 - ((constant->value.byteCount + 1) & 3));
assert((export->buffer.data.byteCount & 3) == 0);
}
// Write out all layers.
for (uintptr_t i = 0; i < arrlenu(styleSet->layers); i++) {
@ -1571,11 +1543,6 @@ void StyleSetOp(RfState *state, RfItem *item, void *pointer) {
ThemeStyle *entry = (ThemeStyle *) ((uint8_t *) export->buffer.data.buffer + styleListOffset) + i;
entry->layerListOffset = layerListOffset;
}
// Write out the bitmap.
state->access(state, bitmap, bitmapBytes);
free(bitmap);
} else {
RfStructOp(state, item, pointer);
}
@ -1723,6 +1690,25 @@ void ObjectAddObjectProperty(Object2 *object, const char *cName, uint64_t value)
arrput(object->properties, property);
}
void AutoNameOverrideObject(Object2 *override, uint32_t primaryState, uint32_t stateBits) {
const char *cPrimaryStateStrings[] = {
"Any", "Idle", "Hovered", "Pressed", "Disabled", "Inactive",
};
const char *cStateBitStrings[] = {
"Focus", "Check", "Indtm", "DefBtn", "Sel", "FcItem", "ListFc", "BfEnt", "AfExt",
};
snprintf(override->cName, sizeof(override->cName), "?%s", primaryState ? cPrimaryStateStrings[primaryState] : "");
for (uintptr_t i = 0; i < 16; i++) {
if (stateBits & (1 << (15 - i))) {
snprintf(override->cName + strlen(override->cName), sizeof(override->cName) - strlen(override->cName),
"%s%s", i || primaryState ? "&" : "", cStateBitStrings[i]);
}
}
}
uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *idAllocator, Layer *layer) {
char cPropertyName[PROPERTY_NAME_SIZE];
@ -1731,19 +1717,6 @@ uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *
} else if (paint->tag == Paint_solid + 1) {
return ColorLookupPointer(paint->solid.color)->object2ID;
} else if (paint->tag == Paint_linearGradient + 1) {
bool constantColor = true;
for (uintptr_t i = 1; i < arrlenu(paint->linearGradient.stops); i++) {
if (paint->linearGradient.stops[i].color != paint->linearGradient.stops[0].color) {
constantColor = false;
break;
}
}
if (constantColor) {
return ColorLookupPointer(paint->linearGradient.stops[0].color)->object2ID;
}
Object2 object = { .type = OBJ_PAINT_LINEAR_GRADIENT, .id = ++(*idAllocator) };
ObjectAddIntegerProperty(&object, "_graphX", *x);
@ -1794,6 +1767,7 @@ uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *
ObjectAddIntegerProperty(&override, "_primaryState", s->primaryState);
ObjectAddIntegerProperty(&override, "_stateBits", stateBits);
ObjectAddIntegerProperty(&override, "_duration", s->duration);
AutoNameOverrideObject(&override, s->primaryState, stateBits);
bool addObject = false;
@ -1892,6 +1866,7 @@ uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *
ObjectAddIntegerProperty(&override, "_primaryState", s->primaryState);
ObjectAddIntegerProperty(&override, "_stateBits", stateBits);
ObjectAddIntegerProperty(&override, "_duration", s->duration);
AutoNameOverrideObject(&override, s->primaryState, stateBits);
bool addObject = false;
@ -2004,8 +1979,6 @@ void ExportProperty2(Layer *layer, Property *property, Object2 *override) {
RfItem item = PaintSolid_Type.fields[PaintSolid_color].item;
uint32_t value; item.type->op(&state.s, &item, &value);
ObjectAddObjectProperty(override, "borderPaint", ColorLookupPointer(value)->object2ID);
} else if (property->path[3] == LayerBox_mainPaint && property->path[4] == Paint_overwrite && property->path[5] == PaintOverwrite_color) {
fprintf(stderr, "\t>>\n");
} else {
unhandled = true;
}
@ -2082,9 +2055,7 @@ void ExportProperty2(Layer *layer, Property *property, Object2 *override) {
}
void ActionExportDesigner2(void *cp) {
// TODO Inherited text styles.
// TODO Merging identical layers and styles.
// TODO Auto-name override layers.
Object2 *objects = NULL;
uint64_t objectIDAllocator = 0;
@ -2138,6 +2109,8 @@ void ActionExportDesigner2(void *cp) {
for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) {
int x = x0;
Style *style = styleSet.styles[i];
fprintf(stderr, "style: %.*s\n", (int) style->name.byteCount, (const char *) style->name.buffer);
Object2 layerGroup = { .type = OBJ_LAYER_GROUP, .id = ++objectIDAllocator };
Object2 metrics = { 0 }, textStyle = { 0 };
@ -2206,15 +2179,39 @@ void ActionExportDesigner2(void *cp) {
} else if (layer->base.tag == LayerBase_metrics + 1) {
LayerMetrics *m = &layer->base.metrics;
assert(!m->globalOffset.l && !m->globalOffset.r && !m->globalOffset.t && !m->globalOffset.b);
LayerMetrics *inherit = NULL;
object.type = OBJ_VAR_TEXT_STYLE, object.id = ++objectIDAllocator;
ObjectAddObjectProperty(&object, "textColor", ColorLookupPointer(m->textColor)->object2ID);
ObjectAddObjectProperty(&object, "selectedBackground", ColorLookupPointer(m->selectedBackground)->object2ID);
ObjectAddObjectProperty(&object, "selectedText", ColorLookupPointer(m->selectedText)->object2ID);
ObjectAddIntegerProperty(&object, "textSize", m->textSize);
ObjectAddIntegerProperty(&object, "fontWeight", m->fontWeight);
ObjectAddIntegerProperty(&object, "isItalic", m->italic);
ObjectAddIntegerProperty(&object, "fontFamily", m->fontFamily == FONT_FAMILY_MONO ? 0xFFFD : 0xFFFF);
if (m->inheritText.byteCount) {
for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) {
Style *style = styleSet.styles[i];
if (m->inheritText.byteCount == style->name.byteCount
&& 0 == memcmp(m->inheritText.buffer, style->name.buffer, style->name.byteCount)) {
inherit = &LayerLookup(style->layers[0])->base.metrics;
break;
}
}
}
if (inherit) {
ObjectAddObjectProperty(&object, "textColor", ColorLookupPointer(inherit->textColor)->object2ID);
ObjectAddObjectProperty(&object, "selectedBackground", ColorLookupPointer(inherit->selectedBackground)->object2ID);
ObjectAddObjectProperty(&object, "selectedText", ColorLookupPointer(inherit->selectedText)->object2ID);
ObjectAddIntegerProperty(&object, "textSize", inherit->textSize);
ObjectAddIntegerProperty(&object, "fontWeight", inherit->fontWeight);
ObjectAddIntegerProperty(&object, "isItalic", inherit->italic);
ObjectAddIntegerProperty(&object, "fontFamily", inherit->fontFamily == FONT_FAMILY_MONO ? 0xFFFD : 0xFFFF);
} else {
ObjectAddObjectProperty(&object, "textColor", ColorLookupPointer(m->textColor)->object2ID);
ObjectAddObjectProperty(&object, "selectedBackground", ColorLookupPointer(m->selectedBackground)->object2ID);
ObjectAddObjectProperty(&object, "selectedText", ColorLookupPointer(m->selectedText)->object2ID);
ObjectAddIntegerProperty(&object, "textSize", m->textSize);
ObjectAddIntegerProperty(&object, "fontWeight", m->fontWeight);
ObjectAddIntegerProperty(&object, "isItalic", m->italic);
ObjectAddIntegerProperty(&object, "fontFamily", m->fontFamily == FONT_FAMILY_MONO ? 0xFFFD : 0xFFFF);
}
ObjectAddIntegerProperty(&object, "iconSize", m->iconSize);
ObjectAddObjectProperty(&object, "iconColor", ColorLookupPointer(m->iconColor)->object2ID);
textStyle = object;
@ -2267,6 +2264,7 @@ void ActionExportDesigner2(void *cp) {
assert(arrlenu(s->keyframes) == 1);
Keyframe *keyframe = s->keyframes[0];
#if 0
char buffer[256];
snprintf(buffer, sizeof(buffer), "%s%s%s%s%s%s%s%s%s%s",
((StringOption *) PrimaryState_Type.fields[s->primaryState].item.options)->string,
@ -2281,6 +2279,7 @@ void ActionExportDesigner2(void *cp) {
s->flagSelected ? " (selected)" : "");
fprintf(stderr, "%.*s:%.*s:%s:%d\n", (int) style->name.byteCount, (char *) style->name.buffer,
(int) layer->name.byteCount, (char *) layer->name.buffer, buffer, s->duration);
#endif
uint32_t stateBits = 0;
if (s->flagFocused) stateBits |= THEME_STATE_FOCUSED;
@ -2302,6 +2301,7 @@ void ActionExportDesigner2(void *cp) {
ObjectAddIntegerProperty(&override, "_primaryState", s->primaryState);
ObjectAddIntegerProperty(&override, "_stateBits", stateBits);
ObjectAddIntegerProperty(&override, "_duration", s->duration);
AutoNameOverrideObject(&override, s->primaryState, stateBits);
bool addObject = false;
@ -2351,7 +2351,7 @@ void ActionExportDesigner2(void *cp) {
}
}
{
if (layerCount) {
Object2 object = layerGroup;
ObjectAddIntegerProperty(&object, "_graphX", x);
ObjectAddIntegerProperty(&object, "_graphY", y);
@ -2360,6 +2360,9 @@ void ActionExportDesigner2(void *cp) {
ObjectAddIntegerProperty(&object, "layers_count", layerCount);
arrput(objects, object);
x += 100;
} else {
arrfree(layerGroup.properties);
layerGroup.id = 0;
}
{
@ -2370,6 +2373,7 @@ void ActionExportDesigner2(void *cp) {
ObjectAddIntegerProperty(&object, "_graphW", 80);
ObjectAddIntegerProperty(&object, "_graphH", 60);
ObjectAddIntegerProperty(&object, "isPublic", style->publicStyle);
ObjectAddIntegerProperty(&object, "headerID", style->id);
ObjectAddObjectProperty(&object, "appearance", layerGroup.id);
ObjectAddObjectProperty(&object, "metrics", metrics.id);
ObjectAddObjectProperty(&object, "textStyle", textStyle.id);
@ -2593,11 +2597,10 @@ void DrawStyle(UIPainter *painter, UIRectangle generalBounds, UIRectangle *globa
ThemeDrawLayer(&themePainter, bounds2, &themeData, scale, *(EsRectangle *) opaqueRegion);
} else {
EsBufferRead(&themeData, sizeof(ThemeLayer));
const ThemeMetrics *metrics = (const ThemeMetrics *) EsBufferRead(&themeData, sizeof(ThemeMetrics));
globalOffset->l = metrics->globalOffset.l * scale;
globalOffset->r = metrics->globalOffset.r * scale;
globalOffset->t = metrics->globalOffset.t * scale;
globalOffset->b = metrics->globalOffset.b * scale;
globalOffset->l = 0;
globalOffset->r = 0;
globalOffset->t = 0;
globalOffset->b = 0;
}
free(dataBuffer);
@ -6086,8 +6089,7 @@ int main(int argc, char **argv)
filePath = argv[1];
exportPath = argv[2];
embedBitmapPath = argc >= 4 ? argv[3] : NULL;
stylesPath = argc >= 5 ? argv[4] : NULL;
stylesPath = argc >= 4 ? argv[3] : NULL;
UIInitialise();

View File

@ -16,8 +16,8 @@
// 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:
// Import old theming data.
// Export.
// Exporting sequences.
// Calculating additional metric rectangles (paintOutsets, opaqueInsets and approximateBorders).
// Prototyping display: previewing state transitions.
// TODO Additional features:
@ -37,6 +37,7 @@
// Proper bezier path editor.
// Path boolean operations.
// Timeline editor for applying a given state change, with rows for possibly many different layers.
// Metrics: layoutVertical.
// TODO Reorganize old theming data!
@ -160,6 +161,7 @@ void SetBit(uint32_t *value, uint32_t bit, bool on) {
#include "../shared/math.cpp"
#include "../shared/array.cpp"
#include "../shared/hash.cpp"
#include "../shared/hash_table.cpp"
#include "../desktop/renderer.cpp"
#include "../desktop/theme.cpp"
@ -332,11 +334,18 @@ struct Step {
};
};
struct ExportOffset {
uint64_t objectID;
uintptr_t offset;
char cPropertyName[PROPERTY_NAME_SIZE];
};
Array<Step> undoStack;
Array<Step> redoStack;
bool documentModified;
uint64_t selectedObjectID;
HashStore<uint64_t, uintptr_t> objectLookup;
Array<ExportOffset> exportOffsets;
// Document state:
Array<Object> objects;
@ -360,6 +369,16 @@ Object *ObjectFind(uint64_t id) {
#endif
}
ExportOffset *ExportOffsetFindObject(uint64_t id) {
for (uintptr_t i = 0; i < exportOffsets.Length(); i++) {
if (exportOffsets[i].objectID == id) {
return &exportOffsets[i];
}
}
return nullptr;
}
void ObjectSetSelected(uint64_t id, bool removeSelectedFlagFromPreviousSelection = true) {
if (selectedObjectID && removeSelectedFlagFromPreviousSelection) {
Object *object = ObjectFind(selectedObjectID);
@ -416,7 +435,7 @@ Property *PropertyFindOrInherit(Object *object, const char *cName, uint8_t type
uintptr_t depth = 0;
while (object && (depth++ < 100)) {
if (!ObjectIsConditional(object) || (canvas->previewStateActive && ObjectMatchesPreviewState(object))) {
if (!ObjectIsConditional(object) || (canvas && canvas->previewStateActive && ObjectMatchesPreviewState(object))) {
// Return the value if the object has this property.
Property *property = PropertyFind(object, cName);
if (property) return type && property->type != type ? nullptr : property;
@ -488,6 +507,8 @@ void DocumentSave(void *) {
}
void DocumentLoad() {
// TODO Check names are zero-terminated.
#ifdef OS_ESSENCE
EsBuffer buffer = {};
buffer.out = (uint8_t *) EsFileStoreReadAll(fileStore, &buffer.bytes);
@ -1424,6 +1445,10 @@ void InspectorPopulate() {
InspectorAddLink(object, "Metrics:", "metrics");
InspectorAddLink(object, "Text style:", "textStyle");
InspectorAddBooleanToggle(object, "Public style", "isPublic");
char buffer[128];
snprintf(buffer, sizeof(buffer), "Header ID: %d", PropertyReadInt32(object, "headerID"));
UILabelCreate(0, 0, buffer, -1);
} else if (object->type == OBJ_VAR_COLOR) {
InspectorBind(&UIColorPickerCreate(&UIPanelCreate(0, 0)->e, UI_COLOR_PICKER_HAS_OPACITY)->e, object->id, "color", INSPECTOR_COLOR_PICKER);
InspectorBind(&UITextboxCreate(0, 0)->e, object->id, "color", INSPECTOR_COLOR_TEXTBOX);
@ -2075,10 +2100,10 @@ void CanvasDrawLayer(Object *object, UIRectangle bounds, UIPainter *painter, int
}
if (object->type == OBJ_LAYER_BOX) {
bounds.l += PropertyFindOrInheritReadInt32(object, "offset0") * canvas->zoom;
bounds.r += PropertyFindOrInheritReadInt32(object, "offset1") * canvas->zoom;
bounds.t += PropertyFindOrInheritReadInt32(object, "offset2") * canvas->zoom;
bounds.b += PropertyFindOrInheritReadInt32(object, "offset3") * canvas->zoom;
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) };
@ -2103,8 +2128,8 @@ void CanvasDrawLayer(Object *object, UIRectangle bounds, UIPainter *painter, int
textStyle.font.family = ES_FONT_SANS;
textStyle.font.weight = 5;
textStyle.size = 10;
textStyle.color = GraphGetColorFromProperty(PropertyFindOrInherit(false, object, "color"));
textStyle.blur = GraphGetIntegerFromProperty(PropertyFindOrInherit(false, object, "blur"));
textStyle.color = GraphGetColorFromProperty(PropertyFindOrInherit(object, "color"));
textStyle.blur = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "blur"));
if (textStyle.blur > 10) textStyle.blur = 10;
EsDrawTextSimple((_EsPainter *) &themePainter, ui.instance->window, bounds, "Sample", -1, textStyle, ES_TEXT_H_CENTER | ES_TEXT_V_CENTER);
#endif
@ -2138,6 +2163,7 @@ void CanvasDrawLayer(Object *object, UIRectangle bounds, UIPainter *painter, int
LAYER_READ_INT32(position1);
LAYER_READ_INT32(position2);
LAYER_READ_INT32(position3);
#undef LAYER_READ_INT32
UIRectangle outBounds;
outBounds.l = bounds.l + offset0 * canvas->zoom + position0 * inWidth / 100;
@ -2170,11 +2196,11 @@ void CanvasDrawStyle(Object *object, UIRectangle bounds, UIPainter *painter, int
if (object->type == OBJ_VAR_TEXT_STYLE) {
EsTextStyle textStyle = {};
textStyle.font.family = GraphGetIntegerFromProperty(PropertyFindOrInherit(false, object, "fontFamily"));
textStyle.font.weight = GraphGetIntegerFromProperty(PropertyFindOrInherit(false, object, "fontWeight"));
textStyle.font.italic = GraphGetIntegerFromProperty(PropertyFindOrInherit(false, object, "isItalic"));
textStyle.size = GraphGetIntegerFromProperty(PropertyFindOrInherit(false, object, "textSize")) * canvas->zoom;
textStyle.color = GraphGetColorFromProperty(PropertyFindOrInherit(false, object, "textColor"));
textStyle.font.family = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "fontFamily"));
textStyle.font.weight = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "fontWeight"));
textStyle.font.italic = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "isItalic"));
textStyle.size = GraphGetIntegerFromProperty(PropertyFindOrInherit(object, "textSize")) * canvas->zoom;
textStyle.color = GraphGetColorFromProperty(PropertyFindOrInherit(object, "textColor"));
EsDrawTextSimple((_EsPainter *) &themePainter, ui.instance->window, bounds, "Sample", -1, textStyle, ES_TEXT_H_CENTER | ES_TEXT_V_CENTER);
#if 0
EsDrawStandardIcon((_EsPainter *) &themePainter, ES_ICON_GO_NEXT_SYMBOLIC,
@ -2182,6 +2208,10 @@ void CanvasDrawStyle(Object *object, UIRectangle bounds, UIPainter *painter, int
GraphGetColorFromProperty(PropertyFindOrInherit(false, object, "iconColor")));
#endif
}
#else
if (object->type == OBJ_VAR_TEXT_STYLE && depth == 0) {
UIDrawString(painter, bounds, "TxtStyle", -1, 0xFF000000, UI_ALIGN_CENTER, nullptr);
}
#endif
if (object->type == OBJ_STYLE) {
@ -2325,8 +2355,10 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) {
Property *style = PropertyFind(object, "style", PROP_OBJECT);
canvas->previewStateActive = object->id == selectedObjectID;
CanvasDrawStyle(ObjectFind(style ? style->object : 0), bounds, painter);
} else if (object->type == OBJ_LAYER_METRICS) {
// TODO Visually show the preferred size, insets and gaps?
UIDrawString(painter, bounds, "Metrics", -1, 0xFF000000, UI_ALIGN_CENTER, nullptr);
} else {
// TODO Preview for the metrics layer. Show the preferred size, insets and gaps?
// TODO Preview for OBJ_VAR_CONTOUR_STYLE.
}
@ -2340,7 +2372,6 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) {
if (canvas->showArrows && !canvas->showPrototype) {
// Draw object connections.
// TODO This will be awfully slow when there's many objects...
for (uintptr_t i = 0; i < objects.Length(); i++) {
Object *object = &objects[i];
@ -2592,6 +2623,39 @@ void ObjectAddCommandInternal(void *cp) {
p = { .type = PROP_INT, .integer = y }; strcpy(p.cName, "_graphY"); object.properties.Add(p);
p = { .type = PROP_INT, .integer = w }; strcpy(p.cName, "_graphW"); object.properties.Add(p);
p = { .type = PROP_INT, .integer = h }; strcpy(p.cName, "_graphH"); object.properties.Add(p);
if (object.type == OBJ_STYLE) {
// TODO Prevent taking IDs of style objects in the clipboard?
uint8_t allocatedIDs[32768 / 8] = {};
for (uintptr_t i = 0; i < objects.Length(); i++) {
if (objects[i].type == OBJ_STYLE) {
int32_t id = PropertyReadInt32(&objects[i], "headerID");
if (id > 0 && id < 32768) {
allocatedIDs[id / 8] |= 1 << (id % 8);
}
}
}
bool foundID = false;
for (int32_t i = 1; i < 32768; i++) {
if (!(allocatedIDs[i / 8] & (1 << (i % 8)))) {
p = { .type = PROP_INT, .integer = i }; strcpy(p.cName, "headerID"); object.properties.Add(p);
foundID = true;
break;
}
}
if (!foundID) {
UIDialogShow(window, 0, "Error: No free header IDs.\n%f%b", "OK");
object.properties.Free();
return;
}
}
ObjectAddInternal(object);
}
@ -2697,6 +2761,325 @@ void ObjectDuplicateCommand(void *) {
//////////////////////////////////////////////////////////////
Rectangle8 ExportCalculatePaintOutsets(Object *object) {
return {}; // TODO;
}
Rectangle8 ExportCalculateOpaqueInsets(Object *object) {
return {}; // TODO;
}
Rectangle8 ExportCalculateApproximateBorders(Object *object) {
return {}; // TODO;
}
#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 Recursively exporting nested groups.
// TODO Handling styles that don't have metrics/textStyle.
// Create the list of styles.
FILE *output = fopen("desktop/styles.header", "wb");
for (uintptr_t i = 0; i < objects.Length(); i++) {
Object *object = &objects[i];
if (object->type == OBJ_STYLE) {
bool isPublic = PropertyReadInt32(object, "isPublic");
int32_t headerID = PropertyReadInt32(object, "headerID");
if (!headerID) {
continue;
}
fprintf(output, "%sdefine ES_STYLE_", !isPublic ? "private " : "");
bool dot = false;
for (uintptr_t j = 0; object->cName[j]; j++) {
char c = object->cName[j];
if (c == '.') {
fprintf(output, "_");
dot = true;
} else if (c >= 'A' && c <= 'Z' && j && !dot) {
fprintf(output, "_%c", c);
} else if (c >= 'a' && c <= 'z') {
fprintf(output, "%c", c - 'a' + 'A');
dot = false;
} else {
fprintf(output, "%c", c);
dot = false;
}
}
fprintf(output, " (ES_STYLE_CAST(%d))\n", (headerID << 1) | 1);
}
}
fclose(output);
output = fopen("res/Theme.dat", "wb");
// Write the header.
ThemeHeader header = { 0 };
header.signature = THEME_HEADER_SIGNATURE;
for (uintptr_t i = 0; i < objects.Length(); i++) {
if (objects[i].type == OBJ_STYLE) {
header.styleCount++;
} else if ((objects[i].type == OBJ_VAR_COLOR || objects[i].type == OBJ_VAR_INT) && PropertyReadInt32(&objects[i], "isExported")) {
header.constantCount++;
}
}
fwrite(&header, 1, sizeof(header), output);
// Write the list of styles.
for (uintptr_t i = 0; i < objects.Length(); i++) {
Object *object = &objects[i];
if (object->type != OBJ_STYLE) {
continue;
}
int32_t headerID = PropertyReadInt32(object, "headerID");
ThemeStyle entry = {};
entry.id = (headerID << 1) | 1;
entry.layerCount = 1;
Object *appearance = PropertyFindOrInheritReadObject(object, "appearance");
if (appearance && appearance->type == OBJ_LAYER_GROUP) {
entry.layerCount += PropertyReadInt32(appearance, "layers_count");
entry.paintOutsets = ExportCalculatePaintOutsets(appearance);
entry.opaqueInsets = ExportCalculateOpaqueInsets(appearance);
entry.approximateBorders = ExportCalculateApproximateBorders(appearance);
}
fwrite(&entry, 1, sizeof(entry), output);
}
// Write the list of constants.
for (uintptr_t i = 0; i < objects.Length(); i++) {
Object *object = &objects[i];
if ((object->type != OBJ_VAR_COLOR && object->type != OBJ_VAR_INT) || !PropertyReadInt32(object, "isExported")) {
continue;
}
ThemeConstant constant = {};
constant.scale = PropertyReadInt32(object, "isScaled");
constant.hash = CalculateCRC64(object->cName, strlen(object->cName), 0);
if (object->type == OBJ_VAR_COLOR) {
snprintf(constant.cValue, sizeof(constant.cValue), "0x%.8X", (uint32_t) PropertyReadInt32(object, "color"));
} else if (object->type == OBJ_VAR_INT) {
snprintf(constant.cValue, sizeof(constant.cValue), "%d", (int32_t) PropertyReadInt32(object, "value"));
}
fwrite(&constant, 1, sizeof(constant), output);
}
// Write out all layers.
for (uintptr_t i = 0; i < objects.Length(); i++) {
Object *object = &objects[i];
if (object->type != OBJ_STYLE) {
continue;
}
Object *metrics = PropertyFindOrInheritReadObject(object, "metrics");
Object *textStyle = PropertyFindOrInheritReadObject(object, "textStyle");
Object *appearance = PropertyFindOrInheritReadObject(object, "appearance");
if (metrics && textStyle) {
ExportOffset exportOffset = {};
exportOffset.objectID = textStyle->id;
exportOffset.offset = ftell(output);
exportOffsets.Add(exportOffset);
ThemeLayer layer = {};
layer.type = THEME_LAYER_METRICS;
layer.dataByteCount = sizeof(ThemeLayer) + sizeof(ThemeMetrics);
ThemeMetrics _metrics = {};
_metrics.insets.l = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "insets0"));
_metrics.insets.r = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "insets1"));
_metrics.insets.t = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "insets2"));
_metrics.insets.b = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "insets3"));
_metrics.clipInsets.l = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "clipInsets0"));
_metrics.clipInsets.r = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "clipInsets1"));
_metrics.clipInsets.t = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "clipInsets2"));
_metrics.clipInsets.b = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "clipInsets3"));
_metrics.clipEnabled = PropertyFindOrInheritReadInt32(metrics, "clipEnabled");
_metrics.cursor = PropertyFindOrInheritReadInt32(metrics, "cursor");
_metrics.preferredWidth = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "preferredWidth"));
_metrics.preferredHeight = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "preferredHeight"));
_metrics.minimumWidth = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "minimumWidth"));
_metrics.minimumHeight = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "minimumHeight"));
_metrics.maximumWidth = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "maximumWidth"));
_metrics.maximumHeight = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "maximumHeight"));
_metrics.gapMajor = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "gapMajor"));
_metrics.gapMinor = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "gapMinor"));
_metrics.gapWrap = GraphGetIntegerFromProperty(PropertyFindOrInherit(metrics, "gapWrap"));
int32_t horizontalTextAlign = PropertyFindOrInheritReadInt32(metrics, "horizontalTextAlign");
int32_t verticalTextAlign = PropertyFindOrInheritReadInt32(metrics, "verticalTextAlign");
int32_t wrapText = PropertyFindOrInheritReadInt32(metrics, "wrapText");
int32_t ellipsis = PropertyFindOrInheritReadInt32(metrics, "ellipsis");
_metrics.textAlign = (wrapText ? ES_TEXT_WRAP : 0) | (ellipsis ? ES_TEXT_ELLIPSIS : 0)
| (horizontalTextAlign == 1 ? ES_TEXT_H_LEFT : horizontalTextAlign == 3 ? ES_TEXT_H_RIGHT : ES_TEXT_H_CENTER)
| (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"));
fwrite(&layer, 1, sizeof(layer), output);
fwrite(&_metrics, 1, sizeof(_metrics), output);
} else {
assert(false); // TODO.
}
if (appearance && appearance->type == OBJ_LAYER_GROUP) {
int32_t layerCount = PropertyReadInt32(appearance, "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(appearance, cPropertyName, PROP_OBJECT);
Object *layerObject = ObjectFind(layerProperty ? layerProperty->object : 0);
if (!layerObject) continue;
ExportOffset exportOffset = {};
exportOffset.objectID = layerObject->id;
exportOffset.offset = ftell(output);
exportOffsets.Add(exportOffset);
#define LAYER_READ_INT32(x) sprintf(cPropertyName, "layers_%d_" #x, i); int8_t x = PropertyReadInt32(appearance, 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
uint8_t buffer[4096];
EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) };
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);
} 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);
} 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));
} else {
assert(false);
}
layer.dataByteCount = data.position + sizeof(layer);
fwrite(&layer, 1, sizeof(layer), output);
fwrite(data.out, 1, data.position, output);
assert(!data.error);
}
}
}
// Write out layer lists for styles.
for (uintptr_t i = 0; i < objects.Length(); i++) {
Object *object = &objects[i];
if (object->type != OBJ_STYLE) {
continue;
}
{
ExportOffset exportOffset = {};
exportOffset.objectID = object->id;
exportOffset.offset = ftell(output);
exportOffsets.Add(exportOffset);
}
{
Object *textStyle = PropertyFindOrInheritReadObject(object, "textStyle");
uint32_t exportOffset = ExportOffsetFindObject(textStyle->id)->offset;
fwrite(&exportOffset, 1, sizeof(exportOffset), output);
}
Object *appearance = PropertyFindOrInheritReadObject(object, "appearance");
if (appearance && appearance->type == OBJ_LAYER_GROUP) {
int32_t layerCount = PropertyReadInt32(appearance, "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(appearance, cPropertyName, PROP_OBJECT);
Object *layerObject = ObjectFind(layerProperty ? layerProperty->object : 0);
if (!layerObject) continue;
uint32_t exportOffset = ExportOffsetFindObject(layerObject->id)->offset;
fwrite(&exportOffset, 1, sizeof(exportOffset), output);
}
}
}
// Update the style list to point to the layer lists.
uintptr_t writeOffset = sizeof(ThemeHeader);
for (uintptr_t i = 0; i < objects.Length(); i++) {
Object *object = &objects[i];
if (object->type != OBJ_STYLE) continue;
uint32_t exportOffset = ExportOffsetFindObject(object->id)->offset;
fseek(output, writeOffset, SEEK_SET);
fwrite(&exportOffset, 1, sizeof(exportOffset), output);
writeOffset += sizeof(ThemeStyle);
}
}
#endif
//////////////////////////////////////////////////////////////
int WindowMessage(UIElement *element, UIMessage message, int di, void *dp) {
if (message == UI_MSG_WINDOW_CLOSE) {
#ifndef OS_ESSENCE
@ -2720,7 +3103,20 @@ void DocumentFileMenu(void *) {
}
#endif
int main() {
int main(int argc, char **argv) {
#ifndef OS_ESSENCE
if (argc == 2) {
if (0 == strcmp(argv[1], "export")) {
Export();
} else {
fprintf(stderr, "Error: Unknown action '%s'.\n", argv[1]);
return 1;
}
return 0;
}
#endif
UIInitialise();
ui.theme = _uiThemeClassic;
window = UIWindowCreate(0, UI_ELEMENT_PARENT_PUSH | UI_WINDOW_MAXIMIZE, "Designer", 0, 0);
@ -2802,6 +3198,6 @@ void _UIMessageProcess(EsMessage *message) {
void _start() {
_init();
main();
main(0, nullptr);
}
#endif