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