private static void RightHorizontalSplitPopup(SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds) { // Calculate left for right aligned split Vector2 popupPosition = new Vector2(systemWindow.Width - popup.Widget.Width, 0); Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); popup.Widget.Height = anchorLeft.Y; popup.Widget.Position = popupPosition; }
private static void BestPopupPosition(SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds) { // Calculate left aligned screen space position (using widgetRelativeTo.parent) Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom); Vector2 popupPosition = anchorLeft; var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds; Vector2 xPosition = GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); Vector2 screenPosition; screenPosition = anchorLeft + xPosition; // Constrain if (screenPosition.X + popup.Widget.Width > systemWindow.Width || screenPosition.X < 0) { xPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); } popupPosition += xPosition; Vector2 yPosition = GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); screenPosition = anchorLeft + yPosition; // Constrain if (anchor.AltMate != null && (screenPosition.Y + popup.Widget.Height > systemWindow.Height || screenPosition.Y < 0)) { yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); } popupPosition += yPosition; popup.Widget.Position = popupPosition; }
public static void ShowPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds, int borderWidth, Action <SystemWindow, MatePoint, MatePoint, RectangleDouble> layoutHelper) { var hookedParents = new HashSet <GuiWidget>(); List <IIgnoredPopupChild> ignoredWidgets = popup.Widget.Children.OfType <IIgnoredPopupChild>().ToList(); void widget_Draw(object sender, DrawEventArgs e) { if (borderWidth > 0) { e.Graphics2D.Render( new Stroke( new RoundedRect(popup.Widget.LocalBounds, 0), borderWidth * 2), AppContext.Theme.PopupBorderColor); } } void widgetRelativeTo_PositionChanged(object sender, EventArgs e) { if (anchor.Widget?.Parent != null) { layoutHelper.Invoke(systemWindow, anchor, popup, altBounds); } } void CloseMenu() { popup.Widget.AfterDraw -= widget_Draw; popup.Widget.Close(); anchor.Widget.Closed -= anchor_Closed; // Unbind callbacks on parents for position_changed if we're closing foreach (GuiWidget widget in hookedParents) { widget.PositionChanged -= widgetRelativeTo_PositionChanged; widget.BoundsChanged -= widgetRelativeTo_PositionChanged; } // Long lived originating item must be unregistered anchor.Widget.Closed -= anchor_Closed; // Restore focus to originating widget on close if (anchor.Widget?.HasBeenClosed == false) { anchor.Widget.Focus(); } } void FocusChanged(object s, EventArgs e) { UiThread.RunOnIdle(() => { // Fired any time focus changes. Traditionally we closed the menu if we weren't focused. // To accommodate children (or external widgets) having focus we also query for and consider special cases bool specialChildHasFocus = ignoredWidgets.Any(w => w.ContainsFocus || w.Focused || w.KeepMenuOpen); bool descendantIsHoldingOpen = popup.Widget.Descendants <GuiWidget>().Any(w => w is IIgnoredPopupChild ignoredPopupChild && ignoredPopupChild.KeepMenuOpen); // If the focused changed and we've lost focus and no special cases permit, close the menu if (!popup.Widget.ContainsFocus && !specialChildHasFocus && !descendantIsHoldingOpen && !PopupWidget.DebugKeepOpen) { CloseMenu(); } }); } void anchor_Closed(object sender, EventArgs e) { // If the owning widget closed, so should we CloseMenu(); } foreach (var ancestor in anchor.Widget.Parents <GuiWidget>().Where(p => p != systemWindow)) { if (hookedParents.Add(ancestor)) { ancestor.PositionChanged += widgetRelativeTo_PositionChanged; ancestor.BoundsChanged += widgetRelativeTo_PositionChanged; } } popup.Widget.ContainsFocusChanged += FocusChanged; popup.Widget.AfterDraw += widget_Draw; widgetRelativeTo_PositionChanged(anchor.Widget, null); anchor.Widget.Closed += anchor_Closed; // When the widgets position changes, sync the popup position systemWindow?.AddChild(popup.Widget); popup.Widget.Closed += (s, e) => { Console.WriteLine(); }; popup.Widget.Focus(); popup.Widget.Invalidate(); }
public static void ShowRightSplitPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), int borderWidth = 1) { ShowPopup(systemWindow, anchor, popup, altBounds, borderWidth, RightHorizontalSplitPopup); }
public static void ShowPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), int borderWidth = 1) { ShowPopup(systemWindow, anchor, popup, altBounds, borderWidth, BestPopupPosition); }
public static void ShowPopover(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), double secondsToClose = 0) { var settingsRow = anchor.Widget as SettingsRow; var sliceSettingsPopover = popup.Widget as ClickablePopover; var hookedWidgets = new HashSet <GuiWidget>(); void Anchor_Closed(object sender, EventArgs e) { if (popup.Widget is IOverrideAutoClose overideAutoClose && !overideAutoClose.AllowAutoClose) { return; } // If the owning widget closed, so should we popup.Widget.Close(); foreach (var widget in hookedWidgets) { widget.Closed -= Anchor_Closed; } } void widgetRelativeTo_PositionChanged(object sender, EventArgs e) { if (anchor.Widget?.Parent != null) { // Calculate left aligned screen space position (using widgetRelativeTo.parent) Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom); Vector2 popupPosition = anchorLeft; var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds; Vector2 xPosition = GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); Vector2 screenPosition; screenPosition = anchorLeft + xPosition; // Constrain if (screenPosition.X + popup.Widget.Width > systemWindow.Width || screenPosition.X < 0) { var altXPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); var altScreenPosition = anchorLeft + altXPosition; // Prefer clipping on edge revealed by resize if ((popup.AltMate.Right && altScreenPosition.X > -15) || (popup.AltMate.Left && altScreenPosition.X + popup.Widget.Width < systemWindow.Width)) { xPosition = altXPosition; if (settingsRow != null && sliceSettingsPopover != null) { sliceSettingsPopover.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Left ? ArrowDirection.Right : ArrowDirection.Left; } } } popupPosition += xPosition; Vector2 yPosition = GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); screenPosition = anchorLeft + yPosition; // Constrain if (anchor.AltMate != null && (screenPosition.Y + popup.Widget.Height > systemWindow.Height || screenPosition.Y < 0)) { yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); if (settingsRow != null) { settingsRow.ArrowDirection = settingsRow.ArrowDirection == ArrowDirection.Up ? ArrowDirection.Down: ArrowDirection.Up; } } popup.Widget.Closed += Anchor_Closed; anchor.Widget.Closed += Anchor_Closed; hookedWidgets.Add(anchor.Widget); foreach (var widget in anchor.Widget.Parents <GuiWidget>()) { widget.Closed += Anchor_Closed; hookedWidgets.Add(widget); } popupPosition += yPosition; popup.Widget.Position = popupPosition; } } widgetRelativeTo_PositionChanged(anchor.Widget, null); // When the widgets position changes, sync the popup position systemWindow?.AddChild(popup.Widget); if (secondsToClose > 0) { UiThread.RunOnIdle(() => Anchor_Closed(null, null), secondsToClose); } }
public static void ShowPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble)) { var hookedParents = new HashSet <GuiWidget>(); List <IIgnoredPopupChild> ignoredWidgets = popup.Widget.Children.OfType <IIgnoredPopupChild>().ToList(); void widgetRelativeTo_PositionChanged(object sender, EventArgs e) { if (anchor.Widget?.Parent != null) { // Calculate left aligned screen space position (using widgetRelativeTo.parent) Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position); anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom); Vector2 popupPosition = anchorLeft; var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds; Vector2 xPosition = GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); Vector2 screenPosition; screenPosition = anchorLeft + xPosition; // Constrain if (screenPosition.X + popup.Widget.Width > systemWindow.Width || screenPosition.X < 0) { xPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); } popupPosition += xPosition; Vector2 yPosition = GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds); screenPosition = anchorLeft + yPosition; // Constrain if (anchor.AltMate != null && (screenPosition.Y + popup.Widget.Height > systemWindow.Height || screenPosition.Y < 0)) { yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds); } popupPosition += yPosition; popup.Widget.Position = popupPosition; } } void CloseMenu() { popup.Widget.Close(); anchor.Widget.Closed -= anchor_Closed; // Unbind callbacks on parents for position_changed if we're closing foreach (GuiWidget widget in hookedParents) { widget.PositionChanged -= widgetRelativeTo_PositionChanged; widget.BoundsChanged -= widgetRelativeTo_PositionChanged; } // Long lived originating item must be unregistered anchor.Widget.Closed -= anchor_Closed; // Restore focus to originating widget on close if (anchor.Widget?.HasBeenClosed == false) { anchor.Widget.Focus(); } } void FocusChanged(object s, EventArgs e) { UiThread.RunOnIdle(() => { // Fired any time focus changes. Traditionally we closed the menu if we weren't focused. // To accommodate children (or external widgets) having focus we also query for and consider special cases bool specialChildHasFocus = ignoredWidgets.Any(w => w.ContainsFocus || w.Focused || w.KeepMenuOpen); bool descendantIsHoldingOpen = popup.Widget.Descendants <GuiWidget>().Any(w => w is IIgnoredPopupChild ignoredPopupChild && ignoredPopupChild.KeepMenuOpen); // If the focused changed and we've lost focus and no special cases permit, close the menu if (!popup.Widget.ContainsFocus && !specialChildHasFocus && !descendantIsHoldingOpen) { CloseMenu(); } }); } void anchor_Closed(object sender, EventArgs e) { // If the owning widget closed, so should we CloseMenu(); } foreach (var ancestor in anchor.Widget.Parents <GuiWidget>().Where(p => p != systemWindow)) { if (hookedParents.Add(ancestor)) { ancestor.PositionChanged += widgetRelativeTo_PositionChanged; ancestor.BoundsChanged += widgetRelativeTo_PositionChanged; } } popup.Widget.ContainsFocusChanged += FocusChanged; widgetRelativeTo_PositionChanged(anchor.Widget, null); anchor.Widget.Closed += anchor_Closed; // When the widgets position changes, sync the popup position systemWindow?.AddChild(popup.Widget); popup.Widget.Closed += (s, e) => { Console.WriteLine(); }; popup.Widget.Focus(); popup.Widget.Invalidate(); }