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); | ||||
| 	} 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) { | ||||
| 			// 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.
 | ||||
|  | @ -974,7 +974,7 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { | |||
| WindowTab *WindowTabCreate(ContainerWindow *container) { | ||||
| 	WindowTab *tab = (WindowTab *) EsHeapAllocate(sizeof(WindowTab), true); | ||||
| 	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"; | ||||
| 	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); | ||||
| void AccessKeysCenterHint(EsElement *element, EsMessage *message); | ||||
| 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 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 InspectorNotifyElementContentChanged(EsElement *element); | ||||
| 
 | ||||
| #define UI_STATE_RELAYOUT 		(1 <<  2) | ||||
| #define UI_STATE_RELAYOUT_CHILD		(1 <<  3) | ||||
| #define UI_STATE_DESTROYING		(1 <<  4) | ||||
| #define UI_STATE_DESTROYING_CHILD	(1 <<  5) | ||||
| // Updating:
 | ||||
| #define UI_STATE_RELAYOUT 		(1 <<  0) | ||||
| #define UI_STATE_RELAYOUT_CHILD		(1 <<  1) | ||||
| #define UI_STATE_DESTROYING		(1 <<  2) | ||||
| #define UI_STATE_DESTROYING_CHILD	(1 <<  3) | ||||
| 
 | ||||
| #define UI_STATE_HOVERED		(1 <<  6) | ||||
| #define UI_STATE_LEFT_PRESSED		(1 <<  7) | ||||
| #define UI_STATE_STRONG_PRESSED		(1 <<  8) | ||||
| #define UI_STATE_FOCUS_WITHIN		(1 <<  9) | ||||
| #define UI_STATE_FOCUSED		(1 << 10) | ||||
| #define UI_STATE_LOST_STRONG_FOCUS	(1 << 11) | ||||
| #define UI_STATE_MENU_SOURCE		(1 << 12) | ||||
| // Interaction state:
 | ||||
| #define UI_STATE_FOCUS_WITHIN		(1 <<  4) | ||||
| #define UI_STATE_FOCUSED		(1 <<  5) | ||||
| #define UI_STATE_LOST_STRONG_FOCUS	(1 <<  6) | ||||
| #define UI_STATE_ENTERED		(1 <<  7) | ||||
| 
 | ||||
| #define UI_STATE_ANIMATING		(1 << 13) | ||||
| #define UI_STATE_ENTERED		(1 << 14) | ||||
| #define UI_STATE_BLOCK_INTERACTION	(1 << 16) | ||||
| // Presence on arrays:
 | ||||
| #define UI_STATE_ANIMATING		(1 <<  8) | ||||
| #define UI_STATE_CHECK_VISIBLE		(1 <<  9) | ||||
| #define UI_STATE_QUEUED_ENSURE_VISIBLE	(1 << 10) | ||||
| 
 | ||||
| #define UI_STATE_TEMP			(1 << 17) | ||||
| #define UI_STATE_Z_STACK		(1 << 18) | ||||
| #define UI_STATE_COMMAND_BUTTON		(1 << 19) | ||||
| // Behaviour modifiers:
 | ||||
| #define UI_STATE_STRONG_PRESSED		(1 << 11) | ||||
| #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_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 { | ||||
| 	EsUICallback messageClass; | ||||
|  | @ -334,7 +341,7 @@ struct EsImageDisplay : EsElement { | |||
| 
 | ||||
| struct ScrollPane { | ||||
| 	EsElement *parent, *pad; | ||||
| 	EsScrollbar *bar[2]; | ||||
| 	struct Scrollbar *bar[2]; | ||||
| 	double position[2]; | ||||
| 	int64_t limit[2]; | ||||
| 	int32_t fixedViewport[2]; | ||||
|  | @ -430,8 +437,6 @@ struct ColorPickerHost { | |||
| 	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) { | ||||
| 	if (*pointer) { | ||||
| 		EsHeapFree(*pointer); | ||||
|  | @ -481,8 +486,7 @@ struct EsWindow : EsElement { | |||
| 		  *pressed,  | ||||
| 		  *focused, | ||||
| 		  *inactiveFocus, | ||||
| 		  *dragged, | ||||
| 		  *ensureVisible; | ||||
| 		  *dragged; | ||||
| 
 | ||||
| 	EsButton *enterButton,  | ||||
| 		 *escapeButton,  | ||||
|  | @ -502,6 +506,7 @@ struct EsWindow : EsElement { | |||
| 	EsRectangle updateRegionInProgress; // For visualizePaintSteps.
 | ||||
| 
 | ||||
| 	Array<struct SizeAlternative> sizeAlternatives; | ||||
| 	Array<struct UpdateAction> updateActions; | ||||
| 
 | ||||
| 	EsElement *source; // Menu source.
 | ||||
| 	EsWindow *targetMenu; // The menu that keyboard events should be sent to.
 | ||||
|  | @ -510,6 +515,12 @@ struct EsWindow : EsElement { | |||
| 	double announcementTimeMs; | ||||
| }; | ||||
| 
 | ||||
| struct UpdateAction { | ||||
| 	EsElement *element; | ||||
| 	EsGeneric context; | ||||
| 	void (*callback)(EsElement *, EsGeneric); | ||||
| }; | ||||
| 
 | ||||
| struct SizeAlternative { | ||||
| 	EsElement *small, *big; | ||||
| 	int widthThreshold, heightThreshold; | ||||
|  | @ -789,6 +800,7 @@ void UIWindowDestroy(EsWindow *window) { | |||
| 	EsHandleClose(window->handle); | ||||
| 	window->checkVisible.Free(); | ||||
| 	window->sizeAlternatives.Free(); | ||||
| 	window->updateActions.Free(); | ||||
| 	window->dialogs.Free(); | ||||
| 	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->window = window; | ||||
| 	window->Initialise(nullptr, ES_CELL_FILL, ProcessRootMessage, nullptr); | ||||
| 	window->cName = "window"; | ||||
| 	window->window = window; | ||||
| 	window->width = window->windowWidth, window->height = window->windowHeight; | ||||
| 	window->hovered = window; | ||||
| 	window->hovering = true; | ||||
|  | @ -1741,13 +1753,14 @@ bool EsElement::RefreshStyleState() { | |||
| 
 | ||||
| 	if (flags & ES_ELEMENT_DISABLED) { | ||||
| 		styleStateFlags |= THEME_PRIMARY_STATE_DISABLED; | ||||
| 	} else if (window && !window->activated && !window->appearActivated) { | ||||
| 	} else if (!window->activated && !window->appearActivated) { | ||||
| 		styleStateFlags |= THEME_PRIMARY_STATE_INACTIVE; | ||||
| 	} 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)) { | ||||
| 			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; | ||||
| 		} else { | ||||
| 			styleStateFlags |= THEME_PRIMARY_STATE_IDLE; | ||||
|  | @ -2550,7 +2563,7 @@ void EsElementUpdateContentSize(EsElement *element, uint32_t flags) { | |||
| 
 | ||||
| // #define ENABLE_SMOOTH_SCROLLING
 | ||||
| 
 | ||||
| struct EsScrollbar : EsElement { | ||||
| struct Scrollbar : EsElement { | ||||
| 	EsButton *up, *down; | ||||
| 	EsElement *thumb; | ||||
| 	double position, autoScrollSpeed, smoothScrollTarget; | ||||
|  | @ -2558,7 +2571,7 @@ struct EsScrollbar : EsElement { | |||
| 	bool horizontal; | ||||
| }; | ||||
| 
 | ||||
| void ScrollbarLayout(EsScrollbar *scrollbar) { | ||||
| void ScrollbarLayout(Scrollbar *scrollbar) { | ||||
| 	if (scrollbar->viewportSize >= scrollbar->contentSize || scrollbar->viewportSize <= 0 || scrollbar->contentSize <= 0) { | ||||
| 		EsElementSetDisabled(scrollbar, true); | ||||
| 	} 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(); | ||||
| 
 | ||||
| 	if (scrollbar->viewportSize == viewportSize && scrollbar->contentSize == contentSize) { | ||||
|  | @ -2620,7 +2633,7 @@ void ScrollbarSetMeasurements(EsScrollbar *scrollbar, int viewportSize, int cont | |||
| 	ScrollbarLayout(scrollbar); | ||||
| } | ||||
| 
 | ||||
| void ScrollbarSetPosition(EsScrollbar *scrollbar, double position, bool sendMovedMessage, bool smoothScroll) { | ||||
| void ScrollbarSetPosition(Scrollbar *scrollbar, double position, bool sendMovedMessage, bool smoothScroll) { | ||||
| 	EsMessageMutexCheck(); | ||||
| 
 | ||||
| 	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) { | ||||
| 		EsMessage m = { ES_MSG_SCROLLBAR_MOVED }; | ||||
| 		m.scrollbarMoved.scroll = (int) position; | ||||
| 		m.scrollbarMoved.previous = previous; | ||||
| 		m.scroll.scroll = (int) position; | ||||
| 		m.scroll.previous = previous; | ||||
| 		EsMessageSend(scrollbar, &m); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -2662,7 +2675,7 @@ void ScrollbarSetPosition(EsScrollbar *scrollbar, double position, bool sendMove | |||
| } | ||||
| 
 | ||||
| int ProcessScrollbarButtonMessage(EsElement *element, EsMessage *message) { | ||||
| 	EsScrollbar *scrollbar = (EsScrollbar *) element->parent; | ||||
| 	Scrollbar *scrollbar = (Scrollbar *) element->parent; | ||||
| 
 | ||||
| 	if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { | ||||
| 		element->state |= UI_STATE_STRONG_PRESSED; | ||||
|  | @ -2693,8 +2706,8 @@ int ProcessScrollbarButtonMessage(EsElement *element, EsMessage *message) { | |||
| 	return ES_HANDLED; | ||||
| } | ||||
| 
 | ||||
| EsScrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { | ||||
| 	EsScrollbar *scrollbar = (EsScrollbar *) EsHeapAllocate(sizeof(EsScrollbar), true); | ||||
| Scrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { | ||||
| 	Scrollbar *scrollbar = (Scrollbar *) EsHeapAllocate(sizeof(Scrollbar), true); | ||||
| 	if (!scrollbar) return nullptr; | ||||
| 	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) { | ||||
| 		EsScrollbar *scrollbar = (EsScrollbar *) element; | ||||
| 		Scrollbar *scrollbar = (Scrollbar *) element; | ||||
| 
 | ||||
| 		if (message->type == ES_MSG_LAYOUT) { | ||||
| 			ScrollbarLayout(scrollbar); | ||||
|  | @ -2730,7 +2743,7 @@ EsScrollbar *ScrollbarCreate(EsElement *parent, uint64_t flags) { | |||
| 	scrollbar->down->messageUser = ProcessScrollbarButtonMessage; | ||||
| 
 | ||||
| 	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(); | ||||
| 
 | ||||
| 		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; | ||||
| 					EsMessage m = *message; | ||||
| 					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); | ||||
| 				} | ||||
| 
 | ||||
|  | @ -2901,8 +2914,8 @@ void ScrollPane::SetPosition(int axis, double newScroll, bool sendMovedMessage) | |||
| 	if (sendMovedMessage) { | ||||
| 		EsMessage m = {}; | ||||
| 		m.type = axis ? ES_MSG_SCROLL_Y : ES_MSG_SCROLL_X; | ||||
| 		m.scrollbarMoved.scroll = position[axis]; | ||||
| 		m.scrollbarMoved.previous = previous; | ||||
| 		m.scroll.scroll = position[axis]; | ||||
| 		m.scroll.previous = previous; | ||||
| 		EsMessageSend(parent, &m); | ||||
| 	} | ||||
| } | ||||
|  | @ -2966,6 +2979,8 @@ void ScrollPane::Refresh() { | |||
| 
 | ||||
| 	EsRectangle border = parent->style->borders; | ||||
| 
 | ||||
| 	bool previousEnabled[2] = { enabled[0], enabled[1] }; | ||||
| 
 | ||||
| 	if (bar[0]) { | ||||
| 		bar[0]->InternalMove(parent->width - parent->internalOffsetRight - border.r - border.l, bar[0]->style->preferredHeight,  | ||||
| 				border.l, parent->height - parent->internalOffsetBottom - border.b); | ||||
|  | @ -2982,6 +2997,12 @@ void ScrollPane::Refresh() { | |||
| 		pad->InternalMove(parent->internalOffsetRight, parent->internalOffsetBottom,  | ||||
| 				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; }; | ||||
|  | @ -3188,7 +3209,7 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) { | |||
| 			child->state |= UI_STATE_BLOCK_INTERACTION; | ||||
| 		} | ||||
| 	} 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 deltaY = message->type == ES_MSG_SCROLL_Y ? delta : 0;  | ||||
| 
 | ||||
|  | @ -5801,7 +5822,6 @@ void EsElement::Destroy(bool manual) { | |||
| 
 | ||||
| 	if (window->hovered == this) { | ||||
| 		window->hovered = window; | ||||
| 		window->state |= UI_STATE_HOVERED; | ||||
| 		EsMessage m = {}; | ||||
| 		m.type = ES_MSG_HOVERED_START; | ||||
| 		EsMessageSend(window, &m); | ||||
|  | @ -5819,7 +5839,6 @@ void EsElement::Destroy(bool manual) { | |||
| 	if (window->defaultEnterButton 	== this) window->defaultEnterButton = nullptr;		 | ||||
| 	if (window->enterButton 	== this) window->enterButton = window->defaultEnterButton; | ||||
| 	if (window->escapeButton 	== this) window->escapeButton = nullptr; | ||||
| 	if (window->ensureVisible 	== this) window->ensureVisible = nullptr; | ||||
| 	if (window->dragged 		== this) window->dragged = nullptr; | ||||
| 	if (gui.clickChainElement       == this) gui.clickChainElement = nullptr; | ||||
| 
 | ||||
|  | @ -6084,16 +6103,15 @@ void UIFindHoverElement(EsWindow *window) { | |||
| 		element = UIFindHoverElementRecursively(window, 0, 0, position); | ||||
| 	} | ||||
| 
 | ||||
| 	if (element->state & UI_STATE_HOVERED) { | ||||
| 		EsAssert(window->hovered == element); // Window's hovered element mismatched element state flags.
 | ||||
| 	} else { | ||||
| 	if (window->hovered != element) { | ||||
| 		EsElement *previous = window->hovered; | ||||
| 		window->hovered = element; | ||||
| 
 | ||||
| 		EsMessage m = {}; | ||||
| 		m.type = ES_MSG_HOVERED_END; | ||||
| 		window->hovered->state &= ~UI_STATE_HOVERED; | ||||
| 		EsMessageSend(window->hovered, &m); | ||||
| 		element->state |= UI_STATE_HOVERED; | ||||
| 		EsMessageSend(previous, &m); | ||||
| 		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; | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	EsMessageMutexCheck(); | ||||
| 
 | ||||
|  | @ -6195,7 +6241,7 @@ void EsElementFocus(EsElement *element, uint32_t flags) { | |||
| 	// Ensure the element is visible.
 | ||||
| 
 | ||||
| 	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.
 | ||||
| 		EsElement *element = window->hovered; | ||||
| 
 | ||||
| 		if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { | ||||
| 			element->state |= UI_STATE_LEFT_PRESSED; | ||||
| 		} | ||||
| 
 | ||||
| 		window->pressed = element; | ||||
| 		EsMessage m = { ES_MSG_PRESSED_START }; | ||||
| 		EsMessageSend(element, &m); | ||||
|  | @ -6630,11 +6672,10 @@ void UIMouseUp(EsWindow *window, EsMessage *message, bool sendClick) { | |||
| 			EsMessageSend(pressed, &m); | ||||
| 		} | ||||
| 
 | ||||
| 		pressed->state &= ~UI_STATE_LEFT_PRESSED; | ||||
| 		EsMessage m = { ES_MSG_PRESSED_END }; | ||||
| 		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) { | ||||
| 				m.type = ES_MSG_MOUSE_LEFT_CLICK; | ||||
| 				EsMessageSend(pressed, &m); | ||||
|  | @ -7157,22 +7198,16 @@ void UIWindowLayoutNow(EsWindow *window, ProcessMessageTiming *timing) { | |||
| 
 | ||||
| 	window->InternalMove(window->width, window->height, 0, 0); | ||||
| 
 | ||||
| 	if (window->ensureVisible) { | ||||
| 		EsElement *child = window->ensureVisible, *e = window->ensureVisible; | ||||
| 	while (window->updateActions.Length()) { | ||||
| 		// TODO Preventing/detecting infinite cycles?
 | ||||
| 		UpdateAction action = window->updateActions[0]; | ||||
| 		window->updateActions.DeleteSwap(0); | ||||
| 
 | ||||
| 		while (e->parent) { | ||||
| 			EsMessage m = { ES_MSG_ENSURE_VISIBLE }; | ||||
| 			m.child = child; | ||||
| 			e = e->parent; | ||||
| 
 | ||||
| 			if (ES_HANDLED == EsMessageSend(e, &m)) { | ||||
| 				child = e; | ||||
| 		if (~action.element->state & UI_STATE_DESTROYING) { | ||||
| 			action.callback(action.element, action.context); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 		window->ensureVisible = nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	if (window->processCheckVisible) { | ||||
| 		for (uintptr_t i = 0; i < window->checkVisible.Length(); i++) { | ||||
| 			EsElement *element = window->checkVisible[i]; | ||||
|  |  | |||
|  | @ -64,6 +64,8 @@ struct ListViewColumn { | |||
| int ListViewProcessItemMessage(EsElement *element, EsMessage *message); | ||||
| void ListViewSetSortAscending(EsMenu *menu, EsGeneric context); | ||||
| void ListViewSetSortDescending(EsMenu *menu, EsGeneric context); | ||||
| void ListViewPopulateActionCallback(EsElement *element, EsGeneric); | ||||
| void ListViewEnsureVisibleActionCallback(EsElement *element, EsGeneric); | ||||
| 
 | ||||
| struct EsListView : EsElement { | ||||
| 	ScrollPane scroll; | ||||
|  | @ -122,6 +124,7 @@ struct EsListView : EsElement { | |||
| 	EsListViewIndex ensureVisibleIndex; | ||||
| 	uint8_t ensureVisibleAlign; | ||||
| 	bool ensureVisibleQueued; | ||||
| 	bool populateQueued; | ||||
| 
 | ||||
| 	// Fixed item storage:
 | ||||
| 	Array<ListViewFixedItem> fixedItems; | ||||
|  | @ -334,11 +337,17 @@ struct EsListView : EsElement { | |||
| 	} | ||||
| 
 | ||||
| 	void EnsureItemVisible(EsListViewIndex groupIndex, EsListViewIndex index, uint8_t align) { | ||||
| 		ensureVisibleQueued = true; | ||||
| 		ensureVisibleGroupIndex = groupIndex; | ||||
| 		ensureVisibleIndex = index; | ||||
| 		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) { | ||||
|  | @ -528,7 +537,7 @@ struct EsListView : EsElement { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	void Populate() { | ||||
| 	void _Populate() { | ||||
| #if 0 | ||||
| 		EsPrint("--- Before Populate() ---\n"); | ||||
| 		EsPrint("Scroll: %i\n", (int) (scroll.position[1] - style->insets.t)); | ||||
|  | @ -743,6 +752,21 @@ struct EsListView : EsElement { | |||
| 			visibleItem->element->Destroy(); | ||||
| 			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) { | ||||
|  | @ -1649,25 +1673,13 @@ struct EsListView : EsElement { | |||
| 			firstLayout = true; | ||||
| 			Wrap(message->layout.sizeChanged); | ||||
| 
 | ||||
| 			if (ensureVisibleQueued) { | ||||
| 				ensureVisibleQueued = false; | ||||
| 				_EnsureItemVisible(ensureVisibleGroupIndex, ensureVisibleIndex, ensureVisibleAlign); | ||||
| 				// TODO _EnsureItemVisible may call Populate; if this happens, we don't need to call it below.
 | ||||
| 			if (columnHeader) { | ||||
| 				columnHeader->InternalMove(Width(GetBounds()), columnHeader->style->preferredHeight, 0, 0); | ||||
| 			} | ||||
| 
 | ||||
| 			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) { | ||||
| 			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)) { | ||||
| 				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++) { | ||||
| 				if (hasFocusedItem && visibleItems[i].index == focusedItemIndex && visibleItems[i].group == focusedItemGroup) { | ||||
| 					focused = i; | ||||
| 				} else if (visibleItems[i].element->state & UI_STATE_HOVERED) { | ||||
| 				} else if (window->hovered == visibleItems[i].element) { | ||||
| 					hovered = i; | ||||
| 				} else { | ||||
| 					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) { | ||||
| 	return ((EsListView *) element)->ProcessMessage(message); | ||||
| } | ||||
|  |  | |||
|  | @ -5,7 +5,6 @@ | |||
| opaque_type EsElement          EsElementPublic; | ||||
| opaque_type EsPanel            EsElement; | ||||
| opaque_type EsWindow           EsElement; | ||||
| opaque_type EsScrollbar        EsElement; | ||||
| opaque_type EsButton           EsElement; | ||||
| opaque_type EsTextDisplay      EsElement; | ||||
| opaque_type EsIconDisplay      EsElement; | ||||
|  | @ -1627,6 +1626,10 @@ struct EsMessageItemToString { | |||
| 	STRING text; | ||||
| }; | ||||
| 
 | ||||
| struct EsMessageScroll { | ||||
| 	int scroll, previous; | ||||
| }; | ||||
| 
 | ||||
| // List view messages. | ||||
| 
 | ||||
| struct EsMessageIterateIndex { | ||||
|  | @ -1712,10 +1715,6 @@ struct EsMessageGetColumnSort { | |||
| 
 | ||||
| // Specific element messages. | ||||
| 
 | ||||
| struct EsMessageScrollbarMoved { | ||||
| 	int scroll, previous; | ||||
| }; | ||||
| 
 | ||||
| struct EsMessageSliderMoved { | ||||
| 	double value, previous; | ||||
| 	bool inDrag; | ||||
|  | @ -1847,6 +1846,7 @@ struct EsMessage { | |||
| 		EsMessageFocus focus; | ||||
| 		EsMessageScrollWheel scrollWheel; | ||||
| 		EsMessageWindowActivated windowActivated; | ||||
| 		EsMessageScroll scroll; | ||||
| 		const EsStyle *childStyleVariant; | ||||
| 		EsRectangle *accessKeyHintBounds; | ||||
| 		EsPainter *painter; | ||||
|  | @ -1868,7 +1868,6 @@ struct EsMessage { | |||
| 		EsMessageGetColumnSort getColumnSort; | ||||
| 
 | ||||
| 		// Specific element messages: | ||||
| 		EsMessageScrollbarMoved scrollbarMoved; | ||||
| 		EsMessageSliderMoved sliderMoved; | ||||
| 		EsMessageColorChanged colorChanged; | ||||
| 		EsMessageNumberDragDelta numberDragDelta; | ||||
|  |  | |||
|  | @ -3570,11 +3570,13 @@ void TextboxRefreshVisibleLines(EsTextbox *textbox, bool repaint = true) { | |||
| 
 | ||||
| 	if (refreshXLimit) { | ||||
| 		textbox->scroll.Refresh(); | ||||
| 		EsElementRelayout(textbox); | ||||
| 	} | ||||
| 
 | ||||
| 	textbox->scroll.SetX(scrollX); | ||||
| 	if (repaint) textbox->Repaint(true); | ||||
| 
 | ||||
| 	if (repaint) { | ||||
| 		textbox->Repaint(true); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 			if (plan) EsDrawText(painter, plan, bounds, nullptr, nullptr); | ||||
| 		} | ||||
| 	} else if (message->type == ES_MSG_MOUSE_LEFT_DOWN) { | ||||
| 		return ES_HANDLED; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
|  | @ -4555,7 +4559,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { | |||
| 			TextboxFindLongestLine(textbox); | ||||
| 			textbox->scroll.Refresh(); | ||||
| 			EsTextboxEnsureCaretVisible(textbox); | ||||
| 			textbox->window->ensureVisible = textbox; | ||||
| 			UIQueueEnsureVisibleMessage(textbox); | ||||
| 		} | ||||
| 	} 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); | ||||
|  | @ -4676,7 +4680,7 @@ int ProcessTextboxMessage(EsElement *element, EsMessage *message) { | |||
| 		DocumentLine *lastLine = &textbox->lines.Last(); | ||||
| 		message->measure.height = lastLine->yPosition + lastLine->height + textbox->insets.t + textbox->insets.b; | ||||
| 	} 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) { | ||||
| 		TextboxRefreshVisibleLines(textbox, false); | ||||
| 		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)) { | ||||
| 		windowManager.cursorID = argument1; | ||||
| 		windowManager.cursorImageOffsetX = (int8_t) ((argument2 >> 0) & 0xFF); | ||||
| 		windowManager.cursorImageOffsetY = (int8_t) ((argument2 >> 8) & 0xFF); | ||||
| 		windowManager.cursorImageOffsetX = (int8_t) ((argument2 >> 0) & 0xFF) - CURSOR_PADDING_L; | ||||
| 		windowManager.cursorImageOffsetY = (int8_t) ((argument2 >> 8) & 0xFF) - CURSOR_PADDING_T; | ||||
| 		windowManager.cursorShadow = argument3 & (1 << 30); | ||||
| 
 | ||||
| 		int width = imageWidth + CURSOR_PADDING_L + CURSOR_PADDING_R; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 nakst
						nakst