#include "ET++.ph" #ifdef __GNUG__ #pragma implementation #endif #include "Box.h" #include "Class.h" #include "OrdColl.h" #include "Math.h" #include "Look.h" #include "String.h" #include "Buttons.h" #include "TextItem.h" struct rcinfo { int wd, ht, bs; int hfixed, vfixed; }; //---- Box --------------------------------------------------------------------- NewMetaImpl(Box,CompositeVObject, (T(colsrows), T(gap), TE(align))); Box::Box(int id, const Point &cr, const Point &g, VObjAlign a) : colsrows(cr), gap(g), align(a), CompositeVObject(id, (SeqCollection*)0) { } Box::Box(int id, const Point &cr, const Point &g, VObjAlign a, VObject *va_(vop), ...) : colsrows(cr), gap(g), align(a), CompositeVObject(id, (SeqCollection*)0) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); va_end(ap); } Box::Box(int id, const Point &cr, const Point &g, VObjAlign a, SeqCollection *sc) : colsrows(cr), gap(g), align(a), CompositeVObject(id, sc) { } Box::Box(int id, const Point &cr, const Point &g, VObjAlign a, va_list ap) : colsrows(cr), gap(g), align(a), CompositeVObject(id, ap) { } void Box::SetAlign(VObjAlign a) { align= a; } void Box::SetGap(const Point &g) { gap= g; } void Box::SetColsRowsSize(const Point &cr) { colsrows= cr; } Point Box::ColsRowsSize() { int n= Size(); if (colsrows.y <= 0 && colsrows.x <= 0) { int c= Math::Sqrt(n); return Point(c, (n-1)/c+1); } if (colsrows.y <= 0) return Point(colsrows.x, (n-1)/colsrows.x+1); if (colsrows.x <= 0) return Point((n-1)/colsrows.y+1, colsrows.y); return colsrows; } Metric Box::getMinSize(Point &rc, rcinfo *rci, bool natural) { register int x, y; Metric m(-gap, 0); getGrid(rc, rci, natural); for (x= 0; x < rc.x; x++) m.extent.x+= rci[x].wd+gap.x; for (y= 0; y < rc.y; y++) m.extent.y+= rci[y].ht+gap.y; if (align & eVObjVBase) m.base= rci[0].bs; else if (Size() > 0) m.base= At(0)->Base(); return m; } void Box::getGrid(Point &rc, rcinfo *rci, bool natural) { VObjectIter next(this); register VObject *vop; register int x, y, hh, bb, maxwd= 0, maxht= 0, n; bool hexpand= align & eVObjHExpand, vexpand= (align & eVObjVExpand) && !(align & eVObjVBase); for (y= 0; y < rc.y; y++) { hh= bb= 0; for (x= 0; x < rc.x; x++) { if (vop= next()) { Metric m(vop->GetMinSize()); if (natural) { Point e(vop->GetExtent()); if (e.x > m.extent.x) m.extent.x= e.x; if (e.y > m.extent.y) m.extent.y= e.y; } if (align & eVObjVBase) { hh= Math::Max(hh, m.Base()); int eb= m.Height()-m.Base(); bb= Math::Max(bb, eb); } else { hh= Math::Max(hh, m.extent.y); } rci[x].wd= Math::Max(rci[x].wd, m.Width()); maxwd= Math::Max(maxwd, m.Width()); if (!hexpand || vop->TestFlag(eVObjHFixed)) rci[x].hfixed++; if (!vexpand || vop->TestFlag(eVObjVFixed)) rci[y].vfixed++; } } rci[y].ht= hh+bb; rci[y].bs= hh; maxht= Math::Max(maxht, hh+bb); } for (x= 0; x < rc.x; x++) { if (rci[x].hfixed >= rc.y) rci[x].hfixed= 1; else rci[x].hfixed= 0; } for (y= 0; y < rc.y; y++) { if (rci[y].vfixed >= rc.x) rci[y].vfixed= 1; else rci[y].vfixed= 0; } /* for (x= 0; x < rc.x; x++) { if (rci[x].hfixed > 0) rci[x].hfixed= 1; else rci[x].hfixed= 0; } for (y= 0; y < rc.y; y++) { if (rci[y].vfixed > 0) rci[y].vfixed= 1; else rci[y].vfixed= 0; } */ if ((align & eVObjHGapExpand) && rc.x > 1) { ResetFlag(eVObjHFixed); } else { for (n= x= 0; x < rc.x; x++) if (rci[x].hfixed) n++; SetFlag(eVObjHFixed, n >= rc.x); } if ((align & eVObjVGapExpand) && rc.y > 1) { ResetFlag(eVObjVFixed); } else { for (n= y= 0; y < rc.y; y++) if (rci[y].vfixed) n++; SetFlag(eVObjVFixed, n >= rc.y); } if (align & eVObjHEqual) for (x= 0; x < rc.x; x++) rci[x].wd= maxwd; if (align & eVObjVEqual) for (y= 0; y < rc.y; y++) rci[y].ht= maxht; } void Box::expand(Point &rc, rcinfo *rci, Point &g, Point &r) { register int x, y; bool hagain, vagain; rcinfo *rci2= new rcinfo[Math::Max(rc.x, rc.y)]; Point ne(GetExtent()); Point oe(getMinSize(rc, rci, TRUE).extent); Point mine(getMinSize(rc, rci2, FALSE).extent); Point diff(ne-mine); g= gap; r= gPoint0; if (diff.x > 0) { if (align & eVObjHGapExpand) { if (rc.x > 1) { g.x= diff.x/(rc.x-1); r.x= diff.x-g.x*(rc.x-1); g.x+= gap.x; } } } if (diff.y > 0) { if (align & eVObjVGapExpand) { if (rc.y > 1) { g.y= diff.y/(rc.y-1); r.y= diff.y-g.y*(rc.y-1); g.y+= gap.y; } } } hagain= vagain= TRUE; for (int i= 0; i < 2; i++) { Point newe(ne), olde(oe); if (hagain && (align & eVObjHExpand)) { for (x= 0; x < rc.x; x++) { if (rci[x].hfixed) { // col not hfixed newe.x-= rci[x].wd; olde.x-= rci[x].wd; } if (x < rc.x-1) { newe.x-= gap.x; olde.x-= gap.x; } } if (olde.x > 0) { int total= newe.x; hagain= FALSE; for (x= 0; x < rc.x; x++) { if (!rci[x].hfixed) { rci[x].wd= (rci[x].wd*newe.x)/olde.x; total-= rci[x].wd; } } for (x= 0; total > 0 && x < rc.x; x++) { if (!rci[x].hfixed) { rci[x].wd++; total--; } } for (x= 0; x < rc.x; x++) { if (!rci[x].hfixed && rci[x].wd < rci2[x].wd) { hagain= TRUE; break; } } } } if (vagain && (align & eVObjVExpand)) { for (y= 0; y < rc.y; y++) { if (rci[y].vfixed) { // row not vfixed newe.y-= rci[y].ht; olde.y-= rci[y].ht; } if (y < rc.y-1) { newe.y-= gap.y; olde.y-= gap.y; } } if (olde.y > 0) { int total= newe.y; vagain= FALSE; for (y= 0; y < rc.y; y++) { if (!rci[y].vfixed) { rci[y].ht= (rci[y].ht*newe.y)/olde.y; total-= rci[y].ht; } } for (y= 0; total > 0 && y < rc.y; y++) { if (!rci[y].vfixed) { rci[y].ht++; total--; } } for (y= 0; y < rc.y; y++) { if (!rci[y].vfixed && rci[y].ht < rci2[y].ht) { vagain= TRUE; break; } } } } if (hagain) for (x= 0; x < rc.x; x++) rci[x].wd= rci2[x].wd; if (vagain) for (y= 0; y < rc.y; y++) rci[y].ht= rci2[y].ht; } delete rci2; } Metric Box::GetMinSize() { Point rc(ColsRowsSize()); rcinfo *rci= new rcinfo[Math::Max(rc.x, rc.y)]; Metric m(getMinSize(rc, rci, FALSE)); delete rci; return m; } void Box::SetOrigin(Point at) { VObjectIter next(this); register VObject *vop; register int x, y; Point g, r, rr, a, rc(ColsRowsSize()); rcinfo *rci= new rcinfo[Math::Max(rc.x, rc.y)]; expand(rc, rci, g, r); VObject::SetOrigin(at); a.y= at.y; rr.y= r.y; for (y= 0; y < rc.y; y++) { a.x= at.x; rr.x= r.x; for (x= 0; x < rc.x; x++) { if (vop= next()) vop->Align(a, Metric(rci[x].wd, rci[y].ht, rci[y].bs), align); a.x+= rci[x].wd + g.x; if (rr.x > 0) { a.x++; rr.x--; } } a.y+= rci[y].ht + g.y; if (rr.y > 0) { a.y++; rr.y--; } } delete rci; } void Box::SetExtent(Point ee) { VObjectIter next(this); register VObject *vop; register x, y; Point g, r, rc(ColsRowsSize()); rcinfo *rci= new rcinfo[Math::Max(rc.x, rc.y)]; bool hexpand= align & (eVObjHExpand|eVObjHEqual), vexpand= (align & (eVObjVExpand|eVObjVEqual)) && !(align & eVObjVBase); Point e(getMinSize(rc, rci, FALSE).extent); if (!TestFlag(eVObjHFixed)) e.x= ee.x; if (!TestFlag(eVObjVFixed) && !(align & eVObjVBase)) e.y= ee.y; VObject::SetExtent(e); expand(rc, rci, g, r); for (y= 0; y < rc.y; y++) { for (x= 0; x < rc.x; x++) { if (vop= next()) { Point ms(vop->GetMinSize().extent); e= vop->GetExtent(); if (e.x < ms.x || e.y < ms.y) { if (e.x < ms.x) e.x= ms.x; if (e.y < ms.y) e.y= ms.y; } if (hexpand && !vop->TestFlag(eVObjHFixed)) e.x= rci[x].wd; if (vexpand && !vop->TestFlag(eVObjVFixed)) e.y= rci[y].ht; vop->SetExtent(e); } } } delete rci; } OStream& Box::PrintOn(OStream &s) { CompositeVObject::PrintOn(s); return s << colsrows SP << gap SP << (int)align SP; } IStream& Box::ReadFrom(IStream &s) { CompositeVObject::ReadFrom(s); return s >> colsrows >> gap >> Enum(align); } int Box::FindVObject(VObject *v) { VObject *vop; VObjectIter next(this); for (int i= 0; vop= next(); i++) if (v == vop) return i; return -1; } void Box::CalcResize(int where, Point d, rcinfo *minsize, rcinfo *normsize, rcinfo *result) { Point rc(ColsRowsSize()); int i; if (d.x) { // vertical bool got= TRUE; int dd, gg= 0; if (d.x < 0) { dd= -d.x; while (dd > 0 && got) { got= FALSE; for (i= 0; i < where; i++) { if (!normsize[i].hfixed && result[i].wd > minsize[i].wd) { result[i].wd--; dd--; gg++; got= TRUE; break; } } } while (gg > 0) { for (i= where+1; i < rc.x; i++) { if (!normsize[i].hfixed) { result[i].wd++; gg--; break; } } } } else { dd= d.x; while (dd > 0 && got) { got= FALSE; for (i= where+1; i < rc.x; i++) { if (!normsize[i].hfixed && result[i].wd > minsize[i].wd) { result[i].wd--; dd--; gg++; got= TRUE; break; } } } while (gg > 0) { for (i= 0; i < where; i++) { if (!normsize[i].hfixed) { result[i].wd++; gg--; break; } } } } } if (d.y) { // hor bool got= TRUE; int dd, gg= 0; if (d.y < 0) { dd= -d.y; while (dd > 0 && got) { got= FALSE; for (i= 0; i < where; i++) { if (!normsize[i].vfixed && result[i].ht > minsize[i].ht) { result[i].ht--; dd--; gg++; got= TRUE; break; } } } while (gg > 0) { for (i= where+1; i < rc.y; i++) { if (!normsize[i].vfixed) { result[i].ht++; gg--; break; } } } } else { dd= d.y; while (dd > 0 && got) { got= FALSE; for (i= where+1; i < rc.y; i++) { if (!normsize[i].vfixed && result[i].ht > minsize[i].ht) { result[i].ht--; dd--; gg++; got= TRUE; break; } } } while (gg > 0) { for (i= 0; i < where; i++) { if (!normsize[i].vfixed) { result[i].ht++; gg--; break; } } } } } } void Box::Resize(rcinfo *newsize) { register VObject *vop; register int x, y; VObjectIter next(this); Point at(GetOrigin()), a, rc(ColsRowsSize()); Rectangle inval; bool hexpand= align & (eVObjHExpand|eVObjHEqual), vexpand= (align & (eVObjVExpand|eVObjVEqual)) && !(align & eVObjVBase); a.y= at.y; for (y= 0; y < rc.y; y++) { a.x= at.x; for (x= 0; x < rc.x; x++) { if (vop= next()) { Rectangle oldr(vop->contentRect); Point e(vop->GetExtent()); if (e.x == 0 || e.y == 0) e= vop->GetMinSize().extent; if (hexpand && !vop->TestFlag(eVObjHFixed)) e.x= newsize[x].wd; if (vexpand && !vop->TestFlag(eVObjVFixed)) e.y= newsize[y].ht; vop->SetExtent(e); vop->Align(a, Metric(newsize[x].wd, newsize[y].ht, newsize[y].bs), align); if (vop->contentRect != oldr) inval.Merge(vop->contentRect); } a.x+= newsize[x].wd + gap.x; } a.y+= newsize[y].ht + gap.y; } InvalidateRect(inval); } //---- SplitMover -------------------------------------------------------------- class SplitMover: public Command { Rectangle constrainRect; Point delta, rc; Box *sbox; VObject *where; rcinfo *minsize, *result, *normsize; int iwhere; public: SplitMover(Box *sb, VObject *w); ~SplitMover(); Command *TrackMouse(TrackPhase, Point, Point, Point); void TrackConstrain(Point ap, Point pp, Point *np); void TrackFeedback(Point, Point, bool on); }; SplitMover::SplitMover(Box *sb, VObject *w) { sbox= sb; constrainRect= sbox->contentRect; where= w; iwhere= sbox->FindVObject(where); rc= sbox->ColsRowsSize(); int n= Math::Max(rc.x, rc.y); minsize= new rcinfo[n]; sbox->getGrid(rc, minsize, FALSE); normsize= new rcinfo[n]; sbox->getGrid(rc, normsize, TRUE); } SplitMover::~SplitMover() { SafeDelete(minsize); SafeDelete(normsize); SafeDelete(result); } void SplitMover::TrackConstrain(Point ap, Point, Point *np) { Rectangle r(where->contentRect); r.origin+= *np-ap; *np+= r.AmountToTranslateWithin(constrainRect); } Command *SplitMover::TrackMouse(TrackPhase tp, Point ap, Point, Point np) { delta= np-ap; SafeDelete(result); int n= Math::Max(rc.x, rc.y); result= new rcinfo[n]; MemCpy(result, normsize, n*sizeof(struct rcinfo)); sbox->CalcResize(iwhere, delta, minsize, normsize, result); if (tp == eTrackRelease) { sbox->Resize(result); return gNoChanges; } return this; } void SplitMover::TrackFeedback(Point, Point, bool) { Point gap(sbox->GetGap()), at(sbox->GetOrigin()), e(sbox->GetExtent()); if (delta.x) { // vertical for (int x= 0; x < rc.x; x++) { at.x+= result[x].wd; GrLine(at, at+Point(0, e.y)); at.x+= gap.x; } } if (delta.y) { // hor for (int y= 0; y < rc.y; y++) { at.y+= result[y].ht; GrLine(at, at+Point(e.x, 0)); at.y+= gap.y; } } } //---- HBox -------------------------------------------------------------------- NewMetaImpl0(HBox,Box); HBox::HBox(const Point &g, VObjAlign a) : Box(cIdNone, Point(0,1), g, a) { } HBox::HBox(const Point &g, VObjAlign a, VObject *va_(vop), ...) : Box(cIdNone, Point(0,1), g, a) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); va_end(ap); } HBox::HBox(const Point &g, VObjAlign a, SeqCollection *c) : Box(cIdNone, Point(0,1), g, a, c) { } HBox::HBox(VObject *va_(vop), ...) : Box(cIdNone, Point(0,1), gPoint2, (VObjAlign)(eVObjVTop|eVObjHExpand|eVObjVExpand)) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); va_end(ap); } //---- VBox -------------------------------------------------------------------- NewMetaImpl0(VBox,Box); VBox::VBox(const Point &g, VObjAlign a) : Box(cIdNone, Point(1,0), g, a) { } VBox::VBox(const Point &g, VObjAlign a, VObject *va_(vop), ...) : Box(cIdNone, Point(1,0), g, a) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); va_end(ap); } VBox::VBox(const Point &g, VObjAlign a, SeqCollection *c) : Box(cIdNone, Point(1,0), g, a, c) { } VBox::VBox(VObject *va_(vop), ...) : Box(cIdNone, Point(1,0), gPoint2, (VObjAlign)(eVObjHLeft|eVObjHExpand|eVObjVExpand)) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); va_end(ap); } //---- SplitHandle ------------------------------------------------------------- NewMetaImpl0(SplitHandle,VObject); SplitHandle::SplitHandle() { } Metric SplitHandle::GetMinSize() { Metric m(gLook->SashLayout()->GetMinSize(this)); Box *b= (Box*) GetContainer(); if (b && b->IsKindOf(Box)) { Point rc(b->ColsRowsSize()); if (rc.x > rc.y) { SetFlag(eVObjHFixed); m.extent.y*= 2; } else if (rc.x < rc.y) { SetFlag(eVObjVFixed); m.extent.x*= 2; } } return m; } void SplitHandle::Draw(Rectangle r) { gLook->SashLayout()->Adorn(this, r, 0); } Command *SplitHandle::DoLeftButtonDownCommand(Point, Token, int) { Box *sb= (Box*) GetContainer(); if (sb && sb->IsKindOf(Box)) return new SplitMover(sb, this); return gNoChanges; } //---- VObjectPair ------------------------------------------------------------- NewMetaImpl0(VObjectPair,HBox); VObjectPair::VObjectPair(VObject *l, VObject *r, const Point &g) : HBox(g, eVObjVBase, l, r, 0) { } //---- Expander ---------------------------------------------------------------- NewMetaImpl0(Expander, Box); Expander::Expander(int id, Direction d, const Point &g) : Box(id, gPoint0, g, (VObjAlign)0) { Init(d); } Expander::Expander(int id, Direction d, const Point &g, VObject *va_(vop), ...) : Box(id, gPoint0, g, (VObjAlign)0) { va_list ap; va_start(ap,va_(vop)); SetItems(va_(vop), ap); Init(d); va_end(ap); } Expander::Expander(int id, Direction d, const Point &g, SeqCollection *c) : Box(id, gPoint0, g, (VObjAlign)0, c) { Init(d); } void Expander::Init(Direction d) { if (d == eVert) { align= (VObjAlign)(eVObjHLeft|eVObjVExpand|eVObjHExpand); SetColsRowsSize(Point(1,0)); } else { align= (VObjAlign)(eVObjVTop|eVObjVExpand|eVObjHExpand); SetColsRowsSize(Point(0,1)); } } //---- HExpander --------------------------------------------------------------- HExpander::HExpander(const Point &g, VObject *va_(vop), ...) : Expander(cIdNone, eHor, g, (SeqCollection*)0) { va_list ap; va_start(ap,va_(vop)); SetItems(va_(vop), ap); va_end(ap); } //---- VExpander --------------------------------------------------------------- VExpander::VExpander(const Point &g, VObject *va_(vop), ...) : Expander(cIdNone, eVert, g, (SeqCollection*)0) { va_list ap; va_start(ap,va_(vop)); SetItems(va_(vop), ap); va_end(ap); } //---- Cluster ----------------------------------------------------------------- NewMetaImpl0(Cluster,Box); Cluster::Cluster(int id, VObjAlign a, const Point &g) : Box(id, gPoint0, g, a) { Init(); } Cluster::Cluster(int id, VObjAlign a, const Point &g, SeqCollection *cp) : Box(id, gPoint0, g, a, cp) { Init(); } Cluster::Cluster(int id, VObjAlign a, const Point &g, VObject *va_(vop), ...) : Box(id, gPoint0, g, a) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); Init(); va_end(ap); } Cluster::Cluster(int id, VObjAlign a, const Point &g, va_list ap) : Box(id, gPoint0, g, a, ap) { Init(); } void Cluster::Init() { if (align & eVObjH) SetColsRowsSize(Point(1,0)); if (align & eVObjV) SetColsRowsSize(Point(0,1)); } //---- ManyOfCluster ----------------------------------------------------------- NewMetaImpl0(ManyOfCluster,Cluster); ManyOfCluster::ManyOfCluster(int id, VObjAlign a, const Point &g, SeqCollection *cp) : Cluster(id, a, g, cp) { SetFlag(eVObjVFixed); } ManyOfCluster::ManyOfCluster(int id, VObjAlign a, const Point &g, VObject *va_(vop), ...) : Cluster(id, a, g) { va_list ap; va_start(ap,va_(vop)); SetItems(va_(vop), ap); va_end(ap); } ManyOfCluster::ManyOfCluster(int id, VObject *va_(vop), ...) : Cluster(id, eVObjHLeft) { va_list ap; va_start(ap,va_(vop)); SetItems(va_(vop), ap); va_end(ap); } ManyOfCluster::ManyOfCluster(int id, VObjAlign a, const Point &g, char *va_(cp), ...) : Cluster(id, a, g) { char *t; va_list ap; va_start(ap,va_(cp)); Add(new ToggleButton(id+0, va_(cp))); for (int i= 1; t= va_arg(ap, char*); i++) Add(new ToggleButton(id+i, t)); va_end(ap); } ManyOfCluster::ManyOfCluster(int id, char *va_(cp), ...) : Cluster(id, eVObjHLeft) { char *t; va_list ap; va_start(ap,va_(cp)); Add(new ToggleButton(id+0, va_(cp))); for (int i= 1; t= va_arg(ap, char*); i++) Add(new ToggleButton(id+i, t)); va_end(ap); } void ManyOfCluster::Control(int id, int p, void *v) { if (p == cPartToggle) Cluster::Control(GetId(), id, v); } void ManyOfCluster::SetItem(int id, bool state) { VObjectIter next(this); register VObject *dip; while (dip= next()) if (dip->IsKindOf(StateButton) && dip->GetId() == id) { ((StateButton*)dip)->SetValue(state ? 1 : 0); break; } } void ManyOfCluster::SetAllItems(bool state) { VObjectIter next(this); register VObject *dip; while (dip= next()) if (dip->IsKindOf(StateButton)) ((StateButton*)dip)->SetValue(state ? 1 : 0); } bool ManyOfCluster::IsItemOn(int id) { VObjectIter next(this); register VObject *dip; while (dip= next()) if (dip->IsKindOf(StateButton) && dip->GetId() == id) return ((StateButton*)dip)->GetValue() != 0; return FALSE; } //---- OneOfCluster ------------------------------------------------------------ NewMetaImpl0(OneOfCluster,Cluster); OneOfCluster::OneOfCluster(int id, VObjAlign a, const Point &g, SeqCollection *cp) : Cluster(id, a, g, cp) { if (Size() > 0) SetItemOn(At(0)->GetId()); } OneOfCluster::OneOfCluster(int id, VObjAlign a, const Point &g, VObject *va_(vop), ...) : Cluster(id, a, g) { va_list ap; va_start(ap,va_(vop)); SetItems(va_(vop), ap); if (Size() > 0) SetItemOn(At(0)->GetId()); va_end(ap); } OneOfCluster::OneOfCluster(int id, VObject *va_(vop), ...) : Cluster(id, eVObjHLeft) { va_list ap; va_start(ap,va_(vop)); SetItems(va_(vop), ap); if (Size() > 0) SetItemOn(At(0)->GetId()); va_end(ap); } OneOfCluster::OneOfCluster(int id, VObjAlign a, const Point &g, char *va_(cp), ...) : Cluster(id, a, g) { char *t; va_list ap; va_start(ap,va_(cp)); Add(new RadioButton(id+0, va_(cp))); for (int i= 1; t= va_arg(ap, char*); i++) Add(new RadioButton(id+i, t)); SetItemOn(At(0)->GetId()); va_end(ap); } OneOfCluster::OneOfCluster(int id, char *va_(cp), ...) : Cluster(id, eVObjHLeft) { char *t; va_list ap; va_start(ap,va_(cp)); Add(new RadioButton(id+0, va_(cp))); for (int i= 1; t= va_arg(ap, char*); i++) Add(new RadioButton(id+i, t)); SetItemOn(At(0)->GetId()); va_end(ap); } void OneOfCluster::SetValue(int id) { VObjectIter next(this); register VObject *dip; while (dip= next()) if (dip->IsKindOf(StateButton)) ((StateButton*)dip)->SetValue((int) dip->GetId() == id); } int OneOfCluster::GetValue() { VObjectIter next(this); register VObject *dip; while (dip= next()) if (dip->IsKindOf(StateButton)) if (((StateButton*)dip)->GetValue()) return dip->GetId(); return cIdNone; } void OneOfCluster::Control(int id, int part, void *v) { if (part == cPartToggle) { SetItemOn(id); Cluster::Control(GetId(), id, v); } } //---- Form -------------------------------------------------------------------- NewMetaImpl0(Form, Box); Form::Form(int id, VObjAlign, const Point &g) : Box(id, Point(2,0), g, (VObjAlign)(eVObjHLeft|eVObjHExpand|eVObjVBase)) { } Form::Form(int id, VObjAlign, const Point &g, SeqCollection *cp) : Box(id, Point(2,0), g, (VObjAlign)(eVObjHLeft|eVObjHExpand|eVObjVBase), cp) { } Form::Form(int id, VObjAlign, const Point &g, VObject *va_(vop), ...) : Box(id, Point(2,0), g, (VObjAlign)(eVObjHLeft|eVObjHExpand|eVObjVBase)) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); va_end(ap); } Form::Form(VObject *va_(vop), ...) : Box(cIdNone, Point(2,0), gPoint2, (VObjAlign)(eVObjHLeft|eVObjHExpand|eVObjVCenter)) { va_list ap; va_start(ap, va_(vop)); SetItems(va_(vop), ap); va_end(ap); } Form::Form(int id, VObjAlign, const Point &g, char* va_(label), ...) : Box(id, Point(2,0), g, (VObjAlign)(eVObjHLeft|eVObjHExpand|eVObjVCenter)) { va_list ap; va_start(ap, va_(label)); Init(va_(label), ap); va_end(ap); } Form::Form(char* va_(label), ...) : Box(cIdNone, Point(2,0), gPoint2, (VObjAlign)(eVObjHLeft|eVObjHExpand|eVObjVCenter)) { va_list ap; va_start(ap, va_(label)); Init(va_(label), ap); va_end(ap); } void Form::Init(char *label, va_list ap) { register VObject *vop; for (int i= 0; ; i++) { if (Math::Even(i)) { char *s= (i == 0) ? label : va_arg(ap, char*); if (s) { vop= new TextItem(s); //vop->SetFlag(eVObjHFixed); } else break; } else { if ((vop= va_arg(ap, VObject*)) == 0) break; } Add(vop); } } void Form::SetContainer(VObject *v) { Box::SetContainer(v); VObjectIter next(this); Object *op; while (op= next()) { op->SetFlag(eVObjHFixed); op= next(); if (op == 0) return; } }