shoes4 icon indicating copy to clipboard operation
shoes4 copied to clipboard

Add drag-and-drop functionality

Open wasnotrice opened this issue 12 years ago • 25 comments

Let's explore how to add drag-and-drop to Shoes. How should the DSL read? I think it's technically doable in Swt.

wasnotrice avatar Oct 25 '12 18:10 wasnotrice

Phew. Hard nut to crack.

From Squeak Smalltalk I know an object oriented approach. There the objects have methods like "canBeDroppedOn: anObject" and "accepts: anObject" (method names are not accurate, could look it up though).

how about kind of:

drag_and_drop element, on: container

or something like that? First thing of the top of my head.

PragTob avatar Oct 25 '12 20:10 PragTob

+1 for "canBeDroppedOn: anObject" and "accepts: anObject" In general, I find smalltalk to always be the right-headed object-orientation example.

Peter Fitzgibbons (847) 859-9550 Email: [email protected] IM GTalk: peter.fitzgibbons IM AOL: [email protected]

On Thu, Oct 25, 2012 at 3:16 PM, Tobias Pfeiffer [email protected]:

Phew. Hard nut to crack.

From Squeak Smalltalk I know an object oriented approach. There the objects have methods like "canBeDroppedOn: anObject" and "accepts: anObject" (method names are not accurate, could look it up though).

how about kind of:

drag_and_drop element, on: container

or something like that? First thing of the top of my head.

— Reply to this email directly or view it on GitHubhttps://github.com/shoes/shoes4/issues/139#issuecomment-9792442.

pjfitzgibbons avatar Oct 25 '12 20:10 pjfitzgibbons

The problem however is that we'd need objects for that... and so far shoes, imo, is more kind of a markup language/DSL. I never wrote my own rectangle or something... that doesn't seem to be too common or am I wrong?

Oh and now I looked it up. I was a bit wrong, there is no "can be dropped on" - just whether a morph is accepted. But by default in Squeak Smalltalk you can drag and drop just about anything. Oh for understanding: Allg raphical objects in squeak smalltalk are Morphs.

ReceiverMorph»wantsDroppedMorph: aMorph event: anEvent
  (return a boolean here)

Through different methods you can specify what happens if the Morph can't be dropped here (for instance send it back to the starting position).

What I'm talking about is chapter 11.7 of the free (Squeak by Example PDF)[http://www.squeakbyexample.org/] - if anyone wants further info or something :-)

PragTob avatar Oct 25 '12 20:10 PragTob

What about something like this:

Shoes.app do
  edit_box width: 10, dragndrop: lambda { |obj| ... }
end

davorb avatar Oct 26 '12 05:10 davorb

@davorb I like where you're going with this. We could even offer shortcuts for common operations

Shoes.app do
  image "cat3.jpg", width: 100, height: 100, drag: true
  stack do
    title "Cats"
    flow :drop => :append do
      image "cat1.jpg"
      image "cat2.jpg"
    end
  end
end

wasnotrice avatar Oct 29 '12 03:10 wasnotrice

@wasnotrice That's genius!

davorb avatar Oct 29 '12 09:10 davorb

Yep, agreed... genius! +1 for the DSL.

"droppables" are identified by drag: true, "drop targets" are identified by drop:

What would be the potential drop-opts ?

Peter Fitzgibbons (847) 859-9550 Email: [email protected] IM GTalk: peter.fitzgibbons IM AOL: [email protected]

On Mon, Oct 29, 2012 at 4:39 AM, Davor Babić [email protected]:

@wasnotrice https://github.com/wasnotrice That's genius!

— Reply to this email directly or view it on GitHubhttps://github.com/shoes/shoes4/issues/139#issuecomment-9860470.

pjfitzgibbons avatar Oct 29 '12 10:10 pjfitzgibbons

Oh neat.

steveklabnik avatar Oct 30 '12 02:10 steveklabnik

Potential drop-outs would be primarily text, I think. On Oct 29, 2012 6:40 AM, "Peter Fitzgibbons" [email protected] wrote:

Yep, agreed... genius! +1 for the DSL.

"droppables" are identified by drag: true, "drop targets" are identified by drop:

What would be the potential drop-opts ?

Peter Fitzgibbons (847) 859-9550 Email: [email protected] IM GTalk: peter.fitzgibbons IM AOL: [email protected]

On Mon, Oct 29, 2012 at 4:39 AM, Davor Babić [email protected]:

@wasnotrice https://github.com/wasnotrice That's genius!

— Reply to this email directly or view it on GitHub< https://github.com/shoes/shoes4/issues/139#issuecomment-9860470>.

— Reply to this email directly or view it on GitHubhttps://github.com/shoes/shoes4/issues/139#issuecomment-9862023.

