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