BookmarkSubscribeRSS Feed

Re: MouseBox problem "<< SetDropTrack"

msharp

Super User

Joined:

Jul 28, 2015

MouseBoxes are hard.  I'm trying to implement a drag and drop solution to move pictures around.

Below I've taken the example code from Scripting Index >> Mouse Box >> SetDropTrack and have re-implemented it to contain images in the boxes instead of letters.  Except I can't get the images to populate in the new location after dropping.  Any help would be appreciated.

Names Default To Here( 1 );

//Datatable with :LocalPath Column that contains paths to image files on computer

dtFull = current data table();

path1 = dtFull:LocalPath[20];

path2 = dtFull:LocalPath[21];

path3 = dtFull:LocalPath[22];

path4 = dtFull:LocalPath[23];

path5 = dtFull:LocalPath[20];

path6 = dtFull:LocalPath[21];

path7 = dtFull:LocalPath[22];

path8 = dtFull:LocalPath[23];

img = NewImage(path1);

img2 = NewImage(path2);

img3 = NewImage(path3);

img4 = NewImage(path4);

img5 = NewImage(path1);

img6 = NewImage(path2);

img7 = NewImage(path3);

img8 = NewImage(path4);

//Below Modified Scripting Index >> SetDropTrack example

nextToBlank = Function( {x, y}, /* helper function */

       If( /* child is border, grandchild is text */

              (x > 1 & isempty(((puzzle[x - 1][y] << child) << child) << getimage)) | (x < 3 & isempty(((puzzle[x + 1][y] << child) << child) << getimage))

               | (y > 1 & isempty(((puzzle[x][y - 1] << child) << child) << getimage)) | (y < 3 & isempty(((puzzle[x][y + 1] << child) << child) << getimage))

       ,

              1,

              0

       )

);/* only allow drag begin if next door to empty cell */

dragBegin = Function( {this, clickPt},

       {x, y} = this << getUserData;

       Print("dragBegin");

       If( nextToBlank( x, y ),

              image = ((this << child) << child) << getImage/* the message is the textbox content */

       , /* else */

              0 /* suppress the drag */

       );

);/* function to remove the character from the source cell, but only if the drop was successful */

dragEnd = Function( {this, clickPt, how}, /* how is copy/move/ignore */

       destbox = this << getDestBox;

       If( Is Empty( destBox ),

              Show( "unknown destination" );

              0 /* don't know where the dest was, force ignore */

              ;

       ,

              Try(

                     {x, y} = destbox << GetUserData,

                     x = -1;

                     y = -1;

              ); /* the destbox might not have a list in userdata */

              If(

                     Try(

                           puzzle[x][y] != destbox,

                           1 /*throw is same as !=*/

                     )

              , /* x,y might not be valid index */

                     Show( "not dropped in this puzzle" );

                     0 /* not this puzzle instance, force ignore */

                     ;

              , /* else */

                     If( how == "ignore",

                           Show( "drop not completed" );

                           0 /* the drop was not completed */

                           ;

                     , /* else */

                           ((this << child) << child) << setImage( " " )

                     )

              );

       );

       0 /* the return code is ignored */

       ;

);/* function to decide if a drop is allowed.  return codes (0,1) are critical. */

dropTrack = Function( {this, clickPt},

       sourcebox = this << getSourceBox;

       If( Is Empty( sourcebox ),

              Show( "unknown source" );

              0 /* no drop from unknown source box */

              ;

       , /* else */

              Try(

                     {x, y} = sourcebox << getUserData,

                     x = -1;

                     y = -1;

              ); /* the sourcebox mightnot have a list in userdata */

              If(

                     Try(

                           puzzle[x][y] != sourcebox,

                           1 /*throw is same as !=*/

                     )

              , /* x,y might not be valid index */

                     Show( "not from this puzzle" );

                     0 /* not sourced from this puzzle instance, ignore */

                     ;

              , /* else */

                     If( !isempty(((this << child) << child) << getImage),

                           0 /* no drop on occupied cell */

                     , /* else */

                           1 /* allow drop on the blank cell */

                     )

              );

       );

);/* function to implement the drop */

dropCommit = Function( {this, clickPt, image},

       ((this << child) << child) << setImage( image );

       1; /* ignored */

);/* cursor changer for cells that can source a drag */

