internal bool HasToolbar; //small caption, maybe no splitter etc /// <summary> /// This ctor is used at startup, when adding from XML. /// </summary> internal _Panel(AuDockPanel manager, _Split parentSplit, XElement x, _Tab parentTab = null) : base(manager, parentSplit) { var name = x.Attr("name"); var c = manager._initControls[name]; _manager._aPanel.Add(this); this.Content = c; Debug.Assert(c.Name == name); this.Name = name; this.ParentTab = parentTab; if (c is ToolStrip ts) { _InitToolstrip(ts); } else if (x.HasAttr("doc")) { this.HasDocument = true; // c.AccessibleRole = AccessibleRole.Document; //no, its child is DOCUMENT //} else { // c.AccessibleRole = AccessibleRole.Pane; } c.AccessibleRole = AccessibleRole.Pane; this.InitDockStateFromXML(x); }
/// <summary> /// This ctor is used when a floating _Panel dropped on a docked non-tabbed _Panel caption. /// item1 or item2 must be docked, but not both. /// </summary> internal _Tab(AuDockPanel manager, _Split parentSplit, _Panel item1, _Panel item2) : base(manager, parentSplit) { manager._aTab.Add(this); this.Items = new List <_Panel>() { item1, item2 }; item1.ParentTab = item2.ParentTab = this; Debug.Assert(item1.IsDocked != item2.IsDocked); _dockedItemCount = 1; this.SetActiveItem(item1.IsDocked ? item1 : item2); }
/// <summary> /// This ctor is used when a floating _ContentNode dropped on a docked _ContentNode. /// child1 or child2 must be docked, but not both. /// </summary> internal _Split(AuDockPanel manager, _Split parentSplit, _Node child1, _Node child2, bool isVertical) : base(manager, parentSplit) { manager._aSplit.Add(this); Child1 = child1; Child2 = child2; child1.ParentSplit = child2.ParentSplit = this; Debug.Assert(child1.IsDocked != child2.IsDocked); _dockedChildCount = 1; IsVerticalSplit = isVertical; SplitterWidth = _splitterWidth; _isFraction = true; _fraction = 0.5F; }
bool _onlyIcons; //display only icons in tab buttons (too small to display text) /// <summary> /// This ctor is used at startup, when adding from XML. /// </summary> internal _Tab(AuDockPanel manager, _Split parentSplit, XElement x) : base(manager, parentSplit) { manager._aTab.Add(this); int iAct = x.Attr("active", 0); var xPanels = x.Elements("panel"); this.Items = new List <_Panel>(); int i = 0; foreach (var xx in xPanels) { var gp = new _Panel(manager, parentSplit, xx, this); this.Items.Add(gp); if (gp.IsDocked) { _dockedItemCount++; if (i == iAct || this.ActiveItem == null) { this.ActiveItem = gp; //if iAct invalid, let the first docked panel be active } } i++; } foreach (var gp in this.Items) { if (gp.IsDocked && gp != this.ActiveItem) { gp.Content.Visible = false; } } this.InitDockStateFromXML(x); }
internal _Node(AuDockPanel manager, _Split parentSplit) { _manager = manager; ParentSplit = parentSplit; //manager._nodes.Add(this); }
/// <summary> /// Docks this _Panel or _Tab in an existing or new _Tab or _Split. /// If need, creates new _Tab or _Split in gcTarget place and adds gcTarget and this to it. Else reorders if need. /// This can be a new _Panel, with null ParentSplit and ParentTab, dock state not Docked. /// </summary> /// <param name="gcTarget">New sibling _Panel (side can be any) or sibling _Tab (when side is SplitX) or parent _Tab (when side is TabX).</param> /// <param name="side">Specifies whether to add on a _Tab or _Split, and at which side of gcTarget.</param> internal void DockBy(_ContentNode gcTarget, _DockHow side) { var gpThis = this as _Panel; var gtThisParent = gpThis?.ParentTab; var gsThisParent = this.ParentSplit; var gsTargetParent = gcTarget.ParentSplit; if (side == _DockHow.TabBefore || side == _DockHow.TabAfter) { var gpTarget = gcTarget as _Panel; _Tab gtTargetParent = (gpTarget != null) ? gpTarget.ParentTab : gcTarget as _Tab; bool after = side == _DockHow.TabAfter; bool sameTargetTab = false; if (gtTargetParent != null) { gtTargetParent.AddOrReorderItem(gpThis, gpTarget, after); if (gtThisParent == gtTargetParent) { sameTargetTab = true; } } else { var gtNew = new _Tab(_manager, gsTargetParent, after ? gpTarget : gpThis, after ? gpThis : gpTarget); gsTargetParent.ReplaceChild(gpTarget, gtNew); gtNew.Bounds = gpTarget.Bounds; gtNew.CaptionAt = gpTarget.CaptionAt; } if (!sameTargetTab) { this.ParentSplit = gsTargetParent; if (gtThisParent != null) { gtThisParent.OnItemRemoved(gpThis); } else { gsThisParent?.OnChildRemoved(this); } } } else { if (gcTarget.IsTabbedPanel) { gcTarget = (gcTarget as _Panel).ParentTab; } bool after = side == _DockHow.SplitRight || side == _DockHow.SplitBelow; bool verticalSplit = side == _DockHow.SplitLeft || side == _DockHow.SplitRight; if (gsTargetParent == gsThisParent && gtThisParent == null) { //just change vertical/horizontal or/and swap with sibling gsThisParent.RepositionChild(this, verticalSplit, after); } else { var gsNew = new _Split(_manager, gsTargetParent, after ? gcTarget : this, after ? this : gcTarget, verticalSplit); gsTargetParent.ReplaceChild(gcTarget, gsNew); gsNew.Bounds = gcTarget.Bounds; if (gtThisParent != null) { gpThis.ParentTab = null; gtThisParent.OnItemRemoved(gpThis); } else { gsThisParent?.OnChildRemoved(this); } } } SetDockState(_DockState.Docked, false); }
internal _DockState SavedVisibleDockState; //when hidden, in what state to show internal _ContentNode(AuDockPanel manager, _Split parentSplit) : base(manager, parentSplit) { _parentControl = manager; }
internal _DummyNode(AuDockPanel manager, _Split parentSplit) : base(manager, parentSplit) { this.DockState = _DockState.Hidden; }
//Loads and parses XML. Creates the _aX lists, _firstSplit and the tree structure. void _LoadXmlAndCreateLayout(string xmlFileDefault, string xmlFileCustomized) { //We have 1 or 2 XML files containing panel/toolbar layout. //xmlFileDefault contains default XML. It eg can be in AFolders.ThisApp. //xmlFileCustomized contains previously saved XML (user-modified layout). //At first try to load xmlFileCustomized. If it does not exist or is invalid, load xmlFileDefault; or get missing data from xmlFileDefault, if possible. //Also loads xmlFileDefault when xmlFileCustomized XML does not match panels of new app version and cannot resolve it (eg some panels removed). bool usesDefaultXML = false; string xmlFile = xmlFileCustomized, xmlVersion = null, outInfo = null; for (int i = 0; i < 2; i++) { if (i == 0) { if (!AFile.ExistsAsFile(xmlFile)) { continue; } } else { usesDefaultXML = true; xmlFile = xmlFileDefault; } bool fileLoaded = false; try { var x = AExtXml.LoadElem(xmlFile); fileLoaded = true; if (!usesDefaultXML) { xmlVersion = x.Attr("version"); } x = x.Element("split"); //THIS DOES THE MAIN JOB _firstSplit = new _Split(this, null, x); if (_aPanel.Count < _initControls.Count) //more panels added in this app version { if (usesDefaultXML) { throw new Exception("debug1"); } _GetPanelXmlFromDefaultFile(xmlFileDefault); } break; //speed: xml.Load takes 170 microseconds. //tested: XML can be added to Application Settings, but var xml=Properties.Settings.Default.PanelsXML takes 61 MILLIseconds. } catch (Exception e) { var sErr = $"Failed to load file '{xmlFile}'.\r\n\t{e.ToStringWithoutStack()}"; if (usesDefaultXML) { _xmlFile = null; ADialog.ShowError("Cannot load panel/toolbar layout.", $"{sErr}\r\n\r\nReinstall the application."); Environment.Exit(1); } else { //probably in this version there are less panels, most likely when downgraded. Or the file is corrupt. if (fileLoaded && xmlVersion != _asmVersion) { outInfo = "Info: this application version resets the panel/toolbar layout, sorry."; } else { AWarning.Write(sErr, -1); } } _aSplit.Clear(); _aTab.Clear(); _aPanel.Clear(); } } //if(usesDefaultXML || xmlVersion == _asmVersion) return; if (outInfo != null) { AOutput.Write(outInfo); } }
int _width; //used if !_isFraction; if _isWidth1, it is Child1 width, else Child2 with /// <summary> /// This ctor is used at startup, when adding from XML. /// </summary> internal _Split(AuDockPanel manager, _Split parentSplit, XElement x) : base(manager, parentSplit) { manager._aSplit.Add(this); if (!x.HasAttr("hor")) { IsVerticalSplit = true; } int k = x.Attr("splitter", -1); if (k < 0 || k > 20) { k = _splitterWidth; } this.SplitterWidth = k; //SHOULDDO: use DPI-dependent units, not pixels. Especially if form size depends on DPI. if (!(_isFraction = x.Attr(out _fraction, "f")) && !(_isWidth1 = x.Attr(out _width, "w1"))) { _width = x.Attr("w2", 1); } foreach (var xe in x.Elements()) { _Node gn = null; switch (xe.Name.LocalName) { case "panel": gn = new _Panel(manager, this, xe); break; case "split": gn = new _Split(manager, this, xe); break; case "tab": gn = new _Tab(manager, this, xe); break; case "dummy": gn = new _DummyNode(_manager, this); break; default: continue; } if (gn.IsDocked) { _dockedChildCount++; } if (Child1 == null) { Child1 = gn; } else { Child2 = gn; break; } } if (Child2 == null) { throw new Exception(); } if (_dockedChildCount == 0) { this.DockState = _DockState.Hidden; } }