Source code: jpicedt/format/latex/parser/LaTeXPutExpression.java
1 /*
2 * jPicEdt version 1.3.2, a picture editor for LaTeX.
3 * Copyright (C) 1999-2002 Sylvain Reynal
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 *
16 * Sylvain Reynal
17 * Département de Physique
18 * Ecole Nationale Supérieure de l'Electronique et de ses Applications (ENSEA)
19 * 6, avenue du Ponceau
20 * F-95014 CERGY CEDEX
21 * Tel : 00 +33 130 736 245
22 * Fax : 00 +33 130 736 667
23 * e-mail : reynal@ensea.fr
24 * jPicEdt web page : http://www.jpicedt.org
25 */
26 package jpicedt.format.latex.parser;
27
28 import jpicedt.graphic.io.parser.*;
29 import jpicedt.graphic.PicPoint;
30 import jpicedt.graphic.model.*;
31
32 /**
33 * \\put(x,y){argument} Depending on the argument found, instanciates :<p>
34 * - PicText : \\makebox, \\framebox, \\dashbox or LR-argument <p>
35 * - PicPolygon : \\line, \\vector.
36 * - PicEllipse : \\circle
37 *
38 * @author reynal
39 */
40 public class LaTeXPutExpression extends SequenceExpression implements ExpressionConstants,PicObjectConstants {
41
42 private Pool pool;
43 private PicPoint putPoint = new PicPoint();// \\put^(x,y)^{...} i.e. location
44 private StringBuffer hrArgument = new StringBuffer(); // used by HRArgument
45
46 // used by LaTeXBoxExpression :
47 private boolean isFixedSizeBox;
48 private double boxWidth, boxHeight, boxDash;
49 private String horAlign, vertAlign;
50 // used by LaTeXLineExpression :
51 private double x,y;
52 // use by LaTeXCircleExpression :
53 private boolean filledCircle;
54
55 /**
56 * Constructor for the LaTeXPutExpression object
57 * @param pl Description of the Parameter
58 */
59 public LaTeXPutExpression(Pool pl) {
60
61 super(true);
62 pool = pl;
63
64 add(new LiteralExpression("\\put"));
65 add(WHITE_SPACES_OR_EOL);
66 add(
67 new PicPointExpression("(", ",", ")") {
68 public void action(ParserEvent e) {
69 if (DEBUG) System.out.println(e);
70 putPoint = ((PicPoint) e.getValue()).toMm(pool.getDouble(LaTeXParser.KEY_UNIT_LENGTH));// global var
71 }
72 });
73 add(WHITE_SPACES_OR_EOL);
74
75 // {stuff} :
76 AlternateExpression putArgs = new AlternateExpression();
77 putArgs.add(new LaTeXBoxExpression());// \\makebox, ...
78 putArgs.add(new LaTeXCircleExpression(false));// \\circle{d}
79 putArgs.add(new LaTeXCircleExpression(true));// \\circle*{d}
80 putArgs.add(new LaTeXOvalExpression());// \\oval(w,h)
81 putArgs.add(new LaTeXLineExpression());// \\line(x,y){len}
82 // [pending] LR-argument, line, vector, ...
83 putArgs.add(new HRArgument()); // pure HR argument (must always be added last)
84 SequenceExpression putArgsEOL = new SequenceExpression(WHITE_SPACES_OR_EOL, putArgs, false);
85 add(new EnclosingExpression("{", putArgsEOL, "}"));
86
87 }
88
89 /** called when this SequenceExpression was successfully parsed -> reinit locals for next time */
90 public void action(ParserEvent e){
91 if (DEBUG) System.out.println(e);
92 putPoint = new PicPoint();
93 hrArgument = new StringBuffer(); // used by HRArgument
94 horAlign = PicText.CENTER_H;
95 vertAlign = PicText.CENTER_V;
96 isFixedSizeBox = false;
97 filledCircle = false;
98 }
99
100 public String toString(){
101 return "[LaTeXPutExpression]";
102 }
103
104 //////////////////////////////////////////// CIRCLE //////////////////////////////////////////////
105
106 /**
107 * \circle{diam} -> circle <p>
108 * \circle*{diam} -> disk (filled)<p>
109 */
110 class LaTeXCircleExpression extends SequenceExpression {
111
112 public LaTeXCircleExpression(boolean filled) {
113
114 super(true);// throw IncompleteExpression
115 filledCircle = filled;
116
117 if (filled) this.add(new LaTeXInstanciationExpression("\\circle*{", new PicEllipse(), pool));
118 else this.add(new LaTeXInstanciationExpression("\\circle{", new PicEllipse(), pool));
119 this.add(WHITE_SPACES_OR_EOL);
120 this.add(
121 new NumericalExpression(DOUBLE, POSITIVE, "}", true) {
122 public void action(ParserEvent e) {
123 if (DEBUG) System.out.println(e);
124 PicEllipse ell = (PicEllipse)(pool.currentObj);
125 ell.setPoint(PicEllipse.P_CENTER, putPoint);
126 double diam = getValue().doubleValue() * pool.getDouble(LaTeXParser.KEY_UNIT_LENGTH);
127 ell.setWidth(diam);
128 ell.setHeight(diam);
129 if (filledCircle) ell.setAttribute(FILL_STYLE,SOLID);
130 }
131 }
132 );
133 }
134 }
135
136 //////////////////////////////////////////// OVAL //////////////////////////////////////////////
137
138 /**
139 * \oval(w,h) or \oval(w,h)[align] (for half- or quarter- ovals).
140 * <p>
141 * Shape is centered on putPoint.
142 * [pending] add "rounded corner" capacity to PicRectangle
143 */
144 class LaTeXOvalExpression extends SequenceExpression {
145
146 public LaTeXOvalExpression() {
147
148 super(true);// throw IncompleteExpression
149
150 this.add(new LaTeXInstanciationExpression("\\oval", new PicRectangle(), pool));
151 this.add(WHITE_SPACES_OR_EOL);
152 this.add(
153 new PicPointExpression("(", ",", ")"){
154 public void action(ParserEvent e) {
155 if (DEBUG) System.out.println(e);
156 PicPoint pt = (PicPoint)e.getValue();
157 PicRectangle oval = (PicRectangle)pool.currentObj;
158 oval.setPoint(PicRectangle.P_CENTER, putPoint);
159 double w = pt.x * pool.getDouble(LaTeXParser.KEY_UNIT_LENGTH);
160 oval.setWidth(w);
161 double h = pt.y * pool.getDouble(LaTeXParser.KEY_UNIT_LENGTH);
162 oval.setHeight(h);
163 }
164 }
165 );
166 this.add(WHITE_SPACES_OR_EOL);
167 // [pending] not used so far !!!
168 SequenceExpression alignmentExp = new SequenceExpression(true);// throw IncompleteSequence Exception
169 alignmentExp.add(new LiteralExpression("["));
170 alignmentExp.add(new TextAlignment()); // swallows chars till "]" is found
171 this.add(new OptionalExpression(alignmentExp));
172 }
173 }
174
175 //////////////////////////////////////////// LINES //////////////////////////////////////////////
176
177 /**
178 * \\line(x,y){hor-len} -> line starting at (x,y), and having hor-len as its horizonal extent (except
179 * for vertical lines, where hor-len specifies the vertical extent.<p>
180 * \\vector(x,y){hor-len} -> same thing, yet with an arrow
181 */
182 class LaTeXLineExpression extends SequenceExpression {
183
184 public LaTeXLineExpression() {
185
186 super(true);// throw IncompleteExpression
187
188 // \line -> set first polygon point
189 this.add(new AlternateExpression(
190 new LaTeXInstanciationExpression("\\line", new PicPolygon(new PicPoint(),new PicPoint()), pool),
191 new LaTeXInstanciationExpression("\\vector", new PicPolygon(new PicPoint(),new PicPoint()), pool){
192 public void action(ParserEvent e) {
193 super.action(e);
194 pool.currentObj.setAttribute(RIGHT_ARROW, Arrow.ARROW_HEAD);
195 }}));
196 this.add(WHITE_SPACES_OR_EOL);
197 // (x,y) -> set slope
198 this.add(
199 new PicPointExpression("(", ",", ")"){
200 public void action(ParserEvent e) {
201 if (DEBUG) System.out.println(e);
202 PicPoint pt = (PicPoint)e.getValue();
203 x = pt.x ; y = pt.y;
204 }
205 }
206 );
207 this.add(WHITE_SPACES_OR_EOL);
208 // {
209 this.add(new LiteralExpression("{"));
210 // len} -> must be .ge. 0
211 this.add(
212 new NumericalExpression(DOUBLE, POSITIVE, "}", true) {
213 public void action(ParserEvent e) {
214 if (DEBUG) System.out.println(e);
215 // horizontal extent (except for vertical lines) :
216 double len = ((Double)e.getValue()).doubleValue() * pool.getDouble(LaTeXParser.KEY_UNIT_LENGTH);
217 PicPolygon pp = ((PicPolygon)(pool.currentObj));
218 // vertical line :
219 PicPoint pt1 = new PicPoint(putPoint);
220 if (x==0){
221 if (y>=0) pt1.translate(0,len);
222 else pt1.translate(0,-len);
223 }
224 // other lines :
225 else {
226 if (x>=0) pt1.x += len;
227 else pt1.x -= len;
228 if (y>=0) pt1.y += len * Math.abs(y/x);
229 else pt1.y -= len * Math.abs(y/x);
230 }
231 pp.setPoint(0,putPoint);
232 pp.setPoint(1,pt1);
233 }
234 }
235 );
236 }
237 }
238
239 //////////////////////////////////////////// BOXES //////////////////////////////////////////////
240
241 /**
242 * PicText : argument =<br>
243 * \\makebox(w,h)[vh]{text or LaTeX command}<br>
244 * \\framebox(w,h)[vh]{text or LaTeX command}<br>
245 * \\dashbox{dash}(w,h)[vh]{text or LaTeX command}<br>
246 * interpret(c) return false if none of these have been found, and cursor position is left unchanged<br>
247 * Uses "TextAlignement"<BR>
248 * @author reynal
249 */
250 class LaTeXBoxExpression extends SequenceExpression {
251
252 public LaTeXBoxExpression() {
253
254 super(true);// possibly throws IncompleteSequence Exception if only \\XXXXbox was found
255
256 PicAttributeSet dummy = new PicAttributeSet(); // only here because PicText constructor requires one.
257
258
259 // boxtype :
260 AlternateExpression boxType = new AlternateExpression();// \|/ boxed ?
261
262 // \\makebox
263 boxType.add(new LaTeXInstanciationExpression(
264 "\\makebox",
265 new PicText(new PicPoint(), "", PicText.NO_FRAME, PicText.CENTER_H, PicText.CENTER_V, dummy),
266 pool));
267
268 // \\framebox
269 boxType.add(new LaTeXInstanciationExpression(
270 "\\framebox",
271 new PicText(new PicPoint(), "", PicText.RECTANGLE, PicText.CENTER_H, PicText.CENTER_V, dummy),
272 pool));
273
274 // \\frame (must appear AFTER framebox !!!)
275 boxType.add(new LaTeXInstanciationExpression(
276 "\\frame",
277 new PicText(new PicPoint(), "", PicText.RECTANGLE, PicText.CENTER_H, PicText.CENTER_V, dummy),
278 pool));
279
280 // \\dashbox{dash}
281 boxType.add(new SequenceExpression(
282 new LaTeXInstanciationExpression(
283 "\\dashbox",
284 new PicText(new PicPoint(), "", PicText.RECTANGLE, PicText.CENTER_H, PicText.CENTER_V, dummy),
285 pool),
286 WHITE_SPACES_OR_EOL,
287 new SequenceExpression(
288 new LiteralExpression("{"), // {dash}
289 new NumericalExpression(DOUBLE, POSITIVE, "}", true) {
290 public void action(ParserEvent e) {
291 if (DEBUG) System.out.println(e);
292 boxDash = ((Double) e.getValue()).doubleValue() * pool.getDouble(LaTeXParser.KEY_UNIT_LENGTH);
293 pool.currentObj.setAttribute(DASH_OPAQUE, new Double(boxDash));
294 pool.currentObj.setAttribute(DASH_TRANSPARENT, new Double(boxDash));
295 }
296 },
297 true),
298 true));// possibly throws IncompleteSequence Exception once "{" was found
299 this.add(boxType);
300 this.add(WHITE_SPACES_OR_EOL);
301 // (w,h) (optional ; if found, we instanciate a PicRectangle and make the previously instanciated
302 // PicText frameless)
303 this.add(new OptionalExpression(new PicPointExpression("(", ",", ")"){
304 public void action(ParserEvent e){
305 if (DEBUG) System.out.println(e);
306 isFixedSizeBox = true; // flag to inform the EnclosingExpression - see below - it must instanciate a PicRectangle
307 PicPoint pt = (PicPoint)e.getValue();
308 boxWidth = pt.x; boxHeight = pt.y;
309 }}));
310 this.add(WHITE_SPACES_OR_EOL);
311 // optional alignment : [vh] where v = b|t|c|"" and h = r|l|c|"" ("" default to center)
312 SequenceExpression alignmentExp = new SequenceExpression(true);// throw IncompleteSequence Exception
313 alignmentExp.add(new LiteralExpression("["));
314 alignmentExp.add(new TextAlignment()); // swallows chars till "]" is found
315 alignmentExp.add(WHITE_SPACES_OR_EOL);
316 this.add(new OptionalExpression(alignmentExp));
317 // text or LaTeX Command
318 this.add(WHITE_SPACES_OR_EOL);
319 this.add(new BoxEnclosedText());
320 }
321 }
322
323 /**
324 * Handles text inside a box-command (e.g. \\makebox{text}), after replacing CR by white-spaces as TeX does.
325 */
326 class BoxEnclosedText extends EnclosingExpression {
327
328 public BoxEnclosedText(){
329 super("{", null, "}");
330 }
331
332 public void action(ParserEvent e) {
333 if (DEBUG) System.out.println(e);
334 PicText text = ((PicText)pool.currentObj);
335 String s = getEnclosedString().replace('\n',' ');
336 s = Context.removeRedundantWhiteSpaces(s);
337 text.setText(s);
338 text.setVertAlign(vertAlign);
339 text.setHorAlign(horAlign);
340 if (isFixedSizeBox){
341 // change text location :
342 PicPoint ptText = new PicPoint();
343 if (vertAlign == PicText.TOP) ptText.y = putPoint.y + boxHeight;
344 else if (vertAlign == PicText.BOTTOM) ptText.y = putPoint.y;
345 else ptText.y = putPoint.y + 0.5*boxHeight; // CENTER_V
346 if (horAlign == PicText.LEFT) ptText.x = putPoint.x;
347 else if (horAlign == PicText.RIGHT) ptText.x = putPoint.x + boxWidth;
348 else ptText.x = putPoint.x + 0.5*boxWidth; // CENTER_H
349 text.setPoint(PicText.P_ANCHOR, ptText);
350 // possibly add a box on its own, set its size and location :
351 if (text.getFrameType() == PicText.RECTANGLE){
352 // suppress box from PicText
353 text.setFrameType(PicText.NO_FRAME);
354 PicPoint pt2 = new PicPoint(putPoint.x + boxWidth, putPoint.y + boxHeight);
355 // copy attribute set from text to box (dash, ...)
356 PicRectangle box = new PicRectangle(putPoint,pt2,text.getAttributeSet());
357 pool.currentGroup.addChild(box);
358 pool.currentObj = box; // only for security reason... (probably useless)
359 }
360 isFixedSizeBox = false; // reset flag for next time !
361 }
362 else {
363 text.setPoint(PicText.P_ANCHOR, putPoint);
364 }
365 }
366 }
367
368 /**
369 * handles boxes alignement, e.g. "bc]" ,... First "[" isn't parsed here.
370 * Modifies global vars "vertAlign" and "horAlign".
371 */
372 class TextAlignment extends WordExpression {
373
374 public TextAlignment(){
375 super("]", true); // swallows "]" and can return an empty String as in "[]"
376 }
377
378 public void action(ParserEvent e) {
379 if (DEBUG) System.out.println(e);
380 String s = (String) e.getValue();
381
382 if (s.indexOf("t")!=-1) vertAlign = PicText.TOP;
383 else if (s.indexOf("b")!=-1) vertAlign = PicText.BOTTOM;
384 else vertAlign = PicText.CENTER_V;
385
386 if (s.indexOf("l")!=-1) horAlign = PicText.LEFT;
387 else if (s.indexOf("r")!=-1) horAlign = PicText.RIGHT;
388 else horAlign = PicText.CENTER_H;
389 }
390 }
391
392 /**
393 * swallow as many chars as possible and push them in "hrArgument" buffer, replacing
394 * CR by whitespaces, as TeX does.
395 */
396 class HRArgumentSucker extends WildCharExpression {
397
398 public HRArgumentSucker(){ // no jokes, but it really sucks !
399 super(ANY_CHAR_EOL);
400 }
401 public void action(ParserEvent e){
402 if (DEBUG) System.out.println(e);
403 Character cc = getCharacter();
404 if (cc.charValue() == '\n') hrArgument.append(' ');
405 else hrArgument.append(cc);
406 }
407 }
408
409 /**
410 * handles content of "{stuff}" when no other expression matches, by instanciating a PicText
411 * with "stuff" as the PicText string
412 */
413 class HRArgument extends RepeatExpression {
414
415 HRArgument(){
416 super(null,0,AT_LEAST);
417 setPattern(new HRArgumentSucker());
418 }
419
420 public void action(ParserEvent e){
421 if (DEBUG) System.out.println(e);
422 String s = Context.removeRedundantWhiteSpaces(hrArgument.toString());
423 pool.currentObj = new PicText(putPoint, s, PicText.NO_FRAME, PicText.CENTER_H, PicText.CENTER_V, pool.getAttributeSet(LaTeXParser.KEY_ATTRIBUTES));
424 pool.currentGroup.addChild(pool.currentObj);
425 }
426 }
427
428 }
429