RTE avec AGG
shadwolf15-Nov-2006/15:15:30+1:00
RTE = Rich text editing
c'est pas possibilité de choisir a tout moment de façon dynamique le format du texte que vous etes entrain de construire

par extension ca permet aussi de réalisé du texte colorisé a la volée.

Il y a un an quand je travaillait sur MDP GUI je me suis dit que se projet aurait absoluement tout a gagner d'une interface RTE.

J'ai donc commencer à chercher a réaliser un moteur RTE simple mais efficace. Mon gros point d'achoppement etant
la gestion du texte de facon dynamique.

je vous met ici le lien vers ce que j'ai fait
http://shadwolf.free.fr/rte-dev-work-draw.r
shadwolf15-Nov-2006/15:26:45+1:00
Mon idée c'est d'intersepter la saisie de remplir une mémoire tampon et formater. Puis on appelle le moteur pour redessinner le texte à l'écran.

saisie texte -> tampon formatage -> redessin a l'ecran le texte formaté

Mon gro gros problème c'est la gestion du curseur et sa mise en relation avec la position dans le tampon de texte.

example:

On saisie un paragraphe de text en plein milieu on veut inserrer un texte en rouge. comment dans le tampon de texte formaté identifier ou inserrer le nouveau texte qui doit apparaitre en plein milieu.

don mon gros problème c'est donc de faire le lien entre tampon texte et position du curseur dans la widget de saisie.
Didec15-Nov-2006/16:42:57+1:00
Entre parenthèse, Cyphre travaille sur le moteur RTE pour Rebol 3.0. On en a vue le proto à Milan.
Je sais y'a pas encore de Rebol 3.0 et il va falloir être patient.
Mais à mon avis il est plus sage d'attendre pour ces "grosses" évolutions que de passer trop longtemps à faire quelque chose qui sera peu utilisable (lenteur) et prochainement obsolète (v3).
shadwolf15-Nov-2006/17:08:43+1:00
le moteur "RTE d'usine" répondra t'il vraiement à nos
besoins?

lenteur hum faut pas exagérer AGG c tres tres rapide quand meme de la a le mettre a genoux on a de la marge...

Personellement je déteste la façon de gérer le curseur de saisie dans VID (widget area). On en a vachement discuter qaund je travaillait sur MDP-GUI ( insertion des balises MPD autour d'un texte sélectionné ca m'a dit fait mal au cranne)

pour ma part ce genre de projet a pour vocation de proposé aussi une approche plus simple de la gestion du curseur et des sélections dynamiques.

Enfin et là je parle d'experience vécu il a fallut qu'on cours après Carl pendant 2 ans pour avoir REBOL 1.3 donc combient de temps faudra t'il attendre pour rebol3.0.

J'attend la correction d'un bug AGG pour mon moteur AGG/SVG
depuis plus d'un an.

Bref le choix est simple dideC soit on se prend par la main on fait une jolie widget sympatique (qui serra intégrée dans REB-GUI) soit on attend et au final on est pas certain qu'elle ait le comportement que l'on souhaite. Si la widget de cyphre ne rempli pas nos attentes où que l'on decouvre un bug dedans il faudra attendre encore une fois les calendes grecs pour avoir un correctif.

Pour toute ces raisons et aussi parce que ca nous permet d'approfondir la connaissance de AGG.
DideC15-Nov-2006/20:23:43+1:00
OK.

Soyons clair. Les problèmes de Perf. seront sensibles dés que le contenu de ton area sera important ou si celle-ci est grande (genre 800x600). On y peut pas grand chose, c'est le blitter de View qui fait ça.

J'ai fait un moteur de rendu RTE (qui est dans lecture-forum : tout le monde peut y regarder) et je le constate déjà. Etant donné le casse tête que ça a été pour placer les élements les uns par rapport aux autres (taille de police diférente, gras, italique...), je pense bien que la gestion du curseur sera fort sympathique

Pour le moment, je n'ai pas de temps pour Rebol et donc pas non plus pour ce projet.

D'autres s'y sont frotté et si rien n'a vraiment vu le jour jusqu'ici, c'est peut-être pour ces raisons.

Mais j'encourage les volontaires motivés à s'y mettre. Il y a plusieurs façons de réaliser tout ça. : la bonne n'a peut être pas encore été trouvée.
Goldevil15-Nov-2006/23:45:02+1:00
Petite question. Mes souvenir de programmation bas niveau sont loins mais je me pose quelques questions.

D'après cette discussion, j'ai l'impression que la zone de texte est gérée sous forme de canvas graphique de la taille du texte complet. Cela signifie que si le texte fait 600x2000 pixels (même si 600x300 sont affichés), la mémoire utilisée est bien celle d'une zone graphique de 600x2000.

Ouvrir un document de 100 pages remplirait la mémoir du PC par une seule grosse image de +/- 100 Mo (estimation à la grosse louche pour des caractères de 8 pixels de haut affichés en 24 bits.

C'est pas gérable comme technique. Mais ai-je bien compris?


Mon expérience dans les zones d'éditions de texte c'est que le software doit refaire un rendering de la zone à afficher à chaque événement envoyé par l'interface graphique. Donc dessiner les lettres à afficher uniquement dans la zone graphique visualisée.

Evidemment, il y a des techniques d'accélération. Si l'assenceur vertical descend de 30 pixels, on s'occupe de copier la zone qui restera affichée de 30 pixels et on dessine les lettres que pour les 30 pixels du bas.

D'après ce que je sais, en rebol, faut pas mal chipoter pour faire cela.

Pour revenir à la question d'un éditeur de texte destiné à la programmation, il y a peut-être beaucoup plus simple.

Imaginons que la zone d'édition ne peut avoir que les dimensions multiples de la taille d'un caractère et que la police est non proportionnelle (courrier).
Dans ce cas, on ne doit jamais afficher des lettres coupées.

On découpe la zone a afficher en n widgets de type "text" les uns au dessus des autres.
view layout [
ligne_1: text "" 600x20
return
ligne_2: text "" 600x20
return
ligne_3: text "" 600x20
return
ligne_4: text "" 600x20
return
ligne_5: text "" 600x20
return
]

L'événement scroll vers le bas ne demande que de calculer quelle partie du texte il faut copier dans chacun des widgets.
Le problème de la coloration se limite donc à travailler sur un widget qui affiche toujours exactement une ligne de texte.
shadwolf16-Nov-2006/11:31:48+1:00
shadwolf16-Nov-2006/21:06:17+1:00
nouvelle version de rte qui marche bcp mieu
parcontre je vais devoir améliorer le moteur
de rendu pour gérer plusieurs sortes de formats textes sur une meme ligne.
Et gérer aussi le mode paragraphe

Puis l'insertion de texte a la position du curseur.

pour teste la nouvelle version (virer les probe pour avoir une idée de la vitesse réelle du moteur):

http://shadwolf.free.fr/rte-evolution.r
shadwolf17-Nov-2006/13:11:21+1:00
golevil j'ai pensé a ce que tu propose et voici quels sont a mon avi le problèmes principaux des cette méthode.

1) on ne peux pas avoir des changements de format de texte en plein milieu d'une ligne.

