2017-05-23 10:51:12 -07:00
/ *
Copyright ( c ) 2014 , Lars Brubaker
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 .
* /
2017-05-27 17:48:32 -07:00
using System ;
using System.IO ;
2017-05-23 10:51:12 -07:00
using MatterHackers.Agg ;
2017-05-27 17:48:32 -07:00
using MatterHackers.Agg.ImageProcessing ;
2017-08-20 02:34:39 -07:00
using MatterHackers.Agg.Platform ;
2017-05-23 10:51:12 -07:00
using MatterHackers.Agg.UI ;
using MatterHackers.Localizations ;
2017-05-27 17:48:32 -07:00
using MatterHackers.VectorMath ;
2017-05-23 10:51:12 -07:00
namespace MatterHackers.MatterControl.PartPreviewWindow
{
2017-05-27 17:48:32 -07:00
public class OverflowDropdown : PopupButton
{
2017-05-23 10:51:12 -07:00
public OverflowDropdown ( bool allowLightnessInvert )
: base ( LoadThemedIcon ( allowLightnessInvert ) )
{
this . ToolTipText = "More..." . Localize ( ) ;
}
2017-08-12 00:23:26 -07:00
public static BorderDouble MenuPadding { get ; set ; } = new BorderDouble ( 40 , 8 , 20 , 8 ) ;
2017-06-07 09:14:02 -07:00
2017-05-27 17:48:32 -07:00
public static ImageWidget LoadThemedIcon ( bool allowLightnessInvert )
2017-05-23 10:51:12 -07:00
{
2017-08-20 02:34:39 -07:00
var imageBuffer = AggContext . StaticData . LoadIcon ( Path . Combine ( "ViewTransformControls" , "overflow.png" ) , 32 , 32 ) ;
2017-05-23 10:51:12 -07:00
if ( ! ActiveTheme . Instance . IsDarkTheme & & allowLightnessInvert )
{
imageBuffer . InvertLightness ( ) ;
}
2017-05-27 17:48:32 -07:00
return new ImageWidget ( imageBuffer ) ;
2017-05-23 10:51:12 -07:00
}
2017-06-07 08:19:30 -07:00
2017-08-12 00:23:26 -07:00
public static MenuItem CreateHorizontalLine ( )
2017-06-07 08:19:30 -07:00
{
return new MenuItem ( new GuiWidget ( )
{
2017-08-07 15:47:27 -07:00
HAnchor = HAnchor . Stretch ,
2017-06-07 08:19:30 -07:00
Height = 1 ,
BackgroundColor = RGBA_Bytes . LightGray ,
Margin = new BorderDouble ( 10 , 1 ) ,
2017-08-07 15:47:27 -07:00
VAnchor = VAnchor . Center ,
2017-06-07 08:19:30 -07:00
} , "HorizontalLine" ) ;
}
2017-08-12 00:23:26 -07:00
public static MenuItem CreateMenuItem ( string name , string value = null , double pointSize = 12 )
2017-06-07 08:19:30 -07:00
{
var menuStatesView = new MenuItemColorStatesView ( name )
{
NormalBackgroundColor = RGBA_Bytes . White ,
OverBackgroundColor = RGBA_Bytes . Gray ,
NormalTextColor = RGBA_Bytes . Black ,
OverTextColor = RGBA_Bytes . Black ,
DisabledTextColor = RGBA_Bytes . Gray ,
PointSize = pointSize ,
2017-08-12 00:23:26 -07:00
Padding = MenuPadding ,
2017-06-07 08:19:30 -07:00
} ;
return new MenuItem ( menuStatesView , value ? ? name )
{
Text = name ,
Name = name + " Menu Item"
} ;
}
2017-06-12 14:19:04 -07:00
2017-06-12 16:55:07 -07:00
protected override void BeforeShowPopup ( )
2017-06-12 14:19:04 -07:00
{
if ( this . PopupContent . BackgroundColor = = RGBA_Bytes . Transparent )
{
2017-06-12 16:55:07 -07:00
this . PopupContent . BackgroundColor = RGBA_Bytes . White ;
2017-06-12 14:19:04 -07:00
}
}
2017-05-27 17:48:32 -07:00
}
2017-06-12 14:19:04 -07:00
public class PopupButton : GuiWidget , IIgnoredPopupChild
2017-05-27 17:48:32 -07:00
{
private static readonly RGBA_Bytes slightShade = new RGBA_Bytes ( 0 , 0 , 0 , 40 ) ;
2017-06-12 16:51:17 -07:00
private GuiWidget buttonView ;
2017-05-27 17:48:32 -07:00
private bool menuVisibileAtMouseDown = false ;
2017-06-12 16:51:17 -07:00
private bool menuVisible = false ;
2017-05-27 17:48:32 -07:00
private PopupWidget popupWidget ;
2017-06-27 18:41:34 -07:00
public PopupButton ( )
{
}
2017-05-27 17:48:32 -07:00
public PopupButton ( GuiWidget buttonView )
{
this . Margin = 3 ;
2017-08-07 15:47:27 -07:00
this . HAnchor = HAnchor . Fit ;
this . VAnchor = VAnchor . Fit ;
2017-05-27 17:48:32 -07:00
this . buttonView = buttonView ;
2017-08-15 15:11:37 -07:00
this . buttonView . Selectable = false ;
2017-05-27 17:48:32 -07:00
this . AddChild ( buttonView ) ;
}
2017-06-12 16:51:17 -07:00
public bool AlignToRightEdge { get ; set ; }
public RGBA_Bytes BorderColor { get ; set ; } = RGBA_Bytes . Gray ;
public Func < GuiWidget > DynamicPopupContent { get ; set ; }
2017-06-13 14:32:09 -07:00
public IPopupLayoutEngine PopupLayoutEngine { get ; set ; }
2017-05-27 17:48:32 -07:00
public Direction PopDirection { get ; set ; } = Direction . Down ;
2017-06-13 16:40:10 -07:00
public bool MakeScrollable { get ; set ; } = true ;
2017-05-23 10:51:12 -07:00
public GuiWidget PopupContent { get ; set ; }
public override void OnMouseDown ( MouseEventArgs mouseEvent )
{
2017-05-27 17:48:32 -07:00
// Store the menu state at the time of mousedown
menuVisibileAtMouseDown = menuVisible ;
2017-05-23 10:51:12 -07:00
base . OnMouseDown ( mouseEvent ) ;
}
2017-05-27 17:48:32 -07:00
public override void OnMouseUp ( MouseEventArgs mouseEvent )
2017-05-23 10:51:12 -07:00
{
2017-06-27 18:41:34 -07:00
// HACK: Child controls seem to be interfering with this.MouseCaptured - this short term workaround ensure we get clicks but likely mean mouse down outside of the control will fire the popup
bool mouseUpInBounds = this . PositionWithinLocalBounds ( mouseEvent . X , mouseEvent . Y ) ;
2017-05-27 17:48:32 -07:00
// Only show the popup if the menu was hidden as the mouse events started
2017-06-27 18:41:34 -07:00
if ( ( mouseUpInBounds | | buttonView ? . MouseCaptured = = true )
2017-06-10 12:57:40 -07:00
& & ! menuVisibileAtMouseDown )
2017-05-23 10:51:12 -07:00
{
ShowPopup ( ) ;
2017-06-16 23:01:59 -07:00
// Set a background color while the menu is active
2017-05-23 10:51:12 -07:00
this . BackgroundColor = slightShade ;
}
2017-05-27 17:48:32 -07:00
base . OnMouseUp ( mouseEvent ) ;
2017-05-23 10:51:12 -07:00
}
2017-06-12 16:55:07 -07:00
public void ShowPopup ( )
2017-05-23 10:51:12 -07:00
{
2017-06-13 14:32:09 -07:00
if ( PopupLayoutEngine = = null )
{
2017-07-28 15:39:35 -07:00
PopupLayoutEngine = new PopupLayoutEngine ( this . PopupContent , this , this . PopDirection , 0 , this . AlignToRightEdge ) ;
2017-06-13 14:32:09 -07:00
}
2017-05-27 17:48:32 -07:00
menuVisible = true ;
2017-05-23 10:51:12 -07:00
2017-05-24 14:19:02 -07:00
this . PopupContent ? . ClearRemovedFlag ( ) ;
if ( this . DynamicPopupContent ! = null )
{
2017-05-26 00:23:20 -07:00
this . PopupContent = this . DynamicPopupContent ( ) ;
2017-05-24 14:19:02 -07:00
}
if ( this . PopupContent = = null )
{
return ;
}
2017-05-23 10:51:12 -07:00
2017-06-12 16:55:07 -07:00
this . BeforeShowPopup ( ) ;
2017-06-13 16:40:10 -07:00
popupWidget = new PopupWidget ( this . PopupContent , PopupLayoutEngine , MakeScrollable )
2017-05-23 10:51:12 -07:00
{
BorderWidth = 1 ,
2017-06-12 14:19:04 -07:00
BorderColor = this . BorderColor ,
2017-05-23 10:51:12 -07:00
} ;
2017-05-27 17:48:32 -07:00
2017-05-23 10:51:12 -07:00
popupWidget . Closed + = ( s , e ) = >
{
2017-06-16 23:01:59 -07:00
// Clear the temp background color
this . BackgroundColor = RGBA_Bytes . Transparent ;
2017-05-27 17:48:32 -07:00
menuVisible = false ;
popupWidget = null ;
2017-05-23 10:51:12 -07:00
} ;
popupWidget . Focus ( ) ;
}
2017-06-12 16:55:07 -07:00
protected virtual void BeforeShowPopup ( )
{
}
2017-05-23 10:51:12 -07:00
}
}