コード例 #1
0
 public MuseumStoryLayout(IEmbeddedResources embeddedResources, IWorldTreeService worldTreeService)
 {
     this.worldTreeService = worldTreeService;
     floorModel            = embeddedResources.PlaneModel(PlaneModelSourcePlane.Xy, PlaneModelSourceNormalDirection.Positive,
                                                          globalRadius, globalRadius, 1, 1);
     ceilingModel = embeddedResources.PlaneModel(PlaneModelSourcePlane.Xy, PlaneModelSourceNormalDirection.Negative,
                                                 globalRadius, globalRadius, 1, 1);
     exitWallModel = embeddedResources.PlaneModel(PlaneModelSourcePlane.Xz, PlaneModelSourceNormalDirection.Negative,
                                                  exitHalfLength, ceilingHalfHeight, 1, 1);
     corridorWallModel = embeddedResources.PlaneModel(PlaneModelSourcePlane.Xz, PlaneModelSourceNormalDirection.Negative,
                                                      corridorHalfWidth, ceilingHalfHeight, 1, 1);
     frustumModel  = embeddedResources.SimpleFrustumModel();
     floorMaterial = StandardMaterial.New()
                     .SetDiffuseMap(embeddedResources.Image("Textures/museum_floor.jpg"))
                     .SetNoSpecular(true)
                     .FromGlobalCache();
     ceilingMaterial = StandardMaterial.New()
                       .SetDiffuseMap(embeddedResources.Image("Textures/museum_ceiling.jpg"))
                       .SetNoSpecular(true)
                       .FromGlobalCache();
     wallMaterial = StandardMaterial.New()
                    .SetDiffuseMap(embeddedResources.Image("Textures/museum_wall.jpg"))
                    .SetNoSpecular(true)
                    .FromGlobalCache();
     frustumMaterial = StandardMaterial.New()
                       .SetDiffuseColor(Color4.Green)
                       .SetIgnoreLighting(true)
                       .FromGlobalCache();
 }
コード例 #2
0
        public SceneTreeGui(IEventRoutingService eventRoutingService, IWorldTreeService worldTreeService, IViewService viewService,
                            IPresentationGuiCommands commands, ICommonGuiObjects commonGuiObjects)
        {
            itemIndex             = new Dictionary <ISceneNode, TreeItem>();
            this.worldTreeService = worldTreeService;
            this.viewService      = viewService;
            this.commands         = commands;

            eyeIcon    = Icon.FromResource("Clarity.Ext.Gui.EtoForms.Resources.eye_icon.ico");
            sceneIcon  = Icon.FromResource("Clarity.Ext.Gui.EtoForms.Resources.scene_icon.ico");
            viewIcon   = Icon.FromResource("Clarity.Ext.Gui.EtoForms.Resources.view_icon.ico");
            layoutIcon = Icon.FromResource("Clarity.Ext.Gui.EtoForms.Resources.layout_icon.ico");
            entityIcon = Icon.FromResource("Clarity.Ext.Gui.EtoForms.Resources.entity_icon.ico");
            whiteIcon  = Icon.FromResource("Clarity.Ext.Gui.EtoForms.Resources.white_icon.ico");

            rootItem = new TreeItem {
                Text = "GuiRoot", Expanded = true
            };
            treeView = new TreeView
            {
                Width       = 250,
                DataStore   = rootItem,
                ContextMenu = commonGuiObjects.SelectionContextMenu
            };
            //RebuildFromRoot();
            eventRoutingService.RegisterServiceDependency(typeof(ISceneTreeGui), typeof(IWorldTreeService));
            eventRoutingService.Subscribe <IWorldTreeUpdatedEvent>(typeof(ISceneTreeGui), nameof(OnWorldUpdated), OnWorldUpdated);
            eventRoutingService.Subscribe <IAppModeChangedEvent>(typeof(ISceneTreeGui), nameof(OnAppModeChanged), OnAppModeChanged);
            treeView.SelectionChanged += OnSelectionChanged;
            treeView.NodeMouseClick   += OnNodeMouseClick;
            treeView.MouseDoubleClick += OnNodeMouseDoubleClick;

            viewService.Update += OnViewServiceUpdate;
        }
