#if 1

    #include "project.h"

    CONTYPE OVERLAYId = SOB_CONTAINER_NO;

SOBDATA* OVERLAYLastCreated;
SOBFNC_SETVALUE OVERLAY_SOB_Show;
// ---------------------------------

static  myUInt ReSize_OVERLAY(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the OVERLAY CONTAINER

    // We have a number of things to do here:
    //  set the display height and display width of a child
    //  set the display X and displayY of a child with respect to the containers CLIENT area
    //  set the containers minWidth and minHeight

    // ---------------------------------
    // this container template is configured to
    // - have a border
    // - place its children in a simple column

    // ---------------------------------

    // this function / method is triggered by:
    //  1) adding a new child
    //  2) a change in size of a child that is itself a container
    // so we can NOT assume that we know the largest WIDTH or largest HEIGHT of its children

    // in some types of container we might not care about one or the other
    // but we ALWAYS care about atleast one of them ( i.e.  largest WIDTH or largest HEIGHT )

    //  swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.ReSize\n"));  ReportError(txtBuffer);

    // WARNING: by    managed  I mean that atleast one dimension of a child is managed
    // I can think of the following container types
    //     1 row      unmanaged
    //     1 row      with managed height
    //     n rows     with managed height and managed width
    //     1 row      with managed width   // can look ugly. A row of same width but different heights?

    //     1 column    unmanaged
    //     1 column    with managed width
    //     n columns   with managed height and managed width
    //     1 column    with managed height   // can look ugly. A row of different width but same heights?

    // and then we have the each of these with/without a container border
    // the following code can be used of rall of the above E
    // EXCEPT
    //     n rows     with managed height and managed width
    //     n columns   with managed height and managed width
    //
    // the necessary changes are to values

    // ---------------------------------
    // CUSTOMISE THIS     the initialisation value of   ColOrRow
    // 0    for a ROW  orientated container
    // 1    for a COLUMN  orientated container
    // ---------------------------------

    int ColOrRow = 0;

    // ---------------------------------
    // CUSTOMISE THIS     the initialisation value of   setDefault
    // 0    no width/height management
    // 1         manage HEIGHT  if   ColOrRow   selects ROW = 0
    //      or   manage WIDTH  if   ColOrRow   selects COL = 1
    // ---------------------------------

    int useDefault = 0;

    // ---------------------------------

    int WidestChild = 0, HighestChild = 0;
    conData->minWidth = 0;
    conData->minHeight = 0;

    int cnt = 0;

    // ---------------------------------
    SOBDATA* childObject = SOB.GetFirstChild(conData);
    while (childObject)
    {
        cnt++;

        if (childObject->minWidth > WidestChild)     WidestChild = childObject->minWidth;
        if (childObject->minHeight > HighestChild)   HighestChild = childObject->minHeight;

        childObject = SOB.GetNextChild(childObject);
    }
    // ---------------------------------

    conData->minHeight = HighestChild + conData->top + conData->bottom;
    conData->minWidth = WidestChild + conData->left + conData->right;

    // ---------------------------------
    // It took me a long time to sort out containers that have boundaries.
    //
    // If you request a container of says 10 pixels across and 5 pixels down
    // then, IF there is no boundary then that is what you get.
    // No issues!
    //
    //
    // BUT, If you include a boundary in the containers style when calling
    // sob_CreateWindowExNew THEN what happens is:
    //
    // the top and left boundaries, typically of thickness one pixel,
    // are drawn in the top and left edges of the  10 x 5 pixels shape.
    // Is okay.
    // BUT the right and bottom boundaries are drawn AFTER the 10 * 5 pixel area.
    // So the requested 10 x5 shapes occupies   11 x 6 pixels on the screen.
    // AND THEN I want a 1 pixel spacing between the boundaries and the children shape(s).
    // So, if says the area occupied by the children is say 50 x 25 pixels
    // then we must ask the WINDOWsS drawing routines to draw our container as
    //   boundary width + spacing +  50 + spacing
    //      by
    //   boundary width + spacing + 25 + spacing
    //
    // Whilst for our own management / sizing/ positioning purposes the container is
    // seen as being
    //   boundary width + spacing +  50 + spacing + boundary
    //      by
    //   boundary width + spacing + 25 + spacing + boundary

    // ---------------------------------

    conData->minWidth += conData->left + conData->right;
    conData->minHeight += conData->top + conData->bottom;

    // ---------------------------------
    // now set childrens display WIDTH/HEIGHT
    // Ignore any STRETCH effects.
    // Ignore any surround/boundaries.
    // Just set  the width/height of the area that the widget's pixels occupy

    childObject = OVERLAY.FirstChild(conData);
    while (childObject)
    {
        childObject->displayHeight = HighestChild;
        childObject->displayWidth = WidestChild;

        childObject = SOB.GetNextChild(childObject);
    }

    // ---------------------------------
    // now set childrens display POSITIONS
    // of the object in the CLIENT area of the host.
    // So take account of the  sobBnd  values,
    // and of any STRETCHING

    int Xpos = conData->left;
    int Ypos = conData->top;
    int freeWidth = 0, freeHeight = 0;

    cnt = 0;

    childObject = OVERLAY.FirstChild(conData);
    while (childObject)
    {
        // ---------------------------------
        //   child positioning
        // ---------------------------------

        childObject->displayX = Xpos;
        childObject->displayY = Ypos;

        // ---------------------------------
        if (conData->stretchSobData)
        {
            childObject->displayWidth = conData->displayWidth - 2 * (conData->left + conData->right);
            childObject->displayHeight = conData->displayHeight - 2 * (conData->top + conData->bottom);
        }
        // ---------------------------------
        childObject = SOB.GetNextChild(childObject);
    }

    return SOB_OK;
}

