Warning, file /pim/kalarm/src/daymatrix.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  daymatrix.cpp  -  calendar day matrix display
0003  *  Program:  kalarm
0004  *  This class is adapted from KODayMatrix in KOrganizer.
0005  *
0006  *  SPDX-FileCopyrightText: 2001 Eitzenberger Thomas <thomas.eitzenberger@siemens.at>
0007  *  Parts of the source code have been copied from kdpdatebutton.cpp
0008  *
0009  *  SPDX-FileCopyrightText: 2003 Cornelius Schumacher <schumacher@kde.org>
0010  *  SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
0011  *  SPDX-FileCopyrightText: 2021-2023 David Jarvie <djarvie@kde.org>
0012  *
0013  *  SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0014 */
0015 
0016 #include "daymatrix.h"
0017 
0018 #include "newalarmaction.h"
0019 #include "preferences.h"
0020 #include "resources/resources.h"
0021 #include "kalarmcalendar/holidays.h"
0022 
0023 #include <KLocalizedString>
0024 
0025 #include <QMenu>
0026 #include <QApplication>
0027 #include <QMouseEvent>
0028 #include <QPainter>
0029 #include <QToolTip>
0030 
0031 #include <cmath>
0032 
0033 namespace
0034 {
0035 const int NUMROWS = 6;                // number of rows displayed in the matrix
0036 const int NUMDAYS = NUMROWS * 7;      // number of days displayed in the matrix
0037 const int NO_SELECTION = -1000000;    // invalid selection start/end value
0038 
0039 const QColor HOLIDAY_BACKGROUND_COLOUR(255,100,100);  // add a preference for this?
0040 const int    TODAY_MARGIN_WIDTH(2);
0041 
0042 struct TextColours
0043 {
0044     QColor disabled;
0045     QColor thisMonth;
0046     QColor otherMonth;
0047     QColor thisMonthHoliday {HOLIDAY_BACKGROUND_COLOUR};
0048     QColor otherMonthHoliday;
0049 
0050     explicit TextColours(const QPalette& palette);
0051 
0052 private:
0053     QColor getShadedColour(const QColor& colour, bool enabled) const;
0054 };
0055 }
0056 
0057 DayMatrix::DayMatrix(QWidget* parent)
0058     : QFrame(parent)
0059     , mDayLabels(NUMDAYS)
0060     , mSelStart(NO_SELECTION)
0061     , mSelEnd(NO_SELECTION)
0062 {
0063     mHolidays.reserve(NUMDAYS);
0064     for (int i = 0; i < NUMDAYS; ++i)
0065         mHolidays.append(QString());
0066 
0067     Resources* resources = Resources::instance();
0068     connect(resources, &Resources::resourceAdded, this, &DayMatrix::resourceUpdated);
0069     connect(resources, &Resources::resourceRemoved, this, &DayMatrix::resourceRemoved);
0070     connect(resources, &Resources::settingsChanged, this, &DayMatrix::resourceSettingsChanged);
0071     connect(resources, &Resources::eventsAdded, this, &DayMatrix::resourceUpdated);
0072     connect(resources, &Resources::eventUpdated, this, &DayMatrix::resourceUpdated);
0073     connect(resources, &Resources::eventsRemoved, this, &DayMatrix::resourceUpdated);
0074     Preferences::connect(&Preferences::holidaysChanged, this, &DayMatrix::slotUpdateView);
0075     Preferences::connect(&Preferences::workTimeChanged, this, &DayMatrix::slotUpdateView);
0076 }
0077 
0078 DayMatrix::~DayMatrix()
0079 {
0080 }
0081 
0082 /******************************************************************************
0083 * Return all selected dates from mSelStart to mSelEnd, in date order.
0084 */
0085 QList<QDate> DayMatrix::selectedDates() const
0086 {
0087     QList<QDate> selDays;
0088     if (mSelStart != NO_SELECTION)
0089     {
0090         selDays.reserve(mSelEnd - mSelStart + 1);
0091         for (int i = mSelStart;  i <= mSelEnd;  ++i)
0092             selDays.append(mStartDate.addDays(i));
0093     }
0094     return selDays;
0095 }
0096 
0097 /******************************************************************************
0098 * Clear the current selection of dates.
0099 */
0100 void DayMatrix::clearSelection()
0101 {
0102     setMouseSelection(NO_SELECTION, NO_SELECTION, true);
0103 }
0104 
0105 /******************************************************************************
0106 * Evaluate the index for today, and update the display if it has changed.
0107 */
0108 void DayMatrix::updateToday(const QDate& newDate)
0109 {
0110     const int index = mStartDate.daysTo(newDate);
0111     if (index != mTodayIndex)
0112     {
0113         mTodayIndex = index;
0114         updateEvents();
0115 
0116         if (mSelStart != NO_SELECTION  &&  mSelStart < mTodayIndex)
0117         {
0118             if (mSelEnd < mTodayIndex)
0119                 setMouseSelection(NO_SELECTION, NO_SELECTION, true);
0120             else
0121                 setMouseSelection(mTodayIndex, mSelEnd, true);
0122         }
0123         else
0124             update();
0125     }
0126 }
0127 
0128 /******************************************************************************
0129 * Set a new start date for the matrix. If changed, or other changes are
0130 * pending, recalculates which days in the matrix alarms occur on, and which are
0131 * holidays/non-work days, and repaints.
0132 */
0133 void DayMatrix::setStartDate(const QDate& startDate)
0134 {
0135     if (!startDate.isValid())
0136         return;
0137 
0138     if (startDate != mStartDate)
0139     {
0140         if (mSelStart != NO_SELECTION)
0141         {
0142             // Adjust selection indexes to be relative to the new start date.
0143             const int diff = startDate.daysTo(mStartDate);
0144             mSelStart += diff;
0145             mSelEnd   += diff;
0146             if (mSelectionMustBeVisible)
0147             {
0148                 // Ensure that the whole selection is still visible: if not, cancel the selection.
0149                 if (mSelStart < 0  ||  mSelEnd >= NUMDAYS)
0150                     setMouseSelection(NO_SELECTION, NO_SELECTION, true);
0151             }
0152         }
0153 
0154         mStartDate = startDate;
0155 
0156         QLocale locale;
0157         mMonthStartIndex = -1;
0158         mMonthEndIndex = NUMDAYS-1;
0159         for (int i = 0; i < NUMDAYS; ++i)
0160         {
0161             const int day = mStartDate.addDays(i).day();
0162             mDayLabels[i] = locale.toString(day);
0163 
0164             if (day == 1)    // start of a month
0165             {
0166                 if (mMonthStartIndex < 0)
0167                     mMonthStartIndex = i;
0168                 else
0169                     mMonthEndIndex = i - 1;
0170             }
0171         }
0172 
0173         mTodayIndex = mStartDate.daysTo(KADateTime::currentDateTime(Preferences::timeSpec()).date());
0174         updateView();
0175     }
0176     else if (mPendingChanges)
0177         updateView();
0178 }
0179 
0180 /******************************************************************************
0181 * If changes are pending, recalculate which days in the matrix have alarms
0182 * occurring, and which are holidays/non-work days. Repaint the matrix.
0183 */
0184 void DayMatrix::updateView(const Resource& resource)
0185 {
0186     if (!mStartDate.isValid())
0187         return;
0188 
0189     // TODO_Recurrence: If we just change the selection, but not the data,
0190     // there's no need to update the whole list of alarms... This is just a
0191     // waste of computational power
0192     updateEvents(resource);
0193 
0194     // Find which holidays occur for the dates in the matrix.
0195     const KAlarmCal::Holidays& holidays = Preferences::holidays();
0196     for (int i = 0; i < NUMDAYS; ++i)
0197     {
0198         const QStringList names = holidays.holidayNames(mStartDate.addDays(i));
0199         if (!names.isEmpty())
0200             mHolidays[i] = names.join(i18nc("delimiter for joining holiday names", ","));
0201         else
0202             mHolidays[i].clear();
0203     }
0204 
0205     update();
0206 }
0207 
0208 /******************************************************************************
0209 * Find which days currently displayed have alarms scheduled, for all active
0210 * resources.
0211 */
0212 void DayMatrix::updateEvents(const Resource& resource)
0213 {
0214     const QDate startDate = (mTodayIndex <= 0) ? mStartDate : mStartDate.addDays(mTodayIndex);
0215     const KADateTime before = KADateTime(startDate, QTime(0,0,0), Preferences::timeSpec()).addSecs(-60);
0216     const KADateTime to(mStartDate.addDays(NUMDAYS-1), QTime(23,59,0), Preferences::timeSpec());
0217 
0218     mEventDates.clear();
0219     const QList<Resource> resources = Resources::enabledResources(CalEvent::ACTIVE);
0220     for (const Resource& res : resources)
0221     {
0222         if (!resource.isValid()  ||  res.id() == resource.id())
0223             updateEvents(res, before, to);
0224         if (mEventDates.count() < NUMDAYS)
0225             mEventDates |= mResourceEventDates[res.id()];
0226     }
0227 
0228     mPendingChanges = false;
0229 }
0230 
0231 /******************************************************************************
0232 * Find which days currently displayed have alarms scheduled for a resource.
0233 */
0234 void DayMatrix::updateEvents(const Resource& resource, const KADateTime& before, const KADateTime& to)
0235 {
0236     ResourceId id = resource.id();
0237     const KADateTime::Spec timeSpec = Preferences::timeSpec();
0238 
0239     mResourceEventDates[id].clear();
0240     const QList<KAEvent> events = resource.events();
0241     const CalEvent::Types types = resource.enabledTypes() & CalEvent::ACTIVE;
0242     for (const KAEvent& event : events)
0243     {
0244         if (event.enabled()  &&  (event.category() & types))
0245         {
0246             // The event has an enabled alarm type.
0247             // Find all its recurrences/repetitions within the time period.
0248             DateTime nextDt;
0249             for (KADateTime from = before;  ;  )
0250             {
0251                 event.nextOccurrence(from, nextDt, KAEvent::Repeats::Return);
0252                 if (!nextDt.isValid())
0253                     break;
0254                 from = nextDt.effectiveKDateTime().toTimeSpec(timeSpec);
0255                 if (from > to)
0256                     break;
0257                 if (!event.excludedByWorkTimeOrHoliday(from))
0258                 {
0259                     mResourceEventDates[id] += from.date();
0260                     if (mResourceEventDates[id].count() >= NUMDAYS)
0261                         break;   // all days have alarms due
0262                 }
0263 
0264                 // If the alarm recurs more than once per day, don't waste
0265                 // time checking any more occurrences for the same day.
0266                 from.setTime(QTime(23,59,0));
0267             }
0268             if (mResourceEventDates[id].count() >= NUMDAYS)
0269                 break;   // all days have alarms due
0270         }
0271     }
0272 }
0273 
0274 /******************************************************************************
0275 * Return the holiday description (if any) for a date.
0276 */
0277 QString DayMatrix::getHolidayLabel(int offset) const
0278 {
0279     if (offset < 0 || offset > NUMDAYS - 1)
0280         return {};
0281     return mHolidays[offset];
0282 }
0283 
0284 /******************************************************************************
0285 * Determine the day index at a geometric position.
0286 * Return = NO_SELECTION if outside the widget, or if the date is earlier than today.
0287 */
0288 int DayMatrix::getDayIndex(const QPoint& pt) const
0289 {
0290     const int x = pt.x();
0291     const int y = pt.y();
0292     if (x < 0  ||  y < 0  ||  x > width()  ||  y > height())
0293         return NO_SELECTION;
0294     const int xd = static_cast<int>(x / mDaySize.width());
0295     const int i = 7 * int(y / mDaySize.height())
0296                 + (QApplication::isRightToLeft() ? 6 - xd : xd);
0297     if (i < mTodayIndex  ||  i > NUMDAYS-1)
0298         return NO_SELECTION;
0299     return i;
0300 }
0301 
0302 void DayMatrix::setRowHeight(int rowHeight)
0303 {
0304     mRowHeight = rowHeight;
0305     setMinimumSize(minimumWidth(), mRowHeight * NUMROWS + TODAY_MARGIN_WIDTH*2);
0306 }
0307 
0308 /******************************************************************************
0309 * Called when the events in a resource have been updated.
0310 * Re-evaluate all events in the resource.
0311 */
0312 void DayMatrix::resourceUpdated(Resource& resource)
0313 {
0314     mPendingChanges = true;
0315     updateView(resource);
0316 }
0317 
0318 /******************************************************************************
0319 * Called when a resource has been removed.
0320 * Remove all its events from the view.
0321 */
0322 void DayMatrix::resourceRemoved(ResourceId id)
0323 {
0324     mPendingChanges = true;
0325     updateView(Resources::resource(id));
0326 }
0327 
0328 /******************************************************************************
0329 * Called when a resource's settings have been changed.
0330 * If it has been disabled, remove all its events from the view.
0331 */
0332 void DayMatrix::resourceSettingsChanged(Resource& resource, ResourceType::Changes changes)
0333 {
0334     if (changes == ResourceType::Enabled)
0335     {
0336         if (!resource.isEnabled(CalEvent::ACTIVE))
0337         {
0338             // Active events are now disabled for the resource.
0339             mPendingChanges = true;
0340             updateView(resource);
0341         }
0342         // else if active events are now enabled, they will be added by eventsAdded()
0343     }
0344 }
0345 
0346 /******************************************************************************
0347 * Called when the holiday or work time settings have changed.
0348 * Re-evaluate all events in the view.
0349 */
0350 void DayMatrix::slotUpdateView()
0351 {
0352     mPendingChanges = true;
0353     updateView();
0354     Q_EMIT selected(mLastSelectedDates, true);
0355 }
0356 
0357 // ----------------------------------------------------------------------------
0358 //  M O U S E   E V E N T   H A N D L I N G
0359 // ----------------------------------------------------------------------------
0360 
0361 bool DayMatrix::event(QEvent* event)
0362 {
0363     if (event->type() == QEvent::ToolTip)
0364     {
0365         // Tooltip event: show the holiday name.
0366         auto* helpEvent = static_cast<QHelpEvent*>(event);
0367         const int i = getDayIndex(helpEvent->pos());
0368         const QString tipText = getHolidayLabel(i);
0369         if (!tipText.isEmpty())
0370             QToolTip::showText(helpEvent->globalPos(), tipText);
0371         else
0372             QToolTip::hideText();
0373     }
0374     return QWidget::event(event);
0375 }
0376 
0377 void DayMatrix::mousePressEvent(QMouseEvent* e)
0378 {
0379     int i = getDayIndex(e->pos());
0380     if (i < 0)
0381     {
0382         mSelInit = NO_SELECTION;   // invalid: it's not in the matrix or it's before today
0383         setMouseSelection(NO_SELECTION, NO_SELECTION, true);
0384         return;
0385     }
0386     if (e->button() == Qt::RightButton)
0387     {
0388         if (i < mSelStart  ||  i > mSelEnd)
0389             setMouseSelection(i, i, true);
0390         popupMenu(e->globalPosition().toPoint());
0391     }
0392     else if (e->button() == Qt::LeftButton)
0393     {
0394         if (i >= mSelStart  &&  i <= mSelEnd)
0395         {
0396             mSelInit = NO_SELECTION;   // already selected: cancel the current selection
0397             setMouseSelection(NO_SELECTION, NO_SELECTION, true);
0398             return;
0399         }
0400         mSelInit = i;
0401         setMouseSelection(i, i, false);   // don't emit signal until mouse move has completed
0402     }
0403 }
0404 
0405 void DayMatrix::popupMenu(const QPoint& pos)
0406 {
0407     NewAlarmAction newAction(false, QString(), nullptr);
0408     QMenu* popup = newAction.menu();
0409     connect(&newAction, &NewAlarmAction::selected, this, &DayMatrix::newAlarm);
0410     connect(&newAction, &NewAlarmAction::selectedTemplate, this, &DayMatrix::newAlarmFromTemplate);
0411     popup->exec(pos);
0412 }
0413 
0414 void DayMatrix::mouseReleaseEvent(QMouseEvent* e)
0415 {
0416     if (e->button() != Qt::LeftButton)
0417         return;
0418 
0419     if (mSelInit < 0)
0420         return;
0421     int i = getDayIndex(e->pos());
0422     if (i < 0)
0423     {
0424         // Emit signal after move (without changing the selection).
0425         setMouseSelection(mSelStart, mSelEnd, true);
0426         return;
0427     }
0428 
0429     setMouseSelection(mSelInit, i, true);
0430 }
0431 
0432 void DayMatrix::mouseMoveEvent(QMouseEvent* e)
0433 {
0434     if (mSelInit < 0)
0435         return;
0436     int i = getDayIndex(e->pos());
0437     setMouseSelection(mSelInit, i, false);   // don't emit signal until mouse move has completed
0438 }
0439 
0440 /******************************************************************************
0441 * Set the current day selection, and update the display.
0442 * Note that the selection may extend past the end of the current matrix.
0443 */
0444 void DayMatrix::setMouseSelection(int start, int end, bool emitSignal)
0445 {
0446     if (!mAllowMultipleSelection)
0447         start = end;
0448     if (end < start)
0449         std::swap(start, end);
0450     if (start != mSelStart  ||  end != mSelEnd)
0451     {
0452         mSelStart = start;
0453         mSelEnd   = end;
0454         if (mSelStart < 0  ||  mSelEnd < 0)
0455             mSelStart = mSelEnd = NO_SELECTION;
0456         update();
0457     }
0458 
0459     if (emitSignal)
0460     {
0461         const QList<QDate> dates = selectedDates();
0462         if (dates != mLastSelectedDates)
0463         {
0464             mLastSelectedDates = dates;
0465             Q_EMIT selected(dates, false);
0466         }
0467     }
0468 }
0469 
0470 /******************************************************************************
0471 * Called to paint the widget.
0472 */
0473 void DayMatrix::paintEvent(QPaintEvent*)
0474 {
0475     QPainter p;
0476     const QRect rect = frameRect();
0477     const double dayHeight = mDaySize.height();
0478     const double dayWidth  = mDaySize.width();
0479     const bool isRTL = QApplication::isRightToLeft();
0480 
0481     const QPalette pal = palette();
0482 
0483     p.begin(this);
0484 
0485     // Draw the background
0486     p.fillRect(0, 0, rect.width(), rect.height(), QBrush(pal.color(QPalette::Base)));
0487 
0488     // Draw the frame
0489     p.setPen(pal.color(QPalette::Mid));
0490     p.drawRect(0, 0, rect.width() - 1, rect.height() - 1);
0491     p.translate(1, 1);    // don't paint over borders
0492 
0493     // Draw the background colour for all days not in the selected month.
0494     const QColor GREY_COLOUR(pal.color(QPalette::AlternateBase));
0495     if (mMonthStartIndex >= 0)
0496         colourBackground(p, GREY_COLOUR, 0, mMonthStartIndex - 1);
0497     colourBackground(p, GREY_COLOUR, mMonthEndIndex + 1, NUMDAYS - 1);
0498 
0499     // Draw the background colour for all selected days.
0500     if (mSelStart != NO_SELECTION)
0501     {
0502         const QColor SELECTION_COLOUR(pal.color(QPalette::Highlight));
0503         colourBackground(p, SELECTION_COLOUR, mSelStart, mSelEnd);
0504     }
0505 
0506     // Find holidays which are non-work days.
0507     QSet<QDate> nonWorkHolidays;
0508     {
0509         const KAlarmCal::Holidays& holidays = Preferences::holidays();
0510         for (int i = 0; i < NUMDAYS; ++i)
0511         {
0512             const QDate date = mStartDate.addDays(i);
0513             if (holidays.isHoliday(date))
0514                 nonWorkHolidays += date;
0515         }
0516     }
0517     const QBitArray workDays = Preferences::workDays();
0518 
0519     // Draw the day label for each day in the matrix.
0520     TextColours textColours(pal);
0521     const QFont savedFont = font();
0522     QColor lastColour;
0523     for (int i = 0; i < NUMDAYS; ++i)
0524     {
0525         const int row    = i / 7;
0526         const int column = isRTL ? 6 - (i - row * 7) : i - row * 7;
0527 
0528         const bool nonWorkDay = (i >= mTodayIndex) && (!workDays[mStartDate.addDays(i).dayOfWeek()-1] || nonWorkHolidays.contains(mStartDate.addDays(i)));
0529 
0530         const QColor colour = textColour(textColours, pal, i, !nonWorkDay);
0531         if (colour != lastColour)
0532         {
0533             lastColour = colour;
0534             p.setPen(colour);
0535         }
0536 
0537         if (mTodayIndex == i)
0538         {
0539             // Draw a rectangle round today.
0540             const QPen savedPen = p.pen();
0541             QPen todayPen = savedPen;
0542             todayPen.setWidth(TODAY_MARGIN_WIDTH);
0543             p.setPen(todayPen);
0544             p.drawRect(QRectF(column * dayWidth, row * dayHeight, dayWidth, dayHeight));
0545             p.setPen(savedPen);
0546         }
0547 
0548         // If any events occur on the day, draw it in bold
0549         const bool hasEvent = mEventDates.contains(mStartDate.addDays(i));
0550         if (hasEvent)
0551         {
0552             QFont evFont = savedFont;
0553             evFont.setWeight(QFont::Black);
0554             evFont.setPointSize(evFont.pointSize() + 1);
0555             evFont.setStretch(110);
0556             p.setFont(evFont);
0557         }
0558 
0559         p.drawText(QRectF(column * dayWidth, row * dayHeight, dayWidth, dayHeight),
0560                    Qt::AlignHCenter | Qt::AlignVCenter, mDayLabels.at(i));
0561 
0562         if (hasEvent)
0563             p.setFont(savedFont);   // restore normal font
0564     }
0565     p.end();
0566 }
0567 
0568 /******************************************************************************
0569 * Paint a background colour for a range of days.
0570 */
0571 void DayMatrix::colourBackground(QPainter& p, const QColor& colour, int start, int end)
0572 {
0573     if (end < 0)
0574         return;
0575     if (start < 0)
0576         start = 0;
0577     const int row = start / 7;
0578     if (row >= NUMROWS)
0579         return;
0580     const int column = start - row * 7;
0581 
0582     const double dayHeight = mDaySize.height();
0583     const double dayWidth  = mDaySize.width();
0584     const bool isRTL = QApplication::isRightToLeft();
0585 
0586     if (row == end / 7)
0587     {
0588         // Single row to highlight.
0589         p.fillRect(QRectF((isRTL ? (7 - (end - start + 1) - column) : column) * dayWidth,
0590                           row * dayHeight,
0591                           (end - start + 1) * dayWidth - 2,
0592                           dayHeight),
0593                    colour);
0594     }
0595     else
0596     {
0597         // Draw first row, to the right of the start day.
0598         p.fillRect(QRectF((isRTL ? 0 : column * dayWidth), row * dayHeight,
0599                           (7 - column) * dayWidth - 2, dayHeight),
0600                    colour);
0601         // Draw full block till last line
0602         int selectionHeight = end / 7 - row;
0603         if (selectionHeight + row >= NUMROWS)
0604             selectionHeight = NUMROWS - row;
0605         if (selectionHeight > 1)
0606             p.fillRect(QRectF(0, (row + 1) * dayHeight,
0607                               7 * dayWidth - 2, (selectionHeight - 1) * dayHeight),
0608                        colour);
0609         // Draw last row, to the left of the end day.
0610         if (end / 7 < NUMROWS)
0611         {
0612             const int selectionWidth = end - 7 * (end / 7) + 1;
0613             p.fillRect(QRectF((isRTL ? (7 - selectionWidth) * dayWidth : 0),
0614                               (row + selectionHeight) * dayHeight,
0615                               selectionWidth * dayWidth - 2, dayHeight),
0616                        colour);
0617         }
0618     }
0619 }
0620 
0621 /******************************************************************************
0622 * Called when the widget is resized. Set the size of each date in the matrix.
0623 */
0624 void DayMatrix::resizeEvent(QResizeEvent*)
0625 {
0626     const QRect sz = frameRect();
0627     const int padding = style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing) / 2;
0628     mDaySize.setHeight((sz.height() - padding) * 7.0 / NUMDAYS);
0629     mDaySize.setWidth(sz.width() / 7.0);
0630 }
0631 
0632 /******************************************************************************
0633 * Evaluate the text color to show a given date.
0634 */
0635 QColor DayMatrix::textColour(const TextColours& textColours, const QPalette& palette, int dayIndex, bool workDay) const
0636 {
0637     if (dayIndex >= mSelStart  &&  dayIndex <= mSelEnd)
0638     {
0639         if (dayIndex == mTodayIndex)
0640             return QColor(QStringLiteral("lightgrey"));
0641         if (workDay)
0642             return palette.color(QPalette::HighlightedText);
0643     }
0644     if (dayIndex < mTodayIndex)
0645         return textColours.disabled;
0646     if (dayIndex >= mMonthStartIndex  &&  dayIndex <= mMonthEndIndex)
0647         return workDay ? textColours.thisMonth : textColours.thisMonthHoliday;
0648     else
0649         return workDay ? textColours.otherMonth : textColours.otherMonthHoliday;
0650 }
0651 
0652 /*===========================================================================*/
0653 
0654 TextColours::TextColours(const QPalette& palette)
0655 {
0656     thisMonth         = palette.color(QPalette::Text);
0657     disabled          = getShadedColour(thisMonth, false);
0658     otherMonth        = getShadedColour(thisMonth, true);
0659     thisMonthHoliday  = thisMonth;
0660     thisMonthHoliday.setRed((thisMonthHoliday.red() + 255) / 2);
0661     otherMonthHoliday = getShadedColour(thisMonthHoliday, true);
0662 }
0663 
0664 QColor TextColours::getShadedColour(const QColor& colour, bool enabled) const
0665 {
0666     QColor shaded;
0667     int h = 0;
0668     int s = 0;
0669     int v = 0;
0670     colour.getHsv(&h, &s, &v);
0671     s = s / (enabled ? 2 : 4);
0672     v = enabled ? (4*v + 5*255) / 9 : (v + 5*255) / 6;
0673     shaded.setHsv(h, s, v);
0674     return shaded;
0675 }
0676 
0677 #include "moc_daymatrix.cpp"
0678 
0679 // vim: et sw=4: