'+--------------------------------------------------------------------------+
'|                                  GMAP                                    |
'|                            Alias GDImage MAP                             |
'|                                                                          |
'|         Load large image using the GDImage zoom control feature.         |
'|                                                                          |
'+--------------------------------------------------------------------------+
'|                                                                          |
'|                         Author Patrice TERRIER                           |
'|                                                                          |
'|                           copyright (c) 2011                             |
'|                                                                          |
'|                Patrice Terrier http://www.zapsolution.com                |
'|                                                                          |
'+--------------------------------------------------------------------------+
'|                  Project started on : 05-09-2011 (MM-DD-YYYY)            |
'|                        Last revised : 05-16-2011 (MM-DD-YYYY)            |
'+--------------------------------------------------------------------------+

#COMPILE EXE "GMAP.exe"

#INCLUDE "WIN32API.INC"
#INCLUDE "COMMCTRL.INC"
#INCLUDE "UXTHEME.INC"

'------------------------------------------------------------------------------------------
#RESOURCE "GMAP.pbr"
'------------------------------------------------------------------------------------------
#INCLUDE "gdimage.inc"
'#INCLUDE "TB_XPBUTTON.INC"
'------------------------------------------------------------------------------------------
DECLARE FUNCTION zTrace LIB "zTrace.DLL" ALIAS "zTrace" (zMessage AS ASCIIZ) AS LONG

DECLARE FUNCTION zSpinnerInit LIB "zSpin.dll" ALIAS "zSpinnerInit" (BYVAL hParent AS DWORD, zTmp AS ASCIIZ) AS LONG
DECLARE FUNCTION zSpinnerRunning LIB "zSpin.dll" ALIAS "zSpinnerRunning" () AS LONG
DECLARE SUB zSpinnerClose LIB "zSpin.dll" ALIAS "zSpinnerClose" ()

%ID_THUMB_RECT      = -1  '// Thumb rectangle
%ID_LOGO            = -2  '// Logo

%IDC_GDImageZOOM    = -11 '// Main GDImage ZOOM control         (use negative value to prevent conflict with sprite ID)
%IDC_GDImageTHUMB   = -12 '// Child popup GDImage THUMB control (use negative value to prevent conflict with sprite ID)
%IDC_GDImageCONTACT = -13 '// GDImage contact sheet             (use negative value to prevent conflict with sprite ID)

%IDC_MAP_LIST       = 101 '// MAP listbox
%IDC_ZOOM           = 102 '// Thumb zoom slider
%IDC_SPLIT_TOP      = 103 '// Horizontal splitter
%IDC_SPLIT_BOTTOM   = 104 '// Horizontal splitter

%IDC_PANNEL         = 105
%IDC_COORD_X        = 106
%IDC_COORD_Y        = 107
%IDC_ID             = 108
%IDC_LABEL          = 109
%IDC_ID_COORD_X     = 110
%IDC_ID_COORD_Y     = 111

%ID_LEFT_ARROW      = -9998  '// Contact sheet left arrow
%ID_RIGHT_ARROW     = -9999  '// Contact sheet right arrow
%ID_FirstContact    = -10000 '// Start of contact ID

%CLIENT_WIDTH       = 1024
%CLIENT_HEIGHT      = 768

%ALPHA_MIN          = 85
%ALPHA_STEP         = 15

%CONTACT_TIMER      = 1
%COLORGRAY          = &HC0C0C0

$UP_ARROW           = "t"
$DN_ARROW           = "u"

GLOBAL ghMain, ghTool, ghZoomCtrl, ghThumbCtrl, ghContactCtrl, ghPannel, ghRemoveFocus AS DWORD
GLOBAL gnThumb_xP, gnThumb_yP, gnThumb_xS, gnThumb_yS, gnThumbXpos, gnThumbYpos AS LONG
GLOBAL gnThumbWasXpos, gnThumbWasYpos AS LONG
GLOBAL gnFocusContactID, gnHoverContactID, gnMovingContact, gnHoverContactArrow AS LONG
GLOBAL gsMapPath, gsResPath, gsFileName AS STRING
GLOBAL gnMarlettFont AS LONG

'// Creates a marlett font to display arrow inside of splitter button
FUNCTION MarlettFont() AS LONG

    DIM LF AS LogFont

    LF.lfHeight         = 18
    LF.lfWidth          = 18
    LF.lfCharSet        = 1 '%DEFAULT_CHARSET
    LF.lfOutPrecision   = 6'0 '%OUT_DEFAULT_PRECIS
    LF.lfClipPrecision  = 0 '%OUT_DEFAULT_PRECIS
    LF.lfQuality        = 0 '5'CLEAR_TYPE
    LF.lfPitchAndFamily = 0 '%DEFAULT_PITCH OR %FF_DONTCARE
    LF.lfFaceName = "MARLETT"

    FUNCTION = CreateFontIndirect(LF)
END FUNCTION

FUNCTION WinMain (BYVAL hInstance     AS LONG, _
                  BYVAL hPrevInstance AS LONG, _
                  BYVAL lpCmdLine     AS ASCIIZ PTR, _
                  BYVAL iCmdShow      AS LONG) AS LONG

    LOCAL Msg AS tagMsg
    LOCAL wc AS WndClassEx
    LOCAL zClass, zTitle AS ASCIIZ * 80
    LOCAL rc AS RECT
    LOCAL dwStyle, dwStyleEx, hMutex, hFound, hCtrl AS DWORD
    LOCAL x, y, IsInitialized AS LONG
'
    LOCAl hWinXP_Lib           AS LONG ' Handle to WinXP Theme DLL
    LOCAL hWinXP_IsThemeActive AS LONG ' Handle to WinXP's IsThemeActive function
'
    zClass = "ZOOMPLUS"
'
    hMutex = CreateMutex(BYVAL %Null, 0, zClass)
    IF hMutex THEN
       IF GetLastError = %ERROR_ALREADY_EXISTS THEN
          DO
             hFound = FindWindow(zClass, ""): IF hFound THEN EXIT DO
             WHILE PeekMessage(Msg, %NULL, %NULL, %NULL, %PM_REMOVE): WEND
          LOOP
          IF IsIconic(hFound) THEN CALL ShowWindow(hFound, %SW_RESTORE)
          CALL SetForeGroundWindow(hFound)
          FUNCTION = 0
          EXIT FUNCTION
       END IF
    END IF
'
    wc.cbSize = SIZEOF(wc)
    IsInitialized = GetClassInfoEx(hInstance, zClass, wc)
    IF IsInitialized    = 0 THEN
       wc.cbSize        = SIZEOF(wc)
       wc.style         = %CS_DBLCLKS OR %CS_HREDRAW OR %CS_VREDRAW
       wc.lpfnWndProc   = CODEPTR(WndProc)
       wc.cbClsExtra    = 0
       wc.cbWndExtra    = 0
       wc.hInstance     = hInstance
       wc.hIcon         = LoadIcon(wc.hInstance, "PROGRAM")
       wc.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
       wc.hbrBackground = %NULL ' GetStockObject(%BLACK_BRUSH)
       wc.lpszMenuName  = %NULL
       wc.lpszClassName = VARPTR(zClass)
       wc.hIconSm       = wc.hIcon
       IF RegisterClassEx(wc) THEN IsInitialized = %TRUE
    END IF
'
    IF IsInitialized THEN

       '// Setup global path
       gsMapPath = EXE.Path$ + "Map\" 
       gsResPath = EXE.Path$ + "Resource\"

       '// Load the GDImage.dll
       ZI_LoadDLL("") '// Replace "" with a GDImage private key to unlock the DLL.

       '// Display the loading spinner
       zSpinnerInit(ghMain, gsResPath + "spinner.png")

       '// Window Extended Style
       dwStyleEx = 0
       '// Windows Style
       'dwStyle = %WS_POPUP OR %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN
       dwStyle = %WS_OVERLAPPEDWINDOW OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN

       '// Adjust window to the client size
       CALL SetRect(rc, 0, 0, %CLIENT_WIDTH, %CLIENT_HEIGHT)
       CALL AdjustWindowRectEx(rc, dwStyle, %FALSE, dwStyleEx)

       x = MAX&((GetSystemMetrics(%SM_CXSCREEN) - rc.nRight - rc.nLeft) * 0.5, 0)
       y = MAX&((GetSystemMetrics(%SM_CYSCREEN) - rc.nBottom - rc.nTop) * 0.5, 0)

       '// Create the MAIN window
       zTitle = "GDImageMAP - GDImage " + ZI_Version
       ghMain = CreateWindowEx(dwStyleEx, _           ' Extended Style For The Window
                             zClass, _                ' Class Name
                             zTitle, _                ' Window Title
                             dwStyle, _               ' Defined Window Style
                             x, y, _                  ' Window Position
                             rc.nRight - rc.nLeft, _  ' Calculate Window Width
                             rc.nBottom - rc.nTop, _  ' Calculate Window Height
                             %NULL, _                 ' No Parent Window
                             %NULL, _                 ' No Menu
                             hInstance, _             ' Instance
                             BYVAL %NULL)             ' Dont Pass Anything To WM_CREATE

       IF ghMain THEN

          '// Creates a marlett font to display arrow inside of splitter button
          gnMarlettFont = MarlettFont()

          '// Create child controls
          CreateChildControls(zClass, hInstance)

          '// Add logo to the main GDImage ZoomCtrl
          AddLogo(ghZoomCtrl)

         '// We use a callback to monitor the messages from the GDImage controls
          GDImageEnableEvents()   

          '// Load default image
          gsFileName = gsMapPath + "Europe_satellite.jpg"
          GDImageLoadBackground(gsFileName)
          '// Fill up the MAP listbox and detect the active contact sprite
          gnFocusContactID = GDImageDetectMap(ghMain, hInstance)
          '// Build the contact sheet
          GDImageBuildContactSheet()

          '// Show the main window
          CALL ShowWindow(ghMain, %SW_SHOW)
          CALL ShowWindow(ghTool, %SW_SHOW)
          CALL SetForegroundWindow(ghMain)                  ' Slightly Higher Priority
          CALL SetFocus(ghMain)                             ' Sets Keyboard Focus To The Window

          '// Remove the spinner
          zSpinnerClose()

          CALL SetTimer(ghMain, %CONTACT_TIMER, 40, %NULL)
          WHILE GetMessage(Msg, %NULL, 0, 0)
              IF IsDialogMessage(ghMain, Msg) = %FALSE THEN
                 CALL TranslateMessage(msg)                ' Translate The Message
                 CALL DispatchMessage(msg)                 ' Dispatch The Message
              END IF
          WEND
          CALL KillTimer(ghMain, %CONTACT_TIMER)
          IF gnMarlettFont THEN DeleteObject(gnMarlettFont)

          FUNCTION = msg.wParam
