#!/usr/bin/env wish

###############################################################################
#
# mpeditor.tcl
#
# Un éditeur metapost en Tcl/Tk
#
# Copyright (C) 2003 David COBAC - dcobac@larochelle-innovation.com
#
# Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le
# modifier conformément aux dispositions de la Licence Publique Générale GNU,
# telle que publiée par la Free Software Foundation ; version 2 de la licence,
# ou toute version ultérieure.
#
# Ce programme est distribué dans l'espoir qu'il sera utile, mais SANS AUCUNE
# GARANTIE ; sans même la garantie implicite de COMMERCIALISATION ou
# D'ADAPTATION A UN OBJET PARTICULIER. Pour plus de détail, voir la Licence
# Publique Générale GNU.
#
# Version 0.2.2 du 01 janvier 2004 par David Cobac
#
###############################################################################

# ces options sont données par gtklook.tcl
option add *borderWidth 1 widgetDefault
option add *activeBorderWidth 1 widgetDefault
option add *selectBorderWidth 1 widgetDefault

option add *padX 2
option add *padY 4

option add *Listbox.background white
option add *Listbox.selectBorderWidth 0
option add *Listbox.selectForeground white
option add *Listbox.selectBackground #4a6984

option add *Entry.background white
option add *Entry.selectBorderWidth 0
option add *Entry.selectForeground white
option add *Entry.selectBackground #4a6984

option add *Text.background white
option add *Text.selectBorderWidth 0
option add *Text.selectForeground white
option add *Text.selectBackground #4a6984

option add *Menu.activeBackground #4a6984
option add *Menu.activeForeground white
option add *Menu.activeBorderWidth 0
option add *Menu.highlightThickness 0
option add *Menu.borderWidth 2

option add *MenuButton.activeBackground #4a6984
option add *MenuButton.activeForeground white
option add *MenuButton.activeBorderWidth 0
option add *MenuButton.highlightThickness 0
option add *MenuButton.borderWidth 0

option add *highlightThickness 0
option add *troughColor #bdb6ad

option add *Font {Helvetica 10}

set Chemin(abs) [pwd]
set NomScript [info script]
set Chemin(rel) [file dirname $NomScript]

namespace eval Editeur {
	
    variable application mpeditor
    variable version 0.2.2
    variable ausujetdeDC  { "David COBAC" "dcobac@larochelle-innovation.com"\
				"http://dcobac.free.fr"\
				"Décembre 2003 / Janvier 2004" }
    variable fichier
    variable types {
	{{Fichiers metapost} {.mp}}
    }
    
    variable travailencours 0
    variable langage
    variable listLang
    variable motscles
    set motscles(mp) \
	[list abs ahangle ahlength and angle arclength arctime background bbox bboxmargin\
	     beveled black blue bluepart boolean bot bp butt cc ceiling center char\
	     charcode circleit circmargin clip cm color controls cosd curl currentpen\
	     currentpicture cutafter cutbefore cutdraw cuttings cycle dashed dashpattern\
	     day dd decimal decr def defaultdx defaultdy defaultfont defaultpen\
	     defaultscale dir direction directionpoint directiontime ditto div dotlabel\
	     dotlabels dotprod down downto draw draw_mark draw_marked drawarrow\
	     drawboxed drawboxes drawdblarrow drawoptions drawshadowed drawunboxed else\
	     elseif end enddef endfig endfor endgroup epsilon evenly exitif exitunless\
	     expr expression extra_endfig extra_beginfig false fi false fill filldraw\
	     fixpos fixsize floor fontsize for forever forsuffixes fullcircle getmid\
	     green greenpart halfcircle hex hide identity if in inclinaison incr infinity\
	     infont input interim intersection intersectionpoint intersectiontimes\
	     inverse joinup kerning known label labeloffset labels left length let lft\
	     linecap linejoin llcorner llft logginall lrcorner lrt  makepath makepen\
	     mark_angle draw_rt_angle max mexp middlepoint midpoint min mitered\
	     miterlimit mlog mm mod month mp newinternal normaldeviate not nullpicture\
	     numeric oct odd off on nul of or origin pair path pausing pc pen pencircle\
	     penoffset pensquare pic pickup picture point precontrol primary primarydef\
	     prologues pt quartercircle red redpart reflectedabout relation reverse right\
	     rlap rotated rotatedaround rotation round rounded rt save scaled\
	     secondarydef self setbounds shifted shipout show showdependencies\
	     showstopping showtoken showvariable sind slanted special sqrt squared step\
	     str string strut subpath substring suffix tag tension tertiarydef text\
	     thelabel time token tag to top tracingall tracingcapsules tracingchoices\
	     tracingcommands tracingequations tracinglostchars tracingmacros tracingnone\
	     tracingonline tracingoutput tracingrestores tracingspecs tracingstats\
	     tracingtitles transform transformed true truecorners figure ulcorner ulft\
	     undraw unfill unfilldraw uniformdeviate unitsquare unitvector unknown until\
	     up upto urcorner urt vardef warningcheck whatever white withcolor withdots\
	     withpen xpart xscaled xxpart xypart year ypart yscaled yxpart yypart zscaled ]
	
    set motscles(tex) [list btex etex verbatimtex]

    variable debut
    variable fin
    variable couleur
    # mpost
    set couleur(0) red
    # points virgules
    set couleur(1) lightgreen
    # variable
    set couleur(2) lightblue
    # beginfig et endfig
    set couleur(3) #0098ff
    # inclusion tex
    set couleur(4) green
    # commentaire
    set couleur(5) #9fbc9f
    # fond
    set couleur(fond) black
    # curseur
    set couleur(curseur) white
    # taille de la police
    variable sz 16
    variable ListeRecents {}
    variable ListeProcs {}
    variable ListeOccurences {}
}