2) le compositing VID et surtout l'appel systématique sur view layout c'est tres lent( c'est pour ca que pour les MD-browser et MDP-GUI ashley a proposer de passer par face/pane y inserer des objet VID préformaté et juste faire un show face (ce qui est 100 fois plus rapide a l'écran que la méthode avec view layout à chaque fosi que l'on mofie le contenu de la fenêtre)

3) pas de gestion de paragaphe de texte

4) pas de resize possible

5) pas de selection possible d'une pour plusieurs ligne en meme temps

6) ca deviendrait assez lourd en mémoire.

7) on garde le système de gestion du curseur par défaut de VID et c'est trop moche ^^

c'est après une longue réflexion que j'ai opté pour la solution Draw/AGG
shadwolf20-Nov-2006/12:20+1:00
On peut résumer la gestion du RTE avec DRAW/AGG a de la manipulation de liste et de chaîne de caractères ce qui il me semble est justement le point for de REBOL ^^

Le seul truc pour lequel je coince un peu en fait c'est la gestion du curseur relative à l'ajout de texte ayant un format différent dans une ligne ou un paragraphe déjà existant.
shadwolf20-Nov-2006/19:17:49+1:00
bon j'ai encore améliorer mon code RTE basé sur Draw/AGG .
Je suis assez content du résultat le code est compact et ca troune plutôt bien. Quand on pense que ce moteur RTE ne fait pas plus de 80 lignes de code ca fait froid dans le dos ^^.

la gestion du speudo curseur reste le point le plus abétant pour l'instant on lui observer une tendence a se décaler progressivement j'aimerai avoir des idées sur comment le gérer au mieu.

http://shadwolf.free.fr/rte-evolution2.r
shadwolf20-Nov-2006/19:21:58+1:00
bon lien
http://shadwolf.free.fr/rte-evolution02.r
shadwolf23-Nov-2006/20:39:49+1:00
support du texte en couleur ^^

http://shadwolf.free.fr/rte-evolution03.r
Reb-Kodeur24-Nov-2006/8:43:21+1:00
Problème avec les touches INSERT ET SUPPRIMER et les nombres
Reb-Kodeur24-Nov-2006/9:01:01+1:00
Non les nombres c'est ok.

Il faut absolument trouver un moyen pour connaitre la taille de ce qui est dessiné lorsque l'instruction 'draw draw-text' est passée.
Reb-Kodeur24-Nov-2006/9:35:18+1:00
Sinon ne peut-on pas créer une image du text et ensuite connaitre la taille de l'image.. je sais c'est un peu time et process consuming... et ensuite passer cette taille au cursor-offset
coccinelle27-Nov-2006/16:33:18+1:00
Hello Shad,

J'ai jeté un coup d'oeil sur ton moteur et effectivement, le positionnement du curseur n'est pas terrible.

Tu devrais t'inspirer du code utilisé pour la saisie. Il existe une fonction edit-text qui gère cette saisie. Tu devrais y jeter un coup d'oeil pour t'en inspirer.

