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);
 | 
					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 UIQueueEnsureVisibleMessage(EsElement *element, bool center);
 | 
				
			||||||
void ColorPickerCreate(EsElement *parent, struct ColorPickerHost host, uint32_t initialColor, bool showTextbox);
 | 
					void ColorPickerCreate(EsElement *parent, struct ColorPickerHost host, uint32_t initialColor, bool showTextbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InspectorSetup(EsWindow *window);
 | 
					void InspectorSetup(EsWindow *window);
 | 
				
			||||||
| 
						 | 
					@ -134,6 +134,7 @@ void InspectorNotifyElementContentChanged(EsElement *element);
 | 
				
			||||||
#define UI_STATE_ANIMATING		(1 <<  9)
 | 
					#define UI_STATE_ANIMATING		(1 <<  9)
 | 
				
			||||||
#define UI_STATE_CHECK_VISIBLE		(1 << 10)
 | 
					#define UI_STATE_CHECK_VISIBLE		(1 << 10)
 | 
				
			||||||
#define UI_STATE_QUEUED_ENSURE_VISIBLE	(1 << 11)
 | 
					#define UI_STATE_QUEUED_ENSURE_VISIBLE	(1 << 11)
 | 
				
			||||||
 | 
					#define UI_STATE_ENSURE_VISIBLE_CENTER  (1 << 12)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Behaviour modifiers:
 | 
					// Behaviour modifiers:
 | 
				
			||||||
#define UI_STATE_STRONG_PRESSED		(1 << 12)
 | 
					#define UI_STATE_STRONG_PRESSED		(1 << 12)
 | 
				
			||||||
| 
						 | 
					@ -2588,6 +2589,8 @@ struct Scrollbar : EsElement {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ScrollbarLayout(Scrollbar *scrollbar) {
 | 
					void ScrollbarLayout(Scrollbar *scrollbar) {
 | 
				
			||||||
 | 
						// TODO Do this as an UpdateAction?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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 {
 | 
				
			||||||
| 
						 | 
					@ -3194,12 +3197,16 @@ int ProcessPanelMessage(EsElement *element, EsMessage *message) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (message->type == ES_MSG_ENSURE_VISIBLE) {
 | 
						} else if (message->type == ES_MSG_ENSURE_VISIBLE) {
 | 
				
			||||||
		if (panel->scroll.enabled[0] || panel->scroll.enabled[1]) {
 | 
							if (panel->scroll.enabled[0] || panel->scroll.enabled[1]) {
 | 
				
			||||||
			EsElement *child = message->child, *e = child;
 | 
								EsElement *child = message->ensureVisible.descendent, *e = child;
 | 
				
			||||||
			int offsetX = panel->scroll.position[0], offsetY = panel->scroll.position[1];
 | 
								int offsetX = 0, offsetY = 0;
 | 
				
			||||||
			while (e != element) offsetX += e->offsetX, offsetY += e->offsetY, e = e->parent;
 | 
								while (e != element) offsetX += e->offsetX, offsetY += e->offsetY, e = e->parent;
 | 
				
			||||||
			EsRectangle bounds = panel->GetBounds();
 | 
								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;
 | 
								return ES_HANDLED;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			// This is not a scroll container, so don't update the child element being made visible.
 | 
								// 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) {
 | 
					void UISendEnsureVisibleMessage(EsElement *element, EsGeneric) {
 | 
				
			||||||
	EsElement *child = element, *e = element;
 | 
						EsElement *child = element, *e = element;
 | 
				
			||||||
 | 
						bool center = element->state & UI_STATE_ENSURE_VISIBLE_CENTER;
 | 
				
			||||||
	EsAssert(element->state & UI_STATE_QUEUED_ENSURE_VISIBLE);
 | 
						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) {
 | 
						while (e->parent) {
 | 
				
			||||||
		EsMessage m = { ES_MSG_ENSURE_VISIBLE };
 | 
							EsMessage m = { ES_MSG_ENSURE_VISIBLE };
 | 
				
			||||||
		m.child = child;
 | 
							m.ensureVisible.descendent = child;
 | 
				
			||||||
 | 
							m.ensureVisible.center = center;
 | 
				
			||||||
		e = e->parent;
 | 
							e = e->parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (ES_HANDLED == EsMessageSend(e, &m)) {
 | 
							if (ES_HANDLED == EsMessageSend(e, &m)) {
 | 
				
			||||||
| 
						 | 
					@ -6177,7 +6186,11 @@ void UISendEnsureVisibleMessage(EsElement *element, EsGeneric) {
 | 
				
			||||||
	EsAssert(~element->state & UI_STATE_QUEUED_ENSURE_VISIBLE);
 | 
						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) {
 | 
						if (~element->state & UI_STATE_QUEUED_ENSURE_VISIBLE) {
 | 
				
			||||||
		element->state |= UI_STATE_QUEUED_ENSURE_VISIBLE;
 | 
							element->state |= UI_STATE_QUEUED_ENSURE_VISIBLE;
 | 
				
			||||||
		UpdateAction action = {};
 | 
							UpdateAction action = {};
 | 
				
			||||||
| 
						 | 
					@ -6258,7 +6271,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) {
 | 
				
			||||||
		UIQueueEnsureVisibleMessage(element);
 | 
							UIQueueEnsureVisibleMessage(element, true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1632,6 +1632,11 @@ struct EsMessageScroll {
 | 
				
			||||||
	int scroll, previous;
 | 
						int scroll, previous;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct EsMessageEnsureVisible {
 | 
				
			||||||
 | 
						bool center; // If false, only center the element if it is partially obscured.
 | 
				
			||||||
 | 
						EsElement *descendent;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// List view messages.
 | 
					// List view messages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct EsMessageIterateIndex {
 | 
					struct EsMessageIterateIndex {
 | 
				
			||||||
| 
						 | 
					@ -1862,11 +1867,12 @@ struct EsMessage {
 | 
				
			||||||
		EsMessageScrollWheel scrollWheel;
 | 
							EsMessageScrollWheel scrollWheel;
 | 
				
			||||||
		EsMessageWindowActivated windowActivated;
 | 
							EsMessageWindowActivated windowActivated;
 | 
				
			||||||
		EsMessageScroll scroll;
 | 
							EsMessageScroll scroll;
 | 
				
			||||||
 | 
							EsMessageEnsureVisible ensureVisible;
 | 
				
			||||||
		const EsStyle *childStyleVariant;
 | 
							const EsStyle *childStyleVariant;
 | 
				
			||||||
		EsRectangle *accessKeyHintBounds;
 | 
							EsRectangle *accessKeyHintBounds;
 | 
				
			||||||
		EsPainter *painter;
 | 
							EsPainter *painter;
 | 
				
			||||||
		EsElement *child;
 | 
					 | 
				
			||||||
		EsCursorStyle cursorStyle;
 | 
							EsCursorStyle cursorStyle;
 | 
				
			||||||
 | 
							EsElement *child;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// List view messages:
 | 
							// List view messages:
 | 
				
			||||||
		EsMessageIterateIndex iterateIndex;
 | 
							EsMessageIterateIndex iterateIndex;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2919,6 +2919,8 @@ struct EsTextbox : EsElement {
 | 
				
			||||||
	char *editStartContent;
 | 
						char *editStartContent;
 | 
				
			||||||
	int32_t editStartContentBytes;
 | 
						int32_t editStartContentBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool ensureCaretVisibleQueued;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	EsUICallback overlayCallback;
 | 
						EsUICallback overlayCallback;
 | 
				
			||||||
	EsGeneric overlayData;
 | 
						EsGeneric overlayData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2926,7 +2928,7 @@ struct EsTextbox : EsElement {
 | 
				
			||||||
	uintptr_t activeLineAllocated;
 | 
						uintptr_t activeLineAllocated;
 | 
				
			||||||
	int32_t activeLineIndex, activeLineStart, activeLineOldBytes, activeLineBytes;
 | 
						int32_t activeLineIndex, activeLineStart, activeLineOldBytes, activeLineBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int32_t longestLine, longestLineWidth; // To set the horizontal scrollbar's size.
 | 
						int32_t longestLine, longestLineWidth; // To set the horizontal scroll bar's size.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TextboxCaret carets[2]; // carets[1] is the actual caret; carets[0] is the selection anchor.
 | 
						TextboxCaret carets[2]; // carets[1] is the actual caret; carets[0] is the selection anchor.
 | 
				
			||||||
	TextboxCaret wordSelectionAnchor, wordSelectionAnchor2;
 | 
						TextboxCaret wordSelectionAnchor, wordSelectionAnchor2;
 | 
				
			||||||
| 
						 | 
					@ -3341,11 +3343,22 @@ TextboxVisibleLine *TextboxGetVisibleLine(EsTextbox *textbox, int32_t documentLi
 | 
				
			||||||
		? nullptr : &textbox->visibleLines[documentLineIndex - textbox->firstVisibleLine];
 | 
							? 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];
 | 
						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];
 | 
							DocumentLine *line = &textbox->lines[caret.line];
 | 
				
			||||||
		int caretY = line->yPosition + textbox->insets.t;
 | 
							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);
 | 
									textbox->scroll.SetY(scrollY);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TextboxVisibleLine *visibleLine = TextboxGetVisibleLine(textbox, caret.line);
 | 
						TextboxVisibleLine *visibleLine = TextboxGetVisibleLine(textbox, caret.line);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (visibleLine) {
 | 
						if (visibleLine) {
 | 
				
			||||||
 | 
							EsRectangle bounds = textbox->GetBounds();
 | 
				
			||||||
		DocumentLine *line = &textbox->lines[caret.line];
 | 
							DocumentLine *line = &textbox->lines[caret.line];
 | 
				
			||||||
		int scrollX = textbox->scroll.position[0];
 | 
							int scrollX = textbox->scroll.position[0];
 | 
				
			||||||
		int viewportWidth = bounds.r;
 | 
							int viewportWidth = bounds.r;
 | 
				
			||||||
| 
						 | 
					@ -3386,7 +3407,19 @@ void EsTextboxEnsureCaretVisible(EsTextbox *textbox, bool verticallyCenter) {
 | 
				
			||||||
		textbox->scroll.SetX(scrollX);
 | 
							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) {
 | 
					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[0] = header->caretsBefore[0];
 | 
				
			||||||
		textbox->carets[1] = header->caretsBefore[1];
 | 
							textbox->carets[1] = header->caretsBefore[1];
 | 
				
			||||||
		EsTextboxInsert(textbox, (const char *) (header + 1), header->insertBytes, true);
 | 
							EsTextboxInsert(textbox, (const char *) (header + 1), header->insertBytes, true);
 | 
				
			||||||
 | 
							EsTextboxEnsureCaretVisible(textbox);
 | 
				
			||||||
	} else if (message->type == ES_MSG_UNDO_CANCEL) {
 | 
						} else if (message->type == ES_MSG_UNDO_CANCEL) {
 | 
				
			||||||
		// Nothing to do.
 | 
							// Nothing to do.
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue