#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8

## EXTRAITS DE LA LICENCE
## Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2012-2012)
## Adresse mèl :
## CALISTE, damien P caliste AT cea P fr.

## Ce logiciel est un programme informatique servant à visualiser des
## structures atomiques dans un rendu pseudo-3D. 
## Ce logiciel est régi par la licence CeCILL soumise au droit français et
## respectant les principes de diffusion des logiciels libres. Vous pouvez
## utiliser, modifier et/ou redistribuer ce programme sous les conditions
## de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
## sur le site "http://www.cecill.info".
## Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
## pris connaissance de la licence CeCILL, et que vous en avez accepté les
## termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).

## LICENCE SUM UP
## Copyright CEA, contributors: Damien CALISTE, L_Sim laboratory, (2012-2012)
## E-mail address:
## CALISTE, damien P caliste AT cea P fr.

## This software is a computer program whose purpose is to visualize atomic
## configurations in 3D.
## This software is governed by the CeCILL  license under French law and
## abiding by the rules of distribution of free software.  You can  use, 
## modify and/ or redistribute the software under the terms of the CeCILL
## license as circulated by CEA, CNRS and INRIA at the following URL
## "http://www.cecill.info". 
## The fact that you are presently reading this means that you have had
## knowledge of the CeCILL license and that you accept its terms. You can
## find a copy of this licence shipped with this software at
## Documentation/licence.en.txt.

from gi.repository import v_sim
from gi.repository import Gtk

import numpy

from matplotlib.figure import Figure
from matplotlib.backends.backend_cairo import FigureCanvasCairo as FigureCanvas
from matplotlib.backends.backend_cairo import RendererCairo as Renderer

dpi = 100
fig_width = 3
fig_height = 2

def mplCurveDraw(widget, cr, f, renderer):
  renderer.gc.ctx = cr
  w = widget.get_allocated_width()
  h = widget.get_allocated_height()
  cr.translate(max(0, (w - fig_width * dpi) * 0.5),
               -max(0, (h - fig_height * dpi) * 0.5))
  renderer.set_width_height(w, h)
  f.draw(renderer)

def onTogglePick(widget, interPick, panel, wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref):
  render = v_sim.UiMainClass.getDefaultRendering()
  if (widget.get_active()):
    handle = interPick.connect("node-selection", onNodeSelected, panel, widget,
                               wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref)
    interPick.set_data("pick", handle)
    render.pushInteractive(interPick)
    render.pushMessage("Pick a node with the mouse")
  else:
    interPick.disconnect(interPick.get_data("pick"))
    render.popInteractive(interPick)
    render.popMessage()

def onNodeSelected(inter, kind, node0, node1, node2, panel, toggle,
                   entryX, entryY, entryZ, entryX_ref, entryY_ref, entryZ_ref):
  if not(kind == v_sim.InteractivePick.SELECTED):
    return

  data = panel.getData()
  (x, y, z) = data.getNodeCoordinates(node0)
  if entryX_ref is not None:
    entryX.setValue(x - entryX_ref.getValue())
  else:
    entryX.setValue(x)
  if entryY_ref is not None:
    entryY.setValue(y - entryY_ref.getValue())
  else:
    entryY.setValue(y)
  if entryZ_ref is not None:
    entryZ.setValue(z - entryZ_ref.getValue())
  else:
    entryZ.setValue(z)
  toggle.set_active(False)

def onDraw(widget, area, mplFig, panel, combo, (ox, oy, oz), (dx, dy, dz)):
  # We get the scalar field.
  it = combo.get_active_iter()
  if it is None:
    return
  model = combo.get_model()
  (field,) = model.get(it, v_sim.UiSurfacesFieldId.POINTER)
  data = panel.getData()

  # We setup the data to iterate over.
  orig = numpy.array(data.convertXYZToReduced((ox.getValue(), oy.getValue(), oz.getValue())))
  vect = numpy.array(data.convertXYZToReduced((dx.getValue(), dy.getValue(), dz.getValue())))
  norm = 1. / numpy.sqrt(vect[0] * vect[0] + vect[1] * vect[1] + vect[2] * vect[2])
  vect *= norm
  l0 = max(-orig[0] / max(vect[0], 1e-6), -orig[1] / max(vect[1], 1e-6), -orig[2] / max(vect[2], 1e-6))
  l1 = min((1. - orig[0]) / max(vect[0], 1e-6), (1. - orig[1]) / max(vect[1], 1e-6), (1. - orig[2]) / max(vect[2], 1e-6))
  orig0 = numpy.array(data.convertReducedToXYZ(tuple(orig + l0 * vect)))
  vect0 = numpy.array(data.convertReducedToXYZ(tuple(orig + l1 * vect))) - orig0
  norm = numpy.sqrt(vect0[0] * vect0[0] + vect0[1] * vect0[1] + vect0[2] * vect0[2])
  
  # We setup the data to be plotted.
  a = mplFig.add_subplot(111)
  x = numpy.arange(0.0, 1.0, 0.01)
  y = numpy.arange(0.0, 1.0, 0.01)
  for i in range(100):
    point = orig0 + x[i] * vect0
    (valid, val) = field.getValue(tuple(point), (0,0,0))
    if valid:
      y[i] = val
  x *= norm
  a.plot(x,y)
  # We ask for redraw of the widget.
  area.queue_draw()

