Merge lp:~feng-kylin/unity/unityshell-rotated-kylin into lp:unity

Proposed by handsome_feng on 2015-12-22
Status: Merged
Approved by: Marco Trevisan (Treviño) on 2016-03-11
Approved revision: 4026
Merged at revision: 4089
Proposed branch: lp:~feng-kylin/unity/unityshell-rotated-kylin
Merge into: lp:unity
Diff against target: 3776 lines (+1504/-456)
49 files modified
com.canonical.Unity.gschema.xml (+9/-0)
dash/DashController.cpp (+22/-7)
hud/HudController.cpp (+11/-6)
launcher/BFBLauncherIcon.cpp (+4/-3)
launcher/BFBLauncherIcon.h (+1/-1)
launcher/EdgeBarrierController.cpp (+19/-4)
launcher/HudLauncherIcon.cpp (+5/-3)
launcher/HudLauncherIcon.h (+2/-3)
launcher/Launcher.cpp (+337/-94)
launcher/Launcher.h (+5/-0)
launcher/LauncherController.cpp (+57/-33)
launcher/LauncherControllerPrivate.h (+5/-3)
launcher/LauncherIcon.cpp (+8/-1)
launcher/QuicklistView.cpp (+205/-93)
launcher/SoftwareCenterLauncherIcon.cpp (+1/-0)
launcher/Tooltip.cpp (+213/-61)
launcher/Tooltip.h (+4/-0)
panel/PanelView.cpp (+4/-2)
plugins/unityshell/src/unityshell.cpp (+29/-15)
resources/launcher_arrow_btt_19.svg (+18/-0)
resources/launcher_arrow_btt_37.svg (+21/-0)
resources/launcher_arrow_outline_btt_19.svg (+15/-0)
resources/launcher_arrow_outline_btt_37.svg (+19/-0)
resources/launcher_arrow_ttb_19.svg (+16/-0)
resources/launcher_arrow_ttb_37.svg (+21/-0)
resources/launcher_pip_btt_19.svg (+18/-0)
resources/launcher_pip_btt_37.svg (+19/-0)
tests/autopilot/unity/emulators/__init__.py (+8/-1)
tests/autopilot/unity/emulators/launcher.py (+57/-26)
tests/autopilot/unity/tests/launcher/__init__.py (+10/-1)
tests/autopilot/unity/tests/launcher/test_icon_behavior.py (+13/-4)
tests/autopilot/unity/tests/launcher/test_keynav.py (+13/-13)
tests/autopilot/unity/tests/launcher/test_reveal.py (+2/-2)
tests/autopilot/unity/tests/launcher/test_scroll.py (+3/-2)
tests/autopilot/unity/tests/launcher/test_switcher.py (+1/-1)
tests/autopilot/unity/tests/launcher/test_tooltips.py (+2/-2)
tests/autopilot/unity/tests/test_dash.py (+6/-4)
tests/autopilot/unity/tests/test_hud.py (+30/-8)
tests/autopilot/unity/tests/test_quicklist.py (+16/-6)
tests/autopilot/unity/tests/test_spread.py (+1/-1)
tests/autopilot/unity/tests/test_wm_keybindings.py (+8/-2)
tests/test_bfb_launcher_icon.cpp (+1/-1)
tests/test_hud_launcher_icon.cpp (+1/-1)
tests/test_launcher.cpp (+35/-1)
tests/test_launcher_controller.cpp (+20/-0)
unity-shared/IconRenderer.cpp (+134/-37)
unity-shared/SpreadFilter.cpp (+5/-2)
unity-shared/UnitySettings.cpp (+39/-8)
unity-shared/UnitySettings.h (+11/-4)
To merge this branch: bzr merge lp:~feng-kylin/unity/unityshell-rotated-kylin
Reviewer Review Type Date Requested Status
Marco Trevisan (Treviño) 2015-12-22 Approve on 2016-03-11
Review via email: mp+281182@code.launchpad.net

Commit message

Launcher: add Bottom mode, so that the launcher can be positioned horisontally

Description of the change

Added an option that change the launcher from the left of the screen to the bottom.

To post a comment you must log in.
4012. By handsome_feng on 2015-12-22

Added a new EdgeBarrier for launcher on the bottom

Marco Trevisan (Treviño) (3v1n0) wrote :

From a high level prospective, I can say that launcher works quite well (nice work!).
I've not checked all the internals, but I like most of things I see.

The Hud should always show the embedded icon in this case, the changes are included in lp:~3v1n0/unity/rotated-improvements

Pips in switcher should be still horizontal, so please use this:
 - http://pastebin.ubuntu.com/14138663/

In general, when you call multiple times in the same function Settings::Instance().launcher_position(), please store the return value to a variable once and reuse it, instead of calling the property method.

Inside Launcher.cpp is probably worth to keep this saved as launcher_position_, so that you can reduce the overhead of calling the method everytime.

So, for now merge with lp:~3v1n0/unity/rotated-improvements, and please include the cleanups I mentioned.

4013. By handsome_feng on 2015-12-23

merge trunk

4014. By handsome_feng on 2015-12-23

merging lp:~3v1n0/unity/rotated-improvements

4015. By handsome_feng on 2015-12-23

cleanups

handsome_feng (feng-kylin) wrote :

> From a high level prospective, I can say that launcher works quite well (nice
> work!).
> I've not checked all the internals, but I like most of things I see.
>
> The Hud should always show the embedded icon in this case, the changes are
> included in lp:~3v1n0/unity/rotated-improvements
>
> Pips in switcher should be still horizontal, so please use this:
> - http://pastebin.ubuntu.com/14138663/
>
> In general, when you call multiple times in the same function
> Settings::Instance().launcher_position(), please store the return value to a
> variable once and reuse it, instead of calling the property method.
>
> Inside Launcher.cpp is probably worth to keep this saved as
> launcher_position_, so that you can reduce the overhead of calling the method
> everytime.
>
> So, for now merge with lp:~3v1n0/unity/rotated-improvements, and please
> include the cleanups I mentioned.

Done.

But change the "vertical" barriers depending on launcher position
cause the sticky edge do not work when launcher on the bottom.

4016. By handsome_feng on 2015-12-25

modified something about quicklist mousearea and launcher folding icon

4017. By handsome_feng on 2015-12-28

move the launcher-position from com.canonical.Unity to com.canonical.Unity.Launcher

4018. By handsome_feng on 2015-12-30

fix the error in test_launcher.cpp

4019. By handsome_feng on 2016-01-12

modified the x_offset for plugin 'expo' and 'scale'

4020. By handsome_feng on 2016-01-27

center the anchor of quicklist

4021. By handsome_feng on 2016-01-29

center the anchor of tooltip

4022. By handsome_feng on 2016-02-16

merge trunk

4023. By handsome_feng on 2016-03-02

fix the bug that launcher locate in the wrong position when scale changed

4024. By handsome_feng on 2016-03-02

merge trunk

4025. By handsome_feng on 2016-03-08

Recalculate launcher height

4026. By handsome_feng on 2016-03-11

Fix some fials in hud and dash autopilot tests

Marco Trevisan (Treviño) (3v1n0) wrote :

Looks good, there's just a slight change I'd like you to include: http://paste.ubuntu.com/15348300/

Thanks a lot for this huge contribution

review: Approve
Marco Trevisan (Treviño) (3v1n0) wrote :

So, this doesn't merge with latest trunk...

So please merge this against with trunk. Then merge lp:~feng-kylin/unity/MoveDashToBottom with this one.

4027. By handsome_feng on 2016-03-18

