/* 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 "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"

#include "tools-types.h"

#include "config/pikaguiconfig.h"

#include "core/pikaimage.h"

#include "widgets/pikahelp-ids.h"
#include "widgets/pikawidgets-utils.h"

#include "display/pikacanvasrectangle.h"
#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "display/pikadisplayshell-scale.h"

#include "pikamagnifyoptions.h"
#include "pikamagnifytool.h"
#include "pikatoolcontrol.h"

#include "pika-intl.h"


static void   pika_magnify_tool_button_press   (PikaTool              *tool,
                                                const PikaCoords      *coords,
                                                guint32                time,
                                                GdkModifierType        state,
                                                PikaButtonPressType    press_type,
                                                PikaDisplay           *display);
static void   pika_magnify_tool_button_release (PikaTool              *tool,
                                                const PikaCoords      *coords,
                                                guint32                time,
                                                GdkModifierType        state,
                                                PikaButtonReleaseType  release_type,
                                                PikaDisplay           *display);
static void   pika_magnify_tool_motion         (PikaTool              *tool,
                                                const PikaCoords      *coords,
                                                guint32                time,
                                                GdkModifierType        state,
                                                PikaDisplay           *display);
static void   pika_magnify_tool_modifier_key   (PikaTool              *tool,
                                                GdkModifierType        key,
                                                gboolean               press,
                                                GdkModifierType        state,
                                                PikaDisplay           *display);
static void   pika_magnify_tool_cursor_update  (PikaTool              *tool,
                                                const PikaCoords      *coords,
                                                GdkModifierType        state,
                                                PikaDisplay           *display);

static void   pika_magnify_tool_draw           (PikaDrawTool          *draw_tool);

static void   pika_magnify_tool_update_items   (PikaMagnifyTool       *magnify);


G_DEFINE_TYPE (PikaMagnifyTool, pika_magnify_tool, PIKA_TYPE_DRAW_TOOL)

#define parent_class pika_magnify_tool_parent_class


void
pika_magnify_tool_register (PikaToolRegisterCallback  callback,
                            gpointer                  data)
{
  (* callback) (PIKA_TYPE_MAGNIFY_TOOL,
                PIKA_TYPE_MAGNIFY_OPTIONS,
                pika_magnify_options_gui,
                0,
                "pika-zoom-tool",
                _("Zoom"),
                _("Zoom Tool: Adjust the zoom level"),
                N_("_Zoom"), "Z",
                NULL, PIKA_HELP_TOOL_ZOOM,
                PIKA_ICON_TOOL_ZOOM,
                data);
}

static void
pika_magnify_tool_class_init (PikaMagnifyToolClass *klass)
{
  PikaToolClass     *tool_class      = PIKA_TOOL_CLASS (klass);
  PikaDrawToolClass *draw_tool_class = PIKA_DRAW_TOOL_CLASS (klass);

  tool_class->button_press   = pika_magnify_tool_button_press;
  tool_class->button_release = pika_magnify_tool_button_release;
  tool_class->motion         = pika_magnify_tool_motion;
  tool_class->modifier_key   = pika_magnify_tool_modifier_key;
  tool_class->cursor_update  = pika_magnify_tool_cursor_update;

  draw_tool_class->draw      = pika_magnify_tool_draw;
}

static void
pika_magnify_tool_init (PikaMagnifyTool *magnify_tool)
{
  PikaTool *tool = PIKA_TOOL (magnify_tool);

  pika_tool_control_set_scroll_lock            (tool->control, TRUE);
  pika_tool_control_set_handle_empty_image     (tool->control, TRUE);
  pika_tool_control_set_wants_click            (tool->control, TRUE);
  pika_tool_control_set_snap_to                (tool->control, FALSE);

  pika_tool_control_set_tool_cursor            (tool->control,
                                                PIKA_TOOL_CURSOR_ZOOM);
  pika_tool_control_set_cursor_modifier        (tool->control,
                                                PIKA_CURSOR_MODIFIER_PLUS);
  pika_tool_control_set_toggle_cursor_modifier (tool->control,
                                                PIKA_CURSOR_MODIFIER_MINUS);

  magnify_tool->x = 0;
  magnify_tool->y = 0;
  magnify_tool->w = 0;
  magnify_tool->h = 0;
}

static void
pika_magnify_tool_button_press (PikaTool            *tool,
                                const PikaCoords    *coords,
                                guint32              time,
                                GdkModifierType      state,
                                PikaButtonPressType  press_type,
                                PikaDisplay         *display)
{
  PikaMagnifyTool *magnify = PIKA_MAGNIFY_TOOL (tool);

  magnify->x = coords->x;
  magnify->y = coords->y;
  magnify->w = 0;
  magnify->h = 0;

  pika_tool_control_activate (tool->control);
  tool->display = display;

  pika_draw_tool_start (PIKA_DRAW_TOOL (tool), display);
}

static void
pika_magnify_tool_button_release (PikaTool              *tool,
                                  const PikaCoords      *coords,
                                  guint32                time,
                                  GdkModifierType        state,
                                  PikaButtonReleaseType  release_type,
                                  PikaDisplay           *display)
{
  PikaMagnifyTool    *magnify = PIKA_MAGNIFY_TOOL (tool);
  PikaMagnifyOptions *options = PIKA_MAGNIFY_TOOL_GET_OPTIONS (tool);
  PikaDisplayShell   *shell   = pika_display_get_shell (tool->display);

  pika_draw_tool_stop (PIKA_DRAW_TOOL (tool));

  pika_tool_control_halt (tool->control);

  switch (release_type)
    {
    case PIKA_BUTTON_RELEASE_CLICK:
    case PIKA_BUTTON_RELEASE_NO_MOTION:
      pika_display_shell_scale (shell,
                                options->zoom_type,
                                0.0,
                                PIKA_ZOOM_FOCUS_POINTER);
      break;

    case PIKA_BUTTON_RELEASE_NORMAL:
      {
        gdouble  x, y;
        gdouble  width, height;
        gboolean resize_window;

        x      = (magnify->w < 0) ?  magnify->x + magnify->w : magnify->x;
        y      = (magnify->h < 0) ?  magnify->y + magnify->h : magnify->y;
        width  = (magnify->w < 0) ? -magnify->w : magnify->w;
        height = (magnify->h < 0) ? -magnify->h : magnify->h;

        /* Resize windows only in multi-window mode */
        resize_window = (options->auto_resize &&
                         ! PIKA_GUI_CONFIG (display->config)->single_window_mode);

        pika_display_shell_scale_to_rectangle (shell,
                                               options->zoom_type,
                                               x, y, width, height,
                                               resize_window);
      }
      break;

    default:
      break;
    }
}