track = Function( {this, clickPt},

       {x, y} = this << getUserData;

       If( nextToBlank( x, y ),

              this << setCursor( "Hand" ),

              this << setCursor( "Arrow" )

       );

       1; /* ignored */

);/* helper function to construct the displaybox tree */

mb = Function( {letter, x, y},

       MouseBox(

              Border Box( Left( 9 ), Right( 9 ), top( 3 ), bottom( 3 ), sides( 15 ),

                     Picture Box( letter )

              ),

              <<setUserData( Eval List( {x, y} ) ), /* remember my location.  I don't move, but my content changes. */

              <<setDragEnable( 1 ),

              <<setDragBegin( dragBegin ), /* dragFunctions defined below */

              <<setDragEnd( dragEnd ),

              <<setDropEnable( 1 ),

              <<setDropTrack( dropTrack ),

              <<setDropCommit( dropCommit ),

              <<setTrackEnable( 1 ),

              <<setTrack( track )

       )

);

puzzle = Eval List(

       {Eval List( {mb( img , 1, 1 ), mb( img2, 1, 2 ), mb( " ", 1, 3 )} ),

       Eval List( {mb( img3, 2, 1 ), mb( img4, 2, 2 ), mb( img5, 2, 3 )} ),

       Eval List( {mb( img6, 3, 1 ), mb( img7, 3, 2 ), mb( img8, 3, 3 )} )}

);

New Window( "puzzle",

       Border Box( Left( 5 ), Right( 5 ), top( 5 ), bottom( 5 ), sides( 15 ),

              Lineup Box( N Col( 3 ), spacing( 3, 3 ),

                     puzzle[1][1],

                     puzzle[1][2],

                     puzzle[1][3],

                     puzzle[2][1],

                     puzzle[2][2],

                     puzzle[2][3],

                     puzzle[3][1],

                     puzzle[3][2],

                     puzzle[3][3],

              )

       )

);

1 ACCEPTED SOLUTION

Accepted Solutions
Highlighted
Craige_Hales

Staff

Joined:

Mar 21, 2013

Solution

So close! the clipboard is only set up to move text, not other JMP objects.  You can convert the picture to a large chunk of text and move that through the clipboard.  (You could also build a different mechanism, perhaps with an associative array to hold the images, using a character key to the associative array.  It would look more complicated but be less stressful on the clipboard/CPU.  If you drag out of the puzzle, into another editor, you'll see the huge chunk of text.)


the character conversion makes your code begin to work:


    image = char(((this << child) << child) << getImage);/* the message is the textbox content */

    image;

and

    image=parse(image);

    ((this<<child)<<child)<<setimage(image);

Craige
4 REPLIES
msharp

Super User

Joined:

Jul 28, 2015

I'm a little surprised no one has responded in a couple days.  I think this problem is kind of fun.  I decided to attach a script with pictures to help others troubleshoot easier.  I've also added notes to better indicate the part of the code I'm having issues with.

Highlighted
Craige_Hales

Staff

Joined:

Mar 21, 2013

Solution

So close! the clipboard is only set up to move text, not other JMP objects.  You can convert the picture to a large chunk of text and move that through the clipboard.  (You could also build a different mechanism, perhaps with an associative array to hold the images, using a character key to the associative array.  It would look more complicated but be less stressful on the clipboard/CPU.  If you drag out of the puzzle, into another editor, you'll see the huge chunk of text.)


the character conversion makes your code begin to work:


    image = char(((this << child) << child) << getImage);/* the message is the textbox content */

    image;

and

    image=parse(image);

    ((this<<child)<<child)<<setimage(image);

Craige
msharp

Super User

Joined:

Jul 28, 2015

Thanks for the info.  Seeing your code and explanation I came up with a third solution.  I decided to store the image into a unique namespace (aka. image:image) which I can pass between the functions.

Craige@JMP​ did you see my other post? MouseBox Selecting Multiple Images I also want to be able to select multiple images at one time.  I feel the mousebox can be tricky and the documentation isn't great so I'd appreciate anything info you can provide.

Craige_Hales

Staff

Joined:

Mar 21, 2013

Example posted.

Craige