Merge lp:~haggai-eran/nux/rtl-rebased into lp:nux/2.0
- rtl-rebased
- Merge into 2.0
Status: | Superseded |
---|---|
Proposed branch: | lp:~haggai-eran/nux/rtl-rebased |
Merge into: | lp:nux/2.0 |
Diff against target: |
678 lines (+207/-97) 7 files modified
Nux/Area.cpp (+11/-0) Nux/Area.h (+16/-0) Nux/HLayout.cpp (+146/-97) Nux/Layout.cpp (+16/-0) Nux/Layout.h (+3/-0) Nux/Nux.cpp (+12/-0) Nux/Nux.h (+3/-0) |
To merge this branch: | bzr merge lp:~haggai-eran/nux/rtl-rebased |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jay Taoko | Pending | ||
Review via email: mp+82225@code.launchpad.net |
This proposal has been superseded by a proposal from 2012-04-27.
Commit message
Add right-to-left mirroring support. Implement mirroring for HLayout.
Description of the change
Hi,
Here's my branch rebased against trunk. I hope the changes are more clear now.
There's still a problem with this patch to HLayout, though. When in right-to-left state, it packs child elements to the layout starting from the last on the list, instead of starting from the first, in order to get them in reverse order. However, it seems that for some of the widgets this doesn't work very well. I checked the CheckBox example, and the AbstractChecked
Should I change my patch to pack the children in their logical order, starting from the rightmost edge, or should I leave the code as it is, and try to fix uses like the AbstractChecked
Regards,
Haggai
Jay Taoko (jaytaoko) wrote : | # |
Haggai Eran (haggai-eran) wrote : | # |
Jay,
I agree that we should be able to set directionality on per-layout basis. I even implemented it as a member of Area. However, I think that the default when using an RTL locale should be right to left, for all widgets, and not just specific HLayouts.
In the example you described, you could show the detailed widgets like this (in LTR):
[ combobox ↓ | button | [x] checkbox ]
Then, I expect the RTL rendering to be like this:
[ checkbox [x] | button | ↓ combobox ]
The internal layout of comboboxes and checkboxes should also be mirrored.
Please compare how GTK looks in LTR and RTL in the following two screenshots of the widget factory:
http://
http://
Haggai
Jay Taoko (jaytaoko) wrote : | # |
Ok, I see how it is. I think many widget will have to have support for a RTL design.
But first we can get this branch in since it has global support for RTL at the layout level. Then the next step would be to go to each individual widgets that requires it and review the design.
It is up to me now to review and adapt this branch and see that we can merge it. We now have the requirement of proposing tests along side major features. Can you think of some way we can test the features of this branch?
Haggai Eran (haggai-eran) wrote : | # |
Hi,
I think that perhaps rewriting the code to pack in the same order as in LTR might still have some advantages. I've tried to think on how that would work. Instead of walking the list of HLayout children in reverse, and packing them to the left, I'll walk the list in the usual order, and pack from right to left.
As far as I can see, I would only need to change HLayout:
Regarding tests, I suppose that a tests for HLayout can be modified to test the RTL case as well, but I cannot find such a test (perhaps my tree isn't updated). I imagine a test that creates an HLayout, with several children that are using different settings for scaling, vertical placement, etc. and asserting there placement. What do you think?
Unmerged revisions
- 521. By Haggai Eran
-
Change LayoutContentDi
stribution only when in RTL mode. - 520. By Haggai Eran
-
More HLayout changes toward right-to-left support.
- 519. By Haggai Eran
-
Add right-to-left mirroring support. Implement mirroring for HLayout.
Preview Diff
1 | === modified file 'Nux/Area.cpp' |
2 | --- Nux/Area.cpp 2011-10-18 21:10:05 +0000 |
3 | +++ Nux/Area.cpp 2011-11-14 21:17:09 +0000 |
4 | @@ -39,6 +39,7 @@ |
5 | , geometry_(0, 0, DEFAULT_WIDGET_WIDTH, DEFAULT_WIDGET_HEIGHT) |
6 | , min_size_(AREA_MIN_WIDTH, AREA_MIN_HEIGHT) |
7 | , max_size_(AREA_MAX_WIDTH, AREA_MAX_HEIGHT) |
8 | + , _direction (GetDefaultDirection()) |
9 | { |
10 | visible_ = true; |
11 | view_enabled_ = true; |
12 | @@ -1026,5 +1027,15 @@ |
13 | |
14 | return false; |
15 | } |
16 | + |
17 | + Direction Area::GetDirection() const |
18 | + { |
19 | + return _direction; |
20 | + } |
21 | + |
22 | + void Area::SetDirection(Direction direction) |
23 | + { |
24 | + _direction = direction; |
25 | + } |
26 | } |
27 | |
28 | |
29 | === modified file 'Nux/Area.h' |
30 | --- Nux/Area.h 2011-10-17 21:23:50 +0000 |
31 | +++ Nux/Area.h 2011-11-14 21:17:09 +0000 |
32 | @@ -140,6 +140,12 @@ |
33 | KEY_NAV_ENTER, |
34 | }; |
35 | |
36 | + typedef enum |
37 | + { |
38 | + LeftToRight, |
39 | + RightToLeft |
40 | + } Direction; |
41 | + |
42 | class Layout; |
43 | class View; |
44 | class Area; |
45 | @@ -547,6 +553,14 @@ |
46 | */ |
47 | bool AcceptMouseWheelEvent() const; |
48 | |
49 | + //! Return the direction of the area. |
50 | + Direction GetDirection() const; |
51 | + //! Sets the direction of the area. |
52 | + /*! |
53 | + @param direction Either nux::LeftToRight or nux::RightToLeft |
54 | + */ |
55 | + void SetDirection(Direction direction); |
56 | + |
57 | protected: |
58 | /* |
59 | This function is reimplemented in Layout as it need to perform some special operations. |
60 | @@ -633,6 +647,8 @@ |
61 | bool _accept_mouse_wheel_event; |
62 | bool _accept_keyboard_event; |
63 | |
64 | + Direction _direction; |
65 | + |
66 | friend class Layout; |
67 | friend class View; |
68 | friend class WindowThread; |
69 | |
70 | === modified file 'Nux/HLayout.cpp' |
71 | --- Nux/HLayout.cpp 2011-10-21 22:06:35 +0000 |
72 | +++ Nux/HLayout.cpp 2011-11-14 21:17:09 +0000 |
73 | @@ -127,7 +127,7 @@ |
74 | margin = 0; |
75 | } |
76 | |
77 | - LayoutContentDistribution stacking = GetContentDistribution(); |
78 | + LayoutContentDistribution stacking = GetEffectiveContentDistribution(); |
79 | |
80 | switch(stacking) |
81 | { |
82 | @@ -178,6 +178,8 @@ |
83 | } |
84 | |
85 | std::list<Area *>::iterator it; |
86 | + std::list<Area *>::reverse_iterator revit; |
87 | + Area* area; |
88 | |
89 | for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
90 | { |
91 | @@ -248,19 +250,24 @@ |
92 | ComputeStacking(width, offset_space, space_after_element); |
93 | current_x += offset_space; |
94 | |
95 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
96 | + revit = _layout_element_list.rbegin(); |
97 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++, revit++) |
98 | { |
99 | - if (!(*it)->IsVisible()) |
100 | + if (GetDirection() == LeftToRight) |
101 | + area = *it; |
102 | + else |
103 | + area = *revit; |
104 | + if (!area->IsVisible()) |
105 | continue; |
106 | |
107 | current_x += space_after_element; |
108 | |
109 | - (*it)->SetBaseX(current_x); |
110 | - (*it)->SetBaseY(current_y); |
111 | + area->SetBaseX(current_x); |
112 | + area->SetBaseY(current_y); |
113 | |
114 | - MinorDimensionSize extend = (*it)->GetExtend(); |
115 | - MinorDimensionPosition positioning = (*it)->GetPositioning(); |
116 | - float percentage = (*it)->GetPercentage(); |
117 | + MinorDimensionSize extend = area->GetExtend(); |
118 | + MinorDimensionPosition positioning = area->GetPositioning(); |
119 | + float percentage = area->GetPercentage(); |
120 | |
121 | // Compute the size of an ellement in the minor dimension(vertical) |
122 | switch(extend) |
123 | @@ -270,7 +277,7 @@ |
124 | // The size of the processed element in the minor dimension is a percentage of layout minor dimension size. |
125 | // Note that children of the processed element may force it to have a bigger size. |
126 | int percentage_height = (height * percentage) / 100.0f; |
127 | - (*it)->SetBaseHeight(percentage_height); |
128 | + area->SetBaseHeight(percentage_height); |
129 | break; |
130 | } |
131 | |
132 | @@ -278,7 +285,7 @@ |
133 | { |
134 | // Force the element height to be the minimum has defined with SetMinimumHeight. |
135 | // The children of this element can force it to get larger. |
136 | - (*it)->ApplyMinHeight(); |
137 | + area->ApplyMinHeight(); |
138 | break; |
139 | } |
140 | |
141 | @@ -291,30 +298,30 @@ |
142 | case MINOR_SIZE_FULL: |
143 | default: |
144 | { |
145 | - (*it)->SetBaseHeight(height); |
146 | + area->SetBaseHeight(height); |
147 | break; |
148 | } |
149 | } |
150 | |
151 | // Compute the position of an element in the minor dimension. |
152 | - if ((*it)->GetBaseHeight() < height) |
153 | + if (area->GetBaseHeight() < height) |
154 | { |
155 | - int widget_height = (*it)->GetBaseHeight(); |
156 | + int widget_height = area->GetBaseHeight(); |
157 | |
158 | switch(positioning) |
159 | { |
160 | case MINOR_POSITION_START: |
161 | { |
162 | // do nothing |
163 | - (*it)->SetBaseY(current_y); |
164 | + area->SetBaseY(current_y); |
165 | break; |
166 | } |
167 | case MINOR_POSITION_END: |
168 | { |
169 | if (widget_height < height) |
170 | - (*it)->SetBaseY(current_y + height - widget_height); |
171 | + area->SetBaseY(current_y + height - widget_height); |
172 | else |
173 | - (*it)->SetBaseY(current_y); |
174 | + area->SetBaseY(current_y); |
175 | |
176 | break; |
177 | } |
178 | @@ -323,14 +330,14 @@ |
179 | default: |
180 | { |
181 | if (widget_height < height) |
182 | - (*it)->SetBaseY(current_y + (height - widget_height) / 2); |
183 | + area->SetBaseY(current_y + (height - widget_height) / 2); |
184 | else |
185 | - (*it)->SetBaseY(current_y); |
186 | + area->SetBaseY(current_y); |
187 | } |
188 | } |
189 | } |
190 | |
191 | - current_x += (*it)->GetBaseWidth() + space_after_element + space_between_children_; |
192 | + current_x += area->GetBaseWidth() + space_after_element + space_between_children_; |
193 | } |
194 | |
195 | // Manage child layout |
196 | @@ -351,9 +358,15 @@ |
197 | // We check if that is the case and force a recompute. |
198 | std::vector<int> FullSizeUnadjusted; |
199 | |
200 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
201 | + revit = _layout_element_list.rbegin(); |
202 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++, revit++) |
203 | { |
204 | - if (!(*it)->IsVisible()) |
205 | + if (GetDirection() == LeftToRight) |
206 | + area = *it; |
207 | + else |
208 | + area = *revit; |
209 | + |
210 | + if (!area->IsVisible()) |
211 | continue; |
212 | bool smaller_height = false; |
213 | bool larger_height = false; |
214 | @@ -361,16 +374,16 @@ |
215 | bool smaller_width = false; |
216 | int ret = 0; |
217 | |
218 | - if (((*it)->IsLayout() || (*it)->IsView()) /*&& ((*it)->IsLayoutDone() == false)*/ /*&& ((*it)->GetScaleFactor() != 0)*/) |
219 | + if ((area->IsLayout() || area->IsView()) /*&& (area->IsLayoutDone() == false)*/ /*&& (area->GetScaleFactor() != 0)*/) |
220 | { |
221 | - ret = (*it)->ComputeContentSize(); |
222 | + ret = area->ComputeContentSize(); |
223 | |
224 | larger_width = (ret & eLargerWidth) ? true : false; |
225 | smaller_width = (ret & eSmallerWidth) ? true : false; |
226 | smaller_height = (ret & eSmallerHeight) ? true : false; |
227 | larger_height = (ret & eLargerHeight) ? true : false; |
228 | |
229 | - if ((larger_width || smaller_width) && ((*it)->IsLayoutDone() == false)) |
230 | + if ((larger_width || smaller_width) && (area->IsLayoutDone() == false)) |
231 | { |
232 | // Stop computing the size of this layout. Its size was not convenient to its children. So the children size take priority |
233 | // over the layout. In ComputeContentSize, the dimension of the layout has been set so it encompasses its children(and the margins). |
234 | @@ -383,37 +396,37 @@ |
235 | |
236 | { |
237 | unadjusted_layout = true; |
238 | - (*it)->SetLayoutDone(true); |
239 | + area->SetLayoutDone(true); |
240 | } |
241 | } |
242 | |
243 | - if ((smaller_height == false) && ((*it)->GetExtend() == MINOR_SIZE_FULL) && ((*it)->GetBaseHeight() < (*it)->GetMaximumHeight())) |
244 | + if ((smaller_height == false) && (area->GetExtend() == MINOR_SIZE_FULL) && (area->GetBaseHeight() < area->GetMaximumHeight())) |
245 | { |
246 | // We catch all object whose size is possibly larger than the layout. We check there size at the end and |
247 | // recompute the layout if necessary. |
248 | // For layout elements, make sure that the stretch factor is not 0. If it is, it means it will not use the |
249 | // size provided by the parent layout. Its size will be adjusted to the minimum size of the layout content. |
250 | - if (! ((*it)->IsLayout() && (*it)->GetScaleFactor() == 0)) |
251 | - FullSizeUnadjusted.push_back((*it)->GetBaseHeight()); |
252 | + if (! (area->IsLayout() && area->GetScaleFactor() == 0)) |
253 | + FullSizeUnadjusted.push_back(area->GetBaseHeight()); |
254 | } |
255 | |
256 | - if ((smaller_height || larger_height) && ((*it)->GetExtend() == MINOR_SIZE_MATCHCONTENT)) |
257 | + if ((smaller_height || larger_height) && (area->GetExtend() == MINOR_SIZE_MATCHCONTENT)) |
258 | { |
259 | - (*it)->SetMinimumHeight((*it)->GetBaseHeight()); |
260 | + area->SetMinimumHeight(area->GetBaseHeight()); |
261 | unadjusted_layout = true; |
262 | } |
263 | |
264 | // Should be reactivate so that if the parent Layout does not call |
265 | // ComputeContentPosition, at least it is done here to arrange the internal |
266 | // element of the children. |
267 | - //(*it)->ComputeContentPosition(0,0); |
268 | + //area->ComputeContentPosition(0,0); |
269 | } |
270 | |
271 | - m_fittingWidth += (*it)->GetBaseWidth(); |
272 | - |
273 | - element_height = (*it)->GetBaseHeight(); |
274 | - |
275 | - if ((*it)->IsSpaceLayout() == false) |
276 | + m_fittingWidth += area->GetBaseWidth(); |
277 | + |
278 | + element_height = area->GetBaseHeight(); |
279 | + |
280 | + if (area->IsSpaceLayout() == false) |
281 | { |
282 | if ((GetScaleFactor() != 0) /* && (ret & eSmallerHeight)*/) |
283 | { |
284 | @@ -434,7 +447,7 @@ |
285 | m_contentHeight = element_height; |
286 | } |
287 | |
288 | -// else if ((*it)->GetExtend() == MINOR_SIZE_FULL) |
289 | +// else if (area->GetExtend() == MINOR_SIZE_FULL) |
290 | // { |
291 | // unadjusted_layout = true; |
292 | // } |
293 | @@ -525,15 +538,22 @@ |
294 | int available_width = width; |
295 | unsigned int max_stretchfactor = GetMaxStretchFactor(); |
296 | std::list<Area *>::iterator it; |
297 | + std::list<Area *>::reverse_iterator revit; |
298 | + Area* area; |
299 | |
300 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
301 | + revit = _layout_element_list.rbegin(); |
302 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++, revit++) |
303 | { |
304 | - if (!(*it)->IsVisible()) |
305 | + if (GetDirection() == LeftToRight) |
306 | + area = *it; |
307 | + else |
308 | + area = *revit; |
309 | + if (!area->IsVisible()) |
310 | continue; |
311 | |
312 | - if (((*it)->GetScaleFactor() == 0) && ((*it)->IsLayoutDone() != true)) |
313 | + if ((area->GetScaleFactor() == 0) && (area->IsLayoutDone() != true)) |
314 | { |
315 | - (*it)->ApplyMinWidth(); |
316 | + area->ApplyMinWidth(); |
317 | } |
318 | } |
319 | |
320 | @@ -570,27 +590,32 @@ |
321 | |
322 | if (available_width <= 2) |
323 | { |
324 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
325 | + revit = _layout_element_list.rbegin(); |
326 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++, revit++) |
327 | { |
328 | - if (!(*it)->IsVisible()) |
329 | + if (GetDirection() == LeftToRight) |
330 | + area = *it; |
331 | + else |
332 | + area = *revit; |
333 | + if (!area->IsVisible()) |
334 | continue; |
335 | |
336 | - if (((*it)->GetScaleFactor() != 0) && (*it)->IsArea()) |
337 | + if ((area->GetScaleFactor() != 0) && area->IsArea()) |
338 | { |
339 | // If it is not an object of type eInputArea, do not set layout_done_ to true, |
340 | // so, the layout management function will later be called on the object. |
341 | - (*it)->ApplyMinWidth(); |
342 | - (*it)->SetLayoutDone(true); |
343 | + area->ApplyMinWidth(); |
344 | + area->SetLayoutDone(true); |
345 | } |
346 | - else if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayout()) && ((*it)->IsLayoutDone() == false)) // layout and not fixed by child |
347 | + else if ((area->GetScaleFactor() != 0) && (area->IsLayout()) && (area->IsLayoutDone() == false)) // layout and not fixed by child |
348 | { |
349 | // The out of bound must be reset to false. |
350 | - (*it)->ApplyMinWidth(); |
351 | - (*it)->SetLayoutDone(false); |
352 | + area->ApplyMinWidth(); |
353 | + area->SetLayoutDone(false); |
354 | } |
355 | - else if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) // layout and not fixed |
356 | + else if ((area->GetScaleFactor() != 0) && (area->IsLayoutDone() == false)) // layout and not fixed |
357 | { |
358 | - (*it)->ApplyMinWidth(); |
359 | + area->ApplyMinWidth(); |
360 | // A layout must never have layout_done_ set to true "here" because it must continue |
361 | // doing the layout of its children and finally resize itself to fit them. |
362 | // The same way, A layout size factor should never be set to 0. |
363 | @@ -604,20 +629,26 @@ |
364 | Area *LastElementThatCanBeResized = 0; |
365 | int total_distributed_size = 0; |
366 | |
367 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
368 | + revit = _layout_element_list.rbegin(); |
369 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++, revit++) |
370 | { |
371 | - if (!(*it)->IsVisible()) |
372 | + if (GetDirection() == LeftToRight) |
373 | + area = *it; |
374 | + else |
375 | + area = *revit; |
376 | + |
377 | + if (!area->IsVisible()) |
378 | continue; |
379 | |
380 | - if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) |
381 | + if ((area->GetScaleFactor() != 0) && (area->IsLayoutDone() == false)) |
382 | { |
383 | - float sf = (float) (*it)->GetScaleFactor(); |
384 | + float sf = (float) area->GetScaleFactor(); |
385 | cumul += sf / max_stretchfactor; |
386 | - LastElementThatCanBeResized = (*it); |
387 | + LastElementThatCanBeResized = area; |
388 | } |
389 | else |
390 | { |
391 | - total_distributed_size += (*it)->GetBaseWidth(); |
392 | + total_distributed_size += area->GetBaseWidth(); |
393 | } |
394 | } |
395 | |
396 | @@ -633,14 +664,20 @@ |
397 | |
398 | need_recompute = false;; |
399 | |
400 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; it++) |
401 | + revit = _layout_element_list.rbegin(); |
402 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end() && !need_recompute; it++, revit++) |
403 | { |
404 | - if (!(*it)->IsVisible()) |
405 | + if (GetDirection() == LeftToRight) |
406 | + area = *it; |
407 | + else |
408 | + area = *revit; |
409 | + |
410 | + if (!area->IsVisible()) |
411 | continue; |
412 | |
413 | - if (((*it)->GetScaleFactor() != 0) && ((*it)->IsLayoutDone() == false)) |
414 | + if ((area->GetScaleFactor() != 0) && (area->IsLayoutDone() == false)) |
415 | { |
416 | - unsigned int sf = (*it)->GetScaleFactor(); |
417 | + unsigned int sf = area->GetScaleFactor(); |
418 | int new_width; |
419 | |
420 | if (sf == max_stretchfactor) |
421 | @@ -654,7 +691,7 @@ |
422 | |
423 | total_distributed_size += new_width; |
424 | |
425 | - if (LastElementThatCanBeResized == (*it)) |
426 | + if (LastElementThatCanBeResized == area) |
427 | { |
428 | // Redistribute the remaining size to the last element(at the right). |
429 | // This is necessary because of imprecision. For instance if available_height = 451 and we have 2 elements |
430 | @@ -667,8 +704,8 @@ |
431 | } |
432 | } |
433 | |
434 | - int elemt_max_width = (*it)->GetMaximumSize().width; |
435 | - int elemt_min_width = (*it)->GetMinimumSize().width; |
436 | + int elemt_max_width = area->GetMaximumSize().width; |
437 | + int elemt_min_width = area->GetMinimumSize().width; |
438 | |
439 | // A layout must never have layout_done_ set to true "here" because it must continue |
440 | // doing the layout of its children and finally resize itself to fit them. |
441 | @@ -679,22 +716,22 @@ |
442 | if (new_width < elemt_min_width) |
443 | { |
444 | // assume the minimum width |
445 | - (*it)->SetBaseWidth(elemt_min_width); |
446 | + area->SetBaseWidth(elemt_min_width); |
447 | |
448 | - if ((*it)->IsLayout() == false || (*it)->IsSpaceLayout()) |
449 | + if (area->IsLayout() == false || area->IsSpaceLayout()) |
450 | { |
451 | - (*it)->SetLayoutDone(true); |
452 | + area->SetLayoutDone(true); |
453 | need_recompute = true; |
454 | } |
455 | } |
456 | else if (new_width > elemt_max_width) |
457 | { |
458 | // assume the maximum width |
459 | - (*it)->SetBaseWidth(elemt_max_width); |
460 | + area->SetBaseWidth(elemt_max_width); |
461 | |
462 | - if ((*it)->IsLayout() == false || (*it)->IsSpaceLayout()) |
463 | + if (area->IsLayout() == false || area->IsSpaceLayout()) |
464 | { |
465 | - (*it)->SetLayoutDone(true); |
466 | + area->SetLayoutDone(true); |
467 | need_recompute = true; |
468 | } |
469 | |
470 | @@ -706,7 +743,7 @@ |
471 | } |
472 | else |
473 | { |
474 | - (*it)->SetBaseWidth(new_width); |
475 | + area->SetBaseWidth(new_width); |
476 | } |
477 | } |
478 | else |
479 | @@ -714,10 +751,10 @@ |
480 | // For fixed element, reset their size to the same so it is checked against |
481 | // the min and max. This is necessary in case you have set the size of the element first then latter, |
482 | // you define its MinimumSize and/or MaximumSize size. |
483 | - unsigned int w = (*it)->GetBaseWidth(); |
484 | - unsigned int h = (*it)->GetBaseHeight(); |
485 | - (*it)->SetBaseWidth(w); |
486 | - (*it)->SetBaseHeight(h); |
487 | + unsigned int w = area->GetBaseWidth(); |
488 | + unsigned int h = area->GetBaseHeight(); |
489 | + area->SetBaseWidth(w); |
490 | + area->SetBaseHeight(h); |
491 | } |
492 | } |
493 | } |
494 | @@ -754,6 +791,8 @@ |
495 | void HLayout::ComputeContentPosition(float offsetX, float offsetY) |
496 | { |
497 | std::list<Area *>::iterator it; |
498 | + std::list<Area *>::reverse_iterator revit; |
499 | + Area* area; |
500 | { |
501 | unsigned int num_element = 0; |
502 | for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
503 | @@ -778,37 +817,42 @@ |
504 | ComputeStacking(width, offset_space, element_margin); |
505 | current_x += offset_space; |
506 | |
507 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
508 | + revit = _layout_element_list.rbegin(); |
509 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++, revit++) |
510 | { |
511 | - if (!(*it)->IsVisible()) |
512 | + if (GetDirection() == LeftToRight) |
513 | + area = *it; |
514 | + else |
515 | + area = *revit; |
516 | + if (!area->IsVisible()) |
517 | continue; |
518 | |
519 | current_x += element_margin; |
520 | |
521 | - (*it)->SetBaseX(current_x); |
522 | - (*it)->SetBaseY(current_y); |
523 | - |
524 | - MinorDimensionSize extend = (*it)->GetExtend(); |
525 | - MinorDimensionPosition positioning = (*it)->GetPositioning(); |
526 | - |
527 | - if ((*it)->GetBaseHeight() < height) |
528 | + area->SetBaseX(current_x); |
529 | + area->SetBaseY(current_y); |
530 | + |
531 | + MinorDimensionSize extend = area->GetExtend(); |
532 | + MinorDimensionPosition positioning = area->GetPositioning(); |
533 | + |
534 | + if (area->GetBaseHeight() < height) |
535 | { |
536 | - int widget_height = (*it)->GetBaseHeight(); |
537 | + int widget_height = area->GetBaseHeight(); |
538 | |
539 | switch(positioning) |
540 | { |
541 | case MINOR_POSITION_START: |
542 | { |
543 | // do nothing |
544 | - (*it)->SetBaseY(current_y); |
545 | + area->SetBaseY(current_y); |
546 | break; |
547 | } |
548 | case MINOR_POSITION_END: |
549 | { |
550 | if (widget_height < height) |
551 | - (*it)->SetBaseY(current_y + height - widget_height); |
552 | + area->SetBaseY(current_y + height - widget_height); |
553 | else |
554 | - (*it)->SetBaseY(current_y); |
555 | + area->SetBaseY(current_y); |
556 | |
557 | break; |
558 | } |
559 | @@ -817,29 +861,34 @@ |
560 | default: |
561 | { |
562 | if (widget_height < height) |
563 | - (*it)->SetBaseY(current_y + (height - widget_height) / 2); |
564 | + area->SetBaseY(current_y + (height - widget_height) / 2); |
565 | else |
566 | - (*it)->SetBaseY(current_y); |
567 | + area->SetBaseY(current_y); |
568 | } |
569 | } |
570 | } |
571 | |
572 | - current_x += (*it)->GetBaseWidth() + element_margin + space_between_children_; |
573 | + current_x += area->GetBaseWidth() + element_margin + space_between_children_; |
574 | } |
575 | } |
576 | |
577 | - for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) |
578 | + revit = _layout_element_list.rbegin(); |
579 | + for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++, revit++) |
580 | { |
581 | - if (!(*it)->IsVisible()) |
582 | + if (GetDirection() == LeftToRight) |
583 | + area = *it; |
584 | + else |
585 | + area = *revit; |
586 | + if (!area->IsVisible()) |
587 | continue; |
588 | |
589 | - if ((*it)->Type().IsDerivedFromType(Layout::StaticObjectType)) |
590 | + if (area->Type().IsDerivedFromType(Layout::StaticObjectType)) |
591 | { |
592 | - (*it)->ComputeContentPosition(offsetX, offsetY); |
593 | + area->ComputeContentPosition(offsetX, offsetY); |
594 | } |
595 | - else if ((*it)->Type().IsDerivedFromType(View::StaticObjectType)) |
596 | + else if (area->Type().IsDerivedFromType(View::StaticObjectType)) |
597 | { |
598 | - (*it)->ComputeContentPosition(offsetX, offsetY); |
599 | + area->ComputeContentPosition(offsetX, offsetY); |
600 | } |
601 | } |
602 | } |
603 | |
604 | === modified file 'Nux/Layout.cpp' |
605 | --- Nux/Layout.cpp 2011-10-17 20:57:35 +0000 |
606 | +++ Nux/Layout.cpp 2011-11-14 21:17:09 +0000 |
607 | @@ -557,6 +557,22 @@ |
608 | return m_ContentStacking; |
609 | } |
610 | |
611 | + LayoutContentDistribution Layout::GetEffectiveContentDistribution() |
612 | + { |
613 | + LayoutContentDistribution stacking = GetContentDistribution(); |
614 | + if (GetDirection() == LeftToRight) |
615 | + return stacking; |
616 | + switch (stacking) |
617 | + { |
618 | + case eStackLeft: |
619 | + return eStackRight; |
620 | + case eStackRight: |
621 | + return eStackLeft; |
622 | + default: |
623 | + return stacking; |
624 | + } |
625 | + } |
626 | + |
627 | void Layout::RequestBottomUpLayoutComputation(Area *bo_initiator) |
628 | { |
629 | |
630 | |
631 | === modified file 'Nux/Layout.h' |
632 | --- Nux/Layout.h 2011-10-10 01:52:00 +0000 |
633 | +++ Nux/Layout.h 2011-11-14 21:17:09 +0000 |
634 | @@ -201,6 +201,9 @@ |
635 | virtual void SetContentDistribution(LayoutContentDistribution stacking_order); |
636 | virtual LayoutContentDistribution GetContentDistribution(); |
637 | |
638 | + //! Switch the content distribution in case a RightToLeft direction is used |
639 | + LayoutContentDistribution GetEffectiveContentDistribution(); |
640 | + |
641 | virtual bool FindWidget(Area *WidgetObject) const; |
642 | virtual bool IsEmpty() const; |
643 | /* |
644 | |
645 | === modified file 'Nux/Nux.cpp' |
646 | --- Nux/Nux.cpp 2011-11-10 17:28:44 +0000 |
647 | +++ Nux/Nux.cpp 2011-11-14 21:17:09 +0000 |
648 | @@ -349,4 +349,16 @@ |
649 | return NUX_STATIC_CAST(WindowThread *, thread)->GetGraphicsEngine(); |
650 | } |
651 | |
652 | + static Direction defaultDirection = LeftToRight; |
653 | + |
654 | + Direction GetDefaultDirection() |
655 | + { |
656 | + return defaultDirection; |
657 | + } |
658 | + |
659 | + void SetDefaultDirection(Direction direction) |
660 | + { |
661 | + defaultDirection = direction; |
662 | + } |
663 | + |
664 | } |
665 | |
666 | === modified file 'Nux/Nux.h' |
667 | --- Nux/Nux.h 2011-10-21 22:06:35 +0000 |
668 | +++ Nux/Nux.h 2011-11-14 21:17:09 +0000 |
669 | @@ -150,6 +150,9 @@ |
670 | |
671 | inlDeclareThreadLocalStorage(NThread *, 0, ThreadLocal_InalogicAppImpl); |
672 | |
673 | + Direction GetDefaultDirection(); |
674 | + void SetDefaultDirection(Direction direction); |
675 | + |
676 | } |
677 | |
678 | #endif // NUX_H |
Haggai
Selecting right to left has to be done per layout. Lets say you have an horizontal layout that has a checkbox followed by a button, and the button is followed by a combobox. In LTR order you get this:
checkbox | button | combobox
If you make the HLayout to be RTL then the content will look like this:
combobox| button | checkbox
This should work out fine because only a specific HLayout has been been changed to RTL.
So you have to select only the layouts of the interface that need to be inverted. Rather than having SetDefaultDirection in Nux.cpp, it should be a function member of LinearLayout. Then for each layout (HLayout or VLayout), you will be able to decide if it goes from LTR or RTL. Individual views like the Checkbox, will remain un-affected.
How about that?