// ---------------------------------

CONTAINERINFORM Display_OVERLAY;
static  myUInt Display_OVERLAY(SOBDATA* conData)
{   // conData   = & SOBDATA for the CONTAINER   being displayed

    // typically called by a parent container
    // we should display this container and its SOB children, and trigger any child containers to do the same!

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Display given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return NULLV;
    }
    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Display given a non OVERLAY object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return SOB_NOK;
    }

    //    swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Display\n"));  addText(txtBuffer);

    // ---------------------------------

    ReSize_OVERLAY(conData);

    SOBDATA* childObject = NULL;

    childObject = OVERLAY.FirstChild(conData);
    while (childObject)
    {
        if ((childObject->type EQU SOB_TYPE_CONTAINER) LAND(childObject->pVtbl)   LAND(childObject->pVtbl->UpDateChildren))
        CONTAINER.Display(childObject);
        childObject = SOB.GetNextChild(childObject);
    }

    return SOB_OK;
}

// ---------------------------------

CONTAINERCREATE LastWidget_OVERLAY;
static SOBDATA* LastWidget_OVERLAY()
{
    return  OVERLAYLastCreated;
}

// ---------------------------------

SOBFNC_GETTEXT OVERLAY_SOB_GetTypeText;
static TCHAR* OVERLAY_SOB_GetTypeText(SOBDATA* thisSob)
{
    static TCHAR objType[] = TEXT("OVERLAY");
    return  objType;
}

CONTAINERGETTEXT GetTypeText_OVERLAY;
static  TCHAR* GetTypeText_OVERLAY(SOBDATA* conData)
{

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.GetTypeText given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return NULL;
    }

    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.GetTypeText given a non OVERLAY object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return NULL;
    }

    //  swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.GetTypeText\n"));  addText(txtBuffer);

    return   OVERLAY_SOB_GetTypeText(conData);
}

// ---------------------------------

CONTAINERINFORM  UpDateChildren_OVERLAY;

static  myUInt UpDateChildren_OVERLAY(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the OVERLAY CONTAINER   that is UPDATING it's children

    // ---------------------------------

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.UpDateChildren given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.UpDateChildren given a non OVERLAY object\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    //   swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.UpDateChildren %04i\n"), conData->sIndex)  ;  addText(txtBuffer);

    ReSize_OVERLAY(conData);

    SOBDATA* childObject = NULL;

    childObject = OVERLAY.FirstChild(conData);
    while (childObject)
    {
        if ((childObject->type EQU SOB_TYPE_CONTAINER) LAND(childObject->pVtbl)   LAND(childObject->pVtbl->UpDateChildren))
        CONTAINER.UpDateChildren(childObject);
        childObject = SOB.GetNextChild(childObject);
    }

    return SOB_OK;
}

// ---------------------------------

CONTAINERINFORM  Open_OVERLAY;
static  myUInt Open_OVERLAY(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the OVERLAY CONTAINER   being Opened
    // i.e. made the parent of container of subsequent children

    // ---------------------------------

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Open given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Open given a non OVERLAY object\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    // swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Open\n"));  addText(txtBuffer);

    sob_set_pSobObj(conData);

    return SOB_OK;
}

