#include "TGView.h"
#include "TGScrollBar.h"
#include "TGResourcePool.h"
#include "TMath.h"
#include "KeySymbols.h"
ClassImp(TGViewFrame)
TGViewFrame::TGViewFrame(TGView *v, UInt_t w, UInt_t h, UInt_t options,
ULong_t back) :
TGCompositeFrame(v, w, h, options | kOwnBackground, back)
{
fView = v;
SetBackgroundColor(back);
gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
kButtonPressMask | kButtonReleaseMask |
kButtonMotionMask, kNone, kNone);
AddInput(kKeyPressMask | kEnterWindowMask | kLeaveWindowMask |
kFocusChangeMask);
SetWindowAttributes_t wattr;
wattr.fMask = kWAWinGravity | kWABitGravity;
wattr.fBitGravity = 1;
wattr.fWinGravity = 1;
gVirtualX->ChangeWindowAttributes(fId, &wattr);
fEditDisabled = kEditDisableGrab | kEditDisableKeyEnable | kEditDisableBtnEnable;
}
ClassImp(TGView)
TGView::TGView(const TGWindow *p, UInt_t w, UInt_t h, Int_t id,
UInt_t xMargin, UInt_t yMargin, UInt_t options,
UInt_t sboptions, ULong_t back)
: TGCompositeFrame(p, w, h, options, GetDefaultFrameBackground())
{
fWidgetId = id;
fMsgWindow = p;
fWidgetFlags = kWidgetWantFocus;
fXMargin = xMargin;
fYMargin = yMargin;
fScrollVal.fX = 1;
fScrollVal.fY = 1;
fExposedRegion.Empty();
fClipboard = fClient->GetResourcePool()->GetClipboard();
fCanvas = new TGViewFrame(this, 10, 10, kChildFrame | kOwnBackground, back);
AddFrame(fCanvas);
if (!(sboptions & kNoHSB)) {
fHsb = new TGHScrollBar(this, 10, 10, kChildFrame);
AddFrame(fHsb);
fHsb->Associate(this);
} else {
fHsb = 0;
}
if (!(sboptions & kNoVSB)) {
fVsb = new TGVScrollBar(this, 10, 10, kChildFrame);
AddFrame(fVsb);
fVsb->Associate(this);
} else {
fVsb = 0;
}
fWhiteGC.SetGraphicsExposures(kTRUE);
fWhiteGC.SetBackground(back);
if (fVsb) {
fVsb->SetEditDisabled(kEditDisableGrab | kEditDisableBtnEnable);
}
if (fHsb) {
fHsb->SetEditDisabled(kEditDisableGrab | kEditDisableBtnEnable);
}
fEditDisabled = kEditDisableLayout;
delete fLayoutManager;
fLayoutManager = 0;
}
TGView::~TGView()
{
if (!MustCleanup()) {
delete fCanvas;
delete fHsb;
delete fVsb;
}
}
void TGView::Clear(Option_t *)
{
fScrolling = -1;
fMousePos.fX = fMousePos.fY = -1;
fVisible.fX = fVisible.fY = 0;
UpdateBackgroundStart();
fVirtualSize = TGDimension(0, 0);
gVirtualX->ClearArea(fCanvas->GetId(), 0, 0,
fCanvas->GetWidth(), fCanvas->GetHeight());
Layout();
}
void TGView::SetVisibleStart(Int_t newTop, Int_t direction)
{
if (direction == kHorizontal) {
if (newTop / fScrollVal.fX == fVisible.fX / fScrollVal.fX) {
return;
}
ScrollCanvas(newTop, kHorizontal);
} else {
if (newTop / fScrollVal.fY == fVisible.fY / fScrollVal.fY) {
return;
}
ScrollCanvas(newTop, kVertical);
}
}
void TGView::DrawRegion(Int_t, Int_t, UInt_t, UInt_t)
{
return;
}
void TGView::UpdateRegion(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
x = x < 0 ? 0 : x;
y = y < 0 ? 0 : y;
w = x + w > fCanvas->GetWidth() ? fCanvas->GetWidth() - x : w;
h = y + h > fCanvas->GetHeight() ? fCanvas->GetHeight() - y : h;
if (fExposedRegion.IsEmpty()) {
fExposedRegion.fX = x;
fExposedRegion.fY = y;
fExposedRegion.fW = w;
fExposedRegion.fH = h;
} else {
TGRectangle r(x, y, w, h);
fExposedRegion.Merge(r);
}
fClient->NeedRedraw(this);
}
void TGView::UpdateBackgroundStart()
{
fWhiteGC.SetTileStipXOrigin(-fVisible.fX);
fWhiteGC.SetTileStipYOrigin(-fVisible.fY);
}
Bool_t TGView::HandleButton(Event_t *event)
{
if (event->fType == kButtonPress) {
int amount, ch;
ch = fCanvas->GetHeight();
if (fScrollVal.fY == 1) {
amount = fScrollVal.fY * TMath::Max(ch/6, 1);
} else {
amount = fScrollVal.fY * 5;
}
if (event->fState & kKeyShiftMask) {
amount = fScrollVal.fY;
} else if (event->fState & kKeyControlMask) {
amount = ch - TMath::Max(ch / 20, 1);
}
if (event->fCode == kButton4) {
ScrollDown(amount);
return kTRUE;
} else if (event->fCode == kButton5) {
ScrollUp(amount);
return kTRUE;
}
}
return kFALSE;
}
void TGView::DoRedraw()
{
DrawBorder();
if (!fExposedRegion.IsEmpty()) {
DrawRegion(fExposedRegion.fX, fExposedRegion.fY,
fExposedRegion.fW, fExposedRegion.fH);
fExposedRegion.Empty();
}
}
Bool_t TGView::HandleExpose(Event_t *event)
{
if (event->fWindow == fCanvas->GetId()) {
TGPosition pos(event->fX, event->fY);
TGDimension dim(event->fWidth, event->fHeight);
TGRectangle rect(pos, dim);
if (fExposedRegion.IsEmpty()) {
fExposedRegion = rect;
} else {
if (((!rect.fX && !fExposedRegion.fY) ||
(!rect.fY && !fExposedRegion.fX)) &&
((rect.fX >= (int)fExposedRegion.fW) ||
(rect.fY >= (int)fExposedRegion.fH))) {
DrawRegion(rect.fX, rect.fY, rect.fW, rect.fY);
} else {
fExposedRegion.Merge(rect);
}
}
fClient->NeedRedraw(this);
} else {
return TGCompositeFrame::HandleExpose(event);
}
return kTRUE;
}
Bool_t TGView::ProcessMessage(Long_t msg, Long_t parm1, Long_t)
{
switch(GET_MSG(msg)) {
case kC_HSCROLL:
switch(GET_SUBMSG(msg)) {
case kSB_SLIDERTRACK:
case kSB_SLIDERPOS:
SetVisibleStart(Int_t(parm1 * fScrollVal.fX), kHorizontal);
break;
}
break;
case kC_VSCROLL:
switch(GET_SUBMSG(msg)) {
case kSB_SLIDERTRACK:
case kSB_SLIDERPOS:
SetVisibleStart(Int_t(parm1 * fScrollVal.fY), kVertical);
break;
}
break;
default:
break;
}
return kTRUE;
}
void TGView::Layout()
{
Bool_t need_vsb, need_hsb;
Int_t cw, ch;
need_vsb = need_hsb = kFALSE;
cw = fWidth - (fBorderWidth << 1) - fXMargin - 1;
ch = fHeight - (fBorderWidth << 1) - fYMargin - 1;
fCanvas->SetWidth(cw);
fCanvas->SetHeight(ch);
ItemLayout();
if ((Int_t)fVirtualSize.fWidth > cw) {
if (fHsb) {
need_hsb = kTRUE;
ch -= fVsb->GetDefaultWidth();
if (ch < 0) ch = 0;
fCanvas->SetHeight(ch);
ItemLayout();
}
}
if ((Int_t)fVirtualSize.fHeight > ch) {
if (fVsb) {
need_vsb = kTRUE;
cw -= fHsb->GetDefaultHeight();
if (cw < 0) cw = 0;
fCanvas->SetWidth(cw);
ItemLayout();
}
}
if ((Int_t)fVirtualSize.fWidth > cw) {
if (!need_hsb) {
need_hsb = kTRUE;
ch -= fVsb->GetDefaultWidth();
if (ch < 0) ch = 0;
fCanvas->SetHeight(ch);
ItemLayout();
}
}
if (need_hsb) {
fHsb->MoveResize(fBorderWidth + fXMargin, ch + fBorderWidth + fYMargin,
cw, fHsb->GetDefaultHeight());
fHsb->MapRaised();
} else {
fHsb->UnmapWindow();
fHsb->SetPosition(0);
}
if (need_vsb) {
fVsb->MoveResize(cw + fBorderWidth + fXMargin, fBorderWidth + fYMargin,
fVsb->GetDefaultWidth(), ch);
fVsb->MapWindow();
} else {
fVsb->UnmapWindow();
fVsb->SetPosition(0);
}
fCanvas->MoveResize(fBorderWidth + fXMargin, fBorderWidth + fYMargin, cw, ch);
if (fHsb) {
fHsb->SetRange(fVirtualSize.fWidth / fScrollVal.fX, fCanvas->GetWidth() / fScrollVal.fX);
}
if (fVsb) {
fVsb->SetRange(fVirtualSize.fHeight / fScrollVal.fY, fCanvas->GetHeight() / fScrollVal.fY);
}
}
void TGView::DrawBorder()
{
switch (fOptions & (kSunkenFrame | kRaisedFrame | kDoubleBorder)) {
case kSunkenFrame | kDoubleBorder:
gVirtualX->DrawLine(fId, GetShadowGC()(), 0, 0, fWidth-2, 0);
gVirtualX->DrawLine(fId, GetShadowGC()(), 0, 0, 0, fHeight-2);
gVirtualX->DrawLine(fId, GetBlackGC()(), 1, 1, fWidth-3, 1);
gVirtualX->DrawLine(fId, GetBlackGC()(), 1, 1, 1, fHeight-3);
gVirtualX->DrawLine(fId, GetHilightGC()(), 0, fHeight-1, fWidth-1, fHeight-1);
gVirtualX->DrawLine(fId, GetHilightGC()(), fWidth-1, fHeight-1, fWidth-1, 0);
gVirtualX->DrawLine(fId, GetBckgndGC()(), 1, fHeight-2, fWidth-2, fHeight-2);
gVirtualX->DrawLine(fId, GetBckgndGC()(), fWidth-2, 1, fWidth-2, fHeight-2);
break;
default:
TGFrame::DrawBorder();
break;
}
}
void TGView::ScrollToPosition(TGLongPosition pos)
{
if (pos.fX < 0) pos.fX = 0;
if (pos.fY < 0) pos.fY = 0;
if (pos.fX != fHsb->GetPosition()) fHsb->SetPosition(pos.fX / fScrollVal.fX);
if (pos.fY != fVsb->GetPosition()) fVsb->SetPosition(pos.fY / fScrollVal.fY);
}
void TGView::ScrollCanvas(Int_t new_top, Int_t direction)
{
Point_t points[4];
Int_t xsrc, ysrc, xdest, ydest, cpyheight, cpywidth;
if (new_top < 0) {
return;
}
if (direction == kVertical) {
if (new_top == fVisible.fY) {
return;
}
points[0].fX = points[3].fX = 0;
points[1].fX = points[2].fX = fCanvas->GetWidth();
xsrc = xdest = 0;
cpywidth = 0;
if (new_top < fVisible.fY) {
ysrc = 0;
ydest = Int_t(fVisible.fY - new_top);
cpyheight = ydest;
if (ydest > (Int_t)fCanvas->GetHeight()) {
ydest = fCanvas->GetHeight();
}
points[1].fY = points[0].fY = 0;
points[3].fY = points[2].fY = ydest;
} else {
ydest = 0;
ysrc = Int_t(new_top - fVisible.fY);
cpyheight= ysrc;
if (ysrc > (Int_t)fCanvas->GetHeight()) {
ysrc = fCanvas->GetHeight();
}
points[1].fY = points[0].fY = fCanvas->GetHeight()-ysrc;
points[3].fY = points[2].fY = fCanvas->GetHeight();
}
fVisible.fY = new_top;
if (fVisible.fY < 0) {
fVisible.fY = 0;
}
} else {
if (new_top == fVisible.fX) {
return;
}
points[0].fY = points[1].fY = 0;
points[2].fY = points[3].fY = fCanvas->GetHeight();
ysrc = ydest = 0;
cpyheight = 0;
if (new_top < fVisible.fX) {
xsrc = 0;
xdest = Int_t(fVisible.fX - new_top);
cpywidth = xdest;
if (xdest < 0) {
xdest = fCanvas->GetWidth();
}
points[0].fX = points[3].fX = 0;
points[1].fX = points[2].fX = xdest ;
} else {
xdest = 0;
xsrc = Int_t(new_top - fVisible.fX);
cpywidth = xsrc;
if (xsrc > (Int_t)fCanvas->GetWidth()) {
xsrc = fCanvas->GetWidth();
}
points[0].fX = points[3].fX = fCanvas->GetWidth()-xsrc;
points[1].fX = points[2].fX = fCanvas->GetWidth();
}
fVisible.fX = new_top;
if (fVisible.fX < 0) {
fVisible.fX = 0;
}
}
UpdateBackgroundStart();
gVirtualX->CopyArea(fCanvas->GetId(), fCanvas->GetId(), fWhiteGC(),
xsrc, ysrc, fCanvas->GetWidth()-cpywidth,
fCanvas->GetHeight()-cpyheight, xdest, ydest);
UInt_t xdiff = points[2].fX - points[0].fX;
UInt_t ydiff = points[2].fY - points[0].fY;
#ifdef WIN32
xdiff = xdiff << 1;
ydiff = ydiff << 1;
#endif
DrawRegion(points[0].fX, points[0].fY, xdiff, ydiff);
}
void TGView::ChangeBackground(Pixel_t col)
{
fCanvas->SetBackgroundColor(col);
fWhiteGC.SetBackground(col);
fWhiteGC.SetForeground(col);
DrawRegion(0, 0, fCanvas->GetWidth(), fCanvas->GetHeight());
}
void TGView::SetBackgroundColor(Pixel_t col)
{
fCanvas->SetBackgroundColor(col);
fWhiteGC.SetBackground(col);
fWhiteGC.SetForeground(col);
}
void TGView::SetBackgroundPixmap(Pixmap_t p)
{
fCanvas->SetBackgroundPixmap(p);
}