From 676162a438c85d06ecf84e4fefe5ef00448e5280 Mon Sep 17 00:00:00 2001
From: nakst <>
Date: Sun, 22 Aug 2021 18:52:11 +0100
Subject: [PATCH] left align access key hints on checkboxs

---
 desktop/gui.cpp         | 38 ++++++++++++++++++++++++--------------
 desktop/list_view.cpp   |  4 +++-
 desktop/os.header       |  1 -
 desktop/syscall.cpp     |  1 -
 util/header_generator.c | 10 ++++++++--
 5 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/desktop/gui.cpp b/desktop/gui.cpp
index 591e9d1..ccec009 100644
--- a/desktop/gui.cpp
+++ b/desktop/gui.cpp
@@ -83,6 +83,7 @@ void UIMaybeRemoveFocusedElement(EsWindow *window);
 EsTextStyle TextPlanGetPrimaryStyle(EsTextPlan *plan);
 EsElement *UIFindHoverElementRecursively(EsElement *element, int offsetX, int offsetY, EsPoint position);
 const EsStyle *UIGetDefaultStyleVariant(const EsStyle *style, EsElement *parent);
+void AccessKeysCenterHint(EsElement *element, EsMessage *message);
 
 void InspectorSetup(EsWindow *window);
 void InspectorNotifyElementEvent(EsElement *element, const char *cCategory, const char *cFormat, ...);
@@ -3695,6 +3696,11 @@ int ProcessButtonMessage(EsElement *element, EsMessage *message) {
 		} else {
 			button->MaybeRefreshStyle();
 		}
+	} else if (message->type == ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS && (button->flags & (ES_BUTTON_RADIOBOX | ES_BUTTON_CHECKBOX))) {
+		EsRectangle bounds = element->GetWindowBounds();
+		int width = Width(*message->accessKeyHintBounds), height = Height(*message->accessKeyHintBounds);
+		int x = bounds.l - 3 * width / 4, y = (bounds.t + bounds.b) / 2 - height / 4;
+		*message->accessKeyHintBounds = ES_RECT_4(x - width / 2, x + width / 2, y - height / 4, y + 3 * height / 4);
 	} else if (message->type == ES_MSG_RADIO_GROUP_UPDATED && (button->flags & ES_BUTTON_RADIOBOX)) {
 		EsButtonSetCheck(button, ES_CHECK_UNCHECKED);
 	} else if (message->type == ES_MSG_FOCUSED_START) {
@@ -4591,6 +4597,8 @@ int ProcessSplitBarMessage(EsElement *element, EsMessage *message) {
 		} else {
 			return 0;
 		}
+	} else if (message->type == ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS) {
+		AccessKeysCenterHint(element, message);
 	} else {
 		return 0;
 	}
