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();
  

}
openSUSE Build Service is sponsored by