VERSION 1.0 CLASS BEGIN MultiUse = -1 'True END Attribute VB_Name = "API_ShapeStorage" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = False Attribute VB_Exposed = False ' ===== Visio shape storage manager simulating grid ======== ' Shared module version: 20210707 ' Depends on: ' Required reference: Scripting Option Explicit Private Const SS_AREA_RATIO = 20# ' target sum widht / height ratio Private Const SS_STORAGE_GAP = 0.1 ' gap between shapes in inches Private Const SS_STORAGE_MAX_LVL = 1024 ' maximum number of rows Private Const SS_PRECISION = 3 Private originX_ As Double Private originY_ As Double Private areaHeight_ As Double Private lvlCount_ As Long Private levelHeight_(1 To SS_STORAGE_MAX_LVL) As Double Private levelX_(1 To SS_STORAGE_MAX_LVL) As Double Private levelY_(1 To SS_STORAGE_MAX_LVL) As Double Public items_ As Scripting.Dictionary Public Function Init(xOrigin As Double, yOrigin As Double) originX_ = xOrigin originY_ = yOrigin areaHeight_ = 0 lvlCount_ = 0 Set items_ = New Scripting.Dictionary End Function Public Property Get TargetPage() As Visio.Page If items_.Count > 0 Then _ Set TargetPage = items_.Items(1).Parent End Property Public Function Store(target As Visio.Shape) As Boolean Store = Not items_.Exists(target.ID) If Not Store Then _ Exit Function Call items_.Add(target.ID, target) Dim nLvl&: nLvl = GetLevelForNew(target.Cells("Height")) target.Cells("PinX") = levelX_(nLvl) + target.Cells("Width") / 2# target.Cells("PinY") = levelY_(nLvl) + target.Cells("Height") / 2# Call IncrementLevelWidth(nLvl, target.Cells("Width")) End Function Public Function GiveBack(target As Visio.Shape) If items_.Exists(target.ID) Then _ Call items_.Remove(target.ID) End Function '============= Private Function GetLevelForNew(dHeight As Double) As Long Dim minLvl&: minLvl = 0 Dim minX As Double: minX = 100000000# Dim nLvl& For nLvl = 1 To lvlCount_ Step 1 If VBA.Round(levelHeight_(nLvl), SS_PRECISION) + SS_STORAGE_GAP >= VBA.Round(dHeight, SS_PRECISION) And _ VBA.Round(minX, SS_PRECISION) > VBA.Round(levelX_(nLvl), SS_PRECISION) Then minLvl = nLvl minX = levelX_(nLvl) End If Next nLvl If minLvl = 0 Then GetLevelForNew = CreateNewLevel(dHeight) ElseIf levelX_(minLvl) > SS_AREA_RATIO * VBA.Round(areaHeight_, SS_PRECISION) And lvlCount_ <= SS_STORAGE_MAX_LVL Then GetLevelForNew = CreateNewLevel(dHeight) Else GetLevelForNew = minLvl End If End Function Private Function CreateNewLevel(dHeight As Double) As Long lvlCount_ = lvlCount_ + 1 levelHeight_(lvlCount_) = dHeight levelY_(lvlCount_) = originY_ + areaHeight_ levelX_(lvlCount_) = originX_ areaHeight_ = areaHeight_ + dHeight + SS_STORAGE_GAP CreateNewLevel = lvlCount_ End Function Private Function IncrementLevelWidth(nLvl&, incWidth As Double) levelX_(nLvl) = levelX_(nLvl) + SS_STORAGE_GAP + incWidth End Function