# Editeur::afficherTaille
#        affiche la taille du buffer affiché

proc Editeur::afficherTaille { etiquette } {
    variable fichier
    $etiquette configure -text "[ file size $fichier ] octets"
}

# Editeur::Ouvrir
#        ouverture d'un fichier à traiter

proc Editeur::Ouvrir { widtexte } {
    global Chemin
    variable application
    variable fichier
    variable types
    
    set choix [ tk_getOpenFile -title "$application : 0uvrir"\
		    -initialdir $Chemin(rel) -filetypes $types]
    if [ string compare $choix "" ] {
	set resultat [ Editeur::chargerTexte $widtexte $choix ]
	if { $resultat == 0 } {
	    set fichier $choix
	    Editeur::Recents $choix
	    Editeur::MiseAJour $widtexte
	}
    }
}

# Editeur::Fermer
#        fermeture du fichier actuellement traitée
#        TODO : demander une sauvegarde éventuelle

proc Editeur::Fermer { widtexte } {
    variable application
    variable version
    variable fichier
    variable langage
    variable motscles
    
    $widtexte delete 0.0 end
    .fpw.fcompil.text delete 0.0 end
    set fichier ""
    set langage ""
    
    wm title . "$application version : $version"
}

# Editeur::Sauvegarder
#        sauvegarder (sous) le buffer actuel

proc Editeur::Sauvegarder { widtexte flag } {
    variable application
    variable fichier
    variable types
    
    if {$flag==1} {
	set choix [ tk_getSaveFile -title "$application : Sauvegarder sous"\
			-defaultextension .mp -filetypes $types] ;
    } else {
	if [catch {set choix $fichier}] {
	    tk_messageBox -type ok -icon warning \
		-message "Aucun fichier n'a encore été défini, utilisez :
\"Sauvegarder sous\"."
	    return
	}
    }
    
    if {$choix==""} {
	tk_messageBox -type ok -icon warning \
	    -message "Erreur d'écriture ... le fichier n'a pas été enregistré."
    } else {
	set idf [open $choix w]
	set contenu [ $widtexte get 1.0 end ]
	puts -nonewline $idf $contenu
	close $idf
	set fichier $choix
	Editeur::afficherTaille .fetat.taille
	if {$flag==1} {
	    Editeur::MiseAJour $widtexte
	}
    }
}

# Editeur::MiseAJour
#        Actualisation de l'affichage notamment la coloration

proc Editeur::MiseAJour { widtexte } {
    variable application
    variable version
    variable fichier
    variable langage
	
    set langage [ string range [file extension $fichier] 1 end]
    wm title . "$application version $version traite : $fichier"
    Editeur::ouvrirFicLang
    Editeur::Coloration $widtexte 1
    Editeur::afficherTaille .fetat.taille
    Editeur::NbLignes .fpw.ftext.text .fetat.nblignes
}

# Editeur::chargerTexte
#        chargement du contenu d'un fichier

proc Editeur::chargerTexte { widtexte choix } {
    variable application
    if [ catch { open $choix } FIC ] {
	tk_messageBox -type ok -icon warning \
	    -message "Impossible d'ouvrir le fichier $choix"
	return 1
    } else {
	$widtexte delete 0.0 end
	set contenu [ read -nonewline $FIC ]
	regsub -all {\ {4}} $contenu "\t" contenu
	$widtexte insert 0.0 $contenu
	close $FIC
	return 0
    }
}

# Editeur::toutSelectionner
#        Sélection de tout le buffer

proc Editeur::toutSelectionner { widtexte } {
    $widtexte tag add sel 0.0 end
}

# Editeur::Defaire
#        Retour en arrière sur la dernière commande

proc Editeur::Defaire { widtexte } {
    catch {$widtexte edit undo}
}

# Editeur::Refaire
#        Refaire une action précédemment annulée

proc Editeur::Refaire { widtexte } {
    catch {$widtexte edit redo}
}

# Editeur::Copier
#        Copie dans le presse-papier de la sélection

proc Editeur::Copier { widtexte } {
    set ranges [ $widtexte tag ranges sel ]
    if { [llength $ranges] == 0 } { return }
    set i1 [ lindex $ranges 0 ]; set i2 [ lindex $ranges 1 ]
    set texte [ $widtexte get $i1 $i2 ]
    clipboard clear
    clipboard append $texte
    return [list $i1 $i2]
}

# Editeur::Coller
#        Collage à l'endroit courant du contenu du presse-papier

proc Editeur::Coller { widtexte } {
	if [ catch { selection get -selection CLIPBOARD } texte ] { return }
	$widtexte insert insert $texte
}

# Editeur::Couper
#        Copier + Effacer

proc Editeur::Couper { widtexte } {
	set indices [Editeur::Copier]
	$widtexte delete [lindex $indices 0] [lindex $indices 1]
}

# Editeur::indentationAuto
#        Indentation automatique
#        TODO: à améliorer avec string repeat

proc Editeur::indentationAuto { widtexte } {
    set position [expr {int([$widtexte index insert])-1}]
    set indice [$widtexte search -forwards -count long\
		    -regexp (\\t)* ${position}.0 ${position}.end]
    if {[info exists long]==0} {return}
    set espace ""
    for {set i 1} {$i<=$long} {incr i} {
	append espace "\t"
    }
    $widtexte insert  [$widtexte index insert] $espace
}

# Editeur::Indenter
#        Indente tout le buffer
#        TODO: peut-être faire ligne par ligne...

proc Editeur::Indenter {widtexte} {
    set contenu [$widtexte get 1.0 end]
    regsub -all {\ {4}} $contenu "\t" contenu
    $widtexte delete 1.0 end
    $widtexte insert 1.0 $contenu
}

