Skip to content

Commit 5c6ee1d

Browse files
committed
menu-applet: vectorBox removal test
still needs tuning + fix places hover issue
1 parent 01d90c1 commit 5c6ee1d

File tree

1 file changed

+108
-107
lines changed
  • files/usr/share/cinnamon/applets/menu@cinnamon.org

1 file changed

+108
-107
lines changed

files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js

Lines changed: 108 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,106 @@ class VisibleChildIterator {
9999
}
100100
}
101101

102+
class Rect {
103+
constructor(x, y, width, height) {
104+
this.x1 = x;
105+
this.y1 = y;
106+
this.x2 = x + width;
107+
this.y2 = y + height;
108+
}
109+
containsPoint(x, y) {
110+
if ((x < this.x1 || x > this.x2) || (y < this.y1 || y > this.y2))
111+
return false;
112+
return true;
113+
}
114+
}
115+
116+
class SelectionInhibitor {
117+
constructor() {
118+
this._timeoutId = 0;
119+
this._container = null;
120+
this._bounds = null;
121+
this._lastPos = null;
122+
this._inhibited = false;
123+
this._averageSlope = 0;
124+
}
125+
126+
get inhibited() {
127+
return this._inhibited;
128+
}
129+
130+
inhibit() {
131+
if (!this._container)
132+
return;
133+
134+
if (!this._timeoutId) {
135+
let [cx, cy] = this._container.get_transformed_position();
136+
let [cw, ch] = this._container.get_transformed_size();
137+
this._bounds = new Rect(cx, cy, cw, ch);
138+
this._timeoutId = Mainloop.timeout_add(50, this._trackMouse.bind(this));
139+
}
140+
141+
this._setInhibited(true);
142+
}
143+
144+
stop() {
145+
if (this._timeoutId)
146+
Mainloop.source_remove(this._timeoutId);
147+
148+
this._setInhibited(false);
149+
this._timeoutId = 0;
150+
this._bounds = null;
151+
this._inhibited = false;
152+
this._averageSlope = 0;
153+
}
154+
155+
setContainer(container) {
156+
this.stop();
157+
this._container = container;
158+
}
159+
160+
_setInhibited(state) {
161+
if (state == this._inhibited || !this._container)
162+
return;
163+
164+
let [mx, my, ] = global.get_pointer();
165+
this._lastPos = [mx, my];
166+
this._averageSlope = 0;
167+
this._inhibited = state;
168+
169+
for (let actor of this._container.get_children())
170+
actor.set_reactive(!state);
171+
}
172+
173+
_trackMouse() {
174+
if (!this._timeoutId)
175+
return;
176+
177+
let [x, y, mask] = global.get_pointer();
178+
if (!this._bounds.containsPoint(x, y)) {
179+
this.stop();
180+
return false;
181+
}
182+
183+
if (this._inhibited) {
184+
let dx = x - this._lastPos[0];
185+
let dy = Math.abs(y - this._lastPos[1]);
186+
187+
if (dx > 0 && dy > 0) {
188+
this._averageSlope += dy / dx;
189+
this._averageSlope /= 2;
190+
}
191+
//log(`averageSlope = ${this._averageSlope}; dx = ${dx}; dy = ${dy}`);
192+
if (this._averageSlope > 4 || dx < 0 || (dx == 0 && dy > 0)) {
193+
this._setInhibited(false)
194+
}
195+
196+
}
197+
this._lastPos = [x, y];
198+
return true;
199+
}
200+
}
201+
102202
class ApplicationContextMenuItem extends PopupMenu.PopupBaseMenuItem {
103203
constructor(appButton, label, action, iconName) {
104204
super({focusOnHover: false});
@@ -1149,6 +1249,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
11491249
this.noRecentDocuments = true;
11501250
this._activeContextMenuParent = null;
11511251
this._activeContextMenuItem = null;
1252+
this.selectionInhibitor = new SelectionInhibitor();
11521253
this._display();
11531254
appsys.connect('installed-changed', Lang.bind(this, this.onAppSysChanged));
11541255
AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._refreshFavs));
@@ -1352,7 +1453,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
13521453
this.closeContextMenus(null, false);
13531454

