{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "3c9af890-8b49-44fe-9279-4ef33aaaab2d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import remi.gui as gui\n",
    "from remi import start, App\n",
    "from threading import Timer, Thread\n",
    "import re"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "d1eacbad-a65d-4a50-9340-27268629b703",
   "metadata": {},
   "outputs": [],
   "source": [
    "remiport = 8086"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "261c2b8e-0919-49be-9fd2-79264a69eac9",
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyApp(App):\n",
    "    def __init__(self, *args):\n",
    "        super(MyApp, self).__init__(*args)\n",
    "\n",
    "    def _net_interface_ip(self):\n",
    "        ip = super()._net_interface_ip()\n",
    "        return ip + f\"/proxy/{remiport}\"\n",
    "    \n",
    "    def _overload(self, data, **kwargs):\n",
    "        if \"filename\" in kwargs:\n",
    "            filename = kwargs['filename']\n",
    "        else:\n",
    "            return data\n",
    "        paths = self.all_paths()\n",
    "        for pattern in paths.keys():\n",
    "            if ( filename.endswith(\".css\") or filename.endswith(\".html\") or filename.endswith(\".js\") or filename.endswith(\"internal\") ):\n",
    "                if type(data) == str:\n",
    "                    data = re.sub(f\"/{pattern}:\", f\"/proxy/{remiport}/{pattern}:\", data)\n",
    "                else:\n",
    "                    data = re.sub(f\"/{pattern}:\", f\"/proxy/{remiport}/{pattern}:\", data.decode()).encode()\n",
    "        return data\n",
    "\n",
    "    def _process_all(self, func, **kwargs):\n",
    "        print(kwargs)\n",
    "        kwargs.update({\"overload\": self._overload})\n",
    "        super()._process_all(func, **kwargs)\n",
    "\n",
    "    def idle(self):\n",
    "        self.counter.set_text('Running Time: ' + str(self.count))\n",
    "        self.progress.set_value(self.count%100)\n",
    "\n",
    "    def main(self):\n",
    "        # the margin 0px auto centers the main container\n",
    "        verticalContainer = gui.Container(width=540, margin='0px auto', style={'display': 'block', 'overflow': 'hidden'})\n",
    "\n",
    "        horizontalContainer = gui.Container(width='100%', layout_orientation=gui.Container.LAYOUT_HORIZONTAL, margin='0px', style={'display': 'block', 'overflow': 'auto'})\n",
    "        \n",
    "        subContainerLeft = gui.Container(width=320, style={'display': 'block', 'overflow': 'auto', 'text-align': 'center'})\n",
    "        self.img = gui.Image(f'/res:logo.png', height=100, margin='10px')\n",
    "        self.img.onclick.do(self.on_img_clicked)\n",
    "\n",
    "        self.table = gui.Table.new_from_list([('ID', 'First Name', 'Last Name'),\n",
    "                                   ('101', 'Danny', 'Young'),\n",
    "                                   ('102', 'Christine', 'Holand'),\n",
    "                                   ('103', 'Lars', 'Gordon'),\n",
    "                                   ('104', 'Roberto', 'Robitaille'),\n",
    "                                   ('105', 'Maria', 'Papadopoulos')], width=300, height=200, margin='10px')\n",
    "        self.table.on_table_row_click.do(self.on_table_row_click)\n",
    "\n",
    "        # the arguments are\twidth - height - layoutOrientationOrizontal\n",
    "        subContainerRight = gui.Container(style={'width': '220px', 'display': 'block', 'overflow': 'auto', 'text-align': 'center'})\n",
    "        self.count = 0\n",
    "        self.counter = gui.Label('', width=200, height=30, margin='10px')\n",
    "\n",
    "        self.lbl = gui.Label('This is a LABEL!', width=200, height=30, margin='10px')\n",
    "\n",
    "        self.bt = gui.Button('Press me!', width=200, height=30, margin='10px')\n",
    "        # setting the listener for the onclick event of the button\n",
    "        self.bt.onclick.do(self.on_button_pressed)\n",
    "\n",
    "        self.txt = gui.TextInput(width=200, height=30, margin='10px')\n",
    "        self.txt.set_text('This is a TEXTAREA')\n",
    "        self.txt.onchange.do(self.on_text_area_change)\n",
    "\n",
    "        self.spin = gui.SpinBox(1, 0, 100, width=200, height=30, margin='10px')\n",
    "        self.spin.onchange.do(self.on_spin_change)\n",
    "\n",
    "        self.progress = gui.Progress(1, 100, width=200, height=5)\n",
    "\n",
    "        self.check = gui.CheckBoxLabel('Label checkbox', True, width=200, height=30, margin='10px')\n",
    "        self.check.onchange.do(self.on_check_change)\n",
    "\n",
    "        self.btInputDiag = gui.Button('Open InputDialog', width=200, height=30, margin='10px')\n",
    "        self.btInputDiag.onclick.do(self.open_input_dialog)\n",
    "\n",
    "        self.btFileDiag = gui.Button('File Selection Dialog', width=200, height=30, margin='10px')\n",
    "        self.btFileDiag.onclick.do(self.open_fileselection_dialog)\n",
    "\n",
    "        self.btUploadFile = gui.FileUploader('./', width=200, height=30, margin='10px')\n",
    "        self.btUploadFile.onsuccess.do(self.fileupload_on_success)\n",
    "        self.btUploadFile.onfailed.do(self.fileupload_on_failed)\n",
    "\n",
    "        items = ('Danny Young','Christine Holand','Lars Gordon','Roberto Robitaille')\n",
    "        self.listView = gui.ListView.new_from_list(items, width=300, height=120, margin='10px')\n",
    "        self.listView.onselection.do(self.list_view_on_selected)\n",
    "\n",
    "        self.link = gui.Link(\"http://localhost:8081\", \"A link to here\", width=200, height=30, margin='10px')\n",
    "\n",
    "        self.dropDown = gui.DropDown.new_from_list(('DropDownItem 0', 'DropDownItem 1'),\n",
    "                                                   width=200, height=20, margin='10px')\n",
    "        self.dropDown.onchange.do(self.drop_down_changed)\n",
    "        self.dropDown.select_by_value('DropDownItem 0')\n",
    "\n",
    "        self.slider = gui.Slider(10, 0, 100, 5, width=200, height=20, margin='10px')\n",
    "        self.slider.onchange.do(self.slider_changed)\n",
    "\n",
    "        self.colorPicker = gui.ColorPicker('#ffbb00', width=200, height=20, margin='10px')\n",
    "        self.colorPicker.onchange.do(self.color_picker_changed)\n",
    "\n",
    "        self.date = gui.Date('2015-04-13', width=200, height=20, margin='10px')\n",
    "        self.date.onchange.do(self.date_changed)\n",
    "\n",
    "        self.video = gui.Widget( _type='iframe', width=290, height=200, margin='10px')\n",
    "        self.video.attributes['src'] = \"https://drive.google.com/file/d/0B0J9Lq_MRyn4UFRsblR3UTBZRHc/preview\"\n",
    "        self.video.attributes['width'] = '100%'\n",
    "        self.video.attributes['height'] = '100%'\n",
    "        self.video.attributes['controls'] = 'true'\n",
    "        self.video.style['border'] = 'none'\n",
    "                                     \n",
    "        self.tree = gui.TreeView(width='100%', height=300)\n",
    "        ti1 = gui.TreeItem(\"Item1\")\n",
    "        ti2 = gui.TreeItem(\"Item2\")\n",
    "        ti3 = gui.TreeItem(\"Item3\")\n",
    "        subti1 = gui.TreeItem(\"Sub Item1\")\n",
    "        subti2 = gui.TreeItem(\"Sub Item2\")\n",
    "        subti3 = gui.TreeItem(\"Sub Item3\")\n",
    "        subti4 = gui.TreeItem(\"Sub Item4\")\n",
    "        subsubti1 = gui.TreeItem(\"Sub Sub Item1\")\n",
    "        subsubti2 = gui.TreeItem(\"Sub Sub Item2\")\n",
    "        subsubti3 = gui.TreeItem(\"Sub Sub Item3\")\n",
    "        self.tree.append([ti1, ti2, ti3])\n",
    "        ti2.append([subti1, subti2, subti3, subti4])\n",
    "        subti4.append([subsubti1, subsubti2, subsubti3])\n",
    "        \n",
    "        # appending a widget to another, the first argument is a string key\n",
    "        subContainerRight.append([self.counter, self.lbl, self.bt, self.txt, self.spin, self.progress, self.check, self.btInputDiag, self.btFileDiag])\n",
    "        # use a defined key as we replace this widget later\n",
    "        fdownloader = gui.FileDownloader('download test', '../remi/res/logo.png', width=200, height=30, margin='10px')\n",
    "        subContainerRight.append(fdownloader, key='file_downloader')\n",
    "        subContainerRight.append([self.btUploadFile, self.dropDown, self.slider, self.colorPicker, self.date, self.tree])\n",
    "        self.subContainerRight = subContainerRight\n",
    "\n",
    "        subContainerLeft.append([self.img, self.table, self.listView, self.link, self.video])\n",
    "\n",
    "        horizontalContainer.append([subContainerLeft, subContainerRight])\n",
    "\n",
    "        menu = gui.Menu(width='100%', height='30px')\n",
    "        m1 = gui.MenuItem('File', width=100, height=30)\n",
    "        m2 = gui.MenuItem('View', width=100, height=30)\n",
    "        m2.onclick.do(self.menu_view_clicked)\n",
    "        m11 = gui.MenuItem('Save', width=100, height=30)\n",
    "        m12 = gui.MenuItem('Open', width=100, height=30)\n",
    "        m12.onclick.do(self.menu_open_clicked)\n",
    "        m111 = gui.MenuItem('Save', width=100, height=30)\n",
    "        m111.onclick.do(self.menu_save_clicked)\n",
    "        m112 = gui.MenuItem('Save as', width=100, height=30)\n",
    "        m112.onclick.do(self.menu_saveas_clicked)\n",
    "        m3 = gui.MenuItem('Dialog', width=100, height=30)\n",
    "        m3.onclick.do(self.menu_dialog_clicked)\n",
    "\n",
    "        menu.append([m1, m2, m3])\n",
    "        m1.append([m11, m12])\n",
    "        m11.append([m111, m112])\n",
    "\n",
    "        menubar = gui.MenuBar(width='100%', height='30px')\n",
    "        menubar.append(menu)\n",
    "\n",
    "        verticalContainer.append([menubar, horizontalContainer])\n",
    "\n",
    "        #this flag will be used to stop the display_counter Timer\n",
    "        self.stop_flag = False \n",
    "\n",
    "        # kick of regular display of counter\n",
    "        self.display_counter()\n",
    "\n",
    "        # returning the root widget\n",
    "        return verticalContainer\n",
    "\n",
    "    def display_counter(self):\n",
    "        self.count += 1\n",
    "        if not self.stop_flag:\n",
    "            Timer(1, self.display_counter).start()\n",
    "\n",
    "    def menu_dialog_clicked(self, widget):\n",
    "        self.dialog = gui.GenericDialog(title='Dialog Box', message='Click Ok to transfer content to main page', width='500px')\n",
    "        self.dtextinput = gui.TextInput(width=200, height=30)\n",
    "        self.dtextinput.set_value('Initial Text')\n",
    "        self.dialog.add_field_with_label('dtextinput', 'Text Input', self.dtextinput)\n",
    "\n",
    "        self.dcheck = gui.CheckBox(False, width=200, height=30)\n",
    "        self.dialog.add_field_with_label('dcheck', 'Label Checkbox', self.dcheck)\n",
    "        values = ('Danny Young', 'Christine Holand', 'Lars Gordon', 'Roberto Robitaille')\n",
    "        self.dlistView = gui.ListView.new_from_list(values, width=200, height=120)\n",
    "        self.dialog.add_field_with_label('dlistView', 'Listview', self.dlistView)\n",
    "\n",
    "        self.ddropdown = gui.DropDown.new_from_list(('DropDownItem 0', 'DropDownItem 1'),\n",
    "                                                    width=200, height=20)\n",
    "        self.dialog.add_field_with_label('ddropdown', 'Dropdown', self.ddropdown)\n",
    "\n",
    "        self.dspinbox = gui.SpinBox(min=0, max=5000, width=200, height=20)\n",
    "        self.dspinbox.set_value(50)\n",
    "        self.dialog.add_field_with_label('dspinbox', 'Spinbox', self.dspinbox)\n",
    "\n",
    "        self.dslider = gui.Slider(10, 0, 100, 5, width=200, height=20)\n",
    "        self.dspinbox.set_value(50)\n",
    "        self.dialog.add_field_with_label('dslider', 'Slider', self.dslider)\n",
    "\n",
    "        self.dcolor = gui.ColorPicker(width=200, height=20)\n",
    "        self.dcolor.set_value('#ffff00')\n",
    "        self.dialog.add_field_with_label('dcolor', 'Colour Picker', self.dcolor)\n",
    "\n",
    "        self.ddate = gui.Date(width=200, height=20)\n",
    "        self.ddate.set_value('2000-01-01')\n",
    "        self.dialog.add_field_with_label('ddate', 'Date', self.ddate)\n",
    "\n",
    "        self.dialog.confirm_dialog.do(self.dialog_confirm)\n",
    "        self.dialog.show(self)\n",
    "\n",
    "    def dialog_confirm(self, widget):\n",
    "        result = self.dialog.get_field('dtextinput').get_value()\n",
    "        self.txt.set_value(result)\n",
    "\n",
    "        result = self.dialog.get_field('dcheck').get_value()\n",
    "        self.check.set_value(result)\n",
    "\n",
    "        result = self.dialog.get_field('ddropdown').get_value()\n",
    "        self.dropDown.select_by_value(result)\n",
    "\n",
    "        result = self.dialog.get_field('dspinbox').get_value()\n",
    "        self.spin.set_value(result)\n",
    "\n",
    "        result = self.dialog.get_field('dslider').get_value()\n",
    "        self.slider.set_value(result)\n",
    "\n",
    "        result = self.dialog.get_field('dcolor').get_value()\n",
    "        self.colorPicker.set_value(result)\n",
    "\n",
    "        result = self.dialog.get_field('ddate').get_value()\n",
    "        self.date.set_value(result)\n",
    "\n",
    "        result = self.dialog.get_field('dlistView').get_value()\n",
    "        self.listView.select_by_value(result)\n",
    "\n",
    "    # listener function\n",
    "    def on_img_clicked(self, widget):\n",
    "        self.lbl.set_text('Image clicked!')\n",
    "\n",
    "    def on_table_row_click(self, table, row, item):\n",
    "        self.lbl.set_text('Table Item clicked: ' + item.get_text())\n",
    "\n",
    "    def on_button_pressed(self, widget):\n",
    "        self.lbl.set_text('Button pressed! ')\n",
    "        self.bt.set_text('Hi!')\n",
    "\n",
    "    def on_text_area_change(self, widget, newValue):\n",
    "        self.lbl.set_text('Text Area value changed!')\n",
    "\n",
    "    def on_spin_change(self, widget, newValue):\n",
    "        self.lbl.set_text('SpinBox changed, new value: ' + str(newValue))\n",
    "\n",
    "    def on_check_change(self, widget, newValue):\n",
    "        self.lbl.set_text('CheckBox changed, new value: ' + str(newValue))\n",
    "\n",
    "    def open_input_dialog(self, widget):\n",
    "        self.inputDialog = gui.InputDialog('Input Dialog', 'Your name?',\n",
    "                                           initial_value='type here', \n",
    "                                           width=500)\n",
    "        self.inputDialog.confirm_value.do(\n",
    "            self.on_input_dialog_confirm)\n",
    "\n",
    "        # here is returned the Input Dialog widget, and it will be shown\n",
    "        self.inputDialog.show(self)\n",
    "\n",
    "    def on_input_dialog_confirm(self, widget, value):\n",
    "        self.lbl.set_text('Hello ' + value)\n",
    "\n",
    "    def open_fileselection_dialog(self, widget):\n",
    "        self.fileselectionDialog = gui.FileSelectionDialog('File Selection Dialog', 'Select files and folders', False,\n",
    "                                                           '.')\n",
    "        self.fileselectionDialog.confirm_value.do(\n",
    "            self.on_fileselection_dialog_confirm)\n",
    "\n",
    "        # here is returned the Input Dialog widget, and it will be shown\n",
    "        self.fileselectionDialog.show(self)\n",
    "\n",
    "    def on_fileselection_dialog_confirm(self, widget, filelist):\n",
    "        # a list() of filenames and folders is returned\n",
    "        self.lbl.set_text('Selected files: %s' % ','.join(filelist))\n",
    "        if len(filelist):\n",
    "            f = filelist[0]\n",
    "            # replace the last download link\n",
    "            fdownloader = gui.FileDownloader(\"download selected\", f, width=200, height=30)\n",
    "            self.subContainerRight.append(fdownloader, key='file_downloader')\n",
    "\n",
    "    def list_view_on_selected(self, widget, selected_item_key):\n",
    "        \"\"\" The selection event of the listView, returns a key of the clicked event.\n",
    "            You can retrieve the item rapidly\n",
    "        \"\"\"\n",
    "        self.lbl.set_text('List selection: ' + self.listView.children[selected_item_key].get_text())\n",
    "\n",
    "    def drop_down_changed(self, widget, value):\n",
    "        self.lbl.set_text('New Combo value: ' + value)\n",
    "\n",
    "    def slider_changed(self, widget, value):\n",
    "        self.lbl.set_text('New slider value: ' + str(value))\n",
    "\n",
    "    def color_picker_changed(self, widget, value):\n",
    "        self.lbl.set_text('New color value: ' + value)\n",
    "\n",
    "    def date_changed(self, widget, value):\n",
    "        self.lbl.set_text('New date value: ' + value)\n",
    "\n",
    "    def menu_save_clicked(self, widget):\n",
    "        self.lbl.set_text('Menu clicked: Save')\n",
    "\n",
    "    def menu_saveas_clicked(self, widget):\n",
    "        self.lbl.set_text('Menu clicked: Save As')\n",
    "\n",
    "    def menu_open_clicked(self, widget):\n",
    "        self.lbl.set_text('Menu clicked: Open')\n",
    "\n",
    "    def menu_view_clicked(self, widget):\n",
    "        self.lbl.set_text('Menu clicked: View')\n",
    "\n",
    "    def fileupload_on_success(self, widget, filename):\n",
    "        self.lbl.set_text('File upload success: ' + filename)\n",
    "\n",
    "    def fileupload_on_failed(self, widget, filename):\n",
    "        self.lbl.set_text('File upload failed: ' + filename)\n",
    "\n",
    "    def on_close(self):\n",
    "        \"\"\" Overloading App.on_close event to stop the Timer.\n",
    "        \"\"\"\n",
    "        self.stop_flag = True\n",
    "        super(MyApp, self).on_close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "288af5fb-7a9c-4d0b-b7bc-6acb3146eb7d",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "remi.server      INFO     Started httpserver http://127.0.0.1:8086/\n"
     ]
    }
   ],
   "source": [
    "myRemi = Thread(target=start, \n",
    "                         args=(MyApp,),\n",
    "                         kwargs={'address':'127.0.0.1', \n",
    "                                 'port':remiport, \n",
    "                                 'multiple_instance':True,\n",
    "                                 'enable_file_cache':True, \n",
    "                                 'update_interval':0.5, \n",
    "                                 'start_browser':False,\n",
    "                                  })\n",
    "myRemi.start()  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7548e87-1260-4190-9947-1b5677554998",
   "metadata": {},
   "source": [
    "http://127.0.0.1:8888/proxy/8086/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c5435343-168e-4a00-a4d2-e245c622335b",
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import IFrame"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "edfabb0f-36bc-4114-bdc5-6bbf25dc8d17",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"100%\"\n",
       "            height=\"600px\"\n",
       "            src=\"http://localhost:8888/proxy/8086/\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "            \n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.IFrame at 0x21d76acd7c0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "remi.request     INFO     built UI (path=/)\n",
      "127.0.0.1 - - [24/Nov/2021 17:20:26] \"GET / HTTP/1.1\" 200 -\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{}\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "remi.server.ws   INFO     connection established: ('127.0.0.1', 49592)\n",
      "remi.server.ws   INFO     handshake complete\n"
     ]
    }
   ],
   "source": [
    "IFrame(src=f\"http://localhost:8888/proxy/{remiport}/\",width=\"100%\",height=\"600px\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b1ae2367-e0be-4332-a2aa-542afcabc8a2",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "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.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
