Skip to content

Commit 2710e82

Browse files
committed
Add support for vertical splits in DataViewport
1 parent bfb0ec0 commit 2710e82

2 files changed

Lines changed: 175 additions & 64 deletions

File tree

Source/UI/DataViewport.cpp

Lines changed: 136 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ DraggableTabComponent::DraggableTabComponent (DataViewport* parent_) : TabbedCom
160160
setTabBarDepth (28);
161161
setOutline (0);
162162
setIndent (5); // gap to leave around the edge of the content component
163+
getTabbedButtonBar().setMinimumTabScaleFactor (0.5f);
163164

164165
Path closeButtonPath;
165166
closeButtonPath.addLineSegment (Line<float> (0, 0, 12, 12), 1.0f);
@@ -512,12 +513,10 @@ void DraggableTabComponent::takeComponentSnapshot (int tabIndex, const String& t
512513
}
513514
}
514515

515-
AddTabbedComponentButton::AddTabbedComponentButton()
516-
: Button ("Add Tabbed Component")
516+
AddTabbedComponentButton::AddTabbedComponentButton (SplitType splitType)
517+
: Button ("Add Tabbed Component"), type (splitType)
517518
{
518519
path.addRoundedRectangle (1, 1, 18, 18, 3.0f);
519-
path.addLineSegment (Line<float> (9, 1, 9, 19), 0.0f);
520-
path.addTriangle (12, 7, 12, 13, 17, 10);
521520
}
522521

523522
AddTabbedComponentButton::~AddTabbedComponentButton() = default;
@@ -538,11 +537,21 @@ void AddTabbedComponentButton::paintButton (Graphics& g, bool isMouseOverButton,
538537
g.setColour (btnColour.withAlpha (0.9f));
539538
}
540539

541-
g.strokePath (path, PathStrokeType (1.0f));
540+
Path splitPath;
541+
if (type == SplitType::Horizontal)
542+
{
543+
g.drawRoundedRectangle (3, 3, getWidth() - 6, getHeight() - 6, 2, 1);
544+
g.fillRect ((float) (getWidth() / 2) - 0.5f, 3.0f, 1.0f, (float) (getHeight() - 6));
545+
}
546+
else
547+
{
548+
g.drawRoundedRectangle (3, 3, getWidth() - 6, getHeight() - 6, 2, 1);
549+
g.fillRect (3.0f, (float) (getHeight() / 2) - 0.5f, (float) (getWidth() - 6), 1.0f);
550+
}
542551
}
543552

