.. -*- coding: UTF-8 -*-

:Subtitle: What's underneath the Overlays

.. _overlays-label:

Overlays and Decorations
========================

Overlays grew out of the desire to put a background image on a ListView.
(See :ref:`blog-overlays` for the details).

`ObjectListView` provides a normal set of operations to manage overlays::

    public void AddOverlay(IOverlay overlay);
    public bool HasOverlay(IOverlay overlay);
    public void RemoveOverlay(IOverlay overlay);

The `IOverlay` interface is very simple::

    public interface IOverlay {
        void Draw(ObjectListView olv, Graphics g, Rectangle r);
    }

Within the `Draw()` method, your implementation can draw whatever it likes.

In the Overlays.cs file, you can find several examples of overlays that
can serve as your model for implementation. The two most common overlays
are image overlays and text overlays.

* `ImageOverlay` draws an image over the `ObjectListView`

* `TextOverlay` is a highly configurable overlay that can draw bordered, colored
  and backgrounded text. The text can be rotated.

These two overlays are so common that `ObjectListView` comes with one of each
predefined. These predefined overlays are exposed to the IDE, so that they
can be configured directly from there. So, for the majority of cases, this
is the only understanding of overlays that you will need.

Disabling overlays
------------------

Though they seem simple, overlays are actually quite tricky underneath.
If they are causing problems (for example, if you are seeing `GlassPanelForms`
turn up where you are not expecting them), you can completely disable them
by setting `UseOverlays` to *false*.

Implementation
--------------

Overlays are implemented using the Layered Window API. This API allows a
toplevel windows to be translucent and partially transparent. Internally,
the `ObjectListView` creates a transparent window, positions it above the
control, and then paints the overlays onto that window.

.. image:: images/overlay.png

So, when displaying overlays, the `ObjectListView` creates a new
top-level window, and puts that above the control. In this way,
it looks like the overlays are drawn onto the list, but in reality,
they are completely separate.

And the two shall become one
----------------------------

The tricky bits of the overlay implementation are making the
overlay window acts as if it is actually part of the `ObjectListView`.

Obviously, when the `ObjectListView` moves, the overlay window must
move too. If we could make the overlay window a child window of the
`ObjectListView`, then Windows would make that happen for us. But
layered windows *have* to be top level windows. So we have to
manually move the overlay window when the `ObjectListView` moves.

Similarly, when the `ObjectListView` is resized, we have to manually
resize the overlay window to match the new size. If we do this resizing
in realtime as the user is resizing the window, it slows down the resizing
considerably. Apparently, resizing a large Layered window is an expensive
operation. So, we simply hide the overlays while the window is resized,
and then show them again once the resizing is complete.

The most difficult bit of making the overlay behaves as if it
were part of the `ObjectListView` is when the `ObjectListView` is hidden.
Simply being hidden (i.e. Visible = false) isn't a problem, but hidden
by placing other controls over the top of the `ObjectListView` is a major
problem.

Remember the overlay window is a separate top level window. Changing the
ordering of child windows within another top level window doesn't affect the
overlay window - it thinks it is still directly over the `ObjectListView`. Which
it is, in a way, it's just that other controls are now over the top of the
`ObjectListView`. The overlay window will still be visible, but the
`ObjectListView` will not be, so the overlays will be drawn on top of whatever
controls are over the `ObjectListView`.

If you think putting controls over the top of other control sounds like a
very unlikely scenario, this is exactly how tab controls work. They play with
the z-ordering of their TabPanels, moving the current TabPanel in front of the
other tabs. As currently implemented, `ObjectListView` understand the standard
Window Forms TabControl, and will correctly hide their overlays when a parent
TabControl switches tabs.

But if you are using a non-standard TabControl-like control, you will have to
do this hiding of overlay windows yourself. It is enough to call `HideOverlays()`
at the right time. `ObjectListView` will show their overlays when they are needed.

So, if you find in your app, that a parent control is hiding your `ObjectListView`
(as it should), but you can still see the overlays (when you shouldn't),
you have to call `HideOverlays()` when the `ObjectListView` is hidden.