// @(#)root/gui:$Name: $:$Id: TGView.cxx,v 1.14 2005/08/18 14:13:27 brun Exp $
// Author: Fons Rademakers 30/6/2000
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
/**************************************************************************
This source is based on Xclass95, a Win95-looking GUI toolkit.
Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.
Xclass95 is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
**************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TGView //
// //
// A TGView provides the infrastructure for text viewer and editor //
// widgets. It provides a canvas (TGViewFrame) and (optionally) a //
// vertical and horizontal scrollbar and methods for marking and //
// scrolling. //
// //
// The TGView (and derivatives) will generate the following //
// event messages: //
// kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false] //
// kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0 //
// kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x) //
// kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x) //
// kC_TEXTVIEW, kTXT_F3, widget id, true //
// kC_TEXTVIEW, kTXT_OPEN, widget id, 0 //
// kC_TEXTVIEW, kTXT_CLOSE, widget id, 0 //
// kC_TEXTVIEW, kTXT_SAVE, widget id, 0 //
// //
//////////////////////////////////////////////////////////////////////////
#include "TGView.h"
#include "TGScrollBar.h"
#include "TGResourcePool.h"
#include "TSystem.h"
#include "TMath.h"
#include "KeySymbols.h"
//______________________________________________________________________________
Bool_t TViewTimer::Notify()
{
fView->HandleTimer(this);
Reset();
return kFALSE;
}
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)
{
// Create a editor frame.
fView = v;
SetBackgroundColor(back);
gVirtualX->GrabButton(fId, kAnyButton, kAnyModifier,
kButtonPressMask | kButtonReleaseMask |
kButtonMotionMask, kNone, kNone);
AddInput(kKeyPressMask | kEnterWindowMask | kLeaveWindowMask |
kFocusChangeMask | kStructureNotifyMask);
}
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())
{
// Create an editor view, containing an TGEditorFrame and (optionally)
// a horizontal and vertical scrollbar.
fWidgetId = id;
fMsgWindow = p;
fWidgetFlags = kWidgetWantFocus;
SetLayoutManager(new TGHorizontalLayout(this));
fXMargin = xMargin;
fYMargin = yMargin;
fScrollVal.fX = 1;
fScrollVal.fY = 1;
fClipboard = fClient->GetResourcePool()->GetClipboard();
fCanvas = new TGViewFrame(this, 10, 10, kChildFrame, 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 = GetWhiteGC();
fWhiteGC.SetGraphicsExposures(kTRUE);
Clear();
Layout();
fScrollTimer = new TViewTimer(this, 75);
gSystem->AddTimer(fScrollTimer);
fReadOnly = kFALSE;
}
//______________________________________________________________________________
TGView::~TGView()
{
// Delete view.
delete fScrollTimer;
if (!MustCleanup()) {
delete fCanvas;
delete fHsb;
delete fVsb;
}
}
//______________________________________________________________________________
void TGView::Clear(Option_t *)
{
// Clear view.
fIsMarked = kFALSE;
fIsSaved = kTRUE;
fScrolling = -1;
fIsMarking = kFALSE;
fMarkedStart.fX = fMarkedStart.fY = 0;
fMarkedEnd.fX = fMarkedEnd.fY = 0;
fMousePos.fX = fMousePos.fY = -1;
fVisible.fX = fVisible.fY = 0;
SetVsbPosition(0);
SetHsbPosition(0);
}
//______________________________________________________________________________
void TGView::SetVisibleStart(Int_t newTop, Int_t direction)
{
// Scroll view in specified direction to make newTop the visible location.
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);
}
}
//______________________________________________________________________________
Bool_t TGView::HandleExpose(Event_t *event)
{
// Handle expose events.
if (event->fWindow == fCanvas->GetId()) {
DrawRegion(event->fX, event->fY, event->fWidth, event->fHeight);
} else
TGCompositeFrame::HandleExpose(event);
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGView::HandleCrossing(Event_t *event)
{
// Handle mouse crossing event.
if (event->fWindow != fCanvas->GetId())
return kTRUE;
fMousePos.fY = ToObjYCoord(fVisible.fY + event->fY);
if (ToScrYCoord(fMousePos.fY+1) >= (Int_t)fCanvas->GetHeight())
fMousePos.fY--;
fMousePos.fX = ToObjXCoord(fVisible.fX + event->fX, fMousePos.fY);
if (fMousePos.fX >= ReturnLineLength(fMousePos.fY))
fMousePos.fX--;
if ((event->fState & kButton1Mask) && fIsMarked && fIsMarking) {
if (event->fType == kLeaveNotify) {
if (event->fX < 0) {
fScrolling = 0;
return kFALSE;
}
if (event->fX >= (Int_t)fCanvas->GetWidth()) {
fScrolling = 1;
return kFALSE;
}
if (event->fY < 0) {
fScrolling = 2;
return kFALSE;
}
if (event->fY >= (Int_t)fCanvas->GetHeight()) {
fScrolling = 3;
return kFALSE;
}
} else {
fScrolling = -1;
Mark(fMousePos.fX, fMousePos.fY);
}
} else
fIsMarking = kFALSE;
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGView::HandleTimer(TTimer *)
{
// Handle scroll timer.
TGLongPosition size;
if (fIsMarked) {
size.fY = ToObjYCoord(fVisible.fY + fCanvas->GetHeight()) - 1;
size.fX = ToObjXCoord(fVisible.fX + fCanvas->GetWidth(), fMousePos.fY) - 1;
switch (fScrolling) {
case -1:
break;
case 0:
if (fVisible.fX == 0) {
fScrolling = -1;
break;
} else {
SetHsbPosition(fVisible.fX / fScrollVal.fX - 1);
Mark(ToObjXCoord(fVisible.fX, fMousePos.fY) - 1, fMousePos.fY);
}
break;
case 1:
if ((Int_t)fCanvas->GetWidth() >= ToScrXCoord(ReturnLineLength(fMousePos.fY), fMousePos.fY)) {
fScrolling = -1;
break;
} else {
SetHsbPosition(fVisible.fX / fScrollVal.fX + 1);
Mark(size.fX+1, fMousePos.fY);
}
break;
case 2:
if (fVisible.fY == 0) {
fScrolling = -1;
break;
} else {
SetVsbPosition(fVisible.fY / fScrollVal.fY - 1);
Mark(fMousePos.fX, fMarkedStart.fY - 1);
}
break;
case 3:
if ((Int_t)fCanvas->GetHeight() >= ToScrYCoord(ReturnLineCount())) {
fScrolling = -1;
break;
} else {
SetVsbPosition(fVisible.fY / fScrollVal.fY + 1);
Mark(fMousePos.fX, size.fY + 1);
}
break;
default:
break;
}
}
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGView::HandleButton(Event_t *event)
{
// Handle mouse button event in text editor.
if (event->fWindow != fCanvas->GetId()) {
return kFALSE;
}
if (event->fCode == kButton1) {
if (event->fType == kButtonPress) {
if (fIsMarked) {
if (event->fState & kKeyShiftMask) {
fIsMarking = kTRUE;
TGView::HandleMotion(event);
return kTRUE;
}
fIsMarked = kFALSE;
UnMark();
}
fIsMarked = kTRUE;
fIsMarking = kTRUE;
fMousePos.fY = ToObjYCoord(fVisible.fY + event->fY);
fMousePos.fX = ToObjXCoord(fVisible.fX + event->fX, fMousePos.fY);
fMarkedStart.fX = fMarkedEnd.fX = fMousePos.fX;
fMarkedStart.fY = fMarkedEnd.fY = fMousePos.fY;
} else {
fScrolling = -1;
if ((fMarkedStart.fX == fMarkedEnd.fX) &&
(fMarkedStart.fY == fMarkedEnd.fY)) {
fIsMarked = kFALSE;
SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_ISMARKED),
fWidgetId, kFALSE);
Marked(kFALSE);
} else {
SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_ISMARKED),
fWidgetId, kTRUE);
Marked(kTRUE);
}
fIsMarking = kFALSE;
}
} else if (event->fCode == kButton4) {
// move three lines up
if (fVisible.fY > 0) {
SetVsbPosition(fVisible.fY / fScrollVal.fY - 3);
//Mark(fMousePos.fX, fMarkedStart.fY - 3);
}
} else if (event->fCode == kButton5) {
// move three lines down
if ((Int_t)fCanvas->GetHeight() < ToScrYCoord(ReturnLineCount())) {
TGLongPosition size;
size.fY = ToObjYCoord(fVisible.fY + fCanvas->GetHeight()) - 1;
SetVsbPosition(fVisible.fY / fScrollVal.fY + 3);
//Mark(fMousePos.fX, size.fY + 3);
}
} else if (event->fType == kButtonPress) {
if (event->fCode == kButton2) {
SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_CLICK2),
fWidgetId, (event->fYRoot << 16) | event->fXRoot);
} else if (event->fCode == kButton3) {
SendMessage(fMsgWindow, MK_MSG(kC_TEXTVIEW, kTXT_CLICK3),
fWidgetId, (event->fYRoot << 16) | event->fXRoot);
}
}
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGView::HandleDoubleClick(Event_t *event)
{
// handle double click
if (event->fWindow != fCanvas->GetId()) {
return kFALSE;
}
return kFALSE;
}
//______________________________________________________________________________
Bool_t TGView::HandleMotion(Event_t *event)
{
// Handle mouse motion event in the text editor widget.
if ((ToObjYCoord(fVisible.fY+event->fY) == fMousePos.fY) &&
(ToObjXCoord(fVisible.fX+event->fX, ToObjYCoord(fVisible.fY+event->fY)) == fMousePos.fX))
return kTRUE;
if (fScrolling != -1) {
return kTRUE;
}
fMousePos.fY = ToObjYCoord(fVisible.fY+event->fY);
if (fMousePos.fY >= ReturnLineCount())
fMousePos.fY = ReturnLineCount()-1;
fMousePos.fX = ToObjXCoord(fVisible.fX+event->fX, fMousePos.fY);
if (fMousePos.fX > ReturnLineLength(fMousePos.fY))
fMousePos.fX = ReturnLineLength(fMousePos.fY);
if (event->fWindow != fCanvas->GetId())
return kTRUE;
if (!fIsMarked || !fIsMarking)
return kTRUE;
if (event->fX < 0)
return kTRUE;
if (event->fX >= (Int_t)fCanvas->GetWidth())
return kTRUE;
if (event->fY < 0)
return kTRUE;
if (event->fY >= (Int_t)fCanvas->GetHeight())
return kTRUE;
Mark(fMousePos.fX, fMousePos.fY);
return kTRUE;
}
//______________________________________________________________________________
Bool_t TGView::ProcessMessage(Long_t msg, Long_t parm1, Long_t)
{
// Process scrollbar messages.
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()
{
// Layout the components of view.
HLayout();
VLayout();
}
//______________________________________________________________________________
void TGView::HLayout()
{
// Horizontal layout of widgets (canvas, scrollbar).
if (!fHsb) return;
Int_t tcw, tch;
Long_t cols;
tch = fHeight - (fBorderWidth << 1) - fYMargin-1;
tcw = fWidth - (fBorderWidth << 1) - fXMargin-1;
if (fVsb && fVsb->IsMapped()) {
tcw -= fVsb->GetDefaultWidth();
if (tcw < 0) tcw = 0;
}
fCanvas->SetHeight(tch);
fCanvas->SetWidth(tcw);
cols = ReturnLongestLineWidth();
if (cols <= tcw) {
if (fHsb && fHsb->IsMapped()) {
SetVisibleStart(0, kHorizontal);
fHsb->UnmapWindow();
VLayout();
}
fCanvas->MoveResize(fBorderWidth + fXMargin, fBorderWidth + fYMargin, tcw, tch);
} else {
if (fHsb) {
tch -= fHsb->GetDefaultHeight();
if (tch < 0) tch = 0;
fHsb->MoveResize(fBorderWidth, fHeight - fHsb->GetDefaultHeight()-fBorderWidth,
tcw+1+fBorderWidth, fHsb->GetDefaultHeight());
fHsb->MapWindow();
fHsb->SetRange(Int_t(cols/fScrollVal.fX), Int_t(tcw/fScrollVal.fX));
}
fCanvas->MoveResize(fBorderWidth + fXMargin, fBorderWidth + fYMargin, tcw, tch);
}
}
//______________________________________________________________________________
void TGView::VLayout()
{
// Vertical layout of widgets (canvas, scrollbar).
Int_t tcw, tch;
Long_t lines;
tch = fHeight - (fBorderWidth << 1) - fYMargin-1;
tcw = fWidth - (fBorderWidth << 1) - fXMargin-1;
if (fHsb && fHsb->IsMapped()) {
tch -= fHsb->GetDefaultHeight();
if (tch < 0) tch = 0;
}
fCanvas->SetHeight(tch);
fCanvas->SetWidth(tcw);
lines = ReturnHeighestColHeight();
if (lines <= tch) {
if (fVsb && fVsb->IsMapped()) {
SetVisibleStart(0, kVertical);
fVsb->UnmapWindow();
HLayout();
}
fCanvas->MoveResize(fBorderWidth + fXMargin, fBorderWidth + fYMargin, tcw, tch);
} else {
if (fVsb) {
tcw -= fVsb->GetDefaultWidth();
if (tcw < 0) tcw = 0;
fVsb->MoveResize(fWidth - fVsb->GetDefaultWidth() - fBorderWidth, fBorderWidth,
fVsb->GetDefaultWidth(), tch+1+fBorderWidth);
fVsb->MapWindow();
fVsb->SetRange(Int_t(lines/fScrollVal.fY), Int_t(tch/fScrollVal.fY));
}
fCanvas->MoveResize(fBorderWidth + fXMargin, fBorderWidth + fYMargin, tcw, tch);
}
}
//______________________________________________________________________________
void TGView::SetSBRange(Int_t direction)
{
// Set the range for the kVertical or kHorizontal scrollbar.
if (direction == kVertical) {
if (!fVsb)
return;
if (ReturnHeighestColHeight() <= (Int_t)fCanvas->GetHeight()) {
if (fVsb->IsMapped())
VLayout();
else
return;
}
if (!fVsb->IsMapped())
VLayout();
fVsb->SetRange(Int_t(ReturnHeighestColHeight()/fScrollVal.fY),
Int_t(fCanvas->GetHeight()/fScrollVal.fY));
} else {
if (!fHsb)
return;
if (ReturnLongestLineWidth() <= (Int_t)fCanvas->GetWidth()) {
if (fHsb->IsMapped())
HLayout();
else
return;
}
if (!fHsb->IsMapped())
HLayout();
fHsb->SetRange(Int_t(ReturnLongestLineWidth()/fScrollVal.fX),
Int_t(fCanvas->GetWidth()/fScrollVal.fX));
}
}
//______________________________________________________________________________
void TGView::SetHsbPosition(Long_t newPos)
{
// Set position of horizontal scrollbar.
if (fHsb && fHsb->IsMapped())
fHsb->SetPosition(Int_t(newPos));
else
SetVisibleStart(Int_t(newPos * fScrollVal.fX), kHorizontal);
}
//______________________________________________________________________________
void TGView::SetVsbPosition(Long_t newPos)
{
// Set position of vertical scrollbar.
if (fVsb && fVsb->IsMapped())
fVsb->SetPosition(Int_t(newPos));
else
SetVisibleStart(Int_t(newPos * fScrollVal.fY), kVertical);
}
//______________________________________________________________________________
void TGView::ShowBottom()
{
// Show bottom of the page.
Int_t tch;
Long_t lines, newPos;
tch = fCanvas->GetHeight();
lines = ReturnHeighestColHeight();
if (lines > tch) {
newPos = lines / fScrollVal.fY;
SetVsbPosition(newPos);
}
Layout();
}
//______________________________________________________________________________
void TGView::ShowTop()
{
// Show top of the page.
SetVsbPosition(0);
Layout();
}
//______________________________________________________________________________
void TGView::DrawBorder()
{
// Draw the border of the text edit widget.
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::ScrollCanvas(Int_t new_top, Int_t direction)
{
// Scroll the canvas to new_top in the kVertical or kHorizontal direction.
Point_t points[4];
Int_t xsrc, ysrc, xdest, ydest, cpyheight, cpywidth;
if (direction == kVertical) {
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 ; // -1;
} 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; // +1;
points[3].fY = points[2].fY = fCanvas->GetHeight();
}
fVisible.fY = new_top;
if (fVisible.fY < 0)
fVisible.fY = 0;
} else {
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 ; // -1;
} 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; // +1;
points[1].fX = points[2].fX = fCanvas->GetWidth();
}
fVisible.fX = new_top;
if (fVisible.fX < 0)
fVisible.fX = 0;
}
// Copy the scrolled region to its new position
gVirtualX->CopyArea(fCanvas->GetId(), fCanvas->GetId(), fWhiteGC(),
xsrc, ysrc, fCanvas->GetWidth()-cpywidth,
fCanvas->GetHeight()-cpyheight, xdest, ydest);
// Clear the remaining area of any old text
gVirtualX->ClearArea(fCanvas->GetId(), points[0].fX, points[0].fY,
points[2].fX - points[0].fX,
points[2].fY - points[0].fY);
DrawRegion(points[0].fX, points[0].fY,
points[2].fX - points[0].fX, points[2].fY - points[0].fY);
}
ROOT page - Class index - Class Hierarchy - Top of the page
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.