[text] Different selection modes with multiple clicks

ClutterText should offer multiple selection modes depending on the
number of pointer clicks.

Following the GTK+ conventions:

  - double click selects the current word
  - triple click selects the current line
This commit is contained in:
Emmanuele Bassi 2009-03-30 16:46:57 +01:00
parent f6d938a0db
commit 02ea81ce02

View File

@ -887,6 +887,157 @@ cursor_paint (ClutterText *self)
}
}
static gint
clutter_text_move_word_backward (ClutterText *self,
gint start)
{
ClutterTextPrivate *priv = self->priv;
gint retval = start;
if (priv->text && start > 0)
{
PangoLayout *layout = clutter_text_get_layout (self);
PangoLogAttr *log_attrs = NULL;
gint n_attrs = 0;
pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
retval = start - 1;
while (retval > 0 && !log_attrs[retval].is_word_start)
retval -= 1;
g_free (log_attrs);
}
return retval;
}
static gint
clutter_text_move_word_forward (ClutterText *self,
gint start)
{
ClutterTextPrivate *priv = self->priv;
gint retval = start;
if (priv->text && start > 0)
{
PangoLayout *layout = clutter_text_get_layout (self);
PangoLogAttr *log_attrs = NULL;
gint n_attrs = 0;
pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
retval = start - 1;
while (retval > 0 && !log_attrs[retval].is_word_end)
retval += 1;
g_free (log_attrs);
}
return retval;
}
static gint
clutter_text_move_line_start (ClutterText *self,
gint start)
{
ClutterTextPrivate *priv = self->priv;
PangoLayoutLine *layout_line;
PangoLayout *layout;
gint line_no;
gint index_;
gint position;
layout = clutter_text_get_layout (self);
if (start == 0)
index_ = 0;
else
index_ = offset_to_bytes (priv->text, start);
pango_layout_index_to_line_x (layout, index_,
0,
&line_no, NULL);
layout_line = pango_layout_get_line_readonly (layout, line_no);
if (!layout_line)
return FALSE;
pango_layout_line_x_to_index (layout_line, 0, &index_, NULL);
position = bytes_to_offset (priv->text, index_);
return position;
}
static gint
clutter_text_move_line_end (ClutterText *self,
gint start)
{
ClutterTextPrivate *priv = self->priv;
PangoLayoutLine *layout_line;
PangoLayout *layout;
gint line_no;
gint index_;
gint trailing;
gint position;
layout = clutter_text_get_layout (self);
if (start == 0)
index_ = 0;
else
index_ = offset_to_bytes (priv->text, priv->position);
pango_layout_index_to_line_x (layout, index_,
0,
&line_no, NULL);
layout_line = pango_layout_get_line_readonly (layout, line_no);
if (!layout_line)
return FALSE;
pango_layout_line_x_to_index (layout_line, G_MAXINT, &index_, &trailing);
index_ += trailing;
position = bytes_to_offset (priv->text, index_);
return position;
}
static void
clutter_text_select_word (ClutterText *self)
{
gint cursor_pos = self->priv->position;
gint start_pos, end_pos;
start_pos = clutter_text_move_word_backward (self, cursor_pos);
end_pos = clutter_text_move_word_forward (self, cursor_pos);
clutter_text_set_selection (self, start_pos, end_pos);
}
static void
clutter_text_select_line (ClutterText *self)
{
ClutterTextPrivate *priv = self->priv;
gint cursor_pos = priv->position;
gint start_pos, end_pos;
if (priv->single_line_mode)
{
start_pos = 0;
end_pos = -1;
}
else
{
start_pos = clutter_text_move_line_start (self, cursor_pos);
end_pos = clutter_text_move_line_end (self, cursor_pos);
}
clutter_text_set_selection (self, start_pos, end_pos);
}
static gboolean
clutter_text_button_press (ClutterActor *actor,
ClutterButtonEvent *event)
@ -918,14 +1069,34 @@ clutter_text_button_press (ClutterActor *actor,
res = clutter_actor_transform_stage_point (actor, x, y, &x, &y);
if (res)
{
gint offset;
index_ = clutter_text_coords_to_position (self,
CLUTTER_UNITS_TO_INT (x),
CLUTTER_UNITS_TO_INT (y));
clutter_text_set_cursor_position (self,
bytes_to_offset (priv->text, index_));
clutter_text_set_selection_bound (self,
bytes_to_offset (priv->text, index_));
offset = bytes_to_offset (priv->text, index_);
/* what we select depends on the number of button clicks we
* receive:
*
* 1: just position the cursor and the selection
* 2: select the current word
* 3: select the contents of the whole actor
*/
if (event->click_count == 1)
{
clutter_text_set_cursor_position (self, offset);
clutter_text_set_selection_bound (self, offset);
}
else if (event->click_count == 2)
{
clutter_text_select_word (self);
}
else if (event->click_count == 3)
{
clutter_text_select_line (self);
}
}
/* grab the pointer */
@ -1259,7 +1430,7 @@ clutter_text_real_move_left (ClutterText *self,
len = priv->n_chars;
if (pos != 0 && len !=0)
if (pos != 0 && len != 0)
{
if (pos == -1)
clutter_text_set_cursor_position (self, len - 1);
@ -1406,30 +1577,9 @@ clutter_text_real_line_start (ClutterText *self,
ClutterModifierType modifiers)
{
ClutterTextPrivate *priv = self->priv;
PangoLayoutLine *layout_line;
PangoLayout *layout;
gint line_no;
gint index_;
gint position;
layout = clutter_text_get_layout (self);
if (priv->position == 0)
index_ = 0;
else
index_ = offset_to_bytes (priv->text, priv->position);
pango_layout_index_to_line_x (layout, index_,
0,
&line_no, NULL);
layout_line = pango_layout_get_line_readonly (layout, line_no);
if (!layout_line)
return FALSE;
pango_layout_line_x_to_index (layout_line, 0, &index_, NULL);
position = bytes_to_offset (priv->text, index_);
position = clutter_text_move_line_start (self, priv->position);
clutter_text_set_cursor_position (self, position);
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
@ -1445,33 +1595,9 @@ clutter_text_real_line_end (ClutterText *self,
ClutterModifierType modifiers)
{
ClutterTextPrivate *priv = self->priv;
PangoLayoutLine *layout_line;
PangoLayout *layout;
gint line_no;
gint index_;
gint trailing;
gint position;
layout = clutter_text_get_layout (self);
if (priv->position == 0)
index_ = 0;
else
index_ = offset_to_bytes (priv->text, priv->position);
pango_layout_index_to_line_x (layout, index_,
0,
&line_no, NULL);
layout_line = pango_layout_get_line_readonly (layout, line_no);
if (!layout_line)
return FALSE;
pango_layout_line_x_to_index (layout_line, G_MAXINT, &index_, &trailing);
index_ += trailing;
position = bytes_to_offset (priv->text, index_);
position = clutter_text_move_line_end (self, priv->position);
clutter_text_set_cursor_position (self, position);
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))