Edit control: Fix margin bugs

Michael Kaufmann hallo at michael-kaufmann.ch
Sat Jun 25 05:49:32 CDT 2005


Changelog:
  - Remove the old margins from the format rectangle before adding the 
new margins
  - Adjust the format rectangle and repaint the control after the 
margins have been set
  - New tests

-------------- next part --------------
Index: dlls/user/edit.c
===================================================================
RCS file: /home/wine/wine/dlls/user/edit.c,v
retrieving revision 1.32
diff -u -r1.32 edit.c
--- dlls/user/edit.c	24 Jun 2005 11:33:23 -0000	1.32
+++ dlls/user/edit.c	24 Jun 2005 23:20:07 -0000
@@ -213,6 +213,7 @@
 static void	EDIT_PaintLine(EDITSTATE *es, HDC hdc, INT line, BOOL rev);
 static INT	EDIT_PaintText(EDITSTATE *es, HDC hdc, INT x, INT y, INT line, INT col, INT count, BOOL rev);
 static void	EDIT_SetCaretPos(EDITSTATE *es, INT pos, BOOL after_wrap);
+static void	EDIT_AdjustFormatRect(EDITSTATE *es);
 static void	EDIT_SetRectNP(EDITSTATE *es, LPRECT lprc);
 static void	EDIT_UnlockBuffer(EDITSTATE *es, BOOL force);
 static void	EDIT_UpdateScrollInfo(EDITSTATE *es);
@@ -239,7 +240,7 @@
 static void	EDIT_EM_SetHandle(EDITSTATE *es, HLOCAL hloc);
 static void	EDIT_EM_SetHandle16(EDITSTATE *es, HLOCAL16 hloc);
 static void	EDIT_EM_SetLimitText(EDITSTATE *es, INT limit);
-static void	EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right);
+static void	EDIT_EM_SetMargins(EDITSTATE *es, INT action, INT left, INT right, BOOL repaint);
 static void	EDIT_EM_SetPasswordChar(EDITSTATE *es, WCHAR c);
 static void	EDIT_EM_SetSel(EDITSTATE *es, UINT start, UINT end, BOOL after_wrap);
 static BOOL	EDIT_EM_SetTabStops(EDITSTATE *es, INT count, LPINT tabs);
@@ -735,7 +736,7 @@
 	/* The following EM_xxx are new to win95 and don't exist for 16 bit */
 
 	case EM_SETMARGINS:
-		EDIT_EM_SetMargins(es, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
+		EDIT_EM_SetMargins(es, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam), TRUE);
 		break;
 
 	case EM_GETMARGINS:
@@ -2233,41 +2234,16 @@
 
 /*********************************************************************
  *
- *	EDIT_SetRectNP
+ *	EDIT_AdjustFormatRect
  *
- *	note:	this is not (exactly) the handler called on EM_SETRECTNP
- *		it is also used to set the rect of a single line control
+ *	Adjusts the format rectangle for the current font and the
+ *	current client rectangle.
  *
  */
