| @@ -254,12 +254,15 @@ static JuceAppDelegate* juceAppDelegate = 0; | |||
| void MessageManager::runDispatchLoop() | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| if (! quitMessagePosted) // check that the quit message wasn't already posted.. | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| // must only be called by the message thread! | |||
| jassert (isThisTheMessageThread()); | |||
| // must only be called by the message thread! | |||
| jassert (isThisTheMessageThread()); | |||
| [NSApp run]; | |||
| [NSApp run]; | |||
| } | |||
| } | |||
| void MessageManager::stopDispatchLoop() | |||
| @@ -8636,7 +8636,7 @@ public: | |||
| bool isExhausted() throw() | |||
| { | |||
| return pos >= zipEntryInfo.compressedSize; | |||
| return headerSize <= 0 || pos >= zipEntryInfo.compressedSize; | |||
| } | |||
| int64 getPosition() throw() | |||
| @@ -37043,7 +37043,7 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||
| { | |||
| if (MessageManager::instance->currentThreadHasLockedMessageManager()) | |||
| { | |||
| locked = true; // either we're on the message thread, or this it's a re-entrant call. | |||
| locked = true; // either we're on the message thread, or this is a re-entrant call. | |||
| } | |||
| else | |||
| { | |||
| @@ -37422,7 +37422,6 @@ public: | |||
| addTimer (t); | |||
| const ScopedUnlock ul (lock); | |||
| callbackNeeded = false; | |||
| JUCE_TRY | |||
| { | |||
| @@ -44946,7 +44945,8 @@ BEGIN_JUCE_NAMESPACE | |||
| ProgressBar::ProgressBar (double& progress_) | |||
| : progress (progress_), | |||
| displayPercentage (true) | |||
| displayPercentage (true), | |||
| lastCallbackTime (0) | |||
| { | |||
| currentValue = jlimit (0.0, 1.0, progress); | |||
| } | |||
| @@ -45014,9 +45014,14 @@ void ProgressBar::timerCallback() | |||
| { | |||
| if (currentValue < newProgress | |||
| && newProgress >= 0 && newProgress < 1.0 | |||
| && currentValue >= 0 && newProgress < 1.0) | |||
| && currentValue >= 0 && currentValue < 1.0) | |||
| { | |||
| newProgress = jmin (currentValue + 0.02, newProgress); | |||
| const uint32 now = Time::getMillisecondCounter(); | |||
| const int timeSinceLastCallback = (int) (now - lastCallbackTime); | |||
| lastCallbackTime = now; | |||
| newProgress = jmin (currentValue + 0.00018 * timeSinceLastCallback, | |||
| newProgress); | |||
| } | |||
| currentValue = newProgress; | |||
| @@ -51606,7 +51611,8 @@ END_JUCE_NAMESPACE | |||
| BEGIN_JUCE_NAMESPACE | |||
| class TreeViewContentComponent : public Component | |||
| class TreeViewContentComponent : public Component, | |||
| public TooltipClient | |||
| { | |||
| public: | |||
| TreeViewContentComponent (TreeView* const owner_) | |||
| @@ -51868,6 +51874,20 @@ public: | |||
| owner->itemsChanged(); | |||
| } | |||
| const String getTooltip() | |||
| { | |||
| int x, y; | |||
| getMouseXYRelative (x, y); | |||
| Rectangle pos; | |||
| TreeViewItem* const item = findItemAt (y, pos); | |||
| if (item != 0) | |||
| return item->getTooltip(); | |||
| return owner->getTooltip(); | |||
| } | |||
| juce_UseDebuggingNewOperator | |||
| private: | |||
| @@ -52533,6 +52553,11 @@ void TreeViewItem::itemSelectionChanged (bool) | |||
| { | |||
| } | |||
| const String TreeViewItem::getTooltip() | |||
| { | |||
| return String::empty; | |||
| } | |||
| const String TreeViewItem::getDragSourceDescription() | |||
| { | |||
| return String::empty; | |||
| @@ -60487,10 +60512,8 @@ AlertWindow* LookAndFeel::createAlertWindow (const String& title, | |||
| aw->addButton (button1, 1, KeyPress (KeyPress::returnKey, 0, 0), button1ShortCut); | |||
| aw->addButton (button2, 0, KeyPress (KeyPress::escapeKey, 0, 0), button2ShortCut); | |||
| } | |||
| else | |||
| else if (numButtons == 3) | |||
| { | |||
| jassert (numButtons == 3); | |||
| aw->addButton (button1, 1, button1ShortCut); | |||
| aw->addButton (button2, 2, button2ShortCut); | |||
| aw->addButton (button3, 0, KeyPress (KeyPress::escapeKey, 0, 0)); | |||
| @@ -61571,7 +61594,7 @@ ImageEffectFilter* LookAndFeel::getSliderEffect() | |||
| static const TextLayout layoutTooltipText (const String& text) throw() | |||
| { | |||
| const float tooltipFontSize = 15.0f; | |||
| const float tooltipFontSize = 12.0f; | |||
| const int maxToolTipWidth = 400; | |||
| const Font f (tooltipFontSize, Font::bold); | |||
| @@ -61586,7 +61609,7 @@ void LookAndFeel::getTooltipSize (const String& tipText, int& width, int& height | |||
| const TextLayout tl (layoutTooltipText (tipText)); | |||
| width = tl.getWidth() + 14; | |||
| height = tl.getHeight() + 10; | |||
| height = tl.getHeight() + 6; | |||
| } | |||
| void LookAndFeel::drawTooltip (Graphics& g, const String& text, int width, int height) | |||
| @@ -61595,8 +61618,10 @@ void LookAndFeel::drawTooltip (Graphics& g, const String& text, int width, int h | |||
| const Colour textCol (findColour (TooltipWindow::textColourId)); | |||
| #if ! JUCE_MAC // The mac windows already have a non-optional 1 pix outline, so don't double it here.. | |||
| g.setColour (findColour (TooltipWindow::outlineColourId)); | |||
| g.drawRect (0, 0, width, height); | |||
| g.drawRect (0, 0, width, height, 1); | |||
| #endif | |||
| const TextLayout tl (layoutTooltipText (text)); | |||
| @@ -72476,10 +72501,9 @@ bool ComponentPeer::handleKeyPress (const int keyCode, | |||
| if (keyInfo.isKeyCode (KeyPress::tabKey) && Component::getCurrentlyFocusedComponent() != 0) | |||
| { | |||
| Component::getCurrentlyFocusedComponent() | |||
| ->moveKeyboardFocusToSibling (! keyInfo.getModifiers().isShiftDown()); | |||
| keyWasUsed = true; | |||
| Component* const currentlyFocused = Component::getCurrentlyFocusedComponent(); | |||
| currentlyFocused->moveKeyboardFocusToSibling (! keyInfo.getModifiers().isShiftDown()); | |||
| keyWasUsed = (currentlyFocused != Component::getCurrentlyFocusedComponent()); | |||
| break; | |||
| } | |||
| @@ -73869,14 +73893,12 @@ ThreadWithProgressWindow::ThreadWithProgressWindow (const String& title, | |||
| timeOutMsWhenCancelling (timeOutMsWhenCancelling_) | |||
| { | |||
| alertWindow = LookAndFeel::getDefaultLookAndFeel() | |||
| .createAlertWindow (title, String::empty, cancelButtonText, String::empty, String::empty, | |||
| AlertWindow::NoIcon, 1, 0); | |||
| .createAlertWindow (title, String::empty, cancelButtonText, | |||
| String::empty, String::empty, | |||
| AlertWindow::NoIcon, hasCancelButton ? 1 : 0, 0); | |||
| if (hasProgressBar) | |||
| alertWindow->addProgressBarComponent (progress); | |||
| if (hasCancelButton) | |||
| alertWindow->addButton (cancelButtonText, 1); | |||
| } | |||
| ThreadWithProgressWindow::~ThreadWithProgressWindow() | |||
| @@ -73895,13 +73917,13 @@ bool ThreadWithProgressWindow::runThread (const int priority) | |||
| alertWindow->setMessage (message); | |||
| } | |||
| const bool wasCancelled = alertWindow->runModalLoop() != 0; | |||
| const bool finishedNaturally = alertWindow->runModalLoop() != 0; | |||
| stopThread (timeOutMsWhenCancelling); | |||
| alertWindow->setVisible (false); | |||
| return ! wasCancelled; | |||
| return finishedNaturally; | |||
| } | |||
| void ThreadWithProgressWindow::setProgress (const double newProgress) | |||
| @@ -73920,7 +73942,7 @@ void ThreadWithProgressWindow::timerCallback() | |||
| if (! isThreadRunning()) | |||
| { | |||
| // thread has finished normally.. | |||
| alertWindow->exitModalState (0); | |||
| alertWindow->exitModalState (1); | |||
| alertWindow->setVisible (false); | |||
| } | |||
| else | |||
| @@ -73943,7 +73965,6 @@ TooltipWindow::TooltipWindow (Component* const parentComponent, | |||
| millisecondsBeforeTipAppears (millisecondsBeforeTipAppears_), | |||
| mouseX (0), | |||
| mouseY (0), | |||
| lastMouseMoveTime (0), | |||
| lastHideTime (0), | |||
| lastComponentUnderMouse (0), | |||
| changedCompsSinceShown (true) | |||
| @@ -73964,7 +73985,7 @@ TooltipWindow::~TooltipWindow() | |||
| void TooltipWindow::paint (Graphics& g) | |||
| { | |||
| getLookAndFeel().drawTooltip (g, tip, getWidth(), getHeight()); | |||
| getLookAndFeel().drawTooltip (g, tipShowing, getWidth(), getHeight()); | |||
| } | |||
| void TooltipWindow::mouseEnter (const MouseEvent&) | |||
| @@ -73972,104 +73993,113 @@ void TooltipWindow::mouseEnter (const MouseEvent&) | |||
| hide(); | |||
| } | |||
| void TooltipWindow::showFor (Component* const c) | |||
| void TooltipWindow::showFor (Component* const c, const String& tip) | |||
| { | |||
| TooltipClient* const ttc = dynamic_cast <TooltipClient*> (c); | |||
| jassert (tip.isNotEmpty()); | |||
| tipShowing = tip; | |||
| if (ttc != 0 && ! c->isCurrentlyBlockedByAnotherModalComponent()) | |||
| tip = ttc->getTooltip(); | |||
| else | |||
| tip = String::empty; | |||
| int mx, my; | |||
| Desktop::getMousePosition (mx, my); | |||
| if (tip.isEmpty()) | |||
| { | |||
| hide(); | |||
| } | |||
| else | |||
| { | |||
| int mx, my; | |||
| Desktop::getMousePosition (mx, my); | |||
| if (getParentComponent() != 0) | |||
| getParentComponent()->globalPositionToRelative (mx, my); | |||
| if (getParentComponent() != 0) | |||
| getParentComponent()->globalPositionToRelative (mx, my); | |||
| int x, y, w, h; | |||
| getLookAndFeel().getTooltipSize (tip, w, h); | |||
| int x, y, w, h; | |||
| getLookAndFeel().getTooltipSize (tip, w, h); | |||
| if (mx > getParentWidth() / 2) | |||
| x = mx - (w + 12); | |||
| else | |||
| x = mx + 24; | |||
| if (mx > getParentWidth() / 2) | |||
| x = mx - (w + 12); | |||
| else | |||
| x = mx + 24; | |||
| if (my > getParentHeight() / 2) | |||
| y = my - (h + 6); | |||
| else | |||
| y = my + 6; | |||
| if (my > getParentHeight() / 2) | |||
| y = my - (h + 6); | |||
| else | |||
| y = my + 6; | |||
| setBounds (x, y, w, h); | |||
| setVisible (true); | |||
| setBounds (x, y, w, h); | |||
| setVisible (true); | |||
| if (getParentComponent() == 0) | |||
| { | |||
| addToDesktop (ComponentPeer::windowHasDropShadow | |||
| | ComponentPeer::windowIsTemporary); | |||
| } | |||
| if (getParentComponent() == 0) | |||
| { | |||
| addToDesktop (ComponentPeer::windowHasDropShadow | |||
| | ComponentPeer::windowIsTemporary); | |||
| } | |||
| toFront (false); | |||
| } | |||
| toFront (false); | |||
| const String TooltipWindow::getTipFor (Component* const c) | |||
| { | |||
| if (c->isValidComponent() && Process::isForegroundProcess()) | |||
| { | |||
| TooltipClient* const ttc = dynamic_cast <TooltipClient*> (c); | |||
| if (ttc != 0 && ! c->isCurrentlyBlockedByAnotherModalComponent()) | |||
| return ttc->getTooltip(); | |||
| } | |||
| return String::empty; | |||
| } | |||
| void TooltipWindow::hide() | |||
| { | |||
| tipShowing = String::empty; | |||
| removeFromDesktop(); | |||
| setVisible (false); | |||
| } | |||
| void TooltipWindow::timerCallback() | |||
| { | |||
| const unsigned int now = Time::getApproximateMillisecondCounter(); | |||
| Component* const newComp = Component::getComponentUnderMouse(); | |||
| const String newTip (getTipFor (newComp)); | |||
| const bool tipChanged = (newTip != lastTipUnderMouse || newComp != lastComponentUnderMouse); | |||
| lastComponentUnderMouse = newComp; | |||
| lastTipUnderMouse = newTip; | |||
| const int clickCount = Desktop::getInstance().getMouseButtonClickCounter(); | |||
| const bool mouseWasClicked = clickCount > mouseClicks; | |||
| mouseClicks = clickCount; | |||
| int mx, my; | |||
| Desktop::getMousePosition (mx, my); | |||
| const bool mouseMovedQuickly = (abs (mx - mouseX) + abs (my - mouseY) > 12); | |||
| mouseX = mx; | |||
| mouseY = my; | |||
| const unsigned int now = Time::getApproximateMillisecondCounter(); | |||
| Component* const underMouse = Component::getComponentUnderMouse(); | |||
| const bool changedComp = (underMouse != lastComponentUnderMouse); | |||
| lastComponentUnderMouse = underMouse; | |||
| if (tipChanged || mouseWasClicked || mouseMovedQuickly) | |||
| lastCompChangeTime = now; | |||
| if (changedComp | |||
| || abs (mx - mouseX) > 4 | |||
| || abs (my - mouseY) > 4 | |||
| || Desktop::getInstance().getMouseButtonClickCounter() > mouseClicks) | |||
| if (isVisible() || now < lastHideTime + 500) | |||
| { | |||
| lastMouseMoveTime = now; | |||
| if (isVisible()) | |||
| // if a tip is currently visible (or has just disappeared), update to a new one | |||
| // immediately if needed.. | |||
| if (newComp == 0 || mouseWasClicked || newTip.isEmpty()) | |||
| { | |||
| lastHideTime = now; | |||
| hide(); | |||
| if (isVisible()) | |||
| { | |||
| lastHideTime = now; | |||
| hide(); | |||
| } | |||
| } | |||
| else if (tipChanged) | |||
| { | |||
| showFor (newComp, newTip); | |||
| } | |||
| changedCompsSinceShown = changedCompsSinceShown || changedComp; | |||
| tip = String::empty; | |||
| mouseX = mx; | |||
| mouseY = my; | |||
| } | |||
| if (changedCompsSinceShown) | |||
| else | |||
| { | |||
| if ((now > lastMouseMoveTime + millisecondsBeforeTipAppears | |||
| || now < lastHideTime + 500) | |||
| && ! isVisible()) | |||
| // if there isn't currently a tip, but one is needed, only let it | |||
| // appear after a timeout.. | |||
| if (newTip.isNotEmpty() | |||
| && newTip != tipShowing | |||
| && now > lastCompChangeTime + millisecondsBeforeTipAppears) | |||
| { | |||
| if (underMouse->isValidComponent()) | |||
| showFor (underMouse); | |||
| changedCompsSinceShown = false; | |||
| showFor (newComp, newTip); | |||
| } | |||
| } | |||
| mouseClicks = Desktop::getInstance().getMouseButtonClickCounter(); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -270323,12 +270353,15 @@ static JuceAppDelegate* juceAppDelegate = 0; | |||
| void MessageManager::runDispatchLoop() | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| if (! quitMessagePosted) // check that the quit message wasn't already posted.. | |||
| { | |||
| const ScopedAutoReleasePool pool; | |||
| // must only be called by the message thread! | |||
| jassert (isThisTheMessageThread()); | |||
| // must only be called by the message thread! | |||
| jassert (isThisTheMessageThread()); | |||
| [NSApp run]; | |||
| [NSApp run]; | |||
| } | |||
| } | |||
| void MessageManager::stopDispatchLoop() | |||
| @@ -29942,16 +29942,17 @@ private: | |||
| const int millisecondsBeforeTipAppears; | |||
| int mouseX, mouseY, mouseClicks; | |||
| unsigned int lastMouseMoveTime, lastHideTime; | |||
| unsigned int lastCompChangeTime, lastHideTime; | |||
| Component* lastComponentUnderMouse; | |||
| bool changedCompsSinceShown; | |||
| String tip; | |||
| String tipShowing, lastTipUnderMouse; | |||
| void paint (Graphics& g); | |||
| void mouseEnter (const MouseEvent& e); | |||
| void timerCallback(); | |||
| void showFor (Component* const c); | |||
| static const String getTipFor (Component* const c); | |||
| void showFor (Component* const c, const String& tip); | |||
| void hide(); | |||
| TooltipWindow (const TooltipWindow&); | |||
| @@ -43355,6 +43356,11 @@ public: | |||
| */ | |||
| virtual void itemSelectionChanged (bool isNowSelected); | |||
| /** The item can return a tool tip string here if it wants to. | |||
| @see TooltipClient | |||
| */ | |||
| virtual const String getTooltip(); | |||
| /** To allow items from your treeview to be dragged-and-dropped, implement this method. | |||
| If this returns a non-empty name then when the user drags an item, the treeview will | |||
| @@ -45947,6 +45953,7 @@ private: | |||
| double currentValue; | |||
| bool displayPercentage; | |||
| String displayedMessage, currentMessage; | |||
| uint32 lastCallbackTime; | |||
| void timerCallback(); | |||
| @@ -278,7 +278,7 @@ void MessageManagerLock::init (Thread* const threadToCheck, ThreadPoolJob* const | |||
| { | |||
| if (MessageManager::instance->currentThreadHasLockedMessageManager()) | |||
| { | |||
| locked = true; // either we're on the message thread, or this it's a re-entrant call. | |||
| locked = true; // either we're on the message thread, or this is a re-entrant call. | |||
| } | |||
| else | |||
| { | |||
| @@ -247,7 +247,6 @@ public: | |||
| addTimer (t); | |||
| const ScopedUnlock ul (lock); | |||
| callbackNeeded = false; | |||
| JUCE_TRY | |||
| { | |||
| @@ -40,7 +40,8 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| ProgressBar::ProgressBar (double& progress_) | |||
| : progress (progress_), | |||
| displayPercentage (true) | |||
| displayPercentage (true), | |||
| lastCallbackTime (0) | |||
| { | |||
| currentValue = jlimit (0.0, 1.0, progress); | |||
| } | |||
| @@ -109,9 +110,14 @@ void ProgressBar::timerCallback() | |||
| { | |||
| if (currentValue < newProgress | |||
| && newProgress >= 0 && newProgress < 1.0 | |||
| && currentValue >= 0 && newProgress < 1.0) | |||
| && currentValue >= 0 && currentValue < 1.0) | |||
| { | |||
| newProgress = jmin (currentValue + 0.02, newProgress); | |||
| const uint32 now = Time::getMillisecondCounter(); | |||
| const int timeSinceLastCallback = (int) (now - lastCallbackTime); | |||
| lastCallbackTime = now; | |||
| newProgress = jmin (currentValue + 0.00018 * timeSinceLastCallback, | |||
| newProgress); | |||
| } | |||
| currentValue = newProgress; | |||
| @@ -119,6 +119,7 @@ private: | |||
| double currentValue; | |||
| bool displayPercentage; | |||
| String displayedMessage, currentMessage; | |||
| uint32 lastCallbackTime; | |||
| void timerCallback(); | |||
| @@ -41,7 +41,8 @@ BEGIN_JUCE_NAMESPACE | |||
| //============================================================================== | |||
| class TreeViewContentComponent : public Component | |||
| class TreeViewContentComponent : public Component, | |||
| public TooltipClient | |||
| { | |||
| public: | |||
| TreeViewContentComponent (TreeView* const owner_) | |||
| @@ -303,6 +304,20 @@ public: | |||
| owner->itemsChanged(); | |||
| } | |||
| const String getTooltip() | |||
| { | |||
| int x, y; | |||
| getMouseXYRelative (x, y); | |||
| Rectangle pos; | |||
| TreeViewItem* const item = findItemAt (y, pos); | |||
| if (item != 0) | |||
| return item->getTooltip(); | |||
| return owner->getTooltip(); | |||
| } | |||
| //============================================================================== | |||
| juce_UseDebuggingNewOperator | |||
| @@ -980,6 +995,11 @@ void TreeViewItem::itemSelectionChanged (bool) | |||
| { | |||
| } | |||
| const String TreeViewItem::getTooltip() | |||
| { | |||
| return String::empty; | |||
| } | |||
| const String TreeViewItem::getDragSourceDescription() | |||
| { | |||
| return String::empty; | |||
| @@ -337,6 +337,11 @@ public: | |||
| */ | |||
| virtual void itemSelectionChanged (bool isNowSelected); | |||
| /** The item can return a tool tip string here if it wants to. | |||
| @see TooltipClient | |||
| */ | |||
| virtual const String getTooltip(); | |||
| /** To allow items from your treeview to be dragged-and-dropped, implement this method. | |||
| If this returns a non-empty name then when the user drags an item, the treeview will | |||
| @@ -495,10 +495,8 @@ AlertWindow* LookAndFeel::createAlertWindow (const String& title, | |||
| aw->addButton (button1, 1, KeyPress (KeyPress::returnKey, 0, 0), button1ShortCut); | |||
| aw->addButton (button2, 0, KeyPress (KeyPress::escapeKey, 0, 0), button2ShortCut); | |||
| } | |||
| else | |||
| else if (numButtons == 3) | |||
| { | |||
| jassert (numButtons == 3); | |||
| aw->addButton (button1, 1, button1ShortCut); | |||
| aw->addButton (button2, 2, button2ShortCut); | |||
| aw->addButton (button3, 0, KeyPress (KeyPress::escapeKey, 0, 0)); | |||
| @@ -1591,7 +1589,7 @@ ImageEffectFilter* LookAndFeel::getSliderEffect() | |||
| //============================================================================== | |||
| static const TextLayout layoutTooltipText (const String& text) throw() | |||
| { | |||
| const float tooltipFontSize = 15.0f; | |||
| const float tooltipFontSize = 12.0f; | |||
| const int maxToolTipWidth = 400; | |||
| const Font f (tooltipFontSize, Font::bold); | |||
| @@ -1606,7 +1604,7 @@ void LookAndFeel::getTooltipSize (const String& tipText, int& width, int& height | |||
| const TextLayout tl (layoutTooltipText (tipText)); | |||
| width = tl.getWidth() + 14; | |||
| height = tl.getHeight() + 10; | |||
| height = tl.getHeight() + 6; | |||
| } | |||
| void LookAndFeel::drawTooltip (Graphics& g, const String& text, int width, int height) | |||
| @@ -1615,8 +1613,10 @@ void LookAndFeel::drawTooltip (Graphics& g, const String& text, int width, int h | |||
| const Colour textCol (findColour (TooltipWindow::textColourId)); | |||
| #if ! JUCE_MAC // The mac windows already have a non-optional 1 pix outline, so don't double it here.. | |||
| g.setColour (findColour (TooltipWindow::outlineColourId)); | |||
| g.drawRect (0, 0, width, height); | |||
| g.drawRect (0, 0, width, height, 1); | |||
| #endif | |||
| const TextLayout tl (layoutTooltipText (text)); | |||
| @@ -461,13 +461,12 @@ bool ComponentPeer::handleKeyPress (const int keyCode, | |||
| if (keyInfo.isKeyCode (KeyPress::tabKey) && Component::getCurrentlyFocusedComponent() != 0) | |||
| { | |||
| Component::getCurrentlyFocusedComponent() | |||
| ->moveKeyboardFocusToSibling (! keyInfo.getModifiers().isShiftDown()); | |||
| keyWasUsed = true; | |||
| Component* const currentlyFocused = Component::getCurrentlyFocusedComponent(); | |||
| currentlyFocused->moveKeyboardFocusToSibling (! keyInfo.getModifiers().isShiftDown()); | |||
| keyWasUsed = (currentlyFocused != Component::getCurrentlyFocusedComponent()); | |||
| break; | |||
| } | |||
| target = target->parentComponent_; | |||
| } | |||
| @@ -50,14 +50,12 @@ ThreadWithProgressWindow::ThreadWithProgressWindow (const String& title, | |||
| timeOutMsWhenCancelling (timeOutMsWhenCancelling_) | |||
| { | |||
| alertWindow = LookAndFeel::getDefaultLookAndFeel() | |||
| .createAlertWindow (title, String::empty, cancelButtonText, String::empty, String::empty, | |||
| AlertWindow::NoIcon, 1, 0); | |||
| .createAlertWindow (title, String::empty, cancelButtonText, | |||
| String::empty, String::empty, | |||
| AlertWindow::NoIcon, hasCancelButton ? 1 : 0, 0); | |||
| if (hasProgressBar) | |||
| alertWindow->addProgressBarComponent (progress); | |||
| if (hasCancelButton) | |||
| alertWindow->addButton (cancelButtonText, 1); | |||
| } | |||
| ThreadWithProgressWindow::~ThreadWithProgressWindow() | |||
| @@ -76,13 +74,13 @@ bool ThreadWithProgressWindow::runThread (const int priority) | |||
| alertWindow->setMessage (message); | |||
| } | |||
| const bool wasCancelled = alertWindow->runModalLoop() != 0; | |||
| const bool finishedNaturally = alertWindow->runModalLoop() != 0; | |||
| stopThread (timeOutMsWhenCancelling); | |||
| alertWindow->setVisible (false); | |||
| return ! wasCancelled; | |||
| return finishedNaturally; | |||
| } | |||
| void ThreadWithProgressWindow::setProgress (const double newProgress) | |||
| @@ -101,7 +99,7 @@ void ThreadWithProgressWindow::timerCallback() | |||
| if (! isThreadRunning()) | |||
| { | |||
| // thread has finished normally.. | |||
| alertWindow->exitModalState (0); | |||
| alertWindow->exitModalState (1); | |||
| alertWindow->setVisible (false); | |||
| } | |||
| else | |||
| @@ -36,6 +36,7 @@ BEGIN_JUCE_NAMESPACE | |||
| #include "juce_TooltipWindow.h" | |||
| #include "../../../../juce_core/basics/juce_Time.h" | |||
| #include "../../../../juce_core/threads/juce_Process.h" | |||
| #include "../lookandfeel/juce_LookAndFeel.h" | |||
| #include "../juce_Desktop.h" | |||
| @@ -47,7 +48,6 @@ TooltipWindow::TooltipWindow (Component* const parentComponent, | |||
| millisecondsBeforeTipAppears (millisecondsBeforeTipAppears_), | |||
| mouseX (0), | |||
| mouseY (0), | |||
| lastMouseMoveTime (0), | |||
| lastHideTime (0), | |||
| lastComponentUnderMouse (0), | |||
| changedCompsSinceShown (true) | |||
| @@ -68,7 +68,7 @@ TooltipWindow::~TooltipWindow() | |||
| void TooltipWindow::paint (Graphics& g) | |||
| { | |||
| getLookAndFeel().drawTooltip (g, tip, getWidth(), getHeight()); | |||
| getLookAndFeel().drawTooltip (g, tipShowing, getWidth(), getHeight()); | |||
| } | |||
| void TooltipWindow::mouseEnter (const MouseEvent&) | |||
| @@ -76,104 +76,113 @@ void TooltipWindow::mouseEnter (const MouseEvent&) | |||
| hide(); | |||
| } | |||
| void TooltipWindow::showFor (Component* const c) | |||
| void TooltipWindow::showFor (Component* const c, const String& tip) | |||
| { | |||
| TooltipClient* const ttc = dynamic_cast <TooltipClient*> (c); | |||
| jassert (tip.isNotEmpty()); | |||
| tipShowing = tip; | |||
| int mx, my; | |||
| Desktop::getMousePosition (mx, my); | |||
| if (ttc != 0 && ! c->isCurrentlyBlockedByAnotherModalComponent()) | |||
| tip = ttc->getTooltip(); | |||
| else | |||
| tip = String::empty; | |||
| if (getParentComponent() != 0) | |||
| getParentComponent()->globalPositionToRelative (mx, my); | |||
| if (tip.isEmpty()) | |||
| { | |||
| hide(); | |||
| } | |||
| else | |||
| { | |||
| int mx, my; | |||
| Desktop::getMousePosition (mx, my); | |||
| int x, y, w, h; | |||
| getLookAndFeel().getTooltipSize (tip, w, h); | |||
| if (getParentComponent() != 0) | |||
| getParentComponent()->globalPositionToRelative (mx, my); | |||
| if (mx > getParentWidth() / 2) | |||
| x = mx - (w + 12); | |||
| else | |||
| x = mx + 24; | |||
| int x, y, w, h; | |||
| getLookAndFeel().getTooltipSize (tip, w, h); | |||
| if (my > getParentHeight() / 2) | |||
| y = my - (h + 6); | |||
| else | |||
| y = my + 6; | |||
| if (mx > getParentWidth() / 2) | |||
| x = mx - (w + 12); | |||
| else | |||
| x = mx + 24; | |||
| setBounds (x, y, w, h); | |||
| setVisible (true); | |||
| if (my > getParentHeight() / 2) | |||
| y = my - (h + 6); | |||
| else | |||
| y = my + 6; | |||
| if (getParentComponent() == 0) | |||
| { | |||
| addToDesktop (ComponentPeer::windowHasDropShadow | |||
| | ComponentPeer::windowIsTemporary); | |||
| } | |||
| setBounds (x, y, w, h); | |||
| setVisible (true); | |||
| toFront (false); | |||
| } | |||
| if (getParentComponent() == 0) | |||
| { | |||
| addToDesktop (ComponentPeer::windowHasDropShadow | |||
| | ComponentPeer::windowIsTemporary); | |||
| } | |||
| const String TooltipWindow::getTipFor (Component* const c) | |||
| { | |||
| if (c->isValidComponent() && Process::isForegroundProcess()) | |||
| { | |||
| TooltipClient* const ttc = dynamic_cast <TooltipClient*> (c); | |||
| toFront (false); | |||
| if (ttc != 0 && ! c->isCurrentlyBlockedByAnotherModalComponent()) | |||
| return ttc->getTooltip(); | |||
| } | |||
| return String::empty; | |||
| } | |||
| void TooltipWindow::hide() | |||
| { | |||
| tipShowing = String::empty; | |||
| removeFromDesktop(); | |||
| setVisible (false); | |||
| } | |||
| void TooltipWindow::timerCallback() | |||
| { | |||
| const unsigned int now = Time::getApproximateMillisecondCounter(); | |||
| Component* const newComp = Component::getComponentUnderMouse(); | |||
| const String newTip (getTipFor (newComp)); | |||
| const bool tipChanged = (newTip != lastTipUnderMouse || newComp != lastComponentUnderMouse); | |||
| lastComponentUnderMouse = newComp; | |||
| lastTipUnderMouse = newTip; | |||
| const int clickCount = Desktop::getInstance().getMouseButtonClickCounter(); | |||
| const bool mouseWasClicked = clickCount > mouseClicks; | |||
| mouseClicks = clickCount; | |||
| int mx, my; | |||
| Desktop::getMousePosition (mx, my); | |||
| const bool mouseMovedQuickly = (abs (mx - mouseX) + abs (my - mouseY) > 12); | |||
| mouseX = mx; | |||
| mouseY = my; | |||
| const unsigned int now = Time::getApproximateMillisecondCounter(); | |||
| Component* const underMouse = Component::getComponentUnderMouse(); | |||
| const bool changedComp = (underMouse != lastComponentUnderMouse); | |||
| lastComponentUnderMouse = underMouse; | |||
| if (changedComp | |||
| || abs (mx - mouseX) > 4 | |||
| || abs (my - mouseY) > 4 | |||
| || Desktop::getInstance().getMouseButtonClickCounter() > mouseClicks) | |||
| { | |||
| lastMouseMoveTime = now; | |||
| if (tipChanged || mouseWasClicked || mouseMovedQuickly) | |||
| lastCompChangeTime = now; | |||
| if (isVisible()) | |||
| if (isVisible() || now < lastHideTime + 500) | |||
| { | |||
| // if a tip is currently visible (or has just disappeared), update to a new one | |||
| // immediately if needed.. | |||
| if (newComp == 0 || mouseWasClicked || newTip.isEmpty()) | |||
| { | |||
| lastHideTime = now; | |||
| hide(); | |||
| if (isVisible()) | |||
| { | |||
| lastHideTime = now; | |||
| hide(); | |||
| } | |||
| } | |||
| else if (tipChanged) | |||
| { | |||
| showFor (newComp, newTip); | |||
| } | |||
| changedCompsSinceShown = changedCompsSinceShown || changedComp; | |||
| tip = String::empty; | |||
| mouseX = mx; | |||
| mouseY = my; | |||
| } | |||
| if (changedCompsSinceShown) | |||
| else | |||
| { | |||
| if ((now > lastMouseMoveTime + millisecondsBeforeTipAppears | |||
| || now < lastHideTime + 500) | |||
| && ! isVisible()) | |||
| // if there isn't currently a tip, but one is needed, only let it | |||
| // appear after a timeout.. | |||
| if (newTip.isNotEmpty() | |||
| && newTip != tipShowing | |||
| && now > lastCompChangeTime + millisecondsBeforeTipAppears) | |||
| { | |||
| if (underMouse->isValidComponent()) | |||
| showFor (underMouse); | |||
| changedCompsSinceShown = false; | |||
| showFor (newComp, newTip); | |||
| } | |||
| } | |||
| mouseClicks = Desktop::getInstance().getMouseButtonClickCounter(); | |||
| } | |||
| END_JUCE_NAMESPACE | |||
| @@ -101,16 +101,17 @@ private: | |||
| //============================================================================== | |||
| const int millisecondsBeforeTipAppears; | |||
| int mouseX, mouseY, mouseClicks; | |||
| unsigned int lastMouseMoveTime, lastHideTime; | |||
| unsigned int lastCompChangeTime, lastHideTime; | |||
| Component* lastComponentUnderMouse; | |||
| bool changedCompsSinceShown; | |||
| String tip; | |||
| String tipShowing, lastTipUnderMouse; | |||
| void paint (Graphics& g); | |||
| void mouseEnter (const MouseEvent& e); | |||
| void timerCallback(); | |||
| void showFor (Component* const c); | |||
| static const String getTipFor (Component* const c); | |||
| void showFor (Component* const c, const String& tip); | |||
| void hide(); | |||
| TooltipWindow (const TooltipWindow&); | |||
| @@ -137,7 +137,7 @@ public: | |||
| bool isExhausted() throw() | |||
| { | |||
| return pos >= zipEntryInfo.compressedSize; | |||
| return headerSize <= 0 || pos >= zipEntryInfo.compressedSize; | |||
| } | |||
| int64 getPosition() throw() | |||