2014-02-15 18:06:03 -08:00
/ *
2018-01-14 10:13:42 -08:00
Copyright ( c ) 2018 , Lars Brubaker , John Lewin
2014-02-15 18:06:03 -08:00
All rights reserved .
Redistribution and use in source and binary forms , with or without
2015-04-08 15:20:10 -07:00
modification , are permitted provided that the following conditions are met :
2014-02-15 18:06:03 -08:00
1. Redistributions of source code must retain the above copyright notice , this
2015-04-08 15:20:10 -07:00
list of conditions and the following disclaimer .
2014-02-15 18:06:03 -08:00
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
2015-04-08 15:20:10 -07:00
and / or other materials provided with the distribution .
2014-02-15 18:06:03 -08:00
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
2015-04-08 15:20:10 -07:00
of the authors and should not be interpreted as representing official policies ,
2014-02-15 18:06:03 -08:00
either expressed or implied , of the FreeBSD Project .
* /
2016-08-10 15:18:03 -07:00
2017-07-01 16:47:37 -07:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2014-01-29 19:09:30 -08:00
using MatterHackers.Agg ;
2014-02-05 17:47:13 -08:00
using MatterHackers.Agg.UI ;
2014-01-29 19:09:30 -08:00
using MatterHackers.Localizations ;
2014-11-03 12:13:03 -08:00
using MatterHackers.MatterControl.CustomWidgets ;
2018-01-08 13:13:32 -08:00
using MatterHackers.MatterControl.PartPreviewWindow ;
2018-01-14 10:36:05 -08:00
using MatterHackers.MatterControl.PrintLibrary ;
using MatterHackers.MatterControl.SetupWizard ;
2014-02-05 17:47:13 -08:00
using MatterHackers.VectorMath ;
2014-01-29 19:09:30 -08:00
2014-02-15 18:06:03 -08:00
namespace MatterHackers.MatterControl.SlicerConfiguration
2018-01-18 17:59:24 -08:00
{
2017-10-15 16:24:39 -07:00
public class SliceSettingsWidget : FlowLayoutWidget
2015-04-08 15:20:10 -07:00
{
2017-09-13 21:38:34 -07:00
internal PresetsToolbar settingsControlBar ;
2016-04-21 17:24:56 -07:00
2017-12-27 13:45:47 -08:00
internal SettingsContext settingsContext ;
2017-09-17 01:11:18 -07:00
private PrinterConfig printer ;
2017-12-29 09:10:37 -08:00
private Color textColor ;
2018-01-14 10:13:42 -08:00
private SliceSettingsTabView sliceSettingsTabView ;
2017-06-08 16:43:30 -07:00
2017-10-31 14:37:28 -07:00
private ThemeConfig theme ;
public SliceSettingsWidget ( PrinterConfig printer , SettingsContext settingsContext , ThemeConfig theme )
2017-09-13 22:15:00 -07:00
: base ( FlowDirection . TopToBottom )
2015-04-08 15:20:10 -07:00
{
2017-10-31 14:37:28 -07:00
this . theme = theme ;
2017-09-17 01:11:18 -07:00
this . printer = printer ;
2017-12-29 09:10:37 -08:00
this . textColor = ActiveTheme . Instance . PrimaryTextColor ;
2017-05-24 14:19:02 -07:00
this . BackgroundColor = ApplicationController . Instance . Theme . TabBodyBackground ;
2017-05-23 10:51:12 -07:00
2017-09-03 18:50:44 +03:00
this . settingsContext = settingsContext ;
2016-04-18 11:31:31 -07:00
2017-09-17 01:11:18 -07:00
settingsControlBar = new PresetsToolbar ( printer )
2016-03-30 18:33:29 -07:00
{
2017-08-07 15:47:27 -07:00
HAnchor = HAnchor . Stretch ,
2016-03-30 18:33:29 -07:00
Padding = new BorderDouble ( 8 , 12 , 8 , 8 )
} ;
2014-01-29 19:09:30 -08:00
2017-09-13 22:15:00 -07:00
this . AddChild ( settingsControlBar ) ;
2016-04-21 17:24:56 -07:00
2018-01-14 10:13:42 -08:00
this . RebuildSliceSettingsTabs ( ) ;
2017-06-02 17:04:02 -07:00
2018-01-14 10:36:05 -08:00
ApplicationController . Instance . ShowHelpChanged + = ShowHelp_Changed ;
2017-06-02 17:04:02 -07:00
this . AnchorAll ( ) ;
}
2018-01-14 10:36:05 -08:00
private void ShowHelp_Changed ( object sender , EventArgs e )
{
this . RebuildSliceSettingsTabs ( ) ;
}
private void RebuildSliceSettingsTabs ( )
2017-06-02 17:04:02 -07:00
{
2017-09-13 22:36:08 -07:00
// Close and remove children
2018-01-14 10:13:42 -08:00
sliceSettingsTabView ? . Close ( ) ;
this . AddChild (
sliceSettingsTabView = new SliceSettingsTabView (
settingsContext ,
printer ,
this . UserLevel ,
theme ,
isPrimarySettingsView : true ,
2018-01-21 21:07:14 -08:00
databaseMRUKey : UserSettingsKey . SliceSettingsWidget_CurrentTab ,
extendPopupMenu : this . ExtendOverflowMenu ) ) ;
2018-01-14 10:36:05 -08:00
}
2018-01-21 21:07:14 -08:00
private void ExtendOverflowMenu ( PopupMenu popupMenu )
2018-01-14 10:36:05 -08:00
{
popupMenu . CreateHorizontalLine ( ) ;
PopupMenu . MenuItem menuItem ;
menuItem = popupMenu . CreateMenuItem ( "Export" . Localize ( ) ) ;
menuItem . Click + = ( s , e ) = >
{
DialogWindow . Show < ExportSettingsPage > ( ) ;
} ;
menuItem = popupMenu . CreateMenuItem ( "Restore Settings" . Localize ( ) ) ;
menuItem . Click + = ( s , e ) = >
{
DialogWindow . Show < PrinterProfileHistoryPage > ( ) ;
} ;
menuItem . Enabled = ! string . IsNullOrEmpty ( AuthenticationData . Instance . ActiveSessionUsername ) ;
menuItem = popupMenu . CreateMenuItem ( "Reset to Defaults" . Localize ( ) ) ;
menuItem . Click + = ( s , e ) = >
{
UiThread . RunOnIdle ( ( ) = >
{
StyledMessageBox . ShowMessageBox (
revertSettings = >
{
if ( revertSettings )
{
bool onlyReloadSliceSettings = true ;
if ( printer . Settings . GetValue < bool > ( SettingsKey . print_leveling_required_to_print )
& & printer . Settings . GetValue < bool > ( SettingsKey . print_leveling_enabled ) )
{
onlyReloadSliceSettings = false ;
}
printer . Settings . ClearUserOverrides ( ) ;
printer . Settings . Save ( ) ;
if ( onlyReloadSliceSettings )
{
printer ? . Bed . GCodeRenderer ? . Clear3DGCode ( ) ;
}
else
{
ApplicationController . Instance . ReloadAll ( ) ;
}
}
} ,
"Resetting to default values will remove your current overrides and restore your original printer settings.\nAre you sure you want to continue?" . Localize ( ) ,
"Revert Settings" . Localize ( ) ,
StyledMessageBox . MessageType . YES_NO ) ;
} ) ;
} ;
2014-12-31 14:17:18 -08:00
}
2017-12-12 12:06:20 -08:00
public string UserLevel { get ; } = "Advanced" ;
2015-04-08 15:20:10 -07:00
2017-09-04 23:49:05 +03:00
// TODO: This should just proxy to settingsControlBar.Visible. Having local state and pushing values on event listeners seems off
2017-01-11 14:27:33 -08:00
private bool showControlBar = true ;
public bool ShowControlBar
{
get { return showControlBar ; }
set
{
settingsControlBar . Visible = value ;
showControlBar = value ;
}
}
2017-09-14 07:46:12 -07:00
2017-02-03 13:06:08 -08:00
public override void OnClosed ( ClosedEventArgs e )
2015-04-08 15:20:10 -07:00
{
2018-01-14 10:36:05 -08:00
ApplicationController . Instance . ShowHelpChanged - = ShowHelp_Changed ;
2015-04-08 15:20:10 -07:00
base . OnClosed ( e ) ;
}
2018-01-14 10:13:42 -08:00
}
2017-06-08 16:43:30 -07:00
2018-01-14 10:13:42 -08:00
public class SliceSettingsTabView : SimpleTabs
{
private int tabIndexForItem = 0 ;
private Dictionary < string , UIField > allUiFields = new Dictionary < string , UIField > ( ) ;
private ThemeConfig theme ;
private PrinterConfig printer ;
private SettingsContext settingsContext ;
private bool isPrimarySettingsView ;
private bool showSubGroupHeadings = false ;
2018-01-14 10:36:05 -08:00
private SearchInputBox searchPanel ;
private int groupPanelCount = 0 ;
private List < ( GuiWidget widget , SliceSettingData settingData ) > settingsRows ;
private TextWidget filteredItemsHeading ;
2018-01-18 17:59:24 -08:00
private EventHandler unregisterEvents ;
2018-01-21 21:07:14 -08:00
private Action < PopupMenu > externalExtendMenu ;
2017-11-16 09:56:16 -08:00
2018-01-21 21:07:14 -08:00
public SliceSettingsTabView ( SettingsContext settingsContext , PrinterConfig printer , string UserLevel , ThemeConfig theme , bool isPrimarySettingsView , string databaseMRUKey , Action < PopupMenu > extendPopupMenu = null )
: base ( theme )
2018-01-14 10:36:05 -08:00
{
2018-01-14 10:13:42 -08:00
this . VAnchor = VAnchor . Stretch ;
this . HAnchor = HAnchor . Stretch ;
2018-01-21 21:07:14 -08:00
this . externalExtendMenu = extendPopupMenu ;
var overflowBar = this . TabBar as OverflowBar ;
overflowBar . ExtendOverflowMenu = this . ExtendOverflowMenu ;
var overflowButton = this . TabBar . RightAnchorItem ;
overflowButton . Name = "Slice Settings Overflow Menu" ;
2018-01-14 10:13:42 -08:00
2018-01-21 21:07:14 -08:00
this . TabBar . Padding = this . TabBar . Margin . Clone ( right : theme . ToolbarPadding . Right ) ;
2018-01-14 10:36:05 -08:00
searchPanel = new SearchInputBox ( )
{
Visible = false ,
BackgroundColor = theme . ActiveTabBarBackground ,
MinimumSize = new Vector2 ( 0 , this . TabBar . Height )
} ;
searchPanel . searchInput . Margin = new BorderDouble ( 3 , 0 ) ;
searchPanel . searchInput . ActualTextEditWidget . EnterPressed + = ( s , e ) = >
{
var filter = searchPanel . searchInput . Text . Trim ( ) ;
foreach ( var item in this . settingsRows )
{
var metaData = item . settingData ;
// Show matching items
item . widget . Visible = metaData . SlicerConfigName . IndexOf ( filter , StringComparison . OrdinalIgnoreCase ) > = 0
| | metaData . HelpText . IndexOf ( filter , StringComparison . OrdinalIgnoreCase ) > = 0 ;
}
this . ShowFilteredView ( ) ;
} ;
2018-01-23 12:35:27 -08:00
searchPanel . ResetButton . Click + = ( s , e ) = >
2018-01-14 10:36:05 -08:00
{
searchPanel . Visible = false ;
searchPanel . searchInput . Text = "" ;
this . ClearFilter ( ) ;
} ;
// Add heading for My Settings view
searchPanel . AddChild ( filteredItemsHeading = new TextWidget ( "My Modified Settings" , pointSize : theme . DefaultFontSize , textColor : theme . Colors . PrimaryTextColor )
{
Margin = new BorderDouble ( left : 10 ) ,
HAnchor = HAnchor . Left ,
VAnchor = VAnchor . Center ,
Visible = false
} , 0 ) ;
this . AddChild ( searchPanel , 0 ) ;
2018-01-16 15:05:58 -08:00
var scrollable = new ScrollableWidget ( true )
{
HAnchor = HAnchor . Stretch ,
VAnchor = VAnchor . Stretch ,
} ;
scrollable . ScrollArea . HAnchor = HAnchor . Stretch ;
//scrollable.ScrollArea.VAnchor = VAnchor.Fit;
var tabContainer = new FlowLayoutWidget ( FlowDirection . TopToBottom )
{
VAnchor = VAnchor . Fit ,
HAnchor = HAnchor . Stretch ,
//DebugShowBounds = true,
//MinimumSize = new Vector2(200, 200)
} ;
scrollable . AddChild ( tabContainer ) ;
this . AddChild ( scrollable ) ;
// Force TopToBottom flowlayout contained in scrollable as AddChild target
this . TabContainer = tabContainer ;
2018-01-14 10:13:42 -08:00
this . theme = theme ;
this . printer = printer ;
this . settingsContext = settingsContext ;
this . isPrimarySettingsView = isPrimarySettingsView ;
this . TabBar . BackgroundColor = theme . ActiveTabBarBackground ;
2017-07-01 16:47:37 -07:00
2018-01-14 10:13:42 -08:00
tabIndexForItem = 0 ;
2018-01-11 12:29:19 -08:00
2018-01-14 10:13:42 -08:00
var userLevel = SettingsOrganizer . Instance . UserLevels [ UserLevel ] ;
2018-01-14 10:36:05 -08:00
this . settingsRows = new List < ( GuiWidget , SliceSettingData ) > ( ) ;
2018-01-18 17:59:24 -08:00
allUiFields = new Dictionary < string , UIField > ( ) ;
2018-01-14 10:13:42 -08:00
// Loop over categories creating a tab for each
foreach ( var category in userLevel . Categories )
2015-04-08 15:20:10 -07:00
{
2018-01-14 10:13:42 -08:00
if ( category . Name = = "Printer"
& & ( settingsContext . ViewFilter = = NamedSettingsLayers . Material | | settingsContext . ViewFilter = = NamedSettingsLayers . Quality ) )
{
continue ;
}
2017-06-11 14:29:42 -07:00
2018-01-14 10:13:42 -08:00
var categoryPanel = new FlowLayoutWidget ( FlowDirection . TopToBottom )
2016-07-15 11:52:06 -07:00
{
2018-01-14 10:13:42 -08:00
VAnchor = VAnchor . Fit ,
HAnchor = HAnchor . Stretch ,
} ;
// Loop over all groups in this tab and add their content
2018-01-31 15:10:38 -08:00
bool first = true ;
2018-01-14 10:13:42 -08:00
foreach ( var group in category . Groups )
{
if ( group . Name = = "Connection" )
{
categoryPanel . AddChild (
this . CreateOemProfileInfoRow ( ) ) ;
}
2018-01-31 15:10:38 -08:00
var groupContent = this . CreateGroupContent ( group ) ;
2014-01-29 19:09:30 -08:00
2018-01-31 15:10:38 -08:00
if ( groupContent . Descendants < SliceSettingsRow > ( ) . Any ( ) )
2018-01-16 15:05:58 -08:00
{
2018-01-31 15:10:38 -08:00
categoryPanel . AddChild ( groupContent ) ;
if ( groupContent is SectionWidget sectionWidget )
{
sectionWidget . Checkbox . Checked = first ;
first = false ;
}
}
}
if ( categoryPanel . Descendants < SliceSettingsRow > ( ) . Any ( ) )
{
this . AddTab (
new ToolTab (
category . Name . Localize ( ) ,
this ,
categoryPanel ,
theme ,
hasClose : false ,
pointSize : theme . DefaultFontSize )
{
Name = category . Name + " Tab" ,
InactiveTabColor = Color . Transparent ,
ActiveTabColor = theme . ActiveTabColor
} ) ;
}
2018-01-03 22:25:25 -08:00
}
2015-04-16 18:08:43 -07:00
2018-01-14 10:36:05 -08:00
this . TabBar . AddChild ( new HorizontalSpacer ( ) ) ;
var searchButton = ApplicationController . Instance . Theme . CreateSearchButton ( ) ;
searchButton . Click + = ( s , e ) = >
{
filteredItemsHeading . Visible = false ;
searchPanel . searchInput . Visible = true ;
searchPanel . Visible = true ;
searchPanel . searchInput . Focus ( ) ;
this . TabBar . Visible = false ;
} ;
this . TabBar . AddChild ( searchButton ) ;
2018-01-21 21:07:14 -08:00
searchButton . VAnchor = VAnchor . Center ;
searchButton . VAnchorChanged + = ( s , e ) = > Console . WriteLine ( ) ;
2018-01-14 10:13:42 -08:00
// Restore the last selected tab
if ( int . TryParse ( UserSettings . Instance . get ( databaseMRUKey ) , out int tabIndex )
& & tabIndex > = 0
& & tabIndex < this . TabCount - 1 )
{
this . SelectedTabIndex = tabIndex ;
}
else
{
this . SelectedTabIndex = 0 ;
}
2015-04-16 18:08:43 -07:00
2018-01-14 10:13:42 -08:00
// Store the last selected tab on change
this . ActiveTabChanged + = ( s , e ) = >
{
if ( settingsContext . IsPrimarySettingsView )
{
UserSettings . Instance . set ( databaseMRUKey , this . SelectedTabIndex . ToString ( ) ) ;
}
} ;
2018-01-18 17:59:24 -08:00
ActiveSliceSettings . SettingChanged . RegisterEvent (
( s , e ) = >
{
if ( e is StringEventArgs stringEvent )
{
string settingsKey = stringEvent . Data ;
if ( this . allUiFields . TryGetValue ( settingsKey , out UIField uifield ) )
{
string currentValue = settingsContext . GetValue ( settingsKey ) ;
if ( uifield . Value ! = currentValue
| | settingsKey = = "com_port" )
{
uifield . SetValue (
currentValue ,
userInitiated : false ) ;
}
}
}
} ,
ref unregisterEvents ) ;
2015-04-08 15:20:10 -07:00
}
2014-01-29 19:09:30 -08:00
2018-01-21 21:07:14 -08:00
private void ExtendOverflowMenu ( PopupMenu popupMenu )
{
popupMenu . CreateMenuItem ( "View Just My Settings" . Localize ( ) ) . Click + = ( s , e ) = >
{
this . FilterToOverrides ( ) ;
} ;
popupMenu . CreateHorizontalLine ( ) ;
popupMenu . CreateBoolMenuItem (
"Show Help" . Localize ( ) ,
( ) = > ApplicationController . Instance . ShowHelpControls ,
( value ) = > ApplicationController . Instance . ShowHelpControls = value ) ;
externalExtendMenu ? . Invoke ( popupMenu ) ;
}
2018-01-14 10:13:42 -08:00
public Dictionary < string , UIField > UIFields = > allUiFields ;
public FlowLayoutWidget CreateGroupContent ( SettingsOrganizer . Group group )
2017-12-27 10:15:35 -08:00
{
var groupPanel = new FlowLayoutWidget ( FlowDirection . TopToBottom )
{
VAnchor = VAnchor . Fit ,
2018-01-03 22:25:25 -08:00
HAnchor = HAnchor . Stretch ,
2018-01-14 10:13:42 -08:00
Padding = new BorderDouble ( 6 , 4 , 6 , 0 ) ,
Name = "GroupPanel" + groupPanelCount + +
2017-12-27 10:15:35 -08:00
} ;
2018-01-03 22:25:25 -08:00
2018-01-14 10:13:42 -08:00
var sectionWidget = new SectionWidget ( group . Name , groupPanel , theme ) . ApplyBoxStyle ( ) ;
2018-01-16 15:05:58 -08:00
2018-01-13 18:40:35 -08:00
foreach ( var subGroup in group . SubGroups )
2017-12-27 10:15:35 -08:00
{
2018-01-14 10:13:42 -08:00
var subGroupPanel = this . AddSettingRowsForSubgroup ( subGroup ) ;
if ( subGroupPanel ! = null )
2017-12-27 10:15:35 -08:00
{
2018-01-14 10:13:42 -08:00
if ( showSubGroupHeadings )
2017-12-27 10:15:35 -08:00
{
2018-01-14 10:13:42 -08:00
var headingColor = theme . Colors . PrimaryTextColor . AdjustLightness ( ActiveTheme . Instance . IsDarkTheme ? 0.5 : 2.8 ) . ToColor ( ) ;
2017-12-27 10:15:35 -08:00
2018-01-04 07:47:01 -08:00
// Section heading
2018-01-14 10:13:42 -08:00
groupPanel . AddChild ( new TextWidget ( " " + subGroup . Name . Localize ( ) , textColor : headingColor , pointSize : theme . FontSize10 )
2018-01-03 22:25:25 -08:00
{
2018-01-04 07:47:01 -08:00
Margin = new BorderDouble ( left : 8 , top : 6 , bottom : 4 ) ,
2018-01-03 22:25:25 -08:00
} ) ;
}
2018-01-14 10:13:42 -08:00
groupPanel . AddChild ( subGroupPanel ) ;
2017-12-27 10:15:35 -08:00
}
}
2018-01-03 22:25:25 -08:00
return sectionWidget ;
2017-12-27 10:15:35 -08:00
}
2018-01-14 10:13:42 -08:00
private GuiWidget AddSettingRowsForSubgroup ( SettingsOrganizer . SubGroup subGroup )
2017-12-27 07:49:43 -08:00
{
var topToBottomSettings = new FlowLayoutWidget ( FlowDirection . TopToBottom )
{
HAnchor = HAnchor . Stretch ,
} ;
2018-01-14 10:13:42 -08:00
topToBottomSettings . AddChild ( new HorizontalLine ( 20 ) ) ;
HorizontalLine lastLine = null ;
2017-12-27 07:49:43 -08:00
2018-01-13 18:13:29 -08:00
foreach ( SliceSettingData settingData in subGroup . Settings )
2017-12-27 07:49:43 -08:00
{
// Note: tab sections may disappear if / when they are empty, as controlled by:
// settingShouldBeShown / addedSettingToSubGroup / needToAddSubGroup
2018-01-14 10:13:42 -08:00
bool settingShouldBeShown = CheckIfShouldBeShown ( settingData , settingsContext ) ;
2017-12-27 07:49:43 -08:00
if ( EngineMappingsMatterSlice . Instance . MapContains ( settingData . SlicerConfigName )
& & settingShouldBeShown )
{
2018-01-18 17:59:24 -08:00
var settingsRow = CreateItemRow ( settingData ) ;
2018-01-14 10:36:05 -08:00
this . settingsRows . Add ( ( settingsRow , settingData ) ) ;
topToBottomSettings . AddChild ( settingsRow ) ;
2017-12-27 07:49:43 -08:00
2018-01-14 10:13:42 -08:00
topToBottomSettings . AddChild ( lastLine = new HorizontalLine ( 20 )
2017-12-27 07:49:43 -08:00
{
Margin = 0
} ) ;
2018-01-14 10:36:05 -08:00
if ( ApplicationController . Instance . ShowHelpControls )
2017-12-27 07:49:43 -08:00
{
topToBottomSettings . AddChild ( AddInHelpText ( topToBottomSettings , settingData ) ) ;
}
}
}
2018-01-14 10:13:42 -08:00
lastLine ? . Close ( ) ;
2017-12-27 07:49:43 -08:00
return ( topToBottomSettings . Children . Count = = 1 ) ? null : topToBottomSettings ;
}
2018-01-14 10:13:42 -08:00
private static bool CheckIfShouldBeShown ( SliceSettingData settingData , SettingsContext settingsContext )
2016-08-11 16:09:45 -07:00
{
2017-08-28 11:27:38 +03:00
bool settingShouldBeShown = settingsContext . ParseShowString ( settingData . ShowIfSet ) ;
2017-09-03 18:28:15 +03:00
if ( settingsContext . ViewFilter = = NamedSettingsLayers . Material | | settingsContext . ViewFilter = = NamedSettingsLayers . Quality )
2016-06-08 09:25:20 -07:00
{
2016-06-08 11:18:53 -07:00
if ( ! settingData . ShowAsOverride )
2016-06-08 09:25:20 -07:00
{
settingShouldBeShown = false ;
}
}
2016-04-20 11:53:08 -07:00
return settingShouldBeShown ;
}
2018-01-14 10:13:42 -08:00
private static GuiWidget AddInHelpText ( FlowLayoutWidget topToBottomSettings , SliceSettingData settingData )
2015-04-08 15:20:10 -07:00
{
2016-05-06 17:56:27 -07:00
double textRegionWidth = 380 * GuiWidget . DeviceScale ;
2015-04-08 15:20:10 -07:00
double helpPointSize = 10 ;
2017-12-29 09:14:17 -08:00
var allText = new FlowLayoutWidget ( FlowDirection . TopToBottom )
{
HAnchor = HAnchor . Stretch ,
Margin = new BorderDouble ( 0 ) ,
Padding = new BorderDouble ( 5 ) ,
} ;
allText . AddChild (
new WrappedTextWidget ( settingData . HelpText , pointSize : helpPointSize , textColor : Color . White )
{
Width = textRegionWidth ,
Margin = new BorderDouble ( 5 , 0 , 0 , 0 )
} ) ;
2015-04-08 15:20:10 -07:00
2017-10-31 12:51:16 -07:00
allText . MinimumSize = new Vector2 ( 0 , allText . MinimumSize . Y ) ;
2016-04-26 15:10:51 -07:00
return allText ;
2015-04-08 15:20:10 -07:00
}
2017-08-28 11:27:38 +03:00
// Creates an information row showing the base OEM profile and its create_date value
2018-01-14 10:13:42 -08:00
public GuiWidget CreateOemProfileInfoRow ( )
2016-07-15 11:52:06 -07:00
{
var dataArea = new FlowLayoutWidget ( FlowDirection . TopToBottom )
{
2017-08-07 15:47:27 -07:00
HAnchor = HAnchor . Stretch ,
2016-07-15 11:52:06 -07:00
} ;
2017-08-28 11:27:38 +03:00
if ( isPrimarySettingsView )
2016-07-18 14:59:14 -07:00
{
2017-02-28 15:56:10 -08:00
// OEM_LAYER_DATE:
string lastUpdateTime = "March 1, 2016" ;
if ( ActiveSliceSettings . Instance ? . OemLayer ! = null )
2016-07-28 16:37:24 -07:00
{
2017-02-28 15:56:10 -08:00
string fromCreatedDate = ActiveSliceSettings . Instance . OemLayer . ValueOrDefault ( SettingsKey . created_date ) ;
try
{
if ( ! string . IsNullOrEmpty ( fromCreatedDate ) )
{
DateTime time = Convert . ToDateTime ( fromCreatedDate ) . ToLocalTime ( ) ;
lastUpdateTime = time . ToString ( "MMMM d, yyyy h:mm tt" ) ;
}
}
catch
2016-07-28 16:37:24 -07:00
{
}
}
2017-02-28 15:56:10 -08:00
var row = new FlowLayoutWidget ( )
2016-07-28 16:37:24 -07:00
{
2017-02-28 15:56:10 -08:00
BackgroundColor = ActiveTheme . Instance . TertiaryBackgroundColor ,
Padding = new BorderDouble ( 5 ) ,
Margin = new BorderDouble ( 3 , 20 , 3 , 0 ) ,
2017-09-07 21:04:21 -07:00
HAnchor = HAnchor . Stretch ,
2017-02-28 15:56:10 -08:00
} ;
2017-09-17 01:11:18 -07:00
string make = settingsContext . GetValue ( SettingsKey . make ) ;
string model = settingsContext . GetValue ( SettingsKey . model ) ;
2017-02-28 15:56:10 -08:00
string title = $"{make} {model}" ;
if ( title = = "Other Other" )
2016-07-28 16:37:24 -07:00
{
2017-02-28 15:56:10 -08:00
title = "Custom Profile" . Localize ( ) ;
2016-07-28 16:37:24 -07:00
}
2016-07-18 14:59:14 -07:00
2017-02-28 15:56:10 -08:00
row . AddChild ( new TextWidget ( title , pointSize : 9 )
{
Margin = new BorderDouble ( 0 , 4 , 10 , 4 ) ,
TextColor = ActiveTheme . Instance . PrimaryTextColor ,
} ) ;
2016-07-28 12:19:30 -07:00
2017-02-28 15:56:10 -08:00
row . AddChild ( new HorizontalSpacer ( ) ) ;
row . AddChild ( new TextWidget ( lastUpdateTime , pointSize : 9 )
{
Margin = new BorderDouble ( 0 , 4 , 10 , 4 ) ,
TextColor = ActiveTheme . Instance . PrimaryTextColor ,
} ) ;
dataArea . AddChild ( row ) ;
}
2016-07-15 11:52:06 -07:00
return dataArea ;
}
2018-01-14 10:13:42 -08:00
2018-01-18 17:59:24 -08:00
internal GuiWidget CreateItemRow ( SliceSettingData settingData )
2017-12-11 22:22:56 -08:00
{
2018-01-12 12:57:53 -08:00
return CreateItemRow ( settingData , settingsContext , printer , theme . Colors . PrimaryTextColor , theme , ref tabIndexForItem , allUiFields ) ;
2017-12-11 22:22:56 -08:00
}
2018-01-12 12:57:53 -08:00
public static GuiWidget CreateItemRow ( SliceSettingData settingData , SettingsContext settingsContext , PrinterConfig printer , Color textColor , ThemeConfig theme , ref int tabIndexForItem , Dictionary < string , UIField > fieldCache = null )
2016-04-18 11:31:31 -07:00
{
2017-08-28 11:27:38 +03:00
string sliceSettingValue = settingsContext . GetValue ( settingData . SlicerConfigName ) ;
2016-04-26 17:15:10 -07:00
2017-09-13 06:59:30 -07:00
UIField uiField = null ;
2016-05-07 21:05:53 -07:00
2017-09-04 23:49:05 +03:00
bool useDefaultSavePattern = true ;
2017-09-13 06:10:24 -07:00
bool placeFieldInDedicatedRow = false ;
2017-09-04 23:49:05 +03:00
2017-12-29 09:14:17 -08:00
var settingsRow = new SliceSettingsRow ( printer , settingsContext , settingData , textColor )
2016-04-18 11:31:31 -07:00
{
2018-01-14 10:13:42 -08:00
Padding = new BorderDouble ( left : 6 ) ,
2017-09-07 16:21:06 -07:00
HAnchor = HAnchor . Stretch ,
VAnchor = VAnchor . Fit
2016-04-18 11:31:31 -07:00
} ;
2017-08-29 14:03:02 +03:00
2016-07-18 15:20:19 -07:00
if ( ! PrinterSettings . KnownSettings . Contains ( settingData . SlicerConfigName ) )
2016-04-18 11:31:31 -07:00
{
2016-06-13 12:31:17 -07:00
// the setting we think we are adding is not in the known settings it may have been deprecated
TextWidget settingName = new TextWidget ( String . Format ( "Setting '{0}' not found in known settings" , settingData . SlicerConfigName ) ) ;
2017-12-29 09:14:17 -08:00
settingName . TextColor = textColor ;
2017-09-04 10:52:56 +03:00
settingsRow . NameArea . AddChild ( settingName ) ;
2017-10-31 11:43:25 -07:00
settingsRow . NameArea . BackgroundColor = Color . Red ;
2016-04-18 11:31:31 -07:00
}
else
2015-04-08 15:20:10 -07:00
{
2017-09-13 06:10:24 -07:00
settingsRow . NameArea . AddChild (
2017-12-29 09:14:17 -08:00
CreateSettingsLabel ( settingData . PresentationName . Localize ( ) , settingData . HelpText , textColor ) ) ;
2015-05-20 12:43:01 -07:00
2015-04-08 15:20:10 -07:00
switch ( settingData . DataEditType )
{
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . INT :
2018-01-13 11:38:46 -08:00
var intField = new IntField ( ) ;
uiField = intField ;
if ( settingData . SlicerConfigName = = "extruder_count" )
{
intField . MaxValue = 4 ;
intField . MinValue = 0 ;
}
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . DOUBLE :
2017-09-01 12:25:19 +03:00
case SliceSettingData . DataEditTypes . OFFSET :
uiField = new DoubleField ( ) ;
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . POSITIVE_DOUBLE :
2017-09-05 14:10:31 +03:00
if ( settingData . SetSettingsOnChange . Count > 0 )
{
uiField = new BoundDoubleField ( settingsContext , settingData ) ;
}
else
{
2017-09-14 22:13:29 -07:00
uiField = new PositiveDoubleField ( ) ;
2017-09-07 08:04:41 -07:00
} ;
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . DOUBLE_OR_PERCENT :
2017-09-01 12:25:19 +03:00
uiField = new DoubleOrPercentField ( ) ;
2015-04-24 13:09:25 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . INT_OR_MM :
2017-09-15 13:43:50 -07:00
uiField = new IntOrMmField ( ) ;
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . CHECK_BOX :
2017-12-29 09:14:17 -08:00
uiField = new ToggleboxField ( textColor ) ;
2017-09-04 23:49:05 +03:00
useDefaultSavePattern = false ;
2017-09-01 12:25:19 +03:00
uiField . ValueChanged + = ( s , e ) = >
{
2017-09-04 23:49:05 +03:00
if ( e . UserInitiated )
2017-09-01 12:25:19 +03:00
{
2017-09-04 23:49:05 +03:00
// Linked settings should be updated in all cases (user clicked checkbox, user clicked clear)
foreach ( var setSettingsData in settingData . SetSettingsOnChange )
2017-09-01 12:25:19 +03:00
{
2017-09-04 23:49:05 +03:00
string targetValue ;
if ( uiField . Content is CheckBox checkbox )
2017-09-01 12:25:19 +03:00
{
2017-09-04 23:49:05 +03:00
if ( setSettingsData . TryGetValue ( checkbox . Checked ? "OnValue" : "OffValue" , out targetValue ) )
{
settingsContext . SetValue ( setSettingsData [ "TargetSetting" ] , targetValue ) ;
}
2017-09-01 12:25:19 +03:00
}
}
2017-09-07 08:41:19 -07:00
// Store actual field value
settingsContext . SetValue ( settingData . SlicerConfigName , uiField . Value ) ;
2017-09-01 12:25:19 +03:00
}
} ;
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . STRING :
2018-01-18 17:03:05 -08:00
case SliceSettingData . DataEditTypes . WIDE_STRING :
2017-09-01 12:25:19 +03:00
uiField = new TextField ( ) ;
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . MULTI_LINE_TEXT :
2017-09-04 23:49:05 +03:00
uiField = new MultilineStringField ( ) ;
2017-09-13 06:10:24 -07:00
placeFieldInDedicatedRow = true ;
2015-04-08 15:20:10 -07:00
break ;
2017-09-12 15:35:38 -07:00
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . COM_PORT :
2017-09-04 23:49:05 +03:00
useDefaultSavePattern = false ;
2017-09-05 14:10:31 +03:00
2017-09-21 15:59:23 -07:00
sliceSettingValue = printer . Settings . Helpers . ComPort ( ) ;
2018-01-12 12:57:53 -08:00
uiField = new ComPortField ( printer , theme ) ;
2017-09-04 13:19:20 +03:00
uiField . ValueChanged + = ( s , e ) = >
{
2017-09-04 23:49:05 +03:00
if ( e . UserInitiated )
{
2017-09-21 15:59:23 -07:00
printer . Settings . Helpers . SetComPort ( uiField . Value ) ;
2017-09-04 23:49:05 +03:00
}
2017-09-04 13:19:20 +03:00
} ;
2016-05-02 16:10:20 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . LIST :
2017-09-04 13:30:56 +03:00
uiField = new ListField ( )
{
2017-11-08 08:36:46 -08:00
ListItems = settingData . ListValues . Split ( ',' ) . ToList ( )
2017-09-04 13:30:56 +03:00
} ;
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . HARDWARE_PRESENT :
2017-12-29 09:14:17 -08:00
uiField = new ToggleboxField ( textColor ) ;
2015-04-08 15:20:10 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . VECTOR2 :
2017-09-04 13:48:35 +03:00
uiField = new Vector2Field ( ) ;
2016-04-18 11:31:31 -07:00
break ;
2016-06-13 13:44:53 -07:00
case SliceSettingData . DataEditTypes . OFFSET2 :
2017-09-14 08:54:04 -07:00
placeFieldInDedicatedRow = true ;
2017-12-29 09:14:17 -08:00
uiField = new ExtruderOffsetField ( settingsContext , settingData . SlicerConfigName , textColor ) ;
2015-04-08 15:20:10 -07:00
break ;
2017-12-23 18:49:31 -08:00
#if ! __ANDROID__
2017-12-15 17:52:17 -08:00
case SliceSettingData . DataEditTypes . IP_LIST :
uiField = new IpAddessField ( printer ) ;
break ;
2017-12-23 18:49:31 -08:00
#endif
2015-04-08 15:20:10 -07:00
default :
2017-09-04 10:52:56 +03:00
// Missing Setting
settingsRow . AddContent ( new TextWidget ( String . Format ( "Missing the setting for '{0}'." , settingData . DataEditType . ToString ( ) ) )
2016-04-18 11:31:31 -07:00
{
2017-12-29 09:14:17 -08:00
TextColor = textColor ,
2017-10-31 11:43:25 -07:00
BackgroundColor = Color . Red
2017-09-04 10:52:56 +03:00
} ) ;
2015-04-08 15:20:10 -07:00
break ;
}
}
2014-07-26 13:43:55 -07:00
2017-08-30 00:55:13 -07:00
if ( uiField ! = null )
{
2017-12-11 22:22:56 -08:00
if ( fieldCache ! = null )
{
fieldCache [ settingData . SlicerConfigName ] = uiField ;
}
2017-08-30 00:55:13 -07:00
2017-11-02 12:10:06 -07:00
uiField . HelpText = settingData . HelpText ;
2017-09-14 14:47:08 -07:00
uiField . Name = $"{settingData.PresentationName} Field" ;
2017-08-30 00:55:13 -07:00
uiField . Initialize ( tabIndexForItem + + ) ;
2018-01-18 17:03:05 -08:00
if ( settingData . DataEditType = = SliceSettingData . DataEditTypes . WIDE_STRING )
{
uiField . Content . HAnchor = HAnchor . Stretch ;
placeFieldInDedicatedRow = true ;
}
2017-09-04 23:49:05 +03:00
uiField . SetValue ( sliceSettingValue , userInitiated : false ) ;
2017-08-30 00:55:13 -07:00
2017-09-01 12:25:19 +03:00
uiField . ValueChanged + = ( s , e ) = >
{
2017-09-04 23:49:05 +03:00
if ( useDefaultSavePattern
& & e . UserInitiated )
{
settingsContext . SetValue ( settingData . SlicerConfigName , uiField . Value ) ;
}
2017-09-01 12:25:19 +03:00
settingsRow . UpdateStyle ( ) ;
} ;
2017-08-30 00:55:13 -07:00
// After initializing the field, wrap with dropmenu if applicable
2018-01-31 16:06:51 -08:00
if ( settingData . QuickMenuSettings . Count > 0
& & settingData . SlicerConfigName = = "baud_rate" )
2018-01-31 16:01:16 -08:00
{
var dropMenu = new DropMenuWrappedField ( uiField , settingData , textColor ) ;
dropMenu . Initialize ( tabIndexForItem ) ;
settingsRow . AddContent ( dropMenu . Content ) ;
}
else
2017-09-13 06:10:24 -07:00
{
if ( ! placeFieldInDedicatedRow )
{
settingsRow . AddContent ( uiField . Content ) ;
}
}
2017-08-30 00:55:13 -07:00
}
2016-04-18 11:31:31 -07:00
// Invoke the UpdateStyle implementation
2016-05-07 21:05:53 -07:00
settingsRow . UpdateStyle ( ) ;
2016-04-26 17:15:10 -07:00
2017-11-16 09:56:16 -08:00
bool settingEnabled = settingsContext . ParseShowString ( settingData . EnableIfSet ) ;
if ( settingEnabled
2018-01-14 10:13:42 -08:00
| | settingsContext . ViewFilter = = NamedSettingsLayers . Material
2017-11-16 09:56:16 -08:00
| | settingsContext . ViewFilter = = NamedSettingsLayers . Quality )
2017-09-04 10:52:56 +03:00
{
2017-09-13 06:10:24 -07:00
if ( placeFieldInDedicatedRow )
{
2017-09-13 18:18:11 -07:00
var column = new FlowLayoutWidget ( FlowDirection . TopToBottom )
2017-09-13 06:10:24 -07:00
{
2017-09-13 18:18:11 -07:00
Name = "column" ,
2017-09-13 06:10:24 -07:00
HAnchor = HAnchor . Stretch ,
VAnchor = VAnchor . Fit
} ;
2017-09-13 18:18:11 -07:00
column . AddChild ( settingsRow ) ;
2017-09-13 06:10:24 -07:00
2017-09-13 18:18:11 -07:00
var row = new FlowLayoutWidget ( )
2017-09-13 06:10:24 -07:00
{
2017-09-13 18:18:11 -07:00
Name = "row" ,
2017-09-13 06:10:24 -07:00
VAnchor = VAnchor . Fit ,
HAnchor = HAnchor . Stretch ,
2017-11-17 17:46:58 -08:00
MinimumSize = new Vector2 ( 0 , 28 ) ,
2017-11-17 17:07:04 -08:00
BackgroundColor = settingsRow . BackgroundColor ,
2017-11-17 17:46:58 -08:00
Border = settingsRow . Border ,
Padding = settingsRow . Padding ,
Margin = settingsRow . Margin ,
2017-09-13 06:10:24 -07:00
} ;
2017-09-13 18:18:11 -07:00
column . AddChild ( row ) ;
2017-09-13 06:10:24 -07:00
2017-09-13 18:18:11 -07:00
var contentWrapper = new GuiWidget
2017-09-13 06:10:24 -07:00
{
2017-09-13 18:18:11 -07:00
Name = "contentWrapper" ,
2017-09-13 06:10:24 -07:00
HAnchor = HAnchor . Stretch ,
VAnchor = VAnchor . Fit ,
Padding = new BorderDouble ( right : 16 , bottom : 10 ) ,
} ;
2017-09-13 18:18:11 -07:00
contentWrapper . AddChild ( uiField . Content ) ;
2017-09-13 06:10:24 -07:00
2017-09-13 18:18:11 -07:00
row . AddChild ( contentWrapper ) ;
2017-09-13 06:10:24 -07:00
settingsRow . StyleChanged + = ( s , e ) = >
{
2017-09-13 18:18:11 -07:00
row . BackgroundColor = settingsRow . BackgroundColor ;
2017-11-17 17:07:04 -08:00
row . BorderColor = settingsRow . HighlightColor ;
2017-09-13 06:10:24 -07:00
} ;
2017-09-13 18:18:11 -07:00
return column ;
2017-09-13 06:10:24 -07:00
}
else
{
return settingsRow ;
}
2017-09-04 10:52:56 +03:00
}
else
2017-08-02 15:19:32 -07:00
{
2018-01-14 10:36:05 -08:00
settingsRow . Enabled = false ;
return settingsRow ;
2017-09-14 08:55:30 -07:00
}
}
2017-12-29 09:14:17 -08:00
public static GuiWidget CreateSettingsLabel ( string label , string helpText , Color textColor )
2017-09-14 13:29:58 -07:00
{
2017-12-29 09:14:17 -08:00
return new WrappedTextWidget ( label , pointSize : 10 , textColor : textColor )
2017-09-14 13:29:58 -07:00
{
2017-11-17 16:49:02 -08:00
VAnchor = VAnchor . Center | VAnchor . Fit ,
2017-09-14 13:29:58 -07:00
ToolTipText = helpText ,
2017-11-21 13:39:49 -08:00
Margin = new BorderDouble ( 0 , 5 , 5 , 5 ) ,
2017-09-14 13:29:58 -07:00
} ;
}
2018-01-14 10:36:05 -08:00
public void FilterToOverrides ( )
{
var defaultCascade = printer . Settings . defaultLayerCascade ;
2018-01-31 17:23:05 -08:00
var baseAndOem = new List < PrinterSettingsLayer > ( ) { printer . Settings . OemLayer , printer . Settings . BaseLayer } ;
2018-01-14 10:36:05 -08:00
foreach ( var item in this . settingsRows )
{
var settingData = item . settingData ;
var ( currentValue , layerName ) = printer . Settings . GetValueAndLayerName ( settingData . SlicerConfigName , defaultCascade ) ;
item . widget . Visible = layerName ! = "Oem" & & layerName ! = "Base" ;
2018-01-31 17:23:05 -08:00
if ( layerName = = "User"
& & currentValue = = printer . Settings . GetValueAndLayerName ( settingData . SlicerConfigName , baseAndOem ) . currentValue )
{
item . widget . Visible = false ;
item . widget . Visible = true ;
item . widget . Visible = false ;
}
2018-01-14 10:36:05 -08:00
}
filteredItemsHeading . Visible = true ;
searchPanel . searchInput . Visible = false ;
this . TabBar . Visible = false ;
searchPanel . Visible = true ;
this . ShowFilteredView ( ) ;
}
2018-01-31 15:10:38 -08:00
List < SectionWidget > widgetsThatWereExpanded = new List < SectionWidget > ( ) ;
2018-01-14 10:36:05 -08:00
private void ShowFilteredView ( )
{
2018-01-31 15:10:38 -08:00
widgetsThatWereExpanded . Clear ( ) ;
2018-01-14 10:36:05 -08:00
// Show any section with visible SliceSettingsRows
foreach ( var section in this . Descendants < SectionWidget > ( ) )
{
// HACK: Include parent visibility in mix as complex fields that return wrapped SliceSettingsRows will be visible and their parent will be hidden
section . Visible = section . Descendants < SliceSettingsRow > ( ) . Any ( row = > row . Visible & & row . Parent . Visible ) ;
2018-01-31 15:10:38 -08:00
if ( ! section . Checkbox . Checked )
{
widgetsThatWereExpanded . Add ( section ) ;
section . Checkbox . Checked = true ;
}
2018-01-14 10:36:05 -08:00
}
// Show all tab containers
foreach ( var tab in this . AllTabs )
{
tab . TabContent . Visible = true ;
}
}
2018-01-18 17:59:24 -08:00
public override void OnClosed ( ClosedEventArgs e )
{
unregisterEvents ? . Invoke ( this , null ) ;
base . OnClosed ( e ) ;
}
2018-01-14 10:36:05 -08:00
public void ClearFilter ( )
{
foreach ( var item in this . settingsRows )
{
// Show matching items
item . widget . Visible = true ;
}
foreach ( var tab in this . AllTabs )
{
tab . TabContent . Visible = ( tab = = this . ActiveTab ) ;
}
foreach ( var section in this . Descendants < SectionWidget > ( ) )
{
// HACK: Include parent visibility in mix as complex fields that return wrapped SliceSettingsRows will be visible and their parent will be hidden
section . Visible = section . Descendants < SliceSettingsRow > ( ) . Any ( row = > row . Visible & & row . Parent . Visible ) ;
}
2018-01-31 15:10:38 -08:00
foreach ( var section in widgetsThatWereExpanded )
{
section . Checkbox . Checked = false ;
}
2018-01-14 10:36:05 -08:00
this . TabBar . Visible = true ;
}
2015-04-08 15:20:10 -07:00
}
2016-08-10 15:18:03 -07:00
}