mirror of https://gitlab.com/nakst/essence
converter sample application
This commit is contained in:
parent
209054f92e
commit
ba4ff01e0f
|
@ -1,8 +1,8 @@
|
|||
# **Essence** — An Operating System
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Support
|
||||
|
||||
|
@ -90,4 +90,4 @@ If you want your project to target Essence, you need to generate the API header
|
|||
|
||||
Currently supported languages are 'c' (also works for C++), 'zig' and 'odin'.
|
||||
|
||||
There is currently no documentation for the API; for examples of how to use the API, consult the standard applications in the `apps/` folder of the source tree. A minimal application is demonstrated in `apps/hello.c` and `apps/hello.ini`. By placing your application's `.ini` file in the `apps/` folder, it will be automatically built by the build system.
|
||||
There is currently no documentation for the API; for examples of how to use the API, consult the standard applications in the `apps/` folder of the source tree. Minimal sample applications are placed in the `apps/samples` folder. By placing your application's `.ini` file in the `apps/` folder, it will be automatically built by the build system.
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
// Include the Essence system header.
|
||||
#include <essence.h>
|
||||
|
||||
// Define the metrics for panelStack.
|
||||
// These values are specified in pixels,
|
||||
// but will be automatically scaled using the UI scaling factor.
|
||||
const EsStyle stylePanelStack = {
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_INSETS
|
||||
| ES_THEME_METRICS_GAP_MAJOR,
|
||||
.insets = ES_RECT_1(20), // Spacing around the contents.
|
||||
.gapMajor = 15, // Spacing between items.
|
||||
},
|
||||
};
|
||||
|
||||
// Define the metrics for panelForm.
|
||||
const EsStyle stylePanelForm = {
|
||||
.metrics = {
|
||||
.mask = ES_THEME_METRICS_GAP_MAJOR
|
||||
| ES_THEME_METRICS_GAP_MINOR,
|
||||
.gapMajor = 5, // Spacing between columns.
|
||||
.gapMinor = 8, // Spacing between rows.
|
||||
},
|
||||
};
|
||||
|
||||
// Global variables.
|
||||
EsTextbox *textboxRate;
|
||||
EsTextbox *textboxAmount;
|
||||
EsTextDisplay *displayResult;
|
||||
|
||||
void ConvertCommand(EsInstance *, EsElement *, EsCommand *) {
|
||||
// Get the conversion rate and amount to convert from the textboxes.
|
||||
double rate = EsTextboxGetContentsAsDouble(textboxRate);
|
||||
double amount = EsTextboxGetContentsAsDouble(textboxAmount);
|
||||
|
||||
// Calculate the result, and format it as a string.
|
||||
char result[64];
|
||||
size_t resultBytes = EsStringFormat(result, sizeof(result), "Result: $%F", rate * amount);
|
||||
|
||||
// Replace the contents of the result textbox.
|
||||
EsTextDisplaySetContents(displayResult, result, resultBytes);
|
||||
}
|
||||
|
||||
void _start() {
|
||||
// We're not using the C standard library,
|
||||
// so we need to initialise global constructors manually.
|
||||
_init();
|
||||
|
||||
while (true) {
|
||||
// Receive a message from the system.
|
||||
EsMessage *message = EsMessageReceive();
|
||||
|
||||
if (message->type == ES_MSG_INSTANCE_CREATE) {
|
||||
// The system wants us to create an instance of our application.
|
||||
// Call EsInstanceCreate with the message and application name.
|
||||
EsInstance *instance = EsInstanceCreate(message, "Converter");
|
||||
|
||||
// Create a layout panel to draw the window background.
|
||||
EsPanel *panelRoot = EsPanelCreate(
|
||||
instance->window, // Make the panel the root element of the window.
|
||||
ES_CELL_FILL // The panel should fill the window.
|
||||
| ES_PANEL_V_SCROLL_AUTO // Automatically show a vertical scroll bar if needed.
|
||||
| ES_PANEL_H_SCROLL_AUTO, // Automatically show a horizontal scroll bar if needed.
|
||||
ES_STYLE_PANEL_WINDOW_BACKGROUND); // Use the window background style.
|
||||
panelRoot->cName = "panelRoot";
|
||||
|
||||
// Create a vertical stack to layout the contents of window.
|
||||
EsPanel *panelStack = EsPanelCreate(
|
||||
panelRoot, // Add it to panelRoot.
|
||||
ES_CELL_H_CENTER // Horizontally center it in panelRoot.
|
||||
| ES_PANEL_STACK // Use the stack layout.
|
||||
| ES_PANEL_VERTICAL, // Layout child elements from top to bottom.
|
||||
&stylePanelStack);
|
||||
|
||||
// Add a second layout panel to panelStack to contain the elements of the form.
|
||||
EsPanel *panelForm = EsPanelCreate(
|
||||
panelStack, // Add it to panelStack.
|
||||
ES_PANEL_TABLE // Use table layout.
|
||||
| ES_PANEL_HORIZONTAL, // Left to right, then top to bottom.
|
||||
&stylePanelForm);
|
||||
|
||||
// Set the number of columns for the panelForm's table layout.
|
||||
EsPanelSetBands(panelForm, 2);
|
||||
|
||||
// Add a text display and textbox for the conversion rate to panelForm.
|
||||
EsTextDisplayCreate(
|
||||
panelForm, // Add it to panelForm. It will go in the first column.
|
||||
ES_CELL_H_RIGHT, // Align it to the right of the column.
|
||||
ES_STYLE_TEXT_LABEL, // Use the text label style.
|
||||
"Amount per dollar:"); // The contents of the text display.
|
||||
textboxRate = EsTextboxCreate(
|
||||
panelForm, // Add it to panelForm. It will go in the second column.
|
||||
ES_CELL_H_LEFT); // Align it to the left of the column.
|
||||
|
||||
// Set the keyboard focus on the rate textbox.
|
||||
EsElementFocus(textboxRate);
|
||||
|
||||
// Add a text display and textbox for the conversion amount to panelForm.
|
||||
EsTextDisplayCreate(panelForm, ES_CELL_H_RIGHT, ES_STYLE_TEXT_LABEL, "Value to convert ($):");
|
||||
textboxAmount = EsTextboxCreate(panelForm, ES_CELL_H_LEFT);
|
||||
|
||||
// We want to add a convert button in the second column of next row.
|
||||
// But the next element we create will go into the first column,
|
||||
// so we create a spacer element first.
|
||||
EsSpacerCreate(panelForm);
|
||||
|
||||
// Create the convert button.
|
||||
EsButton *buttonConvert = EsButtonCreate(
|
||||
panelForm, // Add it to the panelForm. It will go in the second column.
|
||||
ES_CELL_H_LEFT // Align it to the left of the column.
|
||||
| ES_BUTTON_DEFAULT, // Set it as the default button. Pressing Enter will invoke it.
|
||||
0, // Automatically determine the style to use.
|
||||
"Convert"); // The button's label.
|
||||
|
||||
// Set the command callback for the button.
|
||||
// This is called when the button is invoked.
|
||||
// That might be from the user clicking it,
|
||||
// using keyboard input, or an automation API invoking it.
|
||||
EsButtonOnCommand(buttonConvert, ConvertCommand);
|
||||
|
||||
// Add a horizontal line below panelForm.
|
||||
EsSpacerCreate(
|
||||
panelStack, // Add it to panelStack.
|
||||
ES_CELL_H_FILL, // Fill the horizontal width of panelStack.
|
||||
ES_STYLE_SEPARATOR_HORIZONTAL); // Use the horizontal separator style.
|
||||
|
||||
// Add a text display for the conversion result to panelStack.
|
||||
displayResult = EsTextDisplayCreate(panelStack, ES_CELL_H_LEFT, ES_STYLE_TEXT_LABEL,
|
||||
"Press \u201CConvert\u201D to update the result.");
|
||||
|
||||
// Keep receiving messages in a loop,
|
||||
// so the system can handle input messages for the window.
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
[general]
|
||||
name=Converter
|
||||
|
||||
[build]
|
||||
source=apps/converter.cpp
|
|
@ -1629,9 +1629,12 @@ void EsUndoClear(EsUndoManager *manager) {
|
|||
}
|
||||
}
|
||||
|
||||
void EsUndoPush(EsUndoManager *manager, EsUndoCallback callback, const void *item, size_t itemBytes) {
|
||||
void EsUndoPush(EsUndoManager *manager, EsUndoCallback callback, const void *item, size_t itemBytes, bool setAsActiveUndoManager) {
|
||||
EsMessageMutexCheck();
|
||||
EsInstanceSetActiveUndoManager(manager->instance, manager);
|
||||
|
||||
if (setAsActiveUndoManager) {
|
||||
EsInstanceSetActiveUndoManager(manager->instance, manager);
|
||||
}
|
||||
|
||||
Array<uint8_t> *stack = manager->state == UNDO_MANAGER_STATE_UNDOING ? &manager->redoStack : &manager->undoStack;
|
||||
|
||||
|
@ -1651,8 +1654,10 @@ void EsUndoPush(EsUndoManager *manager, EsUndoCallback callback, const void *ite
|
|||
manager->state = UNDO_MANAGER_STATE_NORMAL;
|
||||
}
|
||||
|
||||
EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_UNDO), !manager->undoStack.Length());
|
||||
EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length());
|
||||
if (((APIInstance *) manager->instance->_private)->activeUndoManager == manager) {
|
||||
EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_UNDO), !manager->undoStack.Length());
|
||||
EsCommandSetDisabled(EsCommandByID(manager->instance, ES_COMMAND_REDO), !manager->redoStack.Length());
|
||||
}
|
||||
|
||||
if (manager->instance->undoManager == manager) {
|
||||
InstanceSetModified(manager->instance, true);
|
||||
|
|
|
@ -1268,6 +1268,8 @@ EsRectangle UIGetTransitionEffectRectangle(EsRectangle bounds, EsTransitionType
|
|||
}
|
||||
|
||||
void UIDrawTransitionEffect(EsPainter *painter, EsPaintTarget *sourceSurface, EsRectangle bounds, EsTransitionType type, double progress, bool to) {
|
||||
// TODO Proper blending in the FADE transition.
|
||||
|
||||
if ((type == ES_TRANSITION_FADE_OUT && to) || (type == ES_TRANSITION_FADE_IN && !to)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2278,9 +2280,20 @@ void LayoutStackPrimary(EsPanel *panel, EsMessage *message) {
|
|||
int available = horizontal ? hSpace : vSpace;
|
||||
int perPush = LayoutStackDeterminePerPush(panel, available, horizontal ? vSpace : hSpace);
|
||||
|
||||
int secondary1 = horizontal ? insets.t : insets.l;
|
||||
int secondary2 = horizontal ? bounds.b - insets.b : bounds.r - insets.r;
|
||||
|
||||
int position = horizontal ? (reverse ? insets.r : insets.l) : (reverse ? insets.b : insets.t);
|
||||
bool anyNonHiddenChildren = false;
|
||||
|
||||
if (message->type == ES_MSG_LAYOUT) {
|
||||
if (!horizontal && panel->scroll.enabled[0]) {
|
||||
secondary2 += panel->scroll.limit[0];
|
||||
} else if (horizontal && panel->scroll.enabled[1]) {
|
||||
secondary2 += panel->scroll.limit[1];
|
||||
}
|
||||
}
|
||||
|
||||
for (uintptr_t i = 0; i < childCount; i++) {
|
||||
EsElement *child = panel->GetChild(i);
|
||||
if (child->flags & (ES_ELEMENT_HIDDEN | ES_ELEMENT_NON_CLIENT)) continue;
|
||||
|
@ -2291,7 +2304,7 @@ void LayoutStackPrimary(EsPanel *panel, EsMessage *message) {
|
|||
int width = (child->flags & ES_CELL_H_PUSH) ? perPush : child->GetWidth(vSpace);
|
||||
|
||||
if (reverse) {
|
||||
relative = ES_RECT_4(bounds.r - position - width, bounds.r - position, insets.t, bounds.b - insets.b);
|
||||
relative = ES_RECT_4(bounds.r - position - width, bounds.r - position, secondary1, secondary2);
|
||||
} else {
|
||||
relative = ES_RECT_4(position, position + width, insets.t, bounds.b - insets.b);
|
||||
}
|
||||
|
@ -2301,9 +2314,9 @@ void LayoutStackPrimary(EsPanel *panel, EsMessage *message) {
|
|||
int height = (child->flags & ES_CELL_V_PUSH) ? perPush : child->GetHeight(hSpace);
|
||||
|
||||
if (reverse) {
|
||||
relative = ES_RECT_4(insets.l, bounds.r - insets.r, bounds.b - position - height, bounds.b - position);
|
||||
relative = ES_RECT_4(secondary1, secondary2, bounds.b - position - height, bounds.b - position);
|
||||
} else {
|
||||
relative = ES_RECT_4(insets.l, bounds.r - insets.r, position, position + height);
|
||||
relative = ES_RECT_4(secondary1, secondary2, position, position + height);
|
||||
}
|
||||
|
||||
position += height + gap;
|
||||
|
@ -3392,7 +3405,7 @@ void EsElementSetCellRange(EsElement *element, int xFrom, int yFrom, int xTo, in
|
|||
element->tableCell = cell;
|
||||
}
|
||||
|
||||
void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount, EsPanelBand *columns, EsPanelBand *rows) {
|
||||
void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount, const EsPanelBand *columns, const EsPanelBand *rows) {
|
||||
EsMessageMutexCheck();
|
||||
EsAssert(panel->flags & ES_PANEL_TABLE); // Cannot set the bands layout for a non-table panel.
|
||||
EsHeapFree(panel->bands[0]);
|
||||
|
@ -3407,11 +3420,11 @@ void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount, EsPane
|
|||
if (rows && panel->bands[1]) EsMemoryCopy(panel->bands[1], rows, rowCount * sizeof(EsPanelBand));
|
||||
}
|
||||
|
||||
void EsPanelSetBandsAll(EsPanel *panel, EsPanelBand *column, EsPanelBand *row) {
|
||||
void EsPanelSetBandsAll(EsPanel *panel, const EsPanelBand *column, const EsPanelBand *row) {
|
||||
EsMessageMutexCheck();
|
||||
EsAssert(panel->flags & ES_PANEL_TABLE); // Cannot set the bands layout for a non-table panel.
|
||||
|
||||
EsPanelBand *templates[2] = { column, row };
|
||||
const EsPanelBand *templates[2] = { column, row };
|
||||
|
||||
for (uintptr_t axis = 0; axis < 2; axis++) {
|
||||
if (!templates[axis]) continue;
|
||||
|
@ -3884,7 +3897,7 @@ EsButton *EsButtonCreate(EsElement *parent, uint64_t flags, const EsStyle *style
|
|||
}
|
||||
|
||||
EsButtonSetCheck(button, (EsCheckState) (flags & 3), false);
|
||||
|
||||
button->MaybeRefreshStyle();
|
||||
return button;
|
||||
}
|
||||
|
||||
|
|
|
@ -2291,7 +2291,7 @@ function void EsUndoEndGroup(EsUndoManager *manager);
|
|||
function void EsUndoInvokeGroup(EsUndoManager *manager, bool redo);
|
||||
function bool EsUndoPeek(EsUndoManager *manager, EsUndoCallback *callback, const void **item);
|
||||
function void EsUndoPop(EsUndoManager *manager);
|
||||
function void EsUndoPush(EsUndoManager *manager, EsUndoCallback callback, const void *item, size_t itemBytes);
|
||||
function void EsUndoPush(EsUndoManager *manager, EsUndoCallback callback, const void *item, size_t itemBytes, bool setAsActiveUndoManager = true);
|
||||
function bool EsUndoInUndo(EsUndoManager *manager);
|
||||
function bool EsUndoIsEmpty(EsUndoManager *manager, bool redo);
|
||||
function ES_INSTANCE_TYPE *EsUndoGetInstance(EsUndoManager *manager);
|
||||
|
@ -2440,8 +2440,8 @@ function EsElement *EsSpacerCreate(EsElement *parent, uint64_t flags = ES_FLAGS_
|
|||
function EsSplitter *EsSplitterCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL);
|
||||
function EsCanvasPane *EsCanvasPaneCreate(EsElement *parent, uint64_t flags = ES_FLAGS_DEFAULT, const EsStyle *style = ES_NULL);
|
||||
|
||||
function void EsPanelSetBands(EsPanel *panel, size_t columnCount, size_t rowCount = 0, EsPanelBand *columns = ES_NULL, EsPanelBand *rows = ES_NULL);
|
||||
function void EsPanelSetBandsAll(EsPanel *panel, EsPanelBand *column = ES_NULL, 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 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 EsPanelSwitchTo(EsPanel *panel, EsElement *targetChild, EsTransitionType transitionType, uint32_t flags = ES_FLAGS_DEFAULT, float timeMultiplier = 1); // TODO More customization of transitions?
|
||||
|
|
|
@ -3960,7 +3960,7 @@ void EsTextboxInsert(EsTextbox *textbox, const char *string, ptrdiff_t stringByt
|
|||
}
|
||||
|
||||
undoItem->textbox = textbox;
|
||||
EsUndoPush(textbox->undo, TextboxUndoItemCallback, undoItem, undoItemBytes);
|
||||
EsUndoPush(textbox->undo, TextboxUndoItemCallback, undoItem, undoItemBytes, false /* do not set instance's undo manager */);
|
||||
}
|
||||
|
||||
EsHeapFree(undoItem);
|
||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue