TGHtml.cxx

Go to the documentation of this file.
00001 // $Id: TGHtml.cxx,v 1.4 2007/05/07 15:19:07 brun Exp $
00002 // Author:  Valeriy Onuchin   03/05/2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 /**************************************************************************
00013 
00014     HTML widget for xclass. Based on tkhtml 1.28
00015     Copyright (C) 1997-2000 D. Richard Hipp <drh@acm.org>
00016     Copyright (C) 2002-2003 Hector Peraza.
00017 
00018     This library is free software; you can redistribute it and/or
00019     modify it under the terms of the GNU Library General Public
00020     License as published by the Free Software Foundation; either
00021     version 2 of the License, or (at your option) any later version.
00022 
00023     This library is distributed in the hope that it will be useful,
00024     but WITHOUT ANY WARRANTY; without even the implied warranty of
00025     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026     Library General Public License for more details.
00027 
00028     You should have received a copy of the GNU Library General Public
00029     License along with this library; if not, write to the Free
00030     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00031 
00032 **************************************************************************/
00033 
00034 #include <ctype.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 
00038 #include "TSystem.h"
00039 #include "TGHtml.h"
00040 #include "THashTable.h"
00041 #include "TObjString.h"
00042 #include "TGIdleHandler.h"
00043 #include "TImage.h"
00044 #include "TGScrollBar.h"
00045 #include "TGTextEntry.h"
00046 #include "TGText.h"
00047 #include "Riostream.h"
00048 #include "TGComboBox.h"
00049 #include "TGListBox.h"
00050 
00051 //_____________________________________________________________________________
00052 //
00053 // TGHtml
00054 //
00055 // The ROOT HTML widget. A derivate of TGView.
00056 //_____________________________________________________________________________
00057 
00058 ClassImp(TGHtml)
00059 
00060 int HtmlTraceMask = 0; //HtmlTrace_Table1 | HtmlTrace_Table4;
00061 int HtmlDepth = 0;
00062 
00063 #define DEF_FRAME_BG_COLOR        "#c0c0c0"
00064 #define DEF_FRAME_CURSOR          ""
00065 #define DEF_BUTTON_FG             "black"
00066 #define DEF_BUTTON_HIGHLIGHT_BG   "#d9d9d9"
00067 #define DEF_BUTTON_HIGHLIGHT      "black"
00068 
00069 
00070 //______________________________________________________________________________
00071 TGHtml::TGHtml(const TGWindow *p, int w, int h, int id) : TGView(p, w, h, id)
00072 {
00073    // HTML Widget constructor.
00074 
00075    int i;
00076 
00077    fExiting = 0;
00078    fPFirst = 0;
00079    fPLast = 0;
00080    fNToken = 0;
00081    fLastSized = 0;
00082    fNextPlaced = 0;
00083    fFirstBlock = 0;
00084    fLastBlock = 0;
00085    fFirstInput = 0;
00086    fLastInput = 0;
00087    fNInput = 0;
00088    fNForm = 0;
00089    fVarId = 0;  // do we need this??
00090    fInputIdx = 0;
00091    fRadioIdx = 0;
00092    fSelBegin.fI = 0;
00093    fSelBegin.fP = 0;
00094    fSelEnd.fI = 0;
00095    fSelEnd.fP = 0;
00096    fPSelStartBlock = 0;
00097    fPSelEndBlock = 0;
00098    fInsOnTime = DEF_HTML_INSERT_ON_TIME;
00099    fInsOffTime = DEF_HTML_INSERT_OFF_TIME;
00100    fInsStatus = 0;
00101    fInsTimer = 0;
00102    fIns.fI = 0;
00103    fIns.fP = 0;
00104    fPInsBlock = 0;
00105    fInsIndex = 0;
00106    fZText = 0;
00107    fNText = 0;
00108    fNAlloc = 0;
00109    fNComplete = 0;
00110    fICol = 0;
00111    fIPlaintext = 0;
00112    fPScript = 0;
00113    fIdle = 0;
00114    fStyleStack = 0;
00115    fParaAlignment = ALIGN_None;
00116    fRowAlignment = ALIGN_None;
00117    fAnchorFlags = 0;
00118    fInDt = 0;
00119    fInTr = 0;
00120    fInTd = 0;
00121    fAnchorStart = 0;
00122    fFormStart = 0;
00123    fFormElemStart = 0;
00124    fFormElemLast = 0;
00125    fLoEndPtr = 0;
00126    fLoFormStart = 0;
00127    fInnerList = 0;
00128    ResetLayoutContext();
00129    fHighlightWidth = 0;
00130    fHighlightBgColorPtr = 0;
00131    fHighlightColorPtr = 0;
00132    for (i = 0; i < N_FONT; ++i) fAFont[i] = 0;
00133    memset(fFontValid, 0, sizeof(fFontValid));
00134    for (i = 0; i < N_COLOR; ++i) {
00135       fApColor[i] = 0;
00136       fIDark[i] = 0;
00137       fILight[i] = 0;
00138    }
00139    fFgColor = AllocColor("black");
00140    fBgColor = AllocColor("white"); //AllocColor("#c0c0c0");
00141    fNewLinkColor = AllocColor(DEF_HTML_UNVISITED);
00142    fOldLinkColor = AllocColor(DEF_HTML_VISITED);
00143    fSelectionColor = AllocColor(DEF_HTML_SELECTION_COLOR);
00144 
00145    fApColor[COLOR_Normal] = fFgColor;
00146    fApColor[COLOR_Visited] = fOldLinkColor;
00147    fApColor[COLOR_Unvisited] = fNewLinkColor;
00148    fApColor[COLOR_Selection] = fSelectionColor;
00149    fApColor[COLOR_Background] = fBgColor;
00150 
00151    fBgImage = 0;
00152 
00153    SetBackgroundColor(fApColor[COLOR_Background]->fPixel);
00154    SetBackgroundPixmap(0);  // force usage of solid color
00155 
00156    fColorUsed = 0;
00157 
00158    for (i = 0; i < N_CACHE_GC; ++i) {
00159       fAGcCache[i].fIndex = 0;
00160       fAGcCache[i].fColor = 0;
00161       fAGcCache[i].fFont  = 0;
00162       fAGcCache[i].fGc    = 0;
00163    }
00164    fLastGC = 0;
00165    fSelEndIndex =0;
00166    fSelStartIndex = 0;
00167    fGcNextToFree = 0;
00168    fImageList = 0;
00169    fZBaseHref = 0;
00170    fInnerList = 0;
00171    fFormPadding = 5;
00172    fOverrideFonts = 0;
00173    fOverrideColors = 0;
00174    fHasScript = 0;
00175    fHasFrames = 0;
00176    fAddEndTags = 0;
00177    fTableBorderMin = 0;
00178    fVarind = 0;
00179    fIdind = 0;
00180    fInParse = 0;
00181    fZGoto = 0;
00182    fExts = 0;
00183    fUnderlineLinks = kTRUE;
00184    fExportSelection = DEF_HTML_EXPORT_SEL;
00185    fTableRelief = HTML_RELIEF_RAISED;
00186    fRuleRelief = HTML_RELIEF_SUNKEN;
00187    fRulePadding = 5;
00188    fZBase = 0;
00189    fZBaseHref = 0;
00190    fCursor = kPointer;
00191    fMaxX = 0;
00192    fMaxY = 0;
00193 
00194    fXMargin = fYMargin = 0; //HTML_INDENT/4;
00195 
00196    fFlags = RESIZE_ELEMENTS | RELAYOUT;
00197 
00198    fDirtyLeft = LARGE_NUMBER;
00199    fDirtyRight = 0;
00200    fDirtyTop = LARGE_NUMBER;
00201    fDirtyBottom = 0;
00202 
00203 
00204    fVsb->SetAccelerated();
00205    fHsb->SetAccelerated();
00206 
00207    fLastUri = 0;
00208 
00209    AddInput(kExposureMask | kFocusChangeMask);
00210    AddInput(kButtonPressMask | kButtonReleaseMask | kPointerMotionMask);
00211 
00212    fUidTable = new THashTable(100);
00213 }
00214 
00215 //______________________________________________________________________________
00216 TGHtml::~TGHtml()
00217 {
00218    // HTML widget destructor.
00219 
00220    int i;
00221 
00222    fExiting = 1;
00223    HClear();
00224    for (i = 0; i < N_FONT; i++) {
00225       if (fAFont[i] != 0) fClient->FreeFont(fAFont[i]);
00226    }
00227    if (fInsTimer) delete fInsTimer;
00228    if (fIdle) delete fIdle;
00229 
00230   // TODO: should also free colors!
00231 }
00232 
00233 //______________________________________________________________________________
00234 void TGHtml::UpdateBackgroundStart()
00235 {
00236    // Start background update.
00237 
00238    //GCValues_t gcv;
00239    //unsigned int mask = GCTileStipXOrigin | GCTileStipYOrigin;
00240 //
00241    //gcv.ts_x_origin = -fVvisible.fX;
00242    //gcv.ts_y_origin = -fVisibleStart.fY;
00243    //XChangeGC(GetDisplay(), _backGC, mask, &gcv);
00244 }
00245 
00246 //______________________________________________________________________________
00247 void TGHtml::FreeColor(ColorStruct_t *color)
00248 {
00249    // Free system color.
00250 
00251    gVirtualX->FreeColor(gClient->GetDefaultColormap(), color->fPixel);
00252    delete color;
00253 }
00254 
00255 //______________________________________________________________________________
00256 ColorStruct_t *TGHtml::AllocColor(const char *name)
00257 {
00258    // Allocate system color by name.
00259 
00260    ColorStruct_t *color = new ColorStruct_t;
00261 
00262    color->fPixel = 0;
00263    if (gVirtualX->ParseColor(fClient->GetDefaultColormap(), name, *color)) {
00264       if (!gVirtualX->AllocColor(fClient->GetDefaultColormap(), *color)) {
00265          // force allocation of pixel 0
00266          gVirtualX->QueryColor(fClient->GetDefaultColormap(), *color);
00267          gVirtualX->AllocColor(fClient->GetDefaultColormap(), *color);
00268       }
00269    }
00270 
00271    return color;
00272 }
00273 
00274 //______________________________________________________________________________
00275 ColorStruct_t *TGHtml::AllocColorByValue(ColorStruct_t *color)
00276 {
00277    // Allocate system color by value.
00278 
00279    ColorStruct_t *c = new ColorStruct_t;
00280    *c = *color;
00281 
00282    if (!gVirtualX->AllocColor(gClient->GetDefaultColormap(), *c)) {
00283       // force allocation of pixel 0
00284       c->fPixel = 0;
00285       gVirtualX->QueryColor(gClient->GetDefaultColormap(), *c);
00286       gVirtualX->AllocColor(gClient->GetDefaultColormap(), *c);
00287    }
00288 
00289    return c;
00290 }
00291 
00292 //______________________________________________________________________________
00293 void TGHtml::Clear(Option_t *)
00294 {
00295    // Erase all HTML from this widget and clear the screen. This is
00296    // typically done before loading a new document.
00297 
00298    HClear();
00299    TGView::Clear();
00300    fFlags |= REDRAW_TEXT | VSCROLL | HSCROLL;
00301    ScheduleRedraw();
00302 }
00303 
00304 //______________________________________________________________________________
00305 int TGHtml::ParseText(char *text, const char *index)
00306 {
00307    // Appends (or insert at the specified position) the given HTML text to the
00308    // end of any HTML text that may have been inserted by prior calls to this
00309    // command.  Then it runs the tokenizer, parser and layout engine as far as
00310    // possible with the text that is available. The display is updated
00311    // appropriately.
00312 
00313    SHtmlIndex_t iStart;
00314    TGHtmlElement *savePtr=0;
00315 
00316    iStart.fP = 0;
00317    iStart.fI = 0;
00318 
00319    fLoEndPtr = fPLast;
00320 
00321    if (index) {
00322       int rc = GetIndex(index, &iStart.fP, &iStart.fI);
00323       if (rc != 0) return kFALSE;  // malformed index
00324       if (iStart.fP) {
00325          savePtr = iStart.fP->fPNext;
00326          fPLast = iStart.fP;
00327          iStart.fP->fPNext = 0;
00328       }
00329    }
00330 
00331    TokenizerAppend(text);
00332 
00333    if (fLoEndPtr) {
00334       fFormStart = fLoFormStart;
00335       if (iStart.fP && savePtr) {
00336          AddStyle(fLoEndPtr);
00337          fPLast->fPNext = savePtr;
00338          savePtr->fPPrev = fPLast;
00339          fPLast = fLoEndPtr;
00340          fFlags |= REDRAW_TEXT | RELAYOUT;
00341          ScheduleRedraw();
00342       } else if (fLoEndPtr->fPNext) {
00343          AddStyle(fLoEndPtr->fPNext);
00344       }
00345    } else if (fPFirst) {
00346       fParaAlignment = ALIGN_None;
00347       fRowAlignment = ALIGN_None;
00348       fAnchorFlags = 0;
00349       fInDt = 0;
00350       fAnchorStart = 0;
00351       fFormStart = 0;
00352       fInnerList = 0;
00353       fNInput = 0;
00354       AddStyle(fPFirst);
00355    }
00356 #if 1
00357    fLoEndPtr = fPLast;
00358    fLoFormStart = fFormStart;
00359 #endif
00360 
00361    fFlags |= EXTEND_LAYOUT;
00362    ScheduleRedraw();
00363 
00364    return kTRUE;
00365 }
00366 
00367 //______________________________________________________________________________
00368 void TGHtml::SetTableRelief(int relief)
00369 {
00370    // Sets relief mode of html table.
00371 
00372    if (fTableRelief != relief) {
00373       fTableRelief = relief;
00374       fFlags |= RELAYOUT;
00375       RedrawEverything();
00376    }
00377 }
00378 
00379 //______________________________________________________________________________
00380 void TGHtml::SetRuleRelief(int relief)
00381 {
00382    // Sets relief mode of html rule.
00383 
00384    if (fRuleRelief != relief) {
00385       fRuleRelief = relief;
00386       fFlags |= RELAYOUT;
00387       RedrawEverything();
00388    }
00389 }
00390 
00391 //______________________________________________________________________________
00392 void TGHtml::UnderlineLinks(int onoff)
00393 {
00394    // Set/reset html links underline.
00395 
00396    if (fUnderlineLinks != onoff) {
00397       fUnderlineLinks = onoff;
00398 //    fFlags |= RESIZE_ELEMENTS | RELAYOUT;
00399 //    AddStyle(fPFirst);
00400 
00401       TGHtmlElement *p;
00402       SHtmlStyle_t style = GetCurrentStyle();
00403       for (p = fPFirst; p; p = p->fPNext) {
00404          if (p->fType == Html_A) {
00405             if (fAnchorStart) {
00406                style = PopStyleStack(Html_EndA);
00407                fAnchorStart = 0;
00408                fAnchorFlags = 0;
00409             }
00410             const char *z = p->MarkupArg("href", 0);
00411             if (z) {
00412                style.fColor = GetLinkColor(z);
00413                if (fUnderlineLinks) style.fFlags |= STY_Underline;
00414                fAnchorFlags |= STY_Anchor;
00415                PushStyleStack(Html_EndA, style);
00416                fAnchorStart = (TGHtmlAnchor *) p;
00417             }
00418          } else if (p->fType == Html_EndA) {
00419             if (fAnchorStart) {
00420                ((TGHtmlRef *)p)->fPOther = fAnchorStart;
00421                style = PopStyleStack(Html_EndA);
00422                fAnchorStart = 0;
00423                fAnchorFlags = 0;
00424             }
00425          }
00426          p->fStyle.fFlags &= ~STY_Underline;
00427          p->fStyle.fFlags |= (style.fFlags & STY_Underline);
00428       }
00429 
00430       RedrawEverything();
00431    }
00432 }
00433 
00434 //______________________________________________________________________________
00435 void TGHtml::SetBaseUri(const char *uri)
00436 {
00437    // Sets base URI.
00438 
00439    if (fZBase) delete[] fZBase;
00440    fZBase = 0;
00441    if (uri) fZBase = StrDup(uri);
00442 }
00443 
00444 //______________________________________________________________________________
00445 int TGHtml::GotoAnchor(const char *name)
00446 {
00447    // Go to anchor position.
00448 
00449    const char *z;
00450    TGHtmlElement *p;
00451 
00452    for (p = fPFirst; p; p = p->fPNext) {
00453       if (p->fType == Html_A) {
00454          z = p->MarkupArg("name", 0);
00455          if (z && strcmp(z, name) == 0) {
00456             ScrollToPosition(TGLongPosition(fVisible.fX, ((TGHtmlAnchor *)p)->fY));
00457             return kTRUE;
00458          }
00459       }
00460    }
00461 
00462    return kFALSE;
00463 }
00464 
00465 //______________________________________________________________________________
00466 const char *TGHtml::GetUid(const char *string)
00467 {
00468    // Given a string, this procedure returns a unique identifier for the
00469    // string.
00470    //
00471    // This procedure returns a pointer to a new char string corresponding to
00472    // the "string" argument. The new string has a value identical to string
00473    // (strcmp will return 0), but it's guaranteed that any other calls to this
00474    // procedure with a string equal to "string" will return exactly the same
00475    // result (i.e. can compare pointer *values* directly, without having to
00476    // call strcmp on what they point to).
00477 
00478    //int dummy;
00479 
00480    TObjString *obj = 0;
00481    obj = (TObjString*)fUidTable->FindObject(string);
00482 
00483    if (!obj) {
00484       obj = new TObjString(string);
00485       fUidTable->Add(obj);
00486    }
00487 
00488    return (const char *)obj->GetName();
00489 }
00490 
00491 //______________________________________________________________________________
00492 void TGHtml::ComputeVirtualSize()
00493 {
00494    // Computes virtual size of html area.
00495 
00496    fVirtualSize = TGDimension(fMaxX, fMaxY);
00497 }
00498 
00499 //______________________________________________________________________________
00500 void TGHtml::ClearGcCache()
00501 {
00502    // Clear the cache of GCs
00503 
00504    int i;
00505 
00506    for (i = 0; i < N_CACHE_GC; i++) {
00507       if (fAGcCache[i].fIndex) {
00508          gVirtualX->DeleteGC(fAGcCache[i].fGc);
00509          fAGcCache[i].fIndex = 0;
00510       }
00511    }
00512    fGcNextToFree = 0;
00513 }
00514 
00515 //______________________________________________________________________________
00516 void TGHtml::ResetLayoutContext()
00517 {
00518    // Reset the main layout context in the main widget.  This happens
00519    // before we redo the layout, or just before deleting the widget.
00520 
00521    fLayoutContext.Reset();
00522 }
00523 
00524 //______________________________________________________________________________
00525 void TGHtml::Redraw()
00526 {
00527    // This routine is invoked in order to redraw all or part of the HTML
00528    // widget. This might happen because the display has changed, or in
00529    // response to an expose event. In all cases, though, this routine
00530    // is called by an idle handler.
00531 
00532    Pixmap_t pixmap;           // The buffer on which to render HTML
00533    int x, y, w, h;          // Virtual canvas coordinates of area to draw
00534    int hw;                  // highlight thickness
00535    int clipwinH, clipwinW;  // Width and height of the clipping window
00536    TGHtmlBlock *pBlock;      // For looping over blocks to be drawn
00537    int redoSelection = 0;   // kTRUE to recompute the selection
00538 
00539    // Don't do anything if we are in the middle of a parse.
00540 
00541    if (fInParse) {
00542       fFlags &= ~REDRAW_PENDING;
00543       return;
00544    }
00545 
00546    // Recompute the layout, if necessary or requested.
00547    //
00548    // Calling LayoutDoc() is tricky because LayoutDoc() may invoke one
00549    // or more user-overriden methods, and these methods could, in theory,
00550    // do nasty things. So we have to take precautions:
00551    //
00552    // *  Do not remove the REDRAW_PENDING flag until after LayoutDoc()
00553    //    has been called, to prevent a recursive call to Redraw().
00554 
00555    if ((fFlags & RESIZE_ELEMENTS) != 0 && (fFlags & STYLER_RUNNING) == 0) {
00556       TGHtmlImage *pImage;
00557       for (pImage = fImageList; pImage; pImage = pImage->fPNext) {
00558          pImage->fPList = 0;
00559       }
00560       fLastSized = 0;
00561       fFlags &= ~RESIZE_ELEMENTS;
00562       fFlags |= RELAYOUT;
00563    }
00564 
00565    // We used to make a distinction between RELAYOUT and EXTEND_LAYOUT.
00566    // RELAYOUT would be used when the widget was resized, but the
00567    // less compute-intensive EXTEND_LAYOUT would be used when new
00568    // text was appended.
00569    //
00570    // Unfortunately, EXTEND_LAYOUT has some problem that arise when
00571    // tables are used.  The quick fix is to make an EXTEND_LAYOUT do
00572    // a complete RELAYOUT.  Someday, we need to fix EXTEND_LAYOUT so
00573    // that it works right...
00574 
00575    if ((fFlags & (RELAYOUT | EXTEND_LAYOUT)) != 0
00576       && (fFlags & STYLER_RUNNING) == 0) {
00577       fNextPlaced = 0;
00578       //fNInput = 0;
00579       fVarId = 0;
00580       fMaxX = 0;
00581       fMaxY = 0;
00582       ResetLayoutContext();
00583       fFirstBlock = 0;
00584       fLastBlock = 0;
00585       redoSelection = 1;
00586       fFlags &= ~RELAYOUT;
00587       fFlags |= HSCROLL | VSCROLL | REDRAW_TEXT | EXTEND_LAYOUT;
00588    }
00589 
00590    if ((fFlags & EXTEND_LAYOUT) && fPFirst != 0) {
00591       LayoutDoc();
00592       fFlags &= ~EXTEND_LAYOUT;
00593       FormBlocks();
00594       MapControls();
00595       if (redoSelection && fSelBegin.fP && fSelEnd.fP) {
00596          UpdateSelection(1);
00597          UpdateInsert();
00598       }
00599    }
00600    fFlags &= ~REDRAW_PENDING;
00601 
00602    // No need to do any actual drawing if we aren't mapped
00603 
00604 ////  if (!IsMapped()) return;
00605 
00606    // Update the scrollbars.
00607 
00608    if ((fFlags & (HSCROLL | VSCROLL)) != 0) {
00609       ComputeVirtualSize();
00610       fFlags &= ~(HSCROLL | VSCROLL);
00611 
00612       if (fFlags & REDRAW_PENDING) return;
00613    }
00614 
00615    // Redraw the focus highlight, if requested
00616    hw = fHighlightWidth;
00617    if (fFlags & REDRAW_FOCUS) {
00618       if (hw > 0) {
00619 #if 0
00620       unsigned long color;
00621 
00622       if (fFlags & GOT_FOCUS) {
00623          color = highlightColorPtr;
00624       } else {
00625          color = highlightBgColorPtr;
00626       }
00627       _DrawFocusHighlight(color);
00628 #endif
00629       }
00630       fFlags &= ~REDRAW_FOCUS;
00631    }
00632 
00633    // If the styler is in a callback, abort further processing.
00634    // TODO: check this!
00635 
00636    if (fFlags & STYLER_RUNNING) {
00637       goto earlyOut;
00638    }
00639 
00640    MapControls();
00641 
00642    // Compute the virtual canvas coordinates corresponding to the
00643    // dirty region of the clipping window.
00644 
00645    clipwinW = fCanvas->GetWidth();
00646    clipwinH = fCanvas->GetHeight();
00647    if (fFlags & REDRAW_TEXT) {
00648       w = clipwinW;
00649       h = clipwinH;
00650       x = fVisible.fX;
00651       y = fVisible.fY;
00652       fDirtyLeft = 0;
00653       fDirtyTop = 0;
00654       fFlags &= ~REDRAW_TEXT;
00655    } else {
00656       if (fDirtyLeft < 0) fDirtyLeft = 0;
00657       if (fDirtyRight > clipwinW) fDirtyRight = clipwinW;
00658       if (fDirtyTop < 0) fDirtyTop = 0;
00659       if (fDirtyBottom > clipwinH) fDirtyBottom = clipwinH;
00660       w = fDirtyRight - fDirtyLeft;
00661       h = fDirtyBottom - fDirtyTop;
00662       x = fVisible.fX + fDirtyLeft;
00663       y = fVisible.fY + fDirtyTop;
00664    }
00665 
00666    // Skip the rest of the drawing process if the area to be refreshed is
00667    // less than zero
00668    if (w > 0 && h > 0) {
00669       GContext_t gcBg;
00670       TGRectangle xrec;
00671       // printf("Redraw %dx%d at %d,%d\n", w, h, x, y);
00672 
00673       // Allocate and clear a pixmap upon which to draw
00674       gcBg = GetGC(COLOR_Background, FONT_Any);
00675       pixmap = gVirtualX->CreatePixmap(fCanvas->GetId(), w, h);
00676       xrec.fX = 0;
00677       xrec.fY = 0;
00678       xrec.fW = w;
00679       xrec.fH = h;
00680 #if 0
00681 
00682 //old--    XFillRectangles(GetDisplay(), pixmap, gcBg, &xrec, 1);
00683 //new--    if (fBgImage)
00684 //           BGDraw(fVisible.fX, fVisible.fY, w, h, fBgImage);
00685 #else
00686 
00687       fWhiteGC.SetTileStipXOrigin(-fVisible.fX - fDirtyLeft);
00688       fWhiteGC.SetTileStipYOrigin(-fVisible.fY - fDirtyTop);
00689 
00690       gVirtualX->FillRectangle(pixmap, fWhiteGC.GetGC(), 0, 0, w, h);
00691       UpdateBackgroundStart();  // back to original
00692 #endif
00693 
00694       // Render all visible HTML onto the pixmap
00695       for (pBlock = fFirstBlock; pBlock; pBlock = pBlock->fBNext) {
00696          if (pBlock->fTop <= y+h && pBlock->fBottom >= y-10 &&
00697             pBlock->fLeft <= x+w && pBlock->fRight >= x-10) {
00698             BlockDraw(pBlock, pixmap, x, y, w, h, pixmap);
00699          }
00700       }
00701 
00702       // Finally, copy the pixmap onto the window and delete the pixmap
00703       gVirtualX->CopyArea(pixmap, fCanvas->GetId(),
00704                           gcBg, 0, 0, w, h, fDirtyLeft, fDirtyTop);
00705       gVirtualX->Update(kFALSE);
00706 
00707       gVirtualX->DeletePixmap(pixmap);
00708 //    XFlush(GetDisplay());
00709    }
00710 
00711    // Redraw images, if requested
00712    if (fFlags & REDRAW_IMAGES) {
00713       TGHtmlImage *pImage;
00714       TGHtmlImageMarkup *pElem;
00715       int top, bottom, left, right;     // Coordinates of the clipping window
00716       int imageTop;                     // Top edge of image
00717 
00718       top = fVisible.fY;
00719       bottom = top + fCanvas->GetHeight();
00720       left = fVisible.fX;
00721       right = left + fCanvas->GetWidth();
00722       for (pImage = fImageList; pImage; pImage = pImage->fPNext) {
00723          for (pElem = pImage->fPList; pElem; pElem = pElem->fINext) {
00724             if (pElem->fRedrawNeeded == 0) continue;
00725             imageTop = pElem->fY - pElem->fAscent;
00726             if (imageTop > bottom || imageTop + pElem->fH < top
00727                || pElem->fX > right || pElem->fX + pElem->fW < left) continue;
00728 
00729             DrawImage(pElem, fCanvas->GetId(), left, top, right, bottom);
00730          }
00731       }
00732       fFlags &= ~(REDRAW_IMAGES | ANIMATE_IMAGES);
00733    }
00734 
00735    // Set the dirty region to the empty set.
00736 earlyOut:
00737    fDirtyTop = LARGE_NUMBER;
00738    fDirtyLeft = LARGE_NUMBER;
00739    fDirtyBottom = 0;
00740    fDirtyRight = 0;
00741 
00742    return;
00743 }
00744 
00745 //______________________________________________________________________________
00746 void TGHtml::ScheduleRedraw()
00747 {
00748    // Make sure that a call to the Redraw() routine has been queued.
00749 
00750    if ((fFlags & REDRAW_PENDING) == 0 /*&& IsMapped()*/) {
00751       if (!fIdle) fIdle = new TGIdleHandler(this);
00752       fFlags |= REDRAW_PENDING;
00753    }
00754 }
00755 
00756 //______________________________________________________________________________
00757 Bool_t TGHtml::HandleIdleEvent(TGIdleHandler *idle)
00758 {
00759    // Handles idle event.
00760 
00761    if (idle != fIdle) return kFALSE;
00762    Redraw();
00763    delete fIdle;
00764    fIdle = NULL;
00765    return kTRUE;
00766 }
00767 
00768 //______________________________________________________________________________
00769 void TGHtml::RedrawArea(int left, int top, int right, int bottom)
00770 {
00771    // If any part of the screen needs to be redrawn, then call this routine
00772    // with the values of a box (in window coordinates) that needs to be
00773    // redrawn. This routine will schedule an idle handler to do the redraw.
00774    //
00775    // The box coordinates are relative to the clipping window (fCanvas).
00776 
00777    if (bottom < 0) return;
00778    if (top > (int)fCanvas->GetHeight()) return;
00779    if (right < 0) return;
00780    if (left > (int)fCanvas->GetWidth()) return;
00781    if (fDirtyTop > top) fDirtyTop = top;
00782    if (fDirtyLeft > left) fDirtyLeft = left;
00783    if (fDirtyBottom < bottom) fDirtyBottom = bottom;
00784    if (fDirtyRight < right) fDirtyRight = right;
00785    ScheduleRedraw();
00786 }
00787 
00788 //______________________________________________________________________________
00789 void TGHtml::DrawRegion(Int_t x, Int_t y, UInt_t w, UInt_t h)
00790 {
00791    // Draw region defined by [x,y] [w,h].
00792 
00793    TGView::DrawRegion(x, y, w, h);
00794 
00795 #if 0
00796    RedrawArea(x, y, x + w + 1, y + h + 1);
00797 #else
00798    int left = x;
00799    int top = y;
00800    int right = x + w + 1;
00801    int bottom = y + h + 1;
00802    if (bottom < 0) return;
00803    if (top > (int) fCanvas->GetHeight()) return;
00804    if (right < 0) return;
00805    if (left > (int)fCanvas->GetWidth()) return;
00806    if (fDirtyTop > top) fDirtyTop = top;
00807    if (fDirtyLeft > left) fDirtyLeft = left;
00808    if (fDirtyBottom < bottom) fDirtyBottom = bottom;
00809    if (fDirtyRight < right) fDirtyRight = right;
00810 
00811    fFlags |= REDRAW_PENDING;
00812    Redraw();
00813 #endif
00814    return;
00815 }
00816 
00817 //______________________________________________________________________________
00818 Bool_t TGHtml::ItemLayout()
00819 {
00820    // Layout html widget.
00821 
00822 #if 0
00823    fFlags |= RELAYOUT | VSCROLL | HSCROLL;
00824    Redraw(); //RedrawEverything();
00825 #else
00826    fNextPlaced = 0;
00827    //fNInput = 0;
00828    fVarId = 0;
00829    fMaxX = 0;
00830    fMaxY = 0;
00831    ResetLayoutContext();
00832    fFirstBlock = 0;
00833    fLastBlock = 0;
00834    if (fPFirst != 0) {
00835       LayoutDoc();
00836       FormBlocks();
00837       MapControls();
00838       if (fSelBegin.fP && fSelEnd.fP) {
00839          UpdateSelection(1);
00840          UpdateInsert();
00841       }
00842    }
00843    ComputeVirtualSize();
00844    ScheduleRedraw();
00845 #endif
00846    return kTRUE;
00847 }
00848 
00849 //______________________________________________________________________________
00850 void TGHtml::RedrawBlock(TGHtmlBlock *p)
00851 {
00852    // Redraw the TGHtmlBlock given.
00853 
00854    if (p) {
00855       RedrawArea(p->fLeft - fVisible.fX, p->fTop - fVisible.fY,
00856                  p->fRight - fVisible.fX + 1, p->fBottom - fVisible.fY);
00857    }
00858 }
00859 
00860 //______________________________________________________________________________
00861 void TGHtml::RedrawEverything()
00862 {
00863    // Call this routine to force the entire widget to be redrawn.
00864 
00865    fFlags |= REDRAW_FOCUS | REDRAW_TEXT;
00866    ScheduleRedraw();
00867 }
00868 
00869 //______________________________________________________________________________
00870 void TGHtml::RedrawText(int y)
00871 {
00872    // Call this routine to cause all of the rendered HTML at the
00873    // virtual canvas coordinate of Y and beyond to be redrawn.
00874 
00875    int clipHeight;     // Height of the clipping window
00876 
00877    clipHeight = fCanvas->GetHeight();
00878    y -= fVisible.fY;
00879    if (y < clipHeight) {
00880       RedrawArea(0, y, LARGE_NUMBER, clipHeight);
00881    }
00882 }
00883 
00884 //______________________________________________________________________________
00885 void TGHtml::HClear()
00886 {
00887    // Erase all data from the HTML widget. Bring it back to an empty screen.
00888 
00889    int i;
00890    TGHtmlElement *p, *fPNext;
00891 
00892    fXMargin = fYMargin = 0; //HTML_INDENT/4;
00893 
00894    DeleteControls();
00895    for (p = fPFirst; p; p = fPNext) {
00896       fPNext = p->fPNext;
00897       delete p;
00898    }
00899    fPFirst = 0;
00900    fPLast = 0;
00901    fNToken = 0;
00902    if (fZText) delete[] fZText;
00903    fZText = 0;
00904    fNText = 0;
00905    fNAlloc = 0;
00906    fNComplete = 0;
00907    fIPlaintext = 0;
00908 
00909    for (i = 0; i < N_COLOR; ++i) {
00910       if (fApColor[i] != 0) FreeColor(fApColor[i]);
00911       fApColor[i] = 0;
00912       fIDark[i] = 0;
00913       fILight[i] = 0;
00914    }
00915 
00916    if (!fExiting) {
00917       fFgColor = AllocColor("black");
00918       fBgColor = AllocColor("white"); //AllocColor("#c0c0c0");
00919       fNewLinkColor = AllocColor(DEF_HTML_UNVISITED);
00920       fOldLinkColor = AllocColor(DEF_HTML_VISITED);
00921       fSelectionColor = AllocColor(DEF_HTML_SELECTION_COLOR);
00922 
00923       fApColor[COLOR_Normal] = fFgColor;
00924       fApColor[COLOR_Visited] = fOldLinkColor;
00925       fApColor[COLOR_Unvisited] = fNewLinkColor;
00926       fApColor[COLOR_Selection] = fSelectionColor;
00927       fApColor[COLOR_Background] = fBgColor;
00928 
00929       SetBackgroundColor(fApColor[COLOR_Background]->fPixel);
00930       SetBackgroundPixmap(0);  // use solid color
00931    }
00932 
00933    fColorUsed = 0;
00934    while (fImageList) {
00935       TGHtmlImage *p2 = fImageList;
00936       fImageList = p2->fPNext;
00937       delete p2;
00938    }
00939 
00940    if (fBgImage) delete fBgImage;
00941    fBgImage = 0;
00942 
00943    while (fStyleStack) {
00944       SHtmlStyleStack_t *p2 = fStyleStack;
00945       fStyleStack = p2->fPNext;
00946       delete p2;
00947    }
00948    ClearGcCache();
00949    ResetLayoutContext();
00950 //  if (fZBase) delete[] fZBase;
00951 //  fZBase = 0;
00952 
00953    if (fZBaseHref) delete [] fZBaseHref;
00954    fZBaseHref = 0;
00955    fLastSized = 0;
00956    fNextPlaced = 0;
00957    fFirstBlock = 0;
00958    fLastBlock = 0;
00959    fNInput = 0;
00960    fNForm = 0;
00961    fVarId = 0;
00962    fParaAlignment = ALIGN_None;
00963    fRowAlignment = ALIGN_None;
00964    fAnchorFlags = 0;
00965    fInDt = 0;
00966    fAnchorStart = 0;
00967    fFormStart = 0;
00968    fInnerList = 0;
00969    fMaxX = 0;
00970    fMaxY = 0;
00971 #if 0  // in OXView::Clear()
00972    fVisible = TGPosition(0, 0);
00973    _virtualSize = TGDimension(0, 0);
00974    ScrollTTGPosition(fVisible);
00975 #endif
00976    fPInsBlock = 0;
00977    fIns.fP = 0;
00978    fSelBegin.fP = 0;
00979    fSelEnd.fP = 0;
00980    fPSelStartBlock = 0;
00981    fPSelEndBlock = 0;
00982    fHasScript = 0;
00983    fHasFrames = 0;
00984    fLastUri = 0;
00985 }
00986 
00987 //______________________________________________________________________________
00988 Bool_t TGHtml::HandleTimer(TTimer *t)
00989 {
00990    // Handle timer event.
00991 
00992    if (t == fInsTimer) {
00993       if (fInsTimer) delete fInsTimer;
00994       fInsTimer = NULL;
00995       FlashCursor();
00996       return kTRUE;
00997    } else {
00998       TGHtmlImage *pImage;
00999       for (pImage = fImageList; pImage; pImage = pImage->fPNext) {
01000          if (pImage->fTimer == t) {
01001             AnimateImage(pImage);
01002             return kTRUE;
01003          }
01004       }
01005    }
01006    return kFALSE;
01007 }
01008 
01009 //______________________________________________________________________________
01010 void TGHtml::FlashCursor()
01011 {
01012    // Flash the insertion cursor.
01013 
01014    if (fPInsBlock == 0 || fInsOnTime <= 0 || fInsOffTime <= 0) return;
01015    RedrawBlock(fPInsBlock);
01016    if ((fFlags & GOT_FOCUS) == 0) {
01017       fInsStatus = 0;
01018    } else if (fInsStatus) {
01019       fInsTimer = new TTimer(this, fInsOffTime);
01020       fInsStatus = 0;
01021    } else {
01022       fInsTimer = new TTimer(this, fInsOnTime);
01023       fInsStatus = 1;
01024    }
01025 }
01026 
01027 //______________________________________________________________________________
01028 GContext_t TGHtml::GetGC(int color, int font)
01029 {
01030    // Return a GC from the cache.  As many as N_CACHE_GCs are kept valid
01031    // at any one time.  They are replaced using an LRU algorithm.
01032    //
01033    // A value of FONT_Any (-1) for the font means "don't care".
01034 
01035    int i, j;
01036    GcCache_t *p = fAGcCache;
01037    GCValues_t gcValues;
01038    TGFont *xfont;
01039 
01040    // Check for an existing GC.
01041 
01042    if (color < 0 || color >= N_COLOR) color = 0;
01043    if (font < FONT_Any || font >= N_FONT) font = FONT_Default;
01044 
01045    for (i = 0; i < N_CACHE_GC; i++, p++) {
01046       if (p->fIndex == 0) continue;
01047       if ((font < 0 || p->fFont == font) && p->fColor == color) {
01048          if (p->fIndex > 1) {
01049             for (j = 0; j < N_CACHE_GC; j++) {
01050                if (fAGcCache[j].fIndex && fAGcCache[j].fIndex < p->fIndex ) {
01051                   fAGcCache[j].fIndex++;
01052                }
01053             }
01054             p->fIndex = 1;
01055          }
01056          return fAGcCache[i].fGc;
01057       }
01058    }
01059 
01060    // No GC matches. Find a place to allocate a new GC.
01061 
01062    p = fAGcCache;
01063    for (i = 0; i < N_CACHE_GC; i++, p++) {
01064       if (p->fIndex == 0 || p->fIndex == N_CACHE_GC) break;
01065    }
01066    if (i >= N_CACHE_GC) {  // No slot, so free one (round-robin)
01067       p = fAGcCache;
01068       for (i = 0; i < N_CACHE_GC && i < fGcNextToFree; ++i, ++p) {}
01069          fGcNextToFree = (fGcNextToFree + 1) % N_CACHE_GC;
01070          gVirtualX->DeleteGC(p->fGc);
01071    }
01072    gcValues.fForeground = fApColor[color]->fPixel;
01073    gcValues.fGraphicsExposures = kTRUE;
01074    gcValues.fMask = kGCForeground | kGCGraphicsExposures;
01075 
01076    if (font < 0) font = FONT_Default;
01077    xfont = GetFont(font);
01078 
01079    if (xfont) {
01080       gcValues.fFont = xfont->GetFontHandle();
01081       gcValues.fMask |= kGCFont;
01082    }
01083 
01084    p->fGc = gVirtualX->CreateGC(fId, &gcValues);
01085 
01086    if (p->fIndex == 0) p->fIndex = N_CACHE_GC + 1;
01087    for (j = 0; j < N_CACHE_GC; j++) {
01088       if (fAGcCache[j].fIndex && fAGcCache[j].fIndex < p->fIndex) {
01089          fAGcCache[j].fIndex++;
01090       }
01091    }
01092    p->fIndex = 1;
01093    p->fFont = font;
01094    p->fColor = color;
01095 
01096    return p->fGc;
01097 }
01098 
01099 //______________________________________________________________________________
01100 GContext_t TGHtml::GetAnyGC()
01101 {
01102    // Retrieve any valid GC. The font and color don't matter since the
01103    // GC will only be used for copying.
01104 
01105    int i;
01106    GcCache_t *p = fAGcCache;
01107 
01108    for (i = 0; i < N_CACHE_GC; i++, p++) {
01109       if (p->fIndex) return p->fGc;
01110    }
01111 
01112    return GetGC(COLOR_Normal, FONT_Default);
01113 }
01114 
01115 //______________________________________________________________________________
01116 Bool_t TGHtml::HandleFocusChange(Event_t *event)
01117 {
01118    // Handle focus change event.
01119 
01120    if (event->fType == kFocusIn) {
01121       fFlags |= GOT_FOCUS | REDRAW_FOCUS;
01122       ScheduleRedraw();
01123       UpdateInsert();
01124    } else {  // FocusOut
01125       fFlags &= ~GOT_FOCUS;
01126       fFlags |= REDRAW_FOCUS;
01127       ScheduleRedraw();
01128    }
01129    return kTRUE;
01130 }
01131 
01132 //______________________________________________________________________________
01133 TGHtmlInput *TGHtml::GetInputElement(int x, int y)
01134 {
01135    // This routine searchs for a hyperlink beneath the coordinates x,y
01136    // and returns a pointer to the HREF for that hyperlink. The text
01137    // is held in one of the markup argv[] fields of the <a> markup.
01138 
01139    TGHtmlInput *p;     // For looping over all controls
01140    int vx, vy, vw, vh;    // Part of the virtual canvas that is visible
01141 
01142    vx = fVisible.fX;
01143    vy = fVisible.fY;
01144    vw = fCanvas->GetWidth();
01145    vh = fCanvas->GetHeight();
01146    for (p = fFirstInput; p; p = p->fINext) {
01147       if (p->fFrame == 0) continue;
01148       if (p->fY < vy + vh && p->fY + p->fH > vy &&
01149           p->fX < vx + vw && p->fX + p->fW > vx) {
01150          if ((x > p->fX) && (y > p->fY) && (x < (p->fX + p->fW)) &&
01151              (y < (p->fY + p->fH)) ) {
01152             return p;
01153          }
01154       }
01155    }
01156    return 0;
01157 }
01158 
01159 //______________________________________________________________________________
01160 Bool_t TGHtml::HandleHtmlInput(TGHtmlInput *pr, Event_t *event)
01161 {
01162    // Handle html input (button, checkbox, ...) event.
01163 
01164    Window_t childdum;
01165    Event_t eventSt;
01166    eventSt.fType      = event->fType;
01167    eventSt.fWindow    = event->fWindow;
01168    eventSt.fTime      = event->fTime;
01169    eventSt.fX         = 2;
01170    eventSt.fY         = 2;
01171    eventSt.fXRoot     = event->fXRoot;
01172    eventSt.fYRoot     = event->fYRoot;
01173    eventSt.fCode      = event->fCode;
01174    eventSt.fState     = event->fState;
01175    eventSt.fWidth     = event->fWidth;
01176    eventSt.fHeight    = event->fHeight;
01177    eventSt.fCount     = event->fCount;
01178    eventSt.fSendEvent = event->fSendEvent;
01179    eventSt.fHandle    = event->fHandle;
01180    eventSt.fFormat    = event->fFormat;
01181    eventSt.fUser[0]   = event->fUser[0];
01182    eventSt.fUser[1]   = event->fUser[1];
01183    eventSt.fUser[2]   = event->fUser[2];
01184    eventSt.fUser[3]   = event->fUser[3];
01185    eventSt.fUser[4]   = event->fUser[4];
01186    gVirtualX->TranslateCoordinates(GetId(), pr->fFrame->GetId(),
01187                                    event->fX, event->fY, eventSt.fX,
01188                                    eventSt.fY, childdum);
01189 
01190    const char *name = pr->MarkupArg("name", 0);
01191    const char *val = pr->MarkupArg("value", 0);
01192    switch (pr->fItype) {
01193       case INPUT_TYPE_Submit:
01194       case INPUT_TYPE_Button: {
01195          TGButton *b = (TGButton *) pr->fFrame;
01196          Bool_t was = !b->IsDown();
01197          b->HandleButton(&eventSt);
01198          Bool_t now = !b->IsDown();
01199          if (!was && now) {
01200             if (pr->fItype == INPUT_TYPE_Submit)
01201                SubmitClicked(val);   // emit SubmitClicked
01202             else
01203                ButtonClicked(name, val);   // emit ButtonClicked
01204          }
01205          break;
01206       }
01207       case INPUT_TYPE_Radio: {
01208          TGRadioButton *rb = (TGRadioButton *) pr->fFrame;
01209          Bool_t was = !rb->IsDown();
01210          rb->HandleButton(&eventSt);
01211          Bool_t now = !rb->IsDown();
01212          if ((!was && now) || (was && !now)) {
01213             HandleRadioButton(pr);
01214             RadioChanged(name, val);      // emit RadioChanged
01215          }
01216          break;
01217       }
01218       case INPUT_TYPE_Checkbox: {
01219          TGCheckButton *cb = (TGCheckButton *) pr->fFrame;
01220          Bool_t was = !cb->IsDown();
01221          cb->HandleButton(&eventSt);
01222          Bool_t now = !cb->IsDown();
01223          if ((!was && now) || (was && !now))
01224             CheckToggled(name, !now, val);   // emit CheckToggled
01225          break;
01226       }
01227       case INPUT_TYPE_Text:
01228       case INPUT_TYPE_Password: {
01229          TGTextEntry *te = (TGTextEntry *) pr->fFrame;
01230          te->SetFocus();
01231          break;
01232       }
01233       case INPUT_TYPE_Select: {
01234          RemoveInput(kButtonPressMask | kButtonReleaseMask | kPointerMotionMask);
01235          eventSt.fUser[0] = childdum;
01236          if (pr->fFrame->InheritsFrom("TGComboBox"))
01237             ((TGComboBox *)pr->fFrame)->HandleButton(&eventSt);
01238          else if (pr->fFrame->InheritsFrom("TGListBox"))
01239             ((TGListBox *)pr->fFrame)->HandleButton(&eventSt);
01240          InputSelected(name, val); // emit InputSelected
01241          AddInput(kButtonPressMask | kButtonReleaseMask | kPointerMotionMask);
01242          break;
01243       }
01244       default:
01245          break;
01246    }
01247    return kTRUE;
01248 }
01249 
01250 //______________________________________________________________________________
01251 Bool_t TGHtml::HandleRadioButton(TGHtmlInput *p)
01252 {
01253    // Handle radio button event.
01254 
01255    TGHtmlInput *pr;
01256    for (pr = fFirstInput; pr; pr = pr->fINext) {
01257       if ((pr->fPForm == p->fPForm) && (pr->fItype == INPUT_TYPE_Radio)) {
01258          if (pr != p) {
01259             if (strcmp(pr->MarkupArg("name", ""), p->MarkupArg("name", "")) == 0) {
01260                ((TGRadioButton *)pr->fFrame)->SetState(kButtonUp);
01261             }
01262          }
01263       }
01264    }
01265 
01266    return kTRUE;
01267 }
01268 
01269 //______________________________________________________________________________
01270 void TGHtml::ButtonClicked(const char *name, const char *val)
01271 {
01272    // Emit ButtonClicked() signal.
01273 
01274    Long_t args[2];
01275 
01276    args[0] = (Long_t)name;
01277    args[1] = (Long_t)val;
01278 
01279    Emit("ButtonClicked(char*,char*)", args);
01280 }
01281 
01282 //______________________________________________________________________________
01283 void TGHtml::CheckToggled(const char *name, Bool_t on, const char *val)
01284 {
01285    // Emit CheckToggled() signal.
01286 
01287    Long_t args[3];
01288 
01289    args[0] = (Long_t)name;
01290    args[1] = on;
01291    args[2] = (Long_t)val;
01292 
01293    Emit("CheckToggled(char*,Bool_t,char*)", args);
01294 }
01295 
01296 //______________________________________________________________________________
01297 void TGHtml::RadioChanged(const char *name, const char *val)
01298 {
01299    // Emit RadioChanged() signal.
01300 
01301    Long_t args[2];
01302 
01303    args[0] = (Long_t)name;
01304    args[1] = (Long_t)val;
01305 
01306    Emit("RadioChanged(char*,char*)", args);
01307 }
01308 
01309 //______________________________________________________________________________
01310 void TGHtml::InputSelected(const char *name, const char *val)
01311 {
01312    // Emit Selected() signal.
01313 
01314    Long_t args[2];
01315 
01316    args[0] = (Long_t)name;
01317    args[1] = (Long_t)val;
01318 
01319    Emit("InputSelected(char*,char*)", args);
01320 }
01321 
01322 //______________________________________________________________________________
01323 void TGHtml::SubmitClicked(const char *val)
01324 {
01325    // Emit SubmitClicked() signal.
01326 
01327    Emit("SubmitClicked(char*)", val);
01328 }
01329 
01330 //______________________________________________________________________________
01331 Bool_t TGHtml::HandleButton(Event_t *event)
01332 {
01333    // Handle mouse button event.
01334 
01335    int amount, ch;
01336 
01337    ch = fCanvas->GetHeight();
01338    amount = fScrollVal.fY * TMath::Max(ch/6, 1);
01339 
01340    int ix = event->fX + fVisible.fX;
01341    int iy = event->fY + fVisible.fY;
01342    TGHtmlInput *pr = GetInputElement(ix, iy);
01343    if (pr) {
01344       HandleHtmlInput(pr, event);
01345    }
01346    if ((event->fType == kButtonPress) && (event->fCode == kButton1)) {
01347       int x = event->fX + fVisible.fX;
01348       int y = event->fY + fVisible.fY;
01349       const char *uri = GetHref(x, y);
01350 
01351 #if 0  // insertion cursor test
01352       char ix[20];
01353       sprintf(ix, "begin");
01354       SetInsert(ix);
01355 #endif
01356 
01357       if (uri) {
01358          uri = ResolveUri(uri);
01359          if (uri) {
01360             MouseDown(uri);
01361             //!!delete[] uri;
01362          }
01363       }
01364    } else if (event->fCode == kButton4) {
01365       ScrollToPosition(TGLongPosition(fVisible.fX, fVisible.fY / fScrollVal.fY - amount));
01366    } else if (event->fCode == kButton5) {
01367       ScrollToPosition(TGLongPosition(fVisible.fX, fVisible.fY / fScrollVal.fY + amount));
01368    } else {
01369       return TGView::HandleButton(event);
01370    }
01371    return kTRUE;
01372 }
01373 
01374 //______________________________________________________________________________
01375 Bool_t TGHtml::HandleMotion(Event_t *event)
01376 {
01377    // handle mouse motion events
01378 
01379    int x = event->fX + fVisible.fX;
01380    int y = event->fY + fVisible.fY;
01381    const char *uri = GetHref(x, y);
01382 
01383    if (uri) {
01384       gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kHand));
01385    } else {
01386       gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kPointer));
01387    }
01388 
01389    if (uri != fLastUri) {
01390       fLastUri = uri;
01391       if (uri) uri = ResolveUri(uri);
01392       MouseOver(uri);
01393       //!!if (uri) delete [] uri;
01394    }
01395 
01396    return kTRUE;
01397 }
01398 
01399 //______________________________________________________________________________
01400 TGFont *TGHtml::GetFont(int iFont)
01401 {
01402    // The rendering and layout routines should call this routine in order to
01403    // get a font structure. The iFont parameter specifies which of the N_FONT
01404    // fonts should be obtained. The font is allocated if necessary.
01405 
01406    TGFont *toFree = 0;
01407 
01408    if (iFont < 0) iFont = 0;
01409    if (iFont >= N_FONT) { iFont = N_FONT - 1; CANT_HAPPEN; }
01410 
01411    // If the font has previously been allocated, but the "fontValid" bitmap
01412    // shows it is no longer valid, then mark it for freeing later. We use
01413    // a policy of allocate-before-free because xclass' font cache operates
01414    // much more efficiently that way.
01415 
01416    if (!FontIsValid(iFont) && fAFont[iFont] != 0) {
01417       toFree = fAFont[iFont];
01418       fAFont[iFont] = 0;
01419    }
01420 
01421    // If we need to allocate a font, first construct the font name then
01422    // allocate it.
01423 
01424    if (fAFont[iFont] == 0) {
01425       char name[200];         // Name of the font
01426       const char *familyStr = "";
01427       int iFamily;
01428       int iSize;
01429       int size;
01430 
01431       iFamily = FontFamily(iFont) >> 3;
01432       iSize = FontSize(iFont) + 1;
01433 
01434       switch (iFamily) {
01435 //#define TIMES
01436 #ifdef TIMES
01437          case 0:  familyStr = "times -%d";                 break;
01438          case 1:  familyStr = "times -%d bold";            break;
01439          case 2:  familyStr = "times -%d italic";          break;
01440          case 3:  familyStr = "times -%d bold italic";     break;
01441          case 4:  familyStr = "courier -%d";               break;
01442          case 5:  familyStr = "courier -%d bold";          break;
01443          case 6:  familyStr = "courier -%d italic";        break;
01444          case 7:  familyStr = "courier -%d bold italic";   break;
01445          default: familyStr = "times -16";                 CANT_HAPPEN;
01446 #else
01447          case 0:  familyStr = "helvetica -%d";             break;
01448          case 1:  familyStr = "helvetica -%d bold";        break;
01449          case 2:  familyStr = "helvetica -%d italic";      break;
01450          case 3:  familyStr = "helvetica -%d bold italic"; break;
01451          case 4:  familyStr = "courier -%d";               break;
01452          case 5:  familyStr = "courier -%d bold";          break;
01453          case 6:  familyStr = "courier -%d italic";        break;
01454          case 7:  familyStr = "courier -%d bold italic";   break;
01455          default: familyStr = "helvetica -14";             CANT_HAPPEN;
01456 #endif
01457       }
01458 #if 0
01459       switch (iSize) {
01460          case 1:  size = 6+finc/*8*/;   break;
01461          case 2:  size = 10+finc/*10*/;  break;
01462          case 3:  size = 12+finc/*12*/;  break;
01463          case 4:  size = 14+finc/*14*/;  break;
01464          case 5:  size = 20+finc/*16*/;  break;
01465          case 6:  size = 24+finc/*18*/;  break;
01466          case 7:  size = 30+finc/*24*/;  break;
01467          default: size = 14+finc/*14*/;  CANT_HAPPEN;
01468       }
01469 #else
01470       switch (iSize) {
01471          case 1:  size = 8;   break;
01472          case 2:  size = 10;  break;
01473          case 3:  size = 12;  break;
01474          case 4:  size = 14;  break;
01475          case 5:  size = 16;  break;
01476          case 6:  size = 18;  break;
01477          case 7:  size = 24;  break;
01478          default: size = 14;  CANT_HAPPEN;
01479       }
01480 #endif
01481 #ifdef TIMES
01482       if (iFamily < 4) size += 2;
01483 #endif
01484 
01485       snprintf(name, 199, familyStr, size);
01486 
01487       // Get the named font
01488       fAFont[iFont] = fClient->GetFont(name);
01489 
01490       if (fAFont[iFont] == 0) {
01491          fprintf(stderr, "TGHtml: could not get font \"%s\", trying fixed\n",
01492                  name);
01493          fAFont[iFont] = fClient->GetFont("fixed");
01494       }
01495       if (fAFont[iFont] == 0 ){
01496          fprintf(stderr, "TGHtml: could not get font \"fixed\", trying "
01497                  "\"helvetica -12\"\n");
01498          fAFont[iFont] = fClient->GetFont("helvetica -12");
01499       }
01500       FontSetValid(iFont);
01501    }
01502 
01503    // Free the expired font, if any.
01504 
01505    if (toFree) fClient->FreeFont(toFree);
01506 
01507    return fAFont[iFont];
01508 }
01509 
01510 //______________________________________________________________________________
01511 int TGHtml::InArea(TGHtmlMapArea *p, int left, int top, int x, int y)
01512 {
01513    // Only support rect and circles for now
01514 
01515    int *ip = p->fCoords;
01516    if (!ip) return 0;
01517 
01518    if (p->fMType == HTML_MAP_RECT) {
01519       return ((left + ip[0]) <= x && (left + ip[2]) >= x &&
01520               (top  + ip[1]) <= y && (top  + ip[3]) >= y);
01521    } else if (p->fMType == HTML_MAP_CIRCLE) {
01522       int dx = left + ip[0] - x;
01523       int dy = top + ip[1] - y;
01524       return (dx * dx + dy * dy <= ip[2] * ip[2]);
01525    }
01526    return 0;
01527 }
01528 
01529 //______________________________________________________________________________
01530 TGHtmlElement *TGHtml::GetMap(const char *name)
01531 {
01532    // Returns html map element.
01533 
01534    TGHtmlElement *p = fPFirst;
01535    const char *z, *zb;
01536 
01537    while (p) {
01538       if (p->fType == Html_MAP) {
01539          z = p->MarkupArg("name", 0);
01540          zb = p->MarkupArg("shape", 0);
01541          if (zb && *zb != 'r') return 0;
01542          if (z && !strcmp(z, name)) return p;
01543       }
01544       p = p->fPNext;
01545    }
01546    return 0;
01547 }
01548 
01549 //______________________________________________________________________________
01550 float TGHtml::ColorDistance(ColorStruct_t *pA, ColorStruct_t *pB)
01551 {
01552    // Compute the squared distance between two colors
01553 
01554    float x, y, z;
01555 
01556    x = 0.30 * (pA->fRed - pB->fRed);
01557    y = 0.61 * (pA->fGreen - pB->fGreen);
01558    z = 0.11 * (pA->fBlue - pB->fBlue);
01559 
01560    return x*x + y*y + z*z;
01561 }
01562 
01563 //______________________________________________________________________________
01564 int TGHtml::GetColorByName(const char *zColor)
01565 {
01566    // This routine returns an index between 0 and N_COLOR-1 which indicates
01567    // which ColorStruct_t structure in the fApColor[] array should be used to describe
01568    // the color specified by the given name.
01569 
01570    ColorStruct_t *pNew;
01571    int iColor;
01572    const char *name;  // unique!
01573    int i, n;
01574    char zAltColor[16];
01575 
01576    // Netscape accepts color names that are just HEX values, without
01577    // the # up front.  This isn't valid HTML, but we support it for
01578    // compatibility.
01579 
01580    n = strlen(zColor);
01581    if (n == 6 || n == 3 || n == 9 || n == 12) {
01582       for (i = 0; i < n; i++) {
01583          if (!isxdigit(zColor[i])) break;
01584       }
01585       if (i == n) {
01586          snprintf(zAltColor, 15, "#%s", zColor);
01587       } else {
01588          strlcpy(zAltColor, zColor, sizeof(zAltColor));
01589       }
01590       name = GetUid(zAltColor);
01591    } else {
01592       name = GetUid(zColor);
01593    }
01594 
01595    pNew = AllocColor(name);
01596    if (pNew == 0) {
01597       return 0;      // Color 0 is always the default
01598    }
01599 
01600    iColor = GetColorByValue(pNew);
01601    FreeColor(pNew);
01602 
01603    return iColor;
01604 }
01605 
01606 
01607 // Macros used in the computation of appropriate shadow colors.
01608 
01609 #define MAX_COLOR    65535
01610 #define MAX(A,B)     ((A)<(B)?(B):(A))
01611 #define MIN(A,B)     ((A)<(B)?(A):(B))
01612 
01613 //______________________________________________________________________________
01614 int TGHtml::IsDarkColor(ColorStruct_t *p)
01615 {
01616    // Check to see if the given color is too dark to be easily distinguished
01617    // from black.
01618 
01619    float x, y, z;
01620 
01621    x = 0.50 * p->fRed;
01622    y = 1.00 * p->fGreen;
01623    z = 0.28 * p->fBlue;
01624    return (x*x + y*y + z*z) < (0.05 * MAX_COLOR * MAX_COLOR);
01625 }
01626 
01627 //______________________________________________________________________________
01628 int TGHtml::GetDarkShadowColor(int iBgColor)
01629 {
01630    // Given that the background color is iBgColor, figure out an
01631    // appropriate color for the dark part of a 3D shadow.
01632 
01633    if (fIDark[iBgColor] == 0) {
01634       ColorStruct_t *pRef, val;
01635       pRef = fApColor[iBgColor];
01636       if (IsDarkColor(pRef)) {
01637          int t1, t2;
01638          t1 = (int) MIN(MAX_COLOR, pRef->fRed * 1.2);
01639          t2 = (pRef->fRed * 3 + MAX_COLOR) / 4;
01640          val.fRed = MAX(t1, t2);
01641          t1 = (int) MIN(MAX_COLOR, pRef->fGreen * 1.2);
01642          t2 = (pRef->fGreen * 3 + MAX_COLOR) / 4;
01643          val.fGreen = MAX(t1, t2);
01644          t1 = (int) MIN(MAX_COLOR, pRef->fBlue * 1.2);
01645          t2 = (pRef->fBlue * 3 + MAX_COLOR) / 4;
01646          val.fBlue = MAX(t1, t2);
01647       } else {
01648          val.fRed = (unsigned short) (pRef->fRed * 0.6);
01649          val.fGreen = (unsigned short) (pRef->fGreen * 0.6);
01650          val.fBlue = (unsigned short) (pRef->fBlue * 0.6);
01651       }
01652       fIDark[iBgColor] = GetColorByValue(&val) + 1;
01653    }
01654 
01655    return fIDark[iBgColor] - 1;
01656 }
01657 
01658 //______________________________________________________________________________
01659 int TGHtml::IsLightColor(ColorStruct_t *p)
01660 {
01661    // Check to see if the given color is too light to be easily distinguished
01662    // from white.
01663 
01664    return p->fGreen >= 0.85 * MAX_COLOR;
01665 }
01666 
01667 //______________________________________________________________________________
01668 int TGHtml::GetLightShadowColor(int iBgColor)
01669 {
01670    // Given that the background color is iBgColor, figure out an
01671    // appropriate color for the bright part of the 3D shadow.
01672 
01673    if (fILight[iBgColor] == 0) {
01674       ColorStruct_t *pRef, val;
01675       pRef = fApColor[iBgColor];
01676       if (IsLightColor(pRef)) {
01677          val.fRed = (unsigned short) (pRef->fRed * 0.9);
01678          val.fGreen = (unsigned short) (pRef->fGreen * 0.9);
01679          val.fBlue = (unsigned short) (pRef->fBlue * 0.9);
01680       } else {
01681          int t1, t2;
01682          t1 = (int) MIN(MAX_COLOR, pRef->fGreen * 1.4);
01683          t2 = (pRef->fGreen + MAX_COLOR) / 2;
01684          val.fGreen = MAX(t1, t2);
01685          t1 = (int) MIN(MAX_COLOR, pRef->fRed * 1.4);
01686          t2 = (pRef->fRed + MAX_COLOR) / 2;
01687          val.fRed = MAX(t1, t2);
01688          t1 = (int) MIN(MAX_COLOR, pRef->fBlue * 1.4);
01689          t2 = (pRef->fBlue + MAX_COLOR) / 2;
01690          val.fBlue = MAX(t1, t2);
01691       }
01692       fILight[iBgColor] = GetColorByValue(&val) + 1;
01693    }
01694 
01695    return fILight[iBgColor] - 1;
01696 }
01697 
01698 //______________________________________________________________________________
01699 int TGHtml::GetColorByValue(ColorStruct_t *pRef)
01700 {
01701    // Find a color integer for the color whose color components
01702    // are given by pRef.
01703 
01704    int i;
01705    float dist;
01706    float closestDist;
01707    int closest;
01708    int r, g, b;
01709 # define COLOR_MASK  0xf800
01710 
01711    // Search for an exact match
01712    r = pRef->fRed & COLOR_MASK;
01713    g = pRef->fGreen & COLOR_MASK;
01714    b = pRef->fBlue & COLOR_MASK;
01715    for (i = 0; i < N_COLOR; i++) {
01716       ColorStruct_t *p = fApColor[i];
01717       if (p &&
01718          ((p->fRed & COLOR_MASK) == r) &&
01719          ((p->fGreen & COLOR_MASK) == g) &&
01720          ((p->fBlue & COLOR_MASK) == b)) {
01721          fColorUsed |= (1<<i);
01722          return i;
01723       }
01724    }
01725 
01726    // No exact matches. Look for a completely unused slot
01727    for (i = N_PREDEFINED_COLOR; i < N_COLOR; i++) {
01728       if (fApColor[i] == 0) {
01729          fApColor[i] = AllocColorByValue(pRef);
01730          fColorUsed |= (1<<i);
01731          return i;
01732       }
01733    }
01734 
01735    // No empty slots. Look for a slot that contains a color that
01736    // isn't currently in use.
01737    for (i = N_PREDEFINED_COLOR; i < N_COLOR; i++) {
01738       if (((fColorUsed >> i) & 1) == 0) {
01739          FreeColor(fApColor[i]);
01740          fApColor[i] = AllocColorByValue(pRef);
01741          fColorUsed |= (1<<i);
01742          return i;
01743       }
01744    }
01745 
01746    // Ok, find the existing color that is closest to the color requested
01747    // and use it.
01748    closest = 0;
01749    closestDist = ColorDistance(pRef, fApColor[0]);
01750    for (i = 1; i < N_COLOR; i++) {
01751       dist = ColorDistance(pRef, fApColor[i]);
01752       if (dist < closestDist) {
01753          closestDist = dist;
01754          closest = i;
01755       }
01756    }
01757 
01758    return closest;
01759 }
01760 
01761 //______________________________________________________________________________
01762 const char *TGHtml::GetHref(int x, int y, const char **target)
01763 {
01764    // This routine searchs for a hyperlink beneath the coordinates x,y
01765    // and returns a pointer to the HREF for that hyperlink. The text
01766    // is held in one of the markup argv[] fields of the <a> markup.
01767 
01768    TGHtmlBlock *pBlock;
01769    TGHtmlElement *pElem;
01770 
01771    for (pBlock = fFirstBlock; pBlock; pBlock = pBlock->fBNext) {
01772       if (pBlock->fTop > y || pBlock->fBottom < y ||
01773           pBlock->fLeft > x || pBlock->fRight < x) continue;
01774       pElem = pBlock->fPNext;
01775       if (pElem->fType == Html_IMG) {
01776          TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) pElem;
01777          if (image->fPMap) {
01778             pElem = image->fPMap->fPNext;
01779             while (pElem && pElem->fType != Html_EndMAP) {
01780                if (pElem->fType == Html_AREA) {
01781                   if (InArea((TGHtmlMapArea *) pElem, pBlock->fLeft, pBlock->fTop, x, y)) {
01782                      if (target) *target = pElem->MarkupArg("target", 0);
01783                      return pElem->MarkupArg("href", 0);
01784                   }
01785                }
01786                pElem = pElem->fPNext;
01787             }
01788             continue;
01789          }
01790       }
01791       if ((pElem->fStyle.fFlags & STY_Anchor) == 0) continue;
01792       switch (pElem->fType) {
01793          case Html_Text:
01794          case Html_Space:
01795          case Html_IMG:
01796             while (pElem && pElem->fType != Html_A) pElem = pElem->fPPrev;
01797             if (pElem == 0 || pElem->fType != Html_A) break;
01798             if (target) *target = pElem->MarkupArg("target", 0);
01799             return pElem->MarkupArg("href", 0);
01800 
01801             default:
01802                break;
01803       }
01804    }
01805 
01806    return 0;
01807 }
01808 
01809 //______________________________________________________________________________
01810 int TGHtml::ElementCoords(TGHtmlElement *p, int /*i*/, int pct, int *coords)
01811 {
01812    // Return coordinates of item
01813 
01814    TGHtmlBlock *pBlock;
01815 
01816    while (p && p->fType != Html_Block) p = p->fPPrev;
01817    if (!p) return 1;
01818 
01819    pBlock = (TGHtmlBlock *) p;
01820    if (pct) {
01821       TGHtmlElement *pEnd = fPLast;
01822       TGHtmlBlock *pb2;
01823       while (pEnd && pEnd->fType != Html_Block) pEnd = pEnd->fPPrev;
01824       pb2 = (TGHtmlBlock *) pEnd;
01825 #define HGCo(dir) (pb2 && pb2->dir) ? pBlock->dir * 100 / pb2->dir : 0
01826       coords[0] = HGCo(fLeft);
01827       coords[1] = HGCo(fTop);
01828       coords[3] = HGCo(fRight);
01829       coords[4] = HGCo(fBottom);
01830    } else {
01831       coords[0] = pBlock->fLeft;
01832       coords[1] = pBlock->fTop;
01833       coords[2] = pBlock->fRight;
01834       coords[3] = pBlock->fBottom;
01835    }
01836    return 0;
01837 }
01838 
01839 //______________________________________________________________________________
01840 TGHtmlElement *TGHtml::AttrElem(const char *name, char *value)
01841 {
01842    // Returns html element matching attribute name and value.
01843 
01844    TGHtmlElement *p;
01845    const char *z;
01846 
01847    for (p = fPFirst; p; p = p->fPNext) {
01848       if (p->fType != Html_A) continue;
01849       z = p->MarkupArg(name, 0);
01850       if (z && (strcmp(z, value) == 0)) return p;
01851    }
01852    return 0;
01853 }
01854 
01855 //______________________________________________________________________________
01856 void TGHtml::UpdateSelection(int forceUpdate)
01857 {
01858    // Given the selection end-points in fSelBegin and fSelEnd, recompute
01859    // pSelBeginBlock and fPSelEndBlock, then call UpdateSelectionDisplay()
01860    // to update the display.
01861    //
01862    // This routine should be called whenever the selection changes or
01863    // whenever the set of TGHtmlBlock structures change.
01864 
01865    TGHtmlBlock *pBlock;
01866    int index;
01867    int needUpdate = forceUpdate;
01868    int temp;
01869 
01870    if (fSelEnd.fP == 0) fSelBegin.fP = 0;
01871 
01872    IndexToBlockIndex(fSelBegin, &pBlock, &index);
01873    if (needUpdate || pBlock != fPSelStartBlock) {
01874       needUpdate = 1;
01875       RedrawBlock(fPSelStartBlock);
01876       fPSelStartBlock = pBlock;
01877       fSelStartIndex = index;
01878    } else if (index != fSelStartIndex) {
01879       RedrawBlock(pBlock);
01880       fSelStartIndex = index;
01881    }
01882 
01883    if (fSelBegin.fP == 0) fSelEnd.fP = 0;
01884 
01885    IndexToBlockIndex(fSelEnd, &pBlock, &index);
01886    if (needUpdate || pBlock != fPSelEndBlock) {
01887       needUpdate = 1;
01888       RedrawBlock(fPSelEndBlock);
01889       fPSelEndBlock = pBlock;
01890       fSelEndIndex = index;
01891    } else if (index != fSelEndIndex) {
01892       RedrawBlock(pBlock);
01893       fSelEndIndex = index;
01894    }
01895 
01896    if (fPSelStartBlock && fPSelStartBlock == fPSelEndBlock &&
01897        fSelStartIndex > fSelEndIndex) {
01898       temp = fSelStartIndex;
01899       fSelStartIndex = fSelEndIndex;
01900       fSelEndIndex = temp;
01901    }
01902 
01903    if (needUpdate) {
01904       fFlags |= ANIMATE_IMAGES;
01905       UpdateSelectionDisplay();
01906    }
01907 }
01908 
01909 //______________________________________________________________________________
01910 void TGHtml::UpdateSelectionDisplay()
01911 {
01912    // The fPSelStartBlock and fPSelEndBlock values have been changed.
01913    // This routine's job is to loop over all TGHtmlBlocks and either
01914    // set or clear the HTML_Selected bits in the .fFlags field
01915    // as appropriate.  For every TGHtmlBlock where the bit changes,
01916    // mark that block for redrawing.
01917 
01918    int selected = 0;
01919    SHtmlIndex_t tempIndex;
01920    TGHtmlBlock *pTempBlock;
01921    int temp;
01922    TGHtmlBlock *p;
01923 
01924    for (p = fFirstBlock; p; p = p->fBNext) {
01925       if (p == fPSelStartBlock) {
01926          selected = 1;
01927          RedrawBlock(p);
01928       } else if (!selected && p == fPSelEndBlock) {
01929          selected = 1;
01930          tempIndex = fSelBegin;
01931          fSelBegin = fSelEnd;
01932          fSelEnd = tempIndex;
01933          pTempBlock = fPSelStartBlock;
01934          fPSelStartBlock = fPSelEndBlock;
01935          fPSelEndBlock = pTempBlock;
01936          temp = fSelStartIndex;
01937          fSelStartIndex = fSelEndIndex;
01938          fSelEndIndex = temp;
01939          RedrawBlock(p);
01940       }
01941       if (p->fFlags & HTML_Selected) {
01942          if (!selected) {
01943             p->fFlags &= ~HTML_Selected;
01944             RedrawBlock(p);
01945          }
01946       } else {
01947          if (selected) {
01948             p->fFlags |= HTML_Selected;
01949             RedrawBlock(p);
01950          }
01951       }
01952       if (p == fPSelEndBlock) {
01953          selected = 0;
01954          RedrawBlock(p);
01955       }
01956    }
01957 }
01958 
01959 //______________________________________________________________________________
01960 void TGHtml::LostSelection()
01961 {
01962    // Clear selection.
01963 
01964    if (fExportSelection) {
01965       // clear selection
01966       fPSelStartBlock = 0;
01967       fPSelEndBlock = 0;
01968       fSelBegin.fP = 0;
01969       fSelEnd.fP = 0;
01970       UpdateSelectionDisplay();
01971    }
01972 }
01973 
01974 //______________________________________________________________________________
01975 int TGHtml::SelectionSet(const char *startIx, const char *endIx)
01976 {
01977    // Set selection.
01978 
01979    SHtmlIndex_t sBegin, sEnd;
01980    int bi, ei;
01981 
01982    if (GetIndex(startIx, &sBegin.fP, &sBegin.fI)) {
01983       // malformed start index
01984       return kFALSE;
01985    }
01986 
01987    if (GetIndex(endIx, &sEnd.fP, &sEnd.fI)) {
01988       // malformed end index
01989       return kFALSE;
01990    }
01991 
01992    bi = TokenNumber(sBegin.fP);
01993    ei = TokenNumber(sEnd.fP);
01994 
01995    if (!(sBegin.fP && sEnd.fP)) return kTRUE;
01996 
01997    if (bi < ei || (bi == ei && sBegin.fI <= sEnd.fI)) {
01998       fSelBegin = sBegin;
01999       fSelEnd = sEnd;
02000    } else {
02001       fSelBegin = sEnd;
02002       fSelEnd = sBegin;
02003    }
02004 
02005    UpdateSelection(0);
02006    if (fExportSelection) {
02007       // TODO:
02008       // get selection ownership ... fId, XA_PRIMARY
02009       // selection lost handler must directly call LostSelection()
02010    }
02011 
02012    return kTRUE;
02013 }
02014 
02015 //______________________________________________________________________________
02016 void TGHtml::UpdateInsert()
02017 {
02018    // Recompute the position of the insertion cursor based on the
02019    // position in fIns.
02020 
02021    IndexToBlockIndex(fIns, &fPInsBlock, &fInsIndex);
02022    RedrawBlock(fPInsBlock);
02023    if (fInsTimer == 0) {
02024       fInsStatus = 0;
02025       FlashCursor();
02026    }
02027 }
02028 
02029 //______________________________________________________________________________
02030 int TGHtml::SetInsert(const char *insIx)
02031 {
02032    // Set the position of the insertion cursor.
02033 
02034    SHtmlIndex_t i;
02035 
02036    if (!insIx) {
02037       RedrawBlock(fPInsBlock);
02038       fInsStatus = 0;
02039       fPInsBlock = 0;
02040       fIns.fP = 0;
02041    } else {
02042       if (GetIndex(insIx, &i.fP, &i.fI)) {
02043          // malformed index
02044          return kFALSE;
02045       }
02046       RedrawBlock(fPInsBlock);
02047       fIns = i;
02048       UpdateInsert();
02049    }
02050 
02051    return kTRUE;
02052 }
02053 
02054 //______________________________________________________________________________
02055 void TGHtml::SavePrimitive(ostream &out, Option_t *option /*= ""*/)
02056 {
02057    // Save a html widget as a C++ statement(s) on output stream out.
02058 
02059    out << "   TGHtml *";
02060    out << GetName() << " = new TGHtml(" << fParent->GetName()
02061        << "," << GetWidth() << "," << GetHeight()
02062        << ");"<< endl;
02063    if (option && strstr(option, "keep_names"))
02064       out << "   " << GetName() << "->SetName(\"" << GetName() << "\");" << endl;
02065 
02066    if (fCanvas->GetBackground() != TGFrame::GetWhitePixel()) {
02067       out << "   " << GetName() << "->ChangeBackground(" << fCanvas->GetBackground() << ");" << endl;
02068    }
02069 
02070    TString fn;
02071    TGText txt(GetText());
02072    fn.Form("Html%s.htm", GetName()+5);
02073    txt.Save(fn.Data());
02074    out << "   " << "FILE *f = fopen(\"" << fn.Data() << "\", \"r\");" << endl;
02075    out << "   " << "if (f) {" << endl;
02076    out << "      " << GetName() << "->Clear();" << endl;
02077    out << "      " << GetName() << "->Layout();" << endl;
02078    out << "      " << GetName() << "->SetBaseUri(\"\");" << endl;
02079    out << "      " << "char *buf = (char *)calloc(4096, sizeof(char));" << endl;
02080    out << "      " << "while (fgets(buf, 4096, f)) {" << endl;
02081    out << "         " << GetName() << "->ParseText(buf);" << endl;
02082    out << "      " << "}" << endl;
02083    out << "      " << "free(buf);" << endl;
02084    out << "      " << "fclose(f);" << endl;
02085    out << "   " << "}" << endl;
02086    out << "   " << GetName() << "->Layout();" << endl;
02087 }

Generated on Tue Jul 5 14:22:18 2011 for ROOT_528-00b_version by  doxygen 1.5.1