/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * filename: xutils.c                                                      *
 *                                                                         *
 * UTIL C-source: Medical Image Conversion Utility                         *
 *                                                                         *
 * purpose      : utility routines                                         *
 *                                                                         *
 * project      : (X)MedCon by Erik Nolf                                   *
 *                                                                         *
 * Functions    : XMdcMedconQuit()            - Quit XMedCon main program  *
 *                XMdcMainWidgetsInsensitive()- Make them insensitive      *
 *                XMdcMainWidgetsResensitive()- Make them   sensitive      *
 *                XMdcAskYesNo()              - Ask a Yes/No question      *
 *                XMdcRunDialog()             - Run modal dialog           *
 *                XMdcShowWidget()            - Our show the widget routine*
 *                XMdcSetGbcCorrection()      - Set GBC corrected values   *
 *                XMdcBuildRgbImage()         - Build an RGB image         *
 *                XMdcBuildGdkPixbuf()        - Build GdkPixbuf out img8   *
 *                XMdcBuildGdkPixbufFI()      - Build GdkPixbuf out FI img *
 *                XMdcPreventDelete()         - Prevent delete event       *
 *                XMdcHandlerToHide()         - Hide widget (no delete)    *
 *                XMdcFreeRGB()               - Free RGB image             *
 *                XMdcToggleVisibility()      - Toggle widget visibility   *
 *                XMdcSetImageScales()        - Set width & height scale   *
 *                XMdcScaleW()                - Scale image width          *
 *                XMdcScaleH()                - Scale image height         *
 *                XMdcGetScreenWorkingArea()  - Get screen working area    *
 *                XMdcGetEnvVars()            - Get environment variables  *
 *                                                                         *
 * Note         : Algoritme for gamma/brightness/contrast correction in    *
 *                function XMdcSetGbcCorrection() copied from library      *
 *                Imlib by Rasterman                                       *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 */

/*
   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>
#include <math.h>
#ifdef LIBMDC_HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include "xmedcon.h"

/****************************************************************************
                            F U N C T I O N S
****************************************************************************/

void XMdcMedconQuit(GtkWidget *widget, gpointer data)
{
  XMdcFileReset();
  XMdcFreeMyStuff();

  exit(MDC_OK);

}

void XMdcMainWidgetsInsensitive(void)
{

  if (my.viewwindow != NULL)
    gtk_widget_set_sensitive(my.viewwindow,FALSE);
  if (my.mainwindow != NULL)
    gtk_widget_set_sensitive(my.mainwindow,FALSE);

}

void XMdcMainWidgetsResensitive(void)
{

  if (my.viewwindow != NULL)
    gtk_widget_set_sensitive(my.viewwindow,TRUE);
  if (my.mainwindow != NULL)
    gtk_widget_set_sensitive(my.mainwindow,TRUE);

}

void XMdcAskYesNo(GCallback YesFunc, GCallback NoFunc, char *question)
{
  GtkWidget *dialog;
  GtkWidget *label;
  GtkWidget *button;
  GtkWidget *content_area;

  if (YesFunc == (GCallback)NULL ) return;

  dialog = gtk_dialog_new();

  content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));

  g_signal_connect(dialog, "destroy",
                     G_CALLBACK(gtk_widget_destroy),NULL);
  gtk_window_set_title(GTK_WINDOW(dialog), "Question");
  gtk_container_set_border_width(GTK_CONTAINER(dialog),0);

  label = gtk_label_new(question);
  gtk_widget_set_margin_start(label, 20);
  gtk_widget_set_margin_end(label, 20);
  gtk_widget_set_margin_top(label, 10);
  gtk_widget_set_margin_bottom(label, 10);
  gtk_box_pack_start(GTK_BOX(content_area), label, TRUE, TRUE, 0);
  gtk_widget_show(label);

  button=gtk_dialog_add_button(GTK_DIALOG(dialog), "Yes", GTK_RESPONSE_YES);
  g_signal_connect_swapped(button, "clicked",
                     G_CALLBACK(gtk_widget_hide), dialog);
  g_signal_connect(button, "clicked",
                     G_CALLBACK(YesFunc),NULL);
  g_signal_connect_swapped(button, "clicked",
                     G_CALLBACK(gtk_widget_destroy), dialog);
  gtk_widget_show(button);

  button=gtk_dialog_add_button(GTK_DIALOG(dialog), "No", GTK_RESPONSE_NO);
  if (NoFunc == (GCallback)NULL) {
    g_signal_connect_swapped(button, "clicked",
                       G_CALLBACK(gtk_widget_destroy),
                       dialog);
  }else{
    g_signal_connect_swapped(button, "clicked",
                       G_CALLBACK(gtk_widget_hide), dialog);
    g_signal_connect(button, "clicked",
                       G_CALLBACK(NoFunc),NULL);
    g_signal_connect_swapped(button, "clicked",
                       G_CALLBACK(gtk_widget_destroy), dialog);
  }
  gtk_widget_show(button);

  XMdcRunDialog(dialog);

}