544-
TabbedComponentResizerBar::TabbedComponentResizerBar (StretchableLayoutManager* layoutToUse)
545-
: StretchableLayoutResizerBar (layoutToUse, 1, true), layout (layoutToUse)
553+
TabbedComponentResizerBar::TabbedComponentResizerBar (StretchableLayoutManager* layoutToUse, bool isVerticalBar)
554+
: StretchableLayoutResizerBar (layoutToUse, 1, isVerticalBar), layout (layoutToUse), isVertical (isVerticalBar)
546555
{
547556
dragHandle = Drawable::parseSVGPath (
548557
"M19.63,11.31,16.5,9.17a1,1,0,0,0-1.5.69v4.28a1,1,0,0,0,1.5.69l3.13-2.14A.82.82,0,0,0,19.63,11.31ZM4.37,"
@@ -553,8 +562,8 @@ TabbedComponentResizerBar::~TabbedComponentResizerBar() = default;
553562

554563
void TabbedComponentResizerBar::paint (Graphics& g)
555564
{
556-
int w = getWidth();
557-
int h = getHeight();
565+
const int w = getWidth();
566+
const int h = getHeight();
558567

559568
if (isMouseButtonDown())
560569
g.setColour (findColour (ThemeColours::highlightedFill));
@@ -563,16 +572,30 @@ void TabbedComponentResizerBar::paint (Graphics& g)
563572
else
564573
g.setColour (findColour (ThemeColours::defaultFill).withAlpha (0.6f));
565574

566-
g.fillRect ((w / 2) - 1, 0, 2, h);
567-
568-
g.fillPath (dragHandle, dragHandle.getTransformToScaleToFit (0, (h / 2) - (w / 2), w, w, true));
575+
if (isVertical)
576+
{
577+
g.fillRect ((w / 2) - 1, 0, 2, h);
578+
g.fillPath (dragHandle, dragHandle.getTransformToScaleToFit (0, (h / 2) - (w / 2), w, w, true));
579+
}
580+
else
581+
{
582+
g.fillRect (0, (h / 2) - 1, w, 2);
583+
g.fillPath (dragHandle, dragHandle.getTransformToScaleToFit ((w / 2) - (h / 2), 0, h, h, true).rotated (MathConstants<float>::halfPi, w / 2.0f, h / 2.0f));
584+
}
569585
}
570586

571587
void TabbedComponentResizerBar::mouseDoubleClick (const MouseEvent& event)
572588
{
573589
if (Component* parent = getParentComponent())
574590
{
575-
layout->setItemPosition (1, (parent->getWidth() / 2) - (getWidth() / 2));
591+
if (isVertical)
592+
{
593+
layout->setItemPosition (1, (parent->getWidth() / 2) - (getWidth() / 2));
594+
}
595+
else
596+
{
597+
layout->setItemPosition (1, (parent->getHeight() / 2) - (getHeight() / 2));
598+
}
576599
parent->resized();
577600
}
578601
}
@@ -583,40 +606,44 @@ DataViewport::DataViewport() : shutdown (false)
583606
addAndMakeVisible (c);
584607
draggableTabComponents.add (c);
585608

586-
addTabbedComponentButton = std::make_unique<AddTabbedComponentButton>();
587-
addAndMakeVisible (addTabbedComponentButton.get());
588-
addTabbedComponentButton->addListener (this);
609+
addHorizontalSplitButton = std::make_unique<AddTabbedComponentButton> (AddTabbedComponentButton::SplitType::Horizontal);
610+
addAndMakeVisible (addHorizontalSplitButton.get());
611+
addHorizontalSplitButton->addListener (this);
589612

590-
tabbedComponentResizer = std::make_unique<TabbedComponentResizerBar> (&tabbedComponentLayout);
591-
addChildComponent (tabbedComponentResizer.get());
613+
addVerticalSplitButton = std::make_unique<AddTabbedComponentButton> (AddTabbedComponentButton::SplitType::Vertical);
614+
addAndMakeVisible (addVerticalSplitButton.get());
615+
addVerticalSplitButton->addListener (this);
616+
617+
recreateResizerBar();
592618
}
593619

594620
void DataViewport::resized()
595621
{
596-
int width = getWidth() / draggableTabComponents.size();
622+
const int numComponents = draggableTabComponents.size();
623+
const int width = numComponents > 0 ? getWidth() / numComponents : getWidth();
597624

598-
if (draggableTabComponents.size() == 1)
625+
if (numComponents == 1)
626+
{
599627
draggableTabComponents[0]->setBounds (0, 0, width, getHeight());
600-
else if (draggableTabComponents.size() == 2)
628+
tabbedComponentResizer->setVisible (false);
629+
}
630+
else if (numComponents == 2)
601631
{
632+
tabbedComponentResizer->setVisible (true);
602633
Component* comps[] = { draggableTabComponents[0], tabbedComponentResizer.get(), draggableTabComponents[1] };
603-
tabbedComponentLayout.layOutComponents (comps, 3, 0, 0, getWidth(), getHeight(), false, true);
634+
const bool layOutVertically = splitOrientation == SplitOrientation::Vertical;
635+
tabbedComponentLayout.layOutComponents (comps, 3, 0, 0, getWidth(), getHeight(), layOutVertically, true);
604636
}
605637
else
606638
{
607-
for (int i = 0; i < draggableTabComponents.size(); i++)
639+
tabbedComponentResizer->setVisible (false);
640+
for (int i = 0; i < numComponents; i++)
608641
{
609642
draggableTabComponents[i]->setBounds (width * i, 0, width, getHeight());
610643
}
611644
}
612645

613-
addTabbedComponentButton->setBounds (getWidth() - 24, getHeight() - 26, 20, 20);
614-
addTabbedComponentButton->toFront (false);
615-
616-
if (draggableTabComponents[activeTabbedComponent]->getNumTabs() > 1 && activeTabbedComponent < 2)
617-
addTabbedComponentButton->setVisible (true);
618-
else
619-
addTabbedComponentButton->setVisible (false);
646+
updateControlButtons();
620647
}
621648

622649
void DataViewport::addTab (String name,
@@ -654,26 +681,13 @@ void DataViewport::removeTab (int nodeId, bool sendNotification)
654681

655682
void DataViewport::buttonClicked (Button* button)
656683
{
657-
if (button == addTabbedComponentButton.get())
684+
if (button == addHorizontalSplitButton.get())
658685
{
659-
DraggableTabComponent* d = new DraggableTabComponent (this);
660-
addAndMakeVisible (d);
661-
draggableTabComponents.add (d);
662-
663-
if (draggableTabComponents.size() == 2)
664-
{
665-
tabbedComponentResizer->setVisible (true);
666-
667-
tabbedComponentLayout.setItemLayout (0, -0.25, -0.75, -0.5);
668-
tabbedComponentLayout.setItemLayout (1, 12, 12, 12);
669-
tabbedComponentLayout.setItemLayout (2, -0.25, -0.75, -0.5);
670-
}
671-
672-
resized();
673-
674-
activeTabbedComponent++;
675-
676-
addTabbedComponentButton->setVisible (false);
686+
handleSplit (SplitOrientation::Horizontal);
687+
}
688+
else if (button == addVerticalSplitButton.get())
689+
{
690+
handleSplit (SplitOrientation::Vertical);
677691
}
678692
}
679693

@@ -708,11 +722,7 @@ void DataViewport::removeTabbedComponent (DraggableTabComponent* draggableTabCom
708722

709723
if (draggableTabComponents.size() == 2)
710724
{
711-
tabbedComponentResizer->setVisible (true);
712-
713-
tabbedComponentLayout.setItemLayout (0, -0.25, -0.75, -0.5);
714-
tabbedComponentLayout.setItemLayout (1, 12, 12, 12);
715-
tabbedComponentLayout.setItemLayout (2, -0.25, -0.75, -0.5);
725+
configureLayoutForTwoComponents();
716726
}
717727
else
718728
{
@@ -727,6 +737,8 @@ void DataViewport::saveStateToXml (XmlElement* xml)
727737
{
728738
XmlElement* dataViewportState = xml->createNewChildElement ("DATAVIEWPORT");
729739

740+
dataViewportState->setAttribute ("splitOrientation", splitOrientation == SplitOrientation::Vertical ? "vertical" : "horizontal");
741+
730742
// save tab order in each draggableTabComponent
731743
for (int i = 0; i < draggableTabComponents.size(); i++)
732744
{
@@ -753,6 +765,9 @@ void DataViewport::loadStateFromXml (XmlElement* xml)
753765
{
754766
LOGD ("Loading DataViewport state from XML...");
755767

768+
const auto orientationString = dvXml->getStringAttribute ("splitOrientation", "horizontal");
769+
setSplitOrientation (orientationString.equalsIgnoreCase ("vertical") ? SplitOrientation::Vertical : SplitOrientation::Horizontal);
770+
756771
// remove info, graph, and console tabs
757772
for (int i = 0; i < 3; i++)
758773
removeTab (i);
@@ -773,12 +788,8 @@ void DataViewport::loadStateFromXml (XmlElement* xml)
773788
DraggableTabComponent* d = new DraggableTabComponent (this);
774789
addAndMakeVisible (d);
775790
draggableTabComponents.add (d);
776-
777-
tabbedComponentResizer->setVisible (draggableTabComponents.size() == 2);
778-
779-
tabbedComponentLayout.setItemLayout (0, -0.25, -0.75, -0.5);
780-
tabbedComponentLayout.setItemLayout (1, 12, 12, 12);
781-
tabbedComponentLayout.setItemLayout (2, -0.25, -0.75, -0.5);
791+
if (draggableTabComponents.size() == 2)
792+
configureLayoutForTwoComponents();
782793
}
783794

784795
activeTabbedComponent = index;
@@ -838,3 +849,68 @@ void DataViewport::disableConnectionToEditorViewport()
838849
{
839850
shutdown = true;
840851
}
852+
853+
void DataViewport::recreateResizerBar()
854+
{
855+
tabbedComponentResizer = std::make_unique<TabbedComponentResizerBar> (&tabbedComponentLayout, splitOrientation != SplitOrientation::Vertical);
856+
addChildComponent (tabbedComponentResizer.get());
857+
}
858+
859+
void DataViewport::configureLayoutForTwoComponents()
860+
{
861+
tabbedComponentLayout.clearAllItems();
862+
tabbedComponentResizer->setVisible (true);
863+
tabbedComponentLayout.setItemLayout (0, -0.25, -0.75, -0.5);
864+
tabbedComponentLayout.setItemLayout (1, 16, 16, 16);
865+
tabbedComponentLayout.setItemLayout (2, -0.25, -0.75, -0.5);
866+
}
867+
868+
void DataViewport::updateControlButtons()
869+
{
870+
const int buttonSize = 20;
871+
const int padding = 4;
872+
const int addButtonX = getWidth() - buttonSize - padding;
873+
874+
const bool hasActiveComponent = activeTabbedComponent < draggableTabComponents.size();
875+
const bool canAddSplit = hasActiveComponent && draggableTabComponents[activeTabbedComponent]->getNumTabs() > 1 && activeTabbedComponent < 2;
876+
877+
const int vertY = getHeight() - buttonSize - padding;
878+
const int horizY = vertY - buttonSize - padding;
879+
880+
addHorizontalSplitButton->setBounds (addButtonX, horizY, buttonSize, buttonSize);
881+
addVerticalSplitButton->setBounds (addButtonX, vertY, buttonSize, buttonSize);
882+
883+
addHorizontalSplitButton->toFront (false);
884+
addVerticalSplitButton->toFront (false);
885+
}
886+
887+
void DataViewport::setSplitOrientation (SplitOrientation orientation)
888+
{
889+
splitOrientation = orientation;
890+
recreateResizerBar();
891+
if (draggableTabComponents.size() == 2)
892+
configureLayoutForTwoComponents();
893+
else
894+
tabbedComponentResizer->setVisible (false);
895+
resized();
896+
}
897+
898+
void DataViewport::handleSplit (SplitOrientation desiredOrientation)
899+
{
900+
// Ensure a second component exists
901+
if (draggableTabComponents.size() < 2)
902+
{
903+
DraggableTabComponent* d = new DraggableTabComponent (this);
904+
addAndMakeVisible (d);
905+
draggableTabComponents.add (d);
906+
907+
activeTabbedComponent++;
908+
setSplitOrientation (desiredOrientation);
909+
}
910+
else if (splitOrientation != desiredOrientation)
911+
{
912+
setSplitOrientation (desiredOrientation);
913+
}
914+
915+
resized();
916+
}

0 commit comments

Comments
 (0)