/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * filename: xcolgbc.c                                                     *
 *                                                                         *
 * UTIL C-source: Medical Image Conversion Utility                         *
 *                                                                         *
 * purpose      : color corrections                                        *
 *                                                                         *
 * project      : (X)MedCon by Erik Nolf                                   *
 *                                                                         *
 * Functions    : XMdcColGbcCorrectDraw()         - Draw wrapper Update    *
 *                XMdcColGbcCorrectUpdate()       - Update GBC image       *
 *                XMdcColGbcCorrectMakeIcons()    - Make slider icons      *
 *                XMdcColGbcCorrectAddImg()       - Add example image      *
 *                XMdcColGbcCorrectModValue()     - Modify slider values   *
 *                XMdcColGbcCorrectResetValue()   - Reset  slider values   *
 *                XMdcColGbcCorrectAddOneSlider() - Add one slider         *
 *                XMdcColGbcCorrectAddSliders();  - Add all sliders        *
 *                XMdcColGbcCorrectApply();       - Apply  callback        *
 *                XMdcColGbcCorrectCancel();      - Cancel callback        *
 *                XMdcColGbcCorrectSel();         - GBC selection          *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 */

/*
   Copyright (C) 1997-2026 by Erik Nolf

   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 2, 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, write to the Free Software Foundation, Inc.,
   59 Place - Suite 330, Boston, MA 02111-1307, USA.  */


/****************************************************************************
                              H E A D E R S
****************************************************************************/

#include "m-depend.h"

#include <stdio.h>
#ifdef LIBMDC_HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef LIBMDC_HAVE_STRING_H
#include <string.h>
#endif
#ifdef LIBMDC_HAVE_STRINGS_H
#ifndef _WIN32
#include <strings.h>
#endif
#endif

#include "xmedcon.h"

/****************************************************************************
                              D E F I N E S
****************************************************************************/

static GtkWidget *wgbc=NULL;
static ColorModifier modtmp;
static SliderValueStruct svgamma, svbrightness, svcontrast;

/****************************************************************************
                            F U N C T I O N S
****************************************************************************/
gboolean XMdcColGbcCorrectDraw(GtkWidget *widget,
    GdkEventExpose *event, gpointer data)
{

  XMdcColGbcCorrectUpdate();

  return(TRUE);

}

void XMdcColGbcCorrectUpdate(void)
{
  GtkWidget *area;
  GdkWindow *window;
  GdkPixbuf *imtmp, *imnew;
  GdkDrawingContext *draw_context;
  cairo_region_t *cairo_region;
  cairo_t *cr;
  int w, h;

  area = sGbc.area;

  XMdcSetGbcCorrection(&modtmp);

  imtmp = XMdcBuildGdkPixbuf(sGbc.img8,sGbc.w,sGbc.h,sGbc.t,modtmp.vgbc);

  w = gdk_pixbuf_get_width(sGbc.image);
  h = gdk_pixbuf_get_height(sGbc.image);

  g_object_unref(sGbc.image);

  imnew = gdk_pixbuf_scale_simple(imtmp,w,h,sRenderSelection.Interp);
  g_object_unref(imtmp); sGbc.image = imnew;

  window = gtk_widget_get_window(area);

  cairo_region = cairo_region_create();

  draw_context = gdk_window_begin_draw_frame(window, cairo_region);
  cr = gdk_drawing_context_get_cairo_context(draw_context);

  gdk_cairo_set_source_pixbuf(cr, sGbc.image, 0, 0);
  cairo_paint(cr);

  gdk_window_end_draw_frame(window, draw_context);
  cairo_region_destroy(cairo_region);

  /* Wayland: must send 'draw' signal explicitly */
  gtk_widget_queue_draw(area);

}

void XMdcColGbcCorrectMakeIcons(void)
{

  GdkPixbuf *im0;

  im0=gdk_pixbuf_new_from_data(xmdc_brightness_icon, GDK_COLORSPACE_RGB, FALSE,
                               8, 12, 12, 3*12, (GdkPixbufDestroyNotify)NULL, NULL);
  sGbc.brightness_icon = gdk_pixbuf_add_alpha(im0,TRUE,0xff,0x00,0xff);
  g_object_unref(im0);

  im0=gdk_pixbuf_new_from_data(xmdc_contrast_icon,   GDK_COLORSPACE_RGB, FALSE,
                               8, 12, 12, 3*12, (GdkPixbufDestroyNotify)NULL, NULL);
  sGbc.contrast_icon   = gdk_pixbuf_add_alpha(im0,TRUE,0xff,0x00,0xff);
  g_object_unref(im0);

  im0=gdk_pixbuf_new_from_data(xmdc_gamma_icon,      GDK_COLORSPACE_RGB, FALSE,
                               8, 12, 12, 3*12, (GdkPixbufDestroyNotify)NULL, NULL);
  sGbc.gamma_icon      = gdk_pixbuf_add_alpha(im0,TRUE,0xff,0x00,0xff);
  g_object_unref(im0);

}

