Fix behavior of More... links by adding a Link class

We had problems because the More links were reacting on press but
other elements were reacting on release. (Often the link would trigger
*and* an item.) Just connecting to ::button-release-event on
ClutterText gives a stuck grab (since ClutterText gets the press
but not the release), so we need more complicated code that we
encapsulate into a new class.

link.js: new "pseudo-widget" that implements a clickable link.
overlay.js: Use Link.Link for the More.. links

http://bugzilla.gnome.org/show_bug.cgi?id=573323
This commit is contained in:
Owen W. Taylor 2009-02-26 17:05:35 -05:00
parent 6676260308
commit cb4ad9a963
2 changed files with 104 additions and 26 deletions

81
js/ui/link.js Normal file
View File

@ -0,0 +1,81 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Signals = imports.signals;
// Link is a clickable link. Right now it just handles properly capturing
// press and release events and short-circuiting the button handling in
// ClutterText, but more features like different colors for hover/pressed states
// or a different mouse cursor could be implemented.
//
// The properties passed in are forwarded to the Clutter.Text() constructor,
// so can include, 'text', 'font_name', etc.
function Link(props) {
this._init(props);
}
Link.prototype = {
_init : function(props) {
let realProps = { reactive: true };
// The user can pass in reactive: false to override the above and get
// a non-reactive link (a link to the current page, perhaps)
Lang.copyProperties(props, realProps);
this.actor = new Clutter.Text(realProps);
this.actor._delegate = this;
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect('enter-event', Lang.bind(this, this._onEnter));
this.actor.connect('leave-event', Lang.bind(this, this._onLeave));
this._buttonDown = false;
this._havePointer = false;
},
// Update the text of the link
setText : function(text) {
this.actor.text = text;
},
// We want to react on buttonDown, but if we override button-release-event for
// ClutterText, but not button-press-event, we get a stuck grab. Tracking
// buttonDown and doing the grab isn't really necessary, but doing it makes
// the behavior perfectly correct if the user clicks on one actor, drags
// to another and releases - that should not trigger either actor.
_onButtonPress : function(actor, event) {
this._buttonDown = true;
this._havePointer = true; // Hack to work around poor enter/leave tracking in Clutter
Clutter.grab_pointer(actor);
return true;
},
_onButtonRelease : function(actor, event) {
if (this._buttonDown) {
this._buttonDown = false;
Clutter.ungrab_pointer(actor);
if (this._havePointer)
this.emit('clicked');
}
return true;
},
_onEnter : function(actor, event) {
if (event.get_source() == actor)
this._havePointer = true;
return false;
},
_onLeave : function(actor, event) {
if (event.get_source() == actor)
this._havePointer = false;
return false;
}
};
Signals.addSignalMethods(Link.prototype);

View File

