Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <svx/sdr/overlay/overlaymanagerbuffered.hxx>
21 : #include <svx/sdrpaintwindow.hxx>
22 : #include <vcl/outdev.hxx>
23 : #include <basegfx/point/b2dpoint.hxx>
24 : #include <basegfx/range/b2drange.hxx>
25 : #include <vcl/window.hxx>
26 : #include <vcl/bitmap.hxx>
27 : #include <tools/stream.hxx>
28 : #include <basegfx/matrix/b2dhommatrix.hxx>
29 : #include <vcl/cursor.hxx>
30 : #include <vcl/dibtools.hxx>
31 :
32 :
33 :
34 : namespace sdr
35 : {
36 : namespace overlay
37 : {
38 0 : void OverlayManagerBuffered::ImpPrepareBufferDevice()
39 : {
40 : // compare size of maBufferDevice with size of visible area
41 0 : if(maBufferDevice.GetOutputSizePixel() != getOutputDevice().GetOutputSizePixel())
42 : {
43 : // set new buffer size, copy as much content as possible (use bool parameter for vcl).
44 : // Newly uncovered regions will be repainted.
45 0 : maBufferDevice.SetOutputSizePixel(getOutputDevice().GetOutputSizePixel(), false);
46 : }
47 :
48 : // compare the MapModes for zoom/scroll changes
49 0 : if(maBufferDevice.GetMapMode() != getOutputDevice().GetMapMode())
50 : {
51 : const bool bZoomed(
52 0 : maBufferDevice.GetMapMode().GetScaleX() != getOutputDevice().GetMapMode().GetScaleX()
53 0 : || maBufferDevice.GetMapMode().GetScaleY() != getOutputDevice().GetMapMode().GetScaleY());
54 :
55 0 : if(!bZoomed)
56 : {
57 0 : const Point& rOriginOld = maBufferDevice.GetMapMode().GetOrigin();
58 0 : const Point& rOriginNew = getOutputDevice().GetMapMode().GetOrigin();
59 0 : const bool bScrolled(rOriginOld != rOriginNew);
60 :
61 0 : if(bScrolled)
62 : {
63 : // get pixel bounds
64 0 : const Point aOriginOldPixel(maBufferDevice.LogicToPixel(rOriginOld));
65 0 : const Point aOriginNewPixel(maBufferDevice.LogicToPixel(rOriginNew));
66 0 : const Size aOutputSizePixel(maBufferDevice.GetOutputSizePixel());
67 :
68 : // remember and switch off MapMode
69 0 : const bool bMapModeWasEnabled(maBufferDevice.IsMapModeEnabled());
70 0 : maBufferDevice.EnableMapMode(false);
71 :
72 : // scroll internally buffered stuff
73 0 : const Point aDestinationOffsetPixel(aOriginNewPixel - aOriginOldPixel);
74 : maBufferDevice.DrawOutDev(
75 : aDestinationOffsetPixel, aOutputSizePixel, // destination
76 0 : Point(), aOutputSizePixel); // source
77 :
78 : // restore MapMode
79 0 : maBufferDevice.EnableMapMode(bMapModeWasEnabled);
80 :
81 : // scroll remembered region, too.
82 0 : if(!maBufferRememberedRangePixel.isEmpty())
83 : {
84 0 : const basegfx::B2IPoint aIPointDestinationOffsetPixel(aDestinationOffsetPixel.X(), aDestinationOffsetPixel.Y());
85 0 : const basegfx::B2IPoint aNewMinimum(maBufferRememberedRangePixel.getMinimum() + aIPointDestinationOffsetPixel);
86 0 : const basegfx::B2IPoint aNewMaximum(maBufferRememberedRangePixel.getMaximum() + aIPointDestinationOffsetPixel);
87 0 : maBufferRememberedRangePixel = basegfx::B2IRange(aNewMinimum, aNewMaximum);
88 : }
89 : }
90 : }
91 :
92 : // copy new MapMode
93 0 : maBufferDevice.SetMapMode(getOutputDevice().GetMapMode());
94 : }
95 :
96 : // #i29186#
97 0 : maBufferDevice.SetDrawMode(getOutputDevice().GetDrawMode());
98 0 : maBufferDevice.SetSettings(getOutputDevice().GetSettings());
99 0 : maBufferDevice.SetAntialiasing(getOutputDevice().GetAntialiasing());
100 0 : }
101 :
102 0 : void OverlayManagerBuffered::ImpRestoreBackground() const
103 : {
104 : const Rectangle aRegionRectanglePixel(
105 : maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
106 0 : maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
107 0 : const Region aRegionPixel(aRegionRectanglePixel);
108 :
109 0 : ImpRestoreBackground(aRegionPixel);
110 0 : }
111 :
112 0 : void OverlayManagerBuffered::ImpRestoreBackground(const Region& rRegionPixel) const
113 : {
114 : // MapModes off
115 0 : const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
116 0 : const bool bMapModeWasEnabledSource(maBufferDevice.IsMapModeEnabled());
117 0 : getOutputDevice().EnableMapMode(false);
118 0 : ((OverlayManagerBuffered*)this)->maBufferDevice.EnableMapMode(false);
119 :
120 : // local region
121 0 : RectangleVector aRectangles;
122 0 : rRegionPixel.GetRegionRectangles(aRectangles);
123 :
124 0 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
125 : {
126 : #ifdef DBG_UTIL
127 : // #i72754# possible graphical region test only with non-pro
128 : static bool bDoPaintForVisualControl(false);
129 :
130 : if(bDoPaintForVisualControl)
131 : {
132 : getOutputDevice().SetLineColor(COL_LIGHTGREEN);
133 : getOutputDevice().SetFillColor();
134 : getOutputDevice().DrawRect(*aRectIter);
135 : }
136 : #endif
137 :
138 : // restore the area
139 0 : const Point aTopLeft(aRectIter->TopLeft());
140 0 : const Size aSize(aRectIter->GetSize());
141 :
142 0 : getOutputDevice().DrawOutDev(
143 : aTopLeft, aSize, // destination
144 : aTopLeft, aSize, // source
145 0 : maBufferDevice);
146 : }
147 :
148 : //Region aRegionPixel(rRegionPixel);
149 : //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
150 : //Rectangle aRegionRectanglePixel;
151 :
152 : //while(aRegionPixel.GetEnumRects(aRegionHandle, aRegionRectanglePixel))
153 : //{
154 : #ifdef DBG_U//TIL
155 : // // #i72754# possible graphical region test only with non-pro
156 : // static bool bDoPaintForVisualControl(false);
157 : // if(bDoPaintForVisualControl)
158 : // {
159 : // getOutputDevice().SetLineColor(COL_LIGHTGREEN);
160 : // getOutputDevice().SetFillColor();
161 : // getOutputDevice().DrawRect(aRegionRectanglePixel);
162 : // }
163 : #endif
164 : // // restore the area
165 : // const Point aTopLeft(aRegionRectanglePixel.TopLeft());
166 : // const Size aSize(aRegionRectanglePixel.GetSize());
167 :
168 : // getOutputDevice().DrawOutDev(
169 : // aTopLeft, aSize, // destination
170 : // aTopLeft, aSize, // source
171 : // maBufferDevice);
172 : //}
173 :
174 : //aRegionPixel.EndEnumRects(aRegionHandle);
175 :
176 : // restore MapModes
177 0 : getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
178 0 : ((OverlayManagerBuffered*)this)->maBufferDevice.EnableMapMode(bMapModeWasEnabledSource);
179 0 : }
180 :
181 0 : void OverlayManagerBuffered::ImpSaveBackground(const Region& rRegion, OutputDevice* pPreRenderDevice)
182 : {
183 : // prepare source
184 0 : OutputDevice& rSource = (pPreRenderDevice) ? *pPreRenderDevice : getOutputDevice();
185 :
186 : // Ensure buffer is valid
187 0 : ImpPrepareBufferDevice();
188 :
189 : // build region which needs to be copied
190 0 : Region aRegion(rSource.LogicToPixel(rRegion));
191 :
192 : // limit to PaintRegion if it's a window. This will be evtl. the expanded one,
193 : // but always the exact redraw area
194 0 : if(OUTDEV_WINDOW == rSource.GetOutDevType())
195 : {
196 0 : Window& rWindow = (Window&)rSource;
197 0 : Region aPaintRegionPixel = rWindow.LogicToPixel(rWindow.GetPaintRegion());
198 0 : aRegion.Intersect(aPaintRegionPixel);
199 :
200 : // #i72754# Make sure content is completetly rendered, the window
201 : // will be used as source of a DrawOutDev soon
202 0 : rWindow.Flush();
203 : }
204 :
205 : // also limit to buffer size
206 0 : const Rectangle aBufferDeviceRectanglePixel(Point(), maBufferDevice.GetOutputSizePixel());
207 0 : aRegion.Intersect(aBufferDeviceRectanglePixel);
208 :
209 : // MapModes off
210 0 : const bool bMapModeWasEnabledDest(rSource.IsMapModeEnabled());
211 0 : const bool bMapModeWasEnabledSource(maBufferDevice.IsMapModeEnabled());
212 0 : rSource.EnableMapMode(false);
213 0 : maBufferDevice.EnableMapMode(false);
214 :
215 : // prepare to iterate over the rectangles from the region in pixels
216 0 : RectangleVector aRectangles;
217 0 : aRegion.GetRegionRectangles(aRectangles);
218 :
219 0 : for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
220 : {
221 : // for each rectangle, save the area
222 0 : const Point aTopLeft(aRectIter->TopLeft());
223 0 : const Size aSize(aRectIter->GetSize());
224 :
225 : maBufferDevice.DrawOutDev(
226 : aTopLeft, aSize, // destination
227 : aTopLeft, aSize, // source
228 0 : rSource);
229 : }
230 :
231 : //RegionHandle aRegionHandle(aRegion.BeginEnumRects());
232 : //Rectangle aRegionRectanglePixel;
233 :
234 : //while(aRegion.GetEnumRects(aRegionHandle, aRegionRectanglePixel))
235 : //{
236 : // // for each rectangle, save the area
237 : // Point aTopLeft(aRegionRectanglePixel.TopLeft());
238 : // Size aSize(aRegionRectanglePixel.GetSize());
239 :
240 : // maBufferDevice.DrawOutDev(
241 : // aTopLeft, aSize, // destination
242 : // aTopLeft, aSize, // source
243 : // rSource);
244 :
245 : //}
246 :
247 : //aRegion.EndEnumRects(aRegionHandle);
248 :
249 : // restore MapModes
250 0 : rSource.EnableMapMode(bMapModeWasEnabledDest);
251 0 : maBufferDevice.EnableMapMode(bMapModeWasEnabledSource);
252 0 : }
253 :
254 0 : IMPL_LINK(OverlayManagerBuffered, ImpBufferTimerHandler, AutoTimer*, /*pTimer*/)
255 : {
256 : //Resolves: fdo#46728 ensure this exists until end of scope
257 0 : rtl::Reference<OverlayManager> xRef(this);
258 :
259 : // stop timer
260 0 : maBufferTimer.Stop();
261 :
262 0 : if(!maBufferRememberedRangePixel.isEmpty())
263 : {
264 : // logic size for impDrawMember call
265 : basegfx::B2DRange aBufferRememberedRangeLogic(
266 0 : maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
267 0 : maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
268 0 : aBufferRememberedRangeLogic.transform(getOutputDevice().GetInverseViewTransformation());
269 :
270 : // prepare cursor handling
271 0 : const bool bTargetIsWindow(OUTDEV_WINDOW == rmOutputDevice.GetOutDevType());
272 0 : bool bCursorWasEnabled(false);
273 :
274 : // #i80730# switch off VCL cursor during overlay refresh
275 0 : if(bTargetIsWindow)
276 : {
277 0 : Window& rWindow = static_cast< Window& >(rmOutputDevice);
278 0 : Cursor* pCursor = rWindow.GetCursor();
279 :
280 0 : if(pCursor && pCursor->IsVisible())
281 : {
282 0 : pCursor->Hide();
283 0 : bCursorWasEnabled = true;
284 : }
285 : }
286 :
287 0 : if(DoRefreshWithPreRendering())
288 : {
289 : // #i73602# ensure valid and sized maOutputBufferDevice
290 0 : const Size aDestinationSizePixel(maBufferDevice.GetOutputSizePixel());
291 0 : const Size aOutputBufferSizePixel(maOutputBufferDevice.GetOutputSizePixel());
292 :
293 0 : if(aDestinationSizePixel != aOutputBufferSizePixel)
294 : {
295 0 : maOutputBufferDevice.SetOutputSizePixel(aDestinationSizePixel);
296 : }
297 :
298 0 : maOutputBufferDevice.SetMapMode(getOutputDevice().GetMapMode());
299 0 : maOutputBufferDevice.EnableMapMode(false);
300 0 : maOutputBufferDevice.SetDrawMode(maBufferDevice.GetDrawMode());
301 0 : maOutputBufferDevice.SetSettings(maBufferDevice.GetSettings());
302 0 : maOutputBufferDevice.SetAntialiasing(maBufferDevice.GetAntialiasing());
303 :
304 : // calculate sizes
305 : Rectangle aRegionRectanglePixel(
306 : maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
307 0 : maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
308 :
309 : // truncate aRegionRectanglePixel to destination pixel size, more does
310 : // not need to be prepared since destination is a buffer for a window. So,
311 : // maximum size indirectly shall be limited to getOutputDevice().GetOutputSizePixel()
312 0 : if(aRegionRectanglePixel.Left() < 0L)
313 : {
314 0 : aRegionRectanglePixel.Left() = 0L;
315 : }
316 :
317 0 : if(aRegionRectanglePixel.Top() < 0L)
318 : {
319 0 : aRegionRectanglePixel.Top() = 0L;
320 : }
321 :
322 0 : if(aRegionRectanglePixel.Right() > aDestinationSizePixel.getWidth())
323 : {
324 0 : aRegionRectanglePixel.Right() = aDestinationSizePixel.getWidth();
325 : }
326 :
327 0 : if(aRegionRectanglePixel.Bottom() > aDestinationSizePixel.getHeight())
328 : {
329 0 : aRegionRectanglePixel.Bottom() = aDestinationSizePixel.getHeight();
330 : }
331 :
332 : // get sizes
333 0 : const Point aTopLeft(aRegionRectanglePixel.TopLeft());
334 0 : const Size aSize(aRegionRectanglePixel.GetSize());
335 :
336 : {
337 0 : const bool bMapModeWasEnabledDest(maBufferDevice.IsMapModeEnabled());
338 0 : maBufferDevice.EnableMapMode(false);
339 :
340 : maOutputBufferDevice.DrawOutDev(
341 : aTopLeft, aSize, // destination
342 : aTopLeft, aSize, // source
343 0 : maBufferDevice);
344 :
345 : // restore MapModes
346 0 : maBufferDevice.EnableMapMode(bMapModeWasEnabledDest);
347 : }
348 :
349 : // paint overlay content for remembered region, use
350 : // method from base class directly
351 0 : maOutputBufferDevice.EnableMapMode(true);
352 0 : OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, maOutputBufferDevice);
353 0 : maOutputBufferDevice.EnableMapMode(false);
354 :
355 : // copy to output
356 : {
357 0 : const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
358 0 : getOutputDevice().EnableMapMode(false);
359 :
360 0 : getOutputDevice().DrawOutDev(
361 : aTopLeft, aSize, // destination
362 : aTopLeft, aSize, // source
363 0 : maOutputBufferDevice);
364 :
365 : // debug
366 : /*getOutputDevice().SetLineColor(COL_RED);
367 : getOutputDevice().SetFillColor();
368 : getOutputDevice().DrawRect(Rectangle(aTopLeft, aSize));*/
369 :
370 : // restore MapModes
371 0 : getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
372 : }
373 : }
374 : else
375 : {
376 : // Restore all rectangles for remembered region from buffer
377 0 : ImpRestoreBackground();
378 :
379 : // paint overlay content for remembered region, use
380 : // method from base class directly
381 0 : OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, getOutputDevice());
382 : }
383 :
384 : // VCL hack for transparent child windows
385 : // Problem is e.g. a radiobuttion form control in life mode. The used window
386 : // is a transparence vcl childwindow. This flag only allows the parent window to
387 : // paint into the child windows area, but there is no mechanism which takes
388 : // care for a repaint of the child window. A transparent child window is NOT
389 : // a window which always keeps it's content consistent over the parent, but it's
390 : // more like just a paint flag for the parent.
391 : // To get the update, the windows in question are updated manulally here.
392 0 : if(bTargetIsWindow)
393 : {
394 0 : Window& rWindow = static_cast< Window& >(rmOutputDevice);
395 :
396 : const Rectangle aRegionRectanglePixel(
397 : maBufferRememberedRangePixel.getMinX(),
398 : maBufferRememberedRangePixel.getMinY(),
399 : maBufferRememberedRangePixel.getMaxX(),
400 0 : maBufferRememberedRangePixel.getMaxY());
401 0 : PaintTransparentChildren(rWindow, aRegionRectanglePixel);
402 : }
403 :
404 : // #i80730# restore visibility of VCL cursor
405 0 : if(bCursorWasEnabled)
406 : {
407 0 : Window& rWindow = static_cast< Window& >(rmOutputDevice);
408 0 : Cursor* pCursor = rWindow.GetCursor();
409 :
410 0 : if(pCursor)
411 : {
412 : // check if cursor still exists. It may have been deleted from someone
413 0 : pCursor->Show();
414 : }
415 : }
416 :
417 : // forget remembered Region
418 0 : maBufferRememberedRangePixel.reset();
419 : }
420 :
421 0 : return 0;
422 : }
423 :
424 0 : OverlayManagerBuffered::OverlayManagerBuffered(
425 : OutputDevice& rOutputDevice,
426 : bool bRefreshWithPreRendering)
427 : : OverlayManager(rOutputDevice),
428 0 : mbRefreshWithPreRendering(bRefreshWithPreRendering)
429 : {
430 : // Init timer
431 0 : maBufferTimer.SetTimeout(1);
432 0 : maBufferTimer.SetTimeoutHdl(LINK(this, OverlayManagerBuffered, ImpBufferTimerHandler));
433 0 : }
434 :
435 0 : rtl::Reference<OverlayManager> OverlayManagerBuffered::create(
436 : OutputDevice& rOutputDevice,
437 : bool bRefreshWithPreRendering)
438 : {
439 : return rtl::Reference<OverlayManager>(new OverlayManagerBuffered(rOutputDevice,
440 0 : bRefreshWithPreRendering));
441 : }
442 :
443 0 : OverlayManagerBuffered::~OverlayManagerBuffered()
444 : {
445 : // Clear timer
446 0 : maBufferTimer.Stop();
447 :
448 0 : if(!maBufferRememberedRangePixel.isEmpty())
449 : {
450 : // Restore all rectangles for remembered region from buffer
451 0 : ImpRestoreBackground();
452 : }
453 0 : }
454 :
455 0 : void OverlayManagerBuffered::completeRedraw(const Region& rRegion, OutputDevice* pPreRenderDevice) const
456 : {
457 0 : if(!rRegion.IsEmpty())
458 : {
459 : // save new background
460 0 : ((OverlayManagerBuffered*)this)->ImpSaveBackground(rRegion, pPreRenderDevice);
461 : }
462 :
463 : // call parent
464 0 : OverlayManager::completeRedraw(rRegion, pPreRenderDevice);
465 0 : }
466 :
467 0 : void OverlayManagerBuffered::flush()
468 : {
469 : // call timer handler direct
470 0 : ImpBufferTimerHandler(0);
471 0 : }
472 :
473 : // #i68597# part of content gets copied, react on it
474 0 : void OverlayManagerBuffered::copyArea(const Point& rDestPt, const Point& rSrcPt, const Size& rSrcSize)
475 : {
476 : // scroll local buffered area
477 0 : maBufferDevice.CopyArea(rDestPt, rSrcPt, rSrcSize);
478 0 : }
479 :
480 0 : void OverlayManagerBuffered::restoreBackground(const Region& rRegion) const
481 : {
482 : // restore
483 0 : const Region aRegionPixel(getOutputDevice().LogicToPixel(rRegion));
484 0 : ImpRestoreBackground(aRegionPixel);
485 :
486 : // call parent
487 0 : OverlayManager::restoreBackground(rRegion);
488 0 : }
489 :
490 0 : void OverlayManagerBuffered::invalidateRange(const basegfx::B2DRange& rRange)
491 : {
492 0 : if(!rRange.isEmpty())
493 : {
494 : // buffered output, do not invalidate but use the timer
495 : // to trigger a timer event for refresh
496 0 : maBufferTimer.Start();
497 :
498 : // add the discrete range to the remembered region
499 : // #i75163# use double precision and floor/ceil rounding to get overlapped pixel region, even
500 : // when the given logic region has a width/height of 0.0. This does NOT work with LogicToPixel
501 : // since it just transforms the top left and bottom right points equally without taking
502 : // discrete pixel coverage into account. An empty B2DRange and thus empty logic Rectangle translated
503 : // to an also empty discrete pixel rectangle - what is wrong.
504 0 : basegfx::B2DRange aDiscreteRange(rRange);
505 0 : aDiscreteRange.transform(getOutputDevice().GetViewTransformation());
506 :
507 0 : if(maDrawinglayerOpt.IsAntiAliasing())
508 : {
509 : // assume AA needs one pixel more and invalidate one pixel more
510 0 : const double fDiscreteOne(getDiscreteOne());
511 : const basegfx::B2IPoint aTopLeft(
512 0 : (sal_Int32)floor(aDiscreteRange.getMinX() - fDiscreteOne),
513 0 : (sal_Int32)floor(aDiscreteRange.getMinY() - fDiscreteOne));
514 : const basegfx::B2IPoint aBottomRight(
515 0 : (sal_Int32)ceil(aDiscreteRange.getMaxX() + fDiscreteOne),
516 0 : (sal_Int32)ceil(aDiscreteRange.getMaxY() + fDiscreteOne));
517 :
518 0 : maBufferRememberedRangePixel.expand(aTopLeft);
519 0 : maBufferRememberedRangePixel.expand(aBottomRight);
520 : }
521 : else
522 : {
523 0 : const basegfx::B2IPoint aTopLeft((sal_Int32)floor(aDiscreteRange.getMinX()), (sal_Int32)floor(aDiscreteRange.getMinY()));
524 0 : const basegfx::B2IPoint aBottomRight((sal_Int32)ceil(aDiscreteRange.getMaxX()), (sal_Int32)ceil(aDiscreteRange.getMaxY()));
525 :
526 0 : maBufferRememberedRangePixel.expand(aTopLeft);
527 0 : maBufferRememberedRangePixel.expand(aBottomRight);
528 : }
529 : }
530 0 : }
531 : } // end of namespace overlay
532 : } // end of namespace sdr
533 :
534 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|