mirror of https://gitlab.com/nakst/essence
				
				
				
			designer2 import non-animated data
This commit is contained in:
		
							parent
							
								
									0ff4062673
								
							
						
					
					
						commit
						9dfe4f0a8b
					
				|  | @ -853,7 +853,7 @@ void ThemeDrawBox(EsPainter *painter, EsRectangle rect, EsBuffer *data, float sc | |||
| 	if (borders.l + borders.r > width) { float p = (float) borders.l / (borders.l + borders.r); borders.l = p * width; borders.r = (1 - p) * width; } | ||||
| 	if (borders.t + borders.b > height) { float p = (float) borders.t / (borders.t + borders.b); borders.t = p * height; borders.b = (1 - p) * height; } | ||||
| 
 | ||||
| 	if (isBlurred && !borders.l) { | ||||
| 	if (isBlurred && (!borders.l || !borders.r || !borders.t || !borders.b)) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -1,20 +1,5 @@ | |||
| // TODO Test deleting values in hash stores with variable length keys.
 | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| #ifndef OS_ESSENCE | ||||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <string.h> | ||||
| #define EsHeapAllocate(a, b) ((b) ? calloc(1, (a)) : malloc((a))) | ||||
| #define EsHeapReallocate(a, b, c) ((c) ? (assert(false), nullptr) : realloc((a), (b))) | ||||
| #define EsHeapFree free | ||||
| #define EsMemoryCopy memcpy | ||||
| #define EsMemoryCompare memcmp | ||||
| #define EsAssert assert | ||||
| #endif | ||||
| 
 | ||||
| //////////////////////////////////////////
 | ||||
| 
 | ||||
| struct HashTableKey { | ||||
|  | @ -221,6 +206,7 @@ void HashTableFree(HashTable *table, bool freeLongKeys) { | |||
| 	table->itemCount = 0; | ||||
| 	table->slotCount = 0; | ||||
| 	table->slots = nullptr; | ||||
| 	table->storage = nullptr; | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////
 | ||||
|  | @ -288,10 +274,12 @@ void *HashStorePut(HashTable *table, HashStoreOptions *options, const void *key, | |||
| 		size_t storageAllocated = ((size_t *) table->storage)[-1]; | ||||
| 
 | ||||
| 		if (table->itemCount == storageAllocated) { | ||||
| 			uint8_t *newStorage = (uint8_t *) EsHeapReallocate(table->storage - sizeof(size_t), | ||||
| 					(options->keyBytes + options->valueBytes) * storageAllocated * 2 + sizeof(size_t), true); | ||||
| 			size_t oldSize = (options->keyBytes + options->valueBytes) * storageAllocated; | ||||
| 			size_t newSize = oldSize * 2; | ||||
| 			uint8_t *newStorage = (uint8_t *) EsHeapReallocate(table->storage - sizeof(size_t), newSize + sizeof(size_t), false, nullptr); | ||||
| 			if (!newStorage) return nullptr; | ||||
| 			newStorage += sizeof(size_t); | ||||
| 			EsMemoryZero(newStorage + oldSize, newSize - oldSize); | ||||
| 
 | ||||
| 			if (newStorage != table->storage) { | ||||
| 				for (uintptr_t i = 0; i < table->slotCount; i++) { | ||||
|  | @ -400,7 +388,7 @@ struct HashStore { | |||
| 
 | ||||
| //////////////////////////////////////////
 | ||||
| 
 | ||||
| #ifndef OS_ESSENCE | ||||
| #if 0 | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include "stb_ds.h" | ||||
|  |  | |||
|  | @ -1632,6 +1632,480 @@ void ActionExport(void *_unused) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // ------------------- Exporting to Designer2 -------------------
 | ||||
| 
 | ||||
| enum PropertyType { | ||||
| 	PROP_NONE, | ||||
| 	PROP_COLOR, | ||||
| 	PROP_INT, | ||||
| 	PROP_OBJECT, | ||||
| 	PROP_FLOAT, | ||||
| }; | ||||
| 
 | ||||
| typedef struct Property2 { | ||||
| 	uint8_t type; | ||||
| #define PROPERTY_NAME_SIZE (31) | ||||
| 	char cName[PROPERTY_NAME_SIZE]; | ||||
| 
 | ||||
| 	union { | ||||
| 		int32_t integer; | ||||
| 		uint64_t object; | ||||
| 		float floating; | ||||
| 	}; | ||||
| } Property2; | ||||
| 
 | ||||
| enum ObjectType { | ||||
| 	OBJ_NONE, | ||||
| 
 | ||||
| 	OBJ_STYLE, | ||||
| 	OBJ_COMMENT, | ||||
| 	OBJ_INSTANCE, | ||||
| 
 | ||||
| 	OBJ_VAR_COLOR = 0x40, | ||||
| 	OBJ_VAR_INT, | ||||
| 	OBJ_VAR_TEXT_STYLE, | ||||
| 	OBJ_VAR_ICON_STYLE, | ||||
| 	OBJ_VAR_CONTOUR_STYLE, | ||||
| 	 | ||||
| 	OBJ_PAINT_OVERWRITE = 0x60, | ||||
| 	OBJ_PAINT_LINEAR_GRADIENT, | ||||
| 	OBJ_PAINT_RADIAL_GRADIENT, | ||||
| 
 | ||||
| 	OBJ_LAYER_BOX = 0x80, | ||||
| 	OBJ_LAYER_METRICS, | ||||
| 	OBJ_LAYER_TEXT, | ||||
| 	OBJ_LAYER_GROUP, | ||||
| 	OBJ_LAYER_PATH, | ||||
| 
 | ||||
| 	OBJ_MOD_COLOR = 0xC0, | ||||
| 	OBJ_MOD_MULTIPLY, | ||||
| }; | ||||
| 
 | ||||
| typedef struct Object2 { | ||||
| 	uint8_t type; | ||||
| #define OBJECT_NAME_SIZE (46) | ||||
| 	char cName[OBJECT_NAME_SIZE]; | ||||
| #define OBJECT_IS_SELECTED (1 << 0) | ||||
| #define OBJECT_IN_PROTOTYPE (1 << 1) | ||||
| 	uint8_t flags; | ||||
| 	uint64_t id; | ||||
| 	Property2 *properties; | ||||
| } Object2; | ||||
| 
 | ||||
| void ObjectAddIntegerProperty(Object2 *object, const char *cName, int32_t value) { | ||||
| 	Property2 property = { 0 }; | ||||
| 	property.type = PROP_INT; | ||||
| 	strcpy(property.cName, cName); | ||||
| 	property.integer = value; | ||||
| 	arrput(object->properties, property); | ||||
| } | ||||
| 
 | ||||
| void ObjectAddColorProperty(Object2 *object, const char *cName, uint32_t value) { | ||||
| 	Property2 property = { 0 }; | ||||
| 	property.type = PROP_COLOR; | ||||
| 	strcpy(property.cName, cName); | ||||
| 	property.integer = value; | ||||
| 	arrput(object->properties, property); | ||||
| } | ||||
| 
 | ||||
| void ObjectAddFloatProperty(Object2 *object, const char *cName, float value) { | ||||
| 	Property2 property = { 0 }; | ||||
| 	property.type = PROP_FLOAT; | ||||
| 	strcpy(property.cName, cName); | ||||
| 	property.floating = value; | ||||
| 	arrput(object->properties, property); | ||||
| } | ||||
| 
 | ||||
| void ObjectAddObjectProperty(Object2 *object, const char *cName, uint64_t value) { | ||||
| 	Property2 property = { 0 }; | ||||
| 	property.type = PROP_OBJECT; | ||||
| 	strcpy(property.cName, cName); | ||||
| 	property.object = value; | ||||
| 	arrput(object->properties, property); | ||||
| } | ||||
| 
 | ||||
| uint64_t ExportPaint2(Paint *paint, int *x, int y, Object2 **objects, uint64_t *idAllocator) { | ||||
| 	char cPropertyName[PROPERTY_NAME_SIZE]; | ||||
| 
 | ||||
| 	if (!paint->tag) { | ||||
| 		return 0; | ||||
| 	} 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); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphY", y); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 		ObjectAddFloatProperty(&object, "transformX", paint->linearGradient.transformX); | ||||
| 		ObjectAddFloatProperty(&object, "transformY", paint->linearGradient.transformY); | ||||
| 		ObjectAddFloatProperty(&object, "transformStart", paint->linearGradient.transformStart); | ||||
| 		ObjectAddIntegerProperty(&object, "repeatMode", paint->linearGradient.repeat); | ||||
| 		ObjectAddIntegerProperty(&object, "useGammaInterpolation", paint->linearGradient.useGammaInterpolation); | ||||
| 		ObjectAddIntegerProperty(&object, "useSystemColor", paint->linearGradient.useSystemHue); | ||||
| 		ObjectAddIntegerProperty(&object, "stops_count", arrlenu(paint->linearGradient.stops)); | ||||
| 
 | ||||
| 		for (uintptr_t i = 0; i < arrlenu(paint->linearGradient.stops); i++) { | ||||
| 			sprintf(cPropertyName, "stops_%d_position", (int) i); | ||||
| 			ObjectAddIntegerProperty(&object, cPropertyName, paint->linearGradient.stops[i].position); | ||||
| 			sprintf(cPropertyName, "stops_%d_color", (int) i); | ||||
| 			ObjectAddObjectProperty(&object, cPropertyName, ColorLookupPointer(paint->linearGradient.stops[i].color)->object2ID); | ||||
| 		} | ||||
| 
 | ||||
| 		*x += 100; | ||||
| 		arrput(*objects, object); | ||||
| 		return object.id; | ||||
| 	} else if (paint->tag == Paint_radialGradient + 1) { | ||||
| 		Object2 object = { .type = OBJ_PAINT_RADIAL_GRADIENT, .id = ++(*idAllocator) }; | ||||
| 
 | ||||
| 		ObjectAddIntegerProperty(&object, "_graphX", *x); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphY", y); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 		ObjectAddFloatProperty(&object, "transform0", paint->radialGradient.transform0); | ||||
| 		ObjectAddFloatProperty(&object, "transform1", paint->radialGradient.transform1); | ||||
| 		ObjectAddFloatProperty(&object, "transform2", paint->radialGradient.transform2); | ||||
| 		ObjectAddFloatProperty(&object, "transform3", paint->radialGradient.transform3); | ||||
| 		ObjectAddFloatProperty(&object, "transform4", paint->radialGradient.transform4); | ||||
| 		ObjectAddFloatProperty(&object, "transform5", paint->radialGradient.transform5); | ||||
| 		ObjectAddIntegerProperty(&object, "repeatMode", paint->radialGradient.repeat); | ||||
| 		ObjectAddIntegerProperty(&object, "useGammaInterpolation", paint->radialGradient.useGammaInterpolation); | ||||
| 		ObjectAddIntegerProperty(&object, "stops_count", arrlenu(paint->radialGradient.stops)); | ||||
| 
 | ||||
| 		for (uintptr_t i = 0; i < arrlenu(paint->radialGradient.stops); i++) { | ||||
| 			sprintf(cPropertyName, "stops_%d_position", (int) i); | ||||
| 			ObjectAddIntegerProperty(&object, cPropertyName, paint->radialGradient.stops[i].position); | ||||
| 			sprintf(cPropertyName, "stops_%d_color", (int) i); | ||||
| 			ObjectAddObjectProperty(&object, cPropertyName, ColorLookupPointer(paint->radialGradient.stops[i].color)->object2ID); | ||||
| 		} | ||||
| 
 | ||||
| 		*x += 100; | ||||
| 		arrput(*objects, object); | ||||
| 		return object.id; | ||||
| 	} else if (paint->tag == Paint_overwrite + 1) { | ||||
| 		Object2 object = { .type = OBJ_PAINT_OVERWRITE, .id = ++(*idAllocator) }; | ||||
| 		ObjectAddIntegerProperty(&object, "_graphX", *x); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphY", y); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 		ObjectAddObjectProperty(&object, "color", ColorLookupPointer(paint->overwrite.color)->object2ID); | ||||
| 		*x += 100; | ||||
| 		arrput(*objects, object); | ||||
| 		return object.id; | ||||
| 	} else { | ||||
| 		assert(false); | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| uint64_t ExportFillMode2(PathFillMode *fill, int *x, int y, Object2 **objects, uint64_t *idAllocator) { | ||||
| 	if (fill->tag == PathFillMode_solid + 1) { | ||||
| 		return 0; | ||||
| 	} else if (fill->tag == PathFillMode_contour + 1) { | ||||
| 		Object2 object = { .type = OBJ_VAR_CONTOUR_STYLE, .id = ++(*idAllocator) }; | ||||
| 		ObjectAddIntegerProperty(&object, "_graphX", *x); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphY", y); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 		ObjectAddIntegerProperty(&object, "internalWidth", fill->contour.internalWidth); | ||||
| 		ObjectAddIntegerProperty(&object, "externalWidth", fill->contour.externalWidth); | ||||
| 		ObjectAddIntegerProperty(&object, "integerWidthsOnly", fill->contour.integerWidthsOnly); | ||||
| 		ObjectAddIntegerProperty(&object, "joinMode", fill->contour.joinMode == JOIN_MODE_ROUND ? RAST_LINE_JOIN_ROUND : RAST_LINE_JOIN_MITER); | ||||
| 		ObjectAddIntegerProperty(&object, "capMode", fill->contour.capMode == CAP_MODE_FLAT ? RAST_LINE_CAP_FLAT  | ||||
| 				: fill->contour.capMode == CAP_MODE_ROUND ? RAST_LINE_CAP_ROUND : RAST_LINE_CAP_SQUARE); | ||||
| 		ObjectAddFloatProperty(&object, "miterLimit", fill->contour.joinMode == JOIN_MODE_BEVEL ? 0.0f : fill->contour.miterLimit); | ||||
| 		*x += 100; | ||||
| 		arrput(*objects, object); | ||||
| 		return object.id; | ||||
| 	} else { | ||||
| 		assert(false); | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ActionExportDesigner2(void *cp) { | ||||
| 	// TODO Exporting sequences.
 | ||||
| 	// TODO Inherited text styles.
 | ||||
| 	// TODO Merging identical layers and styles.
 | ||||
| 
 | ||||
| 	Object2 *objects = NULL; | ||||
| 	uint64_t objectIDAllocator = 0; | ||||
| 	char cPropertyName[PROPERTY_NAME_SIZE]; | ||||
| 
 | ||||
| 	int y = 0; | ||||
| 
 | ||||
| 	// Colors.
 | ||||
| 
 | ||||
| 	for (uintptr_t i = 0; i < arrlenu(styleSet.colors); i++) { | ||||
| 		Object2 object = { .type = OBJ_VAR_COLOR, .id = ++objectIDAllocator }; | ||||
| 		snprintf(object.cName, sizeof(object.cName), "%.*s", (int) styleSet.colors[i]->key.byteCount, (const char *) styleSet.colors[i]->key.buffer); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphX", (i % 10) * 180); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphY", (i / 10) * 100 + y); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 		ObjectAddColorProperty(&object, "color", styleSet.colors[i]->value); | ||||
| 		ObjectAddIntegerProperty(&object, "isExported", 0); | ||||
| 		arrput(objects, object); | ||||
| 		styleSet.colors[i]->object2ID = object.id; | ||||
| 	} | ||||
| 
 | ||||
| 	y += (arrlenu(styleSet.colors) / 10) * 100 + 200; | ||||
| 
 | ||||
| 	// Constants.
 | ||||
| 
 | ||||
| 	for (uintptr_t i = 0; i < arrlenu(styleSet.constants); i++) { | ||||
| 		char value[64]; | ||||
| 		snprintf(value, sizeof(value), "%.*s", (int) styleSet.constants[i]->value.byteCount, (const char *) styleSet.constants[i]->value.buffer); | ||||
| 		bool isColor = value[0] == '0' && value[1] == 'x'; | ||||
| 		Object2 object = { .type = isColor ? OBJ_VAR_COLOR : OBJ_VAR_INT, .id = ++objectIDAllocator }; | ||||
| 		snprintf(object.cName, sizeof(object.cName), "%.*s", (int) styleSet.constants[i]->key.byteCount, (const char *) styleSet.constants[i]->key.buffer); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphX", (i % 5) * 360); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphY", (i / 5) * 100 + y); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 		ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 		if (isColor) ObjectAddColorProperty(&object, "color", strtol(value, NULL, 0)); | ||||
| 		else ObjectAddIntegerProperty(&object, "value", strtol(value, NULL, 0)); | ||||
| 		ObjectAddIntegerProperty(&object, "isScaled", styleSet.constants[i]->scale); | ||||
| 		ObjectAddIntegerProperty(&object, "isExported", 1); | ||||
| 		arrput(objects, object); | ||||
| 	} | ||||
| 
 | ||||
| 	y += (arrlenu(styleSet.constants) / 5) * 100 + 200; | ||||
| 
 | ||||
| 	// Styles.
 | ||||
| 
 | ||||
| 	int x0 = 180 * 10 + 200; | ||||
| 	y = 0; | ||||
| 
 | ||||
| 	for (uintptr_t i = 0; i < arrlenu(styleSet.styles); i++) { | ||||
| 		int x = x0; | ||||
| 		Style *style = styleSet.styles[i]; | ||||
| 		 | ||||
| 		Object2 layerGroup = { .type = OBJ_LAYER_GROUP, .id = ++objectIDAllocator }; | ||||
| 		Object2 metrics = { 0 }, textStyle = { 0 }, iconStyle = { 0 }; | ||||
| 		int32_t layerCount = 0; | ||||
| 
 | ||||
| 		for (uintptr_t i = 0; i < arrlenu(style->layers); i++) { | ||||
| 			Layer *layer = LayerLookup(style->layers[i]); | ||||
| 			bool addToLayerGroup = false, addToObjects = false; | ||||
| 			Object2 object = { 0 }; | ||||
| 
 | ||||
| 			if (layer->base.tag == LayerBase_box + 1) { | ||||
| 				object.type = OBJ_LAYER_BOX, object.id = ++objectIDAllocator; | ||||
| 				LayerBox *box = &layer->base.box; | ||||
| 				ObjectAddIntegerProperty(&object, "borders0", box->borders.l); | ||||
| 				ObjectAddIntegerProperty(&object, "borders1", box->borders.r); | ||||
| 				ObjectAddIntegerProperty(&object, "borders2", box->borders.t); | ||||
| 				ObjectAddIntegerProperty(&object, "borders3", box->borders.b); | ||||
| 				ObjectAddIntegerProperty(&object, "corners0", box->corners.tl); | ||||
| 				ObjectAddIntegerProperty(&object, "corners1", box->corners.tr); | ||||
| 				ObjectAddIntegerProperty(&object, "corners2", box->corners.bl); | ||||
| 				ObjectAddIntegerProperty(&object, "corners3", box->corners.br); | ||||
| 				ObjectAddIntegerProperty(&object, "isBlurred", box->blurred); | ||||
| 				ObjectAddIntegerProperty(&object, "autoCorners", box->autoCorners); | ||||
| 				ObjectAddIntegerProperty(&object, "autoBorders", box->autoBorders); | ||||
| 				ObjectAddIntegerProperty(&object, "shadowHiding", box->shadowHiding); | ||||
| 				ObjectAddObjectProperty(&object, "mainPaint", ExportPaint2(&box->mainPaint, &x, y, &objects, &objectIDAllocator)); | ||||
| 				ObjectAddObjectProperty(&object, "borderPaint", ExportPaint2(&box->borderPaint, &x, y, &objects, &objectIDAllocator)); | ||||
| 				addToLayerGroup = true; | ||||
| 				addToObjects = true; | ||||
| 			} else if (layer->base.tag == LayerBase_text + 1) { | ||||
| 				object.type = OBJ_LAYER_TEXT, object.id = ++objectIDAllocator; | ||||
| 				ObjectAddObjectProperty(&object, "color", ColorLookupPointer(layer->base.text.color)->object2ID); | ||||
| 				ObjectAddIntegerProperty(&object, "blur", layer->base.text.blur); | ||||
| 				addToLayerGroup = true; | ||||
| 				addToObjects = true; | ||||
| 			} else if (layer->base.tag == LayerBase_path + 1) { | ||||
| 				object.type = OBJ_LAYER_PATH, object.id = ++objectIDAllocator; | ||||
| 				LayerPath *path = &layer->base.path; | ||||
| 				ObjectAddIntegerProperty(&object, "pathFillEvenOdd", path->evenOdd); | ||||
| 				ObjectAddIntegerProperty(&object, "pathClosed", path->closed); | ||||
| 				ObjectAddIntegerProperty(&object, "alpha", path->alpha); | ||||
| 				ObjectAddIntegerProperty(&object, "points_count", arrlenu(path->points)); | ||||
| 				ObjectAddIntegerProperty(&object, "fills_count", arrlenu(path->fills)); | ||||
| 
 | ||||
| 				for (uintptr_t i = 0; i < arrlenu(path->points); i++) { | ||||
| 					sprintf(cPropertyName, "points_%d_x0", (int) i); | ||||
| 					ObjectAddFloatProperty(&object, cPropertyName, path->points[i].x0); | ||||
| 					sprintf(cPropertyName, "points_%d_y0", (int) i); | ||||
| 					ObjectAddFloatProperty(&object, cPropertyName, path->points[i].y0); | ||||
| 					sprintf(cPropertyName, "points_%d_x1", (int) i); | ||||
| 					ObjectAddFloatProperty(&object, cPropertyName, path->points[i].x1); | ||||
| 					sprintf(cPropertyName, "points_%d_y1", (int) i); | ||||
| 					ObjectAddFloatProperty(&object, cPropertyName, path->points[i].y1); | ||||
| 					sprintf(cPropertyName, "points_%d_x2", (int) i); | ||||
| 					ObjectAddFloatProperty(&object, cPropertyName, path->points[i].x2); | ||||
| 					sprintf(cPropertyName, "points_%d_y2", (int) i); | ||||
| 					ObjectAddFloatProperty(&object, cPropertyName, path->points[i].y2); | ||||
| 				} | ||||
| 
 | ||||
| 				for (uintptr_t i = 0; i < arrlenu(path->fills); i++) { | ||||
| 					sprintf(cPropertyName, "fills_%d_paint", (int) i); | ||||
| 					ObjectAddObjectProperty(&object, cPropertyName, ExportPaint2(&path->fills[i].paint, &x, y, &objects, &objectIDAllocator)); | ||||
| 					sprintf(cPropertyName, "fills_%d_mode", (int) i); | ||||
| 					ObjectAddObjectProperty(&object, cPropertyName, ExportFillMode2(&path->fills[i].mode, &x, y, &objects, &objectIDAllocator)); | ||||
| 				} | ||||
| 
 | ||||
| 				addToLayerGroup = true; | ||||
| 				addToObjects = true; | ||||
| 			} else { | ||||
| 				object.type = OBJ_LAYER_METRICS, object.id = ++objectIDAllocator; | ||||
| 				LayerMetrics *m = &layer->base.metrics; | ||||
| 				ObjectAddIntegerProperty(&object, "clipEnabled", m->clipEnabled); | ||||
| 				ObjectAddIntegerProperty(&object, "wrapText", m->wrapText); | ||||
| 				ObjectAddIntegerProperty(&object, "ellipsis", m->ellipsis); | ||||
| 				ObjectAddIntegerProperty(&object, "insets0", m->insets.l); | ||||
| 				ObjectAddIntegerProperty(&object, "insets1", m->insets.r); | ||||
| 				ObjectAddIntegerProperty(&object, "insets2", m->insets.t); | ||||
| 				ObjectAddIntegerProperty(&object, "insets3", m->insets.b); | ||||
| 				ObjectAddIntegerProperty(&object, "clipInsets0", m->clipInsets.l); | ||||
| 				ObjectAddIntegerProperty(&object, "clipInsets1", m->clipInsets.r); | ||||
| 				ObjectAddIntegerProperty(&object, "clipInsets2", m->clipInsets.t); | ||||
| 				ObjectAddIntegerProperty(&object, "clipInsets3", m->clipInsets.b); | ||||
| 				ObjectAddIntegerProperty(&object, "preferredWidth", m->preferredSize.width); | ||||
| 				ObjectAddIntegerProperty(&object, "preferredHeight", m->preferredSize.height); | ||||
| 				ObjectAddIntegerProperty(&object, "minimumWidth", m->minimumSize.width); | ||||
| 				ObjectAddIntegerProperty(&object, "minimumHeight", m->minimumSize.height); | ||||
| 				ObjectAddIntegerProperty(&object, "maximumWidth", m->maximumSize.width); | ||||
| 				ObjectAddIntegerProperty(&object, "maximumHeight", m->maximumSize.height); | ||||
| 				ObjectAddIntegerProperty(&object, "gapMajor", m->gaps.major); | ||||
| 				ObjectAddIntegerProperty(&object, "gapMinor", m->gaps.minor); | ||||
| 				ObjectAddIntegerProperty(&object, "gapWrap", m->gaps.wrap); | ||||
| 				ObjectAddIntegerProperty(&object, "cursor", m->cursor); | ||||
| 				ObjectAddIntegerProperty(&object, "horizontalTextAlign", m->textHorizontalAlign + 1); | ||||
| 				ObjectAddIntegerProperty(&object, "verticalTextAlign", m->textVerticalAlign + 1); | ||||
| 				assert(!m->globalOffset.l && !m->globalOffset.r && !m->globalOffset.t && !m->globalOffset.b); | ||||
| 				addToObjects = true; | ||||
| 				metrics = object; | ||||
| 
 | ||||
| 				textStyle.type = OBJ_VAR_TEXT_STYLE, textStyle.id = ++objectIDAllocator; | ||||
| 				ObjectAddIntegerProperty(&textStyle, "_graphX", x); | ||||
| 				ObjectAddIntegerProperty(&textStyle, "_graphY", y); | ||||
| 				ObjectAddIntegerProperty(&textStyle, "_graphW", 80); | ||||
| 				ObjectAddIntegerProperty(&textStyle, "_graphH", 60); | ||||
| 				ObjectAddObjectProperty(&textStyle, "textColor", ColorLookupPointer(m->textColor)->object2ID); | ||||
| 				ObjectAddObjectProperty(&textStyle, "selectedBackground", ColorLookupPointer(m->selectedBackground)->object2ID); | ||||
| 				ObjectAddObjectProperty(&textStyle, "selectedText", ColorLookupPointer(m->selectedText)->object2ID); | ||||
| 				ObjectAddIntegerProperty(&textStyle, "textSize", m->textSize); | ||||
| 				ObjectAddIntegerProperty(&textStyle, "fontWeight", m->fontWeight); | ||||
| 				ObjectAddIntegerProperty(&textStyle, "isItalic", m->italic); | ||||
| 				ObjectAddIntegerProperty(&textStyle, "fontFamily", m->fontFamily == FONT_FAMILY_MONO ? 0xFFFD : 0xFFFF); | ||||
| 				arrput(objects, textStyle); | ||||
| 				x += 100; | ||||
| 
 | ||||
| 				iconStyle.type = OBJ_VAR_ICON_STYLE, iconStyle.id = ++objectIDAllocator; | ||||
| 				ObjectAddIntegerProperty(&iconStyle, "_graphX", x); | ||||
| 				ObjectAddIntegerProperty(&iconStyle, "_graphY", y); | ||||
| 				ObjectAddIntegerProperty(&iconStyle, "_graphW", 80); | ||||
| 				ObjectAddIntegerProperty(&iconStyle, "_graphH", 60); | ||||
| 				ObjectAddIntegerProperty(&iconStyle, "iconSize", m->iconSize); | ||||
| 				ObjectAddObjectProperty(&iconStyle, "iconColor", ColorLookupPointer(m->iconColor)->object2ID); | ||||
| 				arrput(objects, iconStyle); | ||||
| 				x += 100; | ||||
| 			} | ||||
| 
 | ||||
| 			if (addToLayerGroup) { | ||||
| 				sprintf(cPropertyName, "layers_%d_layer", layerCount); | ||||
| 				ObjectAddObjectProperty(&layerGroup, cPropertyName, object.id); | ||||
| 				sprintf(cPropertyName, "layers_%d_offset0", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->offset.l); | ||||
| 				sprintf(cPropertyName, "layers_%d_offset1", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->offset.r); | ||||
| 				sprintf(cPropertyName, "layers_%d_offset2", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->offset.t); | ||||
| 				sprintf(cPropertyName, "layers_%d_offset3", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->offset.b); | ||||
| 				sprintf(cPropertyName, "layers_%d_position0", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->position.l); | ||||
| 				sprintf(cPropertyName, "layers_%d_position1", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->position.r); | ||||
| 				sprintf(cPropertyName, "layers_%d_position2", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->position.t); | ||||
| 				sprintf(cPropertyName, "layers_%d_position3", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->position.b); | ||||
| 				sprintf(cPropertyName, "layers_%d_mode", layerCount); | ||||
| 				ObjectAddIntegerProperty(&layerGroup, cPropertyName, layer->mode); | ||||
| 				layerCount++; | ||||
| 			} | ||||
| 
 | ||||
| 			if (addToObjects) { | ||||
| 				ObjectAddIntegerProperty(&object, "_graphX", x); | ||||
| 				ObjectAddIntegerProperty(&object, "_graphY", y); | ||||
| 				ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 				ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 				arrput(objects, object); | ||||
| 				x += 100; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			Object2 object = layerGroup; | ||||
| 			ObjectAddIntegerProperty(&object, "_graphX", x); | ||||
| 			ObjectAddIntegerProperty(&object, "_graphY", y); | ||||
| 			ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 			ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 			ObjectAddIntegerProperty(&object, "layers_count", layerCount); | ||||
| 			arrput(objects, object); | ||||
| 			x += 100; | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			Object2 object = { .type = OBJ_STYLE, .id = ++objectIDAllocator }; | ||||
| 			snprintf(object.cName, sizeof(object.cName), "%.*s", (int) style->name.byteCount, (const char *) style->name.buffer); | ||||
| 			ObjectAddIntegerProperty(&object, "_graphX", x); | ||||
| 			ObjectAddIntegerProperty(&object, "_graphY", y); | ||||
| 			ObjectAddIntegerProperty(&object, "_graphW", 80); | ||||
| 			ObjectAddIntegerProperty(&object, "_graphH", 60); | ||||
| 			ObjectAddIntegerProperty(&object, "isPublic", style->publicStyle); | ||||
| 			ObjectAddObjectProperty(&object, "appearance", layerGroup.id); | ||||
| 			ObjectAddObjectProperty(&object, "metrics", metrics.id); | ||||
| 			ObjectAddObjectProperty(&object, "textStyle", textStyle.id); | ||||
| 			ObjectAddObjectProperty(&object, "iconStyle", iconStyle.id); | ||||
| 			arrput(objects, object); | ||||
| 			x += 100; | ||||
| 		} | ||||
| 
 | ||||
| 		y += 200; | ||||
| 	} | ||||
| 
 | ||||
| 	// Saving.
 | ||||
| 
 | ||||
| 	FILE *f = fopen("bin/designer2.dat", "wb"); | ||||
| 	uint32_t version = 1; | ||||
| 	fwrite(&version, 1, sizeof(uint32_t), f); | ||||
| 	uint32_t objectCount = arrlenu(objects); | ||||
| 	fwrite(&objectCount, 1, sizeof(uint32_t), f); | ||||
| 	fwrite(&objectIDAllocator, 1, sizeof(uint64_t), f); | ||||
| 
 | ||||
| 	for (uintptr_t i = 0; i < arrlenu(objects); i++) { | ||||
| 		Object2 copy = objects[i]; | ||||
| 		uint32_t propertyCount = arrlenu(copy.properties); | ||||
| 		copy.properties = NULL; | ||||
| 		fwrite(©, 1, sizeof(Object2), f); | ||||
| 		fwrite(&propertyCount, 1, sizeof(uint32_t), f); | ||||
| 		fwrite(objects[i].properties, 1, sizeof(Property2) * propertyCount, f); | ||||
| 		arrfree(objects[i].properties); | ||||
| 		assert(objects[i].id); | ||||
| 	} | ||||
| 
 | ||||
| 	fclose(f); | ||||
| 	arrfree(objects); | ||||
| } | ||||
| 
 | ||||
| // ------------------- Preview canvas -------------------
 | ||||
| 
 | ||||
| float Smooth(float x) { | ||||
|  | @ -5334,6 +5808,7 @@ int main(int argc, char **argv) | |||
| 		UIButtonCreate(0, 0, "Save", -1)->invoke = ActionSave; | ||||
| 		UIButtonCreate(0, 0, "Load", -1)->invoke = ActionLoad; | ||||
| 		UIButtonCreate(0, 0, "Export", -1)->invoke = ActionExport; | ||||
| 		UIButtonCreate(0, 0, "Export for Designer2", -1)->invoke = ActionExportDesigner2; | ||||
| 		UIButtonCreate(0, 0, "Import font", -1)->invoke = ActionImportFont; | ||||
| 	UIParentPop(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -350,6 +350,7 @@ struct Color Color_Type RfStructOp { | |||
| 	rfData RfData key; | ||||
| 	rfU32 uint32_t value; | ||||
| 	rfU32 uint32_t id; | ||||
| 	rfNone uint64_t object2ID; | ||||
| }; | ||||
| 
 | ||||
| struct StyleSet StyleSet_Type StyleSetOp { | ||||
|  |  | |||
|  | @ -21,6 +21,8 @@ | |||
| // 	Prototyping display: previewing state transitions.
 | ||||
| 
 | ||||
| // TODO Additional features:
 | ||||
| // 	Scrollbars?
 | ||||
| // 	Icons for different object types (especially color overwrite objects).
 | ||||
| // 	Fix moving/resizing objects when zoomed in.
 | ||||
| // 	Path layers: dashed contours.
 | ||||
| // 	Picking objects: only highlight objects with an applicable type.
 | ||||
|  | @ -71,6 +73,7 @@ | |||
| #define EsHeap void | ||||
| #define EsMemoryCopy memcpy | ||||
| #define EsMemoryCopyReverse memmove | ||||
| #define EsMemoryCompare memcmp | ||||
| #define EsMemoryZero(a, b) memset((a), 0, (b)) | ||||
| #define EsPanic(...) UI_ASSERT(false) | ||||
| #define EsRectangle UIRectangle | ||||
|  | @ -153,6 +156,7 @@ void SetBit(uint32_t *value, uint32_t bit, bool on) { | |||
| #include "../shared/math.cpp" | ||||
| 
 | ||||
| #include "../shared/array.cpp" | ||||
| #include "../shared/hash_table.cpp" | ||||
| #include "../desktop/renderer.cpp" | ||||
| #include "../desktop/theme.cpp" | ||||
| 
 | ||||
|  | @ -329,14 +333,14 @@ Array<Step> undoStack; | |||
| Array<Step> redoStack; | ||||
| bool documentModified; | ||||
| uint64_t selectedObjectID; | ||||
| HashStore<uint64_t, uintptr_t> objectLookup; | ||||
| 
 | ||||
| // Document state:
 | ||||
| Array<Object> objects; | ||||
| uint64_t objectIDAllocator; | ||||
| 
 | ||||
| Object *ObjectFind(uint64_t id) { | ||||
| 	// TODO Use a hash table.
 | ||||
| 
 | ||||
| #if 0 | ||||
| 	for (uintptr_t i = 0; i < objects.Length(); i++) { | ||||
| 		if (objects[i].id == id) { | ||||
| 			return &objects[i]; | ||||
|  | @ -344,6 +348,13 @@ Object *ObjectFind(uint64_t id) { | |||
| 	} | ||||
| 
 | ||||
| 	return nullptr; | ||||
| #else | ||||
| 	if (!id) return nullptr; | ||||
| 	uint64_t *index = objectLookup.Get(&id); | ||||
| 	Object *object = index ? &objects[*index] : nullptr; | ||||
| 	if (object) assert(object->id == id); | ||||
| 	return object; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void ObjectSetSelected(uint64_t id, bool removeSelectedFlagFromPreviousSelection = true) { | ||||
|  | @ -399,7 +410,9 @@ bool ObjectMatchesPreviewState(Object *object) { | |||
| } | ||||
| 
 | ||||
| Property *PropertyFindOrInherit(bool first, Object *object, const char *cName, uint8_t type = 0) { | ||||
| 	while (object) { | ||||
| 	uintptr_t depth = 0; | ||||
| 
 | ||||
| 	while (object && (depth++ < 100)) { | ||||
| 		if (first || !ObjectIsConditional(object) || (canvas->previewStateActive && ObjectMatchesPreviewState(object))) { | ||||
| 			// Return the value if the object has this property.
 | ||||
| 			Property *property = PropertyFind(object, cName); | ||||
|  | @ -432,6 +445,14 @@ Object *PropertyFindOrInheritReadObject(bool first, Object *object, const char * | |||
| 	return property ? ObjectFind(property->object) : nullptr; | ||||
| } | ||||
| 
 | ||||
| void ObjectLookupRebuild() { | ||||
| 	objectLookup.Free(); | ||||
| 
 | ||||
| 	for (uintptr_t i = 0; i < objects.Length(); i++) { | ||||
| 		*objectLookup.Put(&objects[i].id) = i; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DocumentSave(void *) { | ||||
| #ifdef OS_ESSENCE | ||||
| 	EsBuffer buffer = { .canGrow = 1 }; | ||||
|  | @ -491,6 +512,8 @@ void DocumentLoad() { | |||
| 		objects.Add(object); | ||||
| 	} | ||||
| 
 | ||||
| 	ObjectLookupRebuild(); | ||||
| 
 | ||||
| #ifdef OS_ESSENCE | ||||
| 	EsHeapFree(buffer.out); | ||||
| #else | ||||
|  | @ -506,6 +529,7 @@ void DocumentFree() { | |||
| 	objects.Free(); | ||||
| 	undoStack.Free(); | ||||
| 	redoStack.Free(); | ||||
| 	ObjectLookupRebuild(); | ||||
| } | ||||
| 
 | ||||
| void DocumentApplyStep(Step step, StepApplyMode mode = STEP_APPLY_NORMAL) { | ||||
|  | @ -567,6 +591,7 @@ void DocumentApplyStep(Step step, StepApplyMode mode = STEP_APPLY_NORMAL) { | |||
| 		InspectorPopulate(); | ||||
| 	} else if (step.type == STEP_ADD_OBJECT) { | ||||
| 		objects.Add(step.object); | ||||
| 		ObjectLookupRebuild(); | ||||
| 		UIElementRepaint(canvas, nullptr); | ||||
| 		step.objectID = step.object.id; | ||||
| 		step.type = STEP_DELETE_OBJECT; | ||||
|  | @ -585,6 +610,7 @@ void DocumentApplyStep(Step step, StepApplyMode mode = STEP_APPLY_NORMAL) { | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		ObjectLookupRebuild(); | ||||
| 		step.object.flags = 0; | ||||
| 		UIElementRefresh(canvas); | ||||
| 		InspectorPopulate(); | ||||
|  | @ -604,6 +630,7 @@ void DocumentApplyStep(Step step, StepApplyMode mode = STEP_APPLY_NORMAL) { | |||
| 		} | ||||
| 
 | ||||
| 		UI_ASSERT(found); | ||||
| 		ObjectLookupRebuild(); | ||||
| 		UIElementRefresh(canvas); | ||||
| 	} else { | ||||
| 		UI_ASSERT(false); | ||||
|  | @ -2030,6 +2057,12 @@ void CanvasDrawLayerFromData(UIPainter *painter, UIRectangle bounds, EsBuffer da | |||
| } | ||||
| 
 | ||||
| void CanvasDrawColorSwatch(Object *object, UIRectangle bounds, UIPainter *painter) { | ||||
| 	for (int32_t y = bounds.t, y0 = 0; y < bounds.b; y += 15, y0++) { | ||||
| 		for (int32_t x = bounds.l, x0 = 0; x < bounds.r; x += 15, x0++) { | ||||
| 			UIDrawBlock(painter, UIRectangleIntersection(UI_RECT_4(x, x + 15, y, y + 15), bounds), ((x0 ^ y0) & 1) ? 0xFF808080 : 0xFFC0C0C0); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	uint8_t buffer[4096]; | ||||
| 	EsBuffer data = { .out = buffer, .bytes = sizeof(buffer) }; | ||||
| 	ThemeLayer layer = { .position = { .r = 100, .b = 100 }, .type = THEME_LAYER_BOX }; | ||||
|  | @ -2450,13 +2483,16 @@ int CanvasMessage(UIElement *element, UIMessage message, int di, void *dp) { | |||
| 		canvas->lastPanPointX = element->window->cursorX; | ||||
| 		canvas->lastPanPointY = element->window->cursorY; | ||||
| 		UIElementRefresh(canvas); | ||||
| 	} else if (message == UI_MSG_MOUSE_WHEEL && !element->window->ctrl) { | ||||
| 		canvas->panY += di / canvas->zoom; | ||||
| 		UIElementRefresh(canvas); | ||||
| 	} else if (message == UI_MSG_MOUSE_WHEEL && element->window->ctrl) { | ||||
| 		int divisions = -di / 72; | ||||
| 		float factor = 1, perDivision = 1.2f; | ||||
| 		while (divisions > 0) factor *= perDivision, divisions--; | ||||
| 		while (divisions < 0) factor /= perDivision, divisions++; | ||||
| 		if (canvas->zoom * factor > 4) factor = 4 / canvas->zoom; | ||||
| 		if (canvas->zoom * factor < 1) factor = 1 / canvas->zoom; | ||||
| 		if (canvas->zoom * factor < 0.1) factor = 0.1 / canvas->zoom; | ||||
| 		int mx = element->window->cursorX - element->bounds.l; | ||||
| 		int my = element->window->cursorY - element->bounds.t; | ||||
| 		canvas->zoom *= factor; | ||||
|  | @ -2507,6 +2543,14 @@ void CanvasSwitchView(void *) { | |||
| 	UIElementRefresh(canvas); | ||||
| } | ||||
| 
 | ||||
| void CanvasZoom100(void *) { | ||||
| 	float factor = 1.0f / canvas->zoom; | ||||
| 	canvas->zoom *= factor; | ||||
| 	canvas->panX -= UI_RECT_WIDTH(canvas->bounds) / 2 / canvas->zoom * (1 - factor); | ||||
| 	canvas->panY -= UI_RECT_HEIGHT(canvas->bounds) / 2 / canvas->zoom * (1 - factor); | ||||
| 	UIElementRefresh(canvas); | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| void ObjectAddInternal(Object object) { | ||||
|  | @ -2587,7 +2631,7 @@ void ObjectAddCommand(void *) { | |||
| } | ||||
| 
 | ||||
| void ObjectAddInstanceCommand(void *) { | ||||
| 	UIMenu *menu = UIMenuCreate(window->pressed, UI_MENU_NO_SCROLL | UI_MENU_PLACE_ABOVE); | ||||
| 	UIMenu *menu = UIMenuCreate(window->pressed, 0); | ||||
| 
 | ||||
| 	for (uintptr_t i = 0; i < objects.Length(); i++) { | ||||
| 		if (objects[i].type == OBJ_STYLE) { | ||||
|  | @ -2700,14 +2744,11 @@ int main() { | |||
| 		UIButtonCreate(0, UI_BUTTON_SMALL, "Add instance \x18", -1)->invoke = ObjectAddInstanceCommand; | ||||
| 	UIParentPop(); | ||||
| 
 | ||||
| 	canvas->resizeHandles[0] = UIElementCreate(sizeof(UIElement), canvas, 0, ResizeHandleMessage, "Resize handle"); | ||||
| 	canvas->resizeHandles[1] = UIElementCreate(sizeof(UIElement), canvas, 0, ResizeHandleMessage, "Resize handle"); | ||||
| 	canvas->resizeHandles[2] = UIElementCreate(sizeof(UIElement), canvas, 0, ResizeHandleMessage, "Resize handle"); | ||||
| 	canvas->resizeHandles[3] = UIElementCreate(sizeof(UIElement), canvas, 0, ResizeHandleMessage, "Resize handle"); | ||||
| 	canvas->resizeHandles[0]->cp = (void *) (uintptr_t) 0; | ||||
| 	canvas->resizeHandles[1]->cp = (void *) (uintptr_t) 1; | ||||
| 	canvas->resizeHandles[2]->cp = (void *) (uintptr_t) 2; | ||||
| 	canvas->resizeHandles[3]->cp = (void *) (uintptr_t) 3; | ||||
| 	for (uintptr_t i = 0; i < 4; i++) { | ||||
| 		canvas->resizeHandles[i] = UIElementCreate(sizeof(UIElement), canvas, 0, ResizeHandleMessage, "Resize handle"); | ||||
| 		canvas->resizeHandles[i]->cp = (void *) (uintptr_t) i; | ||||
| 	} | ||||
| 
 | ||||
| 	canvas->zoom = canvas->swapZoom = 1.0f; | ||||
| 	canvas->previewPrimaryState = THEME_PRIMARY_STATE_IDLE; | ||||
| 
 | ||||
|  | @ -2715,6 +2756,7 @@ int main() { | |||
| 	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_DELETE, 0, 0, 0, ObjectDeleteCommand, 0)); | ||||
| 
 | ||||
| #ifdef OS_ESSENCE | ||||
|  |  | |||
|  | @ -1133,9 +1133,10 @@ bool UIDrawLine(UIPainter *painter, int x0, int y0, int x1, int y1, uint32_t col | |||
| 	// Apply the clip.
 | ||||
| 
 | ||||
| 	UIRectangle c = painter->clip; | ||||
| 	if (!UI_RECT_VALID(c)) return false; | ||||
| 	int dx = x1 - x0, dy = y1 - y0; | ||||
| 	const int p[4] = { -dx, dx, -dy, dy }; | ||||
| 	const int q[4] = { x0 - c.l, c.r - x0, y0 - c.t, c.b - y0 }; | ||||
| 	const int q[4] = { x0 - c.l, c.r - 1 - x0, y0 - c.t, c.b - 1 - y0 }; | ||||
| 	float t0 = 0.0f, t1 = 1.0f; // How far along the line the points end up.
 | ||||
| 
 | ||||
| 	for (int i = 0; i < 4; i++) { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 nakst
						nakst