コード例 #3
0
 public DirtyHackService(IWorldTreeService worldTreeService, IAppModeService appModeService,
                         IReadOnlyList <IStoryLayout> storyLayouts, IEmbeddedResources embeddedResources)
 {
     this.worldTreeService  = worldTreeService;
     this.appModeService    = appModeService;
     this.storyLayouts      = storyLayouts;
     this.embeddedResources = embeddedResources;
 }
コード例 #4
0
 public DefaultFileLoadInfo(string filePath, IAssetService assetService, IWorldTreeService worldTreeService, LoadWorldPreference worldPreference)
 {
     FileSystem            = new ActualFileSystem();
     FilePath              = filePath;
     this.assetService     = assetService;
     this.worldTreeService = worldTreeService;
     this.worldPreference  = worldPreference;
 }
コード例 #5
0
ファイル: WindowManager.cs プロジェクト: Zulkir/ClarityWorlds
 public WindowManager(IMainForm mainForm, IEventRoutingService eventRoutingService, IWorldTreeService worldTreeService, IViewService viewService)
 {
     this.mainForm         = mainForm;
     this.worldTreeService = worldTreeService;
     this.viewService      = viewService;
     renderControls        = new IRenderGuiControl[] { mainForm.RenderControl };
     eventRoutingService.RegisterServiceDependency(typeof(IWindowManager), typeof(IWorldTreeService));
     eventRoutingService.Subscribe <IAppModeChangedEvent>(typeof(IWindowManager), nameof(OnAppModeChanged), OnAppModeChanged);
     eventRoutingService.SubscribeToAllAfter(typeof(IWindowManager).FullName, OnEveryEvent, true);
 }
コード例 #6
0
        public PropsGuiGroupStoryComponent(IUndoRedoService undoRedo, IReadOnlyList <IStoryLayout> storyLayouts, IWorldTreeService worldTreeService, IStoryService storyService)
        {
            this.undoRedo         = undoRedo;
            this.storyService     = storyService;
            this.worldTreeService = worldTreeService;

            cDefaultAdaptiveStyle = new DropDown();
            typeDict = storyLayouts.ToDictionary(x => x.UserFriendlyName, x => x.Type);
            typeDict.Add("none", null);
            cDefaultAdaptiveStyle.DataStore             = typeDict.Keys;
            cDefaultAdaptiveStyle.SelectedValueChanged += OnDefaultAdaptiveStyleChanged;

            cShowAux1 = new CheckBox {
                Text = "Aux1"
            };
            cShowAux2 = new CheckBox {
                Text = "Aux2"
            };

            cShowAux1.CheckedChanged += OnShowAux1Changed;
            cShowAux2.CheckedChanged += OnShowAux2Changed;

            cExplicitConnections = new GroupBox
            {
                Text = "Explicit Connections"
            };

            var cRedecorate = new Button {
                Text = "Redecorate"
            };

            cRedecorate.Click += (s, a) =>
            {
                storyService.OnBeginTransaction(this);
                storyService.OnEndTransaction(this);
            };

            var layout = new TableLayout(
                new TableRow(new Label {
                Text = "Default Adaptive Style"
            }, cDefaultAdaptiveStyle),
                new TableRow(cShowAux1, cShowAux2),
                new TableRow(cExplicitConnections),
                new TableRow(cRedecorate))
            {
                Padding = new Padding(5),
                Spacing = new Size(5, 5),
            };

            GroupBox = new GroupBox
            {
                Text    = "Story",
                Content = layout
            };
        }