Cette fonction est dans un objet que j'ai trouvé avec un peu d'astuce :
>> layout [x: area]
>> x: bind? first select third second get in x/feel 'engage 'key
>> help x
X is an object of value:
   view*           object!   [screen-face focal-face caret highlight-start high...
   hilight-text    function! [face begin end]
   hilight-all     function! [face]
   unlight-text    function! []
   hilight?        function! []
   hilight-range?  function! [/local start end]
   copy-selected-text function! [face /local start end]
   copy-text       function! [face]
   delete-selected-text function! [/local face start end]
   next-word       function! [str /local s ns]
   back-word       function! [str /local s ns]
   end-of-line     function! [str /local nstr]
   beg-of-line     function! [str /local nstr]
   next-field      function! [face /local item]
   back-field      function! [face /local item]
   keys-to-insert  bitset!   make bitset! #{ 01000000FFFFFFFFFFFFFFFFFFFFFF7FFF...
   keymap          block!    length: 18
   insert-char     function! [face char]
   move            function! [event ctrl plain]
   move-y          function! [face delta /local pos tmp tmp2]
   edit-text       function! [ face event action /local key liney swap-text tmp...
   edit            object!   [redraw detect over engage]
   swipe           object!   [redraw detect over engage]

>>


Marco.
shadwolf30-Nov-2006/20:02+1:00
Le pire c'est que j'ai il y a un en au debut de ce bout d'essai regarder en profondeur la gestion du curseur à la mode
VIEW utilisé dans filed + area.

N'ayant rien compris du tout j'ai opté pour mon propre system qui est comment dire .... Heu .... Nul oui oui c'est bien le mot.

bon si quelqu'un peut m'aider se serrait génial
coccinelle4-Dec-2006/17:11:47+1:00
Si, mais avec des si on met un cachalot dans une boite d'alumettes, donc si j'avais l'envie de faire la chose, j'aurais tendance à faire ainsi.

J'aurais des lignes chainées entre elles contenant un ou plusieurs segments chainés entre eux, un à chaque changement de style.

En utilisant une face et en appliquant la fonction size-text pour chaque segment, on obtient la position horizontale de chacun d'eux ainsi la hauteur de la ligne.

Le même principe peut être appliqué avec les fonctions offset-to-caret et caret-to-offset pour gérer le curseur et sa position dans le texte.

Fort de cela, il devient possible de positionner les segements à l'écran de manière efficace et de gérer la position du curseur.

Mais tout cela ne sont que des idées et doit être vérifié par la pratique.

Marco.
guest24-Dec-2006/22:42:27+1:00
je résume,
impossible de gérer la position du curseur avec draw/agg il faut donc afficher des facettes area à la place, ce qui est super lourdingue si on veut gérer des formatages multiples...
me trompé-je ?
je plussoie la demande de Shad, tant que Draw/agg ne gerera pas la notion de curseur dans les zones text avec Draw, on s'en sortira pas...
coccinelle4-Dec-2006/23:27:03+1:00
Il n'est pas obligatoirement nécessaire d'afficher des facettes, on peut aussi utiliser draw/agg, mais pour calculer la position de chaque morceau de texte et celle du curseur, autant utiliser les moyens que l'on a, soit size-text, offset-to-caret et caret-to-offset
guest25-Dec-2006/22:04:28+1:00
Euh...
les fonctions size-text, offset-to-caret et caret-to-offset ne fonctionnent qu'avec du texte mappé classiquement dans une facette (propriété face/texte) donc avec un style unique (police, paragraph, etc...).
Explique moi l'usage de ces fonctions avec draw lorsqu'on affiche du texte n'importe où avec différentes polices, tailles, et transformations... ???
Je vois pas comment tu fais ou alors j'ai raté un truc...

Pour être plus précis, comment récupères tu le bon morceau de texte (celui qui récupère le carret) en cliquant au hasard sur ta fenêtre "draw" alors que face/text ne contient rien.
coccinelle5-Dec-2006/23:15:12+1:00
Ben pour commencer, voici quelques lignes qui illustrent la transformation face -> draw, et ce avec différents alignements et différentes tailles.
item-info: make system/view/line-info []
view layout [
	p: panel green 300x50 [
		across
		t1: text "bleu" 100x40
			font [size: 12 color: blue align: 'right valign: 'top]
			with [draw-offset: none]
		t2: text "blanc" 80x40
			font [size: 24 color: white align: 'center valign: 'middle]
			with [draw-offset: none]
		t3: text "rouge" 100x40 font-size 24 font-color red with [draw-offset: none]
			font [size: 36 color: red  align: 'left valign: 'bottom]
			with [draw-offset: none]
	]
	do [
		foreach item p/pane [
			textinfo item item-info 0
			item/draw-offset: item/offset + item-info/offset
		]
	]
	box green 300x50 effect [draw [
		font t1/font pen t1/font/color text t1/text t1/draw-offset aliased
		font t2/font pen t2/font/color text t2/text t2/draw-offset aliased
		font t3/font pen t3/font/color text t3/text t3/draw-offset aliased
	]]
]

Pour la gestion du curseur, faut que je travail encore la chose, mais ce n'est pas impossible.

Marco.
guest25-Dec-2006/23:43:48+1:00
...
Evidemment pour la conversion face>draw, c'est trivial.
Mais ce n'est pas le sujet.
Quand je vois ton exemple, je comprends que tu n'as pas encore vraiment réalisé la difficulté du problème posé.
J'espère que je me trompe.
coccinelle6-Dec-2006/10:43:39+1:00
J'espère que tu te trompes.

Voici un exemple qui récupère le caractère sur lequel on a cliqué dans la zone graphique (draw).
p: layout [
	across
	t1: text "bleu" font-size 12 blue bold
		with [draw-offset: none]
	t2: text "blanc" font-size 24 white italic
		with [draw-offset: none]
	t3: text "rouge" font-size 36 red underline
		with [draw-offset: none]
]

item-info: make system/view/line-info []
foreach item p/pane [
	textinfo item item-info 0
	item/draw-offset: item/offset + item-info/offset
]

view layout [
	across text "Curent caractere" cc: field 30 return
	return
	box green p/size effect [draw [
		font t1/font pen t1/font/color text t1/text t1/draw-offset aliased
		font t2/font pen t2/font/color text t2/text t2/draw-offset aliased
		font t3/font pen t3/font/color text t3/text t3/draw-offset aliased
	]] with [
		feel/engage: func [face act event][
			switch act [
				down [
					set-face cc ""
					foreach item p/pane [
						if within? event/offset item/offset item/size [
							set-face cc copy/part offset-to-caret item (event/offset - item/offset) 1
						]
					]
				]
			]
		]
	]
]

Ce n'est qu'une ébauche pour illustrer le principe mais beaucoup reste à faire pour avoir un système fonctionnel.

Marco.
coccinelle6-Dec-2006/11:06:28+1:00
Je veux juste indiquer que les fonction offset-to-caret et caret-to-offet sont buggé lorsque le text est aligné à droite ou centré. Bug dans Rambo #4161

C'est pas un problème lié à ce que je propose. Il suffit de regarder ce que fait le code suivant pour comprendre le problème et de jouer avec le champ:
view layout [
    field 260x50 font [name: "verdana" size: 36 valign: 'middle align: 'right]
]
guest26-Dec-2006/13:57:07+1:00
ok, donc ça ressemble bien au cas de la gestion séparée de chaque zone de texte dans une face text/area dédiée comme cela a été suggéré plus haut.
Dans ton exemple, on pourrait éviter le recours à de multiples faces text, en mappant tour à tour les portions de texte + font dans une seule face text avant de tester la position du carret mais l'idée générale est la seule possible je crois.
Reste que ce système ne marche qu'avec du texte "facetisé".
Il faut oublier les textes vectorisées et toutes les transformations normalement possibles avec Draw et ça c'est vraiment dommage.
coccinelle6-Dec-2006/15:35:31+1:00
Là, on est d'accord, si l'on veut du texte vectorisé et toutes les transformations possibles de Draw/AGG, il faut qu'il gère lui même le curseur. Je ne sais même pas si la librairie AGG le permettrait.

Entièrement d'accord aussi sur le recours à une seule face réutilisée tour à tour, aussi bien pour la génération du dialect Draw que pour la gestion du curseur.

Bon, à priori je ne vais pas aller plus loin dans la recherche, c'était juste un coup de pouce pour Shad.

Marco.
shadwolf6-Dec-2006/17:52:34+1:00
bien ca travail dur a ce que je vois ^^.

désolé de n'avoir pas participé plutot à ce pationnant débat mais en ce momment bcp de travail.

bon je vais regarder ca et laisser ca décanter dans ma tête.

Moi j'ai toujours les meme question et "rétissances" quand a la méthode widgets mapée.
-> ca bouffe de la mémoir comme pas possible (mais bon c'est viable hein ... enfin sauf si tu veux lire ton document sur un I-pod ^_^ MDP-GUI MD-BROWSER et MDP-BROWSER ont tres largement démontré que puisque c'est du widget mapping la mémoire n'est pas tant que ca utilisée (mais quand même beaucoup plus que pour une méthode s'appuyant sur un moteur full DRAW/AGG))

-> l'insertion de nouveau texte dans un bloc de texte existant suppose que l'ont souhaite que le texte ajouté soit aux même normes que le texte existant de faire grandir la taille en x puis en y de la widget mappée quand la longueure du texte dépace une certaine taille

bref ce genre de petit exercice est très formateur et nous permet aussi de voir les fameux bug de rendu de text draw/AGG (deja signalé y a un an sur RAMBO ...) (pas assez d'espace entre les caractere et quasiement illisible en dessus de la font size 11 ... (winXP surtout)
shadwolf6-Dec-2006/18:23:13+1:00
j'oubliai ton example 1) montre bien l'impossibilité de selectioné en meme temps les 3 éléments.

A mon avis ce genre de travail suppose vraiment de redescendre au niveau le plus bas et de trouver un mayen facil pour gérer la zone de texte dans tout sa diversité de style.


Par manque de connaissances je n'arrive pas a trouver un bon moyen de représenter les données avec leur formatage.

Pourtant je pense etre sur la bonne voie mais il me manque un truc ...
guest27-Dec-2006/21:24:29+1:00
Bon quand un problème est compliqué, il faut en revenir à la bonne vielle méthode "divide and conquer".

Je vois 3 modules principaux.

Parseur RTE
==========
traduction du source en une représentation interne de type collection d'objets.
par exemple, la séquence de source:
{bold red "coucou c'est moi"}
pourrait se traduire par la création des objets
font [style: 'bold]
pen [color: red]
text [text: "coucou c'est moi"]
cette représentation interne doit servir à simplifier l'écriture du parser afin d'anticiper l'ajout d'autres formats comme le rtf, RebolDoc et autres.

Module de conversion draw (flush)
=========================
à partir de la collection d'objets internes, ce module est capable de générer un block draw et de l'insérer dans une collection.

Widget draw collector.
=================
A partir d'une collection de blocs DRAW, le widget gère le chargement, le positionnement, le déroullement, etc...
et bien sur l'affichage.
à noter que chaque bloc draw indépendant pourrait être afficher dans une face distincte, ceci afin d'optimiser les perfs à l'affichage. Ne serait raffraichis que les blocs draw modifiés.
On peut noter aussi que ce widget n'afficherait que les blocks visibles de la collection et non pas tous les blocs.
******************

bon je donne une petite idée de ce à quoi ça pourrait ressembler

le framework de base de objets internes pourrait être quelque chose comme :
make item object! [
modified?: false
offset: 0x0 ;
size: 0x0
draw: [] ;séquence à générer en dialect draw
]

ensuite, quelques objets intéressants à déclarer:

text: make item [
text: none
draw: ['text offset text]
size: does [calcul de la taille du texte...]
offset: does [calcul de l'offset du texte ]
]
image: make item [
draw: ['image image]
size: does[image/size]
]
font: make item [
font: make face/font
draw: [font]
]
pen: make item [
color: none
draw: ['pen color]
]

ces objets sont alimentés par le parser RTE qui pourrait ressembler à ça:
[
set val [
file! (image/image: load val flush [image])
| tuple! (pen/color: val)
| string! (text/text: val flush [font pen text])
| integer! (font/font/size: val)
]]

la fonction flush servirait à générer la séquence draw de chaque objet en parametre.
On remarque donc que le parser invoque flush que lorsque 'text ou 'image est modifié mais par quand 'font ou 'pen son modifiés.

exemple de déroulement avec le source RTE suivant:

{15 red "coucou c'est re moi !"}

Lors du parsing, les objets internes suivants seront modifiés:

font/font/size: 15
pen/color: red
text/text: "coucou c'est re moi !"

puis le parser invoque la fonction flush [font pen text] qui assemble les différentes séquences draw de chaque objet modifié indiqué en paramètre.

soit: [font 'pen color 'text offset text] avant d'en faire un reduce et de l'insérer dans la collection de blocks draw gérés par le widget.

Je passe sur le calcul de l'offset qui peut sembler un peu ardu mais dont on a déjà discuté avec les précédents posts.



******
Evidemment ça ne traite que la génération de l'affichage mais c'est une proposition qui aide à bien séparer les différents aspects du problème pour en faciliter le développement.

Enfin bref, voilà comment je m'y prendrais pour commencer...
coccinelle7-Dec-2006/22:38:28+1:00
Assez d'accord avec toi et suis content de voir tous ces échanges d'idées.

Pour le dialecte, je suggère de s'inspirer de TMD (Text Markup Dialect) que nous a proposé Carl ici : http://www.rebol.net/notes/textmarkup.html Ce n'est pas complet mais c'est une direction à prendre je crois.

Pour le positionnement des choses, il faut le faire en deux temps je crois, une premier passage pour les positions horizontales et où l'on calcul la hauteur de chaque ligne puis un deuxième pour les verticales et l'alignement des éléments sur les lignes.

Voilà quelques idées à débattre.

Marco.
guest27-Dec-2006/23:26:47+1:00
le seul truc qui ne me plait pas avec TMD, c'est l'usage des blocks pour inclure des surcharges temporaires.
ça complique pas mal les choses au niveau de la lisibilité du source et de son traitement alors que son intérêt est franchement limité.
Pourquoi ça complique ?
parce que lorsqu'il s'agira de modifier dynamiquement le source en fonction des modifications pilotées par le widget on risque d'avoir du mal à savoir ce qu'il faut modifier dans la structure imbriquée alors que quand tout est linéaire y'a pas ce problème.
Je préferais un langage très simple sans imbrication type RebolDoc.
Même si idéalement, j'admet que le framework devrait être capable de traiter n'importe que langage source (avec leur propres contraintes) si on veut plus tard l'utiliser comme éditeur universel.
coccinelle8-Dec-2006/20:02:14+1:00
Pour le fun, voilà un bout de code amusant :
tmd-ctx: context [
    tmd-layout: func [
        tmd-face [object!]
        /local text stack item info list row rule i draw
    ][
        row: copy []
        item: make face [
            offset: 0x0
            size: tmd-face/size - (2 * tmd-face/edge/size)
            para: make tmd-face/para []
            font: make tmd-face/font [valign: 'top]
        ]
        info: context [
            start: none
            num-chars: none
            offset: 0x0
            size: 0x0
            append row line: context [
                offset: 0x0
                size: 0x0
            ]
        ]
        list: copy []
        stack: copy []
        parse tmd-face/tmd rule: [(
            insert stack item/font
            item/font: make item/font []
        ) any [
            into rule
        |
            set text string! (
                item/text: text
                item/para/indent/x: info/offset/x + info/size/x
                item/line-list: none
                i: 0
                while [
                    textinfo item info: make info [font: item/font] i
                ][
                    if positive? i [append row info/line: context [
                        offset: 0x0
                        size: 0x0
                    ]]
                    info/line/size: to pair! reduce [info/offset/x + info/size/x max info/line/size/y info/size/y]
                    append list info
                    i: i + 1
                ]
                item/font: make stack/1 []
            )
        |
            'bold (item/font/style: union any [item/font/style copy []] [bold])
        |
            'italic (item/font/style: union any [item/font/style copy []] [italic])
        |
            set text integer! (item/font/size: text)
        |
            set text tuple! (item/font/color: text)
        |
            set text word! (
                switch type?/word text: get text [
                    integer! [item/font/size: text]
                    tuple! [item/font/color: text]
                ]
            )
        |
            skip
        ](
            remove stack
            item/font: stack/1
        )]
        row: next row
        forall row [
            row/1/offset/y:  row/-1/offset/y + row/-1/size/y
        ]
        item/para/wrap?: false
        draw: copy [anti-alias off]
        foreach info list [
            item/text: copy/part info/start info/num-chars
            item/size: info/line/size + tmd-face/para/origin + tmd-face/para/margin + (2 * tmd-face/edge/size)
            item/para/indent/x: info/line/offset/x + info/offset/x
            item/font: info/font
            item/font/valign: tmd-face/font/valign
            item/line-list: none
            textinfo item info 0
            append draw compose [
                font (item/font)
                pen (item/font/color)
                text  (item/text) (info/line/offset + info/offset)
            ]
        ]
        tmd-face/effect: compose/only [draw (draw)]
    ]
    
    stylize/master [
        tmd-area: area  feel [
            redraw: func [face act pos][
                if act = 'draw [
                    if all [in face 'colors block? face/colors] [
                        face/color: pick face/colors face <> system/view/focal-face
                    ]
                    tmd-layout face
                ]
            ]
            engage: func [face act event][
                switch act [
                    down [ ; the main mouse button was pressed.
                        if not-equal? face system/view/focal-face [
                            unfocus
                            system/view/focal-face: face
                            show face
                        ]
                    ]
                ]
            ]
        ] para [
            wrap?: true
        ] font [
            valign: 'bottom
        ] with [
            words: reduce [
                'tmd func [new args][args]
            ]
            init: [tmd: select facets 'tmd]
            tmd: none
        ]
    ]
]

x: view layout [
    f: field
    t: tmd-area 400x200 font [valign: 'bottom] tmd [
        "This is an example of REBOL markup text. "
        "Here the word " bold "bold" " is bolded. "
        bold "This entire sentence is bold. "
        "This is " bold italic "bold and italic" ". "
        "This text is " blue "blue in color" ". "
        "This text is " 200.80.40 "redish in color" ". "
        "This is an example of text "
        bold ["that is bold " blue ["blue and " 32 ["REALLY BIG"]]] ". "
        "And now it's normal text"
    ]
]


Y'a encore bien des problèmes d'espacement horizontal et vertical, mais c'est un premier pas.

Marco.

NB. Le curseur n'est pas géré.
coccinelle8-Dec-2006/20:09:57+1:00
Amusez-vous à changer la taile du tdm-area et vous verrez comment le texte est repositionné dans le champs.
guest28-Dec-2006/23:38:12+1:00
good...
Je vais pas pouvoir regarder ça avant lundi prochain.
Bon week.

Steeve
coccinelle8-Dec-2006/23:57:13+1:00
Voilà une dernière version pour ce soir qui aligne un peu mieux les choses et avec les fondations pour le highlight du text. J'ai aussi mis 2 rotary qui permettent de changer la taille de l'area et l'alignement vertical du texte.
tmd-ctx: context [
    tmd-layout: func [
        tmd-face [object!]
        /local text stack item info list row rule i draw
    ][
        row: copy []
        item: make face [
            offset: 0x0
            size: tmd-face/size - (2 * tmd-face/edge/size) - tmd-face/para/origin - tmd-face/para/margin - 4x4
            edge: tmd-face/edge
            para: make tmd-face/para [
            	origin: 0x0
            	margin: 0x0
            ]
            font: make tmd-face/font [
            	offset: 0x0
            	space: 0x0
            	valign: 'top
            ]
        ]
        info: context [
            start: none
            num-chars: none
            offset: 0x0
            size: 0x0
            append row line: context [
                offset: 0x0
                size: 0x0
            ]
        ]
        list: copy []
        stack: copy []
        hilight: off
        parse tmd-face/tmd rule: [(
            insert stack item/font
            item/font: make item/font []
        ) any [
            into rule
        |
            set text string! (
                item/text: text
                item/para/indent/x: info/line/size/x ; offset/x + info/size/x
                item/line-list: none
                i: 0
                while [
                    textinfo item info: make info [
                    	font: item/font
                    	highlight: hilight
                    ] i
                ][
                    if positive? i [append row info/line: context [
                        offset: 0x0
                        size: 0x0
                    ]]
                    info/line/size: to pair! reduce [info/line/size/x + info/size/x  max info/line/size/y info/size/y]
                    append list info
                    i: i + 1
                ]
                item/font: make stack/1 []
            )
        |
            'bold (item/font/style: union any [item/font/style copy []] [bold])
        |
            'italic (item/font/style: union any [item/font/style copy []] [italic])
        |
            'underline (item/font/style: union any [item/font/style copy []] [underline])
        |
            'start (hilight: on)
        |
            'stop (hilight: off)
        |
            set text integer! (item/font/size: text)
        |
            set text tuple! (item/font/color: text)
        |
            set text word! (
                switch type?/word text: get text [
                    integer! [item/font/size: text]
                    tuple! [item/font/color: text]
                ]
            )
        |
            skip
        ](
            remove stack
            item/font: stack/1
        )]
        row/1/offset: row/1/offset + tmd-face/para/origin
        row: next row
        forall row [
	        row/1/offset/x: row/1/offset/x + tmd-face/para/origin/x
            row/1/offset/y: row/-1/offset/y + row/-1/size/y
        ]
        item/para/wrap?: false
        draw: copy []
        foreach info list [
            item/text: copy/part info/start info/num-chars
            item/size: info/line/size + 0x4
            item/para/indent/x: info/line/offset/x + info/offset/x - 4
            item/font: info/font
            item/font/valign: tmd-face/font/valign
            item/line-list: none
            textinfo item info 0
            info/offset/y: info/line/offset/y + info/offset/y
            append draw compose [
            	(either info/highlight [compose [
            		pen (complement tmd-face/color)
            		fill-pen (complement tmd-face/color)
            		box (to pair! reduce [
            			info/offset/x
            			info/line/offset/y
            		]) (to pair! reduce [
            			info/offset/x + info/size/x
            			info/line/offset/y + info/line/size/y
        			])
            	]][[]])
                font (item/font)
                pen (either info/highlight [complement item/font/color][item/font/color])
                text  (item/text) (info/offset) aliased
            ]
        ]
        tmd-face/effect: compose/only [draw (draw)]
    ]
    
    stylize/master [
        tmd-area: area  feel [
            redraw: func [face act pos][
                if act = 'draw [
                    if all [in face 'colors block? face/colors] [
                        face/color: pick face/colors face <> system/view/focal-face
                    ]
                    tmd-layout face
                ]
            ]
            engage: func [face act event][
                switch act [
                    down [ ; the main mouse button was pressed.
                        if not-equal? face system/view/focal-face [
                            unfocus
                            system/view/focal-face: face
                            show face
                        ]
                    ]
                ]
            ]
        ] para [
            wrap?: true
        ] font [
            valign: 'bottom
        ] with [
            words: reduce [
                'tmd func [new args][args]
            ]
            init: [tmd: select facets 'tmd]
            tmd: none
        ]
    ]
]

view layout/size [
	across
    s: rotary "400x150" "300x300" "200x400" "100x500" [t/size: to-pair get-face s unfocus show t]
    v: rotary "middle" "top" "bottom" [t/font/valign: to-word get-face v unfocus show t]
    return
    t: tmd-area para [origin: 10x10 margin: 10x10] font [valign: 'middle] tmd [
        "This is an example of REBOL markup text."
        " Here the word " bold "bold" " is bolded. "
        bold "This entire sentence is bold."
        " This is " bold italic "bold and italic" ". "
        "This text is " blue "blue in color" ". "
        "This text is " 200.80.40 "redish in color" ". "
        underline "This is an e" start "xample of text "
        bold ["that is bold " blue ["blue and " 32 ["REAL" stop "LY BIG"]]] ". "
        "And now it's normal text"
    ]
] 440x600


Rebol est quand même génial, en 170 lignes on obtient quelque chose de sympa.

Marco.
Didec11-Dec-2006/12:38:46+1:00
Chapeau Marco !!

Je vois que tu as utilisé 'textinfo, ce qui simplifi la gestion des saut de lignes automatiques.

Tout ceci me rappelle les longues heures où je bossais sur RTD-STYLE. Je me suis toujours dis que 'textinfo me simplifierais la tâche, mais n'ai jamais eu vraiment le temps et l'envie de m'en servir, car à l'époque, il n'y avait aucune doc.

Il reste à gérer l'alignement vertical des textes de taille différentes sur une même ligne de base. Je ne vois rien dans Rebol pour le faire automatiquement, donc le calcul fait dans RTD-STYLE sera réutilisable.

Il faut aussi gérer la coupure de phrases entre les mots et non n'importe ou (ça me semble trivial après l'utilisation de 'textinfo).

Par contre la structure du dialecte avec des sous-blocks pour 'bold et autres [gras]complique la [ital]gestion d'attributs[/gras] superposés[/ital] comme cette phrase.

Un saut de ligne dans le texte donne un résultat "étrange". Il reste aussi à gérer ça correctement.
guest212-Dec-2006/0:35:36+1:00
c'est joli tout plein tout ça.
De mon côté j'avance pas mal aussi, je devrais présenter un proto bientôt.
Au menu:

- Un dialect spécial pour externaliser et faciliter l'écriture du parseur rte/draw,
- affichage du caret
- gestion partielle de l'insertion/modification/selection
coccinelle12-Dec-2006/9:08:41+1:00
Là ça devient vraiement intéressant. Faut qu'on se partage nos bout de script pour en faire un truc sympa.

J'ai mis sur mon wiki une version où le placement horizontal est nettement amélioré. C'est ici : http://www.ladyreb.org/wiki/doku.php?id=tmdstyle

Le script est un peu fouilli mais c'est normal quand on tatonne.

Didier, je n'ai pas trouvé dans rtd-style où tu fais l'alignement vertical. En fait, j'aurais juste besoin de connaitre la proportion en dessus et en dessous de la ligne de base, après c'est qu'un ajustement de l'offset.

Pour ce qui est du dialect, je suis assez d'accord, les sous-blocks ne sont pas l'idéal, mais sont très Reboliens. C'est qu'une question de parsing qui devrait isolé dans un coin comme le préconise quest2.

Voilà, voilà, Marco.
Didec12-Dec-2006/10:39:24+1:00
Pour l'alignement vertical, on est un peu obligé de travailler en 2 passes :

1) détermination des morceaux de textes composant la ligne à l'écran. Il faut du coup mémoriser pour chacun sa hauteur et la plus grande hauteur du tout !

2) Calcul des offsets verticaux respectifs de chacun en fonction de cette hauteur maxi (de la ligne = hauteur du texte avec la plus grand fontsize) et de la hauteur du morceau de texte en cours. C'est ici qu'on utilise un ratio pour avoir une ligne de base quelque soit la taille.

Dans RTD-STYLE :
1) est fait dans 'emit-text. Je calcule la taille 'sz du morceau de texte avec 'size-text et je mémorise la taille maxi de la ligne 'max-h.

2) est fait dans emit-line (qui créé les instructions Draw à chaque fois qu'une ligne est terminée).
Plus particulièrement les lignes :
	| set x pair! set t string! (
		emit compose/deep [text (to-pair reduce [xm + x/x pos/y + to-rounded-int max-h - x/y * 0.8 + dh]) (t)])

OU 'x est égal au 'sz du 1) et 't est le texte. 'pos-y est la position verticale du haut de la ligne dans le champ. 'dh n'est là que parceque RTD-STYLE gère l'insertion d'images ou même de block VID dans le dialecte et il y a donc une gestion de la hauteur différente. Si il n'y a que du texte il est toujours égal 0 donc ne pas en tenir compte.

En gros l'équation est : haut-de-la-ligne + (hauteur-maxi - hauteur-texte * 0.8)

Une remarque : je ne vois pas trop l'usage du 'valign que tu fais. Après tout, il est spécifié au niveau de l'area et c'est l'ensemble des textes qui devraient se trouver placés en haut en bas ou au milieu de l'area, et non le texte dans la ligne, non ?
coccinelle12-Dec-2006/11:11:42+1:00
Merci Didier,

Le chiffre que je retiens, c'est 0.8 ou 80%.

Pour ce qui est de l'algorithm, c'est bien ce que je fais :
1) Une première passe est faite pour calculer la position horizontale des éléments sur chaque ligne et conserver la hauteur maximum de chaque ligne.
2) Un deuxième passe sur chaque ligne pour calculer sa position en fonction de la hauteur de la ligne précédente,
3) Finalement, chaque élément est positionné verticalement en fonction de la hauteur de la ligne et de son alignement verticale.

C'est lors de cette troisième passe que je vais ajuster l'offset de chaque élément en fonction de cette proportion de 80%.

L'usage que je fais de valign correspond à sa définition dans la documentation de Rebol ainsi qu'à son comportement effectif. Il s'agit de l'alignement du texte sur chaque ligne et non pas dans l'area.

Encore merci pour l'info.
Didec12-Dec-2006/13:34:54+1:00
Ta deuxième passe est-elle absolument nécessaire ? Après tout, on affiche une ligne après l'autre, donc on peut tenir à jour une variable indiquant la position courante (c'est 'pos dans RTD-STYLE). La position verticale de la ligne suivante c'est celle de la précédente + la hauteur-maxi de la précédente. A mettre à jour au changement de ligne !

Evidemment, ce n'est possible que si la passe 3) est faite pendant la passe 1), à chaque changement de ligne, ce qui n'est pas ton cas (mais est celui de RTD-STYLE).
Il sera intéressant de comparer les 2.

Dans la passe 3), il faudra aussi faire l'alignement horizontal (gauche, droite, centré), qui n'est possible qu'après avoir calculé la largeur totale de la ligne en passe 1).