static void
pika_magnify_tool_motion (PikaTool         *tool,
                          const PikaCoords *coords,
                          guint32           time,
                          GdkModifierType   state,
                          PikaDisplay      *display)
{
  PikaMagnifyTool *magnify = PIKA_MAGNIFY_TOOL (tool);

  magnify->w = coords->x - magnify->x;
  magnify->h = coords->y - magnify->y;

  pika_magnify_tool_update_items (magnify);
}

static void
pika_magnify_tool_modifier_key (PikaTool        *tool,
                                GdkModifierType  key,
                                gboolean         press,
                                GdkModifierType  state,
                                PikaDisplay     *display)
{
  PikaMagnifyOptions *options = PIKA_MAGNIFY_TOOL_GET_OPTIONS (tool);

  if (key == pika_get_toggle_behavior_mask ())
    {
      switch (options->zoom_type)
        {
        case PIKA_ZOOM_IN:
          g_object_set (options, "zoom-type", PIKA_ZOOM_OUT, NULL);
          break;

        case PIKA_ZOOM_OUT:
          g_object_set (options, "zoom-type", PIKA_ZOOM_IN, NULL);
          break;

        default:
          break;
        }
    }
}

static void
pika_magnify_tool_cursor_update (PikaTool         *tool,
                                 const PikaCoords *coords,
                                 GdkModifierType   state,
                                 PikaDisplay      *display)
{
  PikaMagnifyOptions *options = PIKA_MAGNIFY_TOOL_GET_OPTIONS (tool);

  pika_tool_control_set_toggled (tool->control,
                                 options->zoom_type == PIKA_ZOOM_OUT);

  PIKA_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
}

static void
pika_magnify_tool_draw (PikaDrawTool *draw_tool)
{
  PikaMagnifyTool *magnify = PIKA_MAGNIFY_TOOL (draw_tool);

  magnify->rectangle =
    pika_draw_tool_add_rectangle (draw_tool, FALSE,
                                  magnify->x,
                                  magnify->y,
                                  magnify->w,
                                  magnify->h);
}

static void
pika_magnify_tool_update_items (PikaMagnifyTool *magnify)
{
  if (pika_draw_tool_is_active (PIKA_DRAW_TOOL (magnify)))
    {
      pika_canvas_rectangle_set (magnify->rectangle,
                                 magnify->x,
                                 magnify->y,
                                 magnify->w,
                                 magnify->h);
    }
}
