# Stage Preview Widget
  
  
The `StagePreviewWidget` is comprised of a few `omni.ui` objects which are stacked on top of one-another.
So first an `omni.ui.ZStack` container is instantiated and using the `omni.ui` with syntax, the remaining objects
are created in its scope:
```python
self.__ui_container = ui.ZStack()
with self.__ui_container:
```
  
  
## Background

First we create an `omni.ui.Rectangle` that will fill the entire frame with a constant color, using black as the default.
We add a few additional style arguments so that the background color can be controlled easily from calling code.
```python
# Add a background Rectangle that is black by default, but can change with a set_style 
ui.Rectangle(style_type_name_override='ViewportBackgroundColor', style={'ViewportBackgroundColor': {'background_color': 0xff000000}})
```
  
  
## ViewportWidget

Next the `omni.kit.widget.viewport.ViewportWidget` is created, directly above the background Rectangle.
In the `stage_preview` example, the `ViewportWidget` is actually created to always fill the parent frame by
passing `resolution='fill_frame'`, which will essentially make it so the black background never seen.
If a constant resolution was requested by passing a tuple `resolution=(640, 480)`; however, the rendered image would be
locked to that resolution and causing the background rect to be seen if the Widget was wider or taller than the texture's
resolution.
```python
self.__vp_widget = ViewportWidget(usd_context_name=usd_context_name, camera_path=camera_path, resolution=resolution, *ui_args, **ui_kw_args)
```
  
  
## SceneView

The final `omni.ui` element we are going to create is an `omni.ui.scene.SceneView`.  We are creating it primarily to
host our camera-manipulators which are written for the `omni.ui.scene` framework, but it could also be used to insert 
additional drawing on top of the `ViewportWidget` in 3D space.

```python
# Add the omni.ui.scene.SceneView that is going to host the camera-manipulator
self.__scene_view = sc.SceneView(aspect_ratio_policy=sc.AspectRatioPolicy.STRETCH)

# And finally add the camera-manipulator into that view
with self.__scene_view.scene:
```
  
  
## Full code
```python
class StagePreviewWidget:
    def __init__(self, usd_context_name: str = '', camera_path: str = None, resolution: Union[tuple, str] = None, *ui_args ,**ui_kw_args):
        """StagePreviewWidget contructor
        Args:
            usd_context_name (str): The name of a UsdContext the Viewport will be viewing.
            camera_path (str): The path of the initial camera to render to.
            resolution (x, y): The resolution of the backing texture, or 'fill_frame' to match the widget's ui-size
            *ui_args, **ui_kw_args: Additional arguments to pass to the ViewportWidget's parent frame
        """
        # Put the Viewport in a ZStack so that a background rectangle can be added underneath
        self.__ui_container = ui.ZStack()
        with self.__ui_container:
            # Add a background Rectangle that is black by default, but can change with a set_style 
            ui.Rectangle(style_type_name_override='ViewportBackgroundColor', style={'ViewportBackgroundColor': {'background_color': 0xff000000}})

            # Create the ViewportWidget, forwarding all of the arguments to this constructor
            self.__vp_widget = ViewportWidget(usd_context_name=usd_context_name, camera_path=camera_path, resolution=resolution, *ui_args, **ui_kw_args)

            # Add the omni.ui.scene.SceneView that is going to host the camera-manipulator
            self.__scene_view = sc.SceneView(aspect_ratio_policy=sc.AspectRatioPolicy.STRETCH)

            # And finally add the camera-manipulator into that view
            with self.__scene_view.scene:
                self.__camera_manip = ViewportCameraManipulator(self.viewport_api)
                model = self.__camera_manip.model

                # Let's disable any undo for these movements as we're a preview-window
                model.set_ints('disable_undo', [1])

                # We'll also let the Viewport automatically push view and projection changes into our scene-view
                self.viewport_api.add_scene_view(self.__scene_view)

    def __del__(self):
        self.destroy()

    def destroy(self):
        self.__view_change_sub = None
        if self.__camera_manip:
            self.__camera_manip.destroy()
            self.__camera_manip = None
        if self.__scene_view:
            self.__scene_view.destroy()
            self.__scene_view = None
        if self.__vp_widget:
            self.__vp_widget.destroy()
            self.__vp_widget = None
        if self.__ui_container:
            self.__ui_container.destroy()
            self.__ui_container = None

    @property
    def viewport_api(self):
        # Access to the underying ViewportAPI object to control renderer, resolution
        return self.__vp_widget.viewport_api

    @property
    def scene_view(self):
        # Access to the omni.ui.scene.SceneView
        return self.__scene_view

    def set_style(self, *args, **kwargs):
        # Give some styling access
        self.__ui_container.set_style(*args, **kwargs)
```
