/* PIKA - Photo and Image Kooker Application
 * a rebranding of The GNU Image Manipulation Program (created with heckimp)
 * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
 *
 * Original copyright, applying to most contents (license remains unchanged): 
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program 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.
 *
 * This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#include <gegl.h>
#include <gtk/gtk.h>

#include "libpikawidgets/pikawidgets.h"

#include "widgets-types.h"

#include "config/pikaguiconfig.h"

#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikadisplay.h"

#include "pikaaction.h"
#include "pikacolordialog.h"
#include "pikadialogfactory.h"
#include "pikafgbgeditor.h"
#include "pikahelp-ids.h"
#include "pikasessioninfo.h"
#include "pikatoolbox.h"
#include "pikatoolbox-color-area.h"
#include "pikauimanager.h"

#include "pika-intl.h"


/*  local function prototypes  */

static void   color_area_foreground_changed (PikaContext          *context,
                                             const PikaRGB        *color,
                                             PikaColorDialog      *dialog);
static void   color_area_background_changed (PikaContext          *context,
                                             const PikaRGB        *color,
                                             PikaColorDialog      *dialog);

static void   color_area_dialog_update      (PikaColorDialog      *dialog,
                                             const PikaRGB        *color,
                                             PikaColorDialogState  state,
                                             PikaContext          *context);

static void   color_area_color_clicked      (PikaFgBgEditor       *editor,
                                             PikaActiveColor       active_color,
                                             PikaContext          *context);
static void   color_area_color_changed      (PikaContext          *context);
static void   color_area_tooltip            (PikaFgBgEditor       *editor,
                                             PikaFgBgTarget        target,
                                             GtkTooltip           *tooltip,
                                             PikaToolbox          *toolbox);


/*  local variables  */

static GtkWidget       *color_area          = NULL;
static GtkWidget       *color_dialog        = NULL;
static gboolean         color_dialog_active = FALSE;
static PikaActiveColor  edit_color          = PIKA_ACTIVE_COLOR_FOREGROUND;
static PikaRGB          revert_fg;
static PikaRGB          revert_bg;


/*  public functions  */

GtkWidget *
pika_toolbox_color_area_create (PikaToolbox *toolbox,
                                gint         width,
                                gint         height)
{
  PikaContext *context;

  g_return_val_if_fail (PIKA_IS_TOOLBOX (toolbox), NULL);

  context = pika_toolbox_get_context (toolbox);

  color_area = pika_fg_bg_editor_new (context);
  gtk_widget_set_size_request (color_area, width, height);

  pika_help_set_help_data (color_area, NULL,
                           PIKA_HELP_TOOLBOX_COLOR_AREA);
  g_object_set (color_area, "has-tooltip", TRUE, NULL);

  g_signal_connect (color_area, "color-clicked",
                    G_CALLBACK (color_area_color_clicked),
                    context);
  g_signal_connect_swapped (color_area, "colors-swapped",
                            G_CALLBACK (color_area_color_changed),
                            context);
  g_signal_connect_swapped (color_area, "colors-default",
                            G_CALLBACK (color_area_color_changed),
                            context);
  g_signal_connect_swapped (color_area, "color-dropped",
                            G_CALLBACK (color_area_color_changed),
                            context);

  g_signal_connect (color_area, "tooltip",
                    G_CALLBACK (color_area_tooltip),
                    toolbox);

  return color_area;
}


/*  private functions  */

static void
color_area_foreground_changed (PikaContext     *context,
                               const PikaRGB   *color,
                               PikaColorDialog *dialog)
{
  if (edit_color == PIKA_ACTIVE_COLOR_FOREGROUND)
    {
      g_signal_handlers_block_by_func (dialog,
                                       color_area_dialog_update,
                                       context);

      /* FIXME this should use PikaColorDialog API */
      pika_color_selection_set_color (PIKA_COLOR_SELECTION (dialog->selection),
                                      color);

      g_signal_handlers_unblock_by_func (dialog,
                                         color_area_dialog_update,
                                         context);
    }
}

static void
color_area_background_changed (PikaContext     *context,
                               const PikaRGB   *color,
                               PikaColorDialog *dialog)
{
  if (edit_color == PIKA_ACTIVE_COLOR_BACKGROUND)
    {
      g_signal_handlers_block_by_func (dialog,
                                       color_area_dialog_update,
                                       context);

      /* FIXME this should use PikaColorDialog API */
      pika_color_selection_set_color (PIKA_COLOR_SELECTION (dialog->selection),
                                      color);

      g_signal_handlers_unblock_by_func (dialog,
                                         color_area_dialog_update,
                                         context);
    }
}

