2#include <score/model/Skin.hpp>
3#include <score/tools/ThreadPool.hpp>
4#include <score/widgets/Pixmap.hpp>
6#include <core/view/QRecentFilesMenu.h>
9#include <QDesktopServices>
12#include <QNetworkAccessManager>
13#include <QNetworkReply>
14#include <QNetworkRequest>
22#include <score_git_info.hpp>
31template <
typename OnSuccess,
typename OnError>
32class HTTPGet final :
public QNetworkAccessManager
35 explicit HTTPGet(QUrl url, OnSuccess on_success, OnError on_error) noexcept
36 : m_callback{std::move(on_success)}
37 , m_error{std::move(on_error)}
39 connect(
this, &QNetworkAccessManager::finished,
this, [
this](QNetworkReply* reply) {
42 qDebug() << reply->errorString();
47 m_callback(reply->readAll());
54 QNetworkRequest req{std::move(url)};
55 req.setRawHeader(
"User-Agent",
"curl/7.35.0");
56 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute,
true);
58 QNetworkRequest::RedirectPolicyAttribute,
59 QNetworkRequest::UserVerifiedRedirectPolicy);
60 req.setAttribute(QNetworkRequest::Http2AllowedAttribute,
true);
62 auto reply = get(req);
63 connect(reply, &QNetworkReply::redirected, reply, &QNetworkReply::redirectAllowed);
78 const QFont& font,
const QString& text,
const QString url, QWidget* parent = 0);
80 void setOpenExternalLink(
bool val) { m_openExternalLink = val; }
81 void setPixmaps(
const QPixmap& pixmap,
const QPixmap& pixmapOn);
83 void disableInteractivity();
84 void setActiveColor(
const QColor& c);
85 void setInactiveColor(
const QColor& c);
86 void setTextOption(QTextOption opt) { m_textOption = opt; }
88 void labelPressed(
const QString& file) W_SIGNAL(labelPressed, file)
90 QRectF textBoundingBox(
double width)
const noexcept;
93 void paintEvent(QPaintEvent* event)
override;
94 void enterEvent(QEnterEvent* event)
override;
95 void leaveEvent(QEvent* event)
override;
96 void mousePressEvent(QMouseEvent* event)
override;
103 bool m_openExternalLink{};
106 QPixmap m_currentPixmap;
110 bool m_interactive{};
111 QColor m_currentColor;
112 QColor m_activeColor;
113 QColor m_inactiveColor;
115 QTextOption m_textOption;
118InteractiveLabel::InteractiveLabel(
119 const QFont& font,
const QString& title,
const QString url, QWidget* parent)
124 , m_openExternalLink(false)
125 , m_drawPixmap(false)
126 , m_interactive(true)
128 auto& skin = score::Skin::instance();
129 m_inactiveColor = QColor{
"#d3d3d3"};
130 m_activeColor = QColor{
"#03C3DD"};
131 m_currentColor = m_inactiveColor;
133 setFixedSize(200, 34);
136void InteractiveLabel::setPixmaps(
const QPixmap& pixmap,
const QPixmap& pixmapOn)
140 m_pixmapOn = pixmapOn;
141 m_currentPixmap = m_pixmap;
144void InteractiveLabel::disableInteractivity()
146 m_interactive =
false;
150void InteractiveLabel::setActiveColor(
const QColor& c)
155void InteractiveLabel::setInactiveColor(
const QColor& c)
158 m_currentColor = m_inactiveColor;
161QRectF InteractiveLabel::textBoundingBox(
double width)
const noexcept
163 int leading = QFontMetrics{m_font}.leading();
165 lay.setText(m_title);
167 lay.setTextOption(m_textOption);
172 QTextLine line = lay.createLine();
176 line.setLineWidth(width);
178 line.setPosition(QPointF(0, height));
179 height += line.height();
182 return lay.boundingRect();
185void InteractiveLabel::paintEvent(QPaintEvent* event)
187 QPainter painter(
this);
189 painter.setRenderHint(QPainter::Antialiasing,
true);
190 painter.setRenderHint(QPainter::TextAntialiasing,
true);
191 painter.setRenderHint(QPainter::RenderHint::SmoothPixmapTransform);
192 painter.setPen(QPen{m_currentColor});
195 QRectF textRect = rect();
198 int size = m_currentPixmap.width() / m_currentPixmap.devicePixelRatio();
201 if(m_textOption.alignment() == Qt::AlignRight)
204 lay.setText(m_title);
206 lay.setTextOption(m_textOption);
210 pixmapX = lay.boundingRect().width();
213 width() - pixmapX - size - 6, (textRect.height() - size - 10) / 2,
215 textRect.setX(textRect.x() + size + 6);
217 painter.setFont(m_font);
218 painter.drawText(textRect, m_title, m_textOption);
222void InteractiveLabel::enterEvent(QEnterEvent* event)
227 m_currentColor = m_activeColor;
228 m_font.setUnderline(
true);
229 m_currentPixmap = m_pixmapOn;
234void InteractiveLabel::leaveEvent(QEvent* event)
239 m_currentColor = m_inactiveColor;
240 m_font.setUnderline(
false);
241 m_currentPixmap = m_pixmap;
246void InteractiveLabel::mousePressEvent(QMouseEvent* event)
248 if(m_openExternalLink)
250 QDesktopServices::openUrl(QUrl(m_url));
261 StartScreen(
const QPointer<QRecentFilesMenu>& recentFiles, QWidget* parent = 0);
263 void openNewDocument() W_SIGNAL(openNewDocument)
264 void openFile(
const QString& file) W_SIGNAL(openFile, file)
265 void openFileDialog() W_SIGNAL(openFileDialog)
266 void loadCrashedSession() W_SIGNAL(loadCrashedSession)
267 void exitApp() W_SIGNAL(exitApp)
269 void addLoadCrashedSession();
272 void paintEvent(QPaintEvent* event)
override;
273 void keyPressEvent(QKeyEvent* event)
override;
276 QPixmap m_background;
286 const QString& n,
const QString& u,
const QString& p,
const QString& pOn)
295StartScreen::StartScreen(
const QPointer<QRecentFilesMenu>& recentFiles, QWidget* parent)
298 auto& skin = score::Skin::instance();
301#if defined(__APPLE__)
302 static constexpr double font_factor = 96. / 72.;
304 static constexpr double font_factor = 1.;
306 QFont f(
"Ubuntu", 14 * font_factor, QFont::Light);
307 f.setHintingPreference(QFont::HintingPreference::PreferFullHinting);
308 f.setStyleStrategy(QFont::PreferAntialias);
310 QFont titleFont(
"Montserrat", 14 * font_factor, QFont::DemiBold);
311 titleFont.setHintingPreference(QFont::HintingPreference::PreferFullHinting);
312 titleFont.setStyleStrategy(QFont::PreferAntialias);
314 this->setEnabled(
true);
315 setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);
316 setWindowModality(Qt::ApplicationModal);
318 m_background = score::get_pixmap(
":/startscreen/startscreensplash.png");
320 if(QPainter painter; painter.begin(&m_background))
322 painter.setRenderHint(QPainter::Antialiasing,
true);
323 painter.setRenderHint(QPainter::TextAntialiasing,
true);
324 painter.setPen(QPen(QColor(
"#0092CF")));
328 painter.drawText(QPointF(217, 188), QCoreApplication::applicationVersion());
333 setFixedSize(m_background.size() / m_background.devicePixelRatioF());
337 auto& tp = score::ThreadPool::instance();
338 auto t = tp.acquireThread();
339 QMetaObject::invokeMethod(t, [t, self = QPointer{
this}, titleFont] {
340 auto m_getLastVersion =
new HTTPGet{
341 QUrl(
"https://ossia.io/score-last-version.txt"),
342 [self, titleFont](
const QByteArray& data) {
343 auto version = QString::fromUtf8(data.simplified());
344 if(SCORE_TAG_NO_V < version)
347 = qApp->tr(
"New version %1 is available, click to update !").arg(version);
348 QString url =
"https://github.com/ossia/score/releases/latest/";
349 QMetaObject::invokeMethod(
350 QCoreApplication::instance(), [self, titleFont, text, url] {
353 InteractiveLabel* label =
new InteractiveLabel{titleFont, text, url, self};
355 score::get_pixmap(
":/icons/version_on.png"),
356 score::get_pixmap(
":/icons/version_off.png"));
357 label->setOpenExternalLink(
true);
358 label->setInactiveColor(QColor{
"#f6a019"});
359 label->setActiveColor(QColor{
"#f0f0f0"});
360 label->setFixedWidth(600);
361 label->move(280, 170);
366 connect(m_getLastVersion, &QObject::destroyed, t, [] {
367 QMetaObject::invokeMethod(QCoreApplication::instance(), [] {
368 auto& tp = score::ThreadPool::instance();
379 auto label =
new InteractiveLabel{titleFont, qApp->tr(
"Recent files"),
"",
this};
380 label->setTextOption(QTextOption(Qt::AlignRight));
382 score::get_pixmap(
":/icons/recent_files.png"),
383 score::get_pixmap(
":/icons/recent_files.png"));
384 label->setInactiveColor(QColor{
"#f0f0f0"});
385 label->setActiveColor(QColor{
"#03C3DD"});
386 label->disableInteractivity();
387 label->move(label_x, label_y);
393 for(
const auto& action : recentFiles->actions())
396 =
new InteractiveLabel{f, action->text(), action->data().toString(),
this};
397 fileLabel->setTextOption(QTextOption(Qt::AlignRight));
399 fileLabel, &score::InteractiveLabel::labelPressed,
this,
400 &score::StartScreen::openFile);
402 auto textHeight = std::max(25, (
int)fileLabel->textBoundingBox(200).height() + 7);
403 fileLabel->setFixedSize(200, textHeight);
404 fileLabel->move(label_x, label_y);
405 label_y += textHeight + 1;
411 =
new InteractiveLabel{titleFont, qApp->tr(
"Restore last session"),
"",
this};
412 m_crashLabel->setTextOption(QTextOption(Qt::AlignRight));
413 m_crashLabel->setPixmaps(
414 score::get_pixmap(
":/icons/reload_crash_off.png"),
415 score::get_pixmap(
":/icons/reload_crash_on.png"));
416 m_crashLabel->move(label_x - 100, label_y);
417 m_crashLabel->setFixedWidth(300);
418 m_crashLabel->setInactiveColor(QColor{
"#f0f0f0"});
419 m_crashLabel->setActiveColor(QColor{
"#f6a019"});
420 m_crashLabel->setDisabled(
true);
421 m_crashLabel->hide();
423 m_crashLabel, &score::InteractiveLabel::labelPressed,
this,
424 &score::StartScreen::loadCrashedSession);
429 InteractiveLabel* label =
new InteractiveLabel{titleFont, qApp->tr(
"New"),
"",
this};
431 score::get_pixmap(
":/icons/new_file_off.png"),
432 score::get_pixmap(
":/icons/new_file_on.png"));
434 label, &score::InteractiveLabel::labelPressed,
this,
435 &score::StartScreen::openNewDocument);
436 label->move(label_x, label_y);
440 InteractiveLabel* label
441 =
new InteractiveLabel{titleFont, qApp->tr(
"Load"),
"",
this};
443 score::get_pixmap(
":/icons/load_off.png"),
444 score::get_pixmap(
":/icons/load_on.png"));
446 label, &score::InteractiveLabel::labelPressed,
this,
447 &score::StartScreen::openFileDialog);
448 label->move(label_x, label_y);
453 auto library_path = settings.value(
"Library/RootPath").toString();
454 InteractiveLabel* label =
new InteractiveLabel{
455 titleFont, qApp->tr(
"Examples"),
"https://ossia.io/score-docs/examples",
this};
457 score::get_pixmap(
":/icons/load_examples_off.png"),
458 score::get_pixmap(
":/icons/load_examples_on.png"));
459 label->setOpenExternalLink(
true);
460 label->move(label_x, label_y);
466 std::array<score::StartScreenLink, 4> menus
467 = {{{qApp->tr(
"Tutorials"),
468 "https://www.youtube.com/"
469 "watch?v=R-3d8K6gQkw&list=PLIHLSiZpIa6YoY1_aW1yetDgZ7tZcxfEC&index=1",
470 ":/icons/tutorials_off.png",
":/icons/tutorials_on.png"},
471 {qApp->tr(
"Contribute"),
"https://opencollective.com/ossia/contribute",
472 ":/icons/contribute_off.png",
":/icons/contribute_on.png"},
473 {qApp->tr(
"Forum"),
"http://forum.ossia.io/",
":/icons/forum_off.png",
474 ":/icons/forum_on.png"},
475 {qApp->tr(
"Chat"),
"https://gitter.im/ossia/score",
":/icons/chat_off.png",
476 ":/icons/chat_on.png"}}};
477 for(
const auto& m : menus)
479 InteractiveLabel* menu_url =
new InteractiveLabel{titleFont, m.name, m.url,
this};
480 menu_url->setOpenExternalLink(
true);
481 menu_url->setPixmaps(score::get_pixmap(m.pixmap), score::get_pixmap(m.pixmapOn));
482 menu_url->move(label_x, label_y);
489 InteractiveLabel* label
490 =
new InteractiveLabel{titleFont, qApp->tr(
"Exit"),
"",
this};
492 score::get_pixmap(
":/icons/exit_off.png"),
493 score::get_pixmap(
":/icons/exit_on.png"));
495 label, &score::InteractiveLabel::labelPressed,
this,
496 &score::StartScreen::exitApp);
497 label->move(label_x, label_y);
501void StartScreen::addLoadCrashedSession()
503 m_crashLabel->show();
504 m_crashLabel->setEnabled(
true);
508void StartScreen::paintEvent(QPaintEvent* event)
510 QPainter painter(
this);
511 painter.setRenderHint(QPainter::RenderHint::SmoothPixmapTransform);
512 painter.drawPixmap(0, 0, m_background);
515void StartScreen::keyPressEvent(QKeyEvent* event)
517 if(event->key() == Qt::Key_Escape)
519 this->openNewDocument();
521 return QWidget::keyPressEvent(event);
Definition StartScreen.hpp:73
Definition StartScreen.hpp:258
Base toolkit upon which the software is built.
Definition Application.cpp:113
void setCursor(Qt::CursorShape c)
setCursor sets the cursor safely.
Definition ClearLayout.cpp:8
Definition StartScreen.hpp:280