/* * BSplitContainer.cs * Copyright (c) 2008-2009 kbinani * * This file is part of Boare.Lib.AppUtil. * * Boare.Lib.AppUtil is free software; you can redistribute it and/or * modify it under the terms of the BSD License. * * Boare.Lib.AppUtil is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace Boare.Lib.AppUtil { [Serializable] public partial class BSplitContainer : ContainerControl { private Orientation m_orientation = Orientation.Horizontal; private int m_splitter_distance = 50; private int m_panel1_min = 25; private int m_panel2_min = 25; private int m_splitter_width = 4; private bool m_splitter_moving = false; private int m_splitter_distance_draft = 50; private BSplitterPanel m_panel1; private BSplitterPanel m_panel2; private System.ComponentModel.IContainer components = null; private bool m_splitter_fixed = false; private Pen m_panel1_border = null; private Pen m_panel2_border = null; private System.Windows.Forms.FixedPanel m_fixed_panel; private PictureBox m_lbl_splitter; private int m_panel2_distance = 1; private double m_distance_rate = 0.5; public event SplitterEventHandler SplitterMoved; [Browsable(false)] public event ControlEventHandler ControlAdded; public BSplitContainer() { InitializeComponent(); if ( m_orientation == Orientation.Horizontal ) { m_lbl_splitter.Cursor = Cursors.VSplit; } else { m_lbl_splitter.Cursor = Cursors.HSplit; } if ( m_orientation == Orientation.Horizontal ) { m_panel2_distance = this.Width - m_splitter_distance; } else { m_panel2_distance = this.Height - m_splitter_distance; } m_distance_rate = m_splitter_distance / (double)(m_splitter_distance + m_panel2_distance); } public System.Windows.Forms.FixedPanel FixedPanel { get { return m_fixed_panel; } set { System.Windows.Forms.FixedPanel old = m_fixed_panel; m_fixed_panel = value; if ( m_fixed_panel != FixedPanel.None && m_fixed_panel != old ) { if ( m_fixed_panel == FixedPanel.Panel1 ) { m_panel2.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; if ( m_orientation == Orientation.Vertical ) { m_panel1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; } else { m_panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left; } } else { m_panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; if ( m_orientation == Orientation.Vertical ) { m_panel2.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; } else { m_panel2.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; } } } } } public bool IsSplitterFixed { get { return m_splitter_fixed; } set { m_splitter_fixed = value; if ( m_splitter_fixed ) { m_lbl_splitter.Cursor = Cursors.Default; } else { if ( m_orientation == Orientation.Horizontal ) { m_lbl_splitter.Cursor = Cursors.VSplit; } else { m_lbl_splitter.Cursor = Cursors.HSplit; } } } } /// /// 使用中のリソースをすべてクリーンアップします。 /// /// マネージ リソースが破棄される場合 true、破棄されない場合は false です。 protected override void Dispose( bool disposing ) { if ( disposing && (components != null) ) { components.Dispose(); } base.Dispose( disposing ); } /// /// デザイナ サポートに必要なメソッドです。このメソッドの内容を /// コード エディタで変更しないでください。 /// private void InitializeComponent() { this.m_lbl_splitter = new System.Windows.Forms.PictureBox(); this.m_panel2 = new Boare.Lib.AppUtil.BSplitterPanel(); this.m_panel1 = new Boare.Lib.AppUtil.BSplitterPanel(); ((System.ComponentModel.ISupportInitialize)(this.m_lbl_splitter)).BeginInit(); this.SuspendLayout(); // // m_lbl_splitter // this.m_lbl_splitter.BackColor = System.Drawing.Color.Transparent; this.m_lbl_splitter.Location = new System.Drawing.Point( 0, 0 ); this.m_lbl_splitter.Name = "m_lbl_splitter"; this.m_lbl_splitter.Size = new System.Drawing.Size( 100, 50 ); this.m_lbl_splitter.TabIndex = 0; this.m_lbl_splitter.TabStop = false; this.m_lbl_splitter.MouseMove += new System.Windows.Forms.MouseEventHandler( this.m_lbl_splitter_MouseMove ); this.m_lbl_splitter.MouseDown += new System.Windows.Forms.MouseEventHandler( this.m_lbl_splitter_MouseDown ); this.m_lbl_splitter.MouseUp += new System.Windows.Forms.MouseEventHandler( this.m_lbl_splitter_MouseUp ); // // m_panel2 // this.m_panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.m_panel2.BorderColor = System.Drawing.Color.Black; this.m_panel2.Location = new System.Drawing.Point( 0, 103 ); this.m_panel2.Margin = new System.Windows.Forms.Padding( 0 ); this.m_panel2.Name = "m_panel2"; this.m_panel2.Size = new System.Drawing.Size( 441, 245 ); this.m_panel2.TabIndex = 1; this.m_panel2.BorderStyleChanged += new System.EventHandler( this.m_panel2_BorderStyleChanged ); this.m_panel2.SizeChanged += new System.EventHandler( this.m_panel2_SizeChanged ); // // m_panel1 // this.m_panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.m_panel1.BorderColor = System.Drawing.Color.Black; this.m_panel1.Location = new System.Drawing.Point( 0, 0 ); this.m_panel1.Margin = new System.Windows.Forms.Padding( 0, 0, 0, 4 ); this.m_panel1.Name = "m_panel1"; this.m_panel1.Size = new System.Drawing.Size( 441, 99 ); this.m_panel1.TabIndex = 0; this.m_panel1.BorderStyleChanged += new System.EventHandler( this.m_panel1_BorderStyleChanged ); this.m_panel1.SizeChanged += new System.EventHandler( this.m_panel1_SizeChanged ); // // SplitContainerEx // this.Controls.Add( this.m_panel2 ); this.Controls.Add( this.m_panel1 ); this.Controls.Add( this.m_lbl_splitter ); this.Size = new System.Drawing.Size( 441, 348 ); this.Paint += new System.Windows.Forms.PaintEventHandler( this.SplitContainerEx_Paint ); ((System.ComponentModel.ISupportInitialize)(this.m_lbl_splitter)).EndInit(); this.ResumeLayout( false ); } private void SplitContainerEx_Paint( object sender, PaintEventArgs e ) { bool panel1_visible = true; if ( Orientation == Orientation.Horizontal ) { if ( m_panel1.Width == 0 ) { panel1_visible = false; } } else { if ( m_panel1.Height == 0 ) { panel1_visible = false; } } if ( m_panel1.BorderStyle == BorderStyle.FixedSingle && panel1_visible ) { if ( m_panel1_border == null ) { m_panel1_border = new Pen( m_panel1.BorderColor ); } else { if ( !m_panel1.BorderColor.Equals( m_panel1_border.Color ) ) { m_panel1_border = new Pen( m_panel1.BorderColor ); } } e.Graphics.DrawRectangle( m_panel1_border, new Rectangle( m_panel1.Left - 1, m_panel1.Top - 1, m_panel1.Width + 1, m_panel1.Height + 1) ); } bool panel2_visible = true; if ( Orientation == Orientation.Horizontal ) { if ( m_panel2.Width == 0 ) { panel2_visible = false; } } else { if ( m_panel2.Height == 0 ) { panel2_visible = false; } } if ( m_panel2.BorderStyle == BorderStyle.FixedSingle && panel2_visible ) { if ( m_panel2_border == null ) { m_panel2_border = new Pen( m_panel2.BorderColor ); } else { if ( !m_panel2.BorderColor.Equals( m_panel2_border.Color ) ) { m_panel2_border = new Pen( m_panel2.BorderColor ); } } e.Graphics.DrawRectangle( m_panel2_border, new Rectangle( m_panel2.Left - 1, m_panel2.Top - 1, m_panel2.Width + 1, m_panel2.Height + 1 ) ); } } private void m_panel2_BorderStyleChanged( object sender, EventArgs e ) { UpdateLayout( m_splitter_distance, m_splitter_width, m_panel1_min, m_panel2_min, false ); } private void m_panel1_BorderStyleChanged( object sender, EventArgs e ) { UpdateLayout( m_splitter_distance, m_splitter_width, m_panel1_min, m_panel2_min, false ); } private void m_panel2_SizeChanged( object sender, EventArgs e ) { m_panel2.Invalidate( true ); } private void m_panel1_SizeChanged( object sender, EventArgs e ) { m_panel1.Invalidate( true ); } public int Panel1MinSize { get { return m_panel1_min; } set { int min_splitter_distance = value; if ( m_splitter_distance < min_splitter_distance && min_splitter_distance > 0 ) { m_splitter_distance = min_splitter_distance; } UpdateLayout( m_splitter_distance, m_splitter_width, value, m_panel2_min, false ); } } public int Panel2MinSize { get { return m_panel2_min; } set { int max_splitter_distance = (m_orientation == Orientation.Horizontal) ? this.Width - m_splitter_width - value : this.Height - m_splitter_width - value; if ( m_splitter_distance > max_splitter_distance && max_splitter_distance > 0 ) { m_splitter_distance = max_splitter_distance; } UpdateLayout( m_splitter_distance, m_splitter_width, m_panel1_min, value, false ); } } public int SplitterWidth { get { return m_splitter_width; } set { if ( value < 1 ) { value = 1; } UpdateLayout( m_splitter_distance, value, m_panel1_min, m_panel2_min, false ); } } private bool UpdateLayout( int splitter_distance, int splitter_width, int panel1_min, int panel2_min, bool check_only ) { Point mouse = this.PointToClient( Control.MousePosition ); int pad1 = (m_panel1.BorderStyle == BorderStyle.FixedSingle) ? 1 : 0; int pad2 = (m_panel2.BorderStyle == BorderStyle.FixedSingle) ? 1 : 0; if ( m_orientation == Orientation.Horizontal ) { int p1 = splitter_distance; if ( p1 < 0 ) { p1 = 0; } else if ( this.Width < p1 + splitter_width ) { p1 = this.Width - splitter_width; } int p2 = this.Width - p1 - splitter_width; if ( check_only ) { if ( p1 < panel1_min || p2 < panel2_min ) { return false; } } else { if ( p1 < panel1_min ) { p1 = panel1_min; } p2 = this.Width - p1 - splitter_width; if ( p2 < panel2_min ) { p2 = panel2_min; //return false; } } if ( !check_only ) { m_panel1.Left = pad1; m_panel1.Top = pad1; m_panel1.Width = (p1 - 2 * pad1 >= 0) ? (p1 - 2 * pad1) : 0; m_panel1.Height = (this.Height - 2 * pad1 >= 0) ? (this.Height - 2 * pad1) : 0; m_panel2.Left = p1 + splitter_width + pad2; m_panel2.Top = pad2; m_panel2.Width = (p2 - 2 * pad2 >= 0) ? (p2 - 2 * pad2) : 0; m_panel2.Height = (this.Height - 2 * pad2 >= 0) ? (this.Height - 2 * pad2) : 0; m_splitter_distance = p1; m_panel2_distance = this.Width - m_splitter_distance; m_distance_rate = m_splitter_distance / (double)(m_splitter_distance + m_panel2_distance); if ( SplitterMoved != null ) { SplitterMoved( this, new SplitterEventArgs( mouse.X, mouse.Y, p1, 0 ) ); } m_splitter_width = splitter_width; m_panel1_min = panel1_min; m_panel2_min = panel2_min; m_lbl_splitter.Left = p1; m_lbl_splitter.Top = 0; m_lbl_splitter.Width = splitter_width; m_lbl_splitter.Height = this.Height; } return true; } else { int p1 = splitter_distance; if ( p1 < 0 ) { p1 = 0; } else if ( this.Height < p1 + splitter_width ) { p1 = this.Height - splitter_width; } int p2 = this.Height - p1 - splitter_width; if ( check_only ) { if ( p1 < panel1_min || p2 < panel2_min ) { return false; } } else { if ( p1 < panel1_min ) { p1 = panel1_min; } p2 = this.Height - p1 - splitter_width; if ( p2 < panel2_min ) { p2 = panel2_min; //return false; } } if ( !check_only ) { m_panel1.Left = pad1; m_panel1.Top = pad1; m_panel1.Width = (this.Width - 2 * pad1 >= 0) ? (this.Width - 2 * pad1) : 0; m_panel1.Height = (p1 - 2 * pad1 >= 0) ? (p1 - 2 * pad1) : 0; m_panel2.Left = pad2; m_panel2.Top = p1 + splitter_width + pad2; m_panel2.Width = (this.Width - 2 * pad2 >= 0) ? (this.Width - 2 * pad2) : 0; m_panel2.Height = (p2 - 2 * pad2 >= 0) ? (p2 - 2 * pad2) : 0; m_splitter_distance = p1; m_panel2_distance = this.Height - m_splitter_distance; m_distance_rate = m_splitter_distance / (double)(m_splitter_distance + m_panel2_distance); if ( SplitterMoved != null ) { SplitterMoved( this, new SplitterEventArgs( mouse.X, mouse.Y, 0, p1 ) ); } m_splitter_width = splitter_width; m_panel1_min = panel1_min; m_panel2_min = panel2_min; m_lbl_splitter.Left = 0; m_lbl_splitter.Top = p1; m_lbl_splitter.Width = this.Width; m_lbl_splitter.Height = splitter_width; } return true; } } public int SplitterDistance { get { return m_splitter_distance; } set { UpdateLayout( value, m_splitter_width, m_panel1_min, m_panel2_min, false ); if ( m_orientation == Orientation.Horizontal ) { m_panel2_distance = this.Width - m_splitter_distance; } else { m_panel2_distance = this.Height - m_splitter_distance; } } } public Orientation Orientation { get { return m_orientation; } set { if ( m_orientation != value ) { m_orientation = value; UpdateLayout( m_splitter_distance, m_splitter_width, m_panel1_min, m_panel2_min, false ); if ( m_orientation == Orientation.Horizontal ) { m_lbl_splitter.Cursor = Cursors.VSplit; } else { m_lbl_splitter.Cursor = Cursors.HSplit; } } } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public BSplitterPanel Panel1 { get { return m_panel1; } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public BSplitterPanel Panel2 { get { return m_panel2; } } protected override void OnSizeChanged( EventArgs e ) { #if DEBUG Console.WriteLine( "BSplitContainer+OnSizeChanged" ); //Console.WriteLine( " FixedPanel=" + FixedPanel ); //Console.WriteLine( " m_splitter_distance=" + m_splitter_distance ); Console.WriteLine( " Width=" + Width ); Console.WriteLine( " Height=" + Height ); //Console.WriteLine( " m_panel2_distance=" + m_panel2_distance ); #endif base.OnSizeChanged( e ); if ( Width <= 0 || Height <= 0 ) { return; } if ( m_fixed_panel == FixedPanel.Panel2 ) { if ( m_orientation == Orientation.Horizontal ) { m_splitter_distance = this.Width - m_panel2_distance; } else { m_splitter_distance = this.Height - m_panel2_distance; } } else if ( m_fixed_panel == FixedPanel.None ) { #if DEBUG //Console.WriteLine( " m_distance_rate=" + m_distance_rate ); #endif if ( m_orientation == Orientation.Horizontal ) { m_splitter_distance = (int)(this.Width * m_distance_rate); } else { m_splitter_distance = (int)(this.Height * m_distance_rate); } } UpdateLayout( m_splitter_distance, m_splitter_width, m_panel1_min, m_panel2_min, false ); } private void m_lbl_splitter_MouseDown( object sender, MouseEventArgs e ) { if ( !m_splitter_fixed ) { m_splitter_moving = true; m_splitter_distance_draft = m_splitter_distance; this.Cursor = (m_orientation == Orientation.Horizontal) ? Cursors.VSplit : Cursors.HSplit; m_lbl_splitter.BackColor = SystemColors.ControlDark; m_lbl_splitter.BringToFront(); } } private void m_lbl_splitter_MouseUp( object sender, MouseEventArgs e ) { if ( m_splitter_moving ) { m_splitter_moving = false; UpdateLayout( m_splitter_distance_draft, m_splitter_width, m_panel1_min, m_panel2_min, false ); this.Cursor = Cursors.Default; m_lbl_splitter.BackColor = SystemColors.Control; } } private void m_lbl_splitter_MouseMove( object sender, MouseEventArgs e ) { base.OnMouseMove( e ); if ( m_splitter_fixed ) { return; } Point mouse_local = this.PointToClient( Control.MousePosition ); if ( m_splitter_moving ) { int new_distance = m_splitter_distance; if ( m_orientation == Orientation.Horizontal ) { new_distance = mouse_local.X; } else { new_distance = mouse_local.Y; } if ( UpdateLayout( new_distance, m_splitter_width, m_panel1_min, m_panel2_min, true ) ) { m_splitter_distance_draft = new_distance; if ( m_orientation == Orientation.Horizontal ) { m_lbl_splitter.Left = m_splitter_distance_draft; } else { m_lbl_splitter.Top = m_splitter_distance_draft; } } } } } }