# Editeur::Quitter
#        On quitte ... snif !

proc Editeur::Quitter {} {
	Editeur::EnregConfig
	Editeur::EnregListeRecents
	destroy .
	exit
}

# Editeur::Recents
#        Actualise la liste récent au besoin

proc Editeur::Recents {fic} {
    variable ListeRecents
    
    if {[lsearch $ListeRecents $fic]!=-1} {return}
    
    set liste [list $fic]
    foreach el $ListeRecents {
	lappend liste $el
    }
    set ListeRecents [lrange $liste 0 9]
    
    Editeur::MaJMenuRecents
}

# Editeur::EnregListeRecents
#        Enregistre la liste des récents pour la récupérer
#        au prochain démarrage

proc Editeur::EnregListeRecents { } {
    global Chemin
    variable ListeRecents
    
    set fichier [open [file join $Chemin(rel) .mpeditor-Recents] w]
    foreach fic $ListeRecents {
	puts $fichier $fic
    }
    close $fichier
}

# Editeur::LectureListeRecents
#        Lit le fichier contenant la liste écent
#        et actualise la variable pour affichage

proc Editeur::LectureListeRecents { } {
    global Chemin
    variable ListeRecents
    
    if {![catch {
	set fichier [open [file join $Chemin(rel) .mpeditor-Recents] r]}]} {
	while {![eof $fichier]} {
	    set capture [gets $fichier]
	    if {$capture!=""} {
		append ListeRecents " [list $capture]"
	    }
	}
	close $fichier
    }
}

# Editeur::MaJMenuRecents
#        Actualise l'affcihage des récents...

proc Editeur::MaJMenuRecents {} {
    variable ListeRecents
    
    set Fichier .menubar.mFichier
    
    $Fichier.lRecents delete 0 end
    foreach el $ListeRecents {
	$Fichier.lRecents  add command -label $el\
	    -command "Editeur::OuvrirRecents .fpw.ftext.text $el"
    }
}

# Editeur::OuvrirRecents
#        Demande après sélection l'ouverture d'un fichier
#        dans la liste des récents

proc Editeur::OuvrirRecents {widtexte choix} {
    variable fichier
    
    set resultat [ Editeur::chargerTexte $widtexte $choix ]
    if { $resultat == 0 } {
	set fichier $choix
	Editeur::MiseAJour $widtexte
    }
}

# Editeur::ouvrirFicLang
#        Actualise la liste des langages à colorer

proc Editeur::ouvrirFicLang { } {
    variable langage
    variable listLang
    
    if { $langage=="mp" } {
	set listLang {mp tex}
    } 
}


##############################################################################
########################## Couleurs et préférences ###########################
##############################################################################

# Editeur::zoneColoration
#        Identifie le début et la fin de la zone à colorer

proc Editeur::zoneColoration { widtexte flag } {
    variable debut
    variable fin
    if {$flag==1} {
	set debut 1.0
	set fin end
    } else {
	set debut [$widtexte index "insert linestart"]
	set fin [$widtexte index "insert lineend"]
    }
}

# Editeur::Coloration
#        Procédure de coloration

proc Editeur::Coloration { widtexte flag } {
    variable travailencours
    variable debut
    variable fin
    variable couleur
    variable motscles
    variable langage
    variable listLang
	
	
    if {$travailencours==1} {return}
    if  {[ info exists langage]==0} {return}
    set travailencours 1
    if {$flag==1} {.fetat.message configure\
		       -text "Travail de coloration en cours ...\
		veuillez patienter";update}
	

    set DifferentesParties {0 espacenom 1 Env 2 var}
    set nb [ llength $listLang ]
    
    for { set u 0 } { $u<$nb } { incr u } {
	set LeLangage [ lindex $listLang $u ]

	lappend DifferentesParties [ expr {$u+3} ] $LeLangage

	# construction des expressions régulières
	# correspondant aux mots clés des langages.
	set ExReg([ expr {$u+3} ]) "("
	append ExReg([ expr {$u+3} ]) \
	    [ string map { " " | } $motscles($LeLangage) ]
	append ExReg([ expr {$u+3} ]) ")"
    }
	
    lappend DifferentesParties [expr {$nb+3}] commentaire
    
    Editeur::zoneColoration $widtexte $flag
    
    # attribution des noms de tags
    # et destruction des tags existants
    foreach {k espece} $DifferentesParties {
	set nom($k) $espece
	$widtexte tag remove $espece $debut $fin
    }
    
    
    set com(0) { -regexp "$ExReg(3)" $debut $fin }
    set com(1) { ";" $debut $fin }
    set com(2) { -regexp {\s*\$(\w|\(|\)|\:|\{|\})+} $debut $fin }
    set com(3) { -regexp {(begin|end)fig(\([0-9]+\)|\s*)} $debut $fin }
    #set com(4) { -regexp "\\s*$ExReg(4)\\s*" $debut $fin }
    set com(4) { -regexp {(btex .* etex)|(\\.*)} $debut $fin}
    set com(5) { -regexp {^\s*%.*$} $debut $fin }
	
	
    for {set j 0} {$j<=5} {incr j} {
	set com($j) "$widtexte search -forwards -count long($j) $com($j)"
	set i($j) [eval $com($j)]
    }		
    
    
    # boucle principale de la recherche des correspondances
    # pour la coloration
    while 1 {
	
	if {[join $i(0)$i(1)$i(2)$i(3)$i(4)$i(5)]==""} {break}
	set min [lindex [lsort -real "$i(0) $i(1) $i(2) $i(3) $i(4) $i(5)"] 0]
	
	for {set u 0} {$u<=5} {incr u} {
	    if {$i($u)==$min} {
		set k $u
		break
	    }
	}
	
	$widtexte tag add $nom($k) $i($k) "$i($k) + $long($k) char"
	set debut "$i($k) + $long($k) char"
	
	# on ne recalcule que celui qu'on vient d'utiliser
	set i($k) [eval $com($k)]
	
    }
    
    for { set k 5 } { $k>=0 } { incr k -1} {
	$widtexte tag configure $nom($k) -foreground $couleur($k)
    }
    
    set travailencours 0
    .fetat.message configure -text ""
    update
}

