~haggai-eran/unity/rtl-menu-popup

« back to all changes in this revision

Viewing changes to plugins/unityshell/src/LayoutSystem.cpp

merge layout system branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
 
2
/*
 
3
 * Copyright (C) 2011 Canonical Ltd
 
4
 *
 
5
 * This program is free software: you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License version 3 as
 
7
 * published by the Free Software Foundation.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 *
 
17
 * Authored by: Jason Smith <jason.smith@canonical.com>
 
18
 */
 
19
 
 
20
#include "LayoutSystem.h"
 
21
#include "WindowManager.h"
 
22
 
 
23
namespace unity {
 
24
namespace ui {
 
25
        
 
26
LayoutSystem::LayoutSystem()
 
27
{
 
28
}
 
29
 
 
30
LayoutSystem::~LayoutSystem()
 
31
{
 
32
}
 
33
 
 
34
void LayoutSystem::LayoutWindows (LayoutWindowList windows, nux::Geometry const& max_bounds, nux::Geometry& final_bounds)
 
35
{
 
36
  unsigned int size = windows.size();
 
37
 
 
38
  if (size == 0)
 
39
    return;
 
40
  
 
41
  for (auto window : windows)
 
42
  {
 
43
        window->geo = WindowManager::Default ()->GetWindowGeometry (window->xid);
 
44
    window->aspect_ratio = (float)window->geo.width / (float)window->geo.height;
 
45
  }
 
46
  
 
47
  // we special case 2 and 3 since they are the most common 
 
48
  // cases (other than 1) and can be made beautiful with relative ease
 
49
  switch (size)  
 
50
  {
 
51
    case 2:
 
52
      LayoutTwoWindows (windows, max_bounds, final_bounds);
 
53
      break;
 
54
    default:
 
55
      LayoutGridWindows (windows, max_bounds, final_bounds);
 
56
      break;
 
57
  }
 
58
}
 
59
 
 
60
void LayoutSystem::LayoutTwoWindows (LayoutWindowList windows, nux::Geometry const& max_bounds, nux::Geometry& final_bounds)
 
61
{
 
62
  LayoutWindow::Ptr first = windows[0];
 
63
  LayoutWindow::Ptr second = windows[1];
 
64
 
 
65
  float combined_aspect = first->aspect_ratio + second->aspect_ratio;
 
66
 
 
67
  final_bounds = max_bounds;
 
68
 
 
69
  if (combined_aspect >= 1.0f)
 
70
  {
 
71
    // aspect is too wide
 
72
    final_bounds.y += (final_bounds.height - (final_bounds.height / combined_aspect)) / 2;
 
73
    final_bounds.height = final_bounds.height / combined_aspect;
 
74
 
 
75
    first->result.x = final_bounds.x;
 
76
    first->result.y = final_bounds.y;
 
77
    first->result.height = final_bounds.height;
 
78
    first->result.width = first->result.height * first->aspect_ratio;
 
79
 
 
80
    second->result.x = final_bounds.x + first->result.width;
 
81
    second->result.y = final_bounds.y;
 
82
    second->result.height = final_bounds.height;
 
83
    second->result.width = second->result.height * second->aspect_ratio;
 
84
  }
 
85
  else if (combined_aspect < 1.0f)
 
86
  {
 
87
    // aspect is too tall
 
88
    final_bounds.x += (final_bounds.width - (final_bounds.width / combined_aspect)) / 2;
 
89
    final_bounds.width = final_bounds.width / combined_aspect;
 
90
 
 
91
    // same as above?
 
92
    first->result.x = final_bounds.x;
 
93
    first->result.y = final_bounds.y;
 
94
    first->result.height = final_bounds.height;
 
95
    first->result.width = first->result.height * first->aspect_ratio;
 
96
 
 
97
    second->result.x = final_bounds.x + first->result.width;
 
98
    second->result.y = final_bounds.y;
 
99
    second->result.height = final_bounds.height;
 
100
    second->result.width = second->result.height * second->aspect_ratio;
 
101
  }
 
102
}
 
103
 
 
104
void LayoutSystem::LayoutGridWindows (LayoutWindowList windows, nux::Geometry const& max_bounds, nux::Geometry& final_bounds)
 
105
{
 
106
  int width = 1;
 
107
  int height = 1;
 
108
 
 
109
  while (width * height < (int) windows.size ())
 
110
  {
 
111
    if (height < width)
 
112
      height++;
 
113
    else
 
114
      width++;
 
115
  }
 
116
 
 
117
  final_bounds = max_bounds;
 
118
 
 
119
  int block_width = final_bounds.width / width;
 
120
  int block_height = final_bounds.height / height;
 
121
 
 
122
  int x = 0;
 
123
  int y = 0;
 
124
 
 
125
  int start_x = final_bounds.x + final_bounds.width;
 
126
  int start_y = final_bounds.y + final_bounds.height;
 
127
 
 
128
  int x1 = G_MAXINT;
 
129
  int y1 = G_MAXINT;
 
130
  int x2 = 0;
 
131
  int y2 = 0;
 
132
 
 
133
  int block_x = start_x;
 
134
  int block_y = start_y;
 
135
  int vertical_offset = 0;
 
136
 
 
137
  LayoutWindowList row_accum;
 
138
 
 
139
  LayoutWindowList::reverse_iterator it;
 
140
  for (it = windows.rbegin (); it != windows.rend (); it++)
 
141
  {
 
142
        auto window = *it;
 
143
    window->result = ScaleBoxIntoBox (nux::Geometry (block_x - block_width, block_y - block_height, block_width, block_height), window->geo);
 
144
    row_accum.push_back (window);
 
145
 
 
146
    x1 = MIN (window->result.x, x1);
 
147
    y1 = MIN (window->result.y, y1);
 
148
    x2 = MAX (window->result.x + window->result.width, x2);
 
149
    y2 = MAX (window->result.y + window->result.height, y2);
 
150
 
 
151
    ++x;
 
152
    block_x -= block_width;
 
153
    if (x >= width || x + y * width == (int) windows.size ())
 
154
    {
 
155
      x = 0;
 
156
            block_x = start_x;
 
157
      ++y;
 
158
 
 
159
      if (y == height - 1)
 
160
      {
 
161
        block_width += (width * height - windows.size ()) * block_width / (windows.size () - width * (height - 1)); 
 
162
      } 
 
163
                
 
164
 
 
165
      if (y2 >= block_y + block_height)
 
166
      {
 
167
        block_y -= block_height;
 
168
      }
 
169
      else
 
170
      {
 
171
        int this_savings = (y1 - (block_y - block_height)) * 2;
 
172
        block_y = block_y - (block_height - this_savings);
 
173
 
 
174
        for (auto w : row_accum)
 
175
                w->result.y += this_savings / 2;
 
176
        
 
177
        vertical_offset += this_savings / 2;
 
178
      }
 
179
 
 
180
      row_accum.clear ();
 
181
    }
 
182
  }
 
183
 
 
184
  x1 = G_MAXINT;
 
185
  y1 = G_MAXINT;
 
186
  x2 = 0;
 
187
  y2 = 0;
 
188
 
 
189
  for (auto window : windows)
 
190
  {
 
191
        window->result.y -= vertical_offset;
 
192
 
 
193
        x1 = MIN (window->result.x, x1);
 
194
    y1 = MIN (window->result.y, y1);
 
195
    x2 = MAX (window->result.x + window->result.width, x2);
 
196
    y2 = MAX (window->result.y + window->result.height, y2);
 
197
  }
 
198
 
 
199
  final_bounds = nux::Geometry (x1, y1, x2 - x1, y2 - y1);
 
200
}
 
201
 
 
202
nux::Geometry LayoutSystem::ScaleBoxIntoBox (nux::Geometry const& bounds, nux::Geometry const& box)
 
203
{
 
204
        float bound_aspect = (float) bounds.width / (float) bounds.height;
 
205
        float box_aspect = (float) box.width / (float) box.height;
 
206
 
 
207
        nux::Geometry result;
 
208
 
 
209
        if (box_aspect > bound_aspect)
 
210
        {
 
211
                // box wider than bounds
 
212
                result.x = bounds.x;
 
213
 
 
214
                result.width = bounds.width;
 
215
                result.height = result.width / box_aspect;
 
216
 
 
217
                result.y = bounds.y + (bounds.height - result.height) / 2;
 
218
        }
 
219
        else
 
220
        {
 
221
                result.y = bounds.y;
 
222
 
 
223
                result.height = bounds.height;
 
224
                result.width = result.height * box_aspect;
 
225
 
 
226
                result.x = bounds.x + (bounds.width - result.width) / 2;
 
227
        }
 
228
 
 
229
        return result;
 
230
}
 
231
 
 
232
LayoutWindow::LayoutWindow(Window xid)
 
233
 : xid (xid)
 
234
{
 
235
 
 
236
}
 
237
 
 
238
}
 
239
}
 
 
b'\\ No newline at end of file'