-static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
+static void EDIT_AdjustFormatRect(EDITSTATE *es)
 {
 	RECT ClientRect;
-	LONG_PTR ExStyle;
-
-	CopyRect(&es->format_rect, rc);
-	ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
-	if ((es->style & WS_POPUP) && !(ExStyle & WS_EX_CLIENTEDGE)) {
-		if (es->style & WS_BORDER) {
-			INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
-			es->format_rect.left += bw;
-			es->format_rect.right -= bw;
-			if (es->line_height + 2 * bw <=
-			    es->format_rect.bottom - es->format_rect.top) {
-				es->format_rect.top += bw;
-				es->format_rect.bottom -= bw;
-			}
-		}
-	} else {
-		if (es->line_height + 2 <=
-			es->format_rect.bottom - es->format_rect.top) {
-			es->format_rect.top++;
-			es->format_rect.bottom--;
-		}
-		es->format_rect.left++;
-		es->format_rect.right--;
-	}
-	es->format_rect.left += es->left_margin;
-	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)
 	{
@@ -2309,6 +2285,47 @@
 
 /*********************************************************************
  *
+ *	EDIT_SetRectNP
+ *
+ *	note:	this is not (exactly) the handler called on EM_SETRECTNP
+ *		it is also used to set the rect of a single line control
+ *
+ */
+static void EDIT_SetRectNP(EDITSTATE *es, LPRECT rc)
+{
+	LONG_PTR ExStyle;
+
+	CopyRect(&es->format_rect, rc);
+	ExStyle = GetWindowLongPtrW(es->hwndSelf, GWL_EXSTYLE);
+	if ((es->style & WS_POPUP) && !(ExStyle & WS_EX_CLIENTEDGE)) {
+		if (es->style & WS_BORDER) {
+			INT bw = GetSystemMetrics(SM_CXBORDER) + 1;
+			es->format_rect.left += bw;
+			es->format_rect.right -= bw;
+			if (es->line_height + 2 * bw <=
+		    	es->format_rect.bottom - es->format_rect.top) {
+				es->format_rect.top += bw;
+				es->format_rect.bottom -= bw;
+			}
+		}
+	} else {
+		if (es->line_height + 2 <=
+			es->format_rect.bottom - es->format_rect.top) {
+			es->format_rect.top++;
+			es->format_rect.bottom--;
+		}
+		es->format_rect.left++;
+		es->format_rect.right--;
+	}
+	
+	es->format_rect.left += es->left_margin;
+	es->format_rect.right -= es->right_margin;
+	EDIT_AdjustFormatRect(es);
+}
+
+
+/*********************************************************************
+ *
  *	EDIT_UnlockBuffer
  *
  */
@@ -3557,7 +3574,7 @@
  *
  */
 static void EDIT_EM_SetMargins(EDITSTATE *es, INT action,
-			       INT left, INT right)
+			       INT left, INT right, BOOL repaint)
 {
 	TEXTMETRICW tm;
 	INT default_left_margin  = 0; /* in pixels */
@@ -3579,18 +3596,28 @@
         }
 
 	if (action & EC_LEFTMARGIN) {
+		es->format_rect.left -= es->left_margin;
 		if (left != EC_USEFONTINFO)
 			es->left_margin = left;
 		else
 			es->left_margin = default_left_margin;
+		es->format_rect.left += es->left_margin;
 	}
 
 	if (action & EC_RIGHTMARGIN) {
+		es->format_rect.right += es->right_margin;
 		if (right != EC_USEFONTINFO)
  			es->right_margin = right;
 		else
 			es->right_margin = default_right_margin;
+		es->format_rect.right -= es->right_margin;
 	}
+	
+	if (action & (EC_LEFTMARGIN | EC_RIGHTMARGIN)) {
+		EDIT_AdjustFormatRect(es);
+		if (repaint) EDIT_UpdateText(es, NULL, TRUE);
+	}
+	
 	TRACE("left=%d, right=%d\n", es->left_margin, es->right_margin);
 }
 
