Subscribe Bookmark RSS Feed

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
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.

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