{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import panel as pn\n",
    "\n",
    "from panel.layout.gridstack import GridStack\n",
    "\n",
    "pn.extension('gridstack')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``GridStack`` layout allows arranging multiple Panel objects in a grid using a simple API to assign objects to individual grid cells or to a grid span. Other layout containers function like lists, but a `GridSpec` has an API similar to a 2D array, making it possible to use 2D assignment to populate, index, and slice the grid.\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
    "\n",
    "* **``allow_resize``** (bool): Whether to allow resizing grid cells.\n",
    "* **``allow_drag``** (bool): Whether to allow dragging grid cells.\n",
    "* **``ncols``** (int): Allows specifying a fixed number of columns (otherwise grid expands to match assigned objects)\n",
    "* **``nrows``** (int): Allows specifying a fixed number of rows (otherwise grid expands to match assigned objects)\n",
    "* **``mode``** (str): Whether to 'warn', 'error', or simply 'override' on overlapping assignment\n",
    "* **``objects``** (list): The list of objects to display in the GridSpec. Should not generally be modified directly except when replaced in its entirety.\n",
    "\n",
    "___"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``GridStack`` can be created either with a fixed size (the default) or with responsive sizing. In both cases the ``GridSpec`` will modify the contents to ensure the objects fill the grid cells assigned to them.\n",
    "\n",
    "To demonstrate this behavior, let us declare a responsively sized ``GridStack`` and then assign ``Spacer`` objects with distinct colors. We populate a ``6x12`` grid with these objects and display it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gstack = GridStack(sizing_mode='stretch_both')\n",
    "\n",
    "gstack[ : , 0: 3] = pn.Spacer(background='red',    margin=0)\n",
    "gstack[0:2, 3: 9] = pn.Spacer(background='green',  margin=0)\n",
    "gstack[2:4, 6:12] = pn.Spacer(background='orange', margin=0)\n",
    "gstack[4:6, 3:12] = pn.Spacer(background='blue',   margin=0)\n",
    "gstack[0:2, 9:12] = pn.Spacer(background='purple', margin=0)\n",
    "\n",
    "gstack"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we can see the fixed-size ``GridStack`` fills the `800x600` pixels assigned to it and each of the Spacer objects has been resized to fill the alloted grid cells, including the empty grid cell in the center. A convenient way to get an overview of the grid without rendering it is to display the ``grid`` property, which returns an array showing which grid cells have been filled:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gstack.grid"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition to assigning objects to the grid we can also index the grid:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Row(gstack[2, 2], width=400, height=400)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And select a subregion using slicing semantics:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gstack[0, 1:]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The behavior when replacing existing grid cells can be controlled using the ``mode`` option. By default the ``GridStack`` will warn when assigning to one or more grid cells that are already occupied. The behavior may be changed to either error or override silently, by setting ``mode='error'`` or ``mode='override'`` respectively.\n",
    "\n",
    "### Fixed size grids\n",
    "\n",
    "We can also set explicit `width` and `height` values on a `GridStack`. Just like in the responsive mode, the ``GridStack`` will automatically set the appropriate sizing values on the grid contents to fill the space correctly. This means that when we resize a component and the state is synced with Python the new size is computed there and only then is the display updated:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import holoviews as hv\n",
    "import holoviews.plotting.bokeh\n",
    "\n",
    "from bokeh.plotting import figure\n",
    "\n",
    "fig = figure()\n",
    "fig.scatter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 2, 1, 0, -1, -2, -3])\n",
    "\n",
    "gstack = GridStack(width=800, height=600)\n",
    "\n",
    "gstack[0, :3] = pn.Spacer(background='#FF0000')\n",
    "gstack[1:3, 0] = pn.Spacer(background='#0000FF')\n",
    "gstack[1:3, 1:3] = fig\n",
    "gstack[3:5, 0] = hv.Curve([1, 2, 3])\n",
    "gstack[3:5, 1] = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'\n",
    "gstack[3:5, 2] = pn.Column(\n",
    "    pn.widgets.FloatSlider(),\n",
    "    pn.widgets.ColorPicker(),\n",
    "    pn.widgets.Toggle(name='Toggle Me!')\n",
    ")\n",
    "\n",
    "gstack"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