void XMdcRunDialog(GtkWidget *dialog)
{
  gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
  gtk_dialog_run(GTK_DIALOG(dialog));
}

void XMdcShowWidget(GtkWidget *widget)
{
  gtk_window_set_position(GTK_WINDOW(widget), GTK_WIN_POS_MOUSE);
  gtk_widget_show(widget);
}

void XMdcSetGbcCorrection(ColorModifier *mod)
{
   double g, b, c, ii, v;
   Uint32 i;

   g = ((double)mod->gamma)      / 256.;
   b = ((double)mod->brightness) / 256.;
   c = ((double)mod->contrast)   / 256.;

   if (g < 0.01) g = 0.01;

   for (i = 0; i < 256; i++) {
      ii = ((double)i) / 256.;
      v = ((ii - 0.5) * c) + 0.5 + (b - 1.);
      if (v > 0) {
        v = pow(((ii - 0.5) * c) + 0.5 + (b - 1.), 1. / g) * 256.;
      }else{
        v = 0.;
      }
      if (v > 255.) {
        v = 255.;
      }else if (v < 0.) {
        v = 0.;
      }
      mod->vgbc[i] = (guchar)v;
   }

}

Uint8 *XMdcBuildRgbImage(Uint8 *img8, Int16 type, Uint32 pixels, Uint8 *vgbc)
{
  Uint8 *imgRGB, rr, gg, bb;
  Uint32 pix;

  imgRGB = (Uint8 *)malloc(pixels * 3);
  if (imgRGB == NULL) return(NULL);

  for (pix=0; pix < pixels; pix++) {
     if (type == COLRGB) {
       rr = img8[pix * 3 + 0];
       gg = img8[pix * 3 + 1];
       bb = img8[pix * 3 + 2];
     }else{
       rr = my.fi->palette[img8[pix] * 3 + 0];
       gg = my.fi->palette[img8[pix] * 3 + 1];
       bb = my.fi->palette[img8[pix] * 3 + 2];
     }
     imgRGB[pix * 3 + 0] = vgbc[rr];
     imgRGB[pix * 3 + 1] = vgbc[gg];
     imgRGB[pix * 3 + 2] = vgbc[bb];
  }

  return(imgRGB);
}

GdkPixbuf *XMdcBuildGdkPixbuf(Uint8 *img8, Uint32 w, Uint32 h, Int16 type, Uint8 *vgbc)
{
  GdkPixbuf *imtmp, *im;
  Uint8 *imgRGB;
  Uint32 pixels = w * h;
  gint rw, rh;

  imgRGB = XMdcBuildRgbImage(img8, type, pixels, vgbc);
  if (imgRGB == NULL) return(NULL);

  rw = (gint)w; rh = (gint)h;

  imtmp = gdk_pixbuf_new_from_data(imgRGB,GDK_COLORSPACE_RGB,FALSE,8,rw,rh
                                         ,(int)(3*w),XMdcFreeRGB,NULL);
  if (imtmp == NULL) { MdcFree(imgRGB); return(NULL); }

  rw = (gint)XMdcScaleW(w); rh = (gint)XMdcScaleH(h);

  if ((rw != w) || (rh != h)) {
    im = gdk_pixbuf_scale_simple(imtmp,rw,rh,sRenderSelection.Interp);
    g_object_unref(imtmp);
  }else{
    im = imtmp;
  }

  return(im);
}