jrgifford avatar Oct 30 '12 02:10 jrgifford

@wasnotrice genius indeed :-D

PragTob avatar Nov 01 '12 12:11 PragTob

Hmmm. Now that I look more closely at Shoes 3, I see that Slot#append only takes a block. In other words, you can't append an existing element--you can only add a new one. Are there any drawbacks to adding an optional argument to #append, #prepend?

We would definitely want to allow a lambda as a drop-opt, as @davorb sketched initially.

flow :drop => { |obj| para "Yum! Thanks for the #{obj.name}" }

It's possible that this is too simplistic to work, but let's give it a shot and see if we can make something usable that is also simple.

:shoe:

wasnotrice avatar Nov 01 '12 18:11 wasnotrice

Sorry for my late reply. The discussion is interesting. But, I think that it's better to reconsider what a drag-and-drop function is and how to use.

Shoes has already some methods, i.e. click, release, motion, mouse, etc. So, within a Shoes window, users can write the code of drag-and-drop by theirselves as their own Shoes apps. For example, a tiny Shoes app Ruby Magnets on Shoes. Watch a demo.

If the drag-and-drop function is that dragging something (e.g. icons) from desktop and dropping them on a Shoes app window or dragging some elements (e.g. image, oval, rect, text, etc.) from a Shoes app window and dropping them on desktop, Shoes doesn't have the feature.

I'm not sure the feature is necessary for Shoes, though...

Shoes doesn't come with tabbed controls or toolbars. Shoes is a tiny toolkit, remember? ;-)

ashbb avatar Nov 01 '12 23:11 ashbb

@ashbb Thanks for Ruby Magnets on Shoes. I had not seen that before. Nice work!

I see how you wrote drag and drop yourself using #click, #motion, and #release. I agree it can be done by the user. But ordinary things are easy in Shoes. Maybe dragging should be easy?

Also, maybe you know the answer to this. In your Ruby Magnets, when you drag something, it doesn't get added to the slot where you drop it. Can users write code in their apps so that when they drop something, it gets appended to a different slot?

wasnotrice avatar Nov 02 '12 15:11 wasnotrice

@wasnotrice Are you looking for #contents? How about the following snippet? Watch the demo. Red and Purple Shoes doesn't work well for now, though. :(

require 'green_shoes'

Shoes.app do
  @f1 = flow do
    background green
    para 'This is green slot', width: 150
    @img = image File.join(DIR, '../static/gshoes-icon.png')
    @img.click{@flag = true}
    @img.release do
      @flag = false
      if @img.top < @f1.height
        @f2.contents.delete @img
        @f1.contents.push @img
      else
        @f1.contents.delete @img
        @f2.contents.push @img
      end
      flush
    end
  end
  @f2 = flow do
    background yellow
    para 'This is yellow slot', width: 150
  end
  motion{|l, t| @img.move(l, t) if @flag}
end

ashbb avatar Nov 03 '12 07:11 ashbb

@ashbb I like it! But this would be so much easier :)

Shoes.app do
  @f1 = flow do
    background green
    para 'This is green slot', width: 150
    @img = image File.join(DIR, '../static/gshoes-icon.png'), drag: true
  end
  @f1.drop do |obj, target|
    target.append(obj) #appending an element also removes it from its old parent
  end
  @f2 = flow do
    background yellow
    para 'This is yellow slot', width: 150
  end
end

I have concerns about using #contents directly. I think this should be a read-only list.

wasnotrice avatar Nov 03 '12 17:11 wasnotrice

Imagine that both flows had that drop block added ;)

wasnotrice avatar Nov 03 '12 17:11 wasnotrice

@wasnotrice

this would be so much easier :)

Yeah, I agree it's much easier.

But,...

I have concerned about using #contents directly. I think this should be a read-only list.

If #contents is an array, user can edit the data within the array freely... For example:

class Slot
  def initialize
    @contents = %w[a b c]
  end
  attr_reader :contents
end

s = Slot.new
s.contents.delete 'a'
p s.contents  #=> ["b", "c"]

ashbb avatar Nov 05 '12 11:11 ashbb

@ashbb

If #contents is an array, user can edit the data within the array freely...

True, if we expose the actual array. But if we only expose a copy:

class Slot
  def contents
    @contents.dup
  end
end

s = Slot.new
s.contents.delete 'a'
p s.contents  #=> ["a", "b", "c"]

Now the user has to work through the Shoes API to change the contents of the slot. This is good. Look what goes wrong in this Shoes4 snippet:

Shoes.app width: 600, height: 200 do
  f1 = flow do
    para "hello"
    para "world"
  end
  stack do 
    para "f1: #{f1}"
    p1 = f1.contents.delete_at(0)
    f1.contents.each { |e| para "#{e} (#{e.text}), parent: #{e.parent}" }
    para "p1's parent: #{p1.parent}"
  end
