/* UFRaw - Unidentified Flying Raw Raw photo loader plugin for The GIMP by Udi Fuchs, based on the gimp plug-in by Pawel T. Jochym jochym at ifj edu pl, based on the gimp plug-in by Dave Coffin http://www.cybercom.net/~dcoffin/ UFRaw is licensed under the GNU General Public License. It uses DCRaw code to do the actual raw decoding. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "ufraw.h" #include "curveeditor_widget.h" #include "ufraw_icon.h" #ifdef HAVE_GTK_2_6 void ufraw_chooser_toggle(GtkToggleButton *button, GtkFileChooser *filechooser); #endif /* Set to huge number so that the preview size is set by the screen size */ const int def_preview_width = 9000; const int def_preview_height = 9000; #define raw_his_size 320 #define live_his_size 256 enum { pixel_format, percent_format }; char *expanderText[] = { "Raw histogram", "Exposure", "White balance", "Color management", "Curve corrections", "Live histogram", NULL }; typedef struct { GtkLabel *labels[4]; int num; int format; } colorLabels; /* All the "global" information is here: */ typedef struct { ufraw_data *UF; conf_data SaveConfig; double initialChanMul[4]; /* Remember the Gtk Widgets that we need to access later */ GtkWidget *ControlsBox, *PreviewWidget, *RawHisto, *LiveHisto; GtkWidget *CurveWidget, *BlackLabel; GtkComboBox *WBCombo, *CurveCombo, *ProfileCombo[profile_types]; GtkLabel *SpotPatch; colorLabels *SpotLabels, *AvrLabels, *DevLabels, *OverLabels, *UnderLabels; GtkToggleButton *AutoExposureButton, *AutoBlackButton; GtkButton *AutoCurveButton; GtkWidget *ResetWBButton, *ResetGammaButton, *ResetLinearButton; GtkWidget *ResetExposureButton, *ResetSaturationButton; GtkWidget *ResetBlackButton, *ResetCurveButton; GtkWidget *UseMatrixButton; GtkTooltips *ToolTips; GtkProgressBar *ProgressBar; /* We need the adjustments for update_scale() */ GtkAdjustment *TemperatureAdjustment; GtkAdjustment *GreenAdjustment; GtkAdjustment *GammaAdjustment; GtkAdjustment *LinearAdjustment; GtkAdjustment *ExposureAdjustment; GtkAdjustment *SaturationAdjustment; long (*SaveFunc)(); long RenderMode; /* Some actions update the progress bar while working, but meanwhile we * want to freeze all other actions. After we thaw the dialog we must * call update_scales() which was also frozen. */ gboolean FreezeDialog; int SpotX1, SpotY1, SpotX2, SpotY2; } preview_data; /* These #defines are not very elegant, but otherwise things get tooo long */ #define CFG data->UF->conf #define Developer data->UF->developer #define CFG_cameraCurve (CFG->curve[camera_curve].m_numAnchors>0) preview_data *get_preview_data(void *object) { GtkWidget *widget; if (GTK_IS_ADJUSTMENT(object)) { widget = g_object_get_data(object, "Parent-Widget"); } else if (GTK_IS_MENU(object)) { widget = g_object_get_data(G_OBJECT(object), "Parent-Widget"); } else if (GTK_IS_MENU_ITEM(object)) { GtkWidget *menu = gtk_widget_get_ancestor(object, GTK_TYPE_MENU); widget = g_object_get_data(G_OBJECT(menu), "Parent-Widget"); } else { widget = object; } GtkWidget *parentWindow = gtk_widget_get_toplevel(widget); preview_data *data = g_object_get_data(G_OBJECT(parentWindow), "Preview-Data"); return data; } void ufraw_focus(void *window, gboolean focus) { if (focus) { GtkWindow *parentWindow = (void *)ufraw_message(UFRAW_SET_PARENT, (char *)window); g_object_set_data(G_OBJECT(window), "WindowParent", parentWindow); if (parentWindow!=NULL) gtk_window_set_accept_focus(GTK_WINDOW(parentWindow), FALSE); } else { GtkWindow *parentWindow = g_object_get_data(G_OBJECT(window), "WindowParent"); ufraw_message(UFRAW_SET_PARENT, (char *)parentWindow); if (parentWindow!=NULL) gtk_window_set_accept_focus(GTK_WINDOW(parentWindow), TRUE); } } void ufraw_messenger(char *message, void *parentWindow) { GtkDialog *dialog; if (parentWindow==NULL) { ufraw_batch_messenger(message); } else { dialog = GTK_DIALOG(gtk_message_dialog_new(GTK_WINDOW(parentWindow), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, message)); gtk_dialog_run(dialog); gtk_widget_destroy(GTK_WIDGET(dialog)); } } void load_curve(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); GtkFileChooser *fileChooser; GtkFileFilter *filter; GSList *list, *saveList; CurveData c; char *cp; user_data = user_data; if (data->FreezeDialog) return; if (CFG->curveCount==max_curves) { ufraw_message(UFRAW_ERROR, "No more room for new curves."); return; } fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new("Load curve", GTK_WINDOW(gtk_widget_get_toplevel(widget)), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL)); ufraw_focus(fileChooser, TRUE); gtk_file_chooser_set_select_multiple(fileChooser, TRUE); #ifdef HAVE_GTK_2_6 gtk_file_chooser_set_show_hidden(fileChooser, FALSE); GtkWidget *button = gtk_check_button_new_with_label( "Show hidden files"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(ufraw_chooser_toggle), fileChooser); gtk_file_chooser_set_extra_widget(fileChooser, button); #endif filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "All curve formats"); gtk_file_filter_add_pattern(filter, "*.ntc"); gtk_file_filter_add_pattern(filter, "*.NTC"); gtk_file_filter_add_pattern(filter, "*.ncv"); gtk_file_filter_add_pattern(filter, "*.NCV"); gtk_file_filter_add_pattern(filter, "*.curve"); gtk_file_filter_add_pattern(filter, "*.CURVE"); gtk_file_chooser_add_filter(fileChooser, filter); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "UFRaw curve format"); gtk_file_filter_add_pattern(filter, "*.curve"); gtk_file_filter_add_pattern(filter, "*.CURVE"); gtk_file_chooser_add_filter(fileChooser, filter); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "Nikon curve format"); gtk_file_filter_add_pattern(filter, "*.ntc"); gtk_file_filter_add_pattern(filter, "*.NTC"); gtk_file_filter_add_pattern(filter, "*.ncv"); gtk_file_filter_add_pattern(filter, "*.NCV"); gtk_file_chooser_add_filter(fileChooser, filter); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "All files"); gtk_file_filter_add_pattern(filter, "*"); gtk_file_chooser_add_filter(fileChooser, filter); if (strlen(CFG->curvePath)>0) gtk_file_chooser_set_current_folder(fileChooser, CFG->curvePath); if (gtk_dialog_run(GTK_DIALOG(fileChooser))==GTK_RESPONSE_ACCEPT) { for (list=saveList=gtk_file_chooser_get_filenames(fileChooser); list!=NULL && CFG->curveCountdata)!=UFRAW_SUCCESS) continue; gtk_combo_box_append_text(data->CurveCombo, c.name); CFG->curve[CFG->curveCount++] = c; CFG->curveIndex = CFG->curveCount-1; if (CFG_cameraCurve) gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex); else gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex-1); cp = g_path_get_dirname(list->data); g_strlcpy(CFG->curvePath, cp, max_path); g_free(cp); g_free(list->data); } if (list!=NULL) ufraw_message(UFRAW_ERROR, "No more room for new curves."); g_slist_free(saveList); } ufraw_focus(fileChooser, FALSE); gtk_widget_destroy(GTK_WIDGET(fileChooser)); } void save_curve(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); GtkFileChooser *fileChooser; GtkFileFilter *filter; char defFilename[max_name]; char *filename, *cp; user_data = user_data; if (data->FreezeDialog) return; fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new("Save curve", GTK_WINDOW(gtk_widget_get_toplevel(widget)), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL)); ufraw_focus(fileChooser, TRUE); #ifdef HAVE_GTK_2_6 gtk_file_chooser_set_show_hidden(fileChooser, FALSE); GtkWidget *button = gtk_check_button_new_with_label( "Show hidden files"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(ufraw_chooser_toggle), fileChooser); gtk_file_chooser_set_extra_widget(fileChooser, button); #endif filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "All curve formats"); gtk_file_filter_add_pattern(filter, "*.ntc"); gtk_file_filter_add_pattern(filter, "*.NTC"); gtk_file_filter_add_pattern(filter, "*.ncv"); gtk_file_filter_add_pattern(filter, "*.NCV"); gtk_file_filter_add_pattern(filter, "*.curve"); gtk_file_filter_add_pattern(filter, "*.CURVE"); gtk_file_chooser_add_filter(fileChooser, filter); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "UFRaw curve format"); gtk_file_filter_add_pattern(filter, "*.curve"); gtk_file_filter_add_pattern(filter, "*.CURVE"); gtk_file_chooser_add_filter(fileChooser, filter); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "Nikon curve format"); gtk_file_filter_add_pattern(filter, "*.ntc"); gtk_file_filter_add_pattern(filter, "*.NTC"); gtk_file_filter_add_pattern(filter, "*.ncv"); gtk_file_filter_add_pattern(filter, "*.NCV"); gtk_file_chooser_add_filter(fileChooser, filter); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "All files"); gtk_file_filter_add_pattern(filter, "*"); gtk_file_chooser_add_filter(fileChooser, filter); if (strlen(CFG->curvePath)>0) gtk_file_chooser_set_current_folder(fileChooser, CFG->curvePath); snprintf(defFilename, max_name, "%s.curve", CFG->curve[CFG->curveIndex].name); gtk_file_chooser_set_current_name(fileChooser, defFilename); if (gtk_dialog_run(GTK_DIALOG(fileChooser))==GTK_RESPONSE_ACCEPT) { filename = gtk_file_chooser_get_filename(fileChooser); curve_save(&CFG->curve[CFG->curveIndex], filename); cp = g_path_get_dirname(filename); g_strlcpy(CFG->curvePath, cp, max_path); g_free(cp); g_free(filename); } ufraw_focus(fileChooser, FALSE); gtk_widget_destroy(GTK_WIDGET(fileChooser)); } void load_profile(GtkWidget *widget, long type) { preview_data *data = get_preview_data(widget); GtkFileChooser *fileChooser; GSList *list, *saveList; GtkFileFilter *filter; char *filename, *cp; profile_data p; if (data->FreezeDialog) return; if (CFG->profileCount[type]==max_profiles) { ufraw_message(UFRAW_ERROR, "No more room for new profiles."); return; } fileChooser = GTK_FILE_CHOOSER(gtk_file_chooser_dialog_new( "Load color profile", GTK_WINDOW(gtk_widget_get_toplevel(widget)), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL)); ufraw_focus(fileChooser, TRUE); gtk_file_chooser_set_select_multiple(fileChooser, TRUE); #ifdef HAVE_GTK_2_6 gtk_file_chooser_set_show_hidden(fileChooser, FALSE); GtkWidget *button = gtk_check_button_new_with_label( "Show hidden files"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(ufraw_chooser_toggle), fileChooser); gtk_file_chooser_set_extra_widget(fileChooser, button); #endif if (strlen(CFG->profilePath)>0) gtk_file_chooser_set_current_folder(fileChooser, CFG->profilePath); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "Color Profiles"); gtk_file_filter_add_pattern(filter, "*.icm"); gtk_file_filter_add_pattern(filter, "*.ICM"); gtk_file_filter_add_pattern(filter, "*.icc"); gtk_file_filter_add_pattern(filter, "*.ICC"); gtk_file_chooser_add_filter(fileChooser, filter); filter = GTK_FILE_FILTER(gtk_file_filter_new()); gtk_file_filter_set_name(filter, "All files"); gtk_file_filter_add_pattern(filter, "*"); gtk_file_chooser_add_filter(fileChooser, filter); if (gtk_dialog_run(GTK_DIALOG(fileChooser))==GTK_RESPONSE_ACCEPT) { for (list=saveList=gtk_file_chooser_get_filenames(fileChooser); list!=NULL && CFG->profileCount[type]data; p = conf_default.profile[type][1]; g_strlcpy(p.file, filename, max_path); /* Make sure we update product name */ Developer->updateTransform = TRUE; developer_profile(Developer, type, &p); if (Developer->profile[type]==NULL) { g_free(list->data); continue; } char *base = g_path_get_basename(filename); char *name = uf_file_set_type(base, ""); char *utf8 = g_filename_to_utf8(name, -1, NULL, NULL, NULL); if (utf8==NULL) utf8 = g_strdup("Unknown file name"); g_strlcpy(p.name, utf8, max_name); g_free(utf8); g_free(name); g_free(base); /* Set some defaults to the profile's curve */ p.gamma = profile_default_gamma(&p); CFG->profile[type][CFG->profileCount[type]++] = p; gtk_combo_box_append_text(data->ProfileCombo[type], p.name); CFG->profileIndex[type] = CFG->profileCount[type]-1; cp = g_path_get_dirname(list->data); g_strlcpy(CFG->profilePath, cp, max_path); g_free(cp); g_free(list->data); } gtk_combo_box_set_active(data->ProfileCombo[type], CFG->profileIndex[type]); if (list!=NULL) ufraw_message(UFRAW_ERROR, "No more room for new profiles."); g_slist_free(saveList); } ufraw_focus(fileChooser, FALSE); gtk_widget_destroy(GTK_WIDGET(fileChooser)); } colorLabels *color_labels_new(GtkTable *table, int x, int y, char *label, int format) { colorLabels *l; GtkWidget *lbl; int c, i = 0; l = g_new(colorLabels, 1); l->format = format; if (label!=NULL){ lbl = gtk_label_new(label); gtk_misc_set_alignment(GTK_MISC(lbl), 1, 0.5); gtk_table_attach(table, lbl, x, x+1, y, y+1, GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0); i++; } for (c=0; c<3; c++, i++) { l->labels[c] = GTK_LABEL(gtk_label_new(NULL)); gtk_table_attach_defaults(table, GTK_WIDGET(l->labels[c]), x+i, x+i+1, y, y+1); } return l; } void color_labels_set(colorLabels *l, double data[3]) { int c; char buf1[max_name], buf2[max_name]; const char *colorName[] = {"red", "green", "blue"}; for (c=0; c<3; c++) { switch (l->format) { case pixel_format: snprintf(buf1, max_name, "%3.f", data[c]); break; case percent_format: if (data[c]<10.0) snprintf(buf1, max_name, "%2.1f%%", data[c]); else snprintf(buf1, max_name, "%2.0f%%", data[c]); break; default: snprintf(buf1, max_name, "ERR"); } snprintf(buf2, max_name, "%s", colorName[c], buf1); gtk_label_set_markup(l->labels[c], buf2); } } enum { render_default, render_overexposed, render_underexposed }; void render_preview(preview_data *data, long mode); gboolean render_raw_histogram(preview_data *data); gboolean render_preview_image(preview_data *data); void render_spot(preview_data *data); void draw_spot(preview_data *data, gboolean draw); void render_preview_callback(GtkWidget *widget, long mode) { preview_data *data = get_preview_data(widget); render_preview(data, mode); } static int renderRestart = FALSE; void render_preview(preview_data *data, long mode) { if (data->FreezeDialog) return; data->RenderMode = mode; g_idle_remove_by_data(data); g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)(render_raw_histogram), data, NULL); } gboolean render_raw_histogram(preview_data *data) { static GdkPixbuf *pixbuf; static guint8 *pixies; int rowstride; guint8 pix[99], *p8, pen[3], *p; guint16 pixtmp[9999]; image_type p16; int x, c, cl, colors, y, y0, y1; int raw_his[raw_his_size][4], raw_his_max; char text[max_name]; g_snprintf(text, max_name, "Black point: %0.3lf", CFG->curve[CFG->curveIndex].m_anchors[0].x); gtk_label_set_text(GTK_LABEL(data->BlackLabel), text); developer_prepare(Developer, data->UF->rgbMax, pow(2, CFG->exposure), CFG->unclip, CFG->chanMul, data->UF->rgb_cam, data->UF->colors, data->UF->useMatrix, &CFG->profile[0][CFG->profileIndex[0]], &CFG->profile[1][CFG->profileIndex[1]], CFG->intent, CFG->saturation, &CFG->curve[CFG->curveIndex]); pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(data->RawHisto)); if (gdk_pixbuf_get_height(pixbuf)!=CFG->rawHistogramHeight+2) { pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, raw_his_size+2, CFG->rawHistogramHeight+2); gtk_image_set_from_pixbuf(GTK_IMAGE(data->RawHisto), pixbuf); g_object_unref(pixbuf); } colors = data->UF->colors; pixies = gdk_pixbuf_get_pixels(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); memset(pixies, 0, (gdk_pixbuf_get_height(pixbuf)-1)* rowstride + gdk_pixbuf_get_width(pixbuf)); memset(raw_his, 0, sizeof(raw_his)); /* Collect histogram data */ for (y=0; yUF->image.height; y++) for (x=0; xUF->image.width; x++) for (c=0; cUF->image.image[y*data->UF->image.width+x][c] * (raw_his_size-1) / data->UF->rgbMax, raw_his_size-1) ][c]++; for (x=0, raw_his_max=1; xrawHistogramScale==log_histogram) raw_his[x][c] = log(1+raw_his[x][c])*1000; y += raw_his[x][c]; } raw_his_max = MAX(raw_his_max, y); } p8 = pix; p = pixies + CFG->rawHistogramHeight*rowstride + 3; for (x=0; xUF->rgbMax; develope(pen, p16, Developer, 8, pixtmp, 1); for (y=0; yrawHistogramHeight/raw_his_max; y++) for (cl=0; cl<3; cl++) pixies[(CFG->rawHistogramHeight-y-y0)*rowstride + 3*(x+1)+cl] = pen[cl]; y0 += y; } /* draw curves on the raw histogram */ for (c=0; cUF->rgbMax; develope(pen, p16, Developer, 8, pixtmp, 1); /* Value for pixel x of color c in a grey pixel */ for (cl=0; clrgbMax * Developer->rgbWB[c] / Developer->rgbWB[cl] / raw_his_size, 0xFFFF); develope(p8, p16, Developer, 8, pixtmp, 1); y=MAX(MAX(p8[0],p8[1]),p8[2]) * (CFG->rawHistogramHeight-1)/MAXOUT; /* Value for pixel x+1 of color c in a grey pixel */ for (cl=0; clrgbMax * Developer->rgbWB[c] / Developer->rgbWB[cl]/raw_his_size-1, 0xFFFF); develope(p8, p16, Developer, 8, pixtmp, 1); y1=MAX(MAX(p8[0],p8[1]),p8[2]) * (CFG->rawHistogramHeight-1)/MAXOUT; for (; y<=y1; y++) for (cl=0; cl<3; cl++) pixies[(CFG->rawHistogramHeight-y)*rowstride + 3*(x+1)+cl] = pen[cl]; /* Value for pixel x of pure color c */ p16[0] = p16[1] = p16[2] = p16[3] = 0; p16[c] = MIN((guint64)x*Developer->rgbMax/raw_his_size, 0xFFFF); develope(p8, p16, Developer, 8, pixtmp, 1); y1=MAX(MAX(p8[0],p8[1]),p8[2]) * (CFG->rawHistogramHeight-1)/MAXOUT; for (; yrawHistogramHeight-y)*rowstride + 3*(x+1)+cl] = pen[cl]/2; /* Value for pixel x+1 of pure color c */ p16[c] = MIN((guint64)(x+1)*Developer->rgbMax/raw_his_size - 1, 0xFFFF); develope(p8, p16, Developer, 8, pixtmp, 1); y1=MAX(MAX(p8[0],p8[1]),p8[2]) * (CFG->rawHistogramHeight-1)/MAXOUT; for (; y<=y1; y++) for (cl=0; cl<3; cl++) pixies[(CFG->rawHistogramHeight-y)*rowstride + 3*(x+1)+cl] = pen[cl]; } } gtk_widget_queue_draw(data->RawHisto); renderRestart = TRUE; g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)(render_preview_image), data, NULL); return FALSE; } gboolean render_preview_image(preview_data *data) { static GdkPixbuf *pixbuf; static guint8 *pixies; static int width, height, x, y, c, o, min, max, rowstride, y0; static int live_his[live_his_size][4], live_his_max; guint8 *p8; guint16 pixtmp[9999]; double rgb[3]; guint64 sum[3], sqr[3]; if (renderRestart) { renderRestart = FALSE; pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(data->PreviewWidget)); width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); pixies = gdk_pixbuf_get_pixels(pixbuf); #ifdef DEBUG fprintf(stderr, "render_preview_image: w=%d, h=%d, r=%d, mode=%d\n", width, height, rowstride, data->RenderMode); fflush(stderr); #endif memset(live_his, 0, sizeof(live_his)); y = y0 = 0; } for (; yUF->image.image[y*width], Developer, 8, pixtmp, width); for (x=0, p8=&pixies[y*rowstride]; xhistogram==luminosity_histogram) live_his[(int)(0.3*p8[0]+0.59*p8[1]+0.11*p8[2])][3]++; if (CFG->histogram==value_histogram) live_his[max][3]++; if (CFG->histogram==saturation_histogram) { if (max==0) live_his[0][3]++; else live_his[255*(max-min)/max][3]++; } for (c=0; c<3; c++) { o = p8[c]; if (data->RenderMode==render_default) { if (CFG->overExp && max==MAXOUT) o = 0; if (CFG->underExp && min==0) o = 255; } else if (data->RenderMode==render_overexposed) { if (o!=255) o = 0; } else if (data->RenderMode==render_underexposed) { if (o!=0) o = 255; } pixies[y*rowstride+3*x+c] = o; } } if (y%32==31) { gtk_widget_queue_draw_area(data->PreviewWidget, 0, y0, width, y+1-y0); y0 = y+1; y++; return TRUE; } } gtk_widget_queue_draw_area(data->PreviewWidget, 0, y0, width, y+1-y0); /* draw live histogram */ pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(data->LiveHisto)); if (gdk_pixbuf_get_height(pixbuf)!=CFG->liveHistogramHeight+2) { pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, live_his_size+2, CFG->liveHistogramHeight+2); gtk_image_set_from_pixbuf(GTK_IMAGE(data->LiveHisto), pixbuf); g_object_unref(pixbuf); } pixies = gdk_pixbuf_get_pixels(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); memset(pixies, 0, (gdk_pixbuf_get_height(pixbuf)-1)*rowstride + gdk_pixbuf_get_width(pixbuf)); for (c=0; c<3; c++) { sum[c] = 0; sqr[c] = 0; for (x=1; xliveHistogramScale==log_histogram) for (c=0; c<4; c++) live_his[x][c] = log(1+live_his[x][c])*1000; if (CFG->histogram==rgb_histogram) for (c=0; c<3; c++) live_his_max = MAX(live_his_max, live_his[x][c]); else if (CFG->histogram==r_g_b_histogram) live_his_max = MAX(live_his_max, live_his[x][0]+live_his[x][1]+live_his[x][2]); else live_his_max = MAX(live_his_max, live_his[x][3]); } #ifdef DEBUG fprintf(stderr, "render_preview: live_his_max=%d\n", live_his_max); fflush(stderr); #endif for (x=0; xliveHistogramHeight; y++) if (CFG->histogram==r_g_b_histogram) { if (y*live_his_max < live_his[x][0]*CFG->liveHistogramHeight) pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+0] = 255; else if (y*live_his_max < (live_his[x][0]+live_his[x][1])*CFG->liveHistogramHeight) pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+1] = 255; else if (y*live_his_max < (live_his[x][0]+live_his[x][1]+live_his[x][2]) *CFG->liveHistogramHeight) pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+2] = 255; } else { for (c=0; c<3; c++) if (CFG->histogram==rgb_histogram) { if (y*live_his_maxliveHistogramHeight) pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+c] = 255; } else { if (y*live_his_maxliveHistogramHeight) pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+c] = 255; } } /* draw vertical line at quarters "behind" the live histogram */ for (y=-1; yliveHistogramHeight+1; y++) for (x=64; x<255; x+=64) if (pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+0]==0 && pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+1]==0 && pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+2]==0 ) for (c=0; c<3; c++) pixies[(CFG->liveHistogramHeight-y)*rowstride+3*(x+1)+c]=64; gtk_widget_queue_draw(data->LiveHisto); for (c=0;c<3;c++) rgb[c] = sum[c]/height/width; color_labels_set(data->AvrLabels, rgb); for (c=0;c<3;c++) rgb[c] = sqrt(sqr[c]/height/width-rgb[c]*rgb[c]); color_labels_set(data->DevLabels, rgb); for (c=0;c<3;c++) rgb[c] = 100.0*live_his[live_his_size-1][c]/height/width; color_labels_set(data->OverLabels, rgb); for (c=0;c<3;c++) rgb[c] = 100.0*live_his[0][c]/height/width; color_labels_set(data->UnderLabels, rgb); render_spot(data); return FALSE; } void render_spot(preview_data *data) { GdkPixbuf *pixbuf; guint8 *pixies; int width, height, rowstride; int c, y, x; int spotStartX, spotStartY, spotSizeX, spotSizeY; double rgb[3]; char tmp[max_name]; if (data->SpotX1<0) return; pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(data->PreviewWidget)); width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); pixies = gdk_pixbuf_get_pixels(pixbuf); for (c=0; c<3; c++) rgb[c] = 0; spotSizeY = abs(data->SpotY1 - data->SpotY2)+1; spotStartY = MIN(data->SpotY1, data->SpotY2); spotSizeX = abs(data->SpotX1 - data->SpotX2)+1; spotStartX = MIN(data->SpotX1, data->SpotX2); for (y=0; ySpotLabels, rgb); snprintf(tmp, max_name, "" " ", (int)rgb[0], (int)rgb[1], (int)rgb[2]); gtk_label_set_markup(data->SpotPatch, tmp); draw_spot(data, TRUE); gtk_widget_queue_draw_area(data->PreviewWidget, spotStartX-1, spotStartY-1, spotStartX+spotSizeX+1, spotStartY+spotSizeY+1); } void pixbuf_mark(int x, int y, guchar *pixbuf, int width, int height, int rowstride, gboolean draw) { int c; if (x<0 || y<0 || x>=width || y>=height) return; for (c=0; c<3; c++) { if (draw) { if ( (x+y)%2 == 0 ) pixbuf[y*rowstride+3*x+c] = pixbuf[y*rowstride+3*x+c]/4; else pixbuf[y*rowstride+3*x+c] = 255-(255-pixbuf[y*rowstride+3*x+c])/4; } else { if ( (x+y)%2 == 0 ) pixbuf[y*rowstride+3*x+c] = pixbuf[y*rowstride+3*x+c]*4; else pixbuf[y*rowstride+3*x+c] = 255-(255-pixbuf[y*rowstride+3*x+c])*4; } } } void draw_spot(preview_data *data, gboolean draw) { GdkPixbuf *pixbuf; guint8 *pixies; int width, height, x, y, rowstride; int spotStartX, spotStartY, spotSizeX, spotSizeY; if (data->SpotX1<0) return; pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(data->PreviewWidget)); width = gdk_pixbuf_get_width(pixbuf); height = gdk_pixbuf_get_height(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); pixies = gdk_pixbuf_get_pixels(pixbuf); spotSizeY = abs(data->SpotY1 - data->SpotY2)+1; spotStartY = MIN(data->SpotY1, data->SpotY2); spotSizeX = abs(data->SpotX1 - data->SpotX2)+1; spotStartX = MIN(data->SpotX1, data->SpotX2); for (x=0; x<=spotSizeX; x++) { pixbuf_mark(spotStartX+x, spotStartY-1, pixies, width, height, rowstride, draw); pixbuf_mark(spotStartX+x, spotStartY+spotSizeY+1, pixies, width, height, rowstride, draw); } for (y=-1; y<=spotSizeY+1; y++) { pixbuf_mark(spotStartX-1, spotStartY+y, pixies, width, height, rowstride, draw); pixbuf_mark(spotStartX+spotSizeX+1, spotStartY+y, pixies, width, height, rowstride, draw); } gtk_widget_queue_draw_area(data->PreviewWidget, spotStartX-1, spotStartY-1, spotSizeX+3, spotSizeY+3); } /* update the UI entries that could have changed automatically */ void update_scales(preview_data *data) { if (data->FreezeDialog) return; data->FreezeDialog = TRUE; if (CFG->curveIndex>camera_curve && !CFG_cameraCurve) gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex-1); else gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex); gtk_combo_box_set_active(data->WBCombo, MAX(CFG->wb, 0)); gtk_adjustment_set_value(data->TemperatureAdjustment, CFG->temperature); gtk_adjustment_set_value(data->GreenAdjustment, CFG->green); gtk_adjustment_set_value(data->ExposureAdjustment, CFG->exposure); gtk_adjustment_set_value(data->SaturationAdjustment, CFG->saturation); gtk_adjustment_set_value(data->GammaAdjustment, CFG->profile[0][CFG->profileIndex[0]].gamma); gtk_adjustment_set_value(data->LinearAdjustment, CFG->profile[0][CFG->profileIndex[0]].linear); if (GTK_WIDGET_SENSITIVE(data->UseMatrixButton)) { data->UF->useMatrix = CFG->profile[0][CFG->profileIndex[0]].useMatrix; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->UseMatrixButton), data->UF->useMatrix); } gtk_toggle_button_set_active(data->AutoExposureButton, CFG->autoExposure); gtk_toggle_button_set_active(data->AutoBlackButton, CFG->autoBlack); gtk_widget_set_sensitive(data->ResetWBButton, ( CFG->wb!=data->SaveConfig.wb ||fabs(CFG->temperature-data->SaveConfig.temperature)>1 ||fabs(CFG->green-data->SaveConfig.green)>0.001 ||CFG->chanMul[0]!=data->initialChanMul[0] ||CFG->chanMul[1]!=data->initialChanMul[1] ||CFG->chanMul[2]!=data->initialChanMul[2] ||CFG->chanMul[3]!=data->initialChanMul[3] ) ); gtk_widget_set_sensitive(data->ResetGammaButton, fabs( profile_default_gamma(&CFG->profile[0][CFG->profileIndex[0]]) - CFG->profile[0][CFG->profileIndex[0]].gamma) > 0.001); gtk_widget_set_sensitive(data->ResetLinearButton, fabs( profile_default_linear(&CFG->profile[0][CFG->profileIndex[0]]) - CFG->profile[0][CFG->profileIndex[0]].linear) > 0.001); gtk_widget_set_sensitive(data->ResetExposureButton, fabs( conf_default.exposure - CFG->exposure) > 0.001); gtk_widget_set_sensitive(data->ResetSaturationButton, fabs( conf_default.saturation - CFG->saturation) > 0.001); gtk_widget_set_sensitive(data->ResetBlackButton, CFG->curve[CFG->curveIndex].m_anchors[0].x!=0.0 || CFG->curve[CFG->curveIndex].m_anchors[0].y!=0.0 ); gtk_widget_set_sensitive(data->ResetCurveButton, CFG->curve[CFG->curveIndex].m_numAnchors>2 || CFG->curve[CFG->curveIndex].m_anchors[1].x!=1.0 || CFG->curve[CFG->curveIndex].m_anchors[1].y!=1.0 ); data->FreezeDialog = FALSE; render_preview(data, render_default); }; void update_scales_callback(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); user_data = user_data; CFG->curveIndex = manual_curve; CFG->curve[CFG->curveIndex] = *curveeditor_widget_get_curve(data->CurveWidget); CFG->autoBlack = FALSE; update_scales(data); } void spot_wb_event(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); int spotStartX, spotStartY, spotSizeX, spotSizeY; int x, y, c; guint64 rgb[4]; user_data = user_data; if (data->FreezeDialog) return; if (data->SpotX1<=0) return; spotSizeY = abs(data->SpotY1 - data->SpotY2)+1; spotStartY = MIN(data->SpotY1, data->SpotY2); spotSizeX = abs(data->SpotX1 - data->SpotX2)+1; spotStartX = MIN(data->SpotX1, data->SpotX2); for (c=0; c<4; c++) rgb[c] = 0; for (y=spotStartY; yUF->colors; c++) rgb[c] += data->UF->image.image[y*data->UF->image.width+x][c]; for (c=0; cUF->colors; c++) CFG->chanMul[c] = (double)spotSizeX * spotSizeY * data->UF->rgbMax / rgb[c]; if (data->UF->colors<4) CFG->chanMul[3] = 0.0; ufraw_message(UFRAW_SET_LOG, "spot_wb: channel multipliers = { %.0f, %.0f, %.0f, %.0f }\n", CFG->chanMul[0], CFG->chanMul[1], CFG->chanMul[2], CFG->chanMul[3]); CFG->wb = spot_wb; ufraw_set_wb(data->UF); if (CFG->autoExposure) ufraw_auto_expose(data->UF); CFG->autoBlack = FALSE; update_scales(data); } void spot_press(GtkWidget *event_box, GdkEventButton *event, gpointer user_data) { preview_data *data = get_preview_data(event_box); event_box = event_box; user_data = user_data; if (data->FreezeDialog) return; if (event->button!=1) return; draw_spot(data, FALSE); data->SpotX1 = event->x; data->SpotY1 = event->y; data->SpotX2 = event->x; data->SpotY2 = event->y; render_spot(data); } gboolean spot_motion(GtkWidget *event_box, GdkEventMotion *event, gpointer user_data) { preview_data *data = get_preview_data(event_box); user_data = user_data; if ((event->state&GDK_BUTTON1_MASK)==0) return FALSE; draw_spot(data, FALSE); data->SpotX2 = MAX(MIN(event->x,data->UF->image.width),0); data->SpotY2 = MAX(MIN(event->y,data->UF->image.height),0); render_spot(data); return FALSE; } GtkWidget *table_with_frame(GtkWidget *box, char *label, gboolean expand) { GtkWidget *frame, *expander; GtkWidget *table; if (GTK_IS_NOTEBOOK(box)) { table = gtk_vbox_new(FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(box), GTK_WIDGET(table), gtk_label_new(label)); } else if (label!=NULL) { table = gtk_table_new(10, 10, FALSE); expander = gtk_expander_new(label); gtk_expander_set_expanded(GTK_EXPANDER(expander), expand); gtk_box_pack_start(GTK_BOX(box), expander, FALSE, FALSE, 0); frame = gtk_frame_new(NULL); gtk_container_add(GTK_CONTAINER(expander), GTK_WIDGET(frame)); gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(table)); } else { table = gtk_table_new(10, 10, FALSE); frame = gtk_frame_new(NULL); gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(table)); } return table; } void button_update(GtkWidget *button, gpointer user_data) { preview_data *data = get_preview_data(button); user_data = user_data; if (button==data->ResetWBButton) { int c; CFG->wb = data->SaveConfig.wb; CFG->temperature = data->SaveConfig.temperature; CFG->green = data->SaveConfig.green; for (c=0; c<4; c++) CFG->chanMul[c] = data->initialChanMul[c]; } if (button==data->ResetGammaButton) { CFG->profile[0][CFG->profileIndex[0]].gamma = profile_default_gamma(&CFG->profile[0][CFG->profileIndex[0]]); } if (button==data->ResetLinearButton) { CFG->profile[0][CFG->profileIndex[0]].linear = profile_default_linear(&CFG->profile[0][CFG->profileIndex[0]]); } if (button==GTK_WIDGET(data->AutoExposureButton)) { CFG->autoExposure = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); if (CFG->autoExposure) ufraw_auto_expose(data->UF); } if (button==data->ResetExposureButton) { CFG->exposure = conf_default.exposure; CFG->autoExposure = FALSE; } if (button==data->ResetSaturationButton) { CFG->saturation = conf_default.saturation; } if (button==GTK_WIDGET(data->AutoBlackButton)) { CFG->autoBlack = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)); if (CFG->autoBlack) { ufraw_auto_black(data->UF); curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); } } if (button==data->ResetBlackButton) { CurveDataSetPoint(&CFG->curve[CFG->curveIndex], 0, conf_default.black, 0); curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); } if (button==GTK_WIDGET(data->AutoCurveButton)) { CFG->autoBlack = FALSE; CFG->curveIndex = manual_curve; ufraw_auto_curve(data->UF); curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); } if (button==data->ResetCurveButton) { if (CFG->curveIndex==manual_curve) { CFG->curve[CFG->curveIndex].m_numAnchors = 2; CFG->curve[CFG->curveIndex].m_anchors[1].x = 1.0; CFG->curve[CFG->curveIndex].m_anchors[1].y = 1.0; } else { CFG->curveIndex = linear_curve; } curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); } if ( button!=GTK_WIDGET(data->AutoBlackButton) && button!=GTK_WIDGET(data->AutoCurveButton) ) { CFG->autoBlack = FALSE; } update_scales(data); return; } void toggle_button_update(GtkToggleButton *button, gboolean *valuep) { preview_data *data = get_preview_data(button); if (valuep==&CFG->unclip) { /* ugly flip needed because CFG->unclip==!clip_button_active */ *valuep = !gtk_toggle_button_get_active(button); if (CFG->autoExposure) ufraw_auto_expose(data->UF); char text[max_name]; snprintf(text, max_name, "Highlight clipping\n" "Current state: %s", CFG->unclip ? "unclip" : "clip"); gtk_tooltips_set_tip(data->ToolTips, GTK_WIDGET(button), text, NULL); CFG->autoBlack = FALSE; update_scales(data); } else { *valuep = gtk_toggle_button_get_active(button); if (valuep==&data->UF->useMatrix) CFG->profile[0][CFG->profileIndex[0]].useMatrix = *valuep; render_preview(data, render_default); } } void toggle_button(GtkTable *table, int x, int y, char *label, gboolean *valuep) { GtkWidget *widget, *align; widget = gtk_check_button_new_with_label(label); if (label==NULL) { align = gtk_alignment_new(1, 0, 0, 1); gtk_container_add(GTK_CONTAINER(align), widget); } else align = widget; gtk_table_attach(table, align, x, x+1, y, y+1, 0, 0, 0, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), *valuep); g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK(toggle_button_update), valuep); } void adjustment_update(GtkAdjustment *adj, double *valuep) { preview_data *data = get_preview_data(adj); if (data->FreezeDialog) return; if (valuep==&CFG->profile[0][0].gamma) valuep = (void *)&CFG->profile[0][CFG->profileIndex[0]].gamma; if (valuep==&CFG->profile[0][0].linear) valuep = (void *)&CFG->profile[0][CFG->profileIndex[0]].linear; /* Do noting if value didn't really change */ long accuracy = (long)g_object_get_data(G_OBJECT(adj), "Adjustment-Accuracy"); if ( fabs(*valuep-gtk_adjustment_get_value(adj))temperature || valuep==&CFG->green) { CFG->wb = manual_wb; ufraw_set_wb(data->UF); if (CFG->autoExposure) ufraw_auto_expose(data->UF); } if (valuep==&CFG->exposure) { CFG->autoExposure = FALSE; } CFG->autoBlack = FALSE; update_scales(data); } GtkAdjustment *adjustment_scale(GtkTable *table, int x, int y, char *label, double value, double *valuep, double min, double max, double step, double jump, long accuracy, char *tip) { preview_data *data = get_preview_data(table); GtkAdjustment *adj; GtkWidget *w, *l; w = gtk_event_box_new(); l = gtk_label_new(label); gtk_misc_set_alignment(GTK_MISC(l), 1, 0.5); gtk_container_add(GTK_CONTAINER(w),l); gtk_tooltips_set_tip(data->ToolTips, w, tip, NULL); gtk_table_attach(table, w, x, x+1, y, y+1, GTK_SHRINK|GTK_FILL, 0, 0, 0); adj = GTK_ADJUSTMENT(gtk_adjustment_new(value, min, max, step, jump, 0)); g_object_set_data(G_OBJECT(adj), "Adjustment-Accuracy",(gpointer)accuracy); g_signal_connect(G_OBJECT(adj), "value-changed", G_CALLBACK(adjustment_update), valuep); w = gtk_hscale_new(adj); g_object_set_data(G_OBJECT(adj), "Parent-Widget", w); gtk_scale_set_draw_value(GTK_SCALE(w), FALSE); gtk_tooltips_set_tip(data->ToolTips, w, tip, NULL); gtk_table_attach(table, w, x+1, x+5, y, y+1, GTK_EXPAND|GTK_FILL, 0, 0, 0); w = gtk_spin_button_new(adj, step, accuracy); gtk_spin_button_set_snap_to_ticks(GTK_SPIN_BUTTON(w), FALSE); gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(w), GTK_UPDATE_IF_VALID); gtk_tooltips_set_tip(data->ToolTips, w, tip, NULL); gtk_table_attach(table, w, x+5, x+7, y, y+1, GTK_SHRINK|GTK_FILL, 0, 0, 0); return adj; } void combo_update(GtkWidget *combo, gint *valuep) { preview_data *data = get_preview_data(combo); if (data->FreezeDialog) return; *valuep = gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); if (valuep==&CFG->curveIndex) { if (!CFG_cameraCurve && CFG->curveIndex>=camera_curve) CFG->curveIndex++; curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); } else if (valuep==&CFG->wb) { ufraw_set_wb(data->UF); if (CFG->autoExposure) ufraw_auto_expose(data->UF); } if (valuep!=&CFG->interpolation) { CFG->autoBlack = FALSE; update_scales(data); } } void radio_menu_update(GtkWidget *item, gint *valuep) { if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item))) { preview_data *data = get_preview_data(item); *valuep = (int)g_object_get_data(G_OBJECT(item), "Radio-Value"); render_preview(data, render_default); } } void container_remove(GtkWidget *widget, gpointer user_data) { GtkContainer *container = GTK_CONTAINER(user_data); gtk_container_remove(container, widget); } void delete_from_list(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); GtkDialog *dialog; long type, index; dialog = GTK_DIALOG(gtk_widget_get_ancestor(widget, GTK_TYPE_DIALOG)); type = (long)g_object_get_data(G_OBJECT(widget), "Type"); index = (long)user_data; if (type<2) { gtk_combo_box_remove_text(data->ProfileCombo[type], index); CFG->profileCount[type]--; if (CFG->profileIndex[type]==CFG->profileCount[type]) { CFG->profileIndex[type]--; } gtk_combo_box_set_active(data->ProfileCombo[type], CFG->profileIndex[type]); for (; indexprofileCount[type]; index++) CFG->profile[type][index] = CFG->profile[type][index+1]; } else { if (CFG_cameraCurve) gtk_combo_box_remove_text(data->CurveCombo, index); else gtk_combo_box_remove_text(data->CurveCombo, index-1); CFG->curveCount--; if (CFG->curveIndex==CFG->curveCount) { CFG->curveIndex--; if (CFG->curveIndex==camera_curve && !CFG_cameraCurve) CFG->curveIndex = linear_curve; if (CFG->curveIndex>camera_curve && !CFG_cameraCurve) gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex-1); else gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex); curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); } for (; indexcurveCount; index++) CFG->curve[index] = CFG->curve[index+1]; } gtk_dialog_response(dialog, GTK_RESPONSE_APPLY); } void configuration_save(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); user_data = user_data; conf_save(CFG, NULL, NULL); data->SaveConfig = *data->UF->conf; } void options_combo_update(GtkWidget *combo, gint *valuep) { GtkDialog *dialog; *valuep = gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); dialog = GTK_DIALOG(gtk_widget_get_ancestor(combo, GTK_TYPE_DIALOG)); gtk_dialog_response(dialog, GTK_RESPONSE_APPLY); } void options_dialog(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); GtkWidget *optionsDialog, *profileTable[2]; GtkComboBox *confCombo; GtkWidget *notebook, *label, *page, *button, *text, *box, *image, *event; GtkTable *curveTable, *table; GtkTextBuffer *confBuffer, *buffer; char txt[max_name], *buf; long i, j; user_data = user_data; if (data->FreezeDialog) return; optionsDialog = gtk_dialog_new_with_buttons("UFRaw options", GTK_WINDOW(gtk_widget_get_toplevel(widget)), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); g_object_set_data(G_OBJECT(optionsDialog), "Preview-Data", data); ufraw_focus(optionsDialog, TRUE); gtk_dialog_set_default_response(GTK_DIALOG(optionsDialog), GTK_RESPONSE_OK); notebook = gtk_notebook_new(); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(optionsDialog)->vbox), notebook); label =gtk_label_new("Settings"); box = gtk_vbox_new(FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box, label); profileTable[0] = table_with_frame(box, "Input color profiles", TRUE); profileTable[1] = table_with_frame(box, "Output color profiles", TRUE); curveTable = GTK_TABLE(table_with_frame(box, "Curves", TRUE)); label = gtk_label_new("Configuration"); box = gtk_vbox_new(FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box, label); page = gtk_scrolled_window_new(NULL, NULL); gtk_box_pack_start(GTK_BOX(box), page, TRUE, TRUE, 0); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(page), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); text = gtk_text_view_new(); gtk_container_add(GTK_CONTAINER(page), text); gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); confBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); table = GTK_TABLE(gtk_table_new(10, 10, FALSE)); gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(table), FALSE, FALSE, 0); label = gtk_label_new("Save image defaults "); event = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(event), label); gtk_tooltips_set_tip(data->ToolTips, event, "Save current image manipulation parameters as defaults.\n" "The output parameters in this window are always saved.", NULL); gtk_table_attach(GTK_TABLE(table), event, 0, 2, 0, 1, 0, 0, 0, 0); confCombo = GTK_COMBO_BOX(gtk_combo_box_new_text()); gtk_combo_box_append_text(confCombo, "Never again"); gtk_combo_box_append_text(confCombo, "Always"); gtk_combo_box_append_text(confCombo, "Just this once"); gtk_combo_box_set_active(confCombo, CFG->saveConfiguration); g_signal_connect(G_OBJECT(confCombo), "changed", G_CALLBACK(options_combo_update), &CFG->saveConfiguration); gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(confCombo), 2, 3, 0, 1, 0, 0, 0, 0); button = gtk_button_new_from_stock(GTK_STOCK_SAVE); gtk_tooltips_set_tip(data->ToolTips, button, "Save resource file ($HOME/.ufrawrc) now", NULL); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(configuration_save), NULL); gtk_table_attach(table, button, 0, 1, 1, 2, 0, 0, 0, 0); label = gtk_label_new("Log"); page = gtk_scrolled_window_new(NULL, NULL); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(page), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); text = gtk_text_view_new(); gtk_container_add(GTK_CONTAINER(page), text); gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text)); char *log = ufraw_message(UFRAW_GET_LOG, NULL); if (log!=NULL) { char *utf8_log = g_filename_to_utf8(log, -1, NULL, NULL, NULL); if (utf8_log==NULL) utf8_log = g_strdup("Encoding conversion failed"); gtk_text_buffer_set_text(buffer, utf8_log, -1); g_free(utf8_log); } label = gtk_label_new("About"); box = gtk_vbox_new(FALSE, 0); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box, label); image = gtk_image_new_from_pixbuf( gdk_pixbuf_new_from_inline(-1, ufraw_icon, FALSE, NULL)); gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0); label = gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(label), "UFRaw " VERSION ""); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); label = gtk_label_new(NULL); gtk_label_set_markup(GTK_LABEL(label), "\n" "The Unidentified Flying Raw " "(UFRaw) is a utility to read\n" "and manipulate raw images from digital cameras.\n" "UFRaw relies on Digital Camera " "Raw (DCRaw)\n" "for the actual encoding of the raw images.\n\n" "Author: Udi Fuchs\n" "Homepage: http://ufraw.sourceforge.net/\n\n"); gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); while (1) { for (j=0; j<2; j++) { gtk_container_foreach(GTK_CONTAINER(profileTable[j]), (GtkCallback)(container_remove), profileTable[j]); table = GTK_TABLE(profileTable[j]); for (i=1; iprofileCount[j]; i++) { snprintf(txt, max_name, "%s (%s)", CFG->profile[j][i].name, CFG->profile[j][i].productName); label = gtk_label_new(txt); gtk_table_attach_defaults(table, label, 0, 1, i, i+1); button = gtk_button_new_from_stock(GTK_STOCK_DELETE); g_object_set_data(G_OBJECT(button), "Type", (void*)j); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(delete_from_list), (gpointer)i); gtk_table_attach(table, button, 1, 2, i, i+1, 0, 0, 0, 0); } } gtk_container_foreach(GTK_CONTAINER(curveTable), (GtkCallback)(container_remove), curveTable); table = curveTable; for (i=camera_curve+1; icurveCount; i++) { label = gtk_label_new(CFG->curve[i].name); gtk_table_attach_defaults(table, label, 0, 1, i, i+1); button = gtk_button_new_from_stock(GTK_STOCK_DELETE); g_object_set_data(G_OBJECT(button), "Type", (void*)2); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(delete_from_list), (gpointer)i); gtk_table_attach(table, button, 1, 2, i, i+1, 0, 0, 0, 0); } conf_save(CFG, NULL, &buf); gtk_text_buffer_set_text(confBuffer, buf, -1); g_free(buf); gtk_widget_show_all(optionsDialog); if (gtk_dialog_run(GTK_DIALOG(optionsDialog))!= GTK_RESPONSE_APPLY) { ufraw_focus(optionsDialog, FALSE); gtk_widget_destroy(optionsDialog); render_preview(data, render_default); return; } } } gboolean window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer user_data) { preview_data *data = get_preview_data(widget); user_data = user_data; event = event; if (data->FreezeDialog) return TRUE; g_object_set_data(G_OBJECT(widget), "WindowResponse", (gpointer)GTK_RESPONSE_CANCEL); gtk_main_quit(); return TRUE; } void expander_state(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); const char *text; GtkWidget *label; int i; user_data = user_data; if (!GTK_IS_EXPANDER(widget)) return; label = gtk_expander_get_label_widget(GTK_EXPANDER(widget)); text = gtk_label_get_text(GTK_LABEL(label)); for (i=0; expanderText[i]!=NULL; i++) if (!strcmp(text, expanderText[i])) CFG->expander[i] = gtk_expander_get_expanded(GTK_EXPANDER(widget)); } gboolean histogram_menu(GtkMenu *menu, GdkEventButton *event) { preview_data *data = get_preview_data(menu); if (data->FreezeDialog) return FALSE; if (event->button!=3) return FALSE; gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } gboolean preview_cursor(GtkWidget *widget, GdkEventCrossing *event, GdkCursor *cursor) { widget = widget; gdk_window_set_cursor(event->window, cursor); return TRUE; } void preview_progress(void *widget, char *text, double progress) { if (widget==NULL) return; preview_data *data = get_preview_data(widget); if (data->ProgressBar==NULL) return; gtk_progress_bar_set_text(data->ProgressBar, text); gtk_progress_bar_set_fraction(data->ProgressBar, progress); while (gtk_events_pending()) gtk_main_iteration(); } void window_response(GtkWidget *widget, gpointer user_data) { preview_data *data = get_preview_data(widget); GtkWindow *window = GTK_WINDOW(gtk_widget_get_toplevel(widget)); if (data->FreezeDialog) return; g_object_set_data(G_OBJECT(window), "WindowResponse", user_data); gtk_main_quit(); } void preview_saver(GtkWidget *widget, ufraw_data *uf) { preview_data *data = get_preview_data(widget); if (data->FreezeDialog==TRUE) return; gtk_widget_set_sensitive(data->ControlsBox, FALSE); data->FreezeDialog = TRUE; (*data->SaveFunc)(widget, uf); data->FreezeDialog = FALSE; gtk_widget_set_sensitive(data->ControlsBox, TRUE); } int ufraw_preview(ufraw_data *uf, int plugin, long (*save_func)()) { GtkWidget *previewWindow, *previewVBox; GtkTable *table; GtkBox *previewHBox, *box, *hbox; GtkComboBox *combo; GtkWidget *button, *saveButton, *saveAsButton=NULL, *event_box, *align, *label, *vBox, *noteBox, *page, *menu, *menu_item; GSList *group; GdkPixbuf *pixbuf; GdkRectangle screen; int max_preview_width, max_preview_height; int preview_width, preview_height, scale, shrinkSave, sizeSave, i; long j; int status, rowstride, curveeditorHeight; guint8 *pixies; char progressText[max_name], text[max_name]; preview_data PreviewData; preview_data *data = &PreviewData; data->UF = uf; data->SaveFunc = save_func; data->SaveConfig = *uf->conf; data->SpotX1 = -1; data->FreezeDialog = TRUE; data->ToolTips = gtk_tooltips_new(); previewWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); char *utf8_filename = g_filename_to_utf8(uf->filename, -1, NULL, NULL, NULL); if (utf8_filename==NULL) utf8_filename = g_strdup("Unknown file name"); char *previewHeader = g_strdup_printf("%s - UFRaw Photo Loader", utf8_filename); gtk_window_set_title(GTK_WINDOW(previewWindow), previewHeader); g_free(previewHeader); g_free(utf8_filename); gtk_window_set_icon(GTK_WINDOW(previewWindow), gdk_pixbuf_new_from_inline(-1, ufraw_icon, FALSE, NULL)); gtk_window_set_resizable(GTK_WINDOW(previewWindow), FALSE); g_signal_connect(G_OBJECT(previewWindow), "delete-event", G_CALLBACK(window_delete_event), NULL); g_object_set_data(G_OBJECT(previewWindow), "Preview-Data", data); ufraw_focus(previewWindow, TRUE); uf->widget = previewWindow; gdk_screen_get_monitor_geometry(gdk_screen_get_default(), 0, &screen); max_preview_width = MIN(def_preview_width, screen.width-400); max_preview_height = MIN(def_preview_height, screen.height-120); scale = MAX((uf->predictateWidth-1)/max_preview_width, (uf->predictateHeight-1)/max_preview_height)+1; scale = MAX(2, scale); preview_width = uf->predictateWidth / scale; preview_height = uf->predictateHeight / scale; snprintf(progressText, max_name, "size %dx%d, scale 1/%d", uf->predictateHeight, uf->predictateWidth, scale); /* With the following guesses the window usually fits into the screen. * There should be more intelegent settings to widget sizes. */ curveeditorHeight = 256; if (screen.height<801) { if (CFG->liveHistogramHeight==conf_default.liveHistogramHeight) CFG->liveHistogramHeight = 96; if (CFG->rawHistogramHeight==conf_default.rawHistogramHeight) CFG->rawHistogramHeight = 96; if (screen.height<800) curveeditorHeight = 192; } previewHBox = GTK_BOX(gtk_hbox_new(FALSE, 0)); gtk_container_add(GTK_CONTAINER(previewWindow), GTK_WIDGET(previewHBox)); previewVBox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(previewHBox, previewVBox, TRUE, TRUE, 2); table = GTK_TABLE(table_with_frame(previewVBox, expanderText[raw_expander], CFG->expander[raw_expander])); event_box = gtk_event_box_new(); gtk_table_attach(table, event_box, 0, 1, 1, 2, 0, 0, 0, 0); pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, raw_his_size+2, CFG->rawHistogramHeight+2); data->RawHisto = gtk_image_new_from_pixbuf(pixbuf); g_object_unref(pixbuf); gtk_container_add(GTK_CONTAINER(event_box), data->RawHisto); pixies = gdk_pixbuf_get_pixels(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); memset(pixies, 0, (gdk_pixbuf_get_height(pixbuf)-1)* rowstride + gdk_pixbuf_get_width(pixbuf)); menu = gtk_menu_new(); g_object_set_data(G_OBJECT(menu), "Parent-Widget", event_box); g_signal_connect_swapped(G_OBJECT(event_box), "button_press_event", G_CALLBACK(histogram_menu), menu); group = NULL; menu_item = gtk_radio_menu_item_new_with_label(group, "Linear"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 6, 7); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->rawHistogramScale==linear_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)linear_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->rawHistogramScale); menu_item = gtk_radio_menu_item_new_with_label(group, "Logarithmic"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 7, 8); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->rawHistogramScale==log_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)log_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->rawHistogramScale); menu_item = gtk_separator_menu_item_new(); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 8, 9); group = NULL; menu_item = gtk_radio_menu_item_new_with_label(group, "96 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 9, 10); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->rawHistogramHeight==96); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)96); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->rawHistogramHeight); menu_item = gtk_radio_menu_item_new_with_label(group, "128 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 10, 11); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->rawHistogramHeight==128); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)128); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->rawHistogramHeight); menu_item = gtk_radio_menu_item_new_with_label(group, "192 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 11, 12); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->rawHistogramHeight==192); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)192); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->rawHistogramHeight); menu_item = gtk_radio_menu_item_new_with_label(group, "256 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 12, 13); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->rawHistogramHeight==256); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)256); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->rawHistogramHeight); gtk_widget_show_all(menu); table = GTK_TABLE(table_with_frame(previewVBox, NULL, FALSE)); data->SpotLabels = color_labels_new(table, 0, 1, "Spot values:", pixel_format); data->SpotPatch = GTK_LABEL(gtk_label_new(NULL)); gtk_table_attach_defaults(table, GTK_WIDGET(data->SpotPatch), 6, 7, 1, 2); data->ControlsBox = noteBox = gtk_notebook_new(); gtk_box_pack_start(GTK_BOX(previewVBox), noteBox, FALSE, FALSE, 0); page = table_with_frame(noteBox, "Base", TRUE); table = GTK_TABLE(table_with_frame(page, NULL, TRUE)); label = gtk_label_new("White balance"); gtk_table_attach(table, label, 0, 1, 0 , 1, 0, 0, 0, 0); data->WBCombo = GTK_COMBO_BOX(gtk_combo_box_new_text()); for (i=0; iWBCombo, wb_preset[i].name); gtk_combo_box_set_active(data->WBCombo, MAX(CFG->wb, 0) ); g_signal_connect(G_OBJECT(data->WBCombo), "changed", G_CALLBACK(combo_update), &CFG->wb); gtk_table_attach(table, GTK_WIDGET(data->WBCombo), 1, 6, 0, 1, GTK_FILL, 0, 0, 0); data->ResetWBButton = gtk_button_new(); gtk_container_add(GTK_CONTAINER(data->ResetWBButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, data->ResetWBButton, "Reset white balance to initial value", NULL); gtk_table_attach(table, data->ResetWBButton, 7, 8, 0, 1, 0, 0, 0, 0); g_signal_connect(G_OBJECT(data->ResetWBButton), "clicked", G_CALLBACK(button_update), NULL); data->TemperatureAdjustment = adjustment_scale(table, 0, 1, "Temperature [K]", CFG->temperature, &CFG->temperature, 2000, 7000, 50, 200, 0, "White balance color temperature (K)"); data->GreenAdjustment = adjustment_scale(table, 0, 2, "Green component", CFG->green, &CFG->green, 0.2, 2.5, 0.01, 0.05, 2, "Green component"); //button = gtk_button_new_with_label("Spot\nWB"); button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_stock( GTK_STOCK_COLOR_PICKER, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, button, "Select a spot on the preview image to apply spot white balance", NULL); gtk_table_attach(table, button, 7, 8, 1, 3, GTK_FILL, 0, 0, 0); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(spot_wb_event), NULL); table = GTK_TABLE(table_with_frame(page, expanderText[color_expander], CFG->expander[color_expander])); for (j=0; jProfileCombo[j] = GTK_COMBO_BOX(gtk_combo_box_new_text()); for (i=0; iprofileCount[j]; i++) gtk_combo_box_append_text(data->ProfileCombo[j], CFG->profile[j][i].name); gtk_combo_box_set_active(data->ProfileCombo[j], CFG->profileIndex[j]); g_signal_connect(G_OBJECT(data->ProfileCombo[j]), "changed", G_CALLBACK(combo_update), &CFG->profileIndex[j]); gtk_table_attach(table, GTK_WIDGET(data->ProfileCombo[j]), 1, 7, 4*j+1, 4*j+2, GTK_FILL, GTK_FILL, 0, 0); button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_stock( GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON)); gtk_table_attach(table, button, 7, 8, 4*j+1, 4*j+2, GTK_SHRINK, GTK_FILL, 0, 0); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(load_profile), (void *)j); } data->UseMatrixButton = gtk_check_button_new_with_label("Use color matrix"); gtk_table_attach(table, data->UseMatrixButton, 0, 3, 2, 3, 0, 0, 0, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->UseMatrixButton), data->UF->useMatrix); g_signal_connect(G_OBJECT(data->UseMatrixButton), "toggled", G_CALLBACK(toggle_button_update), &data->UF->useMatrix); if (data->UF->raw_color || data->UF->colors==4) gtk_widget_set_sensitive(data->UseMatrixButton, FALSE); data->GammaAdjustment = adjustment_scale(table, 0, 3, "Gamma", CFG->profile[0][CFG->profileIndex[0]].gamma, &CFG->profile[0][0].gamma, 0.1, 1.0, 0.01, 0.05, 2, "Gamma correction for the input profile"); data->ResetGammaButton = gtk_button_new(); gtk_container_add(GTK_CONTAINER(data->ResetGammaButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, data->ResetGammaButton, "Reset gamma to default", NULL); gtk_table_attach(table, data->ResetGammaButton, 7, 8, 3, 4, 0, 0, 0, 0); g_signal_connect(G_OBJECT(data->ResetGammaButton), "clicked", G_CALLBACK(button_update), NULL); data->LinearAdjustment = adjustment_scale(table, 0, 4, "Linearity", CFG->profile[0][CFG->profileIndex[0]].linear, &CFG->profile[0][0].linear, 0.0, 1.0, 0.01, 0.05, 2, "Linear part of the gamma correction"); data->ResetLinearButton = gtk_button_new(); gtk_container_add(GTK_CONTAINER(data->ResetLinearButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, data->ResetLinearButton, "Reset linearity to default", NULL); gtk_table_attach(table, data->ResetLinearButton, 7, 8, 4, 5, 0, 0, 0, 0); g_signal_connect(G_OBJECT(data->ResetLinearButton), "clicked", G_CALLBACK(button_update), NULL); label = gtk_label_new("Intent"); gtk_table_attach(table, label, 0, 1, 6, 7, 0, 0, 0, 0); combo = GTK_COMBO_BOX(gtk_combo_box_new_text()); gtk_combo_box_append_text(combo, "Perceptual"); gtk_combo_box_append_text(combo, "Relative colorimetric"); gtk_combo_box_append_text(combo, "Saturation"); gtk_combo_box_append_text(combo, "Absolute colorimetric"); gtk_combo_box_set_active(GTK_COMBO_BOX(combo), CFG->intent); g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(combo_update), &CFG->intent); gtk_table_attach(table, GTK_WIDGET(combo), 1, 7, 6, 7, GTK_FILL, 0, 0, 0); page = table_with_frame(noteBox, "Corrections", TRUE); table = GTK_TABLE(table_with_frame(page, NULL, TRUE)); data->ExposureAdjustment = adjustment_scale(table, 0, 0, "Exposure", CFG->exposure, &CFG->exposure, -3, 3, 0.01, 1.0/6, 2, "EV compensation"); button = gtk_toggle_button_new(); gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_stock( GTK_STOCK_CUT, GTK_ICON_SIZE_BUTTON)); snprintf(text, max_name, "Highlight clipping\n" "Current state: %s", CFG->unclip ? "unclip" : "clip"); gtk_tooltips_set_tip(data->ToolTips, button, text, NULL); gtk_table_attach(table, button, 7, 8, 0, 1, 0, 0, 0, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), !CFG->unclip); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(toggle_button_update), &CFG->unclip); data->AutoExposureButton = GTK_TOGGLE_BUTTON(gtk_toggle_button_new()); gtk_container_add(GTK_CONTAINER(data->AutoExposureButton), gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, GTK_WIDGET(data->AutoExposureButton), "Auto adjust exposure", NULL); gtk_table_attach(table, GTK_WIDGET(data->AutoExposureButton), 8, 9, 0, 1, 0, 0, 0, 0); gtk_toggle_button_set_active(data->AutoExposureButton, CFG->autoExposure); g_signal_connect(G_OBJECT(data->AutoExposureButton), "clicked", G_CALLBACK(button_update), NULL); data->ResetExposureButton = gtk_button_new(); gtk_container_add(GTK_CONTAINER(data->ResetExposureButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, data->ResetExposureButton, "Reset exposure to default", NULL); gtk_table_attach(table, data->ResetExposureButton, 9, 10, 0, 1, 0, 0, 0, 0); g_signal_connect(G_OBJECT(data->ResetExposureButton), "clicked", G_CALLBACK(button_update), NULL); data->SaturationAdjustment = adjustment_scale(table, 0, 1, "Saturation", CFG->saturation, &CFG->saturation, 0.0, 3.0, 0.01, 0.1, 2, "Saturation"); data->ResetSaturationButton = gtk_button_new(); gtk_container_add(GTK_CONTAINER(data->ResetSaturationButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, data->ResetSaturationButton, "Reset saturation to default", NULL); gtk_table_attach(table, data->ResetSaturationButton, 9, 10, 1, 2, 0, 0, 0, 0); g_signal_connect(G_OBJECT(data->ResetSaturationButton), "clicked", G_CALLBACK(button_update), NULL); table = GTK_TABLE(table_with_frame(page, NULL, CFG->expander[curve_expander])); data->CurveCombo = GTK_COMBO_BOX(gtk_combo_box_new_text()); /* Fill in the curve names, skipping "camera curve" if there is * no cameraCurve. This will make some mess later with the counting */ for (i=0; icurveCount; i++) if ( i!=camera_curve || CFG_cameraCurve ) gtk_combo_box_append_text(data->CurveCombo, CFG->curve[i].name); /* This is part of the mess with the combo_box counting */ if (CFG->curveIndex>camera_curve && !CFG_cameraCurve) gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex-1); else gtk_combo_box_set_active(data->CurveCombo, CFG->curveIndex); g_signal_connect(G_OBJECT(data->CurveCombo), "changed", G_CALLBACK(combo_update), &CFG->curveIndex); gtk_table_attach(table, GTK_WIDGET(data->CurveCombo), 0, 7, 0, 1, GTK_FILL, GTK_FILL, 0, 0); button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_stock( GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON)); gtk_table_attach(table, button, 7, 8, 0, 1, GTK_SHRINK, GTK_FILL, 0, 0); gtk_tooltips_set_tip(data->ToolTips, button, "Load curve", NULL); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(load_curve), NULL); button = gtk_button_new(); gtk_container_add(GTK_CONTAINER(button), gtk_image_new_from_stock( GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, button, "Save curve", NULL); gtk_table_attach(table, button, 8, 9, 0, 1, GTK_SHRINK, GTK_FILL, 0, 0); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(save_curve), NULL); data->CurveWidget = curveeditor_widget_new(curveeditorHeight, 256, update_scales_callback, NULL); curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); gtk_table_attach(table, data->CurveWidget, 1, 8, 1, 8, GTK_EXPAND, 0, 0, 0); data->AutoCurveButton = GTK_BUTTON(gtk_button_new()); gtk_container_add(GTK_CONTAINER(data->AutoCurveButton), gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, GTK_WIDGET(data->AutoCurveButton), "Auto adjust curve\n(Flatten histogram)", NULL); gtk_table_attach(table, GTK_WIDGET(data->AutoCurveButton), 8, 9, 6, 7, 0, 0, GTK_SHRINK, 0); g_signal_connect(G_OBJECT(data->AutoCurveButton), "clicked", G_CALLBACK(button_update), NULL); data->ResetCurveButton = gtk_button_new(); gtk_container_add(GTK_CONTAINER(data->ResetCurveButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, GTK_WIDGET(data->ResetCurveButton), "Reset curve to default",NULL); gtk_table_attach(table, GTK_WIDGET(data->ResetCurveButton), 8, 9, 7, 8, 0, 0, 0, 0); g_signal_connect(G_OBJECT(data->ResetCurveButton), "clicked", G_CALLBACK(button_update), NULL); data->BlackLabel = gtk_label_new("Black point: 0.000"); #ifdef HAVE_GTK_2_6 gtk_misc_set_alignment(GTK_MISC(data->BlackLabel), 0.5, 1.0); gtk_label_set_angle(GTK_LABEL(data->BlackLabel), 90); gtk_table_attach(table, data->BlackLabel, 0, 1, 5, 6, 0, GTK_FILL|GTK_EXPAND, 0, 0); #else button = gtk_alignment_new(0, 0, 0, 0); gtk_table_attach(table, button, 0, 1, 5, 6, 0, GTK_FILL|GTK_EXPAND, 0, 0); gtk_misc_set_alignment(GTK_MISC(data->BlackLabel), 0.0, 0.5); gtk_table_attach(table, data->BlackLabel, 1, 8, 8, 9, GTK_FILL, 0, 0, 0); #endif data->ResetBlackButton = gtk_button_new(); gtk_container_add(GTK_CONTAINER(data->ResetBlackButton), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, GTK_WIDGET(data->ResetBlackButton), "Reset black-point to default",NULL); gtk_table_attach(table, GTK_WIDGET(data->ResetBlackButton), 0, 1, 7, 8, 0, GTK_SHRINK, 0, 0); g_signal_connect(G_OBJECT(data->ResetBlackButton), "clicked", G_CALLBACK(button_update), NULL); data->AutoBlackButton = GTK_TOGGLE_BUTTON(gtk_toggle_button_new()); gtk_container_add(GTK_CONTAINER(data->AutoBlackButton), gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON)); gtk_tooltips_set_tip(data->ToolTips, GTK_WIDGET(data->AutoBlackButton), "Auto adjust black-point", NULL); gtk_table_attach(table, GTK_WIDGET(data->AutoBlackButton), 0, 1, 6, 7, 0, 0, GTK_SHRINK, 0); gtk_toggle_button_set_active(data->AutoBlackButton, CFG->autoBlack); g_signal_connect(G_OBJECT(data->AutoBlackButton), "clicked", G_CALLBACK(button_update), NULL); table = GTK_TABLE(table_with_frame(previewVBox, expanderText[live_expander], CFG->expander[live_expander])); event_box = gtk_event_box_new(); gtk_table_attach(table, event_box, 0, 7, 1, 2, 0, 0, 0, 0); pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, live_his_size+2, CFG->liveHistogramHeight+2); data->LiveHisto = gtk_image_new_from_pixbuf(pixbuf); g_object_unref(pixbuf); gtk_container_add(GTK_CONTAINER(event_box), data->LiveHisto); pixies = gdk_pixbuf_get_pixels(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); memset(pixies, 0, (gdk_pixbuf_get_height(pixbuf)-1)* rowstride + gdk_pixbuf_get_width(pixbuf)); menu = gtk_menu_new(); g_object_set_data(G_OBJECT(menu), "Parent-Widget", event_box); g_signal_connect_swapped(G_OBJECT(event_box), "button_press_event", G_CALLBACK(histogram_menu), menu); group = NULL; menu_item = gtk_radio_menu_item_new_with_label(group, "RGB histogram"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 0, 1); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->histogram==rgb_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)rgb_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->histogram); menu_item = gtk_radio_menu_item_new_with_label(group, "R+G+B histogram"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 1, 2); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->histogram==r_g_b_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)r_g_b_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->histogram); menu_item = gtk_radio_menu_item_new_with_label(group, "Luminosity histogram"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 2, 3); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->histogram==luminosity_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)luminosity_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->histogram); menu_item = gtk_radio_menu_item_new_with_label(group, "Value (maximum) histogram"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 3, 4); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->histogram==value_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)value_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->histogram); menu_item = gtk_radio_menu_item_new_with_label(group, "Saturation histogram"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 4, 5); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->histogram==saturation_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)saturation_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->histogram); menu_item = gtk_separator_menu_item_new(); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 5, 6); group = NULL; menu_item = gtk_radio_menu_item_new_with_label(group, "Linear"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 6, 7); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->liveHistogramScale==linear_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)linear_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->liveHistogramScale); menu_item = gtk_radio_menu_item_new_with_label(group, "Logarithmic"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 7, 8); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->liveHistogramScale==log_histogram); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)log_histogram); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->liveHistogramScale); menu_item = gtk_separator_menu_item_new(); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 8, 9); group = NULL; menu_item = gtk_radio_menu_item_new_with_label(group, "96 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 9, 10); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->liveHistogramHeight==96); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)96); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->liveHistogramHeight); menu_item = gtk_radio_menu_item_new_with_label(group, "128 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 10, 11); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->liveHistogramHeight==128); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)128); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->liveHistogramHeight); menu_item = gtk_radio_menu_item_new_with_label(group, "192 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 11, 12); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->liveHistogramHeight==192); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)192); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->liveHistogramHeight); menu_item = gtk_radio_menu_item_new_with_label(group, "256 Pixels"); gtk_menu_attach(GTK_MENU(menu), menu_item, 0, 1, 12, 13); group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menu_item)); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), CFG->liveHistogramHeight==256); g_object_set_data(G_OBJECT(menu_item), "Radio-Value", (gpointer)256); g_signal_connect(G_OBJECT(menu_item), "toggled", G_CALLBACK(radio_menu_update), &CFG->liveHistogramHeight); gtk_widget_show_all(menu); i = 2; data->AvrLabels = color_labels_new(table, 0, i++, "Average:", pixel_format); data->DevLabels = color_labels_new(table, 0, i++, "Std. deviation:", pixel_format); data->OverLabels = color_labels_new(table, 0, i, "Overexposed:", percent_format); toggle_button(table, 4, i, NULL, &CFG->overExp); button = gtk_button_new_with_label("Indicate"); gtk_table_attach(table, button, 6, 7, i, i+1, GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(render_preview_callback), (void *)render_overexposed); g_signal_connect(G_OBJECT(button), "released", G_CALLBACK(render_preview_callback), (void *)render_default); i++; data->UnderLabels = color_labels_new(table, 0, i, "Underexposed:", percent_format); toggle_button(table, 4, i, NULL, &CFG->underExp); button = gtk_button_new_with_label("Indicate"); gtk_table_attach(table, button, 6, 7, i, i+1, GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0); g_signal_connect(G_OBJECT(button), "pressed", G_CALLBACK(render_preview_callback), (void *)render_underexposed); g_signal_connect(G_OBJECT(button), "released", G_CALLBACK(render_preview_callback), (void *)render_default); i++; /* Right side of the preview window */ vBox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(previewHBox, vBox, FALSE, FALSE, 2); align = gtk_alignment_new(0.5, 0.5, 0, 0); gtk_box_pack_start(GTK_BOX(vBox), align, TRUE, TRUE, 0); box = GTK_BOX(gtk_vbox_new(FALSE, 0)); gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(box)); event_box = gtk_event_box_new(); gtk_box_pack_start(box, event_box, FALSE, FALSE, 0); pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, preview_width, preview_height); data->PreviewWidget = gtk_image_new_from_pixbuf(pixbuf); g_object_unref(pixbuf); gtk_container_add(GTK_CONTAINER(event_box), data->PreviewWidget); g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(spot_press), NULL); g_signal_connect(G_OBJECT(event_box), "motion-notify-event", G_CALLBACK(spot_motion), NULL); g_signal_connect(G_OBJECT(event_box), "enter-notify-event", G_CALLBACK(preview_cursor), gdk_cursor_new(GDK_HAND2)); g_signal_connect(G_OBJECT(event_box), "leave-notify-event", G_CALLBACK(preview_cursor), NULL); data->ProgressBar = GTK_PROGRESS_BAR(gtk_progress_bar_new()); gtk_box_pack_start(box, GTK_WIDGET(data->ProgressBar), FALSE, FALSE, 0); box = GTK_BOX(gtk_hbox_new(FALSE, 6)); gtk_box_pack_start(GTK_BOX(vBox), GTK_WIDGET(box), FALSE, FALSE, 6); combo = GTK_COMBO_BOX(gtk_combo_box_new_text()); gtk_combo_box_append_text(combo, "AHD interpolation"); gtk_combo_box_append_text(combo, "VNG interpolation"); gtk_combo_box_append_text(combo, "VNG four color interpolation"); gtk_combo_box_append_text(combo, "Bilinear interpolation"); if (plugin) { gtk_combo_box_append_text(combo, "Half-size interpolation"); } gtk_combo_box_set_active(combo, CFG->interpolation); g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(combo_update), &CFG->interpolation); gtk_box_pack_start(box, GTK_WIDGET(combo), FALSE, FALSE, 0); /* Options button */ align = gtk_alignment_new(0.99, 0.5, 0, 1); gtk_box_pack_start(box, align, TRUE, TRUE, 6); box = GTK_BOX(gtk_hbox_new(TRUE, 6)); gtk_container_add(GTK_CONTAINER(align), GTK_WIDGET(box)); button = gtk_button_new(); hbox = GTK_BOX(gtk_hbox_new(FALSE, 6)); gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(hbox)); gtk_box_pack_start(hbox, gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_BUTTON), FALSE, FALSE, 0); gtk_box_pack_start(hbox, gtk_label_new("Options"), FALSE, FALSE, 0); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(options_dialog), previewWindow); gtk_box_pack_start(box, button, TRUE, TRUE, 0); button = gtk_button_new_from_stock(GTK_STOCK_CANCEL); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(window_response), (gpointer)GTK_RESPONSE_CANCEL); gtk_box_pack_start(box, button, TRUE, TRUE, 0); if (plugin) { saveButton = gtk_button_new_from_stock(GTK_STOCK_OK); gtk_box_pack_start(box, saveButton, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(saveButton), "clicked", G_CALLBACK(preview_saver), uf); gtk_widget_grab_focus(saveButton); } else { saveButton = gtk_button_new_from_stock(GTK_STOCK_SAVE); gtk_box_pack_start(box, saveButton, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(saveButton), "clicked", G_CALLBACK(preview_saver), uf); /* Get the default save options from ufraw_saver() */ char *text = (char *)ufraw_saver(NULL, uf); gtk_tooltips_set_tip(data->ToolTips, saveButton, text, NULL); g_free(text); saveAsButton = gtk_button_new_from_stock(GTK_STOCK_SAVE_AS); gtk_box_pack_start(box, saveAsButton, TRUE, TRUE, 0); g_signal_connect(G_OBJECT(saveAsButton), "clicked", G_CALLBACK(preview_saver), uf); gtk_widget_grab_focus(saveAsButton); } gtk_widget_show_all(previewWindow); gtk_widget_set_sensitive(data->ControlsBox, FALSE); preview_progress(previewWindow, "Loading preview", 0.2); ufraw_load_raw(uf); gtk_widget_set_sensitive(data->ControlsBox, TRUE); shrinkSave = CFG->shrink; sizeSave = CFG->size; CFG->shrink = scale; CFG->size = 0; ufraw_convert_image(data->UF); CFG->shrink = shrinkSave; CFG->size = sizeSave; /* Save InitialChanMul[] for the sake of "Reset WB" */ for (i=0; i<4; i++) data->initialChanMul[i] = CFG->chanMul[i]; /* Update the curve editor in case ufraw_convert_image() modified it. */ curveeditor_widget_set_curve(data->CurveWidget, &CFG->curve[CFG->curveIndex]); if (preview_width!=data->UF->image.width || preview_height!=data->UF->image.height) { pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, data->UF->image.width, data->UF->image.height); gtk_image_set_from_pixbuf(GTK_IMAGE(data->PreviewWidget), pixbuf); g_object_unref(pixbuf); } preview_progress(previewWindow, progressText, 0); data->FreezeDialog = FALSE; update_scales(data); gtk_main(); status = (long)g_object_get_data(G_OBJECT(previewWindow), "WindowResponse"); gtk_container_foreach(GTK_CONTAINER(previewVBox), (GtkCallback)(expander_state), NULL); ufraw_focus(previewWindow, FALSE); gtk_widget_destroy(previewWindow); gtk_object_sink(GTK_OBJECT(data->ToolTips)); /* Make sure that there are no preview idle task remaining */ g_idle_remove_by_data(data); /* In interactive mode outputPath is taken into account only once */ strcpy(uf->conf->outputPath, ""); if (status==GTK_RESPONSE_OK) { if (CFG->saveConfiguration==disabled_state) { /* Restore the original 'image settings' */ conf_copy_image(CFG, &data->SaveConfig); } /* If save 'only this once' was chosen, then so be it */ if (CFG->saveConfiguration==apply_state) CFG->saveConfiguration = disabled_state; conf_save(CFG, NULL, NULL); } else { *CFG = data->SaveConfig; } ufraw_close(data->UF); if (status!=GTK_RESPONSE_OK) return UFRAW_CANCEL; return UFRAW_SUCCESS; }