コード例 #7
0
 public TutorialScenarioOld(IWorldTreeService worldTreeService, INavigationService navigationService, IVrInputDispatcher vrInputDispatcher,
                            IGlobalObjectService globalObjectService, IVrHeadPositionService headPositionService)
 {
     this.worldTreeService    = worldTreeService;
     this.navigationService   = navigationService;
     this.vrInputDispatcher   = vrInputDispatcher;
     this.globalObjectService = globalObjectService;
     this.headPositionService = headPositionService;
     cleanUpList  = new List <GameObject>();
     stageRoomIds = new int[6];
 }
コード例 #8
0
 public TutorialScenario(IWorldTreeService worldTreeService, IVrInputDispatcher inputDispatcher,
                         INavigationService navigationService, ICoroutineService coroutineService, IGlobalObjectService globalObjectService,
                         IVrManipulationService manipulationService)
 {
     this.worldTreeService    = worldTreeService;
     this.inputDispatcher     = inputDispatcher;
     this.navigationService   = navigationService;
     this.coroutineService    = coroutineService;
     this.globalObjectService = globalObjectService;
     this.manipulationService = manipulationService;
 }
コード例 #9
0
 public DefaultStateInitializer(IViewService viewService, IWorldTreeService worldTreeService, Lazy <IAppModeService> appModeServiceLazy,
                                ICommonNodeFactory commonNodeFactory, IAmDiBasedObjectFactory objectFactory, IStoryService storyService, IGui gui)
 {
     this.viewService        = viewService;
     this.worldTreeService   = worldTreeService;
     this.appModeServiceLazy = appModeServiceLazy;
     this.commonNodeFactory  = commonNodeFactory;
     this.objectFactory      = objectFactory;
     this.storyService       = storyService;
     this.gui = gui;
 }
コード例 #10
0
 public SaveLoadService(IEventRoutingService eventRoutingService, IWorldTreeService worldTreeService,
                        Lazy <IDefaultStateInitializer> defaultStateInitializerLazy, IAssetService assetService,
                        IEventRoutingService eventRoutingService1, IReadOnlyWorldBuilder readOnlyWorldBuilder, IMessageBoxService messageBoxService)
 {
     this.eventRoutingService         = eventRoutingService1;
     this.readOnlyWorldBuilder        = readOnlyWorldBuilder;
     this.messageBoxService           = messageBoxService;
     this.defaultStateInitializerLazy = defaultStateInitializerLazy;
     this.worldTreeService            = worldTreeService;
     this.assetService = assetService;
     eventRoutingService.Subscribe <IWorldTreeUpdatedEvent>(typeof(ISaveLoadService), nameof(OnWorldTreeUpdated), OnWorldTreeUpdated);
     // todo: on asset changes
 }
コード例 #11
0
 public StoryService(IEventRoutingService eventRoutingService, IWorldTreeService worldTreeService, IRenderLoopDispatcher renderLoopDispatcher, IReadOnlyList <IStoryLayout> allLayouts)
 {
     this.worldTreeService = worldTreeService;
     layoutsByType         = allLayouts.ToDictionary(x => x.Type, x => x);
     layouts      = new Dictionary <ISceneNode, IStoryLayout>();
     transactions = new List <object>();
     editingScene = Scene.Create(AmFactory.Create <SceneNode>());
     editingScene.BackgroundColor = Color4.Black;
     editSceneComponent           = AmFactory.Create <StoryFlowchartEditSceneComponent>();
     editingScene.Root.Components.Add(editSceneComponent);
     eventRoutingService.RegisterServiceDependency(typeof(IStoryService), typeof(IWorldTreeService));
     eventRoutingService.Subscribe <IWorldTreeUpdatedEvent>(typeof(IStoryService), nameof(OnWorldUpdated), OnWorldUpdated);
     renderLoopDispatcher.Update += editingScene.Root.Update;
 }