GdkPixbuf *XMdcBuildGdkPixbufFI(FILEINFO *fi,Uint32 i,Uint8 *vgbc)
{
   GdkPixbuf *im;
   Uint8 *img8;
   Uint32 w, h;
   Int16 t;

   w = fi->image[i].width;
   h = fi->image[i].height;
   t = fi->image[i].type;

   img8 = MdcGetDisplayImage(fi,i);
   if (img8 == NULL)
     XMdcDisplayFatalErr(MDC_BAD_ALLOC,"Couldn't create byte image");

   im = XMdcBuildGdkPixbuf(img8, w, h, t, vgbc);

   MdcFree(img8);

   if (im == NULL) {
     XMdcDisplayFatalErr(MDC_BAD_ALLOC,"Couldn't create GdkPixbuf");
   }

   return(im);

}

gboolean XMdcPreventDelete(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  return(TRUE);
}

gboolean XMdcHandlerToHide(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  gtk_widget_hide(widget);
  return(TRUE);
}

void XMdcFreeRGB(guchar *pixdata, gpointer data)
{
  MdcFree(pixdata);
}

void XMdcToggleVisibility(GtkWidget *widget)
{
  if (gtk_widget_get_visible(widget)) {
    gtk_widget_hide(widget);
  }else{
    gtk_widget_show(widget);
  }
}

void XMdcSetImageScales(void)
{
  float ratio_width, ratio_height;

  my.scale_width = 1.; my.scale_height = 1.;

  /* scale to real world sizes */

  if (my.fi->pixdim[1] > my.fi->pixdim[2]) {

    /* width > height -> height is unit */
    my.scale_width  = my.fi->pixdim[1] / my.fi->pixdim[2];

  }else if (my.fi->pixdim[2] > my.fi->pixdim[1]) {

    /* height > width -> width  is unit */
    my.scale_height = my.fi->pixdim[2] / my.fi->pixdim[1];

  }

  /* fit to screen sizes */

  ratio_width = ((float)my.fi->mwidth * my.scale_width)
           / ((float)my.screen_width  - (1.2 * (float)XMDC_FREE_BORDER));

  ratio_height = ((float)my.fi->mheight * my.scale_height)
           / ((float)my.screen_height - (1.2 * (float)XMDC_FREE_BORDER));

  if ((ratio_width <= 1.) && (ratio_height <= 1.)) return; /* both fit */

  /* needs resizing */
  if (ratio_width > ratio_height) {
    /* fit via width */
    my.scale_width  /= ratio_width;
    my.scale_height /= ratio_width;
  }else{
    /* fit via height */
    my.scale_width  /= ratio_height;
    my.scale_height /= ratio_height;
  }

}

Uint32 XMdcScaleW(Uint32 width)
{
  Uint32 new_width = width;

  if (my.scale_width != 1.) {

    new_width = (Uint32)((float)width * my.scale_width);

  }

  return(XMdcResize(new_width));
}

Uint32 XMdcScaleH(Uint32 height)
{
  Uint32 new_height = height;

  if (my.scale_height != 1.) {

    new_height = (Uint32)((float)height * my.scale_height);

  }

  return(XMdcResize(new_height));
}

void XMdcGetScreenWorkingArea(void)
{
  GdkDisplay *display;
  GdkMonitor *monitor;
  GdkRectangle workarea;

  /* initialize workarea to a least default */
  workarea.width  = 1280;
  workarea.height = 720;

  /* get monitor; but can be NULL in Gtk+3 */
  display = gdk_display_get_default();
  monitor = gdk_display_get_primary_monitor(display);

  /* should give screen area minus panels, docks, ... */
  if (monitor != NULL) gdk_monitor_get_workarea(monitor, &workarea);

  my.screen_height = workarea.height;
  my.screen_width  = workarea.width;

  MdcDebugPrint("screen_height     = %d",my.screen_height);
  MdcDebugPrint("screen_width      = %d",my.screen_width);

}

void XMdcGetEnvVars(void)
{

  /* dir to color lookup tables */ 
  XMEDCONLUT = getenv("XMEDCONLUT");

  /* dir to raw predef input files */
  XMEDCONRPI = getenv("XMEDCONRPI");

  /* dir to user home directory */
#ifdef _WIN32
  XMEDCONUSR = getenv("USERPROFILE");
#else
  XMEDCONUSR = getenv("HOME");
#endif

  /* file to css theme layout */
  XMEDCONCSS = getenv("XMEDCONCSS");

}
