Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

gbFloorPlanner

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin gbFloorPlanner

    Here's my latest app, gbFloorPlanner. It is an easy to use tool for creating layouts of any kind - house floor plans, garden areas, parties, special events, etc.. If the task involves figuring out how to place items in an area, gbFloorPlanner is the tool for the job!

    Discussion is here.
    Download, including images, source code, and EXE is here.
    Online Help (and full size images) is here.







    Feature List

    gbFloorPlanner provides a complete selection of features for creating and editing floor play layouts.
    • Create layouts quickly using only a mouse
    • Save/restore layout sessions (return to status from last session)
    • Save/Open layouts or selected item to file
    • Rectangle/ellipse/line drawing shapes
    • Item resizing with mouse
    • Rotation of rectangle and line shapes
    • Align items on left or top
    • Import saved layouts/templates into current layout
    • Object Library - items which may be easily added to layout
    • Add your own images to the Image Library
    • Layout Content Listing - all items in current layout
    • Layout Summary Report - summary of unique items in layout
    • Cut/Copy/Paste items in the layout
    • Remove/Restore deleted items (similar to Undo/Redo)
    • Groups (multiple items treated as one)
    • Select/move/delete multiple items
    • Duplicate selected items
    • Place items in front/behind other items
    • Border, Text, Background Color and Fillstyle properties for each item
    • OnScreen ruler
    • Grids (dots or lines)
    • 4 Zoom Factors
    • Snap To Grid (or half-grid)
    • Copy layout image to clipboard
    • Print layout image (portrait/horizontal)


    And here's the compilable code:
    Code:
    'Compilable Example:
    #Compiler PBWin 10
    #Compile Exe "gbfloorplanner.exe"
    #Dim All
    #Debug Error On
    #Debug Display On
    %Unicode = 1
    
    #Include "cwindow.inc"
    #Include "files\gbOnlineUpdate.inc"
    #Include "cgdiplus.inc"
    #Include "ListViewCtrl.inc"
    #Include "HeaderCtrl.inc"
    
    #Resource Manifest, 1, "files\xptheme.xml"
    
    #Resource Icon logo "icons\gbfloorplanner.ico"
    #Resource Icon xopen "icons\folder.ico"
    #Resource Icon xnew "icons\new.ico"
    #Resource Icon xsave "icons\save.ico"
    #Resource Icon xcapture "icons\capture.ico"
    #Resource Icon xxprint "icons\print.ico"
    #Resource Icon xduplicate "icons\copy.ico"
    #Resource Icon xdelete "icons\cancel.ico"
    #Resource Icon xempty "icons\empty.ico"
    #Resource Icon xbox "icons\box.ico"
    #Resource Icon xcircle "icons\circle.ico"
    #Resource Icon xline "icons\minus.ico"
    #Resource Icon xobject "icons\picture.ico"
    #Resource Icon xselect "icons\select.ico"
    #Resource Icon xzoom "icons\zoom.ico"
    #Resource Icon xcut "icons\cut.ico"
    #Resource Icon xsettings "icons\settings.ico"
    #Resource Icon xhelp "icons\help.ico"
    #Resource Icon xfont "icons\font.ico"
    #Resource Icon xtext "icons\text.ico"
    #Resource Icon xgrid "icons\grid.ico"
    #Resource Icon xsnap "icons\snap.ico"
    #Resource Icon xundo "icons\undo.ico"
    #Resource Icon xredo "icons\redo.ico"
    #Resource Icon xruler "icons\ruler.ico"
    #Resource Icon xcontent "icons\table.ico"
    #Resource Icon xlibrary "icons\library.ico"
    #Resource Icon xtitle "icons\title.ico"
    #Resource Icon xtruncate "icons\truncate.ico"
    #Resource Icon xmove "icons\move.ico"
    #Resource Icon xcube "icons\cube.ico"
    #Resource Icon ximport "icons\import.ico"
    #Resource Icon xpaste "icons\paste.ico"
    
    #Resource Wave, camera, "files\camera.wav"
    
    Enum Equates Singular
       IDC_Graphic = 500
       IDC_Preview
       IDC_ComboBox
       IDC_ListView
       IDC_Toolbar
       IDC_ToolbarB
       IDC_StatusBar
    
       IDC_LabelLib
       IDC_LabelLV
    
       IDCE_LabelDesc
       IDCE_TextDesc
       IDCE_FGLabel
       IDCE_FGColor
       IDCE_BGLabel
       IDCE_BGColor
       IDCE_DescColor
       IDCE_DescLabel
       IDCE_BGTransparent
       IDCE_StyleLabel
       IDCE_FillStyle
       IDCE_ImageLabel
       IDCE_Image
       IDCE_ShowBorder
       IDCE_ShowImage
       IDCE_ShowDesc
       IDCE_RoundedBox
       IDCE_Cancel
       IDCE_Save
    
       IDT_New
       IDT_Open
       IDT_SaveAs
       IDT_Save
       IDT_CopyImage
       IDT_Copy
       IDT_Paste
       IDT_Print
       IDT_Clear
       IDT_Select
       IDT_Delete
       IDT_Zoom
       IDT_Truncate
       IDT_Redo
       IDT_Undo
       IDT_Cut
       IDT_Box
       IDT_Circle
       IDT_Line
       IDT_ShowListView
       IDT_ShowLibrary
       IDT_ShowDesc
       IDT_Grid
       IDT_Ruler
       IDT_Snap
       IDT_Font
       IDT_Duplicate
       IDT_Import
       IDT_ShowImages
       IDT_3D
       IDT_Settings
       IDT_Help
    
       IDM_OnlineUpdate
       IDM_LocalHelp
       IDM_CapturePNG
       IDM_ListAllItems
       IDM_GridLines
       IDM_AskConfirmation
       IDM_Landscape
       IDM_AutoSave
       IDM_AutoSelectMode
       IDM_SnapToGrid
       IDM_SnapHalf
       IDM_RoundedBox
       IDM_ShowRuler
       IDM_MinRuler
       IDM_ShowImages
       IDM_SendFront
       IDM_SendBack
       IDM_ShowProperties
       IDM_ShowPropertiesLV
       IDM_Debug
       IDM_Test
       IDM_BGColor
       IDM_FGColor
       IDM_RulerColor
       IDM_GridColor
       IDM_DefaultColors
       IDM_CopyList
       IDM_PrintList
       IDM_SetTextLoc
       IDM_SetTextRotation
       IDM_RotateSelected
       IDM_SetZHeight
       IDM_SummaryDisplay
       IDM_SummaryCopy
       IDM_SummaryPrint
       IDM_OpenLibraryFolder
       IDM_OpenLayoutFolder
       IDM_EditLibrary
       IDM_LoadLibrary
       IDM_SelectMode
       IDM_GroupSelected
       IDM_UnGroupSelected
       IDM_DeleteSelected
       IDM_AlignSelected
       IDM_DuplicateSelectedItems
       IDM_LeftAlign
       IDM_TopAlign
       IDM_SaveSelectedItemsAs
       IDM_UnSelectAllItems
       IDM_SelectAllItems
       IDM_ReplaceSelectedItemsText
       IDM_SetSelectedColor
       IDM_NumberSelectedItems
       IDM_ResetAngle
       IDM_Sep
    
       IDM_Zoom4
       IDM_Zoom10
       IDM_Zoom20
       IDM_Zoom40
       IDM_Zoom60
    
       IDM_Up
       IDM_Down
       IDM_Left
       IDM_Right
       IDM_Delete
    
       Dots
       Lines
    
       IDM_LayoutMenu = 3000
       IDM_ImportMenu = 4000
    
       TBM            = 120
    
       Select = 0
       Move
       Box
       Circle
       Line
       Resize
    
       OverNothing = 0
       OverItem_Selected
       OverItem_NotSelected
       OverResizeMarker
    
       Solid = 0
       Horizontal
       Vertical
       UpwardDiagonal
       DownwardDiagonal
       Crossed
       DiagonalCrossed
    
       Center = 0
       Top
       Bottom
    End Enum
    
    Type LibraryType
       cat As StringZ * 40
       desc As StringZ * 40
       img As StringZ * 40
       x As Long
       y As Long
       z As Long
    End Type
    
    Type OpenGLData
       x0 As Long
       y0 As Long
       z0 As Long
       x As Long
       y As Long
       z As Long
       clr As Long
       desc As StringZ * 40
       img As StringZ * 40
    End Type
    
    Type ListType
       desc As StringZ * 40
       size As StringZ * 40
       qty As Long
    End Type
    
    Type ImageType
       img As StringZ * 40
       pImage As Dword
    End Type
    
    Type ObjectType
       shape As Long          '%Box %Circle %Line
       rect As Rect           'bounding rectangle
       z As Long              'future use in 3D rendering
       sf As Long
       rounded As Long
    
       showborder As Long
       showdesc As Long
       showimage As Long
    
       bgtransparent As Long  'override bgColor
       bgColor As Long        'cell background color
       fgColor As Long        'cell background color
       fillstyle As Long      'fill style
    
       img As StringZ * 40    'image
       imgPos As Long         'location of pImage in Images()
       fliph As Long
       flipv As Long
    
       desc As StringZ * 40
       desccolor As Long
    
       selected As Long
    
       group As StringZ * 40
       unusedB As StringZ * 40
       unusedC As StringZ * 40
    
       z0 As Long
       textpos As Long
       textrot As Long
       keepAR As Long
    
       transparency As Long  '0 to 100
       theta As Long
       unusedF As Long
       unusedG As Long
       unusedH As Long
       unusedI As Long
    End Type
    
    Type CustomColors
       c(15) As Long
    End Type
    
    Type PolyPoints
      count As Long
      x1 As Single
      y1 As Single
      x2 As Single
      y2 As Single
      x3 As Single
      y3 As Single
      x4 As Single
      y4 As Single
    End Type
    
    
    $Ver = "1.2"
    $SessionFile = "tempfiles\session.dat"
    $LibraryFile = "files\library.txt"
    $LibraryImages = "images\"
    $LayoutFiles = "layouts\"
    $ClipboardFile = "tempfiles\clipboard.dat"
    $ThreeDFile = "3d\gbfloorplanner.3db"
    $ListFile = "tempfiles\itemlist.txt"
    
    Global hDlg,hEdit,hFont,hFontB,hFontRot,hGraphic,hToolbar,hListView, hToolbarB,hSettings, hZoom,OldGraphicProc As Dword
    Global hHelp,hPopupGraphic,ghHook,PPC,hTxtWin,hOpen,token,hDC,hPreview,hPreviewDC,hImport,pGraphics As Dword
    Global FontSize, FontAttr, Debug, DrawMode, DescColor, Rounded, RulerColor, GridColor, LineWidth As Long
    Global SF, FPC, ShowGrid, ShowRuler,MinRuler,SnapToGrid,SnapHalf,CanDraw,DrawInWork,Dirty As Long     'feet per cell
    Global D() As ObjectType, CustomColorList As CustomColors, MoveX0, MoveY0,CapturePNG As Long, Images() As ImageType
    Global BGColor, FGColor, BGTransparent, SelectedColor,AskConfirmation, Landscape, ShowImages, ZHeight,Z0Height As Long
    Global GridLines, ShowListView, ShowLibrary, ShowDesc, AutoSave, AutoSelectMode, hPopupListView, LastCat, CaptureNumber As Long
    Global hTBImageList As Dword, Library() As LibraryType, ptMenu As Point, ItemFill() As String
    Global SelectedFileName, FileName, ImportFileName, FontName As WStringZ * %Max_Path, StartupInput As GdiplusStartupInput
    Global NewR, OldR As Rect, UndoPos, BGEdit,RoundEdit,FGEdit,DescEdit,EditPos, vx,vy, MSize As Long, PTS As PolyPoints
    Global qFreq, qStart, qStop As Quad, hDotGraphic, hLineGraphic As Dword, ResizeMarker, ItemBeingResized As Long
    
    Function PBMain() As Long
       Dialog New Pixels, 0, "gbFloorPlanner " + $ver,,,800,600, %WS_OverlappedWindow Or %WS_ClipChildren To hDlg
       Dialog Set Icon hDlg, "logo"
       CreateGridGraphicControls
       CreateContextMenus
       CreateToolbar
       CreateToolbarB
       CreateListView
       CreateStatusBar
       CreateLibraryControls
       CreateGraphic
       Dialog Show Modal hDlg Call DlgProc
       If RestartUpdate Then RestartUpdatedEXE
    End Function
    
    CallBack Function DlgProc() As Long
       Local w,h,x,y,i As Long, temp$, nmtb As TBNotify Ptr
       Local PTT As TooltipText Ptr, rc As Rect, pt As Point, LVHT As LVHitTestInfo
    
       Select Case Cb.Msg
          Case %WM_InitDialog
             QueryPerformanceFrequency qFreq
             hUpdateParent = hDlg
             GetDebug
             ReDim Images(0)
             CreateSubFolders
             StartupInput.GdiplusVersion = 1                  ' Initialize GDI+
             GdiplusStartup(Token, StartupInput, ByVal %NULL) ' Initialize GDI+
             GdipCreateFromHDC(hDC, pGraphics)                 'create graphic object
             BuildAcceleratorTable
             CreateFonts
             LoadItemFillArray
             Settings_INI "get"
             DrawHiddenGrids
             LoadLibraryFile
             ComboBox Select hDlg, %IDC_ComboBox, LastCat
             DisplayItemImagesForSelectedCategory
             ManageLibrary
             Graphic Clear BGColor
             If IsFile($SessionFile) Then
                LoadLayout($SessionFile)
             Else
                FileName = Exe.Path$ + "layouts\untitled.dat"
                ReDim D(0) : ReDim Images(0) : UndoPos = 0 : DrawLayout
             End If
             FillListView
             Dialog Set Text hDlg, "gbFloorPlanner " + $ver + Space$(10) + FileName
             SetMenusAndToolbar
             DrawLayout
          Case %WM_SysCommand
             If AutoSave Then
                SaveSession
             Else
                If IsFile($SessionFile) Then Kill $SessionFile
                If Dirty Then
                   ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
                   Select Case MessageBox(0, "File has changed. Save changes before exiting gbFloorPlanner?", "Exit gbFloorPlanner", %MB_YesNoCancel + %MB_IconQuestion + %MB_TaskModal)
                      Case %IdYes    : SaveLayout(FileName,1)
                      Case %IdNo     : Dirty = 0
                      Case %IdCancel : Function = 1  'abort the close
                   End Select
                   UnhookWindowsHookEx ghHook
                End If
             End If
          Case %WM_Destroy
             ComboBox Get Select hDlg, %IDC_ComboBox To LastCat
             GdiPlusShutDown token
             SetWindowLong hGraphic, %GWL_WndProc, OldGraphicProc
             Settings_INI "save"
    
          Case %WM_Size
             ResizeWindow
    
          Case %WM_SetCursor
             If GetDlgCtrlID(Cb.WParam) = %IDC_Graphic Then
                If DrawMode > %Move Then MousePtr 2 Else MousePtr 1
                Function = 1
             End If
    
          Case %WM_ContextMenu
             ptMenu.x = Lo(Integer,Cb.LParam) : ptMenu.y = Hi(Integer, Cb.LParam)
             Select Case GetDlgCtrlID (Cb.WParam)
                Case %IDC_ListView
                   TrackPopupMenu hPopupListView, %TPM_LeftAlign, ptMenu.x, ptMenu.y, 0, Cb.Hndl, ByVal 0
                Case %IDC_Graphic
                   TrackPopupMenu hPopupGraphic, %TPM_LeftAlign, ptMenu.x, ptMenu.y, 0, Cb.Hndl, ByVal 0
             End Select
    
          Case %WM_Command
             Select Case Cb.Ctl
                Case %IDC_ComboBox
                   Select Case Cb.CtlMsg
                      Case %CBN_SelChange
                         DisplayItemImagesForSelectedCategory
                         ResizeWindow
                   End Select
                Case %IDC_Preview
                   Select Case Cb.CtlMsg
                      Case %STN_DblClk
                         i = GetPreviewSelection
                         If i Then
                            AddLibraryItemToLayout(i)
                            FillListView
                            DrawLayout
                            Dirty = 1
                         End If
                   End Select
    
                Case %IdOk
                   If GetFocus = hListView Then
                      ListView Get Select hDlg, %IDC_ListView To i
                      If i Then
                         EditPos = UndoPos-1+1
                         If EditPos Then DisplayEditDialog : FillListview : DrawLayout
                      End If
                   End If
    
                Case %IDT_New
                   i = 1
                   If Dirty Then
                      ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
                      Select Case MessageBox(0, "File has changed. Save changes before creating new layout?", "New Layout", %MB_YesNoCancel + %MB_IconQuestion + %MB_TaskModal)
                         Case %IdYes    : SaveLayout(FileName,1)
                         Case %IdNo     : 'no action
                         Case %IdCancel : i = 0
                      End Select
                      UnhookWindowsHookEx ghHook
                   End If
                   If i Then
                      FileName = Exe.Path$ + "layouts\untitled.dat"
                      Dialog Set Text hDlg, "gbFloorPlanner " + $ver + Space$(10) + FileName
                      ReDim D(0)
                      ReDim Images(0)
                      UndoPos = 0
                      Dirty = 0
                      FillListView
                      DrawLayout
                   End If
    
                Case %IDT_Open
                   i = 1
                   If Dirty Then
                      ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
                      Select Case MessageBox(0, "File has changed. Save changes before opening new file?", "Open Layout", %MB_YesNoCancel + %MB_IconQuestion + %MB_TaskModal)
                         Case %IdYes    : SaveLayout(FileName,1)
                         Case %IdNo     : 'no action
                         Case %IdCancel : i = 0
                      End Select
                      UnhookWindowsHookEx ghHook
                   End If
                   If i Then
                      If SelectLayoutFile("Open") Then LoadLayout(FileName) : FillListView : DrawLayout : Dirty = 0
                   End If
    
                Case %IDT_Import
                   If SelectLayoutFile("Import") Then ImportLayout(FileName,0) : FillListView : DrawLayout : Dirty = 1
    
                Case %IDT_SaveAs : SaveAs(FileName,1)
    
                Case %IDT_Save
                   Statusbar Set Text hDlg, %IDC_Statusbar, 2,0, "Layout saved as:  " + FileName
                   SaveLayout(FileName,1)
    
                Case %IDT_Delete, %IDM_Delete, %IDM_DeleteSelected
                   DeleteSelectedItems
    
                Case %IDT_Clear
                   'remove user-entered values
                   If AskConfirmation Then
                      ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
                      Select Case MessageBox(0, "Clear all content?", "Clear Drawing", %MB_YesNo + %MB_IconQuestion + %MB_TaskModal)
                         Case %IdYes   : ReDim D(0) : ReDim Images(0) : UndoPos = 0 : DrawLayout : FillListView : Dirty = 1
                         Case %IdNo    : 'no action
                      End Select
                      UnhookWindowsHookEx ghHook
                   Else
                      ReDim D(0) : ReDim Images(0) : UndoPos = 0 : DrawLayout : FillListView : Dirty = 1
                   End If
    
                Case %IDM_Zoom4 To %IDM_Zoom60
                   Select Case Cb.Ctl
                      Case %IDM_Zoom4  : SF = 4  :  PPC = 20  : FPC = 5 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case %IDM_Zoom10 : SF = 10 :  PPC = 20  : FPC = 2 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case %IDM_Zoom20 : SF = 20 :  PPC = 20  : FPC = 1 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case %IDM_Zoom40 : SF = 40 :  PPC = 40  : FPC = 1 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case %IDM_Zoom60 : SF = 60 :  PPC = 60  : FPC = 1 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                   End Select
    
                Case %IDT_Zoom
                   Select Case SF
                      Case 4    : SF = 10 :  PPC = 20  : FPC = 2 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case 10   : SF = 20 :  PPC = 20  : FPC = 1 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case 20   : SF = 40 :  PPC = 40  : FPC = 1 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case 40   : SF = 60 :  PPC = 60  : FPC = 1 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                      Case 60   : SF = 4  :  PPC = 20  : FPC = 5 : DrawHiddenGrids : DrawLayout : SetMenusAndToolbar
                   End Select
    
                Case %IDM_ListAllItems
                   Open $ListFile For Output As #1 : Print #1, ItemProperties(-1) : Close #1
                   i  = Shell ("Notepad " + Exe.Path$ + $ListFile, 1)  'opens Notepad, does not wait for it to close
    
                Case %IDM_CapturePNG
                   CapturePNG = 1
                   sndPlaySound "MailBeep",%Snd_Sync
    
    
                Case %IDT_Select,%IDM_SelectMode  : DrawMode = %Select  : SetMenusAndToolbar
                Case %IDT_Box     : DrawMode = %Box     : SetMenusAndToolbar
                Case %IDT_Circle  : DrawMode = %Circle  : SetMenusAndToolbar
                Case %IDT_Line    : DrawMode = %Line    : SetMenusAndToolbar
    
                Case %IDT_Cut   : If CopySelectedItemsToClipboardFile Then DeleteSelectedItems
                Case %IDT_Copy  : CopySelectedItemsToClipboardFile
                Case %IDT_Paste :
                   If IsFile($ClipboardFile) Then ImportLayout($ClipBoardFile,1) : FillListView : DrawLayout : Dirty = 1 Else Beep
    
                Case %IDT_3D
                   If IsFile(Exe.Path$ + "3d\gbblocks3d.exe ") Then
                      Export3DFile
                      temp$ = Exe.Path$ + "3d\gbblocks3d.exe " + "   " + Exe.Path$ + $ThreeDFile
                      i = Shell(temp$)
                   End If
    
                Case %IDT_Undo : Undo : FillListView : DrawLayout : Dirty = 1
                Case %IDT_Redo : Redo : FillListView : DrawLayout : Dirty = 1
    
                Case %IDT_Truncate
                   ReDim Preserve D(UndoPos)
                   FillListView
                   Dirty = 1
    
                Case %IDT_CopyImage : CopyLayoutImageToClipboard
    
                Case %IDT_Print
                   PrintLayout
                   Graphic Attach hDlg, %IDC_Graphic, ReDraw
    
                Case %IDT_Help
                   temp$ = "http://www.garybeene.com/sw/gbfloorplanner.htm"
                   w = ShellExecute(hDlg, "Open", (temp$), $Nul, $Nul, %SW_ShowNormal)
    
                Case %IDM_LocalHelp    : DisplayLocalHelp
    
                Case %IDM_AskConfirmation
                   AskConfirmation = AskConfirmation Xor 1
                   SetMenusAndToolbar
    
                Case %IDM_Landscape
                   Landscape = Landscape Xor 1
                   SetMenusAndToolbar
    
                Case %IDM_AutoSave
                   AutoSave = AutoSave Xor 1
                   SetMenusAndToolbar
    
                Case %IDM_AutoSelectMode
                   AutoSelectMode = AutoSelectMode Xor 1
                   SetMenusAndToolbar
    
                Case %IDM_GridLines, %IDT_Settings
                   GridLines = GridLines Xor 1
                   SetMenusAndToolbar
                   DrawLayout
    
                Case %IDM_ResetAngle
                   For i = 1 To UndoPos
                      D(i).theta = 0
                   Next i
                   DrawLayout
    
                Case %IDM_NumberSelectedItems
                   ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
                   Select Case MessageBox(0, "Change description on selected items to a sequential number?", "Description Serialization", %MB_OkCancel + %MB_IconQuestion + %MB_TaskModal)
                      Case %IdOk    : AutoNumber : FillListView : DrawLayout
                      Case %IdCancel : Function = 1  'abort the close
                   End Select
                   UnhookWindowsHookEx ghHook
    
                Case %IDT_Grid
                   ShowGrid = ShowGrid Xor 1
                   SetMenusAndToolbar
                   DrawLayout
    
                Case %IDT_ShowLibrary
                   ShowLibrary = ShowLibrary Xor 1
                   SetMenusAndToolbar
                   ManageLibrary
                   ResizeWindow
    
                Case %IDT_ShowListView
                   ShowListView = ShowListview Xor 1
                   SetMenusAndToolbar
                   ManageLibrary
                   ResizeWindow
    
                Case %IDT_ShowImages
                   ShowImages = ShowImages Xor 1
                   SetMenusAndToolbar
                   ManageLibrary
                   DrawLayout
    
                Case %IDT_ShowDesc
                   ShowDesc = ShowDesc Xor 1
                   SetMenusAndToolbar
                   DrawLayout
    
                Case %IDM_ShowRuler, %IDT_Ruler
                   ShowRuler = ShowRuler Xor 1
                   SetMenusAndToolbar
                   DrawLayout
    
                Case %IDM_MinRuler
                   MinRuler = MinRuler Xor 1
                   SetMenusAndToolbar
                   DrawLayout
    
                Case %IDM_GroupSelected
                   temp$ = GuidTxt$(Guid$)
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         D(i).group = temp$
                         Dirty = 1
                      End If
                   Next i
    
                Case %IDM_UnGroupSelected
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         D(i).group = ""
                         Dirty = 1
                      End If
                   Next i
    
                Case %IDM_AlignSelected
                   For i = UndoPos To 1 Step -1
                      If Len(D(i).Group) Then Iterate For  'cannot align a Group, must UnGroup first
                      If D(i).selected Then SnapRect(i) : Dirty = 1
                   Next i
                   DrawLayout
    
                Case %IDM_SetZHeight
                   GetNewZ
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         If ZHeight <> -1 Then D(i).z = ZHeight
                         If Z0Height <> -9999 Then D(i).z0 = Z0Height
                         Dirty = 1
                      End If
                   Next i
    
                Case %IDM_SetTextRotation
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         D(i).textrot = D(i).textrot Xor 1
                         Dirty = 1
                      End If
                   Next i
                   DrawLayout
    
                Case %IDM_RotateSelected
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         If D(i).theta = 135 Then D(i).theta = 0 Else D(i).theta = D(i).theta + 45
                         Dirty = 1
                      End If
                   Next i
                   DrawLayout
    
                Case %IDM_SetTextLoc
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         Select Case D(i).textpos
                            Case %Top     : D(i).textpos = %Center
                            Case %Center  : D(i).textpos = %Bottom
                            Case %Bottom  : D(i).textpos = %Top
                         End Select
                         Dirty = 1
                      End If
                   Next i
                   DrawLayout
    
                Case %IDM_DuplicateSelectedItems, %IDT_Duplicate
                   DuplicateSelectedItems
                   FillListView
                   DrawLayout
    
                Case %IDM_LeftAlign
                   'get leftmost position
                   For i = UndoPos To 1 Step - 1
                      If D(i).selected Then
                         If y Then
                            x = Min(x,D(i).rect.nLeft)
                         Else
                            y = 1
                            x = D(i).rect.nLeft
                         End If
                      End If
                   Next i
                   'offset all rect by that much
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         OffsetRect D(i).rect, -(D(i).rect.nLeft-x) * SF / D(i).sf, 0
                      End If
                   Next i
                   DrawLayout
    
                Case %IDM_TopAlign
                   For i = UndoPos To 1 Step - 1
                      If D(i).selected Then
                         If x Then
                            y = Min(y,D(i).rect.nTop)
                         Else
                            x = 1
                            y = D(i).rect.nTop
                         End If
                      End If
                   Next i
                   For i = UndoPos To 1 Step -1
                      If D(i).selected Then
                         OffsetRect D(i).rect, 0, -(D(i).rect.nTop-y) * SF / D(i).sf
                      End If
                   Next i
                   DrawLayout
    
                Case %IDM_SaveSelectedItemsAs : SaveAs(SelectedFileName, 0)
    
                Case %IDM_SendFront        : SendFront : FillListView : DrawLayout
                Case %IDM_SendBack         : SendBack : FillListView : DrawLayout
    
                Case %IDM_ShowProperties   : ShowProperties
    
                Case %IDM_ShowPropertiesLV
                   ListView Get Count hDlg, %IDC_ListView To h
                   ListView Get Select hDlg, %IDC_ListView To i
                   If i Then
                      ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
                      MessageBox(0, (ItemProperties(h-i+1)), "Show Item Properties", %MB_Ok + %MB_IconInformation + %MB_TaskModal)
                      UnhookWindowsHookEx ghHook
                   End If
    
                Case %IDM_ReplaceSelectedItemsText : ReplaceSelectedItemsText
    
                Case %IDM_SetSelectedColor : SetSelectedColor
    
                Case %IDM_Debug
                   Debug = Debug Xor 1
                   If Debug Then
                      Txt.Window "Debug", 300,300,40,40 To hTxtWin
                   Else
                      Txt.End
                   End If
    
                Case %IDM_SnapToGrid, %IDT_Snap
                   SnapToGrid = SnapToGrid Xor 1
                   SetMenusAndToolbar
    
                Case %IDM_SnapHalf
                   SnapHalf = SnapHalf Xor 1
                   SetMenusAndToolbar
    
                Case %IDM_RoundedBox
                   Rounded = Rounded Xor 1
                   SetMenusAndToolbar
                   DrawLayout
    
                Case %IDM_BGColor   : BGColor = SelectColor(BGColor)  :  DrawHiddenGrids : DrawLayout
                Case %IDM_FGColor   : FGColor = SelectColor(FGColor)  :  DrawHiddenGrids : DrawLayout
    
                Case %IDM_RulerColor  : RulerColor = SelectColor(GridColor) :  DrawHiddenGrids : DrawLayout
                Case %IDM_GridColor   : GridColor = SelectColor(GridColor)  :  DrawHiddenGrids : DrawLayout
    
                Case %IDM_DefaultColors
                   BGColor = %White : FGColor = %Black : RulerColor = %Red : GridColor = %rgb_LightGray
                   DrawHiddenGrids
                   DrawLayout
    
                Case %IDM_CopyList  : CopyList
                Case %IDM_PrintList : PrintList
    
                Case %IDM_UnselectAllItems
                   UnSelectAll
                   FillListView
                   DrawLayout
    
                Case %IDM_SelectAllItems
                   SelectAll
                   FillListView
                   DrawLayout
    
                Case %IDM_OpenLibraryFolder
                   i = ShellExecute(hDlg, "Open", PathName$(Path,$LibraryImages), $Nul, $Nul, %SW_ShowNormal)
    
                Case %IDM_OpenLibraryFolder
                   i = ShellExecute(hDlg, "Open", PathName$(Path,$LayoutFiles), $Nul, $Nul, %SW_ShowNormal)
    
                Case %IDM_EditLibrary
                   i = ShellExecute(hDlg, "Open", ($LibraryFile), $Nul, $Nul, %SW_ShowNormal)
    
                Case %IDM_LoadLibrary
                   LoadLibraryFile
                   DisplayItemImagesForSelectedCategory
    
                Case %IDM_Up    : MoveSelected   0, -1
                Case %IDM_Down  : MoveSelected   0,  1
                Case %IDM_Left  : MoveSelected  -1,  0
                Case %IDM_Right : MoveSelected   1,  0
    
                Case %IDM_LocalHelp    : DisplayLocalHelp
                Case %IDM_OnlineUpdate : CheckForEXEUpdates($ver)
    
                Case %IDM_ImportMenu To %IDM_ImportMenu + 999
                   Menu Get Text hImport, ByCmd Cb.Ctl To temp$
                   temp$ = Exe.Path$ + "layouts\" + temp$ + ".dat"
                   If IsFalse(IsFile(temp$)) Then Exit Select
                   ImportLayout(temp$,0) : FillListView : DrawLayout : Dirty = 1
    
                Case %IDM_LayoutMenu To %IDM_LayoutMenu + 999
                   Menu Get Text hOpen, ByCmd Cb.Ctl To temp$
                   temp$ = Exe.Path$ + "layouts\" + temp$ + ".dat"
                   If IsFalse(IsFile(temp$)) Then Exit Select
                   i = 1
                   If Dirty Then
                      ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
                      Select Case MessageBox(0, "File has changed. Save changes before opening new file?", "Open Layout", %MB_YesNoCancel + %MB_IconQuestion + %MB_TaskModal)
                         Case %IdYes    : SaveLayout(FileName,1)
                         Case %IdNo     : 'no action
                         Case %IdCancel : i = 0
                      End Select
                      UnhookWindowsHookEx ghHook
                   End If
                   If i Then
                      FileName = temp$ : LoadLayout(FileName) : FillListview : DrawLayout : Dirty = 0
                   End If
    
                Case %IDM_SummaryDisplay : SummaryReport "display"
                Case %IDM_SummaryCopy    : SummaryReport "copy"
                Case %IDM_SummaryPrint   : SummaryReport "print"
    
                Case %IDM_Test
    
             End Select
    
          Case %WM_Notify
             If Cb.NmCode = %TTN_GetDispInfo Then
                PTT = Cb.LParam
                @PTT.@lpszText = SetToolTips(Cb.NmId)
             End If
    
             Select Case Cb.NmId
                Case %IDC_ListView
                   Select Case Cb.NmCode
                      Case %NM_Click
                         GetCursorPos LVHT.pt
                         ScreenToClient hListView, LVHT.pt
                         Control Send hDlg, %IDC_ListView, %LVM_SubItemHitTest, 0, VarPtr(LVHT)
                         i = UndoPos-LVHT.iItem
                         If i < 1 Or i > UndoPos Then Exit Select
                         If (LVHT.pt.x < 5) Or (LVHT.pt.x > 17) Then
                            DisplayLayoutIteminStatusbar(i)
                         Else
                            D(i).selected = D(i).selected Xor 1
                            DrawLayout
                         End If
    
                      Case %NM_DblClk
                         ListView Get Select hDlg, %IDC_ListView To i
                         If i Then
                            EditPos = UndoPos-1+1
                            DisplayEditDialog : FillListview : DrawLayout
                         End If
    
                   End Select
                Case %IDC_ToolbarB
                   Select Case Cb.NmCode
                      Case %TBN_DROPDOWN
                         nmtb = Cb.LParam
                         Select Case @nmtb.iItem
                            Case %IDT_Zoom
                               SendMessage(hToolbarB, %TB_GETRECT, @nmtb.iItem, VarPtr(rc))
                               MapWindowPoints(hToolbarB, %HWND_Desktop, ByVal VarPtr(rc), 2)
                               Call TrackPopupMenu (hZoom, 0, rc.nLeft, rc.nBottom, 0, CbHndl, ByVal %Null)
                         End Select
                   End Select
                Case %IDC_Toolbar
                   Select Case Cb.NmCode
                      Case %TBN_DROPDOWN
                         nmtb = Cb.LParam
                         Select Case @nmtb.iItem
                            Case %IDT_Import
                               SendMessage(hToolbar, %TB_GETRECT, @nmtb.iItem, VarPtr(rc))
                               MapWindowPoints(hToolbar, %HWND_Desktop, ByVal VarPtr(rc), 2)
                               CreateImportMenu
                               Call TrackPopupMenu (hImport, 0, rc.nLeft, rc.nBottom, 0, CbHndl, ByVal %Null)
                            Case %IDT_Open
                               SendMessage(hToolbar, %TB_GETRECT, @nmtb.iItem, VarPtr(rc))
                               MapWindowPoints(hToolbar, %HWND_Desktop, ByVal VarPtr(rc), 2)
                               CreateLayoutMenu   'build real time from files in "layout" folder
                               Call TrackPopupMenu (hOpen, 0, rc.nLeft, rc.nBottom, 0, CbHndl, ByVal %Null)
                            Case %IDT_Settings
                               SendMessage(hToolbar, %TB_GETRECT, @nmtb.iItem, VarPtr(rc))
                               MapWindowPoints(hToolbar, %HWND_Desktop, ByVal VarPtr(rc), 2)
                               Call TrackPopupMenu (hSettings, 0, rc.nLeft, rc.nBottom, 0, CbHndl, ByVal %Null)
                            Case %IDT_Help
                               SendMessage(hToolbar, %TB_GETRECT, @nmtb.iItem, VarPtr(rc))
                               MapWindowPoints(hToolbar, %HWND_Desktop, ByVal VarPtr(rc), 2)
                               Call TrackPopupMenu (hHelp, 0, rc.nLeft, rc.nBottom, 0, CbHndl, ByVal %Null)
                         End Select
                   End Select
          End Select
       End Select
    End Function
    
    Sub CreateListView
       If Debug Then Txt.Print FuncName$
       Control Add Label, hDlg, %IDC_LabelLV, "Layout Content", 110, %TBM,150,15
       Control Add ListView, hDlg, %IDC_ListView, "", 110,%TBM+20,200,80,%WS_TabStop Or %LVS_Report Or %LVS_ShowSelAlways Or %LVS_SingleSel, %WS_Ex_Left Or %WS_Ex_ClientEdge
       Control Handle hDlg, %IDC_ListView To hListView
       ListView Insert Column hDlg, %IDC_ListView, 1, "Description", 90, 0
       ListView Insert Column hDlg, %IDC_ListView, 2, "Size (Ft)", 110, 0
       ListView Insert Column hDlg, %IDC_ListView, 3, "Size (In)", 110, 0
       ListView Set StyleXX hDlg, %IDC_ListView, %LVS_Ex_CheckBoxes Or %LVS_Ex_GridLines Or %LVS_Ex_FullRowSelect 'Or %LVS_Ex_DoubleBuffer
    End Sub
    
    Function SetToolTips(cID As Long) As String
    '   If Debug Then Txt.Print FuncName$   '<--- disabled by choice
       Select Case cID         'or this:   @P.hdr.idFrom
          Case %IDT_Open        : Function = "Open Existing Layout"
          Case %IDT_Import      : Function = "Add Content of Existing File to Current Layout"
          Case %IDT_New         : Function = "Create New Layout
          Case %IDT_SaveAs      : Function = "Save Layout As"
          Case %IDT_Save        : Function = "Save Layout As Current File Name (No Confirmation)"
          Case %IDT_ShowListView: Function = "Show Layout Content"
          Case %IDT_ShowLibrary : Function = "Show Library Selections"
          Case %IDT_Ruler       : Function = "Dipslay Ruler in Layout"
          Case %IDT_Grid        : Function = "Show Grid Marks"
          Case %IDT_Snap        : Function = "Set Coordinates to Grid Values"
          Case %IDT_ShowDesc    : Function = "Display Item Description in Layout"
          Case %IDT_ShowImages  : Function = "Display Item Images in Layout"
          Case %IDT_CopyImage   : Function = "Copy Visible Drawing Image to Clipboard"
          Case %IDT_Print       : Function = "Print Drawing"
          Case %IDT_Settings    : Function = "Settings"
          Case %IDT_Help        : Function = "Open Online Help"
    
          Case %IDT_Clear       : Function = "Clear Drawing"
          Case %IDT_Cut         : Function = "Copy Selected Items, Then Remove From Layout"
          Case %IDT_Copy        : Function = "Copy Selected Items to Internal Clipboard"
          Case %IDT_Paste       : Function = "Paste Items from Internal Clipboard"
          Case %IDT_Delete      : Function = "Delete Selected Drawing Items"
          Case %IDT_Zoom        : Function = "Cycle Through Zoom Values"
          Case %IDT_Duplicate   : Function = "Create Duplicate of Selected Items"
          Case %IDT_Undo        : Function = "Remove Last Added Item"
          Case %IDT_Redo        : Function = "Restore Last Removed Item"
          Case %IDT_Truncate    : Function = "Remove Higher Items in Undo Stack "
    
    
          Case %IDT_Select      : Function = "Select Items in Drawing"
          Case %IDT_Box         : Function = "Draw Box in Drawing"
          Case %IDT_Circle      : Function = "Draw Circle/Ellipse in Drawing"
          Case %IDT_Line        : Function = "Draw Line in Drawing"
          Case %IDT_Font        : Function = "Select Text Drawing Font"
          Case %IDT_3D          : Function = "Display Layout in 3D Format"
       End Select
    End Function
    
    
    Sub CreateToolbar
        If Debug Then Txt.Print FuncName$
        ImageList New Icon 24,24,24,40 To hTBImageList
        ImageList Add Icon hTBImageList, "xopen"      '1
        ImageList Add Icon hTBImageList, "xsave"      '2
        ImageList Add Icon hTBImageList, "xempty"     '3
        ImageList Add Icon hTBImageList, "xselect"    '4
        ImageList Add Icon hTBImageList, "xzoom"      '5
        ImageList Add Icon hTBImageList, "xbox"       '6
        ImageList Add Icon hTBImageList, "xcircle"    '7
        ImageList Add Icon hTBImageList, "xline"      '8
        ImageList Add Icon hTBImageList, "xobject"    '9
        ImageList Add Icon hTBImageList, "xduplicate" '10
        ImageList Add Icon hTBImageList, "xxprint"    '11
        ImageList Add Icon hTBImageList, "xsettings"  '12
        ImageList Add Icon hTBImageList, "xhelp"      '13
        ImageList Add Icon hTBImageList, "xdelete"    '14
        ImageList Add Icon hTBImageList, "xfont"      '15
        ImageList Add Icon hTBImageList, "xtext"      '16
        ImageList Add Icon hTBImageList, "xgrid"      '17
        ImageList Add Icon hTBImageList, "xsnap"      '18
        ImageList Add Icon hTBImageList, "xundo"      '19
        ImageList Add Icon hTBImageList, "xredo"      '20
        ImageList Add Icon hTBImageList, "xruler"     '21
        ImageList Add Icon hTBImageList, "xcontent"   '22
        ImageList Add Icon hTBImageList, "xtitle"     '23
        ImageList Add Icon hTBImageList, "xtruncate"  '24
        ImageList Add Icon hTBImageList, "xmove"      '25
        ImageList Add Icon hTBImageList, "xcube"      '26
        ImageList Add Icon hTBImageList, "xcapture"   '27
        ImageList Add Icon hTBImageList, "ximport"    '28
        ImageList Add Icon hTBImageList, "xnew"       '29
        ImageList Add Icon hTBImageList, "xlibrary"   '30
        ImageList Add Icon hTBImageList, "xcut"       '31
        ImageList Add Icon hTBImageList, "xpaste"     '32
    
        Control Add Toolbar, hDlg, %IDC_Toolbar,"", 0,0,0,0, %TbStyle_Tooltips Or %TbStyle_Flat Or %WS_Child
        Control Handle hDlg, %IDC_Toolbar To hToolbar
        SendMessage hToolbar, %TB_SETEXTENDEDSTYLE, 0, %TBSTYLE_EX_DRAWDDARROWS
        Toolbar Set ImageList hDlg, %IDC_Toolbar, hTBImageList, 0
    
        Toolbar Add Button  hDlg, %IDC_Toolbar, 1, %IDT_Open, %BTNS_Button + %BTNS_DropDown, "Open"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 29, %IDT_New, %BTNS_Button, "New"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 2, %IDT_Save, %BTNS_Button, "Save"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 2, %IDT_SaveAs, %BTNS_Button, "SaveAs"
        Toolbar Add Separator hDlg, %IDC_Toolbar, 20
        Toolbar Add Button  hDlg, %IDC_Toolbar, 28, %IDT_Import, %BTNS_Button Or %BTNS_DropDown, "Import"
        Toolbar Add Separator hDlg, %IDC_Toolbar, 20
        Toolbar Add Button  hDlg, %IDC_Toolbar, 30, %IDT_ShowLibrary, %BTNS_Check, "Library"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 22, %IDT_ShowListView, %BTNS_Check, "Content"
        Toolbar Add Separator hDlg, %IDC_Toolbar, 20
        Toolbar Add Button  hDlg, %IDC_Toolbar, 21, %IDT_Ruler, %BTNS_Check, "Ruler"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 17, %IDT_Grid, %BTNS_Check, "Grid"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 18, %IDT_Snap, %BTNS_Check, "Snap"
        Toolbar Add Separator hDlg, %IDC_Toolbar, 20
        Toolbar Add Button  hDlg, %IDC_Toolbar, 23, %IDT_ShowDesc, %BTNS_Check, "Desc"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 9, %IDT_ShowImages, %BTNS_Check, "Images"
        Toolbar Add Separator hDlg, %IDC_Toolbar, 20
        Toolbar Add Button  hDlg, %IDC_Toolbar, 12, %IDT_Settings,  %BTNS_Button Or %BTNS_DropDown, "Settings"
        Toolbar Add Button  hDlg, %IDC_Toolbar, 13, %IDT_Help,  %BTNS_Button Or %BTNS_DropDown, "Help"
    End Sub
    
    Sub CreateToolbarB
        If Debug Then Txt.Print FuncName$
        Control Add Toolbar, hDlg, %IDC_ToolbarB,"", 0,%TBM/2,0,0, %CCS_NoMoveY Or %TbStyle_Tooltips Or %TbStyle_Flat Or %WS_Child
        Control Handle hDlg, %IDC_ToolbarB To hToolbarB
        SendMessage hToolbarB, %TB_SETEXTENDEDSTYLE, 0, %TBSTYLE_EX_DRAWDDARROWS
        Toolbar Set ImageList hDlg, %IDC_ToolbarB, hTBImageList, 0
    
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 3, %IDT_Clear, %BTNS_Button, "Clear"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 24, %IDT_Truncate, %BTNS_Button, "Truncate"
        Toolbar Add Separator hDlg, %IDC_ToolbarB, 20
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 31, %IDT_Cut, %BTNS_Button, "Cut"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 10, %IDT_Copy, %BTNS_Button, "Copy"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 32, %IDT_Paste, %BTNS_Button, "Paste"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 14, %IDT_Delete, %BTNS_Button, "Delete"
        Toolbar Add Separator hDlg, %IDC_ToolbarB, 20
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 5, %IDT_Zoom, %BTNS_Button Or %BTNS_Dropdown, "Zoom"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 10, %IDT_Duplicate, %BTNS_Button, "Duplicate"
        Toolbar Add Separator hDlg, %IDC_ToolbarB, 20
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 19, %IDT_Undo, %BTNS_Button, "Remove"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 20, %IDT_Redo, %BTNS_Button, "Restore"
        Toolbar Add Separator hDlg, %IDC_ToolbarB, 20
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 4, %IDT_Select, %BTNS_CheckGroup, "Select"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 6, %IDT_Box, %BTNS_CheckGroup, "Box"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 7, %IDT_Circle, %BTNS_CheckGroup, "Circle"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 8, %IDT_Line, %BTNS_CheckGroup, "Line"
        Toolbar Add Separator hDlg, %IDC_ToolbarB, 20
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 27, %IDT_CopyImage, %BTNS_Button, "Capture"
        Toolbar Add Button  hDlg, %IDC_ToolbarB, 11, %IDT_Print, %BTNS_Button, "Print"
         Toolbar Add Button  hDlg, %IDC_ToolbarB, 26, %IDT_3D, %BTNS_Button, "3D"
    End Sub
    
    Sub CreateStatusBar
       If Debug Then Txt.Print FuncName$
       Control Add Statusbar, hDlg, %IDC_Statusbar, "",0,0,0,0
       Statusbar Set Parts hDlg, %IDC_Statusbar, 200,99999
       Statusbar Set Text hDlg, %IDC_Statusbar, 1, 0, ""
       Statusbar Set Text hDlg, %IDC_Statusbar, 2, 0, "Welcome to gbFloorplanner!"
    End Sub
    
    Sub CreateGraphic
       If Debug Then Txt.Print FuncName$
       Control Add Graphic, hDlg, %IDC_Graphic,"", 205,%TBM+5,400,400, %SS_Notify, %WS_Ex_ClientEdge
       Control Handle hDlg, %IDC_Graphic To hGraphic
       OldGraphicProc = SetWindowLong(hGraphic, %GWL_WndProc, CodePtr(GraphicProc))
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
       Graphic Get DC To hDC
       Graphic Set Virtual 2400,2400
       Graphic Color %Black, %White
       Graphic Set Overlap
       Graphic Set Mix %R2_CopyPen
    End Sub
    
    Sub CreateGridGraphicControls
       Graphic Bitmap New 2400, 2400 To hDotGraphic
       Graphic Attach hDotGraphic, 0, ReDraw
       Graphic Color %Black, %White
       Graphic Clear
       Graphic Set Overlap
    
       Graphic Bitmap New 2400, 2400 To hLineGraphic
       Graphic Attach hLineGraphic, 0, ReDraw
       Graphic Color %Black, %White
       Graphic Clear
       Graphic Set Overlap
    End Sub
    
    Sub CreateFonts
       If Debug Then Txt.Print FuncName$
       Font New "Tahoma",10,0 To hFont
       Font New "Tahoma",10,1 To hFontB
       Font New "Tahoma",10,0,1,0,900 To hFontRot
    
       Control Set Font hDlg, %IDC_Toolbar, hFont
       Control Set Font hDlg, %IDC_ToolbarB, hFont
       Control Set Font hDlg, %IDC_ListView, hFont
       Control Set Font hDlg, %IDC_ComboBox, hFont
       Control Set Font hDlg, %IDC_Toolbar, hFont
       Control Set Font hDlg, %IDC_Statusbar, hFont
       Control Set Font hDlg, %IDC_Graphic, hFont
       Control Set Font hDlg, %IDC_Preview, hFont
    
       Control Set Font hDlg, %IDC_LabelLib, hFontB
       Control Set Font hDlg, %IDC_LabelLV, hFontB
    End Sub
    
    Sub DrawLayout
       If Debug Then Txt.Print FuncName$
    '   QueryPerformanceCounter qStart
       Graphic Clear BGColor
       If ShowGrid And GridLines   Then Graphic Copy hLineGraphic, 0
       If ShowGrid And GridLines=0 Then Graphic Copy hDotGraphic, 0
       If ShowRuler Then DrawRulers      'feet or pixels, per settings
       DrawObjects                       'all objects boxes, circles, lines, images
       Graphic ReDraw
    '   QueryPerformanceCounter qStop
    '   Statusbar Set Text hDlg, %IDC_Statusbar, 2, 0, Format$((qStop-qStart)/qFreq,"###.000") & " seconds"
    End Sub
    
    Sub DrawHiddenGrids
       If Debug Then Txt.Print FuncName$
       Local i,j,w,h As Long
       w = 2400 : h = 2400
    
       Graphic Attach hLineGraphic, 0, ReDraw
       Graphic Clear BGColor
       For i = 0 To w Step PPC*2 : Graphic Box (i,0)-(i+PPC,h),,GridColor : Next i
       For i = 0 To h Step PPC*2 : Graphic Box (0,i)-(h,i+PPC),,GridColor : Next i
       Graphic ReDraw
    
       Graphic Attach hDotGraphic, 0, ReDraw
       Graphic Clear BGColor
       For i = 0 To w Step PPC
          For j = 0 To h Step PPC
             Graphic Line (i-1,j)-(i+1,j),GridColor
             Graphic Line (i,j-1)-(i,j+1),GridColor
          Next j
       Next i
       Graphic ReDraw
    
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
    End Sub
    
    Sub DrawRulers
       If Debug Then Txt.Print FuncName$
       Local i,j,w,h As Long
       Graphic Get Canvas To w,h
       Graphic Set Font hFont
       Graphic Color RulerColor, -2
       For i = PPC To w Step PPC
          Incr j
          Graphic Set Pos (i-10,5)
          If j * FPC < 10 Then Graphic Set Pos Step (3,0)
          If MinRuler Then
             If j * FPC Mod 10 = 0 Then Graphic Print j * FPC
          Else
             Select Case SF
                Case 4,10,20
                   If j*FPC > 100 Then
                      If (j*FPC) Mod 10 = 0 Then Graphic Print j * FPC
                   Else
                      Graphic Print j * FPC
                   End If
                Case 40,60 : Graphic Print j * FPC
             End Select
          End If
       Next i
       j = 0
       For i = PPC To h Step PPC
          Graphic Set Pos (5,i-5-3)
          Incr j
          If MinRuler Then
             If j * FPC Mod 10 = 0 Then Graphic Print j * FPC
          Else
             Graphic Print j * FPC
          End If
       Next i
       Graphic Set Pos (0,0)
       Graphic Print "Ft"
    End Sub
    
    Sub DrawObjects
       If Debug Then Txt.Print FuncName$
       Local i,FG As Long
       Graphic Style 0 : Graphic Width 3 : Graphic Set Mix %R2_CopyPen
       PTS.count = 4
       For i = 1 To UndoPos
          FG = IIf(D(i).selected,SelectedColor,D(i).fgcolor)
          Select Case D(i).shape
             Case %Box
                If D(i).showborder Or D(i).selected Then
                   If D(i).bgtransparent Then
                      'overrides all other setting
                      If D(i).theta Then
                         GetRotatedPolygonPoints(i)
                         Graphic Polygon PTS,FG,-2,0
                      Else
                         Graphic Box (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),D(i).rounded*20,FG,-2,0
                         'Graphic Box (x0,y0)-(x,y),D(i).rounded*20,FG,-2,0
                      End If
                   ElseIf D(i).fillstyle = 0 Then
                      'solid with no hatching
                      If D(i).theta Then
                         GetRotatedPolygonPoints(i)
                         Graphic Polygon PTS,FG,D(i).bgColor, D(i).fillstyle
                      Else
                         Graphic Box (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),D(i).rounded*20,FG,D(i).bgColor, D(i).fillstyle
                      End If
                   Else
                      Graphic Color D(i).fgcolor, D(i).bgcolor
                      If D(i).theta Then
                         GetRotatedPolygonPoints(i)
                         Graphic Polygon PTS,FG,D(i).fgcolor,D(i).fillstyle
                      Else
                         Graphic Box (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),D(i).rounded*20,FG,D(i).fgcolor,D(i).fillstyle
                      End If
                   End If
                End If
                If D(i).selected Then DrawSelectionMarkers(i)
                If ShowImages And D(i).showimage And Len(D(i).img) Then DrawImage(i)
                If ShowDesc   And D(i).showdesc Then DrawItemText(i)
             Case %Circle
                If D(i).showborder Or D(i).selected Then
                   If D(i).bgtransparent Then
                      'overrides all other settings
                      Graphic Ellipse (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),FG, -2, 0
                   ElseIf D(i).fillstyle = 0 Then
                      'solid with no hatching
                      Graphic Ellipse (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),FG, D(i).bgcolor, D(i).fillstyle
                   Else
                      Graphic Color D(i).fgcolor, D(i).bgColor
                      Graphic Ellipse (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),FG, D(i).fgcolor, D(i).fillstyle
                   End If
                End If
                If D(i).selected Then DrawSelectionMarkers(i)
                If ShowImages And D(i).showimage And Len(D(i).img) Then
                   DrawImage(i)
    '               Graphic Ellipse (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),FG, -2, 0
                End If
                If ShowDesc   And D(i).showdesc Then DrawItemText(i)
             Case %Line
                Graphic Color FGColor, BGColor
                If D(i).theta Then
                   GetRotatedPolygonPoints(i)
                   Graphic Line (PTS.x1,PTS.y1)-(PTS.x3,PTS.y3),FG
                Else
                   Graphic Line (D(i).rect.nLeft*SF/D(i).SF,D(i).rect.nTop*SF/D(i).SF)-(D(i).rect.nRight*SF/D(i).SF,D(i).rect.nBottom*SF/D(i).SF),FG
                End If
                If D(i).selected Then DrawSelectionMarkers(i)
                If ShowDesc And D(i).ShowDesc Then DrawItemText(i)
          End Select
       Next i
    End Sub
    
    Sub GetRotatedPolygonPoints(i As Long)
       Local x0,y0,x,y,cx,cy As Long
       x0 = D(i).rect.nLeft'*SF/D(i).SF
       y0 = D(i).rect.nTop'*SF/D(i).SF
       x  = D(i).rect.nRight'*SF/D(i).SF
       y  = D(i).rect.nBottom'*SF/D(i).SF
       cx = (x0+x)/2 : cy = (y0+y)/2
       PTS.x1 = x0-cx : PTS.y1 = y0-cy : RotateAboutZAxis (D(i).theta, PTS.x1,PTS.y1) : PTS.x1 += cx : PTS.y1+=cy
       PTS.x2 = x-cx  : PTS.y2 = y0-cy : RotateAboutZAxis (D(i).theta, PTS.x2,PTS.y2) : PTS.x2 += cx : PTS.y2+=cy
       PTS.x3 = x-cx  : PTS.y3 = y-cy  : RotateAboutZAxis (D(i).theta, PTS.x3,PTS.y3) : PTS.x3 += cx : PTS.y3+=cy
       PTS.x4 = x0-cx : PTS.y4 = y-cy  : RotateAboutZAxis (D(i).theta, PTS.x4,PTS.y4) : PTS.x4 += cx : PTS.y4+=cy
       PTS.x1 *=SF/D(i).SF : PTS.y1 *=SF/D(i).SF
       PTS.x2 *=SF/D(i).SF : PTS.y2 *=SF/D(i).SF
       PTS.x3 *=SF/D(i).SF : PTS.y3 *=SF/D(i).SF
       PTS.x4 *=SF/D(i).SF : PTS.y4 *=SF/D(i).SF
    End Sub
    
    Sub DrawItemText(i As Long)  'iPos = D(iPos)
       If Debug Then Txt.Print FuncName$
       Local x,y,w,h As Long
       Graphic Color D(i).desccolor, -2
       Graphic Text Size D(i).desc To w,h
       If D(i).textrot Then
          Graphic Set Font hFontRot
          Select Case D(i).textpos
             Case %Top     'Left for rotated text
                x = D(i).rect.nLeft*SF/D(i).SF  + 5
                y = (D(i).rect.nBottom*SF/D(i).SF + (D(i).rect.nTop*SF/D(i).SF - D(i).rect.nTop*SF/D(i).SF-h)/2)
                'Graphic Set Pos  (D(i).rect.nLeft*SF/D(i).SF  + 5, (D(i).rect.nBottom*SF/D(i).SF + (D(i).rect.nTop*SF/D(i).SF - D(i).rect.nTop*SF/D(i).SF-h)/2))
             Case %Center  'Center for rotated text
                x = D(i).rect.nLeft*SF/D(i).SF  + (D(i).rect.nRight*SF/D(i).SF-D(i).rect.nLeft*SF/D(i).SF-h)/2
                y = D(i).rect.nBottom*SF/D(i).SF + (D(i).rect.nTop*SF/D(i).SF - D(i).rect.nTop*SF/D(i).SF-w)/2
                'Graphic Set Pos  (D(i).rect.nLeft*SF/D(i).SF  + (D(i).rect.nRight*SF/D(i).SF-D(i).rect.nLeft*SF/D(i).SF-h)/2, (D(i).rect.nBottom*SF/D(i).SF + (D(i).rect.nTop*SF/D(i).SF - D(i).rect.nTop*SF/D(i).SF-w)/2))
             Case %Bottom  'Right for rotated text
                x = D(i).rect.nRight*SF/D(i).SF - 20
                y = D(i).rect.nBottom*SF/D(i).SF + (D(i).rect.nTop*SF/D(i).SF - D(i).rect.nTop*SF/D(i).SF-h)/2
                'Graphic Set Pos  (D(i).rect.nRight*SF/D(i).SF - 20,(D(i).rect.nBottom*SF/D(i).SF + (D(i).rect.nTop*SF/D(i).SF - D(i).rect.nTop*SF/D(i).SF-h)/2))
          End Select
       Else
          Graphic Set Font hFont
          Select Case D(i).textpos
             Case %Top
                x = D(i).rect.nLeft*SF/D(i).SF + (D(i).rect.nRight*SF/D(i).SF - D(i).rect.nLeft*SF/D(i).SF-w)/2
                y = D(i).rect.nTop*SF/D(i).SF  + 5
                'Graphic Set Pos  (D(i).rect.nLeft*SF/D(i).SF + (D(i).rect.nRight*SF/D(i).SF - D(i).rect.nLeft*SF/D(i).SF-w)/2, D(i).rect.nTop*SF/D(i).SF  + 5)
             Case %Center
                x = D(i).rect.nLeft*SF/D(i).SF + (D(i).rect.nRight*SF/D(i).SF - D(i).rect.nLeft*SF/D(i).SF-w)/2
                y = D(i).rect.nTop*SF/D(i).SF  + (D(i).rect.nBottom*SF/D(i).SF-D(i).rect.nTop*SF/D(i).SF-h)/2
                'Graphic Set Pos  (D(i).rect.nLeft*SF/D(i).SF + (D(i).rect.nRight*SF/D(i).SF - D(i).rect.nLeft*SF/D(i).SF-w)/2, D(i).rect.nTop*SF/D(i).SF  + (D(i).rect.nBottom*SF/D(i).SF-D(i).rect.nTop*SF/D(i).SF-h)/2)
             Case %Bottom
                x = D(i).rect.nLeft*SF/D(i).SF + (D(i).rect.nRight*SF/D(i).SF - D(i).rect.nLeft*SF/D(i).SF-w)/2
                y = D(i).rect.nBottom*SF/D(i).SF - 20
                'Graphic Set Pos  (D(i).rect.nLeft*SF/D(i).SF + (D(i).rect.nRight*SF/D(i).SF - D(i).rect.nLeft*SF/D(i).SF-w)/2, D(i).rect.nBottom*SF/D(i).SF - 20)
          End Select
       End If
       Graphic Set Pos (x,y)
       If InStr(D(i).desc,"|") Then
          For w = 1 To ParseCount(D(i).desc,"|")
             Graphic Print Parse$(D(i).desc,"|",w)
          Next i
       Else
          Graphic Print D(i).desc
       End If
    End Sub
    
    Function PtInResizeMarkers(pt As Point, R As Rect) As Long
       Local tempR As Rect
       tempR.nLeft   = R.nLeft-MSize
       tempR.nTop    = R.nTop-MSize
       tempR.nRight  = R.nLeft
       tempR.nBottom = R.nTop
       If PtInRect(tempR,pt) Then ResizeMarker = 1 : Function = 1 : Exit Function
    
       tempR.nLeft   = R.nRight
       tempR.nTop    = R.nTop-MSize
       tempR.nRight  = R.nRight+MSize
       tempR.nBottom = R.nTop
       If PtInRect(tempR,pt) Then ResizeMarker = 2 : Function = 1 : Exit Function
    
       tempR.nLeft   = R.nRight
       tempR.nTop    = R.nBottom
       tempR.nRight  = R.nRight+MSize
       tempR.nBottom = R.nBottom+MSize
       If PtInRect(tempR,pt) Then ResizeMarker = 3 : Function = 1 : Exit Function
    
       tempR.nLeft   = R.nLeft-MSize
       tempR.nTop    = R.nBottom
       tempR.nRight  = R.nLeft
       tempR.nBottom = R.nBottom+MSize
       If PtInRect(tempR,pt) Then ResizeMarker = 4 : Function = 1 : Exit Function
    
    End Function
    
    Sub DrawSelectionMarkers(i As Long)
       'draw baby boxes
       If D(i).shape = %Line Then
          Graphic Box (D(i).rect.nLeft* SF/D(i).sf-MSize,D(i).rect.nTop* SF/D(i).sf-MSize)-(D(i).rect.nLeft* SF/D(i).sf,D(i).rect.nTop* SF/D(i).sf),,%Red,%Red
          Graphic Box (D(i).rect.nRight* SF/D(i).sf,D(i).rect.nBottom* SF/D(i).sf)-(D(i).rect.nRight* SF/D(i).sf+MSize,D(i).rect.nBottom* SF/D(i).sf+MSize),,%Red,%Red
       Else
          Graphic Box (D(i).rect.nLeft* SF/D(i).sf-MSize,D(i).rect.nTop* SF/D(i).sf-MSize)-(D(i).rect.nLeft* SF/D(i).sf,D(i).rect.nTop* SF/D(i).sf),,%Red,%Red
          Graphic Box (D(i).rect.nRight* SF/D(i).sf,D(i).rect.nTop* SF/D(i).sf-MSize)-(D(i).rect.nRight* SF/D(i).sf+MSize,D(i).rect.nTop* SF/D(i).sf),,%Red,%Red
          Graphic Box (D(i).rect.nLeft* SF/D(i).sf-MSize,D(i).rect.nBottom* SF/D(i).sf)-(D(i).rect.nLeft* SF/D(i).sf,D(i).rect.nBottom* SF/D(i).sf+MSize),,%Red,%Red
          Graphic Box (D(i).rect.nRight* SF/D(i).sf,D(i).rect.nBottom* SF/D(i).sf)-(D(i).rect.nRight* SF/D(i).sf+MSize,D(i).rect.nBottom* SF/D(i).sf+MSize),,%Red,%Red
       End If
    End Sub
    
    Sub Settings_INI(Task$)
       If Debug Then Txt.Print FuncName$
       Local x As Long, y As Long
       Local xResult, yResult, temp, INIFileName As WStringZ*%Max_Path
       INIFileName = Exe.Path$ + Exe.Name$ + ".ini"
       If Task$ = "get" Then
          'get dialog top/left from INI file and use to set Dialog location
          Getprivateprofilestring "All", "Left", "100", xResult, %Max_Path, INIFileName
          Getprivateprofilestring "All", "Top", "100", yResult, %Max_Path, INIFileName
          Dialog Set Loc hDlg, Val(xResult), Val(yResult)   'left/top
    
          'get dialog width/height from INI file and use to set Dialog size
          GetPrivateProfileString "All", "Width", "890", xResult, %Max_Path, INIFileName
          GetPrivateProfileString "All", "Height", "720", yResult, %Max_Path, INIFileName
          Dialog Set Size hDlg,Val(xResult), Val(yResult)   'width/height
    
          'get value for string variables
          Getprivateprofilestring "All", "FileName", Exe.Path$ + "layouts\untitled.dat", FileName, %Max_Path, INIFileName
          Getprivateprofilestring "All", "SelectedFileName", "layouts\selected.dat", SelectedFileName, %Max_Path, INIFileName
          Getprivateprofilestring "All", "FontName", "Tahoma", FontName, %Max_Path, INIFileName
    
          'get value for numeric variables
          Getprivateprofilestring "All", "MSize", "10", temp, %Max_Path, INIFileName:  MSize = Val(temp)
          Getprivateprofilestring "All", "FontSize", "10", temp, %Max_Path, INIFileName:  FontSize = Val(temp)
          Getprivateprofilestring "All", "FontAttr", "0", temp, %Max_Path, INIFileName:  FontAttr = Val(temp)
          Getprivateprofilestring "All", "BGTransparent", "1", temp, %Max_Path, INIFileName: BGTransparent = Val(temp)
          Getprivateprofilestring "All", "BGColor", Str$(%White), temp, %Max_Path, INIFileName: BGColor = Val(temp)
          Getprivateprofilestring "All", "FGColor", Str$(%Black), temp, %Max_Path, INIFileName: FGColor = Val(temp)
          Getprivateprofilestring "All", "SelectedColor", Str$(%Red), temp, %Max_Path, INIFileName: SelectedColor = Val(temp)
          Getprivateprofilestring "All", "AutoSave", "1", temp, %Max_Path, INIFileName: AutoSave = Val(temp)
          Getprivateprofilestring "All", "AutoSelectMode", "1", temp, %Max_Path, INIFileName: AutoSelectMode = Val(temp)
          Getprivateprofilestring "All", "AskConfirmation", "1", temp, %Max_Path, INIFileName: AskConfirmation = Val(temp)
          Getprivateprofilestring "All", "Landscape", "1", temp, %Max_Path, INIFileName: Landscape = Val(temp)
          Getprivateprofilestring "All", "PPC", "25", temp, %Max_Path, INIFileName: PPC = Val(temp)
          Getprivateprofilestring "All", "FPC", "1", temp, %Max_Path, INIFileName: FPC = Val(temp)
          Getprivateprofilestring "All", "SF", "20", temp, %Max_Path, INIFileName: SF = Val(temp)
          Getprivateprofilestring "All", "ShowListView", "0", temp, %Max_Path, INIFileName: ShowListView = Val(temp)
          Getprivateprofilestring "All", "ShowLibrary", "1", temp, %Max_Path, INIFileName: ShowLibrary = Val(temp)
          Getprivateprofilestring "All", "ShowImages", "1", temp, %Max_Path, INIFileName: ShowImages = Val(temp)
          Getprivateprofilestring "All", "ShowDesc", "1", temp, %Max_Path, INIFileName: ShowDesc = Val(temp)
          Getprivateprofilestring "All", "ShowGrid", "1", temp, %Max_Path, INIFileName: ShowGrid = Val(temp)
          Getprivateprofilestring "All", "ShowRuler", "1", temp, %Max_Path, INIFileName: ShowRuler = Val(temp)
          Getprivateprofilestring "All", "MinRuler", "0", temp, %Max_Path, INIFileName: MinRuler = Val(temp)
          Getprivateprofilestring "All", "GridLines", "0", temp, %Max_Path, INIFileName: GridLines = Val(temp)
          Getprivateprofilestring "All", "SnapToGrid", "1", temp, %Max_Path, INIFileName: SnapToGrid = Val(temp)
          Getprivateprofilestring "All", "SnapHalf", "0", temp, %Max_Path, INIFileName: SnapHalf = Val(temp)
          Getprivateprofilestring "All", "DrawMode", "1", temp, %Max_Path, INIFileName: DrawMode = Val(temp)
          Getprivateprofilestring "All", "GridColor", Str$(%rgb_LightGray), temp, %Max_Path, INIFileName: GridColor = Val(temp)
          Getprivateprofilestring "All", "RulerColor", Str$(%Red), temp, %Max_Path, INIFileName: RulerColor = Val(temp)
          Getprivateprofilestring "All", "DescColor", Str$(%rgb_DarkBlue), temp, %Max_Path, INIFileName: DescColor = Val(temp)
          Getprivateprofilestring "All", "Rounded", "0", temp, %Max_Path, INIFileName: Rounded = Val(temp)
          Getprivateprofilestring "All", "LineWidth", "5", temp, %Max_Path, INIFileName: LineWidth = Val(temp)
          Getprivateprofilestring "All", "Dirty", "0", temp, %Max_Path, INIFileName: Dirty = Val(temp)
          Getprivateprofilestring "All", "LastCat", "1", temp, %Max_Path, INIFileName: LastCat = Val(temp)
          Getprivateprofilestring "All", "CaptureNumber", "1", temp, %Max_Path, INIFileName: CaptureNumber = Val(temp)
          Getprivateprofilestring "All", "ZHeight", "50", temp, %Max_Path, INIFileName: ZHeight = Val(temp)
          Getprivateprofilestring "All", "Z0Height", "20", temp, %Max_Path, INIFileName: Z0Height = Val(temp)
    
          For x = 0 To 15
             Getprivateprofilestring "Custom", "CustomColor" + Format$(x,"00"), "", temp, %Max_Path, INIFileName
             CustomColorList.c(x) = Val(temp)
          Next
       End If
    
       If Task$ = "save" Then
          'save dialog size/location unless minimized or maximized
          If IsFalse(IsIconic(hDlg) Or IsZoomed(hDlg)) Then
             Dialog Get Loc hDlg To x,y
             WritePrivateProfileString "All", "Left", Str$(x), INIFileName
             WritePrivateProfileString "All", "Top", Str$(y), INIFileName
             Dialog Get Size hDlg To x,y
             WritePrivateProfileString "All", "Width", Str$(x), INIFileName
             WritePrivateProfileString "All", "Height", Str$(y), INIFileName
          End If
          'save string variables
          WritePrivateProfileString "All", "FileName",FileName, INIFileName
          WritePrivateProfileString "All", "SelectedFileName",SelectedFileName, INIFileName
          WritePrivateProfileString "All", "FontName",FontName, INIFileName
    
          'save numeric variables
          WritePrivateProfileString "All", "MSize", Str$(MSize), INIFileName
          WritePrivateProfileString "All", "FontSize", Str$(FontSize), INIFileName
          WritePrivateProfileString "All", "FontAttr", Str$(FontAttr), INIFileName
          WritePrivateProfileString "All", "BGTransparent", Str$(BGTransparent), INIFileName
          WritePrivateProfileString "All", "BGColor", Str$(BGColor), INIFileName
          WritePrivateProfileString "All", "FBGColor", Str$(FGColor), INIFileName
          WritePrivateProfileString "All", "SelectedColor", Str$(SelectedColor), INIFileName
          WritePrivateProfileString "All", "AutoSave",Str$(AutoSave), INIFileName
          WritePrivateProfileString "All", "AutoSelectMode",Str$(AutoSelectMode), INIFileName
          WritePrivateProfileString "All", "AskConfirmation",Str$(AskConfirmation), INIFileName
          WritePrivateProfileString "All", "Landscape",Str$(Landscape), INIFileName
          WritePrivateProfileString "All", "PPC",Str$(PPC), INIFileName
          WritePrivateProfileString "All", "FPC",Str$(FPC), INIFileName
          WritePrivateProfileString "All", "SF",Str$(SF), INIFileName
          WritePrivateProfileString "All", "ShowListView",Str$(ShowListView), INIFileName
          WritePrivateProfileString "All", "ShowLibrary",Str$(ShowLibrary), INIFileName
          WritePrivateProfileString "All", "ShowImages",Str$(ShowImages), INIFileName
          WritePrivateProfileString "All", "ShowDesc",Str$(ShowDesc), INIFileName
          WritePrivateProfileString "All", "ShowGrid",Str$(ShowGrid), INIFileName
          WritePrivateProfileString "All", "ShowRuler",Str$(ShowRuler), INIFileName
          WritePrivateProfileString "All", "MinRuler",Str$(MinRuler), INIFileName
          WritePrivateProfileString "All", "GridLines",Str$(GridLines), INIFileName
          WritePrivateProfileString "All", "SnapToGrid",Str$(SnapToGrid), INIFileName
          WritePrivateProfileString "All", "SnapHalf",Str$(SnapHalf), INIFileName
          WritePrivateProfileString "All", "DrawMode",Str$(DrawMode), INIFileName
          WritePrivateProfileString "All", "GridColor",Str$(GridColor), INIFileName
          WritePrivateProfileString "All", "RulerColor",Str$(RulerColor), INIFileName
          WritePrivateProfileString "All", "DescColor",Str$(DescColor), INIFileName
          WritePrivateProfileString "All", "Rounded",Str$(Rounded), INIFileName
          WritePrivateProfileString "All", "LineWidth",Str$(LineWidth), INIFileName
          WritePrivateProfileString "All", "Dirty",Str$(Dirty), INIFileName
          WritePrivateProfileString "All", "LastCat",Str$(LastCat), INIFileName
          WritePrivateProfileString "All", "CaptureNumber",Str$(CaptureNumber), INIFileName
          WritePrivateProfileString "All", "ZHeight",Str$(ZHeight), INIFileName
          WritePrivateProfileString "All", "Z0Height",Str$(Z0Height), INIFileName
          For x = 0 To 15
             temp = Str$(CustomColorList.c(x))
             WritePrivateProfileString "Custom", "CustomColor" + Format$(x,"00"), temp, INIFileName
          Next
    
       End If
    End Sub
    
    Sub BuildAcceleratorTable
       If Debug Then Txt.Print FuncName$
       Local cc As Long, ac() As ACCELAPI, hAccelerator As Dword  ' for keyboard accelator table values
       Dim ac(21)
       ac(cc).fvirt = %FVIRTKEY              : ac(cc).key   = %VK_F1 : ac(cc).cmd  = %IDT_Help       : Incr cc
       ac(cc).fvirt = %FVIRTKEY              : ac(cc).key   = %VK_F10: ac(cc).cmd  = %IDM_Debug      : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_A  : ac(cc).cmd  = %IDM_SelectAllItems  : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_B  : ac(cc).cmd  = %IDM_SendBack   : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_C  : ac(cc).cmd  = %IDT_Copy       : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_D  : ac(cc).cmd  = %IDT_Duplicate  : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_E  : ac(cc).cmd  = %IDT_Clear      : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_F  : ac(cc).cmd  = %IDM_SendFront  : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_G  : ac(cc).cmd  = %IDM_AlignSelected : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_H  : ac(cc).cmd  = %IDM_SetZHeight : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_I  : ac(cc).cmd  = %IDM_CapturePNG : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_L  : ac(cc).cmd  = %IDM_ListAllItems : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_N  : ac(cc).cmd  = %IDM_NumberSelectedItems: Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_P  : ac(cc).cmd  = %IDT_Print      : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_R  : ac(cc).cmd  = %IDM_SetTextRotation : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_S  : ac(cc).cmd  = %IDT_Save       : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_T  : ac(cc).cmd  = %IDM_SetTextLoc : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_V  : ac(cc).cmd  = %IDT_Paste      : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_X  : ac(cc).cmd  = %IDT_Cut        : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_W  : ac(cc).cmd  = %IDM_RotateSelected : Incr cc
       ac(cc).fvirt = %FVIRTKEY Or %FCONTROL : ac(cc).key   = %VK_Z  : ac(cc).cmd  = %IDT_Undo       : Incr cc
    
    '   ac(cc).fvirt = %FVIRTKEY : ac(cc).key   = %VK_Up     : ac(cc).cmd   = %IDM_Up     : Incr cc
    '   ac(cc).fvirt = %FVIRTKEY : ac(cc).key   = %VK_Down   : ac(cc).cmd   = %IDM_Down   : Incr cc
    '   ac(cc).fvirt = %FVIRTKEY : ac(cc).key   = %VK_Left   : ac(cc).cmd   = %IDM_Left   : Incr cc
    '   ac(cc).fvirt = %FVIRTKEY : ac(cc).key   = %VK_Right  : ac(cc).cmd   = %IDM_Right  : Incr cc
    
       ac(cc).fvirt = %FVIRTKEY : ac(cc).key   = %VK_Delete : ac(cc).cmd   = %IDT_Delete : Incr cc
       Accel Attach hDlg, AC() To hAccelerator
    End Sub
    
    Sub SaveSession
       If Debug Then Txt.Print FuncName$
       If IsFile($SessionFile) Then Kill $SessionFile
       Open $SessionFile For Binary As #1
       D(0).shape = UndoPos
       D(0).sf = Dirty
       Put #1,,D()
       Close #1
    End Sub
    
    Sub LoadLayout(ByVal fName$)
       If Debug Then Txt.Print FuncName$
       Local i As Long
    
       'load D()
       Open fName$ For Binary As #1
       ReDim D(Lof(1)/SizeOf(ObjectType)-1)
       Get #1,,D()
       Close #1
    
       'imgPos values are invalid, so get new ones
       ReDim Images(0)
       For i = 1 To UBound(D)
          D(i).imgPos = AddImageToImageArray((D(i).img))
       Next i
    
       'extract other paramenters
       UndoPos = D(0).shape
       Dirty = D(0).sf
       Dialog Set Text hDlg, "gbFloorPlanner " + $ver + Space$(10) + FileName
    End Sub
    
    Sub ImportLayout(ByVal fName$, Flag As Long)
       If Debug Then Txt.Print FuncName$
    
       'Get layout file content
       Local i,iCount As Long
       Open fName$ For Binary As #1
       iCount = Lof(1)/SizeOf(ObjectType)-1
       ReDim tempD(iCount) As ObjectType
       Get #1,,tempD()
       Close #1
    
       'imgPos values are invalid, so get new ones
       For i = 1 To UBound(tempD)
          tempD(i).imgPos = AddImageToImageArray((tempD(i).img))
       Next i
    
       'Truncate current layout
       ReDim Preserve D(UndoPos)
       UnSelectAll
    
       'add import file to D()
       iCount = tempD(0).shape   'undopos in the saved layout
       ReDim Preserve D(UBound(D)+iCount)
       For i = 1 To iCount
          D(UndoPos+i) = tempD(i)
          D(UndoPos+i).selected = 1
          If Flag Then OffsetRect D(UndoPos+i).rect, -PPC * D(UndoPos+i).sf / SF, PPC * D(UndoPos+i).sf / SF
       Next i
       DrawMode = %Select
       SetMenusAndToolbar
       UndoPos = UndoPos + iCount
       Dialog Set Text hDlg, "gbFloorPlanner " + $ver + Space$(10) + FileName
    End Sub
    
    Function SBProc(ByVal lMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    '   If Debug Then Txt.Print FuncName$   '<--- disabled by choice
       Local x As Long, y As Long    'MsgBox is approximately 200x200
       CenterOverDialog 200,200,x,y
       If lMsg = %HCBT_ACTIVATE Then
          SetWindowPos wParam, 0, x,y, 0, 0, %SWP_NOSIZE Or %SWP_NOACTIVATE Or %SWP_NOZORDER
          UnhookWindowsHookEx ghHook
       End If
    End Function
    
    Sub CenterOverDialog(BoxX As Long, BoxY As Long, CenterX As Long, CenterY As Long)
       If Debug Then Txt.Print FuncName$
       'gets top/left position to center Box over Dialog
       'you need to know, or at least estimate, the Box size
       Local x As Long, y As Long, w As Long, h As Long
       Dialog Get Loc hDlg To x,y
       Dialog Get Size hDlg To w,h
       CenterX = x + (w-BoxX)/2
       CenterY = y + (h-BoxY)/2
    End Sub
    
    Sub CreateSubFolders
       If Debug Then Txt.Print FuncName$
       If IsFolder (Exe.Path$ + "3d") = %False Then MkDir Exe.Path$ + "3d"
       If IsFolder (Exe.Path$ + "files") = %False Then MkDir Exe.Path$ + "files"
       If IsFolder (Exe.Path$ + "icons") = %False Then MkDir Exe.Path$ + "icons"
       If IsFolder (Exe.Path$ + "tempfiles") = %False Then MkDir Exe.Path$ + "tempfiles"
       If IsFolder (Exe.Path$ + "images") = %False Then MkDir Exe.Path$ + "images"
       If IsFolder (Exe.Path$ + "layouts") = %False Then MkDir Exe.Path$ + "layouts"
    End Sub
    
    Function SelectColor(startcolor&) As Long    'works on pControl
       If Debug Then Txt.Print FuncName$
       Local ColorResult&
       Display Color hDlg, 200, 200, startcolor&, CustomColorList ,0 To ColorResult&
       If ColorResult& = -1 Then Function = startcolor& Else Function = ColorResult&
    End Function
    
    Sub DisplayLocalHelp
       If Debug Then Txt.Print FuncName$
       Local temp$
       temp$ = "gbFloorPlanner  v" + $ver + $CrLf
       temp$ = temp$ + $CrLf + "Add items to layout in 3 ways:"
       temp$ = temp$ + $CrLf + " - draw with mouse (box/circle/line)"
       temp$ = temp$ + $CrLf + " - import exiting layout (use toolbar Import button)"
       temp$ = temp$ + $CrLf + " - import from Library (double-click on Library item)"
       temp$ = temp$ + $CrLf + "Edit item properties in several ways:"
       temp$ = temp$ + $CrLf + " - Property dialog (double-clicking on item in layout or content list)"
       temp$ = temp$ + $CrLf + " - Context menu (right-mouse over item in layout)"
       temp$ = temp$ + $CrLf + "Actions are usually taken on all selected items"
       temp$ = temp$ + $CrLf + " - Move/Group"
       temp$ = temp$ + $CrLf + " - Cut/Copy/Delete"
       temp$ = temp$ + $CrLf + " - Duplicate/Resize/SendtoFron/SendToBack"
       temp$ = temp$ + $CrLf + "By default gbFloorPlanner reopens where the last session left off"
       temp$ = temp$ + $CrLf + "Display of item Text/Image controlled at two levels"
       temp$ = temp$ + $CrLf + " - Item by item setting to allow textm/image to be shown"
       temp$ = temp$ + $CrLf + " - Global setting to show/hide item text/image"
       temp$ = temp$ + $CrLf + "Remove deletes last added item"
       temp$ = temp$ + $CrLf + "Restore adds last removed added item"
       temp$ = temp$ + $CrLf + "Accelerator Key Combinations:"
       temp$ = temp$ + $CrLf + " - F1 - Help
       temp$ = temp$ + $CrLf + " - Ctrl-A - Select all items"
       temp$ = temp$ + $CrLf + " - Ctrl-C - Copy Selected Items"
       temp$ = temp$ + $CrLf + " - Ctrl-D - Duplicate selected items"
       temp$ = temp$ + $CrLf + " - Ctrl-E - Clear (remove) all items"
       temp$ = temp$ + $CrLf + " - Ctrl-H - Opens InputBox for entering Z-value (height) of a layout item"
       temp$ = temp$ + $CrLf + " - Ctrl-I - Capture next selection as *.BMP file in the tempFile subfolder"
       temp$ = temp$ + $CrLf + " - Ctrl-N - Sequentially number selected items"
       temp$ = temp$ + $CrLf + " - Ctrl-P - Print layout image"
       temp$ = temp$ + $CrLf + " - Ctrl-R - Toggle text orientation between vertical and horizontal"
       temp$ = temp$ + $CrLf + " - Ctrl-S - Save layout as current filename with no user confirmation"
       temp$ = temp$ + $CrLf + " - Ctrl-T - Toggle location of text within item boundary"
       temp$ = temp$ + $CrLf + " - Ctrl-V - Paste Items"
       temp$ = temp$ + $CrLf + " - Ctrl-X - Cut selected items"
       temp$ = temp$ + $CrLf + " - Ctrl-Z - Remove"
       temp$ = temp$ + $CrLf + " - Del    - Delete selected items"
       temp$ = temp$ + $CrLf
       ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
       MessageBox(0, (temp$), "Local Help", %MB_Ok + %MB_IconInformation + %MB_TaskModal)
       UnhookWindowsHookEx ghHook
    End Sub
    
    Sub GetDebug
    '   If Debug Then Txt.Print FuncName$   '<--- disabled by choice
       Local temp, INIFileName As WStringZ*%Max_Path
       INIFileName = Exe.Path$ + Exe.Name$ + ".ini"
       Getprivateprofilestring "All", "Debug", "0", temp, %Max_Path, INIFileName:  Debug = Val(temp)
    End Sub
    
    Sub CreateContextMenus
        If Debug Then Txt.Print FuncName$
    
        Menu New PopUp To hSettings
        Menu Add String, hSettings, "Ask Confirmation", %IDM_AskConfirmation, %MF_Enabled
        Menu Add String, hSettings, "Save Session", %IDM_AutoSave, %MF_Enabled
        Menu Add String, hSettings, "Landscape Printing", %IDM_Landscape, %MF_Enabled
        Menu Add String, hSettings, "Grid Lines", %IDM_GridLines, %MF_Enabled
        Menu Add String, hSettings, "Snap To Grid", %IDM_SnapToGrid, %MF_Enabled
        Menu Add String, hSettings, "Snap Half Grid", %IDM_SnapHalf, %MF_Enabled
        Menu Add String, hSettings, "Rounded Boxes", %IDM_RoundedBox, %MF_Enabled
        Menu Add String, hSettings, "Auto Select Mode After Draw", %IDM_AutoSelectMode, %MF_Enabled
        Menu Add String, hSettings, "-",0,0
        Menu Add String, hSettings, "Show Ruler", %IDM_ShowRuler, %MF_Enabled
        Menu Add String, hSettings, "Minimal Ruler", %IDM_MinRuler, %MF_Enabled
        Menu Add String, hSettings, "-",0,0
        Menu Add String, hSettings, "Background Color", %IDM_BGColor, %MF_Enabled
        Menu Add String, hSettings, "ForeGround Color", %IDM_FGColor, %MF_Enabled
        Menu Add String, hSettings, "Ruler Color", %IDM_RulerColor, %MF_Enabled
        Menu Add String, hSettings, "Grid Color", %IDM_GridColor, %MF_Enabled
        Menu Add String, hSettings, "Set Colors to Default", %IDM_DefaultColors, %MF_Enabled
        Menu Add String, hSettings, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hSettings, "Edit Library File", %IDM_EditLibrary, %MF_Enabled
        Menu Add String, hSettings, "Re-Load Library File", %IDM_LoadLibrary, %MF_Enabled
        Menu Add String, hSettings, "Open Library Image Folder", %IDM_OpenLibraryFolder, %MF_Enabled
        Menu Add String, hSettings, "Open Layout Folder", %IDM_OpenLayoutFolder, %MF_Enabled
    
        Menu New PopUp To hZoom
        Menu Add String, hZoom, "20%",   %IDM_Zoom4,   %MF_Enabled
        Menu Add String, hZoom, "50%",   %IDM_Zoom10,  %MF_Enabled
        Menu Add String, hZoom, "100%",  %IDM_Zoom20,  %MF_Enabled
        Menu Add String, hZoom, "200%",  %IDM_Zoom40,  %MF_Enabled
        Menu Add String, hZoom, "300%",  %IDM_Zoom60,  %MF_Enabled
    
        Menu New PopUp To hHelp
        Menu Add String, hHelp, "Local Help",  %IDM_LocalHelp,  %MF_Enabled
        Menu Add String, hHelp, "Online Update",  %IDM_OnlineUpdate,  %MF_Enabled
    
        Menu New PopUp To hPopupGraphic
        Menu Add String, hPopupGraphic, "Enter Select Mode",  %IDM_SelectMode,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Delete Selected Items",  %IDM_DeleteSelected,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Align Selected Items To Grid",  %IDM_AlignSelected,  %MF_Enabled
        Menu Add String, hPopupGraphic, "Left Align Selected Items",  %IDM_LeftAlign,  %MF_Enabled
        Menu Add String, hPopupGraphic, "Top Align Selected Items",  %IDM_TopAlign,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Select All",  %IDM_SelectAllItems,  %MF_Enabled
        Menu Add String, hPopupGraphic, "UnSelect All",  %IDM_UnSelectAllItems,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Group Selected Items",  %IDM_GroupSelected,  %MF_Enabled
        Menu Add String, hPopupGraphic, "UnGroup Selected Items",  %IDM_UnGroupSelected,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Duplicate Selected Items",  %IDM_DuplicateSelectedItems,  %MF_Enabled
        Menu Add String, hPopupGraphic, "Save Selected Items As",  %IDM_SaveSelectedItemsAs,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Replace Descriptions of Selected Items",  %IDM_ReplaceSelectedItemsText,  %MF_Enabled
        Menu Add String, hPopupGraphic, "Set BG Color of Selected Items",  %IDM_SetSelectedColor,  %MF_Enabled
        Menu Add String, hPopupGraphic, "Serialize Selected Items",  %IDM_NumberSelectedItems,  %MF_Enabled
        Menu Add String, hPopupGraphic, "Reset Angle of Selected Items",  %IDM_ResetAngle,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Bring Selected Item To Front",  %IDM_SendFront,  %MF_Enabled
        Menu Add String, hPopupGraphic, "Send Selected Item to Back",  %IDM_SendBack,  %MF_Enabled
        Menu Add String, hPopupGraphic, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupGraphic, "Show Item Properties",  %IDM_ShowProperties,  %MF_Enabled
    
        Menu New PopUp To hPopupListView
        Menu Add String, hPopupListView, "Select All",  %IDM_SelectAllItems,  %MF_Enabled
        Menu Add String, hPopupListView, "UnSelect All",  %IDM_UnSelectAllItems,  %MF_Enabled
        Menu Add String, hPopupListView, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupListView, "Copy List",  %IDM_CopyList,  %MF_Enabled
        Menu Add String, hPopupListView, "Print List", %IDM_PrintList, %MF_Enabled
        Menu Add String, hPopupListView, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupListView, "Display Summary",  %IDM_SummaryDisplay,  %MF_Enabled
        Menu Add String, hPopupListView, "Copy Summary",  %IDM_SummaryCopy,  %MF_Enabled
        Menu Add String, hPopupListView, "Print Summary", %IDM_SummaryPrint, %MF_Enabled
        Menu Add String, hPopupListView, "-", %IDM_Sep, %MF_Enabled
        Menu Add String, hPopupListView, "Show Selected Item Properties",  %IDM_ShowPropertiesLV,  %MF_Enabled
    
    End Sub
    
    Sub SetMenusAndToolbar
       If Debug Then Txt.Print FuncName$
       'Toolbar Buttons
        Toolbar Set State hDlg, %IDC_ToolbarB, ByCmd %IDT_Select,  IIf(DrawMode=%Select Or DrawMode=%Move,%TBState_Checked,0) Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_ToolbarB, ByCmd %IDT_Box,     IIf(DrawMode=%Box,%TBState_Checked,0) Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_ToolbarB, ByCmd %IDT_Circle,  IIf(DrawMode=%Circle,%TBState_Checked,0) Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_ToolbarB, ByCmd %IDT_Line,    IIf(DrawMode=%Line,%TBState_Checked,0) Or %TBState_Enabled
    
        Toolbar Set State hDlg, %IDC_Toolbar, ByCmd %IDT_Ruler, ShowRuler * %TBState_Checked Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_Toolbar, ByCmd %IDT_Grid, ShowGrid * %TBState_Checked Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_Toolbar, ByCmd %IDT_Snap, SnapToGrid * %TBState_Checked Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_Toolbar, ByCmd %IDT_ShowListView, ShowListview * %TBState_Checked Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_Toolbar, ByCmd %IDT_ShowLibrary, ShowLibrary * %TBState_Checked Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_Toolbar, ByCmd %IDT_ShowDesc, ShowDesc * %TBState_Checked Or %TBState_Enabled
        Toolbar Set State hDlg, %IDC_Toolbar, ByCmd %IDT_ShowImages, ShowImages * %TBState_Checked Or %TBState_Enabled
    
       'Menus
        Menu Set State hSettings, ByCmd %IDM_AskConfirmation, AskConfirmation * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_AutoSave, AutoSave * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_Landscape, Landscape * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_GridLines, GridLines * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_SnapToGrid, SnapToGrid * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_SnapHalf, SnapHalf * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_RoundedBox, Rounded * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_ShowRuler, ShowRuler * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_MinRuler, MinRuler * %MFS_Checked Or %MFS_Enabled
        Menu Set State hSettings, ByCmd %IDM_AutoSelectMode, AutoSelectMode * %MFS_Checked Or %MFS_Enabled
    
        Menu Set State hZoom, ByCmd %IDM_Zoom4, IIf(SF=4,1,0)*%MFS_Checked Or %MFS_Enabled
        Menu Set State hZoom, ByCmd %IDM_Zoom10, IIf(SF=10,1,0)*%MFS_Checked Or %MFS_Enabled
        Menu Set State hZoom, ByCmd %IDM_Zoom20, IIf(SF=20,1,0)*%MFS_Checked Or %MFS_Enabled
        Menu Set State hZoom, ByCmd %IDM_Zoom40, IIf(SF=40,1,0)*%MFS_Checked Or %MFS_Enabled
        Menu Set State hZoom, ByCmd %IDM_Zoom60, IIf(SF=60,1,0)*%MFS_Checked Or %MFS_Enabled
    End Sub
    
    Sub PrintList
       If Debug Then Txt.Print FuncName$
       Local i,iCount,iMax As Long, tempA, tempB As String
       ListView Get Count hDlg, %IDC_ListView To iCount
       XPrint Attach Choose
       If Len(XPrint$)=0 Then Exit Sub
       XPrint Set Orientation IIf(Landscape,2,1)
    
       'Get max character length
       For i = 1 To iCount
          ListView Get Text hDlg, %IDC_Listview, i,1 To tempA
          iMax = Max(iMax,Len(tempA))
       Next i
    
       'Print
       For i = 1 To iCount
          ListView Get Text hDlg, %IDC_Listview, i,1 To tempA
          ListView Get Text hDlg, %IDC_Listview, i,2 To tempB
          XPrint tempA Tab(iMax+5); tempB
          If i Mod 50 = 0 Then XPrint FormFeed
       Next i
       XPrint Close
    End Sub
    
    Sub CopyList
       If Debug Then Txt.Print FuncName$
       Local i,iCount As Long, temp, tempA, tempB As String
       ListView Get Count hDlg, %IDC_ListView To iCount
       For i = 1 To iCount
          ListView Get Text hDlg, %IDC_Listview, i,1 To tempA
          ListView Get Text hDlg, %IDC_Listview, i,2 To tempB
          temp = temp + $CrLf + tempA + Space$(40-Len(tempA)) + tempB
       Next i
       Clipboard Reset
       Clipboard Set Text temp
    End Sub
    
    Sub SnapRect (i As Long)
       Local x,y,w,h As Long
    '   SnapPoints D(i).rect.nLeft * SF/D(i).sf, D(i).rect.nTop * SF/D(i).sf
    
       w = (D(i).rect.nRight - D(i).rect.nLeft)
       h = (D(i).rect.nBottom - D(i).rect.nTop)
    
       x = D(i).rect.nLeft * SF / D(i).sf
       y = D(i).rect.nTop * SF / D(i).sf
    
       SnapPoints x,y
    
       D(i).rect.nLeft = x * D(i).sf / SF
       D(i).rect.nTop  = y * D(i).sf / SF
    
       D(i).rect.nRight = (D(i).rect.nLeft + w)
       D(i).rect.nBottom = (D(i).rect.nTop + h)
    End Sub
    
    Sub SnapPoints(x As Long, y As Long)
    '   If Debug Then Txt.Print FuncName$   '<--- disabled by choice
    '   x = (x \ PPC) * PPC
    '   y = (y \ PPC) * PPC
       If SnapHalf Then
          x = ((x+PPC/4) \ (PPC\2)) * (PPC/2)
          y = ((y+PPC/4) \ (PPC\2)) * (PPC/2)
       Else
          x = ((x+PPC/2) \ PPC) * PPC
          y = ((y+PPC/2) \ PPC) * PPC
       End If
    End Sub
    
    Sub FillListView
       If Debug Then Txt.Print FuncName$
       Local i,w,h As Long, tempF,tempI As String
       ListView Reset hDlg, %IDC_ListView
    
       For i = 1 To UndoPos  'UBound(D)
          w = (D(i).rect.nRight - D(i).rect.nLeft) * FPC/PPC
          h = (D(i).rect.nBottom - D(i).rect.nTop) * FPC/PPC
          GetFeetText D(i).rect,tempF,tempI
          Select Case D(i).shape
             Case %Line
                ListView Insert Item hDlg, %IDC_ListView,1,0,D(i).desc
                ListView Set Text hDlg, %IDC_ListView, 1,2, Str$(Fix(Sqr(w*w+h*h)+0.5))
             Case %Box
                ListView Insert Item hDlg, %IDC_ListView, 1,0, D(i).desc
                ListView Set Text hDlg, %IDC_ListView, 1,2, tempF
                ListView Set Text hDlg, %IDC_ListView, 1,3, tempI
             Case %Circle
                ListView Insert Item hDlg, %IDC_ListView, 1,0, D(i).desc
                ListView Set Text hDlg, %IDC_ListView, 1,2, tempF
                ListView Set Text hDlg, %IDC_ListView, 1,3, tempI
          End Select
          ListView_SetCheckState hListView, 0, D(i).selected
       Next i
       ListView Select hDlg, %IDC_ListView,1
       ListView_SetItemState hListView, 0, %LVIS_Focused, %LVIS_Focused  '<--- keyboard synchronizing code
    End Sub
    
    Sub ManageLibrary
       If Debug Then Txt.Print FuncName$
       Local w,h As Long
       Dialog Get Client hDlg To w,h
    
       If ShowListView Then
          Control Normalize hDlg, %IDC_ListView
          Control Normalize hDlg, %IDC_LabelLV
       Else
          Control Hide hDlg, %IDC_ListView
          Control Hide hDlg, %IDC_LabelLV
       End If
    
       If ShowLibrary Then
          Control Normalize hDlg, %IDC_Preview
          Control Normalize hDlg, %IDC_LabelLib
          Control Normalize hDlg, %IDC_ComboBox
       Else
          Control Hide hDlg, %IDC_LabelLib
          Control Hide hDlg, %IDC_Preview
          Control Hide hDlg, %IDC_ComboBox
       End If
    
       If ShowListView And ShowLibrary Then
          Control Set Loc hDlg, %IDC_LabelLV, 110, %TBM
          Control Set Loc hDlg, %IDC_ListView, 110, %TBM+20
    
       ElseIf ShowListView Then
          Control Set Loc hDlg, %IDC_LabelLV,  5, %TBM
          Control Set Loc hDlg, %IDC_ListView, 5, %TBM+20
       End If
    
       Control Set Loc hDlg, %IDC_Graphic, 5 + ShowLibrary * 105 + ShowListview * 205, %TBM
       Control Set Size hDlg, %IDC_Graphic, w - ShowLibrary * 110 - ShowListView * 205, h-%TBM-25
    End Sub
    
    Sub SaveAs(ByVal fName$, Flag As Long)  '1=FileName  0=SelectedFileName
        If Debug Then Txt.Print FuncName$
        'save file to any location
        Local title$, startfolder$, filter$, startfile$, defaultext$, flags&, filevar$, countvar&
        title$ = ""                'caption title. if "", then "Save As" is displayed
        startfolder$ = Exe.Path$ + "layouts"    'initial folder to be displayed
        filter$ = "gbFloorPlanner Layout Files" + $Nul + "*.dat" + $Nul   ' or filter$ = CHR$("Text",0,"*.txt",0)
        startfile$ = fName$      'name to be used as initial selection
        defaultext$ = "dat"        'default extension to append to selection if user does not enter it
        flags& = %OFN_PathMustExist Or %OFN_Explorer Or %OFN_OverWritePrompt
        Display Savefile hDlg, 100, 100, title$, startfolder$, filter$, startfile$, defaultext$, flags& To filevar$, countvar&
        If Len(filevar$) Then
           If Flag Then
              FileName = filevar$         : SaveLayout(FileName,1)
           Else
              SelectedFileName = filevar$ : SaveLayout(SelectedFileName,0)
           End If
        End If
    End Sub
    
    Sub SaveLayout(ByVal fName$, Flag As Long)
        If Debug Then Txt.Print FuncName$
        If IsFile(fName$) Then Kill fName$
        Open fName$ For Binary As #1
        D(0).shape = UndoPos
        D(0).sf = Dirty
        Put #1,,D()
        Close #1
        If Flag Then  '1=FileName, 0=SelectedFileName
           Dirty = 0
           Dialog Set Text hDlg, "gbFloorPlanner " + $ver + Space$(10) + FileName
        End If
    End Sub
    
    Function CopySelectedItemsToClipboardFile() As Long
        If Debug Then Txt.Print FuncName$
        Local i,iCount As Long
        If IsFile($ClipboardFile) Then Kill $ClipboardFile
        Dim tempD(UndoPos) As ObjectType
        For i = 1 To UndoPos
           If D(i).selected Then
              Incr iCount
              tempD(iCount) = D(i)
              tempD(iCount).group = ""
           End If
        Next i
        If iCount Then
           ReDim Preserve tempD(iCount)
           tempD(0).shape = iCount
           Open $ClipboardFile For Binary As #1
           Put #1,,tempD()
           Close #1
           Function = 1
        Else
           Beep
        End If
    End Function
    
    Sub CreateLayoutMenu
       If Debug Then Txt.Print FuncName$
       Local iCount As Long, temp$
       Menu New PopUp To hOpen
       temp$ = Dir$("layouts\*.dat")
       While Len(temp$)
          Incr iCount
          Menu Add String, hOpen, PathName$(Name,temp$), %IDM_LayoutMenu+iCount,  %MF_Enabled
          temp$ = Dir$
       Wend
       If iCount = 0 Then Menu Add String, hOpen, "No layout files found!", %IDM_LayoutMenu,  %MF_Enabled
    End Sub
    
    Sub CreateImportMenu
       If Debug Then Txt.Print FuncName$
       Local iCount As Long, temp$
       Menu New PopUp To hImport
       temp$ = Dir$("layouts\*.dat")
       While Len(temp$)
          Incr iCount
          Menu Add String, hImport, PathName$(Name,temp$), %IDM_ImportMenu+iCount,  %MF_Enabled
          temp$ = Dir$
       Wend
       If iCount = 0 Then Menu Add String, hOpen, "No layout files found!", %IDM_ImportMenu,  %MF_Enabled
    End Sub
    
    Function SelectLayoutFile(title$) As Long
        If Debug Then Txt.Print FuncName$
        Local startfolder$, filter$, startfile$, defaultext$, flags&, filevar$, countvar&
        filter$ = "gbFloorPlanner Layout" + $Nul + "*.dat" + $Nul   ' or filter$ = CHR$("Text",0,"*.txt",0)
        startfolder$ = IIf$(IsFile(FileName), FileName, Exe.Path$)     'initial folder to be displayed
        startfile$ = (FileName)       'name to be used as initial selection
        flags& = %OFN_Explorer Or %OFN_FileMustExist Or %OFN_HideReadOnly
        Display Openfile hDlg, 100, 100, title$, startfolder$, filter$, startfile$, defaultext$, flags& To filevar$, countvar&
        If Len(filevar$) Then
           If title$ = "Open" Then
              FileName = filevar$
           Else
              ImportFileName = filevar$
           End If
           Function = 1
        Else
           Function = 0
        End If
    End Function
    
    Sub Redo
       If Debug Then Txt.Print FuncName$
       If UndoPos = UBound(D) Then Beep : Exit Sub
       Incr UndoPos
       Control ReDraw hDlg, %IDC_ListView
    End Sub
    
    Sub Undo
       If Debug Then Txt.Print FuncName$
       If UndoPos < 1  Then Beep : Exit Sub
       Decr UndoPos
       Control ReDraw hDlg, %IDC_ListView
    End Sub
    
    Sub OrderPoints(R As Rect)
       If Debug Then Txt.Print FuncName$
       Local tempR As Rect
       tempR.nLeft = Min&(R.nLeft,R.nRight)
       tempR.nRight = Max&(R.nLeft,R.nRight)
       tempR.nTop = Min&(R.nTop,R.nBottom)
       tempR.nBottom = Max&(R.nTop,R.nBottom)
       R = tempR
    End Sub
    
    Sub AddObject(NewObjectType As Long, temp$, zIn As Long)
       If Debug Then Txt.Print FuncName$
       UnselectAll
       Incr UndoPos
       ReDim Preserve D(UndoPos)
       D(UndoPos).shape       = NewObjectType
    
       If NewObjectType <> %Line Then OrderPoints(OldR)
    
       D(UndoPos).rect        = OldR
       D(UndoPos).z           = ZHeight
       D(UndoPos).sf          = SF
       D(UndoPos).rounded     = Rounded
    
       D(UndoPos).showborder  = 1
       D(UndoPos).showdesc    = 1
       D(UndoPos).showimage   = 0
    
       D(UndoPos).bgtransparent = BGTransparent
       D(UndoPos).bgcolor       = BGColor
       D(UndoPos).fgcolor       = FGColor
       D(UndoPos).fillstyle     = %Solid '0 Solid 1 Horizontal Lines 2 Vertical Lines 3 Upward Diagonal Lines 4 Downward Diagonal Lines 5 Crossed Lines 6 Diagonal Crossed Lines
    
       D(UndoPos).img         = ""
       D(UndoPos).imgPos      = 0
    
       D(UndoPos).desc        = temp$
       D(UndoPos).desccolor   = DescColor
    
       D(UndoPos).z0          = Z0Height
       D(UndoPos).selected    = 1
       Dirty = 1
    End Sub
    
    Sub AddLibraryItemToLayout(i As Long)
       If Debug Then Txt.Print FuncName$
    '   Local vx,vy As Long
       Graphic Get View To vx,vy
       SnapPoints vx,vy
    
       UnselectAll
       Incr UndoPos
       ReDim Preserve D(UndoPos)
       D(UndoPos).shape        = %Box
    
       D(UndoPos).rect.nLeft   = 2*PPC+vx
       D(UndoPos).rect.nRight  = 2*PPC+vx + Library(i).x * PPC / FPC / 12
       D(UndoPos).rect.nTop    = 2*PPC+vy
       D(UndoPos).rect.nBottom = 2*PPC+vy + Library(i).y * PPC / FPC / 12
    
       D(UndoPos).z            = Library(i).z '* FPC
       D(UndoPos).sf           = SF
       D(UndoPos).rounded      = Rounded
    
       D(UndoPos).showborder   = 0
       D(UndoPos).showdesc     = 0
       D(UndoPos).showimage    = 1
    
       D(UndoPos).bgcolor      = BGColor
       D(UndoPos).bgtransparent= BGTransparent
       D(UndoPos).fgcolor      = FGColor
       D(UndoPos).fillstyle    = %Solid '0 Solid 1 Horizontal Lines 2 Vertical Lines 3 Upward Diagonal Lines 4 Downward Diagonal Lines 5 Crossed Lines 6 Diagonal Crossed Lines
    
       D(UndoPos).img          = Library(i).img
       D(UndoPos).imgPos       = AddImageToImageArray((Library(i).img))
    
       D(UndoPos).desc         = Library(i).desc
       D(UndoPos).desccolor    = DescColor
    
       D(UndoPos).z0           = Z0Height
       D(UndoPos).selected     = 1
       Dirty = 1
    End Sub
    
    Function GraphicProc (ByVal hWnd As Dword, ByVal wMsg As Dword, ByVal wParam As Dword, ByVal lParam As Long) As Long
    '   If Debug Then Txt.Print FuncName$   '<--- diabled by choice
      Select Case wMsg
          Case %WM_LButtonDown   : OnGraphic_LeftButtonDown (hWnd, wParam, lParam)
          Case %WM_MouseMove     : OnGraphic_MouseMove      (hWnd, wParam, lParam)
          Case %WM_LButtonUp     : OnGraphic_LeftButtonUp   (hWnd, wParam, lParam)
          Case %WM_LButtonDblClk : OnGraphic_DoubleClick    (hWnd, wParam, lParam)
      End Select
      Function = CallWindowProc (OldGraphicProc, hWnd, wMsg, wParam, lParam)
    End Function
    
    Sub OnGraphic_DoubleClick (ByVal hWnd As Dword, ByVal wParam As Dword, ByVal lParam As Long)
       If Debug Then Txt.Print FuncName$
       Local i,x,y As Long, pt As Point, R As Rect
    
       If DrawMode <> %Select Then Beep : Exit Sub
    
       'determine what is under the mouse
       EditPos = 0
       Graphic Get View To vx,vy
       pt.x = Lo(Integer, lParam) + vx
       pt.y = Hi(Integer, lParam) + vy
       For i = UndoPos To 1 Step -1
          R.nLeft = D(i).rect.nLeft * SF/D(i).sf
          R.nTop = D(i).rect.nTop * SF/D(i).sf
          R.nRight = D(i).rect.nRight * SF/D(i).sf
          R.nBottom = D(i).rect.nBottom * SF/D(i).sf
          If D(i).shape = %Line Then OrderPoints R : InflateRect R,5,5
          If PtInRect(R,pt) Then EditPos = i : Exit For
       Next i
    
       If EditPos = 0 Then Beep : Exit Sub
       DisplayEditDialog : FillListVIew : DrawLayout
    End Sub
    
    Sub OnGraphic_LeftButtonDown (ByVal hWnd As Dword, ByVal wParam As Dword, ByVal lParam As Long)
      If Debug Then Txt.Print FuncName$
      SetCapture hWnd : SetFocus hWnd
    
      Statusbar Set Text hDlg, %IDC_StatusBar, 1,0, ""
      Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, ""
    
      Graphic Get View To vx,vy
      NewR.nLeft = Max&(0, Lo(Integer, lParam)) + vx : NewR.nRight = NewR.nLeft
      NewR.nTop  = Max&(0, Hi(Integer, lParam)) + vy : NewR.nBottom = NewR.nTop
    
      Select Case DrawMode
         Case %Select, %Resize, %Move
            ManageSelectionsOnLMouseDown(NewR.nLeft,NewR.nTop,wParam And %MK_Control)
      End Select
    
      If SnapToGrid And IsFalse(wParam And %MK_Control) Then SnapPoints(NewR.nLeft,NewR.nTop)
      SetStatusBar1
      OldR = NewR : OldR.nRight = NewR.nLeft : OldR.nBottom = NewR.nTop
      CanDraw = 1
    End Sub
    
    Sub ManageSelectionsOnLMouseDown(x As Long, y As Long, CtrlIsDown As Long)
       If Debug Then Txt.Print FuncName$
       Local i,iResult As Long, pt, ptM As Point, R As Rect, tempF, tempI As String
       'determine what is under the mouse
       pt.x = x : pt.y = y
       iResult = %OverNothing
       For i = UndoPos To 1 Step -1
          R.nLeft = D(i).rect.nLeft * SF/D(i).sf
          R.nTop = D(i).rect.nTop * SF/D(i).sf
          R.nRight = D(i).rect.nRight * SF/D(i).sf
          R.nBottom = D(i).rect.nBottom * SF/D(i).sf
    
          If D(i).selected Then
             ptM.x = pt.x
             ptM.y = pt.y
             If PtInResizeMarkers(ptM,R) Then
                ItemBeingResized = i
                iResult = %OverResizeMarker
                Exit For
             End If
          End If
    
          If D(i).shape = %Line Then OrderPoints R : InflateRect R,5,5
          If PtInRect(R,pt) Then
             iResult = IIf(D(i).selected, %OverItem_Selected,%OverItem_NotSelected)
             Exit For
          End If
       Next i
    
       'select/unselect as required, set DrawMode
       Select Case iResult
          Case %OverNothing          'unselect all items : DrawMode = %Select : Graphic Refresh right now!
             UnselectAll
             FillListView
             DrawLayout
             DrawMode = %Select
    
          Case %OverResizeMarker
             GetFeetText D(ItemBeingResized).rect,tempF,tempI
             Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, D(ItemBeingResized).desc + ":   " + tempF + "     (" + tempI + ")"
             MoveX0 = x : MoveY0 = y
             If SnapToGrid And IsFalse(CtrlIsDown) Then SnapPoints MoveX0, MoveY0
             DrawMode = %Resize
    
          Case %OverItem_Selected
             'if CTRL is up, no action (keep all selections) : DrawMode = %Move '(Copy by using Ctrl-Drag is not supported)
              'if CTRL is down, toggle selection, keep all other selections : DrawMode = %Move
             If CtrlIsDown Then
                D(i).selected = D(i).selected Xor 1
                FillListVIew
                DrawLayout
             End If
    
             GetFeetText D(i).rect,tempF,tempI
             Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, D(i).desc + ":   " + tempF + "     (" + tempI + ")"
             MoveX0 = x : MoveY0 = y
             If SnapToGrid And IsFalse(CtrlIsDown) Then SnapPoints MoveX0, MoveY0
             DrawMode = %Move
    
          Case %OverItem_NotSelected
             'if CTRL is up, select item, remove all other selections : DrawMode = %Move
             'if CTRL is down, toggle selection, keep all other selections : DrawMode = %Move
             If CtrlIsDown Then
                D(i).selected = D(i).selected Xor 1
             Else
                UnSelectAll
                D(i).selected = 1
             End If
             If Len(D(i).group) Then SelectGroupMembers((D(i).group))
             GetFeetText D(i).rect,tempF,tempI
             Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, D(i).desc + ":   " + tempF + "     (" + tempI + ")"
             FillListView
             DrawLayout
             MoveX0 = x : MoveY0 = y
             If SnapToGrid And IsFalse(CtrlIsDown) Then SnapPoints MoveX0, MoveY0
             DrawMode = %Move
       End Select
    End Sub
    
    Sub SelectGroupMembers(G As String)
       If Debug Then Txt.Print FuncName$
       Local j As Long
       For j = 1 To UndoPos
          If D(j).group = G Then D(j).selected = 1
       Next j
    End Sub
    
    Sub OnGraphic_MouseMove (ByVal hWnd As Dword, ByVal wParam As Dword, ByVal lParam As Long)
      If Debug Then Txt.Print FuncName$
      Local ddx,ddy,i As Long, tempR As Rect, tempF,tempI As String
    
       If CanDraw And (wParam And %MK_LBUTTON) Then
          Graphic Get View To vx,vy
          NewR.nRight = Lo(Integer, lParam) + vx
          NewR.nBottom = Hi(Integer, lParam) + vy
    
          If SnapToGrid And IsFalse(wParam And %MK_Control) Then SnapPoints(NewR.nRight,NewR.nBottom)
          SetStatusBar1
    
          DrawInWork = 1
          tempR.nLeft = Min&(NewR.nLeft,NewR.nRight)
          tempR.nRight = Max&(NewR.nLeft,NewR.nRight)
          tempR.nTop = Min&(NewR.nTop,NewR.nBottom)
          tempR.nBottom = Max&(NewR.nTop,NewR.nBottom)
          Graphic Width 3 : Graphic Style 0 : Graphic Set Mix %R2_NOTXORPEN
          Select Case DrawMode
             Case %Move
                ddx = NewR.nRight - MoveX0
                ddy = NewR.nBottom - MoveY0
                For i = 1 To UndoPos
                   If D(i).selected Then
                      OffSetRect D(i).rect, ddx * D(i).sf/SF, ddy*D(i).sf/SF
                   End If
                Next i
                MoveX0 = NewR.nRight
                MoveY0 = NewR.nBottom
                Dirty = 1
                DrawLayout
    
             Case %Resize
                ddx = (NewR.nRight - MoveX0) * D(ItemBeingResized).sf/SF
                ddy = (NewR.nBottom - MoveY0) * D(ItemBeingResized).sf/SF
                Dialog Set Text hdlg, Time$ + Str$(ddx) + Str$(ddy)
                For i = UndoPos To 1 Step -1
                   If D(i).selected Then ReSizeItem(i,ddx,ddy)
                Next i
                MoveX0 = NewR.nRight
                MoveY0 = NewR.nBottom
                Dirty = 1
                DrawLayout
    
             Case %Select
                Graphic Width 1 : Graphic Style 1
                If OldR.nLeft > -1 Then Graphic Box (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), , FGColor, -2, 0
                Graphic Box (tempR.nLeft,tempR.nTop)-(tempR.nRight,tempR.nBottom), , FGColor, -2, 0
                GetFeetText NewR, tempF, tempI
                Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, "Selection Rectangle:   " + tempF + "     (" + tempI + ")"
    
             Case %Line
                Graphic Width LineWidth
                If OldR.nLeft > -1 Then Graphic Line (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), FGColor
                Graphic Line (NewR.nLeft,NewR.nTop)-(NewR.nRight,NewR.nBottom), FGColor
                GetFeetLength NewR, tempF, tempI
                Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, "Line Length:   " + tempF + "     (" + tempI + ")"
                Dirty = 1
    
             Case %Box
                If OldR.nLeft > -1 Then Graphic Box (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), , FGColor, -2, 0
                Graphic Box (tempR.nLeft,tempR.nTop)-(tempR.nRight,tempR.nBottom), , FGColor, -2, 0
                GetFeetText NewR, tempF, tempI
                Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, "Box:   " + tempF + "     (" + tempI + ")"
                Dirty = 1
    
             Case %Circle
                If OldR.nLeft > -1 Then Graphic Ellipse (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), FGColor, -2, 0
                Graphic Ellipse (tempR.nLeft,tempR.nTop)-(tempR.nRight,tempR.nBottom), FGColor, -2, 0
                GetFeetText NewR, tempF, tempI
                Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, "Circle:   " + tempF + "     (" + tempI + ")"
                Dirty = 1
          End Select
          OldR = NewR
          Graphic ReDraw
      End If
    End Sub
    
    Sub ResizeItem(i As Long, ddx As Long, ddy As Long)
       Select Case ResizeMarker
          Case 1  'upper-left
             D(i).rect.nLeft = D(i).rect.nLeft + ddx
             D(i).rect.nTop  = D(i).rect.nTop + ddy
          Case 2  'upper-right
             D(i).rect.nRight = D(i).rect.nRight + ddx
             D(i).rect.nTop  = D(i).rect.nTop + ddy
          Case 3  'lower-right
             D(i).rect.nRight = D(i).rect.nRight + ddx
             D(i).rect.nBottom  = D(i).rect.nBottom + ddy
          Case 4  'lower-left
             D(i).rect.nLeft = D(i).rect.nLeft + ddx
             D(i).rect.nBottom  = D(i).rect.nBottom + ddy
       End Select
    End Sub
    
    Sub SetStatusBar1
      If Debug Then Txt.Print FuncName$
       Local x,y As Long, temp As String
       x = NewR.nRight * 12*FPC/PPC
       y = NewR.nBottom * 12*FPC/PPC
       temp = "Loc: " + Str$(x\12) + "'" + Str$(x Mod 12) + $Dq + " ," + Str$(y\12) + "'" + Str$(y Mod 12) + $Dq
       Statusbar Set Text hDlg, %IDC_StatusBar, 1,0, temp
    End Sub
    
    Sub GetFeetLength(R As Rect, tempF As String, tempI As String)
       If Debug Then Txt.Print FuncName$
       Local w,h,L As Long
       w = (R.nRight - R.nLeft) * 12*FPC/PPC
       h = (R.nBottom - R.nTop) * 12*FPC/PPC
       L = Sqr(w*w + h*h)
       tempI = Str$(L\12) + $Dq
       tempF = Str$(L\12) + "'" + Str$(L \ 12) + $Dq
    End Sub
    
    Sub GetFeetText(R As Rect, tempF As String, tempI As String)
       If Debug Then Txt.Print FuncName$
       Local w,h As Long
       w = (R.nRight - R.nLeft) * 12*FPC/PPC
       h = (R.nBottom - R.nTop) * 12*FPC/PPC
       tempI = Str$(w) + $Dq + " x" + Str$(h) + $Dq
       tempF = Str$(w\12) + "'" + Str$(w Mod 12) + $Dq + " x" + Str$(h\12) + "'" + Str$(h Mod 12) + $Dq
    End Sub
    
    Sub OnGraphic_LeftButtonUp (ByVal hWnd As Dword, ByVal wParam As Dword, ByVal lParam As Long)
      If Debug Then Txt.Print FuncName$
      Local tempF, tempI As String, i As Long
      If DrawInWork Then
          CanDraw = 0 : DrawInWork = 0 : Graphic Set Mix %R2_COPYPEN
          Select Case DrawMode
             Case %Move
                Dialog Set Text hDlg, "gbFloorPlanner " + $ver + Space$(10) + FileName
             Case %Resize
                For i = UndoPos To 1 Step -1
                   If D(i).selected Then
                      If D(i).shape <> %Line Then OrderPoints D(i).rect
                    End If
                Next i
    '            If D(ItemBeingResized).shape <> %Line Then OrderPoints D(ItemBeingResized).rect
                DrawLayout
                Dialog Set Text hDlg, "gbFloorPlanner " + $ver + Space$(10) + FileName
             Case %Select
                Graphic Set Mix %R2_NOTXORPEN
                Graphic Box     (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), , FGColor, -2, 0
                GetFeetText OldR, tempF, tempI
                Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, "Selection Rectangle:   " + tempF + "     (" + tempI + ")"
                If CapturePNG Then
                   CaptureSelectionToFile(OldR)
                   CapturePNG = 0
                Else
                   ManageSelectionsOnLMouseUp(OldR)
                End If
    
             Case %Line
                'If IsRectEmpty(OldR) Then Exit Select
                Graphic Line    (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), FGColor
                AddObject %Line,"Line",ZHeight : FillListView : DrawLayout
                If ShowDesc And D(UBound(D)).ShowDesc Then DrawItemText(UBound(D))
    
             Case %Box
                'If IsRectEmpty(OldR) Then Exit Select
                Graphic Box     (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), , FGColor, -2, 0
                GetFeetText OldR, tempF, tempI
                Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, "Box:  " + tempF + "     (" + tempI + ")"
                AddObject %Box, "Box", ZHeight : FillListView : DrawLayout
                If ShowDesc And D(UBound(D)).ShowDesc Then DrawItemText(UBound(D))
    
             Case %Circle
                'If IsRectEmpty(OldR) Then Exit Select
                Graphic Ellipse (OldR.nLeft,OldR.nTop)-(OldR.nRight,OldR.nBottom), FGColor, -2, 0
                GetFeetText OldR, tempF, tempI
                Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, "Circle:  " + tempF + "     (" + tempI + ")"
                AddObject %Circle, "Circle", ZHeight : FillListView : DrawLayout
                If ShowDesc And D(UBound(D)).ShowDesc Then DrawItemText(UBound(D))
          End Select
      End If
      Graphic ReDraw
      Reset OldR
      If DrawMode = %Move Then DrawMode = %Select
      OldR.nLeft = -1
      ReleaseCapture
      If AutoSelectMode Then DrawMode = %Select : SetMenusAndToolbar
    End Sub
    
    Sub ManageSelectionsOnLMouseUp(ByVal selectionR As Rect)
       If Debug Then Txt.Print FuncName$
       Local i As Long, intersectR,tempD As Rect
       'select all items inside the selection rectangle
    
    '   Graphic Get View To vx,vy
    '   OffSetRect selectionR, vx, vy
       OrderPoints(selectionR)
       If IsRectEmpty(selectionR) Then Exit Sub
    
       For i = UndoPos To 1 Step -1
          tempD.nLeft   = D(i).rect.nLeft * SF / D(i).sf
          tempD.nTop    = D(i).rect.nTop * SF / D(i).sf
          tempD.nRight  = D(i).rect.nRight * SF / D(i).sf
          tempD.nBottom = D(i).rect.nBottom * SF / D(i).sf
          If D(i).shape = %Line Then
             OrderPoints tempD
             InflateRect tempD,5,5
          End If
          IntersectRect intersectR, selectionR, tempD
          If IsRectEmpty(intersectR) Then Iterate For
          D(i).selected = 1
       Next i
       FillListView
       DrawLayout
    End Sub
    
    Sub AutoNumber
       If Debug Then Txt.Print FuncName$
       Local i,iCount As Long
       For i = 1 To UndoPos
          If D(i).selected Then : Incr iCount : D(i).desc = LTrim$(Str$(iCount))
       Next i
    End Sub
    
    Sub DeleteSelectedItems
       If Debug Then Txt.Print FuncName$
       Local i,iCount As Long, tempD As ObjectType
       For i = UndoPos To 1 Step -1
          If D(i).selected Then
             If i <= UndoPos Then Decr UndoPos
             Incr iCount
             tempD = D(i) : tempD.selected = 0
             Array Delete D(i)
             Array Insert D(UndoPos+1), tempD
          End If
       Next i
       If iCount Then
          'ReDim Preserve D(UBound(D)-iCount)
          FillListView
          DrawLayout
          Dirty = 1
       Else
          Beep
       End If
    End Sub
    
    Sub SelectAll
       If Debug Then Txt.Print FuncName$
       Local i As Long
       For i = 1 To UndoPos : D(i).selected = 1 : Next i
    End Sub
    
    Sub UnSelectAll
       If Debug Then Txt.Print FuncName$
       Local i As Long
       For i = 1 To UndoPos : D(i).selected = 0 : Next i
    End Sub
    
    
    Sub LoadLibraryFile
       If Debug Then Txt.Print FuncName$
       'category-x-y-z-image-desc
       Local temp$, LineCount As Long
       Local oldcat$,i As Long
       'load Library()
       Open $LibraryFile For Input As #1
       FileScan #1, Records To LineCount
       ReDim Library(LineCount-1)   '0-based  but 0 position is not used
       Line Input #1, temp$  'header line, unused
       For i = 1 To UBound(Library)
          Line Input #1, temp$
          Library(i).cat  = Parse$(temp$,",",1)
          Library(i).desc = Parse$(temp$,",",2)
          Library(i).x    = Val(Parse$(temp$,",",3))
          Library(i).y    = Val(Parse$(temp$,",",4))
          Library(i).z    = Val(Parse$(temp$,",",5))
          Library(i).img  = Parse$(temp$,",",6)
       Next i
       Close #1
       'sort Library()
       Array Sort Library(), Call LibrarySort_CatName()
       'fill combobox with Library()
       ComboBox Insert hDlg, %IDC_ComboBox, 0, "All"
       For i = 1 To UBound(Library)
          If Library(i).cat <> oldcat$ Then ComboBox Insert hDlg, %IDC_ComboBox, 0, Library(i).cat
          oldcat$ = Library(i).cat
       Next i
    End Sub
    
    Function LibrarySort_CatName(A As LibraryType, B As LibraryType) As Long
    '   If Debug Then Txt.Print FuncName$   '<--- disabled by choice
      If A.cat < B.cat   Then Function = -1 : Exit Function
      If A.cat > B.cat   Then Function = +1 : Exit Function
      If A.desc < B.desc Then Function = -1 : Exit Function
      If A.desc > B.desc Then Function = +1 : Exit Function
    End Function
    
    Sub DisplayLayoutItemInStatusbar(i As Long)
       If Debug Then Txt.Print FuncName$
       Local tempF, tempI As String
       GetFeetText D(i).rect,tempF,tempI
       Statusbar Set Text hDlg, %IDC_StatusBar, 2,0, D(i).desc + ":   " + tempF + "     (" + tempI + ")"
    End Sub
    
    Function InputBoxProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    '   If Debug Then Txt.Print FuncName$   '<---- turned off by choice
       Local szTemp As WStringZ * %Max_Path, cw As CBT_CREATEWND Ptr, cst As CREATESTRUCT Ptr
       Function = CallNextHookEx(ByVal ghHook, ByVal nCode, ByVal wParam, ByVal lParam)
       If nCode < 0 Then Exit Function
       If nCode = %HCBT_ACTIVATE Then UnhookWindowsHookEx ghHook
       If nCode = %HCBT_CREATEWND Then
          cw = lParam         ' Get pointer to CBT_CREATEWND struct so we can...    TT: Nick Melnick
          cst = @cw.lpcs      ' get a pointer to the CREATESTRUCT struct
          GetClassName wParam, szTemp, %Max_Path      ' for each window / control as it is created
          If UCase$(szTemp) = "BUTTON" Then @cst.x = 120  : @cst.cx = 60           'ok and cancel
          If UCase$(szTemp) = "STATIC" Then @cst.x = 400                           'prompt
          If UCase$(szTemp) = "EDIT"   Then @cst.cx = 100 : @cst.y = @cst.y - 130  'textbox
          If UCase$(szTemp) = "EDIT"   Then SetWindowLong wparam, %GWL_Style, GetWindowLong(wParam,%GWL_Style)
          If UCase$(szTemp) = "#32770" Then @cst.cx = 200 : @cst.cy = @cst.cy - 130                'dialog
       End If
    End Function
    
    Sub PrintLayout
       If Debug Then Txt.Print FuncName$
       Local x,y,wNew,hNew,wImg,hImg,wCont,hCont As Long
    
       XPrint Attach Choose
       If Len(XPrint$)=0 Then Exit Sub
       XPrint Set Orientation IIf(Landscape,2,1)
    
       'wCont,hCont = container size : hImg,wImg = original image size : wNew,hNew = image size to fit in container
       Control Get Size hDlg, %IDC_Graphic To wImg,hImg
       XPrint Get Canvas To wCont, hCont
       wNew = wImg / Max(wImg / wCont, hImg / hCont) * 0.9
       hNew = hImg / Max(wImg / wCont, hImg / hCont) * 0.9
       x = (wCont-wNew)/2 : y = (hCont-hNew)/2               'upper/left position so resized image is centered
    
       XPrint Width 5
       XPrint Stretch hGraphic, 0, (0,0)-(wImg-1,hImg-1) To (x,y)-(x+wNew-1,y+hNew-1)  'copy (resized) from memory bitmap to visible image
       XPrint Box (x,y)-(x+wNew-1,y+hNew-1),,%Black
    
       'print FileName
       XPrint Set Pos (x,y/2)
       XPrint "gbFloorPlanner: " + PathName$(Name,FileName)
       XPrint Close
    
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
    End Sub
    
    Sub CopyLayoutImageToClipboard
       If Debug Then Txt.Print FuncName$
       Local hBMP, hBMPDC, hDeskTopDC As Dword, x,y,w,h As Long, pt As Point
    
       'create memory bitmap the size of the Graphic Control (visible area, not the virtual area)
       Control Get Size hDlg, %IDC_Graphic To w,h
       ClientToScreen hGraphic, pt                      'pt contains (0,0)
    
       Graphic Bitmap New w,h To hBMP
       Graphic Attach hBMP,0
       Graphic Get DC To hBMPDC
    
       'bitblt dialog rectangle from the screen to the memory bitmap
       hDeskTopDC = GetDC(%Null)
       BitBlt hBMPDC, 0,0,w,h, hDeskTopDC, pt.x, pt.y, %SRCCopy 'copy desktop image to
       ReleaseDC(%Null,hDeskTopDC)
    
       'send to clipboard
       Clipboard Reset
       Clipboard Set Bitmap hBMP
       sndPlaySound "camera",%Snd_Sync Or %SND_Resource
       Statusbar Set Text hDlg, %IDC_Statusbar, 2, 0, "Image of visible area copied to clipbard"
    
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
    End Sub
    
    Function AddImageToImageArray(imgName$) As Dword   'if exists return position of imgName$, else add to array
       If Debug Then Txt.Print FuncName$
       Local i,j As Long
       'does it already exist in D()? Is so, return that position
       For i = 1 To UBound(Images)
          If imgName$ = Images(j).img Then Function = i : Exit Function
       Next i
    
       'add to image array
       ReDim Preserve Images(UBound(Images)+1)
       GdipLoadImageFromFile((Exe.Path$ + "images\" + imgName$), Images(UBound(Images)).pImage)  'pImage - image object
       Function = UBound(Images)
    End Function
    
    Sub DrawImage(iPos As Long)
       If Debug Then Txt.Print FuncName$
       Local w,h As Long
       w = D(iPos).rect.nRight*SF/D(iPos).sf - D(iPos).rect.nLeft*SF/D(iPos).sf
       h = D(iPos).rect.nBottom*SF/D(iPos).sf - D(iPos).rect.nTop*SF/D(iPos).sf
       If D(iPos).shape = %Box Then
          GdipDrawImageRect(pGraphics, Images(D(iPos).imgPos).pImage,D(iPos).rect.nLeft*SF/D(iPos).sf,D(iPos).rect.nTop*SF/D(iPos).sf,w,h)             'draw image at 0,0
       ElseIf D(iPos).shape = %Circle Then
    '      CopyEllipticalAreaFromImageToMe(iPos)
          GdipDrawImageRect(pGraphics, Images(D(iPos).imgPos).pImage,D(iPos).rect.nLeft*SF/D(iPos).sf,D(iPos).rect.nTop*SF/D(iPos).sf,w,h)             'draw image at 0,0
       End If
    End Sub
    
    Sub ShowProperties
       If Debug Then Txt.Print FuncName$
       Local i,iResult As Long, R As Rect
       ScreenToClient hGraphic, ptMenu
       For i = UndoPos To 1 Step -1
          R.nLeft = D(i).rect.nLeft * SF/D(i).sf
          R.nTop = D(i).rect.nTop * SF/D(i).sf
          R.nRight = D(i).rect.nRight * SF/D(i).sf
          R.nBottom = D(i).rect.nBottom * SF/D(i).sf
          If PtInRect(R,ptMenu) Then iResult = i : Exit For
       Next i
       If iResult Then
          ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
          MessageBox(0, (ItemProperties(iResult)), "Show Item Properties", %MB_Ok + %MB_IconInformation + %MB_TaskModal)
          UnhookWindowsHookEx ghHook
       End If
    End Sub
    
    Sub SendFront
       If Debug Then Txt.Print FuncName$
       Local i,iResult As Long, temp As ObjectType
       For i = UndoPos To 1 Step -1
          If D(i).selected Then iResult = i : Exit For
       Next i
       If iResult Then
          temp = D(iResult)
          Array Delete D(iResult)
          Array Insert D(UndoPos), temp
          FillListview
          DrawLayout
       End If
    End Sub
    
    Sub SendBack
       If Debug Then Txt.Print FuncName$
       Local i As Long, temp As ObjectType
       For i = UndoPos To 1 Step -1
          If D(i).selected Then
             D(i).selected = 0
             temp = D(i)
             Array Delete D(i)
             Array Insert D(1), temp
             FillListView
             DrawLayout
             Exit For
          End If
       Next i
    End Sub
    
    Sub MoveSelected(x As Long, y As Long)
       If Debug Then Txt.Print FuncName$
       Local i As Long
       For i = 1 To UndoPos
          If D(i).selected Then OffSetRect D(i).rect, x * PPC, y * PPC : Dirty = 1
       Next i
       DrawLayout
    End Sub
    
    Sub DisplayEditDialog
       If Debug Then Txt.Print FuncName$
       Local i As Long
       Dialog New Pixels, hDlg, "Edit Layout Item",100,100,275,260,%WS_SysMenu To hEdit
       Dialog Set Icon hEdit, "logo"
    
       Control Add Label, hEdit, %IDCE_LabelDesc, "Desc:", 10,10,50,15
       Control Add TextBox, hEdit, %IDCE_TextDesc,  D(EditPos).desc, 75,10,190,20
    
       FGEdit = D(EditPos).fgcolor
       BGEdit = D(EditPos).bgcolor
       DescEdit = D(EditPos).desccolor
       RoundEdit = D(EditPos).rounded
    
       Control Add Label, hEdit, %IDCE_FGColor, "",  10,45, 15,15, %WS_Border Or %SS_Notify
       Control Add Label, hEdit, %IDCE_FGLabel, "Border Color",     35,45,100,15
       Control Set Color hEdit, %IDCE_FGColor, %Black, FGEdit
    
       Control Add Label, hEdit, %IDCE_DescColor, "", 10,70,15,15, %WS_Border Or %SS_Notify
       Control Add Label, hEdit, %IDCE_DescLabel, "Desc Color",    35,70,100,15
       Control Set Color hEdit, %IDCE_DescColor, %Black, DescEdit
    
       Control Add Label, hEdit, %IDCE_BGColor, "",  130,45,15,15, %WS_Border Or %SS_Notify
       Control Add Label, hEdit, %IDCE_BGLabel, "Background Color", 155,45,125,15
       Control Set Color hEdit, %IDCE_BGColor, %Black, BGEdit
    
       Control Add CheckBox, hEdit, %IDCE_BGTransparent, "BG Transparent", 130,70,150,15, %WS_Border
       Control Set Check hEdit, %IDCE_BGTransparent, D(EditPos).bgTransparent
    
       Control Add Label, hEdit, %IDCE_StyleLabel, "Fill Style:", 10,100,70,20
       Control Add ComboBox, hEdit, %IDCE_FillStyle,,75,100,190,150, %CBS_DropDownList Or %WS_TabStop, %WS_Ex_ClientEdge
       For i = 0 To 6 : ComboBox Insert hEdit, %IDCE_FillStyle,i+1,ItemFill(i) : Next i
       ComboBox Select hEdit, %IDCE_FillStyle, D(EditPos).fillstyle + 1
    
       Control Add Label, hEdit, %IDCE_ImageLabel, "Image:", 10,135,70,20
       Control Add ComboBox, hEdit, %IDCE_Image,,75,135,190,300, %CBS_DropDownList Or %WS_VScroll Or %WS_TabStop, %WS_Ex_ClientEdge
       LoadEditImages
       ComboBox Find Exact hEdit, %IDCE_Image, 1, D(EditPos).img To i
       If i Then ComboBox Select hEdit, %IDCE_Image, i
    
       Control Add CheckBox, hEdit, %IDCE_ShowBorder, "Allow Border/Background", 10,170,200,15, %WS_Border
       Control Set Check hEdit, %IDCE_ShowBorder, D(EditPos).ShowBorder
    
       Control Add CheckBox, hEdit, %IDCE_ShowDesc, "Allow Description", 10,190,150,15, %WS_Border
       Control Set Check hEdit, %IDCE_ShowDesc, D(EditPos).ShowDesc
    
       Control Add CheckBox, hEdit, %IDCE_ShowImage, "Allow Image", 10,210,100,15, %WS_Border
       Control Set Check hEdit, %IDCE_ShowImage, D(EditPos).ShowImage
    
       Control Add CheckBox, hEdit, %IDCE_RoundedBox, "Rounded Edges", 10,230,100,15, %WS_Border
       Control Set Check hEdit, %IDCE_RoundedBox, D(EditPos).Rounded
    
       Control Add Button, hEdit, %IDCE_Save, "Save", 135, 230,60,20
       Control Add Button, hEdit, %IDCE_Cancel, "Cancel", 205, 230,60,20
       Dialog Show Modal hEdit Call EditProc
    End Sub
    
    CallBack Function EditProc() As Long
    '   If Debug Then Txt.Print FuncName$   '<--- disabled by choice
       Local i As Long
       Static PreEditD As ObjectType
       Select Case Cb.Msg
          Case %WM_InitDialog
             PreEditD = D(EditPos)
             For i = %IDCE_LabelDesc To %IDCE_Save : Control Set Font hEdit, i, hFont : Next i
          Case %WM_Destroy
             If EditPos Then
                SaveEditResults
                If PreEditD <> D(EditPos) Then Dirty = 1
             End If
          Case %WM_Command
             Select Case Cb.Ctl
                Case %IDCE_Save
                   Dialog End hEdit
                Case %IDCE_Cancel
                   EditPos = 0
                   Dialog End hEdit
                Case %IDCE_FGColor
                   FGEdit = SelectColor(FGEdit)
                   Control Set Color hEdit, %IDCE_FGColor, %Black, FGEdit
                   Control ReDraw hEdit, %IDCE_FGColor
                Case %IDCE_BGColor
                   BGEdit = SelectColor(BGEdit)
                   Control Set Color hEdit, %IDCE_BGColor, %Black, BGEdit
                   Control ReDraw hEdit, %IDCE_BGColor
                Case %IDCE_DescColor
                   DescEdit = SelectColor(DescEdit)
                   Control Set Color hEdit, %IDCE_DescColor, %Black, DescEdit
                   Control ReDraw hEdit, %IDCE_DescColor
             End Select
       End Select
    End Function
    
    Sub SaveEditResults
       If Debug Then Txt.Print FuncName$
       Local i As Long
       Control Get Text hEdit, %IDCE_TextDesc To D(EditPos).desc
    
       D(EditPos).fgcolor = FGEdit
       D(EditPos).bgcolor = BGEdit
       D(EditPos).desccolor = DescEdit
       Control Get Check hEdit, %IDCE_BGTransparent To D(EditPos).bgTransparent
    
       ComboBox Get Select hEdit, %IDCE_FillStyle To i : D(EditPos).fillstyle = i - 1
    
       Control Get Text hEdit, %IDCE_Image To D(EditPos).img
       D(EditPos).imgPos = AddImageToImageArray((D(EditPos).img))
    
       Control Get Check hEdit, %IDCE_ShowBorder To D(EditPos).ShowBorder
       Control Get Check hEdit, %IDCE_ShowDesc To D(EditPos).ShowDesc
       Control Get Check hEdit, %IDCE_ShowImage To D(EditPos).ShowImage
       Control Get Check hEdit, %IDCE_RoundedBox To D(EditPos).Rounded
    End Sub
    
    Sub LoadItemFillArray
       If Debug Then Txt.Print FuncName$
       ReDim ItemFill(6)
       ItemFill(0) = "Solid"
       ItemFill(1) = "Horizontal Lines"
       ItemFill(2) = "Vertical Lines"
       ItemFill(3) = "Upward Diagonal Lines"
       ItemFill(4) = "Downward Diagonal Lines"
       ItemFill(5) = "Crossed Lines"
       ItemFill(6) = "Diagonal Crossed Lines"
    End Sub
    
    Sub LoadEditImages
       If Debug Then Txt.Print FuncName$
       Local iCount As Long, temp$
       temp$ = Dir$("images\*.*")
       While Len(temp$)
          Incr iCount
          ComboBox Insert hEdit, %IDCE_Image, iCount, temp
          temp$ = Dir$
       Wend
       If iCount = 0 Then ComboBox Insert hEdit, %IDCE_Image,1,"No images found!"
    End Sub
    
    Sub CaptureSelectionToFile(R As Rect)
       If Debug Then Txt.Print FuncName$
       Local w,h As Long, hBMP As Dword
    
       OrderPoints R
       w = R.nRight - R.nLeft + 3
       h = R.nBottom - R.nTop + 3
       Graphic Bitmap New w,h To hBMP
       Graphic Attach hBMP,0
    
       Graphic Copy hDlg, %IDC_Graphic, (R.nLeft-1,R.nTop-1)-(R.nRight+2,R.nBottom+2) To (0,0)
       Incr CaptureNumber
       Graphic Save "tempfiles\gbFloorPlanner_capture_" + Format$(CaptureNumber,"0000") + ".bmp"
    
       Clipboard Reset
       Clipboard Set Bitmap hBMP
    
       Graphic Bitmap End
    
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
       sndPlaySound "camera",%Snd_Sync Or %SND_Resource
       Statusbar Set Text hDlg, %IDC_Statusbar, 2, 0, "Image of selection copied to clipbard and saved to " + "tempfiles\gbFloorPlanner_capture_" + Format$(CaptureNumber,"0000") + ".bmp"
    End Sub
    
    Sub ResizeWindow
    '   If Debug Then Txt.Print FuncName$   '<--- disabled by choice
       Local w,h As Long
    '   Local vx,vy As Long
    
       Graphic Get View To vx,vy
    
       Dialog Get Client hDlg To w,h
       Control Set Size hDlg, %IDC_ListView, 200, h - %TBM - 45
       Control Set Size hDlg, %IDC_Preview, 100, h - %TBM - 85
       If ShowLibrary And ShowListView Then
          Control Set Size hDlg, %IDC_Graphic, w - 20 - ShowLibrary * 100 - ShowListView * 200, h-%TBM-25
       ElseIf ShowLibrary Or ShowListview Then
          Control Set Size hDlg, %IDC_Graphic, w - 10 - ShowLibrary * 105 - ShowListView * 205, h-%TBM-25
       Else
          Control Set Size hDlg, %IDC_Graphic, w - 10, h-%TBM-25
       End If
    
       Graphic Set View vx,vy
       Dialog ReDraw hDlg
    End Sub
    
    Sub DuplicateSelectedItems
       If Debug Then Txt.Print FuncName$
       Local i,j As Long
       'Truncate
       ReDim Preserve D(UndoPos)
       'Duplicate Copies Items
       For i = 1 To UndoPos
          If D(i).selected Then
             j = UBound(D) + 1
             ReDim Preserve D(j)
             D(j) = D(i)
             D(j).group = ""
             OffsetRect D(j).rect, -PPC * D(j).sf / SF, PPC * D(j).sf / SF
             D(i).selected = 0
             Dirty = 1
          End If
       Next i
       UndoPos = UBound(D)
    End Sub
    
    Sub CreateLibraryControls
       If Debug Then Txt.Print FuncName$
       Control Add Label, hDlg, %IDC_LabelLib,"Library",5,%TBM,100,15
       Control Add ComboBox, hDlg, %IDC_ComboBox,,5,%TBM+20,100,300, %WS_VScroll Or %CBS_DropDownList Or %WS_TabStop, %WS_Ex_ClientEdge
       Control Add Graphic, hDlg, %IDC_Preview,"", 5, %TBM+55,100,80, %SS_Notify
       Control Handle hDlg, %IDC_Preview To hPreview
       Graphic Attach hDlg, %IDC_Preview, ReDraw
       Graphic Get DC To hPreviewDC
       Graphic Set Virtual 80,2000
       Graphic Color %Black, -1
       Graphic Set Overlap
       Graphic Set Mix %R2_CopyPen
    End Sub
    
    Sub DisplayItemImagesForSelectedCategory
       If Debug Then Txt.Print FuncName$
       Local i,x,y,iCount,w,h,wG,hG As Long, cat$, temp$,imgName As String
       Local wCont, hCont, wNew, hNew, wImg, hImg As Long
       Local preGraphics, pImage As Dword
    
       Control Get Text hDlg, %IDC_ComboBox To cat$
       Graphic Attach hDlg, %IDC_Preview
       Graphic Clear
    
       For i = 1 To UBound(Library)
          If Library(i).cat = cat$ Or cat$ = "All" Then Incr iCount
       Next i
       Control Get Size hDlg, %IDC_Preview To wG,hG
       wCont = IIf(iCount < (hG\120+1),100,80) : hCont = 80
       Graphic Set Virtual wCont,iCount * 120
       iCount = 0
    
       For i = 1 To UBound(Library)
          If Library(i).cat = cat$ Or cat$ = "All" Then
             'display image
             imgName = Exe.Path$ + "images\" + Library(i).img
             GdipLoadImageFromFile((imgName), pImage)        'load image
             GdipCreateFromHDC(hPreviewDC, preGraphics)        ' Create the Graphic object
             GdipGetImageWidth(pImage,wImg)
             GdipGetImageHeight(pImage, hImg)
    
             'wCont,hCont = container size : hImg,wImg = original image size : wNew,hNew = image size to fit in container
             wNew = wImg / Max(wImg / wCont, hImg / hCont)
             hNew = hImg / Max(wImg / wCont, hImg / hCont)
             x = (wCont-wNew)/2 : y = iCount*120 + (hCont-hNew)/2             'upper/left position so resized image is centered
             GdipDrawImageRect(preGraphics, pImage,x,y,wNew,hNew)  'draw image
    
             'title
             Graphic Text Size PathName$(Name,Library(i).desc) To w,h
             Graphic Set Pos ((wCont-w)/2,iCount*120+80)
             Graphic Print PathName$(Name,Library(i).desc)
    
             'size
             temp$ = LTrim$(Str$(Library(i).x)) + $Dq + " x" + Str$(Library(i).y) + $Dq
             Graphic Text Size temp$ To w,h
             Graphic Set Pos ((wCont-w)/2,iCount*120+95)
             Graphic Print temp$
    
             Incr iCount
    
             'cleanup
             If pImage Then GdipDisposeImage(pImage)
             If preGraphics Then GdipDeleteGraphics(preGraphics)
    
          End If
       Next i
       Graphic ReDraw
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
    End Sub
    
    Function GetPreviewSelection() As Long
       If Debug Then Txt.Print FuncName$
       Local i,iCount,iPos,x,y As Long, pt As Point, cat$
       Control Get Text hDlg, %IDC_ComboBox To cat$
       Graphic Attach hDlg, %IDC_Preview, ReDraw
       Graphic Get View To x,y
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
       GetCursorPos pt
       ScreenToClient hPreview, pt
       pt.y = pt.y + y
       iPos = pt.y \ 120 + 1
       For i = 1 To UBound(Library)
          If Library(i).cat = cat$  Or cat$ = "All" Then
             Incr iCount
             If iCount = iPos Then Function = i : Exit Function
          End If
       Next i
    End Function
    
    Sub SummaryReport(task$)
       If Debug Then Txt.Print FuncName$
       Local i,j,pCount,iCount,tCount As Long, temp, tempA, tempB, tempC As String
    
       'put ListView content in array and sort
       ListView Get Count hDlg, %IDC_ListView To iCount
       ReDim tempList(iCount) As String
       For i = 1 To iCount
          ListView Get Text hDlg, %IDC_Listview, i,1 To tempA
          ListView Get Text hDlg, %IDC_Listview, i,2 To tempB
          tempList(i) = tempA + " " + tempB
       Next i
       Array Sort tempList()
    
       'count unique array elements
       temp = "Total Items: " + Str$(iCount) + $CrLf
       If task$ = "print" Then
          XPrint Attach Choose
          If Len(XPrint$)=0 Then Exit Sub
          XPrint Set Orientation IIf(Landscape,2,1)
          XPrint temp
       End If
    
       tempC = tempList(0) : tCount = 1
        For i = 1 To UBound(tempList)
          If tempList(i) <> tempC Then
             j = j + tCount
             If Len(tempC) Then
                temp = temp + $CrLf + tempC + "  " + Str$(tCount)
                If task$ = "print" Then
                   Incr pCount
                   If pCount Mod 50 = 0 Then XPrint FormFeed
                   XPrint tempC + "  " + Str$(tCount)
                End If
             End If
             tempC = tempList(i)
             tCount = 1
          Else
             Incr tCount
          End If
       Next i
    
       If j < iCount+1 Then
          If Len(tempC) Then temp = temp + $CrLf + tempC + "  " + Str$(tCount)
          If task$ = "print" Then XPrint tempC + "  " + Str$(tCount)
       End If
    
       If task$ = "print" Then XPrint Close
    
       Select Case task$
          Case "display"
             'display the unique elements/count
             ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(SBProc), GetModuleHandle(""), GetCurrentThreadId)
             MessageBox(0, (temp), "Layout Content Summary", %MB_Ok + %MB_IconInformation + %MB_TaskModal)
             UnhookWindowsHookEx ghHook
          Case "copy"
             Clipboard Reset
             Clipboard Set Text temp$
       End Select
    
    End Sub
    
    Function FillStyleDesc(i As Long) As String
       If Debug Then Txt.Print FuncName$
       Select Case i
          Case 0 : Function = "Solid"
          Case 1 : Function = "Horizontal"
          Case 2 : Function = "Vertical"
          Case 3 : Function = "UpwardDiagonal"
          Case 4 : Function = "DownwardDiagonal"
          Case 5 : Function = "Crossed"
          Case 6 : Function = "DiagonalCrossed"
       End Select
    End Function
    
    Sub GetNewZ
       If Debug Then Txt.Print FuncName$
       Local temp$,tmp$, x,y As Long
       Dialog Get Loc hDlg To x,y
       ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(InputBoxProc), GetModuleHandle(""), GetCurrentThreadId)
       CenterOverDialog(300,90,x,y)
       temp$ = InputBox$("", "Enter New Z Values (Z0:Z)", Str$(Z0Height) + ":" + Str$(ZHeight),x,y)
       UnhookWindowsHookEx ghHook
       If Len(temp$) Then
          tmp$ = Parse$(temp$,":",1)
          If Trim$(tmp$) <> "-" Then Z0Height = Val(tmp$) Else Z0Height = -9999
          tmp$ = Parse$(temp$,":",2)
          If Trim$(tmp$) <> "-" Then ZHeight = Max&(1,Val(tmp$)) Else ZHeight = -1
       End If
    End Sub
    
    Sub ReplaceSelectedItemsText
       If Debug Then Txt.Print FuncName$
       Local temp, tempFrom, tempTo As String, i,x,y As Long
    
       'get From:To
       Dialog Get Loc hDlg To x,y
       ghHook = SetWindowsHookEx(%WH_CBT, CodePtr(InputBoxProc), GetModuleHandle(""), GetCurrentThreadId)
       CenterOverDialog(300,90,x,y)
       temp = InputBox$("", "Enter From:To Text", "from:to",x,y)
       UnhookWindowsHookEx ghHook
       If Len(temp) =0 Then Exit Sub
    
       tempFrom = Parse$(temp,":",1)
       tempTo = Parse$(temp,":",2)
    
       For i = UndoPos To 1 Step -1
          If D(i).selected Then
             If LCase$(D(i).desc) = LCase$(tempFrom) Then D(i).desc = tempTo : Dirty = 1
          End If
       Next i
       FillListView
       DrawLayout
    End Sub
    
    Sub SetSelectedColor
       If Debug Then Txt.Print FuncName$
       Local i,NewColor As Long
       'get newcolor
       NewColor = SelectColor(%White)
       For i = UndoPos To 1 Step -1
          If D(i).selected Then D(i).bgcolor = NewColor
       Next i
       DrawLayout
    End Sub
    
    Sub CopyEllipticalAreaFromImageToMe(i As Long)
       If Debug Then Txt.Print FuncName$
       Local x,y,w0,h0,w1,h1 As Long,hWin,hWinDC,pwGraphics As Dword
    
       'do all the drawing on a hidden memory bitmap
       GdiPGetImageWidth(Images(D(i).imgPos).pImage,w0)
       GdiPGetImageHeight(Images(D(i).imgPos).pImage,h0)
    
       Graphic Bitmap New w0,h0 To hWin
       Graphic Attach hWin,0
       Graphic Get DC To hWinDC
    
       GdipCreateFromHDC(hWinDC, pwGraphics)                  ' Create the Graphic object
       GdipDrawImage(pwGraphics, Images(D(i).imgPos).pImage, 0, 0)             ' Draw the image
    
    
       w1 = D(i).rect.nRight - D(i).rect.nLeft
       h1 = D(i).rect.nBottom - D(i).rect.nTop
       x = (w0-w1)/2
       y = (h0-h1)/2
       Graphic Ellipse (x,y)-(w1,h1),%Red
    
       Graphic Paint (1,1), %White,%Red 'RGB(1,1,1)
       Graphic Paint (w0-1,1), %White,%Red 'RGB(1,1,1)
       Graphic Paint (1,h0-1), %White,%Red 'RGB(1,1,1)
       Graphic Paint (w0-1,h0-1), %White,%Red 'RGB(1,1,1)
    
       TransparentBlt hDC,D(i).rect.nLeft+x, D(i).rect.nTop+y,w1,h1,hWinDC,x,y,w0,h0,%Red  'RGB(1,1,1)
       Graphic Bitmap End
       Graphic Attach hDlg, %IDC_Graphic, ReDraw
    '   Graphic Copy hWin,0
    End Sub
    
    Sub Export3DFile
       Local i,XMax,YMax As Long, temp$
       Open $ThreeDFile For Output As #1
    
       'identifier
       Print #1, "gbBlocks3D"
    
       'floor (get perimeter + 20)
       For i = 1 To UndoPos
          XMax = Max&(XMax,D(i).rect.nRight)
          YMax = Max&(YMax,D(i).rect.nBottom)
       Next i
       XMax = Max&(XMax + 20,100) : YMax = Max&(YMax + 20,100)
       temp$ = "0, 0, 0, " + Str$(Xmax)+ "," + Str$(YMax) + ", 20," + Str$(BGColor) + ", 0, 2, 0, 0, 0, Floor, <no image>"
       Print #1, temp$
    
       'parts
       For i = UndoPos To 1 Step -1
          Print #1, Str$(D(i).rect.nLeft), "," + _
                    Str$(D(i).rect.nTop), "," + _
                    Str$(D(i).z0), "," + _
                    Str$(D(i).rect.nRight - D(i).rect.nLeft), "," + _
                    Str$(D(i).rect.nBottom - D(i).rect.nTop), "," + _
                    Str$(D(i).z), "," + _
                    Str$(D(i).bgcolor), "," + _
                    Str$(D(i).transparency), "," + _
                    Str$(D(i).shape), "," + _    '2=rect 3=circle 4=line
                    "0", "," + _   'unusedA
                    "0", "," + _   'unusedB
                    "0", "," + _   'unusedC
                    "", "," + _    'unused string needed by gbBlocks3D
                    D(i).desc, "," + _
                    Exe.Path$ + D(i).img
       Next i
       Close #1
    End Sub
    
    Function ItemProperties(iPos As Long) As String
       If Debug Then Txt.Print FuncName$
    
       Local info$, iResult, Lower, Upper As Long
       If iPos = -1 Then
          Lower = UndoPos : Upper = 1
          info$ = "Number Items:  " + Str$(UndoPos) + "/" + LTrim$(Str$(UBound(D))) + $CrLf
       Else
          Lower = iPos      : Upper = iPos
       End If
    
       For iResult = Lower To Upper Step -1
          If iPos = -1 Then info$ = info$ + $CrLf + "----- Item " + Str$(iResult) + "-------------------------------------
          info$ = info$ + $CrLf + "Desc:" + $Tab + $Tab + D(iResult).desc
          info$ = info$ + $CrLf + "Shape:" + $Tab + $Tab + Choose$(D(iResult).shape,"","Box","Circle","Line")
          info$ = info$ + $CrLf + "Bounding Rect:" + $Tab + Str$(D(iResult).rect.nLeft) + Str$(D(iResult).rect.nTop) + Str$(D(iResult).rect.nRight) + Str$(D(iResult).rect.nBottom)
          info$ = info$ + $CrLf + "z (3D Height):" + $Tab + Str$(D(iResult).z)
          info$ = info$ + $CrLf + "z (3D Position):" + $Tab + Str$(D(iResult).z0)
          info$ = info$ + $CrLf + "Scale Factor:" + $Tab + Str$(D(iResult).sf)
          info$ = info$ + $CrLf + "Rounded:" + $Tab + $Tab + Str$(D(iResult).rounded)
    
          info$ = info$ + $CrLf + "ShowBorder:" + $Tab + Str$(D(iResult).showborder)
          info$ = info$ + $CrLf + "ShowDesc:" + $Tab + Str$(D(iResult).showdesc)
          info$ = info$ + $CrLf + "ShowImage:" + $Tab + Str$(D(iResult).showimage)
    
          info$ = info$ + $CrLf + "BGTransparent:" + $Tab + Str$(D(iResult).bgtransparent)
          info$ = info$ + $CrLf + "BGColor:" + $Tab + $Tab + Str$(D(iResult).bgcolor)
          info$ = info$ + $CrLf + "FGColor:" + $Tab + $Tab + Str$(D(iResult).fgcolor)
          info$ = info$ + $CrLf + "DescColor:" + $Tab + Str$(D(iResult).desccolor)
          info$ = info$ + $CrLf + "FillStyle:" + $Tab + $Tab + FillStyleDesc(D(iResult).fillstyle)
    
          info$ = info$ + $CrLf + "Group:" + $Tab + $Tab + IIf$(Len(D(iResult).group), D(iResult).group, "<none>")
          info$ = info$ + $CrLf + "TextPos:" + $Tab + $Tab + Choose$(D(iResult).textpos+1,"Center","Top","Bottom")
          info$ = info$ + $CrLf + "TextRot:" + $Tab + $Tab + Str$(D(iResult).textrot)
          info$ = info$ + $CrLf + "Theta:" + $Tab + $Tab + Str$(D(iResult).theta)
    
          info$ = info$ + $CrLf + "Image:" + $Tab + $Tab + IIf$(Len(D(iResult).img), D(iResult).img, "<not specified>")
          info$ = info$ + $CrLf + "ImagePos:" + $Tab + IIf$(Len(D(iResult).img), Str$(D(iResult).imgPos), "<not specified>")
    
          info$ = info$ + $CrLf + "Selected:" + $Tab + $Tab + Str$(D(iResult).selected)
       Next iResult
       Function = info$
    End Function
    
    Sub RotateAboutZAxis(Ang As Long, x As Single, y As Single)
       Local NewX, NewY As Long, A As Single
       A = Ang * 3.14159 / 180
       NewX = X * Cos(A) - Y * Sin(A)
       NewY = X * Sin(A) + Y * Cos(A)
       X = NewX : Y = NewY
    End Sub
    As always, suggestions and comments are welcome!
    Last edited by Gary Beene; 19 Mar 2013, 09:33 PM. Reason: updated code to v1.2

  • #2
    Updated code to v1.2.

    Key Features Added since original release:

    1. Resize items using mouse
    2. Rotation of rectangles and lines
    3. Alignment to leftmost/topmost items in selection

    Comment

    Working...
    X