[ruby-gnome2-doc-cvs] [Ruby-GNOME2 Project Website] update - tut-gtk2-dnd-intro

アーカイブの一覧に戻る

ruby-****@sourc***** ruby-****@sourc*****
2013年 3月 13日 (水) 05:16:31 JST


-------------------------
REMOTE_ADDR = 184.145.80.119
REMOTE_HOST = 
        URL = http://ruby-gnome2.sourceforge.jp/hiki.cgi?tut-gtk2-dnd-intro
-------------------------
@@ -1,52 +1,59 @@
-= Drag And Drop
+= (10) Drag And Drop
 {{link "tut-gtk2-dnd", "tut-gtk2-dnd", "tut-gtk", "tut-gtk2-dnd-native-treev"}}
 
 
-# (10.1)/(9a)
+### == Sorry, still under construction
+# (10.1)/(9a) [current file: tut-gtk2-dnd-intro]
+
+
+
 == DnD Introduction
+(10.1){{br}}
 
 
+
+
 When in the context of GUI we are talking about "dragging and dropping" our operating domain consists of three kinds of objects. In particular in our Gtk environment, we are dragging (moving) Gtk widgets between two different geometric locations. One is the location from which you are dragging a widget. This location is called the 'source' location. Naturally, the location to which you would like to drag the widget will then be called the 'destination' location. So the three object we mentioned earlier are (1) the graphic object you are moving, (2) the source location, and (3) the destination location. Behind the scene the drag-and-drop metaphor a significant inter-process communications is shielded from GUI developers. Namely, when a user initiates the drag process in the source environment the information about the object being dragged must be conveyed to the destination so it can properly react to the 'drop'. Depending on the type of 'drag' action the source and destinati
 on may, at the completion of the 'drag', need to perform different but coordinated actions, such as  copying, duplicating and/or removing the object being dragged from the source location, and placing, or perhaps even refusing to accept the dragged object at the destination point.
 
 
 Gtk includes a module and a number of classes to provide required drag-and-drop behaviour and additional helper objects and methods. The most prominent is appropriately called the Gtk::Drag module and some of the helper classes are Gdk::DragContext, Gdk::Atom, Gtk::TargetList, in addition to the Gtk::Selection module. An important part of drag-and-drop features are signals. As it happens, the three drag-and-drop objects rely on Gtk::Widget drag related signals.
 
 
-# (10.2.1)
+
+# (10.1.1)
 === Identifying the DnD Objects
+(10.1.1){{br}}
 
+Unlike to a GUI user, to a GUI developer identification of a drag-and-drop objects is not at all that obvious. While conceptually it should be always easy to determine what is the dragging object and its source and destination locations, in reality the lines between these items may be blurry. This is mostly due to the fact, that Gtk performs many tasks for you behind the scene, and also because the objects that are to be dragged are not at all directly referenced in drag-and-drop API. Instead, the methods in Gtk::Drag module and related classes refer to them as abstract((*targets*))which you have to identify not so much in terms of graphic objects but rather as Gtk+ abstraction defined in Gtk::TargetList. Gtk::TargetList object is an array of targets (i.e. draggable items), that are specified with an ordered list or a tuple of three items '[target, flags, info]'. The((*'target'*))parameter is a string identifying the object to be dragged from the source and dropped onto a de
 stination. The((*'flags'*))parameter is one of the constants defined in Gtk::Drag#TargetFlags (TARGET_SAME_APP, TARGET_SAME_WIDGET, TARGET_OTHER_APP, and TARGET_OTHER_WIDGET). The last((*'info'*))element in the targets tuple is by the application or the developer defined identification integer.
 
-Unlike to a GUI user, to a GUI developer identification of a drag-and-drop objects is not at all that obvious. While conceptually it should be always easy to determine what is the dragging object and its source and destination locations, in reality the lines between these items may be blurry. This is mostly due to the fact, that Gtk performs many tasks for you behind the scene, and also because the objects that are to be dragged are not at all directly referenced in drag-and-drop API. Instead, the methods in Gtk::Drag module and related classes refer to them as abstract((*targets*))which you have to identify not so much in terms of graphic objects but rather as Gtk+ abstraction defined in Gtk::TargetList. Gtk::TargetList object is an array of targets (i.e. draggable items), that are specified with an ordered list or a tuple of three elements '[target, flags, info]'. The((*'target'*))parameter is a string identifying the object to be dragged from the source and dropped onto a
  destination. The((*'flags'*))parameter is one of the constants defined in Gtk::Drag#TargetFlags (TARGET_SAME_APP, TARGET_SAME_WIDGET, TARGET_OTHER_APP, and TARGET_OTHER_WIDGET). The last((*'info'*))element in the targets tuple is by the application or the developer defined identification integer.
-
 As we already mentioned another reason for a blurry view of what a drag-and-drop object is, is the fact that Gtk performs many tasks such as those defined in Gdk::DragContext#GdkDragAction behind the scene. This means that Gtk and not the programer is responsible for copying, moving and/or removing items you are dragging. However, this may may not be entirely true or not at all, depending whether you are dragging items between different widgets or within the widgets that supports dragging and dropping by design. An example of such a widget, which supports dnd by design is the Gtk::TreeView. You may also decide you want to bypass, Gtk default behaviour and implement your own drag-and-drop behaviour. In that case you will need to perform copying and removing dragging objects yourself. In that case you will need to obtain the true dragging object, such as a tree view row, or an icon residing in icon view, or perhaps a different image object all together for instance a large ima
 ge the icon represents. As you can see, in such situations you may need to have a true reference to the dragged object and Gtk's target abstraction may be rather useless. Fortunately these are special cases, and require a better understanding of these issues. You may find it necessary to consult the'Inter-Client Communications Conventions Manual' (ICCCM). Though, our intention here is to provide the basic coverage of the dnd in Ruby Gtk, we will look at some of the more advanced issues, enough to point you in the right direction, and perhaps to inspire developers to polish the rough edges in this areas of Gtk.   
 
 