C'est simple :
place-restante = largeur-totale - marges-retrait-et-autres - largeur-de-la-ligne

Selon l'alignement en cours, il suffit soit d'ajouter place-restante à chaque offset/x (cas alignement droit) ou seulement la moitié (cas alignement centré) ou 0 (cas alignement gauche).

En tout cas, c'est une approche différente, pour un besoin différent : je ne prevoyais pas d'ajouter l'édition à RTD-STYLE, alors qu'ici, c'est l'objectif.
coccinelle12-Dec-2006/16:52:16+1:00
Didier,

Tu avais tout à fait raison, la deuxième passe pouvait être évitée en faisant le calcul à chaque changement de ligne, plus un fois pour la dernière ligne.

J'ai ajouté l'alignement centré et à droite, ce n'était pas trop compliqué.

J'ai aussi revu le code pour le rendre plus simple.

C'est toujours là : http://www.ladyreb.org/wiki/doku.php?id=tmdstyle

Maintenant, je vais passer à la gestion du curseur qui ne devrait pas être trop difficile tant j'ai fait attention à bien conserver les offset & size effectifs.

Je me dis qu'une fois la base faite, il ne devrait pas être trop compliqué de faire des variantes pour l'html ou d'autre variantes de dialecte.
coccinelle13-Dec-2006/16:48:41+1:00
Pour le fun, je vous laisse regarder avec quoi je me bats.