merge trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'com.canonical.Unity.gschema.xml'
2--- com.canonical.Unity.gschema.xml 2016-02-19 21:53:41 +0000
3+++ com.canonical.Unity.gschema.xml 2016-03-18 01:19:20 +0000
4@@ -9,6 +9,10 @@
5 <value nick="Not Expanded" value="0" />
6 <value nick="Expanded" value="1" />
7 </enum>
8+ <enum id="launcher-position-enum">
9+ <value nick="Left" value="0" />
10+ <value nick="Bottom" value="1" />
11+ </enum>
12 <enum id="desktop-type-enum">
13 <value nick="Ubuntu" value="0" />
14 <value nick="UbuntuKylin" value="1" />
15@@ -145,6 +149,11 @@
16 <summary>Version of last migration done</summary>
17 <description>This is a detection key for the favorite migration script to know whether the needed migration is done or not.</description>
18 </key>
19+ <key enum="launcher-position-enum" name="launcher-position">
20+ <default>"Left"</default>
21+ <summary>The position of launcher.</summary>
22+ <description>The position of launcher.</description>
23+ </key>
24 </schema>
25 <schema path="/com/canonical/unity/devices/" id="com.canonical.Unity.Devices" gettext-domain="unity">
26 <key type="as" name="blacklist">
27
28=== modified file 'dash/DashController.cpp'
29--- dash/DashController.cpp 2016-02-17 18:47:09 +0000
30+++ dash/DashController.cpp 2016-03-18 01:19:20 +0000
31@@ -230,15 +230,22 @@
32 nux::Geometry Controller::GetIdealWindowGeometry()
33 {
34 UScreen *uscreen = UScreen::GetDefault();
35- auto monitor_geo = uscreen->GetMonitorGeometry(GetIdealMonitor());
36- int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_);
37+ auto ideal_geo = uscreen->GetMonitorGeometry(GetIdealMonitor());
38+ int launcher_size = unity::Settings::Instance().LauncherSize(monitor_);
39
40 // We want to cover as much of the screen as possible to grab any mouse events outside
41 // of our window
42- return nux::Geometry (monitor_geo.x + launcher_width,
43- monitor_geo.y,
44- monitor_geo.width - launcher_width,
45- monitor_geo.height);
46+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
47+ {
48+ ideal_geo.x += launcher_size;
49+ ideal_geo.width -= launcher_size;
50+ }
51+ else
52+ {
53+ ideal_geo.height -= launcher_size;
54+ }
55+
56+ return ideal_geo;
57 }
58
59 void Controller::OnMonitorChanged(int primary, std::vector<nux::Geometry> const& monitors)
60@@ -262,8 +269,16 @@
61
62 void Controller::UpdateDashPosition()
63 {
64+ auto launcher_position = Settings::Instance().launcher_position();
65+ int left_offset = 0;
66 int top_offset = panel::Style::Instance().PanelHeight(monitor_);
67- int left_offset = unity::Settings::Instance().LauncherWidth(monitor_);
68+ int launcher_size = unity::Settings::Instance().LauncherSize(monitor_);
69+
70+ if (launcher_position == LauncherPosition::LEFT)
71+ {
72+ left_offset = launcher_size;
73+ }
74+
75 view_->SetMonitorOffset(left_offset, top_offset);
76 }
77
78
79=== modified file 'hud/HudController.cpp'
80--- hud/HudController.cpp 2015-04-17 20:32:59 +0000
81+++ hud/HudController.cpp 2016-03-18 01:19:20 +0000
82@@ -174,7 +174,7 @@
83
84 bool Controller::IsLockedToLauncher(int monitor)
85 {
86- if (launcher_locked_out)
87+ if (launcher_locked_out && Settings::Instance().launcher_position() == LauncherPosition::LEFT)
88 {
89 int primary_monitor = UScreen::GetDefault()->GetPrimaryMonitor();
90
91@@ -206,13 +206,13 @@
92 void Controller::SetIcon(std::string const& icon_name)
93 {
94 LOG_DEBUG(logger) << "setting icon to - " << icon_name;
95- int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_index_);
96+ int launcher_size = unity::Settings::Instance().LauncherSize(monitor_index_);
97
98 if (view_)
99 {
100 double scale = view_->scale();
101 int tsize = tile_size().CP(scale);
102- view_->SetIcon(icon_name, tsize, icon_size().CP(scale), launcher_width - tsize);
103+ view_->SetIcon(icon_name, tsize, icon_size().CP(scale), launcher_size - tsize);
104 }
105
106 ubus.SendMessage(UBUS_HUD_ICON_CHANGED, g_variant_new_string(icon_name.c_str()));
107@@ -253,7 +253,7 @@
108
109 if (IsLockedToLauncher(ideal_monitor))
110 {
111- int launcher_width = unity::Settings::Instance().LauncherWidth(ideal_monitor);
112+ int launcher_width = unity::Settings::Instance().LauncherSize(ideal_monitor);
113 geo.x += launcher_width;
114 geo.width -= launcher_width;
115 }
116@@ -269,12 +269,17 @@
117 monitor_index_ = CLAMP(GetIdealMonitor(), 0, static_cast<int>(UScreen::GetDefault()->GetMonitors().size()-1));
118
119 nux::Geometry const& geo = GetIdealWindowGeometry();
120- int launcher_width = unity::Settings::Instance().LauncherWidth(monitor_index_);
121
122 view_->QueueDraw();
123 window_->SetGeometry(geo);
124 panel::Style &panel_style = panel::Style::Instance();
125- view_->SetMonitorOffset(launcher_width, panel_style.PanelHeight(monitor_index_));
126+
127+ int horizontal_offset = 0;
128+
129+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
130+ horizontal_offset = unity::Settings::Instance().LauncherSize(monitor_index_);
131+
132+ view_->SetMonitorOffset(horizontal_offset, panel_style.PanelHeight(monitor_index_));
133 }
134
135 void Controller::OnMouseDownOutsideWindow(int x, int y,
136
137=== modified file 'launcher/BFBLauncherIcon.cpp'
138--- launcher/BFBLauncherIcon.cpp 2016-02-10 18:03:01 +0000
139+++ launcher/BFBLauncherIcon.cpp 2016-03-18 01:19:20 +0000
140@@ -31,10 +31,10 @@
141 namespace launcher
142 {
143
144-BFBLauncherIcon::BFBLauncherIcon(LauncherHideMode hide_mode)
145+BFBLauncherIcon::BFBLauncherIcon()
146 : SimpleLauncherIcon(IconType::HOME)
147 , reader_(dash::GSettingsScopesReader::GetDefault())
148- , launcher_hide_mode_(hide_mode)
149+ , launcher_hide_mode_(LAUNCHER_HIDE_NEVER)
150 {
151 position = Position::BEGIN;
152 SetQuirk(Quirk::VISIBLE, true);
153@@ -79,7 +79,8 @@
154 // If the hud is open, we hide the BFB if we have a locked launcher
155 else if (overlay_identity.Str() == "hud")
156 {
157- if (launcher_hide_mode_ == LAUNCHER_HIDE_NEVER)
158+ if (launcher_hide_mode_ == LAUNCHER_HIDE_NEVER &&
159+ Settings::Instance().launcher_position() == LauncherPosition::LEFT)
160 {
161 SetVisibleOnMonitor(overlay_monitor, !visible);
162 SkipQuirkAnimation(Quirk::VISIBLE, overlay_monitor);
163
164=== modified file 'launcher/BFBLauncherIcon.h'
165--- launcher/BFBLauncherIcon.h 2016-02-10 18:03:01 +0000
166+++ launcher/BFBLauncherIcon.h 2016-03-18 01:19:20 +0000
167@@ -37,7 +37,7 @@
168 {
169
170 public:
171- BFBLauncherIcon(LauncherHideMode hide_mode);
172+ BFBLauncherIcon();
173
174 virtual nux::Color BackgroundColor() const;
175 virtual nux::Color GlowColor();
176
177=== modified file 'launcher/EdgeBarrierController.cpp'
178--- launcher/EdgeBarrierController.cpp 2015-05-28 00:45:21 +0000
179+++ launcher/EdgeBarrierController.cpp 2016-03-18 01:19:20 +0000
180@@ -23,6 +23,7 @@
181 #include "EdgeBarrierControllerPrivate.h"
182 #include "Decaymulator.h"
183 #include <NuxCore/Logger.h>
184+#include "unity-shared/UnitySettings.h"
185 #include "unity-shared/UScreen.h"
186 #include "UnityCore/GLibSource.h"
187
188@@ -93,6 +94,7 @@
189 }));*/
190
191 uscreen->changed.connect(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnUScreenChanged));
192+ Settings::Instance().launcher_position.changed.connect(sigc::hide(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnOptionsChanged)));
193
194 parent_->force_disable.changed.connect(sigc::mem_fun(this, &EdgeBarrierController::Impl::OnForceDisableChanged));
195
196@@ -218,6 +220,7 @@
197 return;
198
199 bool edge_resist = parent_->sticky_edges();
200+ auto launcher_position = Settings::Instance().launcher_position();
201
202 for (unsigned i = 0; i < layout.size(); i++)
203 {
204@@ -246,10 +249,22 @@
205 if (!edge_resist && parent_->options()->hide_mode() == launcher::LauncherHideMode::LAUNCHER_HIDE_NEVER)
206 continue;
207
208- vertical_barrier->x1 = monitor.x;
209- vertical_barrier->x2 = monitor.x;
210- vertical_barrier->y1 = monitor.y;
211- vertical_barrier->y2 = monitor.y + monitor.height;
212+ if (launcher_position == LauncherPosition::LEFT)
213+ {
214+ vertical_barrier->x1 = monitor.x;
215+ vertical_barrier->x2 = monitor.x;
216+ vertical_barrier->y1 = monitor.y;
217+ vertical_barrier->y2 = monitor.y + monitor.height;
218+ }
219+ else
220+ {
221+ vertical_barrier->x1 = monitor.x;
222+ vertical_barrier->x2 = monitor.x + monitor.width;
223+ vertical_barrier->y1 = monitor.y + monitor.height;
224+ vertical_barrier->y2 = monitor.y + monitor.height;
225+ vertical_barrier->direction = DOWN;
226+ }
227+
228 vertical_barrier->index = i;
229
230 vertical_barrier->threshold = parent_->options()->edge_stop_velocity();
231
232=== modified file 'launcher/HudLauncherIcon.cpp'
233--- launcher/HudLauncherIcon.cpp 2014-01-31 16:19:39 +0000
234+++ launcher/HudLauncherIcon.cpp 2016-03-18 01:19:20 +0000
235@@ -22,6 +22,7 @@
236 #include <NuxCore/Logger.h>
237
238 #include "unity-shared/UBusMessages.h"
239+#include "unity-shared/UnitySettings.h"
240
241 #include "config.h"
242 #include <glib/gi18n-lib.h>
243@@ -32,9 +33,9 @@
244 {
245 DECLARE_LOGGER(logger, "unity.launcher.icon.hud");
246
247-HudLauncherIcon::HudLauncherIcon(LauncherHideMode hide_mode)
248+HudLauncherIcon::HudLauncherIcon()
249 : SingleMonitorLauncherIcon(IconType::HUD)
250- , launcher_hide_mode_(hide_mode)
251+ , launcher_hide_mode_(LAUNCHER_HIDE_NEVER)
252 , overlay_monitor_(0)
253 , single_launcher_(false)
254 , launcher_monitor_(0)
255@@ -90,7 +91,7 @@
256 {
257 if (single_launcher_ == single_launcher && launcher_monitor_ == launcher_monitor)
258 return;
259-
260+
261 single_launcher_ = single_launcher;
262 launcher_monitor_ = launcher_monitor;
263
264@@ -112,6 +113,7 @@
265 // If the hud is open, we show the HUD button if we have a locked launcher
266 if (overlay_identity.Str() == "hud" &&
267 launcher_hide_mode_ == LAUNCHER_HIDE_NEVER &&
268+ Settings::Instance().launcher_position() == LauncherPosition::LEFT &&
269 (!single_launcher_ || (single_launcher_ && launcher_monitor_ == overlay_monitor_)))
270 {
271 SetMonitor(visible ? overlay_monitor_ : -1);
272
273=== modified file 'launcher/HudLauncherIcon.h'
274--- launcher/HudLauncherIcon.h 2014-01-31 16:19:39 +0000
275+++ launcher/HudLauncherIcon.h 2016-03-18 01:19:20 +0000
276@@ -32,9 +32,8 @@
277
278 class HudLauncherIcon : public SingleMonitorLauncherIcon
279 {
280-
281 public:
282- HudLauncherIcon(LauncherHideMode hide_mode);
283+ HudLauncherIcon();
284
285 virtual nux::Color BackgroundColor() const;
286 virtual nux::Color GlowColor();
287@@ -53,7 +52,7 @@
288 nux::Color background_color_;
289 LauncherHideMode launcher_hide_mode_;
290 UBusManager ubus_manager_;
291- gint32 overlay_monitor_;
292+ gint32 overlay_monitor_;
293 bool single_launcher_;
294 int launcher_monitor_;
295 };
296
297=== modified file 'launcher/Launcher.cpp'
298--- launcher/Launcher.cpp 2015-11-25 23:16:57 +0000
299+++ launcher/Launcher.cpp 2016-03-18 01:19:20 +0000
300@@ -66,7 +66,7 @@
301
302 const float BACKLIGHT_STRENGTH = 0.9f;
303 const RawPixel ICON_PADDING = 6_em;
304-const RawPixel RIGHT_LINE_WIDTH = 1_em;
305+const RawPixel SIDE_LINE_WIDTH = 1_em;
306
307 const int ANIM_DURATION_SHORT = 125;
308 const int ANIM_DURATION_SHORT_SHORT = 100;
309@@ -126,6 +126,7 @@
310 , launcher_drag_delta_(0)
311 , launcher_drag_delta_max_(0)
312 , launcher_drag_delta_min_(0)
313+ , enter_x_(0)
314 , enter_y_(0)
315 , last_button_press_(0)
316 , urgent_animation_period_(0)
317@@ -135,6 +136,7 @@
318 , last_reveal_progress_(0.0f)
319 , drag_action_(nux::DNDACTION_NONE)
320 , bg_effect_helper_(this)
321+ , launcher_position_(unity::Settings::Instance().launcher_position())
322 , auto_hide_animation_(ANIM_DURATION_SHORT)
323 , hover_animation_(ANIM_DURATION)
324 , drag_over_animation_(ANIM_DURATION_LONG)
325@@ -184,11 +186,16 @@
326
327 TextureCache& cache = TextureCache::GetDefault();
328 launcher_sheen_ = cache.FindTexture("dash_sheen.png");
329- launcher_pressure_effect_ = cache.FindTexture("launcher_pressure_effect.png");
330
331 options.changed.connect(sigc::mem_fun(this, &Launcher::OnOptionsChanged));
332 monitor.changed.connect(sigc::mem_fun(this, &Launcher::OnMonitorChanged));
333
334+ launcher_position_changed_ = unity::Settings::Instance().launcher_position.changed.connect([this] (LauncherPosition const& position) {
335+ launcher_position_ = position;
336+ OnMonitorChanged(monitor);
337+ QueueDraw();
338+ });
339+
340 unity::Settings::Instance().dpi_changed.connect(sigc::mem_fun(this, &Launcher::OnDPIChanged));
341
342 auto_hide_animation_.updated.connect(redraw_cb);
343@@ -303,7 +310,12 @@
344 bool Launcher::MouseBeyondDragThreshold() const
345 {
346 if (GetActionState() == ACTION_DRAG_ICON)
347- return mouse_position_.x > GetGeometry().width + icon_size_.CP(cv_) / 2;
348+ {
349+ if (launcher_position_ == LauncherPosition::LEFT)
350+ return mouse_position_.x > GetGeometry().width + icon_size_.CP(cv_) / 2;
351+ else
352+ return mouse_position_.y < GetGeometry().y - icon_size_.CP(cv_) / 2;
353+ }
354 return false;
355 }
356
357@@ -343,23 +355,31 @@
358
359 void Launcher::SetDndDelta(float x, float y, nux::Geometry const& geo)
360 {
361- auto const& anchor = MouseIconIntersection(x, enter_y_);
362-
363+ auto const& anchor = (launcher_position_ == LauncherPosition::LEFT) ? MouseIconIntersection(x, enter_y_) : MouseIconIntersection(enter_x_, y);
364 int c_icon_size = icon_size_.CP(cv_);
365
366 if (anchor)
367 {
368- float position = y;
369+ float position =(launcher_position_ == LauncherPosition::LEFT) ? y: x;
370+
371 for (AbstractLauncherIcon::Ptr const& model_icon : *model_)
372 {
373 if (model_icon == anchor)
374 {
375 position += c_icon_size / 2;
376- launcher_drag_delta_ = enter_y_ - position;
377-
378- if (position + c_icon_size / 2 + launcher_drag_delta_ > geo.height)
379- launcher_drag_delta_ -= (position + c_icon_size / 2 + launcher_drag_delta_) - geo.height;
380-
381+ if (launcher_position_ == LauncherPosition::LEFT)
382+ {
383+ launcher_drag_delta_ = enter_y_ - position;
384+ if (position + c_icon_size / 2 + launcher_drag_delta_ > geo.height)
385+ launcher_drag_delta_ -= (position + c_icon_size / 2 + launcher_drag_delta_) - geo.height;
386+ }
387+ else
388+ {
389+ launcher_drag_delta_ = enter_x_ - position;
390+
391+ if (position + c_icon_size / 2 + launcher_drag_delta_ > geo.width)
392+ launcher_drag_delta_ -= (position + c_icon_size / 2 + launcher_drag_delta_) - geo.width;
393+ }
394 break;
395 }
396 float visibility = model_icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::VISIBLE, monitor());
397@@ -667,8 +687,9 @@
398 arg.skip = true;
399
400 int c_icon_size = icon_size_.CP(cv_);
401+ auto moving_center = (launcher_position_ == LauncherPosition::LEFT) ? center.y : center.x;
402 // goes for 0.0f when fully unfolded, to 1.0f folded
403- float folding_progress = CLAMP((center.y + c_icon_size - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f);
404+ float folding_progress = CLAMP((moving_center + c_icon_size - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f);
405 float unfold_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::UNFOLDED, monitor());
406 float active_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::ACTIVE, monitor());
407
408@@ -688,23 +709,41 @@
409
410 // icon is crossing threshold, start folding
411 center.z += folded_z_distance * folding_progress;
412- arg.rotation.x = animation_neg_rads * folding_progress;
413+ if (launcher_position_ == LauncherPosition::LEFT)
414+ arg.rotation.x = animation_neg_rads * folding_progress;
415+ else
416+ arg.rotation.y = animation_neg_rads * folding_progress;
417
418- float spacing_overlap = CLAMP((float)(center.y + (2.0f * half_size * size_modifier) + (SPACE_BETWEEN_ICONS.CP(cv_) * size_modifier) - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f);
419+ float spacing_overlap = CLAMP((float)(moving_center + (2.0f * half_size * size_modifier) + (SPACE_BETWEEN_ICONS.CP(cv_) * size_modifier) - folding_threshold) / (float) c_icon_size, 0.0f, 1.0f);
420 float spacing = (SPACE_BETWEEN_ICONS.CP(cv_) * (1.0f - spacing_overlap) + folded_spacing * spacing_overlap) * size_modifier;
421
422 nux::Point3 centerOffset;
423 float center_transit_progress = icon->GetQuirkProgress(AbstractLauncherIcon::Quirk::CENTER_SAVED, monitor());
424 if (center_transit_progress <= 1.0f)
425 {
426- int saved_center = icon->GetSavedCenter(monitor).y - parent_abs_geo.y;
427- centerOffset.y = (saved_center - (center.y + (half_size * size_modifier))) * (1.0f - center_transit_progress);
428- }
429-
430- center.y += half_size * size_modifier; // move to center
431-
432- arg.render_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y + centerOffset.y), roundf(center.z));
433- arg.logical_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y), roundf(center.z));
434+ if (launcher_position_ == LauncherPosition::LEFT)
435+ {
436+ int saved_center = icon->GetSavedCenter(monitor).y - parent_abs_geo.y;
437+ centerOffset.y = (saved_center - (center.y + (half_size * size_modifier))) * (1.0f - center_transit_progress);
438+ }
439+ else
440+ {
441+ int saved_center = icon->GetSavedCenter(monitor).x - parent_abs_geo.x;
442+ centerOffset.x = (saved_center - (center.x + (half_size * size_modifier))) * (1.0f - center_transit_progress);
443+ }
444+ }
445+ if (launcher_position_ == LauncherPosition::LEFT)
446+ {
447+ center.y += half_size * size_modifier; // move to center
448+ arg.render_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y + centerOffset.y), roundf(center.z));
449+ arg.logical_center = nux::Point3(roundf(center.x + icon_hide_offset), roundf(center.y), roundf(center.z));
450+ }
451+ else
452+ {
453+ center.x += half_size * size_modifier;
454+ arg.render_center = nux::Point3(roundf(center.x + centerOffset.x), roundf(center.y + icon_hide_offset), roundf(center.z));
455+ arg.logical_center = nux::Point3(roundf(center.x), roundf(center.y + icon_hide_offset), roundf(center.z));
456+ }
457
458 nux::Point3 icon_center(parent_abs_geo.x + roundf(center.x), parent_abs_geo.y + roundf(center.y), roundf(center.z));
459 icon->SetCenter(icon_center, monitor);
460@@ -715,7 +754,10 @@
461 drag_window_->SetAnimationTarget(icon_center.x, icon_center.y);
462 }
463
464- center.y += (half_size * size_modifier) + spacing; // move to end
465+ if (launcher_position_ == LauncherPosition::LEFT)
466+ center.y += (half_size * size_modifier) + spacing; // move to end
467+ else
468+ center.x += (half_size * size_modifier) + spacing;
469 }
470
471 float Launcher::DragLimiter(float x)
472@@ -757,21 +799,30 @@
473 float folded_size = c_icon_size * folding_not_constant;
474 float folded_spacing = SPACE_BETWEEN_ICONS.CP(cv_) * folding_not_constant;
475
476- center.x = geo.width / 2;
477- center.y = SPACE_BETWEEN_ICONS.CP(cv_);
478+ if (launcher_position_ == LauncherPosition::LEFT)
479+ {
480+ center.x = geo.width / 2;
481+ center.y = SPACE_BETWEEN_ICONS.CP(cv_);
482+ }
483+ else
484+ {
485+ center.x = SPACE_BETWEEN_ICONS.CP(cv_);
486+ center.y = geo.height / 2;
487+ }
488 center.z = 0;
489
490- int launcher_height = geo.height;
491+ int launcher_size = (launcher_position_ == LauncherPosition::LEFT) ? geo.height : geo.width;
492 folded_ = true;
493
494- // compute required height of launcher AND folding threshold
495- float sum = 0.0f + center.y;
496- float folding_threshold = launcher_height - c_icon_size / 2.5f;
497+ // compute required height/width of launcher AND folding threshold
498+ float sum = (launcher_position_ == LauncherPosition::LEFT) ? (0.0f + center.y) : (0.0f + center.x);
499+ float folding_threshold = launcher_size - c_icon_size / 2.5f;
500+
501 for (it = model_->begin(); it != model_->end(); ++it)
502 {
503 float visibility = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::VISIBLE, monitor());
504- float height = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility;
505- sum += height;
506+ float size = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility;
507+ sum += size;
508
509 // magic constant must some day be explained, for now suffice to say this constant prevents the bottom from "marching";
510 const float magic_constant = 1.3f;
511@@ -780,12 +831,12 @@
512 float active_progress = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::ACTIVE, monitor());
513
514 unfold_progress = CLAMP(unfold_progress + active_progress, 0.0f, 1.0f);
515- folding_threshold -= CLAMP(sum - launcher_height, 0.0f, height * magic_constant) * (folding_constant + (1.0f - folding_constant) * unfold_progress);
516+ folding_threshold -= CLAMP(sum - launcher_size, 0.0f, size * magic_constant) * (folding_constant + (1.0f - folding_constant) * unfold_progress);
517 }
518
519- if (sum - SPACE_BETWEEN_ICONS.CP(cv_) <= launcher_height)
520+ if (sum - SPACE_BETWEEN_ICONS.CP(cv_) <= launcher_size)
521 {
522- folding_threshold = launcher_height;
523+ folding_threshold = launcher_size;
524 folded_ = false;
525 }
526
527@@ -806,7 +857,10 @@
528 {
529 if (autohide_progress > 0.0f)
530 {
531- autohide_offset -= geo.width * autohide_progress;
532+ if (launcher_position_ == LauncherPosition::LEFT)
533+ autohide_offset -= geo.width * autohide_progress;
534+ else
535+ autohide_offset += geo.height * autohide_progress;
536 if (options()->auto_hide_animation() == FADE_AND_SLIDE)
537 *launcher_alpha = 1.0f - 0.5f * autohide_progress;
538 }
539@@ -816,7 +870,10 @@
540 if (options()->hide_mode != LAUNCHER_HIDE_NEVER)
541 {
542 float drag_hide_progress = dnd_hide_animation_.GetCurrentValue();
543- autohide_offset -= geo.width * 0.25f * drag_hide_progress;
544+ if (launcher_position_ == LauncherPosition::LEFT)
545+ autohide_offset -= geo.width * 0.25f * drag_hide_progress;
546+ else
547+ autohide_offset += geo.height * 0.25f * drag_hide_progress;
548 hide_machine_.SetQuirk(LauncherHideMachine::DND_PUSHED_OFF, (drag_hide_progress >= 1.0f));
549 }
550
551@@ -824,7 +881,12 @@
552 box_geo = geo;
553
554 if (options()->hide_mode != LAUNCHER_HIDE_NEVER || hide_machine_.GetQuirk(LauncherHideMachine::LOCK_HIDE))
555- box_geo.x += autohide_offset;
556+ {
557+ if (launcher_position_ == LauncherPosition::LEFT)
558+ box_geo.x += autohide_offset;
559+ else
560+ box_geo.y += autohide_offset;
561+ }
562
563 /* Why we need last_geo? It stores the last box_geo (note: as it is a static variable,
564 * it is initialized only first time). Infact we call SetDndDelta that calls MouseIconIntersection
565@@ -835,26 +897,35 @@
566 static nux::Geometry last_geo = box_geo;
567
568 // this happens on hover, basically its a flag and a value in one, we translate this into a dnd offset
569- if (enter_y_ != 0 && enter_y_ + c_icon_size / 2 > folding_threshold)
570- SetDndDelta(last_geo.x + last_geo.width / 2, center.y, geo);
571+ if (launcher_position_ == LauncherPosition::LEFT)
572+ {
573+ if (enter_y_ != 0 && enter_y_ + c_icon_size / 2 > folding_threshold)
574+ SetDndDelta(last_geo.x + last_geo.width / 2, center.y, geo);
575+ }
576+ else
577+ {
578+ if (enter_x_ != 0 && enter_x_ + c_icon_size / 2 > folding_threshold)
579+ SetDndDelta(center.x, last_geo.y + last_geo.height / 2, geo);
580+ }
581
582 // Update the last_geo value.
583 last_geo = box_geo;
584 enter_y_ = 0;
585+ enter_x_ = 0;
586
587 // logically dnd exit only restores to the clamped ranges
588 // hover_progress restores to 0
589 launcher_drag_delta_max_ = 0.0f;
590- launcher_drag_delta_min_ = MIN(0.0f, launcher_height - sum);
591+ launcher_drag_delta_min_ = MIN(0.0f, launcher_size - sum);
592
593 if (hover_progress > 0.0f && launcher_drag_delta_ != 0)
594 {
595- float delta_y = launcher_drag_delta_;
596+ float delta = launcher_drag_delta_;
597
598 if (launcher_drag_delta_ > launcher_drag_delta_max_)
599- delta_y = launcher_drag_delta_max_ + DragLimiter(delta_y - launcher_drag_delta_max_);
600+ delta = launcher_drag_delta_max_ + DragLimiter(delta - launcher_drag_delta_max_);
601 else if (launcher_drag_delta_ < launcher_drag_delta_min_)
602- delta_y = launcher_drag_delta_min_ + DragLimiter(delta_y - launcher_drag_delta_min_);
603+ delta = launcher_drag_delta_min_ + DragLimiter(delta - launcher_drag_delta_min_);
604
605 if (GetActionState() != ACTION_DRAG_LAUNCHER)
606 {
607@@ -862,17 +933,21 @@
608 float dnd_progress = std::pow(drag_over_animation_.GetCurrentValue(), 2);
609
610 if (launcher_drag_delta_ > launcher_drag_delta_max_)
611- delta_y = launcher_drag_delta_max_ + (delta_y - launcher_drag_delta_max_) * dnd_progress;
612+ delta = launcher_drag_delta_max_ + (delta - launcher_drag_delta_max_) * dnd_progress;
613 else if (launcher_drag_delta_ < launcher_drag_delta_min_)
614- delta_y = launcher_drag_delta_min_ + (delta_y - launcher_drag_delta_min_) * dnd_progress;
615+ delta = launcher_drag_delta_min_ + (delta - launcher_drag_delta_min_) * dnd_progress;
616
617 if (dnd_progress == 0.0f)
618- launcher_drag_delta_ = (int) delta_y;
619+ launcher_drag_delta_ = (int) delta;
620 }
621
622- delta_y *= hover_progress;
623- center.y += delta_y;
624- folding_threshold += delta_y;
625+ delta *= hover_progress;
626+ folding_threshold += delta;
627+
628+ if (launcher_position_ == LauncherPosition::LEFT)
629+ center.y += delta;
630+ else
631+ center.x += delta;
632 }
633 else
634 {
635@@ -903,17 +978,26 @@
636 for (it = model_->shelf_begin(); it != model_->shelf_end(); ++it)
637 {
638 float visibility = (*it)->GetQuirkProgress(AbstractLauncherIcon::Quirk::VISIBLE, monitor());
639- float height = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility;
640- shelf_sum += height;
641+ float size = (c_icon_size + SPACE_BETWEEN_ICONS.CP(cv_)) * visibility;
642+ shelf_sum += size;
643 }
644
645 // add bottom padding
646 if (shelf_sum > 0.0f)
647 shelf_sum += SPACE_BETWEEN_ICONS.CP(cv_);
648
649- float shelf_delta = MAX(((launcher_height - shelf_sum) + SPACE_BETWEEN_ICONS.CP(cv_)) - center.y, 0.0f);
650+ float shelf_delta = 0;
651+ if (launcher_position_ == LauncherPosition::LEFT)
652+ {
653+ shelf_delta = MAX(((launcher_size - shelf_sum) + SPACE_BETWEEN_ICONS.CP(cv_)) - center.y, 0.0f);
654+ center.y += shelf_delta;
655+ }
656+ else
657+ {
658+ shelf_delta = MAX(((launcher_size - shelf_sum) + SPACE_BETWEEN_ICONS.CP(cv_)) - center.x, 0.0f);
659+ center.x += shelf_delta;
660+ }
661 folding_threshold += shelf_delta;
662- center.y += shelf_delta;
663
664 force_show_window = false;
665
666@@ -1225,9 +1309,14 @@
667 auto monitor_geo = uscreen->GetMonitorGeometry(new_monitor);
668 unity::panel::Style &panel_style = panel::Style::Instance();
669 int panel_height = panel_style.PanelHeight(new_monitor);
670-
671+ RawPixel launcher_height = icon_size_ + ICON_PADDING * 2 + SIDE_LINE_WIDTH - 2;
672 cv_ = unity::Settings::Instance().em(monitor);
673- Resize(nux::Point(monitor_geo.x, monitor_geo.y + panel_height), monitor_geo.height - panel_height);
674+ launcher_height = launcher_height.CP(cv_) - (1_em).CP(cv_);
675+
676+ if (launcher_position_ == LauncherPosition::LEFT)
677+ Resize(nux::Point(monitor_geo.x, monitor_geo.y + panel_height), monitor_geo.height - panel_height);
678+ else
679+ Resize(nux::Point(monitor_geo.x, monitor_geo.y + monitor_geo.height - launcher_height), monitor_geo.width);
680
681 icon_renderer_->monitor = new_monitor;
682 icon_renderer_->scale = cv_->DPIScale();
683@@ -1240,6 +1329,7 @@
684 SetHideMode(options->hide_mode);
685 SetScrollInactiveIcons(options->scroll_inactive_icons);
686 SetLauncherMinimizeWindow(options->minimize_window_on_click);
687+ OnMonitorChanged(monitor);
688
689 if (model_)
690 {
691@@ -1318,7 +1408,10 @@
692 hovered_ = hovered;
693
694 if (!IsInKeyNavMode() && hovered_)
695+ {
696 enter_y_ = mouse_position_.y;
697+ enter_x_ = mouse_position_.x;
698+ }
699
700 if (folded_)
701 animation::StartOrReverseIf(hover_animation_, hovered_);
702@@ -1334,12 +1427,18 @@
703
704 bool Launcher::MouseOverTopScrollArea()
705 {
706- return mouse_position_.y < SCROLL_AREA_HEIGHT.CP(cv_);
707+ if (launcher_position_ == LauncherPosition::LEFT)
708+ return mouse_position_.y < SCROLL_AREA_HEIGHT.CP(cv_);
709+ else
710+ return mouse_position_.x < SCROLL_AREA_HEIGHT.CP(cv_);
711 }
712
713 bool Launcher::MouseOverBottomScrollArea()
714 {
715- return mouse_position_.y >= GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_);
716+ if (launcher_position_ == LauncherPosition::LEFT)
717+ return mouse_position_.y >= GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_);
718+ else
719+ return mouse_position_.x >= GetGeometry().width - SCROLL_AREA_HEIGHT.CP(cv_);
720 }
721
722 bool Launcher::OnScrollTimeout()
723@@ -1358,7 +1457,11 @@
724 }
725 else
726 {
727- int mouse_distance = (SCROLL_AREA_HEIGHT.CP(cv_) - mouse_position_.y);
728+ int mouse_distance = 0;
729+ if (launcher_position_ == LauncherPosition::LEFT)
730+ mouse_distance = (SCROLL_AREA_HEIGHT.CP(cv_) - mouse_position_.y);
731+ else
732+ mouse_distance = (SCROLL_AREA_HEIGHT.CP(cv_) - mouse_position_.x);
733 int speed = static_cast<float>(mouse_distance) / SCROLL_AREA_HEIGHT.CP(cv_) * SCROLL_FPS;
734 launcher_drag_delta_ += speed;
735 }
736@@ -1371,7 +1474,11 @@
737 }
738 else
739 {
740- int mouse_distance = (mouse_position_.y + 1) - (GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_));
741+ int mouse_distance = 0;
742+ if (launcher_position_ == LauncherPosition::LEFT)
743+ mouse_distance = (mouse_position_.y + 1) - (GetGeometry().height - SCROLL_AREA_HEIGHT.CP(cv_));
744+ else
745+ mouse_distance = (mouse_position_.x + 1) - (GetGeometry().width - SCROLL_AREA_HEIGHT.CP(cv_));
746 int speed = static_cast<float>(mouse_distance) / SCROLL_AREA_HEIGHT.CP(cv_) * SCROLL_FPS;
747 launcher_drag_delta_ -= speed;
748 }
749@@ -1533,7 +1640,10 @@
750 AbstractLauncherIcon::icon_size = icon_size_;
751
752 nux::Geometry const& parent_geo = parent_->GetGeometry();
753- Resize(nux::Point(parent_geo.x, parent_geo.y), parent_geo.height);
754+ if (launcher_position_ == LauncherPosition::LEFT)
755+ Resize(nux::Point(parent_geo.x, parent_geo.y), parent_geo.height);
756+ else
757+ Resize(nux::Point(parent_geo.x, parent_geo.y), parent_geo.width);
758 }
759
760 int Launcher::GetIconSize() const
761@@ -1541,13 +1651,24 @@
762 return icon_size_.CP(cv_);
763 }
764
765-void Launcher::Resize(nux::Point const& offset, int height)
766+void Launcher::Resize(nux::Point const& offset, int size)
767 {
768- RawPixel width = icon_size_ + ICON_PADDING * 2 + RIGHT_LINE_WIDTH - 2;
769-
770- width = width.CP(cv_);
771-
772- SetMaximumHeight(height);
773+ RawPixel width = 0, height = 0;
774+ if (launcher_position_ == LauncherPosition::LEFT)
775+ {
776+ width = icon_size_ + ICON_PADDING * 2 + SIDE_LINE_WIDTH - 2;
777+ width = width.CP(cv_);
778+ height = size;
779+ SetMaximumHeight(height);
780+ }
781+ else
782+ {
783+ height = icon_size_ + ICON_PADDING * 2 + SIDE_LINE_WIDTH - 2;
784+ height = height.CP(cv_);
785+ width = size;
786+ SetMaximumWidth(width);
787+ }
788+
789 SetGeometry(nux::Geometry(0, 0, width, height));
790 parent_->SetGeometry(nux::Geometry(offset.x, offset.y, width, height));
791
792@@ -1692,7 +1813,11 @@
793 bool force_show_window;
794 nux::Geometry const& geo_absolute = GetAbsoluteGeometry();
795 RenderArgs(args, bkg_box, &launcher_alpha, geo_absolute, force_show_window);
796- bkg_box.width -= RIGHT_LINE_WIDTH.CP(cv_);
797+
798+ if (launcher_position_ == LauncherPosition::LEFT)
799+ bkg_box.width -= SIDE_LINE_WIDTH.CP(cv_);
800+ else
801+ bkg_box.height -= SIDE_LINE_WIDTH.CP(cv_);
802
803 if (options()->hide_mode != LAUNCHER_HIDE_NEVER &&
804 bkg_box.x + bkg_box.width <= 0 &&
805@@ -1717,10 +1842,19 @@
806
807 int push_count = 1;
808
809- // clip vertically but not horizontally
810- GfxContext.PushClippingRectangle(nux::Geometry(base.x, bkg_box.y, base.width, bkg_box.height));
811+ if (launcher_position_ == LauncherPosition::LEFT)
812+ GfxContext.PushClippingRectangle(nux::Geometry(base.x, bkg_box.y, base.width, bkg_box.height));
813+ else
814+ GfxContext.PushClippingRectangle(nux::Geometry(bkg_box.x, base.y, bkg_box.width, base.height));
815
816 float reveal_progress = hide_machine_.reveal_progress;
817+ TextureCache& cache = TextureCache::GetDefault();
818+
819+ std::string launcher_pressure_icon = "launcher_pressure_effect.png";
820+ if (launcher_position_ == LauncherPosition::BOTTOM)
821+ launcher_pressure_icon = "launcher_pressure_effect_rotated.png";
822+
823+ launcher_pressure_effect_ = cache.FindTexture(launcher_pressure_icon);
824
825 if ((reveal_progress > 0 || last_reveal_progress_ > 0) && launcher_pressure_effect_.IsValid())
826 {
827@@ -1737,7 +1871,22 @@
828 }
829 nux::Color pressure_color = nux::color::White * last_reveal_progress_;
830 nux::TexCoordXForm texxform_pressure;
831- GfxContext.QRP_1Tex(base.x, base.y, launcher_pressure_effect_->GetWidth(), base.height,
832+
833+ int pressure_y = 0, pressure_width = 0, pressure_height = 0;
834+ if (launcher_position_ == LauncherPosition::LEFT)
835+ {
836+ pressure_y = base.y;
837+ pressure_width = launcher_pressure_effect_->GetWidth();
838+ pressure_height = base.height;
839+ }
840+ else
841+ {
842+ pressure_y = base.y + base.height - SIDE_LINE_WIDTH.CP(cv_) - launcher_pressure_effect_->GetHeight();
843+ pressure_width = base.width;
844+ pressure_height = launcher_pressure_effect_->GetHeight();
845+ }
846+
847+ GfxContext.QRP_1Tex(base.x, pressure_y, pressure_width, pressure_height,
848 launcher_pressure_effect_->GetDeviceTexture(),
849 texxform_pressure,
850 pressure_color);
851@@ -1749,7 +1898,12 @@
852 {
853 nux::ObjectPtr<nux::IOpenGLBaseTexture> blur_texture;
854
855- if (BackgroundEffectHelper::blur_type != unity::BLUR_NONE && (bkg_box.x + bkg_box.width > 0))
856+ bool visible = false;
857+ if ((launcher_position_ == LauncherPosition::LEFT && (bkg_box.x + bkg_box.width > 0)) ||
858+ (launcher_position_ == LauncherPosition::BOTTOM && (bkg_box.y < bkg_box.height)))
859+ visible = true;
860+
861+ if (BackgroundEffectHelper::blur_type != unity::BLUR_NONE && visible)
862 {
863 blur_texture = bg_effect_helper_.GetBlurRegion();
864 }
865@@ -1849,13 +2003,42 @@
866 icon_renderer_->PreprocessIcons(args, base);
867 EventLogic();
868
869+ if (!IsOverlayOpen() && launcher_position_ == LauncherPosition::BOTTOM)
870+ {
871+ const double top_line_opacity = 0.15f * launcher_alpha;
872+
873+ gPainter.Paint2DQuadColor(GfxContext,
874+ nux::Geometry(bkg_box.x,
875+ bkg_box.y,
876+ bkg_box.width,
877+ SIDE_LINE_WIDTH.CP(cv_)),
878+ nux::color::White * top_line_opacity);
879+
880+ gPainter.Paint2DQuadColor(GfxContext,
881+ nux::Geometry(bkg_box.x,
882+ bkg_box.y,
883+ bkg_box.width,
884+ 8),
885+ nux::Color(0x70000000),
886+ nux::Color(0x00000000),
887+ nux::Color(0x00000000),
888+ nux::Color(0x70000000));
889+ }
890+
891 /* draw launcher */
892 for (rev_it = args.rbegin(); rev_it != args.rend(); ++rev_it)
893 {
894 if ((*rev_it).stick_thingy)
895- gPainter.Paint2DQuadColor(GfxContext,
896- nux::Geometry(bkg_box.x, (*rev_it).render_center.y - 3, bkg_box.width, 2),
897- nux::Color(0xAAAAAAAA));
898+ {
899+ if (launcher_position_ == LauncherPosition::LEFT)
900+ gPainter.Paint2DQuadColor(GfxContext,
901+ nux::Geometry(bkg_box.x, (*rev_it).render_center.y - 3, bkg_box.width, 2),
902+ nux::Color(0xAAAAAAAA));
903+ else
904+ gPainter.Paint2DQuadColor(GfxContext,
905+ nux::Geometry((*rev_it).render_center.x - 3, bkg_box.y, 2, bkg_box.height),
906+ nux::Color(0xAAAAAAAA));
907+ }
908
909 if ((*rev_it).skip)
910 continue;
911@@ -1863,14 +2046,14 @@
912 icon_renderer_->RenderIcon(GfxContext, *rev_it, bkg_box, base);
913 }
914
915- if (!IsOverlayOpen())
916+ if (!IsOverlayOpen() && launcher_position_ == LauncherPosition::LEFT)
917 {
918 const double right_line_opacity = 0.15f * launcher_alpha;
919
920 gPainter.Paint2DQuadColor(GfxContext,
921 nux::Geometry(bkg_box.x + bkg_box.width,
922 bkg_box.y,
923- RIGHT_LINE_WIDTH.CP(cv_),
924+ SIDE_LINE_WIDTH.CP(cv_),
925 bkg_box.height),
926 nux::color::White * right_line_opacity);
927
928@@ -1929,7 +2112,18 @@
929 void Launcher::StartIconDragRequest(int x, int y)
930 {
931 auto const& abs_geo = GetAbsoluteGeometry();
932- auto const& drag_icon = MouseIconIntersection(abs_geo.width / 2.0f, y);
933+ int mouse_x = 0, mouse_y = 0;
934+ if (launcher_position_ == LauncherPosition::LEFT)
935+ {
936+ mouse_x = abs_geo.width / 2.0f;
937+ mouse_y = y;
938+ }
939+ else
940+ {
941+ mouse_x = x;
942+ mouse_y = abs_geo.height / 2.0f;
943+ }
944+ auto const& drag_icon = MouseIconIntersection(mouse_x, mouse_y);
945
946 // FIXME: nux doesn't give nux::GetEventButton (button_flags) there, relying
947 // on an internal Launcher property then
948@@ -2064,7 +2258,18 @@
949 return;
950
951 auto const& launcher_geo = GetGeometry();
952- auto const& hovered_icon = MouseIconIntersection((launcher_geo.x + launcher_geo.width) / 2.0, y - GetAbsoluteY());
953+ int mouse_x = 0, mouse_y = 0;
954+ if (launcher_position_ == LauncherPosition::LEFT)
955+ {
956+ mouse_x = (launcher_geo.x + launcher_geo.width) / 2.0;
957+ mouse_y = y - GetAbsoluteY();
958+ }
959+ else
960+ {
961+ mouse_x = x - GetAbsoluteX();
962+ mouse_y = (launcher_geo.y + launcher_geo.height) / 2.0;
963+ }
964+ auto const& hovered_icon = MouseIconIntersection(mouse_x, mouse_y);
965 bool mouse_beyond_drag_threshold = MouseBeyondDragThreshold();
966
967 if (hovered_icon && drag_icon_ != hovered_icon)
968@@ -2088,7 +2293,8 @@
969 if (!icon->IsVisibleOnMonitor(monitor))
970 continue;
971
972- if (y >= icon->GetCenter(monitor).y)
973+ if ((launcher_position_ == LauncherPosition::LEFT && y >= icon->GetCenter(monitor).y) ||
974+ (launcher_position_ == LauncherPosition::BOTTOM && x >= icon->GetCenter(monitor).x))
975 {
976 model_->ReorderAfter(drag_icon_, icon);
977 break;
978@@ -2154,12 +2360,18 @@
979 if (GetActionState() == ACTION_NONE)
980 {
981 #ifdef USE_X11
982- if (nux::Abs(dnd_delta_y_) >= nux::Abs(dnd_delta_x_))
983+ if (nux::Abs(dnd_delta_y_) >= nux::Abs(dnd_delta_x_) && launcher_position_ == LauncherPosition::LEFT)
984 {
985 launcher_drag_delta_ += dnd_delta_y_;
986 SetActionState(ACTION_DRAG_LAUNCHER);
987 hide_machine_.SetQuirk(LauncherHideMachine::VERTICAL_SLIDE_ACTIVE, true);
988 }
989+ else if (nux::Abs(dnd_delta_x_) >= nux::Abs(dnd_delta_y_) && launcher_position_ == LauncherPosition::BOTTOM)
990+ {
991+ launcher_drag_delta_ += dnd_delta_x_;
992+ SetActionState(ACTION_DRAG_LAUNCHER);
993+ hide_machine_.SetQuirk(LauncherHideMachine::VERTICAL_SLIDE_ACTIVE, true);
994+ }
995 else
996 {
997 // We we can safely start the icon drag, from the original mouse-down position
998@@ -2170,7 +2382,10 @@
999 }
1000 else if (GetActionState() == ACTION_DRAG_LAUNCHER)
1001 {
1002- launcher_drag_delta_ += dy;
1003+ if (launcher_position_ == LauncherPosition::LEFT)
1004+ launcher_drag_delta_ += dy;
1005+ else
1006+ launcher_drag_delta_ += dx;
1007 }
1008 else if (GetActionState() == ACTION_DRAG_ICON)
1009 {
1010@@ -2256,20 +2471,42 @@
1011 nux::Geometry const& abs_geo = GetAbsoluteGeometry();
1012
1013 bool apply_to_reveal = false;
1014- if (event->x >= abs_geo.x && event->x <= abs_geo.x + abs_geo.width)
1015+ if (launcher_position_ == LauncherPosition::LEFT)
1016 {
1017- if (!hidden_)
1018- return ui::EdgeBarrierSubscriber::Result::ALREADY_HANDLED;
1019+ if (event->x >= abs_geo.x && event->x <= abs_geo.x + abs_geo.width)
1020+ {
1021+ if (!hidden_)
1022+ return ui::EdgeBarrierSubscriber::Result::ALREADY_HANDLED;
1023
1024- if (options()->reveal_trigger == RevealTrigger::EDGE)
1025- {
1026- if (event->y >= abs_geo.y)
1027- apply_to_reveal = true;
1028+ if (options()->reveal_trigger == RevealTrigger::EDGE)
1029+ {
1030+ if (event->y >= abs_geo.y)
1031+ apply_to_reveal = true;
1032+ }
1033+ else if (options()->reveal_trigger == RevealTrigger::CORNER)
1034+ {
1035+ if (event->y < abs_geo.y)
1036+ apply_to_reveal = true;
1037+ }
1038 }
1039- else if (options()->reveal_trigger == RevealTrigger::CORNER)
1040+ }
1041+ else
1042+ {
1043+ if (event->y >= abs_geo.y && event->y <= abs_geo.y + abs_geo.height)
1044 {
1045- if (event->y < abs_geo.y)
1046- apply_to_reveal = true;
1047+ if (!hidden_)
1048+ return ui::EdgeBarrierSubscriber::Result::ALREADY_HANDLED;
1049+
1050+ if (options()->reveal_trigger == RevealTrigger::EDGE)
1051+ {
1052+ if (event->x >= abs_geo.x + panel::Style::Instance().PanelHeight(monitor()))
1053+ apply_to_reveal = true;
1054+ }
1055+ else if (options()->reveal_trigger == RevealTrigger::CORNER)
1056+ {
1057+ if (event->x < abs_geo.x + panel::Style::Instance().PanelHeight(monitor()))
1058+ apply_to_reveal = true;
1059+ }
1060 }
1061 }
1062
1063@@ -2455,6 +2692,7 @@
1064 arg.render_center = nux::Point3(roundf(texture->GetWidth() / 2.0f), roundf(texture->GetHeight() / 2.0f), 0.0f);
1065 arg.logical_center = arg.render_center;
1066 arg.rotation.x = 0.0f;
1067+ arg.rotation.y = 0.0f;
1068 arg.running_arrow = false;
1069 arg.active_arrow = false;
1070 arg.skip = false;
1071@@ -2616,8 +2854,11 @@
1072
1073 if (options()->hide_mode != LAUNCHER_HIDE_NEVER)
1074 {
1075- if (monitor() == 0 && !IsOverlayOpen() && mouse_position_.x == 0 && !drag_edge_touching_ &&
1076- mouse_position_.y <= (parent_->GetGeometry().height - icon_size_.CP(cv_) - 2 * SPACE_BETWEEN_ICONS.CP(cv_)))
1077+ if ((monitor() == 0 && !IsOverlayOpen() && mouse_position_.x == 0 && !drag_edge_touching_) &&
1078+ ((launcher_position_ == LauncherPosition::LEFT &&
1079+ mouse_position_.y <= (parent_->GetGeometry().height - icon_size_.CP(cv_) - 2 * SPACE_BETWEEN_ICONS.CP(cv_))) ||
1080+ (launcher_position_ == LauncherPosition::BOTTOM &&
1081+ mouse_position_.x <= (parent_->GetGeometry().width - icon_size_.CP(cv_) - 2 * SPACE_BETWEEN_ICONS.CP(cv_)))))
1082 {
1083 if (dnd_hovered_icon_)
1084 {
1085@@ -2628,7 +2869,9 @@
1086 animation::StartOrReverse(dnd_hide_animation_, animation::Direction::FORWARD);
1087 drag_edge_touching_ = true;
1088 }
1089- else if (mouse_position_.x != 0 && drag_edge_touching_)
1090+ else if (drag_edge_touching_ &&
1091+ ((launcher_position_ == LauncherPosition::LEFT && mouse_position_.x != 0) ||
1092+ (launcher_position_ == LauncherPosition::BOTTOM && mouse_position_.y != 0)))
1093 {
1094 animation::StartOrReverse(dnd_hide_animation_, animation::Direction::BACKWARD);
1095 drag_edge_touching_ = false;
1096
1097=== modified file 'launcher/Launcher.h'
1098--- launcher/Launcher.h 2015-05-21 16:30:26 +0000
1099+++ launcher/Launcher.h 2016-03-18 01:19:20 +0000
1100@@ -43,6 +43,7 @@
1101 #include "LauncherHoverMachine.h"
1102 #include "unity-shared/MockableBaseWindow.h"
1103 #include "unity-shared/UBusWrapper.h"
1104+#include "unity-shared/UnitySettings.h"
1105 #include "SoftwareCenterLauncherIcon.h"
1106 #include "TooltipManager.h"
1107
1108@@ -345,6 +346,7 @@
1109 int launcher_drag_delta_;
1110 int launcher_drag_delta_max_;
1111 int launcher_drag_delta_min_;
1112+ int enter_x_;
1113 int enter_y_;
1114 int last_button_press_;
1115 int drag_icon_position_;
1116@@ -367,6 +369,9 @@
1117 BaseTexturePtr launcher_pressure_effect_;
1118 BackgroundEffectHelper bg_effect_helper_;
1119
1120+ LauncherPosition launcher_position_;
1121+ connection::Wrapper launcher_position_changed_;
1122+
1123 nux::animation::AnimateValue<float> auto_hide_animation_;
1124 nux::animation::AnimateValue<float> hover_animation_;
1125 nux::animation::AnimateValue<float> drag_over_animation_;
1126
1127=== modified file 'launcher/LauncherController.cpp'
1128--- launcher/LauncherController.cpp 2016-03-07 18:38:06 +0000
1129+++ launcher/LauncherController.cpp 2016-03-18 01:19:20 +0000
1130@@ -34,13 +34,11 @@
1131 #include "VolumeLauncherIcon.h"
1132 #include "FavoriteStore.h"
1133 #include "FileManagerLauncherIcon.h"
1134-#include "HudLauncherIcon.h"
1135 #include "LauncherController.h"
1136 #include "LauncherControllerPrivate.h"
1137 #include "SoftwareCenterLauncherIcon.h"
1138 #include "ExpoLauncherIcon.h"
1139 #include "TrashLauncherIcon.h"
1140-#include "BFBLauncherIcon.h"
1141 #include "unity-shared/AppStreamApplication.h"
1142 #include "unity-shared/IconRenderer.h"
1143 #include "unity-shared/UScreen.h"
1144@@ -107,6 +105,8 @@
1145 , model_(std::make_shared<LauncherModel>())
1146 , xdnd_manager_(xdnd_manager)
1147 , device_section_(std::make_shared<DeviceLauncherSection>())
1148+ , bfb_icon_(new BFBLauncherIcon())
1149+ , hud_icon_(new HudLauncherIcon())
1150 , expo_icon_(new ExpoLauncherIcon())
1151 , desktop_icon_(new DesktopLauncherIcon())
1152 , edge_barriers_(edge_barriers)
1153@@ -130,20 +130,28 @@
1154 remote_model_.entry_added.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteAdded));
1155 remote_model_.entry_removed.connect(sigc::mem_fun(this, &Impl::OnLauncherEntryRemoteRemoved));
1156
1157- LauncherHideMode hide_mode = parent_->options()->hide_mode;
1158- BFBLauncherIcon* bfb = new BFBLauncherIcon(hide_mode);
1159- RegisterIcon(AbstractLauncherIcon::Ptr(bfb));
1160+ auto hide_mode = parent_->options()->hide_mode();
1161+ bfb_icon_->SetHideMode(hide_mode);
1162+ RegisterIcon(AbstractLauncherIcon::Ptr(bfb_icon_));
1163
1164- HudLauncherIcon* hud = new HudLauncherIcon(hide_mode);
1165- RegisterIcon(AbstractLauncherIcon::Ptr(hud));
1166- hud_icon_ = hud;
1167+ hud_icon_->SetHideMode(hide_mode);
1168+ RegisterIcon(AbstractLauncherIcon::Ptr(hud_icon_));
1169
1170 TrashLauncherIcon* trash = new TrashLauncherIcon();
1171 RegisterIcon(AbstractLauncherIcon::Ptr(trash));
1172
1173- parent_->options()->hide_mode.changed.connect([bfb, hud](LauncherHideMode mode) {
1174- bfb->SetHideMode(mode);
1175- hud->SetHideMode(mode);
1176+ parent_->options()->hide_mode.changed.connect([this] (LauncherHideMode mode) {
1177+ bfb_icon_->SetHideMode(mode);
1178+ hud_icon_->SetHideMode(mode);
1179+ });
1180+
1181+ parent_->multiple_launchers.changed.connect([this] (bool value) {
1182+ UScreen* uscreen = UScreen::GetDefault();
1183+ auto monitors = uscreen->GetMonitors();
1184+ int primary = uscreen->GetPrimaryMonitor();
1185+ EnsureLaunchers(primary, monitors);
1186+ parent_->options()->show_for_all = !value;
1187+ hud_icon_->SetSingleLauncher(!value, primary);
1188 });
1189
1190 WindowManager& wm = WindowManager::Default();
1191@@ -1049,16 +1057,7 @@
1192 : options(std::make_shared<Options>())
1193 , multiple_launchers(true)
1194 , pimpl(new Impl(this, xdnd_manager, edge_barriers))
1195-{
1196- multiple_launchers.changed.connect([this] (bool value) {
1197- UScreen* uscreen = UScreen::GetDefault();
1198- auto monitors = uscreen->GetMonitors();
1199- int primary = uscreen->GetPrimaryMonitor();
1200- pimpl->EnsureLaunchers(primary, monitors);
1201- options()->show_for_all = !value;
1202- pimpl->hud_icon_->SetSingleLauncher(!value, primary);
1203- });
1204-}
1205+{}
1206
1207 Controller::~Controller()
1208 {}
1209@@ -1446,35 +1445,60 @@
1210
1211 switch (keysym)
1212 {
1213- // up (move selection up or go to global-menu if at top-most icon)
1214+ // up
1215 case NUX_VK_UP:
1216 case NUX_KP_UP:
1217- parent_->KeyNavPrevious();
1218+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1219+ // move selection up or go to global-menu if at top-most icon
1220+ parent_->KeyNavPrevious();
1221+ else
1222+ OpenQuicklist();
1223 break;
1224
1225- // down (move selection down and unfold launcher if needed)
1226+ // down
1227 case NUX_VK_DOWN:
1228 case NUX_KP_DOWN:
1229- parent_->KeyNavNext();
1230- break;
1231-
1232- // super/control/esc/left (close quicklist or exit laucher key-focus)
1233+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1234+ // move selection down and unfold launcher if needed
1235+ parent_->KeyNavNext();
1236+ else
1237+ // exit launcher key-focus
1238+ parent_->KeyNavTerminate(false);
1239+ break;
1240+
1241+ // left
1242+ case NUX_VK_LEFT:
1243+ case NUX_KP_LEFT:
1244+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1245+ parent_->KeyNavTerminate(false);
1246+ else
1247+ // move selection left or go to global-menu if at top-most icon or close quicklist
1248+ parent_->KeyNavPrevious();
1249+ break;
1250+
1251+ // right
1252+ case NUX_VK_RIGHT:
1253+ case NUX_KP_RIGHT:
1254+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1255+ OpenQuicklist();
1256+ else
1257+ // move selection right and unfold launcher if needed
1258+ parent_->KeyNavNext();
1259+ break;
1260+
1261+ // super/control/esc (close quicklist or exit laucher key-focus)
1262 case NUX_VK_LWIN:
1263 case NUX_VK_RWIN:
1264 case NUX_VK_CONTROL:
1265- case NUX_VK_LEFT:
1266- case NUX_KP_LEFT:
1267 case NUX_VK_ESCAPE:
1268 // hide again
1269 parent_->KeyNavTerminate(false);
1270 break;
1271
1272- // right/shift-f10 (open quicklist of currently selected icon)
1273+ // shift-f10 (open quicklist of currently selected icon)
1274 case XK_F10:
1275 if (!(state & nux::NUX_STATE_SHIFT))
1276 break;
1277- case NUX_VK_RIGHT:
1278- case NUX_KP_RIGHT:
1279 case XK_Menu:
1280 OpenQuicklist();
1281 break;
1282
1283=== modified file 'launcher/LauncherControllerPrivate.h'
1284--- launcher/LauncherControllerPrivate.h 2016-02-19 12:36:57 +0000
1285+++ launcher/LauncherControllerPrivate.h 2016-03-18 01:19:20 +0000
1286@@ -36,10 +36,11 @@
1287 #include "LauncherEntryRemote.h"
1288 #include "LauncherEntryRemoteModel.h"
1289 #include "LauncherModel.h"
1290+#include "BFBLauncherIcon.h"
1291+#include "HudLauncherIcon.h"
1292 #include "SoftwareCenterLauncherIcon.h"
1293 #include "unity-shared/UBusWrapper.h"
1294 #include "XdndManager.h"
1295-#include "HudLauncherIcon.h"
1296
1297 namespace unity
1298 {
1299@@ -124,9 +125,10 @@
1300 XdndManager::Ptr xdnd_manager_;
1301 DeviceLauncherSection::Ptr device_section_;
1302 LauncherEntryRemoteModel remote_model_;
1303+ BFBLauncherIcon* bfb_icon_;
1304+ HudLauncherIcon* hud_icon_;
1305 AbstractLauncherIcon::Ptr expo_icon_;
1306 AbstractLauncherIcon::Ptr desktop_icon_;
1307- HudLauncherIcon* hud_icon_;
1308
1309 #ifdef USE_X11
1310 ui::EdgeBarrierController::Ptr edge_barriers_;
1311@@ -148,7 +150,7 @@
1312
1313 connection::Wrapper launcher_key_press_connection_;
1314 connection::Wrapper launcher_event_outside_connection_;
1315- connection::Wrapper launcher_key_nav_terminate_;
1316+ connection::Wrapper launcher_key_nav_terminate_;
1317 connection::Wrapper average_color_connection_;
1318 };
1319
1320
1321=== modified file 'launcher/LauncherIcon.cpp'
1322--- launcher/LauncherIcon.cpp 2016-02-25 15:59:41 +0000
1323+++ launcher/LauncherIcon.cpp 2016-03-18 01:19:20 +0000
1324@@ -465,7 +465,14 @@
1325 nux::Point LauncherIcon::GetTipPosition(int monitor) const
1326 {
1327 auto const& converter = Settings::Instance().em(monitor);
1328- return nux::Point(_center[monitor].x + converter->CP(icon_size()) / 2 + 1, _center[monitor].y);
1329+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1330+ {
1331+ return nux::Point(_center[monitor].x + converter->CP(icon_size()) / 2 + 1, _center[monitor].y);
1332+ }
1333+ else
1334+ {
1335+ return nux::Point(_center[monitor].x, _center[monitor].y - converter->CP(icon_size()) / 2 - 1);
1336+ }
1337 }
1338
1339 void LauncherIcon::ShowTooltip()
1340
1341=== modified file 'launcher/QuicklistView.cpp'
1342--- launcher/QuicklistView.cpp 2015-05-20 15:31:09 +0000
1343+++ launcher/QuicklistView.cpp 2016-03-18 01:19:20 +0000
1344@@ -81,8 +81,16 @@
1345 {
1346 SetGeometry(nux::Geometry(0, 0, 1, 1));
1347
1348- _left_space = new nux::SpaceLayout(RawPixel(_padding + ANCHOR_WIDTH + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_),
1349- RawPixel(_padding + ANCHOR_WIDTH + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_),
1350+ int width = 0;
1351+ int height = 0;
1352+ // when launcher is on the left, the anchor is on the left of the menuitem, and
1353+ // when launcher is on the bottom, the anchor is on the bottom of the menuitem.
1354+ if (Settings::Instance().launcher_position == LauncherPosition::LEFT)
1355+ width = ANCHOR_WIDTH;
1356+ else
1357+ height = ANCHOR_WIDTH;
1358+ _left_space = new nux::SpaceLayout(RawPixel(_padding + width + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_),
1359+ RawPixel(_padding + width + CORNER_RADIUS + LEFT_PADDING_CORRECTION).CP(cv_),
1360 1, MAX_HEIGHT.CP(cv_));
1361
1362 _right_space = new nux::SpaceLayout(_padding.CP(cv_) + CORNER_RADIUS.CP(cv_),
1363@@ -94,8 +102,8 @@
1364 _padding.CP(cv_) + CORNER_RADIUS.CP(cv_));
1365
1366 _bottom_space = new nux::SpaceLayout(1, MAX_WIDTH.CP(cv_),
1367- _padding.CP(cv_) + CORNER_RADIUS.CP(cv_),
1368- _padding.CP(cv_) + CORNER_RADIUS.CP(cv_));
1369+ _padding.CP(cv_) + height + CORNER_RADIUS.CP(cv_),
1370+ _padding.CP(cv_) + height + CORNER_RADIUS.CP(cv_));
1371
1372 _vlayout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION);
1373 _vlayout->AddLayout(_top_space, 0);
1374@@ -129,12 +137,35 @@
1375
1376 int QuicklistView::CalculateX() const
1377 {
1378- return _anchorX - _padding.CP(cv_);
1379+ int x = 0;
1380+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1381+ x = _anchorX - _padding.CP(cv_);
1382+ else
1383+ {
1384+ int size = 0;
1385+ int max = GetBaseWidth() - ANCHOR_HEIGHT.CP(cv_) - 2 * CORNER_RADIUS.CP(cv_) - 2 * _padding.CP(cv_);
1386+ if (_top_size.CP(cv_) > max)
1387+ {
1388+ size = max;
1389+ }
1390+ else if (_top_size.CP(cv_) > 0)
1391+ {
1392+ size = _top_size.CP(cv_);
1393+ }
1394+ x = _anchorX - (ANCHOR_HEIGHT.CP(cv_) / 2) - size - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_);
1395+ }
1396+
1397+ return x;
1398 }
1399
1400 int QuicklistView::CalculateY() const
1401 {
1402- return _anchorY - (ANCHOR_HEIGHT.CP(cv_) / 2) - _top_size.CP(cv_) - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_);
1403+ int y = 0;
1404+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1405+ y = _anchorY - (ANCHOR_HEIGHT.CP(cv_) / 2) - _top_size.CP(cv_) - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_);
1406+ else
1407+ y = _anchorY - GetBaseHeight() + _padding.CP(cv_);
1408+ return y;
1409 }
1410
1411 void
1412@@ -338,12 +369,29 @@
1413 auto* us = UScreen::GetDefault();
1414 int ql_monitor = us->GetMonitorAtPosition(_anchorX, _anchorY);
1415 auto const& ql_monitor_geo = us->GetMonitorGeometry(ql_monitor);
1416- int offscreen_size = GetBaseY() + GetBaseHeight() - (ql_monitor_geo.y + ql_monitor_geo.height);
1417+ auto launcher_position = Settings::Instance().launcher_position();
1418
1419- if (offscreen_size > 0)
1420- _top_size = offscreen_size + TOP_SIZE;
1421+ if (launcher_position == LauncherPosition::LEFT)
1422+ {
1423+ int offscreen_size = GetBaseY() + GetBaseHeight() - (ql_monitor_geo.y + ql_monitor_geo.height);
1424+ if (offscreen_size > 0)
1425+ _top_size = offscreen_size + TOP_SIZE;
1426+ else
1427+ _top_size = TOP_SIZE;
1428+ }
1429 else
1430- _top_size = TOP_SIZE;
1431+ {
1432+ int offscreen_size_left = ql_monitor_geo.x - (_anchorX - GetBaseWidth() / 2);
1433+ int offscreen_size_right = _anchorX + GetBaseWidth()/2 - (ql_monitor_geo.x + ql_monitor_geo.width);
1434+ int half_size = (GetBaseWidth() / 2) - _padding.CP(cv_) - CORNER_RADIUS.CP(cv_) - (ANCHOR_HEIGHT.CP(cv_) / 2);
1435+
1436+ if (offscreen_size_left > 0)
1437+ _top_size = half_size - offscreen_size_left;
1438+ else if (offscreen_size_right > 0)
1439+ _top_size = half_size + offscreen_size_right;
1440+ else
1441+ _top_size = half_size;
1442+ }
1443
1444 SetXY(CalculateX(), CalculateY());
1445 }
1446@@ -442,10 +490,14 @@
1447 TotalItemHeight += text_extents.height;
1448 }
1449
1450+ int rotated_anchor_height = 0;
1451+ if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM)
1452+ rotated_anchor_height = ANCHOR_WIDTH;
1453+
1454 if (TotalItemHeight < ANCHOR_HEIGHT.CP(cv_))
1455 {
1456- int b = (ANCHOR_HEIGHT.CP(cv_) - TotalItemHeight) / 2 + _padding.CP(cv_) + CORNER_RADIUS.CP(cv_);
1457- int t = b + OFFSET_CORRECTION.CP(cv_);
1458+ int b = (ANCHOR_HEIGHT.CP(cv_) - TotalItemHeight) / 2 + _padding.CP(cv_) + CORNER_RADIUS.CP(cv_) + rotated_anchor_height;
1459+ int t = b + OFFSET_CORRECTION.CP(cv_) - rotated_anchor_height;
1460
1461 _top_space->SetMinimumHeight(t);
1462 _top_space->SetMaximumHeight(t);
1463@@ -455,8 +507,8 @@
1464 }
1465 else
1466 {
1467- int b = _padding.CP(cv_) + CORNER_RADIUS.CP(cv_);
1468- int t = b + OFFSET_CORRECTION.CP(cv_);
1469+ int b = _padding.CP(cv_) + CORNER_RADIUS.CP(cv_) + rotated_anchor_height;
1470+ int t = b + OFFSET_CORRECTION.CP(cv_) - rotated_anchor_height;
1471
1472 _top_space->SetMinimumHeight(t);
1473 _top_space->SetMaximumHeight(t);
1474@@ -476,7 +528,10 @@
1475
1476 UpdateTexture();
1477
1478- int x = RawPixel(_padding + ANCHOR_WIDTH + CORNER_RADIUS + OFFSET_CORRECTION).CP(cv_);
1479+ int width = 0;
1480+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1481+ width = ANCHOR_WIDTH;
1482+ int x = RawPixel(_padding + width + CORNER_RADIUS + OFFSET_CORRECTION).CP(cv_);
1483 int y = _top_space->GetMinimumHeight();
1484
1485 for (auto const& item : _item_list)
1486@@ -655,7 +710,9 @@
1487
1488 nux::Area* QuicklistView::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type)
1489 {
1490- if (mouse_position.x > _anchorX)
1491+ auto launcher_position = Settings::Instance().launcher_position();
1492+ if ((launcher_position == LauncherPosition::LEFT && (mouse_position.x > _anchorX)) ||
1493+ (launcher_position == LauncherPosition::BOTTOM && (mouse_position.y < _anchorY)))
1494 {
1495 return (CairoBaseWindow::FindAreaUnderMouse(mouse_position, event_type));
1496 }
1497@@ -864,109 +921,164 @@
1498 gfloat radius,
1499 guint pad)
1500 {
1501- // 0 1 2 3
1502- // +--+--------+--+
1503- // | |
1504- // + 14 + 4
1505- // | |
1506- // | |
1507- // | |
1508- // + 13 |
1509- // / |
1510- // / |
1511- // + 12 |
1512- // \ |
1513- // \ |
1514- // 11 + |
1515- // | |
1516- // | |
1517- // | |
1518- // 10 + + 5
1519- // | |
1520- // +--+--------+--+ 6
1521- // 9 8 7
1522+ // On the right of the icon: On the top of the icon:
1523+ // 0 1 2 3 0 1 2 3
1524+ // +--+--------+--+ +--+-----------+--+
1525+ // | | | |
1526+ // + 14 + 4 14 + + 4
1527+ // | | | |
1528+ // | | | |
1529+ // | | | |
1530+ // + 13 | | |
1531+ // / | | |
1532+ // / | | |
1533+ // + 12 | | |
1534+ // \ | | |
1535+ // \ | | |
1536+ // 11 + | | |
1537+ // | | 13 + + 5
1538+ // | | | 10 8 |
1539+ // | | 12 +--+--+ +--+--+ 6
1540+ // 10 + + 5 11 \ / 7
1541+ // | | \ /
1542+ // +--+--------+--+ 6 +
1543+ // 9 8 7 9
1544
1545
1546 gfloat padding = pad;
1547 int ZEROPOINT5 = 0.0f;
1548-
1549- gfloat HeightToAnchor = ((gfloat) height - 2.0f * radius - anchor_height - 2 * padding) / 2.0f;
1550- if (HeightToAnchor < 0.0f)
1551- {
1552- g_warning("Anchor-height and corner-radius a higher than whole texture!");
1553- return;
1554- }
1555+ auto launcher_position = Settings::Instance().launcher_position();
1556
1557 //gint dynamic_size = height - 2*radius - 2*padding - anchor_height;
1558 //gint upper_dynamic_size = upper_size;
1559 //gint lower_dynamic_size = dynamic_size - upper_dynamic_size;
1560
1561+ int size = 0;
1562+ if (launcher_position == LauncherPosition::LEFT)
1563+ size = height;
1564+ else
1565+ size = width;
1566+
1567+ gfloat HeightToAnchor = ((gfloat) size - 2.0f * radius - anchor_height - 2 * padding) / 2.0f;
1568+ if (HeightToAnchor < 0.0f)
1569+ {
1570+ g_warning("Anchor-height and corner-radius a higher than whole texture!");
1571+ return;
1572+ }
1573+
1574 if (upper_size >= 0)
1575 {
1576- if (upper_size > height - 2.0f * radius - anchor_height - 2 * padding)
1577+ if (upper_size > size - 2.0f * radius - anchor_height - 2 * padding)
1578 {
1579 //g_warning ("[_compute_full_mask_path] incorrect upper_size value");
1580 HeightToAnchor = 0;
1581 }
1582 else
1583 {
1584- HeightToAnchor = height - 2.0f * radius - anchor_height - 2 * padding - upper_size;
1585+ HeightToAnchor = size - 2.0f * radius - anchor_height - 2 * padding - upper_size;
1586 }
1587 }
1588 else
1589 {
1590- HeightToAnchor = (height - 2.0f * radius - anchor_height - 2 * padding) / 2.0f;
1591+ if (launcher_position == LauncherPosition::LEFT)
1592+ HeightToAnchor = (size - 2.0f * radius - anchor_height - 2 * padding) / 2.0f;
1593+ else
1594+ HeightToAnchor = size - 2.0f * radius - anchor_height - 2 * padding;
1595 }
1596
1597 cairo_translate(cr, -0.5f, -0.5f);
1598
1599 // create path
1600- cairo_move_to(cr, padding + anchor_width + radius + ZEROPOINT5, padding + ZEROPOINT5); // Point 1
1601- cairo_line_to(cr, width - padding - radius, padding + ZEROPOINT5); // Point 2
1602- cairo_arc(cr,
1603- width - padding - radius + ZEROPOINT5,
1604- padding + radius + ZEROPOINT5,
1605- radius,
1606- -90.0f * G_PI / 180.0f,
1607- 0.0f * G_PI / 180.0f); // Point 4
1608- cairo_line_to(cr,
1609- (gdouble) width - padding + ZEROPOINT5,
1610- (gdouble) height - radius - padding + ZEROPOINT5); // Point 5
1611- cairo_arc(cr,
1612- (gdouble) width - padding - radius + ZEROPOINT5,
1613- (gdouble) height - padding - radius + ZEROPOINT5,
1614- radius,
1615- 0.0f * G_PI / 180.0f,
1616- 90.0f * G_PI / 180.0f); // Point 7
1617- cairo_line_to(cr,
1618- anchor_width + padding + radius + ZEROPOINT5,
1619- (gdouble) height - padding + ZEROPOINT5); // Point 8
1620-
1621- cairo_arc(cr,
1622- anchor_width + padding + radius + ZEROPOINT5,
1623- (gdouble) height - padding - radius,
1624- radius,
1625- 90.0f * G_PI / 180.0f,
1626- 180.0f * G_PI / 180.0f); // Point 10
1627-
1628- cairo_line_to(cr,
1629- padding + anchor_width + ZEROPOINT5,
1630- (gdouble) height - padding - radius - HeightToAnchor + ZEROPOINT5); // Point 11
1631- cairo_line_to(cr,
1632- padding + ZEROPOINT5,
1633- (gdouble) height - padding - radius - HeightToAnchor - anchor_height / 2.0f + ZEROPOINT5); // Point 12
1634- cairo_line_to(cr,
1635- padding + anchor_width + ZEROPOINT5,
1636- (gdouble) height - padding - radius - HeightToAnchor - anchor_height + ZEROPOINT5); // Point 13
1637-
1638- cairo_line_to(cr, padding + anchor_width + ZEROPOINT5, padding + radius + ZEROPOINT5); // Point 14
1639- cairo_arc(cr,
1640- padding + anchor_width + radius + ZEROPOINT5,
1641- padding + radius + ZEROPOINT5,
1642- radius,
1643- 180.0f * G_PI / 180.0f,
1644- 270.0f * G_PI / 180.0f);
1645-
1646+ if (launcher_position == LauncherPosition::LEFT)
1647+ {
1648+ cairo_move_to(cr, padding + anchor_width + radius + ZEROPOINT5, padding + ZEROPOINT5); // Point 1
1649+ cairo_line_to(cr, width - padding - radius, padding + ZEROPOINT5); // Point 2
1650+ cairo_arc(cr,
1651+ width - padding - radius + ZEROPOINT5,
1652+ padding + radius + ZEROPOINT5,
1653+ radius,
1654+ -90.0f * G_PI / 180.0f,
1655+ 0.0f * G_PI / 180.0f); // Point 4
1656+ cairo_line_to(cr,
1657+ (gdouble) width - padding + ZEROPOINT5,
1658+ (gdouble) height - radius - padding + ZEROPOINT5); // Point 5
1659+ cairo_arc(cr,
1660+ (gdouble) width - padding - radius + ZEROPOINT5,
1661+ (gdouble) height - padding - radius + ZEROPOINT5,
1662+ radius,
1663+ 0.0f * G_PI / 180.0f,
1664+ 90.0f * G_PI / 180.0f); // Point 7
1665+ cairo_line_to(cr,
1666+ anchor_width + padding + radius + ZEROPOINT5,
1667+ (gdouble) height - padding + ZEROPOINT5); // Point 8
1668+ cairo_arc(cr,
1669+ anchor_width + padding + radius + ZEROPOINT5,
1670+ (gdouble) height - padding - radius,
1671+ radius,
1672+ 90.0f * G_PI / 180.0f,
1673+ 180.0f * G_PI / 180.0f); // Point 10
1674+ cairo_line_to(cr,
1675+ padding + anchor_width + ZEROPOINT5,
1676+ (gdouble) height - padding - radius - HeightToAnchor + ZEROPOINT5); // Point 11
1677+ cairo_line_to(cr,
1678+ padding + ZEROPOINT5,
1679+ (gdouble) height - padding - radius - HeightToAnchor - anchor_height / 2.0f + ZEROPOINT5); // Point 12
1680+ cairo_line_to(cr,
1681+ padding + anchor_width + ZEROPOINT5,
1682+ (gdouble) height - padding - radius - HeightToAnchor - anchor_height + ZEROPOINT5); // Point 13
1683+ cairo_line_to(cr, padding + anchor_width + ZEROPOINT5, padding + radius + ZEROPOINT5); // Point 14
1684+ cairo_arc(cr,
1685+ padding + anchor_width + radius + ZEROPOINT5,
1686+ padding + radius + ZEROPOINT5,
1687+ radius,
1688+ 180.0f * G_PI / 180.0f,
1689+ 270.0f * G_PI / 180.0f);
1690+ }
1691+ else
1692+ {
1693+ cairo_move_to(cr, padding + radius + ZEROPOINT5, padding + ZEROPOINT5); // Point 1
1694+ cairo_line_to(cr, width - padding - radius, padding + ZEROPOINT5); // Point 2
1695+ cairo_arc(cr,
1696+ width - padding - radius + ZEROPOINT5,
1697+ padding + radius + ZEROPOINT5,
1698+ radius,
1699+ -90.0f * G_PI / 180.0f,
1700+ 0.0f * G_PI / 180.0f); // Point 4
1701+ cairo_line_to(cr,
1702+ (gdouble) width - padding + ZEROPOINT5,
1703+ (gdouble) height - radius - anchor_width - padding + ZEROPOINT5); // Point 5
1704+ cairo_arc(cr,
1705+ (gdouble) width - padding - radius + ZEROPOINT5,
1706+ (gdouble) height - padding - anchor_width - radius + ZEROPOINT5,
1707+ radius,
1708+ 0.0f * G_PI / 180.0f,
1709+ 90.0f * G_PI / 180.0f); // Point 7
1710+ cairo_line_to(cr,
1711+ (gdouble) width - padding - radius - HeightToAnchor + ZEROPOINT5,
1712+ height - padding - anchor_width + ZEROPOINT5); // Point 8
1713+ cairo_line_to(cr,
1714+ (gdouble) width - padding - radius - HeightToAnchor - anchor_height / 2.0f + ZEROPOINT5,
1715+ height - padding + ZEROPOINT5); // Point 9
1716+ cairo_line_to(cr,
1717+ (gdouble) width - padding - radius - HeightToAnchor - anchor_height + ZEROPOINT5,
1718+ height - padding - anchor_width + ZEROPOINT5); // Point 10
1719+ cairo_arc(cr,
1720+ padding + radius + ZEROPOINT5,
1721+ (gdouble) height - padding - anchor_width - radius,
1722+ radius,
1723+ 90.0f * G_PI / 180.0f,
1724+ 180.0f * G_PI / 180.0f); // Point 11
1725+ cairo_line_to(cr,
1726+ padding + ZEROPOINT5,
1727+ (gdouble) height - padding -anchor_width - radius + ZEROPOINT5); // Point 13
1728+ cairo_line_to(cr, padding + ZEROPOINT5, padding + radius + ZEROPOINT5); // Point 14
1729+ cairo_arc(cr,
1730+ padding + radius + ZEROPOINT5,
1731+ padding + radius + ZEROPOINT5,
1732+ radius,
1733+ 180.0f * G_PI / 180.0f,
1734+ 270.0f * G_PI / 180.0f);
1735+ }
1736 cairo_close_path(cr);
1737 }
1738
1739
1740=== modified file 'launcher/SoftwareCenterLauncherIcon.cpp'
1741--- launcher/SoftwareCenterLauncherIcon.cpp 2016-02-23 15:39:49 +0000
1742+++ launcher/SoftwareCenterLauncherIcon.cpp 2016-03-18 01:19:20 +0000
1743@@ -31,6 +31,7 @@
1744 #include "LauncherDragWindow.h"
1745 #include "LauncherModel.h"
1746 #include "DesktopUtilities.h"
1747+#include "unity-shared/UnitySettings.h"
1748
1749 namespace unity
1750 {
1751
1752=== modified file 'launcher/Tooltip.cpp'
1753--- launcher/Tooltip.cpp 2014-08-27 20:53:27 +0000
1754+++ launcher/Tooltip.cpp 2016-03-18 01:19:20 +0000
1755@@ -25,6 +25,7 @@
1756 #include <unity-shared/CairoTexture.h>
1757 #include <unity-shared/RawPixel.h>
1758 #include <unity-shared/UnitySettings.h>
1759+#include <unity-shared/UScreen.h>
1760 #include "unity-shared/DecorationStyle.h"
1761
1762 #include "Tooltip.h"
1763@@ -33,11 +34,14 @@
1764 {
1765 namespace
1766 {
1767- const RawPixel ANCHOR_WIDTH = 14_em;
1768- const RawPixel ANCHOR_HEIGHT = 18_em;
1769- const RawPixel CORNER_RADIUS = 4_em;
1770- const RawPixel TEXT_PADDING = 8_em;
1771- const RawPixel MINIMUM_TEXT_WIDTH = 100_em;
1772+ const RawPixel ANCHOR_WIDTH = 14_em;
1773+ const RawPixel ANCHOR_HEIGHT = 18_em;
1774+ const RawPixel ROTATED_ANCHOR_WIDTH = 18_em;
1775+ const RawPixel ROTATED_ANCHOR_HEIGHT = 10_em;
1776+ const RawPixel CORNER_RADIUS = 4_em;
1777+ const RawPixel LEFT_SIZE = 4_em;
1778+ const RawPixel TEXT_PADDING = 8_em;
1779+ const RawPixel MINIMUM_TEXT_WIDTH = 100_em;
1780 }
1781
1782 NUX_IMPLEMENT_OBJECT_TYPE(Tooltip);
1783@@ -45,17 +49,30 @@
1784 CairoBaseWindow(monitor),
1785 _anchorX(0),
1786 _anchorY(0),
1787+ _left_size(LEFT_SIZE),
1788 _padding(decoration::Style::Get()->ActiveShadowRadius()),
1789 _cairo_text_has_changed(true)
1790 {
1791 _hlayout = new nux::HLayout(TEXT(""), NUX_TRACKER_LOCATION);
1792 _vlayout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION);
1793
1794- _left_space = new nux::SpaceLayout(_padding.CP(cv_) + ANCHOR_WIDTH.CP(cv_), _padding.CP(cv_) + ANCHOR_WIDTH.CP(cv_), 1, 1000);
1795+ int left_space_width = 0;
1796+ int bottom_space_height = 0;
1797+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1798+ {
1799+ left_space_width = _padding.CP(cv_) + ANCHOR_WIDTH.CP(cv_);
1800+ bottom_space_height = _padding.CP(cv_);
1801+ }
1802+ else
1803+ {
1804+ left_space_width = _padding.CP(cv_);
1805+ bottom_space_height = _padding.CP(cv_) + ROTATED_ANCHOR_HEIGHT.CP(cv_);
1806+ }
1807+ _left_space = new nux::SpaceLayout(left_space_width, left_space_width, 1, 1000);
1808 _right_space = new nux::SpaceLayout(_padding.CP(cv_) + CORNER_RADIUS.CP(cv_), _padding.CP(cv_) + CORNER_RADIUS.CP(cv_), 1, 1000);
1809
1810 _top_space = new nux::SpaceLayout(1, 1000, _padding.CP(cv_), _padding.CP(cv_));
1811- _bottom_space = new nux::SpaceLayout(1, 1000, _padding.CP(cv_), _padding.CP(cv_));
1812+ _bottom_space = new nux::SpaceLayout(1, 1000, bottom_space_height, bottom_space_height);
1813
1814 _vlayout->AddLayout(_top_space, 0);
1815
1816@@ -96,6 +113,44 @@
1817 SetLayout(_hlayout);
1818 }
1819
1820+int Tooltip::CalculateX() const
1821+{
1822+ int x = 0;
1823+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1824+ {
1825+ x = _anchorX - _padding.CP(cv_);
1826+ }
1827+ else
1828+ {
1829+ int size = 0;
1830+ int max = GetBaseWidth() - ROTATED_ANCHOR_WIDTH.CP(cv_) - 2 * CORNER_RADIUS.CP(cv_) - 2 * _padding.CP(cv_);
1831+ if (_left_size.CP(cv_) > max)
1832+ {
1833+ size = max;
1834+ }
1835+ else if (_left_size.CP(cv_) > 0)
1836+ {
1837+ size = _left_size.CP(cv_);
1838+ }
1839+ x = _anchorX - (ROTATED_ANCHOR_WIDTH.CP(cv_) / 2) - size - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_);
1840+ }
1841+ return x;
1842+}
1843+
1844+int Tooltip::CalculateY() const
1845+{
1846+ int y = 0;
1847+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1848+ {
1849+ y = _anchorY - ANCHOR_HEIGHT.CP(cv_) / 2 - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_);
1850+ }
1851+ else
1852+ {
1853+ y = _anchorY - GetBaseHeight() + _padding.CP(cv_);
1854+ }
1855+ return y;
1856+}
1857+
1858 nux::Area* Tooltip::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type)
1859 {
1860 // No area under mouse to allow click through to entities below
1861@@ -107,10 +162,25 @@
1862 _anchorX = tip_x;
1863 _anchorY = tip_y;
1864
1865- int x = _anchorX - _padding.CP(cv_);
1866- int y = _anchorY - ANCHOR_HEIGHT.CP(cv_) / 2 - CORNER_RADIUS.CP(cv_) - _padding.CP(cv_);
1867-
1868- SetBaseXY(x, y);
1869+ if (Settings::Instance().launcher_position() == LauncherPosition::BOTTOM)
1870+ {
1871+ auto* us = UScreen::GetDefault();
1872+ int monitor = us->GetMonitorAtPosition(_anchorX, _anchorY);
1873+ auto const& monitor_geo = us->GetMonitorGeometry(monitor);
1874+ int offscreen_size_right = _anchorX + GetBaseWidth()/2 - (monitor_geo.x + monitor_geo.width);
1875+ int offscreen_size_left = monitor_geo.x - (_anchorX - GetBaseWidth()/2);
1876+ int half_size = (GetBaseWidth() / 2) - _padding.CP(cv_) - CORNER_RADIUS.CP(cv_) - (ROTATED_ANCHOR_WIDTH.CP(cv_) / 2);
1877+
1878+ if (offscreen_size_left > 0)
1879+ _left_size = half_size - offscreen_size_left;
1880+ else if (offscreen_size_right > 0)
1881+ _left_size = half_size + offscreen_size_right;
1882+ else
1883+ _left_size = half_size;
1884+ _cairo_text_has_changed = true;
1885+ }
1886+
1887+ SetBaseXY(CalculateX(), CalculateY());
1888 }
1889
1890 void Tooltip::ShowTooltipWithTipAt(int x, int y)
1891@@ -149,7 +219,10 @@
1892 space_height += (ANCHOR_HEIGHT.CP(cv_) - text_height) / 2;
1893
1894 _top_space->SetMinMaxSize(1, space_height);
1895- _bottom_space->SetMinMaxSize(1, space_height + 1);
1896+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1897+ _bottom_space->SetMinMaxSize(1, space_height + 1);
1898+ else
1899+ _bottom_space->SetMinMaxSize(1, space_height + ROTATED_ANCHOR_HEIGHT + 1);
1900
1901 CairoBaseWindow::PreLayoutManagement();
1902 }
1903@@ -250,51 +323,120 @@
1904 gfloat anchor_height,
1905 gfloat width,
1906 gfloat height,
1907- gint upper_size,
1908+ gint left_size,
1909 gfloat radius,
1910 guint pad)
1911 {
1912
1913- // 0 1 2
1914- // +------------+-+
1915- // / + 3
1916- // / |
1917- // + 8 |
1918- // \ |
1919- // \ + 4
1920- // +------------+-+
1921- // 7 6 5
1922+ // On the right of the icon: On the top of the icon:
1923+ // 0 1 2 0 1 2 3
1924+ // +------------------+-+ +-+----------------+-+
1925+ // / + 3 14 + + 4
1926+ // / | | |
1927+ // + 8 | | |
1928+ // \ | | |
1929+ // \ + 4 13 + 10 8 + 5
1930+ // +------------------+-+ +-+---+ +--------+-+
1931+ // 7 6 5 12 11 \ / 7 6
1932+ // + 9
1933
1934 gfloat padding = pad;
1935
1936 cairo_translate(cr, -0.5f, -0.5f);
1937
1938 // create path
1939- cairo_move_to(cr, padding + anchor_width, padding); // Point 0
1940- cairo_line_to(cr, width - padding - radius, padding); // Point 1
1941- cairo_arc(cr,
1942- width - padding - radius,
1943- padding + radius,
1944- radius,
1945- -90.0f * G_PI / 180.0f,
1946- 0.0f * G_PI / 180.0f); // Point 3
1947- cairo_line_to(cr,
1948- (gdouble) width - padding,
1949- (gdouble) height - radius - padding); // Point 4
1950- cairo_arc(cr,
1951- (gdouble) width - padding - radius,
1952- (gdouble) height - padding - radius,
1953- radius,
1954- 0.0f * G_PI / 180.0f,
1955- 90.0f * G_PI / 180.0f); // Point 6
1956- cairo_line_to(cr,
1957- anchor_width + padding,
1958- (gdouble) height - padding); // Point 7
1959-
1960- cairo_line_to(cr,
1961- padding,
1962- (gdouble) height / 2.0f); // Point 8
1963-
1964+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
1965+ {
1966+ cairo_move_to(cr, padding + anchor_width, padding); // Point 0
1967+ cairo_line_to(cr, width - padding - radius, padding); // Point 1
1968+ cairo_arc(cr,
1969+ width - padding - radius,
1970+ padding + radius,
1971+ radius,
1972+ -90.0f * G_PI / 180.0f,
1973+ 0.0f * G_PI / 180.0f); // Point 3
1974+ cairo_line_to(cr,
1975+ (gdouble) width - padding,
1976+ (gdouble) height - radius - padding); // Point 4
1977+ cairo_arc(cr,
1978+ (gdouble) width - padding - radius,
1979+ (gdouble) height - padding - radius,
1980+ radius,
1981+ 0.0f * G_PI / 180.0f,
1982+ 90.0f * G_PI / 180.0f); // Point 6
1983+ cairo_line_to(cr,
1984+ anchor_width + padding,
1985+ (gdouble) height - padding); // Point 7
1986+
1987+ cairo_line_to(cr,
1988+ padding,
1989+ (gdouble) height / 2.0f); // Point 8
1990+ }
1991+ else
1992+ {
1993+ gfloat WidthToAnchor = ((gfloat) width - 2.0f * radius - anchor_width - 2 * padding) / 2.0f;
1994+ if (WidthToAnchor < 0.0f)
1995+ {
1996+ g_warning("Anchor-width and corner-radius a wider than whole texture!");
1997+ return;
1998+ }
1999+
2000+ if (left_size > width - 2.0f * radius - anchor_width - 2 * padding)
2001+ {
2002+ WidthToAnchor = 0;
2003+ }
2004+ else if (left_size < 0)
2005+ {
2006+ WidthToAnchor = width - 2.0f * radius - anchor_width - 2 * padding;
2007+ }
2008+ else
2009+ {
2010+ WidthToAnchor = width - 2.0f * radius - anchor_width - 2 * padding - left_size;
2011+ }
2012+
2013+ cairo_move_to(cr, padding + radius, padding); // Point 1
2014+ cairo_line_to(cr, width - padding - radius, padding); // Point 2
2015+ cairo_arc(cr,
2016+ width - padding - radius,
2017+ padding + radius,
2018+ radius,
2019+ -90.0f * G_PI / 180.0f,
2020+ 0.0f * G_PI / 180.0f); // Point 4
2021+ cairo_line_to(cr,
2022+ (gdouble) width - padding,
2023+ (gdouble) height - radius - anchor_height - padding); // Point 5
2024+ cairo_arc(cr,
2025+ (gdouble) width - padding - radius,
2026+ (gdouble) height - padding - anchor_height - radius,
2027+ radius,
2028+ 0.0f * G_PI / 180.0f,
2029+ 90.0f * G_PI / 180.0f); // Point 7
2030+ cairo_line_to(cr,
2031+ (gdouble) width - padding - radius - WidthToAnchor,
2032+ height - padding - anchor_height); // Point 8
2033+ cairo_line_to(cr,
2034+ (gdouble) width - padding - radius - WidthToAnchor - anchor_width / 2.0f,
2035+ height - padding); // Point 9
2036+ cairo_line_to(cr,
2037+ (gdouble) width - padding - radius - WidthToAnchor - anchor_width,
2038+ height - padding - anchor_height); // Point 10
2039+ cairo_arc(cr,
2040+ padding + radius,
2041+ (gdouble) height - padding - anchor_height - radius,
2042+ radius,
2043+ 90.0f * G_PI / 180.0f,
2044+ 180.0f * G_PI / 180.0f); // Point 11
2045+ cairo_line_to(cr,
2046+ padding,
2047+ (gdouble) height - padding -anchor_height - radius); // Point 13
2048+ cairo_line_to(cr, padding, padding + radius); // Point 14
2049+ cairo_arc(cr,
2050+ padding + radius,
2051+ padding + radius,
2052+ radius,
2053+ 180.0f * G_PI / 180.0f,
2054+ 270.0f * G_PI / 180.0f);
2055+ }
2056 cairo_close_path(cr);
2057 }
2058
2059@@ -388,7 +530,7 @@
2060 gfloat height,
2061 gfloat anchor_width,
2062 gfloat anchor_height,
2063- gint upper_size,
2064+ gint left_size,
2065 gfloat corner_radius,
2066 guint blur_coeff,
2067 nux::Color const& shadow_color,
2068@@ -402,7 +544,7 @@
2069 anchor_height,
2070 width,
2071 height,
2072- upper_size,
2073+ left_size,
2074 corner_radius,
2075 padding_size);
2076
2077@@ -421,7 +563,7 @@
2078 gfloat radius,
2079 gfloat anchor_width,
2080 gfloat anchor_height,
2081- gint upper_size,
2082+ gint left_size,
2083 gboolean negative,
2084 gboolean outline,
2085 gfloat line_width,
2086@@ -434,7 +576,7 @@
2087 anchor_height,
2088 width,
2089 height,
2090- upper_size,
2091+ left_size,
2092 radius,
2093 padding_size);
2094 _finalize(&cr, outline, line_width, color, negative, outline);
2095@@ -445,12 +587,22 @@
2096 if (_cairo_text_has_changed == false)
2097 return;
2098
2099+ SetTooltipPosition(_anchorX, _anchorY);
2100+
2101 int width = GetBaseWidth();
2102 int height = GetBaseHeight();
2103-
2104- int x = _anchorX - _padding.CP(cv_);
2105- int y = _anchorY - height / 2;
2106- SetXY(x, y);
2107+ int anchor_width = 0;
2108+ int anchor_height = 0;
2109+ if (Settings::Instance().launcher_position == LauncherPosition::LEFT)
2110+ {
2111+ anchor_width = ANCHOR_WIDTH;
2112+ anchor_height = ANCHOR_HEIGHT;
2113+ }
2114+ else
2115+ {
2116+ anchor_width = ROTATED_ANCHOR_WIDTH;
2117+ anchor_height = ROTATED_ANCHOR_HEIGHT;
2118+ }
2119
2120 auto const& deco_style = decoration::Style::Get();
2121 float dpi_scale = cv_->DPIScale();
2122@@ -499,9 +651,9 @@
2123 cairo_outline.GetSurface(),
2124 width / dpi_scale,
2125 height / dpi_scale,
2126- ANCHOR_WIDTH,
2127- ANCHOR_HEIGHT,
2128- -1,
2129+ anchor_width,
2130+ anchor_height,
2131+ _left_size,
2132 CORNER_RADIUS,
2133 blur_coef,
2134 shadow_color,
2135@@ -515,9 +667,9 @@
2136 width / dpi_scale,
2137 height / dpi_scale,
2138 CORNER_RADIUS, // radius,
2139- ANCHOR_WIDTH, // anchor_width,
2140- ANCHOR_HEIGHT, // anchor_height,
2141- -1, // upper_size,
2142+ anchor_width, // anchor_width,
2143+ anchor_height, // anchor_height,
2144+ _left_size, // left_size,
2145 true, // negative,
2146 false, // outline,
2147 1.0, // line_width,
2148
2149=== modified file 'launcher/Tooltip.h'
2150--- launcher/Tooltip.h 2014-03-24 23:44:58 +0000
2151+++ launcher/Tooltip.h 2016-03-18 01:19:20 +0000
2152@@ -73,8 +73,12 @@
2153 void NotifyConfigurationChange(int width,
2154 int height);
2155
2156+ int CalculateX() const;
2157+ int CalculateY() const;
2158+
2159 int _anchorX;
2160 int _anchorY;
2161+ RawPixel _left_size; // size of the segment from point 10 to 11, used when launcher at bottom.
2162 RawPixel _padding;
2163
2164 nux::HLayout* _hlayout;
2165
2166=== modified file 'panel/PanelView.cpp'
2167--- panel/PanelView.cpp 2016-03-07 18:37:24 +0000
2168+++ panel/PanelView.cpp 2016-03-18 01:19:20 +0000
2169@@ -368,7 +368,8 @@
2170
2171 int refine_x_pos = geo.x + (stored_dash_width_ - refine_gradient_midpoint);
2172
2173- refine_x_pos += unity::Settings::Instance().LauncherWidth(monitor_);
2174+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
2175+ refine_x_pos += unity::Settings::Instance().LauncherSize(monitor_);
2176 GfxContext.QRP_1Tex(refine_x_pos, geo.y,
2177 bg_refine_tex_->GetWidth(),
2178 bg_refine_tex_->GetHeight(),
2179@@ -465,7 +466,8 @@
2180 nux::Geometry refine_geo = geo;
2181
2182 int refine_x_pos = geo.x + (stored_dash_width_ - refine_gradient_midpoint);
2183- refine_x_pos += unity::Settings::Instance().LauncherWidth(monitor_);
2184+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
2185+ refine_x_pos += unity::Settings::Instance().LauncherSize(monitor_);
2186
2187 refine_geo.x = refine_x_pos;
2188 refine_geo.width = bg_refine_tex_->GetWidth();
2189
2190=== modified file 'plugins/unityshell/src/unityshell.cpp'
2191--- plugins/unityshell/src/unityshell.cpp 2016-03-09 17:30:50 +0000
2192+++ plugins/unityshell/src/unityshell.cpp 2016-03-18 01:19:20 +0000
2193@@ -77,6 +77,7 @@
2194 #include "UScreen.h"
2195
2196 #include "config.h"
2197+#include "unity-shared/UnitySettings.h"
2198
2199 /* FIXME: once we get a better method to add the toplevel windows to
2200 the accessible root object, this include would not be required */
2201@@ -3826,9 +3827,9 @@
2202 }
2203
2204 auto max_bounds = NuxGeometryFromCompRect(output.workArea());
2205- if (launcher_controller_->options()->hide_mode != LAUNCHER_HIDE_NEVER)
2206+ if (launcher_controller_->options()->hide_mode != LAUNCHER_HIDE_NEVER && Settings::Instance().launcher_position() == LauncherPosition::LEFT)
2207 {
2208- int monitor_width = unity_settings_.LauncherWidth(monitor);
2209+ int monitor_width = unity_settings_.LauncherSize(monitor);
2210 max_bounds.x += monitor_width;
2211 max_bounds.width -= monitor_width;
2212 }
2213@@ -4071,22 +4072,35 @@
2214 manager->PromptLockScreen();
2215
2216 auto on_launcher_size_changed = [this] (nux::Area* area, int w, int h) {
2217- /* The launcher geometry includes 1px used to draw the right margin
2218+ /* The launcher geometry includes 1px used to draw the right/top margin
2219 * that must not be considered when drawing an overlay */
2220
2221 auto* launcher = static_cast<Launcher*>(area);
2222- int launcher_width = w - (1_em).CP(unity_settings_.em(launcher->monitor)->DPIScale());
2223-
2224- unity::Settings::Instance().SetLauncherWidth(launcher_width, launcher->monitor);
2225- shortcut_controller_->SetAdjustment(launcher_width, panel_style_.PanelHeight(launcher->monitor));
2226-
2227- CompOption::Value v(launcher_width);
2228- screen->setOptionForPlugin("expo", "x_offset", v);
2229-
2230- if (launcher_controller_->options()->hide_mode == LAUNCHER_HIDE_NEVER)
2231- v.set(0);
2232-
2233- screen->setOptionForPlugin("scale", "x_offset", v);
2234+ auto launcher_position = Settings::Instance().launcher_position();
2235+
2236+ int size = 0;
2237+ if (launcher_position == LauncherPosition::LEFT)
2238+ size = w;
2239+ else
2240+ size = h;
2241+ int launcher_size = size - (1_em).CP(unity_settings_.em(launcher->monitor)->DPIScale());
2242+
2243+ unity::Settings::Instance().SetLauncherSize(launcher_size, launcher->monitor);
2244+ int adjustment_x = 0;
2245+ if (launcher_position == LauncherPosition::LEFT)
2246+ adjustment_x = launcher_size;
2247+ shortcut_controller_->SetAdjustment(adjustment_x, panel_style_.PanelHeight(launcher->monitor));
2248+
2249+ if (launcher_position == LauncherPosition::LEFT)
2250+ {
2251+ CompOption::Value v(launcher_size);
2252+ screen->setOptionForPlugin("expo", "x_offset", v);
2253+
2254+ if (launcher_controller_->options()->hide_mode == LAUNCHER_HIDE_NEVER)
2255+ v.set(0);
2256+
2257+ screen->setOptionForPlugin("scale", "x_offset", v);
2258+ }
2259 };
2260
2261 auto check_launchers_size = [this, on_launcher_size_changed] {
2262
2263=== added file 'resources/launcher_arrow_btt_19.svg'
2264--- resources/launcher_arrow_btt_19.svg 1970-01-01 00:00:00 +0000
2265+++ resources/launcher_arrow_btt_19.svg 2016-03-18 01:19:20 +0000
2266@@ -0,0 +1,18 @@
2267+<?xml version="1.0" encoding="utf-8"?>
2268+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2269+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2270+<svg version="1.1"
2271+ id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png"
2272+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px"
2273+ height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve">
2274+<sodipodi:namedview id="base" inkscape:cx="6.1247407" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="9.1968087" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-text-baseline="false" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" inkscape:zoom="59.292307" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true">
2275+ <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8">
2276+ </inkscape:grid>
2277+</sodipodi:namedview>
2278+<g id="layer1" transform="translate(0,-1033.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer">
2279+ <path id="path5726" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" opacity="0.14" enable-background="new " d="
2280+ M4.696,1043.368l4.8-6.316l4.8,6.316H4.696z"/>
2281+ <path id="path4097" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" fill="#FFFFFF" d="M5.696,1043.368l3.8-5.001
2282+ l3.802,5.001H5.696z"/>
2283+</g>
2284+</svg>
2285
2286=== added file 'resources/launcher_arrow_btt_37.svg'
2287--- resources/launcher_arrow_btt_37.svg 1970-01-01 00:00:00 +0000
2288+++ resources/launcher_arrow_btt_37.svg 2016-03-18 01:19:20 +0000
2289@@ -0,0 +1,21 @@
2290+<?xml version="1.0" encoding="utf-8"?>
2291+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2292+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2293+<svg version="1.1"
2294+ id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_large_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png"
2295+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="36.992px"
2296+ height="20.012px" viewBox="0 0 36.992 20.012" enable-background="new 0 0 36.992 20.012" xml:space="preserve">
2297+<sodipodi:namedview id="base" inkscape:cx="-5.367523" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="31.963893" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" showguides="false" inkscape:zoom="9.3132256" inkscape:snap-grids="false" inkscape:guide-bbox="true" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true">
2298+ <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8">
2299+ </inkscape:grid>
2300+ <sodipodi:guide id="guide3004" position="8,19" orientation="0,1"></sodipodi:guide>
2301+</sodipodi:namedview>
2302+<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer">
2303+
2304+ <path id="path5730" inkscape:connector-curvature="0" inkscape:transform-center-x="16.337474" sodipodi:nodetypes="cccc" opacity="0.14" enable-background="new " d="
2305+ M8.014,1035.374l9.944-12.785l9.945,12.785H8.014z"/>
2306+
2307+ <path id="path4079" inkscape:connector-curvature="0" inkscape:transform-center-x="14.694444" sodipodi:nodetypes="cccc" fill="#FFFFFF" d="
2308+ M9.014,1035.374l8.944-11.5l8.944,11.5H9.014z"/>
2309+</g>
2310+</svg>
2311
2312=== added file 'resources/launcher_arrow_outline_btt_19.svg'
2313--- resources/launcher_arrow_outline_btt_19.svg 1970-01-01 00:00:00 +0000
2314+++ resources/launcher_arrow_outline_btt_19.svg 2016-03-18 01:19:20 +0000
2315@@ -0,0 +1,15 @@
2316+<?xml version="1.0" encoding="utf-8"?>
2317+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2318+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2319+<svg version="1.1"
2320+ id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_outline_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png"
2321+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px"
2322+ height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve">
2323+<sodipodi:namedview id="base" inkscape:cx="2.8593254" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="8.2525377" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-text-baseline="false" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" inkscape:zoom="92.64423" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true">
2324+ <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8">
2325+ </inkscape:grid>
2326+</sodipodi:namedview>
2327+<path id="path5726" opacity="0.14" enable-background="new " d="M5.008,10.006h3.496L9.809,8.29l1.305,1.716h3.496L9.809,3.689
2328+ L5.008,10.006z"/>
2329+<path id="path4097" fill="#FFFFFF" d="M6.008,10.006h1.52l2.281-3l2.281,3h1.52l-3.801-5L6.008,10.006z"/>
2330+</svg>
2331
2332=== added file 'resources/launcher_arrow_outline_btt_37.svg'
2333--- resources/launcher_arrow_outline_btt_37.svg 1970-01-01 00:00:00 +0000
2334+++ resources/launcher_arrow_outline_btt_37.svg 2016-03-18 01:19:20 +0000
2335@@ -0,0 +1,19 @@
2336+<?xml version="1.0" encoding="utf-8"?>
2337+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2338+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2339+<svg version="1.1"
2340+ id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_large_outline_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png"
2341+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="36.992px"
2342+ height="20.012px" viewBox="0 0 36.992 20.012" enable-background="new 0 0 36.992 20.012" xml:space="preserve">
2343+<sodipodi:namedview id="base" inkscape:cx="-2.301892" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="19.020977" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" showguides="false" inkscape:zoom="22.737367" inkscape:snap-grids="false" inkscape:guide-bbox="true" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true">
2344+ <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8">
2345+ </inkscape:grid>
2346+ <sodipodi:guide id="guide3004" position="8,19" orientation="0,1"></sodipodi:guide>
2347+</sodipodi:namedview>
2348+<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer">
2349+ <path id="path5730" inkscape:connector-curvature="0" opacity="0.14" enable-background="new " d="M8.551,1035.374l9.945-12.785
2350+ l9.946,12.785h-4.899l-5.045-6.486l-5.045,6.486H8.551z"/>
2351+ <path id="path4079" inkscape:connector-curvature="0" fill="#FFFFFF" d="M9.551,1035.374h2.957l5.988-7.699l5.989,7.699h2.957
2352+ l-8.946-11.5L9.551,1035.374z"/>
2353+</g>
2354+</svg>
2355
2356=== added file 'resources/launcher_arrow_ttb_19.svg'
2357--- resources/launcher_arrow_ttb_19.svg 1970-01-01 00:00:00 +0000
2358+++ resources/launcher_arrow_ttb_19.svg 2016-03-18 01:19:20 +0000
2359@@ -0,0 +1,16 @@
2360+<?xml version="1.0" encoding="utf-8"?>
2361+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2362+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2363+<svg version="1.1"
2364+ id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_ltr.svg" inkscape:export-xdpi="90" inkscape:export-ydpi="90" inkscape:export-filename="test.png"
2365+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px"
2366+ height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve">
2367+<sodipodi:namedview id="base" inkscape:cx="6.1247407" inkscape:window-maximized="1" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-intersection-paths="true" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true" inkscape:snap-text-baseline="false" pagecolor="#5c48bb" inkscape:cy="9.1968087" bordercolor="#666666" borderopacity="1.0" showgrid="true" inkscape:zoom="59.292307" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:object-paths="true" inkscape:object-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-center="true" inkscape:snap-page="true" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1855" inkscape:window-height="1056" inkscape:window-x="65" inkscape:window-y="24">
2368+ <inkscape:grid type="xygrid" visible="true" enabled="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8">
2369+ </inkscape:grid>
2370+</sodipodi:namedview>
2371+<path id="path5726" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" opacity="0.14" enable-background="new " d="
2372+ M14.296,0l-4.8,6.316L4.696,0H14.296z"/>
2373+<path id="path4097" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" fill="#FFFFFF" d="M13.296,0l-3.8,5L5.695,0H13.296
2374+ z"/>
2375+</svg>
2376
2377=== added file 'resources/launcher_arrow_ttb_37.svg'
2378--- resources/launcher_arrow_ttb_37.svg 1970-01-01 00:00:00 +0000
2379+++ resources/launcher_arrow_ttb_37.svg 2016-03-18 01:19:20 +0000
2380@@ -0,0 +1,21 @@
2381+<?xml version="1.0" encoding="utf-8"?>
2382+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2383+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2384+<svg version="1.1"
2385+ id="svg2" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" inkscape:version="0.48+devel r" sodipodi:docname="launcher_arrow_large_ltr.svg" inkscape:export-xdpi="90" inkscape:export-ydpi="90" inkscape:export-filename="test.png"
2386+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="36.992px"
2387+ height="20.012px" viewBox="0 0 36.992 20.012" enable-background="new 0 0 36.992 20.012" xml:space="preserve">
2388+<sodipodi:namedview id="base" inkscape:cx="-5.367523" inkscape:window-maximized="1" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-intersection-paths="true" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true" showguides="false" pagecolor="#5c48bb" inkscape:cy="31.963893" bordercolor="#666666" borderopacity="1.0" showgrid="true" inkscape:zoom="9.3132256" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:object-paths="true" inkscape:object-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-center="true" inkscape:snap-page="true" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1855" inkscape:window-height="1056" inkscape:window-x="65" inkscape:window-y="24" inkscape:guide-bbox="true" inkscape:snap-grids="false">
2389+ <inkscape:grid type="xygrid" visible="true" enabled="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8">
2390+ </inkscape:grid>
2391+ <sodipodi:guide id="guide3004" orientation="0,1" position="8,19"></sodipodi:guide>
2392+</sodipodi:namedview>
2393+<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer">
2394+
2395+ <path id="path5730" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" inkscape:transform-center-x="16.337474" opacity="0.14" enable-background="new " d="
2396+ M28.646,1015.362l-9.943,12.785l-9.945-12.785H28.646z"/>
2397+
2398+ <path id="path4079" inkscape:connector-curvature="0" sodipodi:nodetypes="cccc" inkscape:transform-center-x="14.694444" fill="#FFFFFF" d="
2399+ M27.647,1015.362l-8.944,11.5l-8.945-11.5H27.647z"/>
2400+</g>
2401+</svg>
2402
2403=== added file 'resources/launcher_pip_btt_19.svg'
2404--- resources/launcher_pip_btt_19.svg 1970-01-01 00:00:00 +0000
2405+++ resources/launcher_pip_btt_19.svg 2016-03-18 01:19:20 +0000
2406@@ -0,0 +1,18 @@
2407+<?xml version="1.0" encoding="utf-8"?>
2408+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2409+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2410+<svg version="1.1"
2411+ id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:version="0.48+devel r" sodipodi:docname="launcher_pip_ltr.svg" inkscape:export-ydpi="90" inkscape:export-xdpi="90" inkscape:export-filename="test.png"
2412+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="18.992px"
2413+ height="10.006px" viewBox="0 0 18.992 10.006" enable-background="new 0 0 18.992 10.006" xml:space="preserve">
2414+<sodipodi:namedview id="base" inkscape:cx="6.9043528" showgrid="true" borderopacity="1.0" bordercolor="#666666" inkscape:cy="9.653247" pagecolor="#5c48bb" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:snap-bbox="true" inkscape:snap-text-baseline="false" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:snap-intersection-paths="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:window-maximized="1" inkscape:zoom="30.357661" inkscape:window-y="24" inkscape:window-x="65" inkscape:window-height="1056" inkscape:window-width="1855" inkscape:current-layer="layer1" inkscape:document-units="px" inkscape:pageshadow="2" inkscape:pageopacity="0" inkscape:snap-page="true" inkscape:snap-center="true" inkscape:snap-midpoints="true" inkscape:object-nodes="true" inkscape:object-paths="true">
2415+ <inkscape:grid type="xygrid" enabled="true" visible="true" id="grid4740" snapvisiblegridlinesonly="true" empspacing="8">
2416+ </inkscape:grid>
2417+</sodipodi:namedview>
2418+<g id="layer1" transform="translate(0,-1033.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer">
2419+ <path id="path5728" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc" opacity="0.14" enable-background="new " d="
2420+ M6.996,1043.368v-3.5l2.5-3l2.5,3v3.5H6.996z"/>
2421+ <path id="path4742" inkscape:connector-curvature="0" sodipodi:nodetypes="cccccc" fill="#FFFFFF" d="M7.996,1043.368v-3l1.5-2
2422+ l1.5,2v3H7.996z"/>
2423+</g>
2424+</svg>
2425
2426=== added file 'resources/launcher_pip_btt_37.svg'
2427--- resources/launcher_pip_btt_37.svg 1970-01-01 00:00:00 +0000
2428+++ resources/launcher_pip_btt_37.svg 2016-03-18 01:19:20 +0000
2429@@ -0,0 +1,19 @@
2430+<?xml version="1.0" encoding="utf-8"?>
2431+<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2432+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2433+<svg version="1.1"
2434+ id="svg2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" inkscape:export-xdpi="90" inkscape:export-ydpi="90" sodipodi:docname="launcher_pip_large_ltr.svg" inkscape:version="0.48+devel r" inkscape:export-filename="test.png"
2435+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 37 20"
2436+ enable-background="new 0 0 37 20" xml:space="preserve">
2437+<sodipodi:namedview id="base" pagecolor="#5c48bb" inkscape:zoom="28.42171" showguides="false" inkscape:cy="12.499554" bordercolor="#666666" borderopacity="1.0" showgrid="true" inkscape:cx="3.9411358" inkscape:snap-global="true" inkscape:object-paths="true" inkscape:object-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-center="true" inkscape:snap-page="true" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:document-units="px" inkscape:current-layer="layer1" inkscape:window-width="1855" inkscape:window-height="1056" inkscape:window-x="65" inkscape:window-y="24" inkscape:guide-bbox="true" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:window-maximized="1" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-intersection-paths="true" inkscape:snap-smooth-nodes="true" inkscape:snap-object-midpoints="true">
2438+ <inkscape:grid type="xygrid" enabled="true" id="grid4740" visible="true" empspacing="8" snapvisiblegridlinesonly="true">
2439+ </inkscape:grid>
2440+ <sodipodi:guide id="guide3004" orientation="0,1" position="8,19"></sodipodi:guide>
2441+</sodipodi:namedview>
2442+<g id="layer1" transform="translate(0,-1015.3622)" inkscape:label="Layer 1" inkscape:groupmode="layer">
2443+ <path id="path5745" sodipodi:nodetypes="cccccc" inkscape:connector-curvature="0" opacity="0.14" enable-background="new " d="
2444+ M14,1035.4v-7.5l4.5-5.5l4.5,5.5v7.5H14z"/>
2445+ <path id="path4742" sodipodi:nodetypes="cccccc" inkscape:connector-curvature="0" fill="#FFFFFF" d="M15,1035.4v-7l3.5-4.5
2446+ l3.5,4.5v7H15z"/>
2447+</g>
2448+</svg>
2449
2450=== added file 'resources/launcher_pressure_effect_rotated.png'
2451Binary files resources/launcher_pressure_effect_rotated.png 1970-01-01 00:00:00 +0000 and resources/launcher_pressure_effect_rotated.png 2016-03-18 01:19:20 +0000 differ
2452=== modified file 'tests/autopilot/unity/emulators/__init__.py'
2453--- tests/autopilot/unity/emulators/__init__.py 2015-08-19 13:54:05 +0000
2454+++ tests/autopilot/unity/emulators/__init__.py 2016-03-18 01:19:20 +0000
2455@@ -20,7 +20,14 @@
2456
2457 from dbus import DBusException
2458
2459-
2460+keys = {
2461+ "Left/launcher/keynav/prev": "launcher/keynav/prev",
2462+ "Left/launcher/keynav/next": "launcher/keynav/next",
2463+ "Left/launcher/keynav/open-quicklist": "launcher/keynav/open-quicklist",
2464+ "Bottom/launcher/keynav/prev": "launcher/keynav/close-quicklist",
2465+ "Bottom/launcher/keynav/next": "launcher/keynav/open-quicklist",
2466+ "Bottom/launcher/keynav/open-quicklist": "launcher/keynav/prev",
2467+}
2468 class UnityIntrospectionObject(CustomEmulatorBase):
2469
2470 DBUS_SERVICE = "com.canonical.Unity"
2471
2472=== modified file 'tests/autopilot/unity/emulators/launcher.py'
2473--- tests/autopilot/unity/emulators/launcher.py 2015-09-10 13:23:47 +0000
2474+++ tests/autopilot/unity/emulators/launcher.py 2016-03-18 01:19:20 +0000
2475@@ -17,6 +17,7 @@
2476 from time import sleep
2477
2478 from unity.emulators import UnityIntrospectionObject
2479+from unity.emulators import keys
2480 from unity.emulators.icons import (
2481 ApplicationLauncherIcon,
2482 BFBLauncherIcon,
2483@@ -37,6 +38,10 @@
2484 BEFORE = 3
2485 AFTER = 4
2486
2487+class LauncherPosition:
2488+ """Define launcher possible positions"""
2489+ LEFT = "Left"
2490+ BOTTOM = "Bottom"
2491
2492 class LauncherController(UnityIntrospectionObject):
2493 """The LauncherController class."""
2494@@ -104,12 +109,16 @@
2495 """Places the mouse on the screen of this launcher."""
2496 move_mouse_to_screen(self.monitor)
2497
2498- def move_mouse_to_right_of_launcher(self):
2499+ def move_mouse_beside_launcher(self):
2500 """Places the mouse to the right of this launcher."""
2501 move_mouse_to_screen(self.monitor)
2502 (x, y, w, h) = self.geometry
2503- target_x = x + w + 10
2504- target_y = y + h / 2
2505+ if h > w:
2506+ target_x = x + w + 10
2507+ target_y = y + h / 2
2508+ else:
2509+ target_x = x + w / 2
2510+ target_y = y - 10
2511
2512 logger.debug("Moving mouse away from launcher.")
2513 self._mouse.move(target_x, target_y, False)
2514@@ -153,8 +162,13 @@
2515 move_mouse_to_screen(self.monitor)
2516 (x, y, w, h) = self.geometry
2517
2518- target_x = x - 300 # this is the pressure we need to reveal the launcher.
2519- target_y = y + h / 2
2520+ if h > w:
2521+ target_x = x - 300 # this is the pressure we need to reveal the launcher.
2522+ target_y = y + h / 2
2523+ else:
2524+ target_x = x + w / 2
2525+ target_y = y + h + 300
2526+
2527 logger.debug("Revealing launcher on monitor %d with mouse.", self.monitor)
2528 self._mouse.move(target_x, target_y, True, 5, .002)
2529
2530@@ -177,7 +191,7 @@
2531 if self.hidemode == 1:
2532 self.is_showing.wait_for(False)
2533
2534- def keyboard_select_icon(self, **kwargs):
2535+ def keyboard_select_icon(self, launcher_position = LauncherPosition.LEFT, **kwargs):
2536 """Using either keynav mode or the switcher, select an icon in the launcher.
2537
2538 The desired mode (keynav or switcher) must be started already before
2539@@ -218,7 +232,7 @@
2540 if matches:
2541 return
2542 if self.in_keynav_mode:
2543- self.key_nav_next()
2544+ self.key_nav_next(launcher_position)
2545 elif self.in_switcher_mode:
2546 self.switcher_next()
2547 raise ValueError("No icon found that matches: %r", kwargs)
2548@@ -244,23 +258,23 @@
2549 self._perform_key_nav_exit_binding("launcher/keynav/activate")
2550 self._get_controller().key_nav_is_active.wait_for(False)
2551
2552- def key_nav_next(self):
2553+ def key_nav_next(self, launcher_position = LauncherPosition.LEFT):
2554 """Moves the launcher keynav focus to the next launcher icon"""
2555 logger.debug("Selecting next item in keyboard navigation mode.")
2556 old_selection = self._get_controller().key_nav_selection
2557- self._perform_key_nav_binding("launcher/keynav/next")
2558+ self._perform_key_nav_binding(keys[launcher_position + "/launcher/keynav/next"])
2559 self._get_controller().key_nav_selection.wait_for(NotEquals(old_selection))
2560
2561- def key_nav_prev(self):
2562+ def key_nav_prev(self, launcher_position = LauncherPosition.LEFT):
2563 """Moves the launcher keynav focus to the previous launcher icon"""
2564 logger.debug("Selecting previous item in keyboard navigation mode.")
2565 old_selection = self._get_controller().key_nav_selection
2566- self._perform_key_nav_binding("launcher/keynav/prev")
2567+ self._perform_key_nav_binding(keys[launcher_position + "/launcher/keynav/prev"])
2568 self._get_controller().key_nav_selection.wait_for(NotEquals(old_selection))
2569
2570- def key_nav_enter_quicklist(self):
2571+ def key_nav_enter_quicklist(self, launcher_position = LauncherPosition.LEFT):
2572 logger.debug("Opening quicklist for currently selected icon.")
2573- self._perform_key_nav_binding("launcher/keynav/open-quicklist")
2574+ self._perform_key_nav_binding(keys[launcher_position + "/launcher/keynav/open-quicklist"])
2575 self.quicklist_open.wait_for(True)
2576
2577 def key_nav_exit_quicklist(self):
2578@@ -329,9 +343,9 @@
2579 self._mouse.click(button)
2580
2581 if (move_mouse_after):
2582- self.move_mouse_to_right_of_launcher()
2583+ self.move_mouse_beside_launcher()
2584
2585- def drag_icon_to_position(self, icon, pos, target, drag_type=IconDragType.INSIDE):
2586+ def drag_icon_to_position(self, icon, pos, target, drag_type=IconDragType.INSIDE, launcher_position=LauncherPosition.LEFT):
2587 """Drag a launcher icon to a new position.
2588
2589 'icon' is the icon to move. It must be either a ApplicationLauncherIcon or an
2590@@ -345,9 +359,14 @@
2591
2592 'drag_type' must be one of IconDragType.INSIDE or IconDragType.OUTSIDE.
2593 This specifies whether the icon is gragged inside the launcher, or to the
2594- right of it. The default is to drag inside the launcher. If it is
2595+ right/top of it. The default is to drag inside the launcher. If it is
2596 specified, and not one of the allowed values, a ValueError will be raised.
2597
2598+ 'launcher_position' must be one of LauncherPosition.LEFT or LauncherPosition.BOTTOM.
2599+ This specifies the launcher position when dragging the icon. The default launcher
2600+ position is at left. If it is specified, and not one of the allowed values, a
2601+ ValueError will be raised.
2602+
2603 For example:
2604
2605 >>> drag_icon_to_position(calc_icon, IconDragType.BEFORE, switcher_icon)
2606@@ -374,29 +393,41 @@
2607 if drag_type not in (IconDragType.INSIDE, IconDragType.OUTSIDE):
2608 raise ValueError("'drag_type' parameter must be one of IconDragType.INSIDE, IconDragType.OUTSIDE")
2609
2610- icon_height = get_compiz_option("unityshell", "icon_size")
2611+ icon_size = get_compiz_option("unityshell", "icon_size")
2612
2613 self.move_mouse_to_icon(icon)
2614 self._mouse.press()
2615 sleep(1)
2616
2617 if drag_type == IconDragType.OUTSIDE:
2618- shift_over = self._mouse.x + (icon_height * 2)
2619- self._mouse.move(shift_over, self._mouse.y, rate=20, time_between_events=0.005)
2620+ if launcher_position == LauncherPosition.LEFT:
2621+ shift_over = self._mouse.x + (icon_size * 3)
2622+ self._mouse.move(shift_over, self._mouse.y, rate=20, time_between_events=0.005)
2623+ else:
2624+ shift_over = self._mouse.y - (icon_size * 3)
2625+ self._mouse.move(self._mouse.x, shift_over, rate=20, time_between_events=0.005)
2626 sleep(0.5)
2627
2628 self.move_mouse_to_icon(target)
2629
2630- target_y = target.center.y
2631- if target_y < icon.center.y:
2632- target_y += icon_height
2633- if pos == IconDragType.BEFORE:
2634- target_y -= icon_height + (icon_height / 2)
2635+ if launcher_position == LauncherPosition.LEFT:
2636+ target_y = target.center.y
2637+ if target_y < icon.center.y:
2638+ target_y += icon_size
2639+ if pos == IconDragType.BEFORE:
2640+ target_y -= icon_size + (icon_size / 2)
2641+ self._mouse.move(self._mouse.x, target_y, rate=20, time_between_events=0.005)
2642+ else:
2643+ target_x = target.center.x
2644+ if target_x < icon.center.x:
2645+ target_x += icon_size
2646+ if pos == IconDragType.BEFORE:
2647+ target_x -= icon_size + (icon_size / 2)
2648+ self._mouse.move(target_x, self._mouse.y, rate=20, time_between_events=0.005)
2649
2650- self._mouse.move(self._mouse.x, target_y, rate=20, time_between_events=0.005)
2651 sleep(1)
2652 self._mouse.release()
2653- self.move_mouse_to_right_of_launcher()
2654+ self.move_mouse_beside_launcher()
2655
2656 def lock_to_launcher(self, icon):
2657 """lock 'icon' to the launcher, if it's not already.
2658
2659=== modified file 'tests/autopilot/unity/tests/launcher/__init__.py'
2660--- tests/autopilot/unity/tests/launcher/__init__.py 2014-01-23 15:51:46 +0000
2661+++ tests/autopilot/unity/tests/launcher/__init__.py 2016-03-18 01:19:20 +0000
2662@@ -13,6 +13,7 @@
2663
2664 from unity.tests import UnityTestCase
2665 from unity.emulators.X11 import set_primary_monitor
2666+from unity.emulators.launcher import LauncherPosition
2667
2668
2669 def _make_scenarios():
2670@@ -35,7 +36,11 @@
2671 """A base class for all launcher tests that uses scenarios to run on
2672 each launcher (for multi-monitor setups).
2673 """
2674- scenarios = _make_scenarios()
2675+ scenarios = multiply_scenarios(_make_scenarios(),
2676+ [
2677+ ('left', {'launcher_position': LauncherPosition.LEFT}),
2678+ ('bottom', {'launcher_position': LauncherPosition.BOTTOM}),
2679+ ])
2680
2681 def setUp(self):
2682 super(LauncherTestCase, self).setUp()
2683@@ -45,6 +50,10 @@
2684 self.set_unity_option('num_launchers', int(self.only_primary))
2685 self.launcher_instance = self.get_launcher()
2686
2687+ old_pos = self.call_gsettings_cmd('get', 'com.canonical.Unity.Launcher', 'launcher-position')
2688+ self.call_gsettings_cmd('set', 'com.canonical.Unity.Launcher', 'launcher-position', '"%s"' % self.launcher_position)
2689+ self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity.Launcher', 'launcher-position', old_pos)
2690+
2691 if not self.launcher_instance:
2692 self.skipTest("Cannot run test with no Launcher on monitor %d." % self.launcher_monitor)
2693
2694
2695=== modified file 'tests/autopilot/unity/tests/launcher/test_icon_behavior.py'
2696--- tests/autopilot/unity/tests/launcher/test_icon_behavior.py 2015-09-10 13:23:47 +0000
2697+++ tests/autopilot/unity/tests/launcher/test_icon_behavior.py 2016-03-18 01:19:20 +0000
2698@@ -17,6 +17,7 @@
2699
2700 from unity.emulators.icons import ApplicationLauncherIcon, ExpoLauncherIcon
2701 from unity.emulators.launcher import IconDragType
2702+from unity.emulators.launcher import LauncherPosition
2703 from unity.tests.launcher import LauncherTestCase, _make_scenarios
2704
2705 from Xlib import Xutil
2706@@ -196,7 +197,8 @@
2707 self.launcher_instance.drag_icon_to_position(
2708 calc_icon,
2709 IconDragType.AFTER,
2710- bfb_icon)
2711+ bfb_icon,
2712+ launcher_position = self.launcher_position)
2713
2714 self.launcher_instance.keyboard_reveal_launcher()
2715 self.addCleanup(self.launcher_instance.keyboard_unreveal_launcher)
2716@@ -354,6 +356,10 @@
2717 [
2718 ('inside', {'drag_type': IconDragType.INSIDE}),
2719 ('outside', {'drag_type': IconDragType.OUTSIDE}),
2720+ ],
2721+ [
2722+ ('left', {'launcher_position': LauncherPosition.LEFT}),
2723+ ('bottom', {'launcher_position': LauncherPosition.BOTTOM}),
2724 ])
2725
2726 def setUp(self):
2727@@ -386,7 +392,8 @@
2728 calc_icon,
2729 IconDragType.AFTER,
2730 bfb_icon,
2731- self.drag_type)
2732+ self.drag_type,
2733+ self.launcher_position)
2734 moved_icon = self.unity.launcher.model.\
2735 get_launcher_icons_for_monitor(self.launcher_monitor)[1]
2736 self.assertThat(moved_icon, Equals(calc_icon))
2737@@ -406,14 +413,16 @@
2738 calc_icon,
2739 IconDragType.AFTER,
2740 bfb_icon,
2741- self.drag_type)
2742+ self.drag_type,
2743+ self.launcher_position)
2744
2745 sleep(1)
2746 self.launcher_instance.drag_icon_to_position(
2747 calc_icon,
2748 IconDragType.BEFORE,
2749 trash_icon,
2750- self.drag_type)
2751+ self.drag_type,
2752+ self.launcher_position)
2753
2754 # Must be the last bamf icon - not necessarily the third-from-end icon.
2755 expected_pos = -2 if self.workspace.num_workspaces < 2 else -1
2756
2757=== modified file 'tests/autopilot/unity/tests/launcher/test_keynav.py'
2758--- tests/autopilot/unity/tests/launcher/test_keynav.py 2015-03-26 12:58:00 +0000
2759+++ tests/autopilot/unity/tests/launcher/test_keynav.py 2016-03-18 01:19:20 +0000
2760@@ -68,7 +68,7 @@
2761 def test_launcher_keynav_forward(self):
2762 """Must be able to move forwards while in keynav mode."""
2763 self.start_keynav_with_cleanup_cancel()
2764- self.launcher_instance.key_nav_next()
2765+ self.launcher_instance.key_nav_next(self.launcher_position)
2766 # The launcher model has hidden items, so the keynav indexes do not
2767 # increase by 1 each time. This test was failing because the 2nd icon
2768 # had an index of 2, not 1 as expected. The best we can do here is to
2769@@ -80,9 +80,9 @@
2770 def test_launcher_keynav_prev_works(self):
2771 """Must be able to move backwards while in keynav mode."""
2772 self.start_keynav_with_cleanup_cancel()
2773- self.launcher_instance.key_nav_next()
2774+ self.launcher_instance.key_nav_next(self.launcher_position)
2775 self.assertThat(self.unity.launcher.key_nav_selection, Eventually(GreaterThan(0)))
2776- self.launcher_instance.key_nav_prev()
2777+ self.launcher_instance.key_nav_prev(self.launcher_position)
2778 self.assertThat(self.unity.launcher.key_nav_selection, Eventually(Equals(0)))
2779
2780 def test_launcher_keynav_cycling_forward(self):
2781@@ -90,29 +90,29 @@
2782 self.start_keynav_with_cleanup_cancel()
2783 prev_icon = 0
2784 for icon in range(1, self.unity.launcher.model.num_launcher_icons()):
2785- self.launcher_instance.key_nav_next()
2786+ self.launcher_instance.key_nav_next(self.launcher_position)
2787 # FIXME We can't directly check for selection/icon number equalty
2788 # since the launcher model also contains "hidden" icons that aren't
2789 # shown, so the selection index can increment by more than 1.
2790 self.assertThat(self.unity.launcher.key_nav_selection, Eventually(GreaterThan(prev_icon)))
2791 prev_icon = self.unity.launcher.key_nav_selection
2792
2793- self.launcher_instance.key_nav_next()
2794+ self.launcher_instance.key_nav_next(self.launcher_position)
2795 self.assertThat(self.unity.launcher.key_nav_selection, Eventually(Equals(0)))
2796
2797 def test_launcher_keynav_cycling_backward(self):
2798 """Launcher keynav must loop through icons when cycling backwards"""
2799 self.start_keynav_with_cleanup_cancel()
2800- self.launcher_instance.key_nav_prev()
2801+ self.launcher_instance.key_nav_prev(self.launcher_position)
2802 # FIXME We can't directly check for self.unity.launcher.num_launcher_icons - 1
2803 self.assertThat(self.unity.launcher.key_nav_selection, Eventually(GreaterThan(1)))
2804
2805 def test_launcher_keynav_can_open_and_close_quicklist(self):
2806 """Tests that we can open and close a quicklist from keynav mode."""
2807 self.start_keynav_with_cleanup_cancel()
2808- self.launcher_instance.key_nav_next()
2809+ self.launcher_instance.key_nav_next(self.launcher_position)
2810 self.addCleanup(self.keyboard.press_and_release, "Escape")
2811- self.launcher_instance.key_nav_enter_quicklist()
2812+ self.launcher_instance.key_nav_enter_quicklist(self.launcher_position)
2813 self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(True)))
2814 self.launcher_instance.key_nav_exit_quicklist()
2815 self.assertThat(self.launcher_instance.quicklist_open, Eventually(Equals(False)))
2816@@ -135,7 +135,7 @@
2817
2818 self.start_keynav_with_cleanup_cancel()
2819
2820- self.launcher_instance.keyboard_select_icon(tooltip_text=calc.name)
2821+ self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text=calc.name)
2822 self.launcher_instance.key_nav_activate()
2823
2824 self.assertTrue(calc.is_active)
2825@@ -148,7 +148,7 @@
2826
2827 self.start_keynav_with_cleanup_cancel()
2828
2829- self.launcher_instance.keyboard_select_icon(tooltip_text="Workspace Switcher")
2830+ self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text="Workspace Switcher")
2831 self.launcher_instance.key_nav_activate()
2832 self.addCleanup(self.keybinding, "expo/cancel")
2833
2834@@ -160,7 +160,7 @@
2835 self.skipTest("This test requires enabled more than one workspace.")
2836 self.start_keynav_with_cleanup_cancel()
2837
2838- self.launcher_instance.keyboard_select_icon(tooltip_text="Workspace Switcher")
2839+ self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text="Workspace Switcher")
2840 self.launcher_instance.key_nav_activate()
2841
2842 self.keyboard.press_and_release("Escape")
2843@@ -209,7 +209,7 @@
2844 """A single click outside of launcher must cancel keynav."""
2845 self.start_keynav_with_cleanup_cancel()
2846
2847- self.launcher_instance.move_mouse_to_right_of_launcher()
2848+ self.launcher_instance.move_mouse_beside_launcher()
2849 self.mouse.click()
2850
2851 self.assertThat(self.unity.launcher.key_nav_is_active, Eventually(Equals(False)))
2852@@ -229,7 +229,7 @@
2853 def test_launcher_keynav_cancel_on_quicklist_activate(self):
2854 """A single click on a quicklist item must cancel keynav."""
2855 self.start_keynav_with_cleanup_cancel()
2856- self.launcher_instance.key_nav_enter_quicklist()
2857+ self.launcher_instance.key_nav_enter_quicklist(self.launcher_position)
2858
2859 bfb_icon = self.unity.launcher.model.get_bfb_icon()
2860 bfb_ql = bfb_icon.get_quicklist()
2861
2862=== modified file 'tests/autopilot/unity/tests/launcher/test_reveal.py'
2863--- tests/autopilot/unity/tests/launcher/test_reveal.py 2014-01-23 15:51:46 +0000
2864+++ tests/autopilot/unity/tests/launcher/test_reveal.py 2016-03-18 01:19:20 +0000
2865@@ -39,7 +39,7 @@
2866
2867 def test_reveal_on_mouse_to_edge(self):
2868 """Tests reveal of launchers by mouse pressure."""
2869- self.launcher_instance.move_mouse_to_right_of_launcher()
2870+ self.launcher_instance.move_mouse_beside_launcher()
2871 self.launcher_instance.mouse_reveal_launcher()
2872 self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True)))
2873
2874@@ -58,7 +58,7 @@
2875 """Tests reveal of launchers by mouse pressure to ensure it doesn't
2876 automatically hide again.
2877 """
2878- self.launcher_instance.move_mouse_to_right_of_launcher()
2879+ self.launcher_instance.move_mouse_beside_launcher()
2880 self.launcher_instance.mouse_reveal_launcher()
2881 self.assertThat(self.launcher_instance.is_showing, Eventually(Equals(True)))
2882
2883
2884=== modified file 'tests/autopilot/unity/tests/launcher/test_scroll.py'
2885--- tests/autopilot/unity/tests/launcher/test_scroll.py 2014-12-15 15:17:36 +0000
2886+++ tests/autopilot/unity/tests/launcher/test_scroll.py 2016-03-18 01:19:20 +0000
2887@@ -88,8 +88,9 @@
2888 launcher_instance.move_mouse_to_icon(last_icon)
2889
2890 # Make sure the first icon is off the screen or else there is no
2891- # scrolling.
2892- self.assertThat(first_icon.center.y, LessThan(y))
2893+ # scrolling when launcher at left
2894+ if w < h:
2895+ self.assertThat(first_icon.center.y, LessThan(y))
2896
2897 # Autoscroll to the first icon
2898 launcher_instance.move_mouse_to_icon(first_icon, autoscroll_offset)
2899
2900=== modified file 'tests/autopilot/unity/tests/launcher/test_switcher.py'
2901--- tests/autopilot/unity/tests/launcher/test_switcher.py 2014-01-23 15:51:46 +0000
2902+++ tests/autopilot/unity/tests/launcher/test_switcher.py 2016-03-18 01:19:20 +0000
2903@@ -152,7 +152,7 @@
2904
2905 self.start_switcher_with_cleanup_cancel()
2906
2907- self.launcher_instance.keyboard_select_icon(tooltip_text=calc.name)
2908+ self.launcher_instance.keyboard_select_icon(self.launcher_position, tooltip_text=calc.name)
2909 self.launcher_instance.switcher_activate()
2910
2911 self.assertThat(lambda: calc.is_active, Eventually(Equals(True)))
2912
2913=== modified file 'tests/autopilot/unity/tests/launcher/test_tooltips.py'
2914--- tests/autopilot/unity/tests/launcher/test_tooltips.py 2014-03-04 22:50:22 +0000
2915+++ tests/autopilot/unity/tests/launcher/test_tooltips.py 2016-03-18 01:19:20 +0000
2916@@ -18,7 +18,7 @@
2917 def setUp(self):
2918 super(LauncherTooltipTests, self).setUp()
2919 self.set_unity_option('launcher_hide_mode', 0)
2920- self.launcher_instance.move_mouse_to_right_of_launcher()
2921+ self.launcher_instance.move_mouse_beside_launcher()
2922 self.icons = self.unity.launcher.model.get_launcher_icons(visible_only=True)
2923
2924 def test_launcher_tooltip_show(self):
2925@@ -49,7 +49,7 @@
2926 b -= 1
2927
2928 # leaving launcher clears tooltips, and instant reveal
2929- self.launcher_instance.move_mouse_to_right_of_launcher()
2930+ self.launcher_instance.move_mouse_beside_launcher()
2931 self.assertEqual(self.get_reveal_behavior(self.icons[b]), self.DELAYED)
2932
2933 def test_launcher_tooltip_disabling(self):
2934
2935=== modified file 'tests/autopilot/unity/tests/test_dash.py'
2936--- tests/autopilot/unity/tests/test_dash.py 2016-02-17 18:40:53 +0000
2937+++ tests/autopilot/unity/tests/test_dash.py 2016-03-18 01:19:20 +0000
2938@@ -148,10 +148,10 @@
2939
2940 self.unity.dash.ensure_visible()
2941
2942- # Click bottom right of the screen, but take into account the non-maximized window -
2943+ # Click right of the screen, but take into account the non-maximized window -
2944 # we do not want to click on it as it focuses the wrong window
2945 w = self.display.get_screen_width() - 1
2946- h = self.display.get_screen_height() - 1
2947+ h = self.display.get_screen_height() / 2
2948
2949 # If the mouse is over the non-maximized window, move it away from it.
2950 (calc_x, calc_y, calc_w, calc_h) = calc_win.get_windows()[0].geometry
2951@@ -689,8 +689,10 @@
2952
2953 self.unity.dash.ensure_visible()
2954
2955- self.assertThat(self.unity.dash.view.x, Eventually(Equals(launcher.geometry.x + launcher.geometry.width - 1)))
2956-
2957+ if launcher.geometry.width < launcher.geometry.height:
2958+ self.assertThat(self.unity.dash.view.x, Eventually(Equals(launcher.geometry.x + launcher.geometry.width - 1)))
2959+ else:
2960+ self.assertThat(self.unity.dash.view.x, Eventually(Equals(0)))
2961
2962 def test_see_more_result_alignment(self):
2963 """The see more results label should be baseline aligned
2964
2965=== modified file 'tests/autopilot/unity/tests/test_hud.py'
2966--- tests/autopilot/unity/tests/test_hud.py 2015-02-19 19:23:39 +0000
2967+++ tests/autopilot/unity/tests/test_hud.py 2016-03-18 01:19:20 +0000
2968@@ -27,6 +27,8 @@
2969 from time import sleep
2970
2971 from unity.emulators.icons import HudLauncherIcon
2972+from unity.emulators.icons import BFBLauncherIcon
2973+from unity.emulators.launcher import LauncherPosition
2974 from unity.tests import UnityTestCase
2975
2976
2977@@ -471,10 +473,10 @@
2978
2979 self.unity.hud.ensure_visible()
2980
2981- # Click bottom right of the screen, but take into account the non-maximized window -
2982+ # Click right of the screen, but take into account the non-maximized window -
2983 # we do not want to click on it as it focuses the wrong window
2984 w = self.display.get_screen_width() - 1
2985- h = self.display.get_screen_height() - 1
2986+ h = (self.display.get_screen_height() - 1) / 2
2987
2988 # If the mouse is over the non-maximized window, move it away from it.
2989 (calc_x, calc_y, calc_w, calc_h) = calc_win.get_windows()[0].geometry
2990@@ -585,7 +587,10 @@
2991
2992 class HudLockedLauncherInteractionsTests(HudTestsBase):
2993
2994- scenarios = _make_monitor_scenarios()
2995+ launcher_position = [('Launcher on the left', {'launcher_position': LauncherPosition.LEFT}),
2996+ ('Launcher on the bottom', {'launcher_position': LauncherPosition.BOTTOM})]
2997+
2998+ scenarios = multiply_scenarios(_make_monitor_scenarios(), launcher_position)
2999
3000 def setUp(self):
3001 super(HudLockedLauncherInteractionsTests, self).setUp()
3002@@ -593,6 +598,10 @@
3003 self.set_unity_option('num_launchers', 0)
3004 self.set_unity_option('launcher_hide_mode', 0)
3005
3006+ old_pos = self.call_gsettings_cmd('get', 'com.canonical.Unity.Launcher', 'launcher-position')
3007+ self.call_gsettings_cmd('set', 'com.canonical.Unity.Launcher', 'launcher-position', '"%s"' % self.launcher_position)
3008+ self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity.Launcher', 'launcher-position', old_pos)
3009+
3010 move_mouse_to_screen(self.hud_monitor)
3011 sleep(0.5)
3012
3013@@ -608,8 +617,9 @@
3014
3015 self.unity.hud.ensure_visible()
3016
3017- self.assertTrue(hud_icon.monitors_visibility[self.hud_monitor])
3018- self.assertTrue(hud_icon.is_on_monitor(self.hud_monitor))
3019+ if self.launcher_position == LauncherPosition.LEFT:
3020+ self.assertTrue(hud_icon.monitors_visibility[self.hud_monitor])
3021+ self.assertTrue(hud_icon.is_on_monitor(self.hud_monitor))
3022 # For some reason the BFB icon is always visible :-/
3023 #bfb_icon.visible, Eventually(Equals(False)
3024
3025@@ -622,6 +632,8 @@
3026 if isinstance(icon, HudLauncherIcon):
3027 self.assertFalse(icon.monitors_desaturated[self.hud_monitor])
3028 else:
3029+ if isinstance(icon, BFBLauncherIcon) and self.launcher_position == LauncherPosition.BOTTOM:
3030+ continue
3031 self.assertTrue(icon.monitors_desaturated[self.hud_monitor])
3032
3033 def test_hud_launcher_icon_click_hides_hud(self):
3034@@ -645,15 +657,24 @@
3035 launcher_screen = [('Launcher on all monitors', {'launcher_primary_only': False}),
3036 ('Launcher on primary monitor', {'launcher_primary_only': True})]
3037
3038- scenarios = multiply_scenarios(_make_monitor_scenarios(), launcher_modes, launcher_screen)
3039+ launcher_position = [('Launcher on the left', {'launcher_position': LauncherPosition.LEFT}),
3040+ ('Launcher on the bottom', {'launcher_position': LauncherPosition.BOTTOM})]
3041+
3042+ scenarios = multiply_scenarios(_make_monitor_scenarios(), launcher_modes, launcher_screen, launcher_position)
3043
3044 def setUp(self):
3045 super(HudVisualTests, self).setUp()
3046 move_mouse_to_screen(self.hud_monitor)
3047 self.set_unity_option('launcher_hide_mode', int(self.launcher_autohide))
3048 self.set_unity_option('num_launchers', int(self.launcher_primary_only))
3049+
3050+ old_pos = self.call_gsettings_cmd('get', 'com.canonical.Unity.Launcher', 'launcher-position')
3051+ self.call_gsettings_cmd('set', 'com.canonical.Unity.Launcher', 'launcher-position', '"%s"' % self.launcher_position)
3052+ self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity.Launcher', 'launcher-position', old_pos)
3053+
3054 self.hud_monitor_is_primary = (self.display.get_primary_screen() == self.hud_monitor)
3055- self.hud_locked = (not self.launcher_autohide and (not self.launcher_primary_only or self.hud_monitor_is_primary))
3056+ self.hud_locked = (not self.launcher_autohide and (not self.launcher_primary_only or self.hud_monitor_is_primary)
3057+ and self.launcher_position != LauncherPosition.BOTTOM)
3058 sleep(0.5)
3059
3060 def test_initially_hidden(self):
3061@@ -671,10 +692,11 @@
3062 monitor_geo = self.display.get_screen_geometry(self.hud_monitor)
3063 monitor_x = monitor_geo[0]
3064 monitor_w = monitor_geo[2]
3065+ launcher = self.unity.launcher.get_launcher_for_monitor(self.hud_monitor)
3066 hud_x = self.unity.hud.geometry[0]
3067 hud_w = self.unity.hud.geometry[2]
3068
3069- if self.hud_locked:
3070+ if self.hud_locked and launcher.geometry.w < launcher.geometry.h:
3071 self.assertThat(hud_x, GreaterThan(monitor_x))
3072 self.assertThat(hud_x, LessThan(monitor_x + monitor_w))
3073 self.assertThat(hud_w, Equals(monitor_x + monitor_w - hud_x))
3074
3075=== modified file 'tests/autopilot/unity/tests/test_quicklist.py'
3076--- tests/autopilot/unity/tests/test_quicklist.py 2015-08-18 10:08:57 +0000
3077+++ tests/autopilot/unity/tests/test_quicklist.py 2016-03-18 01:19:20 +0000
3078@@ -17,7 +17,9 @@
3079 from time import sleep
3080 from xdg.DesktopEntry import DesktopEntry
3081
3082+from unity.emulators import keys
3083 from unity.emulators.quicklist import QuicklistMenuItemLabel
3084+from unity.emulators.launcher import LauncherPosition
3085 from unity.tests import UnityTestCase
3086
3087
3088@@ -193,12 +195,12 @@
3089
3090 icons = self.unity.launcher.model.get_launcher_icons()
3091
3092+ icon1_ql = self.open_quicklist_for_icon(icons[1])
3093+ self.assertThat(icon1_ql.active, Eventually(Equals(True)))
3094+
3095 icon0_ql = self.open_quicklist_for_icon(icons[0])
3096 self.assertThat(icon0_ql.active, Eventually(Equals(True)))
3097-
3098- icon1_ql = self.open_quicklist_for_icon(icons[1])
3099- self.assertThat(icon1_ql.active, Eventually(Equals(True)))
3100- self.assertThat(icon0_ql.wait_until_destroyed, Not(Raises()))
3101+ self.assertThat(icon1_ql.wait_until_destroyed, Not(Raises()))
3102
3103 def test_right_clicking_same_icon_doesnt_reopen_ql(self):
3104 """A right click to the same icon in the launcher must
3105@@ -224,6 +226,10 @@
3106
3107 class QuicklistKeyNavigationTests(UnityTestCase):
3108 """Tests for the quicklist key navigation."""
3109+ scenarios = [
3110+ ('left', {'launcher_position': LauncherPosition.LEFT}),
3111+ ('bottom', {'launcher_position': LauncherPosition.BOTTOM}),
3112+ ]
3113
3114 def setUp(self):
3115 super(QuicklistKeyNavigationTests, self).setUp()
3116@@ -239,6 +245,10 @@
3117
3118 self.ql_launcher = self.unity.launcher.get_launcher_for_monitor(0)
3119
3120+ old_pos = self.call_gsettings_cmd('get', 'com.canonical.Unity.Launcher', 'launcher-position')
3121+ self.call_gsettings_cmd('set', 'com.canonical.Unity.Launcher', 'launcher-position', '"%s"' % self.launcher_position)
3122+ self.addCleanup(self.call_gsettings_cmd, 'set', 'com.canonical.Unity.Launcher', 'launcher-position', old_pos)
3123+
3124 def open_quicklist_with_mouse(self):
3125 """Opens a quicklist with the mouse."""
3126 self.ql_launcher.click_launcher_icon(self.ql_launcher_icon, button=3)
3127@@ -256,8 +266,8 @@
3128 self.ql_launcher.key_nav_start()
3129 self.addCleanup(self.ql_launcher.key_nav_cancel)
3130
3131- self.ql_launcher.keyboard_select_icon(tooltip_text=self.ql_app.name)
3132- self.keybinding("launcher/keynav/open-quicklist")
3133+ self.ql_launcher.keyboard_select_icon(self.launcher_position, tooltip_text=self.ql_app.name)
3134+ self.keybinding(keys[self.launcher_position + "/launcher/keynav/open-quicklist"])
3135 self.addCleanup(self.keybinding, "launcher/keynav/close-quicklist")
3136
3137 self.assertThat(self.ql_launcher_icon.get_quicklist,
3138
3139=== modified file 'tests/autopilot/unity/tests/test_spread.py'
3140--- tests/autopilot/unity/tests/test_spread.py 2015-08-19 09:14:22 +0000
3141+++ tests/autopilot/unity/tests/test_spread.py 2016-03-18 01:19:20 +0000
3142@@ -150,7 +150,7 @@
3143 """Test that the screen spread desaturates the launcher icons"""
3144 self.start_test_application_windows("Calculator", 1)
3145 self.initiate_spread_for_screen()
3146- self.launcher.move_mouse_to_right_of_launcher()
3147+ self.launcher.move_mouse_beside_launcher()
3148 self.assertLauncherIconsDesaturated()
3149
3150 def test_spread_saturate_launcher_icons_on_mouse_over(self):
3151
3152=== modified file 'tests/autopilot/unity/tests/test_wm_keybindings.py'
3153--- tests/autopilot/unity/tests/test_wm_keybindings.py 2015-04-10 21:27:19 +0000
3154+++ tests/autopilot/unity/tests/test_wm_keybindings.py 2016-03-18 01:19:20 +0000
3155@@ -99,10 +99,16 @@
3156 monitor = self.bamf_win.monitor
3157 monitor_geo = self.display.get_screen_geometry(monitor)
3158 launcher = self.unity.launcher.get_launcher_for_monitor(monitor)
3159- launcher_w = 0 if launcher.hidemode else launcher.geometry[2]
3160+ # When launcher at left, do not use launcher_h, otherwise, do not use launcher_w
3161+ if launcher.geometry[2] < launcher.geometry[3]:
3162+ launcher_h = 0
3163+ launcher_w = 0 if launcher.hidemode else launcher.geometry[2]
3164+ else:
3165+ launcher_h = 0 if launcher.hidemode else launcher.geometry[3]
3166+ launcher_w = 0
3167 panel_h = self.unity.panels.get_panel_for_monitor(monitor).geometry[3]
3168 return (monitor_geo[0] + launcher_w, monitor_geo[1] + panel_h,
3169- monitor_geo[2] - launcher_w, monitor_geo[3] - panel_h)
3170+ monitor_geo[2] - launcher_w, monitor_geo[3] - panel_h - launcher_h)
3171
3172 def test_maximize_window(self):
3173 if self.start_restored:
3174
3175=== modified file 'tests/test_bfb_launcher_icon.cpp'
3176--- tests/test_bfb_launcher_icon.cpp 2014-03-21 04:40:12 +0000
3177+++ tests/test_bfb_launcher_icon.cpp 2016-03-18 01:19:20 +0000
3178@@ -31,7 +31,7 @@
3179 {
3180 public:
3181 MockBFBLauncherIcon()
3182- : BFBLauncherIcon(LauncherHideMode::LAUNCHER_HIDE_NEVER)
3183+ : BFBLauncherIcon()
3184 {}
3185 };
3186
3187
3188=== modified file 'tests/test_hud_launcher_icon.cpp'
3189--- tests/test_hud_launcher_icon.cpp 2014-03-21 04:40:12 +0000
3190+++ tests/test_hud_launcher_icon.cpp 2016-03-18 01:19:20 +0000
3191@@ -32,7 +32,7 @@
3192 {
3193 public:
3194 MockHudLauncherIcon()
3195- : HudLauncherIcon(LauncherHideMode::LAUNCHER_HIDE_NEVER)
3196+ : HudLauncherIcon()
3197 {}
3198 };
3199
3200
3201=== modified file 'tests/test_launcher.cpp'
3202--- tests/test_launcher.cpp 2015-10-14 10:34:03 +0000
3203+++ tests/test_launcher.cpp 2016-03-18 01:19:20 +0000
3204@@ -31,6 +31,7 @@
3205 #include "unity-shared/PanelStyle.h"
3206 #include "unity-shared/IconRenderer.h"
3207 #include "unity-shared/UBusMessages.h"
3208+#include "unity-shared/UnitySettings.h"
3209 #include "test_standalone_wm.h"
3210 #include "test_utils.h"
3211
3212@@ -537,11 +538,13 @@
3213
3214 TEST_F(TestLauncher, EdgeBarriersHandlesEvent)
3215 {
3216- auto const& launcher_geo = launcher_->GetAbsoluteGeometry();
3217+ glib::Object<GSettings> gsettings(g_settings_new("com.canonical.Unity.Launcher"));
3218+ auto launcher_geo = launcher_->GetAbsoluteGeometry();
3219 auto barrier = std::make_shared<ui::PointerBarrierWrapper>();
3220 auto event = std::make_shared<ui::BarrierEvent>(0, 0, 0, 100);
3221 launcher_->SetHidden(true);
3222
3223+ g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::LEFT));
3224 options_->reveal_trigger = RevealTrigger::EDGE;
3225
3226 for (int x = launcher_geo.x; x < launcher_geo.x+launcher_geo.width; ++x)
3227@@ -567,6 +570,37 @@
3228 ui::EdgeBarrierSubscriber::Result::HANDLED);
3229 }
3230 }
3231+
3232+ g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::BOTTOM));
3233+ launcher_geo = launcher_->GetAbsoluteGeometry();
3234+ options_->reveal_trigger = RevealTrigger::EDGE;
3235+ int panel_height = panel::Style::Instance().PanelHeight(launcher_->monitor());
3236+
3237+ for (int y = launcher_geo.y; y < launcher_geo.y+launcher_geo.height; ++y)
3238+ {
3239+ for (int x = launcher_geo.x + panel_height; x < launcher_geo.x+launcher_geo.width; ++x)
3240+ {
3241+ event->x = x;
3242+ event->y = y;
3243+ ASSERT_EQ(launcher_->HandleBarrierEvent(barrier, event),
3244+ ui::EdgeBarrierSubscriber::Result::HANDLED);
3245+ }
3246+ }
3247+
3248+ options_->reveal_trigger = RevealTrigger::CORNER;
3249+
3250+ for (int y = launcher_geo.y; y < launcher_geo.y+launcher_geo.height; ++y)
3251+ {
3252+ for (int x = launcher_geo.x; x < launcher_geo.x + panel_height; ++x)
3253+ {
3254+ event->x = x;
3255+ event->y = y;
3256+ ASSERT_EQ(launcher_->HandleBarrierEvent(barrier, event),
3257+ ui::EdgeBarrierSubscriber::Result::HANDLED);
3258+ }
3259+ }
3260+
3261+ g_settings_reset(gsettings, "launcher-position");
3262 }
3263
3264 TEST_F(TestLauncher, DndIsSpecialRequest)
3265
3266=== modified file 'tests/test_launcher_controller.cpp'
3267--- tests/test_launcher_controller.cpp 2016-03-08 01:05:08 +0000
3268+++ tests/test_launcher_controller.cpp 2016-03-18 01:19:20 +0000
3269@@ -42,6 +42,7 @@
3270 #include "mock-application.h"
3271 #include "BamfApplicationManager.h"
3272 #include "bamf-mock-application.h"
3273+#include "unity-shared/UnitySettings.h"
3274
3275 using namespace testmocks;
3276 using namespace unity::launcher;
3277@@ -490,6 +491,25 @@
3278 ASSERT_EQ(launcher_geo.height, monitor_geo.height - panel_style.PanelHeight());
3279 }
3280
3281+TEST_F(TestLauncherController, LauncherPositionResetsOnGsettingsUpdated)
3282+{
3283+ glib::Object<GSettings> gsettings(g_settings_new("com.canonical.Unity.Launcher"));
3284+ g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::LEFT));
3285+ nux::Geometry const& monitor_geo = uscreen.GetMonitorGeometry(0);
3286+ nux::Geometry launcher_geo = lc.launcher().GetAbsoluteGeometry();
3287+ ASSERT_EQ(launcher_geo.x, monitor_geo.x);
3288+ ASSERT_EQ(launcher_geo.y, monitor_geo.y + panel_style.PanelHeight(0));
3289+ ASSERT_EQ(launcher_geo.height, monitor_geo.height - panel_style.PanelHeight(0));
3290+
3291+ g_settings_set_enum(gsettings, "launcher-position", static_cast<int>(LauncherPosition::BOTTOM));
3292+ launcher_geo = lc.launcher().GetAbsoluteGeometry();
3293+ ASSERT_EQ(launcher_geo.x, monitor_geo.x);
3294+ ASSERT_EQ(launcher_geo.y, monitor_geo.y + monitor_geo.height - launcher_geo.height + 1);
3295+ ASSERT_EQ(launcher_geo.width, monitor_geo.width);
3296+
3297+ g_settings_reset(gsettings, "launcher-position");
3298+}
3299+
3300 TEST_F(TestLauncherController, IconCentersResetsOnMonitorsUpdated)
3301 {
3302 uscreen.SetupFakeMultiMonitor();
3303
3304=== modified file 'unity-shared/IconRenderer.cpp'
3305--- unity-shared/IconRenderer.cpp 2016-02-09 18:16:51 +0000
3306+++ unity-shared/IconRenderer.cpp 2016-03-18 01:19:20 +0000
3307@@ -285,8 +285,12 @@
3308 {&icon_shine, "launcher_icon_shine_"+tile_sufix, icon_size},
3309 {&arrow_ltr, "launcher_arrow_ltr_"+marker_sufix, marker_size},
3310 {&arrow_rtl, "launcher_arrow_rtl_"+marker_sufix, marker_size},
3311+ {&arrow_btt, "launcher_arrow_btt_"+marker_sufix, marker_size},
3312+ {&arrow_ttb, "launcher_arrow_ttb_"+marker_sufix, marker_size},
3313 {&arrow_empty_ltr, "launcher_arrow_outline_ltr_"+marker_sufix, marker_size},
3314+ {&arrow_empty_btt, "launcher_arrow_outline_btt_"+marker_sufix, marker_size},
3315 {&pip_ltr, "launcher_pip_ltr_"+marker_sufix, marker_size},
3316+ {&pip_btt, "launcher_pip_btt_"+marker_sufix, marker_size},
3317 {&progress_bar_trough, "progress_bar_trough", icon_size},
3318 {&progress_bar_fill, "progress_bar_fill", image_size - (icon_size - image_size)},
3319 };
3320@@ -327,8 +331,12 @@
3321 BaseTexturePtr icon_shine;
3322 BaseTexturePtr arrow_ltr;
3323 BaseTexturePtr arrow_rtl;
3324+ BaseTexturePtr arrow_btt;
3325+ BaseTexturePtr arrow_ttb;
3326 BaseTexturePtr arrow_empty_ltr;
3327+ BaseTexturePtr arrow_empty_btt;
3328 BaseTexturePtr pip_ltr;
3329+ BaseTexturePtr pip_btt;
3330 BaseTexturePtr progress_bar_trough;
3331 BaseTexturePtr progress_bar_fill;
3332
3333@@ -439,10 +447,20 @@
3334
3335 UpdateIconTransform(launcher_icon, ViewProjectionMatrix, geo, x, y, w, h, z, ui::IconTextureSource::TRANSFORM_GLOW);
3336
3337- w = geo.width + 2;
3338- h = icon_size + spacing;
3339- if (i == (int) args.size() - 1)
3340- h += 4;
3341+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
3342+ {
3343+ w = geo.width + 2;
3344+ h = icon_size + spacing;
3345+ if (i == (int) args.size() - 1)
3346+ h += 4;
3347+ }
3348+ else
3349+ {
3350+ h = geo.height + 2;
3351+ w = icon_size + spacing;
3352+ if (i == (int) args.size() - 1)
3353+ w += 4;
3354+ }
3355 x = it->logical_center.x - w / 2.0f;
3356 y = it->logical_center.y - h / 2.0f;
3357 z = it->logical_center.z;
3358@@ -1023,23 +1041,38 @@
3359 float alpha,
3360 nux::Geometry const& geo)
3361 {
3362- int markerCenter = (int) arg.render_center.y;
3363- markerCenter -= (int)(arg.rotation.x / (2 * M_PI) * icon_size);
3364+ int markerCenter = 0;
3365+ bool switcher_mode = (pip_style != OUTSIDE_TILE);
3366+ bool left_markers = (switcher_mode || Settings::Instance().launcher_position() == LauncherPosition::LEFT);
3367+
3368+ if (left_markers)
3369+ {
3370+ markerCenter = (int) arg.render_center.y;
3371+ markerCenter -= (int)(arg.rotation.x / (2 * M_PI) * icon_size);
3372+ }
3373+ else
3374+ {
3375+ markerCenter = (int) arg.render_center.x;
3376+
3377+ if (pip_style == OUTSIDE_TILE)
3378+ markerCenter += (int)(arg.rotation.y / (2 * M_PI) * icon_size);
3379+ }
3380
3381 if (running > 0)
3382 {
3383- int markerX;
3384-
3385- if (pip_style == OUTSIDE_TILE)
3386- {
3387- markerX = geo.x;
3388- }
3389- else
3390- {
3391- auto const& bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor);
3392- markerX = bounds[0].x + 1;
3393- }
3394-
3395+ int markerX = 0;
3396+ if (left_markers)
3397+ {
3398+ if (pip_style == OUTSIDE_TILE)
3399+ {
3400+ markerX = geo.x;
3401+ }
3402+ else
3403+ {
3404+ auto const& bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor);
3405+ markerX = bounds[0].x + 1;
3406+ }
3407+ }
3408 nux::TexCoordXForm texxform;
3409 nux::Color color = nux::color::LightGrey;
3410
3411@@ -1059,41 +1092,87 @@
3412 if (!arg.running_on_viewport)
3413 {
3414 markers[0] = markerCenter;
3415- texture = local_textures_->arrow_empty_ltr;
3416+ if (left_markers)
3417+ texture = local_textures_->arrow_empty_ltr;
3418+ else
3419+ texture = local_textures_->arrow_empty_btt;
3420 }
3421 else if (running == 1)
3422 {
3423 markers[0] = markerCenter;
3424- texture = local_textures_->arrow_ltr;
3425+ if (left_markers)
3426+ texture = local_textures_->arrow_ltr;
3427+ else
3428+ texture = local_textures_->arrow_btt;
3429 }
3430 else if (running == 2)
3431 {
3432- texture = local_textures_->pip_ltr;
3433+ int texture_size = 0;
3434+ if (left_markers)
3435+ {
3436+ texture = local_textures_->pip_ltr;
3437+ texture_size = texture->GetHeight();
3438+ }
3439+ else
3440+ {
3441+ texture = local_textures_->pip_btt;
3442+ texture_size = texture->GetWidth();
3443+ }
3444
3445- double default_tex_height = local::MARKER_SIZES[local::IconSize::SMALL];
3446- int offset = std::max(1.0, std::round(2.0 * texture->GetHeight() / default_tex_height));
3447+ double default_tex_size = local::MARKER_SIZES[local::IconSize::SMALL];
3448+ int offset = std::max(1.0, std::round(2.0 * texture_size / default_tex_size));
3449 markers[0] = markerCenter - offset;
3450 markers[1] = markerCenter + offset;
3451 }
3452 else
3453 {
3454- texture = local_textures_->pip_ltr;
3455+ int texture_size = 0;
3456+ if (left_markers)
3457+ {
3458+ texture = local_textures_->pip_ltr;
3459+ texture_size = texture->GetHeight();
3460+ }
3461+ else
3462+ {
3463+ texture = local_textures_->pip_btt;
3464+ texture_size = texture->GetWidth();
3465+ }
3466
3467- double default_tex_height = local::MARKER_SIZES[local::IconSize::SMALL];
3468- int offset = std::max(1.0, std::round(4.0 * texture->GetHeight() / default_tex_height));
3469+ double default_tex_size = local::MARKER_SIZES[local::IconSize::SMALL];
3470+ int offset = std::max(1.0, std::round(4.0 * texture_size / default_tex_size));
3471 markers[0] = markerCenter - offset;
3472 markers[1] = markerCenter;
3473 markers[2] = markerCenter + offset;
3474 }
3475
3476+ int markerY = 0;
3477+ if (!left_markers)
3478+ {
3479+ if (pip_style == OUTSIDE_TILE)
3480+ {
3481+ markerY = (geo.y + geo.height) - texture->GetHeight();
3482+ }
3483+ else
3484+ {
3485+ auto const& bounds = arg.icon->GetTransform(ui::IconTextureSource::TRANSFORM_TILE, monitor);
3486+
3487+ markerY = (bounds[2].y - (texture->GetHeight()*scale));
3488+ }
3489+ }
3490+
3491 for (int i = 0; i < 3; i++)
3492 {
3493 int center = markers[i];
3494 if (center == -100)
3495 break;
3496
3497+ if (left_markers)
3498+ markerY = center - std::round(texture->GetHeight() / 2.0f);
3499+ else
3500+ markerX = center - std::round(texture->GetWidth() / 2.0f);
3501+
3502 GfxContext.QRP_1Tex(markerX,
3503- center - std::round(texture->GetHeight() / 2.0f),
3504+ markerY,
3505 texture->GetWidth(),
3506 texture->GetHeight(),
3507 texture->GetDeviceTexture(),
3508@@ -1106,15 +1185,29 @@
3509 {
3510 nux::TexCoordXForm texxform;
3511
3512- auto const& arrow_rtl = local_textures_->arrow_rtl;
3513 nux::Color color = nux::color::LightGrey * alpha;
3514- GfxContext.QRP_1Tex((geo.x + geo.width) - arrow_rtl->GetWidth(),
3515- markerCenter - std::round(arrow_rtl->GetHeight() / 2.0f),
3516- arrow_rtl->GetWidth(),
3517- arrow_rtl->GetHeight(),
3518- arrow_rtl->GetDeviceTexture(),
3519- texxform,
3520- color);
3521+ if (left_markers)
3522+ {
3523+ auto const& arrow_rtl = local_textures_->arrow_rtl;
3524+ GfxContext.QRP_1Tex((geo.x + geo.width) - arrow_rtl->GetWidth(),
3525+ markerCenter - std::round(arrow_rtl->GetHeight() / 2.0f),
3526+ arrow_rtl->GetWidth(),
3527+ arrow_rtl->GetHeight(),
3528+ arrow_rtl->GetDeviceTexture(),
3529+ texxform,
3530+ color);
3531+ }
3532+ else
3533+ {
3534+ auto const& arrow_ttb = local_textures_->arrow_ttb;
3535+ GfxContext.QRP_1Tex(markerCenter - std::round(arrow_ttb->GetWidth() / 2.0f),
3536+ geo.y,
3537+ arrow_ttb->GetWidth(),
3538+ arrow_ttb->GetHeight(),
3539+ arrow_ttb->GetDeviceTexture(),
3540+ texxform,
3541+ color);
3542+ }
3543 }
3544 }
3545
3546@@ -1267,8 +1360,12 @@
3547 float y_cs = -CameraToScreenDistance * tanf(0.5f * Fovy/* *M_PI/180.0f*/);
3548 float x_cs = y_cs * AspectRatio;
3549
3550- ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) *
3551- nux::Matrix4::SCALE(2.0f * x_cs / ViewportWidth, -2.0f * y_cs / ViewportHeight, -2.0f * 3 * y_cs / ViewportHeight /* or -2.0f * x_cs/ViewportWidth*/);
3552+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
3553+ ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) *
3554+ nux::Matrix4::SCALE(2.0f * x_cs / ViewportWidth, -2.0f * y_cs / ViewportHeight, -2.0f * 3 * y_cs / ViewportHeight /* or -2.0f * x_cs/ViewportWidth*/);
3555+ else
3556+ ViewMatrix = nux::Matrix4::TRANSLATE(-x_cs, y_cs, CameraToScreenDistance) *
3557+ nux::Matrix4::SCALE(2.0f * x_cs / ViewportWidth, -2.0f * y_cs / ViewportHeight, -2.0f * x_cs / ViewportWidth);
3558
3559 PerspectiveMatrix.Perspective(Fovy, AspectRatio, NearClipPlane, FarClipPlane);
3560 }
3561
3562=== modified file 'unity-shared/SpreadFilter.cpp'
3563--- unity-shared/SpreadFilter.cpp 2015-11-18 15:43:33 +0000
3564+++ unity-shared/SpreadFilter.cpp 2016-03-18 01:19:20 +0000
3565@@ -55,7 +55,7 @@
3566 auto& settings = Settings::Instance();
3567 auto const& work_area = wm.GetWorkAreaGeometry(0);
3568 int monitor = wm.MonitorGeometryIn(work_area);
3569- int launcher_width = settings.LauncherWidth(monitor);
3570+ int launcher_width = settings.LauncherSize(monitor);
3571 auto const& cv = settings.em(monitor);
3572
3573 search_bar_ = SearchBar::Ptr(new SearchBar());
3574@@ -81,7 +81,10 @@
3575 view_window_->SetOpacity(0.0f);
3576 view_window_->SetEnterFocusInputArea(search_bar_.GetPointer());
3577 view_window_->SetInputFocus();
3578- view_window_->SetXY(OFFSET_X.CP(cv) + std::max(work_area.x, launcher_width), OFFSET_Y.CP(cv) + work_area.y);
3579+ if (Settings::Instance().launcher_position() == LauncherPosition::LEFT)
3580+ view_window_->SetXY(OFFSET_X.CP(cv) + std::max(work_area.x, launcher_width), OFFSET_Y.CP(cv) + work_area.y);
3581+ else
3582+ view_window_->SetXY(OFFSET_X.CP(cv) + work_area.x, OFFSET_Y.CP(cv) + work_area.y);
3583 fade_animator_.updated.connect([this] (double opacity) { view_window_->SetOpacity(opacity); });
3584
3585 nux::GetWindowCompositor().SetKeyFocusArea(search_bar_->text_entry());
3586
3587=== modified file 'unity-shared/UnitySettings.cpp'
3588--- unity-shared/UnitySettings.cpp 2015-12-03 05:57:00 +0000
3589+++ unity-shared/UnitySettings.cpp 2016-03-18 01:19:20 +0000
3590@@ -40,6 +40,9 @@
3591 const std::string DOUBLE_CLICK_ACTIVATE = "double-click-activate";
3592 const std::string DESKTOP_TYPE = "desktop-type";
3593
3594+const std::string LAUNCHER_SETTINGS = "com.canonical.Unity.Launcher";
3595+const std::string LAUNCHER_POSITION = "launcher-position";
3596+
3597 const std::string LIM_SETTINGS = "com.canonical.Unity.IntegratedMenus";
3598 const std::string CLICK_MOVEMENT_THRESHOLD = "click-movement-threshold";
3599 const std::string DOUBLE_CLICK_WAIT = "double-click-wait";
3600@@ -63,7 +66,7 @@
3601 const std::string REMOTE_CONTENT_SETTINGS = "com.canonical.Unity.Lenses";
3602 const std::string REMOTE_CONTENT_KEY = "remote-content-search";
3603
3604-const int DEFAULT_LAUNCHER_WIDTH = 64;
3605+const int DEFAULT_LAUNCHER_SIZE = 64;
3606 const int MINIMUM_DESKTOP_HEIGHT = 800;
3607 const int GNOME_SETTINGS_CHANGED_WAIT_SECONDS = 1;
3608 const double DEFAULT_DPI = 96.0f;
3609@@ -78,12 +81,14 @@
3610 Impl(Settings* owner)
3611 : parent_(owner)
3612 , usettings_(g_settings_new(SETTINGS_NAME.c_str()))
3613+ , launcher_settings_(g_settings_new(LAUNCHER_SETTINGS.c_str()))
3614 , lim_settings_(g_settings_new(LIM_SETTINGS.c_str()))
3615 , ui_settings_(g_settings_new(UI_SETTINGS.c_str()))
3616 , ubuntu_ui_settings_(g_settings_new(UBUNTU_UI_SETTINGS.c_str()))
3617 , gnome_ui_settings_(g_settings_new(GNOME_UI_SETTINGS.c_str()))
3618 , remote_content_settings_(g_settings_new(REMOTE_CONTENT_SETTINGS.c_str()))
3619- , launcher_widths_(monitors::MAX, DEFAULT_LAUNCHER_WIDTH)
3620+ , launcher_sizes_(monitors::MAX, DEFAULT_LAUNCHER_SIZE)
3621+ , cached_launcher_position_(LauncherPosition::LEFT)
3622 , cached_form_factor_(FormFactor::DESKTOP)
3623 , cursor_scale_(1.0)
3624 , cached_double_click_activate_(true)
3625@@ -95,6 +100,8 @@
3626 parent_->form_factor.SetSetterFunction(sigc::mem_fun(this, &Impl::SetFormFactor));
3627 parent_->double_click_activate.SetGetterFunction(sigc::mem_fun(this, &Impl::GetDoubleClickActivate));
3628 parent_->remote_content.SetGetterFunction(sigc::mem_fun(this, &Impl::GetRemoteContentEnabled));
3629+ parent_->launcher_position.SetGetterFunction(sigc::mem_fun(this, &Impl::GetLauncherPosition));
3630+ parent_->launcher_position.SetSetterFunction(sigc::mem_fun(this, &Impl::SetLauncherPosition));
3631 parent_->desktop_type.SetGetterFunction(sigc::mem_fun(this, &Impl::GetDesktopType));
3632
3633 for (unsigned i = 0; i < monitors::MAX; ++i)
3634@@ -109,6 +116,11 @@
3635 parent_->double_click_activate.changed.emit(cached_double_click_activate_);
3636 });
3637
3638+ signals_.Add<void, GSettings*, const gchar*>(launcher_settings_, "changed::" + LAUNCHER_POSITION, [this] (GSettings*, const gchar*) {
3639+ CacheLauncherPosition();
3640+ parent_->launcher_position.changed.emit(cached_launcher_position_);
3641+ });
3642+
3643 signals_.Add<void, GSettings*, const gchar*>(ubuntu_ui_settings_, "changed::" + SCALE_FACTOR, [this] (GSettings*, const gchar* t) {
3644 UpdateDPI();
3645 });
3646@@ -164,6 +176,7 @@
3647 CacheFormFactor();
3648 CacheDoubleClickActivate();
3649 UpdateRemoteContentSearch();
3650+ CacheLauncherPosition();
3651 }
3652
3653 void CacheFormFactor()
3654@@ -197,6 +210,11 @@
3655 cached_double_click_activate_ = g_settings_get_boolean(usettings_, DOUBLE_CLICK_ACTIVATE.c_str());
3656 }
3657
3658+ void CacheLauncherPosition()
3659+ {
3660+ cached_launcher_position_ = static_cast<LauncherPosition>(g_settings_get_enum(launcher_settings_, LAUNCHER_POSITION.c_str()));
3661+ }
3662+
3663 void UpdateLimSetting()
3664 {
3665 parent_->lim_movement_thresold = g_settings_get_uint(lim_settings_, CLICK_MOVEMENT_THRESHOLD.c_str());
3666@@ -220,6 +238,17 @@
3667 return cached_double_click_activate_;
3668 }
3669
3670+ LauncherPosition GetLauncherPosition() const
3671+ {
3672+ return cached_launcher_position_;
3673+ }
3674+
3675+ bool SetLauncherPosition(LauncherPosition launcherPosition)
3676+ {
3677+ g_settings_set_enum(launcher_settings_, LAUNCHER_POSITION.c_str(), static_cast<int>(launcherPosition));
3678+ return false;
3679+ }
3680+
3681 DesktopType GetDesktopType() const
3682 {
3683 return static_cast<DesktopType>(g_settings_get_enum(usettings_, DESKTOP_TYPE.c_str()));
3684@@ -353,6 +382,7 @@
3685
3686 Settings* parent_;
3687 glib::Object<GSettings> usettings_;
3688+ glib::Object<GSettings> launcher_settings_;
3689 glib::Object<GSettings> lim_settings_;
3690 glib::Object<GSettings> ui_settings_;
3691 glib::Object<GSettings> ubuntu_ui_settings_;
3692@@ -361,7 +391,8 @@
3693 glib::Source::UniquePtr changing_gnome_settings_timeout_;
3694 glib::SignalManager signals_;
3695 std::vector<EMConverter::Ptr> em_converters_;
3696- std::vector<int> launcher_widths_;
3697+ std::vector<int> launcher_sizes_;
3698+ LauncherPosition cached_launcher_position_;
3699 FormFactor cached_form_factor_;
3700 double cursor_scale_;
3701 bool cached_double_click_activate_;
3702@@ -423,19 +454,19 @@
3703 return pimpl->em(monitor);
3704 }
3705
3706-void Settings::SetLauncherWidth(int launcher_width, int monitor)
3707+void Settings::SetLauncherSize(int launcher_size, int monitor)
3708 {
3709 if (monitor < 0 || monitor >= (int)monitors::MAX)
3710 {
3711- LOG_ERROR(logger) << "Invalid monitor index: " << monitor << ". Not updating laucher width.";
3712+ LOG_ERROR(logger) << "Invalid monitor index: " << monitor << ". Not updating launcher size.";
3713 }
3714 else
3715 {
3716- pimpl->launcher_widths_[monitor] = launcher_width;
3717+ pimpl->launcher_sizes_[monitor] = launcher_size;
3718 }
3719 }
3720
3721-int Settings::LauncherWidth(int monitor) const
3722+int Settings::LauncherSize(int monitor) const
3723 {
3724 if (monitor < 0 || monitor >= (int)monitors::MAX)
3725 {
3726@@ -443,7 +474,7 @@
3727 return 0;
3728 }
3729
3730- return pimpl->launcher_widths_[monitor];
3731+ return pimpl->launcher_sizes_[monitor];
3732 }
3733
3734 } // namespace unity
3735
3736=== modified file 'unity-shared/UnitySettings.h'
3737--- unity-shared/UnitySettings.h 2015-11-23 09:24:10 +0000
3738+++ unity-shared/UnitySettings.h 2016-03-18 01:19:20 +0000
3739@@ -35,10 +35,16 @@
3740 TV
3741 };
3742
3743+enum class LauncherPosition
3744+{
3745+ LEFT = 0,
3746+ BOTTOM
3747+};
3748+
3749 enum class DesktopType
3750 {
3751- UBUNTU,
3752- UBUNTUKYLIN
3753+ UBUNTU,
3754+ UBUNTUKYLIN
3755 };
3756
3757 class Settings
3758@@ -52,8 +58,8 @@
3759 void SetLowGfxMode(const bool low_gfx);
3760 EMConverter::Ptr const& em(int monitor = 0) const;
3761
3762- void SetLauncherWidth(int launcher_width, int monitor);
3763- int LauncherWidth(int monitor) const;
3764+ void SetLauncherSize(int launcher_size, int monitor);
3765+ int LauncherSize(int mointor) const;
3766
3767 nux::RWProperty<FormFactor> form_factor;
3768 nux::Property<bool> is_standalone;
3769@@ -64,6 +70,7 @@
3770 nux::Property<bool> lim_unfocused_popup;
3771 nux::Property<double> font_scaling;
3772 nux::ROProperty<bool> remote_content;
3773+ nux::RWProperty<LauncherPosition> launcher_position;
3774
3775 sigc::signal<void> dpi_changed;
3776 sigc::signal<void> low_gfx_changed;