Exemple #1
0
    def __init__(self):
        self.rgb_images = []
        for f in os.listdir(RGB_DIR):
            if f.endswith(".jpg") or f.endswith(".png"):
                img = o3d.io.read_image(os.path.join(RGB_DIR, f))
                self.rgb_images.append(img)
        self.depth_images = []
        for f in os.listdir(DEPTH_DIR):
            if f.endswith(".jpg") or f.endswith(".png"):
                img = o3d.io.read_image(os.path.join(DEPTH_DIR, f))
                # The images are pretty dark, so rescale them so that it is
                # obvious that this is a depth image, for the sake of the example
                img = rescale_greyscale(img)
                self.depth_images.append(img)
        assert (len(self.rgb_images) == len(self.depth_images))

        self.window = gui.Application.instance.create_window(
            "Open3D - Video Example", 1000, 500)
        self.window.set_on_layout(self._on_layout)
        self.window.set_on_close(self._on_close)

        self.widget3d = gui.SceneWidget()
        self.widget3d.scene = rendering.Open3DScene(self.window.renderer)
        self.window.add_child(self.widget3d)

        lit = rendering.Material()
        lit.shader = "defaultLit"
        tet = o3d.geometry.TriangleMesh.create_tetrahedron()
        tet.compute_vertex_normals()
        tet.paint_uniform_color([0.5, 0.75, 1.0])
        self.widget3d.scene.add_geometry("tetrahedron", tet, lit)
        bounds = self.widget3d.scene.bounding_box
        self.widget3d.setup_camera(60.0, bounds, bounds.get_center())
        self.widget3d.scene.show_axes(True)

        em = self.window.theme.font_size
        margin = 0.5 * em
        self.panel = gui.Vert(0.5 * em, gui.Margins(margin))
        self.panel.add_child(gui.Label("Color image"))
        self.rgb_widget = gui.ImageWidget(self.rgb_images[0])
        self.panel.add_child(self.rgb_widget)
        self.panel.add_child(gui.Label("Depth image (normalized)"))
        self.depth_widget = gui.ImageWidget(self.depth_images[0])
        self.panel.add_child(self.depth_widget)
        self.window.add_child(self.panel)

        self.is_done = False
        threading.Thread(target=self._update_thread).start()
Exemple #2
0
 def switch_proxy():
     self.logo_idx += 1
     if self.logo_idx % 3 == 0:
         proxy.set_widget(None)
     elif self.logo_idx % 3 == 1:
         # Add a simple image
         logo = gui.ImageWidget(basedir + "/icon-32.png")
         proxy.set_widget(logo)
     else:
         label = gui.Label(
             'Open3D: A Modern Library for 3D Data Processing')
         proxy.set_widget(label)
     w.set_needs_layout()