C'est toujours ici : http://www.ladyreb.org/wiki/doku.php?id=tmdstyle

J'ai abordé le problème du curseur et du highlight. Je le fais bloc par bloc pour l'instant, chaque problème après l'autre. Pour l'instant, je butte sur le caret verticalement.

Enfin, c'est assez rigolo, c'est pourquoi je le partage avec vous.
coccinelle13-Dec-2006/21:40:28+1:00
Voilà, c'est mieux, j'ai posté une version 0.3 qui traite mieux les highlight.

C'est toujours fait bloc par bloc mais c'est géré assez correctement.

Prochaine étape, le highlight au pixel près et la gestion du caret.

C'est toujours au même endroit.
guest213-Dec-2006/23:31:17+1:00
ben de mon côté, je sais pas si j'avance ou je recule.
ça fait 3 fois que je récris tout mon framework pour le rendre plus générique et modulaire.
mais bon... y'a de l'espoir !

la dernière nouveauté, c'est un parseur qui fonctionne séquentiellement et qui devrait permettre de ne générer que ce qui est visible dans la fenêtre.
Devrait être utile pour les gros fichiers sources.
c'est associé à une gestion du défilement de la fenêtre.

j'ai prévu également une notion de container pour améliorer les perfs. Un container est une sous-face qui gère l'affichage et les events entrants pour une fraction de la fenêtre.
L'avantage c'est que suite à une modif, seule le container et non toute la fenêtre, est redessiné.
De plus les containers seront purgés automatiquement quand ils ne seront plus visibles.

