private void UpdateSidebar(MultiPaneControl sender, SidebarEntry[] entries) { // If the sub-sidebar is empty => there nothing to update, do nothing if (entries == null) { return; } // Will be used to update independently the entry's parents from the entrie // to avoid having its newly assigned status being overridden SidebarEntry ActiveEntry = null; // Will be used to go through the active entry's parents SidebarEntry ParentEntry; // Is the entry active? bool ActiveState; // Update every entry of the given sub-sidebar // (disclamer: we don't use a while loop there to disable every inactive state) foreach (SidebarEntry e in this.GoThroughEntries(entries)) { ActiveState = false; // if the sub-sidebar entry has attached page if (e.Target != null) { ActiveState = sender.SelectedPage == e.Target; // if the new page is same page than the attached one: // -> change its color to the active one // -> mark the entry has active // else: // -> put the inactive color // -> mark it as inactive if (ActiveState) { ActiveEntry = e; this.Text = this.BaseName + " - " + e.Text; } } ToggleEntryActive(e, ActiveState); } // Proceed the active entry and its parents (if there was one) if (ActiveEntry != null) { // Mark the parent as active as well ParentEntry = ActiveEntry.parent; while (ParentEntry != null) { ToggleEntryActive(ParentEntry, true); ParentEntry = ParentEntry.parent; } } }
// Toggle the active state of a given entry and thus the color private void ToggleEntryActive(SidebarEntry e, bool active) { e._OwnerController.ForeColor = active ? this.ActiveBaseSidebarEntryColor : this.BaseSidebarEntryColor; e.IsActive = active; }
private FlowLayoutPanel GenerateSidebarEntry(SidebarEntry e) { Label EntryIcon; Label EntryText; // future lambda event handlers EventHandler OnMouseLeave; EventHandler OnMouseEnter; EventHandler OnMouseClick; // Declare and create the entry's container // Warning: we MUST put the declaration here to make the bellow // lambda functions point on the right container. FlowLayoutPanel entry_layout = new FlowLayoutPanel(); // init the entry labels EntryIcon = new Label(); EntryText = new Label(); // create the mouse events (hover and release/ leave) OnMouseEnter = (s, ev) => { // change the entry color to the active one entry_layout.ForeColor = this.ActiveBaseSidebarEntryColor; }; OnMouseLeave = (s, ev) => { // put the inactive color on mouse leave if and only if // the entry is not marked as active if (e.IsActive != true) { entry_layout.ForeColor = this.BaseSidebarEntryColor; } }; OnMouseClick = (s, ev) => { if (e.Target != null) { // Swith to the target SwitchPanel(e.Target); } // if there is a callback, call it if (e.TargetCallback != null) { e.TargetCallback(); } // don't change the active item if there is only a callback and no TargetPage if (!(e.Target == null && e.TargetCallback != null)) { // if the entry is not a child: unexpand everything if (!e.IsExpanded && e.parent == null) { // close everything opened on the sidebar // (we don't care if the entry has children or not, close anyway) UnexpandSidebarEntries(); } // if the entry has children: toggle the children' visibility if (e.children != null && e.children.Length > 0) { // set the children visible e.IsExpanded = !e.IsExpanded; ToggleSidebarChildren(e.children, e.IsExpanded); } } }; // Set the container layout to AutoSize to allow the sidebar to be able to resize itself // + disallow content wrapping to force the layout to resize itself, provoking the sidebar to grow entry_layout.AutoSize = true; entry_layout.WrapContents = false; // set the inactive color to the whole container entry_layout.ForeColor = this.BaseSidebarEntryColor; // assign the events to EVERY component of the entry entry_layout.MouseEnter += OnMouseEnter; entry_layout.MouseLeave += OnMouseLeave; entry_layout.Click += OnMouseClick; EntryIcon.MouseEnter += OnMouseEnter; EntryIcon.MouseLeave += OnMouseLeave; EntryIcon.Click += OnMouseClick; EntryText.MouseEnter += OnMouseEnter; EntryText.MouseLeave += OnMouseLeave; EntryText.Click += OnMouseClick; // ---- // The inner layout is gonna contain in the following order: // [Label: ICON] [Label: Text] // So we put the layout's direction in Left to Right entry_layout.FlowDirection = FlowDirection.LeftToRight; // [Label: ICON] [Label: Text] entry_layout.Controls.Add(EntryIcon); entry_layout.Controls.Add(EntryText); // spacing between every entry is of 15px (margin bottom = 15) entry_layout.Margin = new Padding(this.BaseEntryMargin.Left, this.BaseEntryMargin.Top, this.BaseEntryMargin.Right, this.BaseEntryMargin.Bottom); // the icon's label is a square of 30x30 EntryIcon.AutoSize = false; EntryIcon.Height = EntryIcon.Width = 30; // Auto resize the text label EntryText.AutoSize = true; // align everything on top-left EntryText.TextAlign = EntryIcon.TextAlign = ContentAlignment.TopLeft; // XXX: we probably don't need this line anymore EntryText.Height = EntryIcon.Height; // set the icon's label in MaterialFont EntryIcon.Font = this.IconFont; // Convert the UTF-8 byte array to String EntryIcon.Text = e.Icon != null?Encoding.UTF8.GetString(e.Icon) : ""; // Make the entry's text (entry name) label bigger EntryText.Font = new Font("Microsoft Sans Serif", 13.0f, FontStyle.Regular, GraphicsUnit.Point); EntryText.Text = e.Text; // set the layout's height at the same height of the icon entry_layout.Height = EntryIcon.Height; e._OwnerController = entry_layout; return(entry_layout); }