1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/builder.hxx>
21 #include <vcl/svapp.hxx>
22 #include <vcl/help.hxx>
23 #include <vcl/kernarray.hxx>
24 #include <vcl/menu.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/toolkit/calendar.hxx>
28 #include <vcl/commandevent.hxx>
29 #include <vcl/dockwin.hxx>
30 #include <unotools/calendarwrapper.hxx>
31 #include <unotools/localedatawrapper.hxx>
32 #include <com/sun/star/i18n/Weekdays.hpp>
33 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
34 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
35 #include <sal/log.hxx>
37 #include <calendar.hxx>
39 #include <strings.hrc>
44 #define MONTH_BORDERX 4
46 #define WEEKDAY_OFFY 3
48 #define TITLE_BORDERY 2
50 #define SPIN_OFFY TITLE_BORDERY
52 #define CALENDAR_HITTEST_DAY (sal_uInt16(0x0001))
53 #define CALENDAR_HITTEST_MONTHTITLE (sal_uInt16(0x0004))
54 #define CALENDAR_HITTEST_PREV (sal_uInt16(0x0008))
55 #define CALENDAR_HITTEST_NEXT (sal_uInt16(0x0010))
57 #define MENU_YEAR_COUNT 3
59 using namespace ::com::sun::star
;
61 static void ImplCalendarSelectDate( IntDateSet
* pTable
, const Date
& rDate
, bool bSelect
)
64 pTable
->insert( rDate
.GetDate() );
66 pTable
->erase( rDate
.GetDate() );
71 void Calendar::ImplInit( WinBits nWinStyle
)
73 mpSelectTable
.reset(new IntDateSet
);
75 mnWinStyle
= nWinStyle
;
86 OUString
aGregorian( "gregorian");
87 maCalendarWrapper
.loadCalendar( aGregorian
,
88 Application::GetAppLocaleDataWrapper().getLanguageTag().getLocale());
89 if (maCalendarWrapper
.getUniqueID() != aGregorian
)
91 SAL_WARN( "vcl.control", "Calendar::ImplInit: No ``gregorian'' calendar available for locale ``"
92 << Application::GetAppLocaleDataWrapper().getLanguageTag().getBcp47()
93 << "'' and other calendars aren't supported. Using en-US fallback." );
95 /* If we ever wanted to support other calendars than Gregorian a lot of
96 * rewrite would be necessary to internally replace use of class Date
97 * with proper class CalendarWrapper methods, get rid of fixed 12
98 * months, fixed 7 days, ... */
99 maCalendarWrapper
.loadCalendar( aGregorian
, lang::Locale( "en", "US", ""));
102 SetFirstDate( maCurDate
);
103 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
105 // Sonstige Strings erzeugen
106 maDayText
= VclResId(STR_SVT_CALENDAR_DAY
);
107 maWeekText
= VclResId(STR_SVT_CALENDAR_WEEK
);
109 // Tagestexte anlegen
110 for (sal_Int32 i
= 0; i
< 31; ++i
)
111 maDayTexts
[i
] = OUString::number(i
+1);
116 void Calendar::ApplySettings(vcl::RenderContext
& rRenderContext
)
118 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
119 maSelColor
= rStyleSettings
.GetHighlightTextColor();
120 SetPointFont(rRenderContext
, rStyleSettings
.GetToolFont());
121 rRenderContext
.SetTextColor(rStyleSettings
.GetFieldTextColor());
122 rRenderContext
.SetBackground(Wallpaper(rStyleSettings
.GetFieldColor()));
125 void Calendar::ImplInitSettings()
127 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
128 maSelColor
= rStyleSettings
.GetHighlightTextColor();
129 SetPointFont(*GetOutDev(), rStyleSettings
.GetToolFont());
130 SetTextColor(rStyleSettings
.GetFieldTextColor());
131 SetBackground(Wallpaper(rStyleSettings
.GetFieldColor()));
134 Calendar::Calendar( vcl::Window
* pParent
, WinBits nWinStyle
) :
135 Control( pParent
, nWinStyle
& (WB_TABSTOP
| WB_GROUP
| WB_BORDER
| WB_3DLOOK
) ),
136 maCalendarWrapper( Application::GetAppLocaleDataWrapper().getComponentContext() ),
137 maOldFormatFirstDate( 0, 0, 1900 ),
138 maOldFormatLastDate( 0, 0, 1900 ),
139 maFirstDate( 0, 0, 1900 ),
140 maOldFirstDate( 0, 0, 1900 ),
141 maCurDate( Date::SYSTEM
),
142 maOldCurDate( 0, 0, 1900 )
144 ImplInit( nWinStyle
);
147 Calendar::~Calendar()
152 void Calendar::dispose()
154 mpSelectTable
.reset();
155 mpOldSelectTable
.reset();
159 DayOfWeek
Calendar::ImplGetWeekStart() const
161 // Map i18n::Weekdays to Date DayOfWeek
163 sal_Int16 nDay
= maCalendarWrapper
.getFirstDayOfWeek();
166 case i18n::Weekdays::SUNDAY
:
169 case i18n::Weekdays::MONDAY
:
172 case i18n::Weekdays::TUESDAY
:
175 case i18n::Weekdays::WEDNESDAY
:
178 case i18n::Weekdays::THURSDAY
:
181 case i18n::Weekdays::FRIDAY
:
184 case i18n::Weekdays::SATURDAY
:
188 SAL_WARN( "vcl.control", "Calendar::ImplGetWeekStart: broken i18n Gregorian calendar (getFirstDayOfWeek())");
194 void Calendar::ImplFormat()
201 Size aOutSize
= GetOutputSizePixel();
203 if ( (aOutSize
.Width() <= 1) || (aOutSize
.Height() <= 1) )
206 tools::Long n99TextWidth
= GetTextWidth( "99" );
207 tools::Long nTextHeight
= GetTextHeight();
209 // calculate width and x-position
210 mnDayWidth
= n99TextWidth
+DAY_OFFX
;
211 mnMonthWidth
= mnDayWidth
*7;
212 mnMonthWidth
+= MONTH_BORDERX
*2;
213 mnMonthPerLine
= aOutSize
.Width() / mnMonthWidth
;
214 if ( !mnMonthPerLine
)
216 tools::Long nOver
= (aOutSize
.Width()-(mnMonthPerLine
*mnMonthWidth
)) / mnMonthPerLine
;
217 mnMonthWidth
+= nOver
;
218 mnDaysOffX
= MONTH_BORDERX
;
219 mnDaysOffX
+= nOver
/2;
221 // calculate height and y-position
222 mnDayHeight
= nTextHeight
+ DAY_OFFY
;
223 mnWeekDayOffY
= nTextHeight
+ TITLE_OFFY
+ (TITLE_BORDERY
*2);
224 mnDaysOffY
= mnWeekDayOffY
+ nTextHeight
+ WEEKDAY_OFFY
;
225 mnMonthHeight
= (mnDayHeight
*6) + mnDaysOffY
;
226 mnMonthHeight
+= MONTH_OFFY
;
227 mnLines
= aOutSize
.Height() / mnMonthHeight
;
230 mnMonthHeight
+= (aOutSize
.Height()-(mnLines
*mnMonthHeight
)) / mnLines
;
232 // calculate spinfields
233 tools::Long nSpinSize
= nTextHeight
+TITLE_BORDERY
-SPIN_OFFY
;
234 maPrevRect
.SetLeft( SPIN_OFFX
);
235 maPrevRect
.SetTop( SPIN_OFFY
);
236 maPrevRect
.SetRight( maPrevRect
.Left()+nSpinSize
);
237 maPrevRect
.SetBottom( maPrevRect
.Top()+nSpinSize
);
238 maNextRect
.SetLeft( aOutSize
.Width()-SPIN_OFFX
-nSpinSize
-1 );
239 maNextRect
.SetTop( SPIN_OFFY
);
240 maNextRect
.SetRight( maNextRect
.Left()+nSpinSize
);
241 maNextRect
.SetBottom( maNextRect
.Top()+nSpinSize
);
243 // Calculate DayOfWeekText (gets displayed in a narrow font)
244 maDayOfWeekText
.clear();
245 tools::Long nStartOffX
= 0;
246 sal_Int16 nDay
= maCalendarWrapper
.getFirstDayOfWeek();
247 for ( sal_Int16 nDayOfWeek
= 0; nDayOfWeek
< 7; nDayOfWeek
++ )
250 OUString
aDayOfWeek( maCalendarWrapper
.getDisplayName(
251 i18n::CalendarDisplayIndex::DAY
, nDay
, 2));
252 tools::Long nOffX
= (mnDayWidth
-GetTextWidth( aDayOfWeek
))/2;
257 nOffX
+= nDayOfWeek
* mnDayWidth
;
258 mnDayOfWeekAry
[nDayOfWeek
] = nOffX
;
259 maDayOfWeekText
+= aDayOfWeek
;
264 // header position for the last day of week
265 mnDayOfWeekAry
[7] = mnMonthWidth
;
270 // calculate number of days
272 DayOfWeek eStartDay
= ImplGetWeekStart();
275 Date aTempDate
= GetFirstMonth();
276 maFirstDate
= aTempDate
;
277 nWeekDay
= static_cast<sal_uInt16
>(aTempDate
.GetDayOfWeek());
278 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
279 maFirstDate
.AddDays( -nWeekDay
);
280 mnDayCount
= nWeekDay
;
281 sal_uInt16 nDaysInMonth
;
282 sal_uInt16 nMonthCount
= static_cast<sal_uInt16
>(mnMonthPerLine
*mnLines
);
283 for ( sal_uInt16 i
= 0; i
< nMonthCount
; i
++ )
285 nDaysInMonth
= aTempDate
.GetDaysInMonth();
286 mnDayCount
+= nDaysInMonth
;
287 aTempDate
.AddDays( nDaysInMonth
);
289 Date aTempDate2
= aTempDate
;
291 nDaysInMonth
= aTempDate2
.GetDaysInMonth();
292 aTempDate2
.AddDays( -(nDaysInMonth
-1) );
293 nWeekDay
= static_cast<sal_uInt16
>(aTempDate2
.GetDayOfWeek());
294 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
295 mnDayCount
+= 42-nDaysInMonth
-nWeekDay
;
298 maOtherColor
= COL_LIGHTGRAY
;
299 if ( maOtherColor
.IsRGBEqual( GetBackground().GetColor() ) )
300 maOtherColor
= COL_GRAY
;
302 Date aLastDate
= GetLastDate();
303 if ( (maOldFormatLastDate
!= aLastDate
) ||
304 (maOldFormatFirstDate
!= maFirstDate
) )
306 maOldFormatFirstDate
= maFirstDate
;
307 maOldFormatLastDate
= aLastDate
;
311 sal_Int16 nNewFirstYear
= maFirstDate
.GetYear();
312 sal_Int16 nNewLastYear
= GetLastDate().GetYear();
315 if ( nNewFirstYear
< mnFirstYear
)
317 mnFirstYear
= nNewFirstYear
;
319 if ( nNewLastYear
> mnLastYear
)
321 mnLastYear
= nNewLastYear
;
326 mnFirstYear
= nNewFirstYear
;
327 mnLastYear
= nNewLastYear
;
333 sal_uInt16
Calendar::ImplDoHitTest( const Point
& rPos
, Date
& rDate
) const
338 if ( maPrevRect
.Contains( rPos
) )
339 return CALENDAR_HITTEST_PREV
;
340 else if ( maNextRect
.Contains( rPos
) )
341 return CALENDAR_HITTEST_NEXT
;
346 DayOfWeek eStartDay
= ImplGetWeekStart();
348 rDate
= GetFirstMonth();
350 for ( tools::Long i
= 0; i
< mnLines
; i
++ )
356 tools::Long nYMonth
= nY
+mnMonthHeight
;
357 for ( tools::Long j
= 0; j
< mnMonthPerLine
; j
++ )
359 if ( (rPos
.X() < nX
) && (rPos
.Y() < nYMonth
) )
362 sal_uInt16 nDaysInMonth
= rDate
.GetDaysInMonth();
364 // matching month was found
365 if ( (rPos
.X() > nX
) && (rPos
.Y() < nYMonth
) &&
366 (rPos
.X() < nX
+mnMonthWidth
) )
368 if ( rPos
.Y() < (nY
+(TITLE_BORDERY
*2)+mnDayHeight
))
369 return CALENDAR_HITTEST_MONTHTITLE
;
372 tools::Long nDayX
= nX
+mnDaysOffX
;
373 tools::Long nDayY
= nY
+mnDaysOffY
;
374 if ( rPos
.Y() < nDayY
)
376 sal_Int32 nDayIndex
= static_cast<sal_Int32
>(rDate
.GetDayOfWeek());
377 nDayIndex
= (nDayIndex
+(7-static_cast<sal_Int32
>(eStartDay
))) % 7;
378 if ( (i
== 0) && (j
== 0) )
380 Date aTempDate
= rDate
;
381 aTempDate
.AddDays( -nDayIndex
);
382 for ( nDay
= 0; nDay
< nDayIndex
; nDay
++ )
384 nOffX
= nDayX
+ (nDay
*mnDayWidth
);
385 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
386 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
389 rDate
.AddDays( nDay
);
390 return CALENDAR_HITTEST_DAY
;
394 for ( nDay
= 1; nDay
<= nDaysInMonth
; nDay
++ )
396 if ( rPos
.Y() < nDayY
)
398 rDate
.AddDays( nDayIndex
);
401 nOffX
= nDayX
+ (nDayIndex
*mnDayWidth
);
402 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
403 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
405 rDate
.AddDays( nDay
-1 );
406 return CALENDAR_HITTEST_DAY
;
408 if ( nDayIndex
== 6 )
411 nDayY
+= mnDayHeight
;
416 if ( (i
== mnLines
-1) && (j
== mnMonthPerLine
-1) )
418 sal_uInt16 nWeekDay
= static_cast<sal_uInt16
>(rDate
.GetDayOfWeek());
419 nWeekDay
= (nWeekDay
+(7-static_cast<sal_uInt16
>(eStartDay
))) % 7;
420 sal_Int32 nDayCount
= 42-nDaysInMonth
-nWeekDay
;
421 Date aTempDate
= rDate
;
422 aTempDate
.AddDays( nDaysInMonth
);
423 for ( nDay
= 1; nDay
<= nDayCount
; nDay
++ )
425 if ( rPos
.Y() < nDayY
)
427 rDate
.AddDays( nDayIndex
);
430 nOffX
= nDayX
+ (nDayIndex
*mnDayWidth
);
431 if ( (rPos
.Y() >= nDayY
) && (rPos
.Y() < nDayY
+mnDayHeight
) &&
432 (rPos
.X() >= nOffX
) && (rPos
.X() < nOffX
+mnDayWidth
) )
435 rDate
.AddDays( nDay
-1 );
436 return CALENDAR_HITTEST_DAY
;
438 if ( nDayIndex
== 6 )
441 nDayY
+= mnDayHeight
;
450 rDate
.AddDays( nDaysInMonth
);
463 void ImplDrawSpinArrow(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
, bool bPrev
)
468 tools::Long nHeight
= rRect
.GetHeight();
469 tools::Long nWidth
= rRect
.GetWidth();
470 if (nWidth
< nHeight
)
478 tools::Rectangle
aRect(Point( rRect
.Left() + (nWidth
/ 2) - (nLines
/ 2),
479 rRect
.Top() + (nHeight
/ 2) ),
483 aRect
.AdjustLeft(nLines
);
484 aRect
.AdjustRight(nLines
);
487 rRenderContext
.DrawRect(aRect
);
488 for (i
= 0; i
< nLines
; i
++)
492 aRect
.AdjustLeft( 1 );
493 aRect
.AdjustRight( 1 );
497 aRect
.AdjustLeft( -1 );
498 aRect
.AdjustRight( -1 );
500 aRect
.AdjustTop( -1 );
501 aRect
.AdjustBottom( 1 );
502 rRenderContext
.DrawRect(aRect
);
506 } //end anonymous namespace
508 void Calendar::ImplDrawSpin(vcl::RenderContext
& rRenderContext
)
510 rRenderContext
.SetLineColor();
511 rRenderContext
.SetFillColor(rRenderContext
.GetSettings().GetStyleSettings().GetButtonTextColor());
512 tools::Rectangle aOutRect
= maPrevRect
;
513 aOutRect
.AdjustLeft(3 );
514 aOutRect
.AdjustTop(3 );
515 aOutRect
.AdjustRight( -3 );
516 aOutRect
.AdjustBottom( -3 );
517 ImplDrawSpinArrow(rRenderContext
, aOutRect
, true);
518 aOutRect
= maNextRect
;
519 aOutRect
.AdjustLeft(3 );
520 aOutRect
.AdjustTop(3 );
521 aOutRect
.AdjustRight( -3 );
522 aOutRect
.AdjustBottom( -3 );
523 ImplDrawSpinArrow(rRenderContext
, aOutRect
, false);
526 void Calendar::ImplDrawDate(vcl::RenderContext
& rRenderContext
,
527 tools::Long nX
, tools::Long nY
,
528 sal_uInt16 nDay
, sal_uInt16 nMonth
, sal_Int16 nYear
,
529 bool bOther
, sal_Int32 nToday
)
531 Color
const * pTextColor
= nullptr;
532 const OUString
& rDay
= maDayTexts
[(nDay
- 1) % std::size(maDayTexts
)];
533 tools::Rectangle
aDateRect(nX
, nY
, nX
+ mnDayWidth
- 1, nY
+ mnDayHeight
- 1);
538 if ((nDay
== maCurDate
.GetDay()) &&
539 (nMonth
== maCurDate
.GetMonth()) &&
540 (nYear
== maCurDate
.GetYear()))
546 if (mpSelectTable
->find(Date(nDay
, nMonth
, nYear
).GetDate()) != mpSelectTable
->end())
552 pTextColor
= &maSelColor
;
554 pTextColor
= &maOtherColor
;
559 // display background
560 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
563 rRenderContext
.SetLineColor();
564 rRenderContext
.SetFillColor(rStyleSettings
.GetHighlightColor());
565 rRenderContext
.DrawRect(aDateRect
);
569 tools::Long nTextX
= nX
+ (mnDayWidth
- GetTextWidth(rDay
)) - (DAY_OFFX
/ 2);
570 tools::Long nTextY
= nY
+ (mnDayHeight
- GetTextHeight()) / 2;
573 Color aOldColor
= rRenderContext
.GetTextColor();
574 rRenderContext
.SetTextColor(*pTextColor
);
575 rRenderContext
.DrawText(Point(nTextX
, nTextY
), rDay
);
576 rRenderContext
.SetTextColor(aOldColor
);
579 rRenderContext
.DrawText(Point(nTextX
, nTextY
), rDay
);
582 Date
aTodayDate(maCurDate
);
584 aTodayDate
.SetDate(nToday
);
586 aTodayDate
= Date(Date::SYSTEM
);
587 if ((nDay
== aTodayDate
.GetDay()) &&
588 (nMonth
== aTodayDate
.GetMonth()) &&
589 (nYear
== aTodayDate
.GetYear()))
591 rRenderContext
.SetLineColor(rStyleSettings
.GetWindowTextColor());
592 rRenderContext
.SetFillColor();
593 rRenderContext
.DrawRect(aDateRect
);
596 // if needed do FocusRect
597 if (bFocus
&& HasFocus())
598 ShowFocus(aDateRect
);
601 void Calendar::ImplDraw(vcl::RenderContext
& rRenderContext
)
605 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
606 Size
aOutSize(GetOutputSizePixel());
614 sal_Int32 nToday
= Date(Date::SYSTEM
).GetDate();
618 Date aDate
= GetFirstMonth();
619 DayOfWeek eStartDay
= ImplGetWeekStart();
624 for (i
= 0; i
< mnLines
; i
++)
627 rRenderContext
.SetLineColor();
628 rRenderContext
.SetFillColor(rStyleSettings
.GetFaceColor());
629 tools::Rectangle
aTitleRect(0, nY
, aOutSize
.Width() - 1, nY
+ mnDayHeight
- DAY_OFFY
+ TITLE_BORDERY
* 2);
630 rRenderContext
.DrawRect(aTitleRect
);
631 Point
aTopLeft1(aTitleRect
.Left(), aTitleRect
.Top());
632 Point
aTopLeft2(aTitleRect
.Left(), aTitleRect
.Top() + 1);
633 Point
aBottomRight1(aTitleRect
.Right(), aTitleRect
.Bottom());
634 Point
aBottomRight2(aTitleRect
.Right(), aTitleRect
.Bottom() - 1);
635 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
636 rRenderContext
.DrawLine(aTopLeft1
, Point(aBottomRight1
.X(), aTopLeft1
.Y()));
637 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor() );
638 rRenderContext
.DrawLine(aTopLeft2
, Point(aBottomRight2
.X(), aTopLeft2
.Y()));
639 rRenderContext
.DrawLine(aTopLeft2
, Point(aTopLeft2
.X(), aBottomRight2
.Y()));
640 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor() );
641 rRenderContext
.DrawLine(Point(aTopLeft2
.X(), aBottomRight2
.Y()), aBottomRight2
);
642 rRenderContext
.DrawLine(Point(aBottomRight2
.X(), aTopLeft2
.Y()), aBottomRight2
);
643 rRenderContext
.SetLineColor(rStyleSettings
.GetDarkShadowColor());
644 rRenderContext
.DrawLine(Point(aTopLeft1
.X(), aBottomRight1
.Y()), aBottomRight1
);
645 Point
aSepPos1(0, aTitleRect
.Top() + TITLE_BORDERY
);
646 Point
aSepPos2(0, aTitleRect
.Bottom() - TITLE_BORDERY
);
647 for (j
= 0; j
< mnMonthPerLine
-1; j
++)
649 aSepPos1
.AdjustX(mnMonthWidth
-1 );
650 aSepPos2
.setX( aSepPos1
.X() );
651 rRenderContext
.SetLineColor(rStyleSettings
.GetShadowColor());
652 rRenderContext
.DrawLine(aSepPos1
, aSepPos2
);
653 aSepPos1
.AdjustX( 1 );
654 aSepPos2
.setX( aSepPos1
.X() );
655 rRenderContext
.SetLineColor(rStyleSettings
.GetLightColor());
656 rRenderContext
.DrawLine(aSepPos1
, aSepPos2
);
660 for (j
= 0; j
< mnMonthPerLine
; j
++)
662 nMonth
= aDate
.GetMonth();
663 nYear
= aDate
.GetYear();
665 // display month in title bar
667 nDeltaY
= nY
+ TITLE_BORDERY
;
668 OUString aMonthText
= maCalendarWrapper
.getDisplayName(i18n::CalendarDisplayIndex::MONTH
, nMonth
- 1, 1)
670 + OUString::number(nYear
);
671 tools::Long nMonthTextWidth
= rRenderContext
.GetTextWidth(aMonthText
);
672 tools::Long nMonthOffX1
= 0;
673 tools::Long nMonthOffX2
= 0;
677 nMonthOffX1
= maPrevRect
.Right() + 1;
678 if (j
== mnMonthPerLine
- 1)
679 nMonthOffX2
= aOutSize
.Width() - maNextRect
.Left() + 1;
681 tools::Long nMaxMonthWidth
= mnMonthWidth
- nMonthOffX1
- nMonthOffX2
- 4;
682 if (nMonthTextWidth
> nMaxMonthWidth
)
684 // Abbreviated month name.
685 aMonthText
= maCalendarWrapper
.getDisplayName(i18n::CalendarDisplayIndex::MONTH
, nMonth
- 1, 0)
687 + OUString::number(nYear
);
688 nMonthTextWidth
= rRenderContext
.GetTextWidth(aMonthText
);
690 tools::Long nTempOff
= (mnMonthWidth
- nMonthTextWidth
+ 1) / 2;
691 if (nTempOff
< nMonthOffX1
)
692 nDeltaX
+= nMonthOffX1
+ 1;
695 if (nTempOff
+ nMonthTextWidth
> mnMonthWidth
- nMonthOffX2
)
696 nDeltaX
+= mnMonthWidth
- nMonthOffX2
- nMonthTextWidth
;
700 rRenderContext
.SetTextColor(rStyleSettings
.GetButtonTextColor());
701 rRenderContext
.DrawText(Point(nDeltaX
, nDeltaY
), aMonthText
);
702 rRenderContext
.SetTextColor(rStyleSettings
.GetWindowTextColor());
705 nDayX
= nX
+ mnDaysOffX
;
706 nDayY
= nY
+ mnWeekDayOffY
;
707 nDeltaY
= nDayY
+ mnDayHeight
;
708 rRenderContext
.SetLineColor(rStyleSettings
.GetWindowTextColor());
709 Point
aStartPos(nDayX
, nDeltaY
);
710 rRenderContext
.DrawLine(aStartPos
, Point(nDayX
+ (7 * mnDayWidth
), nDeltaY
));
712 for (int k
=0; k
<7; ++k
)
713 aTmp
.push_back(mnDayOfWeekAry
[k
+1]);
714 rRenderContext
.DrawTextArray(Point(nDayX
+ mnDayOfWeekAry
[0], nDayY
), maDayOfWeekText
, aTmp
, {}, 0, aTmp
.size());
717 sal_uInt16 nDaysInMonth
= aDate
.GetDaysInMonth();
718 nDayX
= nX
+ mnDaysOffX
;
719 nDayY
= nY
+ mnDaysOffY
;
720 sal_uInt16 nDayIndex
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
721 nDayIndex
= (nDayIndex
+ (7 - static_cast<sal_uInt16
>(eStartDay
))) % 7;
722 if (i
== 0 && j
== 0)
724 Date aTempDate
= aDate
;
725 aTempDate
.AddDays( -nDayIndex
);
726 for (nDay
= 0; nDay
< nDayIndex
; ++nDay
)
728 nDeltaX
= nDayX
+ (nDay
* mnDayWidth
);
729 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
+ aTempDate
.GetDay(),
730 aTempDate
.GetMonth(), aTempDate
.GetYear(),
734 for (nDay
= 1; nDay
<= nDaysInMonth
; nDay
++)
736 nDeltaX
= nDayX
+ (nDayIndex
* mnDayWidth
);
737 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
, nMonth
, nYear
,
742 nDayY
+= mnDayHeight
;
747 if ((i
== mnLines
- 1) && (j
== mnMonthPerLine
- 1))
749 sal_uInt16 nWeekDay
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
750 nWeekDay
= (nWeekDay
+ (7 - static_cast<sal_uInt16
>(eStartDay
))) % 7;
751 sal_uInt16 nDayCount
= 42 - nDaysInMonth
- nWeekDay
;
752 Date aTempDate
= aDate
;
753 aTempDate
.AddDays( nDaysInMonth
);
754 for (nDay
= 1; nDay
<= nDayCount
; ++nDay
)
756 nDeltaX
= nDayX
+ (nDayIndex
* mnDayWidth
);
757 ImplDrawDate(rRenderContext
, nDeltaX
, nDayY
, nDay
,
758 aTempDate
.GetMonth(), aTempDate
.GetYear(),
763 nDayY
+= mnDayHeight
;
770 aDate
.AddDays( nDaysInMonth
);
778 ImplDrawSpin(rRenderContext
);
781 void Calendar::ImplUpdateDate( const Date
& rDate
)
783 if (IsReallyVisible() && IsUpdateMode())
785 tools::Rectangle
aDateRect(GetDateRect(rDate
));
786 if (!aDateRect
.IsEmpty())
788 Invalidate(aDateRect
);
793 void Calendar::ImplUpdateSelection( IntDateSet
* pOld
)
795 IntDateSet
* pNew
= mpSelectTable
.get();
797 for (auto const& nKey
: *pOld
)
799 if ( pNew
->find(nKey
) == pNew
->end() )
801 Date
aTempDate(nKey
);
802 ImplUpdateDate(aTempDate
);
806 for (auto const& nKey
: *pNew
)
808 if ( pOld
->find(nKey
) == pOld
->end() )
810 Date
aTempDate(nKey
);
811 ImplUpdateDate(aTempDate
);
816 void Calendar::ImplMouseSelect( const Date
& rDate
, sal_uInt16 nHitTest
)
818 IntDateSet
aOldSel( *mpSelectTable
);
819 Date aOldDate
= maCurDate
;
820 Date aTempDate
= rDate
;
822 if ( !(nHitTest
& CALENDAR_HITTEST_DAY
) )
825 if ( !(nHitTest
& CALENDAR_HITTEST_DAY
) )
826 aTempDate
= maOldCurDate
;
827 if ( aTempDate
!= maCurDate
)
829 maCurDate
= aTempDate
;
830 ImplCalendarSelectDate( mpSelectTable
.get(), aOldDate
, false );
831 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
834 bool bNewSel
= aOldSel
!= *mpSelectTable
;
835 if ( (maCurDate
!= aOldDate
) || bNewSel
)
839 ImplUpdateSelection( &aOldSel
);
840 if ( !bNewSel
|| aOldSel
.find( aOldDate
.GetDate() ) == aOldSel
.end() )
841 ImplUpdateDate( aOldDate
);
842 // assure focus rectangle is displayed again
843 if ( HasFocus() || !bNewSel
844 || mpSelectTable
->find( maCurDate
.GetDate() ) == mpSelectTable
->end() )
845 ImplUpdateDate( maCurDate
);
849 void Calendar::ImplUpdate( bool bCalcNew
)
851 if (IsReallyVisible() && IsUpdateMode())
853 if (bCalcNew
&& !mbCalc
)
857 else if (!mbFormat
&& !mbCalc
)
868 void Calendar::ImplScrollCalendar( bool bPrev
)
870 Date aNewFirstMonth
= GetFirstMonth();
874 aNewFirstMonth
.AddDays( -(aNewFirstMonth
.GetDaysInMonth()-1));
877 aNewFirstMonth
.AddDays( aNewFirstMonth
.GetDaysInMonth());
878 SetFirstDate( aNewFirstMonth
);
881 void Calendar::ImplShowMenu( const Point
& rPos
, const Date
& rDate
)
885 Date aOldFirstDate
= GetFirstMonth();
886 ScopedVclPtrInstance
<PopupMenu
> aPopupMenu
;
887 sal_uInt16 nMonthOff
;
888 sal_uInt16 nCurItemId
;
889 sal_uInt16 nYear
= rDate
.GetYear()-1;
892 sal_uInt16 nYearIdCount
= 1000;
894 nMonthOff
= (rDate
.GetYear()-aOldFirstDate
.GetYear())*12;
895 if ( aOldFirstDate
.GetMonth() < rDate
.GetMonth() )
896 nMonthOff
+= rDate
.GetMonth()-aOldFirstDate
.GetMonth();
898 nMonthOff
-= aOldFirstDate
.GetMonth()-rDate
.GetMonth();
900 // construct menu (include years with different months)
901 for ( i
= 0; i
< MENU_YEAR_COUNT
; i
++ )
903 VclPtrInstance
<PopupMenu
> pYearPopupMenu
;
904 for ( j
= 1; j
<= 12; j
++ )
905 pYearPopupMenu
->InsertItem( nYearIdCount
+j
,
906 maCalendarWrapper
.getDisplayName(
907 i18n::CalendarDisplayIndex::MONTH
, j
-1, 1));
908 aPopupMenu
->InsertItem( 10+i
, OUString::number( nYear
+i
) );
909 aPopupMenu
->SetPopupMenu( 10+i
, pYearPopupMenu
);
910 nYearIdCount
+= 1000;
914 nCurItemId
= aPopupMenu
->Execute( this, rPos
);
920 sal_uInt16 nTempMonthOff
= nMonthOff
% 12;
921 sal_uInt16 nTempYearOff
= nMonthOff
/ 12;
922 sal_uInt16 nNewMonth
= nCurItemId
% 1000;
923 sal_uInt16 nNewYear
= nYear
+((nCurItemId
-1000)/1000);
924 if ( nTempMonthOff
< nNewMonth
)
925 nNewMonth
= nNewMonth
- nTempMonthOff
;
929 nNewMonth
= 12-(nTempMonthOff
-nNewMonth
);
931 nNewYear
= nNewYear
- nTempYearOff
;
932 SetFirstDate( Date( 1, nNewMonth
, nNewYear
) );
935 void Calendar::ImplTracking( const Point
& rPos
, bool bRepeat
)
937 Date aTempDate
= maCurDate
;
938 sal_uInt16 nHitTest
= ImplDoHitTest( rPos
, aTempDate
);
942 mbPrevIn
= (nHitTest
& CALENDAR_HITTEST_PREV
) != 0;
943 mbNextIn
= (nHitTest
& CALENDAR_HITTEST_NEXT
) != 0;
945 if ( bRepeat
&& (mbPrevIn
|| mbNextIn
) )
947 ImplScrollCalendar( mbPrevIn
);
951 ImplMouseSelect( aTempDate
, nHitTest
);
954 void Calendar::ImplEndTracking( bool bCancel
)
956 bool bSelection
= false;
957 bool bSpinDown
= mbSpinDown
;
966 if ( maOldFirstDate
!= maFirstDate
)
967 SetFirstDate( maOldFirstDate
);
971 IntDateSet
aOldSel( *mpSelectTable
);
972 Date aOldDate
= maCurDate
;
973 maCurDate
= maOldCurDate
;
974 *mpSelectTable
= *mpOldSelectTable
;
976 ImplUpdateSelection( &aOldSel
);
977 if ( aOldSel
.find( aOldDate
.GetDate() ) == aOldSel
.end() )
978 ImplUpdateDate( aOldDate
);
979 // assure focus rectangle is displayed again
980 if ( HasFocus() || mpSelectTable
->find( maCurDate
.GetDate() ) == mpSelectTable
->end() )
981 ImplUpdateDate( maCurDate
);
990 // determine if we should scroll the visible area
991 if ( !mpSelectTable
->empty() )
993 Date
aFirstSelDate( *mpSelectTable
->begin() );
994 Date
aLastSelDate( *mpSelectTable
->rbegin() );
995 if ( aLastSelDate
< GetFirstMonth() )
996 ImplScrollCalendar( true );
997 else if ( GetLastMonth() < aFirstSelDate
)
998 ImplScrollCalendar( false );
1002 if ( !bCancel
&& ((maCurDate
!= maOldCurDate
) || (*mpOldSelectTable
!= *mpSelectTable
)) )
1005 if ( !bSelection
&& (mnWinStyle
& WB_TABSTOP
) && !bCancel
)
1008 mpOldSelectTable
.reset();
1011 void Calendar::MouseButtonDown( const MouseEvent
& rMEvt
)
1013 if ( rMEvt
.IsLeft() && !mbMenuDown
)
1015 Date aTempDate
= maCurDate
;
1016 sal_uInt16 nHitTest
= ImplDoHitTest( rMEvt
.GetPosPixel(), aTempDate
);
1019 if ( nHitTest
& CALENDAR_HITTEST_MONTHTITLE
)
1020 ImplShowMenu( rMEvt
.GetPosPixel(), aTempDate
);
1023 maOldFirstDate
= maFirstDate
;
1025 mbPrevIn
= (nHitTest
& CALENDAR_HITTEST_PREV
) != 0;
1026 mbNextIn
= (nHitTest
& CALENDAR_HITTEST_NEXT
) != 0;
1027 if ( mbPrevIn
|| mbNextIn
)
1030 ImplScrollCalendar( mbPrevIn
);
1031 // it should really read BUTTONREPEAT, therefore do not
1032 // change it to SCROLLREPEAT, check with TH,
1033 // why it could be different (71775)
1034 StartTracking( StartTrackingFlags::ButtonRepeat
);
1038 if ( (rMEvt
.GetClicks() != 2) || !(nHitTest
& CALENDAR_HITTEST_DAY
) )
1040 maOldCurDate
= maCurDate
;
1041 mpOldSelectTable
.reset(new IntDateSet( *mpSelectTable
));
1046 ImplMouseSelect( aTempDate
, nHitTest
);
1048 if (rMEvt
.GetClicks() == 2)
1049 maActivateHdl
.Call(this);
1057 Control::MouseButtonDown( rMEvt
);
1060 void Calendar::Tracking( const TrackingEvent
& rTEvt
)
1062 Point aMousePos
= rTEvt
.GetMouseEvent().GetPosPixel();
1064 if ( rTEvt
.IsTrackingEnded() )
1065 ImplEndTracking( rTEvt
.IsTrackingCanceled() );
1067 ImplTracking( aMousePos
, rTEvt
.IsTrackingRepeat() );
1070 void Calendar::KeyInput( const KeyEvent
& rKEvt
)
1072 Date aNewDate
= maCurDate
;
1074 switch ( rKEvt
.GetKeyCode().GetCode() )
1077 aNewDate
.SetDay( 1 );
1081 aNewDate
.SetDay( aNewDate
.GetDaysInMonth() );
1093 aNewDate
.AddDays( -7 );
1097 aNewDate
.AddDays( 7 );
1102 Date aTempDate
= aNewDate
;
1103 aTempDate
.AddDays( -(aNewDate
.GetDay()+1) );
1104 aNewDate
.AddDays( -aTempDate
.GetDaysInMonth() );
1109 aNewDate
.AddDays( aNewDate
.GetDaysInMonth() );
1116 Control::KeyInput( rKEvt
);
1120 if ( aNewDate
!= maCurDate
)
1122 SetCurDate( aNewDate
);
1126 if (rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
)
1128 if (maActivateHdl
.IsSet())
1129 maActivateHdl
.Call(this);
1131 Control::KeyInput(rKEvt
);
1135 void Calendar::Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& )
1137 ImplDraw(rRenderContext
);
1140 void Calendar::GetFocus()
1142 ImplUpdateDate( maCurDate
);
1143 Control::GetFocus();
1146 void Calendar::LoseFocus()
1149 Control::LoseFocus();
1152 void Calendar::Resize()
1158 void Calendar::RequestHelp( const HelpEvent
& rHEvt
)
1160 if ( rHEvt
.GetMode() & (HelpEventMode::QUICK
| HelpEventMode::BALLOON
) )
1162 Date aDate
= maCurDate
;
1163 if ( GetDate( ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ), aDate
) )
1165 tools::Rectangle aDateRect
= GetDateRect( aDate
);
1166 Point aPt
= OutputToScreenPixel( aDateRect
.TopLeft() );
1167 aDateRect
.SetLeft( aPt
.X() );
1168 aDateRect
.SetTop( aPt
.Y() );
1169 aPt
= OutputToScreenPixel( aDateRect
.BottomRight() );
1170 aDateRect
.SetRight( aPt
.X() );
1171 aDateRect
.SetBottom( aPt
.Y() );
1173 if ( rHEvt
.GetMode() & HelpEventMode::QUICK
)
1175 maCalendarWrapper
.setGregorianDateTime( aDate
);
1176 sal_uInt16 nWeek
= static_cast<sal_uInt16
>(maCalendarWrapper
.getValue( i18n::CalendarFieldIndex::WEEK_OF_YEAR
));
1177 sal_uInt16 nMonth
= aDate
.GetMonth();
1178 OUString aStr
= maDayText
1180 + OUString::number(aDate
.GetDayOfYear())
1184 + OUString::number(nWeek
);
1185 // if year is not the same, add it
1186 if ( (nMonth
== 12) && (nWeek
== 1) )
1188 aStr
+= ", " + OUString::number(aDate
.GetNextYear());
1190 else if ( (nMonth
== 1) && (nWeek
> 50) )
1192 aStr
+= ", " + OUString::number(aDate
.GetYear()-1);
1194 Help::ShowQuickHelp( this, aDateRect
, aStr
);
1200 Control::RequestHelp( rHEvt
);
1203 void Calendar::Command( const CommandEvent
& rCEvt
)
1205 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
)
1207 if ( rCEvt
.IsMouseEvent() )
1209 Date aTempDate
= maCurDate
;
1210 sal_uInt16 nHitTest
= ImplDoHitTest( rCEvt
.GetMousePosPixel(), aTempDate
);
1211 if ( nHitTest
& CALENDAR_HITTEST_MONTHTITLE
)
1213 ImplShowMenu( rCEvt
.GetMousePosPixel(), aTempDate
);
1218 else if ( rCEvt
.GetCommand() == CommandEventId::Wheel
)
1220 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
1221 if ( pData
->GetMode() == CommandWheelMode::SCROLL
)
1223 tools::Long nNotchDelta
= pData
->GetNotchDelta();
1224 if ( nNotchDelta
< 0 )
1226 while ( nNotchDelta
< 0 )
1228 ImplScrollCalendar( true );
1234 while ( nNotchDelta
> 0 )
1236 ImplScrollCalendar( false );
1245 Control::Command( rCEvt
);
1248 void Calendar::StateChanged( StateChangedType nType
)
1250 Control::StateChanged( nType
);
1252 if ( nType
== StateChangedType::InitShow
)
1256 void Calendar::DataChanged( const DataChangedEvent
& rDCEvt
)
1258 Control::DataChanged( rDCEvt
);
1260 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
1261 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
1262 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
1263 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
1270 void Calendar::Select()
1272 maSelectHdl
.Call( this );
1275 Date
Calendar::GetFirstSelectedDate() const
1277 if ( !mpSelectTable
->empty() )
1278 return Date( *mpSelectTable
->begin() );
1281 Date
aDate( 0, 0, 0 );
1286 void Calendar::SetCurDate( const Date
& rNewDate
)
1288 if ( !rNewDate
.IsValidAndGregorian() )
1291 if ( maCurDate
== rNewDate
)
1294 bool bUpdate
= IsVisible() && IsUpdateMode();
1295 Date aOldDate
= maCurDate
;
1296 maCurDate
= rNewDate
;
1298 ImplCalendarSelectDate( mpSelectTable
.get(), aOldDate
, false );
1299 ImplCalendarSelectDate( mpSelectTable
.get(), maCurDate
, true );
1301 // shift actual date in the visible area
1302 if ( mbFormat
|| (maCurDate
< GetFirstMonth()) )
1303 SetFirstDate( maCurDate
);
1304 else if ( maCurDate
> GetLastMonth() )
1306 Date aTempDate
= GetLastMonth();
1307 tools::Long nDateOff
= maCurDate
-aTempDate
;
1308 if ( nDateOff
< 365 )
1310 Date aFirstDate
= GetFirstMonth();
1311 aFirstDate
.AddDays( aFirstDate
.GetDaysInMonth() );
1313 while ( nDateOff
> aTempDate
.GetDaysInMonth() )
1315 aFirstDate
.AddDays( aFirstDate
.GetDaysInMonth() );
1316 sal_Int32 nDaysInMonth
= aTempDate
.GetDaysInMonth();
1317 aTempDate
.AddDays( nDaysInMonth
);
1318 nDateOff
-= nDaysInMonth
;
1320 SetFirstDate( aFirstDate
);
1323 SetFirstDate( maCurDate
);
1330 ImplUpdateDate( aOldDate
);
1331 ImplUpdateDate( maCurDate
);
1336 void Calendar::SetFirstDate( const Date
& rNewFirstDate
)
1338 if ( maFirstDate
!= rNewFirstDate
)
1340 maFirstDate
= Date( 1, rNewFirstDate
.GetMonth(), rNewFirstDate
.GetYear() );
1345 Date
Calendar::GetFirstMonth() const
1347 if ( maFirstDate
.GetDay() > 1 )
1349 if ( maFirstDate
.GetMonth() == 12 )
1350 return Date( 1, 1, maFirstDate
.GetNextYear() );
1352 return Date( 1, maFirstDate
.GetMonth()+1, maFirstDate
.GetYear() );
1358 Date
Calendar::GetLastMonth() const
1360 Date aDate
= GetFirstMonth();
1361 sal_uInt16 nMonthCount
= GetMonthCount();
1362 for ( sal_uInt16 i
= 0; i
< nMonthCount
; i
++ )
1363 aDate
.AddDays( aDate
.GetDaysInMonth() );
1368 sal_uInt16
Calendar::GetMonthCount() const
1373 return static_cast<sal_uInt16
>(mnMonthPerLine
*mnLines
);
1376 bool Calendar::GetDate( const Point
& rPos
, Date
& rDate
) const
1378 Date aDate
= maCurDate
;
1379 sal_uInt16 nHitTest
= ImplDoHitTest( rPos
, aDate
);
1380 if ( nHitTest
& CALENDAR_HITTEST_DAY
)
1389 tools::Rectangle
Calendar::GetDateRect( const Date
& rDate
) const
1391 tools::Rectangle aRect
;
1393 if ( mbFormat
|| (rDate
< maFirstDate
) || (rDate
> (maFirstDate
+mnDayCount
)) )
1399 sal_uInt16 nDayIndex
;
1400 Date aDate
= GetFirstMonth();
1402 if ( rDate
< aDate
)
1404 aRect
= GetDateRect( aDate
);
1405 nDaysOff
= aDate
-rDate
;
1406 nX
= nDaysOff
*mnDayWidth
;
1407 aRect
.AdjustLeft( -nX
);
1408 aRect
.AdjustRight( -nX
);
1413 Date aLastDate
= GetLastMonth();
1414 if ( rDate
> aLastDate
)
1416 sal_Int32 nWeekDay
= static_cast<sal_Int32
>(aLastDate
.GetDayOfWeek());
1417 nWeekDay
= (nWeekDay
+(7-ImplGetWeekStart())) % 7;
1418 aLastDate
.AddDays( -nWeekDay
);
1419 aRect
= GetDateRect( aLastDate
);
1420 nDaysOff
= rDate
-aLastDate
;
1422 for ( sal_Int32 i
= 0; i
<= nDaysOff
; i
++ )
1424 if ( aLastDate
== rDate
)
1426 aRect
.AdjustLeft(nDayIndex
*mnDayWidth
);
1427 aRect
.SetRight( aRect
.Left()+mnDayWidth
);
1430 if ( nDayIndex
== 6 )
1433 aRect
.AdjustTop(mnDayHeight
);
1434 aRect
.AdjustBottom(mnDayHeight
);
1444 for ( tools::Long i
= 0; i
< mnLines
; i
++ )
1447 for ( tools::Long j
= 0; j
< mnMonthPerLine
; j
++ )
1449 sal_uInt16 nDaysInMonth
= aDate
.GetDaysInMonth();
1452 if ( (aDate
.GetMonth() == rDate
.GetMonth()) &&
1453 (aDate
.GetYear() == rDate
.GetYear()) )
1455 tools::Long nDayX
= nX
+mnDaysOffX
;
1456 tools::Long nDayY
= nY
+mnDaysOffY
;
1457 nDayIndex
= static_cast<sal_uInt16
>(aDate
.GetDayOfWeek());
1458 nDayIndex
= (nDayIndex
+(7-static_cast<sal_uInt16
>(ImplGetWeekStart()))) % 7;
1459 for ( sal_uInt16 nDay
= 1; nDay
<= nDaysInMonth
; nDay
++ )
1461 if ( nDay
== rDate
.GetDay() )
1463 aRect
.SetLeft( nDayX
+ (nDayIndex
*mnDayWidth
) );
1464 aRect
.SetTop( nDayY
);
1465 aRect
.SetRight( aRect
.Left()+mnDayWidth
);
1466 aRect
.SetBottom( aRect
.Top()+mnDayHeight
);
1469 if ( nDayIndex
== 6 )
1472 nDayY
+= mnDayHeight
;
1479 aDate
.AddDays( nDaysInMonth
);
1483 nY
+= mnMonthHeight
;
1489 void Calendar::EndSelection()
1491 if ( mbDrag
|| mbSpinDown
)
1502 Size
Calendar::CalcWindowSizePixel() const
1505 tools::Long n99TextWidth
= GetTextWidth( "99" );
1506 tools::Long nTextHeight
= GetTextHeight();
1508 aSize
.AdjustWidth((n99TextWidth
+DAY_OFFX
)*7);
1509 aSize
.AdjustWidth(MONTH_BORDERX
*2 );
1511 aSize
.setHeight( nTextHeight
+ TITLE_OFFY
+ (TITLE_BORDERY
*2) );
1512 aSize
.AdjustHeight(nTextHeight
+ WEEKDAY_OFFY
);
1513 aSize
.AdjustHeight((nTextHeight
+DAY_OFFY
)*6);
1514 aSize
.AdjustHeight(MONTH_OFFY
);
1519 Size
Calendar::GetOptimalSize() const
1521 return CalcWindowSizePixel();
1526 class ImplCFieldFloat final
1529 std::unique_ptr
<weld::Builder
> mxBuilder
;
1530 std::unique_ptr
<weld::Container
> mxContainer
;
1531 std::unique_ptr
<weld::Calendar
> mxCalendar
;
1532 std::unique_ptr
<weld::Button
> mxTodayBtn
;
1533 std::unique_ptr
<weld::Button
> mxNoneBtn
;
1536 ImplCFieldFloat(vcl::Window
* pContainer
)
1537 : mxBuilder(Application::CreateInterimBuilder(pContainer
, "svt/ui/calendar.ui", false))
1538 , mxContainer(mxBuilder
->weld_container("Calendar"))
1539 , mxCalendar(mxBuilder
->weld_calendar("date"))
1540 , mxTodayBtn(mxBuilder
->weld_button("today"))
1541 , mxNoneBtn(mxBuilder
->weld_button("none"))
1545 weld::Calendar
* GetCalendar() { return mxCalendar
.get(); }
1546 weld::Button
* EnableTodayBtn(bool bEnable
);
1547 weld::Button
* EnableNoneBtn(bool bEnable
);
1551 mxCalendar
->grab_focus();
1556 struct ImplCFieldFloatWin
: public DropdownDockingWindow
1558 explicit ImplCFieldFloatWin(vcl::Window
* pParent
);
1559 virtual void dispose() override
;
1560 virtual ~ImplCFieldFloatWin() override
;
1561 virtual void GetFocus() override
;
1563 std::unique_ptr
<ImplCFieldFloat
> mxWidget
;
1566 ImplCFieldFloatWin::ImplCFieldFloatWin(vcl::Window
* pParent
)
1567 : DropdownDockingWindow(pParent
)
1569 setDeferredProperties();
1570 mxWidget
.reset(new ImplCFieldFloat(m_xBox
.get()));
1573 ImplCFieldFloatWin::~ImplCFieldFloatWin()
1578 void ImplCFieldFloatWin::dispose()
1581 DropdownDockingWindow::dispose();
1584 void ImplCFieldFloatWin::GetFocus()
1586 DropdownDockingWindow::GetFocus();
1589 mxWidget
->GrabFocus();
1592 weld::Button
* ImplCFieldFloat::EnableTodayBtn(bool bEnable
)
1594 mxTodayBtn
->set_visible(bEnable
);
1595 return bEnable
? mxTodayBtn
.get() : nullptr;
1598 weld::Button
* ImplCFieldFloat::EnableNoneBtn(bool bEnable
)
1600 mxNoneBtn
->set_visible(bEnable
);
1601 return bEnable
? mxNoneBtn
.get() : nullptr;
1604 CalendarField::CalendarField(vcl::Window
* pParent
, WinBits nWinStyle
)
1605 : DateField(pParent
, nWinStyle
)
1606 , mpFloatWin(nullptr)
1607 , mpTodayBtn(nullptr)
1608 , mpNoneBtn(nullptr)
1614 CalendarField::~CalendarField()
1619 void CalendarField::dispose()
1621 mpTodayBtn
= nullptr;
1622 mpNoneBtn
= nullptr;
1623 mpFloatWin
.disposeAndClear();
1624 DateField::dispose();
1627 IMPL_LINK(CalendarField
, ImplSelectHdl
, weld::Calendar
&, rCalendar
, void)
1629 Date aNewDate
= rCalendar
.get_date();
1631 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1632 mpFloatWin
->EnableDocking(false);
1635 if ( IsEmptyDate() || ( aNewDate
!= GetDate() ) )
1637 SetDate( aNewDate
);
1643 IMPL_LINK(CalendarField
, ImplClickHdl
, weld::Button
&, rBtn
, void)
1645 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1646 mpFloatWin
->EnableDocking(false);
1650 if (&rBtn
== mpTodayBtn
)
1652 Date
aToday( Date::SYSTEM
);
1653 if ( (aToday
!= GetDate()) || IsEmptyDate() )
1660 else if (&rBtn
== mpNoneBtn
)
1662 if ( !IsEmptyDate() )
1671 IMPL_LINK_NOARG(CalendarField
, ImplPopupModeEndHdl
, FloatingWindow
*, void)
1677 bool CalendarField::ShowDropDown( bool bShow
)
1682 mpFloatWin
= VclPtr
<ImplCFieldFloatWin
>::Create( this );
1684 Date aDate
= GetDate();
1685 if ( IsEmptyDate() || !aDate
.IsValidAndGregorian() )
1687 aDate
= Date( Date::SYSTEM
);
1689 weld::Calendar
* pCalendar
= mpFloatWin
->mxWidget
->GetCalendar();
1690 pCalendar
->set_date( aDate
);
1691 pCalendar
->connect_activated(LINK(this, CalendarField
, ImplSelectHdl
));
1692 mpTodayBtn
= mpFloatWin
->mxWidget
->EnableTodayBtn(mbToday
);
1693 mpNoneBtn
= mpFloatWin
->mxWidget
->EnableNoneBtn(mbNone
);
1695 mpTodayBtn
->connect_clicked( LINK( this, CalendarField
, ImplClickHdl
) );
1697 mpNoneBtn
->connect_clicked( LINK( this, CalendarField
, ImplClickHdl
) );
1698 Point
aPos(GetParent()->OutputToScreenPixel(GetPosPixel()));
1699 tools::Rectangle
aRect(aPos
, GetSizePixel());
1700 aRect
.AdjustBottom( -1 );
1701 DockingManager
* pDockingManager
= vcl::Window::GetDockingManager();
1702 mpFloatWin
->EnableDocking(true);
1703 pDockingManager
->SetPopupModeEndHdl(mpFloatWin
, LINK(this, CalendarField
, ImplPopupModeEndHdl
));
1704 pDockingManager
->StartPopupMode(mpFloatWin
, aRect
, FloatWinPopupFlags::Down
| FloatWinPopupFlags::GrabFocus
);
1708 vcl::Window::GetDockingManager()->EndPopupMode(mpFloatWin
);
1709 mpFloatWin
->EnableDocking(false);
1715 void CalendarField::StateChanged( StateChangedType nStateChange
)
1717 DateField::StateChanged( nStateChange
);
1719 if ( ( nStateChange
== StateChangedType::Style
) && GetSubEdit() )
1721 WinBits nAllAlignmentBits
= ( WB_LEFT
| WB_CENTER
| WB_RIGHT
| WB_TOP
| WB_VCENTER
| WB_BOTTOM
);
1722 WinBits nMyAlignment
= GetStyle() & nAllAlignmentBits
;
1723 GetSubEdit()->SetStyle( ( GetSubEdit()->GetStyle() & ~nAllAlignmentBits
) | nMyAlignment
);
1727 // tdf#142783 consider the Edit and its DropDown as one compound control for the purpose of
1728 // notification of loss of focus from the control
1729 bool CalendarField::FocusWindowBelongsToControl(const vcl::Window
* pFocusWin
) const
1731 return DateField::FocusWindowBelongsToControl(pFocusWin
) || (mpFloatWin
&& mpFloatWin
->ImplIsWindowOrChild(pFocusWin
));
1734 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */