/* cqcam - Color Quickcam capture programs
 * Copyright (C) 1996-1998 by Patrick Reynolds
 *
 * 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 of
 * the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#include <gtk/gtkadjustment.h>
#include <gtk/gtkcontainer.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkhscale.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkradiobutton.h>
#include <gtk/gtksignal.h>
#include <gtk/gtktogglebutton.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkwidget.h>
#include <gtk/gtkwindow.h>
#include "gtkimagesize.h"

#include <cqcsrv.h>
#include "dimensions.h"
#include "gcam.h"
#include "options.h"

typedef struct {
  char *name;
  int initial, min, max;
  unsigned char command;
  int *location;
  GtkAdjustment **adj;
} GcamControl;

static void program_setting(GtkObject *adj, unsigned char *loc);
static void set_decimation(GtkObject *but, GcamControl *con);
static void update_dimensions();

static GtkAdjustment /**adj_width, *adj_height, */*adj_top, *adj_left;
static GtkWidget *isz;

int dimensions_width=320, dimensions_height=240, dimensions_decimation;
int dimensions_top, dimensions_left;
static int dimensions_base_top, dimensions_base_left;

static GcamControl controls[] = {
    { "Top",  1,  0, 10, 0, &dimensions_base_top,   &adj_top  },
    { "Left", 8,  0, 40, 0, &dimensions_base_left,  &adj_left },
    { "1:1",  1,  0, 1,  1, &dimensions_decimation, 0         },
    { "2:1",  0,  0, 1,  2, &dimensions_decimation, 0         },
    { "4:1",  0,  0, 1,  4, &dimensions_decimation, 0         }
};
static const int nsliders = 2;
static const int nradios = 3;

static void destroy(GtkWidget *, GtkWidget **foo) {
  *foo = 0;
}

GtkWidget *dimensions_create_window() {
  GtkWidget *w = gtk_window_new(GTK_WINDOW_DIALOG);
  gtk_window_set_title(GTK_WINDOW(w), "Image dimensions");
  gtk_window_set_policy(GTK_WINDOW(w), FALSE, FALSE, TRUE);
#ifdef HAVE_GTK_1_0
  gtk_container_border_width(GTK_CONTAINER(w), 10);
#else
  gtk_container_set_border_width(GTK_CONTAINER(w), 10);
#endif
  
  GtkWidget *vbox = gtk_vbox_new(FALSE, 10);
  GtkWidget *hbox = gtk_hbox_new(FALSE, 10);
  GtkWidget *left = gtk_vbox_new(TRUE, 15);
  GtkWidget *middle = gtk_vbox_new(TRUE, 15);
  GtkWidget *right = gtk_vbox_new(FALSE, 2);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 10);
  gtk_box_pack_start(GTK_BOX(hbox), left, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), middle, TRUE, TRUE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), right, FALSE, FALSE, 0);
  gtk_container_add(GTK_CONTAINER(w), vbox);

  int i;
  for (i=0; i<nsliders; i++) {
    GtkWidget *label = gtk_label_new(controls[i].name);
    GtkObject *adj = gtk_adjustment_new(*controls[i].location, controls[i].min,
      controls[i].max, 1, 10, 1);
    GtkWidget *slider = gtk_hscale_new(GTK_ADJUSTMENT(adj));
    gtk_box_pack_start(GTK_BOX(left), label, FALSE, FALSE, 0);
    gtk_box_pack_start(GTK_BOX(middle), slider, TRUE, TRUE, 0);
    gtk_signal_connect(GTK_OBJECT(GTK_RANGE(slider)->adjustment),
      "value_changed", GTK_SIGNAL_FUNC(program_setting), controls[i].location);
    gtk_signal_connect(GTK_OBJECT(GTK_RANGE(slider)->adjustment),
      "value_changed", GTK_SIGNAL_FUNC(update_dimensions), 0);
    if (controls[i].adj)
      *controls[i].adj = GTK_RANGE(slider)->adjustment;
  }
  GSList *group = 0;
  GtkWidget *label = gtk_label_new("Decimation");
  gtk_box_pack_start(GTK_BOX(right), label, FALSE, FALSE, 0);
  for (i=nsliders; i<nsliders+nradios; i++) {
    GtkWidget *button = gtk_radio_button_new_with_label(group,
      controls[i].name);
    if (*controls[i].location == controls[i].command)
#ifdef HAVE_GTK_1_0
      gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
#else
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
#endif
    gtk_signal_connect(GTK_OBJECT(button), "toggled",
      GTK_SIGNAL_FUNC(set_decimation), &controls[i]);
    gtk_signal_connect(GTK_OBJECT(button), "toggled",
      GTK_SIGNAL_FUNC(dimensions_feedback), 0);
    gtk_box_pack_start(GTK_BOX(right), button, FALSE, FALSE, 0);
    if (i<nsliders+nradios-1)
      group = gtk_radio_button_group(GTK_RADIO_BUTTON(button));
  }

  GtkWidget *isz_box = gtk_hbox_new(TRUE, 0);
  isz = gtk_image_size_new(
    640 / (options_32bpp ? 1 : 2) / dimensions_decimation,
    480 / (options_32bpp ? 1 : 2) / dimensions_decimation);
  gtk_signal_connect(GTK_OBJECT(isz), "destroy", GTK_SIGNAL_FUNC(destroy),
    &isz);
  gtk_signal_connect(GTK_OBJECT(isz), "value_changed",
    GTK_SIGNAL_FUNC(update_dimensions), &isz);

  gtk_image_size_set(GTK_IMAGE_SIZE(isz),
    (dimensions_left - dimensions_base_left) /
      dimensions_decimation*2*(options_32bpp?2:1),
    (dimensions_top - dimensions_base_top) /
      dimensions_decimation*(options_32bpp?2:1),
    dimensions_width, dimensions_height);
  gtk_box_pack_start(GTK_BOX(isz_box), isz, FALSE, FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), isz_box, FALSE, FALSE, 0);

  GtkWidget *close_hbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), close_hbox, FALSE, FALSE, 0);
  GtkWidget *close = gtk_button_new_with_label("Close");
  gtk_signal_connect_object(GTK_OBJECT(close), "clicked",
    GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(w));
  gtk_box_pack_end(GTK_BOX(close_hbox), close, FALSE, FALSE, 0);
  GTK_WIDGET_SET_FLAGS(close, GTK_CAN_DEFAULT);
  gtk_widget_grab_default(close);

  return w;
}

void dimensions_init() {
  int i;

  for (i=0; i<nsliders; i++)
    if (controls[i].location)
      *controls[i].location = controls[i].initial;
  for (i=nsliders; i<nsliders+nradios; i++)
    if (controls[i].location && controls[i].initial)
      *controls[i].location = controls[i].command;

  dimensions_top = dimensions_base_top;
  dimensions_left = dimensions_base_left;
}

static void program_setting(GtkObject *adj, unsigned char *loc) {
  *(int*)loc = (int)GTK_ADJUSTMENT(adj)->value;
}

static void set_decimation(GtkObject *obj, GcamControl *con) {
  if (GTK_TOGGLE_BUTTON(obj)->active) {
    send_command(out_fd, CQCSRV_SET_DECIMATION, con->command);
    *(int*)con->location = con->command;
  }
}

static void update_dimensions() {
  send_command(out_fd, CQCSRV_SET_BPP, options_32bpp ? 32 : 24);
  if (dimensions_width != GTK_IMAGE_SIZE(isz)->width) {
    dimensions_width = GTK_IMAGE_SIZE(isz)->width;
    send_command(out_fd, CQCSRV_SET_WIDTH, dimensions_width);
  }
  if (dimensions_height != GTK_IMAGE_SIZE(isz)->height) {
    dimensions_height = GTK_IMAGE_SIZE(isz)->height;
    send_command(out_fd, CQCSRV_SET_HEIGHT, dimensions_height);
  }
  if (dimensions_left != dimensions_base_left +
    GTK_IMAGE_SIZE(isz)->left * dimensions_decimation/2/(options_32bpp?2:1)) {
    dimensions_left = dimensions_base_left +
      GTK_IMAGE_SIZE(isz)->left * dimensions_decimation/2/(options_32bpp?2:1);
    send_command(out_fd, CQCSRV_SET_LEFT, dimensions_left);
  }
  if (dimensions_top != dimensions_base_top +
    GTK_IMAGE_SIZE(isz)->top * dimensions_decimation/(options_32bpp?2:1)) {
    dimensions_top = dimensions_base_top +
      GTK_IMAGE_SIZE(isz)->top * dimensions_decimation/(options_32bpp?2:1);
    send_command(out_fd, CQCSRV_SET_TOP, dimensions_top);
  }
}

void dimensions_feedback() {
  static int old_options_32bpp = 0;
  if (!isz) {
    float multiplier = 1;
    if (old_options_32bpp && !options_32bpp)
      multiplier = 0.5;
    else if (!old_options_32bpp && options_32bpp)
      multiplier = 2;
    old_options_32bpp = options_32bpp;
    if (multiplier != 1) {
      dimensions_width =  (int)(dimensions_width *  multiplier);
      dimensions_height = (int)(dimensions_height * multiplier);
      int left_offset = (dimensions_left - dimensions_base_left) /
        dimensions_decimation*2*(options_32bpp?2:1);
      int top_offset = (dimensions_top - dimensions_base_top) /
        dimensions_decimation*(options_32bpp?2:1);
      left_offset = (int)(left_offset * multiplier);
      top_offset =  (int)(top_offset *  multiplier);
      dimensions_left = (int)(dimensions_base_left +
        left_offset * dimensions_decimation/2/(options_32bpp?2:1));
      dimensions_top = (int)(dimensions_base_top +
        top_offset * dimensions_decimation/(options_32bpp?2:1));
    }
    send_command(out_fd, CQCSRV_SET_BPP,    options_32bpp ? 32 : 24);
    send_command(out_fd, CQCSRV_SET_WIDTH,  dimensions_width);
    send_command(out_fd, CQCSRV_SET_HEIGHT, dimensions_height);
    send_command(out_fd, CQCSRV_SET_LEFT,   dimensions_left);
    send_command(out_fd, CQCSRV_SET_TOP,    dimensions_top);
    return;
  }

  old_options_32bpp = options_32bpp;
  
  int max_width = 320 * (options_32bpp ? 2 : 1) / dimensions_decimation;
  int max_height = 240 * (options_32bpp ? 2 : 1) / dimensions_decimation;
  
  if (max_width != GTK_IMAGE_SIZE(isz)->max_width ||
    max_height != GTK_IMAGE_SIZE(isz)->max_height) {
    float xfactor = (float)max_width / GTK_IMAGE_SIZE(isz)->max_width;
    float yfactor = (float)max_height / GTK_IMAGE_SIZE(isz)->max_height;
    GTK_IMAGE_SIZE(isz)->left   = (int)(GTK_IMAGE_SIZE(isz)->left   * xfactor);
    GTK_IMAGE_SIZE(isz)->top    = (int)(GTK_IMAGE_SIZE(isz)->top    * yfactor);
    GTK_IMAGE_SIZE(isz)->width  = (int)(GTK_IMAGE_SIZE(isz)->width  * xfactor);
    GTK_IMAGE_SIZE(isz)->height = (int)(GTK_IMAGE_SIZE(isz)->height * yfactor);
    gtk_image_size_set_size(GTK_IMAGE_SIZE(isz), max_width, max_height);
    update_dimensions();
  }
}
