#include "TGFrame.h"
#include "TGLayout.h"
#include "TGMenu.h"
#include "TGSplitter.h"
#include "TGSplitFrame.h"
#include "TGInputDialog.h"
#include "TGResourcePool.h"
#include "TRootContextMenu.h"
#include "TClassMenuItem.h"
#include "TContextMenu.h"
#include "TString.h"
#include "TClass.h"
#include "TList.h"
#include "Riostream.h"
ClassImp(TGSplitTool)
ClassImp(TGSplitFrame)
TGSplitTool::TGSplitTool(const TGWindow *p, const TGFrame *f)
: TGCompositeFrame(p, 10, 10, kHorizontalFrame | kRaisedFrame | kFixedSize)
{
SetWindowAttributes_t attr;
attr.fMask = kWAOverrideRedirect | kWASaveUnder;
attr.fOverrideRedirect = kTRUE;
attr.fSaveUnder = kTRUE;
gVirtualX->ChangeWindowAttributes(fId, &attr);
SetBackgroundColor(fClient->GetResourcePool()->GetTipBgndColor());
fRectGC.SetFillStyle(kFillSolid);
fRectGC.SetForeground(0x99ff99);
TClass *cl = TClass::GetClass("TGSplitFrame");
cl->MakeCustomMenuList();
TList *ml = cl->GetMenuList();
((TClassMenuItem *)ml->At(1))->SetTitle("Cleanup Frame");
((TClassMenuItem *)ml->At(2))->SetTitle("Close and Collapse");
((TClassMenuItem *)ml->At(3))->SetTitle("Undock Frame");
((TClassMenuItem *)ml->At(4))->SetTitle("Dock Frame Back");
((TClassMenuItem *)ml->At(5))->SetTitle("Switch to Main");
((TClassMenuItem *)ml->At(6))->SetTitle("Horizontally Split...");
((TClassMenuItem *)ml->At(7))->SetTitle("Vertically Split...");
fContextMenu = new TContextMenu("SplitFrameContextMenu", "Actions");
fMap.SetOwner(kTRUE);
fMap.SetOwnerValue(kFALSE);
MapSubwindows();
if (f) Resize(f->GetWidth()/10, f->GetHeight()/10);
AddInput(kButtonPressMask | kButtonReleaseMask | kPointerMotionMask);
fWindow = f;
fX = fY = -1;
}
TGSplitTool::~TGSplitTool()
{
delete fContextMenu;
}
void TGSplitTool::AddRectangle(TGFrame *frame, Int_t x, Int_t y, Int_t w, Int_t h)
{
TGRectMap *rect = new TGRectMap(x, y, w, h);
fMap.Add(rect, frame);
}
void TGSplitTool::DoRedraw()
{
TGRectMap *rect;
TMapIter next(&fMap);
while ((rect = (TGRectMap*)next())) {
gVirtualX->FillRectangle(fId, GetBckgndGC()(), rect->fX,
rect->fY, rect->fW, rect->fH);
gVirtualX->DrawRectangle(fId, GetBlackGC()(), rect->fX, rect->fY,
rect->fW, rect->fH);
}
DrawBorder();
}
void TGSplitTool::DrawBorder()
{
gVirtualX->DrawLine(fId, GetShadowGC()(), 0, 0, fWidth-2, 0);
gVirtualX->DrawLine(fId, GetShadowGC()(), 0, 0, 0, fHeight-2);
gVirtualX->DrawLine(fId, GetBlackGC()(), 0, fHeight-1, fWidth-1, fHeight-1);
gVirtualX->DrawLine(fId, GetBlackGC()(), fWidth-1, fHeight-1, fWidth-1, 0);
}
Bool_t TGSplitTool::HandleButton(Event_t *event)
{
if (event->fType != kButtonPress)
return kTRUE;
Int_t px = 0, py = 0;
Window_t wtarget;
TGRectMap *rect;
TGSplitFrame *frm = 0;
TMapIter next(&fMap);
while ((rect = (TGRectMap*)next())) {
if (rect->Contains(event->fX, event->fY)) {
frm = (TGSplitFrame *)fMap.GetValue((const TObject *)rect);
gVirtualX->TranslateCoordinates(event->fWindow,
gClient->GetDefaultRoot()->GetId(),
event->fX, event->fY, px, py, wtarget);
fContextMenu->Popup(px, py, frm);
TRootContextMenu *menu = ((TRootContextMenu *)fContextMenu->GetContextMenuImp());
((TGPopupMenu *)menu)->Connect("PoppedDown()", "TGSplitTool", this, "Hide()");
return kTRUE;
}
}
Hide();
return kTRUE;
}
Bool_t TGSplitTool::HandleMotion(Event_t *event)
{
static TGRectMap *rect = 0, *oldrect = 0;
TMapIter next(&fMap);
while ((rect = (TGRectMap*)next())) {
if (rect->Contains(event->fX, event->fY)) {
if (rect != oldrect) {
if (oldrect) {
gVirtualX->FillRectangle(fId, GetBckgndGC()(), oldrect->fX,
oldrect->fY, oldrect->fW, oldrect->fH);
gVirtualX->DrawRectangle(fId, GetBlackGC()(), oldrect->fX, oldrect->fY,
oldrect->fW, oldrect->fH);
}
gVirtualX->FillRectangle(fId, fRectGC(), rect->fX, rect->fY, rect->fW,
rect->fH);
gVirtualX->DrawRectangle(fId, GetBlackGC()(), rect->fX, rect->fY,
rect->fW, rect->fH);
oldrect = rect;
}
return kTRUE;
}
}
if (oldrect) {
gVirtualX->FillRectangle(fId, GetBckgndGC()(), oldrect->fX,
oldrect->fY, oldrect->fW, oldrect->fH);
gVirtualX->DrawRectangle(fId, GetBlackGC()(), oldrect->fX, oldrect->fY,
oldrect->fW, oldrect->fH);
}
return kTRUE;
}
void TGSplitTool::Hide()
{
gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
fMap.Delete();
UnmapWindow();
}
void TGSplitTool::Reset()
{
fMap.Delete();
}
void TGSplitTool::SetPosition(Int_t x, Int_t y)
{
fX = x;
fY = y;
if (fX < -1)
fX = 0;
if (fY < -1)
fY = 0;
if (fWindow) {
if (fX > (Int_t) fWindow->GetWidth())
fX = fWindow->GetWidth();
if (fY > (Int_t) fWindow->GetHeight())
fY = fWindow->GetHeight();
}
}
void TGSplitTool::Show(Int_t x, Int_t y)
{
Move(x, y);
MapWindow();
RaiseWindow();
gVirtualX->GrabPointer(fId, kButtonPressMask | kPointerMotionMask, kNone,
fClient->GetResourcePool()->GetGrabCursor(),
kTRUE, kFALSE);
}
TGSplitFrame::TGSplitFrame(const TGWindow *p, UInt_t w, UInt_t h,
UInt_t options) : TGCompositeFrame(p, w, h, options),
fFrame(0), fSplitter(0), fFirst(0), fSecond(0)
{
fSplitTool = new TGSplitTool(gClient->GetDefaultRoot(), this);
fHRatio = fWRatio = 0.0;
fUndocked = 0;
AddInput(kStructureNotifyMask);
SetCleanup(kLocalCleanup);
}
TGSplitFrame::~TGSplitFrame()
{
delete fSplitTool;
Cleanup();
}
void TGSplitFrame::AddFrame(TGFrame *f, TGLayoutHints *l)
{
TGCompositeFrame::AddFrame(f, l);
fFrame = f;
}
void TGSplitFrame::RemoveFrame(TGFrame *f)
{
TGCompositeFrame::RemoveFrame(f);
if (f == fFrame)
fFrame = 0;
}
void TGSplitFrame::Cleanup()
{
TGCompositeFrame::Cleanup();
fFirst = 0;
fSecond = 0;
fSplitter = 0;
fUndocked = 0;
}
TGSplitFrame *TGSplitFrame::GetTopFrame()
{
TGSplitFrame *top = this;
TGWindow *w = (TGWindow *)GetParent();
TGSplitFrame *p = dynamic_cast<TGSplitFrame *>(w);
while (p) {
top = p;
w = (TGWindow *)p->GetParent();
p = dynamic_cast<TGSplitFrame *>(w);
}
return top;
}
void TGSplitFrame::Close()
{
if (fFrame) {
fFrame->UnmapWindow();
RemoveFrame(fFrame);
}
fFrame = 0;
}
void TGSplitFrame::CloseAndCollapse()
{
if (!fSplitter || !fFirst || !fSecond) {
TGSplitFrame *parent = (TGSplitFrame *)GetParent();
if (parent->GetFirst() && parent->GetSecond()) {
if (parent->GetFirst() == this)
parent->UnSplit("first");
else if (parent->GetSecond() == this)
parent->UnSplit("second");
}
}
}
void TGSplitFrame::Docked(TGFrame* frame)
{
Emit("Docked(TGFrame*)", (Long_t)frame);
}
void TGSplitFrame::ExtractFrame()
{
if (fFrame) {
fFrame->UnmapWindow();
fUndocked = new TGTransientFrame(gClient->GetDefaultRoot(), GetMainFrame(), 800, 600);
fFrame->ReparentWindow(fUndocked);
fUndocked->AddFrame(fFrame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
fUndocked->MapSubwindows();
fUndocked->Layout();
fUndocked->MapWindow();
RemoveFrame(fFrame);
fUndocked->Connect("CloseWindow()", "TGSplitFrame", this, "SwallowBack()");
Undocked(fFrame);
}
}
Bool_t TGSplitFrame::HandleConfigureNotify(Event_t *)
{
if (!fFirst) {
TGWindow *w = (TGWindow *)GetParent();
TGSplitFrame *p = dynamic_cast<TGSplitFrame *>(w);
if (p) {
if (p->GetFirst()) {
Float_t hratio = (Float_t)p->GetFirst()->GetHeight() / (Float_t)p->GetHeight();
Float_t wratio = (Float_t)p->GetFirst()->GetWidth() / (Float_t)p->GetWidth();
p->SetHRatio(hratio);
p->SetWRatio(wratio);
}
}
return kTRUE;
}
if ((fHRatio > 0.0) && (fWRatio > 0.0)) {
Float_t h = fHRatio * (Float_t)GetHeight();
fFirst->SetHeight((UInt_t)h);
Float_t w = fWRatio * (Float_t)GetWidth();
fFirst->SetWidth((UInt_t)w);
}
fHRatio = (Float_t)fFirst->GetHeight() / (Float_t)GetHeight();
fWRatio = (Float_t)fFirst->GetWidth() / (Float_t)GetWidth();
fClient->NeedRedraw(this);
if (!gVirtualX->InheritsFrom("TGX11"))
Layout();
return kTRUE;
}
void TGSplitFrame::HSplit(UInt_t h)
{
if ((fSplitter != 0) || (fFirst != 0) || (fSecond != 0) || (fFrame != 0))
return;
UInt_t height = (h > 0) ? h : fHeight/2;
ChangeOptions((GetOptions() & ~kHorizontalFrame) | kVerticalFrame);
fFirst = new TGSplitFrame(this, fWidth, height, kSunkenFrame | kFixedHeight);
fSecond = new TGSplitFrame(this, fWidth, height, kSunkenFrame);
fSplitter = new TGHSplitter(this, 4, 4);
fSplitter->SetFrame(fFirst, kTRUE);
fSplitter->Connect("ProcessedEvent(Event_t*)", "TGSplitFrame", this,
"OnSplitterClicked(Event_t*)");
TGCompositeFrame::AddFrame(fFirst, new TGLayoutHints(kLHintsExpandX));
TGCompositeFrame::AddFrame(fSplitter, new TGLayoutHints(kLHintsLeft |
kLHintsTop | kLHintsExpandX));
TGCompositeFrame::AddFrame(fSecond, new TGLayoutHints(kLHintsExpandX |
kLHintsExpandY));
}
void TGSplitFrame::VSplit(UInt_t w)
{
if ((fSplitter != 0) || (fFirst != 0) || (fSecond != 0) || (fFrame != 0))
return;
UInt_t width = (w > 0) ? w : fWidth/2;
ChangeOptions((GetOptions() & ~kVerticalFrame) | kHorizontalFrame);
fFirst = new TGSplitFrame(this, width, fHeight, kSunkenFrame | kFixedWidth);
fSecond = new TGSplitFrame(this, width, fHeight, kSunkenFrame);
fSplitter = new TGVSplitter(this, 4, 4);
fSplitter->SetFrame(fFirst, kTRUE);
fSplitter->Connect("ProcessedEvent(Event_t*)", "TGSplitFrame", this,
"OnSplitterClicked(Event_t*)");
TGCompositeFrame::AddFrame(fFirst, new TGLayoutHints(kLHintsExpandY));
TGCompositeFrame::AddFrame(fSplitter, new TGLayoutHints(kLHintsLeft |
kLHintsTop | kLHintsExpandY));
TGCompositeFrame::AddFrame(fSecond, new TGLayoutHints(kLHintsExpandX |
kLHintsExpandY));
}
void TGSplitFrame::MapToSPlitTool(TGSplitFrame *top)
{
Int_t px = 0, py = 0;
Int_t rx = 0, ry = 0;
Int_t cx, cy, cw, ch;
Window_t wtarget;
if (!fFirst && !fSecond) {
TGSplitFrame *parent = dynamic_cast<TGSplitFrame *>((TGFrame *)fParent);
if (parent && parent->fSecond == this) {
if (parent->GetOptions() & kVerticalFrame)
ry = parent->GetFirst()->GetHeight();
if (parent->GetOptions() & kHorizontalFrame)
rx = parent->GetFirst()->GetWidth();
}
gVirtualX->TranslateCoordinates(GetId(), top->GetId(),
fX, fY, px, py, wtarget);
cx = ((px-rx)/10)+2;
cy = ((py-ry)/10)+2;
cw = (fWidth/10)-4;
ch = (fHeight/10)-4;
top->GetSplitTool()->AddRectangle(this, cx, cy, cw, ch);
return;
}
if (fFirst)
fFirst->MapToSPlitTool(top);
if (fSecond)
fSecond->MapToSPlitTool(top);
}
void TGSplitFrame::OnSplitterClicked(Event_t *event)
{
Int_t px = 0, py = 0;
Window_t wtarget;
if (event->fType != kButtonPress)
return;
if (event->fCode != kButton3)
return;
gVirtualX->TranslateCoordinates(event->fWindow,
gClient->GetDefaultRoot()->GetId(),
event->fX, event->fY, px, py, wtarget);
TGSplitFrame *top = GetTopFrame();
top->GetSplitTool()->Reset();
top->GetSplitTool()->Resize(1+top->GetWidth()/10, 1+top->GetHeight()/10);
top->MapToSPlitTool(top);
top->GetSplitTool()->Show(px, py);
}
void TGSplitFrame::SplitHor()
{
char side[200];
snprintf(side, 200, "top");
if (fFrame) {
new TGInputDialog(gClient->GetRoot(), GetTopFrame(),
"In which side the actual frame has to be kept (top / bottom)",
side, side);
if ( strcmp(side, "") == 0 )
return;
}
SplitHorizontal(side);
}
void TGSplitFrame::SplitHorizontal(const char *side)
{
if (fFrame) {
TGFrame *frame = fFrame;
frame->UnmapWindow();
frame->ReparentWindow(gClient->GetDefaultRoot());
RemoveFrame(fFrame);
HSplit();
if (!strcmp(side, "top")) {
frame->ReparentWindow(GetFirst());
GetFirst()->AddFrame(frame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
}
else if (!strcmp(side, "bottom")) {
frame->ReparentWindow(GetSecond());
GetSecond()->AddFrame(frame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
}
}
else {
HSplit();
}
MapSubwindows();
Layout();
}
void TGSplitFrame::SplitVer()
{
char side[200];
snprintf(side, 200, "left");
if (fFrame) {
new TGInputDialog(gClient->GetRoot(), GetTopFrame(),
"In which side the actual frame has to be kept (left / right)",
side, side);
if ( strcmp(side, "") == 0 )
return;
}
SplitVertical(side);
}
void TGSplitFrame::SplitVertical(const char *side)
{
if (fFrame) {
TGFrame *frame = fFrame;
frame->UnmapWindow();
frame->ReparentWindow(gClient->GetDefaultRoot());
RemoveFrame(fFrame);
VSplit();
if (!strcmp(side, "left")) {
frame->ReparentWindow(GetFirst());
GetFirst()->AddFrame(frame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
}
else if (!strcmp(side, "right")) {
frame->ReparentWindow(GetSecond());
GetSecond()->AddFrame(frame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
}
}
else {
VSplit();
}
MapSubwindows();
Layout();
}
void TGSplitFrame::SwallowBack()
{
if (!fUndocked) {
fUndocked = dynamic_cast<TGTransientFrame *>((TQObject*)gTQSender);
}
if (fUndocked) {
TGFrameElement *el = dynamic_cast<TGFrameElement*>(fUndocked->GetList()->First());
if (!el || !el->fFrame) return;
TGSplitFrame *frame = (TGSplitFrame *)el->fFrame;
frame->UnmapWindow();
fUndocked->RemoveFrame(frame);
frame->ReparentWindow(this);
AddFrame(frame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
MapSubwindows();
Layout();
fUndocked->CloseWindow();
fUndocked = 0;
Docked(frame);
}
}
void TGSplitFrame::SwitchFrames(TGFrame *frame, TGCompositeFrame *dest,
TGFrame *prev)
{
TGCompositeFrame *parent = (TGCompositeFrame *)frame->GetParent();
prev->UnmapWindow();
dest->RemoveFrame(prev);
prev->ReparentWindow(gClient->GetDefaultRoot());
frame->UnmapWindow();
parent->RemoveFrame(frame);
frame->ReparentWindow(dest);
dest->AddFrame(frame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
frame->Resize(dest->GetDefaultSize());
dest->MapSubwindows();
dest->Layout();
prev->ReparentWindow(parent);
parent->AddFrame(prev, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
prev->Resize(parent->GetDefaultSize());
parent->MapSubwindows();
parent->Layout();
}
void TGSplitFrame::SwitchToMain()
{
TGFrame *source = fFrame;
TGSplitFrame *dest = GetTopFrame()->GetFirst();
TGFrame *prev = (TGFrame *)(dest->GetFrame());
if ((source != prev) && (source != dest))
SwitchFrames(source, dest, prev);
}
void TGSplitFrame::Undocked(TGFrame* frame)
{
Emit("Undocked(TGFrame*)", (Long_t)frame);
}
void TGSplitFrame::UnSplit(const char *which)
{
TGCompositeFrame *keepframe = 0;
TGSplitFrame *kframe = 0, *dframe = 0;
if (!strcmp(which, "first")) {
dframe = GetFirst();
kframe = GetSecond();
}
else if (!strcmp(which, "second")) {
dframe = GetSecond();
kframe = GetFirst();
}
if (!kframe || !dframe)
return;
keepframe = (TGCompositeFrame *)kframe->GetFrame();
if (keepframe) {
keepframe->UnmapWindow();
keepframe->ReparentWindow(gClient->GetDefaultRoot());
kframe->RemoveFrame(keepframe);
}
Cleanup();
if (keepframe) {
keepframe->ReparentWindow(this);
AddFrame(keepframe, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
}
MapSubwindows();
Layout();
}
void TGSplitFrame::SavePrimitive(std::ostream &out, Option_t *option )
{
if (fBackground != GetDefaultFrameBackground()) SaveUserColor(out, option);
out << std::endl << " // splittable frame" << std::endl;
out << " TGSplitFrame *";
out << GetName() << " = new TGSplitFrame(" << fParent->GetName()
<< "," << GetWidth() << "," << GetHeight();
if (fBackground == GetDefaultFrameBackground()) {
if (!GetOptions()) {
out << ");" << std::endl;
} else {
out << "," << GetOptionString() <<");" << std::endl;
}
} else {
out << "," << GetOptionString() << ",ucolor);" << std::endl;
}
if (option && strstr(option, "keep_names"))
out << " " << GetName() << "->SetName(\"" << GetName() << "\");" << std::endl;
TGLayoutManager * lm = GetLayoutManager();
if ((GetOptions() & kHorizontalFrame) &&
(lm->InheritsFrom(TGHorizontalLayout::Class()))) {
;
} else if ((GetOptions() & kVerticalFrame) &&
(lm->InheritsFrom(TGVerticalLayout::Class()))) {
;
} else {
out << " " << GetName() <<"->SetLayoutManager(";
lm->SavePrimitive(out, option);
out << ");"<< std::endl;
}
SavePrimitiveSubframes(out, option);
}