mais j'ai encore rien de montrable (fallait pas tout casser).
coccinelle14-Dec-2006/16:19:53+1:00
Voilà, j'ai une version qui gère le curseur. J'ai toujours un léger décalage, mais ça vient gentillement.

C'est toujours ici : http://www.ladyreb.org/wiki/doku.php?id=tmdstyle

Si quelqu'un pouvait me rappeler comment éviter que le newline soit transformé en petit caré, ce serait gentil. Je me souviens d'un flag à lever, mais je ne me souviens plus du quel.

Guest2,

2 choses qui te seront utile de savoir :
- le size rendu par textinfo ou size-text est un peu trop grand et entraine un espace un peu trop large pour placer la suite d'un texte. Il faut utiliser caret-to-offset face face/text pour avoir la bonne position.
- pour pouvoir obtenir les événements key (evenement au clavier) il faut que faut que caret pointe sur focal-face/text sinon ça ne marche pas. J'ai eu très peur, mais en créant une face rien que trapper ces événement, je m'en suis sorti.
guest214-Dec-2006/17:15:38+1:00
hum, j'utilisais déjà caret-to-offset et offset-to-caret donc j'avais pas le problème.
pour le prob des touches, j'ai juste donné le focus à ma fenêtre globale (une box) et ça marche.
guest214-Dec-2006/17:43:46+1:00
hum, j'utilisais déjà caret-to-offset et offset-to-caret donc j'avais pas le problème.
pour le prob des touches, j'ai juste donné le focus à ma fenêtre globale (une box) et ça marche.
coccinelle15-Dec-2006/14:49:18+1:00
Juste pour vous dire que maintenant :
- le curseur est géré à peu près correctement (sauf sa couleur)
- les caractères tappés au clavier sont insérés correctement.

