#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "TGHtml.h"
#include "THashTable.h"
#include "TObjString.h"
#include "TGIdleHandler.h"
#include "TImage.h"
#include "TGScrollBar.h"
#include "TGTextEntry.h"
ClassImp(TGHtml)
int HtmlTraceMask = 0;
int HtmlDepth = 0;
#define DEF_FRAME_BG_COLOR "#c0c0c0"
#define DEF_FRAME_CURSOR ""
#define DEF_BUTTON_FG "black"
#define DEF_BUTTON_HIGHLIGHT_BG "#d9d9d9"
#define DEF_BUTTON_HIGHLIGHT "black"
TGHtml::TGHtml(const TGWindow *p, int w, int h, int id) : TGView(p, w, h, id)
{
int i;
_exiting = 0;
pFirst = 0;
pLast = 0;
nToken = 0;
lastSized = 0;
nextPlaced = 0;
firstBlock = 0;
lastBlock = 0;
firstInput = 0;
lastInput = 0;
nInput = 0;
nForm = 0;
varId = 0;
inputIdx = 0;
radioIdx = 0;
selBegin.p = 0;
selEnd.p = 0;
pSelStartBlock = 0;
pSelEndBlock = 0;
insOnTime = DEF_HTML_INSERT_ON_TIME;
insOffTime = DEF_HTML_INSERT_OFF_TIME;
insStatus = 0;
insTimer = 0;
ins.p = 0;
pInsBlock = 0;
insIndex = 0;
zText = 0;
nText = 0;
nAlloc = 0;
nComplete = 0;
iCol = 0;
iPlaintext = 0;
pScript = 0;
fIdle = 0;
styleStack = 0;
paraAlignment = ALIGN_None;
rowAlignment = ALIGN_None;
anchorFlags = 0;
inDt = 0;
inTr = 0;
inTd = 0;
anchorStart = 0;
formStart = 0;
formElemStart = 0;
formElemLast = 0;
loEndPtr = 0;
loFormStart = 0;
innerList = 0;
ResetLayoutContext();
highlightWidth = 0;
highlightBgColorPtr = 0;
highlightColorPtr = 0;
for (i = 0; i < N_FONT; ++i) aFont[i] = 0;
memset(fontValid, 0, sizeof(fontValid));
for (i = 0; i < N_COLOR; ++i) {
apColor[i] = 0;
iDark[i] = 0;
iLight[i] = 0;
}
fgColor = AllocColor("black");
bgColor = AllocColor("white");
newLinkColor = AllocColor(DEF_HTML_UNVISITED);
oldLinkColor = AllocColor(DEF_HTML_VISITED);
selectionColor = AllocColor(DEF_HTML_SELECTION_COLOR);
apColor[COLOR_Normal] = fgColor;
apColor[COLOR_Visited] = oldLinkColor;
apColor[COLOR_Unvisited] = newLinkColor;
apColor[COLOR_Selection] = selectionColor;
apColor[COLOR_Background] = bgColor;
bgImage = 0;
SetBackgroundColor(apColor[COLOR_Background]->fPixel);
SetBackgroundPixmap(0);
colorUsed = 0;
for (i = 0; i < N_CACHE_GC; ++i) aGcCache[i].index = 0;
GcNextToFree = 0;
imageList = 0;
zBaseHref = 0;
innerList = 0;
formPadding = 5;
overrideFonts = 0;
overrideColors = 0;
HasScript = 0;
HasFrames = 0;
AddEndTags = 0;
TableBorderMin = 0;
varind = 0;
idind = 0;
inParse = 0;
zGoto = 0;
exts = 0;
underlineLinks = kTRUE;
exportSelection = DEF_HTML_EXPORT_SEL;
tableRelief = HTML_RELIEF_RAISED;
ruleRelief = HTML_RELIEF_SUNKEN;
rulePadding = 5;
zBase = 0;
zBaseHref = 0;
cursor = kPointer;
maxX = 0;
maxY = 0;
fXMargin = fYMargin = 0;
flags = RESIZE_ELEMENTS | RELAYOUT;
dirtyLeft = LARGE_NUMBER;
dirtyRight = 0;
dirtyTop = LARGE_NUMBER;
dirtyBottom = 0;
fVsb->SetAccelerated();
fHsb->SetAccelerated();
_lastUri = 0;
AddInput(kExposureMask | kFocusChangeMask);
AddInput(kButtonPressMask | kButtonReleaseMask | kPointerMotionMask);
fUidTable = new THashTable(100);
}
TGHtml::~TGHtml()
{
int i;
_exiting = 1;
_Clear();
for (i = 0; i < N_FONT; i++) {
if (aFont[i] != 0) fClient->FreeFont(aFont[i]);
}
if (insTimer) delete insTimer;
if (fIdle) delete fIdle;
}
void TGHtml::UpdateBackgroundStart()
{
}
void TGHtml::FreeColor(ColorStruct_t *color)
{
gVirtualX->FreeColor(gClient->GetDefaultColormap(), color->fPixel);
delete color;
}
ColorStruct_t *TGHtml::AllocColor(const char *name)
{
ColorStruct_t *color = new ColorStruct_t;
color->fPixel = 0;
if (gVirtualX->ParseColor(fClient->GetDefaultColormap(), name, *color)) {
if (!gVirtualX->AllocColor(fClient->GetDefaultColormap(), *color)) {
gVirtualX->QueryColor(fClient->GetDefaultColormap(), *color);
gVirtualX->AllocColor(fClient->GetDefaultColormap(), *color);
}
}
return color;
}
ColorStruct_t *TGHtml::AllocColorByValue(ColorStruct_t *color)
{
ColorStruct_t *c = new ColorStruct_t;
*c = *color;
if (!gVirtualX->AllocColor(gClient->GetDefaultColormap(), *c)) {
c->fPixel = 0;
gVirtualX->QueryColor(gClient->GetDefaultColormap(), *c);
gVirtualX->AllocColor(gClient->GetDefaultColormap(), *c);
}
return c;
}
void TGHtml::Clear(Option_t *)
{
_Clear();
TGView::Clear();
flags |= REDRAW_TEXT | VSCROLL | HSCROLL;
ScheduleRedraw();
}
int TGHtml::ParseText(char *text, const char *index)
{
SHtmlIndex iStart;
TGHtmlElement *savePtr=0;
iStart.p = 0;
iStart.i = 0;
loEndPtr = pLast;
if (index) {
int rc = GetIndex(index, &iStart.p, &iStart.i);
if (rc != 0) return kFALSE;
if (iStart.p) {
savePtr = iStart.p->pNext;
pLast = iStart.p;
iStart.p->pNext = 0;
}
}
TokenizerAppend(text);
if (loEndPtr) {
formStart = loFormStart;
if (iStart.p && savePtr) {
AddStyle(loEndPtr);
pLast->pNext = savePtr;
savePtr->pPrev = pLast;
pLast = loEndPtr;
flags |= REDRAW_TEXT | RELAYOUT;
ScheduleRedraw();
} else if (loEndPtr->pNext) {
AddStyle(loEndPtr->pNext);
}
} else if (pFirst) {
paraAlignment = ALIGN_None;
rowAlignment = ALIGN_None;
anchorFlags = 0;
inDt = 0;
anchorStart = 0;
formStart = 0;
innerList = 0;
nInput = 0;
AddStyle(pFirst);
}
#if 1
loEndPtr = pLast;
loFormStart = formStart;
#endif
flags |= EXTEND_LAYOUT;
ScheduleRedraw();
return kTRUE;
}
void TGHtml::SetTableRelief(int relief)
{
if (tableRelief != relief) {
tableRelief = relief;
flags |= RELAYOUT;
RedrawEverything();
}
}
void TGHtml::SetRuleRelief(int relief)
{
if (ruleRelief != relief) {
ruleRelief = relief;
flags |= RELAYOUT;
RedrawEverything();
}
}
void TGHtml::UnderlineLinks(int onoff)
{
if (underlineLinks != onoff) {
underlineLinks = onoff;
TGHtmlElement *p;
SHtmlStyle style = GetCurrentStyle();
for (p = pFirst; p; p = p->pNext) {
if (p->type == Html_A) {
if (anchorStart) {
style = PopStyleStack(Html_EndA);
anchorStart = 0;
anchorFlags = 0;
}
const char *z = p->MarkupArg("href", 0);
if (z) {
style.color = GetLinkColor(z);
if (underlineLinks) style.flags |= STY_Underline;
anchorFlags |= STY_Anchor;
PushStyleStack(Html_EndA, style);
anchorStart = (TGHtmlAnchor *) p;
}
} else if (p->type == Html_EndA) {
if (anchorStart) {
((TGHtmlRef *)p)->pOther = anchorStart;
style = PopStyleStack(Html_EndA);
anchorStart = 0;
anchorFlags = 0;
}
}
p->style.flags &= ~STY_Underline;
p->style.flags |= (style.flags & STY_Underline);
}
RedrawEverything();
}
}
void TGHtml::SetBaseUri(const char *uri)
{
if (zBase) delete[] zBase;
zBase = 0;
if (uri) zBase = StrDup(uri);
}
int TGHtml::GotoAnchor(const char *name)
{
const char *z;
TGHtmlElement *p;
for (p = pFirst; p; p = p->pNext) {
if (p->type == Html_A) {
z = p->MarkupArg("name", 0);
if (z && strcmp(z, name) == 0) {
ScrollToPosition(TGLongPosition(fVisible.fX, ((TGHtmlAnchor *)p)->y));
return kTRUE;
}
}
}
return kFALSE;
}
const char *TGHtml::GetUid(const char *string)
{
TObjString *obj = 0;
obj = (TObjString*)fUidTable->FindObject(string);
if (!obj) {
obj = new TObjString(string);
fUidTable->Add(obj);
}
return (const char *)obj->GetName();
}
void TGHtml::ComputeVirtualSize()
{
fVirtualSize = TGDimension(maxX, maxY);
}
void TGHtml::ClearGcCache()
{
int i;
for (i = 0; i < N_CACHE_GC; i++) {
if (aGcCache[i].index) {
gVirtualX->DeleteGC(aGcCache[i].gc);
aGcCache[i].index = 0;
}
}
GcNextToFree = 0;
}
void TGHtml::ResetLayoutContext()
{
layoutContext.Reset();
}
void TGHtml::Redraw()
{
Pixmap_t pixmap;
int x, y, w, h;
int hw;
int clipwinH, clipwinW;
TGHtmlBlock *pBlock;
int redoSelection = 0;
if (inParse) {
flags &= ~REDRAW_PENDING;
return;
}
if ((flags & RESIZE_ELEMENTS) != 0 && (flags & STYLER_RUNNING) == 0) {
TGHtmlImage *pImage;
for (pImage = imageList; pImage; pImage = pImage->pNext) {
pImage->pList = 0;
}
lastSized = 0;
flags &= ~RESIZE_ELEMENTS;
flags |= RELAYOUT;
}
if ((flags & (RELAYOUT | EXTEND_LAYOUT)) != 0
&& (flags & STYLER_RUNNING) == 0) {
nextPlaced = 0;
varId = 0;
maxX = 0;
maxY = 0;
ResetLayoutContext();
firstBlock = 0;
lastBlock = 0;
redoSelection = 1;
flags &= ~RELAYOUT;
flags |= HSCROLL | VSCROLL | REDRAW_TEXT | EXTEND_LAYOUT;
}
if ((flags & EXTEND_LAYOUT) && pFirst != 0) {
LayoutDoc();
flags &= ~EXTEND_LAYOUT;
FormBlocks();
MapControls();
if (redoSelection && selBegin.p && selEnd.p) {
UpdateSelection(1);
UpdateInsert();
}
}
flags &= ~REDRAW_PENDING;
if ((flags & (HSCROLL | VSCROLL)) != 0) {
ComputeVirtualSize();
flags &= ~(HSCROLL | VSCROLL);
if (flags & REDRAW_PENDING) return;
}
hw = highlightWidth;
if (flags & REDRAW_FOCUS) {
if (hw > 0) {
#if 0
unsigned long color;
if (flags & GOT_FOCUS) {
color = highlightColorPtr;
} else {
color = highlightBgColorPtr;
}
_DrawFocusHighlight(color);
#endif
}
flags &= ~REDRAW_FOCUS;
}
if (flags & STYLER_RUNNING) {
goto earlyOut;
}
MapControls();
clipwinW = fCanvas->GetWidth();
clipwinH = fCanvas->GetHeight();
if (flags & REDRAW_TEXT) {
w = clipwinW;
h = clipwinH;
x = fVisible.fX;
y = fVisible.fY;
dirtyLeft = 0;
dirtyTop = 0;
flags &= ~REDRAW_TEXT;
} else {
if (dirtyLeft < 0) dirtyLeft = 0;
if (dirtyRight > clipwinW) dirtyRight = clipwinW;
if (dirtyTop < 0) dirtyTop = 0;
if (dirtyBottom > clipwinH) dirtyBottom = clipwinH;
w = dirtyRight - dirtyLeft;
h = dirtyBottom - dirtyTop;
x = fVisible.fX + dirtyLeft;
y = fVisible.fY + dirtyTop;
}
if (w > 0 && h > 0) {
GContext_t gcBg;
TGRectangle xrec;
gcBg = GetGC(COLOR_Background, FONT_Any);
pixmap = gVirtualX->CreatePixmap(fCanvas->GetId(), w, h);
xrec.fX = 0;
xrec.fY = 0;
xrec.fW = w;
xrec.fH = h;
#if 0
#else
fWhiteGC.SetTileStipXOrigin(-fVisible.fX - dirtyLeft);
fWhiteGC.SetTileStipYOrigin(-fVisible.fY - dirtyTop);
gVirtualX->FillRectangle(pixmap, fWhiteGC.GetGC(), 0, 0, w, h);
UpdateBackgroundStart();
#endif
for (pBlock = firstBlock; pBlock; pBlock = pBlock->bNext) {
if (pBlock->top <= y+h && pBlock->bottom >= y-10 &&
pBlock->left <= x+w && pBlock->right >= x-10) {
BlockDraw(pBlock, pixmap, x, y, w, h, pixmap);
}
}
gVirtualX->CopyArea(pixmap, fCanvas->GetId(),
gcBg, 0, 0, w, h, dirtyLeft, dirtyTop);
gVirtualX->Update(kFALSE);
gVirtualX->DeletePixmap(pixmap);
}
if (flags & REDRAW_IMAGES) {
TGHtmlImage *pImage;
TGHtmlImageMarkup *pElem;
int top, bottom, left, right;
int imageTop;
top = fVisible.fY;
bottom = top + fCanvas->GetHeight();
left = fVisible.fX;
right = left + fCanvas->GetWidth();
for (pImage = imageList; pImage; pImage = pImage->pNext) {
for (pElem = pImage->pList; pElem; pElem = pElem->iNext) {
if (pElem->redrawNeeded == 0) continue;
imageTop = pElem->y - pElem->ascent;
if (imageTop > bottom || imageTop + pElem->h < top
|| pElem->x > right || pElem->x + pElem->w < left) continue;
DrawImage(pElem, fCanvas->GetId(), left, top, right, bottom);
}
}
flags &= ~(REDRAW_IMAGES | ANIMATE_IMAGES);
}
earlyOut:
dirtyTop = LARGE_NUMBER;
dirtyLeft = LARGE_NUMBER;
dirtyBottom = 0;
dirtyRight = 0;
return;
}
void TGHtml::ScheduleRedraw()
{
if ((flags & REDRAW_PENDING) == 0 ) {
if (!fIdle) fIdle = new TGIdleHandler(this);
flags |= REDRAW_PENDING;
}
}
Bool_t TGHtml::HandleIdleEvent(TGIdleHandler *idle)
{
if (idle != fIdle) return kFALSE;
Redraw();
delete fIdle;
fIdle = NULL;
return kTRUE;
}
void TGHtml::RedrawArea(int left, int top, int right, int bottom)
{
if (bottom < 0) return;
if (top > (int)fCanvas->GetHeight()) return;
if (right < 0) return;
if (left > (int)fCanvas->GetWidth()) return;
if (dirtyTop > top) dirtyTop = top;
if (dirtyLeft > left) dirtyLeft = left;
if (dirtyBottom < bottom) dirtyBottom = bottom;
if (dirtyRight < right) dirtyRight = right;
ScheduleRedraw();
}
void TGHtml::DrawRegion(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
TGView::DrawRegion(x, y, w, h);
#if 0
RedrawArea(x, y, x + w + 1, y + h + 1);
#else
int left = x;
int top = y;
int right = x + w + 1;
int bottom = y + h + 1;
if (bottom < 0) return;
if (top > (int) fCanvas->GetHeight()) return;
if (right < 0) return;
if (left > (int)fCanvas->GetWidth()) return;
if (dirtyTop > top) dirtyTop = top;
if (dirtyLeft > left) dirtyLeft = left;
if (dirtyBottom < bottom) dirtyBottom = bottom;
if (dirtyRight < right) dirtyRight = right;
flags |= REDRAW_PENDING;
Redraw();
#endif
return;
}
Bool_t TGHtml::ItemLayout()
{
#if 0
flags |= RELAYOUT | VSCROLL | HSCROLL;
Redraw();
#else
nextPlaced = 0;
varId = 0;
maxX = 0;
maxY = 0;
ResetLayoutContext();
firstBlock = 0;
lastBlock = 0;
if (pFirst != 0) {
LayoutDoc();
FormBlocks();
MapControls();
if (selBegin.p && selEnd.p) {
UpdateSelection(1);
UpdateInsert();
}
}
ComputeVirtualSize();
ScheduleRedraw();
#endif
return kTRUE;
}
void TGHtml::RedrawBlock(TGHtmlBlock *p)
{
if (p) {
RedrawArea(p->left - fVisible.fX, p->top - fVisible.fY,
p->right - fVisible.fX + 1, p->bottom - fVisible.fY);
}
}
void TGHtml::RedrawEverything()
{
flags |= REDRAW_FOCUS | REDRAW_TEXT;
ScheduleRedraw();
}
void TGHtml::RedrawText(int y)
{
int clipHeight;
clipHeight = fCanvas->GetHeight();
y -= fVisible.fY;
if (y < clipHeight) {
RedrawArea(0, y, LARGE_NUMBER, clipHeight);
}
}
void TGHtml::_Clear()
{
int i;
TGHtmlElement *p, *pNext;
fXMargin = fYMargin = 0;
DeleteControls();
for (p = pFirst; p; p = pNext) {
pNext = p->pNext;
delete p;
}
pFirst = 0;
pLast = 0;
nToken = 0;
if (zText) delete[] zText;
zText = 0;
nText = 0;
nAlloc = 0;
nComplete = 0;
iPlaintext = 0;
for (i = 0; i < N_COLOR; ++i) {
if (apColor[i] != 0) FreeColor(apColor[i]);
apColor[i] = 0;
iDark[i] = 0;
iLight[i] = 0;
}
if (!_exiting) {
fgColor = AllocColor("black");
bgColor = AllocColor("white");
newLinkColor = AllocColor(DEF_HTML_UNVISITED);
oldLinkColor = AllocColor(DEF_HTML_VISITED);
selectionColor = AllocColor(DEF_HTML_SELECTION_COLOR);
apColor[COLOR_Normal] = fgColor;
apColor[COLOR_Visited] = oldLinkColor;
apColor[COLOR_Unvisited] = newLinkColor;
apColor[COLOR_Selection] = selectionColor;
apColor[COLOR_Background] = bgColor;
SetBackgroundColor(apColor[COLOR_Background]->fPixel);
SetBackgroundPixmap(0);
}
colorUsed = 0;
while (imageList) {
TGHtmlImage *p2 = imageList;
imageList = p2->pNext;
delete p2;
}
if (bgImage) delete bgImage;
bgImage = 0;
while (styleStack) {
SHtmlStyleStack *p2 = styleStack;
styleStack = p2->pNext;
delete p2;
}
ClearGcCache();
ResetLayoutContext();
if (zBaseHref) delete [] zBaseHref;
zBaseHref = 0;
lastSized = 0;
nextPlaced = 0;
firstBlock = 0;
lastBlock = 0;
nInput = 0;
nForm = 0;
varId = 0;
paraAlignment = ALIGN_None;
rowAlignment = ALIGN_None;
anchorFlags = 0;
inDt = 0;
anchorStart = 0;
formStart = 0;
innerList = 0;
maxX = 0;
maxY = 0;
#if 0 // in OXView::Clear()
fVisible = TGPosition(0, 0);
_virtualSize = TGDimension(0, 0);
ScrollTTGPosition(fVisible);
#endif
pInsBlock = 0;
ins.p = 0;
selBegin.p = 0;
selEnd.p = 0;
pSelStartBlock = 0;
pSelEndBlock = 0;
HasScript = 0;
HasFrames = 0;
_lastUri = 0;
}
Bool_t TGHtml::HandleTimer(TTimer *t)
{
if (t == insTimer) {
if (insTimer) delete insTimer;
insTimer = NULL;
FlashCursor();
return kTRUE;
} else {
TGHtmlImage *pImage;
for (pImage = imageList; pImage; pImage = pImage->pNext) {
if (pImage->timer == t) {
AnimateImage(pImage);
return kTRUE;
}
}
}
return kFALSE;
}
void TGHtml::FlashCursor()
{
if (pInsBlock == 0 || insOnTime <= 0 || insOffTime <= 0) return;
RedrawBlock(pInsBlock);
if ((flags & GOT_FOCUS) == 0) {
insStatus = 0;
} else if (insStatus) {
insTimer = new TTimer(this, insOffTime);
insStatus = 0;
} else {
insTimer = new TTimer(this, insOnTime);
insStatus = 1;
}
}
GContext_t TGHtml::GetGC(int color, int font)
{
int i, j;
GcCache *p = aGcCache;
GCValues_t gcValues;
TGFont *xfont;
if (color < 0 || color >= N_COLOR) color = 0;
if (font < FONT_Any || font >= N_FONT) font = FONT_Default;
for (i = 0; i < N_CACHE_GC; i++, p++) {
if (p->index == 0) continue;
if ((font < 0 || p->font == font) && p->color == color) {
if (p->index > 1) {
for (j = 0; j < N_CACHE_GC; j++) {
if (aGcCache[j].index && aGcCache[j].index < p->index ) {
aGcCache[j].index++;
}
}
p->index = 1;
}
return aGcCache[i].gc;
}
}
p = aGcCache;
for (i = 0; i < N_CACHE_GC; i++, p++) {
if (p->index == 0 || p->index == N_CACHE_GC) break;
}
if (i >= N_CACHE_GC) {
p = aGcCache;
for (i = 0; i < N_CACHE_GC && i < GcNextToFree; ++i, ++p) {}
GcNextToFree = (GcNextToFree + 1) % N_CACHE_GC;
gVirtualX->DeleteGC(p->gc);
}
gcValues.fForeground = apColor[color]->fPixel;
gcValues.fGraphicsExposures = kTRUE;
gcValues.fMask = kGCForeground | kGCGraphicsExposures;
if (font < 0) font = FONT_Default;
xfont = GetFont(font);
if (xfont) {
gcValues.fFont = xfont->GetFontHandle();
gcValues.fMask |= kGCFont;
}
p->gc = gVirtualX->CreateGC(fId, &gcValues);
if (p->index == 0) p->index = N_CACHE_GC + 1;
for (j = 0; j < N_CACHE_GC; j++) {
if (aGcCache[j].index && aGcCache[j].index < p->index) {
aGcCache[j].index++;
}
}
p->index = 1;
p->font = font;
p->color = color;
return p->gc;
}
GContext_t TGHtml::GetAnyGC()
{
int i;
GcCache *p = aGcCache;
for (i = 0; i < N_CACHE_GC; i++, p++) {
if (p->index) return p->gc;
}
return GetGC(COLOR_Normal, FONT_Default);
}
Bool_t TGHtml::HandleFocusChange(Event_t *event)
{
if (event->fType == kFocusIn) {
flags |= GOT_FOCUS | REDRAW_FOCUS;
ScheduleRedraw();
UpdateInsert();
} else {
flags &= ~GOT_FOCUS;
flags |= REDRAW_FOCUS;
ScheduleRedraw();
}
return kTRUE;
}
TGHtmlInput *TGHtml::GetInputElement(int x, int y)
{
TGHtmlInput *p;
int vx, vy, vw, vh;
vx = fVisible.fX;
vy = fVisible.fY;
vw = fCanvas->GetWidth();
vh = fCanvas->GetHeight();
for (p = firstInput; p; p = p->iNext) {
if (p->frame == 0) continue;
if (p->y < vy + vh && p->y + p->h > vy &&
p->x < vx + vw && p->x + p->w > vx) {
if ((x > p->x) && (y > p->y) && (x < (p->x + p->w)) &&
(y < (p->y + p->h)) ) {
return p;
}
}
}
return 0;
}
Bool_t TGHtml::HandleHtmlInput(TGHtmlInput *pr, Event_t *event)
{
Window_t childdum;
Event_t eventSt;
eventSt.fType = event->fType;
eventSt.fWindow = event->fWindow;
eventSt.fTime = event->fTime;
eventSt.fX = 2;
eventSt.fY = 2;
eventSt.fXRoot = event->fXRoot;
eventSt.fYRoot = event->fYRoot;
eventSt.fCode = event->fCode;
eventSt.fState = event->fState;
eventSt.fWidth = event->fWidth;
eventSt.fHeight = event->fHeight;
eventSt.fCount = event->fCount;
eventSt.fSendEvent = event->fSendEvent;
eventSt.fHandle = event->fHandle;
eventSt.fFormat = event->fFormat;
eventSt.fUser[0] = event->fUser[0];
eventSt.fUser[1] = event->fUser[1];
eventSt.fUser[2] = event->fUser[2];
eventSt.fUser[3] = event->fUser[3];
eventSt.fUser[4] = event->fUser[4];
gVirtualX->TranslateCoordinates(GetId(), pr->frame->GetId(),
event->fX, event->fY, eventSt.fX,
eventSt.fY, childdum);
const char *name = pr->MarkupArg("name", 0);
const char *val = pr->MarkupArg("value", 0);
switch (pr->itype) {
case INPUT_TYPE_Submit:
case INPUT_TYPE_Button: {
TGButton *b = (TGButton *) pr->frame;
Bool_t was = !b->IsDown();
b->HandleButton(&eventSt);
Bool_t now = !b->IsDown();
if (!was && now) {
if (pr->itype == INPUT_TYPE_Submit)
SubmitClicked(val);
else
ButtonClicked(name, val);
}
break;
}
case INPUT_TYPE_Radio: {
TGRadioButton *rb = (TGRadioButton *) pr->frame;
Bool_t was = !rb->IsDown();
rb->HandleButton(&eventSt);
Bool_t now = !rb->IsDown();
if ((!was && now) || (was && !now)) {
HandleRadioButton(pr);
RadioChanged(name, val);
}
break;
}
case INPUT_TYPE_Checkbox: {
TGCheckButton *cb = (TGCheckButton *) pr->frame;
Bool_t was = !cb->IsDown();
cb->HandleButton(&eventSt);
Bool_t now = !cb->IsDown();
if ((!was && now) || (was && !now))
CheckToggled(name, !now, val);
break;
}
case INPUT_TYPE_Text:
case INPUT_TYPE_Password: {
TGTextEntry *te = (TGTextEntry *) pr->frame;
te->SetFocus();
break;
}
default:
break;
}
return kTRUE;
}
Bool_t TGHtml::HandleRadioButton(TGHtmlInput *p)
{
TGHtmlInput *pr;
for (pr = firstInput; pr; pr = pr->iNext) {
if ((pr->pForm == p->pForm) && (pr->itype == INPUT_TYPE_Radio)) {
if (pr != p) {
if (strcmp(pr->MarkupArg("name", ""), p->MarkupArg("name", "")) == 0) {
((TGRadioButton *)pr->frame)->SetState(kButtonUp);
}
}
}
}
return kTRUE;
}
void TGHtml::ButtonClicked(const char *name, const char *val)
{
Long_t args[2];
args[0] = (Long_t)name;
args[1] = (Long_t)val;
Emit("ButtonClicked(char*,char*)", args);
}
void TGHtml::CheckToggled(const char *name, Bool_t on, const char *val)
{
Long_t args[3];
args[0] = (Long_t)name;
args[1] = on;
args[2] = (Long_t)val;
Emit("CheckToggled(char*,Bool_t,char*)", args);
}
void TGHtml::RadioChanged(const char *name, const char *val)
{
Long_t args[2];
args[0] = (Long_t)name;
args[1] = (Long_t)val;
Emit("RadioChanged(char*,char*)", args);
}
void TGHtml::SubmitClicked(const char *val)
{
Emit("SubmitClicked(char*)", val);
}
Bool_t TGHtml::HandleButton(Event_t *event)
{
int amount, ch;
ch = fCanvas->GetHeight();
amount = fScrollVal.fY * TMath::Max(ch/6, 1);
int ix = event->fX + fVisible.fX;
int iy = event->fY + fVisible.fY;
TGHtmlInput *pr = GetInputElement(ix, iy);
if (pr) {
HandleHtmlInput(pr, event);
}
if ((event->fType == kButtonPress) && (event->fCode == kButton1)) {
int x = event->fX + fVisible.fX;
int y = event->fY + fVisible.fY;
const char *uri = GetHref(x, y);
#if 0 // insertion cursor test
char ix[20];
sprintf(ix, "begin");
SetInsert(ix);
#endif
if (uri) {
uri = ResolveUri(uri);
if (uri) {
MouseDown(uri);
}
}
} else if (event->fCode == kButton4) {
ScrollToPosition(TGLongPosition(fVisible.fX, fVisible.fY / fScrollVal.fY - amount));
} else if (event->fCode == kButton5) {
ScrollToPosition(TGLongPosition(fVisible.fX, fVisible.fY / fScrollVal.fY + amount));
} else {
return TGView::HandleButton(event);
}
return kTRUE;
}
Bool_t TGHtml::HandleMotion(Event_t *event)
{
int x = event->fX + fVisible.fX;
int y = event->fY + fVisible.fY;
const char *uri = GetHref(x, y);
if (uri) {
gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kHand));
} else {
gVirtualX->SetCursor(fId, gVirtualX->CreateCursor(kPointer));
}
if (uri != _lastUri) {
_lastUri = uri;
if (uri) uri = ResolveUri(uri);
MouseOver(uri);
}
return kTRUE;
}
TGFont *TGHtml::GetFont(int iFont)
{
TGFont *toFree = 0;
if (iFont < 0) iFont = 0;
if (iFont >= N_FONT) { iFont = N_FONT - 1; CANT_HAPPEN; }
if (!FontIsValid(iFont) && aFont[iFont] != 0) {
toFree = aFont[iFont];
aFont[iFont] = 0;
}
if (aFont[iFont] == 0) {
char name[200];
const char *familyStr = "";
int iFamily;
int iSize;
int size;
iFamily = FontFamily(iFont) >> 3;
iSize = FontSize(iFont) + 1;
switch (iFamily) {
#ifdef TIMES
case 0: familyStr = "times -%d"; break;
case 1: familyStr = "times -%d bold"; break;
case 2: familyStr = "times -%d italic"; break;
case 3: familyStr = "times -%d bold italic"; break;
case 4: familyStr = "courier -%d"; break;
case 5: familyStr = "courier -%d bold"; break;
case 6: familyStr = "courier -%d italic"; break;
case 7: familyStr = "courier -%d bold italic"; break;
default: familyStr = "times -16"; CANT_HAPPEN;
#else
case 0: familyStr = "helvetica -%d"; break;
case 1: familyStr = "helvetica -%d bold"; break;
case 2: familyStr = "helvetica -%d italic"; break;
case 3: familyStr = "helvetica -%d bold italic"; break;
case 4: familyStr = "courier -%d"; break;
case 5: familyStr = "courier -%d bold"; break;
case 6: familyStr = "courier -%d italic"; break;
case 7: familyStr = "courier -%d bold italic"; break;
default: familyStr = "helvetica -14"; CANT_HAPPEN;
#endif
}
#if 0
switch (iSize) {
case 1: size = 6+finc; break;
case 2: size = 10+finc; break;
case 3: size = 12+finc; break;
case 4: size = 14+finc; break;
case 5: size = 20+finc; break;
case 6: size = 24+finc; break;
case 7: size = 30+finc; break;
default: size = 14+finc; CANT_HAPPEN;
}
#else
switch (iSize) {
case 1: size = 8; break;
case 2: size = 10; break;
case 3: size = 12; break;
case 4: size = 14; break;
case 5: size = 16; break;
case 6: size = 18; break;
case 7: size = 24; break;
default: size = 14; CANT_HAPPEN;
}
#endif
#ifdef TIMES
if (iFamily < 4) size += 2;
#endif
sprintf(name, familyStr, size);
aFont[iFont] = fClient->GetFont(name);\
if (aFont[iFont] == 0) {
fprintf(stderr, "TGHtml: could not get font \"%s\", trying fixed\n",
name);
aFont[iFont] = fClient->GetFont("fixed");
}
if (aFont[iFont]==0 ){
fprintf(stderr, "TGHtml: could not get font \"fixed\", trying "
"\"helvetica -12\"\n");
aFont[iFont] = fClient->GetFont("helvetica -12");
}
FontSetValid(iFont);
}
if (toFree) fClient->FreeFont(toFree);
return aFont[iFont];
}
int TGHtml::InArea(TGHtmlMapArea *p, int left, int top, int x, int y)
{
int *ip = p->coords;
if (!ip) return 0;
if (p->mType == HTML_MAP_RECT) {
return ((left + ip[0]) <= x && (left + ip[2]) >= x &&
(top + ip[1]) <= y && (top + ip[3]) >= y);
} else if (p->mType == HTML_MAP_CIRCLE) {
int dx = left + ip[0] - x;
int dy = top + ip[1] - y;
return (dx * dx + dy * dy <= ip[2] * ip[2]);
}
return 0;
}
TGHtmlElement *TGHtml::GetMap(const char *name)
{
TGHtmlElement *p = pFirst;
const char *z, *zb;
while (p) {
if (p->type == Html_MAP) {
z = p->MarkupArg("name", 0);
zb = p->MarkupArg("shape", 0);
if (zb && *zb != 'r') return 0;
if (z && !strcmp(z, name)) return p;
}
p = p->pNext;
}
return 0;
}
float TGHtml::colorDistance(ColorStruct_t *pA, ColorStruct_t *pB)
{
float x, y, z;
x = 0.30 * (pA->fRed - pB->fRed);
y = 0.61 * (pA->fGreen - pB->fGreen);
z = 0.11 * (pA->fBlue - pB->fBlue);
return x*x + y*y + z*z;
}
int TGHtml::GetColorByName(const char *zColor)
{
ColorStruct_t *pNew;
int iColor;
const char *name;
int i, n;
char zAltColor[16];
n = strlen(zColor);
if (n == 6 || n == 3 || n == 9 || n == 12) {
for (i = 0; i < n; i++) {
if (!isxdigit(zColor[i])) break;
}
if (i == n) {
sprintf(zAltColor, "#%s", zColor);
} else {
strcpy(zAltColor, zColor);
}
name = GetUid(zAltColor);
} else {
name = GetUid(zColor);
}
pNew = AllocColor(name);
if (pNew == 0) {
return 0;
}
iColor = GetColorByValue(pNew);
FreeColor(pNew);
return iColor;
}
#define MAX_COLOR 65535
#define MAX(A,B) ((A)<(B)?(B):(A))
#define MIN(A,B) ((A)<(B)?(A):(B))
int TGHtml::isDarkColor(ColorStruct_t *p)
{
float x, y, z;
x = 0.50 * p->fRed;
y = 1.00 * p->fGreen;
z = 0.28 * p->fBlue;
return (x*x + y*y + z*z) < (0.05 * MAX_COLOR * MAX_COLOR);
}
int TGHtml::GetDarkShadowColor(int iBgColor)
{
if (iDark[iBgColor] == 0) {
ColorStruct_t *pRef, val;
pRef = apColor[iBgColor];
if (isDarkColor(pRef)) {
int t1, t2;
t1 = (int) MIN(MAX_COLOR, pRef->fRed * 1.2);
t2 = (pRef->fRed * 3 + MAX_COLOR) / 4;
val.fRed = MAX(t1, t2);
t1 = (int) MIN(MAX_COLOR, pRef->fGreen * 1.2);
t2 = (pRef->fGreen * 3 + MAX_COLOR) / 4;
val.fGreen = MAX(t1, t2);
t1 = (int) MIN(MAX_COLOR, pRef->fBlue * 1.2);
t2 = (pRef->fBlue * 3 + MAX_COLOR) / 4;
val.fBlue = MAX(t1, t2);
} else {
val.fRed = (unsigned short) (pRef->fRed * 0.6);
val.fGreen = (unsigned short) (pRef->fGreen * 0.6);
val.fBlue = (unsigned short) (pRef->fBlue * 0.6);
}
iDark[iBgColor] = GetColorByValue(&val) + 1;
}
return iDark[iBgColor] - 1;
}
int TGHtml::isLightColor(ColorStruct_t *p)
{
return p->fGreen >= 0.85 * MAX_COLOR;
}
int TGHtml::GetLightShadowColor(int iBgColor)
{
if (iLight[iBgColor] == 0) {
ColorStruct_t *pRef, val;
pRef = apColor[iBgColor];
if (isLightColor(pRef)) {
val.fRed = (unsigned short) (pRef->fRed * 0.9);
val.fGreen = (unsigned short) (pRef->fGreen * 0.9);
val.fBlue = (unsigned short) (pRef->fBlue * 0.9);
} else {
int t1, t2;
t1 = (int) MIN(MAX_COLOR, pRef->fGreen * 1.4);
t2 = (pRef->fGreen + MAX_COLOR) / 2;
val.fGreen = MAX(t1, t2);
t1 = (int) MIN(MAX_COLOR, pRef->fRed * 1.4);
t2 = (pRef->fRed + MAX_COLOR) / 2;
val.fRed = MAX(t1, t2);
t1 = (int) MIN(MAX_COLOR, pRef->fBlue * 1.4);
t2 = (pRef->fBlue + MAX_COLOR) / 2;
val.fBlue = MAX(t1, t2);
}
iLight[iBgColor] = GetColorByValue(&val) + 1;
}
return iLight[iBgColor] - 1;
}
int TGHtml::GetColorByValue(ColorStruct_t *pRef)
{
int i;
float dist;
float closestDist;
int closest;
int r, g, b;
# define COLOR_MASK 0xf800
r = pRef->fRed & COLOR_MASK;
g = pRef->fGreen & COLOR_MASK;
b = pRef->fBlue & COLOR_MASK;
for (i = 0; i < N_COLOR; i++) {
ColorStruct_t *p = apColor[i];
if (p &&
((p->fRed & COLOR_MASK) == r) &&
((p->fGreen & COLOR_MASK) == g) &&
((p->fBlue & COLOR_MASK) == b)) {
colorUsed |= (1<<i);
return i;
}
}
for (i = N_PREDEFINED_COLOR; i < N_COLOR; i++) {
if (apColor[i] == 0) {
apColor[i] = AllocColorByValue(pRef);
colorUsed |= (1<<i);
return i;
}
}
for (i = N_PREDEFINED_COLOR; i < N_COLOR; i++) {
if (((colorUsed >> i) & 1) == 0) {
FreeColor(apColor[i]);
apColor[i] = AllocColorByValue(pRef);
colorUsed |= (1<<i);
return i;
}
}
closest = 0;
closestDist = colorDistance(pRef, apColor[0]);
for (i = 1; i < N_COLOR; i++) {
dist = colorDistance(pRef, apColor[i]);
if (dist < closestDist) {
closestDist = dist;
closest = i;
}
}
return closest;
}
const char *TGHtml::GetHref(int x, int y, const char **target)
{
TGHtmlBlock *pBlock;
TGHtmlElement *pElem;
for (pBlock = firstBlock; pBlock; pBlock = pBlock->bNext) {
if (pBlock->top > y || pBlock->bottom < y ||
pBlock->left > x || pBlock->right < x) continue;
pElem = pBlock->pNext;
if (pElem->type == Html_IMG) {
TGHtmlImageMarkup *image = (TGHtmlImageMarkup *) pElem;
if (image->pMap) {
pElem = image->pMap->pNext;
while (pElem && pElem->type != Html_EndMAP) {
if (pElem->type == Html_AREA) {
if (InArea((TGHtmlMapArea *) pElem, pBlock->left, pBlock->top, x, y)) {
if (target) *target = pElem->MarkupArg("target", 0);
return pElem->MarkupArg("href", 0);
}
}
pElem = pElem->pNext;
}
continue;
}
}
if ((pElem->style.flags & STY_Anchor) == 0) continue;
switch (pElem->type) {
case Html_Text:
case Html_Space:
case Html_IMG:
while (pElem && pElem->type != Html_A) pElem = pElem->pPrev;
if (pElem == 0 || pElem->type != Html_A) break;
if (target) *target = pElem->MarkupArg("target", 0);
return pElem->MarkupArg("href", 0);
default:
break;
}
}
return 0;
}
int TGHtml::ElementCoords(TGHtmlElement *p, int , int pct, int *coords)
{
TGHtmlBlock *pBlock;
while (p && p->type != Html_Block) p = p->pPrev;
if (!p) return 1;
pBlock = (TGHtmlBlock *) p;
if (pct) {
TGHtmlElement *pEnd = pLast;
TGHtmlBlock *pb2;
while (pEnd && pEnd->type != Html_Block) pEnd = pEnd->pPrev;
pb2 = (TGHtmlBlock *) pEnd;
#define HGCo(dir) pb2->dir ? pBlock->dir * 100 / pb2->dir : 0
coords[0] = HGCo(left);
coords[1] = HGCo(top);
coords[3] = HGCo(right);
coords[4] = HGCo(bottom);
} else {
coords[0] = pBlock->left;
coords[1] = pBlock->top;
coords[2] = pBlock->right;
coords[3] = pBlock->bottom;
}
return 0;
}
TGHtmlElement *TGHtml::AttrElem(const char *name, char *value)
{
TGHtmlElement *p;
const char *z;
for (p = pFirst; p; p = p->pNext) {
if (p->type != Html_A) continue;
z = p->MarkupArg(name, 0);
if (z && (strcmp(z, value) == 0)) return p;
}
return 0;
}
void TGHtml::UpdateSelection(int forceUpdate)
{
TGHtmlBlock *pBlock;
int index;
int needUpdate = forceUpdate;
int temp;
if (selEnd.p == 0) selBegin.p = 0;
IndexToBlockIndex(selBegin, &pBlock, &index);
if (needUpdate || pBlock != pSelStartBlock) {
needUpdate = 1;
RedrawBlock(pSelStartBlock);
pSelStartBlock = pBlock;
selStartIndex = index;
} else if (index != selStartIndex) {
RedrawBlock(pBlock);
selStartIndex = index;
}
if (selBegin.p == 0) selEnd.p = 0;
IndexToBlockIndex(selEnd, &pBlock, &index);
if (needUpdate || pBlock != pSelEndBlock) {
needUpdate = 1;
RedrawBlock(pSelEndBlock);
pSelEndBlock = pBlock;
selEndIndex = index;
} else if (index != selEndIndex) {
RedrawBlock(pBlock);
selEndIndex = index;
}
if (pSelStartBlock && pSelStartBlock == pSelEndBlock &&
selStartIndex > selEndIndex) {
temp = selStartIndex;
selStartIndex = selEndIndex;
selEndIndex = temp;
}
if (needUpdate) {
flags |= ANIMATE_IMAGES;
UpdateSelectionDisplay();
}
}
void TGHtml::UpdateSelectionDisplay()
{
int selected = 0;
SHtmlIndex tempIndex;
TGHtmlBlock *pTempBlock;
int temp;
TGHtmlBlock *p;
for (p = firstBlock; p; p = p->bNext) {
if (p == pSelStartBlock) {
selected = 1;
RedrawBlock(p);
} else if (!selected && p == pSelEndBlock) {
selected = 1;
tempIndex = selBegin;
selBegin = selEnd;
selEnd = tempIndex;
pTempBlock = pSelStartBlock;
pSelStartBlock = pSelEndBlock;
pSelEndBlock = pTempBlock;
temp = selStartIndex;
selStartIndex = selEndIndex;
selEndIndex = temp;
RedrawBlock(p);
}
if (p->flags & HTML_Selected) {
if (!selected) {
p->flags &= ~HTML_Selected;
RedrawBlock(p);
}
} else {
if (selected) {
p->flags |= HTML_Selected;
RedrawBlock(p);
}
}
if (p == pSelEndBlock) {
selected = 0;
RedrawBlock(p);
}
}
}
void TGHtml::LostSelection()
{
if (exportSelection) {
pSelStartBlock = 0;
pSelEndBlock = 0;
selBegin.p = 0;
selEnd.p = 0;
UpdateSelectionDisplay();
}
}
int TGHtml::SelectionSet(const char *startIx, const char *endIx)
{
SHtmlIndex sBegin, sEnd;
int bi, ei;
if (GetIndex(startIx, &sBegin.p, &sBegin.i)) {
return kFALSE;
}
if (GetIndex(endIx, &sEnd.p, &sEnd.i)) {
return kFALSE;
}
bi = TokenNumber(sBegin.p);
ei = TokenNumber(sEnd.p);
if (!(sBegin.p && sEnd.p)) return kTRUE;
if (bi < ei || (bi == ei && sBegin.i <= sEnd.i)) {
selBegin = sBegin;
selEnd = sEnd;
} else {
selBegin = sEnd;
selEnd = sBegin;
}
UpdateSelection(0);
if (exportSelection) {
}
return kTRUE;
}
void TGHtml::UpdateInsert()
{
IndexToBlockIndex(ins, &pInsBlock, &insIndex);
RedrawBlock(pInsBlock);
if (insTimer == 0) {
insStatus = 0;
FlashCursor();
}
}
int TGHtml::SetInsert(const char *insIx)
{
SHtmlIndex i;
if (!insIx) {
RedrawBlock(pInsBlock);
insStatus = 0;
pInsBlock = 0;
ins.p = 0;
} else {
if (GetIndex(insIx, &i.p, &i.i)) {
return kFALSE;
}
RedrawBlock(pInsBlock);
ins = i;
UpdateInsert();
}
return kTRUE;
}
Last change: Wed Jun 25 08:40:34 2008
Last generated: 2008-06-25 08:40
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.