Fixed some problems with scrolling in the edit control.
diff --git a/controls/edit.c b/controls/edit.c
index b0ca3f3..5ccc440 100644
--- a/controls/edit.c
+++ b/controls/edit.c
@@ -90,6 +90,8 @@
INT left_margin; /* in pixels */
INT right_margin; /* in pixels */
RECT format_rect;
+ INT text_width; /* width of the widest line in pixels for multi line controls
+ and just line width for single line controls */
INT region_posx; /* Position of cursor relative to region: */
INT region_posy; /* -1: to left, 0: within, 1: to right */
EDITWORDBREAKPROC16 word_break_proc16;
@@ -105,7 +107,6 @@
INT lock_count; /* amount of re-entries in the EditWndProc */
INT tabs_count;
LPINT tabs;
- INT text_width; /* width of the widest line in pixels */
LINEDEF *first_line_def; /* linked list of (soft) linebreaks */
HLOCAL hloc32W; /* our unicode local memory block */
HLOCAL16 hloc16; /* alias for 16-bit control receiving EM_GETHANDLE16
@@ -167,6 +168,7 @@
* Helper functions only valid for one type of control
*/
static void EDIT_BuildLineDefs_ML(WND *wnd, EDITSTATE *es);
+static void EDIT_CalcLineWidth_SL(WND *wnd, EDITSTATE *es);
static LPWSTR EDIT_GetPasswordPointer_SL(EDITSTATE *es);
static void EDIT_MoveDown_ML(WND *wnd, EDITSTATE *es, BOOL extend);
static void EDIT_MovePageDown_ML(WND *wnd, EDITSTATE *es, BOOL extend);
@@ -194,6 +196,7 @@
static void EDIT_SetCaretPos(WND *wnd, EDITSTATE *es, INT pos, BOOL after_wrap);
static void EDIT_SetRectNP(WND *wnd, EDITSTATE *es, LPRECT lprc);
static void EDIT_UnlockBuffer(WND *wnd, EDITSTATE *es, BOOL force);
+static void EDIT_UpdateScrollInfo(WND *wnd, EDITSTATE *es);
static INT CALLBACK EDIT_WordBreakProc(LPWSTR s, INT index, INT count, INT action);
/*
* EM_XXX message handlers
@@ -209,6 +212,7 @@
static INT EDIT_EM_LineIndex(EDITSTATE *es, INT line);
static INT EDIT_EM_LineLength(EDITSTATE *es, INT index);
static BOOL EDIT_EM_LineScroll(WND *wnd, EDITSTATE *es, INT dx, INT dy);
+static BOOL EDIT_EM_LineScroll_internal(WND *wnd, EDITSTATE *es, INT dx, INT dy);
static LRESULT EDIT_EM_PosFromChar(WND *wnd, EDITSTATE *es, INT index, BOOL after_wrap);
static void EDIT_EM_ReplaceSel(WND *wnd, EDITSTATE *es, BOOL can_undo, LPCWSTR lpsz_replace, BOOL send_update);
static LRESULT EDIT_EM_Scroll(WND *wnd, EDITSTATE *es, INT action);
@@ -1221,6 +1225,15 @@
ReleaseDC(wnd->hwndSelf, dc);
}
+/*********************************************************************
+ *
+ * EDIT_CalcLineWidth_SL
+ *
+ */
+static void EDIT_CalcLineWidth_SL(WND *wnd, EDITSTATE *es)
+{
+ es->text_width = SLOWORD(EDIT_EM_PosFromChar(wnd, es, strlenW(es->text), FALSE));
+}
/*********************************************************************
*
@@ -1474,7 +1487,7 @@
if(es->hloc32W)
{
- TRACE("Locking 32-bit UNICODE buffer\n");
+ /*TRACE("Locking 32-bit UNICODE buffer\n");*/
es->text = LocalLock(es->hloc32W);
if(es->hloc32A)
@@ -2047,19 +2060,7 @@
BOOL after_wrap)
{
LRESULT res = EDIT_EM_PosFromChar(wnd, es, pos, after_wrap);
- INT x = SLOWORD(res);
- INT y = SHIWORD(res);
-
- if(x < es->format_rect.left)
- x = es->format_rect.left;
- if(x > es->format_rect.right - 2)
- x = es->format_rect.right - 2;
- if(y > es->format_rect.bottom)
- y = es->format_rect.bottom;
- if(y < es->format_rect.top)
- y = es->format_rect.top;
- SetCaretPos(x, y);
- return;
+ SetCaretPos(SLOWORD(res), SHIWORD(res));
}
@@ -2087,10 +2088,29 @@
es->format_rect.right -= es->right_margin;
es->format_rect.right = max(es->format_rect.right, es->format_rect.left + es->char_width);
if (es->style & ES_MULTILINE)
- es->format_rect.bottom = es->format_rect.top +
- max(1, (es->format_rect.bottom - es->format_rect.top) / es->line_height) * es->line_height;
+ {
+ INT fw, vlc, max_x_offset, max_y_offset;
+
+ vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+ es->format_rect.bottom = es->format_rect.top + max(1, vlc) * es->line_height;
+
+ /* correct es->x_offset */
+ fw = es->format_rect.right - es->format_rect.left;
+ max_x_offset = es->text_width - fw;
+ if(max_x_offset < 0) max_x_offset = 0;
+ if(es->x_offset > max_x_offset)
+ es->x_offset = max_x_offset;
+
+ /* correct es->y_offset */
+ max_y_offset = es->line_count - vlc;
+ if(max_y_offset < 0) max_y_offset = 0;
+ if(es->y_offset > max_y_offset)
+ es->y_offset = max_y_offset;
+ }
else
+ /* Windows doesn't care to fix text placement for SL controls */
es->format_rect.bottom = es->format_rect.top + es->line_height;
+
if ((es->style & ES_MULTILINE) && !(es->style & ES_AUTOHSCROLL))
EDIT_BuildLineDefs_ML(wnd, es);
}
@@ -2159,6 +2179,42 @@
/*********************************************************************
*
+ * EDIT_UpdateScrollInfo
+ *
+ */
+static void EDIT_UpdateScrollInfo(WND *wnd, EDITSTATE *es)
+{
+ if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK))
+ {
+ SCROLLINFO si;
+ si.cbSize = sizeof(SCROLLINFO);
+ si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
+ si.nMin = 0;
+ si.nMax = es->line_count - 1;
+ si.nPage = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+ si.nPos = es->y_offset;
+ TRACE("SB_VERT, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
+ si.nMin, si.nMax, si.nPage, si.nPos);
+ SetScrollInfo(wnd->hwndSelf, SB_VERT, &si, TRUE);
+ }
+
+ if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK))
+ {
+ SCROLLINFO si;
+ si.cbSize = sizeof(SCROLLINFO);
+ si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
+ si.nMin = 0;
+ si.nMax = es->text_width - 1;
+ si.nPage = es->format_rect.right - es->format_rect.left;
+ si.nPos = es->x_offset;
+ TRACE("SB_HORZ, nMin=%d, nMax=%d, nPage=%d, nPos=%d\n",
+ si.nMin, si.nMax, si.nPage, si.nPos);
+ SetScrollInfo(wnd->hwndSelf, SB_HORZ, &si, TRUE);
+ }
+}
+
+/*********************************************************************
+ *
* EDIT_WordBreakProc
*
* Find the beginning of words.
@@ -2275,7 +2331,7 @@
*
* Hopefully this won't fire back at us.
* We always start with a fixed buffer in the local heap.
- * Despite of the documenation says that the local heap is used
+ * Despite of the documentation says that the local heap is used
* only if DS_LOCALEDIT flag is set, NT and 2000 always allocate
* buffer on the local heap.
*
@@ -2542,22 +2598,46 @@
*
* EM_LINESCROLL
*
- * FIXME: dx is in average character widths
- * However, we assume it is in pixels when we use this
- * function internally
+ * NOTE: dx is in average character widths, dy - in lines;
*
*/
static BOOL EDIT_EM_LineScroll(WND *wnd, EDITSTATE *es, INT dx, INT dy)
{
- INT nyoff;
-
if (!(es->style & ES_MULTILINE))
return FALSE;
- if (-dx > es->x_offset)
- dx = -es->x_offset;
- if (dx > es->text_width - es->x_offset)
- dx = es->text_width - es->x_offset;
+ dx *= es->char_width;
+ return EDIT_EM_LineScroll_internal(wnd, es, dx, dy);
+}
+
+/*********************************************************************
+ *
+ * EDIT_EM_LineScroll_internal
+ *
+ * Version of EDIT_EM_LineScroll for internal use.
+ * It doesn't refuse if ES_MULTILINE is set and assumes that
+ * dx is in pixels, dy - in lines.
+ *
+ */
+static BOOL EDIT_EM_LineScroll_internal(WND *wnd, EDITSTATE *es, INT dx, INT dy)
+{
+ INT nyoff;
+ INT x_offset_in_pixels;
+
+ if (es->style & ES_MULTILINE)
+ {
+ x_offset_in_pixels = es->x_offset;
+ }
+ else
+ {
+ dy = 0;
+ x_offset_in_pixels = SLOWORD(EDIT_EM_PosFromChar(wnd, es, es->x_offset, FALSE));
+ }
+
+ if (-dx > x_offset_in_pixels)
+ dx = -x_offset_in_pixels;
+ if (dx > es->text_width - x_offset_in_pixels)
+ dx = es->text_width - x_offset_in_pixels;
nyoff = max(0, es->y_offset + dy);
if (nyoff >= es->line_count)
nyoff = es->line_count - 1;
@@ -2565,12 +2645,17 @@
if (dx || dy) {
RECT rc1;
RECT rc;
+
+ es->y_offset = nyoff;
+ if(es->style & ES_MULTILINE)
+ es->x_offset += dx;
+ else
+ es->x_offset += dx / es->char_width;
+
GetClientRect(wnd->hwndSelf, &rc1);
IntersectRect(&rc, &rc1, &es->format_rect);
ScrollWindowEx(wnd->hwndSelf, -dx, dy,
NULL, &rc, (HRGN)NULL, NULL, SW_INVALIDATE);
- es->y_offset = nyoff;
- es->x_offset += dx;
}
if (dx && !(es->flags & EF_HSCROLL_TRACK))
EDIT_NOTIFY_PARENT(wnd, EN_HSCROLL, "EN_HSCROLL");
@@ -2742,6 +2827,8 @@
/* FIXME: really inefficient */
if (es->style & ES_MULTILINE)
EDIT_BuildLineDefs_ML(wnd, es);
+ else
+ EDIT_CalcLineWidth_SL(wnd, es);
EDIT_EM_SetSel(wnd, es, s, s, FALSE);
es->flags |= EF_MODIFIED;
@@ -2788,8 +2875,14 @@
return (LRESULT)FALSE;
}
if (dy) {
+ INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
+ /* check if we are going to move too far */
+ if(es->y_offset + dy > es->line_count - vlc)
+ dy = es->line_count - vlc - es->y_offset;
+
+ /* Notification is done in EDIT_EM_LineScroll */
+ if(dy)
EDIT_EM_LineScroll(wnd, es, 0, dy);
- EDIT_NOTIFY_PARENT(wnd, EN_VSCROLL, "EN_VSCROLL");
}
return MAKELONG((INT16)dy, (BOOL16)TRUE);
}
@@ -2826,7 +2919,13 @@
if (x > es->format_rect.right)
dx = x - es->format_rect.left - (HSCROLL_FRACTION - 1) * ww / HSCROLL_FRACTION / cw * cw;
if (dy || dx)
- EDIT_EM_LineScroll(wnd, es, dx, dy);
+ {
+ /* check if we are going to move too far */
+ if(es->x_offset + dx + ww > es->text_width)
+ dx = es->text_width - ww - es->x_offset;
+ if(dx || dy)
+ EDIT_EM_LineScroll_internal(wnd, es, dx, dy);
+ }
} else {
INT x;
INT goal;
@@ -2858,6 +2957,9 @@
EDIT_UpdateText(wnd, NULL, TRUE);
}
}
+
+ if(es->flags & EF_FOCUSED)
+ EDIT_SetCaretPos(wnd, es, es->selection_end, es->flags & EF_AFTER_WRAP);
}
@@ -3107,8 +3209,6 @@
es->flags |= EF_AFTER_WRAP;
else
es->flags &= ~EF_AFTER_WRAP;
- if (es->flags & EF_FOCUSED)
- EDIT_SetCaretPos(wnd, es, end, after_wrap);
/* This is a little bit more efficient than before, not sure if it can be improved. FIXME? */
ORDER_UINT(start, end);
ORDER_UINT(end, old_end);
@@ -3242,6 +3342,7 @@
EDIT_EM_EmptyUndoBuffer(es);
EDIT_EM_ReplaceSel(wnd, es, TRUE, utext, TRUE);
EDIT_EM_SetSel(wnd, es, es->undo_position, es->undo_position + es->undo_insert_count, FALSE);
+ EDIT_EM_ScrollCaret(wnd, es);
HeapFree(GetProcessHeap(), 0, utext);
TRACE("after UNDO:insertion length = %d, deletion buffer = %s\n",
@@ -3636,7 +3737,14 @@
return 0;
}
if (dx)
- EDIT_EM_LineScroll(wnd, es, dx, 0);
+ {
+ INT fw = es->format_rect.right - es->format_rect.left;
+ /* check if we are going to move too far */
+ if(es->x_offset + dx + fw > es->text_width)
+ dx = es->text_width - fw - es->x_offset;
+ if(dx)
+ EDIT_EM_LineScroll_internal(wnd, es, dx, 0);
+ }
return ret;
}
@@ -3706,7 +3814,14 @@
return 0;
}
if (dx)
- EDIT_EM_LineScroll(wnd, es, dx, 0);
+ {
+ INT fw = es->format_rect.right - es->format_rect.left;
+ /* check if we are going to move too far */
+ if(es->x_offset + dx + fw > es->text_width)
+ dx = es->text_width - fw - es->x_offset;
+ if(dx)
+ EDIT_EM_LineScroll_internal(wnd, es, dx, 0);
+ }
return 0;
}
@@ -4180,33 +4295,11 @@
}
if (es->font)
SelectObject(dc, old_font);
- if (es->flags & EF_FOCUSED)
- EDIT_SetCaretPos(wnd, es, es->selection_end,
- es->flags & EF_AFTER_WRAP);
+
if (!wParam)
EndPaint(wnd->hwndSelf, &ps);
- if ((es->style & WS_VSCROLL) && !(es->flags & EF_VSCROLL_TRACK)) {
- INT vlc = (es->format_rect.bottom - es->format_rect.top) / es->line_height;
- SCROLLINFO si;
- si.cbSize = sizeof(SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
- si.nMin = 0;
- si.nMax = es->line_count + vlc - 2;
- si.nPage = vlc;
- si.nPos = es->y_offset;
- SetScrollInfo(wnd->hwndSelf, SB_VERT, &si, TRUE);
- }
- if ((es->style & WS_HSCROLL) && !(es->flags & EF_HSCROLL_TRACK)) {
- SCROLLINFO si;
- INT fw = es->format_rect.right - es->format_rect.left;
- si.cbSize = sizeof(SCROLLINFO);
- si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;
- si.nMin = 0;
- si.nMax = es->text_width + fw - 1;
- si.nPage = fw;
- si.nPos = es->x_offset;
- SetScrollInfo(wnd->hwndSelf, SB_HORZ, &si, TRUE);
- }
+
+ EDIT_UpdateScrollInfo(wnd, es);
}
@@ -4289,6 +4382,8 @@
if (es->style & ES_MULTILINE)
EDIT_BuildLineDefs_ML(wnd, es);
+ else
+ EDIT_CalcLineWidth_SL(wnd, es);
if (redraw)
EDIT_UpdateText(wnd, NULL, TRUE);