395{
396
397 if (mRunningExperiment && mRunningExperiment->
IsRunning()) {
399 }
400
401
402 if (mRunningChain && mRunningExperiment) {
403 bool isRunning = mRunningExperiment->
IsRunning();
404 if (!isRunning) {
405 printf("DEBUG: Chain item finished (IsRunning=false), advancing...\n");
406
407
408
409
411
412
413 FILE* debugLog = fopen("chain_debug.log", "a");
414 if (debugLog) {
415 fprintf(debugLog, "=== Chain item finished ===\n");
416 fprintf(debugLog, " Exit code: %d\n", exitCode);
417 fprintf(debugLog, " mCurrentChainItemIndex: %d\n", mCurrentChainItemIndex);
418 fflush(debugLog);
419 }
420 printf("=== Chain item finished ===\n");
421 printf(" Exit code from GetExitCode(): %d\n", exitCode);
422 printf(" mCurrentChainItemIndex: %d\n", mCurrentChainItemIndex);
423
424
425 bool shouldAbortChain = false;
426 bool isConsentDecline = false;
427 if (debugLog) {
428 fprintf(debugLog, " Checking: exitCode=%d, chainItemIndex=%d\n", exitCode, mCurrentChainItemIndex);
429 }
430 if (exitCode != 0 && mCurrentChain && mCurrentChainItemIndex >= 0 &&
431 mCurrentChainItemIndex < (int)mCurrentChain->GetItems().size()) {
432 const ChainItem& currentItem = mCurrentChain->GetItems()[mCurrentChainItemIndex];
433 if (debugLog) {
435 fflush(debugLog);
436 }
437
438
439
440
441
444 shouldAbortChain = true;
445 isConsentDecline = true;
446 if (debugLog) fprintf(debugLog, " -> CONSENT/GATE DECLINED (code 1), aborting chain\n");
448 if (debugLog) fprintf(debugLog, " -> Consent error (code %d), continuing\n", exitCode);
449 } else {
450 if (debugLog) fprintf(debugLog, " -> Non-consent item or error (code %d), continuing\n", exitCode);
451 }
452 } else {
453 if (debugLog) fprintf(debugLog, " exitCode==0 or invalid index, continuing chain\n");
454 }
455 if (debugLog) {
456 fflush(debugLog);
457 fclose(debugLog);
458 }
459
460 if (shouldAbortChain && isConsentDecline) {
461
462 printf("Chain terminated: User declined consent\n");
463
464
465 mChainAccumulatedStdout += mRunningExperiment->
GetStdout();
466 mChainAccumulatedStderr += mRunningExperiment->
GetStderr();
467 mChainAccumulatedStdout += "\n=== Chain terminated: User declined consent ===\n";
468
469
470 mRunningChain = false;
471 mCurrentChainItemIndex = -1;
472
473
474 if (mCurrentChain) {
475 mCurrentChain->IncrementParticipantCounter();
476 printf("Participant counter incremented to: %d\n", mCurrentChain->GetParticipantCounter());
477 }
478
479
480 delete mRunningExperiment;
481 mRunningExperiment = nullptr;
482
483
484 goto render_ui;
485 }
486
487
488 mChainAccumulatedStdout += mRunningExperiment->
GetStdout();
489 mChainAccumulatedStderr += mRunningExperiment->
GetStderr();
490
491
492 mChainAccumulatedStdout += "\n=== End of item " + std::to_string(mCurrentChainItemIndex + 1) + " ===\n\n";
493 mChainAccumulatedStderr += "\n=== End of item " + std::to_string(mCurrentChainItemIndex + 1) + " ===\n\n";
494
495
496 printf("Chain item %d finished, advancing...\n", mCurrentChainItemIndex + 1);
497 mCurrentChainItemIndex++;
498
499 if (mCurrentChain && mCurrentChainItemIndex < (int)mCurrentChain->GetItems().size()) {
500
501 const ChainItem& item = mCurrentChain->GetItems()[mCurrentChainItemIndex];
502 printf("Advancing to chain item %d/%zu: %s\n",
503 mCurrentChainItemIndex + 1,
504 mCurrentChain->GetItems().size(),
506
507
508 delete mRunningExperiment;
509 mRunningExperiment = nullptr;
510
511
512 ExecuteChainItem(mCurrentChainItemIndex);
513 } else {
514
515 printf("Chain execution completed (all %zu items finished)\n", mCurrentChain->GetItems().size());
516 mRunningChain = false;
517 mCurrentChainItemIndex = -1;
518
519
520 if (mCurrentChain) {
521 mCurrentChain->IncrementParticipantCounter();
522 printf("Participant counter incremented to: %d\n", mCurrentChain->GetParticipantCounter());
523 }
524
525
526 if (mRunningExperiment) {
527 delete mRunningExperiment;
528 mRunningExperiment = nullptr;
529 }
530 }
531 }
532 }
533
534render_ui:
535
536 ImGuiViewport* viewport = ImGui::GetMainViewport();
537 ImGui::SetNextWindowPos(viewport->WorkPos);
538 ImGui::SetNextWindowSize(viewport->WorkSize);
539
540 ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoTitleBar |
541 ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
542 ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus;
543
544 ImGui::Begin("PEBL Launcher", p_open, window_flags);
545
546 RenderMenuBar();
547
548
549 float outputPanelHeight = mOutputExpanded ? 250.0f : 30.0f;
550 float contentHeight = ImGui::GetContentRegionAvail().y - outputPanelHeight;
551 ImGui::BeginChild("MainTabArea", ImVec2(0, contentHeight));
552
553
554
555 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(30, 8));
556 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 8));
557 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 8.0f);
558 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
559 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
560 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
561
562 if (ImGui::BeginTabBar("TopLevelTabs", ImGuiTabBarFlags_None)) {
563
564 ImGui::SetWindowFontScale(1.5f);
565 if (ImGui::BeginTabItem("Manage Studies")) {
566 if (mTopLevelTab != 1) {
567 mTopLevelTab = 0;
568 }
569 ImGui::SetWindowFontScale(1.0f);
570 ImGui::PopStyleColor(3);
571 ImGui::PopStyleVar(3);
572
573
574 RenderStudyBar();
575
576
577 ImGui::Dummy(ImVec2(0, 5));
578
579
580 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20, 6));
581 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));
582 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 6.0f);
583 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
584 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
585 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
586
587 if (ImGui::BeginTabBar("StudyTabs", ImGuiTabBarFlags_None)) {
588 ImGui::SetWindowFontScale(1.3f);
589 if (ImGui::BeginTabItem("Tests")) {
590 ImGui::SetWindowFontScale(1.0f);
591 ImGui::PopStyleColor(3);
592 ImGui::PopStyleVar(3);
593
594 RenderTestsTab();
595 ImGui::EndTabItem();
596
597 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20, 6));
598 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));
599 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 6.0f);
600 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
601 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
602 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
603 ImGui::SetWindowFontScale(1.3f);
604 }
605
606 if (ImGui::BeginTabItem("Chains")) {
607 ImGui::SetWindowFontScale(1.0f);
608 ImGui::PopStyleColor(3);
609 ImGui::PopStyleVar(3);
610
611 RenderChainsTab();
612 ImGui::EndTabItem();
613
614 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20, 6));
615 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));
616 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 6.0f);
617 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
618 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
619 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
620 ImGui::SetWindowFontScale(1.3f);
621 }
622
623 if (ImGui::BeginTabItem("Run")) {
624 ImGui::SetWindowFontScale(1.0f);
625 ImGui::PopStyleColor(3);
626 ImGui::PopStyleVar(3);
627
628 RenderRunTab();
629 ImGui::EndTabItem();
630
631 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(20, 6));
632 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));
633 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 6.0f);
634 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
635 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
636 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
637 }
638
639
640 ImGui::SetWindowFontScale(1.0f);
641 ImGui::PopStyleColor(3);
642 ImGui::PopStyleVar(3);
643
644 ImGui::EndTabBar();
645 } else {
646
647 ImGui::SetWindowFontScale(1.0f);
648 ImGui::PopStyleColor(3);
649 ImGui::PopStyleVar(3);
650 }
651
652 ImGui::EndTabItem();
653
654
655 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(30, 8));
656 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 8));
657 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 8.0f);
658 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
659 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
660 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
661 ImGui::SetWindowFontScale(1.5f);
662 }
663
664
665 ImGuiTabItemFlags quickLaunchFlags = (mTopLevelTab == 1) ? ImGuiTabItemFlags_SetSelected : 0;
666 if (ImGui::BeginTabItem("Quick Launch", nullptr, quickLaunchFlags)) {
667 if (mTopLevelTab == 1) {
668 mTopLevelTab = -1;
669 }
670 ImGui::SetWindowFontScale(1.0f);
671 ImGui::PopStyleColor(3);
672 ImGui::PopStyleVar(3);
673
674 RenderQuickLaunchTab();
675 ImGui::EndTabItem();
676
677
678 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(30, 8));
679 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 8));
680 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 8.0f);
681 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
682 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
683 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
684 ImGui::SetWindowFontScale(1.5f);
685 }
686
687
688 ImGuiTabItemFlags scaleBuilderFlags = (mTopLevelTab == 2) ? ImGuiTabItemFlags_SetSelected : 0;
689 if (ImGui::BeginTabItem("Scales/Surveys", nullptr, scaleBuilderFlags)) {
690 if (mTopLevelTab == 2) {
691 mTopLevelTab = -1;
692 }
693 ImGui::SetWindowFontScale(1.0f);
694 ImGui::PopStyleColor(3);
695 ImGui::PopStyleVar(3);
696
697 ShowScaleBuilder();
698 ImGui::EndTabItem();
699
700
701 ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(30, 8));
702 ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(12, 8));
703 ImGui::PushStyleVar(ImGuiStyleVar_TabRounding, 8.0f);
704 ImGui::PushStyleColor(ImGuiCol_Tab, ImVec4(0.35f, 0.40f, 0.48f, 1.0f));
705 ImGui::PushStyleColor(ImGuiCol_TabHovered, ImVec4(0.35f, 0.60f, 0.85f, 1.0f));
706 ImGui::PushStyleColor(ImGuiCol_TabActive, ImVec4(0.20f, 0.60f, 0.95f, 1.0f));
707 }
708
709
710 ImGui::SetWindowFontScale(1.0f);
711 ImGui::PopStyleColor(3);
712 ImGui::PopStyleVar(3);
713
714 ImGui::EndTabBar();
715 } else {
716
717 ImGui::SetWindowFontScale(1.0f);
718 ImGui::PopStyleColor(3);
719 ImGui::PopStyleVar(3);
720 }
721
722 ImGui::EndChild();
723
724
725 RenderOutputPanel();
726
727 ImGui::End();
728
729
730 if (mShowAbout) {
731 ShowAboutDialog();
732 }
733
734
735 if (mShowVariantNameDialog) {
736 ShowVariantNameDialog();
737 }
738
739
740 if (mShowParameterEditor) {
741 ShowParameterEditor();
742 }
743
744
745 if (mShowSettings) {
746 ShowSettingsDialog();
747 }
748
749
750 if (mPageEditor.
show) {
751 ShowPageEditor();
752 }
753
754
755 if (mTestEditor.
show) {
756 ShowTestEditor();
757 }
758
759
760 if (mShowCodeEditor) {
761 ShowCodeEditor();
762 }
763
764
765 if (mQuestionEditor.
show) {
766 ShowQuestionEditor();
767 }
768
769
770 if (mBatchImport.
show) {
771 ShowBatchImportDialog();
772 }
773
774
775 if (mDimensionEditor.
show) {
776 ShowDimensionEditor();
777 }
778
779
780 if (mCreateStudyDialog.
show) {
781 ShowCreateStudyFromScaleDialog();
782 }
783
784
785 if (mCorrectAnswersEditor.
show) {
786 ShowCorrectAnswersEditor();
787 }
788
789
790 if (mNormsEditor.
show) {
791 ShowNormsEditor();
792 }
793
794
795
796
797 bool translationEditorWasShown = mTranslationEditor.
show;
799 ShowTranslationEditorDialog();
800 }
801
802 if (translationEditorWasShown && !mTranslationEditor.
show &&
803 mTranslationEditor.
scaleMode && mCurrentScale && mScaleManager) {
804 auto reloaded = mScaleManager->LoadScale(mCurrentScale->GetScaleInfo().code);
805 if (reloaded) {
806 mCurrentScale->GetTranslations() = reloaded->GetTranslations();
807 }
809 }
810
811
812 if (mShowNewStudyDialog) {
813 ShowNewStudyDialog();
814 }
815
816
817 if (mShowNewChainDialog) {
818 ShowNewChainDialog();
819 }
820
821
822 if (mShowStudySettingsDialog) {
823 ShowStudySettingsDialog();
824 }
825
826
827 if (mShowFirstRunDialog) {
828 ShowFirstRunDialog();
829 }
830
831
832 if (mShowGettingStartedDialog) {
833 ShowGettingStartedDialog();
834 }
835
836
837 if (mShowDuplicateSubjectWarning) {
838 ShowDuplicateSubjectWarning();
839 }
840
841
842 if (mShowEditParticipantCodeDialog) {
843 ShowEditParticipantCodeDialog();
844 }
845
846
847 if (mShowSnapshotCreated) {
848 ShowSnapshotCreatedDialog();
849 }
850
851
852 mOpenScalesBrowser.
Render();
853}
std::string GetStdout() const
std::string GetStderr() const
std::string GetDisplayName() const