# Editeur::Couleurs
#        Affiche une fenêtre de sélection des couleurs mots-clés
	
proc Editeur::Couleurs { } {
    variable couleur
    
    destroy .fenCoul
    toplevel .fenCoul
    wm title .fenCoul "Choix des couleurs"
    wm resizable .fenCoul false false
    
    set Coul " {Mots courants} 0 \; 1 Variable 2 (begin|end)fig 3 TeX 4 Commentaires 5 Fond fond Curseur curseur"
    foreach {chose cle} $Coul {
	pack [button .fenCoul.$cle -text $chose -width 25 -bg $couleur($cle)\
		  -command "Editeur::ModCouleur $cle" ]
    }
    
    button .fenCoul.ok -text "OK" -width 10 -command "destroy .fenCoul"
    button .fenCoul.defaut -text "Par défaut"\
	-width 10	-command "Editeur::ModCouleur defaut;destroy .fenCoul"
    pack .fenCoul.ok .fenCoul.defaut -side left -expand 1 -fill x
}

# Editeur::ModCouleur
#        Fixe les couleurs pour les différents types de mots à colorer

proc Editeur::ModCouleur {cle} {
    variable couleur
    
    if {$cle=="defaut"} {
	# mpost
	set couleur(0) red
	# points virgules
	set couleur(1) lightgreen
	# variable
	set couleur(2) lightblue
	# beginfig et endfig
	set couleur(3) #0098ff
	# inclusion tex
	set couleur(4) green
	# commentaire
	set couleur(5) #9fbc9f
	# fond
	set couleur(fond) black
	# curseur
	set couleur(curseur) white
    } else {
	set nouvellecouleur [tk_chooseColor -initialcolor $couleur($cle) \
				 -parent .fenCoul\
				 -title "Choisir une couleur"]
	if {$nouvellecouleur==""} {destroy .fenCoul;return}
	set couleur($cle) $nouvellecouleur
	if {$cle=="fond"} {
	    .fpw.ftext.text configure -bg $nouvellecouleur
	} elseif {$cle=="curseur"} {
	    .fpw.ftext.text configure -fg $nouvellecouleur\
		-insertbackground $nouvellecouleur
	} else {
	    .fpw.ftext.text tag configure $cle -foreground $nouvellecouleur
	}
	.fenCoul.$cle configure -bg $nouvellecouleur
    }
}

# Editeur::TaillePolice
#        Affiche une toplevel de sélection de taille de la police

proc Editeur::TaillePolice {} {
    variable sz
    
    destroy .choixsz
    toplevel .choixsz
    wm title .choixsz "Taille de la police"
    wm resizable .choixsz false false
    
    frame .choixsz.f1;set w .choixsz.f1
    label $w.l -text "Taille de la police"
    entry $w.e -bg white -width 3
    button $w.b -text "Par défaut" \
	-command "set sz 16;.fpw.ftext.text configure -font \"Courier 16\";destroy .choixsz"
    pack $w.l $w.e $w.b -side left -fill x
    
    frame .choixsz.f2;set w .choixsz.f2
    button $w.b1 -text OK \
	-command "set sz \[.choixsz.f1.e get\]
.fpw.ftext.text configure -font \"Courier \$sz\"
destroy .choixsz "
    button $w.b2 -text "Annuler" -command "destroy .choixsz"
    pack  $w.b1 $w.b2 -side left -expand 1 -fill x
    
    pack .choixsz.f1 -fill x
    pack .choixsz.f2 -fill x
    
    .choixsz.f1.e insert end $sz
}

###############################################################################
######################## aides programmeur metapost ###########################
###############################################################################

proc Editeur::InsertionCode { widtexte code } {
    switch $code {
	fig {
	    set contenu [ $widtexte get 1.0 end ]
	    set nb [expr {[regexp -all beginfig $contenu]-1}]
	    set code "%\nbeginfig([incr nb]);\n\nendfig;"
	    set pos  "insert - 1 lines"
	}
	latex  {
	    set code "btex  etex"
	    set pos  "insert - 5 chars"
	}
	platex {
	    set code "verbatimtex\n%&latex
\\documentclass{article}
\\usepackage\[T1\]{fontenc}
\\usepackage\[frenchb\]{babel}
\\begin{document}\netex\n"
	    set pos  "insert"
	}
    }
    # le deuxième "insert" est le nom spécial de la marque actuelle
    # de la position du curseur
    $widtexte insert insert $code
    $widtexte mark set insert $pos
}



proc Editeur::RechercheFigs { widtexte } {
    variable ListeProcs
    set debut 1.0
    set ListeProcs ""
    while 1 {
	set indice [$widtexte search -forwards -regexp {^\s*proc} $debut end]
	if {$indice==""} {break}
	set indice [$widtexte search -forwards -count longueur\
			-regexp {\s*[a-zA-Z]+[a-zA-Z0-9]*(::)*[a-zA-Z0-9]+\s} "$indice + 4 char" end]
	append ListeProcs "[$widtexte get $indice "$indice + $longueur char"] $indice"
	set debut "$indice + $longueur char"
    }
    return $ListeProcs
}

