Files
raDIYo/swradiyomainwidget.cpp
2025-08-05 22:36:00 +02:00

443 lines
11 KiB
C++

/***************************************************************************
source::worx raDIYo
Copyright © 2020-2022 c.holzheuer
c.holzheuer@sourceworx.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
***************************************************************************/
#include <QDebug>
#include <QAction>
#include <QCoreApplication>
#include <QMouseEvent>
#include <QPainter>
#include <QTime>
#include <QTimer>
#include <QMediaPlayer>
#include <QUrl>
#include <QFileInfo>
#include <QStyle>
#include <QFileDialog>
#include <QStandardPaths>
#include <QMessageBox>
#include <QFontDatabase>
//#include <QHoverEvent>
//#include <QPointF>
//#include <algorithm> // std::swap
//#include <iostream>
#include <swradiyomainwidget.h>
#include <ui_swradiyomainwidget.h>
#include <swcontrolstates.h>
#include <swplayercontrol.h>
#include <swsendercontrol.h>
#include <swsongscontrol.h>
#include <swshutdowncontrol.h>
#include <swclockcontrol.h>
#include <swalarmcontrol.h>
#include <swsetupcontrol.h>
#include <swusbcontrol.h>
#include <swbluetoothcontrol.h>
#include <SWPiGPIO.h>
/*
static QString formatTime( qint64 timeMilliSeconds )
{
qint64 seconds = timeMilliSeconds / 1000;
const qint64 minutes = seconds / 60;
seconds -= minutes * 60;
return QStringLiteral("%1:%2")
.arg(minutes, 2, 10, QLatin1Char('0'))
.arg(seconds, 2, 10, QLatin1Char('0'));
}
*/
/**
* @brief SWRaDIYoMainWidget --doku begins here ---
* @param parent
*
* contains copy-writen material from qt example code:
* @see shaped clock example
* @see embedded/flipdigits example
*
*/
SWRaDIYoMainWidget::SWRaDIYoMainWidget( QWidget *parent )
: SWRaDIYoBaseWidget( parent )
{
setupFonts();
setupUi( this );
/// Setup Controls: 'RaDIYo' Buttons
/// Reihenfolge beachten, die iost wichtig für
/// die button-asuwahl per dial
_controller.addButton( _buttonPlay, PlayerControl, "play" );
_controller.addButton( _buttonSender, SenderControl, "sender" );
_controller.addButton( _buttonSongs, SongsControl, "songs" );
_controller.addButton( _buttonUSB, UsbControl, "usb" );
//_controller.addButton( _buttonBlueTooth, SWBLUETOOTHCONTROL, "bluetooth" );
_controller.addButton( _buttonClock, ClockControl, "clock" );
_controller.addButton( _buttonAlarm, AlarmControl, "alarm" );
_controller.addButton( _buttonSetup, SetupControl, "setup" );
_controller.addButton( _buttonShutdown, ShutdownControl, "shutdown" );
/// Alle Controls, schön vorsortiert.
_senderControl = new SWSenderControl( this );
_songsControl = new SWSongsControl( this );
_playerControl = new SWPlayerControl( this );
_controller.addControl( PlayerControl, _playerControl );
_controller.addControl( SenderControl, _senderControl );
_controller.addControl( SongsControl, _songsControl );
_controller.addControl( UsbControl, new SWUSBControl( this ) );
_controller.addControl( ClockControl, new SWClockControl( this ) );
_controller.addControl( AlarmControl, new SWAlarmControl( this ) );
_controller.addControl( SetupControl, new SWSetupControl( this ) );
_controller.addControl( ShutdownControl, new SWShutdownControl( this ) );
//_controller.addControl( SWBLUETOOTHCONTROL] = new SWBlueToothControl( this );
connect( &_raDIYoButtons, &QButtonGroup::idClicked, this, &SWControlStates::onIdActivated );
/// play button hat ne sonderstellung
connect( _buttonPlay, &QPushButton::clicked, this, &SWControlStates::onVolumeButtonClicked );
/// Setup Controls: Fake Dials unter Win, echte für Linux
setupDials();
/// startup
loadSettings();
/// bei untätigkeit kommt wieder die Uhr
_idleTimer.setInterval( raDIYo::IdleTimeOut );
_idleTimer.setSingleShot( true );
connect( &_idleTimer, &QTimer::timeout, this, &SWRaDIYoMainWidget::onIdleTimeOut );
/// Setup Controls: Volume
connect( _volumeWidget, SIGNAL(valueChanged(int)), this, SLOT(onVolumeValueChanged(int)) );
QString defSender =_settings.value( raDIYo::KeyDefaultSender ).toString();
_nowPlaying = SWPlayableItem( defSender, SWPlayableItem::WebStream, raDIYo::DefaultVolume );
onVolumeValueChanged( _nowPlaying.volume );
/// wir nehmen den default-sender
_currentTitle->setText( _nowPlaying.title );
/// not least
_version->setText( raDIYo::Version );
}
/**
* @brief ~SWRaDIYoMainWidget Destructor.
*/
SWRaDIYoMainWidget::~SWRaDIYoMainWidget()
{
}
void SWRaDIYoMainWidget::setCurrentControl( SWAbstractControl* control )
{
_currentCtrl = control;
_currentCtrl->show();
}
void SWRaDIYoMainWidget::setupDials()
{
/* FIX!
* Schaltschema bei Click:
* Radio aus / Uhr -click-> Radio ein
* Radio ein -click-> Radio aus / Uhr
* Radio aus / Uhr -turn-> Radio ein / VolumeDislay
* Radio ein -turn-> Radio ein / VolumeDislay
*/
// Prinzip: Clicks (also 'drücken' in echt) schalten weiter, drehen schaltet auch weiter
// wenn das control mit 'drehen' nix anfangen kann, wie z.B. das FlipClock control
//#ifdef Q_OS_LINUX
// Linux, kompiliert auch unter Win
_dialLeft = new PiGPIORotaryDial( 13, 6, 5, this );
_dialRight = new PiGPIORotaryDial( 22, 27, 17, this );
connect( _dialLeft, SIGNAL(clicked()), _controller, SLOT(onSenderButtonClicked()) );
connect( _dialRight, SIGNAL(clicked()), _controller, SLOT(onVolumeButtonClicked()) );
connect( _dialLeft, SIGNAL(valueChanged(int)), _controller, SLOT(onSenderValueChanged(int)) );
connect( _dialRight, SIGNAL(valueChanged(int)), _volumeWidget, SLOT(onDialValueChanged(int)) );
//#endif
#ifdef Q_OS_WIN
qDebug() << " --- Q_OS_WIN";
/// Setup Controls: Fake Dials
connect( &_dialDialog.leftDial().pushButton(), &QPushButton::clicked, _controller, &SWControlStates::onSenderButtonClicked );
connect( &_dialDialog.leftDial().dial(), &QDial::valueChanged, _controller, &SWControlStates::onSenderValueChanged );
connect( &_dialDialog.rightDial().pushButton(), &QPushButton::clicked, _controller, &SWControlStates::onVolumeButtonClicked );
connect( &_dialDialog.rightDial().dial(), &QDial::valueChanged, _volumeWidget, &SWVolumeWidget::onDialValueChanged );
_dialDialog.show();
#endif
}
QSettings& SWRaDIYoMainWidget::settings()
{
return _settings;
}
/// ???
void SWRaDIYoMainWidget::onIdleTimeOut()
{
qDebug() << "--- onIdleTimeOut";
// swap back
//swapControls( IDClockControl );
}
void SWRaDIYoMainWidget::swapControls( int newID )
{
/// FIX! ButtonGroup anpassen!!!
/*
qDebug() << "Fade IN" << newID << " Fade OUT: " << _currentCtrlID;
// ausblenden
currentControl().fadeOut();
_raDIYoButtons.button( _currentCtrlID )->setChecked( false );
// alte ID merken
_lastControlID = _currentCtrlID;
// einblenden
_currentCtrlID = newID;
_raDIYoButtons.button( newID )->setChecked( true );
currentControl().fadeIn();
*/
}
/**
* @brief onIDTriggered
* @param newID
*/
void SWRaDIYoMainWidget::onIDTriggered( int newID )
{
}
void SWRaDIYoMainWidget::onVolumeValueChanged( int value )
{
/// 'setValue( value )' reicht hier nicht,
/// denn der neue Wert muss weiter gereicht
/// werden, also 'onDialValueChanged'
_volumeWidget->onDialValueChanged( value );
_playerControl->onDialValueChanged( value );
_dialDialog.rightDial().dial().setValue( value );
//_dialRight.setValue( value );
}
// ...
void SWRaDIYoMainWidget::onEntryActivated( SWPlayableItem item )
{
qDebug() << "--:onEntryActivated: " << item.title << ": " << item.urlText;
// Das SIGNAL kommt von einem Control, also schalten wir wieder
// zurück auf die Buttons
_isCtrlActive = false;
// mehrfache ansagen ignorieren
if( _nowPlaying.urlText == item.urlText )
return;
// merken
_nowPlaying = item;
// abschalten ...
_isPlayerActive = false;
// ... und wieder anschalten
togglePlayMode();
}
/**
* @brief startPlaying: von aussen und von innen
* @param title<
* @param urlText
* @param startnow
*/
void SWRaDIYoMainWidget::togglePlayMode()
{
/*
_isPlayerActive = !_isPlayerActive;
//QString fullUrl = raDIYo::SngDir + urlText;
qDebug() << "\n\n+++ togglePlayMode(): " << _currentCtrlID << " :" << _nowPlaying.title << " Url: " << _nowPlaying.urlText << "\n\n";
//FIX!
//QString color = _isPlayerActive ? "rgb(181,181,181)" : "rgb(69,69,69);";
//_currentTitle->setStyleSheet( _titleCss.arg( color ) );
_currentTitle->setText( _nowPlaying.title );
_buttonPlay->setStyleSheet( _isPlayerActive ? _buttonPauseCss : _buttonPlayCss ) ;
//_buttonPlay->setStyleSheet( _buttonPauseCss ) ;
// FIX! das haut nicht hin
if( !_isPlayerActive )
{
qDebug() << " --- Player OFF";
_playerControl->stopPlaying();
/// SpectrumDisplay abschalten, aber nur wenn eingeschaltet war
if( _currentCtrlID == IDPlayerControl )
swapControls( _lastControlID );
return;
}
qDebug() << " --- Player ON";
swapControls( IDPlayerControl );
_playerControl->startPlaying( _nowPlaying.urlText );
*/
}
/**
* @brief Fonts explicit laden, _vor_ setupUi
*/
void SWRaDIYoMainWidget::setupFonts()
{
QStringList fontList = QDir( raDIYo::FontDir ).entryList();
for( const QString& fontName : fontList )
QFontDatabase::addApplicationFont( raDIYo::FontDir + fontName );
}
/**
* @brief loadSettings: die Einstellungen laden
*/
void SWRaDIYoMainWidget::loadSettings()
{
/// Dss ist die Bildschirmgröße des Raspi 7 inch displays
resize( SWScreenLargeX, SWScreenLargeY );
/// hier sind wir auch für die voreinstellungen zuständig: falls
/// nicht vorhanden, default setzen
if( !_settings.contains( raDIYo::KeySongsDir ) )
_settings.setValue( raDIYo::KeySongsDir, QDir::homePath() + raDIYo::SongsDir );
/// default Sender belegen
if( !_settings.contains( raDIYo::KeyDefaultSender ) )
_settings.setValue( raDIYo::KeyDefaultSender, raDIYo::DefaultSender );
/// Wir lesen die Hard-Kodierte Senderliste und schreiben sie in die
/// settings datenbank
if( !_settings.contains( raDIYo::KeySenderList ) )
{
QString senderList = readResource( raDIYo::ResSenderList );
// oder doch lieber in ein FILE?
_settings.setValue( raDIYo::KeySenderList, senderList );
}
// setup list controls
_senderControl->loadEntryList( _settings.value( raDIYo::KeySenderList ).toString() );
_songsControl->loadEntryList( _settings.value( raDIYo::KeySongsDir ).toString() );
}
/**
* @brief setAlarm @todo implementation
*/
void SWRaDIYoMainWidget::setAlarm()
{
}
/**
* @brief saveSettings @todo implementation
*/
void SWRaDIYoMainWidget::saveSettings()
{
}
/**
* @brief onShutDown
* @todo implementation
* @todo shutdown der hardware -> use linux 'sudo kill me'
*/
void SWRaDIYoMainWidget::onShutDown()
{
// wir wollen sterben
::exit( 0 );
}