mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Added TabBarButton::setExtraComponent() method to allow custom components to be inserted into tabs. This involved a big refactoring and clean-up of all the tab drawing methods in the LookAndFeel class. Also (slightly) cleaned up some of the crappy old code in the WidgetsDemo while I was adding a demo for this.
This commit is contained in:
parent
1e9e6cbf79
commit
591ce2a396
5 changed files with 412 additions and 386 deletions
|
|
@ -33,60 +33,51 @@ class BouncingBallComponent : public Component,
|
|||
public:
|
||||
BouncingBallComponent()
|
||||
{
|
||||
x = Random::getSystemRandom().nextFloat() * 100.0f;
|
||||
y = Random::getSystemRandom().nextFloat() * 100.0f;
|
||||
Random random;
|
||||
|
||||
dx = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f;
|
||||
dy = Random::getSystemRandom().nextFloat() * 8.0f - 4.0f;
|
||||
const int size = 10 + random.nextInt (30);
|
||||
|
||||
colour = Colour (Random::getSystemRandom().nextInt())
|
||||
ballBounds.setBounds (random.nextFloat() * 100.0f,
|
||||
random.nextFloat() * 100.0f,
|
||||
size, size);
|
||||
|
||||
direction.x = random.nextFloat() * 8.0f - 4.0f;
|
||||
direction.y = random.nextFloat() * 8.0f - 4.0f;
|
||||
|
||||
colour = Colour (random.nextInt())
|
||||
.withAlpha (0.5f)
|
||||
.withBrightness (0.7f);
|
||||
|
||||
int size = 10 + Random::getSystemRandom().nextInt (30);
|
||||
setSize (size, size);
|
||||
|
||||
startTimer (60);
|
||||
}
|
||||
|
||||
~BouncingBallComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
g.setColour (colour);
|
||||
g.fillEllipse (x - getX(), y - getY(), getWidth() - 2.0f, getHeight() - 2.0f);
|
||||
g.fillEllipse (ballBounds - getPosition().toFloat());
|
||||
}
|
||||
|
||||
void timerCallback()
|
||||
{
|
||||
x += dx;
|
||||
y += dy;
|
||||
ballBounds += direction;
|
||||
|
||||
if (x < 0)
|
||||
dx = fabsf (dx);
|
||||
if (ballBounds.getX() < 0) direction.x = fabsf (direction.x);
|
||||
if (ballBounds.getY() < 0) direction.y = fabsf (direction.y);
|
||||
if (ballBounds.getRight() > getParentWidth()) direction.x = -fabsf (direction.x);
|
||||
if (ballBounds.getBottom() > getParentHeight()) direction.y = -fabsf (direction.y);
|
||||
|
||||
if (x > getParentWidth())
|
||||
dx = -fabsf (dx);
|
||||
|
||||
if (y < 0)
|
||||
dy = fabsf (dy);
|
||||
|
||||
if (y > getParentHeight())
|
||||
dy = -fabsf (dy);
|
||||
|
||||
setTopLeftPosition ((int) x, (int) y);
|
||||
setBounds (ballBounds.getSmallestIntegerContainer());
|
||||
}
|
||||
|
||||
bool hitTest (int /*x*/, int /*y*/)
|
||||
bool hitTest (int /* x */, int /* y */)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
Colour colour;
|
||||
float x, y, dx, dy;
|
||||
Rectangle<float> ballBounds;
|
||||
Point<float> direction;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -103,10 +94,6 @@ public:
|
|||
addAndMakeVisible (&(balls[i]));
|
||||
}
|
||||
|
||||
~DragOntoDesktopDemoComp()
|
||||
{
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent& e)
|
||||
{
|
||||
dragger.startDraggingComponent (this, e);
|
||||
|
|
@ -114,7 +101,7 @@ public:
|
|||
|
||||
void mouseDrag (const MouseEvent& e)
|
||||
{
|
||||
if (parent == 0)
|
||||
if (parent == nullptr)
|
||||
{
|
||||
delete this; // If our parent has been deleted, we'll just get rid of this component
|
||||
}
|
||||
|
|
@ -146,17 +133,16 @@ public:
|
|||
else
|
||||
g.fillAll (Colours::blue.withAlpha (0.2f));
|
||||
|
||||
String desc ("drag this box onto the desktop to show how the same component can move from being lightweight to being a separate window");
|
||||
|
||||
g.setFont (15.0f);
|
||||
g.setColour (Colours::black);
|
||||
g.drawFittedText (desc, 4, 0, getWidth() - 8, getHeight(), Justification::horizontallyJustified, 5);
|
||||
g.drawFittedText ("drag this box onto the desktop to show how the same component can move from being lightweight to being a separate window",
|
||||
4, 0, getWidth() - 8, getHeight(), Justification::horizontallyJustified, 5);
|
||||
|
||||
g.drawRect (0, 0, getWidth(), getHeight());
|
||||
g.drawRect (getLocalBounds());
|
||||
}
|
||||
|
||||
private:
|
||||
Component::SafePointer<Component> parent; // A safe-pointer will become zero if the component that it refers to is deleted..
|
||||
Component::SafePointer<Component> parent; // A safe-pointer will become null if the component that it refers to is deleted..
|
||||
ComponentDragger dragger;
|
||||
|
||||
BouncingBallComponent balls[3];
|
||||
|
|
@ -168,18 +154,12 @@ class CustomMenuComponent : public PopupMenu::CustomComponent,
|
|||
{
|
||||
public:
|
||||
CustomMenuComponent()
|
||||
: blobX (0),
|
||||
blobY (0)
|
||||
{
|
||||
// set off a timer to move a blob around on this component every
|
||||
// 300 milliseconds - see the timerCallback() method.
|
||||
startTimer (300);
|
||||
}
|
||||
|
||||
~CustomMenuComponent()
|
||||
{
|
||||
}
|
||||
|
||||
void getIdealSize (int& idealWidth,
|
||||
int& idealHeight)
|
||||
{
|
||||
|
|
@ -193,7 +173,7 @@ public:
|
|||
g.fillAll (Colours::yellow.withAlpha (0.3f));
|
||||
|
||||
g.setColour (Colours::pink);
|
||||
g.fillEllipse ((float) blobX, (float) blobY, 30.0f, 40.0f);
|
||||
g.fillEllipse (blobPosition);
|
||||
|
||||
g.setFont (Font (14.0f, Font::italic));
|
||||
g.setColour (Colours::black);
|
||||
|
|
@ -205,13 +185,15 @@ public:
|
|||
|
||||
void timerCallback()
|
||||
{
|
||||
blobX = Random::getSystemRandom().nextInt (getWidth());
|
||||
blobY = Random::getSystemRandom().nextInt (getHeight());
|
||||
Random random;
|
||||
blobPosition.setBounds (random.nextInt (getWidth()),
|
||||
random.nextInt (getHeight()),
|
||||
40, 30);
|
||||
repaint();
|
||||
}
|
||||
|
||||
private:
|
||||
int blobX, blobY;
|
||||
Rectangle<float> blobPosition;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -250,23 +232,16 @@ public:
|
|||
changeWidthToFitText();
|
||||
}
|
||||
|
||||
~ColourChangeButton()
|
||||
{
|
||||
}
|
||||
|
||||
void clicked()
|
||||
{
|
||||
#if JUCE_MODAL_LOOPS_PERMITTED
|
||||
ColourSelector colourSelector;
|
||||
colourSelector.setName ("background");
|
||||
colourSelector.setCurrentColour (findColour (TextButton::buttonColourId));
|
||||
colourSelector.addChangeListener (this);
|
||||
colourSelector.setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
|
||||
colourSelector.setSize (300, 400);
|
||||
ColourSelector* colourSelector = new ColourSelector();
|
||||
colourSelector->setName ("background");
|
||||
colourSelector->setCurrentColour (findColour (TextButton::buttonColourId));
|
||||
colourSelector->addChangeListener (this);
|
||||
colourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
|
||||
colourSelector->setSize (300, 400);
|
||||
|
||||
CallOutBox callOut (colourSelector, *this, 0);
|
||||
callOut.runModalLoop();
|
||||
#endif
|
||||
CallOutBox::launchAsynchronously (*this, colourSelector, nullptr);
|
||||
}
|
||||
|
||||
void changeListenerCallback (ChangeBroadcaster* source)
|
||||
|
|
@ -417,8 +392,7 @@ static Component* createRadioButtonPage()
|
|||
group->setBounds (20, 20, 220, 140);
|
||||
page->addAndMakeVisible (group);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
ToggleButton* tb = new ToggleButton ("radio button #" + String (i + 1));
|
||||
page->addAndMakeVisible (tb);
|
||||
|
|
@ -430,7 +404,7 @@ static Component* createRadioButtonPage()
|
|||
tb->setToggleState (true, false);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
DrawablePath normal, over;
|
||||
|
||||
|
|
@ -460,7 +434,7 @@ static Component* createRadioButtonPage()
|
|||
db->setToggleState (true, false);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
TextButton* tb = new TextButton ("button " + String (i + 1));
|
||||
|
||||
|
|
@ -512,41 +486,37 @@ public:
|
|||
// create an image-above-text button from these drawables..
|
||||
DrawableButton* db = new DrawableButton ("Button 1", DrawableButton::ImageAboveTextLabel);
|
||||
db->setImages (&normal, &over, &down);
|
||||
|
||||
addAndMakeVisible (db);
|
||||
db->setBounds (10, 30, 80, 80);
|
||||
db->setTooltip ("this is a DrawableButton with a label");
|
||||
addAndMakeVisible (db);
|
||||
|
||||
//==============================================================================
|
||||
// create an image-only button from these drawables..
|
||||
db = new DrawableButton ("Button 2", DrawableButton::ImageFitted);
|
||||
db->setImages (&normal, &over, &down);
|
||||
db->setClickingTogglesState (true);
|
||||
|
||||
addAndMakeVisible (db);
|
||||
db->setBounds (90, 30, 80, 80);
|
||||
db->setTooltip ("this is an image-only DrawableButton");
|
||||
db->addListener (buttonListener);
|
||||
addAndMakeVisible (db);
|
||||
|
||||
//==============================================================================
|
||||
// create an image-on-button-shape button from the same drawables..
|
||||
db = new DrawableButton ("Button 3", DrawableButton::ImageOnButtonBackground);
|
||||
db->setImages (&normal, 0, 0);
|
||||
|
||||
addAndMakeVisible (db);
|
||||
db->setBounds (200, 30, 110, 25);
|
||||
db->setTooltip ("this is a DrawableButton on a standard button background");
|
||||
addAndMakeVisible (db);
|
||||
|
||||
//==============================================================================
|
||||
db = new DrawableButton ("Button 4", DrawableButton::ImageOnButtonBackground);
|
||||
db->setImages (&normal, &over, &down);
|
||||
db->setClickingTogglesState (true);
|
||||
db->setBackgroundColours (Colours::white, Colours::yellow);
|
||||
|
||||
addAndMakeVisible (db);
|
||||
db->setBounds (200, 70, 50, 50);
|
||||
db->setTooltip ("this is a DrawableButton on a standard button background");
|
||||
db->addListener (buttonListener);
|
||||
addAndMakeVisible (db);
|
||||
|
||||
//==============================================================================
|
||||
HyperlinkButton* hyperlink
|
||||
|
|
@ -577,10 +547,10 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
animateButton = new TextButton ("click to animate...");
|
||||
addAndMakeVisible (animateButton);
|
||||
animateButton->changeWidthToFitText (24);
|
||||
animateButton->setTopLeftPosition (350, 70);
|
||||
animateButton->addListener (this);
|
||||
addAndMakeVisible (animateButton);
|
||||
}
|
||||
|
||||
~ButtonsPage()
|
||||
|
|
@ -642,8 +612,7 @@ static Component* createMiscPage()
|
|||
comboBox->setEditableText (true);
|
||||
comboBox->setJustificationType (Justification::centred);
|
||||
|
||||
int i;
|
||||
for (i = 1; i < 100; ++i)
|
||||
for (int i = 1; i < 100; ++i)
|
||||
comboBox->addItem ("combo box item " + String (i), i);
|
||||
|
||||
comboBox->setSelectedId (1);
|
||||
|
|
@ -705,10 +674,12 @@ public:
|
|||
|
||||
void resized()
|
||||
{
|
||||
int toolbarThickness = (int) depthSlider.getValue();
|
||||
|
||||
if (toolbar.isVertical())
|
||||
toolbar.setBounds (0, 0, (int) depthSlider.getValue(), getHeight());
|
||||
toolbar.setBounds (getLocalBounds().removeFromLeft (toolbarThickness));
|
||||
else
|
||||
toolbar.setBounds (0, 0, getWidth(), (int) depthSlider.getValue());
|
||||
toolbar.setBounds (getLocalBounds().removeFromTop (toolbarThickness));
|
||||
}
|
||||
|
||||
void sliderValueChanged (Slider*)
|
||||
|
|
@ -740,7 +711,6 @@ private:
|
|||
{
|
||||
public:
|
||||
DemoToolbarItemFactory() {}
|
||||
~DemoToolbarItemFactory() {}
|
||||
|
||||
//==============================================================================
|
||||
// Each type of item a toolbar can contain must be given a unique ID. These
|
||||
|
|
@ -870,10 +840,6 @@ private:
|
|||
comboBox.setEditableText (true);
|
||||
}
|
||||
|
||||
~CustomToolbarComboBox()
|
||||
{
|
||||
}
|
||||
|
||||
bool getToolbarItemSizes (int /*toolbarDepth*/, bool isToolbarVertical,
|
||||
int& preferredSize, int& minSize, int& maxSize)
|
||||
{
|
||||
|
|
@ -919,9 +885,19 @@ public:
|
|||
addTab ("buttons", getRandomBrightColour(), new ButtonsPage (this), true);
|
||||
addTab ("radio buttons", getRandomBrightColour(), createRadioButtonPage(), true);
|
||||
addTab ("misc widgets", getRandomBrightColour(), createMiscPage(), true);
|
||||
|
||||
getTabbedButtonBar().getTabButton (2)->setExtraComponent (new CustomTabButton(), TabBarButton::afterText);
|
||||
}
|
||||
|
||||
void buttonClicked (Button* button)
|
||||
{
|
||||
showBubbleMessage (button,
|
||||
"This is a demo of the BubbleMessageComponent, which lets you pop up a message pointing "
|
||||
"at a component or somewhere on the screen.\n\n"
|
||||
"The message bubbles will disappear after a timeout period, or when the mouse is clicked.");
|
||||
}
|
||||
|
||||
void showBubbleMessage (Component* targetComponent, const String& textToShow)
|
||||
{
|
||||
BubbleMessageComponent* bmc = new BubbleMessageComponent();
|
||||
|
||||
|
|
@ -935,18 +911,44 @@ public:
|
|||
addChildComponent (bmc);
|
||||
}
|
||||
|
||||
AttributedString text ("This is a demo of the BubbleMessageComponent, which lets you pop up a message pointing "
|
||||
"at a component or somewhere on the screen.\n\n"
|
||||
"The message bubbles will disappear after a timeout period, or when the mouse is clicked.");
|
||||
AttributedString text (textToShow);
|
||||
text.setJustification (Justification::centred);
|
||||
|
||||
bmc->showAt (button, text, 2000, true, true);
|
||||
bmc->showAt (targetComponent, text, 2000, true, true);
|
||||
}
|
||||
|
||||
static const Colour getRandomBrightColour()
|
||||
{
|
||||
return Colour (Random::getSystemRandom().nextFloat(), 0.1f, 0.97f, 1.0f);
|
||||
}
|
||||
|
||||
// This is a small star button that is put inside one of the tabs. You can
|
||||
// use this technique to create things like "close tab" buttons, etc.
|
||||
class CustomTabButton : public Component
|
||||
{
|
||||
public:
|
||||
CustomTabButton()
|
||||
{
|
||||
setSize (20, 20);
|
||||
}
|
||||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
Path p;
|
||||
p.addStar (Point<float>(), 7, 1.0f, 2.0f);
|
||||
|
||||
g.setColour (Colours::green);
|
||||
g.fillPath (p, RectanglePlacement (RectanglePlacement::centred)
|
||||
.getTransformToFit (p.getBounds(), getLocalBounds().reduced (2, 2).toFloat()));
|
||||
}
|
||||
|
||||
void mouseDown (const MouseEvent&)
|
||||
{
|
||||
DemoTabbedComponent* dtc = findParentComponentOfClass<DemoTabbedComponent>();
|
||||
|
||||
dtc->showBubbleMessage (this, "This is a custom tab component");
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -997,9 +999,7 @@ class ColourSelectorDialogWindow : public DialogWindow
|
|||
{
|
||||
public:
|
||||
ColourSelectorDialogWindow()
|
||||
: DialogWindow ("Colour selector demo",
|
||||
Colours::lightgrey,
|
||||
true)
|
||||
: DialogWindow ("Colour selector demo", Colours::lightgrey, true)
|
||||
{
|
||||
setContentOwned (new ColourSelector(), false);
|
||||
centreWithSize (400, 400);
|
||||
|
|
@ -1044,29 +1044,27 @@ public:
|
|||
|
||||
void buttonPressed (const ButtonType buttonId, const bool isDown)
|
||||
{
|
||||
String desc;
|
||||
setMessage (getDescriptionOfButtonType (buttonId) + (isDown ? " -- [down]"
|
||||
: " -- [up]"));
|
||||
}
|
||||
|
||||
switch (buttonId)
|
||||
static String getDescriptionOfButtonType (const ButtonType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case menuButton: desc = "menu button (short)"; break;
|
||||
case playButton: desc = "play button"; break;
|
||||
case plusButton: desc = "plus button"; break;
|
||||
case minusButton: desc = "minus button"; break;
|
||||
case rightButton: desc = "right button (short)"; break;
|
||||
case leftButton: desc = "left button (short)"; break;
|
||||
case rightButton_Long: desc = "right button (long)"; break;
|
||||
case leftButton_Long: desc = "left button (long)"; break;
|
||||
case menuButton_Long: desc = "menu button (long)"; break;
|
||||
case playButtonSleepMode: desc = "play (sleep mode)"; break;
|
||||
case switched: desc = "remote switched"; break;
|
||||
case menuButton: return "menu button (short)";
|
||||
case playButton: return "play button";
|
||||
case plusButton: return "plus button";
|
||||
case minusButton: return "minus button";
|
||||
case rightButton: return "right button (short)";
|
||||
case leftButton: return "left button (short)";
|
||||
case rightButton_Long: return "right button (long)";
|
||||
case leftButton_Long: return "left button (long)";
|
||||
case menuButton_Long: return "menu button (long)";
|
||||
case playButtonSleepMode: return "play (sleep mode)";
|
||||
case switched: return "remote switched";
|
||||
default: return "unknown";
|
||||
}
|
||||
|
||||
if (isDown)
|
||||
desc << " -- [down]";
|
||||
else
|
||||
desc << " -- [up]";
|
||||
|
||||
setMessage (desc);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1093,7 +1091,7 @@ public:
|
|||
menuButton.setBounds (10, 10, 200, 24);
|
||||
menuButton.addListener (this);
|
||||
menuButton.setTriggeredOnMouseDown (true); // because this button pops up a menu, this lets us
|
||||
// hold down the button and drag straight onto the menu
|
||||
// hold down the button and drag straight onto the menu
|
||||
|
||||
//==============================================================================
|
||||
addAndMakeVisible (&enableButton);
|
||||
|
|
@ -1135,7 +1133,6 @@ public:
|
|||
m.addColouredItem (4, "Coloured item", Colours::green);
|
||||
m.addSeparator();
|
||||
m.addCustomItem (5, new CustomMenuComponent());
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
PopupMenu tabsMenu;
|
||||
|
|
@ -1143,8 +1140,8 @@ public:
|
|||
tabsMenu.addItem (1002, "Show tabs at the bottom", true, tabs.getOrientation() == TabbedButtonBar::TabsAtBottom);
|
||||
tabsMenu.addItem (1003, "Show tabs at the left", true, tabs.getOrientation() == TabbedButtonBar::TabsAtLeft);
|
||||
tabsMenu.addItem (1004, "Show tabs at the right", true, tabs.getOrientation() == TabbedButtonBar::TabsAtRight);
|
||||
m.addSubMenu ("Tab position", tabsMenu);
|
||||
|
||||
m.addSubMenu ("Tab position", tabsMenu);
|
||||
m.addSeparator();
|
||||
|
||||
PopupMenu dialogMenu;
|
||||
|
|
@ -1154,28 +1151,22 @@ public:
|
|||
dialogMenu.addItem (103, "Show an alert-window with a 'question' icon...");
|
||||
|
||||
dialogMenu.addSeparator();
|
||||
|
||||
dialogMenu.addItem (110, "Show an ok/cancel alert-window...");
|
||||
|
||||
dialogMenu.addSeparator();
|
||||
|
||||
dialogMenu.addItem (111, "Show an alert-window with some extra components...");
|
||||
|
||||
dialogMenu.addSeparator();
|
||||
|
||||
dialogMenu.addItem (112, "Show a ThreadWithProgressWindow demo...");
|
||||
|
||||
m.addSubMenu ("AlertWindow demonstrations", dialogMenu);
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
m.addItem (120, "Show a colour selector demo...");
|
||||
m.addSeparator();
|
||||
|
||||
#if JUCE_MAC
|
||||
#if JUCE_MAC
|
||||
m.addItem (140, "Run the Apple Remote Control test...");
|
||||
m.addSeparator();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
PopupMenu nativeFileChoosers;
|
||||
nativeFileChoosers.addItem (121, "'Load' file browser...");
|
||||
|
|
@ -1221,12 +1212,12 @@ public:
|
|||
{
|
||||
AlertWindow::AlertIconType icon = AlertWindow::NoIcon;
|
||||
|
||||
if (result == 101)
|
||||
icon = AlertWindow::WarningIcon;
|
||||
else if (result == 102)
|
||||
icon = AlertWindow::InfoIcon;
|
||||
else if (result == 103)
|
||||
icon = AlertWindow::QuestionIcon;
|
||||
switch (result)
|
||||
{
|
||||
case 101: icon = AlertWindow::WarningIcon; break;
|
||||
case 102: icon = AlertWindow::InfoIcon; break;
|
||||
case 103: icon = AlertWindow::QuestionIcon; break;
|
||||
}
|
||||
|
||||
AlertWindow::showMessageBoxAsync (icon,
|
||||
"This is an AlertWindow",
|
||||
|
|
@ -1252,14 +1243,10 @@ public:
|
|||
|
||||
w.addTextEditor ("text", "enter some text here", "text field:");
|
||||
|
||||
StringArray options;
|
||||
options.add ("option 1");
|
||||
options.add ("option 2");
|
||||
options.add ("option 3");
|
||||
options.add ("option 4");
|
||||
w.addComboBox ("option", options, "some options");
|
||||
const char* options[] = { "option 1", "option 2", "option 3", "option 4", nullptr };
|
||||
w.addComboBox ("option", StringArray (options), "some options");
|
||||
|
||||
w.addButton ("ok", 1, KeyPress (KeyPress::returnKey, 0, 0));
|
||||
w.addButton ("ok", 1, KeyPress (KeyPress::returnKey, 0, 0));
|
||||
w.addButton ("cancel", 0, KeyPress (KeyPress::escapeKey, 0, 0));
|
||||
|
||||
if (w.runModalLoop() != 0) // is they picked 'ok'
|
||||
|
|
|
|||
|
|
@ -26,35 +26,23 @@
|
|||
TabBarButton::TabBarButton (const String& name, TabbedButtonBar& owner_)
|
||||
: Button (name),
|
||||
owner (owner_),
|
||||
overlapPixels (0)
|
||||
overlapPixels (0),
|
||||
extraCompPlacement (afterText)
|
||||
{
|
||||
shadow.setShadowProperties (2.2f, 0.7f, 0, 0);
|
||||
setComponentEffect (&shadow);
|
||||
setWantsKeyboardFocus (false);
|
||||
}
|
||||
|
||||
TabBarButton::~TabBarButton()
|
||||
{
|
||||
}
|
||||
TabBarButton::~TabBarButton() {}
|
||||
|
||||
int TabBarButton::getIndex() const
|
||||
{
|
||||
return owner.indexOfTabButton (this);
|
||||
}
|
||||
int TabBarButton::getIndex() const { return owner.indexOfTabButton (this); }
|
||||
Colour TabBarButton::getTabBackgroundColour() const { return owner.getTabBackgroundColour (getIndex()); }
|
||||
bool TabBarButton::isFrontTab() const { return getToggleState(); }
|
||||
|
||||
void TabBarButton::paintButton (Graphics& g,
|
||||
bool isMouseOverButton,
|
||||
bool isButtonDown)
|
||||
void TabBarButton::paintButton (Graphics& g, const bool isMouseOverButton, const bool isButtonDown)
|
||||
{
|
||||
const Rectangle<int> area (getActiveArea());
|
||||
g.setOrigin (area.getX(), area.getY());
|
||||
|
||||
getLookAndFeel().drawTabButton (g, area.getWidth(), area.getHeight(),
|
||||
owner.getTabBackgroundColour (getIndex()),
|
||||
getIndex(), getButtonText(), *this,
|
||||
owner.getOrientation(),
|
||||
isMouseOverButton, isButtonDown,
|
||||
getToggleState());
|
||||
getLookAndFeel().drawTabButton (*this, g, isMouseOverButton, isButtonDown);
|
||||
}
|
||||
|
||||
void TabBarButton::clicked (const ModifierKeys& mods)
|
||||
|
|
@ -69,25 +57,21 @@ bool TabBarButton::hitTest (int mx, int my)
|
|||
{
|
||||
const Rectangle<int> area (getActiveArea());
|
||||
|
||||
if (owner.getOrientation() == TabbedButtonBar::TabsAtLeft
|
||||
|| owner.getOrientation() == TabbedButtonBar::TabsAtRight)
|
||||
if (owner.isVertical())
|
||||
{
|
||||
if (isPositiveAndBelow (mx, getWidth())
|
||||
&& my >= area.getY() + overlapPixels
|
||||
&& my < area.getBottom() - overlapPixels)
|
||||
&& my >= area.getY() + overlapPixels && my < area.getBottom() - overlapPixels)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mx >= area.getX() + overlapPixels && mx < area.getRight() - overlapPixels
|
||||
&& isPositiveAndBelow (my, getHeight()))
|
||||
if (isPositiveAndBelow (my, getHeight())
|
||||
&& mx >= area.getX() + overlapPixels && mx < area.getRight() - overlapPixels)
|
||||
return true;
|
||||
}
|
||||
|
||||
Path p;
|
||||
getLookAndFeel().createTabButtonShape (p, area.getWidth(), area.getHeight(),
|
||||
getIndex(), getButtonText(), *this,
|
||||
owner.getOrientation(), false, false, getToggleState());
|
||||
getLookAndFeel().createTabButtonShape (*this, p, false, false);
|
||||
|
||||
return p.contains ((float) (mx - area.getX()),
|
||||
(float) (my - area.getY()));
|
||||
|
|
@ -95,24 +79,98 @@ bool TabBarButton::hitTest (int mx, int my)
|
|||
|
||||
int TabBarButton::getBestTabLength (const int depth)
|
||||
{
|
||||
return jlimit (depth * 2,
|
||||
depth * 7,
|
||||
getLookAndFeel().getTabButtonBestWidth (getIndex(), getButtonText(), depth, *this));
|
||||
int textWidth = getLookAndFeel().getTabButtonBestWidth (*this, depth);
|
||||
int extraCompSize = extraComponent != nullptr ? (owner.isVertical() ? extraComponent->getHeight()
|
||||
: extraComponent->getWidth()) : 0;
|
||||
|
||||
return jlimit (depth * 2, depth * 8, textWidth + extraCompSize);
|
||||
}
|
||||
|
||||
Rectangle<int> TabBarButton::getActiveArea()
|
||||
void TabBarButton::calcAreas (Rectangle<int>& extraComp, Rectangle<int>& text) const
|
||||
{
|
||||
text = getActiveArea();
|
||||
|
||||
const int depth = owner.isVertical() ? text.getWidth() : text.getHeight();
|
||||
const int indent = getLookAndFeel().getTabButtonOverlap (depth);
|
||||
|
||||
if (owner.isVertical())
|
||||
text.reduce (0, indent);
|
||||
else
|
||||
text.reduce (indent, 0);
|
||||
|
||||
if (extraComponent != nullptr)
|
||||
{
|
||||
if (extraCompPlacement == beforeText)
|
||||
{
|
||||
switch (owner.getOrientation())
|
||||
{
|
||||
case TabbedButtonBar::TabsAtLeft: extraComp = text.removeFromBottom (extraComponent->getHeight()); break;
|
||||
case TabbedButtonBar::TabsAtRight: extraComp = text.removeFromTop (extraComponent->getHeight()); break;
|
||||
case TabbedButtonBar::TabsAtBottom:
|
||||
case TabbedButtonBar::TabsAtTop: extraComp = text.removeFromLeft (extraComponent->getWidth()); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (owner.getOrientation())
|
||||
{
|
||||
case TabbedButtonBar::TabsAtLeft: extraComp = text.removeFromTop (extraComponent->getHeight()); break;
|
||||
case TabbedButtonBar::TabsAtRight: extraComp = text.removeFromBottom (extraComponent->getHeight()); break;
|
||||
case TabbedButtonBar::TabsAtBottom:
|
||||
case TabbedButtonBar::TabsAtTop: extraComp = text.removeFromRight (extraComponent->getWidth()); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle<int> TabBarButton::getTextArea() const
|
||||
{
|
||||
Rectangle<int> extraComp, text;
|
||||
calcAreas (extraComp, text);
|
||||
return text;
|
||||
}
|
||||
|
||||
Rectangle<int> TabBarButton::getActiveArea() const
|
||||
{
|
||||
Rectangle<int> r (getLocalBounds());
|
||||
const int spaceAroundImage = getLookAndFeel().getTabButtonSpaceAroundImage();
|
||||
const TabbedButtonBar::Orientation orientation = owner.getOrientation();
|
||||
|
||||
if (owner.getOrientation() != TabbedButtonBar::TabsAtLeft) r.removeFromRight (spaceAroundImage);
|
||||
if (owner.getOrientation() != TabbedButtonBar::TabsAtRight) r.removeFromLeft (spaceAroundImage);
|
||||
if (owner.getOrientation() != TabbedButtonBar::TabsAtBottom) r.removeFromTop (spaceAroundImage);
|
||||
if (owner.getOrientation() != TabbedButtonBar::TabsAtTop) r.removeFromBottom (spaceAroundImage);
|
||||
if (orientation != TabbedButtonBar::TabsAtLeft) r.removeFromRight (spaceAroundImage);
|
||||
if (orientation != TabbedButtonBar::TabsAtRight) r.removeFromLeft (spaceAroundImage);
|
||||
if (orientation != TabbedButtonBar::TabsAtBottom) r.removeFromTop (spaceAroundImage);
|
||||
if (orientation != TabbedButtonBar::TabsAtTop) r.removeFromBottom (spaceAroundImage);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void TabBarButton::setExtraComponent (Component* comp, ExtraComponentPlacement placement)
|
||||
{
|
||||
jassert (extraCompPlacement == beforeText || extraCompPlacement == afterText);
|
||||
extraCompPlacement = placement;
|
||||
addAndMakeVisible (extraComponent = comp);
|
||||
resized();
|
||||
}
|
||||
|
||||
void TabBarButton::childBoundsChanged (Component* c)
|
||||
{
|
||||
if (c == extraComponent)
|
||||
resized();
|
||||
}
|
||||
|
||||
void TabBarButton::resized()
|
||||
{
|
||||
if (extraComponent != nullptr)
|
||||
{
|
||||
Rectangle<int> extraComp, text;
|
||||
calcAreas (extraComp, text);
|
||||
|
||||
if (! extraComp.isEmpty())
|
||||
extraComponent->setBounds (extraComp);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class TabbedButtonBar::BehindFrontTabComp : public Component,
|
||||
|
|
@ -127,8 +185,7 @@ public:
|
|||
|
||||
void paint (Graphics& g)
|
||||
{
|
||||
getLookAndFeel().drawTabAreaBehindFrontButton (g, getWidth(), getHeight(),
|
||||
owner, owner.getOrientation());
|
||||
getLookAndFeel().drawTabAreaBehindFrontButton (owner, g, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
void enablementChanged()
|
||||
|
|
@ -211,12 +268,12 @@ void TabbedButtonBar::addTab (const String& tabName,
|
|||
TabInfo* newTab = new TabInfo();
|
||||
newTab->name = tabName;
|
||||
newTab->colour = tabBackgroundColour;
|
||||
newTab->component = createTabButton (tabName, insertIndex);
|
||||
jassert (newTab->component != nullptr);
|
||||
newTab->button = createTabButton (tabName, insertIndex);
|
||||
jassert (newTab->button != nullptr);
|
||||
|
||||
tabs.insert (insertIndex, newTab);
|
||||
currentTabIndex = tabs.indexOf (currentTab);
|
||||
addAndMakeVisible (newTab->component, insertIndex);
|
||||
addAndMakeVisible (newTab->button, insertIndex);
|
||||
|
||||
resized();
|
||||
|
||||
|
|
@ -232,7 +289,7 @@ void TabbedButtonBar::setTabName (const int tabIndex, const String& newName)
|
|||
if (tab != nullptr && tab->name != newName)
|
||||
{
|
||||
tab->name = newName;
|
||||
tab->component->setButtonText (newName);
|
||||
tab->button->setButtonText (newName);
|
||||
resized();
|
||||
}
|
||||
}
|
||||
|
|
@ -288,7 +345,7 @@ void TabbedButtonBar::setCurrentTabIndex (int newIndex, const bool sendChangeMes
|
|||
|
||||
for (int i = 0; i < tabs.size(); ++i)
|
||||
{
|
||||
TabBarButton* tb = tabs.getUnchecked(i)->component;
|
||||
TabBarButton* tb = tabs.getUnchecked(i)->button;
|
||||
tb->setToggleState (i == newIndex, false);
|
||||
}
|
||||
|
||||
|
|
@ -304,13 +361,13 @@ void TabbedButtonBar::setCurrentTabIndex (int newIndex, const bool sendChangeMes
|
|||
TabBarButton* TabbedButtonBar::getTabButton (const int index) const
|
||||
{
|
||||
TabInfo* const tab = tabs[index];
|
||||
return tab == nullptr ? nullptr : static_cast <TabBarButton*> (tab->component);
|
||||
return tab == nullptr ? nullptr : static_cast <TabBarButton*> (tab->button);
|
||||
}
|
||||
|
||||
int TabbedButtonBar::indexOfTabButton (const TabBarButton* button) const
|
||||
{
|
||||
for (int i = tabs.size(); --i >= 0;)
|
||||
if (tabs.getUnchecked(i)->component == button)
|
||||
if (tabs.getUnchecked(i)->button == button)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
|
|
@ -329,17 +386,17 @@ void TabbedButtonBar::resized()
|
|||
int depth = getWidth();
|
||||
int length = getHeight();
|
||||
|
||||
if (orientation == TabsAtTop || orientation == TabsAtBottom)
|
||||
if (! isVertical())
|
||||
std::swap (depth, length);
|
||||
|
||||
const int overlap = lf.getTabButtonOverlap (depth) + lf.getTabButtonSpaceAroundImage() * 2;
|
||||
|
||||
int i, totalLength = overlap;
|
||||
int totalLength = overlap;
|
||||
int numVisibleButtons = tabs.size();
|
||||
|
||||
for (i = 0; i < tabs.size(); ++i)
|
||||
for (int i = 0; i < tabs.size(); ++i)
|
||||
{
|
||||
TabBarButton* const tb = tabs.getUnchecked(i)->component;
|
||||
TabBarButton* const tb = tabs.getUnchecked(i)->button;
|
||||
|
||||
totalLength += tb->getBestTabLength (depth) - overlap;
|
||||
tb->overlapPixels = overlap / 2;
|
||||
|
|
@ -366,22 +423,22 @@ void TabbedButtonBar::resized()
|
|||
const int buttonSize = jmin (proportionOfWidth (0.7f), proportionOfHeight (0.7f));
|
||||
extraTabsButton->setSize (buttonSize, buttonSize);
|
||||
|
||||
if (orientation == TabsAtTop || orientation == TabsAtBottom)
|
||||
{
|
||||
tabsButtonPos = getWidth() - buttonSize / 2 - 1;
|
||||
extraTabsButton->setCentrePosition (tabsButtonPos, getHeight() / 2);
|
||||
}
|
||||
else
|
||||
if (isVertical())
|
||||
{
|
||||
tabsButtonPos = getHeight() - buttonSize / 2 - 1;
|
||||
extraTabsButton->setCentrePosition (getWidth() / 2, tabsButtonPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
tabsButtonPos = getWidth() - buttonSize / 2 - 1;
|
||||
extraTabsButton->setCentrePosition (tabsButtonPos, getHeight() / 2);
|
||||
}
|
||||
|
||||
totalLength = 0;
|
||||
|
||||
for (i = 0; i < tabs.size(); ++i)
|
||||
for (int i = 0; i < tabs.size(); ++i)
|
||||
{
|
||||
TabBarButton* const tb = tabs.getUnchecked(i)->component;
|
||||
TabBarButton* const tb = tabs.getUnchecked(i)->button;
|
||||
|
||||
const int newLength = totalLength + tb->getBestTabLength (depth);
|
||||
|
||||
|
|
@ -406,7 +463,7 @@ void TabbedButtonBar::resized()
|
|||
|
||||
TabBarButton* frontTab = nullptr;
|
||||
|
||||
for (i = 0; i < tabs.size(); ++i)
|
||||
for (int i = 0; i < tabs.size(); ++i)
|
||||
{
|
||||
TabBarButton* const tb = getTabButton (i);
|
||||
|
||||
|
|
@ -416,10 +473,10 @@ void TabbedButtonBar::resized()
|
|||
|
||||
if (i < numVisibleButtons)
|
||||
{
|
||||
if (orientation == TabsAtTop || orientation == TabsAtBottom)
|
||||
tb->setBounds (pos, 0, bestLength, getHeight());
|
||||
else
|
||||
if (isVertical())
|
||||
tb->setBounds (0, pos, getWidth(), bestLength);
|
||||
else
|
||||
tb->setBounds (pos, 0, bestLength, getHeight());
|
||||
|
||||
tb->toBack();
|
||||
|
||||
|
|
@ -478,7 +535,7 @@ void TabbedButtonBar::showExtraItemsMenu()
|
|||
{
|
||||
const TabInfo* const tab = tabs.getUnchecked(i);
|
||||
|
||||
if (! tab->component->isVisible())
|
||||
if (! tab->button->isVisible())
|
||||
m.addItem (i + 1, tab->name, true, i == currentTabIndex);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,47 @@ public:
|
|||
/** Destructor. */
|
||||
~TabBarButton();
|
||||
|
||||
/** Returns the bar that contains this button. */
|
||||
TabbedButtonBar& getTabbedButtonBar() const { return owner; }
|
||||
|
||||
//==============================================================================
|
||||
/** When adding an extra component to the tab, this indicates which side of
|
||||
the text it should be placed on. */
|
||||
enum ExtraComponentPlacement
|
||||
{
|
||||
beforeText,
|
||||
afterText
|
||||
};
|
||||
|
||||
/** Sets an extra component that will be shown in the tab.
|
||||
|
||||
This optional component will be positioned inside the tab, either to the left or right
|
||||
of the text. You could use this to implement things like a close button or a graphical
|
||||
status indicator. If a non-null component is passed-in, the TabbedButtonBar will take
|
||||
ownership of it and delete it when required.
|
||||
*/
|
||||
void setExtraComponent (Component* extraTabComponent,
|
||||
ExtraComponentPlacement extraComponentPlacement);
|
||||
|
||||
/** Returns an area of the component that's safe to draw in.
|
||||
|
||||
This deals with the orientation of the tabs, which affects which side is
|
||||
touching the tabbed box's content component.
|
||||
*/
|
||||
Rectangle<int> getActiveArea() const;
|
||||
|
||||
/** Returns the area of the component that should contain its text. */
|
||||
Rectangle<int> getTextArea() const;
|
||||
|
||||
/** Returns this tab's index in its tab bar. */
|
||||
int getIndex() const;
|
||||
|
||||
/** Returns the colour of the tab. */
|
||||
Colour getTabBackgroundColour() const;
|
||||
|
||||
/** Returns true if this is the frontmost (selected) tab. */
|
||||
bool isFrontTab() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Chooses the best length for the tab, given the specified depth.
|
||||
|
||||
|
|
@ -59,28 +100,24 @@ public:
|
|||
virtual int getBestTabLength (int depth);
|
||||
|
||||
//==============================================================================
|
||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown);
|
||||
void clicked (const ModifierKeys& mods);
|
||||
void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown);
|
||||
void clicked (const ModifierKeys&);
|
||||
bool hitTest (int x, int y);
|
||||
void resized();
|
||||
void childBoundsChanged (Component*);
|
||||
|
||||
protected:
|
||||
//==============================================================================
|
||||
friend class TabbedButtonBar;
|
||||
TabbedButtonBar& owner;
|
||||
int overlapPixels;
|
||||
DropShadowEffect shadow;
|
||||
int overlapPixels;
|
||||
|
||||
/** Returns an area of the component that's safe to draw in.
|
||||
|
||||
This deals with the orientation of the tabs, which affects which side is
|
||||
touching the tabbed box's content component.
|
||||
*/
|
||||
Rectangle<int> getActiveArea();
|
||||
|
||||
/** Returns this tab's index in its tab bar. */
|
||||
int getIndex() const;
|
||||
ScopedPointer<Component> extraComponent;
|
||||
ExtraComponentPlacement extraCompPlacement;
|
||||
|
||||
private:
|
||||
void calcAreas (Rectangle<int>&, Rectangle<int>&) const;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabBarButton);
|
||||
};
|
||||
|
||||
|
|
@ -135,11 +172,16 @@ public:
|
|||
*/
|
||||
void setOrientation (Orientation orientation);
|
||||
|
||||
/** Returns the current orientation.
|
||||
|
||||
/** Returns the bar's current orientation.
|
||||
@see setOrientation
|
||||
*/
|
||||
Orientation getOrientation() const noexcept { return orientation; }
|
||||
Orientation getOrientation() const noexcept { return orientation; }
|
||||
|
||||
/** Returns true if the orientation is TabsAtLeft or TabsAtRight. */
|
||||
bool isVertical() const noexcept { return orientation == TabsAtLeft || orientation == TabsAtRight; }
|
||||
|
||||
/** Returns the thickness of the bar, which may be its width or height, depending on the orientation. */
|
||||
int getThickness() const noexcept { return isVertical() ? getWidth() : getHeight(); }
|
||||
|
||||
/** Changes the minimum scale factor to which the tabs can be compressed when trying to
|
||||
fit a lot of tabs on-screen.
|
||||
|
|
@ -154,14 +196,12 @@ public:
|
|||
void clearTabs();
|
||||
|
||||
/** Adds a tab to the bar.
|
||||
|
||||
Tabs are added in left-to-right reading order.
|
||||
|
||||
If this is the first tab added, it'll also be automatically selected.
|
||||
*/
|
||||
void addTab (const String& tabName,
|
||||
const Colour& tabBackgroundColour,
|
||||
int insertIndex = -1);
|
||||
int insertIndex);
|
||||
|
||||
/** Changes the name of one of the tabs. */
|
||||
void setTabName (int tabIndex,
|
||||
|
|
@ -280,7 +320,7 @@ private:
|
|||
|
||||
struct TabInfo
|
||||
{
|
||||
ScopedPointer<TabBarButton> component;
|
||||
ScopedPointer<TabBarButton> button;
|
||||
String name;
|
||||
Colour colour;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2079,60 +2079,64 @@ int LookAndFeel::getTabButtonSpaceAroundImage()
|
|||
return 4;
|
||||
}
|
||||
|
||||
void LookAndFeel::createTabButtonShape (Path& p, int width, int height, int /*tabIndex*/,
|
||||
const String& /*text*/, Button& /*button*/, TabbedButtonBar::Orientation orientation,
|
||||
const bool /*isMouseOver*/, const bool /*isMouseDown*/, const bool /*isFrontTab*/)
|
||||
int LookAndFeel::getTabButtonBestWidth (TabBarButton& button, int tabDepth)
|
||||
{
|
||||
const float w = (float) width;
|
||||
const float h = (float) height;
|
||||
return Font (tabDepth * 0.6f).getStringWidth (button.getButtonText().trim())
|
||||
+ getTabButtonOverlap (tabDepth) * 2;
|
||||
}
|
||||
|
||||
void LookAndFeel::createTabButtonShape (TabBarButton& button, Path& p, bool isMouseOver, bool isMouseDown)
|
||||
{
|
||||
const Rectangle<int> activeArea (button.getActiveArea());
|
||||
const float w = (float) activeArea.getWidth();
|
||||
const float h = (float) activeArea.getHeight();
|
||||
|
||||
float length = w;
|
||||
float depth = h;
|
||||
|
||||
if (orientation == TabbedButtonBar::TabsAtLeft
|
||||
|| orientation == TabbedButtonBar::TabsAtRight)
|
||||
{
|
||||
if (button.getTabbedButtonBar().isVertical())
|
||||
std::swap (length, depth);
|
||||
}
|
||||
|
||||
const float indent = (float) getTabButtonOverlap ((int) depth);
|
||||
const float overhang = 4.0f;
|
||||
|
||||
if (orientation == TabbedButtonBar::TabsAtLeft)
|
||||
switch (button.getTabbedButtonBar().getOrientation())
|
||||
{
|
||||
p.startNewSubPath (w, 0.0f);
|
||||
p.lineTo (0.0f, indent);
|
||||
p.lineTo (0.0f, h - indent);
|
||||
p.lineTo (w, h);
|
||||
p.lineTo (w + overhang, h + overhang);
|
||||
p.lineTo (w + overhang, -overhang);
|
||||
}
|
||||
else if (orientation == TabbedButtonBar::TabsAtRight)
|
||||
{
|
||||
p.startNewSubPath (0.0f, 0.0f);
|
||||
p.lineTo (w, indent);
|
||||
p.lineTo (w, h - indent);
|
||||
p.lineTo (0.0f, h);
|
||||
p.lineTo (-overhang, h + overhang);
|
||||
p.lineTo (-overhang, -overhang);
|
||||
}
|
||||
else if (orientation == TabbedButtonBar::TabsAtBottom)
|
||||
{
|
||||
p.startNewSubPath (0.0f, 0.0f);
|
||||
p.lineTo (indent, h);
|
||||
p.lineTo (w - indent, h);
|
||||
p.lineTo (w, 0.0f);
|
||||
p.lineTo (w + overhang, -overhang);
|
||||
p.lineTo (-overhang, -overhang);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.startNewSubPath (0.0f, h);
|
||||
p.lineTo (indent, 0.0f);
|
||||
p.lineTo (w - indent, 0.0f);
|
||||
p.lineTo (w, h);
|
||||
p.lineTo (w + overhang, h + overhang);
|
||||
p.lineTo (-overhang, h + overhang);
|
||||
case TabbedButtonBar::TabsAtLeft:
|
||||
p.startNewSubPath (w, 0.0f);
|
||||
p.lineTo (0.0f, indent);
|
||||
p.lineTo (0.0f, h - indent);
|
||||
p.lineTo (w, h);
|
||||
p.lineTo (w + overhang, h + overhang);
|
||||
p.lineTo (w + overhang, -overhang);
|
||||
break;
|
||||
|
||||
case TabbedButtonBar::TabsAtRight:
|
||||
p.startNewSubPath (0.0f, 0.0f);
|
||||
p.lineTo (w, indent);
|
||||
p.lineTo (w, h - indent);
|
||||
p.lineTo (0.0f, h);
|
||||
p.lineTo (-overhang, h + overhang);
|
||||
p.lineTo (-overhang, -overhang);
|
||||
break;
|
||||
|
||||
case TabbedButtonBar::TabsAtBottom:
|
||||
p.startNewSubPath (0.0f, 0.0f);
|
||||
p.lineTo (indent, h);
|
||||
p.lineTo (w - indent, h);
|
||||
p.lineTo (w, 0.0f);
|
||||
p.lineTo (w + overhang, -overhang);
|
||||
p.lineTo (-overhang, -overhang);
|
||||
break;
|
||||
|
||||
default:
|
||||
p.startNewSubPath (0.0f, h);
|
||||
p.lineTo (indent, 0.0f);
|
||||
p.lineTo (w - indent, 0.0f);
|
||||
p.lineTo (w, h);
|
||||
p.lineTo (w + overhang, h + overhang);
|
||||
p.lineTo (-overhang, h + overhang);
|
||||
break;
|
||||
}
|
||||
|
||||
p.closeSubPath();
|
||||
|
|
@ -2140,13 +2144,13 @@ void LookAndFeel::createTabButtonShape (Path& p, int width, int height, int /*ta
|
|||
p = p.createPathWithRoundedCorners (3.0f);
|
||||
}
|
||||
|
||||
void LookAndFeel::fillTabButtonShape (Graphics& g, const Path& path, const Colour& preferredColour,
|
||||
int /*tabIndex*/, const String& /*text*/, Button& button,
|
||||
TabbedButtonBar::Orientation /*orientation*/, const bool /*isMouseOver*/,
|
||||
const bool /*isMouseDown*/, const bool isFrontTab)
|
||||
void LookAndFeel::fillTabButtonShape (TabBarButton& button, Graphics& g, const Path& path, bool isMouseOver, bool isMouseDown)
|
||||
{
|
||||
g.setColour (isFrontTab ? preferredColour
|
||||
: preferredColour.withMultipliedAlpha (0.9f));
|
||||
const Colour tabBackground (button.getTabBackgroundColour());
|
||||
const bool isFrontTab = button.isFrontTab();
|
||||
|
||||
g.setColour (isFrontTab ? tabBackground
|
||||
: tabBackground.withMultipliedAlpha (0.9f));
|
||||
|
||||
g.fillPath (path);
|
||||
|
||||
|
|
@ -2157,44 +2161,44 @@ void LookAndFeel::fillTabButtonShape (Graphics& g, const Path& path, const Colou
|
|||
g.strokePath (path, PathStrokeType (isFrontTab ? 1.0f : 0.5f));
|
||||
}
|
||||
|
||||
void LookAndFeel::drawTabButtonText (Graphics& g, int x, int y, int w, int h,
|
||||
const Colour& preferredBackgroundColour, int /*tabIndex*/,
|
||||
const String& text, Button& button, TabbedButtonBar::Orientation orientation,
|
||||
const bool isMouseOver, const bool isMouseDown, const bool isFrontTab)
|
||||
void LookAndFeel::drawTabButtonText (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
|
||||
{
|
||||
int length = w;
|
||||
int depth = h;
|
||||
const Rectangle<float> area (button.getTextArea().toFloat());
|
||||
|
||||
if (orientation == TabbedButtonBar::TabsAtLeft
|
||||
|| orientation == TabbedButtonBar::TabsAtRight)
|
||||
{
|
||||
int length = area.getWidth();
|
||||
int depth = area.getHeight();
|
||||
|
||||
if (button.getTabbedButtonBar().isVertical())
|
||||
std::swap (length, depth);
|
||||
}
|
||||
|
||||
Font font (depth * 0.6f);
|
||||
font.setUnderline (button.hasKeyboardFocus (false));
|
||||
|
||||
GlyphArrangement textLayout;
|
||||
textLayout.addFittedText (font, text.trim(),
|
||||
textLayout.addFittedText (font, button.getButtonText().trim(),
|
||||
0.0f, 0.0f, (float) length, (float) depth,
|
||||
Justification::centred,
|
||||
jmax (1, depth / 12));
|
||||
|
||||
AffineTransform t;
|
||||
|
||||
switch (orientation)
|
||||
switch (button.getTabbedButtonBar().getOrientation())
|
||||
{
|
||||
case TabbedButtonBar::TabsAtLeft: t = t.rotated (float_Pi * -0.5f).translated ((float) x, (float) (y + h)); break;
|
||||
case TabbedButtonBar::TabsAtRight: t = t.rotated (float_Pi * 0.5f).translated ((float) (x + w), (float) y); break;
|
||||
default: t = t.translated ((float) x, (float) y);
|
||||
case TabbedButtonBar::TabsAtLeft: t = t.rotated (float_Pi * -0.5f).translated (area.getX(), area.getBottom()); break;
|
||||
case TabbedButtonBar::TabsAtRight: t = t.rotated (float_Pi * 0.5f).translated (area.getRight(), area.getY()); break;
|
||||
case TabbedButtonBar::TabsAtTop:
|
||||
case TabbedButtonBar::TabsAtBottom: t = t.translated (area.getX(), area.getY()); break;
|
||||
default: jassertfalse; break;
|
||||
}
|
||||
|
||||
if (isFrontTab && (button.isColourSpecified (TabbedButtonBar::frontTextColourId) || isColourSpecified (TabbedButtonBar::frontTextColourId)))
|
||||
if (button.isFrontTab() && (button.isColourSpecified (TabbedButtonBar::frontTextColourId)
|
||||
|| isColourSpecified (TabbedButtonBar::frontTextColourId)))
|
||||
g.setColour (findColour (TabbedButtonBar::frontTextColourId));
|
||||
else if (button.isColourSpecified (TabbedButtonBar::tabTextColourId) || isColourSpecified (TabbedButtonBar::tabTextColourId))
|
||||
else if (button.isColourSpecified (TabbedButtonBar::tabTextColourId)
|
||||
|| isColourSpecified (TabbedButtonBar::tabTextColourId))
|
||||
g.setColour (findColour (TabbedButtonBar::tabTextColourId));
|
||||
else
|
||||
g.setColour (preferredBackgroundColour.contrasting());
|
||||
g.setColour (button.getTabBackgroundColour().contrasting());
|
||||
|
||||
if (! (isMouseOver || isMouseDown))
|
||||
g.setOpacity (0.8f);
|
||||
|
|
@ -2205,85 +2209,60 @@ void LookAndFeel::drawTabButtonText (Graphics& g, int x, int y, int w, int h,
|
|||
textLayout.draw (g, t);
|
||||
}
|
||||
|
||||
int LookAndFeel::getTabButtonBestWidth (int /*tabIndex*/, const String& text, int tabDepth, Button&)
|
||||
{
|
||||
Font f (tabDepth * 0.6f);
|
||||
return f.getStringWidth (text.trim()) + getTabButtonOverlap (tabDepth) * 2;
|
||||
}
|
||||
|
||||
void LookAndFeel::drawTabButton (Graphics& g, int w, int h, const Colour& preferredColour,
|
||||
int tabIndex, const String& text, Button& button, TabbedButtonBar::Orientation orientation,
|
||||
const bool isMouseOver, const bool isMouseDown, const bool isFrontTab)
|
||||
void LookAndFeel::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown)
|
||||
{
|
||||
Path tabShape;
|
||||
createTabButtonShape (tabShape, w, h, tabIndex, text, button, orientation,
|
||||
isMouseOver, isMouseDown, isFrontTab);
|
||||
createTabButtonShape (button, tabShape, isMouseOver, isMouseDown);
|
||||
|
||||
fillTabButtonShape (g, tabShape, preferredColour,
|
||||
tabIndex, text, button, orientation,
|
||||
isMouseOver, isMouseDown, isFrontTab);
|
||||
const Rectangle<int> activeArea (button.getActiveArea());
|
||||
tabShape.applyTransform (AffineTransform::translation ((float) activeArea.getX(),
|
||||
(float) activeArea.getY()));
|
||||
|
||||
const int depth = (orientation == TabbedButtonBar::TabsAtLeft || orientation == TabbedButtonBar::TabsAtRight) ? w : h;
|
||||
const int indent = getTabButtonOverlap (depth);
|
||||
int x = 0, y = 0;
|
||||
fillTabButtonShape (button, g, tabShape, isMouseOver, isMouseDown);
|
||||
|
||||
if (orientation == TabbedButtonBar::TabsAtLeft || orientation == TabbedButtonBar::TabsAtRight)
|
||||
{
|
||||
y += indent;
|
||||
h -= indent * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += indent;
|
||||
w -= indent * 2;
|
||||
}
|
||||
|
||||
drawTabButtonText (g, x, y, w, h, preferredColour,
|
||||
tabIndex, text, button, orientation,
|
||||
isMouseOver, isMouseDown, isFrontTab);
|
||||
drawTabButtonText (button, g, isMouseOver, isMouseDown);
|
||||
}
|
||||
|
||||
void LookAndFeel::drawTabAreaBehindFrontButton (Graphics& g, int w, int h, TabbedButtonBar& tabBar,
|
||||
TabbedButtonBar::Orientation orientation)
|
||||
void LookAndFeel::drawTabAreaBehindFrontButton (TabbedButtonBar& bar, Graphics& g, const int w, const int h)
|
||||
{
|
||||
const float shadowSize = 0.2f;
|
||||
|
||||
float x1 = 0, y1 = 0, x2 = 0, y2 = 0;
|
||||
Rectangle<int> shadowRect, line;
|
||||
ColourGradient gradient (Colours::black.withAlpha (bar.isEnabled() ? 0.3f : 0.15f), 0, 0,
|
||||
Colours::transparentBlack, 0, 0, false);
|
||||
|
||||
switch (orientation)
|
||||
switch (bar.getOrientation())
|
||||
{
|
||||
case TabbedButtonBar::TabsAtLeft:
|
||||
x1 = (float) w;
|
||||
x2 = w * (1.0f - shadowSize);
|
||||
shadowRect.setBounds ((int) x2, 0, w - (int) x2, h);
|
||||
gradient.point1.x = (float) w;
|
||||
gradient.point2.x = w * (1.0f - shadowSize);
|
||||
shadowRect.setBounds ((int) gradient.point2.x, 0, w - (int) gradient.point2.x, h);
|
||||
line.setBounds (w - 1, 0, 1, h);
|
||||
break;
|
||||
|
||||
case TabbedButtonBar::TabsAtRight:
|
||||
x2 = w * shadowSize;
|
||||
shadowRect.setBounds (0, 0, (int) x2, h);
|
||||
gradient.point2.x = w * shadowSize;
|
||||
shadowRect.setBounds (0, 0, (int) gradient.point2.x, h);
|
||||
line.setBounds (0, 0, 1, h);
|
||||
break;
|
||||
|
||||
case TabbedButtonBar::TabsAtTop:
|
||||
y1 = (float) h;
|
||||
y2 = h * (1.0f - shadowSize);
|
||||
shadowRect.setBounds (0, (int) y2, w, h - (int) y2);
|
||||
gradient.point1.y = (float) h;
|
||||
gradient.point2.y = h * (1.0f - shadowSize);
|
||||
shadowRect.setBounds (0, (int) gradient.point2.y, w, h - (int) gradient.point2.y);
|
||||
line.setBounds (0, h - 1, w, 1);
|
||||
break;
|
||||
|
||||
case TabbedButtonBar::TabsAtBottom:
|
||||
y2 = h * shadowSize;
|
||||
shadowRect.setBounds (0, 0, w, (int) y2);
|
||||
gradient.point2.y = h * shadowSize;
|
||||
shadowRect.setBounds (0, 0, w, (int) gradient.point2.y);
|
||||
line.setBounds (0, 0, w, 1);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
g.setGradientFill (ColourGradient (Colours::black.withAlpha (tabBar.isEnabled() ? 0.3f : 0.15f), x1, y1,
|
||||
Colours::transparentBlack, x2, y2, false));
|
||||
g.setGradientFill (gradient);
|
||||
g.fillRect (shadowRect.expanded (2, 2));
|
||||
|
||||
g.setColour (Colour (0x80000000));
|
||||
|
|
|
|||
|
|
@ -513,61 +513,16 @@ public:
|
|||
GroupComponent& group);
|
||||
|
||||
//==============================================================================
|
||||
virtual void createTabButtonShape (Path& p,
|
||||
int width, int height,
|
||||
int tabIndex,
|
||||
const String& text,
|
||||
Button& button,
|
||||
TabbedButtonBar::Orientation orientation,
|
||||
bool isMouseOver,
|
||||
bool isMouseDown,
|
||||
bool isFrontTab);
|
||||
|
||||
virtual void fillTabButtonShape (Graphics& g,
|
||||
const Path& path,
|
||||
const Colour& preferredBackgroundColour,
|
||||
int tabIndex,
|
||||
const String& text,
|
||||
Button& button,
|
||||
TabbedButtonBar::Orientation orientation,
|
||||
bool isMouseOver,
|
||||
bool isMouseDown,
|
||||
bool isFrontTab);
|
||||
|
||||
virtual void drawTabButtonText (Graphics& g,
|
||||
int x, int y, int w, int h,
|
||||
const Colour& preferredBackgroundColour,
|
||||
int tabIndex,
|
||||
const String& text,
|
||||
Button& button,
|
||||
TabbedButtonBar::Orientation orientation,
|
||||
bool isMouseOver,
|
||||
bool isMouseDown,
|
||||
bool isFrontTab);
|
||||
|
||||
virtual int getTabButtonOverlap (int tabDepth);
|
||||
virtual int getTabButtonSpaceAroundImage();
|
||||
virtual int getTabButtonOverlap (int tabDepth);
|
||||
virtual int getTabButtonBestWidth (TabBarButton&, int tabDepth);
|
||||
|
||||
virtual int getTabButtonBestWidth (int tabIndex,
|
||||
const String& text,
|
||||
int tabDepth,
|
||||
Button& button);
|
||||
virtual void drawTabButton (TabBarButton&, Graphics& g, bool isMouseOver, bool isMouseDown);
|
||||
virtual void drawTabButtonText (TabBarButton&, Graphics& g, bool isMouseOver, bool isMouseDown);
|
||||
virtual void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics& g, int w, int h);
|
||||
|
||||
virtual void drawTabButton (Graphics& g,
|
||||
int w, int h,
|
||||
const Colour& preferredColour,
|
||||
int tabIndex,
|
||||
const String& text,
|
||||
Button& button,
|
||||
TabbedButtonBar::Orientation orientation,
|
||||
bool isMouseOver,
|
||||
bool isMouseDown,
|
||||
bool isFrontTab);
|
||||
|
||||
virtual void drawTabAreaBehindFrontButton (Graphics& g,
|
||||
int w, int h,
|
||||
TabbedButtonBar& tabBar,
|
||||
TabbedButtonBar::Orientation orientation);
|
||||
virtual void createTabButtonShape (TabBarButton&, Path& path, bool isMouseOver, bool isMouseDown);
|
||||
virtual void fillTabButtonShape (TabBarButton&, Graphics& g, const Path& path, bool isMouseOver, bool isMouseDown);
|
||||
|
||||
virtual Button* createTabBarExtrasButton();
|
||||
|
||||
|
|
@ -673,8 +628,16 @@ private:
|
|||
bool flatOnTop,
|
||||
bool flatOnBottom) noexcept;
|
||||
|
||||
// This has been deprecated - see the new parameter list..
|
||||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
||||
// These methods have been deprecated - see their new parameter lists..
|
||||
virtual int drawFileBrowserRow (Graphics&, int, int, const String&, Image*, const String&, const String&, bool, bool, int) { return 0; }
|
||||
virtual int drawTabButton (Graphics&, int, int, const Colour&, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; }
|
||||
virtual int createTabButtonShape (Path&, int, int, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; }
|
||||
virtual int fillTabButtonShape (Graphics&, const Path&, const Colour&, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; }
|
||||
virtual int drawTabAreaBehindFrontButton (Graphics&, int, int, TabbedButtonBar&, TabbedButtonBar::Orientation) { return 0; }
|
||||
virtual int drawTabButtonText (Graphics&, int, int, int, int, const Colour&, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; }
|
||||
virtual int getTabButtonBestWidth (int, const String&, int, Button&) { return 0; }
|
||||
#endif
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue