Using the HTML browser dialog - a location browser

Macro file: browser.lym

The HTML browser dialog is very handy to implement simple user interfaces based on HTML code and a client/server scheme. This setup is similar to that of the HTTP client/server pair. The BrowserDialog object acts as a HTML browser and a BrowserSource object is used to deliver the HTML code for that browser.

In the HTML browser, each link that uses the "int:" scheme is resolved by asking the BrowserSource object for the data for that URL. This scheme can be used to build user interfaces in the same way a web application would implement a simple user interface.

In addition to simply delivering data, the BrowserSource object may perform actions on the KLayout API, such as zooming to a certain location, opening files, etc. This enables a new class of applications based on HTML and direct interaction with the application core.

The example given here employs this technique to implement a simple location browser: given a set of three locations, the user can browse to one of these locations by clicking the link. To try this application, load a layout and use "Browser example" from the "Tools/Example" menu.

Source code

module Examples

  # ---------------------------------------------------------------------------
  #  The HTML browser object
  
  class Browser < RBA::BrowserDialog
  
    def open
      @browser_source = Server.new(self)
      self.set_source(@browser_source)
      self.show
    end
  
    def closed
      @browser_source.close
      @browser_source = nil
    end
  
  end
  
  # ---------------------------------------------------------------------------
  #  The data provider for the browser 
  
  class Server < RBA::BrowserSource
  
    #  set up the data provider
    def initialize(browser)
  
      #  this is an arbitrary list of locations to go to
      @boxes = [ RBA::DBox::new(-10.0, 110.0, 10.0, 130.0),
                 RBA::DBox::new(10.0, 100.0, 12.0, 103.0),
                 RBA::DBox::new(22.0, -10.0, 23.0, -11.0) ]
  
      @marker = nil
      @visited = []
      @boxes.size.times { @visited.push(false) }
      @browser = browser
  
    end
  
    #  on close, destroy the marker 
    def close
      if @marker != nil
        @marker.destroy
      end
      @marker = nil
    end
  
    #  reimplementation of the data provider's main function
    def get( url )
  
      if url =~ /^int:zoom_to\?(\d+)/
        #  navigate to the specified position
        navigate($1.to_i)
        #  deliver nothing - this will make the browser not reload a new page here
        return ""
      else 
        #  deliver the index page
        return self.index
      end
  
    end
  
    #  deliver the index page
    def index
      r = "<html><h1>Locations to select</h1><p><p>"
      @boxes.size.times do |index|
        if @visited[index]
          #  visited locations are shown in red color
          r += "<a style=\"color:#ff0000\" href=\"int:zoom_to?#{index}\">Zoom to location " + @boxes[index].to_s + "</a><p>"
        else
          r += "<a href=\"int:zoom_to?#{index}\">Zoom to location " + @boxes[index].to_s + "</a></b><p>"
        end
      end
      return r
    end
  
    #  go to a certain location
    def navigate(loc_index)
  
      if loc_index < @boxes.size
  
        #  mark this location as visited
        @visited[loc_index] = true
  
        #  place the marker on the current view. If no view is opened, this may be nil!
        view = RBA::Application::instance.main_window.current_view
        if view != nil
  
          #  zoom to the specified position (put 10 micron space around that location to 
          #  get the displayed rectangle)
          box = @boxes[loc_index]
          view.zoom_box(box.enlarged(RBA::DPoint::new(10.0, 10.0)))
  
          #  before creating a new marker, delete the current marker unless it was destroyed already 
          #  (this is a recommended safty measure)
          if @marker != nil && !@marker.destroyed
            @marker.destroy
          end
  
          #  create a new marker that shows the box selected
          @marker = RBA::Marker::new(view)
          @marker.set_box(box)
  
        end
  
        #  force a reload of the page (necessary, since the color of the links may have changed)
        @browser.reload 
  
      end
  
    end
  
  end
  
  # ---------------------------------------------------------------------------
  #  Open the browser
  
  # Destroy any existing one
  @browser && @browser._destroy
  
  # Create a new one and open it
  @browser = Browser.new
  @browser.open

end