hydrogen 1.2.6
ShotList.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include <QRegularExpression>
24
25#include <core/Hydrogen.h>
26#include <core/EventQueue.h>
27
28#include "ShotList.h"
29#include "HydrogenApp.h"
30
31#ifndef H2CORE_HAVE_QT6
32
33ShotList::ShotList( QString sShotsFilename ) {
34 QFile shots( sShotsFilename );
35 m_nNextShot = 0;
36
37 if ( ! shots.open( QIODevice::ReadOnly ) ) {
38 ___ERRORLOG( QString( "Cannot open shot list file '%1' " ).arg( shots.fileName() ) );
39 return;
40 }
41 while (! shots.atEnd() ) {
42 m_shots << shots.readLine();
43 }
44
46}
47
48ShotList::ShotList( QStringList shots ) {
49 m_shots = shots;
50
52}
53
55 if ( auto pHydrogenApp = HydrogenApp::get_instance() ) {
56 pHydrogenApp->removeEventListener( this );
57 }
58}
59
60QWidget *ShotList::findWidgetInheriting( QObject *pObject, const QString& sName ) {
61 const auto sNameLocal8Bit = sName.toLocal8Bit();
62 if ( pObject->inherits( sNameLocal8Bit.data() ) ) {
63 return dynamic_cast< QWidget *>( pObject );
64 }
65 for ( QObject *pC : pObject->children() ) {
66 QWidget *pW = findWidgetInheriting( pC, sName );
67 if ( pW ) {
68 return pW;
69 }
70 }
71 return nullptr;
72}
73
74QWidget *ShotList::findWidget( QString &sName ) {
75 for ( QWidget * pTop : QApplication::topLevelWidgets() ) {
76
77 QWidget *pWidget = pTop->findChild< QWidget *>( sName );
78 if ( !pWidget && pTop->objectName() == sName ) {
79 pWidget = dynamic_cast< QWidget *>( pTop );
80 }
81 if ( !pWidget ) {
82 pWidget = findWidgetInheriting( pTop, sName );
83 }
84 if ( pWidget ) {
85 return pWidget;
86 }
87 }
88 return nullptr;
89}
90
91void ShotList::shoot( QString s ) {
92 ___INFOLOG( QString( "Taking shot: %1" ).arg( s.trimmed() ) );
93 QStringList words = s.trimmed().split(
94 QRegularExpression( "\\s+" ) );
95 if ( s.size() == 0 ) {
96 return;
97 }
98 QString sCmd = words[ 0 ];
99
100 if ( sCmd.startsWith( "#" ) || sCmd == "" ) {
101 // Empty line or "#" to start a comment
102 } else if ( sCmd.compare( "fin", Qt::CaseInsensitive) == 0 ) {
103 // Finish the shot list and quit Hydrogen
104
105 // Since the shot lists do also toggle some buttons that mark
106 // the overall song modified, we need to discard the flag in
107 // order to avoid a popup dialog.
109
110 QTimer::singleShot( 1, QApplication::instance(), &QApplication::closeAllWindows );
111 } else if ( sCmd.compare( "dump", Qt::CaseInsensitive) == 0 ) {
112 // Dump object tree for debugging
113 for ( QWidget *pTop : QApplication::topLevelWidgets() ) {
114 pTop->dumpObjectTree();
115 }
116 } else if ( sCmd.compare( "grab", Qt::CaseInsensitive ) == 0 ) {
117
118 if ( words.size() < 2 ) {
119 ___ERRORLOG( QString( "Syntax: grab <widget> [as <filename>] [size w d] [offset x y ]." ) );
120 } else {
121 words.pop_front();
122 QString sWidgetName = words[0];
123 words.pop_front();
124 QRect rect( 0, 0, -1, -1 );
125 QString sFileName = QString( "%1.png" ).arg( sWidgetName );
126 while ( !words.empty() ) {
127 if ( words[0] == "as" ) {
128 words.pop_front();
129 if ( words.size() < 1 ) {
130 ___ERRORLOG( QString( "Syntax: grab ... as <filename>" ) );
131 } else {
132 sFileName = words[0];
133 words.pop_front();
134 }
135 } else if ( words[0] == "size" ) {
136 words.pop_front();
137 if ( words.size() < 2 ) {
138 ___ERRORLOG( QString( "Syntax: grab ... size <width> <height>" ) );
139 } else {
140 rect.setWidth( words[0].toInt() );
141 rect.setHeight( words[1].toInt() );
142 words.pop_front();
143 words.pop_front();
144 }
145 } else if ( words[0] == "offset" ) {
146 words.pop_front();
147 if ( words.size() < 2 ) {
148 ___ERRORLOG( QString( "Syntax: grab ... offset <width> <height>" ) );
149 } else {
150 rect.setX( words[0].toInt() );
151 rect.setY( words[1].toInt() );
152 words.pop_front();
153 words.pop_front();
154 }
155 } else {
156 ___ERRORLOG( QString( "Syntax: grab <widget> [as <filename>] [size w d] [offset x y ]."
157 " Unexpected '%1'" ).arg( words[0] ) );
158 break;
159 }
160 }
161
162 QWidget *pWidget = findWidget( sWidgetName );
163 if ( pWidget ) {
164 QPixmap p = pWidget->grab();
165 QRect oldRect = rect;
166 // Scale 'rect' up to match device pixels of pixmap
167 rect = QRect( rect.topLeft() * p.devicePixelRatio(),
168 rect.size() * p.devicePixelRatio() );
169 if ( rect.width() <= 0 ) {
170 rect.setWidth( p.rect().width() );
171 }
172 if ( rect.height() <= 0 ) {
173 rect.setHeight( p.rect().height() );
174 }
175 QRect grabRect = rect.intersected( p.rect() );
176 p.copy( grabRect ).save( sFileName );
177 ___INFOLOG( QString( "Saved grabbed widget %1" ).arg( sFileName ) );
178 } else {
179 ___ERRORLOG( QString( "Couldn't find widget named '%1' to grab" ).arg( sWidgetName ) );
180 }
181 }
182
183 } else if ( sCmd.compare( "slot", Qt::CaseInsensitive ) == 0 ) {
184
185 if ( words.size() >= 3 ) {
186 QString sWidgetName = words[ 1 ];
187 QString sMethodName = words[ 2 ];
188 QWidget *pWidget = findWidget( sWidgetName );
189
190 if ( pWidget ) {
191 ___INFOLOG( QString( "Invoking '%1' on '%2'" ).arg( sMethodName, sWidgetName ) );
192 bool bSuccess = false;
193 const auto sMethodNameLocal8Bit = sMethodName.toLocal8Bit();
194 switch ( words.size() ) {
195 case 3:
196 bSuccess = QMetaObject::invokeMethod(
197 pWidget, sMethodNameLocal8Bit.data(), Qt::DirectConnection );
198 break;
199 case 4:
200 bSuccess = QMetaObject::invokeMethod(
201 pWidget, sMethodNameLocal8Bit.data(), Qt::DirectConnection,
202 Arg( words[3] ) );
203 break;
204 case 5:
205 bSuccess = QMetaObject::invokeMethod(
206 pWidget, sMethodNameLocal8Bit.data(), Qt::DirectConnection,
207 Arg( words[3] ), Arg( words[4] ) );
208 break;
209 case 6:
210 bSuccess = QMetaObject::invokeMethod(
211 pWidget, sMethodNameLocal8Bit.data(), Qt::DirectConnection,
212 Arg( words[3] ), Arg( words[4] ), Arg( words[5] ) );
213 break;
214 default:
215 ___ERRORLOG( "Unsupported number of arguments in %0" );
216 }
217
218 if ( !bSuccess ) {
219 ___ERRORLOG( QString( "Couldn't invoke '%1' on '%2'" )
220 .arg( sMethodName, sWidgetName ) );
221 } else {
222 ___INFOLOG( "OK" );
223 }
224 } else {
225 ___ERRORLOG( QString( "Couldn't find widget named '%1' to invoke '%2' on" )
226 .arg( sWidgetName, sMethodName ) );
227 }
228 } else {
229 ___ERRORLOG( QString( "Syntax: slot <widget> <method> [args]" ) );
230 }
231 } else {
232 ___ERRORLOG( QString("Unknown command '%1'").arg( sCmd ) );
233 }
234}
235
237 m_nNextShot = 0;
238 if ( m_shots.size() != 0 ) {
239 nextShot();
240 }
241}
242
244 QMetaObject::invokeMethod( this, "nextShot", Qt::QueuedConnection );
245}
246
247void ShotList::nextShot( void ) {
248 if ( ( m_nNextShot + 1) < m_shots.size() ) {
250 }
251 shoot( m_shots[ m_nNextShot++ ] );
252}
253
254#endif
#define ___INFOLOG(x)
Definition Object.h:258
#define ___ERRORLOG(x)
Definition Object.h:260
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
Definition EventQueue.h:224
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
void setIsModified(bool bIsModified)
Wrapper around Song::setIsModified() that checks whether a song is set.
void addEventListener(EventListener *pListener)
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
Buffer for construction of Q_ARGs.
Definition ShotList.h:63
void nextShotEvent() override
Definition ShotList.cpp:243
static QWidget * findWidgetInheriting(QObject *pObject, const QString &sName)
Find a widget which inherits the named class.
Definition ShotList.cpp:60
QStringList m_shots
Definition ShotList.h:95
ShotList(QStringList shots)
Definition ShotList.cpp:48
void shoot()
Definition ShotList.cpp:236
void nextShot(void)
Definition ShotList.cpp:247
int m_nNextShot
Definition ShotList.h:96
static QWidget * findWidget(QString &sName)
Find a widget by name.
Definition ShotList.cpp:74
@ EVENT_NEXT_SHOT
Definition EventQueue.h:177