mirror of https://gitlab.com/nakst/essence
				
				
				
			update actions for textbox ensure caret visible
This commit is contained in:
		
							parent
							
								
									3fe7464ed5
								
							
						
					
					
						commit
						73920030ff
					
				| 
						 | 
				
			
			@ -106,7 +106,7 @@ 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 UIQueueEnsureVisibleMessage(EsElement *element, bool center);
 | 
			
		||||
void ColorPickerCreate(EsElement *parent, struct ColorPickerHost host, uint32_t initialColor, bool showTextbox);
 | 
			
		||||
 | 
			
		||||
void InspectorSetup(EsWindow *window);
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +134,7 @@ void InspectorNotifyElementContentChanged(EsElement *element);
 | 
			
		|||
#define UI_STATE_ANIMATING		(1 <<  9)
 | 
			
		||||
#define UI_STATE_CHECK_VISIBLE		(1 << 10)
 | 
			
		||||
#define UI_STATE_QUEUED_ENSURE_VISIBLE	(1 << 11)
 | 
			
		||||
#define UI_STATE_ENSURE_VISIBLE_CENTER  (1 << 12)
 | 
			
		||||
 | 
			
		||||
// Behaviour modifiers:
 | 
			
		||||
#define UI_STATE_STRONG_PRESSED		(1 << 12)
 | 
			
		||||
