Exemplo n.º 1
0
        void _SaveLayout()
        {
            try {
                if (ZResetLayoutAfterRestart)
                {
                    AFile.Delete(_xmlFile);
                    return;
                }
                AFile.CreateDirectoryFor(_xmlFile);
                var sett = new XmlWriterSettings()
                {
                    OmitXmlDeclaration = true,
                    Indent             = true,
                    IndentChars        = "\t"
                };
                AFile.Save(_xmlFile, temp => {
                    using (var x = XmlWriter.Create(temp, sett)) {
                        x.WriteStartDocument();
                        x.WriteStartElement("panels");
                        x.WriteAttributeString("version", _asmVersion);
                        _firstSplit.Save(x);
                        x.WriteEndDocument();
                    }
                });
            }
            catch (Exception ex) {
#if DEBUG
                AOutput.QM2.Write(ex);                 //cannot Write or show dialog in ctor
#else
                _ = ex;
#endif
                //AOutput.Write(ex);
                //these don't work, maybe because now is closing app. Never mind, unlikely to fail, and not very important.
                //ADialog.ShowError("Failed to save panel/toolbar layout", _xmlFile, DFlags.Wider, expandedText: e.ToString());
                //MessageBox.Show("aaaa");
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates a menu or toolbar item.
        /// </summary>
        /// <param name="x">XML element containing item properties.</param>
        /// <param name="isMenu">false if toolbar item, true if menu item (also if menu bar item).</param>
        ToolStripItem _CreateChildItem(XElement x, bool isMenu)
        {
            string s, tag = x.Name.LocalName;

            if (tag == "sep")
            {
                return new ToolStripSeparator()
                       {
                           Tag = x
                       }
            }
            ;

            ToolStripItem item; ToolStripMenuItem mi;
            bool          isControl = false, needHandler = false;

            if (isMenu)
            {
                mi = new ToolStripMenuItem();

                item = mi;
                if (x.HasElements || x.HasAttr("dd"))
                {
                    _Submenu(x, mi, tag);
                }
                else
                {
                    needHandler = true;
                }
            }
            else if (x.HasAttr("type"))
            {
                isControl = true;
                string cue = x.Attr("cue");
                s = x.Attr("type");
                switch (s)
                {
                case "edit":
                    var ed = new ToolStripSpringTextBox();
                    if (cue != null)
                    {
                        ed.ZSetCueBanner(cue);
                    }
                    item = ed;
                    break;

                case "combo":
                    var combo = new ToolStripSpringComboBox();
                    if (cue != null)
                    {
                        combo.ZSetCueBanner(cue);
                    }
                    item = combo;
                    break;

                default:
                    Debug.Assert(false);
                    return(null);
                }
                if (cue != null)
                {
                    item.AccessibleName = cue;
                }
            }
            else if (x.HasElements || x.HasAttr("dd"))
            {
                ToolStripDropDownItem ddi;
                var handler = _callbacks.GetClickHandler(tag);
                if (handler != null)
                {
                    var sb = new ToolStripSplitButton();
                    sb.ButtonClick += handler;
                    ddi             = sb;
                }
                else
                {
                    ddi = new ToolStripDropDownButton();
                }
                item = ddi;
                _Submenu(x, ddi, tag);
            }
            else
            {
                needHandler = true;
                var b = new ToolStripButton();
                item = b;
            }

            item.Name = tag;
            item.Tag  = x;

            _SetItemProperties(x, item, isMenu, isControl);

            if (needHandler)
            {
                var handler = _callbacks.GetClickHandler(tag);
                if (handler != null)
                {
                    item.Click += handler;
                }
                else
                {
                    ADebug.Print("no handler of " + tag);
                    //return null;
                    //item.Enabled = false;
                    item.Visible = false;
                }
            }

            return(item);
        }

        void _Submenu(XElement x, ToolStripDropDownItem ddItem, string tag)
        {
            var s = x.Attr("dd");

            if (!s.NE())
            {
                ddItem.DropDown = Submenus[s];
            }
            else
            {
                var dd = ddItem.DropDown as ToolStripDropDownMenu;                 //note: not ddItem.DropDown=new ToolStripDropDownMenu(). Then eg hotkeys don't work.
                dd.Name = tag;
                dd.Tag  = x;
                Submenus.Add(tag, dd);

                if (s != null)                              //attribute dd="". Will be filled later, eg on Opening event.
                {
                    dd.Items.Add(new ToolStripSeparator()); //else no drop arrow and no Opening event
                    return;
                }
#if !LAZY_MENUS
                dd.SuspendLayout();                 //with this don't need lazy menus
                _AddChildItems(x, dd, true);
                dd.ResumeLayout(false);
#else
                //Fill menu items later. This saves ~50 ms of startup time if not using dd.SuspendLayout. With dd.SuspendLayout - just 5 ms.
                //Can do it with Opening event or with timer. With timer easier. With event users cannot use MSAA etc to automate clicking menu items (with timer cannot use it only the first 1-2 seconds).
#if true
                ATimer.After(500, t =>
                {
                    dd.SuspendLayout();
                    _AddChildItems(x, dd, true);
                    dd.ResumeLayout(false);
                });
#else
                dd.Items.Add(new ToolStripSeparator());
                CancelEventHandler eh = null;
                eh = (sender, e) =>
                {
                    dd.Opening -= eh;
                    dd.Items.Clear();
                    _AddChildItems(x, dd, true);
                };
                dd.Opening += eh;
#endif
#endif
            }
        }

        void _SetItemProperties(XElement x, ToolStripItem item, bool isMenu, bool isControl)
        {
            string s, defaultText = null;

            var tt = x.Attr("tt");             //tooltip

            item.ToolTipText = tt ?? (isMenu ? null : (defaultText = _GetDefaultItemText(x)));

            if (!isMenu)
            {
                if (x.HasAttr("hide"))
                {
                    item.Overflow = ToolStripItemOverflow.Always;
                }
                else if (!_inBuildAll)
                {
                    item.Overflow = ToolStripItemOverflow.AsNeeded;
                }
            }
            if (isControl)
            {
                return;
            }

            Image im = null;

            if (x.Attr(out s, "i2"))              //custom image as icon file
            {
                im = AIcon.GetFileIconImage(s);
                if (im == null)
                {
                    AOutput.Write($"Failed to get {(isMenu ? "menu item" : "toolbar button")} {x.Name} icon from file {s}\n\tTo fix this, right-click it and select Properties...");
                }
                //SHOULDDO: async or cache
            }
            if (im == null && x.Attr(out s, "i"))
            {
                im = _callbacks.GetImage(s);                                              //image from resources
            }
            item.Image = im;

            if (x.Attr(out s, "color") && ColorInt.FromString(s, out var color))
            {
                item.ForeColor = (Color)color;
            }
            else if (!_inBuildAll)
            {
                item.ForeColor = Color.FromKnownColor(KnownColor.ControlText);
            }

            bool hasCustomText = x.Attr(out s, "t2");             //custom text

            item.Text = s ?? defaultText ?? _GetDefaultItemText(x);

            if (isMenu)
            {
                var mi = item as ToolStripMenuItem;
                if (!_inBuildAll)
                {
                    mi.ShortcutKeys             = 0;
                    mi.ShortcutKeyDisplayString = null;
                }
                if (x.Attr(out s, "hk"))
                {
                    bool ok = AKeys.More.ParseHotkeyString(s, out var hk);
                    if (ok)
                    {
                        try { mi.ShortcutKeys = hk; } catch { ok = false; }
                    }
                    if (!ok)
                    {
                        ADebug.Print("Invalid hotkey: " + s);
                    }
                }
                if (x.Attr(out string ss, "hkText"))
                {
                    mi.ShortcutKeyDisplayString = (s == null) ? ss : s + ", " + ss;
                }
            }
            else
            {
                var style = item.Image == null ? ToolStripItemDisplayStyle.ImageAndText : (ToolStripItemDisplayStyle)x.Attr("style", 0);
                if (style == 0)
                {
                    style = hasCustomText ? ToolStripItemDisplayStyle.ImageAndText : ToolStripItemDisplayStyle.Image;                            //0 is ToolStripItemDisplayStyle.None
                }
                item.DisplayStyle = style;
            }
        }

        /// <summary>
        /// If x has attribute t, gets its value.
        /// Else gets its name and converts to text, eg "File_OneTwo" to "One Two".
        /// </summary>
        string _GetDefaultItemText(XElement x)
        {
            if (!x.Attr(out string s, "t"))
            {
                string tag = x.Name.LocalName;
                s = tag.Remove(0, tag.LastIndexOf('_') + 1);                 //eg "Edit_Copy" -> "Copy"
                s = s.RegexReplace("(?<=[^A-Z])(?=[A-Z])", " ");             //"OneTwoThree" -> "One Two Three". //speed: don't need to optimize.
            }
            return(s);
        }

        /// <summary>
        /// Merges custom attributes into default menubar or toolbar XML.
        /// Reorders toolbar buttons if need.
        /// </summary>
        /// <param name="xCustom">Root element of customizations file.</param>
        /// <param name="xtsDef">Default menustrip or toolstrip. For custom toolbars the function can replace it.</param>
        /// <param name="name">xtsDef name, just to avoid getting it again.</param>
        /// <param name="isMenu"></param>
        void _MergeCustom(XElement xCustom, ref XElement xtsDef, string name, bool isMenu)
        {
            var xtsCust = xCustom.Element(xtsDef.Name); if (xtsCust == null)

            {
                return;
            }

            if (isMenu)
            {
            }
            else if (name.Starts("Custom"))
            {
                var xc = xCustom.Element(name); if (xc == null)
                {
                    return;
                }
                xc.Remove();
                xtsDef.ReplaceWith(xc);
                xtsDef = xc;
                return;
                //MSDN: "if the new content has no parent, then the objects are simply attached to the XML tree. If the new content already is parented and is part of another XML tree, then the new content is cloned". Tested, it's true.
            }
            else
            {
                //reorder toolbar buttons
                if (xtsCust.Attr(out string s, "order"))
                {
                    xtsDef.Elements("sep").Remove();                     //remove all default <sep/>, because all separators now are in the 'order' attribute
                    var a = s.SegSplit(" ");
                    for (int i = a.Length - 1; i >= 0; i--)
                    {
                        if (a[i] == "sep")
                        {
                            xtsDef.AddFirst(new XElement("sep"));
                        }
                        else
                        {
                            var xb = xtsDef.Element(a[i]); if (xb == null)
                            {
                                continue;
                            }
                            xb.Remove(); xtsDef.AddFirst(xb);
                        }
                    }
                }
            }

            foreach (var xCust in xtsCust.Elements())
            {
                foreach (var xDef in xtsDef.Descendants(xCust.Name))
                {
                    foreach (var att in xCust.Attributes())
                    {
                        xDef.SetAttributeValue(att.Name, att.Value);
                    }
                }
            }
        }

        /// <summary>
        /// Extracts differences between _xmlFileDefault and _xStrips and saves to _xmlFileCustom.
        /// </summary>
        void _DiffCustom()
        {
            var    xStripsDefault = AExtXml.LoadElem(_xmlFileDefault);
            var    xStripsCustom  = new XElement("strips");
            string s;

            //menus
            _DiffDescendants(MenuBar.Tag as XElement, true);

            //standard toolbars
            foreach (var ts in Toolbars.Values)
            {
                if (ts == _tsCustom1 || ts == _tsCustom2)
                {
                    continue;
                }
                _DiffDescendants(ts.Tag as XElement, false);
            }

            void _DiffDescendants(XElement xts, bool isMenu)
            {
                XElement xtsDef = xStripsDefault.Element(xts.Name), xtsCust = null;

                foreach (var x in xts.Descendants())
                {
                    var name = x.Name; if (name == "sep")
                    {
                        continue;
                    }
                    XElement xDef = xtsDef.Desc(name), xCust = null;
                    foreach (var att in x.Attributes())
                    {
                        var aname = att.Name;
                        if (att.Value == xDef.Attr(aname))
                        {
                            continue;
                        }
                        if (xtsCust == null)
                        {
                            xStripsCustom.Add(xtsCust = new XElement(xts.Name));
                        }
                        if (xCust == null)
                        {
                            xtsCust.Add(xCust = new XElement(name));
                        }
                        xCust.SetAttributeValue(aname, att.Value);
                    }
                }
                if (isMenu)
                {
                    return;
                }
                //order
                var s1 = new StringBuilder();
                var s2 = new StringBuilder();

                foreach (var x in xts.Elements())
                {
                    if (s1.Length > 0)
                    {
                        s1.Append(' ');
                    }
                    s1.Append(x.Name);
                }
                foreach (var x in xtsDef.Elements())
                {
                    if (s2.Length > 0)
                    {
                        s2.Append(' ');
                    }
                    s2.Append(x.Name);
                }
                s = s1.ToString();
                if (s != s2.ToString())
                {
                    if (xtsCust == null)
                    {
                        xStripsCustom.Add(xtsCust = new XElement(xts.Name));
                    }
                    xtsCust.SetAttributeValue("order", s);
                }
            }

            //custom toolbars. Temporarily move them from _xStrips to xCustom.
            var xCust1 = _tsCustom1.Tag as XElement;
            var xCust2 = _tsCustom2.Tag as XElement;

            if (xCust1.HasElements)
            {
                xCust1.Remove(); xStripsCustom.Add(xCust1);
            }
            if (xCust2.HasElements)
            {
                xCust2.Remove(); xStripsCustom.Add(xCust2);
            }

            //AOutput.Clear();
            //AOutput.Write(xStripsCustom);
#if true
            //save
            try {
                AFile.CreateDirectoryFor(_xmlFileCustom);
                xStripsCustom.SaveElem(_xmlFileCustom);
            }
            catch (Exception e) {
                AOutput.Write("Failed to save XML file", _xmlFileCustom, e.Message);
            }
#endif

            if (xCust1.HasElements)
            {
                xCust1.Remove(); _xStrips.Add(xCust1);
            }
            if (xCust2.HasElements)
            {
                xCust2.Remove(); _xStrips.Add(xCust2);
            }
        }