Apr 2003, S.Geerken@ping.de Last update: Dec 2004 ========= Selection ========= The selection module (selection.[ch]) handles selections, as well as activation of links, which is closely related. General Overview ================ The selection module defines a structure "Selection", which is associated to GtkDwViewport, and so to a widget tree. The selection state is controlled by "abstract events", which are sent by single widgets by calling one of the following functions: a_Selection_button_press for button press events, a_Selection_button_release for button release events, and a_Selection_button_motion for motion events (with pressed mouse button). The widget must construct simple iterators (DwIterator), which will be transferred to extended iterators (DwExtIterator), see below for more details. All event handling functions have the same signature, the arguments in detail are: - DwIterator *it the iterator pointing on the item under the mouse pointer, - gint char_pos the exact (character) position within the iterator, - gint link if this item is associated with a link, its number (see DwImage, section "signals" for the meaning), otherwise -1, - GdkEventButton *event the event itself; only the button is used, - gboolean within_content TRUE, if there is some selectable content unter the mouse cursor; if set to FALSE, the "full screen" feature is used on double click. In some cases, char_pos would be difficult to determine. E.g., when the DwPage widget decides that the user is pointing on a position _at_the_end_ of an image (DwImage), it constructs a simple iterator pointing on this image widget. In a simple iterator, that fact that the pointer is at the end, would be represented by char_pos == 1. But when transferring this simple iterator into an extended iterator, this simple iterator is discarded and instead the stack has an iterator pointing to text at the top. As a result, only the first letter of the ALT text would be copied. To avoid this problem, widgets should in this case pass SELECTION_EOW (end of word) as char_pos, which is then automatically reduced to the actual length of the extended(!) iterator. The return value is the same as in DwWidget event handling methods. I.e., in most cases, they should simply return it. The events "link_pressed", "link_released" and "link_clicked" (but not "link_entered") are emitted by these functions, so that widgets which let the selection module handle links, should only emit "link_entered" for themselves. (See DwImage.txt for a description of this.) Selection State =============== Selection interferes with handling the activation of links, so the latter is also handled by the selection module. Details are based on following guidelines: 1. It should be simple to select links and to start selection in links. The rule to distinguish between link activation and selection is that the selection starts as soon as the user leaves the link. (This is, IMO, a useful feature. Even after drag and drop has been implemented in dillo, this should be somehow preserved.) 2. The selection should stay as long as possible, i.e., the old selection is only cleared when a new selection is started. The latter leads to a model with two states: the selection state and the link handling state. The general selection works, for events not pointing on links, like this (numbers in parantheses after the event denote the button, "n" means arbitrary button): motion(1) ,-----. | | press(1) on non-link V | NONE -----------------------> SELECTING <----------------. ^ | | | | release(1) | | | | press(1) | no V yes | `----------------------- Anything selected? --------> SELECTED The selected region is represented by two DwExtIterators. Links are handled by a different state machine: ,-----------------------------. | | | Switch to selection | (SELECTING) for n == 1. | ^ | | no | | yes | Still the same link? --. | ^ | | | | | | motion(n) | V press(n) on links | | NONE ---------------------> PRESSED(n) <-----' ^ | | | release(n) | | | V yes | Still the same link? -----------------. | | | | | no V | V Send "clicked" signal. | Switch to selection | | (SELECTED) for n == 1. | | | | |`----------------------------' | | | `----------------------------------------------------------' Switching to selection simply means that the selection state will eventually be SELECTED/SELECTING, with the original and the actual position making up the selection region. This happens for button 1, events with buttons other than 1 do not affect selection at all. TODO ==== * a_Selection_button_motion currently always assumes that button 1 has been pressed (since otherwise it would not do anything). This should be made a bit cleaner. * The selection should be cleared, when the user selects something somewhere else (perhaps switched into "non-active" mode, as some Gtk+ widgets do).