File gui-gtk.c of Package arachne
/*
gui-gtk.c
Author: Hayden Walles
Date: 5 March 2008
GTK+ support for Arachne. This is stuff that was originally in arachne.c but was moved out so that different GUIs could be supported.
*/
/*
Copyright (C) 2007,2008 Hayden Walles
This file is part of Arachne.
Arachne 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.
Arachne 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 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "arachne.h"
gchar *LastPath=NULL;
/*These global variables hold the various icons for the toolbar and application window.*/
extern GdkPixdata ergsminus,ergsminus24,ergsplus,ergsplus24,horzmode,horzmode24,vertmode,vertmode24,origmode,origmode24,ergsnormal,ergsnormal24,arachne48,arachne32,arachne24,arachne16;
GdkPixbuf *ErgsPlus48,*ErgsPlus24,*ErgsMinus48,*ErgsMinus24,*OrigMode48,*OrigMode24,*HorzMode48,*HorzMode24,*VertMode24,*VertMode48,*ErgsNormal24,*ErgsNormal48,*Arachne48,*Arachne32,*Arachne24,*Arachne16;
GtkIconSet *ErgsPlus,*ErgsMinus,*HorzMode,*VertMode,*OrigMode,*ErgsNormal;
GList *ArachneIcons;
/*And this function is called at the start of the program to initialise them.*/
void initIcons(void){
GError *error=NULL;
GtkIconSource *src;
GtkIconFactory *factory;
ErgsPlus48=gdk_pixbuf_from_pixdata(&ergsplus,TRUE,&error);
ErgsPlus24=gdk_pixbuf_from_pixdata(&ergsplus24,TRUE,&error);
ErgsMinus48=gdk_pixbuf_from_pixdata(&ergsminus,TRUE,&error);
ErgsMinus24=gdk_pixbuf_from_pixdata(&ergsminus24,TRUE,&error);
ErgsNormal48=gdk_pixbuf_from_pixdata(&ergsnormal,TRUE,&error);
ErgsNormal24=gdk_pixbuf_from_pixdata(&ergsnormal24,TRUE,&error);
Arachne48=gdk_pixbuf_from_pixdata(&arachne48,TRUE,&error);
Arachne32=gdk_pixbuf_from_pixdata(&arachne32,TRUE,&error);
Arachne24=gdk_pixbuf_from_pixdata(&arachne24,TRUE,&error);
Arachne16=gdk_pixbuf_from_pixdata(&arachne16,TRUE,&error);
HorzMode48=gdk_pixbuf_from_pixdata(&horzmode,TRUE,&error);
HorzMode24=gdk_pixbuf_from_pixdata(&horzmode24,TRUE,&error);
VertMode48=gdk_pixbuf_from_pixdata(&vertmode,TRUE,&error);
VertMode24=gdk_pixbuf_from_pixdata(&vertmode24,TRUE,&error);
OrigMode48=gdk_pixbuf_from_pixdata(&origmode,TRUE,&error);
OrigMode24=gdk_pixbuf_from_pixdata(&origmode24,TRUE,&error);
src=gtk_icon_source_new();
ErgsPlus = gtk_icon_set_new();
ErgsMinus = gtk_icon_set_new();
ErgsNormal = gtk_icon_set_new();
HorzMode = gtk_icon_set_new();
VertMode = gtk_icon_set_new();
OrigMode = gtk_icon_set_new();
gtk_icon_source_set_pixbuf(src,ErgsPlus48);
gtk_icon_set_add_source(ErgsPlus,src);
gtk_icon_source_set_pixbuf(src,ErgsMinus48);
gtk_icon_set_add_source(ErgsMinus,src);
gtk_icon_source_set_pixbuf(src,ErgsNormal48);
gtk_icon_set_add_source(ErgsNormal,src);
gtk_icon_source_set_pixbuf(src,HorzMode48);
gtk_icon_set_add_source(HorzMode,src);
gtk_icon_source_set_pixbuf(src,VertMode48);
gtk_icon_set_add_source(VertMode,src);
gtk_icon_source_set_pixbuf(src,OrigMode48);
gtk_icon_set_add_source(OrigMode,src);
gtk_icon_source_set_pixbuf(src,ErgsPlus24);
gtk_icon_source_set_size_wildcarded(src,FALSE);
gtk_icon_source_set_size(src,GTK_ICON_SIZE_LARGE_TOOLBAR);
gtk_icon_set_add_source(ErgsPlus,src);
gtk_icon_source_set_pixbuf(src,ErgsMinus24);
gtk_icon_set_add_source(ErgsMinus,src);
gtk_icon_source_set_pixbuf(src,ErgsNormal24);
gtk_icon_set_add_source(ErgsNormal,src);
gtk_icon_source_set_pixbuf(src,HorzMode24);
gtk_icon_set_add_source(HorzMode,src);
gtk_icon_source_set_pixbuf(src,VertMode24);
gtk_icon_set_add_source(VertMode,src);
gtk_icon_source_set_pixbuf(src,OrigMode24);
gtk_icon_set_add_source(OrigMode,src);
gtk_icon_source_free(src); /*should free src, oh well.*/
factory = gtk_icon_factory_new();
gtk_icon_factory_add(factory,"arachne_protect",ErgsPlus);
gtk_icon_factory_add(factory,"arachne_expose",ErgsMinus);
gtk_icon_factory_add(factory,"arachne_auto",ErgsNormal);
gtk_icon_factory_add(factory,"arachne_horzmode",HorzMode);
gtk_icon_factory_add(factory,"arachne_vertmode",VertMode);
gtk_icon_factory_add(factory,"arachne_origmode",OrigMode);
gtk_icon_factory_add_default(factory);
/*Now the app icons.*/
ArachneIcons=NULL;
ArachneIcons=g_list_append(ArachneIcons,Arachne16);
ArachneIcons=g_list_append(ArachneIcons,Arachne24);
ArachneIcons=g_list_append(ArachneIcons,Arachne32);
ArachneIcons=g_list_append(ArachneIcons,Arachne48);
/*And that should be that.*/
}
/*These are the callbacks.*/
void menuModeO(GtkWidget *widget, gpointer user){
LOOM *loom=user;
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))){
changeModeO(loom);
}
}
void menuModeV(GtkWidget *widget, gpointer user){
LOOM *loom=user;
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))){
changeModeV(loom);
}
}
void menuModeH(GtkWidget *widget, gpointer user){
LOOM *loom=user;
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))){
changeModeH(loom);
}
}
void toolbarModeO(GtkWidget *widget, gpointer user){
LOOM *loom=user;
if(toolbar_toggle_is_active(widget)){
changeModeO(loom);
}
}
void toolbarModeH(GtkWidget *widget, gpointer user){
LOOM *loom=user;
if(toolbar_toggle_is_active(widget)){
changeModeH(loom);
}
}
void toolbarModeV(GtkWidget *widget, gpointer user){
LOOM *loom=user;
if(toolbar_toggle_is_active(widget)){
changeModeV(loom);
}
}
void menuProtectTool(GtkWidget *widget,gpointer user){
LOOM *sm=user;
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))){
toolbar_deactivate_toggle(sm->exposebtn);
toolbar_deactivate_toggle(sm->clearbtn);
menu_uncheck_item(sm->clearmenu);
menu_uncheck_item(sm->exposemenu);
pickupProtectTool(sm);
}
}
void menuHideTool(GtkWidget *widget,gpointer user){
LOOM *sm=user;
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))){
toolbar_deactivate_toggle(sm->protectbtn);
toolbar_deactivate_toggle(sm->clearbtn);
menu_uncheck_item(sm->protectmenu);
menu_uncheck_item(sm->clearmenu);
pickupHideTool(sm);
}
}
void menuClearTool(GtkWidget *widget,gpointer user){
LOOM *sm=user;
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))){
toolbar_deactivate_toggle(sm->exposebtn);
toolbar_deactivate_toggle(sm->protectbtn);
menu_uncheck_item(sm->protectmenu);
menu_uncheck_item(sm->exposemenu);
pickupClearTool(sm);
}
}
void toolbarProtectTool(GtkWidget *widget,gpointer user){
LOOM *sm=user;
if(toolbar_toggle_is_active(widget)){
toolbar_deactivate_toggle(sm->exposebtn);
toolbar_deactivate_toggle(sm->clearbtn);
menu_uncheck_item(sm->clearmenu);
menu_uncheck_item(sm->exposemenu);
pickupProtectTool(sm);
}
}
void toolbarHideTool(GtkWidget *widget,gpointer user){
LOOM *sm=user;
if(toolbar_toggle_is_active(widget)){
toolbar_deactivate_toggle(sm->protectbtn);
toolbar_deactivate_toggle(sm->clearbtn);
menu_uncheck_item(sm->protectmenu);
menu_uncheck_item(sm->clearmenu);
pickupHideTool(sm);
}
}
void toolbarClearTool(GtkWidget *widget,gpointer user){
LOOM *sm=user;
if(toolbar_toggle_is_active(widget)){
toolbar_deactivate_toggle(sm->exposebtn);
toolbar_deactivate_toggle(sm->protectbtn);
menu_uncheck_item(sm->protectmenu);
menu_uncheck_item(sm->exposemenu);
pickupClearTool(sm);
}
}
void menuDynamicEnergy(GtkWidget *widget, gpointer user){
LOOM *sm=user;
sm->flags&=~LOOM_DYNAMIC_ENERGY;
if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget)))
sm->flags|=LOOM_DYNAMIC_ENERGY;
switchDynamicEnergy(sm);
}
void menuOpen(GtkWidget *widget, gpointer user){
GtkWidget *dialog;
LOOM *loom=user;
int response;
dialog = gtk_file_chooser_dialog_new ("Open File",
loom->window,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER (dialog),TRUE);
if(LastPath!=NULL)
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER (dialog),LastPath);
response=gtk_dialog_run (GTK_DIALOG (dialog));
if(response== GTK_RESPONSE_ACCEPT)
{
char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if(LastPath!=NULL)
g_free(LastPath);
LastPath=gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
gtk_widget_destroy (dialog);
replaceLoomFromFile (loom,filename);
g_free (filename);
}
else
gtk_widget_destroy (dialog);
}
void menuSave(GtkWidget *widget, gpointer user){
GtkWidget *dialog;
LOOM *loom=user;
char scratchname[1024],*dotptr;
int len;
if((loom->mode==LOOM_MODE_ORIG)||(loom->map==NULL)){
guiReportError(loom,"The current image does not differ from the initial image - there is nothing to save.");
return;
}
dialog = gtk_file_chooser_dialog_new ("Save File",
loom->window,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
NULL);
// gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
if(LastPath!=NULL)
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), LastPath);
dotptr=strrchr(loom->filename,'.');
if(dotptr==NULL)
len=strlen(loom->filename);
else
len=dotptr-loom->filename;
if(len>1024-32)
len=1024-32; //give it plenty of room to avoid an overrun.
if(loom->mode==LOOM_MODE_HORZ)
sprintf(scratchname,"%.*s_%dx%d.jpg",len,loom->filename,loom->span,imageHeight(loom->image));
else
sprintf(scratchname,"%.*s_%dx%d.jpg",len,loom->filename,imageWidth(loom->image),loom->span);
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), scratchname);
// gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), loom->filename);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
{
char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
saveLoom(loom,filename);
// save_to_file (filename);
g_free (filename);
}
if(LastPath==NULL)
g_free(LastPath);
LastPath=gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
gtk_widget_destroy (dialog);
}
void menuAbout(GtkWidget *widget, gpointer user){
LOOM *loom = user;
gchar *authors[]={"Hayden Walles",NULL};
if(gtk_check_version(2,12,0)==NULL){
gtk_show_about_dialog (loom->window,
"program-name", "Arachne", /*Later versions use this instead of name.*/
"title", "About Arachne",
"authors",authors,
"copyright","Copyright 2007, 2008 Hayden Walles",
"version",VERSION_STRING,
"website","http://seam-carver.sourceforge.net/",
NULL);
}
else {
gtk_show_about_dialog (loom->window,
"name", "Arachne",
"title", "About Arachne",
"authors",authors,
"copyright","Copyright 2007, 2008 Hayden Walles",
"version",VERSION_STRING,
"website","http://seam-carver.sourceforge.net/",
NULL);
}
}
void menuHelp(GtkWidget *widget, gpointer user){
LOOM *loom = user;
if(!viewHtml(HELP_PATH))
guiReportError(loom,"Unable to start web browser. You can find help at %s\n",HELP_PATH);
}
void mouseDown(GtkWidget *widget, GdkEventButton *event,gpointer user){
LOOM *sm=user;
int x,y;
GdkRectangle rect;
gtk_grab_add(widget);
if((sm->mode==LOOM_MODE_ORIG)&&(sm->tool!=0)){
/*We're in original mode, and we are using some kind of tool.*/
/*Redraw the screen under the new cursor positions so that the guide moves.*/
x=event->x;
y=event->y;
rect.x=x-sm->toolwidth/2;
rect.y=y-sm->toolwidth/2;
rect.width=rect.height=sm->toolwidth;
gdk_window_invalidate_rect(widget->window,&rect,FALSE);
sm->private.oldx=x;
sm->private.oldy=y;
arachneAnnotate(sm,x,y);
}
}
void mouseUp(GtkWidget *widget, GdkEventButton *event,gpointer user){
LOOM *sm=user;
gtk_grab_remove(widget);
}
void mouseMoved(GtkWidget *widget, GdkEventMotion *event, gpointer user){
LOOM *sm=user;
int x,y;
GdkRectangle rect;
int mark;
x=event->x;
y=event->y;
// printf("Mouse moved %d,%d\n",x,y);
if((sm->mode==LOOM_MODE_ORIG)&&(sm->tool!=0)){
/*We're in original mode, and we are using some kind of tool.*/
if((sm->private.oldx!=x)||(sm->private.oldy!=y)){
/*Redraw the screen under the old and new cursor positions so that the guide moves.*/
rect.x=sm->private.oldx-sm->toolwidth/2;
rect.y=sm->private.oldy-sm->toolwidth/2;
rect.width=rect.height=sm->toolwidth;
gdk_window_invalidate_rect(widget->window,&rect,FALSE);
rect.x=x-sm->toolwidth/2;
rect.y=y-sm->toolwidth/2;
rect.width=rect.height=sm->toolwidth;
gdk_window_invalidate_rect(widget->window,&rect,FALSE);
sm->private.oldx=x;
sm->private.oldy=y;
if(event->state&GDK_BUTTON_MASK){
arachneAnnotate(sm,x,y);
}
}
}
}
void mouseArrived(GtkWidget *widget, GdkEventCrossing *event, gpointer user){
LOOM *sm=user;
int x,y;
GdkRectangle rect;
x=event->x;
y=event->y;
// printf("Mouse arrived\n");
if((event->mode==GDK_CROSSING_NORMAL)&&(sm->mode==LOOM_MODE_ORIG)&&(sm->tool!=0)){
/*We're in original mode, and we are using some kind of tool.*/
/*Redraw the screen under the new cursor positions so that the guide appears.*/
rect.x=x-sm->toolwidth/2;
rect.y=y-sm->toolwidth/2;
rect.width=rect.height=sm->toolwidth;
gdk_window_invalidate_rect(widget->window,&rect,FALSE);
sm->private.oldx=x;
sm->private.oldy=y;
}
}
void mouseLeft(GtkWidget *widget, GdkEventCrossing *event, gpointer user){
LOOM *sm=user;
int x,y;
GdkRectangle rect;
x=event->x;
y=event->y;
// printf("Mouse left\n");
if((event->mode==GDK_CROSSING_NORMAL)&&(sm->mode==LOOM_MODE_ORIG)&&(sm->tool!=0)){
/*We're in original mode, and we are using some kind of tool.*/
/*Redraw the screen under the old cursor positions so that the guide disappears.*/
rect.x=sm->private.oldx-sm->toolwidth/2;
rect.y=sm->private.oldy-sm->toolwidth/2;
rect.width=rect.height=sm->toolwidth;
sm->private.oldx=sm->private.oldy=-100;
gdk_window_invalidate_rect(widget->window,&rect,FALSE);
}
}
gboolean resize_view(GtkWidget *widget, GdkEventConfigure *event,gpointer user){
LOOM *sm;
char scratchname[32];
sm=user;
arachneResizeView(sm,event->width,event->height);
// if(preView(sm))
/*Does this line belong here - or should invalidating the rectangle be a generic operation performed from the main program?*/
gdk_window_invalidate_rect(widget->window,NULL,FALSE);
return FALSE;
}
gboolean draw_view(GtkWidget *widget, GdkEventExpose *event,gpointer user){
int w,h;
LOOM *sm;
sm=user;
if(sm->mode==LOOM_MODE_NONE){
return FALSE;
}
else {
w=sm->private.viewwidth;
h=sm->private.viewheight;
}
gdk_draw_rgb_image(widget->window,
widget->style->fg_gc[GTK_STATE_NORMAL],
0,
0,
w,
h,
GDK_RGB_DITHER_NORMAL,
sm->private.view,
w*3);
if((sm->mode==LOOM_MODE_ORIG)&&(sm->tool!=0)){
gdk_draw_rectangle(widget->window,
widget->style->fg_gc[GTK_STATE_NORMAL],
FALSE,
sm->private.oldx-sm->toolwidth/2,
sm->private.oldy-sm->toolwidth/2,
sm->toolwidth-1, //unfilled rectangles are drawn one pixel wider than the dimensions specified.
sm->toolwidth-1);
}
return TRUE;
}
/*End of callbacks.*/
/*This is called by addLoomFromFile, to initialise GUI specific elements of the new LOOM.*/
int guiInitialiseLoom(LOOM *new){
GtkHBox *hbox;
GtkVBox *vbox;
GtkToolbar *toolbar;
GtkToolItem *modehbutton,*modevbutton,*modeorigbutton;
GtkToolItem *sep;
GtkToolItem *protectbutton,*hidebutton,*normalbutton;
GtkMenuBar *menubar,*filemenu,*optionsmenu,*modemenu;
GtkWidget *item,*menu;
GtkStatusbar *status;
char scratchname[256];
/*This is very messy, and there is no error checking at all.*/
new->private.view=NULL;
new->window=GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
g_signal_connect (new->window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_window_set_icon_list(new->window,ArachneIcons);
menubar=GTK_MENU_BAR(gtk_menu_bar_new());
/*File menu*/
menu=gtk_menu_new();
item = gtk_menu_item_new_with_mnemonic("_Open...");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "activate",
G_CALLBACK (menuOpen), new);
item = gtk_menu_item_new_with_mnemonic("Save _As...");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "activate",
G_CALLBACK (menuSave), new);
item = gtk_menu_item_new_with_mnemonic("_Quit");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "activate",
G_CALLBACK(gtk_main_quit), NULL);
item = gtk_menu_item_new_with_mnemonic("_File");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),item);
/*Mode menu*/
menu=gtk_menu_new();
item = gtk_radio_menu_item_new_with_mnemonic(NULL,"_Width");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "toggled",
G_CALLBACK (menuModeH), new);
new->horzmodemenu=item;
item = gtk_radio_menu_item_new_with_mnemonic(gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item)),"_Height");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "toggled",
G_CALLBACK (menuModeV), new);
new->vertmodemenu=item;
item = gtk_radio_menu_item_new_with_mnemonic(gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item)),"_Original");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "toggled",
G_CALLBACK (menuModeO), new);
new->origmodemenu=item;
item = gtk_menu_item_new_with_mnemonic("_Mode");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),item);
/*Tools menu.*/
menu=gtk_menu_new();
item = gtk_check_menu_item_new_with_mnemonic("_Protect");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "toggled",
G_CALLBACK (menuProtectTool), new);
new->protectmenu=item;
item = gtk_check_menu_item_new_with_mnemonic("_Expose");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "toggled",
G_CALLBACK (menuHideTool), new);
new->exposemenu=item;
item = gtk_check_menu_item_new_with_mnemonic("_Clear");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "toggled",
G_CALLBACK (menuClearTool), new);
new->clearmenu=item;
item = gtk_menu_item_new_with_mnemonic("_Tools");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),item);
/*Options menu.*/
menu=gtk_menu_new();
item = gtk_check_menu_item_new_with_mnemonic("_Dynamic Energy");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "toggled",
G_CALLBACK (menuDynamicEnergy), new);
item = gtk_menu_item_new_with_mnemonic("_Options");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),item);
/*Help menu.*/
menu=gtk_menu_new();
item = gtk_menu_item_new_with_mnemonic("_Help");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "activate",
G_CALLBACK (menuHelp), new);
item = gtk_menu_item_new_with_mnemonic("_About");
gtk_menu_shell_append(GTK_MENU_SHELL(menu),item);
g_signal_connect (item, "activate",
G_CALLBACK (menuAbout), new);
item = gtk_menu_item_new_with_mnemonic("_Help");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),menu);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar),item);
/*That's the menu's done.*/
new->private.drawable = GTK_DRAWING_AREA(gtk_drawing_area_new());
if(new->filename==NULL){
gtk_widget_set_size_request(GTK_WIDGET(new->private.drawable),512,256); //make sure no resizing goes on for the moment.
gtk_window_set_default_size(new->window,512,256);
}
else {
gtk_widget_set_size_request(GTK_WIDGET(new->private.drawable),imageWidth(new->image),imageHeight(new->image)); //make sure no resizing goes on for the moment.
gtk_window_set_default_size(new->window,imageWidth(new->image),imageHeight(new->image));
}
gtk_widget_add_events(GTK_WIDGET(new->private.drawable),GDK_POINTER_MOTION_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_ENTER_NOTIFY_MASK|GDK_BUTTON_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK);
g_signal_connect (new->private.drawable, "motion-notify-event",
G_CALLBACK (mouseMoved), new);
g_signal_connect (new->private.drawable, "leave-notify-event",
G_CALLBACK (mouseLeft), new);
g_signal_connect (new->private.drawable, "enter-notify-event",
G_CALLBACK (mouseArrived), new);
g_signal_connect (new->private.drawable, "button-press-event",
G_CALLBACK (mouseDown), new);
g_signal_connect (new->private.drawable, "button-release-event",
G_CALLBACK (mouseUp), new);
vbox=GTK_VBOX(gtk_vbox_new(FALSE,1));
// hbox=GTK_HBOX(gtk_hbox_new(FALSE,1));
gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(menubar),FALSE,FALSE,0);
toolbar=GTK_TOOLBAR(gtk_toolbar_new());
new->private.progress=GTK_PROGRESS_BAR(gtk_progress_bar_new());
// gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(toolbar),TRUE,TRUE,0);
modehbutton=gtk_radio_tool_button_new_from_stock(NULL,"arachne_horzmode");
gtk_tool_button_set_label(GTK_TOOL_BUTTON(modehbutton),"Width");
g_signal_connect(modehbutton,"toggled",G_CALLBACK(toolbarModeH),new);
modevbutton=gtk_radio_tool_button_new_from_stock(gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(modehbutton)),"arachne_vertmode");
gtk_tool_button_set_label(GTK_TOOL_BUTTON(modevbutton),"Height");
g_signal_connect(modevbutton,"toggled",G_CALLBACK(toolbarModeV),new);
modeorigbutton=gtk_radio_tool_button_new_from_stock(gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(modehbutton)),"arachne_origmode");
gtk_tool_button_set_label(GTK_TOOL_BUTTON(modeorigbutton),"Original");
g_signal_connect(modeorigbutton,"toggled",G_CALLBACK(toolbarModeO),new);
gtk_toolbar_insert(toolbar,GTK_TOOL_ITEM(modehbutton),0);
gtk_toolbar_insert(toolbar,GTK_TOOL_ITEM(modevbutton),-1);
gtk_toolbar_insert(toolbar,GTK_TOOL_ITEM(modeorigbutton),-1);
sep=gtk_separator_tool_item_new();
gtk_toolbar_insert(toolbar,GTK_TOOL_ITEM(sep),-1);
protectbutton=gtk_toggle_tool_button_new_from_stock("arachne_protect");
gtk_tool_button_set_label(GTK_TOOL_BUTTON(protectbutton),"Protect");
g_signal_connect(protectbutton,"toggled",G_CALLBACK(toolbarProtectTool),new);
hidebutton=gtk_toggle_tool_button_new_from_stock("arachne_expose");
gtk_tool_button_set_label(GTK_TOOL_BUTTON(hidebutton),"Expose");
g_signal_connect(hidebutton,"toggled",G_CALLBACK(toolbarHideTool),new);
normalbutton=gtk_toggle_tool_button_new_from_stock("arachne_auto");
gtk_tool_button_set_label(GTK_TOOL_BUTTON(normalbutton),"Clear");
g_signal_connect(normalbutton,"toggled",G_CALLBACK(toolbarClearTool),new);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar),GTK_TOOL_ITEM(protectbutton),-1);
gtk_toolbar_insert(toolbar,GTK_TOOL_ITEM(hidebutton),-1);
gtk_toolbar_insert(toolbar,GTK_TOOL_ITEM(normalbutton),-1);
// gtk_box_pack_end(hbox,new->private.progress,TRUE,TRUE,0);
gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(toolbar),FALSE,TRUE,0);
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(modeorigbutton),TRUE);
new->horzmodebtn=GTK_WIDGET(modehbutton);
new->vertmodebtn=GTK_WIDGET(modevbutton);
new->origmodebtn=GTK_WIDGET(modeorigbutton);
new->protectbtn=GTK_WIDGET(protectbutton);
new->exposebtn=GTK_WIDGET(hidebutton);
new->clearbtn=GTK_WIDGET(normalbutton);
if(new->filename==NULL)
sprintf(scratchname,"Arachne");
else
sprintf(scratchname,"Arachne - %.220s\n",new->filename); //a bit risky.
gtk_window_set_title(new->window,scratchname);
g_signal_connect(new->private.drawable,"expose_event",G_CALLBACK(draw_view),new);
g_signal_connect(new->private.drawable,"configure_event",G_CALLBACK(resize_view),new);
status=GTK_STATUSBAR(gtk_statusbar_new());
gtk_statusbar_set_has_resize_grip(status,FALSE);
gtk_box_pack_end(GTK_BOX(status),GTK_WIDGET(new->private.progress),FALSE,FALSE,0);
new->private.statusbar=status;
new->private.statuscontext=gtk_statusbar_get_context_id(status,"Size");
// gtk_box_pack_end(GTK_BOX(vbox),GTK_WIDGET(new->private.progress),FALSE,FALSE,0);
gtk_box_pack_end(GTK_BOX(vbox),GTK_WIDGET(status),FALSE,FALSE,0);
gtk_box_pack_end(GTK_BOX(vbox),GTK_WIDGET(new->private.drawable),TRUE,TRUE,0);
gtk_container_add(GTK_CONTAINER(new->window),GTK_WIDGET(vbox));
//if(new->filename==NULL){
// setModeWidgets(new,FALSE);
// setToolWidgets(new,FALSE);
// }
gtk_widget_show_all(GTK_WIDGET(new->window));
}
int guiReloadLoom(LOOM *new){
char *slashptr;
char scratchname[256];
if(new->private.view!=NULL)
free(new->private.view);
new->private.view=NULL;
slashptr=strrchr(new->filename,'/');
if(slashptr==NULL)
slashptr=new->filename;
else
slashptr++;
sprintf(scratchname,"Arachne - %.220s\n",slashptr); //a bit risky.
gtk_window_set_title(new->window,scratchname);
gtk_window_resize(new->window,imageWidth(new->image),imageHeight(new->image));
}
void guiReportError(LOOM *loom,char *fmt, ...){
va_list ap;
char *msg;
GtkWindow *win;
// GtkMessageDialog *dlg;
GtkWidget *dlg;
if(loom==NULL)
win=NULL;
else
win=loom->window;
va_start(ap,fmt);
if(vasprintf(&msg,fmt,ap)<0){
vfprintf(stderr,fmt,ap);
fprintf(stderr,"Ran out of memory. Exiting\n");
exit(1);
}
dlg=gtk_message_dialog_new(win,
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
msg);
free(msg);
gtk_dialog_run(GTK_DIALOG(dlg));
gtk_widget_destroy(dlg);
return;
}
void guiSetStatus(LOOM *loom,char *fmt, ...){
va_list ap;
char *msg;
GtkWindow *win;
// GtkMessageDialog *dlg;
GtkWidget *dlg;
win=loom->window;
va_start(ap,fmt);
if(vasprintf(&msg,fmt,ap)<0){
guiReportError(loom,"Out of memory.\n");
}
gtk_statusbar_pop(loom->private.statusbar,loom->private.statuscontext);
gtk_statusbar_push(loom->private.statusbar,loom->private.statuscontext,msg);
free(msg);
}
int guiPrepareView(LOOM *loom, int width, int height){
loom->private.viewwidth=width;
loom->private.viewheight=height;
if((loom->private.view=realloc(loom->private.view,sizeof(guchar)*width*height*3))==NULL){
guiReportError(loom,"Out of memory.");
return 0;
}
return 1;
}
/*This is called at the end of preview.*/
void guiUpdateView(LOOM *loom){
gdk_window_invalidate_rect(GTK_WIDGET(loom->private.drawable)->window,NULL,FALSE);
}
void guiClearWaiting(void){
while (gtk_events_pending ())
gtk_main_iteration ();
}
void guiSetWindowMinimum(LOOM *loom, int minwidth, int minheight){
gtk_widget_set_size_request(GTK_WIDGET(loom->private.drawable),minwidth,minheight);
}
void guiBeginComputation(LOOM *loom){
gtk_widget_set_sensitive(GTK_WIDGET(loom->window),FALSE);
}
void guiEndComputation(LOOM *loom){
gtk_widget_set_sensitive(GTK_WIDGET(loom->window),TRUE);
}
int main(int argc, char **argv){
gtk_init(&argc,&argv);
initIcons();
arachneStart(argc, argv);
gtk_main();
}