proc Editeur::AfficheListeFigs { widtexte } {
    variable ListeProcs
    variable couleur
    
    destroy .fpw.ftext.text.fenprocs
    destroy .fpw.ftext.text.sy
    text .fpw.ftext.text.fenprocs -wrap word -bg $couleur(fond)\
	-fg $couleur(curseur) -tabs {1c} -font "Helvetica 14"\
	-yscrollcommand ".fpw.ftext.text.sy set"
    scrollbar .fpw.ftext.text.sy -orient vertical\
	-command ".fpw.ftext.text.fenprocs yview"
    
    Editeur::RechercheFigs $widtexte
    set max 0
    set compteur 0
    foreach {el i} $ListeProcs {
	incr compteur
	set l [string length $el]
	if {$l>$max} {set max $l}
	.fpw.ftext.text.fenprocs insert end $el
	.fpw.ftext.text.fenprocs tag add\
	    $el "current linestart" "current lineend"
	.fpw.ftext.text.fenprocs tag configure\
	    $el -foreground blue -underline 1
	.fpw.ftext.text.fenprocs tag bind $el <1> "
			destroy .fpw.ftext.text.fenprocs
			destroy .fpw.ftext.text.sy
			$widtexte delete {current linestart} {current lineend + 1 char}
			$widtexte see $i
		"
	.fpw.ftext.text.fenprocs insert end \n
    }
    .fpw.ftext.text.fenprocs insert 1.0	"Liste des $compteur procédures\n\n"
    .fpw.ftext.text.fenprocs configure -width [expr {$max+2}]
    
    .fpw.ftext.text window create "current linestart"\
	-window .fpw.ftext.text.fenprocs
    .fpw.ftext.text window create current -window .fpw.ftext.text.sy -stretch 1
    .fpw.ftext.text insert current \n
    bind .fpw.ftext.text.fenprocs <3> "
		destroy .fpw.ftext.text.fenprocs
		destroy .fpw.ftext.text.sy
		$widtexte delete {current linestart} {current lineend + 1 char}
	"
}

proc Editeur::RechercherElement { widtexte element bit } {
    variable ListeOccurences
    
    set debut 1.0
    
    set ListeOccurences ""
    if {$bit==1} {
	set com "-regexp $element"
    } else {
	set com $element
    }
    
    while 1 {
	set lacom "$widtexte search -forwards -count longueur $com \"$debut\" end"
	set indice [eval $lacom]
	if {$indice==""} {break}
	lappend ListeOccurences $indice
	set debut "$indice + $longueur char"
    }
    return $ListeOccurences
}

proc Editeur::AfficheListeOccurences { widtexte element } {
    variable ListeOccurences
    variable couleur
    
    destroy .fpw.ftext.text.fenoccs
    destroy .fpw.ftext.text.occssy
    text .fpw.ftext.text.fenoccs -wrap word -bg $couleur(fond)\
	-fg $couleur(curseur) -tabs {1c} -font "Helvetica 14"\
	-yscrollcommand ".fpw.ftext.text.occssy set"
    scrollbar .fpw.ftext.text.occssy -orient vertical\
	-command ".fpw.ftext.text.fenoccs yview"
    
    Editeur::RechercherElement $widtexte $element 0
    
    set f .fpw.ftext.text.fenoccs
    set compteur 0
    if {[llength $ListeOccurences]!=0} {
	foreach el $ListeOccurences {
	    $f insert end "Occurence $compteur"
	    $f tag add $compteur "current linestart" "current lineend"
	    $f tag configure $compteur -foreground blue -underline 1
	    $f tag bind $compteur <1> "
				$widtexte see $el
			"
	    $f insert end \n
	    incr compteur
	}
    }
    $f insert 1.0 "$compteur occurence(s) de \"$element\"\n\n"
    
    .fpw.ftext.text window create "current linestart" -window $f
    .fpw.ftext.text window create current\
	-window .fpw.ftext.text.occssy -stretch 1
    .fpw.ftext.text insert current \n
    bind $f <3> "
		destroy $f
		destroy .fpw.ftext.text.occssy
		$widtexte delete {current linestart} {current lineend + 1 char}
	"
}

proc Editeur::CommenterSelection { widtexte bit } {
    
    set ranges [ $widtexte tag ranges sel ]
    if { [llength $ranges] == 0 } { return }
    set lgn1 [expr {int([lindex $ranges 0])}]
    set lgn2 [expr {int([lindex $ranges 1])}]
    if {$bit==1} {
	for {set i $lgn1} {$i<=$lgn2} {incr i} {
	    $widtexte insert $i.0 %
	}
    } else {
	for {set i $lgn1} {$i<=$lgn2} {incr i} {
	    if {[$widtexte get $i.0 $i.1]=="%"} {
		$widtexte delete $i.0 $i.1
	    }
	}
    }
}

###############################################################################
######################## fin aides programmeur metapost #######################
###############################################################################

proc Editeur::NbLignes { widtexte widetiquette } {
    set nb [expr int([$widtexte index end])-1]
    set mot lignes
    if {$nb==1} {set mot seule\ ligne}
    
    set coords [$widtexte index insert]
    
    $widetiquette configure -text "$coords\t$nb $mot"
}



proc Editeur::EnregConfig { } {
    global Chemin
    variable version
    variable couleur
    variable sz
    
    set fichier [open [file join $Chemin(rel) .mpeditor] w]
    puts $fichier "# fichier de configuration de mpeditor version $version"
    puts $fichier "####################################################"
    foreach cle [array names couleur] {
	puts $fichier "# Couleur $cle\nset couleur($cle) $couleur($cle)"
    }
    puts $fichier "# Taille police \nset sz $sz"
    close $fichier
}


