static gboolean
gimp_container_grid_view_move_by (GimpContainerGridView *grid_view,
                                  gint                   x,
                                  gint                   y)
{
  GimpContainerView *view = GIMP_CONTAINER_VIEW (grid_view);
  GimpContainer     *container;
  GimpViewable      *item;
  gint               index;

  if (! grid_view->selected_item)
    return FALSE;

  container = gimp_container_view_get_container (view);

  item = grid_view->selected_item->viewable;

  index = gimp_container_get_child_index (container, GIMP_OBJECT (item));

  index += x;
  index = CLAMP (index, 0, gimp_container_get_n_children (container) - 1);

  index += y * grid_view->columns;
  while (index < 0)
    index += grid_view->columns;
  while (index >= gimp_container_get_n_children (container))
    index -= grid_view->columns;

  item = (GimpViewable *) gimp_container_get_child_by_index (container, index);
  if (item)
    gimp_container_view_item_selected (GIMP_CONTAINER_VIEW (view), item);

  return TRUE;
}
static void
gimp_container_entry_changed (GtkEntry          *entry,
                              GimpContainerView *view)
{
  GimpContainer *container = gimp_container_view_get_container (view);
  GimpObject    *object;
  const gchar   *text;

  if (! container)
    return;

  text = gtk_entry_get_text (entry);

  object = gimp_container_get_child_by_name (container, text);

  if (object)
    {
      gtk_widget_modify_text (GTK_WIDGET (entry), GTK_STATE_NORMAL, NULL);
      gimp_container_view_item_selected (view, GIMP_VIEWABLE (object));
    }
  else
    {
      /* While editing the entry, contents shows in red for non-existent item. */
      GdkColor     gdk_red;

      gdk_red.red = 65535;
      gdk_red.green = 0;
      gdk_red.blue = 0;

      gtk_widget_modify_text (GTK_WIDGET (entry), GTK_STATE_NORMAL, &gdk_red);
    }
}
static void
gimp_container_entry_match_selected (GtkEntryCompletion *widget,
                                     GtkTreeModel       *model,
                                     GtkTreeIter        *iter,
                                     GimpContainerView  *view)
{
  GimpViewRenderer *renderer;

  gtk_tree_model_get (model, iter,
                      GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
                      -1);

  gimp_container_view_item_selected (view, renderer->viewable);
  g_object_unref (renderer);
}
static gboolean
gimp_container_grid_view_item_selected (GtkWidget      *widget,
                                        GdkEventButton *bevent,
                                        gpointer        data)
{
  if (bevent->type == GDK_BUTTON_PRESS && bevent->button == 1)
    {
      if (gtk_widget_get_can_focus (data) && ! gtk_widget_has_focus (data))
        gtk_widget_grab_focus (GTK_WIDGET (data));

      gimp_container_view_item_selected (GIMP_CONTAINER_VIEW (data),
                                         GIMP_VIEW (widget)->viewable);
    }

  return FALSE;
}
static void
gimp_container_entry_changed (GtkEntry          *entry,
                              GimpContainerView *view)
{
  GimpContainer *container = gimp_container_view_get_container (view);
  GimpObject    *object;
  const gchar   *text;

  if (! container)
    return;

  text = gtk_entry_get_text (entry);

  object = gimp_container_get_child_by_name (container, text);

  if (object)
    gimp_container_view_item_selected (view, GIMP_VIEWABLE (object));
}
static void
gimp_container_combo_box_changed (GtkComboBox       *combo,
                                  GimpContainerView *view)
{
  GtkTreeIter iter;

  if (gtk_combo_box_get_active_iter (combo, &iter))
    {
      GimpViewRenderer *renderer;

      gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
                          GIMP_CONTAINER_TREE_STORE_COLUMN_RENDERER, &renderer,
                          -1);

      gimp_container_view_item_selected (view, renderer->viewable);
      g_object_unref (renderer);
    }
}
static void
gimp_container_grid_view_item_context (GtkWidget *widget,
                                       gpointer   data)
{
  /*  ref the view because calling gimp_container_view_item_selected()
   *  may destroy the widget
   */
  g_object_ref (data);

  if (gimp_container_view_item_selected (GIMP_CONTAINER_VIEW (data),
                                         GIMP_VIEW (widget)->viewable))
    {
      gimp_container_view_item_context (GIMP_CONTAINER_VIEW (data),
                                        GIMP_VIEW (widget)->viewable);
    }

  g_object_unref (data);
}
static void
gimp_container_combo_box_changed (GtkComboBox       *combo_box,
                                  GimpContainerView *view)
{
  GtkTreeIter iter;

  if (GTK_COMBO_BOX_CLASS (parent_class)->changed)
    GTK_COMBO_BOX_CLASS (parent_class)->changed (combo_box);

  if (gtk_combo_box_get_active_iter (combo_box, &iter))
    {
      GimpViewRenderer *renderer;

      gtk_tree_model_get (gtk_combo_box_get_model (combo_box), &iter,
                          COLUMN_RENDERER, &renderer,
                          -1);

      gimp_container_view_item_selected (view, renderer->viewable);
      g_object_unref (renderer);
    }
}
static gboolean
gimp_container_grid_view_move_cursor (GimpContainerGridView *grid_view,
                                      GtkMovementStep        step,
                                      gint                   count)
{
  GimpContainerView *view = GIMP_CONTAINER_VIEW (grid_view);
  GimpContainer     *container;
  GimpViewable      *item;

  if (! gtk_widget_has_focus (GTK_WIDGET (grid_view)) || count == 0)
    return FALSE;

  container = gimp_container_view_get_container (view);

  switch (step)
    {
    case GTK_MOVEMENT_PAGES:
      return gimp_container_grid_view_move_by (grid_view, 0,
                                               count * grid_view->visible_rows);

    case GTK_MOVEMENT_BUFFER_ENDS:
      count = count < 0 ? 0 : gimp_container_get_n_children (container) - 1;

      item = (GimpViewable *) gimp_container_get_child_by_index (container,
                                                                 count);
      if (item)
        gimp_container_view_item_selected (view, item);

      return TRUE;

    default:
      break;
    }

  return FALSE;
}