#include "TGPicture.h"
#include "TGListBox.h"
#include "TGScrollBar.h"
#include "TGResourcePool.h"
#include "TSystem.h"
#include "Riostream.h"
#include "TMath.h"
#include <stdlib.h>
const TGFont *TGTextLBEntry::fgDefaultFont = 0;
TGGC *TGTextLBEntry::fgDefaultGC = 0;
ClassImp(TGLBEntry)
ClassImp(TGTextLBEntry)
ClassImp(TGLineLBEntry)
ClassImp(TGLBContainer)
ClassImp(TGListBox)
TGLBEntry::TGLBEntry(const TGWindow *p, Int_t id, UInt_t options, Pixel_t back) :
TGFrame(p, 10, 10, options | kOwnBackground, back)
{
fActive = kFALSE;
fEntryId = id;
fBkcolor = back;
fEditDisabled = kEditDisable | kEditDisableGrab;
SetWindowName();
}
void TGLBEntry::Activate(Bool_t a)
{
if (fActive == a) return;
fActive = a;
DoRedraw();
}
void TGLBEntry::Toggle()
{
fActive = !fActive;
DoRedraw();
}
TGTextLBEntry::TGTextLBEntry(const TGWindow *p, TGString *s, Int_t id,
GContext_t norm, FontStruct_t font, UInt_t options, ULong_t back) :
TGLBEntry(p, id, options, back)
{
fText = s;
fTextChanged = kTRUE;
fFontStruct = font;
fNormGC = norm;
int max_ascent, max_descent;
if (fText) fTWidth = gVirtualX->TextWidth(fFontStruct, fText->GetString(), fText->GetLength());
gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
fTHeight = max_ascent + max_descent;
Resize(fTWidth, fTHeight + 1);
fEditDisabled = kEditDisable | kEditDisableGrab;
SetWindowName();
}
TGTextLBEntry::~TGTextLBEntry()
{
if (fText) delete fText;
}
void TGTextLBEntry::DrawCopy(Handle_t id, Int_t x, Int_t y)
{
int max_ascent, max_descent;
y += (fHeight - fTHeight) >> 1;
gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
if (fActive) {
gVirtualX->SetForeground(fNormGC, fgDefaultSelectedBackground );
gVirtualX->FillRectangle(id,fNormGC, x, y, fWidth, fHeight);
gVirtualX->SetForeground(fNormGC, fClient->GetResourcePool()->GetSelectedFgndColor());
fText->Draw(id, fNormGC, x + 3, y + max_ascent);
} else {
gVirtualX->SetForeground(fNormGC, fBkcolor);
gVirtualX->FillRectangle(id, fNormGC, x, y, fWidth, fHeight);
gVirtualX->SetForeground(fNormGC, GetForeground());
fText->Draw(id, fNormGC, x + 3, y + max_ascent);
}
}
void TGTextLBEntry::DoRedraw()
{
if (fId) DrawCopy(fId, 0, 0);
}
void TGTextLBEntry::SetText(TGString *new_text)
{
if (fText) delete fText;
fText = new_text;
fTextChanged = kTRUE;
int max_ascent, max_descent;
fTWidth = gVirtualX->TextWidth(fFontStruct, fText->GetString(), fText->GetLength());
gVirtualX->GetFontProperties(fFontStruct, max_ascent, max_descent);
fTHeight = max_ascent + max_descent;
Resize(fTWidth + 3, fTHeight + 1);
DoRedraw();
}
FontStruct_t TGTextLBEntry::GetDefaultFontStruct()
{
if (!fgDefaultFont)
fgDefaultFont = gClient->GetResourcePool()->GetDefaultFont();
return fgDefaultFont->GetFontStruct();
}
const TGGC &TGTextLBEntry::GetDefaultGC()
{
if (!fgDefaultGC)
fgDefaultGC = new TGGC(*gClient->GetResourcePool()->GetFrameGC());
return *fgDefaultGC;
}
TGLineLBEntry::TGLineLBEntry(const TGWindow *p, Int_t id, const char *str,
UInt_t w, Style_t style, UInt_t options, ULong_t back) :
TGTextLBEntry(p, new TGString(str), id, GetDefaultGC()(),
GetDefaultFontStruct(), options, back)
{
GCValues_t gcv;
gcv.fMask = kGCLineStyle | kGCLineWidth | kGCFillStyle | kGCDashList;
fLineWidth = gcv.fLineWidth = w;
gcv.fFillStyle = kFillSolid;
gcv.fDashLen = 2;
gcv.fDashOffset = 0;
memcpy(gcv.fDashes, "\x5\x5", 3);
gcv.fLineStyle = kLineOnOffDash;
fLineGC = fClient->GetGC(&gcv, kTRUE);
SetLineStyle(style);
int max_ascent, max_descent;
fTWidth = gVirtualX->TextWidth(GetDefaultFontStruct(), "8", 1);
fTWidth += 15;
gVirtualX->GetFontProperties(GetDefaultFontStruct(),
max_ascent, max_descent);
fTHeight = max_ascent + max_descent;
Resize(fTWidth, fTHeight + 1);
fEditDisabled = kEditDisable | kEditDisableGrab;
SetWindowName();
}
TGLineLBEntry::~TGLineLBEntry()
{
fClient->FreeGC(fLineGC);
}
void TGLineLBEntry::Update(TGLBEntry *e)
{
TGTextLBEntry::Update(e);
fClient->FreeGC(fLineGC);
fLineGC = ((TGLineLBEntry *)e)->GetLineGC();
fLineGC->AddReference();
}
void TGLineLBEntry::SetLineStyle(Style_t linestyle)
{
static const char* dashed = "\x3\x3";
static const char* dotted= "\x1\x2";
static const char* dasheddotted = "\x3\x4\x1\x4";
static const char* ls05 = "\x5\x3\x1\x3";
static const char* ls06 = "\x5\x3\x1\x3\x1\x3\x1\x3";
static const char* ls07 = "\x5\x5";
static const char* ls08 = "\x5\x3\x1\x3\x1\x3";
static const char* ls09 = "\x20\x5";
static const char* ls10 = "\x20\x10\x1\x10";
if (linestyle <= 1) {
fLineGC->SetLineStyle(kLineSolid);
} else {
switch (linestyle) {
case 2:
fLineGC->SetDashList(dashed, 2);
break;
case 3:
fLineGC->SetDashList(dotted, 2);
break;
case 4:
fLineGC->SetDashList(dasheddotted, 4);
break;
case 5:
fLineGC->SetDashList(ls05, 4);
break;
case 6:
fLineGC->SetDashList(ls06, 8);
break;
case 7:
fLineGC->SetDashList(ls07, 2);
break;
case 8:
fLineGC->SetDashList(ls08, 6);
break;
case 9:
fLineGC->SetDashList(ls09, 2);
break;
case 10:
fLineGC->SetDashList(ls10, 4);
break;
}
}
fLineGC->SetCapStyle(0);
fLineStyle = linestyle;
}
void TGLineLBEntry::SetLineWidth(Int_t width)
{
fLineWidth = width;
fLineGC->SetLineWidth(fLineWidth);
}
void TGLineLBEntry::DrawCopy(Handle_t id, Int_t x, Int_t y)
{
TGTextLBEntry::DrawCopy(id, x, y);
if (!strcmp(TGTextLBEntry::GetTitle(),"None")) return;
if (fActive) {
gVirtualX->SetForeground(fLineGC->GetGC(),
fClient->GetResourcePool()->GetSelectedFgndColor());
} else {
gVirtualX->SetForeground(fLineGC->GetGC(),
fClient->GetResourcePool()->GetBlackColor());
}
gVirtualX->DrawLine(id, fLineGC->GetGC(), x + fTWidth + 5, y + fHeight/2,
x + fWidth - 5, y + fHeight/2);
}
void TGLineLBEntry::DoRedraw()
{
if (fId) DrawCopy(fId, 0, 0);
}
TGIconLBEntry::TGIconLBEntry(const TGWindow *p, Int_t id, const char *str,
const TGPicture *pic,
UInt_t , Style_t , UInt_t options, ULong_t back) :
TGTextLBEntry(p, new TGString(str), id, GetDefaultGC()(),
GetDefaultFontStruct(), options, back)
{
int max_ascent, max_descent;
fPicture = pic;
if (fPicture) {
fTWidth += fPicture->GetWidth() + 4;
((TGPicture *)pic)->AddReference();
}
else
fTWidth += 20;
gVirtualX->GetFontProperties(GetDefaultFontStruct(),
max_ascent, max_descent);
fTHeight = max_ascent + max_descent;
if (fPicture && fPicture->GetHeight() > fTHeight)
fTHeight = fPicture->GetHeight();
Resize(fTWidth, fTHeight + 1);
fEditDisabled = kEditDisable | kEditDisableGrab;
SetWindowName();
}
TGIconLBEntry::~TGIconLBEntry()
{
fClient->FreePicture(fPicture);
}
void TGIconLBEntry::Update(TGLBEntry *e)
{
TGTextLBEntry::Update(e);
}
void TGIconLBEntry::DrawCopy(Handle_t id, Int_t x, Int_t y)
{
Int_t off_x = 0;
if (fPicture) {
fPicture->Draw(id, fNormGC, x + 2, y);
off_x = fPicture->GetWidth() + 4;
}
TGTextLBEntry::DrawCopy(id, x + off_x, y);
}
void TGIconLBEntry::DoRedraw()
{
if (fId) DrawCopy(fId, 0, 0);
}
void TGIconLBEntry::SetPicture(const TGPicture *pic)
{
fClient->FreePicture(fPicture);
((TGPicture *)pic)->AddReference();
fPicture = pic;
}
class TGLBFrameElement : public TGFrameElement {
public:
TGLBFrameElement(TGFrame *f, TGLayoutHints *l) : TGFrameElement(f, l) {}
virtual ~TGLBFrameElement() {}
Bool_t IsSortable() const { return kTRUE; }
Int_t Compare(const TObject *obj) const {
if (!fFrame->InheritsFrom(TGTextLBEntry::Class())) {
return 0;
}
TGTextLBEntry *f1 = (TGTextLBEntry*)fFrame;
TGTextLBEntry *f2 = (TGTextLBEntry *) ((TGFrameElement *) obj)->fFrame;
double d1, d2;
const char *t1 = f1->GetText()->Data();
const char *t2 = f2->GetText()->Data();
if ((d1 = atof(t1)) && (d2 = atof(t2))) {
return (d1 > d2);
} else {
return strcmp(t1, t2);
}
return 0;
}
};
TGLBContainer::TGLBContainer(const TGWindow *p, UInt_t w, UInt_t h,
UInt_t options, ULong_t back) :
TGContainer(p, w, h, options, back)
{
fLastActive = 0;
fMsgWindow = p;
fMultiSelect = kFALSE;
fChangeStatus = kFALSE;
SetWindowName();
fEditDisabled = kEditDisableGrab | kEditDisableBtnEnable | kEditDisableKeyEnable;
}
TGLBContainer::~TGLBContainer()
{
Cleanup();
}
void TGLBContainer::Layout()
{
TGContainer::Layout();
TGFrame::Resize(fListBox->GetViewPort()->GetWidth(), fHeight);
}
void TGLBContainer::DoRedraw()
{
return TGContainer::DoRedraw();
}
void TGLBContainer::AddEntry(TGLBEntry *lbe, TGLayoutHints *lhints)
{
TGLBFrameElement *nw = new TGLBFrameElement(lbe, lhints ? lhints : fgDefaultHints);
fList->Add(nw);
ClearViewPort();
}
void TGLBContainer::InsertEntry(TGLBEntry *lbe, TGLayoutHints *lhints, Int_t afterID)
{
TGLBEntry *e;
TGFrameElement *el, *nw;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
e = (TGLBEntry *) el->fFrame;
if (e->EntryId() == afterID) break;
}
if (!el && afterID != -1) {
nw = new TGLBFrameElement(lbe, lhints ? lhints : fgDefaultHints);
fList->Add(nw);
} else {
nw = new TGLBFrameElement(lbe, lhints);
nw->fFrame = lbe;
nw->fLayout = lhints;
nw->fState = 1;
if (afterID == -1)
fList->AddFirst(nw);
else
fList->AddAfter(el, nw);
}
ClearViewPort();
}
void TGLBContainer::AddEntrySort(TGLBEntry *lbe, TGLayoutHints *lhints)
{
TGLBEntry *e;
TGFrameElement *el, *nw;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
e = (TGLBEntry *) el->fFrame;
if (e->EntryId() > lbe->EntryId()) break;
}
if (!el) {
nw = new TGLBFrameElement(lbe, lhints ? lhints : fgDefaultHints);
fList->Add(nw);
} else {
nw = new TGLBFrameElement(lbe, lhints);
nw->fFrame = lbe;
nw->fLayout = lhints;
nw->fState = 1;
fList->AddBefore(el, nw);
}
ClearViewPort();
}
void TGLBContainer::RemoveEntry(Int_t id)
{
TGLBEntry *e;
TGFrameElement *el;
TGLayoutHints *l;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
e = (TGLBEntry *) el->fFrame;
l = el->fLayout;
if (e->EntryId() == id) {
if (fLastActive == e) fLastActive = 0;
e->DestroyWindow();
fList->Remove(el);
delete el;
delete e;
delete l;
break;
}
}
ClearViewPort();
}
void TGLBContainer::RemoveEntries(Int_t from_ID, Int_t to_ID)
{
TGLBEntry *e;
TGFrameElement *el;
TGLayoutHints *l;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
e = (TGLBEntry *) el->fFrame;
l = el->fLayout;
if ((e->EntryId() >= from_ID) && (e->EntryId() <= to_ID)) {
if (fLastActive == e) fLastActive = 0;
e->DestroyWindow();
fList->Remove(el);
delete el;
delete e;
delete l;
}
}
ClearViewPort();
}
void TGLBContainer::RemoveAll()
{
TGLBEntry *e;
TGFrameElement *el;
TGLayoutHints *l;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
e = (TGLBEntry *) el->fFrame;
l = el->fLayout;
if (fLastActive == e) fLastActive = 0;
e->DestroyWindow();
fList->Remove(el);
delete el;
delete e;
delete l;
}
ClearViewPort();
}
TGLBEntry *TGLBContainer::Select(Int_t id)
{
return Select(id, kTRUE);
}
TGLBEntry *TGLBContainer::Select(Int_t id, Bool_t sel)
{
TGLBEntry *f;
TGFrameElement *el;
if (!fMultiSelect && fLastActive) {
fLastActive->Activate(kFALSE);
fLastActive = 0;
}
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
if (f->EntryId() == id) {
f->Activate(sel);
if (fMultiSelect == kFALSE && sel == kTRUE) {
fLastActive = f;
fLastActiveEl = el;
}
ClearViewPort();
return f;
}
}
return 0;
}
Int_t TGLBContainer::GetSelected() const
{
if (fLastActive == 0) return -1;
return fLastActive->EntryId();
}
Bool_t TGLBContainer::GetSelection(Int_t id)
{
TGLBEntry *f;
TGFrameElement *el;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
if (f->EntryId() == id)
return f->IsActive();
}
return kFALSE;
}
void TGLBContainer::GetSelectedEntries(TList *selected)
{
TGLBEntry *f;
TGFrameElement *el;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
if (f->IsActive()) {
selected->Add(f);
}
}
}
void TGLBContainer::SetMultipleSelections(Bool_t multi)
{
TGFrameElement *el;
fMultiSelect = multi;
if (!fMultiSelect) {
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
((TGLBEntry *)(el->fFrame))->Activate(kFALSE);
}
}
fLastActive = 0;
fLastActiveEl = 0;
ClearViewPort();
}
TGVScrollBar *TGLBContainer::GetVScrollbar() const
{
return fListBox ? fListBox->GetVScrollbar() : 0;
}
void TGLBContainer::SetVsbPosition(Int_t newPos)
{
TGVScrollBar *vb = GetVScrollbar();
if (vb && vb->IsMapped()) {
vb->SetPosition(newPos);
}
}
Bool_t TGLBContainer::HandleButton(Event_t *event)
{
int xf0, yf0, xff, yff;
TGLBEntry *f;
TGFrameElement *el;
TGLBEntry *last = fLastActive;
TGPosition pos = GetPagePosition();
Int_t x = pos.fX + event->fX;
Int_t y = pos.fY + event->fY;
Bool_t activate = kFALSE;
if (fClient->IsEditable() && (event->fCode == kButton3)) {
return kTRUE;
}
TGVScrollBar *vb = GetVScrollbar();
if ((event->fCode == kButton4) && vb){
Int_t newpos = vb->GetPosition() - 1;
if (newpos < 0) newpos = 0;
vb->SetPosition(newpos);
ClearViewPort();
return kTRUE;
}
if ((event->fCode == kButton5) && vb) {
Int_t newpos = vb->GetPosition() + 1;
vb->SetPosition(newpos);
ClearViewPort();
return kTRUE;
}
gVirtualX->SetInputFocus(fId);
if (fMultiSelect) {
if (event->fType == kButtonPress) {
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
xf0 = f->GetX();
yf0 = f->GetY();
xff = xf0 + f->GetWidth();
yff = yf0 + f->GetHeight();
activate = fMapSubwindows ? (f->GetId() == (Window_t)event->fUser[0]) :
(x > xf0) && (x < xff) && (y > yf0) && (y < yff);
if (activate) {
fLastActive = f;
fLastActiveEl = el;
f->Toggle();
fChangeStatus = f->IsActive() ? 1 : 0;
SendMessage(fMsgWindow, MK_MSG(kC_CONTAINER, kCT_ITEMCLICK),
f->EntryId(), 0);
break;
}
}
} else {
fChangeStatus = -1;
}
} else {
if (event->fType == kButtonPress) {
if (fLastActive) {
fLastActive->Activate(kFALSE);
fLastActive = 0;
}
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
xf0 = f->GetX();
yf0 = f->GetY();
xff = xf0 + f->GetWidth();
yff = yf0 + f->GetHeight();
activate = fMapSubwindows ? (f->GetId() == (Window_t)event->fUser[0]) :
(x > xf0) && (x < xff) && (y > yf0) && (y < yff) && !f->IsActive();
if (activate) {
f->Activate(kTRUE);
fLastActive = f;
fLastActiveEl = el;
} else {
f->Activate(kFALSE);
}
}
} else {
if (fLastActive) {
f = fLastActive;
SendMessage(fMsgWindow, MK_MSG(kC_CONTAINER, kCT_ITEMCLICK),
f->EntryId(), 0);
}
}
}
if (event->fType == kButtonRelease) {
fScrolling = kFALSE;
gSystem->RemoveTimer(fScrollTimer);
}
if (fChangeStatus || (last != fLastActive))
ClearViewPort();
if (fListBox->GetParent()->InheritsFrom("TGComboBoxPopup"))
fListBox->GetContainer()->RemoveInput(kPointerMotionMask);
return kTRUE;
}
Bool_t TGLBContainer::HandleDoubleClick(Event_t *ev)
{
if (!fMultiSelect) {
if (fLastActive) {
TGLBEntry *f = fLastActive;
SendMessage(fMsgWindow, MK_MSG(kC_CONTAINER, kCT_ITEMDBLCLICK),
f->EntryId(), 0);
DoubleClicked(f, ev->fCode);
DoubleClicked(f, ev->fCode, ev->fXRoot, ev->fYRoot);
}
}
return kTRUE;
}
Bool_t TGLBContainer::HandleMotion(Event_t *event)
{
int xf0, yf0, xff, yff;
static Long64_t was = gSystem->Now();
Long64_t now = gSystem->Now();
if ((now-was) < 50) return kFALSE;
was = now;
TGLBEntry *f;
TGFrameElement *el;
TGPosition pos = GetPagePosition();
TGDimension dim = GetPageDimension();
Int_t x = pos.fX + event->fX;
Int_t y = pos.fY + event->fY;
Bool_t activate = kFALSE;
TGLBEntry *last = fLastActive;
if (fMultiSelect) {
if ((event->fY < 10) || (event->fY > Int_t(dim.fHeight) - 10)) {
if (!fScrolling) {
fScrollTimer->Reset();
gSystem->AddTimer(fScrollTimer);
}
fScrolling = kTRUE;
}
else if (fChangeStatus >= 0) {
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
xf0 = f->GetX();
yf0 = f->GetY();
xff = xf0 + f->GetWidth();
yff = yf0 + f->GetHeight();
activate = fMapSubwindows ? (f->GetId() == (Window_t)event->fUser[0]) :
(x > xf0) && (x < xff) && (y > yf0) && (y < yff);
if (activate) {
if (fChangeStatus != (f->IsActive() ? 1 : 0)) {
f->Toggle();
ClearViewPort();
SendMessage(fMsgWindow, MK_MSG(kC_CONTAINER, kCT_ITEMCLICK),
f->EntryId(), 0);
}
break;
}
}
}
} else if (fListBox->GetParent()->InheritsFrom("TGComboBoxPopup")) {
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
xf0 = f->GetX();
yf0 = f->GetY();
xff = xf0 + f->GetWidth();
yff = yf0 + f->GetHeight();
activate = fMapSubwindows ? (f->GetId() == (Window_t)event->fUser[0]) :
(x > xf0) && (x < xff) && (y > yf0) && (y < yff) && !f->IsActive();
if (activate) {
f->Activate(kTRUE);
fLastActive = f;
fLastActiveEl = el;
} else {
f->Activate(kFALSE);
}
if (last != fLastActive) {
ClearViewPort();
}
}
}
return kTRUE;
}
void TGLBContainer::OnAutoScroll()
{
TGFrameElement* el = 0;
TGLBEntry *f = 0;
Int_t yf0, yff;
Bool_t changed = kFALSE;
TGDimension dim = GetPageDimension();
TGPosition pos = GetPagePosition();
Window_t dum1, dum2;
Event_t ev;
ev.fType = kButtonPress;
Int_t x, y;
gVirtualX->QueryPointer(fId,dum1,dum2,ev.fXRoot,ev.fYRoot,x,y,ev.fState);
TGVScrollBar *vb = GetVScrollbar();
if (y > 0 && y < 10) {
Int_t newpos = vb->GetPosition() - 1;
if (newpos < 0) newpos = 0;
vb->SetPosition(newpos);
changed = kTRUE;
}
else if (y > (Int_t)dim.fHeight - 10 && y < (Int_t)dim.fHeight) {
Int_t newpos = vb->GetPosition() + 1;
vb->SetPosition(newpos);
changed = kTRUE;
}
if (changed && fChangeStatus >= 0) {
pos = GetPagePosition();
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
yf0 = f->GetY();
yff = yf0 + f->GetHeight();
if ((y + pos.fY > yf0) && (y + pos.fY < yff)) {
if (fChangeStatus != (f->IsActive() ? 1 : 0)) {
f->Toggle();
ClearViewPort();
SendMessage(fMsgWindow, MK_MSG(kC_CONTAINER, kCT_ITEMCLICK),
f->EntryId(), 0);
}
break;
}
}
}
}
void TGLBContainer::ActivateItem(TGFrameElement *el)
{
TGContainer::ActivateItem(el);
fLastActive = (TGLBEntry *)el->fFrame;
}
Int_t TGLBContainer::GetPos(Int_t id)
{
Int_t pos = 0;
TGLBEntry *f;
TGFrameElement *el;
TIter next(fList);
while ((el = (TGFrameElement *) next())) {
f = (TGLBEntry *) el->fFrame;
if (f->EntryId() == id)
return pos;
pos++;
}
return -1;
}
TGListBox::TGListBox(const TGWindow *p, Int_t id,
UInt_t options, ULong_t back) :
TGCompositeFrame(p, 10, 10, options, back)
{
fMsgWindow = p;
fWidgetId = id;
fItemVsize = 1;
fIntegralHeight = kTRUE;
InitListBox();
}
TGListBox::~TGListBox()
{
if (!MustCleanup()) {
delete fVScrollbar;
delete fVport;
delete fLbc;
}
}
void TGListBox::InitListBox()
{
fVport = new TGViewPort(this, 6, 6, kChildFrame | kOwnBackground, fgWhitePixel);
fVScrollbar = new TGVScrollBar(this, kDefaultScrollBarWidth, 6);
fLbc = new TGLBContainer(fVport, 10, 10, kVerticalFrame, fgWhitePixel);
fLbc->fViewPort = fVport;
fLbc->Associate(this);
fLbc->SetListBox(this);
SetContainer(fLbc);
AddFrame(fVport, 0);
AddFrame(fVScrollbar, 0);
fVScrollbar->Associate(this);
fVScrollbar->AddInput(kButtonPressMask | kButtonReleaseMask |
kPointerMotionMask);
fLbc->RemoveInput(kPointerMotionMask);
fLbc->AddInput(kButtonPressMask | kButtonReleaseMask | kButtonMotionMask);
fVport->SetEditDisabled(kEditDisable | kEditDisableGrab);
fVScrollbar->SetEditDisabled(kEditDisable | kEditDisableGrab | kEditDisableBtnEnable);
fLbc->SetEditDisabled(kEditDisableGrab | kEditDisableBtnEnable | kEditDisableKeyEnable);
fEditDisabled = kEditDisableLayout;
delete fLayoutManager;
fLayoutManager = 0;
}
void TGListBox::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:
TGCompositeFrame::DrawBorder();
break;
}
}
void TGListBox::AddEntry(TGString *s, Int_t id)
{
TGTextLBEntry *lbe;
TGLayoutHints *lhints;
lbe = new TGTextLBEntry(fLbc, s, id);
lhints = new TGLayoutHints(kLHintsExpandX | kLHintsTop);
fItemVsize = TMath::Max(fItemVsize, lbe->GetDefaultHeight());
fLbc->AddEntry(lbe, lhints);
}
void TGListBox::AddEntry(const char *s, Int_t id)
{
AddEntry(new TGString(s), id);
}
void TGListBox::AddEntry(TGLBEntry *lbe, TGLayoutHints *lhints)
{
fItemVsize = TMath::Max(fItemVsize, lbe->GetDefaultHeight());
fLbc->AddEntry(lbe, lhints);
}
void TGListBox::AddEntrySort(TGString *s, Int_t id)
{
TGTextLBEntry *lbe;
TGLayoutHints *lhints;
lbe = new TGTextLBEntry(fLbc, s, id);
lhints = new TGLayoutHints(kLHintsExpandX | kLHintsTop);
fItemVsize = TMath::Max(fItemVsize, lbe->GetDefaultHeight());
fLbc->AddEntrySort(lbe, lhints);
}
void TGListBox::AddEntrySort(const char *s, Int_t id)
{
AddEntrySort(new TGString(s), id);
}
void TGListBox::AddEntrySort(TGLBEntry *lbe, TGLayoutHints *lhints)
{
fItemVsize = TMath::Max(fItemVsize, lbe->GetDefaultHeight());
fLbc->AddEntrySort(lbe, lhints);
}
void TGListBox::InsertEntry(TGString *s, Int_t id, Int_t afterID)
{
TGTextLBEntry *lbe;
TGLayoutHints *lhints;
lbe = new TGTextLBEntry(fLbc, s, id);
lhints = new TGLayoutHints(kLHintsExpandX | kLHintsTop);
fItemVsize = TMath::Max(fItemVsize, lbe->GetDefaultHeight());
fLbc->InsertEntry(lbe, lhints, afterID);
}
void TGListBox::InsertEntry(const char *s, Int_t id, Int_t afterID)
{
InsertEntry(new TGString(s), id, afterID);
}
void TGListBox::NewEntry(const char *s)
{
Int_t selected = fLbc->GetSelected();
if ((selected < 0) || (selected == GetNumberOfEntries())) {
AddEntry(s, GetNumberOfEntries()+1);
} else {
InsertEntry(s, GetNumberOfEntries()+1, selected);
}
Layout();
}
void TGListBox:: RemoveEntry(Int_t id)
{
if (id >= 0) {
fLbc->RemoveEntry(id);
Layout();
return;
}
if (!fLbc->GetMultipleSelections()) {
fLbc->RemoveEntry(fLbc->GetSelected());
Layout();
return;
}
TList li;
fLbc->GetSelectedEntries(&li);
TGLBEntry *e;
TIter next(&li);
while ((e = (TGLBEntry*)next())) {
fLbc->RemoveEntry(e->EntryId());
}
Layout();
}
void TGListBox::RemoveAll()
{
fLbc->RemoveAll();
Layout();
}
void TGListBox::RemoveEntries(Int_t from_ID, Int_t to_ID)
{
fLbc->RemoveEntries(from_ID, to_ID);
Layout();
}
void TGListBox::InsertEntry(TGLBEntry *lbe, TGLayoutHints *lhints, int afterID)
{
fItemVsize = TMath::Max(fItemVsize, lbe->GetDefaultHeight());
fLbc->InsertEntry(lbe, lhints, afterID);
}
TGLBEntry *TGListBox::GetEntry(Int_t id) const
{
TIter next(fLbc->GetList());
TGFrameElement *el;
while ((el = (TGFrameElement *)next())) {
TGLBEntry *lbe = (TGLBEntry *)el->fFrame;
if (lbe->EntryId() == id) return lbe;
}
return 0;
}
void TGListBox::SetTopEntry(Int_t id)
{
Int_t idPos;
idPos = fLbc->GetPos(id);
if (idPos < 0)
return;
Layout();
fVScrollbar->SetPosition(idPos);
}
void TGListBox::Resize(UInt_t w, UInt_t h)
{
if (fIntegralHeight)
h = TMath::Max(fItemVsize, ((h - (fBorderWidth << 1)) / fItemVsize) * fItemVsize)
+ (fBorderWidth << 1);
TGCompositeFrame::Resize(w, h);
DoRedraw();
}
void TGListBox::MoveResize(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
if (fIntegralHeight)
h = TMath::Max(fItemVsize, ((h - (fBorderWidth << 1)) / fItemVsize) * fItemVsize)
+ (fBorderWidth << 1);
TGCompositeFrame::MoveResize(x, y, w, h);
DoRedraw();
}
TGDimension TGListBox::GetDefaultSize() const
{
UInt_t h;
if (fIntegralHeight)
h = TMath::Max(fItemVsize, ((fHeight - (fBorderWidth << 1)) / fItemVsize) * fItemVsize)
+ (fBorderWidth << 1);
else
h = fHeight;
return TGDimension(fWidth, h);
}
void TGListBox::Layout()
{
TGFrame *container;
UInt_t cw, ch, tch;
Bool_t need_vsb;
need_vsb = kFALSE;
container = fVport->GetContainer();
cw = fWidth - (fBorderWidth << 1);
ch = fHeight - (fBorderWidth << 1);
container->SetWidth(cw);
container->SetHeight(ch);
if (container->GetDefaultHeight() > ch) {
need_vsb = kTRUE;
cw -= fVScrollbar->GetDefaultWidth();
if ((Int_t) cw < 0) {
Warning("Layout", "width would become too small, setting to 10");
cw = 10;
}
container->SetWidth(cw);
}
fVport->MoveResize(fBorderWidth, fBorderWidth, cw, ch);
container->Layout();
tch = TMath::Max(container->GetDefaultHeight(), ch);
container->SetHeight(0);
container->Resize(cw, tch);
if (need_vsb) {
fVScrollbar->MoveResize(cw+fBorderWidth, fBorderWidth, fVScrollbar->GetDefaultWidth(), ch);
fVScrollbar->MapWindow();
} else {
fVScrollbar->UnmapWindow();
fVScrollbar->SetPosition(0);
}
fVScrollbar->SetRange((Int_t)TMath::Ceil((Double_t)container->GetHeight()/(Double_t)fItemVsize),
fVport->GetHeight()/fItemVsize);
((TGContainer *)container)->ClearViewPort();
}
void TGListBox::SortByName(Bool_t ascend)
{
fLbc->GetList()->Sort(ascend);
Layout();
fLbc->ClearViewPort();
}
Int_t TGListBox::GetSelected() const
{
TGLBContainer *ct = (TGLBContainer *) fVport->GetContainer();
return ct->GetSelected();
}
void TGListBox::GetSelectedEntries(TList *selected)
{
fLbc->GetSelectedEntries(selected);
}
void TGListBox::ChangeBackground(Pixel_t back)
{
fBackground = back;
TIter next(fLbc->GetList());
TGFrameElement *el;
while ((el = (TGFrameElement *)next())) {
TGLBEntry *lbe = (TGLBEntry *)el->fFrame;
lbe->SetBackgroundColor(back);
}
fLbc->ClearViewPort();
}
Bool_t TGListBox::ProcessMessage(Long_t msg, Long_t parm1, Long_t)
{
switch (GET_MSG(msg)) {
case kC_VSCROLL:
switch (GET_SUBMSG(msg)) {
case kSB_SLIDERTRACK:
case kSB_SLIDERPOS:
fVport->SetVPos(Int_t(-parm1 * fItemVsize));
break;
}
break;
case kC_CONTAINER:
switch (GET_SUBMSG(msg)) {
case kCT_ITEMCLICK:
{
SendMessage(fMsgWindow, MK_MSG(kC_COMMAND, kCM_LISTBOX),
fWidgetId, parm1);
if (GetMultipleSelections()) SelectionChanged();
TGLBEntry *entry = GetSelectedEntry();
if (entry) {
if (entry->InheritsFrom(TGTextLBEntry::Class())) {
const char *text;
text = ((TGTextLBEntry*)entry)->GetText()->GetString();
Selected(text);
}
Selected(fWidgetId, (Int_t) parm1);
Selected((Int_t) parm1);
}
}
break;
case kCT_ITEMDBLCLICK:
{
TGLBEntry *entry = GetSelectedEntry();
if (entry) {
if (entry->InheritsFrom(TGTextLBEntry::Class())) {
const char *text;
text = ((TGTextLBEntry*)entry)->GetText()->GetString();
DoubleClicked(text);
}
DoubleClicked(fWidgetId, (Int_t) parm1);
DoubleClicked((Int_t) parm1);
}
}
break;
}
break;
default:
break;
}
return kTRUE;
}
void TGListBox::Selected(Int_t widgetId, Int_t id)
{
Long_t args[2];
args[0] = widgetId;
args[1] = id;
Emit("Selected(Int_t,Int_t)", args);
}
void TGListBox::DoubleClicked(Int_t widgetId, Int_t id)
{
Long_t args[2];
args[0] = widgetId;
args[1] = id;
Emit("DoubleClicked(Int_t,Int_t)", args);
}
TGLBEntry *TGListBox::FindEntry(const char *name) const
{
TList *list = fLbc->GetList();
TGFrameElement *el = (TGFrameElement *)list->First();
while (el) {
if (el->fFrame->GetTitle() == TString(name))
return (TGLBEntry *)el->fFrame;
el = (TGFrameElement *)list->After(el);
}
return 0;
}
void TGListBox::SavePrimitive(ostream &out, Option_t *option )
{
if (fBackground != GetWhitePixel()) SaveUserColor(out, option);
out << endl << " // list box" << endl;
out<<" TGListBox *";
out << GetName() << " = new TGListBox(" << fParent->GetName();
if (fBackground == GetWhitePixel()) {
if (GetOptions() == (kSunkenFrame | kDoubleBorder)) {
if (fWidgetId == -1) {
out <<");" << endl;
} else {
out << "," << fWidgetId << ");" << endl;
}
} else {
out << "," << fWidgetId << "," << GetOptionString() <<");" << endl;
}
} else {
out << "," << fWidgetId << "," << GetOptionString() << ",ucolor);" << endl;
}
if (option && strstr(option, "keep_names"))
out << " " << GetName() << "->SetName(\"" << GetName() << "\");" << endl;
if (!fLbc->GetList()) return;
TGFrameElement *el;
TIter next(fLbc->GetList());
while ((el = (TGFrameElement *) next())) {
out << " " << GetName() << "->AddEntry(";
el->fFrame->SavePrimitive(out, option);
out << ");"<< endl;
}
out << " " << GetName() << "->Resize(" << GetWidth() << "," << GetHeight()
<< ");" << endl;
}
void TGTextLBEntry::SavePrimitive(ostream &out, Option_t * )
{
TString content = GetText()->GetString();
content.ReplaceAll('\\', "\\\\");
content.ReplaceAll("\"", "\\\"");
char quote = '"';
out << quote << content << quote << "," << EntryId();
}