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;
|
||||
|
||||
|
@ -2926,7 +2928,7 @@ struct EsTextbox : EsElement {
|
|||
uintptr_t activeLineAllocated;
|
||||
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 wordSelectionAnchor, wordSelectionAnchor2;
|
||||
|
@ -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) {
|
|||
}
|
||||
}
|
||||
|
||||
textbox->scroll.SetY(scrollY);
|
||||
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