| 
						 | 
				
			
			@ -2588,6 +2589,8 @@ struct Scrollbar : EsElement {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
void ScrollbarLayout(Scrollbar *scrollbar) {
 | 
			
		||||
	// TODO Do this as an UpdateAction?
 | 
			
		||||
 | 
			
		||||
	if (scrollbar->viewportSize >= scrollbar->contentSize || scrollbar->viewportSize <= 0 || scrollbar->contentSize <= 0) {
 | 
			
		||||
		EsElementSetDisabled(scrollbar, true);
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -3194,12 +3197,16 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) {
 | 
			
		|||
		}
 | 
			
		||||
	} else if (message->type == ES_MSG_ENSURE_VISIBLE) {
 | 
			
		||||
		if (panel->scroll.enabled[0] || panel->scroll.enabled[1]) {
 | 
			
		||||
			EsElement *child = message->child, *e = child;
 | 
			
		||||
			int offsetX = panel->scroll.position[0], offsetY = panel->scroll.position[1];
 | 
			
		||||
			EsElement *child = message->ensureVisible.descendent, *e = child;
 | 
			
		||||
			int offsetX = 0, offsetY = 0;
 | 
			
		||||
			while (e != element) offsetX += e->offsetX, offsetY += e->offsetY, e = e->parent;
 | 
			
		||||
			EsRectangle bounds = panel->GetBounds();
 | 
			
		||||
			panel->scroll.SetX(offsetX + child->width / 2 - bounds.r / 2);
 | 
			
		||||
			panel->scroll.SetY(offsetY + child->height / 2 - bounds.b / 2);
 | 
			
		||||
 | 
			
		||||
			if (message->ensureVisible.center || !EsRectangleContainsAll(bounds, ES_RECT_4PD(offsetX, offsetY, child->width, child->height))) {
 | 
			
		||||
				panel->scroll.SetX(offsetX + panel->scroll.position[0] + child->width / 2 - bounds.r / 2);
 | 
			
		||||
				panel->scroll.SetY(offsetY + panel->scroll.position[1] + child->height / 2 - bounds.b / 2);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return ES_HANDLED;
 | 
			
		||||
		} else {
 | 
			
		||||
			// This is not a scroll container, so don't update the child element being made visible.
 | 
			
		||||
| 
						 | 
				
			
			@ -6161,12 +6168,14 @@ bool EsElementIsFocused(EsElement *element) {
 | 
			
		|||
 | 
			
		||||
void UISendEnsureVisibleMessage(EsElement *element, EsGeneric) {
 | 
			
		||||
	EsElement *child = element, *e = element;
 | 
			
		||||
	bool center = element->state & UI_STATE_ENSURE_VISIBLE_CENTER;
 | 
			
		||||
	EsAssert(element->state & UI_STATE_QUEUED_ENSURE_VISIBLE);
 | 
			
		||||
	element->state &= ~UI_STATE_QUEUED_ENSURE_VISIBLE;
 | 
			
		||||
	element->state &= ~(UI_STATE_QUEUED_ENSURE_VISIBLE | UI_STATE_ENSURE_VISIBLE_CENTER);
 | 
			
		||||
 | 
			
		||||
	while (e->parent) {
 | 
			
		||||
		EsMessage m = { ES_MSG_ENSURE_VISIBLE };
 | 
			
		||||
		m.child = child;
 | 
			
		||||
		m.ensureVisible.descendent = child;
 | 
			
		||||
		m.ensureVisible.center = center;
 | 
			
		||||
		e = e->parent;
 | 
			
		||||
 | 
			
		||||
		if (ES_HANDLED == EsMessageSend(e, &m)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -6177,7 +6186,11 @@ void UISendEnsureVisibleMessage(EsElement *element, EsGeneric) {
 | 
			
		|||
	EsAssert(~element->state & UI_STATE_QUEUED_ENSURE_VISIBLE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UIQueueEnsureVisibleMessage(EsElement *element) {
 | 
			
		||||
void UIQueueEnsureVisibleMessage(EsElement *element, bool center) {
 | 
			
		||||
	if (center) {
 | 
			
		||||
		element->state |= UI_STATE_ENSURE_VISIBLE_CENTER;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (~element->state & UI_STATE_QUEUED_ENSURE_VISIBLE) {
 | 
			
		||||
		element->state |= UI_STATE_QUEUED_ENSURE_VISIBLE;
 | 
			
		||||
		UpdateAction action = {};
 | 
			
		||||
| 
						 | 
				
			
			@ -6258,7 +6271,7 @@ void EsElementFocus(EsElement *element, uint32_t flags) {
 | 
			
		|||
	// Ensure the element is visible.
 | 
			
		||||
 | 
			
		||||
	if ((flags & ES_ELEMENT_FOCUS_ENSURE_VISIBLE) && element) {
 | 
			
		||||
		UIQueueEnsureVisibleMessage(element);
 | 
			
		||||
		UIQueueEnsureVisibleMessage(element, true);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1632,6 +1632,11 @@ struct EsMessageScroll {
 | 
			
		|||
	int scroll, previous;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct EsMessageEnsureVisible {
 | 
			
		||||
	bool center; // If false, only center the element if it is partially obscured.
 | 
			
		||||
	EsElement *descendent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// List view messages.
 | 
			
		||||
 | 
			
		||||
struct EsMessageIterateIndex {
 | 
			
		||||
| 
						 | 
				
			
			@ -1862,11 +1867,12 @@ struct EsMessage {
 | 
			
		|||
		EsMessageScrollWheel scrollWheel;
 | 
			
		||||
		EsMessageWindowActivated windowActivated;
 | 
			
		||||
		EsMessageScroll scroll;
 | 
			
		||||
		EsMessageEnsureVisible ensureVisible;
 | 
			
		||||
		const EsStyle *childStyleVariant;
 | 
			
		||||
		EsRectangle *accessKeyHintBounds;
 | 
			
		||||
		EsPainter *painter;
 | 
			
		||||
		EsElement *child;
 | 
			
		||||
		EsCursorStyle cursorStyle;
 | 
			
		||||
		EsElement *child;
 | 
			
		||||
 | 
			
		||||
		// List view messages:
 | 
			
		||||
		EsMessageIterateIndex iterateIndex;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2919,6 +2919,8 @@ struct EsTextbox : EsElement {
 | 
			
		|||
	char *editStartContent;
 | 
			
		||||
	int32_t editStartContentBytes;
 | 
			
		||||
 | 
			
		||||
	bool ensureCaretVisibleQueued;
 | 
			
		||||
 | 
			
		||||
	EsUICallback overlayCallback;
 | 
			
		||||
	EsGeneric overlayData;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3341,11 +3343,22 @@ TextboxVisibleLine *TextboxGetVisibleLine(EsTextbox *textbox, int32_t documentLi
 | 
			
		|||
		? nullptr : &textbox->visibleLines[documentLineIndex - textbox->firstVisibleLine];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) {
 | 
			
		||||
void TextboxEnsureCaretVisibleActionCallback(EsElement *element, EsGeneric context) {
 | 
			
		||||
	EsTextbox *textbox = (EsTextbox *) element;
 | 
			
		||||
	bool verticallyCenter = context.u;
 | 
			
		||||
	TextboxCaret caret = textbox->carets[1];
 | 
			
		||||
	EsRectangle bounds = textbox->GetBounds();
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
	EsPrint("TextboxEnsureCaretVisibleActionCallback ------------\n");
 | 
			
		||||
 | 
			
		||||
	for (uintptr_t i = 0; i < 3; i++) {
 | 
			
		||||
		// ScrollPane::SetY causes ES_MSG_SCROLL_Y to get sent to the textbox.
 | 
			
		||||
		// This causes a TextboxRefreshVisibleLines, which may cause new lines to added.
 | 
			
		||||
		// If these lines had not been previously horizontally measured, this will then occur.
 | 
			
		||||
		// This then causes a ScrollPane::Refresh for the new horizontal width.
 | 
			
		||||
		// If this causes the horizontal scroll bar to appear, then the caret may no longer be fully visible.
 | 
			
		||||
		// Therefore, we repeat up to 3 times to ensure that the caret is definitely fully visible.
 | 
			
		||||
		
 | 
			
		||||
		EsRectangle bounds = textbox->GetBounds();
 | 
			
		||||
		DocumentLine *line = &textbox->lines[caret.line];
 | 
			
		||||
		int caretY = line->yPosition + textbox->insets.t;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3364,13 +3377,21 @@ void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) {
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (textbox->scroll.position[1] != scrollY) {
 | 
			
		||||
				EsPrint("     new scroll %d\n", scrollY);
 | 
			
		||||
				textbox->scroll.SetY(scrollY);
 | 
			
		||||
			} else {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	TextboxVisibleLine *visibleLine = TextboxGetVisibleLine(textbox, caret.line);
 | 
			
		||||
 | 
			
		||||
	if (visibleLine) {
 | 
			
		||||
		EsRectangle bounds = textbox->GetBounds();
 | 
			
		||||
		DocumentLine *line = &textbox->lines[caret.line];
 | 
			
		||||
		int scrollX = textbox->scroll.position[0];
 | 
			
		||||
		int viewportWidth = bounds.r;
 | 
			
		||||
| 
						 | 
				
			
			@ -3386,7 +3407,19 @@ void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) {
 | 
			
		|||
		textbox->scroll.SetX(scrollX);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	UIQueueEnsureVisibleMessage(textbox);
 | 
			
		||||
	UIQueueEnsureVisibleMessage(textbox, false);
 | 
			
		||||
	textbox->ensureCaretVisibleQueued = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) {
 | 
			
		||||
	if (!textbox->ensureCaretVisibleQueued) {
 | 
			
		||||
		UpdateAction action = {};
 | 
			
		||||
		action.element = textbox;
 | 
			
		||||
		action.callback = TextboxEnsureCaretVisibleActionCallback;
 | 
			
		||||
		action.context.u = verticallyCenter;
 | 
			
		||||
		textbox->window->updateActions.Add(action);
 | 
			
		||||
		textbox->ensureCaretVisibleQueued = true;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TextboxMoveCaret(EsTextbox *textbox, TextboxCaret *caret, bool right, int moveType, bool strongWhitespace = false) {
 | 
			
		||||
| 
						 | 
				
			
			@ -3667,6 +3700,7 @@ void TextboxUndoItemCallback(const void *item, EsUndoManager *manager, EsMessage
 | 
			
		|||
		textbox->carets[0] = header->caretsBefore[0];
 | 
			
		||||
		textbox->carets[1] = header->caretsBefore[1];
 | 
			
		||||
		EsTextboxInsert(textbox, (const char *) (header + 1), header->insertBytes, true);
 | 
			
		||||
		EsTextboxEnsureCaretVisible(textbox);
 | 
			
		||||
	} else if (message->type == ES_MSG_UNDO_CANCEL) {
 | 
			
		||||
		// Nothing to do.
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue