Skip to content

Commit 65190b3

Browse files
committed
Store "keyboard focus" in settings. Fix focus edge cases.
1 parent ddd7e2a commit 65190b3

File tree

4 files changed

+49
-19
lines changed

4 files changed

+49
-19
lines changed

melatonin/component_model.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#pragma once
22

33
#include <utility>
4-
4+
#include "helpers/component_helpers.h"
55
#include "juce_gui_basics/juce_gui_basics.h"
66

77
namespace melatonin

melatonin/helpers/overlay_mouse_listener.h

+8-3
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,19 @@ namespace melatonin
3636

3737
void enable()
3838
{
39+
// replace me with an if condition if you are hitting this on purpose
40+
jassert (!enabled);
3941
enabled = true;
4042
root->addMouseListener (this, true);
4143
}
4244

4345
void disable()
4446
{
45-
enabled = false;
46-
root->removeMouseListener (this);
47+
if (enabled)
48+
{
49+
enabled = false;
50+
root->removeMouseListener (this);
51+
}
4752
}
4853

4954
void mouseEnter (const juce::MouseEvent& event) override
@@ -95,7 +100,7 @@ namespace melatonin
95100
}
96101

97102
// not sure if there's a better way to ask "is the mouse outside the plugin now?"
98-
if (!root->contains(event.getEventRelativeTo(root).position))
103+
if (!root->contains (event.getEventRelativeTo (root).position))
99104
outlineComponentCallback (nullptr);
100105
}
101106

melatonin/inspector_component.h

+12-9
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
#include "components/inspector_image_button.h"
44
#include "helpers/misc.h"
5+
#include "melatonin_inspector/melatonin/components/accesibility.h"
56
#include "melatonin_inspector/melatonin/components/box_model.h"
67
#include "melatonin_inspector/melatonin/components/color_picker.h"
78
#include "melatonin_inspector/melatonin/components/component_tree_view_item.h"
89
#include "melatonin_inspector/melatonin/components/preview.h"
910
#include "melatonin_inspector/melatonin/components/properties.h"
10-
#include "melatonin_inspector/melatonin/components/accesibility.h"
1111
#include "melatonin_inspector/melatonin/lookandfeel.h"
1212