void XMdcColGbcCorrectAddImg(GtkWidget *w)
{
  GtkWidget *box, *area, *imgbox;
  int rw, rh;

  rw = (signed)XMdcScaleW(sGbc.w);
  rh = (signed)XMdcScaleH(sGbc.h);

  box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  gtk_box_pack_start(GTK_BOX(w), box, FALSE, FALSE, 0);
  gtk_widget_show(box);

  imgbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2);
  gtk_box_pack_start(GTK_BOX(box), imgbox, TRUE, TRUE, 0);
  gtk_widget_show(imgbox);

  area = gtk_drawing_area_new();

  gtk_widget_set_events(area, GDK_EXPOSURE_MASK);
  gtk_widget_set_size_request(area, rw, rh);
  gtk_box_pack_start(GTK_BOX(imgbox), area, FALSE, FALSE, 0);
  gtk_widget_show(area);
  g_signal_connect(area, "draw",
                     G_CALLBACK(XMdcColGbcCorrectDraw), NULL);
  sGbc.area = area;
}

void XMdcColGbcCorrectModValue(GtkWidget *widget, SliderValueStruct *v)
{

  (*(v->value)) = (int)gtk_adjustment_get_value(v->adj);
  XMdcColGbcCorrectUpdate();
}

void XMdcColGbcCorrectResetValue(GtkWidget *widget, SliderValueStruct *v)
{
  (*(v->value)) = 255;
  gtk_range_set_value(GTK_RANGE(v->range), (gfloat)(*(v->value)));
  XMdcColGbcCorrectUpdate();
}

void XMdcColGbcCorrectAddOneSlider(GtkWidget *w, int *value, GtkWidget *ic, SliderValueStruct *sv)
{
  GtkAdjustment *adj;
  GtkWidget     *range, *button, *box;

  box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  gtk_box_pack_start(GTK_BOX(w), box, FALSE, FALSE, 0);
  gtk_widget_show(box);
  adj = gtk_adjustment_new((gfloat)(*value), 0.0, 1024.0, 1.0, 8.0, 0.0);
  range = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, adj);
  gtk_widget_set_size_request(range, 200, 12);
/* MARK deprecated without replacement - still works without ??
 * gtk_range_set_update_policy(GTK_RANGE(range), GTK_UPDATE_CONTINUOUS); */
  gtk_scale_set_draw_value(GTK_SCALE(range), FALSE);

  sv->adj = adj;
  sv->range = range;
  sv->value = value;
  g_signal_connect(adj, "value_changed",
                     G_CALLBACK(XMdcColGbcCorrectModValue), sv);
  gtk_box_pack_start(GTK_BOX(box), range, FALSE, FALSE, 0);
  gtk_widget_show(range);
  button = gtk_button_new();
  gtk_container_add(GTK_CONTAINER(button), ic);
  gtk_widget_show(ic);
  g_signal_connect(button, "clicked",
                     G_CALLBACK(XMdcColGbcCorrectResetValue), sv);
  gtk_widget_show(button);
  gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 0);

}

void XMdcColGbcCorrectAddSliders(GtkWidget *w)
{
  GtkWidget *frame, *box, *box0, *box1;
  GtkWidget *wg, *wb, *wc;

  XMdcColGbcCorrectMakeIcons();

  wg = gtk_image_new_from_pixbuf(sGbc.gamma_icon);
  wb = gtk_image_new_from_pixbuf(sGbc.brightness_icon);
  wc = gtk_image_new_from_pixbuf(sGbc.contrast_icon);

  box0 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  gtk_container_add(GTK_CONTAINER(w), box0);
  gtk_widget_show(box0);

  box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  gtk_container_add(GTK_CONTAINER(box0), box1);
  gtk_widget_show(box1);

  frame = gtk_aspect_frame_new("Base Levels", 0.5, 0.5, 0.0, TRUE);
  gtk_box_pack_start(GTK_BOX(box1), frame, FALSE, FALSE, 4);
  gtk_widget_show(frame);
  box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  gtk_container_add(GTK_CONTAINER(frame), box);
  gtk_widget_show(box);


  XMdcColGbcCorrectAddOneSlider(box,(int *)&modtmp.gamma,wg,&svgamma);
  XMdcColGbcCorrectAddOneSlider(box,(int *)&modtmp.brightness,wb,&svbrightness);
  XMdcColGbcCorrectAddOneSlider(box,(int *)&modtmp.contrast,wc,&svcontrast);

  XMdcColGbcCorrectAddImg(box0);

}

