2016-02-28 11:54:42 -08:00
/ *
2017-05-27 17:48:32 -07:00
Copyright ( c ) 2017 , Lars Brubaker , John Lewin
2016-02-28 11:54:42 -08:00
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.Collections.Generic ;
2016-02-28 11:54:42 -08:00
using MatterHackers.Agg ;
using MatterHackers.Agg.UI ;
using MatterHackers.Localizations ;
using MatterHackers.MatterControl.CustomWidgets ;
using MatterHackers.VectorMath ;
namespace MatterHackers.MatterControl.PartPreviewWindow
{
2017-05-27 17:48:32 -07:00
public class PopupActionPanel : FlowLayoutWidget , IIgnoredPopupChild
{
public PopupActionPanel ( ) : base ( FlowDirection . TopToBottom )
{
this . Padding = 15 ;
this . BackgroundColor = ActiveTheme . Instance . SecondaryBackgroundColor ;
}
}
public class ScaleControls : PopupActionPanel
2016-02-28 11:54:42 -08:00
{
2016-02-29 07:57:30 -08:00
private Button applyScaleButton ;
2016-02-28 11:54:42 -08:00
private MHNumberEdit scaleRatioControl ;
private EditableNumberDisplay [ ] sizeDisplay = new EditableNumberDisplay [ 3 ] ;
2016-02-29 07:57:30 -08:00
private CheckBox uniformScale ;
private View3DWidget view3DWidget ;
2016-02-28 11:54:42 -08:00
2017-05-27 17:48:32 -07:00
public ScaleControls ( View3DWidget view3DWidget , TextImageButtonFactory buttonFactory )
2016-02-28 11:54:42 -08:00
{
this . view3DWidget = view3DWidget ;
List < GuiWidget > scaleControls = new List < GuiWidget > ( ) ;
// Put in the scale ratio edit field
{
2017-05-27 17:48:32 -07:00
var scaleRatioContainer = new FlowLayoutWidget ( FlowDirection . LeftToRight ) ;
2016-02-28 11:54:42 -08:00
scaleRatioContainer . HAnchor = HAnchor . ParentLeftRight ;
scaleRatioContainer . Padding = new BorderDouble ( 5 ) ;
2017-05-27 17:48:32 -07:00
var scaleRatioLabel = new TextWidget ( "Ratio" . Localize ( ) + ":" , textColor : ActiveTheme . Instance . PrimaryTextColor ) ;
2016-02-28 11:54:42 -08:00
scaleRatioLabel . Margin = new BorderDouble ( 0 , 0 , 3 , 0 ) ;
scaleRatioLabel . VAnchor = VAnchor . ParentCenter ;
scaleRatioContainer . AddChild ( scaleRatioLabel ) ;
scaleRatioContainer . AddChild ( new HorizontalSpacer ( ) ) ;
2016-05-06 17:56:27 -07:00
scaleRatioControl = new MHNumberEdit ( 1 , pixelWidth : 50 * GuiWidget . DeviceScale , allowDecimals : true , increment : . 05 ) ;
2016-02-28 11:54:42 -08:00
scaleRatioControl . SelectAllOnFocus = true ;
scaleRatioControl . VAnchor = VAnchor . ParentCenter ;
scaleRatioContainer . AddChild ( scaleRatioControl ) ;
scaleRatioControl . ActuallNumberEdit . KeyPressed + = ( sender , e ) = >
{
2016-02-29 10:13:51 -08:00
OnSelectedTransformChanged ( this , null ) ;
2016-02-28 11:54:42 -08:00
} ;
scaleRatioControl . ActuallNumberEdit . KeyDown + = ( sender , e ) = >
{
2016-02-29 10:13:51 -08:00
OnSelectedTransformChanged ( this , null ) ;
2016-02-28 11:54:42 -08:00
} ;
scaleRatioControl . ActuallNumberEdit . EnterPressed + = ( object sender , KeyEventArgs keyEvent ) = >
{
ApplyScaleFromEditField ( ) ;
} ;
scaleRatioContainer . AddChild ( CreateScaleDropDownMenu ( ) ) ;
2017-05-27 17:48:32 -07:00
this . AddChild ( scaleRatioContainer ) ;
2016-02-28 11:54:42 -08:00
scaleControls . Add ( scaleRatioControl ) ;
}
2017-05-27 17:48:32 -07:00
applyScaleButton = buttonFactory . Generate ( "Apply Scale" . Localize ( ) , centerText : true ) ;
2016-02-28 11:54:42 -08:00
applyScaleButton . Cursor = Cursors . Hand ;
2017-05-27 17:48:32 -07:00
this . AddChild ( applyScaleButton ) ;
2016-02-28 11:54:42 -08:00
scaleControls . Add ( applyScaleButton ) ;
2017-01-17 14:47:04 -08:00
applyScaleButton . Click + = ( s , e ) = >
2016-02-28 11:54:42 -08:00
{
ApplyScaleFromEditField ( ) ;
} ;
// add in the dimensions
{
2017-05-27 17:48:32 -07:00
this . AddChild ( CreateAxisScalingControl ( "x" . ToUpper ( ) , 0 , buttonFactory ) ) ;
this . AddChild ( CreateAxisScalingControl ( "y" . ToUpper ( ) , 1 , buttonFactory ) ) ;
this . AddChild ( CreateAxisScalingControl ( "z" . ToUpper ( ) , 2 , buttonFactory ) ) ;
2016-02-28 11:54:42 -08:00
uniformScale = new CheckBox ( "Lock Ratio" . Localize ( ) , textColor : ActiveTheme . Instance . PrimaryTextColor ) ;
uniformScale . Checked = true ;
FlowLayoutWidget leftToRight = new FlowLayoutWidget ( ) ;
leftToRight . Padding = new BorderDouble ( 5 , 3 ) ;
leftToRight . AddChild ( uniformScale ) ;
2017-05-27 17:48:32 -07:00
this . AddChild ( leftToRight ) ;
2016-02-28 11:54:42 -08:00
}
2017-05-27 17:48:32 -07:00
view3DWidget . SelectedTransformChanged + = OnSelectedTransformChanged ;
2016-02-28 11:54:42 -08:00
}
private void ApplyScaleFromEditField ( )
{
2017-03-15 16:17:06 -07:00
if ( view3DWidget . Scene . HasSelection )
2016-02-28 11:54:42 -08:00
{
2017-03-15 16:17:06 -07:00
Matrix4X4 startingTransform = view3DWidget . Scene . SelectedItem . Matrix ;
Vector3 currentScale = view3DWidget . Scene . SelectedItem . ExtraData . CurrentScale ;
2016-02-29 10:13:51 -08:00
2016-02-28 11:54:42 -08:00
double scale = scaleRatioControl . ActuallNumberEdit . Value ;
if ( scale > 0 )
{
ScaleAxis ( scale , 0 ) ;
2017-03-15 16:17:06 -07:00
view3DWidget . Scene . SelectedItem . ExtraData . CurrentScale . y = currentScale . y ;
view3DWidget . Scene . SelectedItem . ExtraData . CurrentScale . z = currentScale . z ;
2016-02-28 11:54:42 -08:00
ScaleAxis ( scale , 1 ) ;
2017-03-15 16:17:06 -07:00
view3DWidget . Scene . SelectedItem . ExtraData . CurrentScale . z = currentScale . z ;
2016-02-28 11:54:42 -08:00
ScaleAxis ( scale , 2 ) ;
}
2016-02-29 10:59:30 -08:00
view3DWidget . AddUndoForSelectedMeshGroupTransform ( startingTransform ) ;
2016-02-28 11:54:42 -08:00
}
}
2017-05-27 17:48:32 -07:00
private GuiWidget CreateAxisScalingControl ( string axis , int axisIndex , TextImageButtonFactory buttonFactory )
2016-02-29 07:57:30 -08:00
{
2017-05-27 17:48:32 -07:00
var leftToRight = new FlowLayoutWidget ( )
{
Padding = new BorderDouble ( 5 , 3 )
} ;
2016-02-29 07:57:30 -08:00
2017-05-27 17:48:32 -07:00
var sizeDescription = new TextWidget ( "{0}:" . FormatWith ( axis ) , textColor : ActiveTheme . Instance . PrimaryTextColor ) ;
sizeDescription . VAnchor = VAnchor . ParentCenter ;
2016-02-29 07:57:30 -08:00
leftToRight . AddChild ( sizeDescription ) ;
2017-05-27 17:48:32 -07:00
sizeDisplay [ axisIndex ] = new EditableNumberDisplay ( buttonFactory , "100" , "1000.00" ) ;
2016-02-29 07:57:30 -08:00
sizeDisplay [ axisIndex ] . EditComplete + = ( sender , e ) = >
{
2017-03-15 16:17:06 -07:00
if ( view3DWidget . Scene . HasSelection )
2016-02-29 07:57:30 -08:00
{
2017-03-15 16:17:06 -07:00
Matrix4X4 startingTransform = view3DWidget . Scene . SelectedItem . Matrix ;
2016-02-29 07:57:30 -08:00
SetNewModelSize ( sizeDisplay [ axisIndex ] . GetValue ( ) , axisIndex ) ;
2017-03-15 16:17:06 -07:00
sizeDisplay [ axisIndex ] . SetDisplayString ( "{0:0.00}" . FormatWith ( view3DWidget . Scene . SelectedItem . GetAxisAlignedBoundingBox ( Matrix4X4 . Identity ) . Size [ axisIndex ] ) ) ;
2016-02-29 10:13:51 -08:00
OnSelectedTransformChanged ( null , null ) ;
2016-02-29 10:59:30 -08:00
view3DWidget . AddUndoForSelectedMeshGroupTransform ( startingTransform ) ;
2016-02-29 07:57:30 -08:00
}
else
{
sizeDisplay [ axisIndex ] . SetDisplayString ( "---" ) ;
}
} ;
leftToRight . AddChild ( sizeDisplay [ axisIndex ] ) ;
return leftToRight ;
}
2016-02-28 11:54:42 -08:00
private DropDownMenu CreateScaleDropDownMenu ( )
{
2017-05-27 17:48:32 -07:00
var presetScaleMenu = new DropDownMenu ( "" , Direction . Down )
{
NormalArrowColor = ActiveTheme . Instance . PrimaryTextColor ,
HoverArrowColor = ActiveTheme . Instance . PrimaryTextColor ,
MenuAsWideAsItems = false ,
AlignToRightEdge = true ,
//presetScaleMenu.OpenOffset = new Vector2(-50, 0);
HAnchor = HAnchor . AbsolutePosition ,
VAnchor = VAnchor . AbsolutePosition ,
Width = 25 ,
Height = scaleRatioControl . Height + 2
} ;
2016-02-28 11:54:42 -08:00
presetScaleMenu . AddItem ( "mm to in (.0393)" ) ;
presetScaleMenu . AddItem ( "in to mm (25.4)" ) ;
presetScaleMenu . AddItem ( "mm to cm (.1)" ) ;
presetScaleMenu . AddItem ( "cm to mm (10)" ) ;
2017-05-31 12:42:44 -07:00
presetScaleMenu . AddItem ( "none" . Localize ( ) + " (1)" ) ;
2016-02-28 11:54:42 -08:00
presetScaleMenu . SelectionChanged + = ( sender , e ) = >
{
double scale = 1 ;
switch ( presetScaleMenu . SelectedIndex )
{
case 0 :
scale = 1.0 / 25.4 ;
break ;
case 1 :
scale = 25.4 ;
break ;
case 2 :
scale = . 1 ;
break ;
case 3 :
scale = 10 ;
break ;
case 4 :
scale = 1 ;
break ;
}
scaleRatioControl . ActuallNumberEdit . Value = scale ;
} ;
return presetScaleMenu ;
}
2016-02-29 07:57:30 -08:00
2016-02-28 11:54:42 -08:00
private void ScaleAxis ( double scaleIn , int axis )
{
2017-03-15 16:17:06 -07:00
var selectedItem = view3DWidget . Scene . SelectedItem ;
AxisAlignedBoundingBox originalMeshBounds = selectedItem . GetAxisAlignedBoundingBox ( Matrix4X4 . Identity ) ;
AxisAlignedBoundingBox scaledBounds = selectedItem . GetAxisAlignedBoundingBox ( selectedItem . Matrix ) ;
// first we remove any scale we have applied and then scale to the new value
Vector3 axisRemoveScalings = Vector3 . One ;
if ( originalMeshBounds . XSize > 0 & & scaledBounds . XSize > 0 ) axisRemoveScalings . x = originalMeshBounds . XSize / scaledBounds . XSize ;
if ( originalMeshBounds . YSize > 0 & & scaledBounds . YSize > 0 ) axisRemoveScalings . y = originalMeshBounds . YSize / scaledBounds . YSize ;
if ( originalMeshBounds . ZSize > 0 & & scaledBounds . ZSize > 0 ) axisRemoveScalings . z = originalMeshBounds . ZSize / scaledBounds . ZSize ;
2016-02-28 11:54:42 -08:00
2017-03-15 16:17:06 -07:00
Matrix4X4 removeScaleMatrix = Matrix4X4 . CreateScale ( axisRemoveScalings ) ;
Vector3 newScale = selectedItem . ExtraData . CurrentScale ;
2016-02-28 11:54:42 -08:00
newScale [ axis ] = scaleIn ;
2016-06-22 16:29:14 -07:00
Matrix4X4 totalScale = Matrix4X4 . CreateScale ( newScale ) ;
2016-02-28 11:54:42 -08:00
2017-03-15 16:17:06 -07:00
selectedItem . Matrix = PlatingHelper . ApplyAtCenter ( selectedItem , totalScale ) ;
2016-02-29 10:13:51 -08:00
2017-03-15 16:17:06 -07:00
PlatingHelper . PlaceMeshAtHeight ( selectedItem , originalMeshBounds . minXYZ . z ) ;
2016-07-15 17:07:45 -07:00
2016-02-28 11:54:42 -08:00
view3DWidget . PartHasBeenChanged ( ) ;
Invalidate ( ) ;
2017-03-15 16:17:06 -07:00
view3DWidget . Scene . SelectedItem . ExtraData . CurrentScale [ axis ] = scaleIn ;
2016-02-29 10:13:51 -08:00
OnSelectedTransformChanged ( this , null ) ;
2016-02-28 11:54:42 -08:00
}
2016-02-29 07:57:30 -08:00
2016-02-28 11:54:42 -08:00
private void SetNewModelSize ( double sizeInMm , int axis )
{
2017-03-15 16:17:06 -07:00
if ( view3DWidget . Scene . HasSelection )
2016-02-28 11:54:42 -08:00
{
// because we remove any current scale before we change to a new one we only get the size of the base mesh data
2017-03-15 16:17:06 -07:00
AxisAlignedBoundingBox originalMeshBounds = view3DWidget . Scene . SelectedItem . GetAxisAlignedBoundingBox ( Matrix4X4 . Identity ) ;
2016-02-28 11:54:42 -08:00
double currentSize = originalMeshBounds . Size [ axis ] ;
double desiredSize = sizeDisplay [ axis ] . GetValue ( ) ;
double scaleFactor = 1 ;
if ( currentSize ! = 0 )
{
scaleFactor = desiredSize / currentSize ;
}
if ( uniformScale . Checked )
{
scaleRatioControl . ActuallNumberEdit . Value = scaleFactor ;
ApplyScaleFromEditField ( ) ;
}
else
{
ScaleAxis ( scaleFactor , axis ) ;
}
}
}
2016-02-29 10:13:51 -08:00
private void OnSelectedTransformChanged ( object sender , EventArgs e )
2016-02-28 11:54:42 -08:00
{
if ( sizeDisplay [ 0 ] ! = null
2017-03-15 16:17:06 -07:00
& & view3DWidget . Scene . HasSelection )
2016-02-28 11:54:42 -08:00
{
2017-03-15 16:17:06 -07:00
var selectedItem = view3DWidget . Scene . SelectedItem ;
// TODO: jlewin - could be this simple but how do we call old/new transform values from this context given they've likely been updated and we track one value
// AxisAlignedBoundingBox bounds = view3DWidget.SelectedObject3D.GetAxisAlignedBoundingBox();
AxisAlignedBoundingBox bounds = selectedItem . GetAxisAlignedBoundingBox ( selectedItem . Matrix ) ;
2016-02-28 11:54:42 -08:00
sizeDisplay [ 0 ] . SetDisplayString ( "{0:0.00}" . FormatWith ( bounds . Size [ 0 ] ) ) ;
sizeDisplay [ 1 ] . SetDisplayString ( "{0:0.00}" . FormatWith ( bounds . Size [ 1 ] ) ) ;
sizeDisplay [ 2 ] . SetDisplayString ( "{0:0.00}" . FormatWith ( bounds . Size [ 2 ] ) ) ;
2016-02-29 10:13:51 -08:00
// set the scaling to be this new size
2017-03-15 16:17:06 -07:00
AxisAlignedBoundingBox originalMeshBounds = selectedItem . GetAxisAlignedBoundingBox ( Matrix4X4 . Identity ) ;
AxisAlignedBoundingBox scaledBounds = selectedItem . GetAxisAlignedBoundingBox ( selectedItem . Matrix ) ;
2016-02-29 10:13:51 -08:00
Vector3 currentScale = new Vector3 ( ) ;
currentScale . x = scaledBounds . XSize / originalMeshBounds . XSize ;
currentScale . y = scaledBounds . YSize / originalMeshBounds . YSize ;
currentScale . z = scaledBounds . ZSize / originalMeshBounds . ZSize ;
2017-03-15 16:17:06 -07:00
selectedItem . ExtraData . CurrentScale = currentScale ;
2016-02-28 11:54:42 -08:00
}
else
{
sizeDisplay [ 0 ] . SetDisplayString ( "---" ) ;
sizeDisplay [ 1 ] . SetDisplayString ( "---" ) ;
sizeDisplay [ 2 ] . SetDisplayString ( "---" ) ;
}
}
}
}