コード例 #12
0
ファイル: StoryGraphGui.cs プロジェクト: Zulkir/ClarityWorlds
 public StoryGraphGui(IViewService viewService, IStoryService storyService, IWorldTreeService worldTreeService)
 {
     ViewStoryGraphCommand = new Command(
         (s, a) =>
     {
         viewService.MainView.FocusOn((viewService.MainView.FocusNode.Scene != storyService.EditingScene
                 ? storyService.EditingScene.Root
                 : worldTreeService.MainRoot).GetComponent <IFocusNodeComponent>());
     })
     {
         MenuText    = "Story &Graph",
         ToolBarText = "Story &Graph",
         Shortcut    = Keys.F4
     };
 }
コード例 #13
0
        public UndoRedoService(IWorldTreeService worldTreeService, IAssetService assetService, ISerializationNecessities serializationNecessities, ITrwDiffBuilder diffBuilder)
        {
            this.worldTreeService = worldTreeService;
            this.diffBuilder      = diffBuilder;
            var handlers      = serializationNecessities.GetTrwHandlerContainer(SaveLoadConstants.WorldSerializationType);
            var typeRedirects = serializationNecessities.GetTrwHandlerTypeRedirects(SaveLoadConstants.WorldSerializationType);

            diffApplier = new TrwSerializationDiffApplier(handlers, typeRedirects,
                                                          x => x.Add(SaveLoadConstants.AssetDictBagKey, new Dictionary <string, IAsset>()),
                                                          x => x.Add(SaveLoadConstants.AssetDictBagKey, assetService.Assets));
            diffIdentityComparer = new UndoRedoDiffIdentityComparer();
            undoStack            = new Stack <IUndoable>();
            redoStack            = new Stack <IUndoable>();
            guiObserver          = null;
        }
コード例 #14
0
ファイル: PropsGui.cs プロジェクト: Zulkir/ClarityWorlds
        public PropsGui(IViewService viewService, IUndoRedoService undoRedo, IAssetService assetService, IWorldTreeService worldTreeService,
                        IReadOnlyList <IStoryLayout> storyLayouts, IStoryService storyService, IEmbeddedResources embeddedResources, IWindowQueryService windowQueryService,
                        IMovieUrlLoader movieUrlLoader)
        {
            this.viewService = viewService;

            PropsPanel = new Panel
            {
                Content = new TableLayout(),
                Width   = 250,
                Height  = 300
            };

            groups = new IPropsGuiGroup[]
            {
                new PropsGuiGroupCommon(undoRedo),
                new PropsGuiGroupFluidSimulation(undoRedo),
                new PropsGuiGroupStoryComponent(undoRedo, storyLayouts, worldTreeService, storyService),
                new PropsGuiGroupMovieRectangle(undoRedo, assetService, windowQueryService, movieUrlLoader),
                new PropsGuiGroupHighlightOnMouse(undoRedo),
                new PropsGuiGroupComponents(undoRedo),
            };

            viewService.Update += OnViewServiceUpdate;
        }