@@ -4005,6 +4032,8 @@
  */
 static LRESULT EDIT_WM_Create(EDITSTATE *es, LPCWSTR name)
 {
+        RECT clientRect;
+        
 	TRACE("%s\n", debugstr_w(name));
        /*
         *	To initialize some final structure members, we call some helper
@@ -4014,6 +4043,11 @@
         */
         EDIT_WM_SetFont(es, 0, FALSE);
         EDIT_EM_EmptyUndoBuffer(es);
+        
+        /* We need to calculate the format rect
+           (applications may send EM_SETMARGINS before the control gets visible) */
+        GetClientRect(es->hwndSelf, &clientRect);
+        EDIT_SetRectNP(es, &clientRect);
 
        if (name && *name) {
 	   EDIT_EM_ReplaceSel(es, FALSE, name, FALSE, TRUE);
@@ -4796,7 +4830,7 @@
 	TEXTMETRICW tm;
 	HDC dc;
 	HFONT old_font = 0;
-	RECT r;
+	RECT clientRect;
 
 	es->font = font;
 	dc = GetDC(es->hwndSelf);
@@ -4808,12 +4842,12 @@
 	if (font)
 		SelectObject(dc, old_font);
 	ReleaseDC(es->hwndSelf, dc);
+	
+	/* Reset the format rect and the margins */
+	GetClientRect(es->hwndSelf, &clientRect);
+	EDIT_SetRectNP(es, &clientRect);
 	EDIT_EM_SetMargins(es, EC_LEFTMARGIN | EC_RIGHTMARGIN,
-			   EC_USEFONTINFO, EC_USEFONTINFO);
-
-	/* Force the recalculation of the format rect for each font change */
-	GetClientRect(es->hwndSelf, &r);
-	EDIT_SetRectNP(es, &r);
+			   EC_USEFONTINFO, EC_USEFONTINFO, FALSE);
 
 	if (es->style & ES_MULTILINE)
 		EDIT_BuildLineDefs_ML(es, 0, strlenW(es->text), 0, NULL);
Index: dlls/user/tests/edit.c
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/edit.c,v
retrieving revision 1.9
diff -u -r1.9 edit.c
--- dlls/user/tests/edit.c	20 Jun 2005 14:18:03 -0000	1.9
+++ dlls/user/tests/edit.c	24 Jun 2005 23:20:08 -0000
@@ -916,6 +916,64 @@
     DestroyWindow(hwEdit);
 }
 
+static void test_margins(void)
+{
+    HWND hwEdit;
+    RECT old_rect, new_rect;
+    INT old_left_margin, old_right_margin;
+    DWORD old_margins, new_margins;
+
+    hwEdit = create_editcontrol(WS_BORDER, 0);
+    
+    old_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
+    old_left_margin = LOWORD(old_margins);
+    old_right_margin = HIWORD(old_margins);
+    
+    /* Check if setting the margins works */
+    
+    SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 0));
+    new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
+    ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
+    ok(HIWORD(new_margins) == old_right_margin, "Wrong right margin: %d\n", HIWORD(new_margins));
+    
+    SendMessage(hwEdit, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, 10));
+    new_margins = SendMessage(hwEdit, EM_GETMARGINS, 0, 0);
+    ok(LOWORD(new_margins) == 10, "Wrong left margin: %d\n", LOWORD(new_margins));
+    ok(HIWORD(new_margins) == 10, "Wrong right margin: %d\n", HIWORD(new_margins));
+    
+    
+    /* The size of the rectangle must decrease if we increase the margin */
+    
+    SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(5, 5));
+    SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
+    SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(15, 20));
+    SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+    ok(new_rect.left == old_rect.left + 10, "The left border of the rectangle is wrong\n");
+    ok(new_rect.right == old_rect.right - 15, "The right border of the rectangle is wrong\n");
+    ok(new_rect.top == old_rect.top, "The top border of the rectangle must not change\n");
+    ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle must not change\n");
+    
+    
+    /* If we set the margin to same value as the current margin,
+       the rectangle must not change */
+    
+    SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
+    old_rect.left = 1;
+    old_rect.right = 99;
+    old_rect.top = 1;
+    old_rect.bottom = 99;
+    SendMessage(hwEdit, EM_SETRECT, 0, (LPARAM)&old_rect);    
+    SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&old_rect);
+    SendMessage(hwEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(10, 10));
+    SendMessage(hwEdit, EM_GETRECT, 0, (LPARAM)&new_rect);
+    ok(new_rect.left == old_rect.left, "The left border of the rectangle has changed\n");
+    ok(new_rect.right == old_rect.right, "The right border of the rectangle has changed\n");
+    ok(new_rect.top == old_rect.top, "The top border of the rectangle has changed\n");
+    ok(new_rect.bottom == old_rect.bottom, "The bottom border of the rectangle has changed\n");
+    
+    DestroyWindow (hwEdit);
+}
+
 START_TEST(edit)
 {
     hinst = GetModuleHandleA (NULL);
@@ -926,4 +984,5 @@
     test_edit_control_2();
     test_edit_control_3();
     test_edit_control_4();
+    test_margins();
 }


More information about the wine-patches mailing list