proc Editeur::LectureConfig { } {
    global Chemin
    variable couleur
    variable sz
    
    set fichier [open [file join $Chemin(rel) .mpeditor] r]
    while {![eof $fichier]} {
	eval [gets $fichier]
    }
    close $fichier
}


proc Editeur::compileMP {win wout} {
    variable fichier

    set rep [file dirname $fichier]
    set repactu [pwd]

    cd $rep
    Editeur::Sauvegarder $win 0
    $wout delete @0,0 end
    # déut de la compilation
    proc affiche {f w} {
	upvar encours encours
	if {[eof $f]} {
	    set encours 1
	    catch {close $f}
	    return
	}
	gets $f ligne
	$w insert end $ligne\n
    }
    set encours 1
    set f [open "|mpost $fichier" r]
    fconfigure $f -buffering line
    fileevent $f readable "Editeur::affiche $f $wout"
    vwait encours
    # fin compilation
    cd $repactu

}

proc Editeur::mp2eps {args} {
    variable fichier

    set rep [file dirname $fichier]
    set repactu [pwd]

    cd $rep
    set liste [glob -nocomplain ${args}*]
    set cpt 0
    foreach f $liste {
	if {![file isfile $f] || ![regexp {.([0-9]+)} [file extension $f] a n]} {
	    continue
	}
	
	# on met sous une forme de deux chiffres, en supprimant d'éventuels
	# 0 existants au préalable. Cela suffit pour 100 images ...
	if {$n!=0} {
	    set n [format "%02d" [string trimleft $n 0]]
	} else {
	    set n 00
	}
	regexp {(.*)\.[0-9]+} [file tail $f] a nom
	
	# les variables associées aux fichiers
	foreach ext {tex dvi eps aux log} {
	    eval set ${ext}fic ${nom}_$n.$ext
	}
	
	set idfic [open $texfic w]
	puts $idfic {%% fichier généré par mpeditor : vous pouvez l'effacer !
\documentclass{article}
\usepackage[dvips]{graphicx}
\usepackage[frenchb]{babel}
\setlength{\paperwidth}{21cm}\setlength{\paperheight}{29.7cm}%
\setlength{\textwidth}{21cm}\setlength{\textheight}{29.7cm}%
\setlength{\oddsidemargin}{-1in}\addtolength{\oddsidemargin}{-\hoffset}%
\setlength{\topmargin}{-1in}\addtolength{\topmargin}{-\voffset}%
\setlength{\headsep}{0cm}\setlength{\headheight}{0cm}
\pagestyle{empty}
\begin{document}
\begin{center}}
	puts $idfic "\\includegraphics{$f}"
	puts $idfic {\end{center}
	    \end{document}
	}
	close $idfic
	
	# les compilations
	catch {eval exec latex $texfic} sortie
	catch {eval exec dvips -E $dvific -o $epsfic} sortie
	incr cpt
	# un peu de nettoyage
	foreach ext {tex dvi aux log} {
	    file delete [set ${ext}fic]
	}
    }
    
    cd $repactu
    return $cpt
}

proc Editeur::visuMP {} {
    variable fichier

    .fetat.message configure -text "Veuillez patienter ..."
    update
    set v .visu
    destroy $v
    toplevel $v
    wm title $v "Visualisation"
    
    pack [canvas $v.c -bg grey90 -width 100 -height 50\
	      -yscrollcommand "$v.s set"] -side left -fill y
    pack [scrollbar $v.s -orient vertical\
	      -command "$v.c yview" -width 10] -side right -fill y

    set ficsansext [file rootname $fichier]
    set nb [Editeur::mp2eps ${ficsansext}]

    set h 0
    set L 0
    
    for {set i 0} {$i<=$nb} {incr i} {
	set j [format %02d $i]
	catch {exec convert ${ficsansext}_$j.eps ${ficsansext}_$j.gif} sortie
	if {$sortie!=""} {continue}
	image create photo limage($i) -file  ${ficsansext}_$j.gif
	$v.c create image 0 $h -anchor nw -image limage($i)
	set himage [image height limage($i)]
	set Limage [image width limage($i)]
	$v.c create text 0 [expr {$h+$himage}] -text [file tail ${ficsansext}.$i]\
	    -font {Heletica 10} -anchor nw
	incr h [expr {$himage+10}]
	if {$Limage>$L} {set L $Limage}
	.fetat.message configure -text "Veuillez patienter ... [expr {int($i*100.0/$nb)}]%"
	update
    }
    
    $v.c configure -height $h -width $L
    
    bind $v.c <2> "Editeur::notePos %x %y"
    bind $v.c <B2-Motion> "Editeur::bougePos %x %y $v.c"
    $v.c configure -scrollregion "0 0 $L $h"
    set largeur [expr {$L>[winfo width .]?[winfo width .]+30:$L+30}]
    set hauteur [expr {$h>[winfo height .]?[winfo height .]:$h+15}]
    wm geometry $v ${largeur}x${hauteur}
#    wm maxsize $v ${L} ${h}
    .fetat.message configure -text ""
}


