#include "TCtrlLib.h" #ifdef COMPILER_MSC #pragma hdrstop #endif//COMPILER_MSC #include "TCtrlImg.h" #define LLOG(x) // RLOG(x) #ifdef PLATFORM_WIN32 #include NAMESPACE_UPP void DropFilesRegister(HWND hwnd) { DragAcceptFiles(hwnd, true); } Point DropFilesGetPos(WPARAM hdrop) { POINT pt; if(DragQueryPoint((HDROP)hdrop, &pt)) return Point(pt.x, pt.y); return Null; } Vector DropFilesGetList(WPARAM hdrop) { int count = DragQueryFile((HDROP)hdrop, (DWORD)-1, 0, 0); Vector list; for(int i = 0; i < count; i++) { int length = DragQueryFile((HDROP)hdrop, i, 0, 0); StringBuffer s(length + 1); DragQueryFile((HDROP)hdrop, i, s, length + 1); list.Add(s); } DragFinish((HDROP)hdrop); return list; } #endif bool IsUnique(const ArrayCtrl& table, int item) { if(table.GetCount() <= 1 || !table.IsCursor()) return true; Value value = table.Get(item); for(int t = 0; t < table.GetCount(); t++) if(t != table.GetCursor() && value == table.Get(t, item)) return false; return true; } bool IsUnique(const ArrayCtrl& table, Id id) { return IsUnique(table, table.GetPos(id)); } int SwapRows(ArrayCtrl& table, int row1, int row2) { if(row1 == row2) return row1; // bool s1 = table.IsSelected(row1); // bool s2 = table.IsSelected(row2); int next = row2; int o = table.GetCursor(); table.KillCursor(); Vector row; row <<= table.ReadRow(row2); table.Set(row2, table.ReadRow(row1)); table.Set(row1, row); if(o >= 0) table.SetCursor(o == row1 ? row2 : o == row2 ? row1 : o); // table.Select(row1, s2); // table.Select(row2, s1); return next; } void SetColumn(ArrayCtrl& table, int index, const Value& value) { int c = table.GetCursor(), sc = table.GetCursorSc(); table.KillCursor(); for(int i = 0; i < table.GetCount(); i++) table.Set(i, index, value); table.SetCursor(c); table.ScCursor(sc); } void SetColumn(ArrayCtrl& table, Id column, const Value& value) { SetColumn(table, table.GetPos(column), value); } Index GetSelIndex(const ArrayCtrl& table) { Index out; for(int i = 0; i < table.GetCount(); i++) if(table.IsSelected(i)) out.Add(i); return out; } BorderFrame& TopJoinFrame() { static const ColorF b[] = { (ColorF)1, &SLtGray, &SLtGray, &SLtGray, &SGray }; static BorderFrame frm(b); return frm; } BorderFrame& BottomJoinFrame() { static const ColorF b[] = { (ColorF)1, &SLtGray, &SWhite, &SLtGray, &SLtGray }; static BorderFrame frm(b); return frm; } ////////////////////////////////////////////////////////////////////// // DropButton:: DropButton::DropButton() { SetImage(CtrlImg::down_arrow()); } bool DropButton::HotKey(dword key) { return WhenHotKey(key); } ////////////////////////////////////////////////////////////////////// // ChoiceList:: ChoiceList::ChoiceList() : owner(0), item(0) { AutoHideSb().NoHeader().NoGrid().MouseMoveCursor(); WhenSelect = THISBACK(OnSelect); WhenCancel = THISBACK(OnCancel); dropbutton.WhenPush = THISBACK(OnDrop); AddColumn(); } ChoiceList& ChoiceList::Attach(Ctrl& _owner) { Detach(); owner = &_owner; _owner.AddFrame(dropbutton); dropbutton.WhenHotKey = THISBACK(OnKey); return *this; } void ChoiceList::Detach() { if(owner) owner -> RemoveChild(&dropbutton); owner = NULL; } bool ChoiceList::OnKey(dword key) { switch(key) { case K_ALT_DOWN: OnToggle(); return true; } return false; } void ChoiceList::OnToggle() { if(IsOpen()) OnSelect(); else OnDrop(); } void ChoiceList::OnDrop() { ASSERT(owner && item >= 0 && item < GetIndexCount()); WhenDrop(); PopUpTable::PopUp(owner); FindSetCursor(owner -> GetData(), item); } void ChoiceList::OnSelect() { if(owner && IsCursor() && Get(item) != owner -> GetData()) { owner -> SetData(Get(item)); owner -> UpdateActionRefresh(); } } void ChoiceList::OnCancel() { owner -> SetWantFocus(); } ExtendedButton::ExtendedButton() { Width(16); SetImage(CtrlImg::right_arrow()); } bool ExtendedButton::HotKey(dword key) { if(key == K_ALT_ENTER) { for(Ctrl *p = this; p; p = p->GetParent()) if(p->HasFocus()) { Action(); return true; } } return Button::HotKey(key); } ExtendedFileButton::ExtendedFileButton() { Width(16); SetImage(TCtrlImg::open_small()); // Tip("Otevřít výběr souboru / složky"); // SetLabelText("..."); } bool ExtendedFileButton::HotKey(dword key) { if(key == K_ALT_ENTER) { for(Ctrl *p = this; p; p = p->GetParent()) if(p->HasFocus()) { Action(); return true; } } return Button::HotKey(key); } MenuButton::MenuButton() { WhenPush = callback(this, &MenuButton::OnMenu); } void MenuButton::OnMenu() { MenuBar::Execute(WhenBar, GetScreenRect().TopRight()); } /* void ColorDisplayNull::Paint(Draw& w, const Rect& r, const Value& q, Color i, Color p, dword s) const { Color c = q; w.DrawRect(r, p); if(IsNull(c)) { int size = w.GetTextSize(null_text, StdFont()).cy; w.DrawText(r.left + 2, (r.top + r.bottom - size) >> 1, null_text, StdFont(), i); } else { Color lite = SWhite, dark = SLtGray; if((c.GetR() | c.GetG() | c.GetB()) & 0x80) lite = SLtGray, dark = SBlack; Rect rc = r; rc.Deflate(2); DrawFrame(w, rc, lite, dark); rc.Deflate(1); w.DrawRect(rc, c); } } */ bool IsDragDistance(Point pt1, Point pt2) { #ifdef PLATFORM_WIN32 return tabs(pt1.x - pt2.x) >= GetSystemMetrics(SM_CXDRAG) || tabs(pt1.y - pt2.y) >= GetSystemMetrics(SM_CYDRAG); #endif #ifdef PLATFORM_POSIX enum { CXDRAG = 20, CYDRAG = 20 }; // todo? are there any CXDRAG / CYDRAG system metrics in LINUX? return tabs(pt1.x - pt2.x) >= CXDRAG || tabs(pt1.y - pt2.y) >= CYDRAG; #endif } DragDropCtrl::DragDropCtrl() : state(0) { } DragDropCtrl::~DragDropCtrl() {} bool DragDropCtrl::Push(Point pt, dword keyflags) { return true; } void DragDropCtrl::Drag(Point pt, Point last, Point next, dword keyflags) { Rect rc_last = Null, rc_next = Null; if(!IsNull(last)) rc_last = RectSort(pt, last); if(!IsNull(next)) rc_next = RectSort(pt, next); if(rc_last != rc_next) DragRect(rc_last, rc_next, keyflags); } void DragDropCtrl::Drop(Point pt, Point end, dword keyflags) { DropRect(RectSort(pt, end), keyflags); } void DragDropCtrl::Click(Point pt, dword keyflags) { // no-op, should be implemented in derived class } void DragDropCtrl::DragRect(const Rect& last, const Rect& next, dword keyflags) { ViewDraw draw(this); DrawDragDropRect(draw, IsNull(last) ? Rect(Null) : last.Inflated(1), IsNull(next) ? Rect(Null) : next.Inflated(1), 3); } void DragDropCtrl::DropRect(const Rect& rc, dword keyflags) { // no-op, should be implemented in derived class } void DragDropCtrl::Cancel() { } void DragDropCtrl::DragShow(bool _show) { if(_show && state == HIDDEN) { Drag(start, Null, last, last_key); state = ON; } if(!_show && state == ON) { Drag(start, last, Null, last_key); state = HIDDEN; } } void DragDropCtrl::LeftDown(Point pt, dword keyflags) { SetWantFocus(); LLOG("DragDropCtrl::LeftDown -> " << pt << ", keyflags " << FormatIntHex(keyflags)); if(Push(pt, last_key = keyflags)) { // begin drag & drop state = POSSIBLE; start = last = pt; SetCapture(); } } void DragDropCtrl::LeftDouble(Point pt, dword keyflags) { SetWantFocus(); Push(pt, keyflags | K_MOUSEDOUBLE); } void DragDropCtrl::DragStop(bool accept, dword keyflags) { ReleaseCapture(); DragHide(); if(state == HIDDEN && accept) Drop(start, last, last_key = keyflags); else if(state == POSSIBLE && accept) Click(start, last_key = keyflags); else Cancel(); state = OFF; } void DragDropCtrl::LeftUp(Point pt, dword keyflags) { LLOG("DragDropCtrl::LeftUp -> " << pt); DragStop(true, last_key); } void DragDropCtrl::RightDown(Point pt, dword keyflags) { DragStop(false, last_key); SetWantFocus(); LLOG("DragDropCtrl::RightDown -> " << pt << ", keyflags " << FormatIntHex(keyflags)); if(Push(pt, last_key = keyflags)) { // begin drag & drop state = POSSIBLE; start = last = pt; SetCapture(); } } void DragDropCtrl::RightDouble(Point pt, dword keyflags) { SetWantFocus(); Click(pt, keyflags | K_MOUSEDOUBLE); } void DragDropCtrl::RightUp(Point pt, dword keyflags) { LLOG("DragDropCtrl::RightUp -> " << pt); DragStop(true, last_key); } void DragDropCtrl::MouseMove(Point pt, dword keyflags) { LLOG("DragDropCtrl::MouseMove -> " << pt); if(keyflags != last_key) DragHide(); if(state == POSSIBLE && IsDragDistance(pt, start)) { state = ON; Drag(start, Null, last = pt, last_key = keyflags); } else if(state == ON || state == HIDDEN) { Point plast = (state == ON ? last : Point(Null)); last = pt; last_key = keyflags; state = ON; Drag(start, plast, pt, last_key); } } bool DragDropCtrl::Key(dword key, int repcnt) { if(key == K_ESCAPE) { DragStop(false); return true; } return Ctrl::Key(key, repcnt); } ////////////////////////////////////////////////////////////////////// // StdArrayOrder:: bool StdArrayOrder::operator () (const Vector& row1, const Vector& row2) const { for(int t = 0; t < index.GetCount(); t++) if(int c = StdValueCompare(row1[index[t]], row2[index[t]], lang[t])) return (desc[t] ? c > 0 : c < 0); return false; } ////////////////////////////////////////////////////////////////////// // ArrayPair:: ArrayPair::ArrayPair() { key_index = 0; sort_index = -1; pane_pos = 5000; order = &std_order; NoWantFocus(); Transparent(); *this << left << add << add_all << remove << remove_all << right; left.WhenKillCursor = left.WhenEnterRow = THISBACK(UpdateGUI); right.WhenKillCursor = right.WhenEnterRow = THISBACK(OnRightCursor); left.WhenBar = THISBACK(ToolLeft); right.WhenBar = THISBACK(ToolRight); add <<= THISBACK(OnAdd); add_all <<= THISBACK(OnAddAll); remove <<= THISBACK(OnRemove); remove_all <<= THISBACK(OnRemoveAll); Vert(false); } ArrayPair& ArrayPair::Vert(bool vert) { is_vert = vert; if(is_vert) { add.SetImage(TCtrlImg::pair_down_arrow()); add_all.SetImage(TCtrlImg::pair_down_arrows()); remove.SetImage(TCtrlImg::pair_up_arrow()); remove_all.SetImage(TCtrlImg::pair_up_arrows()); } else { add.SetImage(TCtrlImg::pair_right_arrow()); add_all.SetImage(TCtrlImg::pair_right_arrows()); remove.SetImage(TCtrlImg::pair_left_arrow()); remove_all.SetImage(TCtrlImg::pair_left_arrows()); } Layout(); return *this; } void ArrayPair::SetPos(int pos) { pane_pos = pos; Layout(); } void ArrayPair::Layout() { Size size = GetSize(); Size button = Ctrl::LayoutZoom(24, 24); enum { HGAP = 4, VGAP = 4, BGAP = 2 * VGAP, }; if(is_vert) { int tpart = iscale(size.cy, pane_pos, 10000); left.SetRect(0, 0, size.cx, tpart - (button.cy >> 1) - HGAP); right.SetRect(Rect(0, tpart + (button.cy >> 1) + HGAP, size.cx, size.cy)); int total_wd = 4 * button.cx + 2 * VGAP + BGAP; Rect brc = RectC((size.cx - total_wd) >> 1, tpart - (button.cy >> 1), button.cx, button.cy); add.SetRect(brc); brc.OffsetHorz(button.cx + VGAP); add_all.SetRect(brc); brc.OffsetHorz(button.cx + BGAP); remove.SetRect(brc); brc.OffsetHorz(button.cx + VGAP); remove_all.SetRect(brc); } else { int tpart = iscale(size.cx, pane_pos, 10000); left.SetRect(0, 0, tpart - (button.cx >> 1) - HGAP, size.cy); int rl = tpart + (button.cx >> 1) + HGAP; right.SetRect(rl, 0, size.cx - rl, size.cy); int total_ht = 4 * button.cy + 2 * VGAP + BGAP; Rect brc = RectC(tpart - (button.cx >> 1), (size.cy - total_ht) >> 1, button.cx, button.cy); add.SetRect(brc); brc.OffsetVert(button.cy + VGAP); add_all.SetRect(brc); brc.OffsetVert(button.cy + BGAP); remove.SetRect(brc); brc.OffsetVert(button.cy + VGAP); remove_all.SetRect(brc); } } void ArrayPair::SetData(const Value& value) { ASSERT(key_index >= 0 && key_index < right.GetIndexCount()); if(!right.FindSetCursor(value, key_index)) right.KillCursor(); } Value ArrayPair::GetData() const { ASSERT(key_index >= 0 && key_index < right.GetIndexCount()); if(right.IsCursor()) return right.Get(key_index); else return Value(); } void ArrayPair::SetKey(int i) { key_index = i; } void ArrayPair::SetKey(Id id) { key_index = left.GetPos(id); } void ArrayPair::SetSort(int i, const ArrayCtrl::Order& o) { sort_index = i; order = &o; } void ArrayPair::SetSort(int i) { sort_index = i; order = &std_order; std_order.Set(i); } void ArrayPair::ToolLeft(Bar& bar) { ToolAdd(bar); ToolAddAll(bar); left.StdBar(bar); } void ArrayPair::ToolAdd(Bar& bar) { bar.Add(left.IsCursor(), "Přidat", THISBACK(OnAdd)) .Key(K_RIGHT) .Help("Přidat aktuální řádek tabulky k vybraným hodnotám"); } void ArrayPair::OnAdd() { int lc = left.GetCursor(); if(lc < 0) return; Vector row = left.ReadRow(lc); left.Remove(lc); int rc = right.GetCursor() + 1; Value key = row[key_index]; right.Insert(rc, row); if(sort_index >= 0) SortRight(); right.FindSetCursor(key, key_index); if(left.GetCount() > 0) left.SetCursor(lc < left.GetCount() ? lc : lc - 1); else right.SetWantFocus(); UpdateGUI(); UpdateAction(); WhenAdd(); } void ArrayPair::ToolAddAll(Bar& bar) { bar.Add(left.GetCount() > 0, "Přidat vše", THISBACK(OnAddAll)) .Key(K_CTRL_RIGHT) .Help("Vybrat všechny řádky tabulky"); } void ArrayPair::OnAddAll() { if(left.GetCount() == 0) return; int rc = right.GetCursor() + 1; for(int i = 0; i < left.GetCount(); i++) { right.Insert(rc + i, left.ReadRow(i)); right.SetCursor(rc + i); WhenAdd(); } if(sort_index >= 0) SortRight(); left.Clear(); right.SetCursor(0); right.SetWantFocus(); UpdateGUI(); UpdateAction(); } void ArrayPair::ToolRight(Bar& bar) { ToolRemove(bar); ToolRemoveAll(bar); right.StdBar(bar); } void ArrayPair::ToolRemove(Bar& bar) { bar.Add(right.IsCursor(), "Odebrat", THISBACK(OnRemove)) .Key(K_LEFT) .Help("Odebrat aktuální řádek tabulky z výběru"); } void ArrayPair::OnRemove() { int rc = right.GetCursor(); if(rc < 0) return; Vector row = right.ReadRow(rc); right.Remove(rc); int lc = left.GetCursor() + 1; Value key = row[key_index]; left.Insert(lc, row); if(sort_index >= 0) SortLeft(); left.FindSetCursor(key, key_index); if(right.GetCount() > 0) right.SetCursor(rc < right.GetCount() ? rc : rc - 1); else left.SetWantFocus(); UpdateGUI(); UpdateAction(); } void ArrayPair::ToolRemoveAll(Bar& bar) { bar.Add(right.GetCount() > 0, "Odebrat vše", THISBACK(OnRemoveAll)) .Key(K_CTRL_LEFT) .Help("Vyprázdnit tabulku vybraných hodnot"); } void ArrayPair::OnRemoveAll() { if(right.GetCount() == 0) return; int lc = left.GetCursor() + 1; for(int i = 0; i < right.GetCount(); i++) left.Insert(lc + i, right.ReadRow(i)); if(sort_index >= 0) SortLeft(); left.SetCursor(0); right.Clear(); left.SetWantFocus(); UpdateGUI(); UpdateAction(); } void ArrayPair::OnRightCursor() { UpdateGUI(); Action(); } void ArrayPair::SortLeft() { left.Sort(*order); } void ArrayPair::SortRight() { right.Sort(*order); } void ArrayPair::UpdateGUI() { add.Enable(left.IsCursor()); add_all.Enable(left.GetCount() > 0); remove.Enable(right.IsCursor()); remove_all.Enable(right.GetCount() > 0); } ValueArrayCtrl::ValueArrayCtrl() { WhenArrayAction = THISBACK(OnArrayAction); WhenAccept = true; } void ValueArrayCtrl::SetData(const Value& data) { ValueArray rows = data; SetCount(rows.GetCount()); for(int r = 0; r < GetCount(); r++) { ValueArray cols = rows[r]; ASSERT(cols.GetCount() == GetIndexCount()); for(int c = 0; c < cols.GetCount(); c++) Set(r, c, cols[c]); } WhenSetData(); } Value ValueArrayCtrl::GetData() const { ValueArray rows; for(int r = 0; r < GetCount(); r++) { ValueArray cols; for(int c = 0; c < GetIndexCount(); c++) cols.Add(Get(r, c)); rows.Add(cols); } return rows; } bool ValueArrayCtrl::Accept() { return WhenAccept() && ArrayCtrl::Accept(); } void ValueArrayCtrl::OnArrayAction() { SetModify(); } ////////////////////////////////////////////////////////////////////// // Option3:: /* Option3::Option3() : not_null(false), state(0) { } void Option3::Paint(Draw& w) { Size sz = GetSize(); if(!IsTransparent()) w.DrawRect(0, 0, sz.cx, sz.cy, SLtGray); static const Image indf[] = { CtrlImg::option0(), CtrlImg::option1(), CtrlImg::option0d(), CtrlImg::option1d(), CtrlImg::option0f(), CtrlImg::option1f(), }; Image image; if(!IsShowEnabled()) image = indf[state == 1 ? 3 : 2]; else if(push) image = indf[state == 1 ? 5 : 4]; else image = indf[state]; bool ds = !IsShowEnabled() || state == 2; bool switchimage = false; DrawLabel(w, false, HasFocus(), image, false, 1, ALIGN_LEFT); } Size Option3::GetMinSize() const { return AddFrameSize(16, max(CtrlImg::option0().GetSize().cy, ScreenInfo().GetFontInfo().GetHeight()) + 2); } void Option3::SetData(const Value& data) { if(IsNull(data)) state = not_null ? 0 : 2; else if(IsNumber(data)) state = (double)data ? 1 : 0; else NEVER(); Update(); RefreshPush(); } Value Option3::GetData() const { return state <= 1 ? state : int(Null); } void Option3::RefreshPush() { Refresh(0, 0, CtrlImg::option0().GetSize().cx, GetSize().cy); } void Option3::RefreshFocus() { Refresh(); } void Option3::PerformAction() { state = (state == 2 || state == 1 && not_null ? 0 : state + 1); UpdateAction(); RefreshPush(); } */ bool ShowErrorFocus(bool cond, const char *text, Ctrl& focus) { if(!cond) return false; Exclamation(text); focus.SetFocus(); return true; } END_UPP_NAMESPACE