mirror of https://gitlab.com/nakst/essence
add EsPanelTableAddBandDecorator; script console array of struct viewer
This commit is contained in:
parent
73a6457025
commit
67b268db0a
|
@ -2,6 +2,8 @@
|
|||
#include <essence.h>
|
||||
|
||||
// TODO Resizing the window after calling DirectoryEnumerateChildrenRecursively() is slow.
|
||||
// TODO UTF-8 validation of outputted strings.
|
||||
// TODO Check for heap allocation leaks.
|
||||
|
||||
struct Instance : EsInstance {
|
||||
EsThreadInformation scriptThread;
|
||||
|
@ -348,6 +350,7 @@ EXTERNAL_STUB(ExternalSystemSetEnvironmentVariable);
|
|||
|
||||
#define COLOR_BACKGROUND (0xFFFDFDFD)
|
||||
#define COLOR_ROW_ODD (0xFFF4F4F4)
|
||||
#define COLOR_ROW_HEADER_LINE (0xFFCCCCCC)
|
||||
#define COLOR_OUTPUT_DECORATION_IN_PROGRESS (0xFFFF7F00)
|
||||
#define COLOR_OUTPUT_DECORATION_SUCCESS (0xFF3070FF)
|
||||
#define COLOR_OUTPUT_DECORATION_FAILURE (0xFFFF3040)
|
||||
|
@ -523,16 +526,30 @@ const EsStyle styleOutputDecorationFailure = {
|
|||
},
|
||||
};
|
||||
|
||||
const EsThemeAppearance styleAppearanceRowHeader = {
|
||||
.enabled = true,
|
||||
.backgroundColor = COLOR_BACKGROUND,
|
||||
.borderColor = COLOR_ROW_HEADER_LINE,
|
||||
.borderSize = ES_RECT_4(0, 0, 0, 1),
|
||||
};
|
||||
|
||||
const EsThemeAppearance styleAppearanceRowEven = {
|
||||
.enabled = true,
|
||||
.backgroundColor = COLOR_BACKGROUND,
|
||||
};
|
||||
|
||||
const EsThemeAppearance styleAppearanceRowOdd = {
|
||||
.enabled = true,
|
||||
.backgroundColor = COLOR_ROW_ODD,
|
||||
};
|
||||
|
||||
const EsStyle styleListRowEven = {
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_INSETS,
|
||||
.insets = ES_RECT_1(3),
|
||||
},
|
||||
|
||||
.appearance = {
|
||||
.enabled = true,
|
||||
.backgroundColor = COLOR_BACKGROUND,
|
||||
},
|
||||
.appearance = styleAppearanceRowEven,
|
||||
};
|
||||
|
||||
const EsStyle styleListRowOdd = {
|
||||
|
@ -541,10 +558,7 @@ const EsStyle styleListRowOdd = {
|
|||
.insets = ES_RECT_1(3),
|
||||
},
|
||||
|
||||
.appearance = {
|
||||
.enabled = true,
|
||||
.backgroundColor = COLOR_ROW_ODD,
|
||||
},
|
||||
.appearance = styleAppearanceRowOdd,
|
||||
};
|
||||
|
||||
void AddREPLResult(ExecutionContext *context, EsElement *parent, Node *type, Value value) {
|
||||
|
@ -554,13 +568,16 @@ void AddREPLResult(ExecutionContext *context, EsElement *parent, Node *type, Val
|
|||
size_t bytes;
|
||||
|
||||
if (type->type == T_INT) {
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "(int) %d", value.i);
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "%d", value.i);
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||
} else if (type->type == T_BOOL) {
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "%z", value.i ? "true" : "false");
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||
} else if (type->type == T_NULL) {
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "%z", "null");
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||
} else if (type->type == T_FLOAT) {
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "(float) %F", value.f);
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "%F", value.f);
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||
} else if (type->type == T_STR) {
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||
|
@ -570,7 +587,48 @@ void AddREPLResult(ExecutionContext *context, EsElement *parent, Node *type, Val
|
|||
ScriptHeapEntryToString(context, entry, &valueText, &valueBytes);
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "\"%s\"", valueBytes, valueText);
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||
} else if (type->type == T_LIST && type->firstChild->type == T_STRUCT) {
|
||||
// TODO Row styling.
|
||||
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||
HeapEntry *listEntry = &context->heap[value.i];
|
||||
EsAssert(listEntry->type == T_LIST);
|
||||
if (!listEntry->length) goto normalList;
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) listEntry->list[0].i);
|
||||
EsAssert(context->heap[listEntry->list[0].i].type == T_STRUCT);
|
||||
|
||||
EsPanel *table = EsPanelCreate(parent, ES_CELL_H_FILL | ES_PANEL_HORIZONTAL | ES_PANEL_TABLE);
|
||||
EsPanelSetBands(table, context->heap[listEntry->list[0].i].fieldCount);
|
||||
EsPanelTableAddBandDecorator(table, { .index = 0, .repeatEvery = 0, .axis = 1, .appearance = &styleAppearanceRowHeader });
|
||||
EsPanelTableAddBandDecorator(table, { .index = 1, .repeatEvery = 2, .axis = 1, .appearance = &styleAppearanceRowEven });
|
||||
EsPanelTableAddBandDecorator(table, { .index = 2, .repeatEvery = 2, .axis = 1, .appearance = &styleAppearanceRowOdd });
|
||||
|
||||
{
|
||||
Node *field = type->firstChild->firstChild;
|
||||
|
||||
while (field) {
|
||||
EsTextDisplayCreate(table, ES_CELL_H_FILL, &styleOutputParagraph, field->token.text, field->token.textBytes);
|
||||
field = field->sibling;
|
||||
}
|
||||
}
|
||||
|
||||
for (uintptr_t i = 0; i < listEntry->length; i++) {
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||
HeapEntry *itemEntry = &context->heap[listEntry->list[i].i];
|
||||
EsAssert(itemEntry->type == T_STRUCT);
|
||||
EsAssert(itemEntry->fieldCount == context->heap[listEntry->list[0].i].fieldCount);
|
||||
Node *field = type->firstChild->firstChild;
|
||||
uintptr_t j = 0;
|
||||
|
||||
while (field) {
|
||||
EsAssert(j != itemEntry->fieldCount);
|
||||
AddREPLResult(context, table, field->firstChild, itemEntry->fields[j]);
|
||||
field = field->sibling;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
} else if (type->type == T_LIST) {
|
||||
normalList:;
|
||||
EsPanel *panel = EsPanelCreate(parent, ES_CELL_H_FILL | ES_PANEL_VERTICAL | ES_PANEL_STACK);
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||
HeapEntry *entry = &context->heap[value.i];
|
||||
|
@ -585,13 +643,8 @@ void AddREPLResult(ExecutionContext *context, EsElement *parent, Node *type, Val
|
|||
EsPanel *item = EsPanelCreate(panel, ES_CELL_H_FILL, (i % 2) ? &styleListRowOdd : &styleListRowEven);
|
||||
AddREPLResult(context, item, type->firstChild, entry->list[i]);
|
||||
}
|
||||
} else if (type->type == T_FUNCPTR) {
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphItalic,
|
||||
EsLiteral("Function pointer.\n"));
|
||||
} else if (type->type == T_STRUCT) {
|
||||
EsPanel *panel = EsPanelCreate(parent, ES_CELL_H_FILL | ES_PANEL_VERTICAL | ES_PANEL_STACK);
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "%s:", type->token.textBytes, type->token.text);
|
||||
EsTextDisplayCreate(panel, ES_CELL_H_FILL, &styleOutputParagraph, buffer, bytes);
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||
HeapEntry *entry = &context->heap[value.i];
|
||||
EsAssert(entry->type == T_STRUCT);
|
||||
|
@ -601,14 +654,14 @@ void AddREPLResult(ExecutionContext *context, EsElement *parent, Node *type, Val
|
|||
|
||||
while (field) {
|
||||
EsAssert(i != entry->fieldCount);
|
||||
EsPanel *item = EsPanelCreate(panel, ES_CELL_H_FILL, (i % 2) ? &styleListRowEven : &styleListRowOdd);
|
||||
EsPanel *item = EsPanelCreate(panel, ES_CELL_H_FILL, (i % 2) ? &styleListRowOdd : &styleListRowEven);
|
||||
AddREPLResult(context, item, field->firstChild, entry->fields[i]);
|
||||
field = field->sibling;
|
||||
i++;
|
||||
}
|
||||
} else if (type->type == T_NULL) {
|
||||
char *buffer = EsStringAllocateAndFormat(&bytes, "%z", "null");
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphStrong, buffer, bytes);
|
||||
} else if (type->type == T_FUNCPTR) {
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphItalic,
|
||||
EsLiteral("Function pointer.\n"));
|
||||
} else {
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, &styleOutputParagraphItalic,
|
||||
EsLiteral("The type of the result was not recognized.\n"));
|
||||
|
|
|
@ -382,6 +382,8 @@ struct EsPanel : EsElement {
|
|||
uint16_t bandCount[2];
|
||||
EsPanelBand *bands[2];
|
||||
uintptr_t tableIndex;
|
||||
uint8_t *tableMemoryBase;
|
||||
Array<EsPanelBandDecorator> bandDecorators;
|
||||
|
||||
// TODO This names overlap with fields in EsElement, they should probably be renamed.
|
||||
uint16_t transitionType;
|
||||
|
@ -1985,18 +1987,23 @@ void LayoutTable(EsPanel *panel, EsMessage *message) {
|
|||
|
||||
size_t childCount = panel->GetChildCount();
|
||||
|
||||
EsHeapFree(panel->tableMemoryBase);
|
||||
panel->tableMemoryBase = nullptr;
|
||||
|
||||
uint8_t *memoryBase = (uint8_t *) EsHeapAllocate(sizeof(int) * childCount * 2 + sizeof(EsPanelBand) * (panel->bandCount[0] + panel->bandCount[1]), true), *memory = memoryBase;
|
||||
|
||||
if (!memoryBase) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE These must be contiguous at come at the start of memoryBase, so that the band decorators can look up band positions.
|
||||
EsPanelBand *calculatedProperties[2];
|
||||
calculatedProperties[0] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[0];
|
||||
calculatedProperties[1] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[1];
|
||||
|
||||
int *calculatedSize[2];
|
||||
calculatedSize[0] = (int *) memory; memory += sizeof(int) * childCount;
|
||||
calculatedSize[1] = (int *) memory; memory += sizeof(int) * childCount;
|
||||
EsPanelBand *calculatedProperties[2];
|
||||
calculatedProperties[0] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[0];
|
||||
calculatedProperties[1] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[1];
|
||||
|
||||
for (int axis = 0; axis < 2; axis++) {
|
||||
if (panel->bands[axis]) {
|
||||
|
@ -2243,7 +2250,7 @@ void LayoutTable(EsPanel *panel, EsMessage *message) {
|
|||
EsPrint("\t%d/%d\n", out[0], out[1]);
|
||||
}
|
||||
|
||||
EsHeapFree(memoryBase);
|
||||
panel->tableMemoryBase = memoryBase;
|
||||
}
|
||||
|
||||
int LayoutStackDeterminePerPush(EsPanel *panel, int available, int secondary) {
|
||||
|
@ -3128,6 +3135,9 @@ void PanelTableSetChildCell(EsPanel *panel, EsElement *child) {
|
|||
}
|
||||
|
||||
child->tableCell = cell;
|
||||
|
||||
EsHeapFree(panel->tableMemoryBase);
|
||||
panel->tableMemoryBase = nullptr;
|
||||
}
|
||||
|
||||
int ProcessPanelMessage(EsElement *element, EsMessage *message) {
|
||||
|
@ -3165,6 +3175,28 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) {
|
|||
} else {
|
||||
LayoutStack(panel, message);
|
||||
}
|
||||
} else if (message->type == ES_MSG_PAINT) {
|
||||
uint8_t *memory = panel->tableMemoryBase;
|
||||
EsRectangle client = EsPainterBoundsClient(message->painter);
|
||||
|
||||
if (memory) {
|
||||
EsPanelBand *calculatedProperties[2];
|
||||
calculatedProperties[0] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[0];
|
||||
calculatedProperties[1] = (EsPanelBand *) memory; memory += sizeof(EsPanelBand) * panel->bandCount[1];
|
||||
|
||||
for (uintptr_t i = 0; i < panel->bandDecorators.Length(); i++) {
|
||||
EsPanelBandDecorator decorator = panel->bandDecorators[i];
|
||||
|
||||
for (uintptr_t j = decorator.index; j < panel->bandCount[decorator.axis]; j += decorator.repeatEvery) {
|
||||
EsRectangle bounds;
|
||||
if (decorator.axis) bounds = ES_RECT_4(client.l, client.r, client.t + calculatedProperties[1][j].maximumSize, client.t + calculatedProperties[1][j].maximumSize + calculatedProperties[1][j].preferredSize);
|
||||
else bounds = ES_RECT_4(client.l + calculatedProperties[0][j].maximumSize, client.l + calculatedProperties[0][j].maximumSize + calculatedProperties[0][j].preferredSize, client.t, client.b);
|
||||
EsDrawRectangle(message->painter, bounds, decorator.appearance->backgroundColor,
|
||||
decorator.appearance->borderColor, decorator.appearance->borderSize);
|
||||
if (!decorator.repeatEvery) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (message->type == ES_MSG_PAINT_CHILDREN) {
|
||||
if ((panel->flags & ES_PANEL_SWITCHER) && panel->transitionType != ES_TRANSITION_NONE) {
|
||||
double progress = SmoothAnimationTimeSharp((double) panel->transitionTimeMs / (double) panel->transitionLengthMs);
|
||||
|
@ -3316,7 +3348,11 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) {
|
|||
if ((panel->flags & ES_PANEL_TABLE)) {
|
||||
EsHeapFree(panel->bands[0]);
|
||||
EsHeapFree(panel->bands[1]);
|
||||
EsHeapFree(panel->tableMemoryBase);
|
||||
}
|
||||
|
||||
panel->bandDecorators.Free();
|
||||
panel->movementItems.Free();
|
||||
} else if (message->type == ES_MSG_KEY_DOWN) {
|
||||
if (!(panel->flags & (ES_PANEL_TABLE | ES_PANEL_SWITCHER))
|
||||
&& panel->window->focused && panel->window->focused->parent == panel) {
|
||||
|
@ -3567,6 +3603,8 @@ void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount, const
|
|||
panel->bands[1] = rows ? (EsPanelBand *) EsHeapAllocate(rowCount * sizeof(EsPanelBand), false) : nullptr;
|
||||
if (columns && panel->bands[0]) EsMemoryCopy(panel->bands[0], columns, columnCount * sizeof(EsPanelBand));
|
||||
if (rows && panel->bands[1]) EsMemoryCopy(panel->bands[1], rows, rowCount * sizeof(EsPanelBand));
|
||||
EsHeapFree(panel->tableMemoryBase);
|
||||
panel->tableMemoryBase = nullptr;
|
||||
}
|
||||
|
||||
void EsPanelSetBandsAll(EsPanel *panel, const EsPanelBand *column, const EsPanelBand *row) {
|
||||
|
@ -3591,6 +3629,9 @@ void EsPanelSetBandsAll(EsPanel *panel, const EsPanelBand *column, const EsPanel
|
|||
}
|
||||
|
||||
void EsPanelTableSetChildCells(EsPanel *panel) {
|
||||
EsMessageMutexCheck();
|
||||
EsAssert(panel->flags & ES_PANEL_TABLE);
|
||||
|
||||
// The number of columns/rows should have been set by the time this function is called.
|
||||
EsAssert(panel->bandCount[0] || panel->bandCount[1]);
|
||||
|
||||
|
@ -3602,6 +3643,16 @@ void EsPanelTableSetChildCells(EsPanel *panel) {
|
|||
if (child->flags & ES_ELEMENT_NON_CLIENT) continue;
|
||||
PanelTableSetChildCell(panel, child);
|
||||
}
|
||||
|
||||
EsHeapFree(panel->tableMemoryBase);
|
||||
panel->tableMemoryBase = nullptr;
|
||||
}
|
||||
|
||||
void EsPanelTableAddBandDecorator(EsPanel *panel, EsPanelBandDecorator decorator) {
|
||||
EsMessageMutexCheck();
|
||||
EsAssert(panel->flags & ES_PANEL_TABLE);
|
||||
EsAssert(decorator.axis == 0 || decorator.axis == 1);
|
||||
panel->bandDecorators.Add(decorator);
|
||||
}
|
||||
|
||||
void EsPanelSwitchTo(EsPanel *panel, EsElement *targetChild, EsTransitionType transitionType, uint32_t flags, float timeMultiplier) {
|
||||
|
|
|
@ -1965,6 +1965,12 @@ private struct EsMountPoint {
|
|||
bool addedByApplication;
|
||||
};
|
||||
|
||||
struct EsPanelBandDecorator {
|
||||
uintptr_t index, repeatEvery;
|
||||
uint8_t axis; // 0 for columns, 1 for rows.
|
||||
const EsThemeAppearance *appearance; // Pointer must remain valid.
|
||||
};
|
||||
|
||||
// Function pointer types.
|
||||
|
||||
function_pointer void EsThreadEntryCallback(EsGeneric argument);
|
||||
|
@ -2541,6 +2547,7 @@ function EsCanvasPane *EsCanvasPaneCreate(EsElement *parent, uint64_t flags = ES
|
|||
function void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount = 0, const EsPanelBand *columns = ES_NULL, const EsPanelBand *rows = ES_NULL);
|
||||
function void EsPanelSetBandsAll(EsPanel *panel, const EsPanelBand *column = ES_NULL, const EsPanelBand *row = ES_NULL); // Set all the columns/rows to have the same properties. This must be called after the final number of bands has been determined/set!
|
||||
function void EsPanelTableSetChildCells(EsPanel *panel); // Automatically set the child cells for items in a table. This is only necessary if the number of columns/rows is changed after adding items to a table.
|
||||
function void EsPanelTableAddBandDecorator(EsPanel *panel, EsPanelBandDecorator decorator);
|
||||
|
||||
function void EsPanelSwitchTo(EsPanel *panel, EsElement *targetChild, EsTransitionType transitionType, uint32_t flags = ES_FLAGS_DEFAULT, float timeMultiplier = 1); // TODO More customization of transitions?
|
||||
function void EsPanelStartMovementAnimation(EsPanel *panel, float timeMultiplier = 1); // TODO More customization.
|
||||
|
|
|
@ -374,6 +374,7 @@ EsElementRepaintForScroll=372
|
|||
EsMemoryFaultRange=373
|
||||
EsDrawBitmapScaled=374
|
||||
EsRectangleCenter=375
|
||||
EsPanelTableAddBandDecorator=376
|
||||
EsMountPointGetVolumeInformation=377
|
||||
EsListViewInvalidateAll=378
|
||||
EsListViewGetFocusedItem=379
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// - Other operators: remainder, bitwise shifts, bitwise AND/OR/XOR/NOT, ternary.
|
||||
// - Enums, bitsets.
|
||||
// - Named optional arguments with default values.
|
||||
// - Accessing structs and functypes from inline modules.
|
||||
|
||||
// TODO Larger missing features:
|
||||
// - Serialization.
|
||||
|
@ -1680,6 +1681,8 @@ Node *ParseGlobalVariableOrFunctionDefinition(Tokenizer *tokenizer, bool allowGl
|
|||
}
|
||||
|
||||
Node *ParseRootREPL(Tokenizer *tokenizer) {
|
||||
// TODO Importing modules.
|
||||
|
||||
Node *root = (Node *) AllocateFixed(sizeof(Node));
|
||||
root->type = T_ROOT;
|
||||
Node **link = &root->firstChild;
|
||||
|
|
Loading…
Reference in New Issue