mirror of https://gitlab.com/nakst/essence
				
				
				
			introduce updateActions to UI; bugfixes
This commit is contained in:
		
							parent
							
								
									91a1727974
								
							
						
					
					
						commit
						d913de89ac
					
				|  | @ -954,7 +954,7 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		EsMenuShow(menu); | 		EsMenuShow(menu); | ||||||
| 	} else if (message->type == ES_MSG_MOUSE_MIDDLE_UP && ((element->state & UI_STATE_HOVERED) || (tab->closeButton->state & UI_STATE_HOVERED))) { | 	} else if (message->type == ES_MSG_MOUSE_MIDDLE_UP && element->window->hovered == element) { | ||||||
| 		if (EsButtonGetCheck(tab->closeButton) == ES_CHECK_CHECKED) { | 		if (EsButtonGetCheck(tab->closeButton) == ES_CHECK_CHECKED) { | ||||||
| 			// The tab contains a modified document, so it will probably popup a dialog after it receives the close request.
 | 			// The tab contains a modified document, so it will probably popup a dialog after it receives the close request.
 | ||||||
| 			// Therefore, we should switch to that tab.
 | 			// Therefore, we should switch to that tab.
 | ||||||
|  | @ -974,7 +974,7 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { | ||||||
| WindowTab *WindowTabCreate(ContainerWindow *container) { | WindowTab *WindowTabCreate(ContainerWindow *container) { | ||||||
| 	WindowTab *tab = (WindowTab *) EsHeapAllocate(sizeof(WindowTab), true); | 	WindowTab *tab = (WindowTab *) EsHeapAllocate(sizeof(WindowTab), true); | ||||||
| 	tab->container = container; | 	tab->container = container; | ||||||
| 	tab->Initialise(container->tabBand, ES_CELL_H_SHRINK | ES_CELL_V_BOTTOM, WindowTabMessage, nullptr); | 	tab->Initialise(container->tabBand, ES_CELL_H_FILL | ES_CELL_V_BOTTOM, WindowTabMessage, nullptr); | ||||||
| 	tab->cName = "window tab"; | 	tab->cName = "window tab"; | ||||||
| 	container->openTabs.Add(tab); | 	container->openTabs.Add(tab); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										181
									
								
								desktop/gui.cpp
								
								
								
								
							
							
						
						
									
										181
									
								
								desktop/gui.cpp
								
								
								
								
							|  | @ -107,6 +107,8 @@ EsElement *UIFindHoverElementRecursively(EsElement *element, int offsetX, int of | ||||||
| const EsStyle *UIGetDefaultStyleVariant(const EsStyle *style, EsElement *parent); | const EsStyle *UIGetDefaultStyleVariant(const EsStyle *style, EsElement *parent); | ||||||
| void AccessKeysCenterHint(EsElement *element, EsMessage *message); | void AccessKeysCenterHint(EsElement *element, EsMessage *message); | ||||||
| void UIRemoveFocusFromElement(EsElement *oldFocus); | void UIRemoveFocusFromElement(EsElement *oldFocus); | ||||||
|  | void UIQueueEnsureVisibleMessage(EsElement *element); | ||||||
|  | void ColorPickerCreate(EsElement *parent, struct ColorPickerHost host, uint32_t initialColor, bool showTextbox); | ||||||
| 
 | 
 | ||||||
| void InspectorSetup(EsWindow *window); | void InspectorSetup(EsWindow *window); | ||||||
| void InspectorNotifyElementEvent(EsElement *element, const char *cCategory, const char *cFormat, ...); | void InspectorNotifyElementEvent(EsElement *element, const char *cCategory, const char *cFormat, ...); | ||||||
|  | @ -116,31 +118,36 @@ void InspectorNotifyElementMoved(EsElement *element, EsRectangle takenBounds); | ||||||
| void InspectorNotifyElementPainted(EsElement *element, EsPainter *painter); | void InspectorNotifyElementPainted(EsElement *element, EsPainter *painter); | ||||||
| void InspectorNotifyElementContentChanged(EsElement *element); | void InspectorNotifyElementContentChanged(EsElement *element); | ||||||
| 
 | 
 | ||||||
| #define UI_STATE_RELAYOUT 		(1 <<  2) | // Updating:
 | ||||||
| #define UI_STATE_RELAYOUT_CHILD		(1 <<  3) | #define UI_STATE_RELAYOUT 		(1 <<  0) | ||||||
| #define UI_STATE_DESTROYING		(1 <<  4) | #define UI_STATE_RELAYOUT_CHILD		(1 <<  1) | ||||||
| #define UI_STATE_DESTROYING_CHILD	(1 <<  5) | #define UI_STATE_DESTROYING		(1 <<  2) | ||||||
|  | #define UI_STATE_DESTROYING_CHILD	(1 <<  3) | ||||||
| 
 | 
 | ||||||
| #define UI_STATE_HOVERED		(1 <<  6) | // Interaction state:
 | ||||||
| #define UI_STATE_LEFT_PRESSED		(1 <<  7) | #define UI_STATE_FOCUS_WITHIN		(1 <<  4) | ||||||
| #define UI_STATE_STRONG_PRESSED		(1 <<  8) | #define UI_STATE_FOCUSED		(1 <<  5) | ||||||
| #define UI_STATE_FOCUS_WITHIN		(1 <<  9) | #define UI_STATE_LOST_STRONG_FOCUS	(1 <<  6) | ||||||
| #define UI_STATE_FOCUSED		(1 << 10) | #define UI_STATE_ENTERED		(1 <<  7) | ||||||
| #define UI_STATE_LOST_STRONG_FOCUS	(1 << 11) |  | ||||||
| #define UI_STATE_MENU_SOURCE		(1 << 12) |  | ||||||
| 
 | 
 | ||||||
| #define UI_STATE_ANIMATING		(1 << 13) | // Presence on arrays:
 | ||||||
| #define UI_STATE_ENTERED		(1 << 14) | #define UI_STATE_ANIMATING		(1 <<  8) | ||||||
| #define UI_STATE_BLOCK_INTERACTION	(1 << 16) | #define UI_STATE_CHECK_VISIBLE		(1 <<  9) | ||||||
|  | #define UI_STATE_QUEUED_ENSURE_VISIBLE	(1 << 10) | ||||||
| 
 | 
 | ||||||
| #define UI_STATE_TEMP			(1 << 17) | // Behaviour modifiers:
 | ||||||
| #define UI_STATE_Z_STACK		(1 << 18) | #define UI_STATE_STRONG_PRESSED		(1 << 11) | ||||||
| #define UI_STATE_COMMAND_BUTTON		(1 << 19) | #define UI_STATE_Z_STACK		(1 << 12) | ||||||
|  | #define UI_STATE_COMMAND_BUTTON		(1 << 13) | ||||||
|  | #define UI_STATE_BLOCK_INTERACTION	(1 << 14) | ||||||
|  | #define UI_STATE_RADIO_GROUP		(1 << 15) | ||||||
|  | 
 | ||||||
|  | // Miscellaneous state bits:
 | ||||||
|  | #define UI_STATE_TEMP			(1 << 16) | ||||||
|  | #define UI_STATE_MENU_SOURCE		(1 << 17) | ||||||
|  | #define UI_STATE_MENU_EXITING           (1 << 18) | ||||||
|  | #define UI_STATE_INSPECTING		(1 << 19) | ||||||
| #define UI_STATE_USE_MEASUREMENT_CACHE	(1 << 20) | #define UI_STATE_USE_MEASUREMENT_CACHE	(1 << 20) | ||||||
| #define UI_STATE_CHECK_VISIBLE		(1 << 21) |  | ||||||
| #define UI_STATE_INSPECTING		(1 << 22) |  | ||||||
| #define UI_STATE_RADIO_GROUP		(1 << 23) |  | ||||||
| #define UI_STATE_MENU_EXITING           (1 << 24) |  | ||||||
| 
 | 
 | ||||||
| struct EsElement : EsElementPublic { | struct EsElement : EsElementPublic { | ||||||
| 	EsUICallback messageClass; | 	EsUICallback messageClass; | ||||||
|  | @ -334,7 +341,7 @@ struct EsImageDisplay : EsElement { | ||||||
| 
 | 
 | ||||||
| struct ScrollPane { | struct ScrollPane { | ||||||
| 	EsElement *parent, *pad; | 	EsElement *parent, *pad; | ||||||
| 	EsScrollbar *bar[2]; | 	struct Scrollbar *bar[2]; | ||||||
| 	double position[2]; | 	double position[2]; | ||||||
| 	int64_t limit[2]; | 	int64_t limit[2]; | ||||||
| 	int32_t fixedViewport[2]; | 	int32_t fixedViewport[2]; | ||||||
|  | @ -430,8 +437,6 @@ struct ColorPickerHost { | ||||||
| 	bool hasOpacity; | 	bool hasOpacity; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void ColorPickerCreate(EsElement *parent, ColorPickerHost host, uint32_t initialColor, bool showTextbox); |  | ||||||
| 
 |  | ||||||
| void HeapDuplicate(void **pointer, size_t *outBytes, const void *data, size_t bytes) { | void HeapDuplicate(void **pointer, size_t *outBytes, const void *data, size_t bytes) { | ||||||
| 	if (*pointer) { | 	if (*pointer) { | ||||||
| 		EsHeapFree(*pointer); | 		EsHeapFree(*pointer); | ||||||
|  | @ -481,8 +486,7 @@ struct EsWindow : EsElement { | ||||||
| 		  *pressed,  | 		  *pressed,  | ||||||
| 		  *focused, | 		  *focused, | ||||||
| 		  *inactiveFocus, | 		  *inactiveFocus, | ||||||
| 		  *dragged, | 		  *dragged; | ||||||
| 		  *ensureVisible; |  | ||||||
| 
 | 
 | ||||||
| 	EsButton *enterButton,  | 	EsButton *enterButton,  | ||||||
| 		 *escapeButton,  | 		 *escapeButton,  | ||||||
|  | @ -502,6 +506,7 @@ struct EsWindow : EsElement { | ||||||
| 	EsRectangle updateRegionInProgress; // For visualizePaintSteps.
 | 	EsRectangle updateRegionInProgress; // For visualizePaintSteps.
 | ||||||
| 
 | 
 | ||||||
| 	Array<struct SizeAlternative> sizeAlternatives; | 	Array<struct SizeAlternative> sizeAlternatives; | ||||||
|  | 	Array<struct UpdateAction> updateActions; | ||||||
| 
 | 
 | ||||||
| 	EsElement *source; // Menu source.
 | 	EsElement *source; // Menu source.
 | ||||||
| 	EsWindow *targetMenu; // The menu that keyboard events should be sent to.
 | 	EsWindow *targetMenu; // The menu that keyboard events should be sent to.
 | ||||||
|  | @ -510,6 +515,12 @@ struct EsWindow : EsElement { | ||||||
| 	double announcementTimeMs; | 	double announcementTimeMs; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct UpdateAction { | ||||||
|  | 	EsElement *element; | ||||||
|  | 	EsGeneric context; | ||||||
|  | 	void (*callback)(EsElement *, EsGeneric); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct SizeAlternative { | struct SizeAlternative { | ||||||
| 	EsElement *small, *big; | 	EsElement *small, *big; | ||||||
| 	int widthThreshold, heightThreshold; | 	int widthThreshold, heightThreshold; | ||||||
|  | @ -789,6 +800,7 @@ void UIWindowDestroy(EsWindow *window) { | ||||||
| 	EsHandleClose(window->handle); | 	EsHandleClose(window->handle); | ||||||
| 	window->checkVisible.Free(); | 	window->checkVisible.Free(); | ||||||
| 	window->sizeAlternatives.Free(); | 	window->sizeAlternatives.Free(); | ||||||
|  | 	window->updateActions.Free(); | ||||||
| 	window->dialogs.Free(); | 	window->dialogs.Free(); | ||||||
| 	window->handle = ES_INVALID_HANDLE; | 	window->handle = ES_INVALID_HANDLE; | ||||||
| } | } | ||||||
|  | @ -910,9 +922,9 @@ EsWindow *EsWindowCreate(EsInstance *instance, EsWindowStyle style) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	window->id = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, window->handle, 0, 0, 0); | 	window->id = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, window->handle, 0, 0, 0); | ||||||
|  | 	window->window = window; | ||||||
| 	window->Initialise(nullptr, ES_CELL_FILL, ProcessRootMessage, nullptr); | 	window->Initialise(nullptr, ES_CELL_FILL, ProcessRootMessage, nullptr); | ||||||
| 	window->cName = "window"; | 	window->cName = "window"; | ||||||
| 	window->window = window; |  | ||||||
| 	window->width = window->windowWidth, window->height = window->windowHeight; | 	window->width = window->windowWidth, window->height = window->windowHeight; | ||||||
| 	window->hovered = window; | 	window->hovered = window; | ||||||
| 	window->hovering = true; | 	window->hovering = true; | ||||||
|  | @ -1741,13 +1753,14 @@ bool EsElement::RefreshStyleState() { | ||||||
| 
 | 
 | ||||||
| 	if (flags & ES_ELEMENT_DISABLED) { | 	if (flags & ES_ELEMENT_DISABLED) { | ||||||
| 		styleStateFlags |= THEME_PRIMARY_STATE_DISABLED; | 		styleStateFlags |= THEME_PRIMARY_STATE_DISABLED; | ||||||
| 	} else if (window && !window->activated && !window->appearActivated) { | 	} else if (!window->activated && !window->appearActivated) { | ||||||
| 		styleStateFlags |= THEME_PRIMARY_STATE_INACTIVE; | 		styleStateFlags |= THEME_PRIMARY_STATE_INACTIVE; | ||||||
| 	} else { | 	} else { | ||||||
| 		if (((state & UI_STATE_LEFT_PRESSED) && ((state & UI_STATE_HOVERED) || gui.draggingStarted || (state & UI_STATE_STRONG_PRESSED)))  | 		if (((window->pressed == this && gui.lastClickButton == ES_MSG_MOUSE_LEFT_DOWN)  | ||||||
|  | 					&& (window->hovered == this || gui.draggingStarted || (state & UI_STATE_STRONG_PRESSED)))  | ||||||
| 				|| (state & UI_STATE_MENU_SOURCE)) { | 				|| (state & UI_STATE_MENU_SOURCE)) { | ||||||
| 			styleStateFlags |= THEME_PRIMARY_STATE_PRESSED; | 			styleStateFlags |= THEME_PRIMARY_STATE_PRESSED; | ||||||
| 		} else if (((state & UI_STATE_HOVERED) && !window->pressed && api.global->enableHoverState) || (window && window->pressed == this)) { | 		} else if ((window->hovered == this && !window->pressed && api.global->enableHoverState) || window->pressed == this) { | ||||||
| 			styleStateFlags |= THEME_PRIMARY_STATE_HOVERED; | 			styleStateFlags |= THEME_PRIMARY_STATE_HOVERED; | ||||||
| 		} else { | 		} else { | ||||||
| 			styleStateFlags |= THEME_PRIMARY_STATE_IDLE; | 			styleStateFlags |= THEME_PRIMARY_STATE_IDLE; | ||||||
|  | @ -2550,7 +2563,7 @@ void EsElementUpdateContentSize(EsElement *element, uint32_t flags) { | ||||||
| 
 | 
 | ||||||
| // #define ENABLE_SMOOTH_SCROLLING
 | // #define ENABLE_SMOOTH_SCROLLING
 | ||||||
| 
 | 
 | ||||||
| struct EsScrollbar : EsElement { | struct Scrollbar : EsElement { | ||||||
| 	EsButton *up, *down; | 	EsButton *up, *down; | ||||||
| 	EsElement *thumb; | 	EsElement *thumb; | ||||||
| 	double position, autoScrollSpeed, smoothScrollTarget; | 	double position, autoScrollSpeed, smoothScrollTarget; | ||||||
|  | @ -2558,7 +2571,7 @@ struct EsScrollbar : EsElement { | ||||||
| 	bool horizontal; | 	bool horizontal; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void ScrollbarLayout(EsScrollbar *scrollbar) { | void ScrollbarLayout(Scrollbar *scrollbar) { | ||||||
| 	if (scrollbar->viewportSize >= scrollbar->contentSize || scrollbar->viewportSize <= 0 || scrollbar->contentSize <= 0) { | 	if (scrollbar->viewportSize >= scrollbar->contentSize || scrollbar->viewportSize <= 0 || scrollbar->contentSize <= 0) { | ||||||
| 		EsElementSetDisabled(scrollbar, true); | 		EsElementSetDisabled(scrollbar, true); | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -2607,7 +2620,7 @@ void ScrollbarLayout(EsScrollbar *scrollbar) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ScrollbarSetMeasurements(EsScrollbar *scrollbar, int viewportSize, int contentSize) { | void ScrollbarSetMeasurements(Scrollbar *scrollbar, int viewportSize, int contentSize) { | ||||||
| 	EsMessageMutexCheck(); | 	EsMessageMutexCheck(); | ||||||
| 
 | 
 | ||||||
| 	if (scrollbar->viewportSize == viewportSize && scrollbar->contentSize == contentSize) { | 	if (scrollbar->viewportSize == viewportSize && scrollbar->contentSize == contentSize) { | ||||||
|  | @ -2620,7 +2633,7 @@ void ScrollbarSetMeasurements(EsScrollbar *scrollbar, int viewportSize, int cont | ||||||
| 	ScrollbarLayout(scrollbar); | 	ScrollbarLayout(scrollbar); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void ScrollbarSetPosition(EsScrollbar *scrollbar, double position, bool sendMovedMessage, bool smoothScroll) { | void ScrollbarSetPosition(Scrollbar *scrollbar, double position, bool sendMovedMessage, bool smoothScroll) { | ||||||
| 	EsMessageMutexCheck(); | 	EsMessageMutexCheck(); | ||||||
| 
 | 
 | ||||||
| 	if (position > scrollbar->contentSize - scrollbar->viewportSize) position = scrollbar->contentSize - scrollbar->viewportSize; | 	if (position > scrollbar->contentSize - scrollbar->viewportSize) position = scrollbar->contentSize - scrollbar->viewportSize; | ||||||
|  | @ -2648,8 +2661,8 @@ void ScrollbarSetPosition(EsScrollbar *scrollbar, double position, bool sendMove | ||||||
| 
 | 
 | ||||||
| 	if (sendMovedMessage && scrollbar->oldPosition != (int) scrollbar->position) { | 	if (sendMovedMessage && scrollbar->oldPosition != (int) scrollbar->position) { | ||||||
| 		EsMessage m = { ES_MSG_SCROLLBAR_MOVED }; | 		EsMessage m = { ES_MSG_SCROLLBAR_MOVED }; | ||||||
| 		m.scrollbarMoved.scroll = (int) position; | 		m.scroll.scroll = (int) position; | ||||||
| 		m.scrollbarMoved.previous = previous; | 		m.scroll.previous = previous; | ||||||
| 		EsMessageSend(scrollbar, &m); | 		EsMessageSend(scrollbar, &m); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -2662,7 +2675,7 @@ void ScrollbarSetPosition(EsScrollbar *scrollbar, double position, bool sendMove | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int ProcessScrollbarButtonMessage(EsElement *element, EsMessage *message) { | int ProcessScrollbarButtonMessage(EsElement *element, EsMessage *message) { | ||||||
| 	EsScrollbar *scrollbar = (EsScrollbar *) element->parent; | 	Scrollbar *scrollbar = (Scrollbar *) element->parent; | ||||||
| 
 | 
 | ||||||
| 	if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { | 	if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { | ||||||
| 		element->state |= UI_STATE_STRONG_PRESSED; | 		element->state |= UI_STATE_STRONG_PRESSED; | ||||||
|  | @ -2693,8 +2706,8 @@ int ProcessScrollbarButtonMessage(EsElement *element, EsMessage *message) { | ||||||
| 	return ES_HANDLED; | 	return ES_HANDLED; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| EsScrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { | Scrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { | ||||||
| 	EsScrollbar *scrollbar = (EsScrollbar *) EsHeapAllocate(sizeof(EsScrollbar), true); | 	Scrollbar *scrollbar = (Scrollbar *) EsHeapAllocate(sizeof(Scrollbar), true); | ||||||
| 	if (!scrollbar) return nullptr; | 	if (!scrollbar) return nullptr; | ||||||
| 	scrollbar->thumb = (EsElement *) EsHeapAllocate(sizeof(EsElement), true); | 	scrollbar->thumb = (EsElement *) EsHeapAllocate(sizeof(EsElement), true); | ||||||
| 
 | 
 | ||||||
|  | @ -2703,7 +2716,7 @@ EsScrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	scrollbar->Initialise(parent, flags, [] (EsElement *element, EsMessage *message) { | 	scrollbar->Initialise(parent, flags, [] (EsElement *element, EsMessage *message) { | ||||||
| 		EsScrollbar *scrollbar = (EsScrollbar *) element; | 		Scrollbar *scrollbar = (Scrollbar *) element; | ||||||
| 
 | 
 | ||||||
| 		if (message->type == ES_MSG_LAYOUT) { | 		if (message->type == ES_MSG_LAYOUT) { | ||||||
| 			ScrollbarLayout(scrollbar); | 			ScrollbarLayout(scrollbar); | ||||||
|  | @ -2730,7 +2743,7 @@ EsScrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { | ||||||
| 	scrollbar->down->messageUser = ProcessScrollbarButtonMessage; | 	scrollbar->down->messageUser = ProcessScrollbarButtonMessage; | ||||||
| 
 | 
 | ||||||
| 	scrollbar->thumb->Initialise(scrollbar, ES_CELL_FILL, [] (EsElement *element, EsMessage *message) { | 	scrollbar->thumb->Initialise(scrollbar, ES_CELL_FILL, [] (EsElement *element, EsMessage *message) { | ||||||
| 		EsScrollbar *scrollbar = (EsScrollbar *) element->parent; | 		Scrollbar *scrollbar = (Scrollbar *) element->parent; | ||||||
| 		EsRectangle bounds = scrollbar->GetBounds(); | 		EsRectangle bounds = scrollbar->GetBounds(); | ||||||
| 
 | 
 | ||||||
| 		if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { | 		if (message->type == ES_MSG_MOUSE_LEFT_DRAG) { | ||||||
|  | @ -2804,7 +2817,7 @@ void ScrollPane::Setup(EsElement *_parent, uint8_t _xMode, uint8_t _yMode, uint1 | ||||||
| 					int axis = (element->flags & ES_SCROLLBAR_HORIZONTAL) ? 0 : 1; | 					int axis = (element->flags & ES_SCROLLBAR_HORIZONTAL) ? 0 : 1; | ||||||
| 					EsMessage m = *message; | 					EsMessage m = *message; | ||||||
| 					m.type = axis ? ES_MSG_SCROLL_Y : ES_MSG_SCROLL_X; | 					m.type = axis ? ES_MSG_SCROLL_Y : ES_MSG_SCROLL_X; | ||||||
| 					pane->position[axis] = m.scrollbarMoved.scroll; | 					pane->position[axis] = m.scroll.scroll; | ||||||
| 					EsMessageSend(pane->parent, &m); | 					EsMessageSend(pane->parent, &m); | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | @ -2901,8 +2914,8 @@ void ScrollPane::SetPosition(int axis, double newScroll, bool sendMovedMessage) | ||||||
| 	if (sendMovedMessage) { | 	if (sendMovedMessage) { | ||||||
| 		EsMessage m = {}; | 		EsMessage m = {}; | ||||||
| 		m.type = axis ? ES_MSG_SCROLL_Y : ES_MSG_SCROLL_X; | 		m.type = axis ? ES_MSG_SCROLL_Y : ES_MSG_SCROLL_X; | ||||||
| 		m.scrollbarMoved.scroll = position[axis]; | 		m.scroll.scroll = position[axis]; | ||||||
| 		m.scrollbarMoved.previous = previous; | 		m.scroll.previous = previous; | ||||||
| 		EsMessageSend(parent, &m); | 		EsMessageSend(parent, &m); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -2966,6 +2979,8 @@ void ScrollPane::Refresh() { | ||||||
| 
 | 
 | ||||||
| 	EsRectangle border = parent->style->borders; | 	EsRectangle border = parent->style->borders; | ||||||
| 
 | 
 | ||||||
|  | 	bool previousEnabled[2] = { enabled[0], enabled[1] }; | ||||||
|  | 
 | ||||||
| 	if (bar[0]) { | 	if (bar[0]) { | ||||||
| 		bar[0]->InternalMove(parent->width - parent->internalOffsetRight - border.r - border.l, bar[0]->style->preferredHeight,  | 		bar[0]->InternalMove(parent->width - parent->internalOffsetRight - border.r - border.l, bar[0]->style->preferredHeight,  | ||||||
| 				border.l, parent->height - parent->internalOffsetBottom - border.b); | 				border.l, parent->height - parent->internalOffsetBottom - border.b); | ||||||
|  | @ -2982,6 +2997,12 @@ void ScrollPane::Refresh() { | ||||||
| 		pad->InternalMove(parent->internalOffsetRight, parent->internalOffsetBottom,  | 		pad->InternalMove(parent->internalOffsetRight, parent->internalOffsetBottom,  | ||||||
| 				parent->width - parent->internalOffsetRight - border.r, parent->height - parent->internalOffsetBottom - border.b); | 				parent->width - parent->internalOffsetRight - border.r, parent->height - parent->internalOffsetBottom - border.b); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((bar[0] && previousEnabled[0] != enabled[0]) || (bar[1] && previousEnabled[1] != enabled[1])) { | ||||||
|  | 		// The scroll bars have moved, and so the internal offsets have changed.
 | ||||||
|  | 		// Therefore we need to tell the element to relayout.
 | ||||||
|  | 		EsElementRelayout(parent); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct EsScrollView : EsElement { ScrollPane scroll; }; | struct EsScrollView : EsElement { ScrollPane scroll; }; | ||||||
|  | @ -3188,7 +3209,7 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) { | ||||||
| 			child->state |= UI_STATE_BLOCK_INTERACTION; | 			child->state |= UI_STATE_BLOCK_INTERACTION; | ||||||
| 		} | 		} | ||||||
| 	} else if (message->type == ES_MSG_SCROLL_X || message->type == ES_MSG_SCROLL_Y) { | 	} else if (message->type == ES_MSG_SCROLL_X || message->type == ES_MSG_SCROLL_Y) { | ||||||
| 		int delta = message->scrollbarMoved.scroll - message->scrollbarMoved.previous; | 		int delta = message->scroll.scroll - message->scroll.previous; | ||||||
| 		int deltaX = message->type == ES_MSG_SCROLL_X ? delta : 0;  | 		int deltaX = message->type == ES_MSG_SCROLL_X ? delta : 0;  | ||||||
| 		int deltaY = message->type == ES_MSG_SCROLL_Y ? delta : 0;  | 		int deltaY = message->type == ES_MSG_SCROLL_Y ? delta : 0;  | ||||||
| 
 | 
 | ||||||
|  | @ -5801,7 +5822,6 @@ void EsElement::Destroy(bool manual) { | ||||||
| 
 | 
 | ||||||
| 	if (window->hovered == this) { | 	if (window->hovered == this) { | ||||||
| 		window->hovered = window; | 		window->hovered = window; | ||||||
| 		window->state |= UI_STATE_HOVERED; |  | ||||||
| 		EsMessage m = {}; | 		EsMessage m = {}; | ||||||
| 		m.type = ES_MSG_HOVERED_START; | 		m.type = ES_MSG_HOVERED_START; | ||||||
| 		EsMessageSend(window, &m); | 		EsMessageSend(window, &m); | ||||||
|  | @ -5819,7 +5839,6 @@ void EsElement::Destroy(bool manual) { | ||||||
| 	if (window->defaultEnterButton 	== this) window->defaultEnterButton = nullptr;		 | 	if (window->defaultEnterButton 	== this) window->defaultEnterButton = nullptr;		 | ||||||
| 	if (window->enterButton 	== this) window->enterButton = window->defaultEnterButton; | 	if (window->enterButton 	== this) window->enterButton = window->defaultEnterButton; | ||||||
| 	if (window->escapeButton 	== this) window->escapeButton = nullptr; | 	if (window->escapeButton 	== this) window->escapeButton = nullptr; | ||||||
| 	if (window->ensureVisible 	== this) window->ensureVisible = nullptr; |  | ||||||
| 	if (window->dragged 		== this) window->dragged = nullptr; | 	if (window->dragged 		== this) window->dragged = nullptr; | ||||||
| 	if (gui.clickChainElement       == this) gui.clickChainElement = nullptr; | 	if (gui.clickChainElement       == this) gui.clickChainElement = nullptr; | ||||||
| 
 | 
 | ||||||
|  | @ -6084,16 +6103,15 @@ void UIFindHoverElement(EsWindow *window) { | ||||||
| 		element = UIFindHoverElementRecursively(window, 0, 0, position); | 		element = UIFindHoverElementRecursively(window, 0, 0, position); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (element->state & UI_STATE_HOVERED) { | 	if (window->hovered != element) { | ||||||
| 		EsAssert(window->hovered == element); // Window's hovered element mismatched element state flags.
 | 		EsElement *previous = window->hovered; | ||||||
| 	} else { | 		window->hovered = element; | ||||||
|  | 
 | ||||||
| 		EsMessage m = {}; | 		EsMessage m = {}; | ||||||
| 		m.type = ES_MSG_HOVERED_END; | 		m.type = ES_MSG_HOVERED_END; | ||||||
| 		window->hovered->state &= ~UI_STATE_HOVERED; | 		EsMessageSend(previous, &m); | ||||||
| 		EsMessageSend(window->hovered, &m); |  | ||||||
| 		element->state |= UI_STATE_HOVERED; |  | ||||||
| 		m.type = ES_MSG_HOVERED_START; | 		m.type = ES_MSG_HOVERED_START; | ||||||
| 		EsMessageSend((window->hovered = element), &m); | 		EsMessageSend(element, &m); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -6124,6 +6142,34 @@ bool EsElementIsFocused(EsElement *element) { | ||||||
| 	return element->window->focused == element; | 	return element->window->focused == element; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void UISendEnsureVisibleMessage(EsElement *element, EsGeneric) { | ||||||
|  | 	EsElement *child = element, *e = element; | ||||||
|  | 	EsAssert(element->state & UI_STATE_QUEUED_ENSURE_VISIBLE); | ||||||
|  | 	element->state &= ~UI_STATE_QUEUED_ENSURE_VISIBLE; | ||||||
|  | 
 | ||||||
|  | 	while (e->parent) { | ||||||
|  | 		EsMessage m = { ES_MSG_ENSURE_VISIBLE }; | ||||||
|  | 		m.child = child; | ||||||
|  | 		e = e->parent; | ||||||
|  | 
 | ||||||
|  | 		if (ES_HANDLED == EsMessageSend(e, &m)) { | ||||||
|  | 			child = e; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	EsAssert(~element->state & UI_STATE_QUEUED_ENSURE_VISIBLE); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void UIQueueEnsureVisibleMessage(EsElement *element) { | ||||||
|  | 	if (~element->state & UI_STATE_QUEUED_ENSURE_VISIBLE) { | ||||||
|  | 		element->state |= UI_STATE_QUEUED_ENSURE_VISIBLE; | ||||||
|  | 		UpdateAction action = {}; | ||||||
|  | 		action.element = element; | ||||||
|  | 		action.callback = UISendEnsureVisibleMessage; | ||||||
|  | 		element->window->updateActions.Add(action); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void EsElementFocus(EsElement *element, uint32_t flags) { | void EsElementFocus(EsElement *element, uint32_t flags) { | ||||||
| 	EsMessageMutexCheck(); | 	EsMessageMutexCheck(); | ||||||
| 
 | 
 | ||||||
|  | @ -6195,7 +6241,7 @@ void EsElementFocus(EsElement *element, uint32_t flags) { | ||||||
| 	// Ensure the element is visible.
 | 	// Ensure the element is visible.
 | ||||||
| 
 | 
 | ||||||
| 	if ((flags & ES_ELEMENT_FOCUS_ENSURE_VISIBLE) && element) { | 	if ((flags & ES_ELEMENT_FOCUS_ENSURE_VISIBLE) && element) { | ||||||
| 		window->ensureVisible = element; | 		UIQueueEnsureVisibleMessage(element); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -6585,10 +6631,6 @@ void UIMouseDown(EsWindow *window, EsMessage *message) { | ||||||
| 		// window->hovered will be set to nullptr, so save the element here.
 | 		// window->hovered will be set to nullptr, so save the element here.
 | ||||||
| 		EsElement *element = window->hovered; | 		EsElement *element = window->hovered; | ||||||
| 
 | 
 | ||||||
| 		if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { |  | ||||||
| 			element->state |= UI_STATE_LEFT_PRESSED; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		window->pressed = element; | 		window->pressed = element; | ||||||
| 		EsMessage m = { ES_MSG_PRESSED_START }; | 		EsMessage m = { ES_MSG_PRESSED_START }; | ||||||
| 		EsMessageSend(element, &m); | 		EsMessageSend(element, &m); | ||||||
|  | @ -6630,11 +6672,10 @@ void UIMouseUp(EsWindow *window, EsMessage *message, bool sendClick) { | ||||||
| 			EsMessageSend(pressed, &m); | 			EsMessageSend(pressed, &m); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		pressed->state &= ~UI_STATE_LEFT_PRESSED; |  | ||||||
| 		EsMessage m = { ES_MSG_PRESSED_END }; | 		EsMessage m = { ES_MSG_PRESSED_END }; | ||||||
| 		EsMessageSend(pressed, &m); | 		EsMessageSend(pressed, &m); | ||||||
| 
 | 
 | ||||||
| 		if (message && (pressed->state & UI_STATE_HOVERED) && !gui.draggingStarted && sendClick) { | 		if (message && window->hovered == pressed && !gui.draggingStarted && sendClick) { | ||||||
| 			if (message->type == ES_MSG_MOUSE_LEFT_UP) { | 			if (message->type == ES_MSG_MOUSE_LEFT_UP) { | ||||||
| 				m.type = ES_MSG_MOUSE_LEFT_CLICK; | 				m.type = ES_MSG_MOUSE_LEFT_CLICK; | ||||||
| 				EsMessageSend(pressed, &m); | 				EsMessageSend(pressed, &m); | ||||||
|  | @ -7157,20 +7198,14 @@ void UIWindowLayoutNow(EsWindow *window, ProcessMessageTiming *timing) { | ||||||
| 
 | 
 | ||||||
| 	window->InternalMove(window->width, window->height, 0, 0); | 	window->InternalMove(window->width, window->height, 0, 0); | ||||||
| 
 | 
 | ||||||
| 	if (window->ensureVisible) { | 	while (window->updateActions.Length()) { | ||||||
| 		EsElement *child = window->ensureVisible, *e = window->ensureVisible; | 		// TODO Preventing/detecting infinite cycles?
 | ||||||
|  | 		UpdateAction action = window->updateActions[0]; | ||||||
|  | 		window->updateActions.DeleteSwap(0); | ||||||
| 
 | 
 | ||||||
| 		while (e->parent) { | 		if (~action.element->state & UI_STATE_DESTROYING) { | ||||||
| 			EsMessage m = { ES_MSG_ENSURE_VISIBLE }; | 			action.callback(action.element, action.context); | ||||||
| 			m.child = child; |  | ||||||
| 			e = e->parent; |  | ||||||
| 
 |  | ||||||
| 			if (ES_HANDLED == EsMessageSend(e, &m)) { |  | ||||||
| 				child = e; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 		window->ensureVisible = nullptr; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (window->processCheckVisible) { | 	if (window->processCheckVisible) { | ||||||
|  |  | ||||||
|  | @ -64,6 +64,8 @@ struct ListViewColumn { | ||||||
| int ListViewProcessItemMessage(EsElement *element, EsMessage *message); | int ListViewProcessItemMessage(EsElement *element, EsMessage *message); | ||||||
| void ListViewSetSortAscending(EsMenu *menu, EsGeneric context); | void ListViewSetSortAscending(EsMenu *menu, EsGeneric context); | ||||||
| void ListViewSetSortDescending(EsMenu *menu, EsGeneric context); | void ListViewSetSortDescending(EsMenu *menu, EsGeneric context); | ||||||
|  | void ListViewPopulateActionCallback(EsElement *element, EsGeneric); | ||||||
|  | void ListViewEnsureVisibleActionCallback(EsElement *element, EsGeneric); | ||||||
| 
 | 
 | ||||||
| struct EsListView : EsElement { | struct EsListView : EsElement { | ||||||
| 	ScrollPane scroll; | 	ScrollPane scroll; | ||||||
|  | @ -122,6 +124,7 @@ struct EsListView : EsElement { | ||||||
| 	EsListViewIndex ensureVisibleIndex; | 	EsListViewIndex ensureVisibleIndex; | ||||||
| 	uint8_t ensureVisibleAlign; | 	uint8_t ensureVisibleAlign; | ||||||
| 	bool ensureVisibleQueued; | 	bool ensureVisibleQueued; | ||||||
|  | 	bool populateQueued; | ||||||
| 
 | 
 | ||||||
| 	// Fixed item storage:
 | 	// Fixed item storage:
 | ||||||
| 	Array<ListViewFixedItem> fixedItems; | 	Array<ListViewFixedItem> fixedItems; | ||||||
|  | @ -334,11 +337,17 @@ struct EsListView : EsElement { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void EnsureItemVisible(EsListViewIndex groupIndex, EsListViewIndex index, uint8_t align) { | 	void EnsureItemVisible(EsListViewIndex groupIndex, EsListViewIndex index, uint8_t align) { | ||||||
| 		ensureVisibleQueued = true; |  | ||||||
| 		ensureVisibleGroupIndex = groupIndex; | 		ensureVisibleGroupIndex = groupIndex; | ||||||
| 		ensureVisibleIndex = index; | 		ensureVisibleIndex = index; | ||||||
| 		ensureVisibleAlign = align; | 		ensureVisibleAlign = align; | ||||||
| 		EsElementRelayout(this); | 
 | ||||||
|  | 		if (!ensureVisibleQueued) { | ||||||
|  | 			UpdateAction action = {}; | ||||||
|  | 			action.element = this; | ||||||
|  | 			action.callback = ListViewEnsureVisibleActionCallback; | ||||||
|  | 			window->updateActions.Add(action); | ||||||
|  | 			ensureVisibleQueued = true; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void _EnsureItemVisible(EsListViewIndex groupIndex, EsListViewIndex index, uint8_t align) { | 	void _EnsureItemVisible(EsListViewIndex groupIndex, EsListViewIndex index, uint8_t align) { | ||||||
|  | @ -528,7 +537,7 @@ struct EsListView : EsElement { | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Populate() { | 	void _Populate() { | ||||||
| #if 0 | #if 0 | ||||||
| 		EsPrint("--- Before Populate() ---\n"); | 		EsPrint("--- Before Populate() ---\n"); | ||||||
| 		EsPrint("Scroll: %i\n", (int) (scroll.position[1] - style->insets.t)); | 		EsPrint("Scroll: %i\n", (int) (scroll.position[1] - style->insets.t)); | ||||||
|  | @ -743,6 +752,21 @@ struct EsListView : EsElement { | ||||||
| 			visibleItem->element->Destroy(); | 			visibleItem->element->Destroy(); | ||||||
| 			visibleItems.Delete(visibleIndex); | 			visibleItems.Delete(visibleIndex); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (inlineTextbox) { | ||||||
|  | 			ListViewItem *item = FindVisibleItem(inlineTextboxGroup, inlineTextboxIndex); | ||||||
|  | 			if (item) MoveInlineTextbox(item); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void Populate() { | ||||||
|  | 		if (!populateQueued) { | ||||||
|  | 			UpdateAction action = {}; | ||||||
|  | 			action.element = this; | ||||||
|  | 			action.callback = ListViewPopulateActionCallback; | ||||||
|  | 			window->updateActions.Add(action); | ||||||
|  | 			populateQueued = true; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void Wrap(bool autoScroll) { | 	void Wrap(bool autoScroll) { | ||||||
|  | @ -1649,25 +1673,13 @@ struct EsListView : EsElement { | ||||||
| 			firstLayout = true; | 			firstLayout = true; | ||||||
| 			Wrap(message->layout.sizeChanged); | 			Wrap(message->layout.sizeChanged); | ||||||
| 
 | 
 | ||||||
| 			if (ensureVisibleQueued) { | 			if (columnHeader) { | ||||||
| 				ensureVisibleQueued = false; | 				columnHeader->InternalMove(Width(GetBounds()), columnHeader->style->preferredHeight, 0, 0); | ||||||
| 				_EnsureItemVisible(ensureVisibleGroupIndex, ensureVisibleIndex, ensureVisibleAlign); |  | ||||||
| 				// TODO _EnsureItemVisible may call Populate; if this happens, we don't need to call it below.
 |  | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Populate(); | 			Populate(); | ||||||
| 
 |  | ||||||
| 			if (columnHeader) { |  | ||||||
| 				EsRectangle bounds = GetBounds(); |  | ||||||
| 				columnHeader->InternalMove(Width(bounds), columnHeader->style->preferredHeight, 0, 0); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (inlineTextbox) { |  | ||||||
| 				ListViewItem *item = FindVisibleItem(inlineTextboxGroup, inlineTextboxIndex); |  | ||||||
| 				if (item) MoveInlineTextbox(item); |  | ||||||
| 			} |  | ||||||
| 		} else if (message->type == ES_MSG_SCROLL_X || message->type == ES_MSG_SCROLL_Y) { | 		} else if (message->type == ES_MSG_SCROLL_X || message->type == ES_MSG_SCROLL_Y) { | ||||||
| 			int64_t delta = message->scrollbarMoved.scroll - message->scrollbarMoved.previous; | 			int64_t delta = message->scroll.scroll - message->scroll.previous; | ||||||
| 
 | 
 | ||||||
| 			if ((message->type == ES_MSG_SCROLL_X) == ((flags & ES_LIST_VIEW_HORIZONTAL) ? true : false)) { | 			if ((message->type == ES_MSG_SCROLL_X) == ((flags & ES_LIST_VIEW_HORIZONTAL) ? true : false)) { | ||||||
| 				for (uintptr_t i = 0; i < visibleItems.Length(); i++) { | 				for (uintptr_t i = 0; i < visibleItems.Length(); i++) { | ||||||
|  | @ -1870,7 +1882,7 @@ struct EsListView : EsElement { | ||||||
| 			for (uintptr_t i = 0; i < visibleItems.Length(); i++) { | 			for (uintptr_t i = 0; i < visibleItems.Length(); i++) { | ||||||
| 				if (hasFocusedItem && visibleItems[i].index == focusedItemIndex && visibleItems[i].group == focusedItemGroup) { | 				if (hasFocusedItem && visibleItems[i].index == focusedItemIndex && visibleItems[i].group == focusedItemGroup) { | ||||||
| 					focused = i; | 					focused = i; | ||||||
| 				} else if (visibleItems[i].element->state & UI_STATE_HOVERED) { | 				} else if (window->hovered == visibleItems[i].element) { | ||||||
| 					hovered = i; | 					hovered = i; | ||||||
| 				} else { | 				} else { | ||||||
| 					zOrderItems.Add(visibleItems[i].element); | 					zOrderItems.Add(visibleItems[i].element); | ||||||
|  | @ -2013,6 +2025,22 @@ struct EsListView : EsElement { | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | void ListViewPopulateActionCallback(EsElement *element, EsGeneric) { | ||||||
|  | 	EsListView *view = (EsListView *) element; | ||||||
|  | 	EsAssert(view->populateQueued); | ||||||
|  | 	view->populateQueued = false; | ||||||
|  | 	view->_Populate(); | ||||||
|  | 	EsAssert(!view->populateQueued); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void ListViewEnsureVisibleActionCallback(EsElement *element, EsGeneric) { | ||||||
|  | 	EsListView *view = (EsListView *) element; | ||||||
|  | 	EsAssert(view->ensureVisibleQueued); | ||||||
|  | 	view->ensureVisibleQueued = false; | ||||||
|  | 	view->_EnsureItemVisible(view->ensureVisibleGroupIndex, view->ensureVisibleIndex, view->ensureVisibleAlign); | ||||||
|  | 	EsAssert(!view->ensureVisibleQueued); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int ListViewProcessMessage(EsElement *element, EsMessage *message) { | int ListViewProcessMessage(EsElement *element, EsMessage *message) { | ||||||
| 	return ((EsListView *) element)->ProcessMessage(message); | 	return ((EsListView *) element)->ProcessMessage(message); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,7 +5,6 @@ | ||||||
| opaque_type EsElement          EsElementPublic; | opaque_type EsElement          EsElementPublic; | ||||||
| opaque_type EsPanel            EsElement; | opaque_type EsPanel            EsElement; | ||||||
| opaque_type EsWindow           EsElement; | opaque_type EsWindow           EsElement; | ||||||
| opaque_type EsScrollbar        EsElement; |  | ||||||
| opaque_type EsButton           EsElement; | opaque_type EsButton           EsElement; | ||||||
| opaque_type EsTextDisplay      EsElement; | opaque_type EsTextDisplay      EsElement; | ||||||
| opaque_type EsIconDisplay      EsElement; | opaque_type EsIconDisplay      EsElement; | ||||||
|  | @ -1627,6 +1626,10 @@ struct EsMessageItemToString { | ||||||
| 	STRING text; | 	STRING text; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct EsMessageScroll { | ||||||
|  | 	int scroll, previous; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| // List view messages. | // List view messages. | ||||||
| 
 | 
 | ||||||
| struct EsMessageIterateIndex { | struct EsMessageIterateIndex { | ||||||
|  | @ -1712,10 +1715,6 @@ struct EsMessageGetColumnSort { | ||||||
| 
 | 
 | ||||||
| // Specific element messages. | // Specific element messages. | ||||||
| 
 | 
 | ||||||
| struct EsMessageScrollbarMoved { |  | ||||||
| 	int scroll, previous; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct EsMessageSliderMoved { | struct EsMessageSliderMoved { | ||||||
| 	double value, previous; | 	double value, previous; | ||||||
| 	bool inDrag; | 	bool inDrag; | ||||||
|  | @ -1847,6 +1846,7 @@ struct EsMessage { | ||||||
| 		EsMessageFocus focus; | 		EsMessageFocus focus; | ||||||
| 		EsMessageScrollWheel scrollWheel; | 		EsMessageScrollWheel scrollWheel; | ||||||
| 		EsMessageWindowActivated windowActivated; | 		EsMessageWindowActivated windowActivated; | ||||||
|  | 		EsMessageScroll scroll; | ||||||
| 		const EsStyle *childStyleVariant; | 		const EsStyle *childStyleVariant; | ||||||
| 		EsRectangle *accessKeyHintBounds; | 		EsRectangle *accessKeyHintBounds; | ||||||
| 		EsPainter *painter; | 		EsPainter *painter; | ||||||
|  | @ -1868,7 +1868,6 @@ struct EsMessage { | ||||||
| 		EsMessageGetColumnSort getColumnSort; | 		EsMessageGetColumnSort getColumnSort; | ||||||
| 
 | 
 | ||||||
| 		// Specific element messages: | 		// Specific element messages: | ||||||
| 		EsMessageScrollbarMoved scrollbarMoved; |  | ||||||
| 		EsMessageSliderMoved sliderMoved; | 		EsMessageSliderMoved sliderMoved; | ||||||
| 		EsMessageColorChanged colorChanged; | 		EsMessageColorChanged colorChanged; | ||||||
| 		EsMessageNumberDragDelta numberDragDelta; | 		EsMessageNumberDragDelta numberDragDelta; | ||||||
|  |  | ||||||
|  | @ -3570,11 +3570,13 @@ void TextboxRefreshVisibleLines(EsTextbox *textbox, bool repaint = true) { | ||||||
| 
 | 
 | ||||||
| 	if (refreshXLimit) { | 	if (refreshXLimit) { | ||||||
| 		textbox->scroll.Refresh(); | 		textbox->scroll.Refresh(); | ||||||
| 		EsElementRelayout(textbox); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	textbox->scroll.SetX(scrollX); | 	textbox->scroll.SetX(scrollX); | ||||||
| 	if (repaint) textbox->Repaint(true); | 
 | ||||||
|  | 	if (repaint) { | ||||||
|  | 		textbox->Repaint(true); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void TextboxLineCountChangeCleanup(EsTextbox *textbox, int32_t offsetDelta, int32_t startLine) { | void TextboxLineCountChangeCleanup(EsTextbox *textbox, int32_t offsetDelta, int32_t startLine) { | ||||||
|  | @ -4284,6 +4286,8 @@ int ProcessTextboxMarginMessage(EsElement *element, EsMessage *message) { | ||||||
| 			EsTextPlan *plan = EsTextPlanCreate(element, &properties, bounds, label, textRun, 1); | 			EsTextPlan *plan = EsTextPlanCreate(element, &properties, bounds, label, textRun, 1); | ||||||
| 			if (plan) EsDrawText(painter, plan, bounds, nullptr, nullptr); | 			if (plan) EsDrawText(painter, plan, bounds, nullptr, nullptr); | ||||||
| 		} | 		} | ||||||
|  | 	} else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { | ||||||
|  | 		return ES_HANDLED; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -4555,7 +4559,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { | ||||||
| 			TextboxFindLongestLine(textbox); | 			TextboxFindLongestLine(textbox); | ||||||
| 			textbox->scroll.Refresh(); | 			textbox->scroll.Refresh(); | ||||||
| 			EsTextboxEnsureCaretVisible(textbox); | 			EsTextboxEnsureCaretVisible(textbox); | ||||||
| 			textbox->window->ensureVisible = textbox; | 			UIQueueEnsureVisibleMessage(textbox); | ||||||
| 		} | 		} | ||||||
| 	} else if (message->type == ES_MSG_MOUSE_LEFT_DOWN || message->type == ES_MSG_MOUSE_RIGHT_DOWN) { | 	} else if (message->type == ES_MSG_MOUSE_LEFT_DOWN || message->type == ES_MSG_MOUSE_RIGHT_DOWN) { | ||||||
| 		TextboxMoveCaretToCursor(textbox, message->mouseDown.positionX, message->mouseDown.positionY, message->type == ES_MSG_MOUSE_RIGHT_DOWN); | 		TextboxMoveCaretToCursor(textbox, message->mouseDown.positionX, message->mouseDown.positionY, message->type == ES_MSG_MOUSE_RIGHT_DOWN); | ||||||
|  | @ -4676,7 +4680,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { | ||||||
| 		DocumentLine *lastLine = &textbox->lines.Last(); | 		DocumentLine *lastLine = &textbox->lines.Last(); | ||||||
| 		message->measure.height = lastLine->yPosition + lastLine->height + textbox->insets.t + textbox->insets.b; | 		message->measure.height = lastLine->yPosition + lastLine->height + textbox->insets.t + textbox->insets.b; | ||||||
| 	} else if (message->type == ES_MSG_SCROLL_X) { | 	} else if (message->type == ES_MSG_SCROLL_X) { | ||||||
| 		TextboxSetHorizontalScroll(textbox, message->scrollbarMoved.scroll); | 		TextboxSetHorizontalScroll(textbox, message->scroll.scroll); | ||||||
| 	} else if (message->type == ES_MSG_SCROLL_Y) { | 	} else if (message->type == ES_MSG_SCROLL_Y) { | ||||||
| 		TextboxRefreshVisibleLines(textbox, false); | 		TextboxRefreshVisibleLines(textbox, false); | ||||||
| 		EsElementRepaintForScroll(textbox, message, EsRectangleAdd(element->GetInternalOffset(), element->style->borders)); | 		EsElementRepaintForScroll(textbox, message, EsRectangleAdd(element->GetInternalOffset(), element->style->borders)); | ||||||
|  |  | ||||||
|  | @ -907,8 +907,8 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_SET_CURSOR) { | ||||||
| 
 | 
 | ||||||
| 	if (!window->closed && different && !windowManager.eyedropping && (windowManager.hoverWindow == window || !windowManager.hoverWindow)) { | 	if (!window->closed && different && !windowManager.eyedropping && (windowManager.hoverWindow == window || !windowManager.hoverWindow)) { | ||||||
| 		windowManager.cursorID = argument1; | 		windowManager.cursorID = argument1; | ||||||
| 		windowManager.cursorImageOffsetX = (int8_t) ((argument2 >> 0) & 0xFF); | 		windowManager.cursorImageOffsetX = (int8_t) ((argument2 >> 0) & 0xFF) - CURSOR_PADDING_L; | ||||||
| 		windowManager.cursorImageOffsetY = (int8_t) ((argument2 >> 8) & 0xFF); | 		windowManager.cursorImageOffsetY = (int8_t) ((argument2 >> 8) & 0xFF) - CURSOR_PADDING_T; | ||||||
| 		windowManager.cursorShadow = argument3 & (1 << 30); | 		windowManager.cursorShadow = argument3 & (1 << 30); | ||||||
| 
 | 
 | ||||||
| 		int width = imageWidth + CURSOR_PADDING_L + CURSOR_PADDING_R; | 		int width = imageWidth + CURSOR_PADDING_L + CURSOR_PADDING_R; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 nakst
						nakst