{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Cell Editing\n",
    "DataGrid cells can be edited using in-place editors built into DataGrid. Editing can be initiated by double clicking on a cell or by starting typing the new value for the cell.\n",
    "\n",
    "DataGrids are not editable by default. Editing can be enabled by setting `editable` property to `True`. Selection enablement is required for editing to work and it is set automatically to `cell` mode if it is `none` when editing is enabled.\n",
    "\n",
    "### Cursor Movement\n",
    "Editing is initiated for the `cursor` cell. Cursor cell is the same as the selected cell if there is a single cell selected. If there are multiple cells / rectangles selected then cursor cell is the cell where the last selection rectangle was started.\n",
    "\n",
    "Cursor can be moved in four directions by using the following keyboard keys.\n",
    "- **Down**: Enter\n",
    "- **Up**: Shift + Enter\n",
    "- **Right**: Tab\n",
    "- **Left**: Shift + Tab\n",
    "\n",
    "Once done with editing a cell, cursor can be moved to next cell based on the keyboard hit following the rules above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipydatagrid import DataGrid\n",
    "from json import load\n",
    "import pandas as pd\n",
    "\n",
    "with open(\"./cars.json\") as fobj:\n",
    "    data = load(fobj)\n",
    "df = pd.DataFrame(data[\"data\"]).drop(\"index\", axis=1)\n",
    "\n",
    "datagrid = DataGrid(df, editable=True, layout={\"height\": \"200px\"})\n",
    "datagrid"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "All grid views are updated simultaneously to reflect cell edit changes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datagrid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# keep track of changed cells\n",
    "changed_cells = {}\n",
    "\n",
    "\n",
    "def create_cell_key(cell):\n",
    "    return \"{row}:{column}\".format(row=cell[\"row\"], column=cell[\"column_index\"])\n",
    "\n",
    "\n",
    "def track_changed_cell(cell):\n",
    "    key = create_cell_key(cell)\n",
    "    changed_cells[key] = cell"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Changes to cell values can be tracked by subscribing to `on_cell_change` event as below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def on_cell_changed(cell):\n",
    "    track_changed_cell(cell)\n",
    "    print(\n",
    "        \"Cell at primary key {row} and column '{column}'({column_index}) changed to {value}\".format(\n",
    "            row=cell[\"row\"],\n",
    "            column=cell[\"column\"],\n",
    "            column_index=cell[\"column_index\"],\n",
    "            value=cell[\"value\"],\n",
    "        )\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datagrid.on_cell_change(on_cell_changed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A cell's value can also be changed programmatically by using the DataGrid methods `set_cell_value` and `set_cell_value_by_index`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datagrid.set_cell_value(\"Cylinders\", 2, 12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Whether new cell values are entered using UI or programmatically, both the DataGrid cell rendering and the underlying python data are updated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datagrid.data.iloc[2][\"Cylinders\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datagrid.set_cell_value_by_index(\"Horsepower\", 3, 169)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datagrid.data.iloc[3][\"Origin\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def select_all_changed_cells():\n",
    "    datagrid.clear_selection()\n",
    "    for cell in changed_cells.values():\n",
    "        datagrid.select(cell[\"row\"], cell[\"column_index\"])\n",
    "\n",
    "    return datagrid.selected_cells"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Show all cells changed using UI or programmatically by selecting them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "select_all_changed_cells()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Setting an entire row at once is also possible."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datagrid.set_row_value(0, [260, \"USA\", 10, \"Very fast car\", \"\", 0, \"1999-01-01\", 0, 0, 0])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}