text: #-----------------------------------------------------------------------------
  # Copyright (c) 2012 - 2019, Anaconda, Inc. and Intake contributors
  # All rights reserved.
  #
  # The full license is in the LICENSE file, distributed with this software.
  #-----------------------------------------------------------------------------
  from collections import OrderedDict
  import os
  import panel as pn
  
  
  MAX_WIDTH = 1600
  
  here = os.path.abspath(os.path.dirname(__file__))
  ICONS = {
      'logo': os.path.join(here, 'icons', 'logo.png'),
      'error': os.path.join(here, 'icons', 'baseline-error-24px.svg'),
  }
  
  def enable_widget(widget, enable=True):
      """Set disabled on widget"""
      widget.disabled = not enable
  
  
  def coerce_to_list(items, preprocess=None):
      """Given an instance or list, coerce to list.
  
      With optional preprocessing.
      """
      if not isinstance(items, list):
          items = [items]
      if preprocess:
          items = list(map(preprocess, items))
      return items
  
  
  class Base(object):
      """
      Base class for composable panel objects that make up the GUI.
  
      Parameters
      ----------
      children: list of panel objects
          children that will be used to populate the panel when visible
      panel: panel layout object
          instance of a panel layout (row or column) that contains children
          when visible
      watchers: list of param watchers
          watchers that are set on children - cleaned up when visible
          is set to false.
      visible: bool
          whether or not the instance should be visible. When not visible
          ``panel`` is empty.
      logo : bool, opt
          whether to show the intake logo in a panel to the left of the main
          panel. Default is False
      """
      children = None
      panel = None
      watchers = None
      visible_callback = None
      logo_panel = pn.Column(
          pn.pane.PNG(ICONS['logo'], align='center'), margin=(25, 0, 0, 0), width=50)
      logo = False
  
      def __init__(self, visible=True, visible_callback=None, logo=False):
          self.visible = visible
          self.visible_callback = visible_callback
          self.logo = logo
  
      @property
      def panel(self):
          if not self.logo:
              return self._panel
          return pn.Row(self.logo_panel,
                        self._panel,
                        margin=0)
  
      @panel.setter
      def panel(self, panel):
          self._panel = panel
  
      def servable(self, *args, **kwargs):
          return self.panel.servable(*args, **kwargs)
  
      def show(self, *args, **kwargs):
          return self.panel.show(*args, **kwargs)
  
      def __repr__(self):
          """Print output"""
          return self.panel.__repr__()
  
      def _repr_mimebundle_(self, *args, **kwargs):
          """Display in a notebook or a server"""
          try:
              return self.panel._repr_mimebundle_(*args, **kwargs)
          except:
              raise NotImplementedError("Panel does not seem to be set "
                                        "up properly")
  
      def setup(self):
          """Should instantiate widgets, set ``children``, and set watchers"""
          raise NotImplementedError
  
      @property
      def visible(self):
          """Whether or not the instance should be visible."""
          return self._visible
  
      @visible.setter
      def visible(self, visible):
          """When visible changed, do setup or unwatch and call visible_callback"""
          self._visible = visible
          if visible and len(self._panel.objects) == 0:
              self.setup()
              self._panel.extend(self.children)
          elif not visible and len(self._panel.objects) > 0:
              self.unwatch()
              self._panel.clear()
          if self.visible_callback:
              self.visible_callback(visible)
  
      def unwatch(self):
          """Get rid of any lingering watchers and remove from list"""
          if self.watchers is not None:
              unwatched = []
              for watcher in self.watchers:
                  watcher.inst.param.unwatch(watcher)
                  unwatched.append(watcher)
              self.watchers = [w for w in self.watchers if w not in unwatched]
  
      def __getstate__(self):
          """Serialize the current state of the object"""
          return {'visible': self.visible}
  
      def __setstate__(self, state):
          """Set the current state of the object from the serialized version.
          Works inplace. See ``__getstate__`` to get serialized version and
          ``from_state`` to create a new object."""
          self.visible = state.get('visible', True)
          return self
  
      @classmethod
      def from_state(cls, state):
          """Create a new object from a serialized exising object.
  
          Example
          -------
          original = cls()
          copy = cls.from_state(original.__getstate__())
          """
          return cls().__setstate__(state)
  
  
  class BaseSelector(Base):
      """Base class for capturing selector logic.
  
      Parameters
      ----------
      preprocess: function
          run on every input value when creating options
      widget: panel widget
          selector widget which this class keeps uptodate with class properties
      """
      preprocess = None
      widget = None
  
      @property
      def labels(self):
          """Labels of items in widget"""
          return self.widget.labels
  
      @property
      def items(self):
          """Available items to select from"""
          return self.widget.values
  
      @items.setter
      def items(self, items):
          """When setting items make sure widget options are uptodate"""
          if items is not None:
              self.options = items
  
      def _create_options(self, items):
          """Helper method to create options from list, or instance.
  
          Applies preprocess method if available to create a uniform
          output
          """
          return OrderedDict(map(lambda x: (x.name, x),
                             coerce_to_list(items, self.preprocess)))
  
      @property
      def options(self):
          """Options available on the widget"""
          return self.widget.options
  
      @options.setter
      def options(self, new):
          """Set options from list, or instance of named item
  
          Over-writes old options
          """
          options = self._create_options(new)
          if self.widget.value:
              self.widget.set_param(options=options, value=list(options.values())[:1])
          else:
              self.widget.options = options
              self.widget.value = list(options.values())[:1]
  
      def add(self, items):
          """Add items to options"""
          options = self._create_options(items)
          for k, v in options.items():
              if k in self.labels and v not in self.items:
                  options.pop(k)
                  count = 0
                  while f'{k}_{count}' in self.labels:
                      count += 1
                  options[f'{k}_{count}'] = v
          self.widget.options.update(options)
          self.widget.param.trigger('options')
          self.widget.value = list(options.values())[:1]
  
      def remove(self, items):
          """Remove items from options"""
          items = coerce_to_list(items)
          new_options = {k: v for k, v in self.options.items() if v not in items}
          self.widget.options = new_options
          self.widget.param.trigger('options')
  
      @property
      def selected(self):
          """Value selected on the widget"""
          return self.widget.value
  
      @selected.setter
      def selected(self, new):
          """Set selected from list or instance of object or name.
  
          Over-writes existing selection
          """
          def preprocess(item):
              if isinstance(item, str):
                  return self.options[item]
              return item
          items = coerce_to_list(new, preprocess)
          self.widget.value = items
  
  
  class BaseView(Base):
      def __getstate__(self, include_source=True):
          """Serialize the current state of the object. Set include_source
          to False when using with another panel that will include source."""
          if include_source:
              return {
                  'visible': self.visible,
                  'label': self.source._name,
                  'source': self.source.__getstate__(),
              }
          else:
              return {'visible': self.visible}
  
      def __setstate__(self, state):
          """Set the current state of the object from the serialized version.
          Works inplace. See ``__getstate__`` to get serialized version and
          ``from_state`` to create a new object."""
          if 'source' in state:
              self.source = state['source']
          self.visible = state.get('visible', True)
  
      @property
      def source(self):
          return self._source
  
      @source.setter
      def source(self, source):
          """When the source gets updated, update the select widget"""
          if isinstance(source, list):
              # if source is a list, get first item or None
              source = source[0] if len(source) > 0 else None
          self._source = source
  