'
       END IF

    END IF
'
    IF hMutex THEN CALL CloseHandle(hMutex)
'
END FUNCTION

SUB GDImageLoadBackground(BYVAL sFileName AS STRING)
    LOCAL rc AS RECT
    LOCAL hCtrl AS DWORD
    IF LEN(sFileName) THEN
       LOCAL xPicSize, yPicSize, hDCsrce, hDCdest, WasCursor AS LONG        

       WasCursor = SetCursor(LoadCursor(%NULL, BYVAL %IDC_WAIT))

       '// Delete any existing sprite object before loading a new set
       ZI_DeleteCtrlObject(ghZoomCtrl)

       '// Add new sprite set
       IF LCASE$(sFileName) = LCASE$(gsMapPath + "Europe_satellite.jpg") THEN AddPushPins(ghZoomCtrl)
       IF LCASE$(sFileName) = LCASE$(gsMapPath + "Marianne_pers.jpg") THEN AddBulb256(ghZoomCtrl)
       IF LCASE$(sFileName) = LCASE$(gsMapPath + "First-floor.jpg") THEN AddVia64(ghZoomCtrl)
       IF LCASE$(sFileName) = LCASE$(gsMapPath + "Perspective.jpg") THEN AddPencil(ghZoomCtrl)

       CALL ZI_SetFromFileEx(ghZoomCtrl, (sFileName), 3000, 3000)

       hDCsrce = ZI_GetDC(ghZoomCtrl)
       IF hDCsrce THEN
          ZI_GetBitmapSize(ZI_GetBitmapFromDC(hDCsrce), xPicSize, yPicSize)

          CALL ZI_SetProperty(ghThumbCtrl, %ZI_GradientTop, %COLORGRAY)
          CALL ZI_SetProperty(ghThumbCtrl, %ZI_GradientBottom, %COLORGRAY)
    
          CALL ZI_SetFromFile(ghThumbCtrl, (sFileName))
          '// Refresh the %IDC_GDImageTHUMB display
          CALL ZI_UpdateWindow(ghThumbCtrl, 0)

          '// Save the thumb coordinates
          GetClientRect(ghThumbCtrl, rc)
          ZI_Iconise(xPicSize, yPicSize, rc.nRight, rc.nBottom, gnThumb_xP, gnThumb_yP, gnThumb_xS, gnThumb_yS)

          LOCAL xP, yP, xS, yS, MinValue, MaxValue AS LONG

          '// Update trackbar bounds based on image size
          CALL GetClientRect(ghZoomCtrl, rc)
          CALL ZI_Iconise(xPicSize, yPicSize, rc.nRight, rc.nBottom, xP, yP, xS, yS)
          hCtrl = GetDlgItem(ghTool, %IDC_ZOOM)
          MinValue = ((xS - 24) / xPicSize) * 1000
          MaxValue = 1000
          CALL SendMessage(hCtrl, %TBM_SETRANGE, %TRUE, MAKLNG(MinValue, MaxValue))
          CALL SendMessage(hCtrl, %TBM_SETPOS, %TRUE, MinValue)

          GDImageDrawThumbRect()

       END IF
       CALL SetCursor(WasCursor)
    END IF
END SUB

SUB GDImageDrawThumbRect()
    LOCAL x, y, w, h, nhBitmap, nZoomWidth, nZoomHeight, nW, nH, nPos AS LONG
    LOCAL rZoomValue, rOldZoomValue, rRatio AS SINGLE
    LOCAL lpr AS RECT

'   // UseThisZoom
    nPos = SendMessage(GetDlgItem(ghTool, %IDC_ZOOM), %TBM_GetPos, 0, 0)
    rOldZoomValue = ZI_GetZoomValue(ghZoomCtrl)
    rZoomValue = nPos / 1000
    CALL ZI_SetZoomValue(ghZoomCtrl, rZoomValue)
    CALL ZI_SetZoomScrollInfo(ghZoomCtrl, rOldZoomValue, rZoomValue)

    'rZoomValue = ZI_GetZoomValue(ghZoomCtrl)
    GetClientRect(ghZoomCtrl, lpr)
    ZI_GetImageSizeFromControl(ghZoomCtrl, nW, nH)

    nZoomWidth = nW * rZoomValue
    nZoomHeight = nH * rZoomValue

    rRatio = gnThumb_xS / nZoomWidth

    x = ZI_GetXscroll(ghZoomCtrl)
    y = ZI_GetYscroll(ghZoomCtrl)
    IF nZoomWidth < lpr.nRight OR nZoomHeight < lpr.nBottom THEN
       IF nZoomWidth < lpr.nRight THEN x -= (lpr.nRight - nZoomWidth) \ 2
       IF nZoomHeight < lpr.nBottom THEN y -= (lpr.nBottom - nZoomHeight) \ 2
    END IF
    x = x * rRatio + gnThumb_xP
    y = y * rRatio + gnThumb_yP
    w = lpr.nRight * rRatio
    h = lpr.nBottom * rRatio

    ZD_GetObjectBound(%ID_THUMB_RECT, nW, nH)
    IF nW <> w OR nH <> h THEN
       '// We build the view-port rectangle
       '// it is made of 2 objects:
       '//   - a solid red frame       nObject(1)
       '//   - a translucent rectangle nObject(2) being used to move the view port around
       REDIM tObject(1 TO 2) AS ZOBJECT
       ZI_CreateRectangleObject(tObject(1), 0, 0, w, h, ZD_ColorARGB(16, RGB(16, 16, 16)), 1, %ZS_VISIBLE, %ZD_DRAW_FILLED, 0)
       ZI_CreateRectangleObject(tObject(2), 0, 0, w, h, ZD_ColorARGB(192, RGB(255, 0, 0)), 1, %ZS_VISIBLE, %ZD_DRAW_OUTLINE, 0)

       nhBitmap = ZI_CreateImageComposited("", w, h, BYVAL VARPTR(tObject(1)), UBOUND(tObject()) - LBOUND(tObject()) + 1)
       IF nhBitmap THEN
          ZD_DrawBitmapToCtrl(ghThumbCtrl, x, y, nhBitmap, ZD_ColorARGB(255, 0), %ID_THUMB_RECT, %ZS_VISIBLE)
          ZI_UpdateWindow(ghThumbCtrl, 0)
       END IF
    ELSE
       ZD_SetObjectXY(%ID_THUMB_RECT, x, y, 1)
    END IF
END SUB

SUB GDImageEnableEvents()
    LOCAL cpCallBack AS DWORD
    cpCallBack = CODEPTR(GDImageCallBack)
    ZI_EventMessage(cpCallBack, %WM_LBUTTONDOWN, %TRUE)
    ZI_EventMessage(cpCallBack, %WM_LBUTTONDBLCLK, %TRUE)
    ZI_EventMessage(cpCallBack, %WM_RBUTTONDOWN, %TRUE)
    ZI_EventMessage(cpCallBack, %WM_KEYDOWN, %TRUE)
    ZI_EventMessage(cpCallBack, %WM_MOUSEMOVE, %TRUE)
    ZI_EventMessage(cpCallBack, %WM_HSCROLL, %TRUE)
    ZI_EventMessage(cpCallBack, %WM_VSCROLL, %TRUE)

    'ZI_EventMessage(cpCallBack, %WM_NCHITTEST, %TRUE)
    'ZI_EventMessage(cpCallBack, %WM_MOUSEWHEEL, %TRUE)
END SUB