proc Editeur::Gui { } {
    global tcl_version tcl_platform
    
    variable ausujetdeDC
    variable application
    variable version
    variable fichier
    variable couleur
    variable ListeRecents
    variable sz
    
    # barre de menus
    menu .menubar
    . config -menu .menubar

    foreach m { Fichier Editer Outils Prefs Aide } {
	set $m [ menu .menubar.m$m -tearoff 0]
	.menubar add cascade -label $m -menu .menubar.m$m
    }
    
    $Fichier add command -label "Ouvrir" -accelerator Ctrl+O \
	-command { Editeur::Ouvrir .fpw.ftext.text  }
    $Fichier add cascade -label "Récents" -menu $Fichier.lRecents
    menu $Fichier.lRecents -tearoff 0
    Editeur::MaJMenuRecents
    $Fichier add command -label "Sauvegarder" -accelerator Ctrl+S \
	-command { Editeur::Sauvegarder .fpw.ftext.text 0 }
    $Fichier add command -label "Sauvegarder sous..." -accelerator Ctrl+Shift+S \
	-command { Editeur::Sauvegarder .fpw.ftext.text 1 }
    $Fichier add command -label "Fermer" -accelerator Ctrl+Shift+F \
	-command { Editeur::Fermer .fpw.ftext.text }
    $Fichier add separator
    $Fichier add command -label "Quitter" -accelerator Ctrl+Q \
	-command Editeur::Quitter
    
    if {$tcl_version>=8.4} {
	$Editer add command -label "Défaire" -accelerator Ctrl+Z\
	    -command { Editeur::Defaire .fpw.ftext.text }
	$Editer add command -label "Refaire" -accelerator Ctrl+E\
	    -command { Editeur::Refaire .fpw.ftext.text }
    }
    $Editer  add command -label "Couper" -accelerator Ctrl+X\
	-command { Editeur::Couper .fpw.ftext.text }
    $Editer  add command -label "Copier" -accelerator Ctrl+C\
	-command { Editeur::Copier .fpw.ftext.text }
    $Editer  add command -label "Coller" -accelerator Ctrl+V\
	-command { Editeur::Coller .fpw.ftext.text }
    $Editer add separator
    $Editer add command -label "Sélectionner tout" -accelerator Ctrl+A \
	-command { Editeur::toutSelectionner .fpw.ftext.text }
    

    $Outils add command -label "Compilation du fichier"  -accelerator Ctrl+Alt+C \
	-command "Editeur::compileMP .fpw.ftext.text .fpw.fcompil.text"
    $Outils add command  -label  "Voir les figures"  -accelerator Ctrl+Alt+V \
	-command "Editeur::visuMP"
    #$Outils add command -label "Occurences" \
	-command "Editeur::AfficheListeOccurences .fpw.ftext.text david"
    
    $Outils add command -label "Commenter sélection"\
	-command { Editeur::CommenterSelection .fpw.ftext.text 1 }
    
    $Outils add command -label "Décommenter sélection"\
	-command { Editeur::CommenterSelection .fpw.ftext.text 0 }
    
#    $Procs add command -label "Liste Figures" \
	-command { Editeur::AfficheListeFigs .fpw.ftext.text }
    
    
#    $Prefs add command -label "Coloration" \
	-command { Editeur::Coloration .fpw.ftext.text 1 } 
    $Prefs add command -label "Choix couleurs" \
	-command {Editeur::Couleurs}
    $Prefs add command -label "Taille police" \
	-command {Editeur::TaillePolice}
    
    
    $Aide add command -label "Précision"\
	-command " Editeur::Precision"
    $Aide add command -label "Au sujet de..."\
	-command " Editeur::AuSujetDe \[list \"mpeditor version $version\" $ausujetdeDC\] "

    # options...
    set f .foptions
    frame $f
    button $f.b1 -text "Compilation du fichier" \
	-command "Editeur::compileMP .fpw.ftext.text .fpw.fcompil.text"
    button $f.b2 -text "Voir les figures" -command "Editeur::visuMP"
    button $f.b3 -text "Nouvelle Figure" -command "Editeur::InsertionCode .fpw.ftext.text fig"
    button $f.b4 -text "Code LaTeX" -command "Editeur::InsertionCode .fpw.ftext.text latex"
    button $f.b5 -text "Préambule LaTeX" -command "Editeur::InsertionCode .fpw.ftext.text platex"
    for {set i 3} {$i<=5} {incr i} {
	pack $f.b$i -side left -padx 3
    }
    pack $f -fill x
    
    # une fenêtre multi-contenus
    #Fenêtre Paned Window ... c'est mieux que rien non ?
    if {$tcl_version>=8.4} {
	panedwindow .fpw -orient vertical
    } else {
	frame .fpw
    }
    
    # zone texte
    set f .fpw.ftext
    frame $f -height 200
    
    text $f.text -wrap none -tabs {1c}\
	-xscrollcommand "$f.sx set" -yscrollcommand "$f.sy set" \
	-font "Courier ${sz}" -bg $couleur(fond) -fg $couleur(curseur) -insertbackground\
	$couleur(curseur) -insertofftime 0
    focus $f.text
    
    if {$tcl_version>=8.4} "
	$f.text configure -undo 1 -autoseparators 1
    "
    scrollbar $f.sx -orient horizontal -command "$f.text xview"
    scrollbar $f.sy -orient vertical -command "$f.text yview"
    
    grid $f.text $f.sy -sticky news
    grid $f.sx -sticky news
    grid rowconfigure $f 0 -weight 1
    grid columnconfigure $f 0 -weight 1

    # zone compilation
    set f .fpw.fcompil
    frame $f -height 50
    
    text $f.text -wrap word -tabs {1c}\
	-xscrollcommand "$f.sx set" -yscrollcommand "$f.sy set" \
	-font {Helvetica 10}  -bg white -fg black -insertbackground\
	black -insertofftime 0 -height 3
    scrollbar $f.sx -orient horizontal -command "$f.text xview" -width 10
    scrollbar $f.sy -orient vertical -command "$f.text yview" -width 10
    
    grid $f.text $f.sy -sticky news
    grid $f.sx -sticky news
    grid rowconfigure $f 0 -weight 1
    grid columnconfigure $f 0 -weight 1

    #on met tout cela dans notre fpw :
    if {$tcl_version>=8.4} {
	.fpw add .fpw.ftext .fpw.fcompil
    } else {
	pack .fpw.ftext -padx 2 -pady 2 -fill both -expand true
	pack .fpw.fcompil -padx 2 -pady 2 -fill both -expand true
    }
    pack .fpw -side top -expand yes -fill both -pady 2 -padx 2m

    
    # barre d'etat
    frame .fetat -border 2 -relief flat
    pack .fetat -fill both
    
    label .fetat.message -anchor w -relief sunken
    label .fetat.nblignes -width 16 -anchor e -relief sunken
    label .fetat.taille  -width 16 -anchor e -relief sunken
    pack .fetat.message -ipadx 8 -side left -fill x -expand true
    pack .fetat.nblignes -ipadx 8 -side left
    pack .fetat.taille -ipadx 8 -side right
    
    if { ! [ string compare $tcl_platform(platform) "unix" ] } {
	bind Text <Control-v> {}
    }
    
    bind . <Control-o> { Editeur::Ouvrir .fpw.ftext.text}
    bind . <Control-s> { Editeur::Sauvegarder .fpw.ftext.text 0 }
    bind . <Shift-Control-Key-S> { Editeur::Sauvegarder .fpw.ftext.text 1 }
    bind . <Shift-Control-Key-F> { Editeur::Fermer .fpw.ftext.text }
    bind . <Shift-Control-Key-C> { Editeur::compileMP .fpw.ftext.text .fpw.fcompil.text}
    bind . <Shift-Control-Key-V> { Editeur::visuMP }
    bind . <Control-q> Editeur::Quitter
    
    bind . <Control-a> { Editeur::toutSelectionner .fpw.ftext.text}
    
    bind . <Control-t> { Editeur::evaluationTcl .fpw.ftext.text}
    #bind . <Control-2> {Editeur::CommenterSelection .fpw.ftext.text 1}
    #bind . <Shift-Control-2> {Editeur::CommenterSelection .fpw.ftext.text 0}
    
    bind . <Control-i> {Editeur::Indenter .fpw.ftext.text}
    #bind . <Control-C>  Editeur::Couleurs
    
    
    bind .fpw.ftext.text <Button-3> { tk_popup .menubar.mEditer %X %Y }
    
    bind . <Key> { 
	Editeur::Coloration .fpw.ftext.text 0
	Editeur::NbLignes .fpw.ftext.text .fetat.nblignes	
    }
    bind . <Key-Return> { Editeur::indentationAuto .fpw.ftext.text }
    
    wm title . "$application version : $version"
}