J'ai résolu aussi d'autres problèmes de mise au point. C'est toujours au même endroit : http://www.ladyreb.org/wiki/doku.php?id=tmdstyle

PS. Ca vous intéresse ce genre de style ou est-de un gadget presque inutile ?
guest215-Dec-2006/16:26:31+1:00
béh je sais pas jusqu'où on ira mais temps qu'on est motivé, pourquoi pas continuer...

Là je bosse sur mon parseur pour le rendre réversible.
En un mot un parseur fonctionne habituellement dans un seul sens.
A partir d'une source, il applique des règles et génère une une sortie (dans notre cas du dialecte draw).
Mon but est de réussir à inverser le processus.
A partir, des même règles il est capable de modifier la source si le flux de sortie a été modifié.

Je sais ça parait difficile voir impossible, mais j'approche d'une solution.
shadwolf19-Dec-2006/14:33:16+1:00
inutile ???

Heu je ne crois pas !!
1) Ashley donnerait un oeil et un bras pour avoir ca dans rebgui ^^ en plus la méthode est élégante.

2) On arrive a elever le débat et a aller dans le tres pointu quand meme (bon on a chosi la solution la plus rapide a mettre et la plus esthetique une version Draw /AGG c'est mieux mais rien qu'a l'idée de gérer le curseur moi je choppe une migraine...)

3) Compte sur moi pour faire de la pub et porter le concepte dans RebGUI et comme je l'ai dit depuis le dapart
maintenant qu'on a un plugin REBOL pour tout les navigateurs sous windows 32 avoir ce genre de widget ca pourrait apporter un vrai plus plus a notre chti forum fort sympatique saisie avancée via pluginrebol et TDM -> MakeDoc -> HTML

