== Rendering Widgets
include::../variables.adoc[]

=== WidgetRenderer classes
In general, to fully implement a Widget, you must define its `QWidgetMetaData`,
and supply a subclass of `AbstractWidgetRenderer`, to provide the data to the widget.
(Note the "No Code" category of widgets, which are an exception to this generalization).

The only method required in a subclass of `AbstractWidgetRenderer` is:

   public RenderWidgetOutput render(RenderWidgetInput input) throws QException

The fields available in `RenderWidgetInput` are:

- `Map<String, String> queryParams` - These are parameters supplied by the frontend, for example,
if a user selected values from dropdowns to control a dimension of your widget, those name/value
pairs would be in this map.  Similarly, if your widget is being included on a record view screen, then
the record's primary key will be in this map.
- `QWidgetMetaDataInterface widgetMetaData` - This is the meta-data for the widget being
rendered.  This can be useful in case you are using the same renderer class for multiple widgets.

The only field in `RenderWidgetOutput` is:

- `QWidgetData widgetData` - This is a base class, with several attributes, and more importantly,
several subclasses, specific to the type of widget that is being rendered.

==== Widget-Type Specific Rendering Details
Different widget types expect & require different types of values to be set in the `RenderWidgetOutput` by their renderers.

===== Pie Chart
The `WidgetType.PIE_CHART` requires an object of type `ChartData`.
The fields on this type are:

* `chartData` an instance of `ChartData.Data`, which has the following fields:
** `labels` - *List<String>, required* - the labels for the slices of the pie.
** `datasets` - *List<Dataset> required* - the data for each slice of the pie.
For a Pie chart, only a single entry in this list is used
(other chart types using `ChartData` may support more than 1 entry in this list).
Fields in this object are:
*** `label` - *String, required* - a label to describe the dataset as a whole.
e.g., "Orders" for a pie showing orders of different statuses.
*** `data` - *List<Number>, required* - the data points for each slice of the pie.
*** `color` - *String* - HTML color for the slice
*** `urls` - *List<String>* - Optional URLs for slices of the pie to link to when clicked.
*** `backgroundColors` - *List<String>* - Optional HTML color codes for each slice of the pie.

[source,java]
.Pie chart widget example
----
// meta data
new QWidgetMetaData()
    .withName("pieChartExample")
    .withType(WidgetType.PIE_CHART.getType())
    .withGridColumns(4)
    .withIsCard(true)
    .withLabel("Pie Chart Example")
    .withCodeReference(new QCodeReference(PieChartExampleRenderer.class));

// renderer
private List<String> labels = new ArrayList<>();
private List<String> colors = new ArrayList<>();
private List<Number> data   = new ArrayList<>();

/*******************************************************************************
** helper method - to add values for a slice to the lists
*******************************************************************************/
private void addSlice(String label, String color, Number datum)
{
    labels.add(label);
    colors.add(color);
    data.add(datum);
}

/*******************************************************************************
** main method of the widget renderer
*******************************************************************************/
@Override
public RenderWidgetOutput render(RenderWidgetInput input) throws QException
{
   addSlice("Apple", "#FF0000", 100);
   addSlice("Orange", "#FF8000", 150);
   addSlice("Banana", "#FFFF00", 75);
   addSlice("Lime", "#00FF00", 100);
   addSlice("Blueberry", "#0000FF", 200);

   ChartData chartData = new ChartData()
      .withChartData(new ChartData.Data()
         .withLabels(labels)
         .withDatasets(List.of(
            new ChartData.Data.Dataset()
               .withLabel("Flavor")
               .withData(data)
               .withBackgroundColors(colors)
               .withUrls(urls))));

   return (new RenderWidgetOutput(chartData));
}

----

===== Bar Chart
#todo#

===== Stacked Bar Chart
#todo#

===== Horizontal Bar Chart
#todo#

===== Child Record List
#todo#

===== Line Chart
#todo#

===== Small Line Chart
#todo#

===== Statistics
#todo#

===== Parent Widget
#todo#

===== Composite
A `WidgetType.COMPOSITE` is built by using one or more smaller elements, known as `Blocks`.
Note that `Blocks` can also be used in the data of some other widget types
(specifically, within a cell of a Table-type widget, or (in the future?) as a header above a pie or bar chart).

A composite widget renderer must return data of type `CompositeWidgetData`,
which has the following fields:

* `blocks` - *List<AbstractBlockWidgetData>, required* - The blocks (1 or more) being composited together to make the widget.
See below for details on the specific Block types.
* `styleOverrides` - *Map<String, Serializable>* - Optional map of CSS attributes
(named following javascriptStyleCamelCase) to apply to the `<div>` element that wraps the rendered blocks.
* `layout` - *Layout enum* - Optional specifier for how the blocks should be laid out.
e.g., predefined sets of CSS attributes to achieve specific layouts.
** Note that some blocks are designed to work within composites with specific layouts.
Look for matching names, such as `Layout.BADGES_WRAPPER` to go with `NumberIconBadgeBlock`.

[source,java]
.Composite widget example - consisting of 3 Progress Bar Blocks, and one Divider Block
----
// meta data
new QWidgetMetaData()
    .withName("compositeExample")
    .withType(WidgetType.COMPOSITE.getType())
    .withGridColumns(4)
    .withIsCard(true)
    .withLabel("Composite Example")
    .withCodeReference(new QCodeReference(CompositeExampleRenderer.class));

// renderer
public RenderWidgetOutput render(RenderWidgetInput input) throws QException
{
   CompositeWidgetData data = new CompositeWidgetData();

   data.addBlock(new ProgressBarBlockData()
      .withValues(new ProgressBarValues()
         .withHeading("Blocks")
         .withPercent(new BigDecimal("78.5"))));

   data.addBlock(new ProgressBarBlockData()
      .withValues(new ProgressBarValues()
         .withHeading("Progress")
         .withPercent(new BigDecimal(0))));

   data.addBlock(new DividerBlockData());

   data.addBlock(new ProgressBarBlockData()
      .withStyles(new ProgressBarStyles().withBarColor("#C0C000"))
      .withValues(new ProgressBarValues()
         .withHeading("Custom Color")
         .withPercent(new BigDecimal("75.3"))));

   return (new RenderWidgetOutput(data));
}
----


===== Table
#todo#

===== HTML
#todo#

===== Divider
#todo#

===== Process
#todo#

===== Stepper
#todo#

===== Data Bag Viewer
#todo#

===== Script Viewer
#todo#

=== Block-type Specific Rendering Details
For Composite-type widgets (or other widgets which can include blocks),
there are specific data classes required to be returned by the widget renderer.

Each block type defines a subclass of `AbstractBlockWidgetData`,
which is a generic class with 3 type parameters:

* `V` - an implementation of `BlockValuesInterface` - to define the type of values that the block uses.
* `S` - an implementation of `BlockSlotsInterface` (expected to be an `enum`) - to define the "slots" in the block,
that can have Tooltips and/or Links applied to them.
* `SX` - an implementation of `BlockStylesInterface` - to define the types of style customizations that the block supports.

These type parameters are designed to ensure type-safety for the application developer,
to ensure that only

=== Additional Tips

* To make a Dashboard page (e.g., an App consisting of Widgets) with a parent widget use the parent widget's label as the page's label:
** On the `QAppMetaData` that contains the Parent widget, call
`.withSupplementalMetaData(new MaterialDashboardAppMetaData().withShowAppLabelOnHomeScreen(false))`.
** In the Parent widget's renderer, on the `ParentWidgetData`, call `setLabel("My Label")` and
`setIsLabelPageTitle(true)`.