def panelCreateSelection(panel, vbox, interPick, label,
                         wdx_ref = None, wdy_ref = None, wdz_ref = None):
  # The line to choose the origin/orientation.
  hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)
  vbox.pack_start(hbox, False, False, 0)

  lbl = Gtk.Label.new(label)
  hbox.pack_start(lbl, False, False, 0)

  wdx = v_sim.UiNumericalEntry.new(0.)
  wdx.set_width_chars(6)
  hbox.pack_start(wdx, True, True, 0)
  wdy = v_sim.UiNumericalEntry.new(0.)
  wdy.set_width_chars(6)
  hbox.pack_start(wdy, True, True, 0)
  wdz = v_sim.UiNumericalEntry.new(0.)
  wdz.set_width_chars(6)
  hbox.pack_start(wdz, True, True, 0)

  wd = Gtk.ToggleButton.new()
  wd.add(Gtk.Image.new_from_stock(Gtk.STOCK_FIND, Gtk.IconSize.MENU))
  wd.connect("toggled", onTogglePick, interPick, panel,
             wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref)
  hbox.pack_start(wd, False, False, 0)

  return (wdx, wdy, wdz)

def panelCreateWidgets():
  panel = v_sim.UiPanel.new("mytools", "Customized tools", "My tools")
  panel.setDockable(True)
  panel.attach(v_sim.UiPanelClass.getCommandPanel());

  vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
  panel.add(vbox)

  lbl = Gtk.Label.new("<b>Interpolate data along lines</b>")
  lbl.set_alignment(0., 0.5)
  lbl.set_use_markup(True)
  vbox.pack_start(lbl, False, False, 0)

  # The line to choose a data field.
  hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)
  vbox.pack_start(hbox, False, False, 0)

  lbl = Gtk.Label.new("Choose a data field:")
  hbox.pack_start(lbl, False, False, 0)

  combo = Gtk.ComboBox.new()
  combo.set_model(v_sim.UiPanel.surfaces_getFields())
  hbox.pack_start(combo, True, True, 0)
  renderer = Gtk.CellRendererText.new()
  combo.pack_start(renderer, False)
  renderer.set_property("xalign", 1.0)
  combo.add_attribute(renderer, "markup", v_sim.UiSurfacesFieldId.LABEL)

  interPick = v_sim.Interactive.new(v_sim.InteractiveId.PICK)

  # The line to choose the origin.
  (origx, origy, origz) = panelCreateSelection(panel, vbox, interPick,
                                               "Choose the origin:")

  # The line to choose the direction.
  (dirx, diry, dirz) = panelCreateSelection(panel, vbox, interPick,
                                            "Choose the direction:",
                                            wdx_ref = origx, wdy_ref = origy,
                                            wdz_ref = origz)
  dirx.setValue(1.)
  diry.setValue(1.)
  dirz.setValue(1.)

  # The drawing area for the curve.
  hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
  vbox.pack_start(hbox, True, True, 0)

  scrolled = Gtk.ScrolledWindow.new(None, None)
  scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
  hbox.pack_start(scrolled, True, True, 0)

  f = Figure(figsize=(fig_width,fig_height), dpi = dpi)
  canvas = FigureCanvas(f)
  f.set_canvas(canvas)
  renderer = Renderer(dpi = dpi)

  area = Gtk.DrawingArea.new()
  area.set_size_request(fig_width * dpi, fig_height * dpi)
  area.connect("draw", mplCurveDraw, f, renderer)
  scrolled.add_with_viewport(area)

  # The toolbar for action on the curve.
  wd = Gtk.Toolbar.new()
  wd.set_orientation(Gtk.Orientation.VERTICAL)
  wd.set_style(Gtk.ToolbarStyle.ICONS)
  wd.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR)
  hbox.pack_start(wd, False, False, 0)

  item = Gtk.ToolButton.new_from_stock(Gtk.STOCK_REFRESH)
  item.connect("clicked", onDraw, area, f, panel, combo,
               (origx, origy, origz), (dirx, diry, dirz))
  wd.insert(item, -1)

  return (f, panel, interPick)

# We create the widgets and plot the stuff.
(mplFig, panel, i) = panelCreateWidgets()
panel.show_all()

