public MapRenderer(LayoutRenderer owner, TrackerMapPlacement mapPlacement)
            {
                this.owner     = owner;
                this.placement = mapPlacement;
                this.map       = owner.trackerDefinition.maps[mapPlacement.name];
                var metrics = owner.trackerDefinition.GetEffectiveMetrics(mapPlacement);

                markerSets.AddRange(map.markerSets);
                markerSets.AddRange(mapPlacement.markerSets);

                x          = placement.x ?? 0;
                y          = placement.y ?? 0;
                cellWidth  = placement.cellWidth ?? 1;
                cellHeight = placement.cellHeight ?? 1;
                gridWidth  = map.gridWidth;
                gridHeight = map.gridHeight;
                StateName  = placement.stateName ?? map.stateName;

                var placementBackgrounds = placement.backgrounds ?? metrics.backgrounds ?? new string[0];

                backgrounds = new Bitmap[placementBackgrounds.Length];
                for (var i = 0; i < placementBackgrounds.Length; i++)
                {
                    backgrounds[i] = owner.trackerDefinition.Meta.GetImage(map.backgrounds[i]);
                }
            }
        private void InitializeTracker()
        {
            bool isEmpty     = _layout == null;
            bool willBeEmpty = false;

            if (_layoutFile == null || _layoutName == null)
            {
                willBeEmpty = true;
            }
            else
            {
                TrackerLayout l;
                if (!_layoutFile.layouts.TryGetValue(_layoutName, out l))
                {
                    willBeEmpty = true;
                }
            }

            if (!isEmpty && willBeEmpty)
            {
                UninitializeTracker();
            }
            else if (!willBeEmpty)
            {
                // ACTUALLY INITIALIZE
                FreeLayoutResources();

                _layout = _layoutFile.layouts[_layoutName];
                if (cachedViews.ContainsKey(_layoutName))
                {
                    _renderer = cachedViews[_layoutName];
                    _renderer.Update(); // Todo: determine if cached views should update in realtime, or if not, they should at least to allow redundant invalidations
                }
                else
                {
                    _renderer = new LayoutRenderer(_layoutFile, _layoutName);
                    if (CacheViews && !cachedViews.ContainsKey(_layoutName))
                    {
                        cachedViews.Add(_layoutName, _renderer);
                    }
                }
                foreach (var placement in _layout.maps)
                {
                    var       mmap   = _layoutFile.GetEffectiveMetrics(placement);
                    Rectangle bounds = new Rectangle(
                        mmap.x,
                        mmap.y,
                        mmap.cellWidth * mmap.gridWidth,
                        mmap.cellHeight * mmap.gridHeight
                        );
                    mapBounds.Add(Tuple.Create(mmap, bounds));
                }

                SetupPicker();
                Invalidate(new Rectangle(0, 0, _renderer.Width, _renderer.Height));
            }
        }
 private void FreeLayoutResources()
 {
     // Todo: clear any layout-specific values and free any resources
     if (_renderer != null && (_unloadingLayoutName != null && !cachedViews.ContainsKey(_unloadingLayoutName)))
     {
         _renderer.Dispose();
     }
     _renderer = null;
     _layout   = null;
     mapBounds.Clear();
 }