@ -11,6 +11,7 @@ const Signals = imports.signals;
const AppDisplay = imports.ui.appDisplay; const AppDisplay = imports.ui.appDisplay;
const DocDisplay = imports.ui.docDisplay; const DocDisplay = imports.ui.docDisplay;
const GenericDisplay = imports.ui.genericDisplay; const GenericDisplay = imports.ui.genericDisplay;
const Link = imports.ui.link;
const Main = imports.ui.main; const Main = imports.ui.main;
const Panel = imports.ui.panel; const Panel = imports.ui.panel;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
@ -198,12 +199,11 @@ Sideshow.prototype = {
this._appsSection.append(this._appDisplay.actor, Big.BoxPackFlags.EXPAND); this._appsSection.append(this._appDisplay.actor, Big.BoxPackFlags.EXPAND);
let moreAppsBox = new Big.Box({x_align: Big.BoxAlignment.END}); let moreAppsBox = new Big.Box({x_align: Big.BoxAlignment.END});
this._moreAppsText = new Clutter.Text({ color: SIDESHOW_TEXT_COLOR, this._moreAppsLink = new Link.Link({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px", font_name: "Sans Bold 14px",
text: "More...", text: "More...",
height: LABEL_HEIGHT, height: LABEL_HEIGHT });
reactive: true}); moreAppsBox.append(this._moreAppsLink.actor, Big.BoxPackFlags.EXPAND);
moreAppsBox.append(this._moreAppsText, Big.BoxPackFlags.EXPAND);
this._appsSection.append(moreAppsBox, Big.BoxPackFlags.EXPAND); this._appsSection.append(moreAppsBox, Big.BoxPackFlags.EXPAND);
this.actor.add_actor(this._appsSection); this.actor.add_actor(this._appsSection);
@ -226,12 +226,11 @@ Sideshow.prototype = {
this._docsSection.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND); this._docsSection.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND);
let moreDocsBox = new Big.Box({x_align: Big.BoxAlignment.END}); let moreDocsBox = new Big.Box({x_align: Big.BoxAlignment.END});
this._moreDocsText = new Clutter.Text({ color: SIDESHOW_TEXT_COLOR, this._moreDocsLink = new Link.Link({ color: SIDESHOW_TEXT_COLOR,
font_name: "Sans Bold 14px", font_name: "Sans Bold 14px",
text: "More...", text: "More...",
height: LABEL_HEIGHT, height: LABEL_HEIGHT });
reactive: true}); moreDocsBox.append(this._moreDocsLink.actor, Big.BoxPackFlags.EXPAND);
moreDocsBox.append(this._moreDocsText, Big.BoxPackFlags.EXPAND);
this._docsSection.append(moreDocsBox, Big.BoxPackFlags.EXPAND); this._docsSection.append(moreDocsBox, Big.BoxPackFlags.EXPAND);
this.actor.add_actor(this._docsSection); this.actor.add_actor(this._docsSection);
@ -267,24 +266,22 @@ Sideshow.prototype = {
me._appDisplay.selectFirstItem(); me._appDisplay.selectFirstItem();
}); });
this._moreAppsText.connect('button-press-event', this._moreAppsLink.connect('clicked',
function(o, event) { function(o, event) {
if (me._moreAppsMode) { if (me._moreAppsMode) {
me._unsetMoreAppsMode(); me._unsetMoreAppsMode();
} else { } else {
me._setMoreAppsMode(); me._setMoreAppsMode();
} }
return true;
}); });
this._moreDocsText.connect('button-press-event', this._moreDocsLink.connect('clicked',
function(o, event) { function(o, event) {
if (me._moreDocsMode) { if (me._moreDocsMode) {
me._unsetMoreDocsMode(); me._unsetMoreDocsMode();
} else { } else {
me._setMoreDocsMode(); me._setMoreDocsMode();
} }
return true;
}); });
}, },
@ -319,7 +316,7 @@ Sideshow.prototype = {
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height); this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
this._moreAppsText.hide(); this._moreAppsLink.actor.hide();
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height); this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
// Move the selection to the applications section if it was in the docs section. // Move the selection to the applications section if it was in the docs section.
@ -356,7 +353,7 @@ Sideshow.prototype = {
this._moreAppsMode = false; this._moreAppsMode = false;
this._moreAppsText.hide(); this._moreAppsLink.actor.hide();
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height); this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
@ -410,12 +407,12 @@ Sideshow.prototype = {
this._appDisplay.updateDimensions(this._width + this._additionalWidth, this._appDisplay.updateDimensions(this._width + this._additionalWidth,
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT, this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
EXPANDED_SIDESHOW_COLUMNS); EXPANDED_SIDESHOW_COLUMNS);
this._moreAppsText.text = "Less..."; this._moreAppsLink.setText("Less...");
} else { } else {
this._appDisplay.updateDimensions(this._width, this._appsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT, SIDESHOW_COLUMNS); this._appDisplay.updateDimensions(this._width, this._appsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT, SIDESHOW_COLUMNS);
this._moreAppsText.text = "More..."; this._moreAppsLink.setText("More...");
} }
this._moreAppsText.show(); this._moreAppsLink.actor.show();
}, },
// Sets the 'More' mode for browsing documents. Updates the documents section to have more items. // Sets the 'More' mode for browsing documents. Updates the documents section to have more items.
@ -430,7 +427,7 @@ Sideshow.prototype = {
if (!this._appsSection.has_clip) if (!this._appsSection.has_clip)
this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height); this._appsSection.set_clip(0, 0, this._appsSection.width, this._appsSection.height);
this._moreDocsText.hide(); this._moreDocsLink.actor.hide();
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height); this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
// Move the selection to the docs section if it was in the apps section. // Move the selection to the docs section if it was in the apps section.
@ -469,7 +466,7 @@ Sideshow.prototype = {
this._moreDocsMode = false; this._moreDocsMode = false;
this._moreDocsText.hide(); this._moreDocsLink.actor.hide();
this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height); this._docsSection.set_clip(0, 0, this._docsSection.width, this._docsSection.height);
@ -520,12 +517,12 @@ Sideshow.prototype = {
this._docDisplay.updateDimensions(this._width + this._additionalWidth, this._docDisplay.updateDimensions(this._width + this._additionalWidth,
this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT, this._itemDisplayHeight + SIDESHOW_SECTION_MISC_HEIGHT,
EXPANDED_SIDESHOW_COLUMNS); EXPANDED_SIDESHOW_COLUMNS);
this._moreDocsText.text = "Less..."; this._moreDocsLink.setText("Less...");
} else { } else {
this._docDisplay.updateDimensions(this._width, this._docsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT, SIDESHOW_COLUMNS); this._docDisplay.updateDimensions(this._width, this._docsSectionDefaultHeight - SIDESHOW_SECTION_MISC_HEIGHT, SIDESHOW_COLUMNS);
this._moreDocsText.text = "More..."; this._moreDocsLink.setText("More...");
} }
this._moreDocsText.show(); this._moreDocsLink.actor.show();
} }
}; };