-# (10.2.2)
+# (10.1.2)
 === The DnD Source And Destination Objects
+(10.1.2){{br}}
 
 The source locations and/or widgets are those in which the objects to be dragged originally reside, and the destinations are places, widgets or object onto which you wish to drop the dragged objects. These widgets or objects may be different, for instance you may plan to drag an icon from an icon view onto some other viewing area, perhaps a canvas or a text widget. Or they can be one and the same widget and indeed the same object, as is the case when you are reordering rows in a tree view, or items in the text view. In the previous chapter 9, (section: 9.6.2.2), we have already seen our toolbar 'dnd-toolbox.rb' example in which the source and destination are of the same type namely Gtk::Frame, but they are two different objects.
 
 
-
 # (10.1.2.1)
 :Why Do the DnD Widgets Need a Gdk::Window Of Their Own
 
+    (10.1.2.1){{br}}
     The Gtk API tells us that all the widgets which have their own Gdk::Window can be set as source or destination widgets. A widget that contains its own Gdk::Window must not have Gtk::Widget::NO_WINDOW flag set. You can check for this flag with the Gtk::Widget#no_window? method. (Note that this method returns true if the widget (the receiver object) does not contain the Gdk::Window.)
 
     The above statement is not completely accurate, because it suggests that Gtk widgets without their own Gdk::Window can not be set as source and destination drag-and-drop widgets. Later we will develop a simple example (button-to-label-dnd.rb) program with button as the dnd source and a label as a the dnd destination widget. Neither Gtk button nor label have their own Gdk::Window, and yet they can be set up as source and destination widgets.
 
     What is true with respect to drag-and-drop restrictions for widgets with no Gdk::Window of their own is, that such widgets do not respond to very important dnd((*'drag-data-get'*)) and((*'drag-data-received'*)) signals used by drag-and-drop protocol (PROTO_XDND) on which Gtk's dnd communications is based, which translated to plain English simply means, that such widgets can not benefit from predefined Gtk drag-and-drop actions, and that you will have to provide your own callbacks for either 'drag-begin', 'drag-begin' or some other more appropriate dnd signal.
- 
 
 
-
 The basic principles behind setting up drag-and-drop source and destination objects are simple, however, some widgets support dnd by design, while most of the Gtk widgets do not. Naturally, sometimes you need to mix the two kinds of (the dnd and the non-dnd) widgets. This complicates both the teaching and the learning of the Gtk's dnd metaphor a bit. This perhaps is one of the reasons in most of the currently available Gtk  drag-and-drop tutorials you find rather incomplete or useless examples, such as dragging a button to a label, which in itself is a nonsense proposition, since a label can never contain a button on the first place. Nevertheless, as we will see shortly, using a button and a label for a source and destination, after all, makes sense, especially when the students understand that in this case the source and destination objects themselves are being also dragged and/or manipulated by the dnd.
 
 
-
 # (10.1.2.2)
 :There Are Three Different Source And Destination DnD Set-Up Scenarios
 
+    (10.1.2.2){{br}}
     Normally, you have to set up source and destination widgets. There exists a plethora of methods to accomplish this. However, there are three different situations or circumstances in which you need to set up either source or destination widget for drag-and-drop management. Depending on the combination of the source and destination drag-and-drop widgets you are using in your application, there are many ways to set up (or, as you will soon see, perhaps not at all set up) these source and destination widgets.
 
     We can briefly point out the three different scenarios for setting up source and destination widgets as follows. Starting with those widgets that support dnd by design, we encounter those (1) for which you may simply start using the native dnd facilities without ever setting either the source or the destination widgets (for instance Gtk::TextView is such a widget). (2) Next, from the same category we have such as the Gtk::IconView, or the Gtk::TreeView widget, with which you can use the default dnd behaviour with almost no extra programming work. And lastly, (3) the widgets without native drag-and-drop support for which, in order to use drag-and-drop facilities, you really need to register those widgets as source or destination widget or both. 
@@ -58,12 +65,18 @@
 If you plan to use Gtk's dnd features for either the source or destination widget then during this registration of that particular widget you also need to specify the((*action*))the dnd system is to take for the item being dragged. This action is defined as a constant in Gdk::DragContext#GdkDragAction and conveys to the Gtk system whether the item is to be copied, moved, removed from the source, and how to react at the destination at the time the drop occurs.
 
 :Note:
-    You should be aware, that for the majority of Gtk widgets, Gtk has no clue how to handle them neither on the source nor on the destination side, and that for those widgets any of the predefined actions such as for Gdk::DragContext::ACTION_COPY, {_MOVE, _ASK, etc.}, are meaningless. Indeed, for such widgets you have to implement your own actions in appropriate drag-and-drop signal handlers. The simple 'button-to-label-dnd.rb' example, you will see shortly, falls into this category. 
+    You should be aware, that for the majority of Gtk widgets, Gtk has no clue how to handle them neither on the source nor on the destination side, and that for those widgets any of the predefined actions such as for Gdk::DragContext::ACTION_COPY, {_MOVE, _ASK, etc.}, are meaningless. Indeed, for such widgets you have to implement your own actions in appropriate drag-and-drop signal handlers. The simple 'button-to-label-dnd.rb' example, you will see shortly, falls into this category.
+    
 
 Following are few API examples to show different methods used to register source and destination widgets, and the kind of arguments you may be required to supply when registering these widgets.
 