end

![](https://dl.dropbox.com/u/610739/Screenshots/Screen Shot 2012-11-05 at 11.56.43 AM.png)

What should p1's parent be? If the user can manipulate @contents, how can we manage that?

wasnotrice avatar Nov 05 '12 18:11 wasnotrice

@wasnotrice #dup ... oh, yeah, but really need to do that? Give the users freedom! :-P :-D

Look what goes wrong in this Shoes4 snippet:

Umm, looks bad. The "hello" isn't erased.

What should p1's parent be?

p1 is "hello". So, p1's parent should be f1.

If the user can manipulate @contents, how can we manage that?

If you want to erase the "hello", you have to do not only remove it from f1's contents but also delete the swt-paint-listener.

I think user can do that if we support #clear method for Shoes::TextBlock class. But at that time, user doesn't have to manipulate @contents directly. ;-)

ashbb avatar Nov 06 '12 12:11 ashbb

I agree with @ashbb, access to contents is freedom, operations on contents are dependent upon the implementation framework. I think if we .frozen the result of #contents then the usage will be obviated... can't change a frozen object.

A comment in code here will be very important... make note that the returned object is frozen and in practice cannot be modified because the @contents are not directly synced with the GUI Implementation Framework (ie. SwtShoes). Use the GUI framework operations to manipulate the objects you find in #contents.

Thoughts?

Peter Fitzgibbons (847) 859-9550 Email: [email protected] IM GTalk: peter.fitzgibbons IM AOL: [email protected]

On Tue, Nov 6, 2012 at 6:06 AM, ashbb [email protected] wrote:

@wasnotrice https://github.com/wasnotrice #dup ... oh, yeah, but really need to do that? Give the users freedom! :-P :-D

Look what goes wrong in this Shoes4 snippet:

Umm, looks bad. The "hello" isn't erased.

What should p1's parent be?

p1 is "hello". So, p1's parent should be f1.

If the user can manipulate @contents, how can we manage that?

If you want to erase the "hello", you have to do not only remove it from f1's contents but also delete the swt-paint-listener.

I think user can do that if we support #clear method for Shoes::TextBlock class. But at that time, user doesn't have to manipulate @contentsdirectly. ;-)

— Reply to this email directly or view it on GitHubhttps://github.com/shoes/shoes4/issues/139#issuecomment-10108222.

pjfitzgibbons avatar Nov 06 '12 15:11 pjfitzgibbons

@ashbb I'm all for freedom :D

My point is that when a user manipulates #contents directly, we can't clean up the display like we should. It's better to provide DSL methods for adding/removing objects to slots. But I'm not sure it will work ;)

wasnotrice avatar Nov 07 '12 18:11 wasnotrice

Oops! I know that #remove will work. I'm not sure whether it will work well to move an object from one slot to another (drag-and-drop)

wasnotrice avatar Nov 07 '12 18:11 wasnotrice

Doesn't move in general require a destroy/build of the gui object?

Peter Fitzgibbons (847) 859-9550 Email: [email protected] IM GTalk: peter.fitzgibbons IM AOL: [email protected]

On Wed, Nov 7, 2012 at 12:42 PM, Eric Watson [email protected]:

Oops! I know that #remove will work. I'm not sure whether it will work well to move an object from one slot to another (drag-and-drop)

— Reply to this email directly or view it on GitHubhttps://github.com/shoes/shoes4/issues/139#issuecomment-10159771.

pjfitzgibbons avatar Nov 07 '12 21:11 pjfitzgibbons

Doesn't move in general require a destroy/build of the gui object?

For moving from one container to another, yes.

wasnotrice avatar Nov 08 '12 02:11 wasnotrice

@wasnotrice @pjfitzgibbons and folks,

1st:

It's better to provide DSL methods for adding/removing objects to slots.

Both in Red Shoes and current Shoes4, the elements moved or created with explicit position (ex. image(path).move(l, t) or oval(l, t, w)) don't belong to any slots. So, I agree to provide DSL methods for adding elements to slots. How about the following?

slot = flow
img = image(path)
slot.append img

The #remove method disposes the element and removes it from the slot's contents.

2nd: about "drag-and-drop". I agree with @wasnotrice's DSL.

slot = flow
img = image(path, drag: true)
slot.drop{|obj, target| target.append obj}

But, I'm still not sure whether it's needed... Personally, I think that it's better to leave drag-and-drop function to Shoes app developers. Of course, I don't have any objection to providing drag-and-drop DSL. :)

ashbb avatar Nov 08 '12 12:11 ashbb