@@ -4765,7 +4773,7 @@ int ProcessSplitterMessage(EsElement *element, EsMessage *message) {
 		splitter->addingSplitBar = true;
 		SplitBar *bar = (SplitBar *) EsHeapAllocate(sizeof(SplitBar), true);
 
-		bar->Initialise(splitter, ES_ELEMENT_FOCUSABLE | ES_ELEMENT_NOT_TAB_TRAVERSABLE | ES_ELEMENT_CENTER_ACCESS_KEY_HINT | ES_CELL_EXPAND, 
+		bar->Initialise(splitter, ES_ELEMENT_FOCUSABLE | ES_ELEMENT_NOT_TAB_TRAVERSABLE | ES_CELL_EXPAND, 
 				ProcessSplitBarMessage, splitter->horizontal ? ES_STYLE_SPLIT_BAR_VERTICAL : ES_STYLE_SPLIT_BAR_HORIZONTAL);
 
 		bar->cName = "split bar";
@@ -5863,6 +5871,14 @@ void UIInitialiseKeyboardShortcutNamesTable() {
 	ADD_KEYBOARD_SHORTCUT_NAME(ES_SCANCODE_PERIOD, ".");
 }
 
+void AccessKeysCenterHint(EsElement *element, EsMessage *message) {
+	EsRectangle bounds = element->GetWindowBounds();
+	UIStyle *style = gui.accessKeys.hintStyle;
+	int x = (bounds.l + bounds.r) / 2, y = (bounds.t + bounds.b) / 2 - style->preferredHeight / 4;
+	*message->accessKeyHintBounds = ES_RECT_4(x - style->preferredWidth / 2, x + style->preferredWidth / 2, 
+			y - style->preferredHeight / 4, y + 3 * style->preferredHeight / 4);
+}
+
 void AccessKeysGather(EsElement *element) {
 	if (element->flags & ES_ELEMENT_BLOCK_FOCUS) return;
 	if (element->state & UI_STATE_BLOCK_INTERACTION) return;
@@ -5876,8 +5892,6 @@ void AccessKeysGather(EsElement *element) {
 	if (element->state & UI_STATE_DESTROYING) return;
 	if (element->flags & ES_ELEMENT_DISABLED) return;
 
-	EsRectangle bounds = element->GetWindowBounds();
-
 	AccessKeyEntry entry = {};
 	entry.character = element->accessKey;
 	entry.number = gui.accessKeys.numbers[entry.character - 'A'];
@@ -5885,21 +5899,17 @@ void AccessKeysGather(EsElement *element) {
 
 	if (entry.number >= 10) return;
 
+	EsRectangle bounds = element->GetWindowBounds();
 	UIStyle *style = gui.accessKeys.hintStyle;
-
-	int x, y;
-
-	if (element->flags & ES_ELEMENT_CENTER_ACCESS_KEY_HINT) {
-		x = (bounds.l + bounds.r) / 2;
-		y = (bounds.t + bounds.b) / 2 - style->preferredHeight / 4;
-	} else {
-		x = (bounds.l + bounds.r) / 2;
-		y = bounds.b;
-	}
-
+	int x = (bounds.l + bounds.r) / 2, y = bounds.b;
 	EsRectangle hintBounds = ES_RECT_4(x - style->preferredWidth / 2, x + style->preferredWidth / 2, 
 			y - style->preferredHeight / 4, y + 3 * style->preferredHeight / 4);
 
+	EsMessage m = {};
+	m.type = ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS;
+	m.accessKeyHintBounds = &hintBounds;
+	EsMessageSend(element, &m);
+
 	if (hintBounds.r > (int32_t) gui.accessKeys.window->windowWidth) {
 		hintBounds.l = gui.accessKeys.window->windowWidth - style->preferredWidth;
 		hintBounds.r = hintBounds.l + style->preferredWidth;
diff --git a/desktop/list_view.cpp b/desktop/list_view.cpp
index 96e1cde..3ef96c1 100644
--- a/desktop/list_view.cpp
+++ b/desktop/list_view.cpp
@@ -1801,6 +1801,8 @@ struct EsListView : EsElement {
 			}
 		} else if (message->type == ES_MSG_AFTER_Z_ORDER) {
 			zOrderItems.Free();
+		} else if (message->type == ES_MSG_GET_ACCESS_KEY_HINT_BOUNDS) {
+			AccessKeysCenterHint(this, message);
 		} else if (message->type == ES_MSG_LIST_VIEW_GET_CONTENT && (flags & ES_LIST_VIEW_FIXED_ITEMS)) {
 			uintptr_t index = message->getContent.index;
 			EsAssert(index < fixedItems.Length());
@@ -1939,7 +1941,7 @@ EsListView *EsListViewCreate(EsElement *parent, uint64_t flags, const EsStyle *s
 	view->primaryCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_PRIMARY_CELL, 0), false);
 	view->secondaryCellStyle = GetStyle(MakeStyleKey(ES_STYLE_LIST_SECONDARY_CELL, 0), false);
 
-	view->Initialise(parent, flags | ES_ELEMENT_FOCUSABLE | ES_ELEMENT_CENTER_ACCESS_KEY_HINT, ListViewProcessMessage, style ?: ES_STYLE_LIST_VIEW);
+	view->Initialise(parent, flags | ES_ELEMENT_FOCUSABLE, ListViewProcessMessage, style ?: ES_STYLE_LIST_VIEW);
 	view->cName = "list view";
 
 	view->fixedItemSelection = -1;
diff --git a/desktop/os.header b/desktop/os.header
index 01dc434..d4d5fb1 100644
--- a/desktop/os.header
+++ b/desktop/os.header
@@ -436,7 +436,6 @@ define ES_ELEMENT_NO_HOVER_DESCENDENTS		((_EsLongConstant) (1) << 38) // Prevent
 define ES_ELEMENT_BLOCK_FOCUS			((_EsLongConstant) (1) << 39) // This element and descendents cannot take focus.
 define ES_ELEMENT_NOT_TAB_TRAVERSABLE		((_EsLongConstant) (1) << 40) // Use with ES_ELEMENT_FOCUSABLE to indicate the element cannot be focused from tab traversal.
 define ES_ELEMENT_NO_FOCUS_ON_CLICK		((_EsLongConstant) (1) << 41) // Use with ES_ELEMENT_FOCUSABLE to indicate the element cannot be focused by clicking it.
-define ES_ELEMENT_CENTER_ACCESS_KEY_HINT 	((_EsLongConstant) (1) << 42)
 define ES_ELEMENT_LAYOUT_HINT_HORIZONTAL	((_EsLongConstant) (1) << 43) // Hint for autoCorners and autoBorders.
 define ES_ELEMENT_LAYOUT_HINT_REVERSE		((_EsLongConstant) (1) << 44) // Hint for autoCorners and autoBorders; and tab traversal.
 define ES_ELEMENT_STICKY_ACCESS_KEY		((_EsLongConstant) (1) << 45) // Don't exit access key mode after using the access key.
diff --git a/desktop/syscall.cpp b/desktop/syscall.cpp
index 236314e..cd5932b 100644
--- a/desktop/syscall.cpp
+++ b/desktop/syscall.cpp
@@ -638,7 +638,6 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe);
 
 void MessageDesktop(void *message, size_t messageBytes, EsHandle embeddedWindow = ES_INVALID_HANDLE, EsBuffer *responseBuffer = nullptr) {
 	if (api.startupInformation->isDesktop) {
-		// HACK This assumes the response from DesktopMessage2 will not exceed the size of the pipe's buffer.
 		EsMessage m = {};
 		m.type = ES_MSG_DESKTOP;
 		m.desktop.windowID = embeddedWindow ? EsSyscall(ES_SYSCALL_WINDOW_GET_ID, embeddedWindow, 0, 0, 0) : 0;
diff --git a/util/header_generator.c b/util/header_generator.c
index 4d6e363..996d901 100644
--- a/util/header_generator.c
+++ b/util/header_generator.c
@@ -732,7 +732,7 @@ void OutputOdinVariable(Entry *entry, bool expandStrings, const char *nameSuffix
 			FilePrintFormat(output, "%s%s : string", entry->name, nameSuffix);
 		}
 	} else {
-		FilePrintFormat(output, "%s%s : ", entry->name, nameSuffix);
+		FilePrintFormat(output, "%s%s : ", 0 == strcmp(entry->name, "in") ? "In" : entry->name, nameSuffix);
 		OutputOdinType(entry);
 	}
 }
@@ -878,7 +878,13 @@ void OutputOdin(Entry *root) {
 		Entry *entry = root->children + i;
 
 		if (entry->type == ENTRY_DEFINE) {
-			FilePrintFormat(output, "%s :: %s;\n", TrimPrefix(entry->name), OdinReplaceTypes(entry->define.value, false));
+			const char *styleCast = strstr(entry->define.value, "STYLE_CAST(");
+
+			if (styleCast) {
+				FilePrintFormat(output, "%s :: (^Style)(uintptr(%d));\n", TrimPrefix(entry->name), atoi(styleCast + 11));
+			} else {
+				FilePrintFormat(output, "%s :: %s;\n", TrimPrefix(entry->name), OdinReplaceTypes(entry->define.value, false));
+			}
 		} else if (entry->type == ENTRY_STRUCT) {
 			FilePrintFormat(output, "%s :: struct {\n", TrimPrefix(entry->name));
 			OutputOdinRecord(entry, 0);