|
|
Home » U++ Library support » U++ Library : Other (not classified elsewhere) » Drag and Drop between instances [FEATURE REQUEST]
Drag and Drop between instances [FEATURE REQUEST] [message #29731] |
Thu, 11 November 2010 00:03  |
nixnixnix
Messages: 415 Registered: February 2007 Location: Kelowna, British Columbia
|
Senior Member |
|
|
Hi,
I can't find anything on this but I really suspect it already exists.
My users want to be able to pick up an object from my TreeCtrl and drop it into another instance of my software. The items in my TreeCtrl are all serializable and can already be transferred from one instance to another by writing to file, but D&D would be very slick. However, they don't exist outside the software at the time when the D&D is done.
Is this already possible in UPP or would it be a new feature?
Nick
|
|
|
|
Re: Drag and Drop between instances [FEATURE REQUEST] [message #30009 is a reply to message #29790] |
Thu, 02 December 2010 20:28   |
nixnixnix
Messages: 415 Registered: February 2007 Location: Kelowna, British Columbia
|
Senior Member |
|
|
Cool! Is there an example of this? I already have serialisation functions to copy to and from the clipboard (if that is how it is done).
I get that I need to override DragLeave() in my TreeCtrl and I see there is a member called Clipboard that is of type PasteClip. I imagine that I need to create a StringStream and serialize to it. However, connecting the StringStream to the clipboard is where I am missing a piece.
Hmmm, the more I look the less I think I have a clue. There are no reference examples or documentation for this and when I look at the objects involved (like PasteClip) there are no functions which would let me write to the clipboard.
Nick
[Updated on: Fri, 03 December 2010 02:21] Report message to a moderator
|
|
|
Re: Drag and Drop between instances [FEATURE REQUEST] [message #30140 is a reply to message #30009] |
Sat, 11 December 2010 10:34   |
 |
mirek
Messages: 14255 Registered: November 2005
|
Ultimate Member |
|
|
I have added reference/DragAndDrop example:
#include "CtrlLib/CtrlLib.h"
using namespace Upp;
const char *MyDnDName = "MyReferenceDragAndDropExample";
struct MyApp : TopWindow {
TreeCtrl tree;
typedef MyApp CLASSNAME;
void DropInsert(int parent, int ii, PasteClip& d)
{
tree.AdjustAction(parent, d);
if(d.Accept(MyDnDName)) {
tree.SetCursor(tree.Insert(parent, ii, Image(), ~d));
tree.SetFocus();
}
}
void Drag()
{
if(!tree.IsCursor())
return;
int id = tree.GetCursor();
String text = tree.Get();
Size isz = GetTextSize(text.ToWString(), StdFont());
ImageDraw iw(isz);
iw.DrawRect(isz, White);
iw.DrawText(0, 0, text);
VectorMap<String, ClipData> clip;
clip.Add(MyDnDName, text);
if(DoDragAndDrop(clip, iw) == DND_MOVE)
tree.Remove(id);
}
MyApp() {
Add(tree.SizePos());
Vector<int> parent, parent2;
parent.Add(0);
tree.SetRoot(Image(), "The Tree");
for(int i = 1; i < 10000; i++) {
parent.Add(tree.Add(parent[rand() % parent.GetCount()], Image(),
FormatIntRoman(i, true)));
if((rand() & 3) == 0)
tree.Open(parent.Top());
}
tree.Open(0);
tree.WhenDropInsert = THISBACK(DropInsert);
tree.WhenDrag = THISBACK(Drag);
Sizeable();
}
};
GUI_APP_MAIN
{
MyApp().Run();
}
Frankly, there are more details to care about, so we might want yet another example with even more low-level D&D (and some fine dics about D&D would be fine as well, right?), but as first iteration this might be helpful.
Mirek
|
|
|
Re: Drag and Drop between instances [FEATURE REQUEST] [message #30608 is a reply to message #30140] |
Wed, 12 January 2011 02:37   |
nixnixnix
Messages: 415 Registered: February 2007 Location: Kelowna, British Columbia
|
Senior Member |
|
|
Thanks Mirek,
That all works easy enough. However, an extra complication is that sometimes I DnD between instances but most of the time within the same instance. My code looks like this:
void LayerTree::DropInsert(int parent, int ii, PasteClip& d)
{
AdjustAction(parent, d);
if(AcceptInternal<LayerTree>(d, "mytreedrag")) {
const TreeCtrl &src = GetInternal<LayerTree>(d);
Vector<int> sel = src.GetSel();
SaveStateToLayers(); // we need to rebuild the tree
for(int i=0;i<sel.GetCount();i++)
{
Drop(parent,sel[i],ii);
}
m_ptr->SetTree();
SetFocus();
return;
}
else if(d.Accept("externalInstance"))
{
m_ptr->SetStatus("dropped");
StringStream ss(d.Get());
Layer* pLayer = Layer::Load(ss);
if(pLayer==NULL)
return;
m_ptr->AddLayer(pLayer);
}
// if(AcceptText(d))
// {
// SetCursor(Insert(parent, ii, Image(), GetString(d)));
// SetFocus();
// return;
// }
}
void LayerTree::Drag()
{
if(m_ptr->AreWeBusy())
return;
if(DoDragAndDrop(InternalClip(*this, "mytreedrag"),
this->GetDragSample()) == DND_MOVE)
{
RemoveSelection();
}
}
void LayerTree::DragLeave()
{
int id;
id = GetCursor();
if(id<=0) // if id==0 then its the root node which is not a layer
return;
// copy to clipboard
TreeCtrl::Node node = GetNode(id);
LayerOption* ptr = (LayerOption*)~node.ctrl;
Layer* pLayer = ptr->GetLayer();
StringStream ss;
ss.SetStoring();
ss.Put("layer");
int type = int(pLayer->GetType());
ss.Put32(type);
pLayer->Serialize(ss);
String sLayer(ss);
String text = pLayer->GetName();
Size isz = GetTextSize(text.ToWString(), StdFont());
ImageDraw iw(isz);
iw.DrawRect(isz, White);
iw.DrawText(0, 0, text);
VectorMap<String, ClipData> clip;
clip.Add("externalInstance", sLayer);
if(DoDragAndDrop(clip, iw) == DND_MOVE)
{
}
TreeCtrl::DragLeave();
}
My questions are: do I need to treat my internal drag and drops the same way as my external ones? Is there an external and an internal DnD working simultaneously? Is there a way to know which instance a DnD is coming from?
It all seems to work fine so long as my cursor doesn't leave and return to the same instance.
Cheers,
Nick
|
|
|
|
|
|
|
Re: Drag and Drop between instances [FEATURE REQUEST] [message #30631 is a reply to message #30626] |
Thu, 13 January 2011 01:53   |
nixnixnix
Messages: 415 Registered: February 2007 Location: Kelowna, British Columbia
|
Senior Member |
|
|
Hi Mirek,
Yes that was a typo and should have been DragLeave()
This is my code as it stands just now.
void LayerTree::DropInsert(int parent, int ii, PasteClip& d)
{
AdjustAction(parent, d);
if(!IsDragAndDropSource() && d.Accept("externalInstance"))
{
m_ptr->SetStatus("dropped");
StringStream ss(d.Get());
Layer* pLayer = Layer::Load(ss);
if(pLayer==NULL)
return;
if(parent==0)
{
m_ptr->AddLayer(pLayer);
return;
}
TreeCtrl::Node node = GetNode(parent);
LayerOption* ptr = (LayerOption*)~node.ctrl;
Layer* pParent = ptr->GetLayer();
if(pParent)
{
pParent->AddChild(pLayer);
m_ptr->SetTree();
m_ptr->RefreshNow();
}
else
{
m_ptr->AddLayer(pLayer);
}
}
else if(AcceptInternal<LayerTree>(d, "mytreedrag") )
{
const TreeCtrl &src = GetInternal<LayerTree>(d);
Vector<int> sel = src.GetSel();
SaveStateToLayers(); // we need to rebuild the tree
for(int i=0;i<sel.GetCount();i++)
{
Drop(parent,sel[i],ii);
}
m_ptr->SetTree();
SetFocus();
return;
}
}
void LayerTree::Drag()
{
if(m_ptr->AreWeBusy())
return;
if(DoDragAndDrop(InternalClip(*this, "mytreedrag"),
this->GetDragSample()) == DND_MOVE)
{
RemoveSelection();
}
}
void LayerTree::DragLeave()
{
int id;
id = GetCursor();
if(id<=0) // if id==0 then its the root node which is not a layer
return;
// copy to clipboard
TreeCtrl::Node node = GetNode(id);
LayerOption* ptr = (LayerOption*)~node.ctrl;
Layer* pLayer = ptr->GetLayer();
StringStream ss;
ss.SetStoring();
ss.Put("layer");
int type = int(pLayer->GetType());
ss.Put32(type);
pLayer->Serialize(ss);
String sLayer(ss);
String text = pLayer->GetName();
Size isz = GetTextSize(text.ToWString(), StdFont());
ImageDraw iw(isz);
iw.DrawRect(isz, White);
iw.DrawText(0, 0, text);
VectorMap<String, ClipData> clip;
clip.Add("externalInstance", sLayer);
if(DoDragAndDrop(clip, iw) == DND_MOVE)
{
}
TreeCtrl::DragLeave();
}
I am definitely missing something in my understanding of how these methods are triggered and what they do and so of how to get them to do what I want. I would like to leave the internal clip in tact and to only trigger the external clip once I know it is being dropped on another instance although I expect that is not possible.
Thanks,
Nick
|
|
|
Re: Drag and Drop between instances [FEATURE REQUEST] [message #30637 is a reply to message #30631] |
Thu, 13 January 2011 09:47   |
 |
mirek
Messages: 14255 Registered: November 2005
|
Ultimate Member |
|
|
nixnixnix wrote on Wed, 12 January 2011 19:53 | Hi Mirek,
Yes that was a typo and should have been DragLeave()
This is my code as it stands just now.
void LayerTree::DropInsert(int parent, int ii, PasteClip& d)
{
AdjustAction(parent, d);
if(!IsDragAndDropSource() && d.Accept("externalInstance"))
{
m_ptr->SetStatus("dropped");
StringStream ss(d.Get());
Layer* pLayer = Layer::Load(ss);
if(pLayer==NULL)
return;
if(parent==0)
{
m_ptr->AddLayer(pLayer);
return;
}
TreeCtrl::Node node = GetNode(parent);
LayerOption* ptr = (LayerOption*)~node.ctrl;
Layer* pParent = ptr->GetLayer();
if(pParent)
{
pParent->AddChild(pLayer);
m_ptr->SetTree();
m_ptr->RefreshNow();
}
else
{
m_ptr->AddLayer(pLayer);
}
}
else if(AcceptInternal<LayerTree>(d, "mytreedrag") )
{
const TreeCtrl &src = GetInternal<LayerTree>(d);
Vector<int> sel = src.GetSel();
SaveStateToLayers(); // we need to rebuild the tree
for(int i=0;i<sel.GetCount();i++)
{
Drop(parent,sel[i],ii);
}
m_ptr->SetTree();
SetFocus();
return;
}
}
void LayerTree::Drag()
{
if(m_ptr->AreWeBusy())
return;
if(DoDragAndDrop(InternalClip(*this, "mytreedrag"),
this->GetDragSample()) == DND_MOVE)
{
RemoveSelection();
}
}
void LayerTree::DragLeave()
{
int id;
id = GetCursor();
if(id<=0) // if id==0 then its the root node which is not a layer
return;
// copy to clipboard
TreeCtrl::Node node = GetNode(id);
LayerOption* ptr = (LayerOption*)~node.ctrl;
Layer* pLayer = ptr->GetLayer();
StringStream ss;
ss.SetStoring();
ss.Put("layer");
int type = int(pLayer->GetType());
ss.Put32(type);
pLayer->Serialize(ss);
String sLayer(ss);
String text = pLayer->GetName();
Size isz = GetTextSize(text.ToWString(), StdFont());
ImageDraw iw(isz);
iw.DrawRect(isz, White);
iw.DrawText(0, 0, text);
VectorMap<String, ClipData> clip;
clip.Add("externalInstance", sLayer);
if(DoDragAndDrop(clip, iw) == DND_MOVE)
{
}
TreeCtrl::DragLeave();
}
I am definitely missing something in my understanding of how these methods are triggered and what they do and so of how to get them to do what I want. I would like to leave the internal clip in tact and to only trigger the external clip once I know it is being dropped on another instance although I expect that is not possible.
Thanks,
Nick
|
Ah, I see. Well, without going into details, I can imagine that this can couse great havoc 
DragLeave is intended only for visual feedback in dnd target. It is sort of MouseLeave equivalent (actually, all 'Drag' functions are...)
In any case, all dragged formats have to be known at the moment drag starts. If you do not want to create binary data at that moment, you should rather use
ClipData(const Value& data, String (*render)(const Value& data));
constructor - render is supposed to 'convert' data (which can be basically anything) into your binary binary data, in esence exactly what you are trying to do in DragLeave.
|
|
|
|
|
|
|
|
Goto Forum:
Current Time: Sun Apr 27 01:32:56 CEST 2025
Total time taken to generate the page: 0.01139 seconds
|
|
|