1313
/*
@@ -86,8 +86,7 @@ namespace melatonin
8686
searchBox.setColour (juce::TextEditor::focusedOutlineColourId, juce::Colours::transparentBlack);
8787
searchBox.setTextToShowWhenEmpty ("Filter components...", colors::searchText);
8888
searchBox.setJustification (juce::Justification::centredLeft);
89-
searchBox.onEscapeKey = [&]
90-
{
89+
searchBox.onEscapeKey = [&] {
9190
searchBox.setText ("");
9291
searchBox.giveAwayKeyboardFocus();
9392
lastSearchText = {};
@@ -99,7 +98,7 @@ namespace melatonin
9998
auto searchText = searchBox.getText();
10099
ensureTreeIsConstructed();
101100

102-
if ( lastSearchText.isNotEmpty() && ! searchText.startsWith ( lastSearchText ) )
101+
if (lastSearchText.isNotEmpty() && !searchText.startsWith (lastSearchText))
103102
{
104103
getRoot()->validateSubItems();
105104
}
@@ -136,8 +135,10 @@ namespace melatonin
136135
toggleCallback (!inspectorEnabled);
137136
};
138137

138+
// TODO: refactor this "on" state, it's terribly named
139139
fpsToggle.on = false;
140140
fpsToggle.onClick = [this] {
141+
// TODO: I don't like that the "on" state implicitly was toggled here
141142
settings->props->setValue ("fpsEnabled", fpsToggle.on);
142143
toggleFPSCallback (fpsToggle.on);
143144
};
@@ -147,9 +148,11 @@ namespace melatonin
147148
searchBox.giveAwayKeyboardFocus();
148149
};
149150

150-
tabToggle.on = false;
151+
// TODO: sorta sketchy to "know" the enum default...
152+
tabToggle.on = settings->props->getIntValue ("selectionMode", 0);
151153
tabToggle.onClick = [this] {
152-
toggleSelectionMode(tabToggle.on);
154+
settings->props->setValue ("selectionMode", fpsToggle.on);
155+
toggleSelectionMode (tabToggle.on);
153156
};
154157

155158
// the tree view is empty even if inspector is enabled
@@ -263,7 +266,7 @@ namespace melatonin
263266
colorPickerPanel.setBounds (colorPickerBounds.removeFromTop (32).removeFromLeft (200));
264267

265268
accessibilityPanel.setBounds (mainCol.removeFromTop (32));
266-
accessibility.setBounds (mainCol.removeFromTop (accessibility.isVisible() ? 110 : 0).withTrimmedLeft(32));
269+
accessibility.setBounds (mainCol.removeFromTop (accessibility.isVisible() ? 110 : 0).withTrimmedLeft (32));
267270

268271
propertiesPanel.setBounds (mainCol.removeFromTop (33)); // extra pixel for divider
269272
properties.setBounds (mainCol.withTrimmedLeft (32));
@@ -281,7 +284,7 @@ namespace melatonin
281284
tree.setBounds (treeViewBounds);
282285
}
283286

284-
void displayComponentInfo (Component* component, bool collapseTreeBeforeSelection=false)
287+
void displayComponentInfo (Component* component, bool collapseTreeBeforeSelection = false)
285288
{
286289
TRACE_COMPONENT();
287290

@@ -315,7 +318,7 @@ namespace melatonin
315318
}
316319
}
317320

318-
void selectComponent (Component* component, bool collapseTreeBeforeSelection=false)
321+
void selectComponent (Component* component, bool collapseTreeBeforeSelection = false)
319322
{
320323
TRACE_COMPONENT();
321324

melatonin_inspector.h

+28-6
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ namespace melatonin
8686
setupCallbacks();
8787

8888
setResizable (true, false); // calls resized
89+
90+
// order mattecrs, set the mode before we toggle on
91+
setSelectionMode (static_cast<SelectionMode> (settings->props->getIntValue ("inspectorSelectionMode", FOLLOWS_MOUSE)));
92+
8993
toggle (inspectorEnabledAtStart);
9094
}
9195

@@ -95,6 +99,10 @@ namespace melatonin
9599

96100
this->removeKeyListener (&keyListener);
97101

102+
// the mouse listener is owned and removes itself on destruction
103+
if (selectionMode == FOLLOWS_FOCUS)
104+
juce::Desktop::getInstance().removeFocusChangeListener (this);
105+
98106
// needed, otherwise removing look and feel will save bounds
99107
settings->props.reset();
100108
setLookAndFeel (nullptr);
@@ -299,9 +307,12 @@ namespace melatonin
299307

300308
overlay.setVisible (newStatus);
301309
if (newStatus)
302-
// without this, target apps that have UI to open the inspector
303-
// will select that piece of UI within the same click, see #70
304-
juce::Timer::callAfterDelay (500, [&] { overlayMouseListener.enable(); });
310+
{
311+
if (selectionMode == FOLLOWS_MOUSE)
312+
// without this, target apps that have UI to open the inspector
313+
// will select that piece of UI within the same click, see #70
314+
callAfterDelay (500, [&] { overlayMouseListener.enable(); });
315+
}
305316
else
306317
{
307318
clearSelections();
@@ -340,6 +351,7 @@ namespace melatonin
340351
switch (selectionMode)
341352
{
342353
case FOLLOWS_FOCUS:
354+
selectComponent (nullptr);
343355
juce::Desktop::getInstance().removeFocusChangeListener (this);
344356
break;
345357
case FOLLOWS_MOUSE:
@@ -358,6 +370,9 @@ namespace melatonin
358370
overlayMouseListener.enable();
359371
break;
360372
}
373+
374+
settings->props->setValue ("inspectorSelectionMode", selectionMode);
375+
settings->saveIfNeeded();
361376
}
362377

363378
private:
@@ -401,10 +416,17 @@ namespace melatonin
401416

402417
void globalFocusChanged (Component* focusedComponent) override
403418
{
404-
selectComponent (focusedComponent);
419+
// nullptr focus events fire when focus is lost
420+
if (focusedComponent == nullptr)
421+
return;
422+
423+
// we only want to respond to focus events related to the UI under inspection (root)
424+
// Unfortunately, we can't test to see if the focusedComponent is a child of root
425+
// because JUCE UI like list boxes or text editors sometimes technically have no parent :/
426+
if (focusedComponent != root && focusedComponent->getTopLevelComponent() != inspectorComponent.getTopLevelComponent())
427+
selectComponent (focusedComponent);
405428
}
406429

407-
private:
408430
void timerCallback() override
409431
{
410432
for (auto& ms : juce::Desktop::getInstance().getMouseSources())
@@ -420,7 +442,7 @@ namespace melatonin
420442
overlayMouseListener.selectComponentCallback = [this] (Component* c) { this->selectComponent (c, true); };
421443
overlayMouseListener.componentStartDraggingCallback = [this] (Component* c, const juce::MouseEvent& e) { this->startDragComponent (c, e); };
422444
overlayMouseListener.componentDraggedCallback = [this] (Component* c, const juce::MouseEvent& e) { this->dragComponent (c, e); };
423-
overlayMouseListener.mouseExitCallback = [this]() { if (this->inspectorEnabled) inspectorComponent.redisplaySelectedComponent(); };
445+
overlayMouseListener.mouseExitCallback = [this] { if (this->inspectorEnabled) inspectorComponent.redisplaySelectedComponent(); };
424446

425447
inspectorComponent.selectComponentCallback = [this] (Component* c) { this->selectComponent (c, false); };
426448
inspectorComponent.outlineComponentCallback = [this] (Component* c) { this->outlineComponent (c); };

0 commit comments

Comments
 (0)