static void
color_area_dialog_update (PikaColorDialog      *dialog,
                          const PikaRGB        *color,
                          PikaColorDialogState  state,
                          PikaContext          *context)
{
  switch (state)
    {
    case PIKA_COLOR_DIALOG_OK:
      gtk_widget_hide (color_dialog);
      color_dialog_active = FALSE;
      /* Fallthrough */

    case PIKA_COLOR_DIALOG_UPDATE:
      if (edit_color == PIKA_ACTIVE_COLOR_FOREGROUND)
        {
          g_signal_handlers_block_by_func (context,
                                           color_area_foreground_changed,
                                           dialog);

          pika_context_set_foreground (context, color);

          g_signal_handlers_unblock_by_func (context,
                                             color_area_foreground_changed,
                                             dialog);
        }
      else
        {
          g_signal_handlers_block_by_func (context,
                                           color_area_background_changed,
                                           dialog);

          pika_context_set_background (context, color);

          g_signal_handlers_unblock_by_func (context,
                                             color_area_background_changed,
                                             dialog);
        }
      break;

    case PIKA_COLOR_DIALOG_CANCEL:
      gtk_widget_hide (color_dialog);
      color_dialog_active = FALSE;
      pika_context_set_foreground (context, &revert_fg);
      pika_context_set_background (context, &revert_bg);
      break;
    }

  if (pika_context_get_display (context))
    pika_display_grab_focus (pika_context_get_display (context));
}

static void
color_area_color_clicked (PikaFgBgEditor  *editor,
                          PikaActiveColor  active_color,
                          PikaContext     *context)
{
  PikaRGB      color;
  const gchar *title;

  if (! color_dialog_active)
    {
      pika_context_get_foreground (context, &revert_fg);
      pika_context_get_background (context, &revert_bg);
    }

  if (active_color == PIKA_ACTIVE_COLOR_FOREGROUND)
    {
      pika_context_get_foreground (context, &color);
      title = _("Change Foreground Color");
    }
  else
    {
      pika_context_get_background (context, &color);
      title = _("Change Background Color");
    }

  edit_color = active_color;

  if (! color_dialog)
    {
      color_dialog = pika_color_dialog_new (NULL, context, TRUE,
                                            NULL, NULL, NULL,
                                            GTK_WIDGET (editor),
                                            pika_dialog_factory_get_singleton (),
                                            "pika-toolbox-color-dialog",
                                            &color,
                                            TRUE, FALSE);

      g_signal_connect_object (color_dialog, "update",
                               G_CALLBACK (color_area_dialog_update),
                               G_OBJECT (context), 0);

      g_signal_connect_object (context, "foreground-changed",
                               G_CALLBACK (color_area_foreground_changed),
                               G_OBJECT (color_dialog), 0);
      g_signal_connect_object (context, "background-changed",
                               G_CALLBACK (color_area_background_changed),
                               G_OBJECT (color_dialog), 0);
    }
  else if (! gtk_widget_get_visible (color_dialog))
    {
      pika_dialog_factory_position_dialog (pika_dialog_factory_get_singleton (),
                                           "pika-toolbox-color-dialog",
                                           color_dialog,
                                           pika_widget_get_monitor (GTK_WIDGET (editor)));
    }

  gtk_window_set_title (GTK_WINDOW (color_dialog), title);
  pika_color_dialog_set_color (PIKA_COLOR_DIALOG (color_dialog), &color);

  gtk_window_present (GTK_WINDOW (color_dialog));
  color_dialog_active = TRUE;
}

static void
color_area_color_changed (PikaContext *context)
{
  if (pika_context_get_display (context))
    pika_display_grab_focus (pika_context_get_display (context));
}

static void
color_area_tooltip (PikaFgBgEditor *editor,
                    PikaFgBgTarget  target,
                    GtkTooltip     *tooltip,
                    PikaToolbox    *toolbox)
{
  PikaUIManager *manager = pika_dock_get_ui_manager (PIKA_DOCK (toolbox));
  PikaAction    *action  = NULL;
  const gchar   *text    = NULL;

  switch (target)
    {
    case PIKA_FG_BG_TARGET_FOREGROUND:
      text = _("The active foreground color.\n"
               "Click to open the color selection dialog.");
      break;

    case PIKA_FG_BG_TARGET_BACKGROUND:
      text = _("The active background color.\n"
               "Click to open the color selection dialog.");
      break;

    case PIKA_FG_BG_TARGET_SWAP:
      action = pika_ui_manager_find_action (manager, "context",
                                            "context-colors-swap");
      text = pika_action_get_tooltip (action);
      break;

    case PIKA_FG_BG_TARGET_DEFAULT:
      action = pika_ui_manager_find_action (manager, "context",
                                            "context-colors-default");
      text = pika_action_get_tooltip (action);
      break;

    default:
      break;
    }

  if (text)
    {
      gchar *markup = NULL;

      if (action)
        {
          gchar **accels = pika_action_get_display_accels (action);

          if (accels && accels[0])
            {
              gchar *escaped = g_markup_escape_text (text, -1);

              markup = g_strdup_printf ("%s  <b>%s</b>", escaped, accels[0]);
              g_free (escaped);
            }

          g_strfreev (accels);
        }

      if (markup)
        {
          gtk_tooltip_set_markup (tooltip, markup);
          g_free (markup);
        }
      else
        {
          gtk_tooltip_set_text (tooltip, text);
        }
    }
}