13541455
this._clearAllSelections(true);
1355-
this.destroyVectorBox();
1456+
this.selectionInhibitor.stop();
13561457
}
13571458
}
13581459

@@ -2037,101 +2138,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
20372138
}
20382139
}
20392140

2040-
/*
2041-
* The vectorBox overlays the the categoriesBox to aid in navigation from categories to apps
2042-
* by preventing misselections. It is set to the same size as the categoriesOverlayBox and
2043-
* categoriesBox.
2044-
*
2045-
* The actor is a quadrilateral that we turn into a triangle by setting the A and B vertices to
2046-
* the same position. The size and origin of the vectorBox are calculated in _getVectorInfo().
2047-
* Using those properties, the bounding box is sized as (w, h) and the triangle is defined as
2048-
* follows:
2049-
* _____
2050-
* | /|D
2051-
* | / | AB: (mx, my)
2052-
* | A/ | C: (w, h)
2053-
* | B\ | D: (w, 0)
2054-
* | \ |
2055-
* |____\|C
2056-
*/
2057-
2058-
_getVectorInfo() {
2059-
let [mx, my, mask] = global.get_pointer();
2060-
let [bx, by] = this.categoriesOverlayBox.get_transformed_position();
2061-
let [bw, bh] = this.categoriesOverlayBox.get_transformed_size();
2062-
2063-
let xformed_mx = mx - bx;
2064-
let xformed_my = my - by;
2065-
2066-
if (xformed_mx < 0 || xformed_mx > bw || xformed_my < 0 || xformed_my > bh) {
2067-
return null;
2068-
}
2069-
2070-
return { mx: xformed_mx,
2071-
my: xformed_my,
2072-
w: bw,
2073-
h: bh };
2074-
}
2075-
2076-
makeVectorBox(actor) {
2077-
this.destroyVectorBox(actor);
2078-
let vi = this._getVectorInfo();
2079-
if (!vi) {
2080-
return;
2081-
}
2082-
2083-
this.vectorBox = new St.Polygon({ debug: false, width: vi.w -1, height: vi.h,
2084-
ulc_x: vi.mx, ulc_y: vi.my,
2085-
llc_x: vi.mx, llc_y: vi.my,
2086-
urc_x: vi.w, urc_y: 0,
2087-
lrc_x: vi.w, lrc_y: vi.h });
2088-
2089-
this.categoriesOverlayBox.add_actor(this.vectorBox);
2090-
2091-
this.vectorBox.show();
2092-
this.vectorBox.set_reactive(true);
2093-
2094-
this.vectorBox.connect("leave-event", Lang.bind(this, this.destroyVectorBox));
2095-
this.vectorBox.connect("motion-event", Lang.bind(this, this.maybeUpdateVectorBox));
2096-
this.actor_motion_id = actor.connect("motion-event", Lang.bind(this, this.maybeUpdateVectorBox));
2097-
this.current_motion_actor = actor;
2098-
}
2099-
2100-
maybeUpdateVectorBox() {
2101-
if (this.vector_update_loop) {
2102-
Mainloop.source_remove(this.vector_update_loop);
2103-
this.vector_update_loop = 0;
2104-
}
2105-
this.vector_update_loop = Mainloop.timeout_add(50, Lang.bind(this, this.updateVectorBox));
2106-
}
2107-
2108-
updateVectorBox(actor) {
2109-
if (this.vectorBox) {
2110-
let vi = this._getVectorInfo();
2111-
if (vi) {
2112-
this.vectorBox.ulc_x = vi.mx;
2113-
this.vectorBox.llc_x = vi.mx;
2114-
this.vectorBox.queue_repaint();
2115-
} else {
2116-
this.destroyVectorBox(actor);
2117-
}
2118-
}
2119-
this.vector_update_loop = 0;
2120-
return false;
2121-
}
2122-
2123-
destroyVectorBox(actor) {
2124-
if (this.vectorBox != null) {
2125-
this.vectorBox.destroy();
2126-
this.vectorBox = null;
2127-
}
2128-
if (this.actor_motion_id > 0 && this.current_motion_actor != null) {
2129-
this.current_motion_actor.disconnect(this.actor_motion_id);
2130-
this.actor_motion_id = 0;
2131-
this.current_motion_actor = null;
2132-
}
2133-
}
2134-
21352141
_refreshPlaces () {
21362142
for (let i = 0; i < this._placesButtons.length; i ++) {
21372143
this._placesButtons[i].actor.destroy();
@@ -2160,7 +2166,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21602166
this.closeContextMenus(null, false);
21612167
this._select_category("places");
21622168

2163-
this.makeVectorBox(this.placesButton.actor);
2169+
this.selectionInhibitor.inhibit();
21642170
}
21652171
}));
21662172
this.placesButton.actor.connect('leave-event', Lang.bind(this, function () {
@@ -2234,7 +2240,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
22342240
this.closeContextMenus(null, false);
22352241
this._select_category("recent");
22362242

2237-
this.makeVectorBox(this.recentButton.actor);
2243+
this.selectionInhibitor.inhibit();
22382244
}
22392245
}));
22402246
this.recentButton.actor.connect('leave-event', Lang.bind(this, function () {
@@ -2473,7 +2479,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
24732479
this._allAppsCategoryButton.actor.style_class = "menu-category-button-selected";
24742480
this._select_category(null);
24752481

2476-
this.makeVectorBox(this._allAppsCategoryButton.actor);
2482+
this.selectionInhibitor.inhibit();
24772483
}
24782484
}));
24792485
this._allAppsCategoryButton.actor.connect('leave-event', Lang.bind(this, function () {
@@ -2538,7 +2544,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
25382544
categoryButton.actor.style_class = "menu-category-button-selected";
25392545
this._select_category(dir.get_menu_id());
25402546

2541-
this.makeVectorBox(categoryButton.actor);
2547+
this.selectionInhibitor.inhibit();
25422548
}
25432549
});
25442550
};
@@ -2827,10 +2833,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28272833
_display() {
28282834
this._activeContainer = null;
28292835
this._activeActor = null;
2830-
this.vectorBox = null;
2831-
this.actor_motion_id = 0;
2832-
this.vector_update_loop = null;
2833-
this.current_motion_actor = null;
28342836
let section = new PopupMenu.PopupMenuSection();
28352837
this.menu.addMenuItem(section);
28362838

@@ -2866,11 +2868,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28662868
rightPane.add_actor(topRow);
28672869
rightPane.add_actor(this.categoriesApplicationsBox.actor);
28682870

2869-
this.categoriesOverlayBox = new Clutter.Actor();
28702871
this.categoriesBox = new St.BoxLayout({ style_class: 'menu-categories-box',
28712872
vertical: true,
28722873
accessible_role: Atk.Role.LIST });
2873-
this.categoriesOverlayBox.add_actor(this.categoriesBox);
2874+
this.selectionInhibitor.setContainer(this.categoriesBox);
28742875

28752876
this.applicationsScrollBox = new St.ScrollView({ x_fill: true, y_fill: false, y_align: St.Align.START, style_class: 'vfade menu-applications-scrollbox' });
28762877

@@ -2898,7 +2899,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28982899
this.applicationsBox.add_style_class_name('menu-applications-box'); //this is to support old themes
28992900
this.applicationsScrollBox.add_actor(this.applicationsBox);
29002901
this.applicationsScrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
2901-
this.categoriesApplicationsBox.actor.add_actor(this.categoriesOverlayBox);
2902+
this.categoriesApplicationsBox.actor.add_actor(this.categoriesBox);
29022903
this.categoriesApplicationsBox.actor.add_actor(this.applicationsScrollBox);
29032904

29042905
this.favoritesScrollBox = new St.ScrollView({

0 commit comments

Comments
 (0)