Exemple #3
0
    def __init__(self, vfov=60, max_pcd_vertices=1 << 20, **callbacks):
        """Initialize.

        Args:
            vfov (float): Vertical field of view for the 3D scene.
            max_pcd_vertices (int): Maximum point clud verties for which memory
                is allocated.
            callbacks (dict of kwargs): Callbacks provided by the controller
                for various operations.
        """

        self.vfov = vfov
        self.max_pcd_vertices = max_pcd_vertices

        gui.Application.instance.initialize()
        self.window = gui.Application.instance.create_window(
            "Open3D || Online RGBD Video Processing", 1280, 960)
        # Called on window layout (eg: resize)
        self.window.set_on_layout(self.on_layout)
        self.window.set_on_close(callbacks['on_window_close'])

        self.pcd_material = o3d.visualization.rendering.MaterialRecord()
        self.pcd_material.shader = "defaultLit"
        # Set n_pixels displayed for each 3D point, accounting for HiDPI scaling
        self.pcd_material.point_size = int(4 * self.window.scaling)

        # 3D scene
        self.pcdview = gui.SceneWidget()
        self.window.add_child(self.pcdview)
        self.pcdview.enable_scene_caching(
            True)  # makes UI _much_ more responsive
        self.pcdview.scene = rendering.Open3DScene(self.window.renderer)
        self.pcdview.scene.set_background([1, 1, 1, 1])  # White background
        self.pcdview.scene.set_lighting(
            rendering.Open3DScene.LightingProfile.SOFT_SHADOWS, [0, -6, 0])
        # Point cloud bounds, depends on the sensor range
        self.pcd_bounds = o3d.geometry.AxisAlignedBoundingBox([-3, -3, 0],
                                                              [3, 3, 6])
        self.camera_view()  # Initially look from the camera
        em = self.window.theme.font_size

        # Options panel
        self.panel = gui.Vert(em, gui.Margins(em, em, em, em))
        self.panel.preferred_width = int(360 * self.window.scaling)
        self.window.add_child(self.panel)
        toggles = gui.Horiz(em)
        self.panel.add_child(toggles)

        toggle_capture = gui.ToggleSwitch("Capture / Play")
        toggle_capture.is_on = False
        toggle_capture.set_on_clicked(
            callbacks['on_toggle_capture'])  # callback
        toggles.add_child(toggle_capture)

        self.flag_normals = False
        self.toggle_normals = gui.ToggleSwitch("Colors / Normals")
        self.toggle_normals.is_on = False
        self.toggle_normals.set_on_clicked(
            callbacks['on_toggle_normals'])  # callback
        toggles.add_child(self.toggle_normals)

        view_buttons = gui.Horiz(em)
        self.panel.add_child(view_buttons)
        view_buttons.add_stretch()  # for centering
        camera_view = gui.Button("Camera view")
        camera_view.set_on_clicked(self.camera_view)  # callback
        view_buttons.add_child(camera_view)
        birds_eye_view = gui.Button("Bird's eye view")
        birds_eye_view.set_on_clicked(self.birds_eye_view)  # callback
        view_buttons.add_child(birds_eye_view)
        view_buttons.add_stretch()  # for centering

        save_toggle = gui.Horiz(em)
        self.panel.add_child(save_toggle)
        save_toggle.add_child(gui.Label("Record / Save"))
        self.toggle_record = None
        if callbacks['on_toggle_record'] is not None:
            save_toggle.add_fixed(1.5 * em)
            self.toggle_record = gui.ToggleSwitch("Video")
            self.toggle_record.is_on = False
            self.toggle_record.set_on_clicked(callbacks['on_toggle_record'])
            save_toggle.add_child(self.toggle_record)

        save_buttons = gui.Horiz(em)
        self.panel.add_child(save_buttons)
        save_buttons.add_stretch()  # for centering
        save_pcd = gui.Button("Save Point cloud")
        save_pcd.set_on_clicked(callbacks['on_save_pcd'])
        save_buttons.add_child(save_pcd)
        save_rgbd = gui.Button("Save RGBD frame")
        save_rgbd.set_on_clicked(callbacks['on_save_rgbd'])
        save_buttons.add_child(save_rgbd)
        save_buttons.add_stretch()  # for centering

        self.video_size = (int(240 * self.window.scaling),
                           int(320 * self.window.scaling), 3)
        self.show_color = gui.CollapsableVert("Color image")
        self.show_color.set_is_open(False)
        self.panel.add_child(self.show_color)
        self.color_video = gui.ImageWidget(
            o3d.geometry.Image(np.zeros(self.video_size, dtype=np.uint8)))
        self.show_color.add_child(self.color_video)
        self.show_depth = gui.CollapsableVert("Depth image")
        self.show_depth.set_is_open(False)
        self.panel.add_child(self.show_depth)
        self.depth_video = gui.ImageWidget(
            o3d.geometry.Image(np.zeros(self.video_size, dtype=np.uint8)))
        self.show_depth.add_child(self.depth_video)

        self.status_message = gui.Label("")
        self.panel.add_child(self.status_message)

        self.flag_exit = False
        self.flag_gui_init = False