proc Editeur::AuSujetDe { var } {
    variable application
    
    if [winfo exists .w] {destroy .w}
    toplevel .w
    wm title .w "Au sujet de $application"
    wm resizable .w false false
    wm transient .w .
    wm overrideredirect .w 1
    frame .w.f -relief groove -border 2
    pack .w.f -padx 4 -pady 4 -ipadx 4 -ipady 4
    set i 0
    foreach item $var {
	label .w.f.$i -text $item
	pack .w.f.$i -anchor w
	incr i
    }
    bind .w <Enter> { destroy .w }
    set x0 [ expr ( [winfo width .] - [winfo reqwidth .w] ) / 2 ]
    set y0 [ expr ( [winfo height .] - [winfo reqheight .w] ) / 2 ]
    wm geometry .w +[ expr [winfo x .] + $x0 ]+[ expr [winfo y .] + $y0 ]
    
}

proc Editeur::Precision {  } {
    variable application
    
    if [winfo exists .w] {destroy .w}
    toplevel .w
    wm title .w "Petite précision sur $application"
    wm resizable .w false false
    wm transient .w .
    frame .w.f -relief groove -border 2
    pack .w.f -padx 4 -pady 4 -ipadx 4 -ipady 4
    pack [text .w.f.t -height 10 -width 60]
    set texte {Cet éditeur a été conçu pour une présentation de metapost.

Attention : MPeditor ne détruit AUNCUN fichier, il écrase
des images metapost de même nom mais présentera éventuellement
en visualisation des images qui ne sont pas codées mais précédemment
existantes.

De plus, MPeditor crée des fichiers "nomdefichier_nn.eps" et
"nomdefichier_nn.gif" pour chaque image ! À vous de supprimer
ces fichiers au besoin.
}
    .w.f.t insert end $texte
    bind .w <1> { destroy .w }
    set x0 [ expr ( [winfo width .] - [winfo reqwidth .w] ) / 2 ]
    set y0 [ expr ( [winfo height .] - [winfo reqheight .w] ) / 2 ]
    wm geometry .w +[ expr [winfo x .] + $x0 ]+[ expr [winfo y .] + $y0 ]
    
}

# Editeur::notePos
#
#      Initialise le tableau pos -- callback de B2
#
# Arguments :
#      x position abscisse pointeur sur le canevas
#      y position ordonnée pointeur sur le canevas
# Résultats :
#      Cela permet d'identifier le point de départ et
#      donc la translation effectuée en cas de mouvement

proc Editeur::notePos {x y} {
    global pos
    set pos(x) $x
    set pos(y) $y
}

# Editeur::bougePos
#
#      Procédure de callback de B2-Motion
#
# Arguments :
#      x position abscisse pointeur sur le canevas
#      y position ordonnée pointeur sur le canevas
#      w chemin du canevas
# Résultats :
#      Réalise la translation ... et actualise le tableau pos

proc Editeur::bougePos {x y w} {
    global pos
    $w move all [expr {$x-$pos(x)}] [expr {$y-$pos(y)}]
    set pos(x) $x
    set pos(y) $y
}

catch {Editeur::LectureConfig}
Editeur::LectureListeRecents
Editeur::Gui