CONTAINERINFORM  Update_OVERLAY;
static  myUInt Update_OVERLAY(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the OVERLAY CONTAINER   being UPDATED

    // ---------------------------------

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Update given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Update given a non OVERLAY object\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    // swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Update\n" )  );  addText(txtBuffer);

    ReSize_OVERLAY(conData);

    CONTAINER.Update(conData->ppSobData);

    return SOB_OK;
}

// ---------------------------------
CONTAINERINFORM   UpDateParent_OVERLAY;

static  myUInt UpDateParent_OVERLAY(SOBDATA* childObject)
{   // childObject   = address of the SOBDATA of the CHILD object   being added

    // ---------------------------------
    // This is only invoked in the generic function    sob_new_new
    // ---------------------------------

    #if DeveloperMode

        if (fnInvalidSobGeneric(childObject))
        {
            swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.UpDateParent given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
            return SOB_NOK;
        }

        if (childObject->ppSobData->subType NEQU OVERLAYId)
        {
            swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.UpDateParent given a CHILD object belonging to a different container\n"));  ReportError(txtBuffer);
            SOB.Report(childObject);
            return SOB_NOK;
        }

        //  swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.UpDateParent\n"));  addText(txtBuffer);
    #endif

    // ---------------------------------
    childObject->fncCustomShow = OVERLAY_SOB_Show;

    (void)Update_OVERLAY(childObject->ppSobData);

    return SOB_OK;
}
// ---------------------------------
CONTAINERINFORM   Delete_OVERLAY;

static  myUInt Delete_OVERLAY(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the OVERLAY CONTAINER   being DELETED

    // you MUST do checks on the validity of the input
    // Must protect against a "user" trying to delete an already deleted SOB

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Delete given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Delete given a non OVERLAY object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return SOB_NOK;
    }

    //   swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Delete\n"));  addText(txtBuffer);

    // ---------------------------------
    // trigger a delete on each child of the container

    SOBDATA* childObject = OVERLAY.FirstChild(conData);
    while (childObject)
    {
        if (childObject->type EQU SOB_TYPE_CONTAINER)  CONTAINER.Delete(childObject);  // this "child" is itself a container
        else sobObj_delete(childObject);  //  delete the child's  SOBOBJ

        childObject = SOB.GetFirstChild(conData);  // yes   GetFirstChild,   since we just deleted the original FIRST
    }

    // ---------------------------------

    SOBDATA* pDate = conData->ppSobData;  // get the PARENT of this contaner

    sobObj_delete(conData);  //  delete the container's  SOBOBJ

    CONTAINER.Update(pDate); // trigger an update of the PARENT of the container we have deleted

    return SOB_OK;
}
// ---------------------------------

CONTAINERINFORM   DeleteChildren_OVERLAY;
static  myUInt DeleteChildren_OVERLAY(SOBDATA* conData)
{   // conData   = address of the SOBDATA of the   CONTAINER  whose children are to be DELETED

    return CONTAINER.DeleteChildren(conData);
}

// ---------------------------------
CONTAINERGETSOBDATA FirstChild_OVERLAY;
static  SOBDATA* FirstChild_OVERLAY(SOBDATA* conData)
{
    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.FirstChild given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return NULL;
    }

    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.FirstChild given a non OVERLAY object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return NULL;
    }

    return  conData->headLink;
}

// ---------------------------------

CONTAINERSETVALUE Stretch_OVERLAY;
static myUInt Stretch_OVERLAY(SOBDATA* conData, myUInt value)
{   // conData   = address of the SOBDATA of the OVERLAY CONTAINER

    // you MUST do checks on the validity of the input
    // Must protect against a "user" trying to do an action on  deleted SOB

    if (fnInvalidSobGeneric(conData))
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Stretch given an invalid SOBOBJ\n"));  ReportError(txtBuffer);
        return SOB_NOK;
    }

    if (conData->subType NEQU OVERLAYId)
    {
        swprintf_s(txtBuffer, szTxtBuffer, _TEXT("OVERLAY.Stretch given a non OVERLAY object\n"));  ReportError(txtBuffer);
        SOB.Report(conData);
        return SOB_NOK;
    }

    return SOB.SetStretch(conData, value);
}

