ui: Keyboard controls (#935)
* switch focus between views with Tab * move focus within views with WASD/HJKL/Arrows * move focus between graph edges by holding Shift * move focus between code references by holding Shift * removed graph panning with WASD and moved zooming to Alt + W/S * removed graph navigation by pressing starting character in graph view lists * changed local reference and custom trail shortcuts * updated Keyboard Shortcuts window * use common back and forward shortcuts and YZ & Shift + YZ * fix macOS issue where widgets don't get proper focus after creating a new tab * don't use shared_ptr in QtMainView fixes #486, #327, #214, #210
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
|
||||
#define CODE_TESTS
|
||||
|
||||
#include "header.h"
|
||||
|
||||
// NOTE: complete in both snippet and single mode
|
||||
|
||||
// TEST: Move Focus between locations
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
int sum(int a, int b) // <- ACTION: focus location via hover
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
int diff(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int mult(int a, int b)
|
||||
{
|
||||
return a * b;
|
||||
}
|
||||
|
||||
int div(int a, int b)
|
||||
{
|
||||
return a / b;
|
||||
}
|
||||
|
||||
// ACTION: Use WASD for navigation
|
||||
// RESULTS:
|
||||
// - Focus is moved between locations
|
||||
// - lines without locations are skipped
|
||||
// - focus tries to stay at same column if possible
|
||||
// - view scrolls up and down if focus leaves visible viewport
|
||||
|
||||
// ACTION: Use HJKL for navigation
|
||||
// RESULTS: same as above
|
||||
|
||||
// ACTION: Use arrow keys for navigation
|
||||
// RESULTS: same as above
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Activate location
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
int decimate(int a) // <- ACTION: move focus on 'decimate'
|
||||
{
|
||||
return div(a, 10);
|
||||
}
|
||||
|
||||
// ACTION: Press Enter/E
|
||||
// RESULT: 'decimate' is activated
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Activate local symbol
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
int pow(int a, int b)
|
||||
{
|
||||
int r = 1; // <- ACTION 1: move focus on 'r'
|
||||
for (int i = 0; i < b; ++i)
|
||||
{
|
||||
r *= a;
|
||||
}
|
||||
return r; // <- ACTION 3: move focus on 'r'
|
||||
}
|
||||
|
||||
// ACTION 2: Press Enter/E
|
||||
// RESULT 2: 'r' is activated
|
||||
|
||||
// ACTION 4: Press Enter/E
|
||||
// RESULT 3: 'r' is deactivated
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Navigate between active locations
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
int square(int a)
|
||||
{
|
||||
return mult(a, a); // <- ACTION: activate 'mult'
|
||||
}
|
||||
|
||||
// ACTION: Hold Shift and navigate with keyboard
|
||||
// RESULT: focus is moved between the active locations of 'mult'
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
// TEST: Navigate between active local locations
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
int cube(int a)
|
||||
{
|
||||
int r = square(a); // <- ACTION 1: activate 'square'
|
||||
r = mult(r, a);
|
||||
return r; // <- ACTION 2: activate 'r'
|
||||
}
|
||||
|
||||
// ACTION: Hold Shift and navigate with keyboard
|
||||
// RESULTS:
|
||||
// - focus is moved between the active locations of 'square'
|
||||
// - focus is moved between the active local locations of 'r' inbetween
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// NOTE: Snippet mode only
|
||||
|
||||
|
||||
|
||||
// TEST: Expanding scopes
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION 5: Move focus to file expansion above and press Enter/E
|
||||
|
||||
class Calculator
|
||||
{
|
||||
public:
|
||||
int getValue() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
// ACTION 4: Move focus to scope expansion above and press Enter/E
|
||||
void clearValue()
|
||||
{
|
||||
m_value = 0;
|
||||
}
|
||||
|
||||
void add(int a) // <- ACTION 1: activate 'add'
|
||||
{
|
||||
m_value += a;
|
||||
}
|
||||
// ACTION 2: Move focus to scope expansion below and press Enter/E
|
||||
|
||||
void diff(int a)
|
||||
{
|
||||
m_value -= a;
|
||||
}
|
||||
// ACTION 3: Move focus to scope expansion above and press Enter/E
|
||||
|
||||
void mult(int a)
|
||||
{
|
||||
m_value *= a;
|
||||
}
|
||||
|
||||
void div(int a)
|
||||
{
|
||||
m_value /= a;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_value = 0;
|
||||
};
|
||||
|
||||
// RESULTS 1-4:
|
||||
// - scope is expanded and focus is placed to location closest to expanded line
|
||||
|
||||
// BROKEN: focus is placed but not visible
|
||||
// RESULT 5: Whole file is expanded and focus placed at closest location
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Expand/Minimize snippets
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
int half(int a) // <- ACTION 2: activate 'int'
|
||||
{
|
||||
return div(a, 2);
|
||||
}
|
||||
|
||||
// ACTION 2: Move focus to snippet title bar and press Enter/E
|
||||
// RESULT 2: Snippet is collapsed
|
||||
|
||||
// ACTION 2: Press Enter/E again
|
||||
// RESULT 2: Snippet is expanded again
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
@@ -0,0 +1,157 @@
|
||||
|
||||
#define GRAPH_TESTS
|
||||
|
||||
// TEST: Move Focus between nodes
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
class X;
|
||||
class Y;
|
||||
class Z;
|
||||
|
||||
class A
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
class B : public A // <- ACTION: Activate B
|
||||
{
|
||||
X* x;
|
||||
Y* y;
|
||||
Z* z;
|
||||
};
|
||||
|
||||
class C : public B
|
||||
{
|
||||
int e;
|
||||
};
|
||||
|
||||
class D
|
||||
{
|
||||
B b;
|
||||
};
|
||||
|
||||
// ACTION: Press Tab
|
||||
// RESULTS:
|
||||
// - graph view is focused
|
||||
// - Node 'B' is focused
|
||||
|
||||
// ACTION: Use WASD for navigation
|
||||
// RESULTS:
|
||||
// - Focus is moved between nodes
|
||||
// - Going down from 'B' focuses it's members
|
||||
// - Going up from 'C' focuses 'B's members
|
||||
|
||||
// ACTION: Use HJKL for navigation
|
||||
// RESULTS: same as above
|
||||
|
||||
// ACTION: Use arrow keys for navigation
|
||||
// RESULTS: same as above
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Move Focus between edges
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Hold Shift and use WASD for navigation
|
||||
// RESULTS:
|
||||
// - Focus is moved between edges
|
||||
// - Focus is moved to node if no more edges in that direction
|
||||
|
||||
// ACTION: Hold Shift and use HJKL for navigation
|
||||
// RESULTS: same as above
|
||||
|
||||
// ACTION: Hold Shift and use arrow keys for navigation
|
||||
// RESULTS: same as above
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Moving focus beyond viewport centers focus
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Drag classes far apart
|
||||
// ACTION: Zoom in so not all nodes are visible
|
||||
// ACTION: Navigate focus with keyboard
|
||||
// RESULT: View is panned when focused node is outside of the viewport
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Expand/collapse nodes
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Move focus on class 'A'
|
||||
// ACTION: Hold Shift and press Enter/E
|
||||
// RESULT: 'A' is expanded
|
||||
|
||||
// ACTION: Move focus to 'A::a'
|
||||
// ACTION: Hold Shift and press Enter/E
|
||||
// RESULTS:
|
||||
// - 'A' is collapsed
|
||||
// - 'A' is focused
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Activate node
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Move focus on class 'D'
|
||||
// ACTION: Press Enter/E
|
||||
// RESULT: 'D' is activated
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Activate node in new Tab
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Move focus on 'D::b'
|
||||
// ACTION: Hold Ctrl/CMD + SHIFT and press Enter/E
|
||||
// RESULT: 'D::b' is opened in new tab
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Activate edge
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
B b; // <- ACTION: activate 'B'
|
||||
|
||||
// ACTION: Move focus on type use 'b -> B'
|
||||
// ACTION: Press Enter/E
|
||||
// RESULT: edge is activated
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Activate aggregation edge
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Move focus on aggregation 'D -> B'
|
||||
// ACTION: Press Enter/E
|
||||
// RESULT: aggregation edge is activated
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Expand bundle node
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Move focus on 'Non-indexed Symbols' bundle
|
||||
// ACTION: Press Enter/E
|
||||
// RESULTS:
|
||||
// - bundle is split
|
||||
// - focus is moved to active symbol
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
int sum(int a, int b);
|
||||
|
||||
int diff(int a, int b);
|
||||
|
||||
int mult(int a, int b);
|
||||
|
||||
int div(int a, int b);
|
||||
|
||||
int square(int a);
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#define HISTORY_TESTS
|
||||
|
||||
// TEST: Graph focus restored on back
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
class HistoryTest // <- ACTION: activate
|
||||
{
|
||||
public:
|
||||
int member;
|
||||
int member2;
|
||||
};
|
||||
|
||||
int func()
|
||||
{
|
||||
HistoryTest h;
|
||||
h.member = 0;
|
||||
}
|
||||
|
||||
// ACTION: Focus and activate 'func' in graph
|
||||
// ACTION: Navigate 'back' in history
|
||||
// RESULT: The graph for 'HistoryTest' is restored with focus at 'func'
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Graph aggregation focus restored on back
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
class HistoryTestUser
|
||||
{
|
||||
public:
|
||||
int process()
|
||||
{
|
||||
h.member = 2;
|
||||
h.member2 = 4;
|
||||
}
|
||||
|
||||
HistoryTest h;
|
||||
};
|
||||
|
||||
// ACTION: Focus and activate aggregation 'HistoryTestUser -> HistoryTest'
|
||||
// ACTION: Navigate 'back' in history
|
||||
// RESULT: The graph for 'HistoryTest' is restored with focus at aggregation edge
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Code focus restored on back
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
HistoryTest createTest(); // <- ACTION: focus and activate 'createTest' from code
|
||||
|
||||
// ACTION: Navigate 'back' in history
|
||||
// RESULT: The code view is restored with focus at 'createTest'
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
@@ -0,0 +1,129 @@
|
||||
|
||||
#define VIEW_TESTS
|
||||
|
||||
// TEST: Switch Focus with Tab
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
class ViewTestClass {}; // <- ACTION: Activate
|
||||
|
||||
// ACTION: Press Tab continuously
|
||||
// RESULT: Focus is moved between Graph and Code
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Focus Search View
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Use Find shortcut
|
||||
// RESULT: Search view shows focus
|
||||
|
||||
// ACTION: press Tab
|
||||
// RESULT: Search View loses focus
|
||||
|
||||
// ACTION: Click into search field
|
||||
// RESULT: Search view shows focus
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Focus Graph View
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Hover nodes using the mouse
|
||||
// RESULT: graph view receives focus
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Focus Code View
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
ViewTestClass v; // <- ACTION: Hover location of 'v'
|
||||
|
||||
// RESULT: code view receives focus
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Graph remembers previously focused node
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
// ACTION: Hover a 'ViewTestFocus' in the graph
|
||||
|
||||
// ACTION: Press Tab
|
||||
// RESULT: code view receives focus
|
||||
|
||||
// ACTION: Press Tab
|
||||
// RESULTS:
|
||||
// - graph receives focus
|
||||
// - 'ViewTestFocus' is focused again
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Code remembers previously focused location
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
ViewTestClass var; // <- ACTION: Hover location of 'var'
|
||||
|
||||
// ACTION: Press Tab
|
||||
// RESULT: graph view receives focus
|
||||
|
||||
// ACTION: Press Tab
|
||||
// RESULTS:
|
||||
// - code receives focus
|
||||
// - 'var' is focused again
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Focus at active symbol when clicked in code
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
class ViewTestFocus // <- ACTION: Activate
|
||||
{
|
||||
ViewTestClass member;
|
||||
};
|
||||
|
||||
class ViewTestFocusDerived : public ViewTestFocus {};
|
||||
|
||||
// RESULTS:
|
||||
// - Focus stays in code view
|
||||
// - Clicked location has focus
|
||||
|
||||
// ACTION: Press Tab
|
||||
// RESULTS:
|
||||
// - Focus is moved to graph
|
||||
// - active node receives initial focus
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// TEST: Focus at active symbol when clicked in graph
|
||||
// START ----------------------------------------------------------------------
|
||||
|
||||
class ViewTestFocusUser
|
||||
{
|
||||
ViewTestFocus focus;
|
||||
};
|
||||
|
||||
// ACTION: Activate 'ViewTestFocusUser' in graph
|
||||
|
||||
// RESULTS:
|
||||
// - Focus stays in graph view
|
||||
// - Clicked node has focus
|
||||
|
||||
// ACTION: Press Tab
|
||||
// RESULTS:
|
||||
// - Focus is moved to code
|
||||
// - active location receives initial focus
|
||||
|
||||
// END ------------------------------------------------------------------------
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<config>
|
||||
<description>Test Suites:\n\n [::\tmVIEW_TESTS\ts\tp]\n [::\tmGRAPH_TESTS\ts\tp]\n [::\tmCODE_TESTS\ts\tp]\n [::\tmHISTORY_TESTS\ts\tp]\n</description>
|
||||
<source_groups>
|
||||
<source_group_475571d1-b082-4fff-81c5-d099c19f957d>
|
||||
<cpp_standard>c++17</cpp_standard>
|
||||
<cross_compilation>
|
||||
<target>
|
||||
<abi>unknown</abi>
|
||||
<arch>x86_64</arch>
|
||||
<sys>unknown</sys>
|
||||
<vendor>unknown</vendor>
|
||||
</target>
|
||||
<target_options_enabled>0</target_options_enabled>
|
||||
</cross_compilation>
|
||||
<exclude_filters>
|
||||
<exclude_filter>data/files/template.h</exclude_filter>
|
||||
</exclude_filters>
|
||||
<name>C++ Source Group</name>
|
||||
<source_extensions>
|
||||
<source_extension>.cpp</source_extension>
|
||||
<source_extension>.cxx</source_extension>
|
||||
<source_extension>.cc</source_extension>
|
||||
</source_extensions>
|
||||
<source_paths>
|
||||
<source_path>data</source_path>
|
||||
</source_paths>
|
||||
<status>enabled</status>
|
||||
<type>C++ Source Group</type>
|
||||
</source_group_475571d1-b082-4fff-81c5-d099c19f957d>
|
||||
</source_groups>
|
||||
<version>8</version>
|
||||
</config>
|
||||
Reference in New Issue
Block a user