2018-08-03 16:32:39 -07:00
/ *
Copyright ( c ) 2018 , John Lewin
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
1. Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies ,
either expressed or implied , of the FreeBSD Project .
* /
2019-02-22 22:25:57 -08:00
using System ;
2022-03-11 18:04:32 -08:00
using System.Linq ;
2018-04-11 11:29:21 -07:00
using MatterHackers.Agg ;
2017-10-22 19:42:41 -07:00
using MatterHackers.Agg.UI ;
2018-01-10 18:54:51 -08:00
using MatterHackers.Agg.VertexSource ;
2022-03-11 18:04:32 -08:00
using MatterHackers.VectorMath ;
2017-10-22 19:42:41 -07:00
2017-10-31 17:27:37 -07:00
namespace MatterHackers.MatterControl.CustomWidgets
2017-10-22 19:42:41 -07:00
{
2018-01-10 09:04:31 -08:00
/// <summary>
2018-04-06 06:06:10 -07:00
/// A container control having a header and a content panel, with optional collapse behavior and right aligned widget. Additionally support persistent expansion state via serializationKey
2018-01-10 09:04:31 -08:00
/// </summary>
2018-01-22 10:32:32 -08:00
public class SectionWidget : FlowLayoutWidget , IIgnoredPopupChild
2017-10-22 19:42:41 -07:00
{
2018-06-23 08:00:15 -07:00
protected ExpandCheckboxButton checkbox ;
2018-08-03 16:32:39 -07:00
protected GuiWidget rightAlignedContent ;
2019-02-22 22:25:57 -08:00
public event EventHandler < bool > ExpandedChanged ;
2018-05-30 12:44:30 -07:00
private bool setContentVAnchor ;
2018-01-10 23:59:36 -08:00
2018-05-30 12:44:30 -07:00
public SectionWidget ( string sectionTitle , GuiWidget sectionContent , ThemeConfig theme , GuiWidget rightAlignedContent = null , int headingPointSize = - 1 , bool expandingContent = true , bool expanded = true , string serializationKey = null , bool defaultExpansion = false , bool setContentVAnchor = true )
2017-10-22 19:42:41 -07:00
: base ( FlowDirection . TopToBottom )
{
this . HAnchor = HAnchor . Stretch ;
this . VAnchor = VAnchor . Fit ;
2018-07-15 10:07:30 -07:00
theme . ApplyBorder ( this , new BorderDouble ( top : 1 ) ) ;
2018-01-10 13:41:15 -08:00
2018-05-30 12:44:30 -07:00
this . setContentVAnchor = setContentVAnchor ;
2018-01-04 10:37:41 -08:00
if ( ! string . IsNullOrEmpty ( sectionTitle ) )
2017-10-31 17:27:37 -07:00
{
2018-01-04 10:37:41 -08:00
// Add heading
2020-11-05 09:47:50 -08:00
var pointSize = headingPointSize = = - 1 ? theme . DefaultFontSize : headingPointSize ;
2018-01-08 21:29:41 -08:00
2018-09-28 11:59:59 -07:00
// If the control is expandable and a serialization key is supplied, set expanded from persisted value
if ( serializationKey ! = null & & expandingContent )
2018-04-06 06:06:10 -07:00
{
string dbValue = UserSettings . Instance . get ( serializationKey ) ;
expanded = dbValue = = "1" | | ( dbValue = = null & & defaultExpansion ) ;
}
2018-04-12 08:42:10 -07:00
checkbox = new ExpandCheckboxButton ( sectionTitle , theme , pointSize : pointSize , expandable : expandingContent )
2017-10-22 19:42:41 -07:00
{
2018-02-09 22:51:18 -08:00
HAnchor = HAnchor . Stretch ,
Checked = expanded ,
2018-05-17 13:52:40 -07:00
Padding = 0
2018-02-09 22:51:18 -08:00
} ;
2022-03-11 18:04:32 -08:00
2018-02-09 22:51:18 -08:00
checkbox . CheckedStateChanged + = ( s , e ) = >
{
2022-03-22 17:26:21 -07:00
var scrollable = this . Parents < ScrollableWidget > ( ) . FirstOrDefault ( ) ;
2022-03-11 18:04:32 -08:00
var topPosition = Vector2 . Zero ;
if ( scrollable ! = null )
{
topPosition = scrollable . TopLeftOffset ;
}
2018-09-11 07:49:09 -07:00
if ( expandingContent )
{
ContentPanel . Visible = checkbox . Checked ;
2019-02-22 22:25:57 -08:00
this . ExpandedChanged ? . Invoke ( this , checkbox . Checked ) ;
2018-09-11 07:49:09 -07:00
}
2020-11-05 09:47:50 -08:00
2018-02-17 08:38:43 -08:00
// TODO: Remove this Height = 10 and figure out why the layout engine is not sizing these correctly without this.
2020-11-05 09:47:50 -08:00
ContentPanel . Height = 10 * GuiWidget . DeviceScale ;
2022-03-11 18:04:32 -08:00
if ( scrollable ! = null )
{
scrollable . TopLeftOffset = topPosition ;
}
2018-02-09 22:51:18 -08:00
} ;
2018-01-08 21:29:41 -08:00
2018-04-06 06:06:10 -07:00
if ( serializationKey ! = null )
{
checkbox . CheckedStateChanged + = ( s , e ) = >
{
UserSettings . Instance . set ( serializationKey , checkbox . Checked ? "1" : "0" ) ;
} ;
}
2018-01-04 10:37:41 -08:00
if ( rightAlignedContent = = null )
{
2018-02-17 08:38:43 -08:00
this . AddChild ( checkbox ) ;
2018-01-04 10:37:41 -08:00
}
else
{
2018-08-28 15:50:23 -07:00
rightAlignedContent . HAnchor | = HAnchor . Right ;
2018-06-23 12:00:03 -07:00
var headingRow = new GuiWidget ( )
2018-01-04 10:37:41 -08:00
{
2018-06-23 12:00:03 -07:00
VAnchor = VAnchor . Fit ,
2018-01-04 10:37:41 -08:00
HAnchor = HAnchor . Stretch
} ;
2018-02-17 08:38:43 -08:00
headingRow . AddChild ( checkbox ) ;
2018-01-04 10:37:41 -08:00
headingRow . AddChild ( rightAlignedContent ) ;
this . AddChild ( headingRow ) ;
}
2018-08-03 16:32:39 -07:00
this . rightAlignedContent = rightAlignedContent ;
2018-01-04 10:37:41 -08:00
}
2017-10-22 19:42:41 -07:00
2018-01-08 23:34:40 -08:00
sectionContent . Visible = expanded ;
this . SetContentWidget ( sectionContent ) ;
}
2018-01-10 23:59:36 -08:00
public ICheckbox Checkbox = > checkbox ;
2019-04-26 13:03:35 -07:00
public bool ShowExpansionIcon
{
get = > checkbox . ShowIcon ;
set
{
checkbox . ShowIcon = value ;
checkbox . Padding = value ? 0 : new BorderDouble ( left : this . ContentPanel . Margin . Left ) ;
}
}
2018-01-10 09:04:31 -08:00
public GuiWidget ContentPanel { get ; private set ; }
2018-01-10 13:41:15 -08:00
2018-01-08 23:34:40 -08:00
public void SetContentWidget ( GuiWidget guiWidget )
{
2018-01-10 13:41:15 -08:00
// Close old child
this . ContentPanel ? . Close ( ) ;
// Apply default rules for panel widget
guiWidget . HAnchor = HAnchor . Stretch ;
2018-05-30 12:44:30 -07:00
if ( setContentVAnchor )
{
guiWidget . VAnchor = VAnchor . Fit ;
}
2018-01-08 23:34:40 -08:00
2018-01-10 13:41:15 -08:00
// Set
this . AddChild ( guiWidget ) ;
2018-01-08 23:34:40 -08:00
2018-01-10 13:41:15 -08:00
// Store
this . ContentPanel = guiWidget ;
2018-04-12 21:20:31 -07:00
this . ContentPanel . BorderColor = Color . Transparent ;
2017-10-22 19:42:41 -07:00
}
2018-01-10 18:54:51 -08:00
2021-02-25 23:06:42 -08:00
public int BorderRadius { get ; set ; }
2018-01-10 18:54:51 -08:00
2018-04-11 11:29:21 -07:00
public bool ExpandableWhenDisabled { get ; set ; }
2018-06-23 12:00:45 -07:00
public override string Text
{
get = > checkbox ? . Text ;
set
{
if ( checkbox ! = null )
{
checkbox . Text = value ;
}
}
}
2018-04-11 11:29:21 -07:00
public override bool Enabled
{
2020-11-05 09:47:50 -08:00
get = > this . ExpandableWhenDisabled ? true : base . Enabled ;
2018-04-11 11:29:21 -07:00
set
{
if ( this . ExpandableWhenDisabled )
{
this . ContentPanel . Enabled = value ;
}
else
{
base . Enabled = value ;
}
}
}
2018-01-10 18:54:51 -08:00
public override void OnDrawBackground ( Graphics2D graphics2D )
{
if ( this . BorderRadius > 0 )
{
var rect = new RoundedRect ( this . LocalBounds , this . BorderRadius ) ;
graphics2D . Render ( rect , this . BackgroundColor ) ;
}
else
{
base . OnDrawBackground ( graphics2D ) ;
}
}
2018-09-11 10:57:53 -07:00
2018-10-11 15:04:03 -07:00
public bool KeepMenuOpen = > false ;
2017-10-22 19:42:41 -07:00
}
}