コード例 #15
0
        public FluentGuiService(IViewService viewService, IRenderLoopDispatcher renderLoopDispatcher,
                                IAssetService assetService, IUndoRedoService undoRedo, IEmbeddedResources embeddedResources,
                                IReadOnlyList <IStoryLayout> storyLayouts,
                                // todo: refactor away from using these services
                                IStoryService storyService, IWorldTreeService worldTreeService)
        {
            this.viewService  = viewService;
            this.assetService = assetService;
            this.undoRedo     = undoRedo;

            var mainPanel = new FluentPanel <ISceneNode>(() => selectedSceneNode, x => x != null)
            {
                Width = 300
            };
            var builder = mainPanel.Build().Table();

            {
                var mainGroupBox = builder.Row().GroupBox("common", x => x, x => true).Table();
                mainGroupBox.Row().Label(x => x.Id.ToString());
                mainGroupBox.Row().TextBox(x => x.Name);
            }
            {
                var sceneGroupBox = builder.Row().GroupBox("Scene", x => x.AmParent as IScene, x => x != null).Table();
                var colorRow      = sceneGroupBox.Row();
                colorRow.Label("Bgnd Color");
                colorRow.ColorPicker(x => x.BackgroundColor);
                var skyboxRow = sceneGroupBox.Row();
                skyboxRow.Label("Skybox");
                skyboxRow.DropDown(x => x.Skybox, new Dictionary <string, ISkybox>
                {
                    { "None", null },
                    { "Storm", embeddedResources.Skybox("Skyboxes/storm.skybox") },
                    { "Stars", embeddedResources.Skybox("Skyboxes/stars.skybox") }
                });
            }
            {
                var storyRootGroupBox = builder.Row().GroupBox("Story Root", x => x.SearchComponent <IStoryComponent>(), x => x != null && x.IsLayoutRoot).Table();
                var layoutTypeRow     = storyRootGroupBox.Row();
                layoutTypeRow.Label("LayoutType");
                layoutTypeRow.DropDown(x => x.StartLayoutType, storyLayouts.ToDictionary(x => x.UserFriendlyName, x => x.Type));
                var auxRow12 = storyRootGroupBox.Row();
                auxRow12.CheckBox("Aux 1", x => x.ShowAux1);
                auxRow12.CheckBox("Aux 2", x => x.ShowAux2);
                var auxRow34 = storyRootGroupBox.Row();
                auxRow34.CheckBox("Aux 3", x => x.ShowAux3);
                auxRow34.CheckBox("Aux 4", x => x.ShowAux4);
            }
            {
                var storyNodeGroupBox = builder.Row().GroupBox("Story Node", x => x.SearchComponent <IStoryComponent>(), x => x != null).Table();
                var firstRow          = storyNodeGroupBox.Row();
                firstRow.CheckBox("Instant transition", x => x.InstantTransition);
                firstRow.CheckBox("Skip", x => x.SkipOrder);
                for (var i = 0; i < 4; i++)
                {
                    var iLoc = i;
                    var row  = storyNodeGroupBox.Row();
                    row.Label(x => storyService.GlobalGraph.Next.TryGetValue(x.Node.Id, out var nextList) && iLoc < nextList.Count
                        ? worldTreeService.GetById(nextList[iLoc]).Name
                        : "-");
                    row.Button("X", x => storyService.RemoveEdge(x.Node.Id, storyService.GlobalGraph.Next[x.Node.Id][iLoc]));
                }
            }
            {
                var modelComponentBuilder = builder.Row().GroupBox("Model", x => x.SearchComponent <IModelComponent>(), x => x != null).Table();
                var colorRow = modelComponentBuilder.Row();
                colorRow.CheckBox("SingleColor", x => x.SingleColor);
                colorRow.ColorPicker(x => x.Color);
                var textureRow = modelComponentBuilder.Row();
                textureRow.Label("Image");
                textureRow.Button("Load", OnLoadTextureClicked);
                var checkBoxRow1 = modelComponentBuilder.Row();
                checkBoxRow1.CheckBox("Ignore Lighting", x => x.IgnoreLighting);
                checkBoxRow1.CheckBox("No Specular", x => x.NoSpecular);
                var checkBoxRow2 = modelComponentBuilder.Row();
                checkBoxRow2.CheckBox("Don't cull", x => x.DontCull);
                checkBoxRow2.CheckBox("Ortho", x => x.Ortho);
                modelComponentBuilder.Row().Button("Export", OnExportClick);
            }
            {
                var spherePackingComponentBuilder = builder.Row().GroupBox("Sphere Packing", x => x.SearchComponent <SpherePackingComponent>(), x => x != null).Table();
                var row = spherePackingComponentBuilder.Row();
                row.Label("Radius");
                row.TextBox(x => x.Radius);
                row = spherePackingComponentBuilder.Row();
                row.Label("Color");
                row.ColorPicker(x => x.Color);
            }
            {
                var rectGroupBox  = builder.Row().GroupBox("Rectangle", x => x, x => x.HasComponent <IRectangleComponent>()).Table();
                var commonRectRow = rectGroupBox.Row().Panel(x => x.SearchComponent <IRectangleComponent>(), x => x != null).Table().Row();
                commonRectRow.CheckBox("DragBorders", x => x.DragByBorders);
                var colorRow = rectGroupBox.Row().Panel(x => x.SearchComponent <ColorRectangleComponent>(), x => x != null).Table().Row();
                colorRow.Label("Color");
                colorRow.ColorPicker(x => x.Color);
                // todo: change image
            }
            {
                var viewModel    = new RichTextViewModel(() => selectedSceneNode.SearchComponent <IRichTextComponent>());
                var textGroupBox = builder.Row().GroupBox("Rich Text", x => viewModel, x => x.Valid).Table();
                var bgndModeRow  = textGroupBox.Row();
                bgndModeRow.Label("Bgnd Mode");
                bgndModeRow.DropDown(x => x.BackgroundMode, new Dictionary <string, RtTransparencyMode>
                {
                    ["Opaque"] = RtTransparencyMode.Opaque,
                    ["Native"] = RtTransparencyMode.Native,
                    ["White is transparent"] = RtTransparencyMode.WhiteIsTransparent,
                    ["Black is transparent"] = RtTransparencyMode.BlackIsTransparent,
                });
                var bgndColorRow = textGroupBox.Row();
                bgndColorRow.Label("Bgnd Color");
                bgndColorRow.ColorPicker(x => x.BackgroundColor);
                var bgndOpacityRow = textGroupBox.Row();
                bgndOpacityRow.Label("Bgnd Opacity");
                bgndOpacityRow.Slider(x => x.BackgroundOpacity, 0, 1, 256);

                var alignmentRow = textGroupBox.Row();
                alignmentRow.Label("Alignment");
                alignmentRow.DropDown(x => x.Alignment, new Dictionary <string, RtParagraphAlignment>
                {
                    ["Left"]    = RtParagraphAlignment.Left,
                    ["Center"]  = RtParagraphAlignment.Center,
                    ["Right"]   = RtParagraphAlignment.Right,
                    ["Justify"] = RtParagraphAlignment.Justify,
                });
                var directionRow = textGroupBox.Row();
                directionRow.Label("Direction");
                directionRow.DropDown(x => x.Direction, new Dictionary <string, RtParagraphDirection>
                {
                    ["LeftToRight"] = RtParagraphDirection.LeftToRight,
                    ["RightToLeft"] = RtParagraphDirection.RightToLeft,
                });
                var tabsRow = textGroupBox.Row();
                tabsRow.Label("Tabs");
                tabsRow.NumericUpDown(x => x.Tabs, 0, 16);
                var marginUpRow = textGroupBox.Row();
                marginUpRow.Label("MarginUp");
                marginUpRow.NumericUpDown(x => x.MarginUp, 0, 1000);

                var fontRow = textGroupBox.Row();
                fontRow.Label("Font");
                fontRow.DropDown(x => x.FontFamily, Fonts.AvailableFontFamilies
                                 .Select(x => x.Name)
                                 .OrderBy(r => r)
                                 .ToDictionary(x => x));
                var sizeRow = textGroupBox.Row();
                sizeRow.Label("Size");
                sizeRow.NumericUpDown(x => x.Size, 1, 200);
                var colorRow = textGroupBox.Row();
                colorRow.Label("Color");
                colorRow.ColorPicker(x => x.Color);
                var decorationRow1 = textGroupBox.Row();
                decorationRow1.CheckBox("Bold", x => x.Bold);
                decorationRow1.CheckBox("Italic", x => x.Italic);
                var decorationRow2 = textGroupBox.Row();
                decorationRow2.CheckBox("Underline", x => x.Underline);
                decorationRow2.CheckBox("Strikethrough", x => x.Strikethrough);
                var highlightGroupRow = textGroupBox.Row();
                highlightGroupRow.Label("Highlight Group");
                highlightGroupRow.TextBox(x => x.HighlightGroup);

                var formulaRow = textGroupBox.Row();
                formulaRow.Button("Insert Formula", vm => vm.InsertFormula());
            }
            {
                var highlightOnMouseGroupBox = builder.Row().GroupBox("Highlight on Mouse", x => x.SearchComponent <HighlightOnMouseComponent>(), x => x != null).Table();
                var row = highlightOnMouseGroupBox.Row();
                row.Label("Group Name");
                row.TextBox(x => x.GroupName, x => x ?? "", x => string.IsNullOrEmpty(x) ? null : x);
            }
            {
                var circlePackingGroupBox = builder.Row().GroupBox("Circle Packing", x => x.SearchComponent <ICirclePackingComponent>(), x => x != null).Table();
                var shapeRow = circlePackingGroupBox.Row();
                shapeRow.Label("Shape");
                shapeRow.DropDown(x => x.ShapeName, new[] { "Square", "Circle", "Ellipse" }.ToDictionary(x => x));
                var radiusRow = circlePackingGroupBox.Row();
                radiusRow.Label("Radius");
                radiusRow.TextBox(x => x.CircleRadius);
                var maxCircles = circlePackingGroupBox.Row();
                maxCircles.Label("Max Circles");
                maxCircles.TextBox(x => x.MaxInitialCircles);
                var movementRateRow = circlePackingGroupBox.Row();
                movementRateRow.Label("Smoothness");
                movementRateRow.Slider(x => x.MovementRate, 0, 1, 32);
                var quakeRow = circlePackingGroupBox.Row();
                quakeRow.Label("Quake");
                quakeRow.Slider(x => x.RandomFactor, 0, 1, 32);
                var areaRow = circlePackingGroupBox.Row();
                areaRow.Label("Area");
                areaRow.Label(x => x.Area.ToString(CultureInfo.InvariantCulture));
                var numCirclesRow = circlePackingGroupBox.Row();
                numCirclesRow.Label(x => "Num Circles: " + x.CurrentNumCircles);
                numCirclesRow.Label(x => "Uppber Bound: " + x.MaxCircles);
                var iterPerBreakRow = circlePackingGroupBox.Row();
                iterPerBreakRow.Label("Iteractions per Display");
                iterPerBreakRow.TextBox(x => x.NumIterationPerBreak);
                var batchSizeRow = circlePackingGroupBox.Row();
                batchSizeRow.Label("Batch Size");
                batchSizeRow.TextBox(x => x.BatchSize);
                var resetRow = circlePackingGroupBox.Row();
                resetRow.Label("");
                resetRow.Button("Reset Circles", x => x.ResetPacker());
                var optimizeStepRow = circlePackingGroupBox.Row();
                optimizeStepRow.Label("");
                optimizeStepRow.Button("Optimize Step", x => x.OptimizeStep());
                var runOptimizeRow = circlePackingGroupBox.Row();
                runOptimizeRow.Label("");
                runOptimizeRow.Button("Run Optimization", x => x.RunOptimization());
                var stopOptimizeRow = circlePackingGroupBox.Row();
                stopOptimizeRow.Label("");
                stopOptimizeRow.Button("Stop Optimization", x => x.StopOptimization());
                var deleteCircleRow = circlePackingGroupBox.Row();
                deleteCircleRow.Label("");
                deleteCircleRow.Button("Delete Circle", x => x.DeleteCircle());
                var fillHodeRow = circlePackingGroupBox.Row();
                fillHodeRow.Button("Fill Hole (E)", x => x.TryFillHole(true));
                fillHodeRow.Button("Fill Hole (N)", x => x.TryFillHole(false));
            }
            {
                var circlePackingGroupBox = builder.Row().GroupBox("Circle Packing", x => x.SearchComponent <ICirclePackingAutoComponent>(), x => x != null).Table();
                var shapeRow = circlePackingGroupBox.Row();
                shapeRow.Label("Shape");
                shapeRow.DropDown(x => x.ShapeName, new[] { "Square", "Circle", "Ellipse" }.ToDictionary(x => x));
                var radiusRow = circlePackingGroupBox.Row();
                radiusRow.Label("Radius");
                radiusRow.TextBox(x => x.CircleRadius);
                var numCirclesRow = circlePackingGroupBox.Row();
                numCirclesRow.Label(x => "Num Circles: " + x.NumCircles);
                //numCirclesRow.Label(x => "Uppber Bound: " + x.MaxCircles);
                var attemptsPerDisplayRow = circlePackingGroupBox.Row();
                attemptsPerDisplayRow.Label("Attempts per Display");
                attemptsPerDisplayRow.TextBox(x => x.AttemptsPerRefresh);
                var statsRow = circlePackingGroupBox.Row();
                statsRow.Label(x => $"Seconds: {x.SecondsSinceLastSuccess:F} Attempts: {x.AttemptsSinceLastSuccess}");
                var resetRow = circlePackingGroupBox.Row();
                resetRow.Label("");
                resetRow.Button("Reset", x => x.Reset());
                var runOptimizeRow = circlePackingGroupBox.Row();
                runOptimizeRow.Label("");
                runOptimizeRow.Button("Run", x => x.Run());
                var stopOptimizeRow = circlePackingGroupBox.Row();
                stopOptimizeRow.Label("");
                stopOptimizeRow.Button("Stop", x => x.Stop());
                var deleteCircleRow = circlePackingGroupBox.Row();
            }
            {
                var componentsBuilder = builder.Row().GroupBox("Components", x => x, x => x != null).Table();
                // todo: to ArrayTable
                var componentsCache       = (IEnumerable <ISceneNodeComponent>)null;
                var componentsStringCache = "";
                componentsBuilder.Row().Label(n =>
                {
                    if (n.Components != componentsCache)
                    {
                        componentsCache       = n.Components;
                        componentsStringCache = string.Join("\n", n.Components.Select(c => c.AmInterface.Name));
                    }
                    return(componentsStringCache);
                });

                var newComponentViewModel    = new NewComponentViewModel(() => selectedSceneNode);
                var newComponentPanelBuilder = componentsBuilder.Row().Panel(x => newComponentViewModel, x => true).Table();
                var newComponentRow          = newComponentPanelBuilder.Row();
                newComponentRow.DropDown(x => x.ComponentType, new Dictionary <string, Type>
                {
                    ["Rotate Once"]        = typeof(RotateOnceComponent),
                    ["Highlight on Mouse"] = typeof(HighlightOnMouseComponent),
                    ["Warp Scrolling"]     = typeof(WarpScrollComponent),
                });
                newComponentRow.Button("Add", x =>
                {
                    componentsCache = null;
                    ISceneNodeComponent component;
                    if (x.ComponentType == typeof(RotateOnceComponent))
                    {
                        component = AmFactory.Create <RotateOnceComponent>();
                    }
                    else if (x.ComponentType == typeof(HighlightOnMouseComponent))
                    {
                        component = AmFactory.Create <HighlightOnMouseComponent>();
                    }
                    else if (x.ComponentType == typeof(WarpScrollComponent))
                    {
                        component = AmFactory.Create <WarpScrollComponent>();
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException();
                    }
                    newComponentViewModel.GetNode().Components.Add(component);
                    undoRedo.OnChange();
                });
            }
            builder.Row().Panel(x => x, x => true);

            rootControl = mainPanel;
            renderLoopDispatcher.AfterUpdate += Update;
        }