Revision 5de30b493da9bb707b0bb211107acf10420cb7d6 authored by Ulrich Pegelow on 30 November 2012, 18:40:36 UTC, committed by Ulrich Pegelow on 30 November 2012, 18:40:36 UTC
1 parent 984f66c
Raw File
styles.c
/*
    This file is part of darktable,
    copyright (c) 2009--2010 johannes hanika.

    darktable is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    darktable is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with darktable.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/darktable.h"
#include "common/styles.h"
#include "control/control.h"
#include "control/conf.h"
#include "control/jobs.h"
#include "gui/accelerators.h"
#include "gui/gtk.h"
#include "gui/styles.h"
#include "libs/lib.h"
#include <stdlib.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "dtgtk/button.h"

DT_MODULE(1)

typedef struct dt_lib_styles_t
{
  GtkEntry *entry;
  GtkWidget *duplicate;
  GtkTreeView *list;
  GtkWidget *delete_button, *import_button, *export_button, *edit_button;
}
dt_lib_styles_t;


const char*
name ()
{
  return _("styles");
}

uint32_t views()
{
  return DT_VIEW_LIGHTTABLE;
}

uint32_t container()
{
  return DT_UI_CONTAINER_PANEL_RIGHT_CENTER;
}

int
position ()
{
  return 599;
}

void init_key_accels(dt_lib_module_t *self)
{
  dt_accel_register_lib(self, NC_("accel", "delete"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "export"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "import"), 0, 0);
  dt_accel_register_lib(self, NC_("accel", "edit"), 0, 0);
}

void connect_key_accels(dt_lib_module_t *self)
{
  dt_lib_styles_t *d = (dt_lib_styles_t*)self->data;

  dt_accel_connect_button_lib(self, "delete", d->delete_button);
  dt_accel_connect_button_lib(self, "export", d->export_button);
  dt_accel_connect_button_lib(self, "import", d->import_button);
  if(d->edit_button)
    dt_accel_connect_button_lib(self, "edit", d->edit_button);
}

typedef enum _styles_columns_t
{
  DT_STYLES_COL_NAME=0,
  DT_STYLES_COL_TOOLTIP,
  DT_STYLES_NUM_COLS
}
_styles_columns_t;

static int
get_font_height(GtkWidget *widget, const char *str)
{
  int width, height;

  PangoLayout *layout = pango_layout_new (gtk_widget_get_pango_context (widget));

  pango_layout_set_text(layout, str, -1);
  pango_layout_set_font_description(layout, NULL);
  pango_layout_get_pixel_size (layout, &width, &height);

  g_object_unref (layout);
  return height;
}


static void _gui_styles_update_view( dt_lib_styles_t *d)
{
  /* clear current list */
  GtkTreeIter iter;
  GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(d->list));
  g_object_ref(model);
  gtk_tree_view_set_model(GTK_TREE_VIEW(d->list), NULL);
  gtk_list_store_clear(GTK_LIST_STORE(model));

  GList *result = dt_styles_get_list(gtk_entry_get_text(d->entry));
  if (result)
  {
    do
    {
      dt_style_t *style = (dt_style_t *)result->data;

      char* items_string = dt_styles_get_item_list_as_string (style->name);
      gchar* tooltip = NULL;

      if((style->description) && strlen (style->description))
      {
        tooltip = g_strconcat("<b><i>", style->description, "</i></b>\n", items_string, NULL);
      }
      else
      {
        tooltip = g_strdup(items_string);
      }

      gtk_list_store_append (GTK_LIST_STORE(model), &iter);
      gtk_list_store_set (GTK_LIST_STORE(model), &iter,
                          DT_STYLES_COL_NAME, style->name,
                          DT_STYLES_COL_TOOLTIP, tooltip,
                          -1);

      g_free(style->name);
      g_free(style->description);
      g_free(style);
      g_free(items_string);
      g_free(tooltip);
    }
    while ((result=g_list_next(result))!=NULL);
  }

  gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(d->list), DT_STYLES_COL_TOOLTIP);
  gtk_tree_view_set_model(GTK_TREE_VIEW(d->list), model);
  g_object_unref(model);

}

static void
_styles_row_activated_callback (GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col, gpointer user_data)
{
  dt_lib_styles_t *d = (dt_lib_styles_t *)user_data;

  GtkTreeModel *model;
  GtkTreeIter   iter;
  gtk_widget_set_size_request (GTK_WIDGET (d->list), -1, -1);
  model = gtk_tree_view_get_model (d->list);

  if (!gtk_tree_model_get_iter (model, &iter, path))
    return;

  gchar *name;
  gtk_tree_model_get (model, &iter, DT_STYLES_COL_NAME, &name, -1);

  if (name)
    dt_styles_apply_to_selection (name,gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (d->duplicate)));

}

static void edit_clicked(GtkWidget *w,gpointer user_data)
{
  dt_lib_styles_t *d = (dt_lib_styles_t *)user_data;

  GtkTreeIter iter;
  GtkTreeModel *model;
  model = gtk_tree_view_get_model (d->list);
  GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(d->list));
  if(!gtk_tree_selection_get_selected(selection, &model, &iter)) return;
  char *name=NULL;
  gtk_tree_model_get (model, &iter,
                      DT_STYLES_COL_NAME, &name,
                      -1);
  if (name)
  {
    dt_gui_styles_dialog_edit (name);
    _gui_styles_update_view(d);
  }
}

static char* get_style_name(dt_lib_styles_t *list_style)
{
  GtkTreeIter iter;
  GtkTreeModel *model;
  model = gtk_tree_view_get_model (list_style->list);
  GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_style->list));

  if(!gtk_tree_selection_get_selected(selection, &model, &iter)) return NULL;

  char *name = NULL;
  gtk_tree_model_get (model, &iter,
                      DT_STYLES_COL_NAME, &name,
                      -1);
  return name;
}

static void delete_clicked(GtkWidget *w,gpointer user_data)
{
  dt_lib_styles_t *d = (dt_lib_styles_t *)user_data;
  char *name = get_style_name(d);
  if (name)
  {
    dt_styles_delete_by_name (name);
    _gui_styles_update_view(d);
  }
}

static void export_clicked (GtkWidget *w,gpointer user_data)
{
  dt_lib_styles_t *d = (dt_lib_styles_t *)user_data;
  char *name = get_style_name(d);
  if(name)
  {
    GtkWidget *win = dt_ui_main_window(darktable.gui->ui);
    GtkWidget *filechooser = gtk_file_chooser_dialog_new (_("select directory"),
                             GTK_WINDOW (win),
                             GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
                             GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                             GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
                             (char *)NULL);
    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(filechooser),g_get_home_dir());
    gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE);
    if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT )
    {
      char *filedir = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
      dt_styles_save_to_file(name,filedir,FALSE);
      g_free (filedir);
    }
    g_free(name);
    gtk_widget_destroy (filechooser);
  }
}

static void import_clicked (GtkWidget *w,gpointer user_data)
{
  GtkWidget *win = dt_ui_main_window(darktable.gui->ui);
  GtkWidget *filechooser = gtk_file_chooser_dialog_new (_("select style"),
                           GTK_WINDOW (win),
                           GTK_FILE_CHOOSER_ACTION_OPEN,
                           GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                           GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
                           (char *)NULL);

  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE);
  gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(filechooser),g_get_home_dir());

  GtkFileFilter *filter;
  filter = GTK_FILE_FILTER(gtk_file_filter_new());
  gtk_file_filter_add_pattern(filter, "*.dtstyle");
  gtk_file_filter_set_name(filter, _("darktable style files"));
  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);

  filter = GTK_FILE_FILTER(gtk_file_filter_new());
  gtk_file_filter_add_pattern(filter, "*");
  gtk_file_filter_set_name(filter, _("all files"));

  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(filechooser), filter);

  if (gtk_dialog_run (GTK_DIALOG (filechooser)) == GTK_RESPONSE_ACCEPT )
  {
    char *filename;
    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
    dt_styles_import_from_file(filename);
    //
    dt_lib_styles_t *d = (dt_lib_styles_t *)user_data;
    _gui_styles_update_view(d);
    //
    g_free (filename);
  }
  gtk_widget_destroy (filechooser);
}

static gboolean
entry_callback (GtkEntry *entry, gpointer user_data)
{
  _gui_styles_update_view(user_data);
  return FALSE;
}

static gboolean
entry_activated (GtkEntry *entry, gpointer user_data)
{
  dt_lib_styles_t *d = (dt_lib_styles_t *)user_data;
  const gchar *name = gtk_entry_get_text(d->entry);
  if (name)
    dt_styles_apply_to_selection (name,gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (d->duplicate)));

  return FALSE;
}

static gboolean
duplicate_callback (GtkEntry *entry, gpointer user_data)
{
  dt_lib_styles_t *d = (dt_lib_styles_t *)user_data;
  dt_conf_set_bool ("ui_last/styles_create_duplicate", gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON (d->duplicate)));
  return FALSE;
}

void
gui_init (dt_lib_module_t *self)
{
  dt_lib_styles_t *d = (dt_lib_styles_t *)malloc (sizeof (dt_lib_styles_t));
  self->data = (void *)d;
  d->edit_button = NULL;
  self->widget = gtk_vbox_new (FALSE, 5);
  GtkWidget *w;
  GtkWidget *scrolled;

  /* list */
  d->list = GTK_TREE_VIEW (gtk_tree_view_new ());
  gtk_tree_view_set_headers_visible(d->list,FALSE);
  GtkListStore *liststore = gtk_list_store_new (DT_STYLES_NUM_COLS, G_TYPE_STRING, G_TYPE_STRING);
  GtkTreeViewColumn *col = gtk_tree_view_column_new ();
  gtk_tree_view_append_column (GTK_TREE_VIEW (d->list), col);
  GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_column_pack_start (col, renderer, TRUE);
  gtk_tree_view_column_add_attribute (col, renderer, "text", DT_STYLES_COL_NAME);

  int ht = get_font_height( GTK_WIDGET (d->list), "Dreggn");
  gtk_widget_set_size_request (GTK_WIDGET (d->list), -1, 5*ht);

  gtk_tree_selection_set_mode (gtk_tree_view_get_selection(GTK_TREE_VIEW(d->list)), GTK_SELECTION_SINGLE);
  gtk_tree_view_set_model (GTK_TREE_VIEW(d->list), GTK_TREE_MODEL(liststore));
  g_object_unref (liststore);

  g_object_set(G_OBJECT(d->list), "tooltip-text", _("available styles,\ndoubleclick to apply"), (char *)NULL);
  g_signal_connect (d->list, "row-activated", G_CALLBACK(_styles_row_activated_callback), d);

  /* filter entry */
  w = gtk_entry_new();
  d->entry=GTK_ENTRY(w);
  g_object_set(G_OBJECT(w), "tooltip-text", _("enter style name"), (char *)NULL);
  g_signal_connect (d->entry, "changed", G_CALLBACK(entry_callback),d);
  g_signal_connect (d->entry, "activate", G_CALLBACK(entry_activated),d);

  dt_gui_key_accel_block_on_focus ( GTK_WIDGET (d->entry));
  
  scrolled = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_box_pack_start(GTK_BOX (self->widget),GTK_WIDGET (d->entry),TRUE,FALSE,0);
  gtk_box_pack_start(GTK_BOX (self->widget),GTK_WIDGET (scrolled),TRUE,FALSE,0);
  gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(d->list));

  d->duplicate = gtk_check_button_new_with_label(_("create duplicate"));
  gtk_box_pack_start(GTK_BOX (self->widget),GTK_WIDGET (d->duplicate),TRUE,FALSE,0);
  g_signal_connect (d->duplicate, "toggled", G_CALLBACK(duplicate_callback),d);
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (d->duplicate), dt_conf_get_bool("ui_last/styles_create_duplicate"));
  g_object_set (d->duplicate, "tooltip-text", _("creates a duplicate of the image before applying style"), (char *)NULL);
  
  GtkWidget *hbox  = gtk_hbox_new(TRUE, 5);
  GtkWidget *vbox1 = gtk_vbox_new(TRUE, 5);
  GtkWidget *vbox2 = gtk_vbox_new(TRUE, 5);
  gtk_box_pack_start(GTK_BOX (hbox), vbox1, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX (self->widget),hbox,TRUE,FALSE,0);

  // edit
  GtkWidget *widget = gtk_button_new_with_label(_("edit"));
  d->edit_button = widget;
  g_signal_connect (widget, "clicked", G_CALLBACK(edit_clicked),d);
  g_object_set (widget, "tooltip-text", _("edit the selected style in list above"), (char *)NULL);
  gtk_box_pack_start(GTK_BOX (vbox1),widget,TRUE,TRUE,0);

  // delete
  widget=gtk_button_new_with_label(_("delete"));
  d->delete_button = widget;
  g_signal_connect (widget, "clicked", G_CALLBACK(delete_clicked),d);
  g_object_set (widget, "tooltip-text", _("deletes the selected style in list above"), (char *)NULL);
  gtk_box_pack_start(GTK_BOX (vbox2),widget,TRUE,TRUE,0);
  
  // import button
  GtkWidget *importButton = gtk_button_new_with_label(C_("styles", "import"));
  d->import_button = importButton;
  g_object_set (importButton, "tooltip-text", _("import style from a style file"), (char *)NULL);
  g_signal_connect (importButton, "clicked", G_CALLBACK(import_clicked),d);
  gtk_box_pack_start(GTK_BOX (vbox1),importButton,TRUE,TRUE,0);

  // export button
  GtkWidget *exportButton = gtk_button_new_with_label(_("export"));
  d->export_button = exportButton;
  g_object_set (exportButton, "tooltip-text", _("export the selected style into a style file"), (char *)NULL);
  g_signal_connect (exportButton, "clicked", G_CALLBACK(export_clicked),d);
  gtk_box_pack_start(GTK_BOX (vbox2),exportButton,TRUE,TRUE,0);

  // add entry completion
  GtkEntryCompletion *completion = gtk_entry_completion_new();
  gtk_entry_completion_set_model(completion, gtk_tree_view_get_model(GTK_TREE_VIEW(d->list)));
  gtk_entry_completion_set_text_column(completion, 0);
  gtk_entry_completion_set_inline_completion(completion, TRUE);
  gtk_entry_set_completion(d->entry, completion);

  /* update filtered list */
  _gui_styles_update_view(d);

}

void
gui_cleanup (dt_lib_module_t *self)
{
  free(self->data);
  self->data = NULL;
}


// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
// vim: shiftwidth=2 expandtab tabstop=2 cindent
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-space on;
back to top