Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGHtmlIndex.cxx
Go to the documentation of this file.
1// $Id: TGHtmlIndex.cxx,v 1.2 2007/05/20 23:22:13 rdm Exp $
2// Author: Valeriy Onuchin 03/05/2007
3
4/*************************************************************************
5 * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/**************************************************************************
13
14 HTML widget for xclass. Based on tkhtml 1.28
15 Copyright (C) 1997-2000 D. Richard Hipp <drh@acm.org>
16 Copyright (C) 2002-2003 Hector Peraza.
17
18 This library is free software; you can redistribute it and/or
19 modify it under the terms of the GNU Library General Public
20 License as published by the Free Software Foundation; either
21 version 2 of the License, or (at your option) any later version.
22
23 This library is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 Library General Public License for more details.
27
28 You should have received a copy of the GNU Library General Public
29 License along with this library; if not, write to the Free
30 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
32**************************************************************************/
33
34// Routines that deal with indexes
35
36#include <cctype>
37#include <cstring>
38#include <cstdlib>
39
40#include "TGHtml.h"
41#include "strlcpy.h"
42
43////////////////////////////////////////////////////////////////////////////////
44/// Return a pointer to the Nth TGHtmlElement in the list. If there
45/// is no Nth element, return 0 if flag==0 and return either the first
46/// or last element (whichever is closest) if flag!=0
47
49{
51 int n;
52
53 if (N == 0) return fPFirst;
54
55 if (N > fNToken / 2) {
56 // Start at the end and work back toward the beginning
57 for (p = fPLast, n = fNToken; p; p = p->fPPrev) {
58 if (p->fType != Html_Block) {
59 if (p->fElId == N) break;
60 --n;
61 }
62 }
63 } else {
64 // Start at the beginning and work forward
65 for (p = fPFirst; p; p = p->fPNext) {
66 if (p->fType != Html_Block) {
67 --N;
68 if (N == p->fElId) break;
69 }
70 }
71 }
72
73 return p;
74}
75
76////////////////////////////////////////////////////////////////////////////////
77/// Return the token number for the given TGHtmlElement
78
80{
81 //int n = 0;
82
83 if (!p) return -1;
84 return p->fElId;
85
86/// while (p) {
87/// if (p->fType != Html_Block) ++n;
88/// p = p->fPPrev;
89/// }
90///
91/// return n;
92}
93
94////////////////////////////////////////////////////////////////////////////////
95/// Find the maximum index for the given token
96
97void TGHtml::MaxIndex(TGHtmlElement *p, int *pIndex, int isLast)
98{
99 if (p == 0) {
100 *pIndex = 0;
101 } else {
102 switch (p->fType) {
103 case Html_Text:
104 *pIndex = p->fCount - isLast;
105 break;
106
107 case Html_Space:
108 if (p->fStyle.fFlags & STY_Preformatted) {
109 *pIndex = p->fCount - isLast;
110 } else {
111 *pIndex = 0;
112 }
113 break;
114
115 default:
116 *pIndex = 0;
117 break;
118 }
119 }
120}
121
122////////////////////////////////////////////////////////////////////////////////
123/// Given a Block and an x coordinate, find the Index of the character
124/// that is closest to the given x coordinate.
125///
126/// The x-coordinate might specify a point to the left of the block,
127/// in which case the procedure returns the first token and a character
128/// index of 0. Or the x-coordinate might specify a point to the right
129/// of the block, in which case the last token is returned with an index
130/// equal to its last character.
131
133 TGHtmlElement **ppToken, int *pIndex)
134{
135 TGHtmlElement *p;
136 TGFont *font;
137 int len;
138 int n;
139
140 p = pBlock->fPNext;
141 font = GetFont(p->fStyle.fFont);
142 if (x <= pBlock->fLeft) {
143 *ppToken = p;
144 *pIndex = 0;
145 return;
146 } else if (x >= pBlock->fRight) {
147 *ppToken = p;
148 *pIndex = 0;
149 while (p && p->fType != Html_Block) {
150 *ppToken = p;
151 p = p->fPNext;
152 }
153 p = *ppToken;
154 if (p && p->fType == Html_Text) {
155 *pIndex = p->fCount - 1;
156 }
157 return;
158 }
159 if (pBlock->fN == 0) {
160 *ppToken = p;
161 *pIndex = 0;
162 }
163 n = font->MeasureChars(pBlock->fZ, pBlock->fN, x - pBlock->fLeft, 0, &len);
164 *pIndex = 0;
165 *ppToken = 0;
166 while (p && n >= 0) {
167 switch (p->fType) {
168 case Html_Text:
169 if (n < p->fCount) {
170 *pIndex = n;
171 } else {
172 *pIndex = p->fCount - 1;
173 }
174 *ppToken = p;
175 n -= p->fCount;
176 break;
177
178 case Html_Space:
179 if (p->fStyle.fFlags & STY_Preformatted) {
180 if (n < p->fCount) {
181 *pIndex = n;
182 } else {
183 *pIndex = p->fCount - 1;
184 }
185 *ppToken = p;
186 n -= p->fCount;
187 } else {
188 *pIndex = 0;
189 *ppToken = p;
190 --n;
191 }
192 break;
193
194 default:
195 break;
196 }
197 if (p) p = p->fPNext;
198 }
199}
200
201////////////////////////////////////////////////////////////////////////////////
202/// Convert an Element-based index into a Block-based index.
203///
204/// In other words, given a pointer to an element and an index
205/// of a particular character within that element, compute a
206/// pointer to the TGHtmlBlock used to display that character and
207/// the index in the TGHtmlBlock of the character.
208
210 TGHtmlBlock **ppBlock, int *piIndex)
211{
212 int n = sIndex.fI;
213 TGHtmlElement *p;
214
215 if (sIndex.fP == 0) {
216 *ppBlock = 0;
217 *piIndex = 0;
218 return;
219 }
220 p = sIndex.fP->fPPrev;
221 while (p && p->fType != Html_Block) {
222 switch (p->fType) {
223 case Html_Text:
224 n += p->fCount;
225 break;
226 case Html_Space:
227 if (p->fStyle.fFlags & STY_Preformatted) {
228 n += p->fCount;
229 } else {
230 n++;
231 }
232 break;
233 default:
234 break;
235 }
236 p = p->fPPrev;
237 }
238 if (p) {
239 *ppBlock = (TGHtmlBlock *) p;
240 *piIndex = n;
241 return;
242 }
243 for (p = sIndex.fP; p && p->fType != Html_Block; p = p->fPNext) {}
244 *ppBlock = (TGHtmlBlock *) p;
245 *piIndex = 0;
246}
247
248////////////////////////////////////////////////////////////////////////////////
249/// Modify an index for both pointer and char +/-/=N
250
251int TGHtml::IndexMod(TGHtmlElement **pp, int *ip, char *cp)
252{
253 char nbuf[50];
254 int i, x, cnt, ccnt[2], cflag[2];
255
256 if (pp == 0 || !*pp) return -1;
257 ccnt[0] = ccnt[1] = cflag[0] = cflag[1] = 0;
258 x = 0;
259 while (*cp && x < 2) {
260 cnt = 0;
261 i = 1;
262 while (i < 45 && isdigit(cp[i])) {
263 nbuf[i-1] = cp[i];
264 i++;
265 }
266 if (i > 1) {
267 nbuf[i-1] = 0;
268 cnt = atoi(nbuf);
269 if (cnt < 0) return -1;
270 }
271 switch (*cp) {
272 case '+': if (i == 1) ccnt[x] = 1; else ccnt[x] = cnt; break;
273 case '-': if (i == 1) ccnt[x] = -1; else ccnt[x] = -cnt; break;
274 case '=': ccnt[x] = 0; cflag[x] = 1; break;
275 default: return -1;
276 }
277 cp += i;
278 ++x;
279 }
280 if (ccnt[0] > 0) {
281 for (i = 0; i < ccnt[0] && (*pp)->fPNext; ++i) {
282 *pp = (*pp)->fPNext;
283 while ((*pp)->fType == Html_Block && (*pp)->fPNext) {
284 *pp = (*pp)->fPNext;
285 }
286 }
287 } else if (ccnt[0] < 0) {
288 for (i = 0; ccnt[0] < i && (*pp)->fPPrev; --i) {
289 //printf("i=%d, cnt=%d\n", i, ccnt[0]);
290 *pp = (*pp)->fPPrev;
291 while ((*pp)->fType == Html_Block && (*pp)->fPPrev) {
292 *pp = (*pp)->fPPrev;
293 }
294 }
295 }
296 if (ccnt[1] > 0) {
297 for (i = 0; i < ccnt[1]; ++i) (*ip)++;
298 } else if (ccnt[1] < 0) {
299 for (i = 0; i > ccnt[1]; --i) (*ip)--;
300 }
301 return 0;
302}
303
304////////////////////////////////////////////////////////////////////////////////
305/// Given a base index name (without any modifiers) return a pointer
306/// to the token described, and the character within that token.
307///
308/// Valid input forms include:
309///
310/// N.M Token number N (with numbering starting at 1) and
311/// character number M (with numbering starting at 0).
312///
313/// M.X Like above, but token is markup and X is an attribute.
314///
315/// begin The start of all text
316///
317/// end The end of all text
318///
319/// N.last Last character of token number N.
320///
321/// N.end One past last character of token number N.
322///
323/// sel.first First character of the selection.
324///
325/// sel.last Last character of the selection.
326///
327/// sel.end On past last character of the selection.
328///
329/// insert The character holding the insertion cursor.
330///
331/// @X,Y The character a location X,Y of the clipping window.
332///
333/// &DOM The DOM Address of a token.
334///
335/// Zero is returned if we are successful and non-zero if there is
336/// any kind of error.
337///
338/// If the given token doesn't exist (for example if there are only 10
339/// tokens and 11.5 is requested) then *ppToken is left pointing to NULL.
340/// But the function still returns 0 for success.
341
342int TGHtml::DecodeBaseIndex(const char *baseIx,
343 TGHtmlElement **ppToken, int *pIndex)
344{
345 int i, n, x, y;
346 TGHtmlElement *p = 0;
347 TGHtmlBlock *pBlock;
348 TGHtmlBlock *pNearby;
349 int dist = 1000000;
350 int rc = 0;
351 char buf[200], *base = buf, *suffix, *ep;
352
353 strlcpy(buf, baseIx, sizeof(buf));
354
355 while (isspace((unsigned char)*base)) base++;
356 ep = base;
357 while (*ep && !isspace((unsigned char)*ep)) ep++;
358 *ep = 0;
359
360 if ((suffix = strchr(base, ':'))) *suffix = 0;
361
362 switch (*base) {
363 case '1': case '2': case '3': case '4': case '5':
364 case '6': case '7': case '8': case '9': case '0':
365 // coverity[secure_coding]
366 n = sscanf(base, "%d.%d", &x, &y);
367 if (n > 0) {
368 p = *ppToken = TokenByIndex(x, 0);
369 }
370 if (n == 2) {
371 *pIndex = y;
372 } else {
373 for (i = 1; isdigit(base[i]); ++i) {}
374 if (base[i] == 0) {
375 *pIndex = 0;
376 } else if (strcmp(&base[i], ".last") == 0) {
377 MaxIndex(p, pIndex, 1);
378 } else if (strcmp(&base[i], ".end") == 0) {
379 MaxIndex(p, pIndex, 0);
380 (*pIndex)++;
381 } else {
382 if (n == 1 && p && p->IsMarkup() && base[i] == '.' &&
383 p->MarkupArg(fZBase + i + 1, 0)) {
384 *pIndex = 0;
385 } else {
386 rc = 1;
387 }
388 }
389 }
390 break;
391
392 case 'b':
393 if (strcmp(base, "begin") == 0) {
394 p = *ppToken = fPFirst;
395 *pIndex = 0;
396 } else {
397 rc = 1;
398 }
399 break;
400
401 case 'e':
402 if (strcmp(base, "end") == 0) {
403 p = *ppToken = fPLast;
404 MaxIndex(p, pIndex, 0);
405 } else {
406 rc = 1;
407 }
408 break;
409
410 case 'l':
411 if (strcmp(base, "last") == 0) {
412 p = *ppToken = fPLast;
413 MaxIndex(p, pIndex, 1);
414 } else {
415 rc = 1;
416 }
417 break;
418
419 case 's':
420 if (strcmp(base, "sel.first") == 0) {
421 *ppToken = fSelBegin.fP;
422 *pIndex = fSelBegin.fI;
423 } else if (strcmp(base, "sel.last") == 0) {
424 *ppToken = fSelEnd.fP;
425 *pIndex = fSelEnd.fI;
426 } else if (strcmp(base, "sel.end") == 0) {
427 *ppToken = fSelEnd.fP;
428 *pIndex = fSelEnd.fI + 1;
429 } else {
430 rc = 1;
431 }
432 break;
433
434 case 'i':
435 if (strcmp(baseIx, "insert") == 0) {
436 *ppToken = fIns.fP;
437 *pIndex = fIns.fI;
438 } else {
439 rc = 1;
440 }
441 break;
442
443#if 0
444 case '&':
445 *pIndex = 0;
446 if (DomIdLookup("id", base + 1, ppToken)) rc = 1;
447 break;
448#endif
449
450 case '@':
451 n = sscanf(base, "@%d,%d", &x, &y);
452 if (n != 2) {
453 rc = 1;
454 break;
455 }
456 x += fVisible.fX;
457 y += fVisible.fY;
458 pNearby = 0;
459 *ppToken = fPLast;
460 *pIndex = 0;
461 for (pBlock = fFirstBlock; pBlock; pBlock = pBlock->fBNext) {
462 int dotest;
463 if (pBlock->fN == 0) {
464 switch (pBlock->fPNext->fType) {
465 case Html_LI:
466 case Html_IMG:
467 case Html_INPUT:
468 case Html_TEXTAREA:
469 case Html_SELECT:
470 dotest = 1;
471 break;
472 default:
473 dotest = 0;
474 break;
475 }
476 } else {
477 dotest = 1;
478 }
479 if (dotest) {
480 if (pBlock->fTop <= y && pBlock->fBottom >= y) {
481 if (pBlock->fLeft > x) {
482 if (pBlock->fLeft - x < dist) {
483 dist = pBlock->fLeft - x;
484 pNearby = pBlock;
485 }
486 } else if (pBlock->fRight < x) {
487 if (x - pBlock->fRight < dist) {
488 dist = x - pBlock->fRight;
489 pNearby = pBlock;
490 }
491 } else {
492 FindIndexInBlock(pBlock, x, ppToken, pIndex);
493 break;
494 }
495 } else {
496 int distY;
497 int distX;
498
499 if (pBlock->fBottom < y) {
500 distY = y - pBlock->fBottom;
501 } else {
502 distY = pBlock->fTop - y;
503 }
504 if (pBlock->fLeft > x) {
505 distX = pBlock->fLeft - x;
506 } else if (pBlock->fRight < x) {
507 distX = x - pBlock->fRight;
508 } else {
509 distX = 0;
510 }
511 if (distX + 4*distY < dist) {
512 dist = distX + 4*distY;
513 pNearby = pBlock;
514 }
515 }
516 }
517 }
518 if (pBlock == 0) {
519 if (pNearby) {
520 FindIndexInBlock(pNearby, x, ppToken, pIndex);
521 }
522 }
523 break;
524
525 default:
526 rc = 1;
527 break;
528 }
529 if (suffix) IndexMod(ppToken, pIndex, suffix + 1);
530
531 return rc;
532}
533
534////////////////////////////////////////////////////////////////////////////////
535/// This routine decodes a complete index specification. A complete
536/// index consists of the base specification followed by modifiers.
537
538int TGHtml::GetIndex(const char *zIndex,
539 TGHtmlElement **ppToken, int *pIndex)
540{
541 return DecodeBaseIndex(zIndex, ppToken, pIndex);
542}
#define N
@ Html_TEXTAREA
@ Html_LI
@ Html_Block
@ Html_Space
@ Html_SELECT
@ Html_Text
@ Html_IMG
@ Html_INPUT
#define STY_Preformatted
Definition TGHtml.h:233
Int_t MeasureChars(const char *source, Int_t numChars, Int_t maxLength, Int_t flags, Int_t *length) const
Determine the number of characters from the string that will fit in the given horizontal span.
Definition TGFont.cxx:478
TGHtmlBlock * fBNext
Definition TGHtml.h:720
Html_u16_t fN
Definition TGHtml.h:719
Html_u16_t fRight
Definition TGHtml.h:718
char * fZ
Definition TGHtml.h:716
Html_u16_t fLeft
Definition TGHtml.h:718
int fBottom
Definition TGHtml.h:717
Html_u8_t fType
Definition TGHtml.h:264
SHtmlStyle_t fStyle
Definition TGHtml.h:263
virtual const char * MarkupArg(const char *, const char *)
Definition TGHtml.h:254
TGHtmlElement * fPPrev
Definition TGHtml.h:262
Html_16_t fCount
Definition TGHtml.h:266
virtual int IsMarkup() const
Definition TGHtml.h:253
TGHtmlElement * fPNext
Definition TGHtml.h:261
SHtmlIndex_t fSelBegin
Definition TGHtml.h:1148
const char * fZBase
Definition TGHtml.h:1259
TGHtmlElement * fPFirst
Definition TGHtml.h:1128
int fNToken
Definition TGHtml.h:1130
virtual TGFont * GetFont(int iFont)
The rendering and layout routines should call this routine in order to get a font structure.
Definition TGHtml.cxx:1408
SHtmlIndex_t fIns
Definition TGHtml.h:1162
void IndexToBlockIndex(SHtmlIndex_t sIndex, TGHtmlBlock **ppBlock, int *piIndex)
Convert an Element-based index into a Block-based index.
void MaxIndex(TGHtmlElement *p, int *pIndex, int isLast)
Find the maximum index for the given token.
int IndexMod(TGHtmlElement **pp, int *ip, char *cp)
Modify an index for both pointer and char +/-/=N.
void FindIndexInBlock(TGHtmlBlock *pBlock, int x, TGHtmlElement **ppToken, int *pIndex)
Given a Block and an x coordinate, find the Index of the character that is closest to the given x coo...
TGHtmlElement * TokenByIndex(int N, int flag)
Return a pointer to the Nth TGHtmlElement in the list.
TGHtmlBlock * fFirstBlock
Definition TGHtml.h:1135
TGHtmlElement * fPLast
Definition TGHtml.h:1129
int TokenNumber(TGHtmlElement *p)
Return the token number for the given TGHtmlElement.
SHtmlIndex_t fSelEnd
Definition TGHtml.h:1149
int GetIndex(const char *zIndex, TGHtmlElement **ppToken, int *pIndex)
This routine decodes a complete index specification.
int DecodeBaseIndex(const char *zBase, TGHtmlElement **ppToken, int *pIndex)
Given a base index name (without any modifiers) return a pointer to the token described,...
TGLongPosition fVisible
Definition TGView.h:51
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TGHtmlElement * fP
Definition TGHtml.h:832
unsigned int fFont
Definition TGHtml.h:144
unsigned int fFlags
Definition TGHtml.h:150