diff --git a/js/Makefile.am b/js/Makefile.am index a3e4917db..c57d979a9 100644 --- a/js/Makefile.am +++ b/js/Makefile.am @@ -41,6 +41,7 @@ nobase_dist_js_DATA = \ ui/boxpointer.js \ ui/calendar.js \ ui/checkBox.js \ + ui/centerLayout.js \ ui/ctrlAltTab.js \ ui/dash.js \ ui/dateMenu.js \ diff --git a/js/ui/centerLayout.js b/js/ui/centerLayout.js new file mode 100644 index 000000000..38574fb58 --- /dev/null +++ b/js/ui/centerLayout.js @@ -0,0 +1,56 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Lang = imports.lang; +const Clutter = imports.gi.Clutter; + +const CenterLayout = new Lang.Class({ + Name: 'CenterLayout', + Extends: Clutter.BoxLayout, + + vfunc_allocate: function(container, box, flags) { + let rtl = container.get_text_direction() == Clutter.TextDirection.RTL; + + let availWidth = box.x2 - box.x1; + let availHeight = box.y2 - box.y1; + + // Assume that these are the first three widgets and they are all visible. + let [left, center, right] = container.get_children(); + + // Only support horizontal layouts for now. + let [leftMinWidth, leftNaturalWidth] = left.get_preferred_width(availWidth); + let [centerMinWidth, centerNaturalWidth] = center.get_preferred_width(availWidth); + let [rightMinWidth, rightNaturalWidth] = right.get_preferred_width(availWidth); + + let sideWidth = (availWidth - centerNaturalWidth) / 2; + + let childBox = new Clutter.ActorBox(); + childBox.y1 = box.y1; + childBox.y2 = box.y1 + availHeight; + + let leftSide = Math.min(Math.floor(sideWidth), leftNaturalWidth); + if (rtl) { + childBox.x1 = availWidth - leftSide; + childBox.x2 = availWidth; + } else { + childBox.x1 = 0; + childBox.x2 = leftSide; + } + childBox.x1 += box.x1; + left.allocate(childBox, flags); + + childBox.x1 = box.x1 + Math.ceil(sideWidth); + childBox.x2 = childBox.x1 + centerNaturalWidth; + center.allocate(childBox, flags); + + let rightSide = Math.min(Math.floor(sideWidth), rightNaturalWidth); + if (rtl) { + childBox.x1 = 0; + childBox.x2 = rightSide; + } else { + childBox.x1 = availWidth - rightSide; + childBox.x2 = availWidth; + } + childBox.x1 += box.x1; + right.allocate(childBox, flags); + } +}); diff --git a/js/ui/panel.js b/js/ui/panel.js index 9f3696346..d7b350b20 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -15,6 +15,7 @@ const Signals = imports.signals; const Atk = imports.gi.Atk; +const CenterLayout = imports.ui.centerLayout; const Config = imports.misc.config; const CtrlAltTab = imports.ui.ctrlAltTab; const DND = imports.ui.dnd; @@ -931,12 +932,47 @@ try { log('NMApplet is not supported. It is possible that your NetworkManager version is too old'); } +const PanelLayout = new Lang.Class({ + Name: 'PanelLayout', + Extends: CenterLayout.CenterLayout, + + vfunc_allocate: function(container, box, flags) { + this.parent(container, box, flags); + + let availWidth = box.x2 - box.x1; + let availHeight = box.y2 - box.y1; + + let [left, center, right, leftCorner, rightCorner] = container.get_children(); + let childBox = new Clutter.ActorBox(); + + let cornerMinWidth, cornerMinHeight; + let cornerWidth, cornerHeight; + + [cornerMinWidth, cornerWidth] = leftCorner.get_preferred_width(-1); + [cornerMinHeight, cornerHeight] = leftCorner.get_preferred_height(-1); + childBox.x1 = 0; + childBox.x2 = cornerWidth; + childBox.y1 = availHeight; + childBox.y2 = availHeight + cornerHeight; + leftCorner.allocate(childBox, flags); + + [cornerMinWidth, cornerWidth] = rightCorner.get_preferred_width(-1); + [cornerMinHeight, cornerHeight] = rightCorner.get_preferred_height(-1); + childBox.x1 = availWidth - cornerWidth; + childBox.x2 = availWidth; + childBox.y1 = availHeight; + childBox.y2 = availHeight + cornerHeight; + rightCorner.allocate(childBox, flags); + } +}); + const Panel = new Lang.Class({ Name: 'Panel', _init : function() { - this.actor = new Shell.GenericContainer({ name: 'panel', - reactive: true }); + this.actor = new St.Widget({ name: 'panel', + reactive: true, + layoutManager: new PanelLayout() }); this.actor._delegate = this; this.statusArea = {}; @@ -961,7 +997,6 @@ const Panel = new Lang.Class({ this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT); else this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT); - this.actor.add_actor(this._leftCorner.actor); if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) @@ -970,9 +1005,6 @@ const Panel = new Lang.Class({ this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT); this.actor.add_actor(this._rightCorner.actor); - this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth)); - this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight)); - this.actor.connect('allocate', Lang.bind(this, this._allocate)); this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); Main.layoutManager.panelBox.add(this.actor); @@ -983,83 +1015,6 @@ const Panel = new Lang.Class({ this._updatePanel(); }, - _getPreferredWidth: function(actor, forHeight, alloc) { - alloc.min_size = -1; - alloc.natural_size = Main.layoutManager.primaryMonitor.width; - }, - - _getPreferredHeight: function(actor, forWidth, alloc) { - // We don't need to implement this; it's forced by the CSS - alloc.min_size = -1; - alloc.natural_size = -1; - }, - - _allocate: function(actor, box, flags) { - let allocWidth = box.x2 - box.x1; - let allocHeight = box.y2 - box.y1; - - let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1); - let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1); - let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1); - - let sideWidth, centerWidth; - centerWidth = centerNaturalWidth; - sideWidth = (allocWidth - centerWidth) / 2; - - let childBox = new Clutter.ActorBox(); - - childBox.y1 = 0; - childBox.y2 = allocHeight; - if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) { - childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth), - leftNaturalWidth); - childBox.x2 = allocWidth; - } else { - childBox.x1 = 0; - childBox.x2 = Math.min(Math.floor(sideWidth), - leftNaturalWidth); - } - this._leftBox.allocate(childBox, flags); - - childBox.x1 = Math.ceil(sideWidth); - childBox.y1 = 0; - childBox.x2 = childBox.x1 + centerWidth; - childBox.y2 = allocHeight; - this._centerBox.allocate(childBox, flags); - - childBox.y1 = 0; - childBox.y2 = allocHeight; - if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) { - childBox.x1 = 0; - childBox.x2 = Math.min(Math.floor(sideWidth), - rightNaturalWidth); - } else { - childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth), - rightNaturalWidth); - childBox.x2 = allocWidth; - } - this._rightBox.allocate(childBox, flags); - - let cornerMinWidth, cornerMinHeight; - let cornerWidth, cornerHeight; - - [cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1); - [cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1); - childBox.x1 = 0; - childBox.x2 = cornerWidth; - childBox.y1 = allocHeight; - childBox.y2 = allocHeight + cornerHeight; - this._leftCorner.actor.allocate(childBox, flags); - - [cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1); - [cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1); - childBox.x1 = allocWidth - cornerWidth; - childBox.x2 = allocWidth; - childBox.y1 = allocHeight; - childBox.y2 = allocHeight + cornerHeight; - this._rightCorner.actor.allocate(childBox, flags); - }, - _onButtonPress: function(actor, event) { if (event.get_source() != actor) return false; diff --git a/tests/interactive/center-layout.js b/tests/interactive/center-layout.js new file mode 100644 index 000000000..cdbec4e49 --- /dev/null +++ b/tests/interactive/center-layout.js @@ -0,0 +1,30 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const St = imports.gi.St; + +const CenterLayout = imports.ui.centerLayout; +const UI = imports.testcommon.ui; + +function test() { + let stage = new Clutter.Stage({ user_resizable: true }); + UI.init(stage); + + //////////////////////////////////////////////////////////////////////////////// + + let container = new St.Widget({ style: 'border: 2px solid black;', + layout_manager: new CenterLayout.CenterLayout() }); + container.add_constraint(new Clutter.BindConstraint({ coordinate: Clutter.BindCoordinate.SIZE, source: stage })); + stage.add_actor(container); + + let left = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.RED), width: 300 }); + let center = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.BLUE), width: 100 }); + let right = new Clutter.Actor({ background_color: Clutter.Color.get_static(Clutter.StaticColor.YELLOW), width: 200 }); + + container.add_actor(left); + container.add_actor(center); + container.add_actor(right); + + UI.main(stage); +} +test();