>From 7604617920f3735e0800dc60675a6b9a51395fb9 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Thu, 22 Sep 2011 17:56:40 +0400
Subject: [PATCH 3/3] Enable multiple calendars support

---
 dlls/comctl32/monthcal.c       |  108 ++++++++++++++++++++++++++--------------
 dlls/comctl32/tests/monthcal.c |   22 +++-----
 2 files changed, 78 insertions(+), 52 deletions(-)

diff --git a/dlls/comctl32/monthcal.c b/dlls/comctl32/monthcal.c
index 762a792..5f8a36c 100644
--- a/dlls/comctl32/monthcal.c
+++ b/dlls/comctl32/monthcal.c
@@ -71,6 +71,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(monthcal);
 #define MC_PREVNEXTMONTHTIMER   1	/* Timer IDs */
 #define MC_TODAYUPDATETIMER     2
 
+#define MC_CALENDAR_PADDING     6
+
 #define countof(arr) (sizeof(arr)/sizeof(arr[0]))
 
 /* convert from days to 100 nanoseconds unit - used as FILETIME unit */
@@ -2392,7 +2394,6 @@ MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
 static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
 {
   static const WCHAR O0W[] = { '0','0',0 };
-  HDC hdc = GetDC(infoPtr->hwndSelf);
   RECT *title=&infoPtr->calendars[0].title;
   RECT *prev=&infoPtr->titlebtnprev;
   RECT *next=&infoPtr->titlebtnnext;
@@ -2402,16 +2403,19 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
   RECT *weeknumrect=&infoPtr->calendars[0].weeknums;
   RECT *days=&infoPtr->calendars[0].days;
   RECT *todayrect=&infoPtr->todayrect;
-  SIZE size, sz;
+
+  INT xdiv, dx, dy, i, j, x, y, c_dx, c_dy;
+  WCHAR buff[80];
   TEXTMETRICW tm;
-  HFONT currentFont;
-  INT xdiv, dx, dy, i;
+  SIZE size, sz;
   RECT client;
-  WCHAR buff[80];
+  HFONT font;
+  HDC hdc;
 
   GetClientRect(infoPtr->hwndSelf, &client);
 
-  currentFont = SelectObject(hdc, infoPtr->hFont);
+  hdc = GetDC(infoPtr->hwndSelf);
+  font = SelectObject(hdc, infoPtr->hFont);
 
   /* get the height and width of each day's text */
   GetTextMetricsW(hdc, &tm);
@@ -2441,6 +2445,10 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
   /* recalculate the height and width increments and offsets */
   GetTextExtentPoint32W(hdc, O0W, 2, &size);
 
+  /* restore the originally selected font */
+  SelectObject(hdc, font);
+  ReleaseDC(infoPtr->hwndSelf, hdc);
+
   xdiv = (infoPtr->dwStyle & MCS_WEEKNUMBERS) ? 8 : 7;
 
   infoPtr->width_increment  = size.cx * 2 + 4;
@@ -2461,21 +2469,17 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
   next->right  = title->right - 4;
   next->left   = next->right - (title->bottom - title->top);
 
-  /* titlemonth->left and right change based upon the current month */
-  /* and are recalculated in refresh as the current month may change */
-  /* without the control being resized */
+  /* titlemonth->left and right change based upon the current month
+     and are recalculated in refresh as the current month may change
+     without the control being resized */
   titlemonth->top    = titleyear->top    = title->top    + (infoPtr->height_increment)/2;
   titlemonth->bottom = titleyear->bottom = title->bottom - (infoPtr->height_increment)/2;
 
-  /* setup the dimensions of the rectangle we draw the names of the */
-  /* days of the week in */
-  weeknumrect->left = 0;
-
-  if(infoPtr->dwStyle & MCS_WEEKNUMBERS)
-    weeknumrect->right = prev->right;
-  else
-    weeknumrect->right = weeknumrect->left;
+  /* week numbers */
+  weeknumrect->left  = 0;
+  weeknumrect->right = infoPtr->dwStyle & MCS_WEEKNUMBERS ? prev->right : 0;
 
+  /* days abbreviated names */
   wdays->left   = days->left   = weeknumrect->right;
   wdays->right  = days->right  = wdays->left + 7 * infoPtr->width_increment;
   wdays->top    = title->bottom;
@@ -2489,29 +2493,62 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
   todayrect->top    = days->bottom;
   todayrect->bottom = days->bottom + infoPtr->height_increment;
 
+  /* compute calendar count, update all calendars */
+  x = (client.right  + MC_CALENDAR_PADDING) / (title->right - title->left + MC_CALENDAR_PADDING);
+  /* today label affects whole height */
+  if (infoPtr->dwStyle & MCS_NOTODAY)
+    y = (client.bottom + MC_CALENDAR_PADDING) / (days->bottom - title->top + MC_CALENDAR_PADDING);
+  else
+    y = (client.bottom - todayrect->bottom + todayrect->top + MC_CALENDAR_PADDING) /
+         (days->bottom - title->top + MC_CALENDAR_PADDING);
+
+  /* TODO: ensure that count is properly adjusted to fit 12 months constraint */
+  if (x == 0) x = 1;
+  if (y == 0) y = 1;
+
+  infoPtr->dim.cx = x;
+  infoPtr->dim.cy = y;
+  infoPtr->calendars = ReAlloc(infoPtr->calendars, MONTHCAL_GetCalCount(infoPtr) * sizeof(CALENDAR_INFO));
+
+  for (i = 1; i < MONTHCAL_GetCalCount(infoPtr); i++)
+  {
+      /* set months */
+      infoPtr->calendars[i] = infoPtr->calendars[0];
+      MONTHCAL_GetMonth(&infoPtr->calendars[i].month, i);
+  }
+
   /* offset all rectangles to center in client area */
-  dx = (client.right  - title->right) / 2;
-  dy = (client.bottom - todayrect->bottom) / 2;
+  c_dx = (client.right  - x * title->right - MC_CALENDAR_PADDING * (x-1)) / 2;
+  c_dy = (client.bottom - y * todayrect->bottom - MC_CALENDAR_PADDING * (y-1)) / 2;
 
   /* if calendar doesn't fit client area show it at left/top bounds */
-  if (title->left + dx < 0) dx = 0;
-  if (title->top  + dy < 0) dy = 0;
+  if (title->left + c_dx < 0) c_dx = 0;
+  if (title->top  + c_dy < 0) c_dy = 0;
 
-  if (dx != 0 || dy != 0)
+  for (i = 0; i < y; i++)
   {
-    OffsetRect(title, dx, dy);
-    OffsetRect(prev,  dx, dy);
-    OffsetRect(next,  dx, dy);
-    OffsetRect(titlemonth, dx, dy);
-    OffsetRect(titleyear, dx, dy);
-    OffsetRect(wdays, dx, dy);
-    OffsetRect(weeknumrect, dx, dy);
-    OffsetRect(days, dx, dy);
-    OffsetRect(todayrect, dx, dy);
+      for (j = 0; j < x; j++)
+      {
+          dx = j*(title->right - title->left + MC_CALENDAR_PADDING) + c_dx;
+          dy = i*(days->bottom - title->top  + MC_CALENDAR_PADDING) + c_dy;
+
+          OffsetRect(&infoPtr->calendars[i*x+j].title, dx, dy);
+          OffsetRect(&infoPtr->calendars[i*x+j].titlemonth, dx, dy);
+          OffsetRect(&infoPtr->calendars[i*x+j].titleyear, dx, dy);
+          OffsetRect(&infoPtr->calendars[i*x+j].wdays, dx, dy);
+          OffsetRect(&infoPtr->calendars[i*x+j].weeknums, dx, dy);
+          OffsetRect(&infoPtr->calendars[i*x+j].days, dx, dy);
+      }
   }
 
-  /* TODO: update calendars count */
-  infoPtr->dim.cx = infoPtr->dim.cy = 1;
+  OffsetRect(prev, c_dx, c_dy);
+  OffsetRect(next, (x-1)*(title->right - title->left + MC_CALENDAR_PADDING) + c_dx, c_dy);
+
+  i = infoPtr->dim.cx * infoPtr->dim.cy - infoPtr->dim.cx;
+  todayrect->left   = infoPtr->calendars[i].title.left;
+  todayrect->right  = infoPtr->calendars[i].title.right;
+  todayrect->top    = infoPtr->calendars[i].days.bottom;
+  todayrect->bottom = infoPtr->calendars[i].days.bottom + infoPtr->height_increment;
 
   TRACE("dx=%d dy=%d client[%s] title[%s] wdays[%s] days[%s] today[%s]\n",
 	infoPtr->width_increment,infoPtr->height_increment,
@@ -2520,11 +2557,6 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
         wine_dbgstr_rect(wdays),
         wine_dbgstr_rect(days),
         wine_dbgstr_rect(todayrect));
-
-  /* restore the originally selected font */
-  SelectObject(hdc, currentFont);
-
-  ReleaseDC(infoPtr->hwndSelf, hdc);
 }
 
 static LRESULT MONTHCAL_Size(MONTHCAL_INFO *infoPtr, int Width, int Height)
diff --git a/dlls/comctl32/tests/monthcal.c b/dlls/comctl32/tests/monthcal.c
index 87aadec..ccf8881 100644
--- a/dlls/comctl32/tests/monthcal.c
+++ b/dlls/comctl32/tests/monthcal.c
@@ -1316,18 +1316,15 @@ static void test_monthrange(void)
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
 
     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st_visible);
-    todo_wine {
-        expect(2, res);
-    }
+    expect(2, res);
+
     expect(2000, st_visible[0].wYear);
     expect(11, st_visible[0].wMonth);
     expect(1, st_visible[0].wDay);
     expect(2000, st_visible[1].wYear);
+    expect(12, st_visible[1].wMonth);
+    expect(31, st_visible[1].wDay);
 
-    todo_wine {
-        expect(12, st_visible[1].wMonth);
-        expect(31, st_visible[1].wDay);
-    }
     res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_DAYSTATE, (LPARAM)st_daystate);
     todo_wine {
         expect(4, res);
@@ -1335,12 +1332,9 @@ static void test_monthrange(void)
     expect(2000, st_daystate[0].wYear);
     expect(10, st_daystate[0].wMonth);
     expect(29, st_daystate[0].wDay);
-
-    todo_wine {
-        expect(2001, st_daystate[1].wYear);
-        expect(1, st_daystate[1].wMonth);
-        expect(6, st_daystate[1].wDay);
-    }
+    expect(2001, st_daystate[1].wYear);
+    expect(1, st_daystate[1].wMonth);
+    expect(6, st_daystate[1].wDay);
 
     ok_sequence(sequences, MONTHCAL_SEQ_INDEX, monthcal_monthrange_seq, "monthcal monthrange", FALSE);
 
@@ -1814,7 +1808,7 @@ static void test_MCM_GETCALENDARCOUNT(void)
         return;
     }
 
-    todo_wine expect(2, ret);
+    expect(2, ret);
 
     DestroyWindow(hwnd);
 }
-- 
1.5.6.5

