1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A MIDI and audio sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7
8 Other copyrights also apply to some parts of this work. Please
9 see the AUTHORS file and individual file headers for details.
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version. See the file
15 COPYING included with this distribution for more information.
16 */
17
18
19 #include "TimeSignatureDialog.h"
20
21 #include "misc/ConfigGroups.h"
22 #include "base/Composition.h"
23 #include "base/NotationTypes.h"
24 #include "gui/widgets/TimeWidget.h"
25 #include "gui/widgets/BigArrowButton.h"
26 #include "misc/Strings.h"
27
28 #include <QApplication>
29 #include <QSettings>
30 #include <QDialog>
31 #include <QDialogButtonBox>
32 #include <QGroupBox>
33 #include <QCheckBox>
34 #include <QFont>
TimeDialog(QWidget * parent,QString title,Composition * composition,timeT defaultTime,bool constrainToCompositionDuration)35 #include <QLabel>
36 #include <QObject>
37 #include <QRadioButton>
38 #include <QString>
39 #include <QWidget>
40 #include <QVBoxLayout>
41 #include <QHBoxLayout>
42 #include <QUrl>
43 #include <QDesktopServices>
44
45
46 namespace Rosegarden
47 {
48
49 TimeSignatureDialog::TimeSignatureDialog(QWidget *parent,
50 Composition *composition,
51 timeT insertionTime,
52 TimeSignature sig,
53 bool timeEditable,
54 QString explanatoryText) :
55 QDialog(parent),
56 m_composition(composition),
57 m_timeSignature(sig),
58 m_time(insertionTime),
59 m_numLabel(nullptr),
60 m_denomLabel(nullptr),
61 m_explanatoryLabel(nullptr),
62 m_commonTimeButton(nullptr),
63 m_hideSignatureButton(nullptr),
64 m_normalizeRestsButton(nullptr),
65 m_asGivenButton(nullptr),
66 m_startOfBarButton(nullptr),
67 m_timeEditor(nullptr)
68 {
69 setModal(true);
70 setWindowTitle(tr("Time Signature"));
71 setObjectName("MinorDialog");
72
73 static QFont *timeSigFont = nullptr;
74
75 if (timeSigFont == nullptr) {
76 timeSigFont = new QFont("new century schoolbook", 8, QFont::Bold);
77 timeSigFont->setPixelSize(20);
78 }
79
80 QVBoxLayout *vboxLayout = new QVBoxLayout;
81 setLayout(vboxLayout);
82
83 QGroupBox *groupBox = new QGroupBox(tr("Time signature"));
84 QVBoxLayout *groupBoxLayout = new QVBoxLayout;
85 groupBoxLayout->setSpacing(0);
86 vboxLayout->addWidget(groupBox);
87
88 QWidget *numBox = new QWidget;
89 QHBoxLayout *numBoxLayout = new QHBoxLayout;
90 groupBoxLayout->addWidget(numBox);
91
92 QWidget *denomBox = new QWidget;
93 QHBoxLayout *denomBoxLayout = new QHBoxLayout;
94 groupBoxLayout->addWidget(denomBox);
95
96 QLabel *explanatoryLabel = nullptr;
97 if (!explanatoryText.isEmpty()) {
98 explanatoryLabel = new QLabel(explanatoryText, groupBox);
99 groupBoxLayout->addWidget(explanatoryLabel);
100 }
101 groupBox->setLayout(groupBoxLayout);
102
103 BigArrowButton *numDown = new BigArrowButton(Qt::LeftArrow);
104 numBoxLayout->addWidget(numDown);
105 BigArrowButton *denomDown = new BigArrowButton(Qt::LeftArrow);
106 denomBoxLayout->addWidget(denomDown);
107
108 m_numLabel = new QLabel(QString("%1").arg(m_timeSignature.getNumerator()), numBox );
109 numBoxLayout->addWidget(m_numLabel);
110 m_denomLabel = new QLabel(QString("%1").arg(m_timeSignature.getDenominator()), denomBox );
111 denomBoxLayout->addWidget(m_denomLabel);
112
113 m_numLabel->setAlignment(Qt::AlignCenter);
114 m_denomLabel->setAlignment(Qt::AlignCenter);
115
116 m_numLabel->setFont(*timeSigFont);
117 m_denomLabel->setFont(*timeSigFont);
118
119 BigArrowButton *numUp = new BigArrowButton(Qt::RightArrow);
120 numBoxLayout->addWidget(numUp);
121 numBox->setLayout(numBoxLayout);
122 BigArrowButton *denomUp = new BigArrowButton(Qt::RightArrow);
123 denomBoxLayout->addWidget(denomUp);
124 denomBox->setLayout(denomBoxLayout);
125
126 QObject::connect(numDown, &QAbstractButton::clicked, this, &TimeSignatureDialog::slotNumDown);
127 QObject::connect(numUp, &QAbstractButton::clicked, this, &TimeSignatureDialog::slotNumUp);
128 QObject::connect(denomDown, &QAbstractButton::clicked, this, &TimeSignatureDialog::slotDenomDown);
129 QObject::connect(denomUp, &QAbstractButton::clicked, this, &TimeSignatureDialog::slotDenomUp);
130
131 if (timeEditable) {
132
133 m_timeEditor = new TimeWidget
134 (tr("Time where signature takes effect"),
135 this,
136 composition,
137 m_time,
138 true);
139 vboxLayout->addWidget(m_timeEditor);
140 m_asGivenButton = nullptr;
141 m_startOfBarButton = nullptr;
142
143 } else {
144
145 m_timeEditor = nullptr;
146
147 groupBox = new QGroupBox(tr("Scope"));
148 groupBoxLayout = new QVBoxLayout;
149 vboxLayout->addWidget(groupBox);
150
151 int barNo = composition->getBarNumber(m_time);
152 bool atStartOfBar = (m_time == composition->getBarStart(barNo));
153
154 if (!atStartOfBar) {
155
156 QString scopeText;
157
158 if (barNo != 0 || !atStartOfBar) {
159 if (atStartOfBar) {
160 scopeText = QString
161 (tr("Insertion point is at start of measure %1."))
162 .arg(barNo + 1);
163 } else {
164 scopeText = QString
165 (tr("Insertion point is in the middle of measure %1."))
166 .arg(barNo + 1);
167 }
168 } else {
169 scopeText = QString
170 (tr("Insertion point is at start of composition."));
171 }
172
173 groupBoxLayout->addWidget(new QLabel(scopeText));
174 m_asGivenButton = new QRadioButton
175 (tr("Start measure %1 here").arg(barNo + 2), groupBox);
176 groupBoxLayout->addWidget(m_asGivenButton);
177 if (!atStartOfBar) {
178 m_startOfBarButton = new QRadioButton
179 (tr("Change time from start of measure %1")
180 .arg(barNo + 1), groupBox);
181 groupBoxLayout->addWidget(m_startOfBarButton);
182 m_startOfBarButton->setChecked(true);
183 } else {
184 m_asGivenButton->setChecked(true);
185 }
186 } else {
187 groupBoxLayout->addWidget(
188 new QLabel(tr("Time change will take effect at the start of"
189 " measure %1.").arg(barNo + 1)));
190 }
191 }
192 groupBox->setLayout(groupBoxLayout);
193
194 groupBox = new QGroupBox(tr("Options"));
195 groupBoxLayout = new QVBoxLayout;
196 vboxLayout->addWidget(groupBox);
197 QSettings settings;
198 settings.beginGroup( GeneralOptionsConfigGroup );
199
200 m_hideSignatureButton = new QCheckBox(tr("Hide the time signature"));
201 groupBoxLayout->addWidget(m_hideSignatureButton);
202 m_hideSignatureButton->setChecked
203 ( qStrToBool( settings.value("timesigdialogmakehidden", "false" ) ) );
204
205 m_hideBarsButton = new QCheckBox(tr("Hide the affected bar lines"));
206 groupBoxLayout->addWidget(m_hideBarsButton);
207 m_hideBarsButton->setChecked
208 ( qStrToBool( settings.value("timesigdialogmakehiddenbars", "false" ) ) );
209
210 m_commonTimeButton = new QCheckBox(tr("Show as common time"));
211 groupBoxLayout->addWidget(m_commonTimeButton);
212 m_commonTimeButton->setChecked
213 ( qStrToBool( settings.value("timesigdialogshowcommon", "true" ) ) );
214
215 m_normalizeRestsButton = new QCheckBox
216 (tr("Correct the durations of following measures"));
217 groupBoxLayout->addWidget(m_normalizeRestsButton);
218 m_normalizeRestsButton->setChecked
219 ( qStrToBool( settings.value("timesigdialognormalize", "true" ) ) );
220
221 groupBox->setLayout(groupBoxLayout);
222
223 QObject::connect(m_hideSignatureButton, &QAbstractButton::clicked, this,
224 &TimeSignatureDialog::slotUpdateCommonTimeButton);
225 slotUpdateCommonTimeButton();
226 m_explanatoryLabel = explanatoryLabel;
227
228 settings.endGroup();
229
230 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok
231 | QDialogButtonBox::Cancel
232 | QDialogButtonBox::Help);
233
234 vboxLayout->addWidget(buttonBox);
235
236 connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
237 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
238 connect(buttonBox, &QDialogButtonBox::helpRequested, this, &TimeSignatureDialog::slotHelpRequested);
239
240 }
241
242 TimeSignature
243 TimeSignatureDialog::getTimeSignature() const
244 {
245 QSettings settings;
246 settings.beginGroup( GeneralOptionsConfigGroup );
247
248 settings.setValue("timesigdialogmakehidden", m_hideSignatureButton->isChecked());
249 settings.setValue("timesigdialogmakehiddenbars", m_hideBarsButton->isChecked());
250 settings.setValue("timesigdialogshowcommon", m_commonTimeButton->isChecked());
251 settings.setValue("timesigdialognormalize", m_normalizeRestsButton->isChecked());
252
253 TimeSignature ts(m_timeSignature.getNumerator(),
254 m_timeSignature.getDenominator(),
255 (m_commonTimeButton &&
256 m_commonTimeButton->isEnabled() &&
257 m_commonTimeButton->isChecked()),
258 (m_hideSignatureButton &&
259 m_hideSignatureButton->isEnabled() &&
260 m_hideSignatureButton->isChecked()),
261 (m_hideBarsButton &&
262 m_hideBarsButton->isEnabled() &&
263 m_hideBarsButton->isChecked()));
264
265 settings.endGroup();
266
267 return ts;
268 }
269
270 void
271 TimeSignatureDialog::slotNumDown()
272 {
273 int n = m_timeSignature.getNumerator();
274 if (--n >= 1) {
275 m_timeSignature = TimeSignature(n, m_timeSignature.getDenominator());
276 m_numLabel->setText(QString("%1").arg(n));
277 }
278 slotUpdateCommonTimeButton();
279 }
280
281 void
282 TimeSignatureDialog::slotNumUp()
283 {
284 int n = m_timeSignature.getNumerator();
285 if (++n <= 99) {
286 m_timeSignature = TimeSignature(n, m_timeSignature.getDenominator());
287 m_numLabel->setText(QString("%1").arg(n));
288 }
289 slotUpdateCommonTimeButton();
290 }
291
292 void
293 TimeSignatureDialog::slotDenomDown()
294 {
295 int n = m_timeSignature.getDenominator();
296 if ((n /= 2) >= 1) {
297 m_timeSignature = TimeSignature(m_timeSignature.getNumerator(), n);
298 m_denomLabel->setText(QString("%1").arg(n));
299 }
300 slotUpdateCommonTimeButton();
301 }
302
303 void
304 TimeSignatureDialog::slotDenomUp()
305 {
306 int n = m_timeSignature.getDenominator();
307 if ((n *= 2) <= 64) {
308 m_timeSignature = TimeSignature(m_timeSignature.getNumerator(), n);
309 m_denomLabel->setText(QString("%1").arg(n));
310 }
311 slotUpdateCommonTimeButton();
312 }
313
314 void
315 TimeSignatureDialog::slotUpdateCommonTimeButton()
316 {
317 if (m_explanatoryLabel)
318 m_explanatoryLabel->hide();
319 if (!m_hideSignatureButton || !m_hideSignatureButton->isChecked()) {
320 if (m_timeSignature.getDenominator() == m_timeSignature.getNumerator()) {
321 if (m_timeSignature.getNumerator() == 4) {
322 m_commonTimeButton->setText(tr("Display as common time"));
323 m_commonTimeButton->setEnabled(true);
324 return ;
325 } else if (m_timeSignature.getNumerator() == 2) {
326 m_commonTimeButton->setText(tr("Display as cut common time"));
327 m_commonTimeButton->setEnabled(true);
328 return ;
329 }
330 }
331 }
332 m_commonTimeButton->setEnabled(false);
333 }
334
335 timeT
336 TimeSignatureDialog::getTime() const
337 {
338 if (m_timeEditor) {
339 return m_timeEditor->getTime();
340 } else if (m_asGivenButton && m_asGivenButton->isChecked()) {
341 return m_time;
342 } else if (m_startOfBarButton && m_startOfBarButton->isChecked()) {
343 int barNo = m_composition->getBarNumber(m_time);
344 return m_composition->getBarStart(barNo);
345 } else {
346 return m_time;
347 }
348 }
349
350 bool
351 TimeSignatureDialog::shouldNormalizeRests() const
352 {
353 return (m_normalizeRestsButton && m_normalizeRestsButton->isEnabled() &&
354 m_normalizeRestsButton->isChecked());
355 }
356
357
358 void
359 TimeSignatureDialog::slotHelpRequested()
360 {
361 // TRANSLATORS: if the manual is translated into your language, you can
362 // change the two-letter language code in this URL to point to your language
363 // version, eg. "http://rosegardenmusic.com/wiki/doc:timeSignatureDialog-es" for the
364 // Spanish version. If your language doesn't yet have a translation, feel
365 // free to create one.
366 QString helpURL = tr("http://rosegardenmusic.com/wiki/doc:timeSignatureDialog-en");
367 QDesktopServices::openUrl(QUrl(helpURL));
368 }
369 }
370