4) C'est a mon avis un réel besoin dans les interface graphique de nos jours y a qu'a voir GTK+ et son module interne PANGO

5) ca nous permet de patienter en attendant rebol3.0 et le TDM a la mode RT.

En tout cas je me repète mais c'est du tres bon travail et encore une démonstration concrète de la puissance de rebol et du travail d'équipe.

Maintenant faut finir et diffuser promouvoir mais déjà a mon avis si on l'intègre a RebGUI et a ce forum on aura déjà atteind notre but ^^
shadwolf19-Dec-2006/15:14:24+1:00
puis entre nous encore une autre application bien sympatique de ta widget marco ca va etre un editeur de code source REBOL ^^ genre crimson editor mais vraiement très adapter a rebol
shadwolf19-Dec-2006/15:54:21+1:00
et dans cette optique il nous faut une widget capable de gérer

2000 ligne de code par fichiers ouver et de gerer dans les 50 000 widget coloriées ...

D'où le besoin d'une optimisation maximale en phase 2
coccinelle20-Dec-2006/11:07:35+1:00
1) Ashley donnerait un oeil et un bras pour avoir ca dans rebgui ^^ en plus la méthode est élégante.

Y'a qu'à voir sa réaction sur AltMee :

Impressive effort guys, and while it can enable things like WYSIWYG editors and HTML renderers it's not a priority for RebGUI inclusion at present. I'm comfortable waiting for an "official" solution in R3, but if folks need rich text *now* then they have at least two alternatives!
qualop20-Dec-2006/13:48:26+1:00
perso, entre un alternative qui existe en une qui existera peut être un jour.
j'aurrai tendance a privilegier celle qui existe. donc en tout cas pas R3 pour l'instant

bravo pour votre travail...
shadwolf21-Dec-2006/13:37:42+1:00
Comme j'ai dit la solution R3 c'est pas pour tout de suite et en attendant on fait rien... Moi j'aime pas cette vision des choses. Les gens sont trop dépendant de carl et de la VM et j'aime bien leur montrer que dans la VM y a deja tout ce qu'il faut pour faire tout ce qu'on veux.

Le jour ou R3 sortira on s'appercevra soit que c'est plein de bug et pas exploitable (y a rarement un nouveau truc dans rebol qui sort sans un tas de bug (pas que dans rebol OK.. )). Soit que c'est limité et qu'on peux pas faire tour ce qu'on veux avec et faudra encore attendre pour soit que les bugs soient corrigés soit que les fonction soient étendues.

Voila donc en attendant je milite pour ma part pour une widget qui fait le boulot qui a pas de bug et avace la quelle on peut gentillement faire plein d'applications.

Il ya aussi la widget tree pour rebGUI à faire.

Login required to Post.


Powered by RebelBB and REBOL 2.7.8.4.2