diff --git a/data/Makefile.am b/data/Makefile.am index ca8d6dde0..eee6b2d51 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -18,9 +18,8 @@ dist_image_DATA = \ add-workspace.svg \ close.svg \ info.svg \ - remove-workspace.svg \ - view-more-activated.svg \ - view-more.svg + magnifier.svg \ + remove-workspace.svg schemadir = @GCONF_SCHEMA_FILE_DIR@ schema_DATA = gnome-shell.schemas diff --git a/data/view-more.svg b/data/magnifier.svg similarity index 76% rename from data/view-more.svg rename to data/magnifier.svg index 31af4ee2e..836ee6998 100644 --- a/data/view-more.svg +++ b/data/magnifier.svg @@ -1,5 +1,6 @@ + image/svg+xml - + id="grid2391" + empspacing="5" + visible="true" + enabled="true" + snapvisiblegridlinesonly="true" /> + + style="fill:#ffffff;fill-opacity:1"> + style="fill:#ffffff;fill-opacity:1" /> + style="fill:#ffffff;fill-opacity:1" /> + style="fill:#ffffff;fill-opacity:1" /> \ No newline at end of file diff --git a/data/view-more-activated.svg b/data/view-more-activated.svg deleted file mode 100644 index 787b1ad6f..000000000 --- a/data/view-more-activated.svg +++ /dev/null @@ -1,66 +0,0 @@ - - -image/svg+xml - - - - - - - \ No newline at end of file diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index a1e5f6f7a..7d28fbaff 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -565,9 +565,7 @@ WellGrid.prototype = { _init: function() { this.actor = new Shell.GenericContainer(); - this._separator = new Big.Box({ border_color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR, - border_top: 1, - height: 1 }); + this._separator = new Big.Box({ height: 1 }); this.actor.add_actor(this._separator); this._separatorIndex = 0; this._cachedSeparatorY = 0; diff --git a/js/ui/dash.js b/js/ui/dash.js index c5d8030a6..59426d5e0 100644 --- a/js/ui/dash.js +++ b/js/ui/dash.js @@ -5,6 +5,7 @@ const Clutter = imports.gi.Clutter; const Gio = imports.gi.Gio; const Gtk = imports.gi.Gtk; const Mainloop = imports.mainloop; +const Pango = imports.gi.Pango; const Shell = imports.gi.Shell; const Signals = imports.signals; const Lang = imports.lang; @@ -18,14 +19,35 @@ const Main = imports.ui.main; const DEFAULT_PADDING = 4; const DASH_SECTION_PADDING = 6; -const DASH_SECTION_SPACING = 12; +const DASH_SECTION_SPACING = 40; const DASH_CORNER_RADIUS = 5; -const DASH_SEARCH_BG_COLOR = new Clutter.Color(); -DASH_SEARCH_BG_COLOR.from_pixel(0xffffffff); -const DASH_SECTION_COLOR = new Clutter.Color(); -DASH_SECTION_COLOR.from_pixel(0x846c3dff); -const DASH_TEXT_COLOR = new Clutter.Color(); -DASH_TEXT_COLOR.from_pixel(0xffffffff); + +const BACKGROUND_COLOR = new Clutter.Color(); +BACKGROUND_COLOR.from_pixel(0x000000c0); + +const DASH_PADDING_SIDE = 14; + +const SEARCH_BORDER_BOTTOM_COLOR = new Clutter.Color(); +SEARCH_BORDER_BOTTOM_COLOR.from_pixel(0x191919ff); + +const SECTION_BORDER_COLOR = new Clutter.Color(); +SECTION_BORDER_COLOR.from_pixel(0x262626ff); +const SECTION_BORDER = 1; +const SECTION_INNER_BORDER_COLOR = new Clutter.Color(); +SECTION_INNER_BORDER_COLOR.from_pixel(0x000000ff); +const SECTION_BACKGROUND_TOP_COLOR = new Clutter.Color(); +SECTION_BACKGROUND_TOP_COLOR.from_pixel(0x161616ff); +const SECTION_BACKGROUND_BOTTOM_COLOR = new Clutter.Color(); +SECTION_BACKGROUND_BOTTOM_COLOR.from_pixel(0x000000ff); +const SECTION_INNER_SPACING = 8; + +const BROWSE_ACTIVATED_BG = new Clutter.Color(); +BROWSE_ACTIVATED_BG.from_pixel(0x303030f0); + +const TEXT_COLOR = new Clutter.Color(); +TEXT_COLOR.from_pixel(0x5f5f5fff); +const BRIGHT_TEXT_COLOR = new Clutter.Color(); +BRIGHT_TEXT_COLOR.from_pixel(0xffffffff); const PANE_BORDER_COLOR = new Clutter.Color(); PANE_BORDER_COLOR.from_pixel(0x101d3cfa); @@ -144,7 +166,7 @@ ResultArea.prototype = { // Utility function shared between ResultPane and the DocDisplay in the main dash. // Connects to the detail signal of the display, and on-demand creates a new // pane. -function createPaneForDetails(dash, display, detailsWidth) { +function createPaneForDetails(dash, display) { let detailPane = null; display.connect('show-details', Lang.bind(this, function(display, index) { if (detailPane == null) { @@ -160,7 +182,7 @@ function createPaneForDetails(dash, display, detailsWidth) { if (index >= 0) { detailPane.destroyContent(); - let details = display.createDetailsForIndex(index, detailsWidth, -1); + let details = display.createDetailsForIndex(index, -1); detailPane.content.append(details, Big.BoxPackFlags.EXPAND); detailPane.open(); } else { @@ -170,17 +192,16 @@ function createPaneForDetails(dash, display, detailsWidth) { return null; } -function ResultPane(dash, detailsWidth) { - this._init(dash, detailsWidth); +function ResultPane(dash) { + this._init(dash); } ResultPane.prototype = { __proto__: Pane.prototype, - _init: function(dash, detailsWidth) { + _init: function(dash) { Pane.prototype._init.call(this); this._dash = dash; - this._detailsWidth = detailsWidth; }, // Create an instance of displayClass and pack it into this pane's @@ -188,7 +209,7 @@ ResultPane.prototype = { packResults: function(displayClass, enableNavigation) { let resultArea = new ResultArea(displayClass, enableNavigation); - createPaneForDetails(this._dash, resultArea.display, this._detailsWidth); + createPaneForDetails(this._dash, resultArea.display); this.content.append(resultArea.actor, Big.BoxPackFlags.EXPAND); this.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) { @@ -206,31 +227,89 @@ SearchEntry.prototype = { _init : function() { this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL, y_align: Big.BoxAlignment.CENTER, - background_color: DASH_SEARCH_BG_COLOR, - corner_radius: 4, - spacing: DEFAULT_PADDING, - padding: DEFAULT_PADDING - }); - - let icon = new Gio.ThemedIcon({ name: 'gtk-find' }); - let searchIconTexture = Shell.TextureCache.get_default().load_gicon(icon, 16); - this.actor.append(searchIconTexture, Big.BoxPackFlags.NONE); - + border_bottom: SECTION_BORDER, + border_color: SEARCH_BORDER_BOTTOM_COLOR }); this.pane = null; + this._defaultText = "Find apps or documents"; + + let textProperties = { font_name: "Sans 12" }; + let entryProperties = { editable: true, + activatable: true, + single_line_mode: true, + color: BRIGHT_TEXT_COLOR, + cursor_color: BRIGHT_TEXT_COLOR, + text: '' }; + Lang.copyProperties(textProperties, entryProperties); // We need to initialize the text for the entry to have the cursor displayed // in it. See http://bugzilla.openedhand.com/show_bug.cgi?id=1365 - this.entry = new Clutter.Text({ font_name: "Sans 14px", - editable: true, - activatable: true, - singleLineMode: true, - text: "" - }); + this.entry = new Clutter.Text(entryProperties); + this.entry.connect('notify::text', Lang.bind(this, function () { + this._resetTextState(); + })); this.actor.append(this.entry, Big.BoxPackFlags.EXPAND); + + // Mark as editable just to get a cursor + let defaultTextProperties = { ellipsize: Pango.EllipsizeMode.END, + text: "Find apps or documents", + editable: true, + color: TEXT_COLOR, + cursor_visible: false, + single_line_mode: true }; + Lang.copyProperties(textProperties, defaultTextProperties); + this._defaultText = new Clutter.Text(defaultTextProperties); + this.actor.add_actor(this._defaultText); + this.entry.connect('notify::allocation', Lang.bind(this, function () { + this._repositionDefaultText(); + })); + + this._iconBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER, + y_align: Big.BoxAlignment.CENTER }); + this.actor.append(this._iconBox, Big.BoxPackFlags.END); + + let global = Shell.Global.get(); + let magnifierUri = "file://" + global.imagedir + "magnifier.svg"; + this._magnifierIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER, + magnifierUri, 29, 18); + let closeUri = "file://" + global.imagedir + "close.svg"; + this._closeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER, + closeUri, 18, 18); + this._closeIcon.reactive = true; + this._closeIcon.connect('button-press-event', Lang.bind(this, function () { + this.entry.text = ''; + })); + this._repositionDefaultText(); + this._resetTextState(); }, setPane: function (pane) { this._pane = pane; + }, + + reset: function () { + this.entry.text = ''; + }, + + getText: function () { + return this.entry.text; + }, + + _resetTextState: function () { + let text = this.getText(); + this._iconBox.remove_all(); + if (text != '') { + this._defaultText.hide(); + this._iconBox.append(this._closeIcon, Big.BoxPackFlags.NONE); + } else { + this._defaultText.show(); + this._iconBox.append(this._magnifierIcon, Big.BoxPackFlags.NONE); + } + }, + + _repositionDefaultText: function () { + // Offset a little to show the cursor + this._defaultText.set_position(this.entry.x + 4, this.entry.y); + this._defaultText.set_size(this.entry.width, this.entry.height); } }; Signals.addSignalMethods(SearchEntry.prototype); @@ -242,22 +321,21 @@ function MoreLink() { MoreLink.prototype = { _init : function () { this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL, + padding_right: DEFAULT_PADDING, padding_left: DEFAULT_PADDING, - padding_right: DEFAULT_PADDING }); - let global = Shell.Global.get(); - let inactiveUri = "file://" + global.imagedir + "view-more.svg"; - let activeUri = "file://" + global.imagedir + "view-more-activated.svg"; - this._inactiveIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER, - inactiveUri, 29, 18); - this._activeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER, - activeUri, 29, 18); - this._iconBox = new Big.Box({ reactive: true }); - this._iconBox.append(this._inactiveIcon, Big.BoxPackFlags.NONE); - this.actor.append(this._iconBox, Big.BoxPackFlags.END); - + reactive: true, + x_align: Big.BoxAlignment.CENTER, + y_align: Big.BoxAlignment.CENTER, + border_left: SECTION_BORDER, + border_color: SECTION_BORDER_COLOR }); this.pane = null; - this._iconBox.connect('button-press-event', Lang.bind(this, function (b, e) { + let text = new Clutter.Text({ font_name: "Sans 12px", + color: BRIGHT_TEXT_COLOR, + text: "Browse" }); + this.actor.append(text, Big.BoxPackFlags.NONE); + + this.actor.connect('button-press-event', Lang.bind(this, function (b, e) { if (this.pane == null) { // Ensure the pane is created; the activated handler will call setPane this.emit('activated'); @@ -270,41 +348,66 @@ MoreLink.prototype = { setPane: function (pane) { this._pane = pane; this._pane.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) { - this._iconBox.remove_all(); - this._iconBox.append(isOpen ? this._activeIcon : this._inactiveIcon, - Big.BoxPackFlags.NONE); })); } } Signals.addSignalMethods(MoreLink.prototype); -function SectionHeader(title) { - this._init(title); +function SectionHeader(title, suppressBrowse) { + this._init(title, suppressBrowse); } SectionHeader.prototype = { - _init : function (title) { - this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL }); - let text = new Clutter.Text({ color: DASH_SECTION_COLOR, - font_name: "Sans Bold 10px", + _init : function (title, suppressBrowse) { + this.actor = new Big.Box({ border: SECTION_BORDER, + border_color: SECTION_BORDER_COLOR }); + this._innerBox = new Big.Box({ border: SECTION_BORDER, + border_color: SECTION_INNER_BORDER_COLOR, + padding_left: DEFAULT_PADDING, + orientation: Big.BoxOrientation.HORIZONTAL }); + this.actor.append(this._innerBox, Big.BoxPackFlags.EXPAND); + let backgroundGradient = Shell.create_vertical_gradient(SECTION_BACKGROUND_TOP_COLOR, + SECTION_BACKGROUND_BOTTOM_COLOR); + this._innerBox.add_actor(backgroundGradient); + this._innerBox.connect('notify::allocation', Lang.bind(this, function (actor) { + let [width, height] = actor.get_size(); + backgroundGradient.set_size(width, height); + })); + let textBox = new Big.Box({ padding_top: DEFAULT_PADDING, + padding_bottom: DEFAULT_PADDING }); + let text = new Clutter.Text({ color: TEXT_COLOR, + font_name: "Sans Bold 12px", text: title }); - this.moreLink = new MoreLink(); - this.actor.append(text, Big.BoxPackFlags.EXPAND); - this.actor.append(this.moreLink.actor, Big.BoxPackFlags.END); + textBox.append(text, Big.BoxPackFlags.NONE); + this._innerBox.append(textBox, Big.BoxPackFlags.EXPAND); + if (!suppressBrowse) { + this.moreLink = new MoreLink(); + this._innerBox.append(this.moreLink.actor, Big.BoxPackFlags.END); + } } } -function Dash(displayGridColumnWidth) { - this._init(displayGridColumnWidth); +function Section(titleString, suppressBrowse) { + this._init(titleString, suppressBrowse); +} + +Section.prototype = { + _init: function(titleString, suppressBrowse) { + this.actor = new Big.Box({ spacing: SECTION_INNER_SPACING }); + this.header = new SectionHeader(titleString, suppressBrowse); + this.actor.append(this.header.actor, Big.BoxPackFlags.NONE); + this.content = new Big.Box(); + this.actor.append(this.content, Big.BoxPackFlags.EXPAND); + } +} + +function Dash() { + this._init(); } Dash.prototype = { - _init : function(displayGridColumnWidth) { - this._width = displayGridColumnWidth; - - this._detailsWidth = displayGridColumnWidth * 2; - + _init : function() { let global = Shell.Global.get(); // dash and the popup panes need to be reactive so that the clicks in unoccupied places on them @@ -316,14 +419,21 @@ Dash.prototype = { // of the Group actor ends up including the width of its hidden children, so we were getting a reactive object as // wide as the details pane that was blocking the clicks to the workspaces underneath it even when the details pane // was actually hidden. - this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL, - width: this._width, - padding: DEFAULT_PADDING, + this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, + background_color: BACKGROUND_COLOR, + corner_radius: DASH_CORNER_RADIUS, + padding_left: DASH_PADDING_SIDE, + padding_right: DASH_PADDING_SIDE, reactive: true }); - this.dashContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, - spacing: DASH_SECTION_SPACING }); - this.actor.append(this.dashContainer, Big.BoxPackFlags.EXPAND); + // Size for this one explicitly set from overlay.js + this.searchArea = new Big.Box({ y_align: Big.BoxAlignment.CENTER }); + + this.sectionArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, + spacing: DASH_SECTION_SPACING }); + + this.actor.append(this.searchArea, Big.BoxPackFlags.NONE); + this.actor.append(this.sectionArea, Big.BoxPackFlags.NONE); // The currently active popup display this._activePane = null; @@ -333,24 +443,25 @@ Dash.prototype = { this._searchPane = null; this._searchActive = false; this._searchEntry = new SearchEntry(); - this.dashContainer.append(this._searchEntry.actor, Big.BoxPackFlags.NONE); + this.searchArea.append(this._searchEntry.actor, Big.BoxPackFlags.EXPAND); this._searchAreaApps = null; this._searchAreaDocs = null; this._searchQueued = false; this._searchEntry.entry.connect('text-changed', Lang.bind(this, function (se, prop) { - this._searchActive = this._searchEntry.text != ''; + let text = this._searchEntry.getText(); + this._searchActive = text != ''; if (this._searchQueued) return; if (this._searchPane == null) { - this._searchPane = new ResultPane(this, this._detailsWidth); - this._searchPane.content.append(new Clutter.Text({ color: DASH_SECTION_COLOR, + this._searchPane = new ResultPane(this); + this._searchPane.content.append(new Clutter.Text({ color: TEXT_COLOR, font_name: 'Sans Bold 10px', text: "APPLICATIONS" }), Big.BoxPackFlags.NONE); this._searchAreaApps = this._searchPane.packResults(AppDisplay.AppDisplay, false); - this._searchPane.content.append(new Clutter.Text({ color: DASH_SECTION_COLOR, + this._searchPane.content.append(new Clutter.Text({ color: TEXT_COLOR, font_name: 'Sans Bold 10px', text: "RECENT DOCUMENTS" }), Big.BoxPackFlags.NONE); @@ -360,8 +471,9 @@ Dash.prototype = { } this._searchQueued = true; Mainloop.timeout_add(250, Lang.bind(this, function() { + let text = this._searchEntry.getText(); // Strip leading and trailing whitespace - let text = this._searchEntry.entry.text.replace(/^\s+/g, "").replace(/\s+$/g, ""); + text = text.replace(/^\s+/g, "").replace(/\s+$/g, ""); this._searchQueued = false; this._searchAreaApps.setSearch(text); this._searchAreaDocs.setSearch(text); @@ -380,12 +492,13 @@ Dash.prototype = { return true; })); this._searchEntry.entry.connect('key-press-event', Lang.bind(this, function (se, e) { + let text = this._searchEntry.getText(); let symbol = Shell.get_event_key_symbol(e); if (symbol == Clutter.Escape) { // Escape will keep clearing things back to the desktop. First, if // we have active text, we remove it. - if (this._searchEntry.entry.text != '') - this._searchEntry.entry.text = ''; + if (text != '') + this._searchEntry.reset(); // Next, if we're in one of the "more" modes or showing the details pane, close them else if (this._activePane != null) this._activePane.close(); @@ -423,64 +536,49 @@ Dash.prototype = { /***** Applications *****/ - let appsHeader = new SectionHeader("APPLICATIONS"); - this._appsSection = new Big.Box({ spacing: DEFAULT_PADDING }); - this._appsSection.append(appsHeader.actor, Big.BoxPackFlags.NONE); - - this._appsContent = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL }); - this._appsSection.append(this._appsContent, Big.BoxPackFlags.EXPAND); - this._appWell = new AppDisplay.AppWell(); - this._appsContent.append(this._appWell.actor, Big.BoxPackFlags.EXPAND); + let appsSection = new Section("APPLICATIONS"); + let appWell = new AppDisplay.AppWell(); + appsSection.content.append(appWell.actor, Big.BoxPackFlags.EXPAND); this._moreAppsPane = null; - appsHeader.moreLink.connect('activated', Lang.bind(this, function (link) { + appsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) { if (this._moreAppsPane == null) { - this._moreAppsPane = new ResultPane(this, this._detailsWidth); + this._moreAppsPane = new ResultPane(this); this._moreAppsPane.packResults(AppDisplay.AppDisplay, true); this._addPane(this._moreAppsPane); link.setPane(this._moreAppsPane); } })); - this.dashContainer.append(this._appsSection, Big.BoxPackFlags.NONE); + this.sectionArea.append(appsSection.actor, Big.BoxPackFlags.NONE); /***** Places *****/ - let placesSection = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, - spacing: DEFAULT_PADDING }); - let placesHeader = new SectionHeader("PLACES"); - placesSection.append(placesHeader.actor, Big.BoxPackFlags.NONE); - + let placesSection = new Section("PLACES", true); let placesDisplay = new Places.Places(); - placesSection.append(placesDisplay.actor, Big.BoxPackFlags.EXPAND); - - this.dashContainer.append(placesSection, Big.BoxPackFlags.NONE); + placesSection.content.append(placesDisplay.actor, Big.BoxPackFlags.EXPAND); + this.sectionArea.append(placesSection.actor, Big.BoxPackFlags.NONE); /***** Documents *****/ - this._docsSection = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, - spacing: DEFAULT_PADDING }); + let docsSection = new Section("RECENT DOCUMENTS"); + + let docDisplay = new DocDisplay.DocDisplay(); + docDisplay.load(); + docsSection.content.append(docDisplay.actor, Big.BoxPackFlags.EXPAND); + createPaneForDetails(this, docDisplay); + this._moreDocsPane = null; - - let docsHeader = new SectionHeader("RECENT DOCUMENTS"); - this._docsSection.append(docsHeader.actor, Big.BoxPackFlags.NONE); - - this._docDisplay = new DocDisplay.DocDisplay(); - this._docDisplay.load(); - this._docsSection.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND); - - createPaneForDetails(this, this._docDisplay, this._detailsWidth); - - docsHeader.moreLink.connect('activated', Lang.bind(this, function (link) { + docsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) { if (this._moreDocsPane == null) { - this._moreDocsPane = new ResultPane(this, this._detailsWidth); + this._moreDocsPane = new ResultPane(this); this._moreDocsPane.packResults(DocDisplay.DocDisplay, true); this._addPane(this._moreDocsPane); link.setPane(this._moreDocsPane); } })); - this.dashContainer.append(this._docsSection, Big.BoxPackFlags.EXPAND); + this.sectionArea.append(docsSection.actor, Big.BoxPackFlags.EXPAND); }, show: function() { @@ -489,9 +587,8 @@ Dash.prototype = { }, hide: function() { - this._firstSelectAfterOverviewShow = true; - if (this._searchEntry.entry.text != '') - this._searchEntry.entry.text = ''; + this._firstSelectAfterOverlayShow = true; + this._searchEntry.reset(); if (this._activePane != null) this._activePane.close(); }, diff --git a/js/ui/docDisplay.js b/js/ui/docDisplay.js index d2d4fa305..8dd133966 100644 --- a/js/ui/docDisplay.js +++ b/js/ui/docDisplay.js @@ -68,13 +68,13 @@ DocDisplayItem.prototype = { // Creates and returns a large preview icon, but only if this._docInfo is an image file // and we were able to generate a pixbuf from it successfully. - _createLargePreviewIcon : function(availableWidth, availableHeight) { + _createLargePreviewIcon : function() { if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf("image/") != 0) return null; try { return Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.NONE, - this._docInfo.uri, availableWidth, availableHeight); + this._docInfo.uri, -1, -1); } catch (e) { // An exception will be raised when the image format isn't know /* FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=591480: should diff --git a/js/ui/genericDisplay.js b/js/ui/genericDisplay.js index 3dbc4e92f..6f1347791 100644 --- a/js/ui/genericDisplay.js +++ b/js/ui/genericDisplay.js @@ -183,18 +183,14 @@ GenericDisplayItem.prototype = { /* * Returns an actor containing item details. In the future details can have more information than what * the preview pop-up has and be item-type specific. - * - * availableWidth - width available for displaying details */ - createDetailsActor: function(availableWidth) { + createDetailsActor: function() { let details = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, - spacing: PREVIEW_BOX_SPACING, - width: availableWidth }); + spacing: PREVIEW_BOX_SPACING }); let mainDetails = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL, - spacing: PREVIEW_BOX_SPACING, - width: availableWidth }); + spacing: PREVIEW_BOX_SPACING }); // Inner box with name and description let textDetails = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, @@ -216,7 +212,7 @@ GenericDisplayItem.prototype = { mainDetails.append(textDetails, Big.BoxPackFlags.EXPAND); let previewIcon = this._createPreviewIcon(); - let largePreviewIcon = this._createLargePreviewIcon(availableWidth, -1); + let largePreviewIcon = this._createLargePreviewIcon(); if (previewIcon != null && largePreviewIcon == null) { mainDetails.prepend(previewIcon, Big.BoxPackFlags.NONE); @@ -303,7 +299,7 @@ GenericDisplayItem.prototype = { //// Virtual protected methods //// // Creates and returns a large preview icon, but only if we have a detailed image. - _createLargePreviewIcon : function(availableWidth, availableHeight) { + _createLargePreviewIcon : function() { return null; }, @@ -465,9 +461,9 @@ GenericDisplay.prototype = { return null; }, - createDetailsForIndex: function(index, width, height) { + createDetailsForIndex: function(index) { let item = this._findDisplayedByIndex(index); - return item.createDetailsActor(width, height); + return item.createDetailsActor(); }, //// Protected methods //// diff --git a/js/ui/overview.js b/js/ui/overview.js index 9d42ed159..94b4cbdc4 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -109,7 +109,7 @@ Overview.prototype = { global.overlay_group.add_actor(this._group); // TODO - recalculate everything when desktop size changes - this._dash = new Dash.Dash(displayGridColumnWidth); + this._dash = new Dash.Dash(); this._group.add_actor(this._dash.actor); // Container to hold popup pane chrome. @@ -149,10 +149,34 @@ Overview.prototype = { relayout: function () { let global = Shell.Global.get(); - let contentHeight = global.screen_height - Panel.PANEL_HEIGHT; + let screenHeight = global.screen_height; + let screenWidth = global.screen_width; - this._dash.actor.set_position(0, Panel.PANEL_HEIGHT); - this._dash.actor.set_size(displayGridColumnWidth, contentHeight); + let contentHeight = screenHeight - Panel.PANEL_HEIGHT; + + let workspaceColumnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN; + let workspaceRowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN; + + this._workspacesWidth = displayGridColumnWidth * workspaceColumnsUsed + - WORKSPACE_GRID_PADDING * 2; + // We scale the vertical padding by (screenHeight / screenWidth) + // so that the workspace preserves its aspect ratio. + this._workspacesHeight = displayGridRowHeight * workspaceRowsUsed + - WORKSPACE_GRID_PADDING * (screenHeight / screenWidth) * 2; + + this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING; + this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth); + + let dashY = Panel.PANEL_HEIGHT; + this._dash.actor.set_position(0, dashY); + this._dash.actor.set_size(displayGridColumnWidth, screenHeight - dashY); + this._dash.searchArea.height = this._workspacesY - dashY; + this._dash.sectionArea.height = this._workspacesHeight; + + // place the 'Add Workspace' button in the bottom row of the grid + this._addButtonSize = Math.floor(displayGridRowHeight * 3/5); + this._addButtonX = this._workspacesX + this._workspacesWidth - this._addButtonSize; + this._addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5); this._backOver.set_position(0, Panel.PANEL_HEIGHT); this._backOver.set_size(global.screen_width, contentHeight); @@ -165,10 +189,12 @@ Overview.prototype = { this._transparentBackground.set_position(this._paneContainer.x, this._paneContainer.y); this._transparentBackground.set_size(global.screen_width - this._paneContainer.x, this._paneContainer.height); + + if (this._activeDisplayPane != null) + this._activeDisplayPane.actor.width = displayGridColumnWidth * 2; }, addPane: function (pane) { - pane.actor.width = displayGridColumnWidth * 2; this._paneContainer.append(pane.actor, Big.BoxPackFlags.NONE); // When a pane is displayed, we raise the transparent background to the top // and connect to button-release-event on it, then raise the pane above that. @@ -177,6 +203,7 @@ Overview.prototype = { let backgroundEventId = null; pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) { if (isOpen) { + pane.actor.width = displayGridColumnWidth * 2; this._activeDisplayPane = pane; this._transparentBackground.raise_top(); this._paneContainer.raise_top(); @@ -251,28 +278,13 @@ Overview.prototype = { this.animationInProgress = true; let global = Shell.Global.get(); - let screenWidth = global.screen_width; - let screenHeight = global.screen_height; this._dash.show(); - let columnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN; - let rowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN; - - let workspacesWidth = displayGridColumnWidth * columnsUsed - WORKSPACE_GRID_PADDING * 2; - // We scale the vertical padding by (screenHeight / screenWidth) so that the workspace preserves its aspect ratio. - let workspacesHeight = displayGridRowHeight * rowsUsed - WORKSPACE_GRID_PADDING * (screenHeight / screenWidth) * 2; - - let workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING; - let workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth); - - // place the 'Add Workspace' button in the bottom row of the grid - let addButtonSize = Math.floor(displayGridRowHeight * 3/5); - let addButtonX = workspacesX + workspacesWidth - addButtonSize; - let addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5); - - this._workspaces = new Workspaces.Workspaces(workspacesWidth, workspacesHeight, workspacesX, workspacesY, - addButtonSize, addButtonX, addButtonY); + /* TODO: make this stuff dynamic */ + this._workspaces = new Workspaces.Workspaces(this._workspacesWidth, this._workspacesHeight, + this._workspacesX, this._workspacesY, + this._addButtonSize, this._addButtonX, this._addButtonY); this._group.add_actor(this._workspaces.actor); // The workspaces actor is as big as the screen, so we have to raise the dash above it diff --git a/js/ui/panel.js b/js/ui/panel.js index fa9d6d047..c919ada85 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -20,8 +20,11 @@ const DEFAULT_PADDING = 4; const PANEL_ICON_SIZE = 24; -const PANEL_BACKGROUND_COLOR = new Clutter.Color(); -PANEL_BACKGROUND_COLOR.from_pixel(0x000000ff); +const BACKGROUND_TOP = new Clutter.Color(); +BACKGROUND_TOP.from_pixel(0x414141ff); +const BACKGROUND_BOTTOM = new Clutter.Color(); +BACKGROUND_BOTTOM.from_pixel(0x000000ff); + const PANEL_FOREGROUND_COLOR = new Clutter.Color(); PANEL_FOREGROUND_COLOR.from_pixel(0xffffffff); const SN_BACKGROUND_COLOR = new Clutter.Color(); @@ -83,8 +86,7 @@ AppPanelMenu.prototype = { this.actor.append(labelBox, Big.BoxPackFlags.NONE); this._startupBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL, - y_align: Big.BoxAlignment.CENTER - }); + y_align: Big.BoxAlignment.CENTER }); this.actor.append(this._startupBox, Big.BoxPackFlags.NONE); Main.overview.connect('hiding', Lang.bind(this, function () { @@ -161,9 +163,17 @@ Panel.prototype = { _init : function() { let global = Shell.Global.get(); - this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL, - background_color: PANEL_BACKGROUND_COLOR + + this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL }); + let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP, + BACKGROUND_BOTTOM); + this.actor.connect('notify::allocation', Lang.bind(this, function () { + let [width, height] = this.actor.get_size(); + backgroundGradient.set_size(width, height); + })); + this.actor.add_actor(backgroundGradient); + this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL, y_align: Big.BoxAlignment.CENTER, spacing: DEFAULT_PADDING, diff --git a/js/ui/workspaces.js b/js/ui/workspaces.js index e1c6aba52..0618518c2 100644 --- a/js/ui/workspaces.js +++ b/js/ui/workspaces.js @@ -398,7 +398,9 @@ Workspace.prototype = { // Mark the workspace selected/not-selected setSelected : function(selected) { - if (selected) { + let global = Shell.Global.get(); + // Don't draw a frame if we only have one workspace + if (selected && global.screen.n_workspaces > 1) { if (this._frame) return; @@ -1112,6 +1114,11 @@ Workspaces.prototype = { // FIXME: deal with windows on the lost workspaces } + + // Reset the selection state; if we went from > 1 workspace to 1, + // this has the side effect of removing the frame border + let activeIndex = global.screen.get_active_workspace_index(); + this._workspaces[activeIndex].setSelected(true); }, _activeWorkspaceChanged : function(wm, from, to, direction) {