diff --git a/uppsrc/Core/Convert.h b/uppsrc/Core/Convert.h index 0f9ad38c4..82795d6f8 100644 --- a/uppsrc/Core/Convert.h +++ b/uppsrc/Core/Convert.h @@ -310,13 +310,13 @@ struct LambdaConvertClass : Convert { virtual Value Format(const Value& q) const { return format(q); } virtual Value Scan(const Value& text) const { return scan(text); } - virtual int Filter(int chr) const { return Filter(chr); } + virtual int Filter(int chr) const { return filter(chr); } LambdaConvertClass(F format, S scan, R filter) : format(format), scan(scan), filter(filter) {} }; template -const LambdaConvertClass& LambdaConvert(F format, S scan, R filter) +const auto& LambdaConvert(F format, S scan, R filter) { static LambdaConvertClass x(format, scan, filter); return x; diff --git a/uppsrc/CtrlLib/DisplayPopup.cpp b/uppsrc/CtrlLib/DisplayPopup.cpp index 1170ea729..f1c65e7a4 100644 --- a/uppsrc/CtrlLib/DisplayPopup.cpp +++ b/uppsrc/CtrlLib/DisplayPopup.cpp @@ -9,32 +9,32 @@ Point DisplayPopup::Op(Point p) void DisplayPopup::LeftDown(Point p, dword flags) { - ctrl->LeftDown(Op(p), flags); + if(ctrl) ctrl->LeftDown(Op(p), flags); } void DisplayPopup::LeftDrag(Point p, dword flags) { - ctrl->LeftDrag(Op(p), flags); + if(ctrl) ctrl->LeftDrag(Op(p), flags); } void DisplayPopup::LeftDouble(Point p, dword flags) { - ctrl->LeftDouble(Op(p), flags); + if(ctrl) ctrl->LeftDouble(Op(p), flags); } void DisplayPopup::RightDown(Point p, dword flags) { - ctrl->RightDown(Op(p), flags); + if(ctrl) ctrl->RightDown(Op(p), flags); } void DisplayPopup::LeftUp(Point p, dword flags) { - ctrl->LeftUp(Op(p), flags); + if(ctrl) ctrl->LeftUp(Op(p), flags); } void DisplayPopup::MouseWheel(Point p, int zdelta, dword flags) { - ctrl->MouseWheel(Op(p), zdelta, flags); + if(ctrl) ctrl->MouseWheel(Op(p), zdelta, flags); } void DisplayPopup::MouseLeave() diff --git a/uppsrc/CtrlLib/TreeCtrl.cpp b/uppsrc/CtrlLib/TreeCtrl.cpp index 4b1ef1705..bae192b99 100644 --- a/uppsrc/CtrlLib/TreeCtrl.cpp +++ b/uppsrc/CtrlLib/TreeCtrl.cpp @@ -136,6 +136,7 @@ Size TreeCtrl::Item::GetSize(const Display *treedisplay) const void TreeCtrl::SetRoot(const TreeCtrl::Node& n) { + KillEdit(); (TreeCtrl::Node &)item[0] = n; RefreshItem(0); } @@ -157,6 +158,7 @@ void TreeCtrl::SetRoot(const Image& img, Ctrl& ctrl, int cx, int cy) int TreeCtrl::Insert(int parentid, int i, const TreeCtrl::Node& n) { + KillEdit(); int id; if(freelist >= 0) { id = freelist; @@ -471,7 +473,6 @@ void TreeCtrl::SyncTree(bool immediate) SyncAfterSync(restorefocus); else PostCallback(PTEBACK1(SyncAfterSync, restorefocus)); - KillEdit(); } void TreeCtrl::SyncCtrls(bool add, Ctrl *restorefocus) @@ -835,6 +836,7 @@ void TreeCtrl::ShiftSelect(int l1, int l2) void TreeCtrl::LeftDrag(Point p, dword keyflags) { + OkEdit(); if(p.y + sb.y > sb.GetTotal().cy) return; WhenDrag(); @@ -853,7 +855,7 @@ Rect TreeCtrl::GetValueRect(const Line& l) const return RectC(x, l.y - org.y + (msz.cy - vsz.cy) / 2, vsz.cx, vsz.cy); } -void TreeCtrl::DoClick(Point p, dword flags, bool down) +void TreeCtrl::DoClick(Point p, dword flags, bool down, bool canedit) { Point org = sb; itemclickpos = Null; @@ -870,19 +872,23 @@ void TreeCtrl::DoClick(Point p, dword flags, bool down) Open(l.itemi, !IsOpen(l.itemi)); } else { + auto DoEdit = [&](int qq) { + if(down) + KillEdit(); + if(cursor == qq && qq >= 0 && cursor > 0 && !HasCapture() && WhenEdited && !(flags & (K_SHIFT|K_CTRL)) && + GetValueRect(l).Contains(p) && canedit) + SetTimeCallback(750, THISBACK(StartEdit), TIMEID_STARTEDIT); + }; if(down && IsSel(l.itemi)) { // make possible DnD of multiple items selclick = true; if(down) WhenLeftClick(); + DoEdit(i); return; } SetWantFocus(); int q = cursor; - int qq = q; - if(IsEdit()) { - OkEdit(); - qq = -1; - } + int qq = cursor; SetCursorLine(i, true, false, true); if(multiselect) { int id = GetCursor(); @@ -904,11 +910,7 @@ void TreeCtrl::DoClick(Point p, dword flags, bool down) if(down) WhenLeftClick(); Select(); - - KillEdit(); - if(cursor == qq && qq >= 0 && !HasCapture() && WhenEdited && !(flags & (K_SHIFT|K_CTRL)) && - GetValueRect(l).Contains(p)) - SetTimeCallback(750, [=] { StartEdit(); }, TIMEID_STARTEDIT); + DoEdit(qq); } } @@ -916,7 +918,13 @@ void TreeCtrl::KillEdit() { sb.x.Enable(); sb.y.Enable(); + edit_cursor = -1; KillTimeCallback(TIMEID_STARTEDIT); + if(editor && editor->GetParent() == this) { + int b = editor->HasFocus(); + editor->Remove(); + if(b) SetFocus(); + } } void TreeCtrl::StartEdit() { @@ -938,29 +946,29 @@ void TreeCtrl::StartEdit() { editor->SetFocus(); sb.x.Disable(); sb.y.Disable(); + edit_cursor = GetCursor(); + SyncInfo(); + WhenStartEdit(edit_cursor); } void TreeCtrl::EndEdit() { KillEdit(); - if(editor) { - int b = editor->HasFocus(); - editor->Hide(); - if(b) SetFocus(); - } } void TreeCtrl::OkEdit() { - EndEdit(); - int c = GetCursor(); - if(c >= 0 && editor) - WhenEdited(~*editor); + if(IsEdit()) { + int q = edit_cursor; + if(q >= 0 && editor) + WhenEdited(q, ~*editor); + EndEdit(); + } } void TreeCtrl::SyncInfo() { - if(IsShutdown() || IsPainting()) + if(IsShutdown() || IsPainting() || dirty) return; - if((HasMouse() || info.HasMouse()) && popupex) { + if((HasMouse() || info.HasMouse()) && popupex && !IsEdit()) { Point p = GetMouseViewPos(); Point org = sb; int i = FindLine(p.y + org.y); @@ -1000,20 +1008,22 @@ void TreeCtrl::MouseMove(Point p, dword) void TreeCtrl::LeftDown(Point p, dword flags) { - DoClick(p, flags, true); + OkEdit(); + DoClick(p, flags, true, true); } void TreeCtrl::LeftUp(Point p, dword keyflags) { if(selclick) { - DoClick(p, keyflags, false); + DoClick(p, keyflags, false, false); selclick = false; } } void TreeCtrl::LeftDouble(Point p, dword flags) { - LeftDown(p, flags); + OkEdit(); + DoClick(p, flags, true, false); Point org = sb; if(p.y + org.y > sb.GetTotal().cy) return; @@ -1026,6 +1036,7 @@ void TreeCtrl::LeftDouble(Point p, dword flags) void TreeCtrl::RightDown(Point p, dword flags) { + OkEdit(); Point org = sb; if(p.y + org.y < sb.GetTotal().cy) { int i = FindLine(p.y + org.y); @@ -1352,6 +1363,8 @@ void TreeCtrl::GotFocus() void TreeCtrl::LostFocus() { + if(editor && !editor->HasFocus()) + OkEdit(); if(dirty) return; RefreshLine(cursor); @@ -1360,6 +1373,12 @@ void TreeCtrl::LostFocus() SyncInfo(); } +void TreeCtrl::ChildLostFocus() +{ + if(editor && !editor->HasFocus()) + OkEdit(); +} + void TreeCtrl::ChildRemoved(Ctrl *) { if(!IsShutdown() && !chldlck) diff --git a/uppsrc/CtrlLib/TreeCtrl.h b/uppsrc/CtrlLib/TreeCtrl.h index b4e59e04c..b4cfc3dc8 100644 --- a/uppsrc/CtrlLib/TreeCtrl.h +++ b/uppsrc/CtrlLib/TreeCtrl.h @@ -14,6 +14,7 @@ public: virtual void GotFocus(); virtual void LostFocus(); virtual void ChildGotFocus(); + virtual void ChildLostFocus(); virtual void ChildRemoved(Ctrl *); virtual void SetData(const Value& data); virtual Value GetData() const; @@ -125,6 +126,7 @@ private: One edit_string; Ctrl *editor = NULL; + int edit_cursor = -1; struct SortOrder; @@ -157,14 +159,14 @@ private: bool DnDInsert(int ii, int py, int q, PasteClip& d); void RefreshSel(); void GatherSel(int id, Vector& sel) const; - void DoClick(Point p, dword flags, bool down); + void DoClick(Point p, dword flags, bool down, bool canedit); void SyncInfo(); void SyncAfterSync(Ptr restorefocus); Rect GetValueRect(const Line& l) const; void StartEdit(); void EndEdit(); void KillEdit(); - bool IsEdit() const { return editor && editor->IsVisible(); } + bool IsEdit() const { return editor && editor->GetParent() == this; } void OkEdit(); enum { @@ -194,7 +196,8 @@ public: Event WhenDropInsert; Event WhenDrop; - Event WhenEdited; + Event WhenStartEdit; + Event WhenEdited; // deprecated - use WhenSel Event<> WhenCursor; diff --git a/uppsrc/CtrlLib/src.tpp/TreeCtrl_en-us.tpp b/uppsrc/CtrlLib/src.tpp/TreeCtrl_en-us.tpp index 162ad13a2..34934e1fe 100644 --- a/uppsrc/CtrlLib/src.tpp/TreeCtrl_en-us.tpp +++ b/uppsrc/CtrlLib/src.tpp/TreeCtrl_en-us.tpp @@ -84,15 +84,22 @@ do not apply `- drop into empty area. See [^PasteClip^ PasteClip] for more details.&] [s3; &] [s4; &] -[s5;:Upp`:`:TreeCtrl`:`:WhenEdited: [_^Upp`:`:Event^ Event]<[@(0.0.255) const]_Value[@(0.0.255) `& -]>_[* WhenEdited]&] -[s2;%% When defined, TreeCtrl will start editing the node value when +[s5;:Upp`:`:TreeCtrl`:`:WhenStartEdit: [_^Upp`:`:Event^ Event]<[@(0.0.255) int]>_[* WhenSta +rtEdit]&] +[s2;%% Called before TreeCtrl starts editing the node. The first +parameter is the cursor of edited element.&] +[s3; &] +[s4; &] +[s5;:Upp`:`:TreeCtrl`:`:WhenEdited: [_^Upp`:`:Event^ Event]<[@(0.0.255) int][%% ,][@(0.0.255) +const]_Value[@(0.0.255) `&]>_[* WhenEdited]&] +[s2;%% When defined TreeCtrl will start editing the node value when clicked on already select one (after a while) in a way similar to e.g. FileSel file renaming. When the value is accepted, WhenEdit is called with a new value. Value is not changed in TreeCtrl, if that is desired, it is a responsibility of code that is assigned to the WhenEdited. Default editor is EditString and can be changed -with Editor modifier method.&] +with Editor modifier method. The first parameter is the cursor +of edited element.&] [s3; &] [s4; &] [s5;:TreeCtrl`:`:WhenCursor: [_^Callback^ Callback]_[* WhenCursor]&] diff --git a/uppsrc/Sql/Sqls.h b/uppsrc/Sql/Sqls.h index fd66ec7f4..713a1a54a 100644 --- a/uppsrc/Sql/Sqls.h +++ b/uppsrc/Sql/Sqls.h @@ -23,7 +23,7 @@ class SqlRaw : public String, public ValueType { public: operator Value() const { return RawValue(*this); } SqlRaw(const Value& q) - : String(IsNull(q) ? String() : + : String(IsNull(q) ? String() : IsString(q) ? String(q) : String(RawValue::Extract(q))) {} SqlRaw(const String& s) : String(s) {}