-
-
 You use Gtk::Drag.source_set and Gtk::Drag.dest_set module methods, when source and destination widgets are arbitrary Gtk objects with their own Gdk::Window:
 
 (#1)
@@ -83,13 +89,19 @@
     	actions           = IVDND_ACTION
   )
 
-
 and a less involved:
 
 (#3)
  # Gtk::TreeView#enable_model_drag_dest(targets, actions)
  treeview.enable_model_drag_dest(TVDND_TARGETS, Gdk::DragContext::ACTION_ASK)
 
+ 
 
 The targets argument above identifies all the objects that dnd source and destination will accept. It is convenient to assemble all your targets in a constant since your source and destination widgets need to agree they both will operate with the same drag-and-drop objects (data). Namely, when your source and destination widgets are registered, they should be given the same set of targets as a parameter. The targets argument in either case above is an array of target entries, where each entry is, as mentioned above, the tuple in the form [target, flags, info]. Though you may get away by specifying an empty array ([]) for your targets argument, it is better to create constants with, for your application, meaningful data to be used when registering your source and destination widgets. Here is a code snippet from our next example program in which we build our convenience constants and, indeed, the targets array:
 
@@ -122,12 +128,21 @@
 Do not be too much concerned with all the different ways we may be using when setting up source and destination widgets. Try to emulate the examples you can find in our tutorial, they should provide enough material, to grasp the basic understanding. 
 
 
-# ************
 
 
+
+
 # (10.2)
 == Setting DnD For Widgets Without Their Own Gdk::Window
+(10.2){{br}}
 
+
 As already mentioned, some widgets support dnd by design, while others do not. This creates an unusual learning situation, where initially we are better of looking at the widgets that do not natively support drag-and-drop facilities, though by looking at such widgets we only can observe a partial set of the drag-and-drop features. The reason that the widgets without the native dnd support are a better learning starting point is, that their set-up procedures always reflect the 'source/destination dnd duality', namely, unlike for widgets with the dnd support, where a source or destination, can either be implicitly assumed or enabled, for widgets without the native dnd support we always have to set up a source as well as destination side widgets.
 
 Both the source and destination widget set-up also require you to provide the definitions for the objects to be dragged, in the form of tuples called 'targets', which we discussed above in the '((<Identifying the DnD Objects|tut-gtk2-dnd#Identifying the DnD Objects>))' paragraph.
@@ -135,8 +144,20 @@
 
 When discussing DnD for widgets without their own Gdk::Window we should also point out that for those widgets the 'drag-data-get' and 'drag-data-received' signals are not emitted.
 
+
 :DnD related signals
 
+    (10.2.0.1A){{br}}
+    
     With the exclusion of the above mentioned exceptions ('drag-data-get' and 'drag-data-received' signals) for widgets that do not natively support dnd, all widgets regardless of whether they natively support the dnd, or not, respond to drag related signals defined in Gtk::Widget#Signals. For your convenience I also list these signals in the following listing:
 
      drag-begin ............... self, drag_context
@@ -148,13 +160,26 @@
      drag-leave ............... self, drag_context, time
      drag-motion .............. self, drag_context, x, y, time
 
-
 As you can see the widgets without their own Gdk::Window exhibit a limited set of dnd behaviours (actions). For this reason, when you design your programs, that need dnd facilities with such widgets you need to provide your own code to handle drag signals and implement custom drag-and-drop actions. We will look closely at this in the following section revealing the promised 'button-to-label-dnd.rb'
 
 
 
+
 # (10.2.1)
 === Dragging a Button Onto a Label 
+(10.2.1B){{br}}
 
 {{image_left("button-to-label-dnd-s1.png")}}
 
@@ -162,7 +175,20 @@
 
 {{image_right("drag-document-cursor.png")}} 
 
-Hence if you click, and drag the button widget over to the right side the ((*drag-document*))shape cursor appears (see the small image here on the right). Should you decide to release the mouse button while the 'drag-document shape cursor' remains unchanged, the drag operation is cancelled.
+Hence if you click, and drag the button widget over to the right side the ((*drag-document*))shape cursor appears (see the small image here on the right). Should you decide to release the mouse button while the 'drag-document' shape cursor' remains unchanged, the drag operation is cancelled.   
 
 {{image_right("ask-to-drop-document-cursor.png")}} 
 
@@ -172,25 +185,38 @@
 
 
 
-You almost certainly by now are aware, that for these drag-and-drop actions neither the source button widget nor the destination label widgets offer any particular help with the drag-and-drop operations (actions). We have to provide the appropriate signal handler callbacks, and perform the swapping of the widgets' positions ourselves. However, as you will learn shortly, by registering widgets, that natively do not support dnd behaviour, as dnd source and destination widgets, you actually ask Gtk to chip in, and start providing the basic dnd services such as taking care of cursor shape during dnd operations and some other, to a user not obvious, dnd services.
 
+You almost certainly by now are aware, that for these drag-and-drop actions neither the source button widget nor the destination label widgets offer any particular help with the drag-and-drop operations (actions). We have to provide the appropriate signal handler callbacks, and perform the swapping of the widgets' positions ourselves. However, as you will learn shortly, by registering widgets, that natively do not support dnd behaviour, as dnd source and destination widgets, you actually ask Gtk to chip in, and start providing the basic dnd services such as taking care of cursor shape during dnd operations and some other, to a user not obvious, dnd services. 
+
 We will next look at the code of our 'button to label dnd' example program, which I believe, will provide a more concrete revelations of some of the abstract dnd concepts we have been discussing up to now and finally get your feet 'dnd' wet. But first, we should get ready for a switch from procedural programming paradigm, in which all the examples so far were written, to the object oriented one in which all your future Gtk programming should really be done.
 
 
 
 
-
 {{br}}
 # (10.2.1.1)
 :Time To Start Using Object-Oriented Programming Paradigm
 
+    (10.2.1.1){{br}}
     So far in our tutorial we have mostly ignore the fact that Gtk is really an object oriented GUI system, intended to be used as such. Ruby itself is an excellent object oriented language and it would be inappropriate if we continued to ignore these facts.
 
     From this point on, we will try to stay in the OO paradigm, and we plan that our example programs reflect this, and will from now on consistently use the((*BasicWindow*))class, which provides all the required Gtk::Window behaviours and properties. In fact it itself is a subclass of Gtk::Window class.
 
     In order to use it in your program examples that follow in this tutorial, you need to make sure that the directory (folder) in which ((*'HikiGtk'*))module file called 'hiki-gtk.rb' with ((*BasicWindow*))class definition resides, will be included in Ruby's load path.
 
-
     Hence before you continue, take a few moments and copy the following file into a desired folder or directory on your system:
     
     ((*hiki-gtk.rb*))
@@ -228,10 +241,22 @@
 
 
 
-
 {{br}}
-# (10.2.1 - continued)
-(Back to our 'Dragging a Button Onto a Label' discussion) 
+# (10.2.1 - continued-#2)
+(Back to our 'Dragging a Button Onto a Label' discussion #1 /10.2.1 - continued-#2/) 
 
 The program starts with the widening of the Ruby load path ($:), to ensure our tutorial 'hiki-gtk.rb' class and 'hiki-dnd-dbg.rb' module are found, and with the usual preparation of the driving 'BasicWindow' class.
 
@@ -242,12 +254,24 @@
  include HikiDnDdbg
 
 
-# (10.2.1.1)
+# (10.2.1.1.1)
 :Notes About the DnD Debugging Module:
 
+    (10.2.1.1.1){{br}}
     As you see in the above code snippet in this example here we are using an auxiliary module stored in file called 'hiki-dnd-dbg.rb'. You should copy this file into the folder, where you earlier copied the BasicWindow class file ('hiki-gtk.rb'). Do this now. Here is the file:
 
-
     ((*hiki-dnd-dbg.rb*))
 
      module HikiDnDdbg
@@ -358,16 +370,33 @@
     Do not pay too much attention to the above 'HikiDnDdbg' auxiliary module. It provides rather useful drag-and-drop debugging methods, which if commented out of the example programs that use them should in no way effect user's experience, unless of course that user is a developer, that would like to observe some of the behind the scene run-time program characteristics. The only thing you should pay attention to is how we are including such auxiliary modules into our programs and developing environment.
 
 
-
 Our 'button-to-label-dnd.rb' example program consists of a single 'DnDWindow' class which is a subclass of the 'BasicWindow' base class, i.e. the class defined in the module 'HikiGTK'. The BasicWindow base class is a Gtk::Window class, implementing the most rudimentary Gtk::Window behaviour, that any application should always implement. It sets up the top level 'delete_event' and 'destroy' widget signals, sets up the window title if, it is passed to its window constructor, and takes care of the window size and its border. Indeed, you can override all these properties and behaviours in your main (driving) window subclass you are defining.
 
 
-
+# (10.2.1.1.2)
 :A Note About the DnD Widgets And 'HikiDnDdbg' Module In This Example:
 
+    (10.2.1.1.2){{br}}
     Note, that the 'HikiDnDdbg' module is not terribly important in this program, we could easily live without it. We included it only to add a single method, called 'show_if_widget_contains_its_own_gdk_window', to our 'DnDWindow' class, to show that neither the button nor the label widget contains its own Gdk::Window, and yet, contrary to the official Gtk API documentation, we can set these two widgets as dnd source and destination. 
 
+# +++++++++++++++++++ ++++++++++++++ ++++++++ +++++ +++ +
 
+{{br}}
+# (10.2.1 - continued-#2)
+(Back to our 'Dragging a Button Onto a Label' discussion /10.2.1 - continued-#2/)
+
 Our 'DnDWindow' class contains three methods. The default Ruby constructor (initialize), and three methods of our own, namely the 'set_dnd_source_widget', 'set_dnd_destination_widget', and on_drag_drop methods.
 
 The UI for this program is initialized in the 'initialize' method, where we create both dnd source button and destination label widgets, register them as the source and the destination widget respectively, and finally pack the two into a horizontal box, which is then added to the DnDWindow, and exposed by calling 'show_all' on self, i.e. on the DnDWindow itself. Initialization is concluded by the mandatory 'Gtk::main' call. From the dnd prospective, except the indirect source and destination dnd widget registration there is nothing new revealed in the 'initialize' method. Our interest lies within the two registration 'set_dnd_{source|destination}_widgets' methods. Both of these two methods take as arguments, beside the widget object either Gtk constants or the constants we defined at the beginning of our DnDWindow class. Following is code segment from our DnDWindow class where these constants are defined:
@@ -379,8 +396,28 @@
 
 We already discussed how these constants are assembled above in the paragraph with the title '((<Identifying the DnD Objects|tut-gtk2-dnd#Identifying the DnD Objects>))'. Basically, these constants are used as a convenience to help a developer synchronize the source and destination widget registration. Namely, source and destination widget must agree on the targets, i.e. objects allowed to be dragged and dropped. These objects are described in tuples called 'targets'. If you recall, a tuple consists of three items '[target, flags, info]'. The((*'target'*))parameter is a string identifying the object to be dragged. The((*'flags'*))parameter is one of the constants defined in Gtk::Drag#TargetFlags (TARGET_SAME_APP, TARGET_SAME_WIDGET, TARGET_OTHER_APP, and TARGET_OTHER_WIDGET). And the((*'info'*))element is by the application or the developer defined identification integer. Both source and destination registration methods accept a list (an array) of tuples, which means that th
 ere could be different kinds of objects that are dragged from a source (or perhaps from many different sources), as well that on a destination widget many different kinds of objects can be dropped. Whether the objects can come from different source widgets or even different applications is defined with the flag element in each tuple. Note also the '*_ACTIONS' constant, this constant is not part of the tuple, or 'targets' definition, it is usually different for source widget registration, than for registration of the destination, however interestingly enough, not for or our button and label source and destination widgets! (Note that for both sides we defined the same action, namely, Gdk::DragContext::ACTION_ASK). You can already tell, this constant is defined in Gdk::DragContext#GdkDragAction, and determines how a dragging item is handled on the either source or destination side.
 
+
+# (10.2.1.1a)
 :'set_dnd_source_widget' instance method:
 
+    (10.2.1.1a){{br}}
     As already mentioned, our DnDWindow class has three instance methods we added. First we define the 'set_dnd_source_widget' method to register our 'Drag Here' button as source widget. As you can see from the code, we do not define a signal handler and subsequently also no callback for the source widget. You will see in a moment, that in this program all the work to swap the location of source and destination widgets is performed entirely on the receiving (destination) side. All the dnd work that Gtk does for us here is managing the display, namely, taking care a proper dnd cursor icons are shown during the drag operation. When registering source we also have to provide the argument for 'start_button_mask' parameter, so Gtk knows that if that mouse button is pressed while the cursor is hovering over the source widget, it has to change the cursor icon to 'drag-document' icon. Following is the code segment with our 'set_dnd_source_widget' instance method:
 
      def set_dnd_source_widget(widg)
@@ -404,8 +424,32 @@
 
 It is important to realize that in this program source widget represents both the location from which we start dragging the object, as well as the object we are dragging. On the other hand our destination here, the label, seems more natural - namely it does represent the location to which we are dragging our button object. However, as you will see next, this destination object is removed to make place for the button, we drop on it. (By now you should know that label widget is not a container, and hence it may not hold any other widget, except its text, and optionally an image.)
 
+
+
+# (10.2.1.1b)
 :'set_dnd_destination_widget' instance method:
 
+    (10.2.1.1b){{br}}
     In the 'set_dnd_destination_widget' method we undoubtedly find the gist of this dnd example. But let's first talk about the basics, namely, about setting up the destination, i.e. (Gtk::Drag.dest_set). The firs thing to notice is that beside the 'flags' item in the tuple, we have an extra 'flags' argument, that is not a part of a 'targets' tuple, namely, Gtk::Drag::DEST_DEFAULT_ALL. These flags are defined in Gtk::Drag#DestDefaults. Other thing you should see is, that 'targets' and 'actions' arguments are the same as those used when we registered the source widget. Particularly interesting is the fact, that actions for both source and destination here are also the same, though usually when mixing source and destination widgets with and without native dnd support they differ.
 
     As before note the 'debug-line' tese two lines in source set-up method and here are the only reasons we 'required' our 'HikiDnDdbg' module. However, they serve their purpose, by making a point that widgets without their own Gdk::Window can, indeed, be set up as dnd source and destination widgets. 
@@ -423,12 +447,38 @@
        dest_widg.signal_connect('drag-drop') { |w, e| on_drag_drop(w, e) }
      end
 
-
 We have already discussed the fact that in this program the only dnd related processing is happening at the destination side. Normally, the widgets with Gdk::Window, i.e. with native dnd support at the time the drop occurs emit the 'drag-data-received' signal. However, since label widgets do not exhibit the behaviour of widgets with native dnd support, and we can not count on any built-in dnd actions to be available, also the signals tied to these intrinsic dnd actions are not emitted. Instead we have to monitor for the((*'drag-drop'*))signal. Usually, we would write a signal handler in the code block attached to the 'signal_connect' method, however, wrapping this code in an instance method with a descriptive name identifying the signal, may prove to be more readable, and as we've said before, easier to do localized experiments, testing and debugging, especially when the documentation of the API is rather scarce, as is currently the case with the Gtk drag-and-drop explanatio
 ns.      
 
 
+
+# (10.2.1.1c)
 :'on_drag_drop' instance method:
 
+    (10.2.1.1c){{br}}
     This method is not at all a complicated one and is easy to understand, though, it introduces an interesting concept of removing widgets from a layout container and rearranging the container afterwards, not often seen in this tutorial thus far. We manage the rearrangement with, for this purpose introduced instance variable '@toggled', holding a Boolean value which helps us keeping the record of two distinct source/destination widget location arrangements. 
 
      def on_drag_drop(w, e)
@@ -446,22 +472,73 @@
      end
 
     Though, on my system it is not needed, just to be on the safe side, after rearranging GUI container widgets it is wise to call show_all on the rearranged or on the parent container, as is the case here where 'show_all' call is actually identical to 'self.show_all' - self being the DnDWindow object.
-    
+
+
 Let's look at the complete program now:
 
 
+# (10.2.1.2)
+
+=== Complete 'button-to-label-dnd.rb' Program Listing
+(10.2.1.2)
+
+
+
 {{br}}
 
+## TEST RESULTS: 
+## -------------
+##     B2LDND_FLAGS = Gtk::Drag::TARGET_OTHER_APP ..... works only with other app, 
+##     but not in itself!
+##
+##     B2LDND_FLAGS = Gtk::Drag::TARGET_OTHER_APP | Gtk::Drag::TARGET_SAME_APP
+##     does not work at all!
 
+## class DnDWindow < BasicWindow
+## 
+##  # B2LDND_FLAGS   = TARGET_{SAME_APP, SAME_WIDGET, OTHER_APP, OTHER_WIDGET}
+##  B2LDND_FLAGS   = Gtk::Drag::TARGET_SAME_APP # tested with: _SAME_WIDGET,_OTHER_APP
+##  B2LDND_INFO    = 105
+##  B2LDND_TARGETS = [["btt-2-label dnd test", B2LDND_FLAGS, B2LDND_INFO]]
+##  B2LDND_ACTIONS = Gdk::DragContext::ACTION_ASK #ASK...works!!! # _ASK,_COPY,_LINK,_MOVE,_DEFAULT,_PRIVATE
 
+
+
+
+# (10.2.1.2.1)
 :'button-to-label-dnd' Example Download Notes:
 
+    (10.2.1.2.1){{br}}
     Finally you are going to copy the example program itself onto your system. Do not forget, you can copy each example program into a different directory (folder), you only need to have all the module and class files which you 'require' in the example programs (unless specifically instructed otherwise in the example documentation) in the same directory (as discussed in section # (10.2.1.1) '((<Time To Start Using Object-Oriented Programming Paradigm|tut-gtk2-dnd-intro#Time To Start Using Object-Oriented Programming Paradigm>))').
 
 
 
-
-{{br}}
 ((*button-to-label-dnd.rb*))
 
  #!/usr/bin/env ruby
@@ -545,42 +596,103 @@
  
  DnDWindow.new("Dragging a Button Onto a Label")
 
-{{br}}
 Note, all the instance methods in our DnDWindow class are made private. That is because all of them are invoked internally, and nobody should be allowed to call them explicitly on DnDWindow object. If you are not familiar with OOP, do not worry about the 'private' directive too much, you can omit it in your programs and all will work just fine, the only drawback, will be that your code will not conform to strict OO conventions, and will provide ways to abuse your code, should you deploy it to the world at large.
 
 
 
 {{br}}
-Another DnD example we have for widgets without Gdk::Window is the one from chapter 9, section 9.6.2.2 (((<Dragging a Toolbar Within a Window|tut-gtk2-mnstbs-tb#Dragging a Toolbar Within a Window>))). Let's look at it again here written in object-oriented programming paradigm. This time, we have sufficiently acquainted ourselves with the basics of 'drag-and-drop' system to also look at its design, code and the Gtk dnd features on which it is built.  
+Another DnD example we have for widgets without Gdk::Window is the one from chapter 9, section 9.6.2.2 (((<Dragging a Toolbar Within a Window|tut-gtk2-mnstbs-tb#Dragging a Toolbar Within a Window>))). Let's look at it again here written in object-oriented programming paradigm. This time, we have sufficiently acquainted ourselves with the basics of 'drag-and-drop' system to also look at its design, code and the Gtk dnd features on which it is built. 
 
 
+
+
 {{br}}
 
 # (10.2.2)
 == Dragging a Toolbar Within a Window (oo version)
+(10.2.2){{br}}
 
 Let's first get out of the way the 'oo stuff'. There is nothing new in the preamble (the first three lines after '$:' line) here. With the exception of main window class name, everything we explained above under the title '((<Time To Start Using Object-Oriented Programming Paradigm|tut-gtk2-dnd-intro#Time To Start Using Object-Oriented Programming Paradigm>))' still holds here. Besides we are not extending our driving (main) class with the methods from our debugging module. One thing that needs our attention is the choice of the instance variables. As you see, we choose to use only two instance variables (@entry and @toolbar). All other variables in which we hold references to the needed GUI widgets are stored in local variables. The reasoning behind this choice is the ephemeral nature of source and destination widgets on one hand, and on the other the need to access variables holding references to Gtk widgets from other methods, namely, only entry and toolbar widgets are us
 ed elsewhere. The ephemeral nature of source and destination widgets can be realized, when observing that after a user drags the toolbar from its original source location (frame), and drops it on current destination (frame), the two frames swap their source and destination designation, so the widget that is registered as source in the initialize method after every drag-and-drop operation alters its source or destination association! In other words, the original source frame, after the first drop becomes the new destination, and the frame that used to be the destination before the drop now becomes the new source widget. Notice the difference between either of the two toolbar programs and the above 'button-to-label-dnd.rb' example. Here, the object we drag is the toolbar and the source and destination frames stay on their locations only they swap their source/destination designations. The point here is that an object being dragged may actually be a completely different widget 
 than are the source and destination widgets, which most likely are container widgets holding the 'draggable' items. On the other hand, as we saw above in 'button-to-label-dnd.rb' example, the object we drag is simultaneously also the source widget. There are many different scenarios we can come up with, for instance multiple source and destinations, as well as multiple objects to be dragged between them. Needless to say that we have to implement the actions that take place after their respective (drags) and particularly 'drops' for all widgets without native dnd support, and that different situations or dnd scenarios require different implementations of these actions. We can see this the two examples presented here in section 10.2.
 
 
-
-{{image_right("dnd-toolbar-colage-w-frame-placeholders.png")}}
-
-
 # (10.2.2.1)
 :'dnd-toolbar-oo.rb' program example notes:
+(10.2.2.1){{br}}
 
+
     If you have forgotten the details about this menu bar, revisit the paragraphs in section 9.6.1 under the title  ((<Menus And Sub-menus As Toolbar Items|tut-gtk2-mnstbs-tb#Menus And Sub-menus As Toolbar Items>)).
 
     {{image_left("gnu-baby-32x32.jpg")}}{{image_left("gnu-head-42x42.jpg")}} Just like in chapter 9 you will need to copy the two images here on the left into your working directory, from which you plan to run our next toolbar example program. The image files should be named: 'gnu-baby-32x32.jpg' and 'gnu-head-42x42.jpg' respectively.
 
+{{image_right("dnd-toolbar-colage-w-frame-placeholders.png")}}
 
 
 Let's look at the program before we comment the relevant parts of it in the light of drag-and-drop metaphor:
 
 
+
+
+# (10.2.2.1.1)
 :Programmer's Note:
+
+    (10.2.2.1.1)
     (HikiGtk module can be viewed and copied from section:  10.2.1.1 [((<Time To Start Using Object-Oriented Programming Paradigm|tut-gtk2-dnd-intro#Time To Start Using Object-Oriented Programming Paradigm>))])
 
+
+
+{{br}}
+
 ((*dnd-toolbar-oo.rb*))
 
  #!/usr/bin/env ruby
@@ -624,15 +685,78 @@
      @toolbar.set_size_request(300, -1)
      htbframe.set_size_request(300, -1)
      htbframe.add(@toolbar)
-     
+
      set_dnd_source_frame_widget(htbframe)
      set_dnd_destination_frame_widget(htbframe, vtbframe)  # (source_fr, dest_fr)
-     
+
      add(vbox)
      show_all
      Gtk.main
    end
+
  private
+ 
    # Create a toolbar with Cut, Copy, Paste and Select All
    # toolbar items.
    def create_toolbar
@@ -754,7 +817,74 @@
    ## ----------
    def set_dnd_source_frame_widget(widg)
 
-     ##  Gtk::Drag.dest_unset(widg)     # cancel earlier dnd destination setting //not really needed!
+     ### ---------------------------------------------------------------------(start)--
+     ### NOTE: -- the following is not really necessary, if commented out all 
+     ###          still works fine!
+ ##  Gtk::Drag.dest_unset(widg)     # cancel earlier dnd destibation setting
+     ### ---------------------------------------------------------------------(end)----
 
      widg.add_events(Gdk::Event::BUTTON_PRESS_MASK)
      widg.signal_connect('button-press-event') do |w, e|
@@ -768,7 +835,74 @@
        )
      end
    end
- 
+
    ## ---------------
    ## DnD Destination
    ## ---------------
@@ -828,17 +895,85 @@
 
 What we are interested in, is the overall design or architecture of the top window encapsulated in DndTbWindow class. You can learn all about the layout of this window by reading its 'initialize' method, focusing on Gtk widgets built and gathered in the hierarchy of containers, and for the moment ignoring the drag-and-drop related methods, such as 'set_dnd_source_frame_widget' and 'set_dnd_destination_frame_widget'. We'll talk about these only after we understand the structure and design of the top window.
 
+In summary the main window consists of two parts, the edge frames (on the top, and on the left side of the main window), and the working area in the middle between the two frames. The two frames are the placeholders for our toolbar. Originally the top frame contains the toolbar. When the toolbar is dragged from its original position (frame) onto the other currently empty frame, we have to remove the toolbar from its current (source) frame and place it into the other empty (destination) frame. In this process we also have to shrink the vacated frame and indeed, change the toolbar orientation and size parameters accordingly. Of course we could prepare this window layout, including the toolbar in either position, without the knowledge of how the drag-and-drop features are implemented, and let a software engineer next-door implement the dnd features. But what would be the point ?), actually, the point is just to illustrate the two step approach here. After we have our GUI design
  or window infrastructure established we can start focusing on drag-and-drop issues. 
 
-In summary the main window consists of two parts, the edge frames (on the top, and on the left side of the main window), and the working area in the middle between the two frames. The two frames are the placeholders for our toolbar. Originally the top frame contains the toolbar. When the toolbar is dragged from its original position (frame) onto the other currently empty frame, we have to remove the toolbar from its current (source) frame and place it into the other empty (destination) frame. In this process we also have to shrink the vacated frame and indeed, change the toolbar orientation and size parameters accordingly. Of course we could prepare this window layout, including the toolbar in either position, without the knowledge of how the drag-and-drop features are implemented, and let a software engineer next-door implement the dnd features. But what would be the point ?), actually, the point is just to illustrate the two step approach here. After we have our GUI design
  or window infrastructure established we can start focusing on drag-and-drop issues.
 
 
 
-
 {{br}}
 
 # (10.2.2.2)
 === Preparing DnD Environment In Toolbar Drag Program(s)
+(10.2.2.2){{br}}
 
+
 First dnd related thing we do in our DndTbWindow class is define the our toolbar as the draggable object in accordance with Gtk::Drag module conventions which we discussed at the beginning of this article and in particular in section 10.1.1 called '((<Identifying the DnD Objects|tut-gtk2-dnd#Identifying the DnD Objects>))' and the subsequent section 10.1.2 '((<The DnD Source And Destination Objects|tut-gtk2-dnd#The DnD Source And Destination Objects>))':
 
   TBDND_ACTIONS = actions=Gdk::DragContext::ACTION_ASK  # _ASK,_COPY,_LINK,_MOVE,_DEFAULT,_PRIVATE
@@ -851,23 +919,95 @@
 
 
 
+
 # (10.2.2.3) 
 === Setting Source And Destination Widgets In Toolbar Drag Program(s)
+(10.2.2.3){{br}}
 
+
 Not surprisingly, from the drag-and-drop processing perspective the most important methods in our DndTbWindow class are the 'set_dnd_source_frame_widget' and 'set_dnd_destination_frame_widget'. With the exception of a sneaky pseudo recursive call from the 'reverse_dnd_source_n_destination' method at the time((*'drag-drop'*))signal is emitted and caught by the destination frame, the two 'set_dnd_*' methods are both called only from the initialize method: 
- 
 
      set_dnd_source_frame_widget(htbframe)
      set_dnd_destination_frame_widget(htbframe, vtbframe)  # (source_fr, dest_fr)
 
+
+
 # (10.2.2.3.1)
 :'set_dnd_source_frame_widget(htbframe)' method
 
+    (10.2.2.3.1){{br}}
     The 'set_dnd_source_frame_widget(htbframe)' method is straight forward, nevertheless it contains a few perks that deserve special attention.
 
     In this method we register our source widget (frame) as a listener or the signal handler for 'button-press-event' signals (remember the frames normally do not respond to signals), so we first have to add (register) event/signal for our toolbar frame, and then register this frame's callback proc (or block) to respond to emissions of the 'button-press-event' signals. When and if the 'button-press-event' occurs while cursor is hovering over the frame, we make this signal handler to finally register the widget as the dnd source. The perk is that we can not use the regular Gtk::Drag.source_set method to set up our source widget (frame), as we did in our 'button-to-label-dnd.rb' example.
 
-
      widg.signal_connect('button-press-event') do |w, e|
        Gtk::Drag.begin(
          widget=w,
@@ -881,14 +953,88 @@
     :Note:
         The source dnd widget in our 'dnd-toolbar*.rb' programs does not respond to Gtk::Widget's ((*'drag-*'*))signals at all, in fact these signals do not even provide button, and events parameters, we need to register a dnd source widget!
 
+          dest_widg.signal_connect('drag-drop') do |w, e|
+
 Lastly, we use source widget (placeholder frame) as an argument (htbframe=/horizontal toolbar frame/) when we invoke the 'set_dnd_source_frame_widget (htbframe)' instance method, or as a parameter in this method definition, rather than an instance variable. The same is true for 'set_dnd_destination_frame_widget (htbframe, vtbframe)' instance method and its arguments and parameters. But the explanation of this should wait until you see, that both of these two 'set_dnd_*' methods are also called in a pseudo recursive call when the((*'drag-drop'*))signal is emitted and caught by the destination frame. And this (setting and managing the destination frame) is what we'll look at next.
 
 
 
-
 # (10.2.2.3.2)
 :'set_dnd_destination_frame_widget(htbframe, vtbframe)' method
 
+    (10.2.2.3.2){{br}}
     At first glance the odd thing about this method may be the fact that we receive as parameters both source and destination frames. This will only become clear after we study the destination widget's (frame's) signal-handler. Indeed, for this we first need to set (register) the destination widget, i.e. our destination frame. When called the first time, from initialize method, this frame is the vertical and empty one on the left side of the window. For this registration we use the regular Gtk::Drag.dest_set method.
 
      Gtk::Drag.dest_set(
@@ -911,6 +985,81 @@
     All this is accomplished in the 'drag-drop' signal-handler connected to the current destination widget (frame), where the GUI widgets are rearranged or repositioned and finalized in the the auxiliary 'reverse_dnd_source_n_destination' method, in particular in what we earlier announced as a pseudo recursive call, where the newly positioned widgets are reassigned their source and destination designations, as well as the new destination is re-registered as the new listener for the possible returning 'drag-drop' signal.
 
 
+    (10.2.2.3.2.1)
     :Why pseudo recursive call?
 
         If you look into the 'reverse_dnd_source_n_destination' method, which, upon catching the 'drag-drop' signal, is called last in the signal-handler attached to the current destination frame inside the 'set_dnd_destination_frame_widget' method, you will discover that in it (in the  'reverse_dnd_source_n_destination' method) the 'set_dnd_destination_frame_widget' method is called again, i.e. with the help of 'reverse_dnd_source_n_destination' method, the 'set_dnd_destination_frame_widget' method calls itself:
@@ -922,7 +997,81 @@
          end
 
         The above call from within the 'set_dnd_destination_frame_widget' method would be recursive if the requirement that each time the 'set_dnd_destination_frame_widget' method is called also the 'drag-drop' signal was emitted. This indeed is not the case, since we have just responded to the initial 'drag-drop' event, and are still in the process of turning the two source and destination frame (widget) associations around, and two consecutive drops, one after another, are out of the question. There's no way, any user can be that quick;)
-
 
 
 Finally, after you have seen, the temporary nature of source and destination widgets (frames) in either of our 'dnd-toolbar*.rb' programs, you may better understand the reasons we use source and destination widgets as arguments to these instance methods, rather than instance variables. Anyway, this after all, is more a question of style than substance.




ruby-gnome2-cvs メーリングリストの案内
アーカイブの一覧に戻る