static myUInt OVERLAY_SOB_Show(SOBDATA* thisObj, myUInt value)
{   // conData   = address of the SOBDATA of the OVERLAY CONTAINER

    SOBDATA* childObject = NULL;
    SOBDATA* pData = thisObj->ppSobData;

    childObject = OVERLAY.FirstChild(pData);
    while (childObject)
    {
        ShowWindow(childObject->hWnd, SW_HIDE);
        childObject->showState = SW_HIDE;
        childObject = SOB.GetNextChild(childObject);
    }
    if (value)
    {
        ShowWindow(thisObj->hWnd, SW_SHOWNORMAL);
        thisObj->showState = SW_SHOWNORMAL;
    }
    //   InvalidateRect((pData)->hWnd, (RECT*)NULL, TRUE);
    TOPWINDOW.Display(TopWindowObj);
    return SOB_OK;
}
// ---------------------------------
CONTAINERCREATE Create_OVERLAY;

static  PVTBL* OVERLAY_get_container_vtbl()
{
    static PVTBL conTable;
    static int  conTableFlag = 0;

    if (!conTableFlag)
    {
        // only need to initialise this table once since it is common to all containers of type   OVERLAY

        conTable.AddChild = UpDateParent_OVERLAY;
        conTable.Update = Update_OVERLAY;
        conTable.Delete = Delete_OVERLAY;
        conTable.Display = Display_OVERLAY;
        conTable.TypeText = GetTypeText_OVERLAY;
        conTable.Stretch = Stretch_OVERLAY;
        conTable.Create = Create_OVERLAY;
        conTable.UpDateChildren = UpDateChildren_OVERLAY;
        conTable.ReSize = ReSize_OVERLAY;
        conTable.Open = Open_OVERLAY;
        conTable.LastWidget = LastWidget_OVERLAY;
        conTable.FirstChild = FirstChild_OVERLAY;
        conTable.DeleteChildren = DeleteChildren_OVERLAY;
        conTableFlag = 1;
    }
    return &conTable;
}

// ----------------------------------------------------------------
// the OVERLAY "constructor" function
// ----------------------------------------------------------------
// some   containers do not need any parameters
// Modify this to suit your needs

static SOBDATA* internalCreate_OVERLAY()
{
    if (!OVERLAYId)   OVERLAYId = int_next_contype();

    int height = 0;
    int width = 0;

    SOBDATA* sData = sob_new_new(SOB_TYPE_CONTAINER, OVERLAYId, width, height);
    if (sData EQU NULL) return NULL;

    // ---------------------------------
    //  special properties that are OVERLAY dependent   and   need to be initialised in the instances data

    // sData->fncCustomDelete;   
    // sData->fncCustomGetTypeText;
    sData->fncCustomGetSubTypeText = OVERLAY_SOB_GetTypeText;
    // sData->fncCustomShow;

    // ---------------------------------

    sData->pVtbl = (MNGR_METHOD_TABLE_GENERIC*)OVERLAY_get_container_vtbl();
    // sData->cVtbl = get_container_ctbl_generic();

    // ---------------------------------

    DWORD objStyle = (WS_CHILD | WS_VISIBLE | 0) BAND ~(WS_HSCROLL | WS_VSCROLL);

    (void)sob_CreateWindowExNew(sData, 0, szWindowClass, _TEXT("  "), objStyle);

    WINDOWINFO myWI = {0};
    myWI.cbSize = sizeof(WINDOWINFO);
    GetWindowInfo(sData->hWnd, &myWI);
    sData->right = sData->bottom = 0;

    sData->left = (short int)abs(myWI.rcClient.left - myWI.rcWindow.left);
    sData->top = (short int)abs(myWI.rcWindow.top - myWI.rcClient.top);

    if (sData->left) sData->right = 1 * sData->left;
    if (sData->top) sData->bottom = 1 * sData->top;

    OVERLAYLastCreated = sData;

    return sData;
}

static  SOBDATA* Create_OVERLAY()
{
    return internalCreate_OVERLAY();
}

// ---------------------------------

PVTBL  OVERLAY =
{
    UpDateParent_OVERLAY
    , Update_OVERLAY
    , Delete_OVERLAY
    , Display_OVERLAY
    , GetTypeText_OVERLAY
    , Stretch_OVERLAY

    , ReSize_OVERLAY
    , UpDateChildren_OVERLAY
    , Open_OVERLAY
    , LastWidget_OVERLAY
    , FirstChild_OVERLAY

    , DeleteChildren_OVERLAY

    , Create_OVERLAY
};

#endif