void XMdcColGbcCorrectApply(GtkWidget *widget, gpointer data)
{
  sGbc.mod.gamma = modtmp.gamma;
  sGbc.mod.brightness = modtmp.brightness;
  sGbc.mod.contrast = modtmp.contrast;
  memcpy(sGbc.mod.vgbc,modtmp.vgbc,256);

  if (XMDC_FILE_OPEN == MDC_YES) {

    gtk_widget_set_sensitive(my.viewwindow,FALSE);

    XMdcRemovePreviousColorMap();
    XMdcRemovePreviousImages();

    XMdcBuildColorMap();
    XMdcBuildCurrentImages();

    gtk_widget_set_sensitive(my.viewwindow,TRUE);

  }

}

void XMdcColGbcCorrectSel(GtkWidget *widget, Uint32 nr)
{
  GtkWidget *box1;
  GtkWidget *box2;
  GtkWidget *button;
  GtkWidget *separator;
  GdkPixbuf *im;
  int rw, rh;

  sGbc.nr = nr;
  sGbc.i = my.realnumber[nr];
  sGbc.w = my.fi->image[sGbc.i].width;
  sGbc.h = my.fi->image[sGbc.i].height;
  sGbc.t = my.fi->image[sGbc.i].type;
  modtmp.gamma = sGbc.mod.gamma;
  modtmp.brightness = sGbc.mod.brightness;
  modtmp.contrast = sGbc.mod.contrast;
  XMdcSetGbcCorrection(&modtmp);
  rw = (signed)XMdcScaleW(sGbc.w);
  rh = (signed)XMdcScaleH(sGbc.h);

  MdcFree(sGbc.img8);

  sGbc.img8 = MdcGetDisplayImage(my.fi,sGbc.i);
  if (sGbc.img8 == NULL) {
    XMdcDisplayErr("Couldn't alloc byte buffer");
    return;
  }

  im = XMdcBuildGdkPixbuf(sGbc.img8,sGbc.w,sGbc.h,sGbc.t,modtmp.vgbc);
  if (im == NULL) {
    MdcFree(sGbc.img8);
    XMdcDisplayErr("Couldn't create GdkPixbuf");
    return;
  }

  if ( wgbc == NULL ) {

    sGbc.image = im;

    wgbc = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_resizable(GTK_WINDOW(wgbc), TRUE);

    g_signal_connect(wgbc, "destroy",
                       G_CALLBACK(XMdcMedconQuit), NULL);
    g_signal_connect(wgbc, "delete_event",
              G_CALLBACK(XMdcHandlerToHide), NULL);

    gtk_window_set_title(GTK_WINDOW(wgbc),"Color Correction");
    gtk_container_set_border_width(GTK_CONTAINER(wgbc), 1);

    box1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add(GTK_CONTAINER(wgbc), box1);
    gtk_widget_show(box1);

    /* create sliders for correction */
    XMdcColGbcCorrectAddSliders(box1);

    /* create horizontal separator */
    separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
    gtk_box_pack_start(GTK_BOX(box1), separator, FALSE, FALSE, 0);
    gtk_widget_show(separator);

    /* create bottom button box */
    box2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    gtk_box_pack_start(GTK_BOX(box1), box2, TRUE, TRUE, 2);
    gtk_widget_show(box2);

    button = gtk_button_new_with_label("Apply");
    gtk_box_pack_start(GTK_BOX(box2), button, TRUE, TRUE, 2);
    g_signal_connect_swapped(button, "clicked",
                       G_CALLBACK(gtk_widget_hide), wgbc);
    g_signal_connect(button, "clicked",
                       G_CALLBACK(XMdcColGbcCorrectApply), NULL);
    gtk_widget_show(button);

    button = gtk_button_new_with_label("Cancel");
    gtk_box_pack_start(GTK_BOX(box2), button, TRUE, TRUE, 2);
    g_signal_connect_swapped(button, "clicked",
              G_CALLBACK(gtk_widget_hide), wgbc);
    gtk_widget_show(button);

  }else{

    /* replace image / update sliders */

    gtk_window_set_resizable(GTK_WINDOW(wgbc), TRUE);

    g_object_unref(sGbc.image);

    sGbc.image = im;

    /* DEBUG gdk_window_clear() is gone ...
    window = gtk_widget_get_window(sGbc.area);
    gdk_window_clear(window); */

    gtk_widget_set_size_request(sGbc.area, rw, rh);

    gtk_adjustment_set_value(svgamma.adj, sGbc.mod.gamma);
    gtk_adjustment_set_value(svbrightness.adj, sGbc.mod.brightness);
    gtk_adjustment_set_value(svcontrast.adj, sGbc.mod.contrast);

    XMdcColGbcCorrectUpdate();


  }

  gtk_window_set_resizable(GTK_WINDOW(wgbc), FALSE);

  XMdcShowWidget(wgbc);

}

