/* 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-2002 Spencer Kimball, Peter Mattis, and others
 *
 * 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/>.
 */

#ifndef __PIKA_TOOL_H__
#define __PIKA_TOOL_H__


#include "core/pikaobject.h"


#define PIKA_TYPE_TOOL            (pika_tool_get_type ())
#define PIKA_TOOL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_TOOL, PikaTool))
#define PIKA_TOOL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_TOOL, PikaToolClass))
#define PIKA_IS_TOOL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_TOOL))
#define PIKA_IS_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_TOOL))
#define PIKA_TOOL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_TOOL, PikaToolClass))

#define PIKA_TOOL_GET_OPTIONS(t)  (pika_tool_get_options (PIKA_TOOL (t)))


typedef struct _PikaToolClass PikaToolClass;

struct _PikaTool
{
  PikaObject       parent_instance;

  PikaToolInfo    *tool_info;

  gchar           *label;
  gchar           *undo_desc;
  gchar           *icon_name;
  gchar           *help_id;

  gint             ID;          /*  unique tool ID                         */

  PikaToolControl *control;

  PikaDisplay     *display;     /*  pointer to currently active display    */
  GList           *drawables;   /*  list of the tool's current drawables   */

  /*  private state of pika_tool_set_focus_display() and
   *  pika_tool_set_[active_]modifier_state()
   */
  PikaDisplay     *focus_display;
  GdkModifierType  modifier_state;
  GdkModifierType  button_press_state;
  GdkModifierType  active_modifier_state;

  /*  private state for synthesizing button_release() events
   */
  PikaCoords       last_pointer_coords;
  guint32          last_pointer_time;
  GdkModifierType  last_pointer_state;

  /*  private state for click detection
   */
  gboolean         in_click_distance;
  gboolean         got_motion_event;
  PikaCoords       button_press_coords;
  guint32          button_press_time;

  /*  private list of displays which have a status message from this tool
   */
  GList           *status_displays;

  /*  on-canvas progress  */
  PikaCanvasItem  *progress;
  PikaDisplay     *progress_display;
  GtkWidget       *progress_grab_widget;
  gboolean         progress_cancelable;
};

struct _PikaToolClass
{
  PikaObjectClass  parent_class;

  /*  virtual functions  */

  gboolean        (* has_display)         (PikaTool              *tool,
                                           PikaDisplay           *display);
  PikaDisplay   * (* has_image)           (PikaTool              *tool,
                                           PikaImage             *image);

  gboolean        (* initialize)          (PikaTool              *tool,
                                           PikaDisplay           *display,
                                           GError               **error);
  void            (* control)             (PikaTool              *tool,
                                           PikaToolAction         action,
                                           PikaDisplay           *display);

  void            (* button_press)        (PikaTool              *tool,
                                           const PikaCoords      *coords,
                                           guint32                time,
                                           GdkModifierType        state,
                                           PikaButtonPressType    press_type,
                                           PikaDisplay           *display);
  void            (* button_release)      (PikaTool              *tool,
                                           const PikaCoords      *coords,
                                           guint32                time,
                                           GdkModifierType        state,
                                           PikaButtonReleaseType  release_type,
                                           PikaDisplay           *display);
  void            (* motion)              (PikaTool              *tool,
                                           const PikaCoords      *coords,
                                           guint32                time,
                                           GdkModifierType        state,
                                           PikaDisplay           *display);

  gboolean        (* key_press)           (PikaTool              *tool,
                                           GdkEventKey           *kevent,
                                           PikaDisplay           *display);
  gboolean        (* key_release)         (PikaTool              *tool,
                                           GdkEventKey           *kevent,
                                           PikaDisplay           *display);
  void            (* modifier_key)        (PikaTool              *tool,
                                           GdkModifierType        key,
                                           gboolean               press,
                                           GdkModifierType        state,
                                           PikaDisplay           *display);
  void            (* active_modifier_key) (PikaTool              *tool,
                                           GdkModifierType        key,
                                           gboolean               press,
                                           GdkModifierType        state,
                                           PikaDisplay           *display);

  void            (* oper_update)         (PikaTool              *tool,
                                           const PikaCoords      *coords,
                                           GdkModifierType        state,
                                           gboolean               proximity,
                                           PikaDisplay           *display);
  void            (* cursor_update)       (PikaTool              *tool,
                                           const PikaCoords      *coords,
                                           GdkModifierType        state,
                                           PikaDisplay           *display);

  const gchar   * (* can_undo)            (PikaTool              *tool,
                                           PikaDisplay           *display);
  const gchar   * (* can_redo)            (PikaTool              *tool,
                                           PikaDisplay           *display);
  gboolean        (* undo)                (PikaTool              *tool,
                                           PikaDisplay           *display);
  gboolean        (* redo)                (PikaTool              *tool,
                                           PikaDisplay           *display);

  PikaUIManager * (* get_popup)           (PikaTool              *tool,
                                           const PikaCoords      *coords,
                                           GdkModifierType        state,
                                           PikaDisplay           *display,
                                           const gchar          **ui_path);

  void            (* options_notify)      (PikaTool              *tool,
                                           PikaToolOptions       *options,
                                           const GParamSpec      *pspec);
};


GType             pika_tool_get_type            (void) G_GNUC_CONST;

PikaToolOptions * pika_tool_get_options         (PikaTool            *tool);

void              pika_tool_set_label           (PikaTool            *tool,
                                                 const gchar         *label);
const gchar     * pika_tool_get_label           (PikaTool            *tool);

void              pika_tool_set_undo_desc       (PikaTool            *tool,
                                                 const gchar         *undo_desc);
const gchar     * pika_tool_get_undo_desc       (PikaTool            *tool);

void              pika_tool_set_icon_name       (PikaTool            *tool,
                                                 const gchar         *icon_name);
const gchar     * pika_tool_get_icon_name       (PikaTool            *tool);

void              pika_tool_set_help_id         (PikaTool            *tool,
                                                 const gchar         *help_id);
const gchar     * pika_tool_get_help_id         (PikaTool            *tool);

gboolean          pika_tool_has_display         (PikaTool            *tool,
                                                 PikaDisplay         *display);
PikaDisplay     * pika_tool_has_image           (PikaTool            *tool,
                                                 PikaImage           *image);

gboolean          pika_tool_initialize          (PikaTool            *tool,
                                                 PikaDisplay         *display);
void              pika_tool_control             (PikaTool            *tool,
                                                 PikaToolAction       action,
                                                 PikaDisplay         *display);

void              pika_tool_button_press        (PikaTool            *tool,
                                                 const PikaCoords    *coords,
                                                 guint32              time,
                                                 GdkModifierType      state,
                                                 PikaButtonPressType  press_type,
                                                 PikaDisplay         *display);
void              pika_tool_button_release      (PikaTool            *tool,
                                                 const PikaCoords    *coords,
                                                 guint32              time,
                                                 GdkModifierType      state,
                                                 PikaDisplay         *display);
void              pika_tool_motion              (PikaTool            *tool,
                                                 const PikaCoords    *coords,
                                                 guint32              time,
                                                 GdkModifierType      state,
                                                 PikaDisplay         *display);

gboolean          pika_tool_key_press           (PikaTool            *tool,
                                                 GdkEventKey         *kevent,
                                                 PikaDisplay         *display);
gboolean          pika_tool_key_release         (PikaTool            *tool,
                                                 GdkEventKey         *kevent,
                                                 PikaDisplay         *display);

void              pika_tool_set_focus_display   (PikaTool            *tool,
                                                 PikaDisplay         *display);
void              pika_tool_set_modifier_state  (PikaTool            *tool,
                                                 GdkModifierType      state,
                                                 PikaDisplay         *display);
void        pika_tool_set_active_modifier_state (PikaTool            *tool,
                                                 GdkModifierType      state,
                                                 PikaDisplay         *display);

void              pika_tool_oper_update         (PikaTool            *tool,
                                                 const PikaCoords    *coords,
                                                 GdkModifierType      state,
                                                 gboolean             proximity,
                                                 PikaDisplay         *display);
void              pika_tool_cursor_update       (PikaTool            *tool,
                                                 const PikaCoords    *coords,
                                                 GdkModifierType      state,
                                                 PikaDisplay         *display);

const gchar     * pika_tool_can_undo            (PikaTool            *tool,
                                                 PikaDisplay         *display);
const gchar     * pika_tool_can_redo            (PikaTool            *tool,
                                                 PikaDisplay         *display);
gboolean          pika_tool_undo                (PikaTool            *tool,
                                                 PikaDisplay         *display);
gboolean          pika_tool_redo                (PikaTool            *tool,
                                                 PikaDisplay         *display);

PikaUIManager   * pika_tool_get_popup           (PikaTool            *tool,
                                                 const PikaCoords    *coords,
                                                 GdkModifierType      state,
                                                 PikaDisplay         *display,
                                                 const gchar        **ui_path);

void              pika_tool_push_status         (PikaTool            *tool,
                                                 PikaDisplay         *display,
                                                 const gchar         *format,
                                                 ...) G_GNUC_PRINTF(3,4);
void              pika_tool_push_status_coords  (PikaTool            *tool,
                                                 PikaDisplay         *display,
                                                 PikaCursorPrecision  precision,
                                                 const gchar         *title,
                                                 gdouble              x,
                                                 const gchar         *separator,
                                                 gdouble              y,
                                                 const gchar         *help);
void              pika_tool_push_status_length  (PikaTool            *tool,
                                                 PikaDisplay         *display,
                                                 const gchar         *title,
                                                 PikaOrientationType  axis,
                                                 gdouble              value,
                                                 const gchar         *help);
void              pika_tool_replace_status      (PikaTool            *tool,
                                                 PikaDisplay         *display,
                                                 const gchar         *format,
                                                 ...) G_GNUC_PRINTF(3,4);
void              pika_tool_pop_status          (PikaTool            *tool,
                                                 PikaDisplay         *display);

void              pika_tool_message             (PikaTool            *tool,
                                                 PikaDisplay         *display,
                                                 const gchar         *format,
                                                 ...) G_GNUC_PRINTF(3,4);
void              pika_tool_message_literal     (PikaTool            *tool,
                                                 PikaDisplay         *display,
                                                 const gchar         *message);

void              pika_tool_set_cursor          (PikaTool            *tool,
                                                 PikaDisplay         *display,
                                                 PikaCursorType       cursor,
                                                 PikaToolCursorType   tool_cursor,
                                                 PikaCursorModifier   modifier);


#endif  /*  __PIKA_TOOL_H__  */
