Add remaining files
[juce-lv2.git] / juce / source / src / gui / components / menus / juce_MenuBarComponent.cpp
blobd5f81e9feca654538c5b3a76070380d2cde311f6
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../../core/juce_StandardHeader.h"
28 BEGIN_JUCE_NAMESPACE
30 #include "juce_MenuBarComponent.h"
31 #include "../juce_Desktop.h"
32 #include "../lookandfeel/juce_LookAndFeel.h"
35 //==============================================================================
36 MenuBarComponent::MenuBarComponent (MenuBarModel* model_)
37 : model (nullptr),
38 itemUnderMouse (-1),
39 currentPopupIndex (-1),
40 topLevelIndexClicked (0),
41 lastMouseX (0),
42 lastMouseY (0)
44 setRepaintsOnMouseActivity (true);
45 setWantsKeyboardFocus (false);
46 setMouseClickGrabsKeyboardFocus (false);
48 setModel (model_);
51 MenuBarComponent::~MenuBarComponent()
53 setModel (nullptr);
54 Desktop::getInstance().removeGlobalMouseListener (this);
57 MenuBarModel* MenuBarComponent::getModel() const noexcept
59 return model;
62 void MenuBarComponent::setModel (MenuBarModel* const newModel)
64 if (model != newModel)
66 if (model != nullptr)
67 model->removeListener (this);
69 model = newModel;
71 if (model != nullptr)
72 model->addListener (this);
74 repaint();
75 menuBarItemsChanged (nullptr);
79 //==============================================================================
80 void MenuBarComponent::paint (Graphics& g)
82 const bool isMouseOverBar = currentPopupIndex >= 0 || itemUnderMouse >= 0 || isMouseOver();
84 getLookAndFeel().drawMenuBarBackground (g,
85 getWidth(),
86 getHeight(),
87 isMouseOverBar,
88 *this);
90 if (model != nullptr)
92 for (int i = 0; i < menuNames.size(); ++i)
94 Graphics::ScopedSaveState ss (g);
96 g.setOrigin (xPositions [i], 0);
97 g.reduceClipRegion (0, 0, xPositions[i + 1] - xPositions[i], getHeight());
99 getLookAndFeel().drawMenuBarItem (g,
100 xPositions[i + 1] - xPositions[i],
101 getHeight(),
103 menuNames[i],
104 i == itemUnderMouse,
105 i == currentPopupIndex,
106 isMouseOverBar,
107 *this);
112 void MenuBarComponent::resized()
114 xPositions.clear();
115 int x = 0;
116 xPositions.add (x);
118 for (int i = 0; i < menuNames.size(); ++i)
120 x += getLookAndFeel().getMenuBarItemWidth (*this, i, menuNames[i]);
121 xPositions.add (x);
125 int MenuBarComponent::getItemAt (const int x, const int y)
127 for (int i = 0; i < xPositions.size(); ++i)
128 if (x >= xPositions[i] && x < xPositions[i + 1])
129 return reallyContains (Point<int> (x, y), true) ? i : -1;
131 return -1;
134 void MenuBarComponent::repaintMenuItem (int index)
136 if (isPositiveAndBelow (index, xPositions.size()))
138 const int x1 = xPositions [index];
139 const int x2 = xPositions [index + 1];
141 repaint (x1 - 2, 0, x2 - x1 + 4, getHeight());
145 void MenuBarComponent::setItemUnderMouse (const int index)
147 if (itemUnderMouse != index)
149 repaintMenuItem (itemUnderMouse);
150 itemUnderMouse = index;
151 repaintMenuItem (itemUnderMouse);
155 void MenuBarComponent::setOpenItem (int index)
157 if (currentPopupIndex != index)
159 repaintMenuItem (currentPopupIndex);
160 currentPopupIndex = index;
161 repaintMenuItem (currentPopupIndex);
163 if (index >= 0)
164 Desktop::getInstance().addGlobalMouseListener (this);
165 else
166 Desktop::getInstance().removeGlobalMouseListener (this);
170 void MenuBarComponent::updateItemUnderMouse (int x, int y)
172 setItemUnderMouse (getItemAt (x, y));
175 void MenuBarComponent::showMenu (int index)
177 if (index != currentPopupIndex)
179 PopupMenu::dismissAllActiveMenus();
180 menuBarItemsChanged (nullptr);
182 setOpenItem (index);
183 setItemUnderMouse (index);
185 if (index >= 0)
187 PopupMenu m (model->getMenuForIndex (itemUnderMouse,
188 menuNames [itemUnderMouse]));
190 if (m.lookAndFeel == nullptr)
191 m.setLookAndFeel (&getLookAndFeel());
193 const Rectangle<int> itemPos (xPositions [index], 0, xPositions [index + 1] - xPositions [index], getHeight());
195 m.showMenuAsync (PopupMenu::Options().withTargetComponent (this)
196 .withTargetScreenArea (localAreaToGlobal (itemPos))
197 .withMinimumWidth (itemPos.getWidth()),
198 ModalCallbackFunction::forComponent (menuBarMenuDismissedCallback, this, index));
203 void MenuBarComponent::menuBarMenuDismissedCallback (int result, MenuBarComponent* bar, int topLevelIndex)
205 if (bar != nullptr)
206 bar->menuDismissed (topLevelIndex, result);
209 void MenuBarComponent::menuDismissed (int topLevelIndex, int itemId)
211 topLevelIndexClicked = topLevelIndex;
212 postCommandMessage (itemId);
215 void MenuBarComponent::handleCommandMessage (int commandId)
217 const Point<int> mousePos (getMouseXYRelative());
218 updateItemUnderMouse (mousePos.getX(), mousePos.getY());
220 if (currentPopupIndex == topLevelIndexClicked)
221 setOpenItem (-1);
223 if (commandId != 0 && model != nullptr)
224 model->menuItemSelected (commandId, topLevelIndexClicked);
227 //==============================================================================
228 void MenuBarComponent::mouseEnter (const MouseEvent& e)
230 if (e.eventComponent == this)
231 updateItemUnderMouse (e.x, e.y);
234 void MenuBarComponent::mouseExit (const MouseEvent& e)
236 if (e.eventComponent == this)
237 updateItemUnderMouse (e.x, e.y);
240 void MenuBarComponent::mouseDown (const MouseEvent& e)
242 if (currentPopupIndex < 0)
244 const MouseEvent e2 (e.getEventRelativeTo (this));
245 updateItemUnderMouse (e2.x, e2.y);
247 currentPopupIndex = -2;
248 showMenu (itemUnderMouse);
252 void MenuBarComponent::mouseDrag (const MouseEvent& e)
254 const MouseEvent e2 (e.getEventRelativeTo (this));
255 const int item = getItemAt (e2.x, e2.y);
257 if (item >= 0)
258 showMenu (item);
261 void MenuBarComponent::mouseUp (const MouseEvent& e)
263 const MouseEvent e2 (e.getEventRelativeTo (this));
265 updateItemUnderMouse (e2.x, e2.y);
267 if (itemUnderMouse < 0 && getLocalBounds().contains (e2.x, e2.y))
269 setOpenItem (-1);
270 PopupMenu::dismissAllActiveMenus();
274 void MenuBarComponent::mouseMove (const MouseEvent& e)
276 const MouseEvent e2 (e.getEventRelativeTo (this));
278 if (lastMouseX != e2.x || lastMouseY != e2.y)
280 if (currentPopupIndex >= 0)
282 const int item = getItemAt (e2.x, e2.y);
284 if (item >= 0)
285 showMenu (item);
287 else
289 updateItemUnderMouse (e2.x, e2.y);
292 lastMouseX = e2.x;
293 lastMouseY = e2.y;
297 bool MenuBarComponent::keyPressed (const KeyPress& key)
299 bool used = false;
300 const int numMenus = menuNames.size();
301 const int currentIndex = jlimit (0, menuNames.size() - 1, currentPopupIndex);
303 if (key.isKeyCode (KeyPress::leftKey))
305 showMenu ((currentIndex + numMenus - 1) % numMenus);
306 used = true;
308 else if (key.isKeyCode (KeyPress::rightKey))
310 showMenu ((currentIndex + 1) % numMenus);
311 used = true;
314 return used;
317 void MenuBarComponent::menuBarItemsChanged (MenuBarModel* /*menuBarModel*/)
319 StringArray newNames;
321 if (model != nullptr)
322 newNames = model->getMenuBarNames();
324 if (newNames != menuNames)
326 menuNames = newNames;
327 repaint();
328 resized();
332 void MenuBarComponent::menuCommandInvoked (MenuBarModel* /*menuBarModel*/,
333 const ApplicationCommandTarget::InvocationInfo& info)
335 if (model == nullptr || (info.commandFlags & ApplicationCommandInfo::dontTriggerVisualFeedback) != 0)
336 return;
338 for (int i = 0; i < menuNames.size(); ++i)
340 const PopupMenu menu (model->getMenuForIndex (i, menuNames [i]));
342 if (menu.containsCommandItem (info.commandID))
344 setItemUnderMouse (i);
345 startTimer (200);
346 break;
351 void MenuBarComponent::timerCallback()
353 stopTimer();
355 const Point<int> mousePos (getMouseXYRelative());
356 updateItemUnderMouse (mousePos.getX(), mousePos.getY());
360 END_JUCE_NAMESPACE