diff --git a/src/common/Widgets/FilterUi.cpp b/src/common/Widgets/FilterUi.cpp --- a/src/common/Widgets/FilterUi.cpp +++ b/src/common/Widgets/FilterUi.cpp @@ -1,1293 +1,1293 @@ #include #include "lgi/common/Lgi.h" #include "lgi/common/FilterUi.h" #include "lgi/common/Path.h" #include "lgi/common/Edit.h" #include "lgi/common/Combo.h" #include "lgi/common/DisplayString.h" #include "lgi/common/LgiRes.h" #include "lgi/common/Menu.h" #define FILTER_DRAG_FORMAT "Scribe.FilterItem" #define BaseIconSize 15 static LColour TransparentBlk(0, 0, 0, 0); static LColour ContentColour(0, 0, 0, 160); // Field size #define SIZE_NOT 45 #define SIZE_FIELD_NAME 130 #ifdef MAC #define SIZE_OP 85 #else #define SIZE_OP 75 #endif #define SIZE_VALUE 150 #define IconAlpha 255 static LColour IconColour[IconMax] = { LColour(192, 192, 192, IconAlpha), // new condition LColour(118, 160, 230, IconAlpha), // new and LColour(32, 224, 32, IconAlpha), // new or LColour(230, 90, 65, IconAlpha), // delete LColour(192, 192, 192, IconAlpha), // up LColour(192, 192, 192, IconAlpha), // down LColour(192, 192, 192, IconAlpha), // options LColour(192, 192, 192, IconAlpha), // drop down LColour(255, 192, 0, IconAlpha), // bool false LColour(255, 192, 0, IconAlpha), // bool true }; static const char *IconName[IconMax]; static const char **GetIconNames() { if (!IconName[0]) { int i = 0; IconName[i++] = LLoadString(L_FUI_NEW_CONDITION, "New Condition"); IconName[i++] = LLoadString(L_FUI_NEW_AND, "New And"); IconName[i++] = LLoadString(L_FUI_NEW_OR, "New Or"); IconName[i++] = LLoadString(L_FUI_DELETE, "Delete"); IconName[i++] = LLoadString(L_FUI_MOVE_UP, "Move Up"); IconName[i++] = LLoadString(L_FUI_MOVE_DOWN, "Move Down"); i++; IconName[i++] = LLoadString(L_FUI_OPTIONS, "Options"); i++; IconName[i++] = LLoadString(L_FUI_NOT, "Not"); } return IconName; } class LFilterTree : public LTree, public LDragDropTarget { friend class LFilterItem; public: LFilterTree() : LTree(-1, 0, 0, 100, 100) { } void OnCreate() { SetWindow(this); } void OnFocus(bool f) { if (f && !Selection()) { LTreeItem *n = GetChild(); if (n) n->Select(true); } } // Dnd int WillAccept(LDragFormats &Formats, LPoint Pt, int KeyState) { LFilterItem *i = dynamic_cast(ItemAtPoint(Pt.x, Pt.y)); if (!i || i->GetNode() == LNODE_NEW) return DROPEFFECT_NONE; SelectDropTarget(i); Formats.Supports(FILTER_DRAG_FORMAT); return DROPEFFECT_MOVE; } int OnDrop(LArray &Data, LPoint Pt, int KeyState) { SelectDropTarget(NULL); LFilterItem *Target = dynamic_cast(ItemAtPoint(Pt.x, Pt.y)); if (!Target) return DROPEFFECT_NONE; if (Target->GetNode() == LNODE_COND) { Target = dynamic_cast(Target->GetParent()); if (!Target) return DROPEFFECT_NONE; } for (unsigned i=0; iGetNode() == LNODE_OR || Target->GetNode() == LNODE_AND ) ) { (*Item)->Remove(); int Idx = 0; for (LFilterItem *ti = dynamic_cast(Target->GetChild()); ti && ti->GetNode() != LNODE_NEW; ti = dynamic_cast(ti->GetNext())) { Idx++; } Target->Insert(*Item, Idx); } } } } return DROPEFFECT_NONE; } }; template void HalveAlpha(T *p, int width) { T *e = p + width; while (p < e) { p->a >>= 1; p++; } } static void Draw(LSurface *pDC, int xPos, LColour c, FilterIcon Icon, int px) { pDC->SetOrigin(-xPos, 0); // Clear to transparent black pDC->Colour(TransparentBlk); pDC->Rectangle(); // Draw the icon backrgound double n = px - 2; LPointF Ctr(n/2, n), Rim(n/2, 0); if (1) { // Shadow LPath p; double z = (((double)px)-0.5) / 2; p.Circle(z, z, z); LSolidBrush b(Rgba32(0, 0, 0, 40)); p.Fill(pDC, b); } if (1) { LPath p; p.Circle(n/2, n/2, n/2); LBlendStop r[] = { {0.0, LColour::White.Mix(c, 0.1f).c32()}, {0.3, LColour::White.Mix(c, 0.3f).c32()}, {0.6, c.c32()}, {1.0, LColour::Black.Mix(c, 0.8f).c32()}, }; LRadialBlendBrush b(Ctr, Rim, CountOf(r), r); p.Fill(pDC, b); } if (1) { // Draw the highlight LPath p; p.Circle(n/2, n/2, n/2); LBlendStop Highlight[] = { {0.0, TransparentBlk.c32()}, {0.7, TransparentBlk.c32()}, {0.9, LColour::White.c32()}, }; LLinearBlendBrush b2(Ctr, Rim, CountOf(Highlight), Highlight); p.Fill(pDC, b2); } double k[4] = { n * 3 / 14, n * 3 / 7, n * 4 / 7, n * 11 / 14 }; int Plus[][2] = { {0, 1}, {0, 2}, {1, 2}, {1, 3}, {2, 3}, {2, 2}, {3, 2}, {3, 1}, {2, 1}, {2, 0}, {1, 0}, {1, 1}, {0, 1} }; // Draw the icon content switch (Icon) { default: break; case IconNewCond: case IconBoolTrue: { LPath p; p.Circle(n/2, n/2, n/6); LSolidBrush b(ContentColour); p.Fill(pDC, b); break; } case IconNewAnd: case IconDelete: { LPath p; LPointF Ctr(n/2, n/2); for (int i=0; iGetBits() / 8); switch (Icon) { default: break; // Make new icons translucent case IconNewCond: case IconNewAnd: case IconNewOr: { for (int y=0; yY(); y++) { switch (pDC->GetColourSpace()) { #define HalveAlphaCase(name) \ case Cs##name: HalveAlpha((L##name*)(*pDC)[y] + xOff, px); break HalveAlphaCase(Rgba32); HalveAlphaCase(Bgra32); HalveAlphaCase(Argb32); HalveAlphaCase(Abgr32); default: LAssert(pDC->GetBits() < 32); break; } } break; } } } pDC->SetOrigin(0, 0); } static void PostProcessIcons(LSurface *pDC) { if (pDC && pDC->IsPreMultipliedAlpha()) pDC->ConvertPreMulAlpha(true); } class LFilterViewPrivate { public: LFilterView *View; LAutoPtr Tree; bool ShowLegend = true; LRect Info; LArray Icons; FilterUi_Menu Callback = NULL; LAutoPtr dsNot; LAutoPtr dsAnd; LAutoPtr dsOr; LAutoPtr dsNew; LAutoPtr dsLegend; LString::Array OpNames; LFilterViewPrivate(LFilterView *v, LWindow *wnd) { View = v; dsNot.Reset (new LDisplayString(LSysFont, (char*)LLoadString(L_FUI_NOT, "Not"))); dsNew.Reset (new LDisplayString(LSysBold, (char*)LLoadString(L_FUI_NEW, "New"))); dsAnd.Reset (new LDisplayString(LSysBold, (char*)LLoadString(L_FUI_AND, "And"))); dsOr.Reset (new LDisplayString(LSysBold, (char*)LLoadString(L_FUI_OR, "Or"))); dsLegend.Reset(new LDisplayString(LSysBold, (char*)LLoadString(L_FUI_LEGEND, "Legend:"))); LPointF Scale(1.0f, 1.0f); if (wnd) Scale = wnd->GetDpiScale(); else LAssert(!"No window"); int IconSize = (int) (Scale.x * BaseIconSize); for (int i=0; iCreate(IconSize, IconSize, System32BitColourSpace)) { Draw(Icons[i], 0, IconColour[i], (FilterIcon)i, IconSize); PostProcessIcons(Icons[i]); } } } ~LFilterViewPrivate() { Icons.DeleteObjects(); } }; /////////////////////////////////////////////////////////////////////////////// class LFilterItemPrivate { public: LFilterNode Node; LFilterViewPrivate *Data; LRect Btns[IconMax]; LRect NotBtn; LRect FieldBtn, FieldDropBtn; LRect OpBtn, OpDropBtn; LRect ValueBtn; bool Not; char *Field, *Value; int Op; LEdit *FieldEd, *ValueEd; LCombo *OpCbo; LFilterItemPrivate() { Not = false; Data = 0; Node = LNODE_NULL; EmptyRects(); Field = Value = 0; Op = 0; FieldEd = ValueEd = 0; OpCbo = 0; } ~LFilterItemPrivate() { DeleteArray(Field); DeleteArray(Value); DeleteObj(FieldEd); DeleteObj(OpCbo); DeleteObj(ValueEd); } void EmptyRects() { for (int i=0; iData = Data; SetText("Node"); SetNode(Node); } LFilterItem::~LFilterItem() { DeleteObj(d); } bool LFilterItem::GetNot() { return d->Not; } const char *LFilterItem::GetField() { if (d->FieldEd) return d->FieldEd->Name(); return d->Field; } int LFilterItem::GetOp() { if (d->OpCbo != NULL) return (int)d->OpCbo->Value(); return d->Op; } const char *LFilterItem::GetValue() { if (d->ValueEd) return d->ValueEd->Name(); return d->Value; } void LFilterItem::SetNot(bool b) { d->Not = b; Update(); } void LFilterItem::SetField(const char *s) { DeleteArray(d->Field); d->Field = NewStr(s); if (d->FieldEd) d->FieldEd->Name(s); else Update(); } void LFilterItem::SetOp(int s) { d->Op = s; if (d->OpCbo) d->OpCbo->Value(s); else Update(); } void LFilterItem::SetValue(char *s) { DeleteArray(d->Value); d->Value = NewStr(s); if (d->ValueEd) d->ValueEd->Name(s); else Update(); } #define StartCtrl(Rc, Ed, Name, Obj) \ if (!d->Ed) \ { \ - LPoint sc = d->Data->Tree->_ScrollPos(); \ + LPoint sc = d->Data->Tree->ScrollPxPos(); \ d->Ed = new Obj(n++, c.x1 + Pos->x1 + Rc.x1 - sc.x, c.y1 + Pos->y1 + Rc.y1 - sc.y, \ Rc.X(), Rc.Y(), \ Name); \ if (d->Ed) \ { \ d->Ed->Attach(GetTree()); \ } \ } \ else \ { \ LRect r = Rc; \ - LPoint sc = d->Data->Tree->_ScrollPos(); \ + LPoint sc = d->Data->Tree->ScrollPxPos(); \ r.Offset(c.x1 + Pos->x1 - sc.x, c.y1 + Pos->y1 - sc.y); \ d->Ed->SetPos(r); \ } #define EndEdit(Rc, Ed, Var) \ if (d->Ed) \ { \ DeleteArray(d->Var); \ d->Var = NewStr(d->Ed->Name()); \ DeleteObj(d->Ed); \ } void LFilterItem::_PourText(LPoint &Size) { Size.y = LSysFont->GetHeight() + #ifdef MAC 14; // Not sure what the deal is here... it just looks better. #else 10; #endif switch (d->Node) { case LNODE_NEW: case LNODE_AND: case LNODE_OR: Size.x = 120; break; default: Size.x = 126 + SIZE_NOT + SIZE_FIELD_NAME + SIZE_OP + SIZE_VALUE; break; } } void LFilterItem::_PaintText(LItem::ItemPaintCtx &Ctx) { LRect *Pos = _GetRect(TreeItemText); // Create a memory context LMemDC Buf(Pos->X(), Pos->Y(), System32BitColourSpace); Buf.Colour(L_WORKSPACE); Buf.Rectangle(0); // Draw the background double ox = 1, oy = 1; double r = (double)(Pos->Y() - (oy * 2)) / 2; LColour BackCol = TransparentBlk; LColour Workspace(L_WORKSPACE); switch (d->Node) { case LNODE_NEW: BackCol.Rgb(0xd0, 0xd0, 0xd0); break; case LNODE_COND: default: BackCol = LColour(L_MED); break; case LNODE_AND: case LNODE_OR: BackCol = LColour::White.Mix(IconColour[d->Node], 0.3f); break; } bool IsTarget = IsDropTarget(); if (Select() || IsTarget) { LPath p; LSolidBrush b(LSysColour(L_FOCUS_SEL_BACK)); LRectF PosF(0, 0, Pos->X()-1, Pos->Y()); p.RoundRect(PosF, PosF.Y()/2); p.Fill(&Buf, b); } if (!IsTarget) { LPath p; LSolidBrush b(BackCol); LRectF PosF(0, 0, Pos->X()-(ox*2)-1, Pos->Y()-(oy*2)); PosF.Offset(ox, oy); p.RoundRect(PosF, r); p.Fill(&Buf, b); } if (d->Node == LNODE_NEW) { LPath p; LSolidBrush b(Workspace); LRectF PosF(0, 0, Pos->X()-(ox*2)-3, Pos->Y()-(oy*2)-2); PosF.Offset(ox+1, oy+1); p.RoundRect(PosF, r); p.Fill(&Buf, b); } // Clear the button rects d->EmptyRects(); // Draw the content int IconSize = d->Data->Icons[0]->Y(); int IconY = (int)(oy + r) - (IconSize / 2); switch (d->Node) { case LNODE_NEW: { Buf.Op(GDC_ALPHA); int x = Pos->X() - (int)r - IconSize + 4; int y = (int)(oy + r) - (IconSize / 2); // New OR d->Btns[IconNewOr].ZOff(IconSize-1, IconSize-1); d->Btns[IconNewOr].Offset(x, y); Buf.Blt(x, y, d->Data->Icons[IconNewOr]); x -= 2 + IconSize; // New AND d->Btns[IconNewAnd].ZOff(IconSize-1, IconSize-1); d->Btns[IconNewAnd].Offset(x, y); Buf.Blt(x, y, d->Data->Icons[IconNewAnd]); x -= 2 + IconSize; if (!IsRoot()) { // New Condition d->Btns[IconNewCond].ZOff(IconSize-1, IconSize-1); d->Btns[IconNewCond].Offset(x, y); Buf.Blt(x, y, d->Data->Icons[IconNewCond]); } break; } default: { Buf.Op(GDC_ALPHA); int x = (int)((double)Pos->X() - r - (IconSize / 2) - 2); // Delete d->Btns[IconDelete].ZOff(IconSize-1, IconSize-1); d->Btns[IconDelete].Offset(x, IconY); Buf.Blt(x, IconY, d->Data->Icons[IconDelete]); x -= 2 + IconSize; if (!IsRoot()) { // Move down d->Btns[IconMoveDown].ZOff(IconSize-1, IconSize-1); d->Btns[IconMoveDown].Offset(x, IconY); Buf.Blt(x, IconY, d->Data->Icons[IconMoveDown]); x -= 2 + IconSize; // Move up d->Btns[IconMoveUp].ZOff(IconSize-1, IconSize-1); d->Btns[IconMoveUp].Offset(x, IconY); Buf.Blt(x, IconY, d->Data->Icons[IconMoveUp]); x -= 2 + IconSize; } if (d->Node == LNODE_AND || d->Node == LNODE_OR) { // Configure d->Btns[IconOptions].ZOff(IconSize-1, IconSize-1); d->Btns[IconOptions].Offset(x, IconY); Buf.Blt(x, IconY, d->Data->Icons[IconOptions]); x -= 2 + IconSize; } break; } } switch (d->Node) { default: break; case LNODE_COND: { // Layout stuff d->FieldBtn.ZOff(SIZE_FIELD_NAME, (int)(r * 2) - 5); d->FieldBtn.Offset((int)(ox + r)+SIZE_NOT, (int)oy + 2); d->FieldDropBtn.ZOff(IconSize-1, IconSize-1); d->FieldDropBtn.Offset(d->FieldBtn.x2 + 1, d->FieldBtn.y1 + ((d->FieldBtn.Y()-d->FieldDropBtn.Y())/2)); d->NotBtn.ZOff(IconSize-1, IconSize-1); d->NotBtn.Offset((int)r, IconY); d->OpBtn.ZOff(SIZE_OP, d->FieldBtn.Y()+1); d->OpBtn.Offset(d->FieldDropBtn.x2 + 8, d->FieldBtn.y1-1); d->OpDropBtn.ZOff(IconSize-1, IconSize-1); d->OpDropBtn.Offset(d->OpBtn.x2 + 1, d->FieldDropBtn.y1); d->ValueBtn.ZOff(SIZE_VALUE, d->FieldBtn.Y()-1); d->ValueBtn.Offset(d->OpDropBtn.x2 + 8, d->FieldBtn.y1); // Draw stuff Buf.Op(GDC_ALPHA); Buf.Blt(d->NotBtn.x1, d->NotBtn.y1, d->Data->Icons[d->Not ? IconBoolTrue : IconBoolFalse]); Buf.Blt(d->OpDropBtn.x1, d->OpDropBtn.y1, d->Data->Icons[IconDropDown]); Buf.Blt(d->FieldDropBtn.x1, d->FieldDropBtn.y1, d->Data->Icons[IconDropDown]); Buf.Op(GDC_SET); LSysFont->Transparent(true); LSysFont->Colour(LColour(L_TEXT), Ctx.Back); d->Data->dsNot->Draw(&Buf, d->NotBtn.x2 + 3, d->NotBtn.y1); ShowControls(Select()); if (!Select()) { Buf.Colour(L_WORKSPACE); Buf.Rectangle(&d->FieldBtn); Buf.Rectangle(&d->OpBtn); Buf.Rectangle(&d->ValueBtn); int Tx = 6; int Ty = 2; if (d->Field) { LDisplayString ds(LSysFont, d->Field); ds.Draw(&Buf, d->FieldBtn.x1+Tx, d->FieldBtn.y1+Ty, &d->FieldBtn); } if (d->Op >= 0) { LDisplayString ds(LSysFont, d->Data->OpNames[d->Op]); ds.Draw(&Buf, d->OpBtn.x1+Tx, d->OpBtn.y1+Ty, &d->OpBtn); } if (d->Value) { LDisplayString ds(LSysFont, d->Value); ds.Draw(&Buf, d->ValueBtn.x1+Tx, d->ValueBtn.y1+Ty, &d->ValueBtn); } } break; } case LNODE_NEW: { LSysBold->Transparent(true); LSysBold->Colour(BackCol, Workspace); d->Data->dsNew->Draw(&Buf, (int)r - 3, (int)(oy + r) - (LSysBold->GetHeight() / 2)); break; } case LNODE_AND: { LSysBold->Transparent(true); LSysBold->Colour(IconColour[d->Node], BackCol); d->Data->dsAnd->Draw(&Buf, (int)r - 3, (int)(oy + r) - (LSysBold->GetHeight() / 2)); break; } case LNODE_OR: { LSysBold->Transparent(true); LSysBold->Colour(IconColour[d->Node], BackCol); d->Data->dsOr->Draw(&Buf, (int)r - 3, (int)(oy + r) - (LSysBold->GetHeight() / 2)); break; } } // Blt result to the screen Ctx.pDC->Blt(Pos->x1, Pos->y1, &Buf); // Paint to the right of the item, filling the column. if (Pos->x2 < Ctx.x2) { Ctx.pDC->Colour(L_WORKSPACE); Ctx.pDC->Rectangle(Pos->x2 + 1, Ctx.y1, Ctx.x2, Ctx.y2); } } void LFilterItem::ShowControls(bool s) { if (!GetTree() || d->Node != LNODE_COND) return; if (s) { LRect *Pos = _GetRect(TreeItemText); LRect c = GetTree()->GetClient(); int n = 1; LRect Cbo = d->OpBtn; Cbo.Union(&d->OpDropBtn); StartCtrl(d->FieldBtn, FieldEd, d->Field, LEdit); StartCtrl(Cbo, OpCbo, 0, LCombo); StartCtrl(d->ValueBtn, ValueEd, d->Value, LEdit); if (d->OpCbo && !d->OpCbo->Length()) { LString::Array Ops; if (d->Data->Callback( (LFilterView*) GetTree(), this, FMENU_OP, d->OpBtn, &Ops) > 0) { for (auto op: Ops) d->OpCbo->Insert(op); } if (d->Op) d->OpCbo->Value(d->Op); } } else { EndEdit(FieldBtn, FieldEd, Field); if (d->OpCbo) { d->Op = (int)d->OpCbo->Value(); DeleteObj(d->OpCbo); } EndEdit(ValueBtn, ValueEd, Value); } } void LFilterItem::OnExpand(bool b) { ShowControls(Select() && b); for (LTreeNode *c = GetChild(); c; c = c->GetNext()) { LFilterItem *i = dynamic_cast(c); if (i) i->OnExpand(b); } } bool LFilterItem::OnBeginDrag(LMouse &m) { Drag(GetTree(), m.Event, DROPEFFECT_MOVE); return true; } bool LFilterItem::GetFormats(LDragFormats &Formats) { Formats.Supports(FILTER_DRAG_FORMAT); return true; } bool LFilterItem::GetData(LArray &Data) { LDragData &dd = Data[0]; dd.Format = FILTER_DRAG_FORMAT; LVariant &v = dd.Data[0]; v.Type = GV_VOID_PTR; v.Value.Ptr = this; return true; } bool LFilterItem::OnKey(LKey &k) { if (k.IsChar) { if (k.vkey == LK_SPACE) { if (k.Down()) { SetNode(LNODE_COND); } return true; } } else if (k.IsContextMenu()) { if (k.Down()) { OptionsMenu(); } return true; } else if (k.vkey == LK_DELETE) { if (k.Down() && GetParent() && d->Node != LNODE_NEW) { LTreeItem *p = GetNext(); if (!p) p = GetPrev(); if (!p) p = GetParent(); delete this; if (p) p->Select(true); } return true; } return false; } void LFilterItem::OnMouseClick(LMouse &m) { if (m.Down() && m.Left()) { LRect *Pos = _GetRect(TreeItemText); if (!Pos) return; int Hit = -1; for (int i=0; iBtns[i].Overlap(m.x - Pos->x1, m.y - Pos->y1)) { Hit = i; break; } } LRect Rc, Client = GetTree()->GetClient(); if (d->NotBtn.Overlap(m.x - Pos->x1, m.y - Pos->y1)) { d->Not = !d->Not; Update(); } if (d->Data->Callback) { if (d->FieldDropBtn.Overlap(m.x - Pos->x1, m.y - Pos->y1)) { Rc = d->FieldDropBtn; Rc.Offset(Pos->x1 + Client.x1, Pos->y1 + Client.y1); d->Data->Callback( (LFilterView*) GetTree(), this, FMENU_FIELD, Rc, 0); } else if (d->OpDropBtn.Overlap(m.x - Pos->x1, m.y - Pos->y1)) { Rc = d->OpDropBtn; Rc.Offset(Pos->x1 + Client.x1, Pos->y1 + Client.y1); d->Data->Callback( (LFilterView*) GetTree(), this, FMENU_OP, Rc, 0); } } int Delta = 1; switch (Hit) { case IconMoveUp: { Delta = -1; // Fall thru } case IconMoveDown: { LFilterItem *p = dynamic_cast(GetParent()); if (p) { LTreeItem *m = this; size_t Count = p->Items.Length(); ssize_t Idx = p->Items.IndexOf(m); if (Idx + Delta >= 0 && Idx + Delta < (ssize_t)Count - 1) { p->Items.Delete(m); p->Items.Insert(m, Idx + Delta); p->_RePour(); GetTree()->Invalidate(); } } break; } case IconNewCond: { SetNode(LNODE_COND); break; } case IconNewAnd: { SetNode(LNODE_AND); break; } case IconNewOr: { SetNode(LNODE_OR); break; } case IconDelete: { if (IsRoot() && GetTree()) { GetTree()->Insert(new LFilterItem(d->Data)); } delete this; break; } case IconOptions: { OptionsMenu(); break; } } } } void LFilterItem::OptionsMenu() { LRect *Pos = _GetRect(TreeItemText); if (!Pos) return; LRect Client = GetTree()->GetClient(); LSubMenu s; if (d->Node == LNODE_NEW) s.AppendItem(LLoadString(L_FUI_CONDITION, "Condition"), 3, true); s.AppendItem(LLoadString(L_FUI_AND, "And"), 1, true); s.AppendItem(LLoadString(L_FUI_OR, "Or"), 2, true); LRect r = d->Btns[d->Node == LNODE_NEW ? IconNewCond : IconOptions]; r.Offset(Pos->x1 + Client.x1, Pos->y1 + Client.y1); LPoint p(r.x1, r.y2+1); p -= _ScrollPos(); GetTree()->PointToScreen(p); int Cmd = s.Float(GetTree(), p.x, p.y, true); switch (Cmd) { case 1: d->Node = LNODE_AND; break; case 2: d->Node = LNODE_OR; break; case 3: d->Node = LNODE_COND; break; } Update(); } LFilterNode LFilterItem::GetNode() { return d->Node; } void LFilterItem::SetNode(LFilterNode n) { if (d->Node != n) { if (d->Node == LNODE_NEW && GetParent() && !IsRoot()) { GetParent()->Insert(new LFilterItem(d->Data)); } d->Node = n; Update(); if (d->Node == LNODE_AND || d->Node == LNODE_OR) { Insert(new LFilterItem(d->Data)); Expanded(true); } } } /////////////////////////////////////////////////////////////////////////////// LFilterView::LFilterView(LWindow *wnd, FilterUi_Menu Callback) { d = new LFilterViewPrivate(this, wnd); d->Callback = Callback; d->Tree.Reset(new LFilterTree); Sunken(true); if (d->Callback) { LRect r; d->Callback(this, 0, FMENU_OP, r, &d->OpNames); } d->Tree->Sunken(false); d->Tree->Insert(new LFilterItem(d)); SetDefault(); } LFilterView::~LFilterView() { d->Tree->Empty(); DelView(d->Tree); DeleteObj(d); } void LFilterView::OnCreate() { OnPosChange(); d->Tree->Attach(this); } void LFilterView::SetDefault() { d->Tree->Empty(); d->Tree->Insert(new LFilterItem(d)); } LFilterItem *LFilterView::Create(LFilterNode Node) { return new LFilterItem(d, Node); } void LFilterView::OnPosChange() { LRect c = LLayout::GetClient(); if (d->ShowLegend) { d->Info = c; d->Info.y2 = d->Info.y1 + LSysFont->GetHeight() + 8; c.y1 += d->Info.y2 + 1; } d->Tree->SetPos(c); } /* LRect &LFilterView::GetClient(bool ClientCoods) { static LRect c; c = LView::GetClient(ClientCoods); if (d->ShowLegend) { d->Info = c; d->Info.y2 = d->Info.y1 + LSysFont->GetHeight() + 8; c.y1 += d->Info.y2 + 1; } else { d->Info.ZOff(-1, -1); } return c; } */ void LFilterView::OnPaint(LSurface *pDC) { LLayout::OnPaint(pDC); if (d->ShowLegend) { LMemDC Buf(d->Info.X(), d->Info.Y(), System32BitColourSpace); Buf.Colour(L_MED); Buf.Rectangle(0, 0, Buf.X()-1, Buf.Y()-2); Buf.Colour(L_LOW); Buf.Line(0, Buf.Y()-1, Buf.X()-1, Buf.Y()-1); LSysFont->Transparent(true); LSysFont->Colour(L_TEXT, L_MED); LSysBold->Transparent(true); LSysBold->Colour(L_TEXT, L_MED); int x = 4, y = 4; d->dsLegend->Draw(&Buf, x, y); x += 8 + d->dsLegend->X(); const char **Ico = GetIconNames(); for (int i=0; iIcons[i]); x += 3 + d->Icons[i]->X(); Buf.Op(GDC_SET); LDisplayString ds(LSysFont, (char*)IconName[i]); ds.Draw(&Buf, x, y); x += 12 + ds.X(); } } pDC->Blt(d->Info.x1, d->Info.y1, &Buf); } } LTreeNode *LFilterView::GetRootNode() { return d->Tree; } void LFilterView::Empty() { d->Tree->Empty(); } LAutoPtr LFilterView::CreateIcons(LWindow *wnd) { LPointF scale = wnd->GetDpiScale(); auto Px = (int)(scale.x * BaseIconSize + 0.5); LAutoPtr icons(new LImageList(Px, Px)); if (icons->Create(IconMax * Px, Px, System32BitColourSpace)) { for (int i=0; iSave("D:\\temp\\icons.bmp", icons); return icons; }