|
13 | 13 | #include <ScopicFlowCore/LabelSequenceInteractionController.h> |
14 | 14 | #include <ScopicFlowCore/LabelViewModel.h> |
15 | 15 | #include <ScopicFlowCore/PointSequenceViewModel.h> |
| 16 | +#include <ScopicFlowCore/RangeSequenceViewModel.h> |
| 17 | +#include <ScopicFlowCore/ScaleHighlightViewModel.h> |
16 | 18 | #include <ScopicFlowCore/TimeManipulator.h> |
17 | 19 | #include <ScopicFlowCore/TimeViewModel.h> |
18 | 20 | #include <ScopicFlowCore/TimeLayoutViewModel.h> |
@@ -133,20 +135,25 @@ namespace VisualEditor { |
133 | 135 | keySignatureSequenceViewModel = new sflow::PointSequenceViewModel(q); |
134 | 136 | keySignatureSelectionController = new KeySignatureSelectionController(q); |
135 | 137 |
|
| 138 | + scaleHighlightSequenceViewModel = new sflow::RangeSequenceViewModel(q); |
| 139 | + |
136 | 140 | initStateMachine(); |
137 | 141 | } |
138 | 142 |
|
139 | 143 | void KeySignatureViewModelContextData::bindKeySignatureSequenceViewModel() { |
140 | 144 | Q_Q(ProjectViewModelContext); |
141 | 145 | connect(keySignatureSequence, &dspx::KeySignatureSequence::itemInserted, keySignatureSequenceViewModel, [=, this](dspx::KeySignature *item) { |
142 | 146 | bindKeySignatureDocumentItem(item); |
| 147 | + bindScaleHighlightDocumentItem(item); |
143 | 148 | }); |
144 | 149 | connect(keySignatureSequence, &dspx::KeySignatureSequence::itemRemoved, keySignatureSequenceViewModel, [=, this](dspx::KeySignature *item) { |
145 | 150 | unbindKeySignatureDocumentItem(item); |
| 151 | + unbindScaleHighlightDocumentItem(item); |
146 | 152 | }); |
147 | 153 | // For key signature sequence, item will never be inserted or removed from view |
148 | 154 | for (auto item : keySignatureSequence->asRange()) { |
149 | 155 | bindKeySignatureDocumentItem(item); |
| 156 | + bindScaleHighlightDocumentItem(item); |
150 | 157 | } |
151 | 158 | connect(keySignatureSelectionModel, &dspx::KeySignatureSelectionModel::itemSelected, this, [=, this](dspx::KeySignature *item, bool selected) { |
152 | 159 | qCDebug(lcKeySignatureViewModelContextData) << "KeySignature item selected" << item << selected; |
@@ -338,4 +345,111 @@ namespace VisualEditor { |
338 | 345 | scenario.modifyExistingKeySignatureAt(viewItem->position()); |
339 | 346 | } |
340 | 347 |
|
| 348 | + void KeySignatureViewModelContextData::bindScaleHighlightDocumentItem(dspx::KeySignature *item) { |
| 349 | + if (keySignatureScaleHighlightViewItemMap.contains(item)) { |
| 350 | + return; |
| 351 | + } |
| 352 | + auto viewItem = new sflow::ScaleHighlightViewModel(scaleHighlightSequenceViewModel); |
| 353 | + keySignatureScaleHighlightViewItemMap.insert(item, viewItem); |
| 354 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature scale highlight item inserted" << item << viewItem; |
| 355 | + |
| 356 | + // Store the current nextItem to track disconnections |
| 357 | + QPointer<dspx::KeySignature> currentNextItem = item->nextItem(); |
| 358 | + |
| 359 | + // Connect pos signal |
| 360 | + connect(item, &dspx::KeySignature::posChanged, viewItem, [=, this] { |
| 361 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature scale highlight pos updated" << item << item->pos(); |
| 362 | + updateScaleHighlightViewItem(item); |
| 363 | + }); |
| 364 | + |
| 365 | + // Connect nextItem signal and handle nextItem's pos signal |
| 366 | + connect(item, &dspx::KeySignature::nextItemChanged, viewItem, [=, this] () mutable { |
| 367 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature nextItem changed" << item << item->nextItem(); |
| 368 | + |
| 369 | + // Disconnect previous nextItem's pos signal if any |
| 370 | + if (currentNextItem) { |
| 371 | + disconnect(currentNextItem, &dspx::KeySignature::posChanged, viewItem, nullptr); |
| 372 | + } |
| 373 | + |
| 374 | + // Update current nextItem |
| 375 | + currentNextItem = item->nextItem(); |
| 376 | + |
| 377 | + // Connect new nextItem's pos signal if exists |
| 378 | + if (currentNextItem) { |
| 379 | + connect(currentNextItem, &dspx::KeySignature::posChanged, viewItem, [=, this] { |
| 380 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature nextItem pos updated" << currentNextItem << currentNextItem->pos(); |
| 381 | + updateScaleHighlightViewItem(item); |
| 382 | + }); |
| 383 | + } |
| 384 | + |
| 385 | + updateScaleHighlightViewItem(item); |
| 386 | + }); |
| 387 | + |
| 388 | + // Connect mode and tonality signals |
| 389 | + connect(item, &dspx::KeySignature::modeChanged, viewItem, [=, this] { |
| 390 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature scale highlight mode updated" << item << item->mode(); |
| 391 | + updateScaleHighlightViewItem(item); |
| 392 | + }); |
| 393 | + |
| 394 | + connect(item, &dspx::KeySignature::tonalityChanged, viewItem, [=, this] { |
| 395 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature scale highlight tonality updated" << item << item->tonality(); |
| 396 | + updateScaleHighlightViewItem(item); |
| 397 | + }); |
| 398 | + |
| 399 | + // Connect current nextItem's pos signal if exists |
| 400 | + if (currentNextItem) { |
| 401 | + connect(currentNextItem, &dspx::KeySignature::posChanged, viewItem, [=, this] { |
| 402 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature nextItem pos updated" << currentNextItem << currentNextItem->pos(); |
| 403 | + updateScaleHighlightViewItem(item); |
| 404 | + }); |
| 405 | + } |
| 406 | + |
| 407 | + // Initialize values |
| 408 | + updateScaleHighlightViewItem(item); |
| 409 | + |
| 410 | + scaleHighlightSequenceViewModel->insertItem(viewItem); |
| 411 | + } |
| 412 | + |
| 413 | + void KeySignatureViewModelContextData::unbindScaleHighlightDocumentItem(dspx::KeySignature *item) { |
| 414 | + if (!keySignatureScaleHighlightViewItemMap.contains(item)) { |
| 415 | + return; |
| 416 | + } |
| 417 | + auto viewItem = keySignatureScaleHighlightViewItemMap.take(item); |
| 418 | + qCDebug(lcKeySignatureViewModelContextData) << "KeySignature scale highlight item removed" << item << viewItem; |
| 419 | + |
| 420 | + disconnect(item, nullptr, viewItem, nullptr); |
| 421 | + |
| 422 | + // Disconnect nextItem's pos signal if any |
| 423 | + if (auto nextItem = item->nextItem()) { |
| 424 | + disconnect(nextItem, nullptr, viewItem, nullptr); |
| 425 | + } |
| 426 | + |
| 427 | + scaleHighlightSequenceViewModel->removeItem(viewItem); |
| 428 | + |
| 429 | + viewItem->deleteLater(); |
| 430 | + } |
| 431 | + |
| 432 | + void KeySignatureViewModelContextData::updateScaleHighlightViewItem(dspx::KeySignature *item) { |
| 433 | + auto viewItem = keySignatureScaleHighlightViewItemMap.value(item); |
| 434 | + if (!viewItem) { |
| 435 | + return; |
| 436 | + } |
| 437 | + |
| 438 | + // Calculate position |
| 439 | + viewItem->setPosition(item->pos()); |
| 440 | + |
| 441 | + // Calculate length |
| 442 | + int length; |
| 443 | + if (auto nextItem = item->nextItem()) { |
| 444 | + length = nextItem->pos() - item->pos(); |
| 445 | + } else { |
| 446 | + length = 1073741824; // Default length when no next item |
| 447 | + } |
| 448 | + viewItem->setLength(length); |
| 449 | + |
| 450 | + // Calculate cMask using MusicMode::translateMask |
| 451 | + int cMask = SVS::MusicMode(item->mode()).translateMask(item->tonality(), 0); |
| 452 | + viewItem->setCMask(cMask); |
| 453 | + } |
| 454 | + |
341 | 455 | } |
0 commit comments