Kstars

moonphasecalendarwidget.cpp
1 /*
2  SPDX-FileCopyrightText: 2010 Akarsh Simha <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "moonphasecalendarwidget.h"
8 
9 #include "ksnumbers.h"
10 #include "kstarsdatetime.h"
11 #include "ksutils.h"
12 #include "texturemanager.h"
13 #include "skyobjects/ksmoon.h"
14 #include "skyobjects/ksplanet.h"
15 #include "skyobjects/kssun.h"
16 
17 #include <kcalendarsystem.h>
18 #include <kcolorscheme.h>
19 #include <kglobal.h>
20 #include <kglobalsettings.h>
21 #include <KLocale>
22 
23 #include <QActionEvent>
24 #include <QDebug>
25 #include <QFontDatabase>
26 #include <QPainter>
27 #include <QStyle>
28 #include <QtGui/QStyleOptionViewItem>
29 
30 #include <cmath>
31 
32 MoonPhaseCalendar::MoonPhaseCalendar(KSMoon &moon, KSSun &sun, QWidget *parent)
33  : KDateTable(parent), m_Moon(moon), m_Sun(sun)
34 {
35  // Populate moon images from disk into the hash
36  numDayColumns = calendar()->daysInWeek(QDate::currentDate());
37  numWeekRows = 7;
38  imagesLoaded = false;
39  // TODO: Set geometry.
40 }
41 
42 MoonPhaseCalendar::~MoonPhaseCalendar()
43 {
44 }
45 
47 {
48  const int suggestedMoonImageSize = 50;
49  return QSize(qRound((suggestedMoonImageSize + 2) * numDayColumns),
50  (qRound(suggestedMoonImageSize + 4 + 12) * numWeekRows)); // FIXME: Using hard-coded fontsize
51 }
52 
53 void MoonPhaseCalendar::loadImages()
54 {
55  computeMoonImageSize();
56  qDebug() << "Loading moon images. MoonImageSize = " << MoonImageSize;
57  for (int i = 0; i < 36; ++i)
58  {
59  QString imName = QString().sprintf("moon%02d", i);
60  m_Images[i] = QPixmap::fromImage(TextureManager::getImage(imName))
61  .scaled(MoonImageSize, MoonImageSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
62  }
63  imagesLoaded = true;
64 }
65 
66 void MoonPhaseCalendar::computeMoonImageSize()
67 {
68  cellWidth = width() / (double)numDayColumns;
69  cellHeight = height() / (double)numWeekRows;
70  qDebug() << cellWidth << cellHeight;
71  MoonImageSize =
72  ((cellWidth > cellHeight - 12) ? cellHeight - 12 : cellWidth) - 2; // FIXME: Using hard-coded fontsize
73 }
74 
75 void MoonPhaseCalendar::setGeometry(int, int, int, int)
76 {
77  imagesLoaded = false;
78 }
79 
80 void MoonPhaseCalendar::setGeometry(const QRect &r)
81 {
82  setGeometry(r.x(), r.y(), r.width(), r.height()); // FIXME: +1 / -1 pixel compensation. Not required at the moment.
83 }
84 
85 void MoonPhaseCalendar::paintEvent(QPaintEvent *e)
86 {
87  QPainter p(this);
88  if (!imagesLoaded)
89  loadImages();
90  KColorScheme colorScheme(palette().currentColorGroup(), KColorScheme::View);
91  const QRect &rectToUpdate = e->rect();
92  int leftCol = (int)std::floor(rectToUpdate.left() / cellWidth);
93  int topRow = (int)std::floor(rectToUpdate.top() / cellHeight);
94  int rightCol = (int)std::ceil(rectToUpdate.right() / cellWidth);
95  int bottomRow = (int)std::ceil(rectToUpdate.bottom() / cellHeight);
96  bottomRow = qMin(bottomRow, numWeekRows - 1);
97  rightCol = qMin(rightCol, numDayColumns - 1);
98  p.translate(leftCol * cellWidth, topRow * cellHeight);
99  for (int i = leftCol; i <= rightCol; ++i)
100  {
101  for (int j = topRow; j <= bottomRow; ++j)
102  {
103  this->paintCell(&p, j, i, colorScheme);
104  p.translate(0, cellHeight);
105  }
106  p.translate(cellWidth, 0);
107  p.translate(0, -cellHeight * (bottomRow - topRow + 1));
108  }
109  p.end();
110 }
111 
112 void MoonPhaseCalendar::paintCell(QPainter *painter, int row, int col, const KColorScheme &colorScheme)
113 {
114  double w = cellWidth - 1;
115  double h = cellHeight - 1;
116  QRectF cell = QRectF(0, 0, w, h);
117  QString cellText;
118  QPen pen;
119  QColor cellBackgroundColor, cellTextColor;
121  bool workingDay = false;
122  int cellWeekDay, pos;
123 
124  //Calculate the position of the cell in the grid
125  pos = numDayColumns * (row - 1) + col;
126 
127  //Calculate what day of the week the cell is
128  cellWeekDay = col + calendar()->weekStartDay();
129  if (cellWeekDay > numDayColumns)
130  {
131  cellWeekDay -= numDayColumns;
132  }
133 
134  //See if cell day is normally a working day
135  if (KLocale::global()->workingWeekStartDay() <= KLocale::global()->workingWeekEndDay())
136  {
137  workingDay = cellWeekDay >= KLocale::global()->workingWeekStartDay() &&
138  cellWeekDay <= KLocale::global()->workingWeekEndDay();
139  }
140  else
141  {
142  workingDay = cellWeekDay >= KLocale::global()->workingWeekStartDay() ||
143  cellWeekDay <= KLocale::global()->workingWeekEndDay();
144  }
145 
146  if (row == 0)
147  {
148  //We are drawing a header cell
149 
150  //If not a normal working day, then use "do not work today" color
151  if (workingDay)
152  {
153  cellTextColor = palette().color(QPalette::WindowText);
154  }
155  else
156  {
157  KColorScheme colorScheme(palette().currentColorGroup(), KColorScheme::Window);
158  cellTextColor = colorScheme.foreground(KColorScheme::NegativeText).color();
159  }
160  cellBackgroundColor = palette().color(QPalette::Window);
161 
162  //Set the text to the short day name and bold it
163  cellFont.setBold(true);
164  cellText = calendar()->weekDayName(cellWeekDay, KCalendarSystem::ShortDayName);
165  }
166  else
167  {
168  //We are drawing a day cell
169 
170  //Calculate the date the cell represents
171  QDate cellDate = dateFromPos(pos);
172 
173  bool validDay = calendar()->isValid(cellDate);
174 
175  // Draw the day number in the cell, if the date is not valid then we don't want to show it
176  if (validDay)
177  {
178  cellText = calendar()->dayString(cellDate, KCalendarSystem::ShortFormat);
179  }
180  else
181  {
182  cellText = "";
183  }
184 
185  if (!validDay || calendar()->month(cellDate) != calendar()->month(date()))
186  {
187  // we are either
188  // ° painting an invalid day
189  // ° painting a day of the previous month or
190  // ° painting a day of the following month or
191  cellBackgroundColor = palette().color(backgroundRole());
192  cellTextColor = colorScheme.foreground(KColorScheme::InactiveText).color();
193  }
194  else
195  {
196  //Paint a day of the current month
197 
198  // Background Colour priorities will be (high-to-low):
199  // * Selected Day Background Colour
200  // * Customized Day Background Colour
201  // * Normal Day Background Colour
202 
203  // Background Shape priorities will be (high-to-low):
204  // * Customized Day Shape
205  // * Normal Day Shape
206 
207  // Text Colour priorities will be (high-to-low):
208  // * Customized Day Colour
209  // * Day of Pray Colour (Red letter)
210  // * Selected Day Colour
211  // * Normal Day Colour
212 
213  //Determine various characteristics of the cell date
214  bool selectedDay = (cellDate == date());
215  bool currentDay = (cellDate == QDate::currentDate());
216  bool dayOfPray = (calendar()->dayOfWeek(cellDate) == KLocale::global()->weekDayOfPray());
217 
218  //Default values for a normal cell
219  cellBackgroundColor = palette().color(backgroundRole());
220  cellTextColor = palette().color(foregroundRole());
221 
222  // If we are drawing the current date, then draw it bold and active
223  if (currentDay)
224  {
225  cellFont.setBold(true);
226  cellTextColor = colorScheme.foreground(KColorScheme::ActiveText).color();
227  }
228 
229  // if we are drawing the day cell currently selected in the table
230  if (selectedDay)
231  {
232  // set the background to highlighted
233  cellBackgroundColor = palette().color(QPalette::Highlight);
234  cellTextColor = palette().color(QPalette::HighlightedText);
235  }
236 
237  //If the cell day is the day of religious observance, then always color text red unless Custom overrides
238  if (dayOfPray)
239  {
240  KColorScheme colorScheme(palette().currentColorGroup(),
242  cellTextColor = colorScheme.foreground(KColorScheme::NegativeText).color();
243  }
244  }
245  }
246 
247  //Draw the background
248  if (row == 0)
249  {
250  painter->setPen(cellBackgroundColor);
251  painter->setBrush(cellBackgroundColor);
252  painter->drawRect(cell);
253  }
254  else if (cellBackgroundColor != palette().color(backgroundRole()))
255  {
256  QStyleOptionViewItemV4 opt;
257  opt.initFrom(this);
258  opt.rect = cell.toRect();
259  if (cellBackgroundColor != palette().color(backgroundRole()))
260  {
261  opt.palette.setBrush(QPalette::Highlight, cellBackgroundColor);
262  opt.state |= QStyle::State_Selected;
263  }
264  if (false && opt.state & QStyle::State_Enabled)
265  {
266  opt.state |= QStyle::State_MouseOver;
267  }
268  else
269  {
270  opt.state &= ~QStyle::State_MouseOver;
271  }
272  opt.showDecorationSelected = true;
273  opt.viewItemPosition = QStyleOptionViewItemV4::OnlyOne;
274  style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, this);
275  }
276 
277  if (row != 0)
278  {
279  // Paint the moon phase
280  QDate cellDate = dateFromPos(pos);
281  if (calendar()->isValid(cellDate))
282  {
283  int iPhase = computeMoonPhase(KStarsDateTime(cellDate, QTime(0, 0, 0)));
284  QRect drawRect = cell.toRect();
285  painter->drawPixmap((drawRect.width() - MoonImageSize) / 2,
286  12 + ((drawRect.height() - 12) - MoonImageSize) / 2,
287  m_Images[iPhase]); // FIXME: Using hard coded fon
288  // + painter
289  // painter->drawPixmap( ( drawRect.width() - MoonImageSize )/2,
290  // 12 + (( drawRect.height() - 12 ) - MoonImageSize)/2,
291  // m_Images[ iPhase ] );
292  // FIXME: Using hard coded fontsize
293  // qDebug() << "Drew moon image " << iPhase;
294  }
295  }
296 
297  //Draw the text
298  painter->setPen(cellTextColor);
299  painter->setFont(cellFont);
300  painter->drawText(cell, (row == 0) ? Qt::AlignCenter : (Qt::AlignTop | Qt::AlignHCenter), cellText, &cell);
301 
302  //Draw the base line
303  if (row == 0)
304  {
305  painter->setPen(palette().color(foregroundRole()));
306  painter->drawLine(QPointF(0, h), QPointF(w, h));
307  }
308 
309  // If the day cell we just drew is bigger than the current max cell sizes,
310  // then adjust the max to the current cell
311 
312  /*
313  if ( cell.width() > d->maxCell.width() ) d->maxCell.setWidth( cell.width() );
314  if ( cell.height() > d->maxCell.height() ) d->maxCell.setHeight( cell.height() );
315  */
316 }
317 
318 unsigned short MoonPhaseCalendar::computeMoonPhase(const KStarsDateTime &date)
319 {
320  KSNumbers num(date.djd());
321  KSPlanet earth(I18N_NOOP("Earth"), QString(), QColor("white"), 12756.28 /*diameter in km*/);
322  earth.findPosition(&num);
323 
324  m_Sun.findPosition(
325  &num, 0, 0,
326  &earth); // Find position is overkill for this purpose. Wonder if it is worth making findGeocentricPosition public instead of protected.
327  m_Moon.findGeocentricPosition(&num, &earth);
328 
329  m_Moon.findPhase(&m_Sun);
330 
331  return m_Moon.getIPhase();
332 }
const QColor & color() const const
int weekDayOfPray() const
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
AlignCenter
void setPen(const QColor &color)
QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags)
long double djd() const
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
int right() const const
QRect toRect() const const
void drawRect(const QRectF &rectangle)
QFont systemFont(QFontDatabase::SystemFont type)
int width() const const
int x() const const
int y() const const
void drawText(const QPointF &position, const QString &text)
int left() const const
Provides necessary information about the Moon. A subclass of SkyObject that provides information need...
Definition: ksmoon.h:25
int bottom() const const
Provides necessary information about the Sun.
Definition: kssun.h:23
int top() const const
KeepAspectRatio
QString & sprintf(const char *cformat,...)
Store several time-dependent astronomical quantities.
Definition: ksnumbers.h:42
QDate currentDate()
const QRect & rect() const const
void setBrush(const QBrush &brush)
Provides necessary information about objects in the solar system.
Definition: ksplanet.h:32
QBrush foreground(ForegroundRole=NormalText) const
int workingWeekEndDay() const
QPixmap scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
int height() const const
static KLocale * global()
virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
bool isValid(QStringView ifopt)
static const QImage & getImage(const QString &name)
Return texture image.
void drawLine(const QLineF &line)
#define I18N_NOOP(text)
void setBold(bool enable)
virtual void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const const
void setFont(const QFont &font)
SmoothTransformation
int workingWeekStartDay() const
PE_PanelItemViewItem
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 12 2022 04:00:55 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.