Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

606 lines
17 KiB

  1. /*
  2. * Windows Calendar
  3. * Copyright (c) 1985 by Microsoft Corporation, all rights reserved.
  4. * Written by Mark L. Chamberlin, consultant to Microsoft.
  5. *
  6. ****** calmonth.c
  7. *
  8. */
  9. #include "cal.h"
  10. /**** GetWeekday - calculate day of week from D3. */
  11. WORD APIENTRY GetWeekday (D3*pd3)
  12. {
  13. /* Add 2 since January 1, 1980 was a Tuesday. */
  14. return ((DtFromPd3 (pd3) + 2) % 7);
  15. }
  16. /**** CDaysMonth - return the number of days in the month specified
  17. by the month and year of the D3 argument.
  18. ****/
  19. INT APIENTRY CDaysMonth (D3*pd3)
  20. {
  21. register INT cDays;
  22. /* Calculate the number of days in the current month (adding in
  23. one if this is a leap year and the month is past February.
  24. */
  25. cDays = vrgcDaysMonth [pd3 -> wMonth];
  26. if (pd3 -> wYear % 4 == 0 && pd3 -> wMonth == MONTHFEB)
  27. cDays++;
  28. return (cDays);
  29. }
  30. /**** SetUpMonth - Based on vd3Sel, set up the following:
  31. - vcDaysMonth - number of days in the month being displayed.
  32. - vcWeeksMonth - the number of weeks needed to display the month
  33. (4, 5, or 6).
  34. - vrgbMonth - the array of days. 0's indicate unused entries.
  35. ****/
  36. VOID APIENTRY SetUpMonth ()
  37. {
  38. WORD wDay;
  39. INT *pb; /* changed from BYTE to int */
  40. D3 d3Temp;
  41. INT i;
  42. for (i=0; i< CBMONTHARRAY;i++)
  43. vrgbMonth[i]=0;
  44. /* FillBuf (vrgbMonth, CBMONTHARRAY*sizeof(int), 0); */
  45. /* Set up the count of days in the month. */
  46. vcDaysMonth = CDaysMonth (&vd3Sel);
  47. /* Get the weekday of the the first day of the month. */
  48. d3Temp = vd3Sel;
  49. d3Temp.wDay = 0;
  50. vwWeekdayFirst = GetWeekday (&d3Temp);
  51. /* Calculate the number of weeks we will need to display. */
  52. vcWeeksMonth = (vwWeekdayFirst + 6 + vcDaysMonth) / 7;
  53. /* Fill in the days. */
  54. pb = vrgbMonth + vwWeekdayFirst;
  55. for (wDay = 1; (WORD)wDay <= (WORD)vcDaysMonth; wDay++)
  56. /* *pb++ = (BYTE)wDay; */
  57. *pb++ = wDay;
  58. /* Set the TODAY bit of the appropriate day if today
  59. is in this month.
  60. */
  61. if (vd3Cur.wMonth == vd3Sel.wMonth && vd3Cur.wYear == vd3Sel.wYear)
  62. vrgbMonth [vwWeekdayFirst + vd3Cur.wDay] |= TODAY;
  63. /* Set the marked bits for the marked days in this month. */
  64. GetMarkedDays ();
  65. }
  66. /**** BuildMonthGrid */
  67. VOID APIENTRY BuildMonthGrid ()
  68. {
  69. INT dx;
  70. INT dy;
  71. INT xco;
  72. INT yco;
  73. INT cLines;
  74. /* Calculate the x coordinates if vertical scrollbar is absent */
  75. if (vmScrollMax == 0)
  76. {
  77. dx = (vcxWnd2B + vcxBorder + vcxVScrollBar)/ 7;
  78. vrgxcoGrid [7] = vcxWnd2B + vcxHScrollBar;
  79. }
  80. else
  81. {
  82. /* Calculate the x coordinates if vertical scrollbar is present */
  83. dx = (vcxWnd2B + vcxBorder) / 7;
  84. vrgxcoGrid [7] = vcxWnd2B ;
  85. }
  86. xco = - vcxBorder;
  87. for (cLines = 0; cLines < 7; cLines++)
  88. {
  89. vrgxcoGrid [cLines] = xco;
  90. xco += dx;
  91. }
  92. /* Calculate the y coordinates if horiz. scrollbar is absent. */
  93. if (hmScrollMax == 0)
  94. {
  95. dy = (vcyWnd2BBot - vcyBorder + vcyHScrollBar)/vcWeeksMonth;
  96. vrgycoGrid [vcWeeksMonth] = vcyWnd2B;
  97. }
  98. /* Calculate the y coordinates if horiz. scrollbar is present. */
  99. else
  100. {
  101. dy = (vcyWnd2BBot - vcyBorder) / vcWeeksMonth;
  102. vrgycoGrid [vcWeeksMonth] = vcyWnd2B - vcyHScrollBar;
  103. }
  104. yco = vcyWnd2BTop;
  105. for (cLines = 0; cLines < vcWeeksMonth; cLines++)
  106. {
  107. vrgycoGrid [cLines] = yco;
  108. yco += dy;
  109. }
  110. }
  111. /**** PaintMonthGrid - Paint the grid for the monthly calendar display. */
  112. VOID APIENTRY PaintMonthGrid (HDC hDC)
  113. {
  114. INT *pcoCur;
  115. INT *pcoMax;
  116. BuildMonthGrid ();
  117. /* Draw the horizontal lines. */
  118. pcoCur = vrgycoGrid;
  119. for (pcoMax = pcoCur+vcWeeksMonth; pcoCur < pcoMax; pcoCur++)
  120. PatBlt (hDC, 0, *pcoCur, vcxWnd2B + vcxVScrollBar, vcyBorder, PATCOPY);
  121. /* Draw the vertical lines. */
  122. pcoCur = vrgxcoGrid + 1;
  123. for (pcoMax = pcoCur+6; pcoCur < pcoMax; pcoCur++)
  124. PatBlt(hDC, *pcoCur, vcyWnd2BTop, vcxBorder, vcyWnd2BBot + vcyHScrollBar, PATCOPY);
  125. }
  126. /**** PaintMonth */
  127. VOID APIENTRY PaintMonth (HDC hDC)
  128. {
  129. INT xcoBox;
  130. INT ycoBox;
  131. INT dx;
  132. INT dy;
  133. INT xcoText;
  134. INT ycoText;
  135. INT cDay;
  136. INT cWeek;
  137. INT cch;
  138. CHAR *pch;
  139. INT *pb; /* changed from BYTE to int */
  140. INT *pxcoCur;
  141. INT *pycoCur;
  142. CHAR rgchDayAbbrevs[4];
  143. CHAR rgch[CCHDATEDISP];
  144. DOSDATE dd;
  145. extern HANDLE hinstTimeDate;
  146. INT iWeekStart; /* week no. of month which will appear on top row
  147. in monthview */
  148. INT iWeekEnd; /* week no. which will appear on last row of
  149. month view */
  150. INT iDayStart; /* weekday which will appear on leftmost column */
  151. INT iDayEnd; /* weekday which will appear on rightmost column */
  152. INT MarkedBits; /* the marked bits extracted from a day */
  153. dd.year = vd3Sel.wYear + 1980;
  154. dd.month = vd3Sel.wMonth + 1;
  155. cch = GetLongDateString(&dd, rgch, GDS_LONG | GDS_NODAY);
  156. xcoText = (vcxWnd2B - cch * vcxFont) / 2;
  157. ycoText = 2;
  158. TextOut(hDC, xcoText, ycoText, (LPSTR)rgch, cch );
  159. iDayEnd = 7;
  160. iWeekEnd = vcWeeksMonth + 2;
  161. /* for an unscrolled window */
  162. if ((vmScrollPos == 0) && (hmScrollPos == 0))
  163. {
  164. iWeekStart = 0;
  165. iDayStart = 0;
  166. pb = vrgbMonth;
  167. pycoCur = vrgycoGrid;
  168. }
  169. else /* scrolled window */
  170. {
  171. iWeekStart = vmScrollPos +1;
  172. iDayStart = hmScrollPos;
  173. pycoCur = vrgycoGrid + iWeekStart -(vmScrollPos + 1);
  174. pb = vrgbMonth + (iWeekStart -1)*7 + iDayStart;
  175. }
  176. ycoBox = *pycoCur;
  177. dy = *pycoCur -ycoBox;
  178. pxcoCur = vrgxcoGrid;
  179. pb -= iDayStart - hmScrollPos ;
  180. /* display "S M T W ..." above month grid */
  181. for (cDay = iDayStart; cDay < iDayEnd; cDay++ )
  182. {
  183. INT cchT;
  184. xcoBox = *pxcoCur++;
  185. dx = *pxcoCur -xcoBox;
  186. cchT = LoadString(hinstTimeDate, IDS_DAYABBREVS+cDay,
  187. (LPSTR)rgchDayAbbrevs, 4);
  188. xcoText = xcoBox + (dx - cchT*vcxFont)/2;
  189. ycoText = vcyWnd2BTop -vcyLineToLine;
  190. TextOut (hDC, xcoText, ycoText, (LPSTR)rgchDayAbbrevs, cchT);
  191. }
  192. /* draw the month grid and fill in the dates */
  193. for (cWeek = iWeekStart ; cWeek < iWeekEnd ; cWeek++,pb+=iDayStart)
  194. {
  195. ycoBox = *pycoCur++;
  196. dy = *pycoCur - ycoBox;
  197. pxcoCur = vrgxcoGrid;
  198. for (cDay = iDayStart; cDay < iDayEnd ; cDay++, pb++)
  199. {
  200. xcoBox = *pxcoCur++;
  201. dx = *pxcoCur - xcoBox;
  202. if (*pb !=0)
  203. {
  204. cch = 2;
  205. ByteTo2Digs (*pb & ~(MARK_BOX| TODAY), pch = rgch);
  206. if (*pch == '0')
  207. {
  208. cch--;
  209. pch++;
  210. }
  211. xcoText = xcoBox + (dx - cch * vcxFont) / 2;
  212. ycoText = ycoBox + vcyBorder + (dy - vcyFont) / 2;
  213. /* draw mark symbols, if any */
  214. if ((MarkedBits = ((~CLEARMARKEDBITS) & (*pb))) != 0)
  215. DrawMark (hDC, xcoBox, ycoText, dx, MarkedBits);
  216. if (*pb & TODAY)
  217. ShowToday (hDC, xcoBox, ycoText, dx);
  218. TextOut (hDC, xcoText, ycoText, (LPSTR)pch, cch);
  219. }
  220. }
  221. }
  222. InvertDay (hDC, vd3Sel.wDay);
  223. /* Don't mess with the caret position if the notes have the focus. */
  224. if (vhwndFocus == vhwnd2B)
  225. PositionCaret ();
  226. }
  227. /**** DrawMark ***/
  228. /***********************************************************************
  229. *
  230. * VOID PASCAL DrawMark (hDC, xcoBox, ycoText, dx, MarkedBits)
  231. *
  232. * purpose : To extract the marked bits one by one and draw the corresp.
  233. * mark symbols next to the selected day in month mode.
  234. *
  235. * paramteters : hDC - the display context
  236. * xcoBox - the x-coordinate of the left vertical edge
  237. * of box containing selected day
  238. * ycoText - y-coordinate of text to be written in box
  239. * dx - width of box
  240. * MarkedBits - variable with bits set corresp. to marks on
  241. * selected day
  242. *
  243. * returns : none
  244. *
  245. * called by : PaintMonth
  246. *
  247. ***********************************************************************/
  248. VOID APIENTRY DrawMark (
  249. HDC hDC,
  250. INT xcoBox,
  251. INT ycoText,
  252. INT dx,
  253. INT MarkedBits)
  254. {
  255. INT xcoLeft; /* left x coordinate of box mark */
  256. INT xcoRight; /* right x coordinate of box mark */
  257. INT ycoTop; /* top y coordinate of box mark */
  258. INT ycoBottom; /* bottom y coordinate of box mark */
  259. /* Note - the assumption is that numeric digits will not have
  260. descenders. Therefore, we subtract out the descent when
  261. calculating the space below the date digits in the monthly
  262. calendar display.
  263. */
  264. xcoLeft = xcoBox + (dx - 2 * vcxFont) / 2 - 2 * vcxBorder;
  265. xcoRight = xcoLeft + 2 * vcxFont + 6 * vcxBorder;
  266. ycoTop = ycoText - 2 * vcyBorder;
  267. ycoBottom = ycoText + vcyFont + max (vcyBorder - vcyDescent, 0);
  268. if (MarkedBits & MARK_BOX) /* a box-type mark */
  269. {
  270. PatBlt (hDC, xcoLeft, ycoTop, xcoRight - xcoLeft + 1, vcyBorder, PATCOPY);
  271. PatBlt (hDC, xcoLeft, ycoBottom, xcoRight - xcoLeft + 1, vcyBorder, PATCOPY);
  272. PatBlt (hDC, xcoLeft, ycoTop, vcxBorder, ycoBottom - ycoTop + 1, PATCOPY);
  273. PatBlt (hDC, xcoRight, ycoTop, vcxBorder, ycoBottom - ycoTop + 1, PATCOPY);
  274. }
  275. if (MarkedBits & MARK_CIRCLE) /* a "o" -type mark */
  276. Ellipse (hDC, xcoLeft - 7*vcxBorder, ycoBottom +2*vcyBorder,
  277. xcoLeft - 3*vcxBorder, ycoBottom + 6*vcyBorder);
  278. if (MarkedBits & MARK_PARENTHESES) /* a parentheses-type mark */
  279. {
  280. TextOut ( hDC, xcoLeft - 4*vcxFont/3,ycoText, vszMarkLeftParen, 1);
  281. TextOut ( hDC, xcoRight + 2*vcxBorder,ycoText, vszMarkRightParen,1);
  282. }
  283. if (MarkedBits & MARK_CROSS) /* an "x" mark */
  284. {
  285. (void)MMoveTo (hDC, xcoLeft - 2*vcxBorder, ycoTop - 2*vcxBorder);
  286. LineTo (hDC, xcoLeft - 7*vcxBorder, ycoTop -6*vcxBorder);
  287. (void)MMoveTo (hDC, xcoLeft - 6*vcxBorder, ycoTop - 2*vcxBorder);
  288. LineTo (hDC, xcoLeft - vcxBorder, ycoTop -6*vcxBorder);
  289. }
  290. if (MarkedBits & MARK_UNDERSCORE) /* a "_" mark */
  291. {
  292. /*
  293. ycoBottom = ycoText + 14 * vcyBorder;
  294. */
  295. PatBlt (hDC, xcoLeft, ycoBottom, xcoRight - xcoLeft + 1, vcyBorder, PATCOPY);
  296. }
  297. }
  298. /**** ShowToday */
  299. VOID APIENTRY ShowToday (
  300. HDC hDC,
  301. INT xcoBox,
  302. INT ycoText,
  303. INT dx)
  304. {
  305. TextOut (hDC, xcoBox + 1, ycoText, (LPSTR)">", 1);
  306. TextOut (hDC, xcoBox + dx - vcxFont - 2, ycoText, (LPSTR)"<", 1);
  307. }
  308. /**** InvertDay - Invert the specified day. */
  309. VOID APIENTRY InvertDay (
  310. HDC hDC,
  311. WORD wDay)
  312. {
  313. RECT rect;
  314. MapDayToRect (wDay, &rect);
  315. InvertRect (hDC, (LPRECT)&rect);
  316. }
  317. /**** PositionCaret */
  318. VOID APIENTRY PositionCaret ()
  319. {
  320. RECT rect;
  321. INT xcoCaret;
  322. INT ycoCaret;
  323. MapDayToRect (vd3Sel.wDay, &rect);
  324. /* Center the caret horizontally (it is 2 * vcxFont wide),
  325. and put it just above the bottom of the date box.
  326. */
  327. xcoCaret = (rect.left + rect.right) / 2 - vcxFont;
  328. ycoCaret = rect.bottom - vcyBorder;
  329. SetCaretPos (xcoCaret, ycoCaret);
  330. }
  331. /**** MapDayToRect */
  332. VOID APIENTRY MapDayToRect (
  333. WORD wDay,
  334. RECT *prect)
  335. {
  336. INT ixco;
  337. INT iyco;
  338. INT irgb;
  339. ixco = (irgb = vwWeekdayFirst + wDay - vmScrollPos*7 - hmScrollPos)%7 ;
  340. iyco = irgb / 7;
  341. if ((ixco < 0)||(ixco > 6)||(iyco < 0) ||(iyco > vcWeeksMonth))
  342. {
  343. prect->left = prect->right = 0;
  344. prect->top = prect->bottom = 0;
  345. }
  346. else
  347. {
  348. prect -> left = vrgxcoGrid [ixco] + vcxBorder;
  349. prect -> right = vrgxcoGrid [ixco + 1 ];
  350. prect -> top = vrgycoGrid [iyco] + vcyBorder;
  351. prect -> bottom = vrgycoGrid [iyco + 1];
  352. }
  353. }
  354. /**** FMapCoToIGrid */
  355. BOOL APIENTRY FMapCoToIGrid (
  356. INT co, /* INPUT - the coordinate to map. */
  357. INT *pco, /* INPUT - Coordinates of the grid. */
  358. INT cco, /* INPUT - Count of coordinates in the grid. */
  359. INT *pico) /* OUTPUT - the index of the grid coordinate. */
  360. {
  361. /* Note - by using co >= *pco in the loop control, we map the
  362. the leftmost pixel of the calendar to the first column and
  363. the topmost pixel to the first row. Then, because inside
  364. the loop we use co <= *++pco, the rightmost and bottommost
  365. pixels get mapped to the last column and bottom row.
  366. A click on the border between two adjacent date boxes is
  367. mapped to the one to the right (for vertical borders),
  368. or bottom (for horizontal borders).
  369. */
  370. for (*pico = 0; *pico < cco && co >= *pco; (*pico)++)
  371. {
  372. if (co <= *++pco)
  373. return (TRUE);
  374. }
  375. return (FALSE);
  376. }
  377. /**** DtFromPd3 - convert D3 to DT. */
  378. DT APIENTRY FAR DtFromPd3 (D3 *pd3)
  379. {
  380. static INT cDaysAccum [12] =
  381. {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  382. DT dt;
  383. dt = (pd3 -> wYear) * 365;
  384. /* Add in the days for the preceding leap years. */
  385. if (pd3 -> wYear != 0)
  386. dt += 1 + (pd3 -> wYear - 1) / 4;
  387. /* Add in the days for the full months before the current one. */
  388. dt += (DT)(cDaysAccum [pd3 -> wMonth]);
  389. /* If this is a leap year and the current month is beyond February,
  390. add in an extra day.
  391. */
  392. if (pd3 -> wYear % 4 == 0 && pd3 -> wMonth > MONTHFEB)
  393. dt++;
  394. /* Add in the days of the current month (prior to the current one). */
  395. dt += pd3 -> wDay;
  396. return (dt);
  397. }
  398. /**** GetMarkedDays - set the marked bits in vrgbMonth for the days
  399. of the current month that are marked.
  400. ****/
  401. VOID APIENTRY GetMarkedDays ()
  402. {
  403. D3 d3Temp;
  404. DT dtFirst; /* First day of month. */
  405. DT dtMax; /* Last day of month + 1. */
  406. DT dtCur; /* Day of month of current dd. */
  407. INT itdd; /* Index into the tdd. */
  408. DD *pdd; /* Pointer into the tdd. */
  409. /* Get the DTs of the first and (last + 1) days of the month. */
  410. d3Temp = vd3Sel;
  411. d3Temp.wDay = 0;
  412. dtMax = (dtFirst = DtFromPd3 (&d3Temp)) + vcDaysMonth;
  413. /* Look for the first day of the month. If it's found, itdd will
  414. be its index. If it's not found, itdd will be the index of the
  415. first entry in the tdd that is beyond the first day of the month.
  416. In either case, this is the place where we start looking for marked
  417. days within the current month.
  418. */
  419. FSearchTdd (dtFirst, &itdd);
  420. /* Lock the tdd and looking at all dates in the current month,
  421. set their marked bits in vrgbMonth if they are marked in the
  422. tdd.
  423. */
  424. for (pdd = TddLock () + itdd;
  425. itdd < vcddUsed && (dtCur = pdd -> dt) < dtMax; pdd++, itdd++)
  426. /* set marked bits on each day */
  427. if (pdd -> fMarked)
  428. vrgbMonth [vwWeekdayFirst + (dtCur - dtFirst)] |= pdd -> fMarked;
  429. TddUnlock ();
  430. }
  431. /**** MonthMode - Switch to month mode. */
  432. VOID APIENTRY MonthMode ()
  433. {
  434. if (vfDayMode)
  435. {
  436. /* Record edits and disable focus for now. (When UpdateMonth
  437. calls FFetchNewDate the focus should be NULL so it doesn't
  438. get set to the wrong thing (like Wnd3)).
  439. */
  440. CalSetFocus ((HWND)NULL);
  441. /* Say we are in Month mode. */
  442. vfDayMode = FALSE;
  443. SetScrollRange (vhwnd2B, SB_VERT, 0, SCROLLMONTHLAST, FALSE);
  444. SetScrollPos (vhwnd2B, SB_VERT, vd3Sel.wYear * 12 + vd3Sel.wMonth,
  445. TRUE);
  446. /* Hide the appointment description edit control. */
  447. ShowWindow (vhwnd3, HIDE_WINDOW);
  448. /* Repaint Wnd2A to display "Today is: ..." message. */
  449. InvalidateRect (vhwnd2A, (LPRECT)NULL, TRUE);
  450. /* Note - we are coming from View Month in CalCommand, so
  451. vd3To == vd3Sel. This, along with setting vwDaySticky
  452. to the current selected day will insure that the selected
  453. date does not change when we call UpDateMonth.
  454. */
  455. vwDaySticky = vd3Sel.wDay;
  456. SetScrollPos (vhwnd2B, SB_HORZ, hmScrollPos, TRUE);
  457. SetScrollPos (vhwnd2B, SB_VERT, vmScrollPos, TRUE);
  458. SetScrollRange (vhwnd2B, SB_HORZ, 0, hmScrollMax, TRUE);
  459. SetScrollRange (vhwnd2B, SB_VERT, 0, vmScrollMax, TRUE);
  460. UpdateMonth ();
  461. /* If the focus was in the notes area in day mode, leave it in
  462. the notes area in month mode. Otherwise put the focus on
  463. the calendar.
  464. */
  465. CalSetFocus (vhwndFocus == vhwnd2C ? vhwnd2C : vhwnd2B);
  466. }
  467. }