public static bool Begin(string name, ref bool open, Point position, Size size, double bg_alpha = 1, WindowFlags flags = WindowFlags.VerticalScrollbar) { if (bg_alpha < 0.0f) { throw new ArgumentOutOfRangeException(nameof(bg_alpha), nameof(bg_alpha) + " cannot be negative."); } Form form = Form.current; GUIContext g = form.uiContext; WindowManager w = g.WindowManager; Debug.Assert(name != null); // Window name required Debug.Assert(g.Initialized); // Forgot to call NewFrame() Debug.Assert(g.FrameCountEnded != g.FrameCount); // Called Render() or EndFrame() and haven't called NewFrame() again yet if (flags.HaveFlag(WindowFlags.NoInputs)) { flags |= WindowFlags.NoMove | WindowFlags.NoResize; } // Find or create Window window = w.FindWindowByName(name) ?? w.CreateWindow(name, position, size, flags); // Check if this is the first call of Begin long current_frame = g.FrameCount; bool first_begin_of_the_frame = (window.LastActiveFrame != current_frame); if (first_begin_of_the_frame) { window.Flags = flags; } else { flags = window.Flags; } // Add to stack Window parent_window = w.WindowStack.Count != 0 ? w.WindowStack[w.WindowStack.Count - 1] : null; w.WindowStack.Add(window); w.CurrentWindow = window; Debug.Assert(parent_window != null || !flags.HaveFlag(WindowFlags.ChildWindow)); // Update known root window (if we are a child window, otherwise window == window->RootWindow) int root_idx; for (root_idx = w.WindowStack.Count - 1; root_idx > 0; root_idx--) { if (!(w.WindowStack[root_idx].Flags.HaveFlag(WindowFlags.ChildWindow))) { break; } } window.RootWindow = w.WindowStack[root_idx]; // When reusing window again multiple times a frame, just append content (don't need to setup again) if (first_begin_of_the_frame) { window.FirstUpdate(name, size, ref open, bg_alpha, flags, current_frame, parent_window); } // Inner clipping rectangle { // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior. Rect title_bar_rect = window.TitleBarRect; const float border_size = 0; var paddingHorizontal = window.WindowContainer.RuleSet.PaddingHorizontal; // Force round to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. Rect clip_rect = new Rect( new Point(Math.Floor(0.5f + title_bar_rect.Min.X + Math.Max(border_size, Math.Floor(paddingHorizontal * 0.5f))), Math.Floor(0.5f + title_bar_rect.Max.Y + border_size)), new Point(Math.Floor(0.5f + window.Position.X + window.Size.Width - Math.Max(border_size, Math.Floor(paddingHorizontal * 0.5f))), Math.Floor(0.5f + window.Position.Y + window.Size.Height - border_size))); window.ClipRect = clip_rect; //window.DrawList.AddRect(window.ClipRect.TopLeft, window.ClipRect.BottomRight, Color.Red);//test only } // Clear 'accessed' flag last thing if (first_begin_of_the_frame) { window.Accessed = false; } window.BeginCount++; // Child window can be out of sight and have "negative" clip windows. // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar). if (flags.HaveFlag(WindowFlags.ChildWindow)) { Debug.Assert(flags.HaveFlag(WindowFlags.NoTitleBar)); window.Collapsed = parent_window != null && parent_window.Collapsed; } // Return false if we don't intend to display anything to allow user to perform an early out optimization window.SkipItems = window.Collapsed || !window.Active; window.RenderTree.CurrentContainer = window.ClientAreaNode; return(!window.SkipItems); }
public void FirstUpdate(string name, Size size, ref bool open, double backgroundAlpha, WindowFlags flags, long currentFrame, Window parentWindow) { //short names var form = Form.current; var g = form.uiContext; var w = g.WindowManager; this.Active = true; this.BeginCount = 0; this.ClipRect = Rect.Big; this.LastActiveFrame = currentFrame; var fullScreenRect = new Rect(0, 0, form.ClientSize); if (flags.HaveFlag(WindowFlags.ChildWindow) && !flags.HaveFlag(WindowFlags.ComboBox | WindowFlags.Popup)) { //PushClipRect(parentWindow.ClipRect, true); //ClipRect = GetCurrentClipRect(); } else { //PushClipRect(fullScreenRect, true); //ClipRect = GetCurrentClipRect(); } // (draw outer clip rect for test only here) // determine if window is collapsed if (!flags.HaveFlag(WindowFlags.NoTitleBar) && !flags.HaveFlag(WindowFlags.NoCollapse)) { // Collapse window by double-clicking on title bar if (w.HoveredWindow == this && g.IsMouseHoveringRect(this.TitleBarRect) && Mouse.Instance.LeftButtonDoubleClicked) { this.Collapsed = !this.Collapsed; w.FocusWindow(this); open = !this.Collapsed;//overwrite the open state } } this.Collapsed = !open; //update title bar var titleBarRect = this.TitleBarRect; var windowRounding = (float)this.WindowContainer.RuleSet.Get <double>(GUIStyleName.WindowRounding); if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { //text { // title text var textPrimitive = (TextPrimitive)this.titleBarTitleNode.Primitive; if (textPrimitive.Text != this.Name) { textPrimitive.Text = this.Name; } } } this.ShowWindowClientArea(!this.Collapsed); if (this.Collapsed) { //TODO need to do something here? } else//show and update window client area { if (!flags.HaveFlag(WindowFlags.NoResize) && this.ResizeGripNode == null) { var id = this.GetID("#RESIZE"); var node = new Node(id, "Window_ResizeGrip"); node.Primitive = new PathPrimitive(); this.ResizeGripNode = node; this.AbsoluteVisualList.Add(node); } //resize grip var resizeGripColor = Color.Clear; if (!flags.HaveFlag(WindowFlags.AlwaysAutoResize) && !flags.HaveFlag(WindowFlags.NoResize)) { // Manual resize var br = this.Rect.BottomRight; var resizeRect = new Rect(br - new Vector(windowRounding, windowRounding), br); var resizeId = this.GetID("#RESIZE"); GUIBehavior.ButtonBehavior(resizeRect, resizeId, out var hovered, out var held, ButtonFlags.FlattenChilds); resizeGripColor = held ? this.WindowContainer.RuleSet.Get <Color>(GUIStyleName.ResizeGripColor, GUIState.Active) : hovered ? this.WindowContainer.RuleSet.Get <Color>(GUIStyleName.ResizeGripColor, GUIState.Hover) : this.WindowContainer.RuleSet.Get <Color>(GUIStyleName.ResizeGripColor); if (hovered || held) { //Mouse.Instance.Cursor = Cursor.NeswResize; } if (held) { // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position var t = Mouse.Instance.Position - g.ActiveIdClickOffset - this.Position; var newSizeWidth = t.X + resizeRect.Width; var newSizeHeight = t.Y + resizeRect.Height; var resizeSize = new Size(newSizeWidth, newSizeHeight); this.ApplySize(resizeSize); // adjust scroll parameters var contentSize = this.ContentRect.Size; if (contentSize != Size.Zero) { var vH = this.Rect.Height - this.TitleBarHeight - this.WindowContainer.RuleSet.BorderVertical - this.WindowContainer.RuleSet.PaddingVertical; var cH = contentSize.Height; if (cH > vH) { var oldScrollY = this.Scroll.Y; oldScrollY = MathEx.Clamp(oldScrollY, 0, cH - vH); this.Scroll.Y = oldScrollY; } } } } // Render resize grip // (after the input handling so we don't have a frame of latency) if (!flags.HaveFlag(WindowFlags.NoResize)) { var br = this.Rect.BottomRight; var borderBottom = this.WindowContainer.RuleSet.BorderBottom; var borderRight = this.WindowContainer.RuleSet.BorderRight; var primitive = (PathPrimitive)this.ResizeGripNode.Primitive; primitive.PathClear(); primitive.PathLineTo(br + new Vector(-borderRight, -borderBottom)); primitive.PathLineTo(br + new Vector(-borderRight, -windowRounding)); primitive.PathArcFast(br + new Vector(-windowRounding - borderRight, -windowRounding - borderBottom), windowRounding, 0, 3); primitive.PathFill(resizeGripColor); } this.ContentRect = Rect.Zero; } }
public Window(Form form, string name, Point position, Size size, WindowFlags flags) { this.ID = name.GetHashCode(); this.Name = name; this.Active = this.WasActive = false; this.Position = position; this.ViewportPosition = form.Pos; this.FullSize = size; this.Flags = flags; this.AbsoluteVisualList = new List <Visual>(); this.RenderTree = new RenderTree(this.ID, position, size); this.RenderContext = new RenderContext(this.geometryRenderer, this.MeshList); this.IDStack.Push(this.ID); this.MoveId = this.GetID("#MOVE"); this.MeshList.OwnerName = this.Name; //bool insideMainForm = w.MainForm.ClientRect.Contains(new Rect(position, size)); if (Flags.HaveFlag(WindowFlags.Popup))//TODO consider insideMainForm when multiple-form is ready { Viewport = new Form(position, size, name, WindowTypes.ClientAreaOnly); Viewport.Window = this; Application.AddFrom(Viewport); } else { Viewport = Application.ImGuiContext.WindowManager.MainForm; } #region Window nodes { var windowContainer = new Node(this.GetID("WindowContainer"), "Window Container"); this.WindowContainer = windowContainer; var style = windowContainer.RuleSet; style.BackgroundColor = Color.White; style.BorderRadius = (2, 2, 2, 2); style.BorderColor = (Color.Rgb(0x707070), Color.Rgb(0x707070), Color.Rgb(0x707070), Color.Rgb(0x707070)); style.Set(StylePropertyName.BorderTopColor, Color.Blue, GUIState.Active); style.Set(StylePropertyName.BorderRightColor, Color.Blue, GUIState.Active); style.Set(StylePropertyName.BorderBottomColor, Color.Blue, GUIState.Active); style.Set(StylePropertyName.BorderLeftColor, Color.Blue, GUIState.Active); style.Set(StylePropertyName.BorderTopColor, Color.Gray, GUIState.Hover); style.Set(StylePropertyName.BorderRightColor, Color.Gray, GUIState.Hover); style.Set(StylePropertyName.BorderBottomColor, Color.Gray, GUIState.Hover); style.Set(StylePropertyName.BorderLeftColor, Color.Gray, GUIState.Hover); style.Set(StylePropertyName.BorderTop, 1.0); style.Set(StylePropertyName.BorderRight, 1.0); style.Set(StylePropertyName.BorderBottom, 1.0); style.Set(StylePropertyName.BorderLeft, 1.0); style.Set(StylePropertyName.PaddingTop, 5.0); style.Set(StylePropertyName.PaddingRight, 10.0); style.Set(StylePropertyName.PaddingBottom, 5.0); style.Set(StylePropertyName.PaddingLeft, 10.0); style.Set(StylePropertyName.WindowBorderColor, Color.Rgb(255, 0, 0), GUIState.Normal); style.Set(StylePropertyName.WindowBorderColor, Color.Rgb(0, 0, 255), GUIState.Active); style.Set(StylePropertyName.WindowShadowColor, Color.Argb(100, 227, 227, 227)); style.Set(StylePropertyName.WindowShadowWidth, 15.0); style.Set(StylePropertyName.ResizeGripColor, Color.Argb(0x77303030)); style.Set(StylePropertyName.ResizeGripColor, Color.Argb(0xAA303030), GUIState.Hover); style.Set(StylePropertyName.ResizeGripColor, Color.Argb(0xFF303030), GUIState.Active); style.Set(StylePropertyName.WindowRounding, 20.0); windowContainer.AttachLayoutGroup(true); windowContainer.UseBoxModel = true; var windowStyleOptions = GUILayout.Width(this.FullSize.Width).Height( this.Collapsed ? this.CollapsedHeight : this.FullSize.Height ); windowContainer.RuleSet.ApplyOptions(windowStyleOptions); this.RenderTree.Root.AppendChild(windowContainer); } //title bar if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { this.titleBar = new Node(this.GetID("titleBar"), "title bar"); titleBar.AttachLayoutGroup(false); titleBar.RuleSet.ApplyOptions(GUILayout.ExpandWidth(true).Height(this.TitleBarHeight)); titleBar.UseBoxModel = true; StyleRuleSetBuilder b = new StyleRuleSetBuilder(titleBar); b.Padding((top: 8, right: 8, bottom: 8, left: 8)) .FontColor(Color.Black) .FontSize(12) .BackgroundColor(Color.White) .AlignmentVertical(Alignment.Center) .AlignmentHorizontal(Alignment.Start); this.titleIcon = new Node(this.GetID("icon"), "icon"); titleIcon.AttachLayoutEntry(new Size(20, 20)); titleIcon.RuleSet.ApplyOptions(GUILayout.Width(20).Height(20)); titleIcon.UseBoxModel = false; this.titleText = new Node(this.GetID("title"), "title"); var contentSize = titleText.RuleSet.CalcContentBoxSize(this.Name, GUIState.Normal); titleText.AttachLayoutEntry(contentSize); titleText.RuleSet.ApplyOptions(GUILayout.Height(20)); titleText.UseBoxModel = false; var closeButton = new Node(this.GetID("close button"), "close button"); closeButton.AttachLayoutEntry(new Size(20, 20)); closeButton.RuleSet.ApplyOptions(GUILayout.Width(20).Height(20)); closeButton.UseBoxModel = false; titleBar.AppendChild(titleIcon); titleBar.AppendChild(titleText); this.WindowContainer.AppendChild(titleBar); } //client area { this.clientArea = new Node(this.GetID("Client Area"), "Client Area"); clientArea.AttachLayoutGroup(true); clientArea.RuleSet.BackgroundColor = Color.White; clientArea.RuleSet.Set(StylePropertyName.OverflowY, (int)OverflowPolicy.Scroll); clientArea.RuleSet.Set(StylePropertyName.ScrollBarWidth, CurrentOS.IsDesktopPlatform ? 10.0 : 20.0); clientArea.RuleSet.Set(StylePropertyName.ScrollBarBackgroundColor, Color.Rgb(240)); clientArea.RuleSet.Set(StylePropertyName.ScrollBarButtonColor, Color.Rgb(205), GUIState.Normal); clientArea.RuleSet.Set(StylePropertyName.ScrollBarButtonColor, Color.Rgb(166), GUIState.Hover); clientArea.RuleSet.Set(StylePropertyName.ScrollBarButtonColor, Color.Rgb(96), GUIState.Active); clientArea.RuleSet.ApplyOptions(GUILayout.ExpandWidth(true).ExpandHeight(true)); clientArea.UseBoxModel = true; clientArea.RuleSet.refNode = clientArea; #if ShowClientAreaOutline clientArea.RuleSet.OutlineWidth = 1; clientArea.RuleSet.OutlineColor = Color.DarkRed; #endif this.ClientAreaNode = clientArea; this.WindowContainer.AppendChild(clientArea); } //resize grip (lasy-initialized) if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { this.ShowWindowTitleBar(true); } this.ShowWindowClientArea(!this.Collapsed); #endregion }
public void Setup(string name, Point position, Size size, ref bool open, double bg_alpha, WindowFlags flags, long current_frame, Window parent_window) { Form form = Form.current; GUIContext g = form.uiContext; WindowManager w = g.WindowManager; this.Active = true; this.BeginCount = 0; this.ClipRect = Rect.Big; this.LastActiveFrame = current_frame; // clear draw list, setup outer clip rect this.DrawList.Clear(); this.DrawList.Init(); Rect fullScreenRect = new Rect(0, 0, form.ClientSize); if (flags.HaveFlag(WindowFlags.ChildWindow) && !flags.HaveFlag(WindowFlags.ComboBox | WindowFlags.Popup)) { this.DrawList.PushClipRect(parent_window.ClipRect, true); this.ClipRect = this.DrawList.GetCurrentClipRect(); } else { this.DrawList.PushClipRect(fullScreenRect, true); this.ClipRect = this.DrawList.GetCurrentClipRect(); } // draw outer clip rect //this.DrawList.AddRect(this.ClipRect.TopLeft, this.ClipRect.BottomRight, Color.Blue);//test only // Collapse window by double-clicking on title bar if (!(flags.HaveFlag(WindowFlags.NoTitleBar)) && !(flags.HaveFlag(WindowFlags.NoCollapse))) { if (w.HoveredWindow == this && g.IsMouseHoveringRect(this.TitleBarRect) && Mouse.Instance.LeftButtonDoubleClicked) { this.Collapsed = !this.Collapsed; w.FocusWindow(this); } } else { this.Collapsed = false; } #region size this.ApplySize(this.FullSize); this.Size = this.Collapsed ? this.TitleBarRect.Size : this.FullSize; #endregion #region position this.Position = new Point((int)this.PosFloat.X, (int)this.PosFloat.Y); if (flags.HaveFlag(WindowFlags.ChildWindow)) { this.Position = this.PosFloat = position; this.Size = this.FullSize = size; // 'size' provided by user passed via BeginChild()->Begin(). } #endregion // Draw window + handle manual resize GUIStyle style = this.Style; GUIStyle titleBarStyle = this.TitleBarStyle; Rect title_bar_rect = this.TitleBarRect; float window_rounding = (float)style.Get <double>(GUIStyleName.WindowRounding); if (this.Collapsed) { // Draw title bar only this.DrawList.AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, new Color(0.40f, 0.40f, 0.80f, 0.50f)); } else { Color resize_col = Color.Clear; double rezie_size = this.Style.Get <double>(GUIStyleName.ResizeGripSize); double resize_corner_size = Math.Max(rezie_size * 1.35, window_rounding + 1.0 + rezie_size * 0.2); if (!flags.HaveFlag(WindowFlags.AlwaysAutoResize) && !flags.HaveFlag(WindowFlags.NoResize)) { // Manual resize var br = this.Rect.BottomRight; Rect resize_rect = new Rect(br - new Vector(resize_corner_size * 0.75f, resize_corner_size * 0.75f), br); int resize_id = this.GetID("#RESIZE"); bool hovered, held; GUIBehavior.ButtonBehavior(resize_rect, resize_id, out hovered, out held, ButtonFlags.FlattenChilds); resize_col = held ? style.Get <Color>(GUIStyleName.ResizeGripColor, GUIState.Active) : hovered ? style.Get <Color>(GUIStyleName.ResizeGripColor, GUIState.Hover) : style.Get <Color>(GUIStyleName.ResizeGripColor); if (hovered || held) { //Mouse.Instance.Cursor = Cursor.NeswResize; } if (held) { // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position var t = Mouse.Instance.Position - g.ActiveIdClickOffset - this.Position; var new_size_width = t.X + resize_rect.Width; var new_size_height = t.Y + resize_rect.Height; new_size_width = MathEx.Clamp(new_size_width, 330, fullScreenRect.Width); //min size of a window is 145x235 new_size_height = MathEx.Clamp(new_size_height, 150, fullScreenRect.Height); Size resize_size = new Size(new_size_width, new_size_height); this.ApplySize(resize_size); // adjust scroll parameters var contentSize = this.ContentRect.Size; if (contentSize != Size.Zero) { var vH = this.Rect.Height - this.TitleBarHeight - this.Style.BorderVertical - this.Style.PaddingVertical; var cH = contentSize.Height; if (cH > vH) { var oldScrollY = this.Scroll.Y; oldScrollY = MathEx.Clamp(oldScrollY, 0, cH - vH); this.Scroll.Y = oldScrollY; } } } this.Size = this.FullSize; title_bar_rect = this.TitleBarRect; } // Window background Color bg_color = style.BackgroundColor; if (bg_alpha >= 0.0f) { bg_color.A = bg_alpha; } if (bg_color.A > 0.0f) { this.DrawList.AddRectFilled(this.Position + new Vector(0, this.TitleBarHeight), this.Rect.BottomRight, bg_color, window_rounding, flags.HaveFlag(WindowFlags.NoTitleBar) ? 15 : 4 | 8); } // Title bar if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { this.DrawList.AddRectFilled(title_bar_rect.TopLeft, title_bar_rect.BottomRight, w.FocusedWindow == this ? titleBarStyle.Get <Color>(GUIStyleName.BackgroundColor, GUIState.Active) : titleBarStyle.Get <Color>(GUIStyleName.BackgroundColor), window_rounding, 1 | 2); } // Render resize grip // (after the input handling so we don't have a frame of latency) if (!flags.HaveFlag(WindowFlags.NoResize)) { Point br = this.Rect.BottomRight; var borderBottom = this.Style.BorderBottom; var borderRight = this.Style.BorderRight; this.DrawList.PathLineTo(br + new Vector(-resize_corner_size, -borderBottom)); this.DrawList.PathLineTo(br + new Vector(-borderRight, -resize_corner_size)); this.DrawList.PathArcToFast( new Point(br.X - window_rounding - borderRight, br.Y - window_rounding - borderBottom), window_rounding, 0, 3); this.DrawList.PathFill(resize_col); } // Scroll bar if (flags.HaveFlag(WindowFlags.VerticalScrollbar)) { //get content size without clip var contentPosition = this.ContentRect.TopLeft; var contentSize = this.ContentRect.Size; if (contentSize != Size.Zero) { int id = this.GetID("#SCROLLY"); double scrollBarWidth = this.Style.Get <double>(GUIStyleName.ScrollBarWidth); Point scroll_TopLeft = new Point( this.Rect.Right - scrollBarWidth - this.Style.BorderRight - this.Style.PaddingRight, this.Rect.Top + this.TitleBarHeight + this.Style.BorderTop + this.Style.PaddingTop); var sH = this.Rect.Height - this.TitleBarHeight - this.Style.BorderVertical - this.Style.PaddingVertical + (flags.HaveFlag(WindowFlags.NoResize) ? 0 : -resize_corner_size); var vH = this.Rect.Height - this.TitleBarHeight - this.Style.BorderVertical - this.Style.PaddingVertical; Point scroll_BottomRight = scroll_TopLeft + new Vector(scrollBarWidth, sH); Rect bgRect = new Rect(scroll_TopLeft, scroll_BottomRight); var cH = contentSize.Height; var top = this.Scroll.Y * sH / cH; var height = sH * vH / cH; if (height < sH) { // handle mouse click/drag bool held = false; bool hovered = false; bool previously_held = (g.ActiveId == id); GUIBehavior.ButtonBehavior(bgRect, id, out hovered, out held); if (held) { top = Mouse.Instance.Position.Y - bgRect.Y - 0.5 * height; top = MathEx.Clamp(top, 0, sH - height); var targetScrollY = top * cH / sH; this.SetWindowScrollY(targetScrollY); } Point scrollButton_TopLeft = scroll_TopLeft + new Vector(0, top); Point scrllButton_BottomRight = scrollButton_TopLeft + new Vector(scrollBarWidth, height); Rect buttonRect = new Rect(scrollButton_TopLeft, scrllButton_BottomRight); //Draw vertical scroll bar and button { var bgColor = this.Style.Get <Color>(GUIStyleName.ScrollBarBackgroundColor); var buttonColor = this.Style.Get <Color>(GUIStyleName.ScrollBarButtonColor, held ? GUIState.Active : hovered ? GUIState.Hover : GUIState.Normal); this.DrawList.AddRectFilled(bgRect.TopLeft, buttonRect.TopRight, bgColor); this.DrawList.AddRectFilled(buttonRect.TopLeft, buttonRect.BottomRight, buttonColor); this.DrawList.AddRectFilled(buttonRect.BottomLeft, bgRect.BottomRight, bgColor); } } else { var bgColor = this.Style.Get <Color>(GUIStyleName.ScrollBarBackgroundColor); this.DrawList.AddRectFilled(bgRect.TopLeft, bgRect.BottomRight, bgColor); } } } this.ContentRect = Rect.Zero; } // draw title bar text if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { // title text var state = w.FocusedWindow == this ? GUIState.Active : GUIState.Normal; this.DrawList.DrawBoxModel(title_bar_rect, name, titleBarStyle, state); // close button if (CloseButton(this.GetID("#CLOSE"), new Rect(title_bar_rect.TopRight + new Vector(-45, 0), title_bar_rect.BottomRight))) { open = false; } } // Borders if (flags.HaveFlag(WindowFlags.ShowBorders)) { var state = w.FocusedWindow == this ? GUIState.Active : GUIState.Normal; // window border var borderColor = this.Style.Get <Color>(GUIStyleName.WindowBorderColor, state); this.DrawList.AddRect(this.Position, this.Position + new Vector(this.Size.Width, this.Size.Height), borderColor, window_rounding); // window shadow #if false { var state = w.FocusedWindow == this ? GUIState.Active : GUIState.Normal; var shadowColor = this.Style.Get <Color>(GUIStyleName.WindowShadowColor, state); var shadowWidth = this.Style.Get <double>(GUIStyleName.WindowShadowWidth, state); var d = this.DrawList; //top-left corner d.AddRectFilledGradientTopLeftToBottomRight(this.Rect.TopLeft + new Vector(-shadowWidth, -shadowWidth), this.Rect.TopLeft, Color.Clear, shadowColor); //top d.AddRectFilledGradient(this.Rect.TopLeft + new Vector(0, -shadowWidth), this.Rect.TopRight, Color.Clear, shadowColor); d.AddRectFilledGradient(this.Rect.BottomLeft, this.Rect.BottomRight + new Vector(0, shadowWidth), shadowColor, Color.Clear); } #endif } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() this.WindowClippedRect = this.Rect; this.WindowClippedRect.Intersect(this.ClipRect); }
public static bool Begin(string name, ref bool open, Point position, Size size, double bg_alpha = 1, WindowFlags flags = WindowFlags.VerticalScrollbar) { if (bg_alpha < 0.0f) { throw new ArgumentOutOfRangeException(nameof(bg_alpha), nameof(bg_alpha) + " cannot be negative."); } Form form = Form.current; GUIContext g = form.uiContext; WindowManager w = g.WindowManager; Debug.Assert(name != null); // Window name required Debug.Assert(g.Initialized); // Forgot to call NewFrame() Debug.Assert(g.FrameCountEnded != g.FrameCount); // Called Render() or EndFrame() and haven't called NewFrame() again yet if (flags.HaveFlag(WindowFlags.NoInputs)) { flags |= WindowFlags.NoMove | WindowFlags.NoResize; } // Find or create Window window = w.FindWindowByName(name) ?? w.CreateWindow(name, position, size, flags); // Check if this is the first call of Begin long current_frame = g.FrameCount; bool first_begin_of_the_frame = (window.LastActiveFrame != current_frame); if (first_begin_of_the_frame) { window.Flags = flags; } else { flags = window.Flags; } // Add to stack Window parent_window = w.WindowStack.Count != 0 ? w.WindowStack[w.WindowStack.Count - 1] : null; w.WindowStack.Add(window); w.CurrentWindow = window; Debug.Assert(parent_window != null || !flags.HaveFlag(WindowFlags.ChildWindow)); // Update known root window (if we are a child window, otherwise window == window->RootWindow) int root_idx; for (root_idx = w.WindowStack.Count - 1; root_idx > 0; root_idx--) { if (!(w.WindowStack[root_idx].Flags.HaveFlag(WindowFlags.ChildWindow))) { break; } } window.RootWindow = w.WindowStack[root_idx]; // When reusing window again multiple times a frame, just append content (don't need to setup again) if (first_begin_of_the_frame) { window.FirstUpdate(name, size, ref open, bg_alpha, flags, current_frame, parent_window); ImGui.Development.Metrics.ActiveWindows++; } // Clear 'accessed' flag last thing if (first_begin_of_the_frame) { window.Accessed = false; } window.BeginCount++; // Child window can be out of sight and have "negative" clip windows. // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar). if (flags.HaveFlag(WindowFlags.ChildWindow)) { Debug.Assert(flags.HaveFlag(WindowFlags.NoTitleBar)); window.Collapsed = parent_window != null && parent_window.Collapsed; window.Position = position; } // Return false if we don't intend to display anything to allow user to perform an early out optimization window.SkipItems = window.Collapsed || !window.Active; window.RenderTree.CurrentContainer = window.ClientAreaNode; return(!window.SkipItems); }
public void FirstUpdate(string name, Size size, ref bool open, double backgroundAlpha, WindowFlags flags, long currentFrame, Window parentWindow) { //short names var g = Application.ImGuiContext; var w = g.WindowManager; this.Active = true; this.BeginCount = 0; this.LastActiveFrame = currentFrame; // update viewport UpdateWindowViewport(this); w.CurrentViewport = Viewport; if (Viewport != null) { Viewport.LastFrameActive = g.FrameCount; } // determine if window is collapsed if (!flags.HaveFlag(WindowFlags.NoTitleBar) && !flags.HaveFlag(WindowFlags.NoCollapse)) { // Collapse window by double-clicking on title bar if (w.HoveredWindow == this && g.IsMouseHoveringRect(this.TitleBarRect) && Mouse.Instance.LeftButtonDoubleClicked) { this.Collapsed = !this.Collapsed; w.FocusWindow(this); open = !this.Collapsed; //overwrite the open state } } this.Collapsed = !open; //window container using (var dc = WindowContainer.RenderOpen()) { dc.DrawBoxModel(WindowContainer); } //update title bar var windowRounding = (float)this.WindowContainer.RuleSet.Get <double>(StylePropertyName.WindowRounding); if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { // background using (var dc = this.titleBar.RenderOpen()) { dc.DrawBoxModel(this.titleBar.RuleSet, this.titleBar.Rect); } //icon using (var dc = titleIcon.RenderOpen()) { dc.DrawImage(@"assets/images/logo.png", this.titleIcon.Rect); } //title using (var dc = titleText.RenderOpen()) { dc.DrawGlyphRun(titleText.RuleSet, this.Name, titleText.Rect.TopLeft); } } this.ShowWindowClientArea(!this.Collapsed); if (!this.Collapsed) { //show and update window client area using (var dc = clientArea.RenderOpen()) { dc.DrawBoxModel(clientArea); } if (!flags.HaveFlag(WindowFlags.NoResize)) { if (this.ResizeGripNode == null) { var id = this.GetID("#RESIZE"); var node = new Node(id, "Window_ResizeGrip"); this.ResizeGripNode = node; this.AbsoluteVisualList.Add(node); } //resize grip this.ResizeGripNode.ActiveSelf = true; var resizeGripColor = Color.Clear; var br = this.Rect.BottomRight; if (!flags.HaveFlag(WindowFlags.AlwaysAutoResize) && !flags.HaveFlag(WindowFlags.NoResize)) { // Manual resize var resizeRect = new Rect( br - new Vector(this.WindowContainer.PaddingLeft + this.WindowContainer.BorderLeft, this.WindowContainer.PaddingBottom + this.WindowContainer.BorderLeft), br); var resizeId = this.GetID("#RESIZE"); GUIBehavior.ButtonBehavior(resizeRect, resizeId, out var hovered, out var held, ButtonFlags.FlattenChilds); resizeGripColor = held ? this.WindowContainer.RuleSet.Get <Color>(StylePropertyName.ResizeGripColor, GUIState.Active) : hovered ? this.WindowContainer.RuleSet.Get <Color>(StylePropertyName.ResizeGripColor, GUIState.Hover) : this.WindowContainer.RuleSet.Get <Color>(StylePropertyName.ResizeGripColor); if (hovered || held) { Mouse.Instance.Cursor = (Cursor.NwseResize); } else { Mouse.Instance.Cursor = (Cursor.Default); } if (held) { // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position var t = Mouse.Instance.Position - g.ActiveIdClickOffset - this.Position; var newSizeWidth = t.X + resizeRect.Width; var newSizeHeight = t.Y + resizeRect.Height; var resizeSize = new Size(newSizeWidth, newSizeHeight); this.ApplySize(resizeSize); } } // Render resize grip // (after the input handling so we don't have a frame of latency) var borderBottom = this.WindowContainer.RuleSet.BorderBottom; var paddingBottom = this.WindowContainer.RuleSet.PaddingBottom; var borderRight = this.WindowContainer.RuleSet.BorderRight; var paddingRight = this.WindowContainer.RuleSet.PaddingRight; using (var dc = this.ResizeGripNode.RenderOpen()) { var path = new PathGeometry(); var figure = new PathFigure(); var A = br + new Vector(-10 - borderRight - paddingRight, 0); var B = br + new Vector(0, -10 - borderBottom - paddingBottom); figure.StartPoint = A; figure.IsFilled = true; figure.Segments.Add(new LineSegment(B, false)); figure.Segments.Add(new LineSegment(br, false)); figure.Segments.Add(new LineSegment(A, false)); path.Figures.Add(figure); dc.DrawGeometry(new Brush(resizeGripColor), null, path); } } this.ContentRect = Rect.Zero; } }
public static bool Begin(string name, ref bool open, Point position, Size size, double bg_alpha = 1, WindowFlags flags = WindowFlags.VerticalScrollbar) { Form form = Form.current; GUIContext g = form.uiContext; WindowManager w = g.WindowManager; Debug.Assert(name != null); // Window name required Debug.Assert(g.Initialized); // Forgot to call NewFrame() Debug.Assert(g.FrameCountEnded != g.FrameCount); // Called Render() or EndFrame() and haven't called NewFrame() again yet if (flags.HaveFlag(WindowFlags.NoInputs)) { flags |= WindowFlags.NoMove | WindowFlags.NoResize; } // Find or create Window window = w.FindWindowByName(name) ?? w.CreateWindow(name, position, size, flags); // Check if this is the first call of Begin long current_frame = g.FrameCount; bool first_begin_of_the_frame = (window.LastActiveFrame != current_frame); if (first_begin_of_the_frame) { window.Flags = flags; } else { flags = window.Flags; } // Add to stack Window parent_window = w.WindowStack.Count != 0 ? w.WindowStack[w.WindowStack.Count - 1] : null; w.WindowStack.Add(window); w.CurrentWindow = window; Debug.Assert(parent_window != null || !flags.HaveFlag(WindowFlags.ChildWindow)); // Update known root window (if we are a child window, otherwise window == window->RootWindow) int root_idx; for (root_idx = w.WindowStack.Count - 1; root_idx > 0; root_idx--) { if (!(w.WindowStack[root_idx].Flags.HaveFlag(WindowFlags.ChildWindow))) { break; } } window.RootWindow = w.WindowStack[root_idx]; // When reusing window again multiple times a frame, just append content (don't need to setup again) if (first_begin_of_the_frame) { window.Active = true; window.BeginCount = 0; window.ClipRect = Rect.Big; window.LastActiveFrame = current_frame; // clear draw list, setup outer clip rect window.DrawList.Clear(); window.DrawList.Init(); Rect fullScreenRect = new Rect(0, 0, form.ClientSize); if (flags.HaveFlag(WindowFlags.ChildWindow) && !flags.HaveFlag(WindowFlags.ComboBox | WindowFlags.Popup)) { window.DrawList.PushClipRect(parent_window.ClipRect, true); window.ClipRect = window.DrawList.GetCurrentClipRect(); } else { window.DrawList.PushClipRect(fullScreenRect, true); window.ClipRect = window.DrawList.GetCurrentClipRect(); } // draw outer clip rect //window.DrawList.AddRect(window.ClipRect.TopLeft, window.ClipRect.BottomRight, Color.Blue);//test only // Collapse window by double-clicking on title bar if (!(flags.HaveFlag(WindowFlags.NoTitleBar)) && !(flags.HaveFlag(WindowFlags.NoCollapse))) { if (w.HoveredWindow == window && g.IsMouseHoveringRect(window.TitleBarRect) && Mouse.Instance.LeftButtonDoubleClicked) { window.Collapsed = !window.Collapsed; w.FocusWindow(window); } } else { window.Collapsed = false; } #region size window.ApplySize(window.FullSize); window.Size = window.Collapsed ? window.TitleBarRect.Size : window.FullSize; #endregion #region position window.Position = new Point((int)window.PosFloat.X, (int)window.PosFloat.Y); if (flags.HaveFlag(WindowFlags.ChildWindow)) { window.Position = window.PosFloat = position; window.Size = window.FullSize = size; // 'size' provided by user passed via BeginChild()->Begin(). } #endregion // Draw window + handle manual resize GUIStyle style = window.Style; GUIStyle titleBarStyle = window.TitleBarStyle; Rect title_bar_rect = window.TitleBarRect; float window_rounding = (float)style.Get <double>(GUIStyleName.WindowRounding); if (window.Collapsed) { // Draw title bar only window.DrawList.AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, new Color(0.40f, 0.40f, 0.80f, 0.50f)); } else { Color resize_col = Color.Clear; double rezie_size = window.Style.Get <double>(GUIStyleName.ResizeGripSize); double resize_corner_size = Math.Max(rezie_size * 1.35, window_rounding + 1.0 + rezie_size * 0.2); if (!flags.HaveFlag(WindowFlags.AlwaysAutoResize) && !flags.HaveFlag(WindowFlags.NoResize)) { // Manual resize var br = window.Rect.BottomRight; Rect resize_rect = new Rect(br - new Vector(resize_corner_size * 0.75f, resize_corner_size * 0.75f), br); int resize_id = window.GetID("#RESIZE"); bool hovered, held; GUIBehavior.ButtonBehavior(resize_rect, resize_id, out hovered, out held, ButtonFlags.FlattenChilds); resize_col = held ? style.Get <Color>(GUIStyleName.ResizeGripColor, GUIState.Active) : hovered?style.Get <Color>(GUIStyleName.ResizeGripColor, GUIState.Hover) : style.Get <Color>(GUIStyleName.ResizeGripColor); if (hovered || held) { //Mouse.Instance.Cursor = Cursor.NeswResize; } if (held) { // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position var t = Mouse.Instance.Position - g.ActiveIdClickOffset - window.Position; var new_size_width = t.X + resize_rect.Width; var new_size_height = t.Y + resize_rect.Height; new_size_width = MathEx.Clamp(new_size_width, 330, fullScreenRect.Width);//min size of a window is 145x235 new_size_height = MathEx.Clamp(new_size_height, 150, fullScreenRect.Height); Size resize_size = new Size(new_size_width, new_size_height); window.ApplySize(resize_size); // adjust scroll parameters var contentSize = window.ContentRect.Size; if (contentSize != Size.Zero) { var vH = window.Rect.Height - window.TitleBarHeight - window.Style.BorderVertical - window.Style.PaddingVertical; var cH = contentSize.Height; if (cH > vH) { var oldScrollY = window.Scroll.Y; oldScrollY = MathEx.Clamp(oldScrollY, 0, cH - vH); window.Scroll.Y = oldScrollY; } } } window.Size = window.FullSize; title_bar_rect = window.TitleBarRect; } // Window background Color bg_color = style.BackgroundColor; if (bg_alpha >= 0.0f) { bg_color.A = bg_alpha; } if (bg_color.A > 0.0f) { window.DrawList.AddRectFilled(window.Position + new Vector(0, window.TitleBarHeight), window.Rect.BottomRight, bg_color, window_rounding, flags.HaveFlag(WindowFlags.NoTitleBar) ? 15 : 4 | 8); } // Title bar if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { window.DrawList.AddRectFilled(title_bar_rect.TopLeft, title_bar_rect.BottomRight, w.FocusedWindow == window ? titleBarStyle.Get <Color>(GUIStyleName.BackgroundColor, GUIState.Active) : titleBarStyle.Get <Color>(GUIStyleName.BackgroundColor), window_rounding, 1 | 2); } // Render resize grip // (after the input handling so we don't have a frame of latency) if (!flags.HaveFlag(WindowFlags.NoResize)) { Point br = window.Rect.BottomRight; var borderBottom = window.Style.BorderBottom; var borderRight = window.Style.BorderRight; window.DrawList.PathLineTo(br + new Vector(-resize_corner_size, -borderBottom)); window.DrawList.PathLineTo(br + new Vector(-borderRight, -resize_corner_size)); window.DrawList.PathArcToFast(new Point(br.X - window_rounding - borderRight, br.Y - window_rounding - borderBottom), window_rounding, 0, 3); window.DrawList.PathFill(resize_col); } // Scroll bar if (flags.HaveFlag(WindowFlags.VerticalScrollbar)) { //get content size without clip var contentPosition = window.ContentRect.TopLeft; var contentSize = window.ContentRect.Size; if (contentSize != Size.Zero) { int id = window.GetID("#SCROLLY"); double scrollBarWidth = window.Style.Get <double>(GUIStyleName.ScrollBarWidth); Point scroll_TopLeft = new Point( window.Rect.Right - scrollBarWidth - window.Style.BorderRight - window.Style.PaddingRight, window.Rect.Top + window.TitleBarHeight + window.Style.BorderTop + window.Style.PaddingTop); var sH = window.Rect.Height - window.TitleBarHeight - window.Style.BorderVertical - window.Style.PaddingVertical - resize_corner_size; var vH = window.Rect.Height - window.TitleBarHeight - window.Style.BorderVertical - window.Style.PaddingVertical; Point scroll_BottomRight = scroll_TopLeft + new Vector(scrollBarWidth, sH); Rect bgRect = new Rect(scroll_TopLeft, scroll_BottomRight); var cH = contentSize.Height; var top = window.Scroll.Y * sH / cH; var height = sH * vH / cH; if (height < sH) { // handle mouse click/drag bool held = false; bool hovered = false; bool previously_held = (g.ActiveId == id); GUIBehavior.ButtonBehavior(bgRect, id, out hovered, out held); if (held) { top = Mouse.Instance.Position.Y - bgRect.Y - 0.5 * height; top = MathEx.Clamp(top, 0, sH - height); var targetScrollY = top * cH / sH; window.SetWindowScrollY(targetScrollY); } Point scrollButton_TopLeft = scroll_TopLeft + new Vector(0, top); Point scrllButton_BottomRight = scrollButton_TopLeft + new Vector(scrollBarWidth, height); Rect buttonRect = new Rect(scrollButton_TopLeft, scrllButton_BottomRight); //Draw vertical scroll bar and button { var bgColor = window.Style.Get <Color>(GUIStyleName.ScrollBarBackgroundColor); var buttonColor = window.Style.Get <Color>(GUIStyleName.ScrollBarButtonColor, held ? GUIState.Active : hovered ? GUIState.Hover : GUIState.Normal); window.DrawList.AddRectFilled(bgRect.TopLeft, buttonRect.TopRight, bgColor); window.DrawList.AddRectFilled(buttonRect.TopLeft, buttonRect.BottomRight, buttonColor); window.DrawList.AddRectFilled(buttonRect.BottomLeft, bgRect.BottomRight, bgColor); } } else { var bgColor = window.Style.Get <Color>(GUIStyleName.ScrollBarBackgroundColor); window.DrawList.AddRectFilled(bgRect.TopLeft, bgRect.BottomRight, bgColor); } } } window.ContentRect = Rect.Zero; } // draw title bar text if (!flags.HaveFlag(WindowFlags.NoTitleBar)) { var state = w.FocusedWindow == window ? GUIState.Active : GUIState.Normal; window.DrawList.DrawBoxModel(title_bar_rect, name, titleBarStyle, state); } // Borders if (flags.HaveFlag(WindowFlags.ShowBorders)) { var state = w.FocusedWindow == window ? GUIState.Active : GUIState.Normal; // window border var borderColor = window.Style.Get <Color>(GUIStyleName.WindowBorderColor, state); window.DrawList.AddRect(window.Position, window.Position + new Vector(window.Size.Width, window.Size.Height), borderColor, window_rounding); // window shadow #if false { var state = w.FocusedWindow == window ? GUIState.Active : GUIState.Normal; var shadowColor = window.Style.Get <Color>(GUIStyleName.WindowShadowColor, state); var shadowWidth = window.Style.Get <double>(GUIStyleName.WindowShadowWidth, state); var d = window.DrawList; //top-left corner d.AddRectFilledGradientTopLeftToBottomRight(window.Rect.TopLeft + new Vector(-shadowWidth, -shadowWidth), window.Rect.TopLeft, Color.Clear, shadowColor); //top d.AddRectFilledGradient(window.Rect.TopLeft + new Vector(0, -shadowWidth), window.Rect.TopRight, Color.Clear, shadowColor); d.AddRectFilledGradient(window.Rect.BottomLeft, window.Rect.BottomRight + new Vector(0, shadowWidth), shadowColor, Color.Clear); } #endif } // Save clipped aabb so we can access it in constant-time in FindHoveredWindow() window.WindowClippedRect = window.Rect; window.WindowClippedRect.Intersect(window.ClipRect); } // Inner clipping rectangle { // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior. Rect title_bar_rect = window.TitleBarRect; const float border_size = 0; var paddingHorizontal = window.Style.PaddingHorizontal; // Force round to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result. Rect clip_rect = new Rect( new Point(Math.Floor(0.5f + title_bar_rect.Min.X + Math.Max(border_size, Math.Floor(paddingHorizontal * 0.5f))), Math.Floor(0.5f + title_bar_rect.Max.Y + border_size)), new Point(Math.Floor(0.5f + window.Position.X + window.Size.Width - Math.Max(border_size, Math.Floor(paddingHorizontal * 0.5f))), Math.Floor(0.5f + window.Position.Y + window.Size.Height - border_size))); window.DrawList.PushClipRect(clip_rect, true); window.ClipRect = clip_rect; //window.DrawList.AddRect(window.ClipRect.TopLeft, window.ClipRect.BottomRight, Color.Red);//test only } // Clear 'accessed' flag last thing if (first_begin_of_the_frame) { window.Accessed = false; } window.BeginCount++; // Child window can be out of sight and have "negative" clip windows. // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar). if (flags.HaveFlag(WindowFlags.ChildWindow)) { Debug.Assert(flags.HaveFlag(WindowFlags.NoTitleBar)); window.Collapsed = parent_window != null && parent_window.Collapsed; } window.StackLayout.Begin(); // Return false if we don't intend to display anything to allow user to perform an early out optimization window.SkipItems = window.Collapsed || !window.Active; return(!window.SkipItems); }