FUNCTION GDImageCallBack_Ctrl(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    LOCAL lpr AS RECT
    LOCAL nRet, nObjectID, nState, nStateCount AS LONG
'    LOCAL sNomLabel AS STRING
    LOCAL x, y, x1, y1, ObjectType AS LONG
   
    nObjectID = ZI_MouseOverObjectID()
   
    SELECT CASE LONG Msg
    CASE %WM_LBUTTONDOWN
         IF nObjectID THEN
            IF nObjectID <> %IDC_GDImageZOOM THEN
               LOCAL nSelected AS LONG
               nSelected = ZD_GetObjectSelected(nObjectID)
               IF ZI_IsCtrlKeyPressed() THEN
                  IF nSelected THEN nSelected = 1
'REM                  gSprite[nObjectID].selected = nSelected
               END IF
            ELSE
'REM               IF ZI_IsCtrlKeyPressed() = 0 THEN SpriteClearSelection()        
            END IF
         END IF         
    CASE %WM_LBUTTONDBLCLK
         '// If we have any sprite
         IF ZI_GetCtrlObjectCount(hWnd) AND nObjectID > 0 THEN
            nStateCount = ZD_GetObjectFrameCount(nObjectID)
            IF nStateCount > 1 THEN
               nState = ZD_GetObjectFrameToUse(nObjectID) + 1: IF nState > nStateCount THEN nState = 1 
               ZD_SetObjectFrameToUse(nObjectID, nState, %TRUE)
            END IF
         END IF
        
    CASE %WM_RBUTTONDOWN
        
    CASE %WM_MOUSEMOVE
         IF nObjectID THEN
            IF nObjectID = %IDC_GDImageZOOM THEN
               GDImageDrawThumbRect()
            END IF
         END IF 
   
    CASE %WM_KEYDOWN
         nObjectID = ZI_GetObjectFocusID() '// On récupère l'ID du sprite qui a le focus
         IF nObjectID THEN '// Handle the sprites move
            ZD_GetObjectXY(nObjectID, x, y)
            x1 = x '// Make a copy to preserve original value
            y1 = y '// Make a copy to preserve original value
            '// Check if keyboard accelerator keys are yeld down
            LOCAL UseStep AS LONG
            IF ZI_IsCtrlKeyPressed() THEN
               UseStep = 4
               IF ZI_IsShiftKeyPressed THEN UseStep = 16
            ELSEIF ZI_IsShiftKeyPressed THEN
               UseStep = 2
            ELSE
               UseStep = 1 
            END IF
            LOCAL useWidth, useHeight AS LONG
            '// Does the sprite must move with the background?
            IF ZD_GetObjectScroll(nObjectID) THEN
               '// Get the image background size
               ZI_GetBitmapSize(ZI_GetBMP(ghZoomCtrl), useWidth, useHeight)
            ELSE
               '// Get the client size of the control
               GetClientRect(ghZoomCtrl, lpr)
               useWidth = lpr.nRight: useHeight = lpr.nBottom
            END IF
            LOCAL BoundWidth, BoundHeight AS LONG
            '// Retrieve the sprite's size
            ZD_GetObjectBound(nObjectID, BoundWidth, BoundHeight)
            LOCAL x2Div2, y2Div2 AS LONG 
            x2Div2 = BoundWidth \ 2
            y2Div2 = BoundHeight \ 2
            SELECT CASE LONG wParam
            CASE %VK_HOME
                 x1 = 0
            CASE %VK_END
                 x1 = MAX&(useWidth - BoundWidth, 0)
            CASE %VK_PRIOR
                 y1 = 0
            CASE %VK_NEXT
                 y1 = MAX&(useHeight - BoundHeight, 0)
            CASE %VK_LEFT, %VK_NUMPAD4
                 IF x1 > -x2Div2 THEN x1 = Max&(x1 - UseStep, -x2Div2)
            CASE %VK_UP, %VK_NUMPAD8
                 IF y1 > -y2Div2 THEN y1 = Max&(y1 - UseStep, -y2Div2)
            CASE %VK_RIGHT, %VK_NUMPAD6
                 IF x1 < useWidth - x2Div2 THEN
                    x1 = MIN&(x1 + UseStep, useWidth - x2Div2)
                 END IF
            CASE %VK_DOWN, %VK_NUMPAD2
                 IF y1 < useHeight - y2Div2 THEN
                    y1 = MIN&(y1 + UseStep, useHeight - y2Div2)
                 END IF
            END SELECT
           
            IF x <> x1 OR y <> y1 THEN
               x = x1: y = y1         
               ZD_SetObjectXY(nObjectID, x1, y1, %TRUE)
            END IF
           
         END IF
      
    CASE %WM_VSCROLL, %WM_HSCROLL
         GDImageDrawThumbRect()
      
    END SELECT
   
    FUNCTION = nRet

END FUNCTION

FUNCTION GDImageCallBack_Contact(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    LOCAL hList, nRet, nObjectID, ObjectType AS LONG
    LOCAL sLabelName AS STRING

    STATIC sWasContactLabel AS STRING

    nObjectID = ZI_MouseOverObjectID()

    SELECT CASE LONG Msg
    CASE %WM_LBUTTONDOWN
         IF nObjectID THEN
            IF nObjectID < %ID_RIGHT_ARROW THEN        
               ObjectType = ZD_GetObjectType(nObjectID)
               IF (ObjectType = %OBJECT_BITMAP) OR (ObjectType = %OBJECT_TEXTBITMAP) THEN
                  IF gnFocusContactID <> nObjectID THEN
                     ZD_SetObjectAlpha(gnFocusContactID, %ALPHA_MIN, %FALSE)
                     hList = GetDlgItem(ghMain, %IDC_MAP_LIST)
                     ListSelectPlus(hList, nObjectID)
                     gnFocusContactID = nObjectID
                     ZD_SetObjectAlpha(gnFocusContactID, 255, %TRUE)

                     gsFileName = ListGetText(GetDlgItem(ghMain, %IDC_MAP_LIST), %ID_FirstContact - nObjectID + 1)
                     GDImageLoadBackground(gsFileName)

                  END IF
               END IF
            ELSE
               IF nObjectID = %ID_LEFT_ARROW THEN
                  IF gnMovingContact = 0 THEN
                     MoveContactToTheRight()
                  END IF
               ELSEIF nObjectID = %ID_RIGHT_ARROW THEN  
                  IF gnMovingContact = 0 THEN
                     MoveContactToTheLeft()
                  END IF
               END IF
            END IF
         END IF    
    CASE %WM_LBUTTONUP
      
    CASE %WM_MOUSEMOVE
         IF nObjectID < %ID_RIGHT_ARROW THEN
            IF gnHoverContactID <> nObjectID THEN
               gnHoverContactID = nObjectID
              
               '// Tooltip hover image
               sLabelName = ZD_GetObjectImageLabel(nObjectID)
               '// Tooltip hover image
               IF sLabelName <> sWasContactLabel THEN
                  ZI_SetToolTipText(ghContactCtrl, (sLabelName))
               END IF
               sWasContactLabel = sLabelName 
              
            END IF   
         ELSE
            '// Clear the tooltip
            sWasContactLabel = "": ZI_SetToolTipText(ghContactCtrl, (sWasContactLabel))
                
            gnHoverContactID = 0
            IF nObjectID = %ID_LEFT_ARROW THEN
               IF gnHoverContactArrow = 0 THEN
                  gnHoverContactArrow = -1
                  MoveContactLeftRight(1)
               END IF
            ELSEIF nObjectID = %ID_RIGHT_ARROW THEN
               IF gnHoverContactArrow = 0 THEN
                  gnHoverContactArrow = -1
                  MoveContactLeftRight(-1)
               END IF
            END IF
         END IF
    END SELECT

    hWnd = 0: wParam =0: lParam = 0
    FUNCTION = nRet
END FUNCTION

FUNCTION GDImageCallBack_Thumb(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    LOCAL nRet, nID AS LONG
    
    nID = ZI_MouseOverObjectID()

    IF nID <> GetDlgCtrlID(hWnd) THEN '// We must be hover the red rectangle
     
       LOCAL x, y, w, h, nW, nH, dx, dy, nX, nY, lpX, lpY AS LONG
       DIM sif AS SCROLLINFO
       LOCAL nZoomWidth, nZoomHeight AS LONG
       LOCAL rThumbRatio, rRatio, rZoomValue AS SINGLE
       rZoomValue = ZI_GetZoomValue(ghZoomCtrl)
       
       LOCAL lpr AS RECT
       GetClientRect(ghZoomCtrl, lpr)
       
       ZI_GetImageSizeFromControl(ghZoomCtrl, nW, nH)
       
       IF gnThumb_xS <> 0 THEN rRatio = (nW * rZoomValue) / gnThumb_xS  


       SELECT CASE LONG Msg
       
       CASE %WM_LBUTTONDOWN
           
       CASE %WM_MOUSEMOVE     
            IF ZI_IsLButtonDown() THEN
               '// Get the sprite size
               ZD_GetObjectBound(nID, w, h)
                 
               '// Mouse coordinates
               lpX = LO(INTEGER, lParam): lpY = HI(INTEGER, lParam)
               '// Coordonnées XY au moment du clic gauche qui débute le déplacement.
               ZD_GetObjectXYcapture(nID, nx, ny)
               x = lpX - nx: y = lpY - nY
                 
               '// Adjust the coordinates to stay inside of the zoomed image bounds
               nZoomWidth = nW * rZoomValue: nZoomHeight = nH * rZoomValue
               dx = 0: dy = 0
               IF nZoomWidth < lpr.nRight OR nZoomHeight < lpr.nBottom THEN
                  rThumbRatio = gnThumb_xS / nZoomWidth
                  IF nZoomWidth < lpr.nRight THEN dx = ((lpr.nRight - nZoomWidth) \ 2) * rThumbRatio
                  IF nZoomHeight < lpr.nBottom THEN dy = ((lpr.nBottom - nZoomHeight) \ 2) * rThumbRatio
               END IF
               IF x < gnThumb_xP - dx THEN
                  x = gnThumb_xP - dx
               ELSEIF x > gnThumb_xP + gnThumb_xS - w + dx THEN
                  x = gnThumb_xP + gnThumb_xS - w + dx
               END IF
               IF y < gnThumb_yP - dy THEN
                  y = gnThumb_yP - dy 
               ELSEIF y > gnThumb_yP + gnThumb_yS - h + dy THEN
                  y = gnThumb_yP + gnThumb_yS - h + dy
               END IF
               '// Retrieve the previous coordinates
               ZD_GetObjectXY(nID, nX, nY)       
               nX = x - nX: nY = y - nY
               IF nX OR NY THEN
                  sif.cbSize = SIZEOF(sif)
                  sif.fMask  = %SIF_ALL
                  IF nX THEN
                     GetScrollInfo(ghZoomCtrl, %SB_HORZ, sif)
                     sif.nPos += nX * rRatio
                     SetScrollInfo(ghZoomCtrl, %SB_HORZ, sif, %TRUE)
                     SendMessage(ghZoomCtrl, %WM_HSCROLL, MAKLNG(%SB_HORZ, 0), 0)
                  END IF
                  IF nY THEN    
                     GetScrollInfo(ghZoomCtrl, %SB_VERT, sif)
                     sif.nPos += nY * rRatio
                     SetScrollInfo(ghZoomCtrl, %SB_VERT, sif, %TRUE)
                     SendMessage(ghZoomCtrl, %WM_VSCROLL, MAKLNG(%SB_VERT, 0), 0)
                  END IF
               END IF
               '// Apply new coordinates
               ZD_SetObjectXY(nID, x, y, 0)
               GDImageDrawThumbRect()
               nRet = 1

            END IF

       CASE %WM_KEYDOWN
            '// Check if keyboard accelerator keys are yeld down
            LOCAL UseStep AS LONG
            IF ZI_IsCtrlKeyPressed() THEN
               UseStep = 4
               IF ZI_IsShiftKeyPressed THEN UseStep = 16
            ELSEIF ZI_IsShiftKeyPressed THEN
               UseStep = 2
            ELSE
               UseStep = 1 
            END IF
            ZD_GetObjectXY(nID, x, y)
            '// Get the sprite size
            ZD_GetObjectBound(nID, w, h)
           
            SELECT CASE LONG wParam
            CASE %VK_HOME, %VK_NUMPAD7
                 x = gnThumb_xP
            CASE %VK_END, %VK_NUMPAD1
                 x = gnThumb_xP + gnThumb_xS - w
            CASE %VK_PRIOR, %VK_NUMPAD9
                 y = gnThumb_yP
            CASE %VK_NEXT, %VK_NUMPAD3
                 y = gnThumb_yP + gnThumb_yS - h
            CASE %VK_LEFT, %VK_NUMPAD4
                 x -= UseStep
            CASE %VK_UP, %VK_NUMPAD8
                 y -= UseStep
            CASE %VK_RIGHT, %VK_NUMPAD6
                 x += UseStep
            CASE %VK_DOWN, %VK_NUMPAD2
                 y += UseStep
            END SELECT
            '// Adjust the coordinates to stay inside of the zoomed image bounds
            nZoomWidth = nW * rZoomValue: nZoomHeight = nH * rZoomValue
            dx = 0: dy = 0
            IF nZoomWidth < lpr.nRight OR nZoomHeight < lpr.nBottom THEN
               rThumbRatio = gnThumb_xS / nZoomWidth
               IF nZoomWidth < lpr.nRight THEN dx = ((lpr.nRight - nZoomWidth) \ 2) * rThumbRatio
               IF nZoomHeight < lpr.nBottom THEN dy = ((lpr.nBottom - nZoomHeight) \ 2) * rThumbRatio
            END IF
            IF x < gnThumb_xP - dx THEN
               x = gnThumb_xP - dx
            ELSEIF x > gnThumb_xP + gnThumb_xS - w + dx THEN
               x = gnThumb_xP + gnThumb_xS - w + dx
            END IF
            IF y < gnThumb_yP - dy THEN
               y = gnThumb_yP - dy 
            ELSEIF y > gnThumb_yP + gnThumb_yS - h + dy THEN
               y = gnThumb_yP + gnThumb_yS - h + dy
            END IF
            '// Retrieve the previous coordinates
            ZD_GetObjectXY(nID, nX, nY)       
            nX = x - nX: nY = y - nY
            IF nX OR nY THEN
               sif.cbSize = SIZEOF(sif)
               sif.fMask  = %SIF_ALL
               IF nX THEN
                  GetScrollInfo(ghZoomCtrl, %SB_HORZ, sif)
                  sif.nPos += nX * rRatio
                  SetScrollInfo(ghZoomCtrl, %SB_HORZ, sif, %TRUE)
                  SendMessage(ghZoomCtrl, %WM_HSCROLL, MAKLNG(%SB_HORZ, 0), 0)
               END IF
               IF nY THEN    
                  GetScrollInfo(ghZoomCtrl, %SB_VERT, sif)
                  sif.nPos += nY * rRatio
                  SetScrollInfo(ghZoomCtrl, %SB_VERT, sif, %TRUE)
                  SendMessage(ghZoomCtrl, %WM_VSCROLL, MAKLNG(%SB_VERT, 0), 0)
               END IF
            END IF
            '// Apply the new coordinates
            ZD_SetObjectXY(nID, x, y, 0)
            GDImageDrawThumbRect()
            nRet = 1

       END SELECT
    ELSE
       SELECT CASE LONG Msg
       CASE %WM_VSCROLL, %WM_HSCROLL
            GDImageDrawThumbRect()
       END SELECT
    END IF
    FUNCTION = nRet

END FUNCTION

FUNCTION GDImageCallBack(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    LOCAL nObjectID, nCtrlID, nRet AS LONG

    IF Msg = %WM_MOUSEMOVE THEN

       LOCAL lp AS POINTAPI
       GetCursorPos(lp)
       hWnd = WindowFromPoint(lp.X, lp.Y)
       IF hWnd = ghZoomCtrl THEN
          ScreenToClient(ghZoomCtrl, lp)
          GDImageDisplayMouseXY(ghZoomCtrl, LO(INTEGER, lParam), HI(INTEGER, lParam))

          LOCAL sNomLabel AS STRING
          STATIC sWasCtrlLabel AS STRING
          '// Get the sprite mousehover ID 
          nObjectID = ZI_MouseOverObjectID() 
          sNomLabel = ZD_GetObjectImageLabel(nObjectID)
          '// Display the object tooltip. 
          IF sNomLabel <> sWasCtrlLabel THEN
'REM               ZI_SetToolTipText(hWnd, sNomLabel)
             SetWindowText(GetDlgItem(ghPannel, %IDC_LABEL), (sNomLabel))
             IF nObjectID = %IDC_GDImageZOOM THEN
                SetWindowText(GetDlgItem(ghPannel, %IDC_ID), "")
                SetWindowText(GetDlgItem(ghPannel, %IDC_ID_COORD_X), "")
                SetWindowText(GetDlgItem(ghPannel, %IDC_ID_COORD_Y), "")
             ELSE
                SetWindowText(GetDlgItem(ghPannel, %IDC_ID), STR$(nObjectID))
                LOCAL nX, nY AS LONG
                ZD_GetObjectXY(nObjectID, nX, nY)
                SetWindowText(GetDlgItem(ghPannel, %IDC_ID_COORD_X), STR$(nX) + " ")
                SetWindowText(GetDlgItem(ghPannel, %IDC_ID_COORD_Y), STR$(nY))
            END IF  
          END IF
          sWasCtrlLabel = sNomLabel
       END IF
       nCtrlID = GetDlgCtrlID(hWnd)

    ELSE

       nObjectID = ZI_GetObjectFocusID()
       IF nObjectID THEN
          '// Make sure that the active GDImage control is the parent of the object that has the focus.
          '// nCtrlID doit correspondre au contrôle GDImage qui est le parent de l'objet qui a le focus. 
          nCtrlID = GetDlgCtrlID(ZD_GetObjectParent(nObjectID))
       ELSE
          nCtrlID = GetDlgCtrlID(hWnd)
       END IF

    END IF


    IF nCtrlID = %IDC_GDImageZOOM THEN
       nRet = GDImageCallBack_Ctrl(hWnd, Msg, wParam, lParam)
    ELSEIF nCtrlID = %IDC_GDImageCONTACT THEN
       nRet = GDImageCallBack_Contact(hWnd, Msg, wParam, lParam)
    ELSE
       nRet = GDImageCallBack_Thumb(hWnd, Msg, wParam, lParam)
    END IF

    FUNCTION = nRet

END FUNCTION

FUNCTION CheckWindowExStyle(BYVAL hWnd AS LONG, BYVAL nStyle AS LONG) AS LONG
    IF (GetWindowLong(hWnd, %GWL_EXSTYLE) AND nStyle) = nStyle THEN FUNCTION = -1
END FUNCTION

FUNCTION zGetCTLText(BYVAL hCtrl AS LONG) AS STRING
    LOCAL szText AS ASCIIZ * 4096, Length AS LONG
    Length = GetWindowText(hCtrl, szText, SIZEOF(szText))
    IF Length THEN FUNCTION = LEFT$(szText, Length)
END FUNCTION

FUNCTION WndProc(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    LOCAL ps AS PAINTSTRUCT
    LOCAL lpr, rc AS RECT
    LOCAL lp AS POINTAPI
    LOCAL Orientation, Img, ImgW, ImgH, WasCursor AS LONG

    STATIC hStaticBrush AS DWORD

    SELECT CASE Msg

    CASE %WM_CREATE

    CASE %WM_MOUSEMOVE

         IF ZI_IsLButtonDown() AND hWnd = ghTool THEN
            '// Use the low level API to Move the window form
            CALL SendMessage(hWnd, %WM_NCLBUTTONDOWN, %HTCAPTION, 0)
         END IF
         
    CASE %WM_GETMINMAXINFO 'Set minimum and naximum dialog size
         LOCAL MinMax AS MINMAXINFO PTR
         MinMax = lParam
       ' Window Extended Style
         dwStyleEx& = %WS_EX_APPWINDOW OR %WS_EX_WINDOWEDGE
       ' Windows Style
         dwStyle& = %WS_OVERLAPPEDWINDOW
         CALL SetRect(rc, 0, 0, %CLIENT_WIDTH, %CLIENT_HEIGHT)
         CALL AdjustWindowRectEx(rc, dwStyle&, %FALSE, dwStyleEx&) ' Adjust Window To True Requested Size
         @MinMax.ptMinTrackSize.x = rc.nRight - rc.nLeft
         @MinMax.ptMinTrackSize.y = rc.nBottom - rc.nTop
         FUNCTION = 0: EXIT FUNCTION

'    CASE %WM_CTLCOLORBTN
'         CALL SetBkMode(wParam, %TRANSPARENT)
'         FUNCTION = GetStockObject(%NULL_BRUSH)
'         EXIT FUNCTION

    CASE %WM_CTLCOLORSTATIC
         IF GetDlgCtrlID(lParam) = 0 THEN
            CALL SetTextColor(wParam, RGB(92,92,92))
            CALL SetBkMode(wParam, %TRANSPARENT)
            IF hStaticBrush = 0 THEN hStaticBrush = CreateSolidBrush(RGB(224,223,227))
            FUNCTION = hStaticBrush
            EXIT FUNCTION
         END IF

    CASE %WM_VSCROLL, %WM_HSCROLL
         IF lParam = GetDlgItem(ghTool, %IDC_ZOOM) THEN
            wP& = LOWRD(wParam)
            IF (wP& > %SB_LINEUP - 1) AND (wP& < %SB_ENDSCROLL + 1) THEN
                GDImageDrawThumbRect()
                FUNCTION = 0: EXIT FUNCTION
            END IF
         END IF
         
    CASE %WM_COMMAND
         SELECT CASE LONG LOWRD(wParam)
         CASE %IDC_SPLIT_TOP
              IF zGetCTLText(lParam) = $UP_ARROW THEN
                 SetWindowText(lParam, $DN_ARROW)
                 ShowWindow(ghContactCtrl, %SW_HIDE)
                 GetClientRect(lParam, rc)
                 MoveWindow(lParam, 0, 0, rc.nRight, rc.nBottom, 1)
                 ZI_SetAnchorMode(lParam, %ANCHOR_WIDTH)

                 GetWindowRect(ghZoomCtrl, lpr)
                 lp.x = lpr.nLeft: lp.y = lpr.nTop
                 ScreenToClient(ghMain, lp)
                 lp.y = rc.nBottom
                 GetClientRect(ghContactCtrl, rc)
                 MoveWindow(ghZoomCtrl, lp.x, lp.y, lpr.nRight - lpr.nLeft, lpr.nBottom - lpr.nTop + rc.nBottom, 1)
                 ZI_SetAnchorMode(ghZoomCtrl, %ANCHOR_HEIGHT_WIDTH)

              ELSE

                 GetWindowRect(ghZoomCtrl, lpr)
                 lp.x = lpr.nLeft: lp.y = lpr.nTop
                 ScreenToClient(ghMain, lp)
                 GetClientRect(ghContactCtrl, rc)
                 lp.y += rc.nBottom
                 MoveWindow(ghZoomCtrl, lp.x, lp.y, lpr.nRight - lpr.nLeft, lpr.nBottom - lpr.nTop - rc.nBottom, 1)
                 ZI_SetAnchorMode(ghZoomCtrl, %ANCHOR_HEIGHT_WIDTH)

                 SetWindowText(lParam, $UP_ARROW)
                 GetClientRect(ghContactCtrl, lpr)
                 GetClientRect(lParam, rc)
                 MoveWindow(lParam, 0, lpr.nBottom, rc.nRight, rc.nBottom, 1)
                 ZI_SetAnchorMode(lParam, %ANCHOR_WIDTH)
                 ShowWindow(ghContactCtrl, %SW_SHOW)

              END IF
              SetFocus(ghRemoveFocus)
              GDImageDrawThumbRect()

         CASE %IDC_SPLIT_BOTTOM
              IF zGetCTLText(lParam) = $DN_ARROW THEN
                 SetWindowText(lParam, $UP_ARROW)
                 ShowWindow(ghPannel, %SW_HIDE)
                 GetClientRect(ghMain, lpr)
                 GetClientRect(lParam, rc)
                 MoveWindow(lParam, 0, lpr.nBottom - rc.nBottom, rc.nRight, rc.nBottom, 1)
                 ZI_SetAnchorMode(lParam, %ANCHOR_BOTTOM_WIDTH)

                 GetWindowRect(ghZoomCtrl, lpr)
                 lp.x = lpr.nLeft: lp.y = lpr.nTop
                 ScreenToClient(ghMain, lp)
                 GetClientRect(ghPannel, rc)
                 MoveWindow(ghZoomCtrl, lp.x, lp.y, lpr.nRight - lpr.nLeft, lpr.nBottom - lpr.nTop + rc.nBottom, 1)
                 ZI_SetAnchorMode(ghZoomCtrl, %ANCHOR_HEIGHT_WIDTH)

              ELSE

                 GetWindowRect(ghZoomCtrl, lpr)
                 lp.x = lpr.nLeft: lp.y = lpr.nTop
                 ScreenToClient(ghMain, lp)
                 GetClientRect(ghPannel, rc)
                 MoveWindow(ghZoomCtrl, lp.x, lp.y, lpr.nRight - lpr.nLeft, lpr.nBottom - lpr.nTop - rc.nBottom, 1)
                 ZI_SetAnchorMode(ghZoomCtrl, %ANCHOR_HEIGHT_WIDTH)

                 SetWindowText(lParam, $DN_ARROW)
                 GetClientRect(ghMain, lpr)
                 GetClientRect(ghPannel, rc): lpr.nBottom -= rc.nBottom
                 GetClientRect(lParam, rc)
                 MoveWindow(lParam, 0, lpr.nBottom - rc.nBottom, rc.nRight, rc.nBottom, 1)
                 ZI_SetAnchorMode(lParam, %ANCHOR_BOTTOM_WIDTH)
                 ShowWindow(ghPannel, %SW_SHOW)

              END IF
              SetFocus(ghRemoveFocus)
              GDImageDrawThumbRect()

         END SELECT

    CASE %WM_TIMER
         IF wParam = %CONTACT_TIMER THEN
            RenderAnimation()
            FUNCTION = 0: EXIT FUNCTION
         END IF

    CASE %WM_MOVE
         IF hWnd = ghTool THEN 
            GDImageThumbMoved()
         ELSE
            GDImageResize(0)
         END IF
         
    CASE %WM_SIZE
         GDImageResize(10 + wParam)

    CASE %WM_ERASEBKGND
         CALL GetClientRect(hWnd, rc)
         CALL ZI_GradientPaintDC(wParam, 0, 0, rc.nRight, rc.nBottom, RGB(224,223,227), RGB(224,223,227))
         FUNCTION = 1: EXIT FUNCTION

'   CASE %WM_PAINT
'        FUNCTION = 0: EXIT FUNCTION

'   CASE %WM_CLOSE

    CASE %WM_DESTROY
         IF hStaticBrush THEN DeleteObject(hStaticBrush)
         CALL PostQuitMessage(0)
         FUNCTION = 0: EXIT FUNCTION
    END SELECT

    FUNCTION = DefWindowProc(hWnd, Msg, wParam, lParam)

END FUNCTION

SUB GDImageDisplayMouseXY(BYVAL hWnd AS LONG, BYVAL x AS LONG, BYVAL y AS LONG)
    LOCAL rZoomValue AS SINGLE
    LOCAL zTxt AS ASCIIZ * 16
    LOCAL lpr AS RECT
    LOCAL nW, nH, ZoomW, ZoomH, xOffset, yOffset, xCurrentScroll, yCurrentScroll AS LONG

    '// Get current Zoom value
    rZoomValue = ZI_GetZoomValue(hWnd)
    '// Retrieve the size of the memory bitmap
    ZI_GetImageSizeFromControl(hWnd, nW, nH)      
    '// Get the client size of the control
    GetClientRect(hWnd, lpr)
    '// Compute x,y offset
    ZoomW = nW * rZoomValue
    ZoomH = nH * rZoomValue
    xOffset = 0: yOffset = 0
    IF ZoomW < lpr.nRight OR ZoomH < lpr.nBottom THEN
       IF ZoomW < lpr.nRight THEN xOffset = (lpr.nRight - ZoomW) \ 2
       IF ZoomH < lpr.nBottom THEN yOffset = (lpr.nBottom - ZoomH) \ 2
    END IF
    '// Retrieve scroll values
    xCurrentScroll = ZI_GetXscroll(hWnd)
    yCurrentScroll = ZI_GetYscroll(hWnd)
    '// Show mouse coordinates
    CALL SetWindowText(GetDlgItem(ghPannel, %IDC_COORD_X), STR$(CLNG((x + xCurrentScroll - xOffset) / rZoomValue)) + " ")
    CALL SetWindowText(GetDlgItem(ghPannel, %IDC_COORD_Y), STR$(CLNG((y + yCurrentScroll - yOffset) / rZoomValue)))
END SUB

SUB GDImageThumbMoved()
    '// This procedure is called to update the global gnThumbXpos and gnThumbYpos
    '// once the Thumb window has been moved. 
    LOCAL lpr, rc AS RECT
    GetWindowRect(ghTool, lpr)
    GetWindowRect(ghZoomCtrl, rc)
    gnThumbXpos = lpr.nLeft - rc.nLeft
    gnThumbYpos = lpr.nTop - rc.nTop
END SUB

SUB GDImageResize(BYVAL wParam AS LONG)
    LOCAL lpr, rc AS RECT, nX, nY AS LONG

    GetWindowRect(ghTool, lpr)
    GetWindowRect(ghZoomCtrl, rc)

    IF wParam = 10 + %SIZE_MAXIMIZED THEN
       nX = rc.nLeft
       nY = rc.nTop
    ELSE
       nX = rc.nLeft + gnThumbXpos
       nY = MAX&(rc.nTop + gnThumbYpos, rc.nTop)
    END IF
    MoveWindow(ghTool, nX, nY, lpr.nRight - lpr.nLeft, lpr.nBottom - lpr.nTop, 1)

    IF wParam THEN
       ZI_UpdateWindow(ghZoomCtrl, 0)
    END IF
    GDImageShowContactArrow()

END SUB

FUNCTION CreateControl(BYVAL dwStyleEx AS DWORD, _
                       zClass AS ASCIIZ, zCaption AS ASCIIZ, BYVAL dwStyle AS DWORD, _
                       BYVAL x AS LONG, BYVAL y AS LONG, BYVAL w AS LONG, BYVAL h AS LONG, _
                       BYVAL nParent AS DWORD, BYVAL nID AS LONG, BYVAL nInstance AS DWORD, _
                       BYVAL Anchor AS LONG) AS DWORD
    LOCAL hCtrl AS DWORD
    hCtrl = CreateWindowEx(dwStyleEx, zClass, zCaption, dwStyle, x, y, w, h, nParent, nID, nInstance, BYVAL 0)
    IF hCtrl THEN
       CALL SendMessage(hCtrl, %WM_SETFONT, GetStockObject(%ANSI_VAR_FONT), 0)
       CALL ZI_SetAnchorMode(hCtrl, Anchor)
    END IF
    FUNCTION = hCtrl
END FUNCTION

SUB CreateChildControls(zClass AS ASCIIZ, BYVAL hInstance AS LONG)
    LOCAL dwStyle, dwStyleEx, hCtrl AS DWORD
    LOCAL rc AS RECT

    ghRemoveFocus = CreateControl(0, "BUTTON", "", %WS_CHILD, 0, 0, 0, 0, ghMain, 0, hInstance, 0)

    '// ******************************************************************************
    '// Create the main GDImage contact sheet control
    dwStyle = %WS_CHILD OR %WS_VISIBLE
    ghContactCtrl = CreateControl(0, $GDImageClassName, "", dwStyle, 0, 0, %CLIENT_WIDTH, 128, ghMain, %IDC_GDImageCONTACT, hInstance, %ANCHOR_WIDTH)
    '// Gradiant color to paint the background
    ZI_SetProperty(ghContactCtrl, %ZI_GradientTop, %COLORGRAY)
    ZI_SetProperty(ghContactCtrl, %ZI_GradientBottom, %COLORGRAY)
    '// Add tooltip support to the GDImage contact sheet.
    ZI_CreateToolTip(ghContactCtrl, "") 

    '// =============================================================================
    '// Splitter top buton
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_TABSTOP
    hCtrl = CreateControl(0, "BUTTON", $UP_ARROW, dwStyle, 0, 128, %CLIENT_WIDTH, 9 + 3, ghMain, %IDC_SPLIT_TOP, hInstance, %ANCHOR_WIDTH)
    SendMessage(hCtrl, %WM_SETFONT, gnMarlettFont, 0)

    '// ******************************************************************************
    '// Create the main GDImage ZoomPlus control
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %WS_HSCROLL OR %WS_VSCROLL
    ghZoomCtrl = CreateControl(0, $GDImageClassName, "", dwStyle, 0, 128 + 9 + 3, %CLIENT_WIDTH, 574 - 3, ghMain, %IDC_GDImageZOOM, hInstance, %ANCHOR_HEIGHT_WIDTH)
    '// Don't forget to make it a ZOOM window !
    CALL ZI_SetProperty(ghZoomCtrl, %ZI_ZoomWindow, %TRUE)
    '// Gradiant color to paint the background
    CALL ZI_SetProperty(ghZoomCtrl, %ZI_GradientTop, %COLORGRAY)
    CALL ZI_SetProperty(ghZoomCtrl, %ZI_GradientBottom, %COLORGRAY)

    '// ******************************************************************************
    '// Create the GDImage ToolWindow control
    GetWindowRect(ghZoomCtrl, rc)
    dwStyle = %WS_POPUP OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN OR %WS_BORDER 'OR %WS_CAPTION
    dwStyleEx = %WS_EX_TOOLWINDOW
    ghTool = CreateControl(dwStyleEx, zClass, "", dwStyle, rc.nLeft, rc.nTop, 164, 205, ghMain, 0, hInstance, 0)

    '// ******************************************************************************
    '// Create the GDImage ToolWindow Thumb control
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER
    ghThumbCtrl = CreateControl(0, $GDImageClassName, "", dwStyle, 1, 22, 160, 160, ghTool, %IDC_GDImageTHUMB, hInstance, 0) 
    '// This is a fit to window control
    CALL ZI_SetProperty(ghThumbCtrl, %ZI_FitToWindow, 1)

    '// ******************************************************************************
    '// Create the zoom trackbar
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %TBS_BOTH OR %TBS_HORZ OR %TBS_NOTICKS OR %WS_TABSTOP
    hCtrl = CreateControl(0, "msctls_trackbar32", "", dwStyle, 1, 185, 160, 16, ghTool, %IDC_ZOOM, hInstance, 0)
    CALL SendMessage(hCtrl, %TBM_SETRANGE, %TRUE, MAKLNG(194, 1020))
    CALL SendMessage(hCtrl, %TBM_SETPAGESIZE, 0, 5)
    '// Setup zoom default
    CALL SendMessage(hCtrl, %TBM_SETPOS, %TRUE, 195)

    '// =============================================================================
    '// Splitter bottom buton
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_TABSTOP ' window styles
    hCtrl = CreateControl(0, "BUTTON", $DN_ARROW, dwStyle, 0, 711, %CLIENT_WIDTH, 9 + 3, ghMain, %IDC_SPLIT_BOTTOM, hInstance, %ANCHOR_BOTTOM_WIDTH)
    SendMessage(hCtrl, %WM_SETFONT, gnMarlettFont, 0)

    '// ******************************************************************************
    '// Bottom pannel container
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %WS_CLIPCHILDREN
    ghPannel = CreateControl(0, zClass, "", dwStyle, 0, 723, %CLIENT_WIDTH, %CLIENT_HEIGHT - 723, ghMain, %IDC_PANNEL, hInstance, %ANCHOR_BOTTOM_WIDTH)

    '// ******************************************************************************
    '// Mouse coordinates
    dwStyle = %WS_CHILD OR %WS_VISIBLE
    CreateControl(0, "STATIC", "X.Y", dwStyle, 100, 15, 20, 16, ghPannel, 0, hInstance, %ANCHOR_BOTTOM)
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER
    CreateControl(0, "STATIC", "", dwStyle OR %SS_RIGHT, 120, 14, 44, 16, ghPannel, %IDC_COORD_X, hInstance, %ANCHOR_BOTTOM)
    CreateControl(0, "STATIC", "", dwStyle, 165, 14, 44, 16, ghPannel, %IDC_COORD_Y, hInstance, %ANCHOR_BOTTOM)

    '// ******************************************************************************
    '// Sprite ID and LABEL
    dwStyle = %WS_CHILD OR %WS_VISIBLE
    CreateControl(0, "STATIC", "ID", dwStyle, 222, 15, 14, 16, ghPannel, 0, hInstance, %ANCHOR_BOTTOM)
    dwStyle = %WS_CHILD OR %WS_VISIBLE OR %ES_READONLY OR %WS_BORDER
    CreateControl(0, "STATIC", "", dwStyle, 236, 14, 44, 16, ghPannel, %IDC_ID, hInstance, %ANCHOR_BOTTOM)
    CreateControl(0, "STATIC", "", dwStyle, 281, 14, 300, 16, ghPannel, %IDC_LABEL, hInstance, %ANCHOR_BOTTOM)

    '// ******************************************************************************
    '// Sprite coordinates
    dwStyle = %WS_CHILD OR %WS_VISIBLE
    CreateControl(0, "STATIC", "X.Y", dwStyle, 584, 15, 20, 16, ghPannel, 0, hInstance, %ANCHOR_BOTTOM)
    dwStyle =  %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER
    CreateControl(0, "STATIC", "", dwStyle OR %SS_RIGHT, 604, 14, 44, 16, ghPannel, %IDC_ID_COORD_X, hInstance, %ANCHOR_BOTTOM)
    CreateControl(0, "STATIC", "", dwStyle, 649, 14, 44, 16, ghPannel, %IDC_ID_COORD_Y, hInstance, %ANCHOR_BOTTOM)
 
END SUB

SUB ListDeleteAll(BYVAL hList AS LONG)
    IF hList THEN CALL SendMessage(hList, %LB_RESETCONTENT, 0, 0)
END SUB

FUNCTION ListAdd(BYVAL hList AS LONG, zTmp AS ASCIIZ) AS LONG
    IF hList THEN
       IF LEN(zTmp) THEN FUNCTION = SendMessage(hList, %LB_ADDSTRING, 0, VARPTR(zTmp))
    END IF
END FUNCTION

FUNCTION ListFindString(BYVAL hList AS LONG, zTmp AS ASCIIZ) AS LONG
    LOCAL nIndex AS LONG
    nIndex = SendMessage(hList, %LB_FINDSTRING, -1, VARPTR(zTmp))
    IF nIndex > -1 THEN INCR nIndex: FUNCTION = nIndex
END FUNCTION

SUB ListSelectPlus(BYVAL hList AS LONG, BYVAL nSelected AS LONG)
    IF nSelected > 0 THEN DECR nSelected '// Because ListBox is zero based
    IF hList THEN CALL SendMessage(hList, %LB_SETCURSEL, nSelected, 0)
END SUB

FUNCTION ListCount(BYVAL hList AS LONG) AS LONG
    IF hList THEN FUNCTION = SendMessage(hList, %LB_GETCOUNT, 0, 0)
END FUNCTION

FUNCTION ListGetCursel(BYVAL hList AS LONG) AS LONG
    LOCAL nSelected AS LONG
    IF hList THEN
       nSelected = SendMessage(hList, %LB_GETCURSEL, 0, 0)
       IF nSelected > -1 THEN INCR nSelected '// Because ListBox is zero based
    END IF
    FUNCTION = nSelected
END FUNCTION

FUNCTION ListGetText(BYVAL hList AS LONG, BYVAL nItem AS LONG) AS STRING
    LOCAL sItem AS STRING, nLEN AS LONG
    IF nItem > 0 THEN
       DECR nItem
       nLEN = SendMessage(hList, %LB_GETTEXTLEN, nItem, 0)
       sItem = SPACE$(nLEN)
       CALL SendMessage(hList, %LB_GETTEXT, nItem, BYVAL STRPTR(sItem))
       FUNCTION = sItem
    END IF
END FUNCTION

FUNCTION GDImageDetectMap(BYVAL hWnd AS DWORD, BYVAL hInstance AS LONG) AS LONG
    LOCAL hList, WashFind, hFind, MapCount, nSelected AS LONG
    LOCAL fd AS WIN32_FIND_DATA
    LOCAL zTmp AS ASCIIZ * %MAX_PATH, zMapToUse AS ASCIIZ * %MAX_PATH

    zMapToUse = gsFileName: CALL CharLower(zMapToUse)

    hList = GetDlgItem(hWnd, %IDC_MAP_LIST)
    IF hList = 0 THEN
       hList = CreateWindowEx(0, "LISTBOX", "", %WS_CHILD OR %LBS_SORT, 0, -1000, 0, 0, _
                              hWnd, %IDC_MAP_LIST, hInstance, BYVAL 0)
    ELSE
       CALL ListDeleteAll(hList)
    END IF

    WashFind = FindFirstFile((gsMapPath + "*.*"), fd)
    hFind = WashFind
    DO WHILE hFind > 0
       IF ASC(fd.cFileName) <> 46 THEN
          IF INSTR(CHR$(0,1,32,33,128), CHR$(fd.dwFileAttributes)) THEN
             zTmp = gsMapPath + fd.cFileName: CALL CharLower(zTmp)
             IF INSTR(".bmp.png.jpg.tif.gif.", RIGHT$(zTmp, 4) + $Dot) THEN
                IF ListAdd(hList, zTmp) > -1 THEN
                   INCR MapCount
                END IF
             END IF
          END IF
       END IF
       hFind = FindNextFile(WashFind, fd)
    LOOP
    CALL FindClose(WashFind)

    nSelected = ListFindString(hList, zMapToUse)
    CALL ListSelectPlus(hList, nSelected)
    IF nSelected THEN 
       FUNCTION = %ID_FirstContact - nSelected + 1
    END IF

END FUNCTION

SUB GDImageBuildContactSheet()
    LOCAL lpr AS RECT
    LOCAL hList, nID, nUseAlpha, K, hBitmap, nX, nY, nW, nH, nSizeX, nSizeY, nCountMax AS LONG
    LOCAL zFileName AS ASCIIZ * %MAX_PATH

    hList = GetDlgItem(ghMain, %IDC_MAP_LIST)
    GetClientRect(ghContactCtrl, lpr)

    nCountMax = ListCount(hList)
    nSizeX = lpr.nBottom - 4: nSizeY = nSizeX: nX = 2: nY = 2
    nID = %ID_FirstContact
    FOR K = 1 TO nCountMax

        zFileName = ListGetText(hList, K)
        hBitmap = ZI_FitBitmapFromFile(zFileName, nSizeX, nSizeY)
        IF nID = gnFocusContactID THEN nUseAlpha = 255 ELSE nUseAlpha = %ALPHA_MIN
        ZD_DrawBitmapToCtrl(ghContactCtrl, nX, nY, hBitmap, ZD_ColorARGB(nUseAlpha, 0), nID, %ZS_HIDDEN)
        IF nID <> gnFocusContactID THEN
           ZD_SetObjectScale(nID, 0.9)
        END IF
        ZD_SetObjectLocked(nID, %TRUE)
        zFileName = PATHNAME$(NAME, zFileName): REPLACE "_" WITH " " IN zFileName
        ZD_SetObjectImageLabel(nID, zFileName)
  
        nX += nSizeX + 4
        nID -= 1
    NEXT

    '// Left navigation arrow
    hBitmap = ZI_CreateBitmapFromFile(gsResPath + "Left_arrow.png", nW, nH)
    nY += (nSizeY - nH) * 0.5
    ZD_DrawBitmapToCtrl(ghContactCtrl, 0, nY, hBitmap, ZD_ColorARGB(255, 0), %ID_LEFT_ARROW, %ZS_HIDDEN)
    ZD_SetObjectLocked(%ID_LEFT_ARROW, %TRUE)
    ZD_SetObjectAnchorMode(%ID_LEFT_ARROW, %ANCHOR_LEFT)

    '// Right navigation arrow
    hBitmap = ZI_CreateBitmapFromFile(gsResPath + "Right_arrow.png", nW, nH)
    ZD_DrawBitmapToCtrl(ghContactCtrl, lpr.nRight - nW, nY, hBitmap, ZD_ColorARGB(255, 0), %ID_RIGHT_ARROW, %ZS_HIDDEN)
    ZD_SetObjectLocked(%ID_RIGHT_ARROW, %TRUE)
    ZD_SetObjectAnchorMode(%ID_RIGHT_ARROW, %ANCHOR_RIGHT)

    '// Show icons and navigation arrows
    ZD_GetObjectXY(1, nX, nY): IF nX < 0 THEN ZD_SetObjectVisibility(%ID_LEFT_ARROW, %TRUE)
    ZD_GetObjectXY(nCountMax, nX, nY): IF nX > lpr.nRight THEN ZD_SetObjectVisibility(%ID_RIGHT_ARROW, %TRUE)
    nID = %ID_FirstContact
    FOR K = 1 TO nCountMax
        ZD_SetObjectVisibility(nID, %TRUE)
        nID -= 1
    NEXT

    GDImageShowContactArrow()

END SUB

SUB RenderAnimation()
    LOCAL K, nID, nCountMax, nDone, nAlpha AS LONG
    LOCAL rScale AS SINGLE

    LOCAL lp AS POINTAPI
    GetCursorPos(lp)
    IF WindowFromPoint(lp.X, lp.Y) <> ghContactCtrl THEN gnHoverContactID = 0

    nCountMax = ListCount(GetDlgItem(ghMain, %IDC_MAP_LIST))
    nID = %ID_FirstContact - nCountMax + 1
    FOR K = nCountMax TO 1 STEP -1
        IF nID <> gnFocusContactID THEN
           nAlpha = ZD_GetObjectAlpha(nID)
           rScale = ZD_GetObjectScale(nID)
           IF nID = gnHoverContactID THEN
              IF nAlpha < 255 THEN
                 nDone = -1
                 nAlpha += %ALPHA_STEP
                 IF nAlpha > 255 THEN nAlpha = 255
                 IF rScale < 1 THEN
                    rScale += 0.02: IF rScale > 1 THEN rScale = 1
                    ZD_SetObjectScale(nID, rScale)
                 END IF
                 ZD_SetObjectAlpha(nID, nAlpha, %FALSE)
              END IF
           ELSE
              IF nAlpha > %ALPHA_MIN THEN
                 nDone = -1
                 nAlpha -= %ALPHA_STEP
                 IF nAlpha < %ALPHA_MIN THEN nAlpha = %ALPHA_MIN
                 IF rScale > 0.9 THEN
                    rScale -= 0.02: IF rScale < 0.9 THEN rScale = 0.9
                    ZD_SetObjectScale(nID, rScale)
                 END IF
                 ZD_SetObjectAlpha(nID, nAlpha, %FALSE)
              END IF
           END IF
        END IF 
        nID += 1
    NEXT

    IF nDone THEN
       ZI_UpdateWindow(ghContactCtrl, 0)
    END IF

END SUB

SUB MoveContactLeftRight(LOCAL nLeftRight AS LONG)
    LOCAL lpr AS RECT
    LOCAL nID, K, nS, nStepX, nX, nY, nDoIt, nUseStep, nCountMax, nArrowClic AS LONG

    GetClientRect(ghContactCtrl, lpr)
    nCountMax = ListCount(GetDlgItem(ghMain, %IDC_MAP_LIST))
    nUseStep = 4
    IF lpr.nRight > 1024 THEN nUseStep = 8
    IF lpr.nRight > 1600 THEN nUseStep = 16
    nUseStep = nUseStep * nLeftRight

    IF nUseStep < 0 THEN '// Right arrow
       ZD_GetObjectXY(%ID_FirstContact - nCountMax + 1, nX, nY): IF nX > lpr.nRight THEN nDoIt = -1 
    ELSE                 '// Left arrow
       ZD_GetObjectXY(%ID_FirstContact, nX, nY): IF nX < 0 THEN nDoIt = -1
    END IF

    IF nDoIt THEN
       nStepX = ABS(nUseStep)
       IF gnMovingContact = 0 THEN
          gnMovingContact = 1
          FOR nS = 1 TO lpr.nBottom STEP nStepX
              nID = %ID_FirstContact
              FOR K = 1 TO nCountMax
                  ZD_GetObjectXY(nID, nX, nY)
                  ZD_SetObjectXY(nID, nX + nUseStep, nY, %FALSE)
                  nID -= 1
              NEXT
              ZD_GetObjectXY(%ID_FirstContact, nX, nY): IF nX < 0 THEN nDoIt = %TRUE ELSE nDoIt = %FALSE: nArrowClic = %ID_LEFT_ARROW
              ZD_SetObjectVisibility(%ID_LEFT_ARROW, nDoIt) 
              ZD_GetObjectXY(%ID_FirstContact - nCountMax + 1, nX, nY): IF nX > lpr.nRight THEN nDoIt = %TRUE ELSE nDoIt = %FALSE: nArrowClic = %ID_RIGHT_ARROW
              ZD_SetObjectVisibility(%ID_RIGHT_ARROW, nDoIt)
      
              IF nArrowClic = 0 THEN ZI_UpdateWindow(ghContactCtrl, 0)
          NEXT
          IF ZD_IsObjectVisible(%ID_RIGHT_ARROW) = 0 THEN
             ZD_GetObjectXY(%ID_FirstContact - nCountMax + 1, nX, nY)
             IF nX + lpr.nBottom > lpr.nRight THEN MoveContactToTheLeft()
          END IF
          IF ZD_IsObjectVisible(%ID_LEFT_ARROW) = 0 THEN
             ZD_GetObjectXY(%ID_FirstContact, nX, nY)
             IF nX > 0 THEN MoveContactToTheRight()
          END IF
          gnHoverContactArrow = 0
          gnMovingContact = 0
       END IF
    END IF

END SUB

SUB MoveContactToTheLeft()
    LOCAL lpr AS RECT
    LOCAL nCountMax, nID, K, nX, nY, nUseX AS LONG

    GetClientRect(ghContactCtrl, lpr)
    nCountMax = ListCount(GetDlgItem(ghMain, %IDC_MAP_LIST))
    ZD_GetObjectXY(%ID_FirstContact - nCountMax + 1, nX, nY)
    nUseX = lpr.nRight + 1
    nID = %ID_FirstContact - nCountMax + 1
    FOR K = nCountMax TO 1 STEP -1
        nUseX -= lpr.nBottom
        ZD_SetObjectXY(nID, nUseX, nY, %FALSE)
        nID += 1
    NEXT
    '// Shall we show the arrow icon?
    GDImageShowContactArrow()
END SUB

SUB MoveContactToTheRight()
    LOCAL lpr AS RECT
    LOCAL nID, nCountMax, K, nX, nY, nUseX AS LONG
    GetClientRect(ghContactCtrl, lpr)
    nCountMax = ListCount(GetDlgItem(ghMain, %IDC_MAP_LIST))
    ZD_GetObjectXY(%ID_FirstContact, nX, nY)
    nID = %ID_FirstContact
    FOR K = 1 TO nCountMax
        ZD_SetObjectXY(nID, nUseX, nY, %FALSE)
        nUseX += lpr.nBottom
        nID -= 1
    NEXT
    '// Shall we show the arrow icon?
    GDImageShowContactArrow()
END SUB

SUB GDImageShowContactArrow()
    LOCAL lpr AS RECT
    LOCAL nCountMax, nX, nY, nW, nH, nDoIt AS LONG
    nCountMax = ListCount(GetDlgItem(ghMain, %IDC_MAP_LIST))
    IF nCountMax THEN
       GetClientRect(ghContactCtrl, lpr)

       ZD_GetObjectXY(%ID_FirstContact, nX, nY)
       IF nX < 0 THEN nDoIt = %TRUE ELSE nDoIt = %FALSE
       ZD_SetObjectVisibility(%ID_LEFT_ARROW, nDoIt) 

       ZD_GetObjectXY(%ID_FirstContact - nCountMax + 1, nX, nY)
       ZD_GetObjectBound(%ID_FirstContact - nCountMax + 1, nW, nH)
       IF nX + nW > lpr.nRight THEN nDoIt = %TRUE ELSE nDoIt = %FALSE
       ZD_SetObjectVisibility(%ID_RIGHT_ARROW, nDoIt)
  
       ZI_UpdateWindow(ghContactCtrl, 0)
    END IF
END SUB

SUB AddLogo(BYVAL hCtrl AS DWORD)
    LOCAL nID, hBitmap, XPicSize, YPicSize AS LONG 
    LOCAL rc AS RECT

    '// Add the sprite logo that is un-affected by the zoom.
    hBitmap = ZI_CreateBitmapFromFile(gsResPath + "GDImage.png", XPicSize, YPicSize)
    IF hBitmap THEN
       nID = %ID_LOGO
       GetClientRect(hCtrl, rc)
       ZD_DrawBitmapToCtrl(hCtrl, rc.nRight - XPicSize, rc.nBottom - YPicSize, hBitmap, ZD_ColorARGB(255, 0), nID, %ZS_VISIBLE)
       ZD_SetObjectAnchorMode(nID, %ANCHOR_BOTTOM_RIGHT)
       '// Lock and disable the sprite image.
       ZD_SetObjectLocked(nID, %TRUE)
       '// Do not alter the size and location of this sprite in case of Zoom control.
       ZD_SetObjectHidden(nID, %TRUE)
    END IF

END SUB

SUB AddPushPins(BYVAL hCtrl AS DWORD)

    LOCAL nID, hBitmap, XPicSize, YPicSize AS LONG 

    nID = 1
    hBitmap = ZI_CreateBitmapFromFile(gsResPath + "PushPins.png", XPicSize, YPicSize)
    ZD_DrawBitmapToCtrl(hCtrl, 1065, 1365, hBitmap, ZD_ColorARGB(255, 0), nID, %ZS_VISIBLE)
		ZD_SetObjectFrameCount(nID, XPicSize \ YPicSize) '// <---- Sprite multi-state.
		ZD_SetObjectScroll(nID, %TRUE)
    ZD_SetObjectFrameToUse(nID, 1, %FALSE)
    ZD_SetObjectImageLabel(nID, "Patrice lives here")
    ZD_SetObjectLocked(nID, %TRUE)

    nID = 2
    ZD_CloneObject(1, nID, 936, 1558)
    ZD_SetObjectImageLabel(nID, "José lives here")

END SUB

SUB AddBulb256(BYVAL hCtrl AS DWORD)

    LOCAL nID, hBitmap, XPicSize, YPicSize AS LONG 

    nID = 1
    hBitmap = ZI_CreateBitmapFromFile(gsResPath + "Bulb_256.png", XPicSize, YPicSize)
    ZD_DrawBitmapToCtrl(hCtrl, 878, 710, hBitmap, ZD_ColorARGB(255, 0), nID, %ZS_VISIBLE)
		ZD_SetObjectFrameCount(nID, XPicSize \ YPicSize) '// <---- Sprite multi-state.
		ZD_SetObjectScroll(nID, %TRUE)
    ZD_SetObjectFrameToUse(nID, 1, %FALSE)
    ZD_SetObjectImageLabel(nID, "For rent")

    nID = 2
    ZD_CloneObject(1, nID, 1978, 910)
    ZD_SetObjectFrameToUse(nID, 2, %FALSE)
    ZD_SetObjectImageLabel(nID, "For sale")

END SUB

SUB AddVia64(BYVAL hCtrl AS DWORD)

    LOCAL nID, hBitmap, XPicSize, YPicSize AS LONG 

    nID = 1
    hBitmap = ZI_CreateBitmapFromFile(gsResPath + "Via_64.png", XPicSize, YPicSize)
    ZD_DrawBitmapToCtrl(hCtrl, 1386, 336, hBitmap, ZD_ColorARGB(255, 0), nID, %ZS_VISIBLE)
		ZD_SetObjectFrameCount(nID, XPicSize \ YPicSize) '// <---- Sprite multi-state.
		ZD_SetObjectScroll(nID, %TRUE)
    ZD_SetObjectFrameToUse(nID, 1, %FALSE)
    ZD_SetObjectImageLabel(nID, "Default")

    nID = 2
    ZD_CloneObject(1, nID, 2305, 1356)
    ZD_SetObjectFrameToUse(nID, 2, %FALSE)
    ZD_SetObjectImageLabel(nID, "Disabled")

    nID = 3
    ZD_CloneObject(1, nID, 510, 1211)
    ZD_SetObjectFrameToUse(nID, 3, %FALSE)
    ZD_SetObjectImageLabel(nID, "Green")

    nID = 4
    ZD_CloneObject(1, nID, 1812, 987)
    ZD_SetObjectFrameToUse(nID, 4, %FALSE)
    ZD_SetObjectImageLabel(nID, "Red focus")

END SUB

SUB AddPencil(BYVAL hCtrl AS DWORD)

    LOCAL nID, hBitmap, XPicSize, YPicSize AS LONG 

    nID = 1
    hBitmap = ZI_CreateBitmapFromFile(gsResPath + "Pencil.png", XPicSize, YPicSize)
    ZD_DrawBitmapToCtrl(hCtrl, 1425, 1972, hBitmap, ZD_ColorARGB(255, 0), nID, %ZS_VISIBLE)
		ZD_SetObjectScroll(nID, %TRUE)
    ZD_SetObjectImageLabel(nID, "Pencil")

END SUB