Exemple #4
0
    def __init__(self, config, font_id):
        self.config = config

        self.window = gui.Application.instance.create_window(
            'Open3D - Reconstruction', 1280, 800)

        w = self.window
        em = w.theme.font_size

        spacing = int(np.round(0.25 * em))
        vspacing = int(np.round(0.5 * em))

        margins = gui.Margins(vspacing)

        # First panel
        self.panel = gui.Vert(spacing, margins)

        ## Items in fixed props
        self.fixed_prop_grid = gui.VGrid(2, spacing, gui.Margins(em, 0, em, 0))

        ### Depth scale slider
        scale_label = gui.Label('Depth scale')
        self.scale_slider = gui.Slider(gui.Slider.INT)
        self.scale_slider.set_limits(1000, 5000)
        self.scale_slider.int_value = int(config.depth_scale)
        self.fixed_prop_grid.add_child(scale_label)
        self.fixed_prop_grid.add_child(self.scale_slider)

        voxel_size_label = gui.Label('Voxel size')
        self.voxel_size_slider = gui.Slider(gui.Slider.DOUBLE)
        self.voxel_size_slider.set_limits(0.003, 0.01)
        self.voxel_size_slider.double_value = config.voxel_size
        self.fixed_prop_grid.add_child(voxel_size_label)
        self.fixed_prop_grid.add_child(self.voxel_size_slider)

        trunc_multiplier_label = gui.Label('Trunc multiplier')
        self.trunc_multiplier_slider = gui.Slider(gui.Slider.DOUBLE)
        self.trunc_multiplier_slider.set_limits(1.0, 20.0)
        self.trunc_multiplier_slider.double_value = config.trunc_voxel_multiplier
        self.fixed_prop_grid.add_child(trunc_multiplier_label)
        self.fixed_prop_grid.add_child(self.trunc_multiplier_slider)

        est_block_count_label = gui.Label('Est. blocks')
        self.est_block_count_slider = gui.Slider(gui.Slider.INT)
        self.est_block_count_slider.set_limits(40000, 100000)
        self.est_block_count_slider.int_value = config.block_count
        self.fixed_prop_grid.add_child(est_block_count_label)
        self.fixed_prop_grid.add_child(self.est_block_count_slider)

        est_point_count_label = gui.Label('Est. points')
        self.est_point_count_slider = gui.Slider(gui.Slider.INT)
        self.est_point_count_slider.set_limits(500000, 8000000)
        self.est_point_count_slider.int_value = config.est_point_count
        self.fixed_prop_grid.add_child(est_point_count_label)
        self.fixed_prop_grid.add_child(self.est_point_count_slider)

        ## Items in adjustable props
        self.adjustable_prop_grid = gui.VGrid(2, spacing,
                                              gui.Margins(em, 0, em, 0))

        ### Reconstruction interval
        interval_label = gui.Label('Recon. interval')
        self.interval_slider = gui.Slider(gui.Slider.INT)
        self.interval_slider.set_limits(1, 500)
        self.interval_slider.int_value = 50
        self.adjustable_prop_grid.add_child(interval_label)
        self.adjustable_prop_grid.add_child(self.interval_slider)

        ### Depth max slider
        max_label = gui.Label('Depth max')
        self.max_slider = gui.Slider(gui.Slider.DOUBLE)
        self.max_slider.set_limits(3.0, 6.0)
        self.max_slider.double_value = config.depth_max
        self.adjustable_prop_grid.add_child(max_label)
        self.adjustable_prop_grid.add_child(self.max_slider)

        ### Depth diff slider
        diff_label = gui.Label('Depth diff')
        self.diff_slider = gui.Slider(gui.Slider.DOUBLE)
        self.diff_slider.set_limits(0.07, 0.5)
        self.diff_slider.double_value = config.odometry_distance_thr
        self.adjustable_prop_grid.add_child(diff_label)
        self.adjustable_prop_grid.add_child(self.diff_slider)

        ### Update surface?
        update_label = gui.Label('Update surface?')
        self.update_box = gui.Checkbox('')
        self.update_box.checked = True
        self.adjustable_prop_grid.add_child(update_label)
        self.adjustable_prop_grid.add_child(self.update_box)

        ### Ray cast color?
        raycast_label = gui.Label('Raycast color?')
        self.raycast_box = gui.Checkbox('')
        self.raycast_box.checked = True
        self.adjustable_prop_grid.add_child(raycast_label)
        self.adjustable_prop_grid.add_child(self.raycast_box)

        set_enabled(self.fixed_prop_grid, True)

        ## Application control
        b = gui.ToggleSwitch('Resume/Pause')
        b.set_on_clicked(self._on_switch)

        ## Tabs
        tab_margins = gui.Margins(0, int(np.round(0.5 * em)), 0, 0)
        tabs = gui.TabControl()

        ### Input image tab
        tab1 = gui.Vert(0, tab_margins)
        self.input_color_image = gui.ImageWidget()
        self.input_depth_image = gui.ImageWidget()
        tab1.add_child(self.input_color_image)
        tab1.add_fixed(vspacing)
        tab1.add_child(self.input_depth_image)
        tabs.add_tab('Input images', tab1)

        ### Rendered image tab
        tab2 = gui.Vert(0, tab_margins)
        self.raycast_color_image = gui.ImageWidget()
        self.raycast_depth_image = gui.ImageWidget()
        tab2.add_child(self.raycast_color_image)
        tab2.add_fixed(vspacing)
        tab2.add_child(self.raycast_depth_image)
        tabs.add_tab('Raycast images', tab2)

        ### Info tab
        tab3 = gui.Vert(0, tab_margins)
        self.output_info = gui.Label('Output info')
        self.output_info.font_id = font_id
        tab3.add_child(self.output_info)
        tabs.add_tab('Info', tab3)

        self.panel.add_child(gui.Label('Starting settings'))
        self.panel.add_child(self.fixed_prop_grid)
        self.panel.add_fixed(vspacing)
        self.panel.add_child(gui.Label('Reconstruction settings'))
        self.panel.add_child(self.adjustable_prop_grid)
        self.panel.add_child(b)
        self.panel.add_stretch()
        self.panel.add_child(tabs)

        # Scene widget
        self.widget3d = gui.SceneWidget()

        # FPS panel
        self.fps_panel = gui.Vert(spacing, margins)
        self.output_fps = gui.Label('FPS: 0.0')
        self.fps_panel.add_child(self.output_fps)

        # Now add all the complex panels
        w.add_child(self.panel)
        w.add_child(self.widget3d)
        w.add_child(self.fps_panel)

        self.widget3d.scene = rendering.Open3DScene(self.window.renderer)
        self.widget3d.scene.set_background([1, 1, 1, 1])

        w.set_on_layout(self._on_layout)
        w.set_on_close(self._on_close)

        self.is_done = False

        self.is_started = False
        self.is_running = False
        self.is_surface_updated = False

        self.idx = 0
        self.poses = []

        # Start running
        threading.Thread(name='UpdateMain', target=self.update_main).start()
    def __init__(self):
        self.window = gui.Application.instance.create_window("Test", 400, 768)
        # self.window = gui.Application.instance.create_window("Test", 400, 768,
        #                                                        x=50, y=100)
        w = self.window  # for more concise code

        # Rather than specifying sizes in pixels, which may vary in size based
        # on the monitor, especially on macOS which has 220 dpi monitors, use
        # the em-size. This way sizings will be proportional to the font size,
        # which will create a more visually consistent size across platforms.
        em = w.theme.font_size

        # Widgets are laid out in layouts: gui.Horiz, gui.Vert,
        # gui.CollapsableVert, and gui.VGrid. By nesting the layouts we can
        # achieve complex designs. Usually we use a vertical layout as the
        # topmost widget, since widgets tend to be organized from top to bottom.
        # Within that, we usually have a series of horizontal layouts for each
        # row.
        layout = gui.Vert(0, gui.Margins(0.5 * em, 0.5 * em, 0.5 * em,
                                         0.5 * em))

        # Create the menu. The menu is global (because the macOS menu is global),
        # so only create it once.
        if gui.Application.instance.menubar is None:
            menubar = gui.Menu()
            test_menu = gui.Menu()
            test_menu.add_item("An option", ExampleWindow.MENU_CHECKABLE)
            test_menu.set_checked(ExampleWindow.MENU_CHECKABLE, True)
            test_menu.add_item("Unavailable feature",
                               ExampleWindow.MENU_DISABLED)
            test_menu.set_enabled(ExampleWindow.MENU_DISABLED, False)
            test_menu.add_separator()
            test_menu.add_item("Quit", ExampleWindow.MENU_QUIT)
            # On macOS the first menu item is the application menu item and will
            # always be the name of the application (probably "Python"),
            # regardless of what you pass in here. The application menu is
            # typically where About..., Preferences..., and Quit go.
            menubar.add_menu("Test", test_menu)
            gui.Application.instance.menubar = menubar

        # Each window needs to know what to do with the menu items, so we need
        # to tell the window how to handle menu items.
        w.set_on_menu_item_activated(ExampleWindow.MENU_CHECKABLE,
                                     self._on_menu_checkable)
        w.set_on_menu_item_activated(ExampleWindow.MENU_QUIT,
                                     self._on_menu_quit)

        # Create a file-chooser widget. One part will be a text edit widget for
        # the filename and clicking on the button will let the user choose using
        # the file dialog.
        self._fileedit = gui.TextEdit()
        filedlgbutton = gui.Button("...")
        filedlgbutton.horizontal_padding_em = 0.5
        filedlgbutton.vertical_padding_em = 0
        filedlgbutton.set_on_clicked(self._on_filedlg_button)

        # (Create the horizontal widget for the row. This will make sure the
        # text editor takes up as much space as it can.)
        fileedit_layout = gui.Horiz()
        fileedit_layout.add_child(gui.Label("Model file"))
        fileedit_layout.add_child(self._fileedit)
        fileedit_layout.add_fixed(0.25 * em)
        fileedit_layout.add_child(filedlgbutton)
        # add to the top-level (vertical) layout
        layout.add_child(fileedit_layout)

        # Create a collapsable vertical widget, which takes up enough vertical
        # space for all its children when open, but only enough for text when
        # closed. This is useful for property pages, so the user can hide sets
        # of properties they rarely use. All layouts take a spacing parameter,
        # which is the spacinging between items in the widget, and a margins
        # parameter, which specifies the spacing of the left, top, right,
        # bottom margins. (This acts like the 'padding' property in CSS.)
        collapse = gui.CollapsableVert("Widgets", 0.33 * em,
                                       gui.Margins(em, 0, 0, 0))
        self._label = gui.Label("Lorem ipsum dolor")
        self._label.text_color = gui.Color(1.0, 0.5, 0.0)
        collapse.add_child(self._label)

        # Create a checkbox. Checking or unchecking would usually be used to set
        # a binary property, but in this case it will show a simple message box,
        # which illustrates how to create simple dialogs.
        cb = gui.Checkbox("Enable some really cool effect")
        cb.set_on_checked(self._on_cb)  # set the callback function
        collapse.add_child(cb)

        # Create a color editor. We will change the color of the orange label
        # above when the color changes.
        color = gui.ColorEdit()
        color.color_value = self._label.text_color
        color.set_on_value_changed(self._on_color)
        collapse.add_child(color)

        # This is a combobox, nothing fancy here, just set a simple function to
        # handle the user selecting an item.
        combo = gui.Combobox()
        combo.add_item("Show point labels")
        combo.add_item("Show point velocity")
        combo.add_item("Show bounding boxes")
        combo.set_on_selection_changed(self._on_combo)
        collapse.add_child(combo)

        # This is a toggle switch, which is similar to a checkbox. To my way of
        # thinking the difference is subtle: a checkbox toggles properties
        # (for example, purely visual changes like enabling lighting) while a
        # toggle switch is better for changing the behavior of the app (for
        # example, turning on processing from the camera).
        switch = gui.ToggleSwitch("Continuously update from camera")
        switch.set_on_clicked(self._on_switch)
        collapse.add_child(switch)

        # Add a simple image
        logo = gui.ImageWidget(basedir + "/icon-32.png")
        collapse.add_child(logo)

        # Add a list of items
        lv = gui.ListView()
        lv.set_items(["Ground", "Trees", "Buildings" "Cars", "People"])
        lv.selected_index = lv.selected_index + 2  # initially is -1, so now 1
        lv.set_on_selection_changed(self._on_list)
        collapse.add_child(lv)

        # Add a tree view
        tree = gui.TreeView()
        tree.add_text_item(tree.get_root_item(), "Camera")
        geo_id = tree.add_text_item(tree.get_root_item(), "Geometries")
        mesh_id = tree.add_text_item(geo_id, "Mesh")
        tree.add_text_item(mesh_id, "Triangles")
        tree.add_text_item(mesh_id, "Albedo texture")
        tree.add_text_item(mesh_id, "Normal map")
        points_id = tree.add_text_item(geo_id, "Points")
        tree.can_select_items_with_children = True
        tree.set_on_selection_changed(self._on_tree)
        # does not call on_selection_changed: user did not change selection
        tree.selected_item = points_id
        collapse.add_child(tree)

        # Add two number editors, one for integers and one for floating point
        # Number editor can clamp numbers to a range, although this is more
        # useful for integers than for floating point.
        intedit = gui.NumberEdit(gui.NumberEdit.INT)
        intedit.int_value = 0
        intedit.set_limits(1, 19)  # value coerced to 1
        intedit.int_value = intedit.int_value + 2  # value should be 3
        doubleedit = gui.NumberEdit(gui.NumberEdit.DOUBLE)
        numlayout = gui.Horiz()
        numlayout.add_child(gui.Label("int"))
        numlayout.add_child(intedit)
        numlayout.add_fixed(
            em)  # manual spacing (could set it in Horiz() ctor)
        numlayout.add_child(gui.Label("double"))
        numlayout.add_child(doubleedit)
        collapse.add_child(numlayout)

        # Create a progress bar. It ranges from 0.0 to 1.0.
        self._progress = gui.ProgressBar()
        self._progress.value = 0.25  # 25% complete
        self._progress.value = self._progress.value + 0.08  # 0.25 + 0.08 = 33%
        prog_layout = gui.Horiz(em)
        prog_layout.add_child(gui.Label("Progress..."))
        prog_layout.add_child(self._progress)
        collapse.add_child(prog_layout)

        # Create a slider. It acts very similar to NumberEdit except that the
        # user moves a slider and cannot type the number.
        slider = gui.Slider(gui.Slider.INT)
        slider.set_limits(5, 13)
        slider.set_on_value_changed(self._on_slider)
        collapse.add_child(slider)

        # Create a text editor. The placeholder text (if not empty) will be
        # displayed when there is no text, as concise help, or visible tooltip.
        tedit = gui.TextEdit()
        tedit.placeholder_text = "Edit me some text here"

        # on_text_changed fires whenever the user changes the text (but not if
        # the text_value property is assigned to).
        tedit.set_on_text_changed(self._on_text_changed)

        # on_value_changed fires whenever the user signals that they are finished
        # editing the text, either by pressing return or by clicking outside of
        # the text editor, thus losing text focus.
        tedit.set_on_value_changed(self._on_value_changed)
        collapse.add_child(tedit)

        # Create a widget for showing/editing a 3D vector
        vedit = gui.VectorEdit()
        vedit.vector_value = [1, 2, 3]
        vedit.set_on_value_changed(self._on_vedit)
        collapse.add_child(vedit)

        # Create a VGrid layout. This layout specifies the number of columns
        # (two, in this case), and will place the first child in the first
        # column, the second in the second, the third in the first, the fourth
        # in the second, etc.
        # So:
        #      2 cols             3 cols                  4 cols
        #   |  1  |  2  |   |  1  |  2  |  3  |   |  1  |  2  |  3  |  4  |
        #   |  3  |  4  |   |  4  |  5  |  6  |   |  5  |  6  |  7  |  8  |
        #   |  5  |  6  |   |  7  |  8  |  9  |   |  9  | 10  | 11  | 12  |
        #   |    ...    |   |       ...       |   |         ...           |
        vgrid = gui.VGrid(2)
        vgrid.add_child(gui.Label("Trees"))
        vgrid.add_child(gui.Label("12 items"))
        vgrid.add_child(gui.Label("People"))
        vgrid.add_child(gui.Label("2 (93% certainty)"))
        vgrid.add_child(gui.Label("Cars"))
        vgrid.add_child(gui.Label("5 (87% certainty)"))
        collapse.add_child(vgrid)

        # Create a tab control. This is really a set of N layouts on top of each
        # other, but with only one selected.
        tabs = gui.TabControl()
        tab1 = gui.Vert()
        tab1.add_child(gui.Checkbox("Enable option 1"))
        tab1.add_child(gui.Checkbox("Enable option 2"))
        tab1.add_child(gui.Checkbox("Enable option 3"))
        tabs.add_tab("Options", tab1)
        tab2 = gui.Vert()
        tab2.add_child(gui.Label("No plugins detected"))
        tab2.add_stretch()
        tabs.add_tab("Plugins", tab2)
        collapse.add_child(tabs)

        # Quit button. (Typically this is a menu item)
        button_layout = gui.Horiz()
        ok_button = gui.Button("Ok")
        ok_button.set_on_clicked(self._on_ok)
        button_layout.add_stretch()
        button_layout.add_child(ok_button)

        layout.add_child(collapse)
        layout.add_child(button_layout)

        # We're done, set the window's layout
        w.add_child(layout)