This section explains you through an example the steps needed for implementing drag and drop. The example is about using drag and drop to transfer files.
We use a ListTree widget to list directories and files. The file items will be the drag sources. We use a TextWidget for a drop target. When the user press-drag-release a file item over the window of TextWidget, the file will be loaded into the text widget.
How do we transfere files? The simplest way is to transfer the complete path of files. This will work if the file-lister and text-widget are running under the same environment. It will probabily not work if, say, the file-lister and the text-widget are running on machines across two different local networks. So we'll need a way to convert the contents of a file, just in case the text-widget cannot find the file the file-lister supplied.
So we need two target items. We have to create them first.
MY_FILE_NAME_ATOM = EZ_GetAtom("MY_FILE_NAME_ATOM"); MY_FILE_CONTENTS_ATOM = EZ_GetAtom("MY_FILE_CONTENTS_ATOM");
Now we come to the most important part, writing conversion routines. We first explain the encoders which will be registered to file-items. For each file-item, we'll record its full path and the length of the path in the client data slots of its private data structure. So encode the path name does not need too much work.
int encodeFileName(EZ_Item *item, void *data,
char **message, int *length, int *needFree)
if(item)
char *ptr = (char *)EZ_GetItemPtrData(item);
int len = EZ_GetItemIntData(item);
if(len > 0)
*length = len;
*message = ptr;
*needFree = 0; /* we don't want to free it */
return(EZ_DND_SUCCESS);
return(EZ_DND_FAILURE);
To encode the contents of a file, we'll have to figure out the length of the file and allocate a buffer to copy the the contents. We'll do this naively.
int encodeFileContents(EZ_Item *item, void *data,
char **message, int *length, int *needFree)
if(item)
char *ptr = (char *)EZ_GetItemPtrData(item);
int len = EZ_GetItemIntData(item);
if(len > 0)
char *msg;
int c, totalLength = 0;
FILE *fp = fopen(ptr, "r");
if(fp)
while(fgetc(fp) != EOF) totalLength++;
(void)rewind(fp);
msg = (char *)malloc( (totalLength + 1)*sizeof(char));
ptr = msg;
while((c = fgetc(fp)) != EOF) *ptr++ =c;
fclose(fp);
*length = totalLength;
*message = msg;
*needFree = 1; /* ask EZWGL to free msg when done */
return(EZ_DND_SUCCESS);
return(EZ_DND_FAILURE);
Now the decoders. They are registered to the text-widget. For file
names, we'll try to open the file for reading. If succesful, we'll
call EZ_TextLoadFile
to load the file into the text-widget.
Otherwise, we'll return EZ_DND_FAILURE
.
int decodeFileName(EZ_Widget *widget, void *data,
char *message, int length)
if(widget)
if(length > 0)
FILE *fp = fopen(message, "r");
if(fp)
fclose(fp);
EZ_TextLoadFile(widget, message);
return(EZ_DND_SUCCESS);
return(EZ_DND_FAILURE);
To decode the file contents, we'll just treat it as a string and
call EZ_TextInsertString
to insert it into the text-widget.
int decodeFileContents(EZ_Widget *widget, void *data,
char *message, int length)
if(widget)
if(length > 0)
EZ_FreezeWidget(widget);
EZ_TextClear(widget);
EZ_TextInsertString(widget, message);
EZ_UnFreezeWidget(widget);
return(EZ_DND_SUCCESS);
return(EZ_DND_FAILURE);
We have done the essential part needed for drag and drop. Now we'll
just have to put things together and register the encoders and
decoders. Unfortunately the order of registration matters. The
EZwgl will try the conversion targets from the first to the
last of the target list registered to an object.
So we'll register the (en)decoder for target
MY_FILE_NAME_ATOM
first, since converting file names does
not need too much data movement. It is the prefered target.
List below is the complete code for this example.
/******************* Example Source ***************************************/
#include "EZ.h"
int encodeFileName(EZ_Widget *, void *, char **, int *, int *);
int encodeFileContents(EZ_Widget *, void *, char **, int *, int *);
void destroyCallBack(EZ_Item *, void *);
EZ_TreeNode *MyCreateFileItem(char *);
Atom MY_FILE_NAME_ATOM;
Atom MY_FILE_CONTENTS_ATOM;
main(int ac, char **av)
{
EZ_Widget *frame, *listTree;
EZ_TreeNode *root;
EZ_Initialize(ac,av,0);
/* the two target atoms */
MY_FILE_NAME_ATOM = EZ_GetAtom("MY_FILE_NAME_ATOM");
MY_FILE_CONTENTS_ATOM = EZ_GetAtom("MY_FILE_CONTENTS_ATOM");
frame = EZ_CreateWidget(EZ_WIDGET_FRAME, NULL,
EZ_LABEL_STRING, "Drag sources",
EZ_FILL_MODE, EZ_FILL_BOTH,
EZ_WIDTH, 300, EZ_HEIGHT, 400, 0);
listTree = EZ_CreateWidget(EZ_WIDGET_TREE, frame, 0);
/* we have to use a customized fileNode creater
* to register DnD encoders and to remember pathnames
*/
(void)EZ_SetDirTreeFileNodeCreator(MyCreateFileItem);
root = EZ_CreateDirTree("./*"); /* */
EZ_SetListTreeWidgetTree(listTree, root);
EZ_DisplayWidget(frame);
EZ_EventMainLoop();
}
EZ_TreeNode *MyCreateFileItem(char *fname)
{
EZ_TreeNode *node = NULL;
if(fname)
{
EZ_Item *item = NULL;
char *ptr, name[256];
int len;
/* don't mess with fname, work on a local copy of it */
strcpy(name, fname);
len = strlen(name);
if(name[len-1] == '/') name[len-1] = 0;
if((ptr = strrchr(name,'/'))) ptr++;
else ptr = name;
item = EZ_CreateLabelItem(ptr, NULL);
if(item)
{
/* store the full pathname. Use destroyCallback to
* release the allocated memory !!
*/
char *path = (char *)malloc((len+2)*sizeof(char));
(void)strcpy(path,fname);
EZ_ConfigureItem(item, EZ_CLIENT_PTR_DATA, path,
EZ_CLIENT_INT_DATA, len,
EZ_DESTROY_CALLBACK, destroyCallBack, path, 0);
EZ_ItemAddDnDDataEncoder(item,MY_FILE_NAME_ATOM,0,
encodeFileName,NULL, NULL, NULL);
EZ_ItemAddDnDDataEncoder(item,MY_FILE_CONTENTS_ATOM,0,
encodeFileContents, NULL, NULL, NULL);
node = EZ_CreateTreeNode(NULL, item);
}
}
return(node);
}
void destroyCallBack(EZ_Item *item, void *data)
{
if(data) (void)free((char *)data); /* free the allocated path */
}
int encodeFileName(EZ_Item *item, void *data,
char **message, int *length, int *needFree)
{
if(item)
{
char *ptr = (char *)EZ_GetItemPtrData(item);
int len = EZ_GetItemIntData(item);
if(len > 0)
{
*length = len;
*message = ptr;
*needFree = 0;
return(EZ_DND_SUCCESS);
}
}
return(EZ_DND_FAILURE);
}
int encodeFileContents(EZ_Item *item, void *data,
char **message, int *length, int *needFree)
{
if(item)
{
char *ptr = (char *)EZ_GetItemPtrData(item);
int len = EZ_GetItemIntData(item);
if(len > 0)
{
char *msg;
int c, totalLength = 0;
FILE *fp = fopen(ptr, "r");
if(fp) while(fgetc(fp) != EOF) totalLength++;
(void)fseek(fp, 0L, SEEK_SET);
msg = (char *)malloc( (totalLength + 1)*sizeof(char));
ptr = msg;
while((c = fgetc(fp)) != EOF) *ptr++ =c;
fclose(fp);
*length = totalLength;
*message = msg;
*needFree = 1;
return(EZ_DND_SUCCESS);
}
}
return(EZ_DND_FAILURE);
}
/******************* Example Target ***************************************/
#include "EZ.h"
int decodeFileName(EZ_Widget *, void *, char *, int);
int decodeFileContents(EZ_Widget *, void *, char *, int);
Atom MY_FILE_NAME_ATOM;
Atom MY_FILE_CONTENTS_ATOM;
main(int ac, char **av)
{
EZ_Widget *frame, *textW;
EZ_Initialize(ac,av,0);
MY_FILE_NAME_ATOM = EZ_GetAtom("MY_FILE_NAME_ATOM");
MY_FILE_CONTENTS_ATOM = EZ_GetAtom("MY_FILE_CONTENTS_ATOM");
frame = EZ_CreateWidget(EZ_WIDGET_FRAME,NULL,
EZ_LABEL_STRING, "Drag target",
EZ_FILL_MODE, EZ_FILL_BOTH, 0);
textW = EZ_CreateWidget(EZ_WIDGET_TEXT, frame, 0);
EZ_WidgetAddDnDDataDecoder(textW, MY_FILE_NAME_ATOM, 0,
decodeFileName, NULL,
NULL, NULL);
EZ_WidgetAddDnDDataDecoder(textW, MY_FILE_CONTENTS_ATOM, 0,
decodeFileContents, NULL,
NULL, NULL);
EZ_DisplayWidget(frame);
EZ_EventMainLoop();
}
int decodeFileName(EZ_Widget *widget, void *data,
char *message, int length)
{
if(widget)
{
if(length > 0)
{
FILE *fp = fopen(message, "r");
if(fp)
{
EZ_TextLoadFile(widget, message);
fclose(fp);
return(EZ_DND_SUCCESS);
}
}
}
return(EZ_DND_FAILURE);
}
int decodeFileContents(EZ_Widget *widget, void *data,
char *message, int length)
{
if(widget)
{
if(length > 0)
{
EZ_FreezeWidget(widget);
EZ_TextClear(widget);
EZ_TextInsertString(widget, message);
EZ_UnFreezeWidget(widget);
return(EZ_DND_SUCCESS);
}
}
return(EZ_DND_FAILURE);
}