/*************************************************************************
*
* GTK Euler
*
*************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/times.h>
#include <time.h>
#include <dirent.h>
#include <fnmatch.h>
#include <locale.h>
#include "../pixmaps/icon.xpm"
#include "../pixmaps/logo.xpm"
#ifdef RS6000
#include <sys/time.h>
void gettimer (int, struct timestruc_t *);
#endif
#include "sysdep.h"
#include "mainloop.h"
#include "help.h"
#include "rc.h"
#include "term.h"
#include "metagtk.h"
#include "metaps.h"
#include "output.h"
#include "earray.h"
/*-----------------------------------------------------------------------
* Global variables
*----------------------------------------------------------------------*/
static int is_demo = 0;
static int in_text = 1;
static EulerPrefs prefs;
static GtkWidget *term_window = NULL;
static GtkWidget *term;
static GtkWidget *meta_window = NULL;
static GtkWidget *meta;
/*-----------------------------------------------------------------------
* Euler callbacks
*----------------------------------------------------------------------*/
/* text_mode
* Switch to text. Graphics should not be deleted.
* On a window system make text visible.
*/
void text_mode (void)
{
if (!in_text)
{
in_text=1;
gdk_window_raise(term_window->window);
}
}
/* graphic_mode
* Switch to graphics. Text must not be deleted.
* On a window system make graphics visible.
*/
void graphic_mode (void)
{
if (in_text)
{
in_text=0;
gdk_window_raise(meta_window->window);
}
}
/************************************************************************
*
* Graphic window
*
* The graphic screen has coordinates from 0.0 to 1024.0 (double).
* There should be a function, which computes the correct screen
* coordinates from these internal ones.
*
************************************************************************/
int usecolors=1;
/* getpixelsize
* Compute the size of pixel in screen coordinates.
*/
void getpixelsize (double *x, double *y)
{
*x=1024.0/meta->allocation.width;
*y=1024.0/meta->allocation.height;
}
/* gflush
* Flush out remaining graphic commands (for multitasking).
* This serves to synchronize the graphics on multitasking systems.
*/
void gflush (void)
{
}
/*
* S O U N D W A V E S
*/
#ifdef WAVES
void sys_playwav (char *file)
{
}
#endif
/*
* G R A P H I C I N P U T
*/
/* mouse
* wait, until the user marked a screen point with the mouse.
* Return screen coordinates.
*/
void mouse (double *x, double *y)
{
while (1)
{
if (gdk_events_pending())
{
GtkMeta *m = GTK_META(meta);
gtk_main_iteration();
if (m->x>0.0 && m->y>0.0)
{
*x=m->x;
*y=m->y;
m->x = m->y = -1.0;
return;
}
else
{
GtkTerm *t = GTK_TERM(term);
if (t->scan==escape)
{
*x=-1.0; *y=-1.0; return;
}
t->scan = t->code = 0;
}
}
else usleep(1);
}
}
static int notekey=0;
/* test_key
* see, if user pressed the keyboard.
* return the scancode, if he did.
*/
int test_key ()
{
while (gtk_events_pending())
{
GtkTerm *t = GTK_TERM(term);
gtk_main_iteration();
if (t->scan==escape) {
t->scan = t->code = 0;
return escape;
} else {
if (t->scan) notekey=t->scan;
else notekey=t->code;
t->scan = t->code = 0;
return 0;
}
}
return 0;
}
int test_code (void)
{
int key=0;
if (notekey)
{ key=notekey;
notekey=0;
return key;
}
while (gtk_events_pending())
{
GtkTerm *t=GTK_TERM(term);
gtk_main_iteration();
if (t->scan) {
key = t->scan;
t->scan = t->code = 0;
return key;
} else if (t->code) {
key = t->code;
t->scan = t->code = 0;
return key;
}
}
return 0;
}
/************************************************************************
*
* Text Window
*
* The following text screen commands should be emulated on a graphic
* work station. This can be done by a standard emulator (e.g. VT100)
* or within a window displaying the text. Additional features may be
* added, such as viewing old text. But the input line should be
* visible as soon as a key is pressed by the user.
*
************************************************************************/
/* Clear the text screen */
void clear_screen (void)
{
gtk_term_clear(term);
}
/* Print a line onto the text screen, parse tabs and '\n'.
* Printing should be done at the cursor position. There is no need
* to clear the line at a '\n'.
* The cursor should move forward with the print.
* Think of the function as a simple emulator.
* If you have a line buffered input with echo then do not print,
* when the command line is on.
*/
void gprint (char *s) /* print an output text (no newline) */
{
gtk_term_print(term,s);
}
/* wait for a keystroke. return the scancode and the ascii code.
* scancode should be a code from scantyp. Do at least generate
* 'enter'.
*/
gboolean forcebreak = FALSE;
int wait_key (int *scan)
{
int key;
GtkTerm *t = GTK_TERM(term);
t->scan = t->code = 0;
*scan=0;
while (!forcebreak) {
if (gtk_events_pending())
{
gtk_main_iteration();
if (t->scan || t->code) break;
t->scan = t->code = 0;
}
else usleep(1);
}
if (forcebreak){
t->scan = enter;
e_insert(t->history,e_get_length(t->history)-1,e_get_text(t->a,t->cur)+t->promptlen,0);
if (e_get_length(t->history) > t->max_history)
e_remove(t->history,0);
t->hist=e_get_length(t->history)-1;
set_editline(e_get_text(t->a,t->cur)+t->promptlen);
key = 0;
forcebreak = FALSE;
}
else
key = t->code;
*scan = t->scan;
t->scan = t->code = 0;
return key;
}
/* the command line is active (edit.c) */
void edit_on (void)
{
gtk_term_edit_on(term);
}
/* the command line is no longer in use (graphics or computing) (edit.c) */
void edit_off (void)
{
gtk_term_edit_off(term);
}
/************************************************************************
*
* System
*
************************************************************************/
static char path[256];
/* sets the path if dir!=0 and returns the path */
char *cd (char *dir)
{
chdir(dir);
if (getcwd(path,256)) return path;
return dir;
}
static void shellsort(char **buf, int n)
{
int h, i, j;
int seq[28];
int p1=1, p2=1, p3=1, s=-1;
/*
* establish increment sequence (see Knuth, Vol 3)
*/
do {
if (++s % 2) {
seq[s] = 8*p1 - 6*p2 + 1;
} else {
seq[s] = 9*p1 - 9*p3 + 1;
p2 *= 2;
p3 *= 2;
}
p1 *= 2;
} while(3*seq[s] < n);
s = s > 0 ? s-1 : 0;
/*
* sort
*/
while (s >= 0) {
/* sort-by-insertion in increments of h */
h = seq[s--];
for (i = h; i<n; i++) {
char *t = buf[i];
for (j = i-h; j >= 0 && strcmp(buf[j], t)>0; j -= h)
buf[j+h] = buf[j];
buf[j+h] = t;
}
}
}
static int match (char *pat, char *s)
{ if (*pat==0) return *s==0;
if (*pat=='*')
{ pat++;
if (!*pat) return 1;
while (*s)
{ if (match(pat,s)) return 1;
s++;
}
return 0;
}
if (*s==0) return 0;
if (*pat=='?') return match(pat+1,s+1);
if (*pat!=*s) return 0;
return match(pat+1,s+1);
}
/*
* scan a directory and get :
* files : an array of entries matching the pattern
* files_count : number of files entries
* the function returns the max length of a file entry
*/
int scan_dir(char *dir_name, char *pat, char ** files[], int *files_count)
{
DIR *dir;
struct dirent *entry;
int entry_count=0, len=0;
char **buf = NULL;
dir = opendir(dir_name);
if (dir) {
while((entry = readdir(dir)) != NULL) {
if (match(pat,entry->d_name)) {
int l=strlen(entry->d_name);
len = MAX(len,l);
entry_count ++;
buf = (char**)realloc(buf,entry_count*sizeof(char *));
buf[entry_count-1]=(char*)malloc(l+1);
strcpy(buf[entry_count-1],entry->d_name);
}
}
closedir(dir);
shellsort(buf, entry_count);
}
*files = buf;
*files_count = entry_count;
return len;
}
/* execute
* Call an external program, return 0, if there was no error.
* No need to support this on multitasking systems.
*/
int execute (char *dir, char *progname)
{
return 0;
}
/* shrink
* allows shrinking of memory for single task systems.
* simply return 1 if you do not support this or set NOSHRINK in funcs.c
*/
int shrink (size_t size)
{
return 1;
}
/* myclock
* define a timer in seconds.
*/
double myclock (void)
{
#ifdef RS6000
struct timestruc_t t;
gettimer(TIMEOFDAY,&t);
return (t.tv_sec+t.tv_nsec/1000000000.0);
#else
return ((double)(times(NULL)))/CLK_TCK;
#endif
}
/* sys_wait
* Wait for time seconds or until a key press.
* Return the scan code or 0 (time exceeded).
*/
void sys_wait (double delay, int *scan)
{
double now;
GtkTerm *t = GTK_TERM(term);
now=myclock();
*scan=0;
t->scan = t->code = 0;
while (myclock()<now+delay)
{
while (gtk_events_pending())
{
gtk_main_iteration();
if (t->scan) {
*scan = notekey = t->scan;
t->scan = t->code = 0;
} else if (t->code) {
*scan = notekey = t->code;
t->scan = t->code = 0;
}
}
if (*scan==switch_screen)
{ if (in_text)
{ graphic_mode();
wait_key(scan);
text_mode();
}
else
{ text_mode();
wait_key(scan);
graphic_mode();
}
*scan=0;
}
if (*scan) return;
usleep(1);
}
*scan=0;
}
/* stack_init
* get memory for stack.
*/
static int stack_init (long size)
{
ramstart = (char *)malloc(size*1024l);
if (!ramstart) return 0; /* fail */
ramend = ramstart+size*1024l;
return 1; /* success */
}
static void save_rc()
{
if (prefs.saveatexit) eulerrc_save(&prefs);
}
static void euler_exit()
{
save_rc();
exit(0);
}
/*-----------------------------------------------------------------------
* GTK things
*----------------------------------------------------------------------*/
static void destroy_yesno_dialog(GtkWidget *widget)
{
if (widget) {
GtkWidget *dialog = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "dialog");
gtk_widget_destroy(dialog);
}
}
static char* get_filename(gpointer data, char *prefix)
{
char *filename;
char *newname;
GtkWidget *filechooser = (GtkWidget*)data;
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
if (!g_str_has_suffix(filename, prefix))
newname = g_strdup_printf("%s%s", filename, prefix);
else
newname = g_strdup(filename);
return newname;
}
static void infobox(GtkWidget *parent, char *text)
{
GtkWidget * dialog;
GtkWidget * hbox;
GtkWidget * icon;
GtkWidget * label;
GtkWidget * button;
dialog = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog),"Information");
gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(parent));
gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_MOUSE);
g_signal_connect(G_OBJECT(dialog),"delete_event",G_CALLBACK(gtk_widget_destroy),NULL);
g_signal_connect(G_OBJECT(dialog),"destroy",G_CALLBACK(gtk_widget_destroy),NULL);
gtk_widget_realize(dialog);
hbox = gtk_hbox_new(FALSE,10);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),hbox,TRUE,TRUE,0);
icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
gtk_box_pack_start(GTK_BOX(hbox),icon,FALSE,FALSE,0);
label = gtk_label_new(text);
gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
gtk_box_pack_start(GTK_BOX(hbox),label,TRUE,TRUE,0);
/*
* setup the buttons (Yes, No and Cancel)
*/
button = gtk_button_new_from_stock(GTK_STOCK_OK);
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
g_signal_connect_swapped(G_OBJECT(button),"clicked",G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0);
gtk_widget_grab_default(button);
gtk_widget_show_all(dialog);
}
static void yesnoquestion(char *text, GCallback yes_cb, GCallback no_cb, GtkWidget *window)
{
GtkWidget * dialog;
GtkWidget * hbox;
GtkWidget * icon;
GtkWidget * label;
GtkWidget * button;
dialog = gtk_dialog_new();
gtk_window_set_title(GTK_WINDOW(dialog),"Question");
gtk_window_set_transient_for(GTK_WINDOW(dialog),GTK_WINDOW(window));
gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_window_set_position(GTK_WINDOW(dialog),GTK_WIN_POS_CENTER_ON_PARENT);
g_signal_connect(G_OBJECT(dialog),"delete_event",
G_CALLBACK(gtk_widget_destroy),NULL);
g_signal_connect(G_OBJECT(dialog),"destroy",
G_CALLBACK(gtk_widget_destroy),NULL);
gtk_widget_realize(dialog);
hbox = gtk_hbox_new(FALSE,10);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),hbox,TRUE,TRUE,0);
icon = gtk_image_new_from_stock(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
gtk_box_pack_start(GTK_BOX(hbox),icon,FALSE,FALSE,0);
label = gtk_label_new(text);
gtk_label_set_justify(GTK_LABEL(label),GTK_JUSTIFY_LEFT);
gtk_box_pack_start(GTK_BOX(hbox),label,TRUE,TRUE,0);
/*
* setup the buttons (Yes, No and Cancel)
*/
button = gtk_button_new_from_stock(GTK_STOCK_YES);
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
g_object_set_data(G_OBJECT(button), "dialog", (gpointer) dialog);
if (GTK_IS_FILE_CHOOSER(window))
g_signal_connect(G_OBJECT(button),"clicked",
G_CALLBACK(yes_cb),window);
else
g_signal_connect(G_OBJECT(button),"clicked",
G_CALLBACK(yes_cb),NULL);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0);
gtk_widget_grab_default(button);
button = gtk_button_new_from_stock(GTK_STOCK_NO);
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
g_object_set_data(G_OBJECT(button), "dialog", (gpointer) dialog);
if (no_cb)
g_signal_connect(G_OBJECT(button),"clicked",
G_CALLBACK(no_cb),NULL);
else
g_signal_connect_swapped(G_OBJECT(button),"clicked",
G_CALLBACK(gtk_widget_destroy),dialog);
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0);
button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
GTK_WIDGET_SET_FLAGS(button,GTK_CAN_DEFAULT);
if (GTK_IS_FILE_CHOOSER(window))
g_signal_connect_swapped(G_OBJECT(button),"clicked",
G_CALLBACK(gtk_widget_destroy),window);
g_signal_connect_swapped(G_OBJECT(button),"clicked",
G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog));
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area),button,TRUE,TRUE,0);
gtk_widget_show_all(dialog);
}
/*-----------------------------------------------------------------------
* About box
*----------------------------------------------------------------------*/
void activate_url(GtkAboutDialog *about, const gchar *url, gpointer data)
{
char *browser;
browser = g_strconcat(prefs.browser," ",url," &", NULL);
system(browser);
g_free(browser);
}
static void about()
{
GtkWidget *aboutdialog;
GdkPixbuf *buff;
const gchar *authors[] = {"Rene Grothmann <grothm@ku-eichstaett.de>",
"Eric Boucharé <bouchare.eric@wanadoo.fr>",
"Puji Prasetiyo <aripujiprasetiyo@yahoo.com>",
NULL
};
aboutdialog = gtk_about_dialog_new ();
buff = gdk_pixbuf_new_from_xpm_data((const char**) logo_xpm);
gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (aboutdialog), buff);
gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (aboutdialog), VERSION);
gtk_about_dialog_set_name (GTK_ABOUT_DIALOG (aboutdialog), "Euler");
gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (aboutdialog),
"Copyright © 2001,2005 Rene Grothmann, Eric Boucharé, Puji Prasetiyo");
gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (aboutdialog),
"EULER is a program for quickly and interactively\n"
"computing with real and complex numbers and\n"
"matrices, or with intervals. It can draw your\n"
"functions in two and three dimensions");
gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (aboutdialog), authors);
gtk_about_dialog_set_url_hook (activate_url, NULL, NULL);
gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (aboutdialog), "http://euler.sourceforge.net");
gtk_about_dialog_set_license(GTK_ABOUT_DIALOG (aboutdialog),
"This program is free software; you can redistribute it and/or\n"
"modify it under the terms of the GNU Library General Public License as\n"
"published by the Free Software Foundation; either version 2 of the\n"
"License, or (at your option) any later version.\n"
"\n"
"This library is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
"Library General Public License for more details.\n"
"\n"
"You should have received a copy of the GNU Library General Public\n"
"License along with the Gnome Library; see the file COPYING.LIB. If not,\n"
"write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
"Boston, MA 02111-1307, USA.\n");
gtk_dialog_run (GTK_DIALOG(aboutdialog));
gtk_widget_destroy (aboutdialog);
}
/*---------------------------------------------------------------------------
* preference box
*---------------------------------------------------------------------------*/
static GtkWidget * estack;
static GtkWidget * gstack;
static GtkWidget * glines;
static GtkWidget * browser;
static GtkWidget * color_button[16];
static GtkWidget * atexitbut;
static GtkWidget * fontbutton;
static GtkWidget * editordialog;
static GtkWidget * etextview;
static short def_colors[3][MAX_COLORS] = {
{255,0,100,0 ,0 ,0 ,100,150,100,50,220 ,80 ,80 ,80 ,140,190},
{255,0,0 ,100,0 ,100,100,150,100,50,80 ,220 ,80 ,140 ,140,190},
{255,0,0 ,0 ,100,100, 0,150,100,50,80 ,80 ,220 ,140 , 80,190}
};
static void prefs_apply_cb(GtkWidget *widget, gpointer data)
{
int val, i, j, changed = 0;
const gchar *pfont = NULL;
val = atol(gtk_entry_get_text(GTK_ENTRY(estack)));
if (val) prefs.estack = val;
val = atol(gtk_entry_get_text(GTK_ENTRY(gstack)));
if (val) prefs.gstack = val;
val = atol(gtk_entry_get_text(GTK_ENTRY(glines)));
pfont = gtk_font_button_get_font_name(GTK_FONT_BUTTON(fontbutton));
if (pfont) {
strcpy(prefs.pfont,pfont);
if (editordialog)
gtk_widget_modify_font(etextview, pango_font_description_from_string(pfont));
}
if (val) {
prefs.glines = val;
setmetalines(prefs.glines);
gtk_meta_update_lines(meta);
}
for (i=0 ; i<16 ; i++) {
GdkColor gcolor;
short color[3];
gtk_color_button_get_color(GTK_COLOR_BUTTON(color_button[i]),&gcolor);
color[0] = gcolor.red>>8;
color[1] = gcolor.green>>8;
color[2] = gcolor.blue>>8;
for (j=0 ; j<3 ; j++)
if (prefs.colors[j][i]!=color[j]) {
prefs.colors[j][i]=color[j];
changed =1;
}
}
if (changed) {
setmetacolors(prefs.colors);
gtk_meta_update_colors(meta);
}
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(atexitbut)))
prefs.saveatexit = 1;
else
prefs.saveatexit = 0;
if (strlen(gtk_entry_get_text(GTK_ENTRY(browser))))
strcpy(prefs.browser,gtk_entry_get_text(GTK_ENTRY(browser)));
}
static void prefs_ok_cb(GtkWidget *widget, gpointer data)
{
prefs_apply_cb(widget,data);
}
static void prefs_reset_cb(GtkWidget *widget, gpointer data)
{
GdkColor color;
char *s;
int i;
gtk_entry_set_text(GTK_ENTRY(browser),E_BROWSER_DEFAULT);
s = g_strdup_printf("%ld",E_ESTACK_DEFAULT);
gtk_entry_set_text(GTK_ENTRY(estack),s);
g_free(s);
s = g_strdup_printf("%ld",E_GSTACK_DEFAULT);
gtk_entry_set_text(GTK_ENTRY(gstack),s);
g_free(s);
s = g_strdup_printf("%d",E_GLINES_DEFAULT);
gtk_entry_set_text(GTK_ENTRY(glines),s);
g_free(s);
s = g_strdup_printf("%s",E_PFONT_DEFAULT);
gtk_font_button_set_font_name(GTK_FONT_BUTTON(fontbutton),s);
g_free(s);
for (i=0 ; i<16 ; i++) {
color.red = ((gushort)def_colors[0][i])<<8;
color.green = ((gushort)def_colors[1][i])<<8;
color.blue = ((gushort)def_colors[2][i])<<8;
gtk_color_button_set_color(GTK_COLOR_BUTTON(color_button[i]), &color);
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(atexitbut),TRUE);
}
static void prefs_box()
{
GtkWidget *dialog;
GtkWidget *notebook;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *alignment;
GtkWidget *table;
GtkWidget *hbox;
GtkWidget *pref_vbox;
GtkWidget *vbox;
GtkWidget *button;
int i;
char *s;
dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (G_OBJECT(dialog),"delete_event",
G_CALLBACK(gtk_widget_destroy),NULL);
g_signal_connect (G_OBJECT(dialog),"destroy",
G_CALLBACK(gtk_widget_destroy),NULL);
gtk_window_set_title (GTK_WINDOW (dialog), "Preferences ...");
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
pref_vbox = gtk_vbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (dialog), pref_vbox);
gtk_container_set_border_width (GTK_CONTAINER (pref_vbox), 5);
notebook = gtk_notebook_new ();
gtk_box_pack_start (GTK_BOX (pref_vbox), notebook, TRUE, TRUE, 0);
frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (notebook), frame);
gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
alignment = gtk_alignment_new (0, 0, 0, 0);
gtk_container_add (GTK_CONTAINER (frame), alignment);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (alignment), vbox);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
label = gtk_label_new ("You can setup the memory size of the stack used for calculation. This will be effective on Euler restart.");
gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
label = gtk_label_new ("Stack memory (KB) :");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
label = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
estack = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), estack, FALSE, TRUE, 0);
s = g_strdup_printf("%d",prefs.estack);
gtk_entry_set_text(GTK_ENTRY(estack),s);
g_free(s);
label = gtk_label_new ("You can setup the memory size of the buffer used for graphics. This will be effective on Euler][ restart.");
gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
hbox = gtk_hbox_new (FALSE, 5);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
label = gtk_label_new ("Graphics buffer (KB) :");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
label = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
gstack = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), gstack, FALSE, TRUE, 0);
s = g_strdup_printf("%d",prefs.gstack);
gtk_entry_set_text(GTK_ENTRY(gstack),s);
g_free(s);
label = gtk_label_new ("Memory");
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 0), label);
frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (notebook), frame);
gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
alignment = gtk_alignment_new (0, 0, 1, 1);
gtk_container_add (GTK_CONTAINER (frame), alignment);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (alignment), vbox);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
label = gtk_label_new ("You can setup the height of the graphics window in lines of text. This will not change the effective height of the graphics window, but the font size.");
gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
label = gtk_label_new ("Number of lines :");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
label = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
glines = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), glines, FALSE, FALSE, 0);
s = g_strdup_printf("%d",prefs.glines);
gtk_entry_set_text(GTK_ENTRY(glines),s);
g_free(s);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
label = gtk_label_new("Editor font: ");
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
fontbutton = gtk_font_button_new ();
gtk_font_button_set_use_font (GTK_FONT_BUTTON (fontbutton), TRUE);
gtk_font_button_set_font_name(GTK_FONT_BUTTON (fontbutton), prefs.pfont);
gtk_box_pack_start (GTK_BOX (hbox), fontbutton, TRUE, TRUE, 0);
label = gtk_label_new ("Font");
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 1), label);
frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (notebook), frame);
gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
alignment = gtk_alignment_new (0, 0, 1, 1);
gtk_container_add (GTK_CONTAINER (frame), alignment);
gtk_container_set_border_width (GTK_CONTAINER (alignment), 5);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (alignment), vbox);
label = gtk_label_new ("You can setup the colors used for the graphics. The change will be set when you click on Apply or OK.");
gtk_label_set_line_wrap(GTK_LABEL(label),TRUE);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
table = gtk_table_new (8, 4, TRUE);
gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
for (i=0 ; i<8 ; i++) {
GdkColor color;
s = g_strdup_printf("%d",i);
label = gtk_label_new(s);
gtk_widget_show (label);
gtk_table_attach(GTK_TABLE(table),label,0,1,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2);
color_button[i] = gtk_color_button_new();
color.red = ((gushort)prefs.colors[0][i])<<8;
color.green = ((gushort)prefs.colors[1][i])<<8;
color.blue = ((gushort)prefs.colors[2][i])<<8;
gtk_color_button_set_color(GTK_COLOR_BUTTON(color_button[i]), &color);
gtk_widget_show (color_button[i]);
gtk_table_attach(GTK_TABLE(table),color_button[i],1,2,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2);
g_free(s);
s = g_strdup_printf("%d",i+8);
color_button[i+8] = gtk_color_button_new();
color.red = ((gushort)prefs.colors[0][i+8])<<8;
color.green = ((gushort)prefs.colors[1][i+8])<<8;
color.blue = ((gushort)prefs.colors[2][i+8])<<8;
gtk_color_button_set_color(GTK_COLOR_BUTTON(color_button[i+8]), &color);
gtk_widget_show (color_button[i+8]);
gtk_table_attach(GTK_TABLE(table),color_button[i+8],2,3,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2);
label = gtk_label_new(s);
gtk_widget_show (label);
gtk_table_attach(GTK_TABLE(table),label,3,4,i,i+1,GTK_FILL|GTK_EXPAND,GTK_FILL|GTK_EXPAND,2,2);
g_free(s);
}
label = gtk_label_new ("Colors");
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 2), label);
frame = gtk_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (notebook), frame);
gtk_container_set_border_width (GTK_CONTAINER (frame), 5);
alignment = gtk_alignment_new (0, 0, 1, 1);
gtk_container_add (GTK_CONTAINER (frame), alignment);
gtk_container_set_border_width (GTK_CONTAINER (alignment), 5);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (alignment), vbox);
atexitbut = gtk_check_button_new_with_mnemonic ("Save preferences at Euler exit");
gtk_box_pack_start (GTK_BOX (vbox), atexitbut, FALSE, FALSE, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (atexitbut), TRUE);
label = gtk_label_new ("Browser used to view documentation");
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
browser = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (vbox), browser, FALSE, FALSE, 0);
s = g_strdup_printf("%s",prefs.browser);
gtk_entry_set_text(GTK_ENTRY(browser),s);
g_free(s);
label = gtk_label_new ("Misc");
gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), 3), label);
hbox = gtk_hbox_new (FALSE, 3);
gtk_box_pack_start (GTK_BOX (pref_vbox), hbox, FALSE, TRUE, 0);
button = gtk_button_new_with_mnemonic ("Default");
g_signal_connect (G_OBJECT(button), "clicked",
G_CALLBACK (prefs_reset_cb),NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
label = gtk_label_new (NULL);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
g_signal_connect_swapped (G_OBJECT(button), "clicked",
G_CALLBACK (gtk_widget_destroy),G_OBJECT(dialog));
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
button = gtk_button_new_with_mnemonic ("Apply");
g_signal_connect (G_OBJECT(button), "clicked",
G_CALLBACK (prefs_apply_cb),NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
button = gtk_button_new_from_stock (GTK_STOCK_OK);
g_signal_connect (G_OBJECT(button), "clicked",
G_CALLBACK (prefs_ok_cb),NULL);
g_signal_connect_swapped (G_OBJECT(button), "clicked",
G_CALLBACK (gtk_widget_destroy),G_OBJECT(dialog));
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show_all(dialog);
}
static void edit_comment_cb(GtkWidget *widget, gpointer data)
{
char *text;
GtkTextIter start, end;
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(data));
if (buffer) {
gtk_text_buffer_get_bounds(buffer, &start, &end);
text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
if (g_utf8_validate(text, -1, NULL))
text = g_locale_from_utf8(text, -1, NULL, NULL, NULL);
gtk_term_set_comment(term,text);
}
}
/*---------------------------------------------------------------------------
* comment editor
*---------------------------------------------------------------------------*/
static void editcomment(char *text)
{
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *scrolledwindow;
GtkWidget *textview;
GtkWidget *hbuttonbox;
GtkWidget *button;
GtkTextBuffer *buffer;
dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(dialog),"delete_event",
G_CALLBACK(gtk_widget_destroy),NULL);
g_signal_connect(G_OBJECT(dialog),"destroy",
G_CALLBACK(gtk_widget_destroy),NULL);
gtk_window_set_title (GTK_WINDOW (dialog), "Edit comment");
gtk_window_set_default_size (GTK_WINDOW (dialog), 350, 250);
gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_window_set_modal(GTK_WINDOW(dialog),TRUE);
vbox = gtk_vbox_new (FALSE, 5);
gtk_container_add (GTK_CONTAINER (dialog), vbox);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
buffer = gtk_text_buffer_new(NULL);
if (text != NULL) gtk_text_buffer_set_text(buffer, text, -1);
textview = gtk_text_view_new_with_buffer (buffer);
gtk_container_add (GTK_CONTAINER (scrolledwindow), textview);
hbuttonbox = gtk_hbutton_box_new ();
gtk_widget_show (hbuttonbox);
gtk_box_pack_start (GTK_BOX (vbox), hbuttonbox, FALSE, FALSE, 0);
button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
g_signal_connect_swapped(G_OBJECT(button),"clicked",
G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog));
gtk_container_add (GTK_CONTAINER (hbuttonbox), button);
button = gtk_button_new_from_stock (GTK_STOCK_OK);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(edit_comment_cb),GTK_OBJECT(textview));
g_signal_connect_swapped(G_OBJECT(button),"clicked",
G_CALLBACK(gtk_widget_destroy),GTK_OBJECT(dialog));
gtk_container_add (GTK_CONTAINER (hbuttonbox), button);
gtk_widget_show_all(dialog);
}
/*---------------------------------------------------------------------------
* menu
*---------------------------------------------------------------------------*/
void file_select (GtkFileChooserAction action,
gchar *title,
gchar *pattern,
gchar *filename,
GCallback func,
GtkWidget *window)
{
GtkWidget *dialog;
GtkWidget *dialog_vbox;
GtkWidget *dialog_action_area;
GtkWidget *button;
GtkFileFilter *filter;
dialog = gtk_file_chooser_dialog_new (title, GTK_WINDOW(window), action, NULL);
g_signal_connect(G_OBJECT(dialog), "delete_event",
G_CALLBACK(gtk_widget_destroy), NULL);
g_signal_connect(G_OBJECT(dialog), "destroy",
G_CALLBACK(gtk_widget_destroy), NULL);
gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
filter = gtk_file_filter_new ();
gtk_file_filter_add_pattern(filter, pattern);
gtk_file_filter_set_name(filter, pattern);
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
if (filename && action == GTK_FILE_CHOOSER_ACTION_SAVE)
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), g_path_get_basename(filename));
dialog_vbox = GTK_DIALOG (dialog)->vbox;
dialog_action_area = GTK_DIALOG (dialog)->action_area;
gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area), GTK_BUTTONBOX_END);
button = gtk_button_new_from_stock ("gtk-cancel");
g_signal_connect_swapped(G_OBJECT(button), "clicked",
G_CALLBACK(gtk_widget_destroy), dialog);
gtk_box_pack_start(GTK_BOX(dialog_action_area), button, FALSE, FALSE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
if (action == GTK_FILE_CHOOSER_ACTION_OPEN)
button = gtk_button_new_from_stock ("gtk-open");
else if (action == GTK_FILE_CHOOSER_ACTION_SAVE)
button = gtk_button_new_from_stock ("gtk-save");
else
return;
g_signal_connect(G_OBJECT(button),"clicked",
G_CALLBACK(func),dialog);
gtk_box_pack_start(GTK_BOX(dialog_action_area), button, FALSE, FALSE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show_all(dialog);
gtk_dialog_run (GTK_DIALOG (dialog));
}
static void open_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".en");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (!gtk_term_load(term,filename)) {
char *txt = g_strdup_printf("\nI could not open the file\n%s !\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
} else {
gtk_widget_destroy((GtkWidget*)data);
is_demo = 0;
}
chdir(g_dirname(filename));
}
static void postscript_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".eps");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (!dump_postscript(filename)) {
char *txt = g_strdup_printf("\nI could not save the postscript graphics to the file\n%s\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
}
else
gtk_widget_destroy((GtkWidget*)data);
}
static void overwrite_yes_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".en");
destroy_yesno_dialog(widget);
if (!gtk_term_save(term,filename)) {
char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
}
else
gtk_widget_destroy((GtkWidget*)data);
chdir(g_dirname(filename));
}
static void save_as_cb(GtkWidget *widget, gpointer data)
{
struct stat statbuf;
char *filename = get_filename(data, ".en");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (stat(filename, &statbuf) == 0) /* file exists */
yesnoquestion("Destination file exists, overwrite it?",
G_CALLBACK(overwrite_yes_cb), NULL, (GtkWidget*)data);
else
overwrite_yes_cb(NULL, data);
}
static void overwrite_yes_open_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".en");
destroy_yesno_dialog(widget);
if (gtk_term_save(term,filename)) {
gtk_widget_destroy((GtkWidget*)data);
chdir(g_dirname(filename));
file_select(GTK_FILE_CHOOSER_ACTION_OPEN,
"Open A Notebook ...", "*.en", NULL,
G_CALLBACK(open_cb), term_window);
} else {
char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe notebook open command is aborted ...\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
chdir(g_dirname(filename));
}
}
static void save_as_open_cb(GtkWidget *widget, gpointer data)
{
struct stat statbuf;
char *filename = get_filename(data, ".en");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (stat(filename, &statbuf) == 0) /* file exists */
yesnoquestion("Destination file exists, overwrite it?",
G_CALLBACK(overwrite_yes_open_cb), NULL, (GtkWidget*)data);
else
overwrite_yes_open_cb(NULL, data);
}
static void save_as_new_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".en");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (gtk_term_save(term,filename)) {
gtk_widget_destroy((GtkWidget*)data);
gtk_term_clear_new(term);
is_demo = 0;
} else {
char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe new notebook command is aborted ...\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
}
chdir(g_dirname(filename));
}
static void overwrite_yes_quit_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".en");
destroy_yesno_dialog(widget);
if (gtk_term_save(term,filename)){
gtk_widget_destroy((GtkWidget*)data);
euler_exit();
}
else {
char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe quit notebook command is aborted ...\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
}
chdir(g_dirname(filename));
}
static void save_as_quit_cb(GtkWidget *widget, gpointer data)
{
struct stat statbuf;
char *filename = get_filename(data, ".en");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (stat(filename, &statbuf) == 0) /* file exists */
yesnoquestion("Destination file exists, overwrite it?",
G_CALLBACK(overwrite_yes_quit_cb), NULL, (GtkWidget*)data);
else
overwrite_yes_quit_cb(NULL, data);
}
static void yes_quit_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
if (!gtk_term_is_named(term))
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Notebook As ...", "*.en", "untitled",
G_CALLBACK(save_as_quit_cb), term_window);
else {
gtk_term_save(term,NULL);
euler_exit();
}
}
static void no_quit_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
euler_exit();
}
static void quit_cb(GObject *widget, gpointer data)
{
if (!is_demo && gtk_term_is_changed(term))
yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_quit_cb),G_CALLBACK(no_quit_cb),term_window);
else
euler_exit();
}
/*---------------------------------------------------------------------------
* toolbar callbacks
*---------------------------------------------------------------------------*/
static void yes_new_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
if (!gtk_term_is_named(term))
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Notebook As ...", "*.en", "untitled",
G_CALLBACK(save_as_new_cb), term_window);
else {
gtk_term_save(term,NULL);
gtk_term_clear_new(term);
is_demo = 0;
}
}
static void no_new_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
gtk_term_clear_new(term);
is_demo = 0;
}
static void yes_open_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
if (!gtk_term_is_named(term))
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Notebook As ...", "*.en", "untitled",
G_CALLBACK(save_as_open_cb), term_window);
else {
gtk_term_save(term,NULL);
file_select(GTK_FILE_CHOOSER_ACTION_OPEN,
"Open A Notebook ...", "*.en", NULL,
G_CALLBACK(open_cb), term_window);
}
}
static void no_open_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
file_select(GTK_FILE_CHOOSER_ACTION_OPEN,
"Open A Notebook ...", "*.en", NULL,
G_CALLBACK(open_cb), term_window);
}
/*-------------------------------------------------------------
* internal editor
*------------------------------------------------------------*/
static GtkWidget * estatusbar;
static GtkWidget * entry;
static GtkWidget * loadbutton;
static GtkWidget * savebutton;
static GtkTextBuffer * etextbuffer;
static gint row, col;
static gchar *efname = "";
static gboolean echanged = FALSE;
static void buffer_changed(void)
{
char *title = g_strdup_printf("Editor [*%s]",efname);
gtk_window_set_title(GTK_WINDOW(editordialog), title);
g_free(title);
echanged = TRUE;
gtk_widget_set_sensitive(loadbutton, FALSE);
gtk_widget_set_sensitive(savebutton, TRUE);
}
static void buffer_saved(void)
{
char *title = g_strdup_printf("Editor [%s]",efname);
gtk_window_set_title(GTK_WINDOW(editordialog), title);
g_free(title);
echanged = FALSE;
gtk_widget_set_sensitive(loadbutton, strlen(efname));
gtk_widget_set_sensitive(savebutton, FALSE);
}
static void clear_editor(void)
{
efname = "";
gtk_text_buffer_set_text(etextbuffer, "", -1);
gtk_widget_grab_focus (etextview);
buffer_saved();
}
static void get_row_col(GtkTextIter iter, int *row, int *col)
{
GtkTextIter start;
guint tab_size = 8;
*row = gtk_text_iter_get_line(&iter);
start = iter;
gtk_text_iter_set_line_offset(&start, 0);
*col = 0;
while (!gtk_text_iter_equal(&start, &iter))
{
if (gtk_text_iter_get_char (&start) == '\t')
(*col) += (tab_size - (*col % tab_size));
else
++(*col);
gtk_text_iter_forward_char(&start);
}
}
static void find(GtkTextView *text_view, const gchar *text, GtkTextIter *iter)
{
GtkTextIter mstart, mend;
GtkTextMark *last_pos;
if(gtk_text_iter_forward_search(iter, text, 0, &mstart, &mend, NULL))
{
gtk_text_buffer_select_range(etextbuffer, &mstart, &mend);
last_pos = gtk_text_buffer_create_mark(etextbuffer, "last_pos",
&mend, FALSE);
gtk_text_view_scroll_to_mark(text_view, last_pos, 0, TRUE, 0.5, 0.5);
}
}
static void save_file(GtkWidget *parent, char *filename)
{
FILE *file;
char *text;
GtkTextIter start, end;
file = fopen(filename,"w");
if (!file) {
char *txt = g_strdup_printf("\nCould not save the file\n%s !\n",filename);
infobox(parent, txt);
g_free(txt);
return;
}
else {
gtk_text_buffer_get_bounds(etextbuffer, &start, &end);
text = gtk_text_buffer_get_text(etextbuffer, &start, &end, TRUE);
if (g_utf8_validate(text, -1, NULL))
text = g_locale_from_utf8(text, -1, NULL, NULL, NULL);
fprintf(file,text);
fclose(file);
efname = filename;
buffer_saved();
if (GTK_IS_FILE_CHOOSER(parent)) gtk_widget_destroy(parent);
}
chdir(g_dirname(filename));
}
static void cursor_moved(void)
{
char *msg;
GtkTextIter iter;
int r, c;
gtk_text_buffer_get_iter_at_mark (etextbuffer, &iter,
gtk_text_buffer_get_insert(etextbuffer));
get_row_col(iter, &r, &c);
row = r; col = c;
msg = g_strdup_printf("Ln:%d Col:%d", row + 1, col + 1);
gtk_statusbar_push(GTK_STATUSBAR (estatusbar), 0, msg);
g_free (msg);
}
static void overwrite_yes_e_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
save_file((GtkWidget*)data, get_filename(data, ".e"));
}
static void save_as_e_cb(GtkWidget *widget, gpointer data)
{
struct stat statbuf;
char *filename = get_filename(data, ".e");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (stat(filename, &statbuf) == 0) /* file exists */
yesnoquestion("Destination file exists, overwrite it?",
G_CALLBACK(overwrite_yes_e_cb),
NULL, (GtkWidget*)data);
else
save_file((GtkWidget*)data, filename);
}
static void open_file(GtkWidget *parent, char *filename)
{
FILE *file;
char line[1024];
char *text;
int length;
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (!(file = fopen(filename, "r+")))
if (!(file = fopen(filename, "r"))) {
char *txt = g_strdup_printf("\nCould not open the file\n%s !\n",filename);
infobox(parent, txt);
g_free(txt);
return;
}
if (GTK_IS_FILE_CHOOSER(parent)) gtk_widget_destroy(parent);
clear_editor();
efname = filename;
while(!feof(file) && !ferror(file)) {
length = fread(line, sizeof(char), 1023, file);
line[length] = '\0';
if (!g_utf8_validate(line, strlen(line), NULL)) {
text = g_locale_to_utf8(line, strlen(line), NULL, NULL, NULL);
gtk_text_buffer_insert_at_cursor(etextbuffer, text, strlen(text));
}
else
gtk_text_buffer_insert_at_cursor(etextbuffer, line, strlen(line));
}
fclose(file);
buffer_saved();
chdir(g_dirname(filename));
}
static void open_e_cb(GtkWidget *widget, gpointer data)
{
open_file((GtkWidget*)data, get_filename(data, ".e"));
}
static void save_or_save_as(void)
{
if (strlen(efname))
save_file(editordialog, efname);
else
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Module As ...", "*.e", "untitled",
G_CALLBACK(save_as_e_cb), editordialog);
}
static void yes_new_e_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
save_or_save_as();
clear_editor();
}
static void no_new_e_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
clear_editor();
}
static void yes_open_e_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
save_or_save_as();
file_select(GTK_FILE_CHOOSER_ACTION_OPEN,
"Open A Module ...", "*.e", NULL,
G_CALLBACK(open_e_cb), editordialog);
}
static void no_open_e_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
file_select(GTK_FILE_CHOOSER_ACTION_OPEN,
"Open module ...", "*.e", NULL,
G_CALLBACK(open_e_cb), editordialog);
}
static void yes_quit_e_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
save_or_save_as();
gtk_widget_destroy(editordialog);
editordialog = NULL;
}
static void no_quit_e_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
gtk_widget_destroy(editordialog);
editordialog = NULL;
}
static void yes_quit_e_quit_cb(GtkWidget *widget, gpointer data)
{
yes_quit_e_cb(widget, NULL);
quit_cb(NULL, NULL);
}
static void no_quit_e_quit_cb(GtkWidget *widget, gpointer data)
{
no_quit_e_cb(widget, NULL);
quit_cb(NULL, NULL);
}
static void editor_delete_cb(GtkWidget *widget, gpointer data)
{
if (echanged)
if (widget)
yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_quit_e_quit_cb),G_CALLBACK(no_quit_e_quit_cb),editordialog);
else
yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_quit_e_cb),G_CALLBACK(no_quit_e_cb),editordialog);
else {
gtk_widget_destroy(editordialog);
editordialog = NULL;
if (widget) quit_cb(NULL, NULL);
}
}
static void on_editor_new(GtkWidget *widget, gpointer data)
{
if (echanged)
yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_new_e_cb),G_CALLBACK(no_new_e_cb),editordialog);
else
clear_editor();
}
static void on_editor_open(GtkWidget *widget, gpointer data)
{
if(echanged)
yesnoquestion("\nThe current module has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_open_e_cb),G_CALLBACK(no_open_e_cb),editordialog);
else
file_select(GTK_FILE_CHOOSER_ACTION_OPEN,
"Open A Module ...", "*.e", NULL,
G_CALLBACK(open_e_cb), editordialog);
}
static void on_editor_save(GtkWidget *widget, gpointer data)
{
save_or_save_as();
}
static void on_editor_save_as(GtkWidget *widget, gpointer data)
{
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Module As ...", "*.e", strlen(efname) ? efname : "untitled",
G_CALLBACK(save_as_e_cb), editordialog);
}
static void on_editor_find(GtkWidget *widget, gpointer data)
{
const gchar *text;
GtkTextMark *last_pos;
GtkTextIter iter;
int r, c;
text = gtk_entry_get_text(GTK_ENTRY(entry));
if (!strlen(text)) return;
last_pos = gtk_text_buffer_get_mark (etextbuffer, "last_pos");
if (last_pos == NULL)
gtk_text_buffer_get_start_iter (etextbuffer, &iter);
else{
gtk_text_buffer_get_iter_at_mark (etextbuffer, &iter, last_pos);
get_row_col(iter, &r, &c);
if (row != r || col != (c-strlen(text)))
gtk_text_buffer_get_iter_at_line_offset(etextbuffer, &iter, row, col);
}
find (GTK_TEXT_VIEW(etextview), text, &iter);
}
static void on_editor_load(GtkWidget *widget, gpointer data)
{
GtkTerm *t = GTK_TERM(term);
if (t->editing) {
char *text = g_strdup_printf("load \"%s\"", efname);
if (!strlen(efname)) return;
if (t->pos<=e_get_text_length(t->a,t->cur))
e_remove_text(t->a,t->cur,1,e_get_text_length(t->a,t->cur)-1);
gtk_term_delete_current_output(term);
output(text);
gtk_term_redraw(term);
strcpy(input_line, text);
forcebreak = TRUE;
g_free(text);
}
}
static void editor(void)
{
GtkWidget *vbox;
GtkWidget *toolbar;
GtkWidget *button;
GtkWidget *toolitem;
GtkWidget *vseparator;
GtkWidget *scrolledwindow;
GtkWidget *image;
GtkTooltips *tips;
PangoFontDescription *pfd;
GtkIconSize tmp_toolbar_icon_size;
if (editordialog) {
gdk_window_raise(editordialog->window);
return;
}
editordialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
// gtk_window_set_transient_for(GTK_WINDOW(editordialog),GTK_WINDOW(term_window));
// gtk_window_set_modal(GTK_WINDOW(editordialog),TRUE);
gtk_window_set_position(GTK_WINDOW(editordialog),GTK_WIN_POS_MOUSE);
gtk_window_set_title (GTK_WINDOW (editordialog), "Editor []");
gtk_window_set_default_size (GTK_WINDOW (editordialog), 500, 400);
g_signal_connect_swapped(G_OBJECT(editordialog), "delete_event",
G_CALLBACK(editor_delete_cb), NULL);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (editordialog), vbox);
toolbar = gtk_toolbar_new ();
gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
gtk_toolbar_set_tooltips(GTK_TOOLBAR(toolbar), TRUE);
gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
tips = gtk_tooltips_new();
tmp_toolbar_icon_size = gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar));
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_widget_show (toolitem);
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
button = gtk_button_new ();
gtk_tooltips_set_tip(tips, button, "Create new module", NULL);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_new), NULL);
gtk_container_add (GTK_CONTAINER (toolitem), button);
image = gtk_image_new_from_stock ("gtk-new", GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
button = gtk_button_new ();
gtk_tooltips_set_tip(tips, button, "Open module", NULL);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_open), NULL);
gtk_container_add (GTK_CONTAINER (toolitem), button);
image = gtk_image_new_from_stock ("gtk-open", GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
savebutton = gtk_button_new ();
gtk_tooltips_set_tip(tips, savebutton, "Save module", NULL);
gtk_button_set_relief (GTK_BUTTON (savebutton), GTK_RELIEF_NONE);
gtk_button_set_focus_on_click (GTK_BUTTON (savebutton), FALSE);
g_signal_connect(G_OBJECT(savebutton), "clicked", G_CALLBACK(on_editor_save), NULL);
gtk_container_add (GTK_CONTAINER (toolitem), savebutton);
image = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (savebutton), image);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
button = gtk_button_new ();
gtk_tooltips_set_tip(tips, button, "Save module as ...", NULL);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_save_as), NULL);
gtk_container_add (GTK_CONTAINER (toolitem), button);
image = gtk_image_new_from_stock ("gtk-save-as", GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
gtk_container_set_border_width (GTK_CONTAINER (toolitem), 5);
vseparator = gtk_vseparator_new ();
gtk_container_add (GTK_CONTAINER (toolitem), vseparator);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
entry = gtk_entry_new ();
gtk_container_add (GTK_CONTAINER (toolitem), entry);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
button = gtk_button_new ();
gtk_tooltips_set_tip(tips, button, "Find text", NULL);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(on_editor_find), NULL);
gtk_container_add (GTK_CONTAINER (toolitem), button);
image = gtk_image_new_from_stock ("gtk-find", GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
gtk_container_set_border_width (GTK_CONTAINER (toolitem), 5);
vseparator = gtk_vseparator_new ();
gtk_widget_show (vseparator);
gtk_container_add (GTK_CONTAINER (toolitem), vseparator);
toolitem = (GtkWidget*) gtk_tool_item_new ();
gtk_container_add (GTK_CONTAINER (toolbar), toolitem);
loadbutton = gtk_button_new ();
gtk_tooltips_set_tip(tips, loadbutton, "Load module into euler", NULL);
gtk_button_set_relief (GTK_BUTTON (loadbutton), GTK_RELIEF_NONE);
gtk_button_set_focus_on_click (GTK_BUTTON (loadbutton), FALSE);
g_signal_connect(G_OBJECT(loadbutton), "clicked", G_CALLBACK(on_editor_load), NULL);
gtk_container_add (GTK_CONTAINER (toolitem), loadbutton);
image = gtk_image_new_from_stock ("gtk-go-down", GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (loadbutton), image);
scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
gtk_box_pack_start (GTK_BOX (vbox), scrolledwindow, TRUE, TRUE, 0);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
etextview = gtk_text_view_new ();
pfd = pango_font_description_from_string (prefs.pfont);
gtk_widget_modify_font(etextview,pfd);
gtk_container_add (GTK_CONTAINER (scrolledwindow), etextview);
etextbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(etextview));
g_signal_connect (etextbuffer, "mark_set", G_CALLBACK (cursor_moved), NULL);
g_signal_connect (etextbuffer, "changed", G_CALLBACK (cursor_moved), NULL);
g_signal_connect (etextbuffer, "changed", G_CALLBACK (buffer_changed), NULL);
estatusbar = gtk_statusbar_new();
gtk_box_pack_start(GTK_BOX(vbox), estatusbar, FALSE, FALSE, 0);
if (strlen(efname)) open_file(editordialog, efname);
gtk_widget_show_all(editordialog);
gtk_widget_grab_focus (etextview);
cursor_moved();
buffer_saved();
}
/*---------------------------------------------------------------------------
* term callbacks and drag & drop
*---------------------------------------------------------------------------*/
static guint id;
static gboolean savesuccess = FALSE;
static GdkAtom text_uri_list, application_octet_stream, text_plain;
enum {TARGET_RAW_DATA, TARGET_URI_LIST};
/* Targets which other apps can offer to us */
static GtkTargetEntry targets_to_accept[] =
{
{"application/octet-stream", 0, TARGET_RAW_DATA},
{"text/uri-list", 0, TARGET_URI_LIST}
};
#define MAX_HOST_NAME_LEN 256 /* XXX: Limit */
char our_host_name[MAX_HOST_NAME_LEN];
static gchar *dnd_path=NULL;
static void term_changed_cb(GtkWidget *widget, gpointer data)
{
char *title = g_strdup_printf("Euler [*%s]",gtk_term_get_name(term));
gtk_window_set_title(GTK_WINDOW(term_window), title);
g_free(title);
}
static void term_saved_cb(GtkWidget *widget, gpointer data)
{
char *title = g_strdup_printf("Euler [%s]",gtk_term_get_name(term));
gtk_window_set_title(GTK_WINDOW(term_window), title);
g_free(title);
}
static void term_editing_cb(GtkWidget *widget, gpointer data)
{
if (gtk_term_is_initialized(term))
gtk_statusbar_pop(GTK_STATUSBAR(widget),id);
else
gtk_statusbar_push(GTK_STATUSBAR(widget),id," Editing ...");
}
static void term_interpreting_cb(GtkWidget *widget, gpointer data)
{
gtk_statusbar_push(GTK_STATUSBAR(widget),id," Running ...");
}
static gint term_cfg_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
{
GtkTerm *term = GTK_TERM(widget);
prefs.twidth = term->twidth;
prefs.theight = term->theight;
return FALSE;
}
static void overwrite_yes_dndopen_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".en");
destroy_yesno_dialog(widget);
if (gtk_term_save(term,filename)) {
gtk_widget_destroy((GtkWidget*)data);
chdir(g_dirname(dnd_path));
savesuccess = gtk_term_load(term, dnd_path);
} else {
char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe notebook open command is aborted ...\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
chdir(g_dirname(filename));
savesuccess = FALSE;
}
}
static void save_as_dndopen_cb(GtkWidget *widget, gpointer data)
{
struct stat statbuf;
char *filename = get_filename(data, ".en");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (stat(filename, &statbuf) == 0) /* file exists */
yesnoquestion("Destination file exists, overwrite it?",
G_CALLBACK(overwrite_yes_dndopen_cb),
NULL, (GtkWidget*)data);
else {
overwrite_yes_dndopen_cb(NULL, data);
gtk_widget_destroy((GtkWidget*)data);
}
}
static void yes_dndopen_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
if (!gtk_term_is_named(term))
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Notebook As ...", "*.en", "untitled",
G_CALLBACK(save_as_dndopen_cb), term_window);
else {
gtk_term_save(term,NULL);
gtk_term_load(term, dnd_path);
chdir(g_dirname(dnd_path));
}
}
static void no_dndopen_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
gtk_term_load(term, dnd_path);
chdir(g_dirname(dnd_path));
}
static GdkAtom best_raw(GdkDragContext *context);
static gboolean provides(GdkDragContext *context, GdkAtom target);
/* Convert a list of URIs into a list of strings.
* Lines beginning with # are skipped.
* The text block passed in is zero terminated (after the final CRLF)
*/
GSList *uri_list_to_gslist(char *uri_list)
{
GSList *list = NULL;
while (*uri_list)
{
char *linebreak;
char *uri;
int length;
linebreak = strchr(uri_list, 13);
if (!linebreak || linebreak[1] != 10)
{
infobox(term_window, "Incorrect or missing line break "
"in text/uri-list data\n");
return list;
}
length = linebreak - uri_list;
if (length && uri_list[0] != '#')
{
uri = g_malloc(sizeof(char) * (length + 1));
strncpy(uri, uri_list, length);
uri[length] = 0;
list = g_slist_append(list, uri);
}
uri_list = linebreak + 2;
}
return list;
}
/* Convert a URI to a local pathname (or NULL if it isn't local).
* The returned pointer points inside the input string.
* Possible formats:
* /path
* ///path
* //host/path
* file://host/path
*/
char *get_local_path(char *uri)
{
if (*uri == '/')
{
char *path;
if (uri[1] != '/')
return uri; /* Just a local path - no host part */
path = strchr(uri + 2, '/');
if (!path)
return NULL; /* //something */
if (path - uri == 2)
return path; /* ///path */
if (strlen(our_host_name) == path - uri - 2 &&
strncmp(uri + 2, our_host_name, path - uri - 2) == 0)
return path; /* //myhost/path */
return NULL; /* From a different host */
}
else
{
if (strncasecmp(uri, "file:", 5))
return NULL; /* Don't know this format */
uri += 5;
if (*uri == '/')
return get_local_path(uri);
return NULL;
}
}
/*
* This is called when the remote application wants to send us some
* data. We get to decide what kind of data we'd like.
*/
static int drag_drop(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time)
{
/* FIXME
make term_window can't accept dnd
if it has a shown transient window */
guchar *leafname = NULL;
GdkAtom target;
if (gtk_drag_get_source_widget(context))
return TRUE; /* Drag to ourselves - ignore */
if (provides(context, text_uri_list))
target = text_uri_list;
else
{
leafname = g_strdup("Untitled");
target = best_raw(context);
}
/* Associate the leafname with the context */
if (leafname)
g_dataset_set_data_full(context, "uri", leafname, g_free);
if (target)
gtk_drag_get_data(widget, context, target, time);
else
gtk_drag_finish(context, FALSE, FALSE, time);
return TRUE;
}
/* Look for the best target type for transferring data */
static GdkAtom best_raw(GdkDragContext *context)
{
if (provides(context, text_plain))
return text_plain;
if (provides(context, application_octet_stream))
return application_octet_stream;
infobox(term_window, "I can't get the data from the other application\n");
return GDK_NONE;
}
/* Is the sended willing to supply this target type? */
static gboolean provides(GdkDragContext *context, GdkAtom target)
{
GList *targets = context->targets;
while (targets && ((GdkAtom) targets->data != target))
targets = targets->next;
return targets != NULL;
}
/* Called when some data arrives from the remote app (which we asked for
* in drag_drop.
*/
static void drag_data_received(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint32 time)
{
if (!selection_data->data)
{
/* Timeout? */
gtk_drag_finish(context, FALSE, FALSE, time);
return;
}
if (selection_data->target == text_uri_list)
{
GSList *files;
char *localpath;
files = uri_list_to_gslist(selection_data->data);
if (files == NULL || files->next)
{
/* Only one file at a time for now */
infobox(term_window, "Sorry, can only load one file at a time");
gtk_drag_finish(context, FALSE, FALSE, time);
return;
}
localpath = get_local_path((char *) files->data);
/* Remember the URI for the data */
g_dataset_set_data_full(context,"uri",files->data,g_free);
if (localpath)
{
gboolean success = FALSE;
if (gtk_term_is_editing(term)) {
if (!is_demo && gtk_term_is_changed(term)) {
dnd_path=localpath;
yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_dndopen_cb),G_CALLBACK(no_dndopen_cb),term_window);
success = savesuccess;
} else {
success = gtk_term_load(term, localpath);
chdir(g_dirname(localpath));
}
} else {
infobox(term_window, "You cannot load another notebook\nwhile the interpreter is running ...");
}
gtk_drag_finish(context,success,FALSE,time);
}
else
{
gtk_drag_finish(context, FALSE, FALSE, time);
}
}
else
{
gtk_drag_finish(context, FALSE, FALSE, time);
}
}
/*---------------------------------------------------------------------------
* metagtk callbacks
*---------------------------------------------------------------------------*/
static gint meta_cfg_cb(GtkWidget *widget, GdkEventConfigure *event)
{
prefs.gwidth = event->width;
prefs.gheight = event->height;
return FALSE;
}
/*---------------------------------------------------------------------------
* demo callbacks
*---------------------------------------------------------------------------*/
static const char *demo_name = NULL;
static void save_as_demo_cb(GtkWidget *widget, gpointer data)
{
char *filename = get_filename(data, ".en");
if ((!filename) || (strcmp(filename,"") == 0))
return;
if (gtk_term_save(term,filename)) {
gchar *s;
chdir(g_dirname(filename));
s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL);
gtk_term_load(term,s);
g_free(s);
is_demo = 1;
gtk_widget_destroy((GtkWidget*)data);
} else {
char *txt = g_strdup_printf("\nI could not save the notebook to the file\n%s\nThe notebook open command is aborted ...\n",filename);
infobox((GtkWidget*)data, txt);
g_free(txt);
chdir(g_dirname(filename));
}
}
static void yes_demo_cb(GtkWidget *widget, gpointer data)
{
destroy_yesno_dialog(widget);
if (!gtk_term_is_named(term))
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Notebook As ...", "*.en", "untitled",
G_CALLBACK(save_as_demo_cb), term_window);
else {
gchar *s;
gtk_term_save(term,NULL);
s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL);
gtk_term_load(term,s);
g_free(s);
is_demo = 1;
}
}
static void no_demo_cb(GtkWidget *widget, gpointer data)
{
gchar *s;
destroy_yesno_dialog(widget);
s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL);
gtk_term_load(term,s);
g_free(s);
is_demo = 1;
}
static void demo_cb(GtkAction *action)
{
g_return_if_fail(action != NULL);
g_return_if_fail(GTK_IS_ACTION(action));
demo_name = gtk_action_get_name(action);
if (!is_demo) {
if (gtk_term_is_changed(term))
yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_demo_cb),G_CALLBACK(no_demo_cb),term_window);
else {
gchar *s;
s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL);
gtk_term_load(term,s);
g_free(s);
is_demo = 1;
}
} else {
gchar *s;
s = g_strconcat(INSTALL_DIR,"/share/euler/progs/",demo_name,NULL);
gtk_term_load(term,s);
g_free(s);
is_demo = 1;
}
}
/*---------------------------------------------------------------------------
* main
*---------------------------------------------------------------------------*/
static void on_file_new(GtkAction *action)
{
if (!is_demo && gtk_term_is_changed(term))
yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_new_cb),G_CALLBACK(no_new_cb),term_window);
else {
gtk_term_clear_new(term);
is_demo = 0;
}
}
static void on_file_open(GtkAction *action)
{
if (!is_demo && gtk_term_is_changed(term))
yesnoquestion("\nThe current notebook has been modified ...\nDo you want to save it?\n",
G_CALLBACK(yes_open_cb),G_CALLBACK(no_open_cb),term_window);
else
file_select(GTK_FILE_CHOOSER_ACTION_OPEN,
"Open A Notebook ...", "*.en", NULL,
G_CALLBACK(open_cb), term_window);
}
static void on_file_save(GtkAction *action)
{
if (!gtk_term_is_named(term))
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Notebook As ...", "*.en", "untitled",
G_CALLBACK(save_as_cb), term_window);
else if (!is_demo)
gtk_term_save(term,NULL);
}
static void on_file_save_as(GtkAction *action)
{
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Save Notebook As ...", "*.en", gtk_term_is_named(term) ? gtk_term_get_name(term) : "untitled",
G_CALLBACK(save_as_cb), term_window);
}
static void on_export_to_postscript(GtkAction *action)
{
file_select(GTK_FILE_CHOOSER_ACTION_SAVE,
"Export Graphics As ...", "*.eps", "untitled",
G_CALLBACK(postscript_cb), term_window);
}
static void on_file_quit(GObject *object)
{
if (editordialog) {
gdk_window_raise(editordialog->window);
editor_delete_cb(term_window, NULL);
}
else quit_cb(object, NULL);
}
static void on_edit_cut (GtkAction *action)
{
gtk_term_cut(term);
}
static void on_edit_copy (GtkAction *action)
{
gtk_term_copy(term);
}
static void on_edit_paste (GtkAction *action)
{
gtk_term_paste(term);
}
static void on_edit_insert_command (GtkAction *action)
{
gtk_term_insert_command(term,NULL);
}
static void on_edit_delete_command (GtkAction *action)
{
gtk_term_delete_command(term);
}
static void on_edit_clear_outputs (GtkAction *action)
{
gtk_term_delete_outputs(term);
}
static void on_edit_delete_output (GtkAction *action)
{
gtk_term_delete_current_output(term);
}
static void on_edit_edit_comment (GtkAction *action)
{
gchar *buffer = gtk_term_get_comment(term);
if (buffer)
if (!g_utf8_validate(buffer, -1, NULL))
buffer = g_locale_to_utf8(buffer, -1, NULL, NULL, NULL);
editcomment(buffer);
}
static void on_misc_editor (GtkAction *action)
{
editor();
}
static void on_misc_preferences (GtkAction *action)
{
prefs_box();
}
static void on_help_doc (GtkAction *action)
{
char *browser;
browser = g_strconcat(prefs.browser," ",INSTALL_DIR,"/share/doc/euler/index.html &",NULL);
system(browser);
g_free(browser);
}
static void on_help_about (GtkAction *action)
{
about();
}
static GtkActionEntry actionentries[] = {
/* file menu */
{ "FileMenu" , NULL , "_File" },
{ "New" , GTK_STOCK_NEW , "_New" , "<control>N", "Create a new file" , G_CALLBACK (on_file_new) },
{ "Open" , GTK_STOCK_OPEN , "_Open" , "<control>O", "Open a file" , G_CALLBACK (on_file_open) },
{ "Save" , GTK_STOCK_SAVE , "_Save" , "<control>S", "Save current file" , G_CALLBACK (on_file_save) },
{ "SaveAs" , GTK_STOCK_SAVE_AS , "Save _As..." , NULL , "Save to a file" , G_CALLBACK (on_file_save_as) },
{ "ExportMenu" , NULL , "Export Graphics To" },
{ "Postscript" , NULL , "Postscript" , "<control>P", NULL , G_CALLBACK (on_export_to_postscript) },
{ "Quit" , GTK_STOCK_QUIT , "_Quit" , "<control>Q", "Quit" , G_CALLBACK (on_file_quit) },
/* edit menu */
{ "EditMenu" , NULL , "_Edit" },
{ "Cut" , GTK_STOCK_CUT , "Cu_t" , "<control>X", "Cut selection" , G_CALLBACK (on_edit_cut) },
{ "Copy" , GTK_STOCK_COPY , "_Copy" , "<control>C", "Copy selection" , G_CALLBACK (on_edit_copy) },
{ "Paste" , GTK_STOCK_PASTE , "_Paste" , "<control>V", "Paste clipboard content" , G_CALLBACK (on_edit_paste) },
{ "InsertCommand", GTK_STOCK_ADD , "Insert Command" , "<control>I", "Insert Command" , G_CALLBACK (on_edit_insert_command) },
{ "DeleteCommand", GTK_STOCK_REMOVE , "Delete Command" , "<control>D", "Delete Current Command" , G_CALLBACK (on_edit_delete_command) },
{ "ClearOutputs" , GTK_STOCK_CLEAR , "Clear All Outputs" , NULL , "Clear All Outputs" , G_CALLBACK (on_edit_clear_outputs) },
{ "DeleteOutput" , GTK_STOCK_DELETE , "Delete Current Output" , NULL , "Delete Current Output" , G_CALLBACK (on_edit_delete_output) },
{ "EditComment" , GTK_STOCK_JUSTIFY_FILL , "Edit Comment", "<control>E", "Edit Command..." , G_CALLBACK (on_edit_edit_comment) },
/* misc menu */
{ "MiscMenu" , NULL , "_Misc" },
{ "DemoMenu" , NULL , "Demo" },
{ "Editor" , GTK_STOCK_EDIT , "Editor" , NULL , "Internal Editor..." , G_CALLBACK (on_misc_editor) },
{ "Preferences" , GTK_STOCK_PREFERENCES, "Preferences" , NULL , NULL , G_CALLBACK (on_misc_preferences) },
/* help menu */
{ "HelpMenu" , NULL , "_Help" },
{ "Documentation", GTK_STOCK_HELP , "Documentation" , "F1" , NULL , G_CALLBACK (on_help_doc) },
{ "About" , GTK_STOCK_ABOUT , "_About" , "<control>A", "About" , G_CALLBACK (on_help_about) },
};
static guint n_actionentries = G_N_ELEMENTS (actionentries);
static const gchar *ui_info =
"<ui>"
" <menubar name='MenuBar'>"
" <menu name='File' action='FileMenu'>"
" <menuitem action='New'/>"
" <menuitem action='Open'/>"
" <menuitem action='Save'/>"
" <menuitem action='SaveAs'/>"
" <separator/>"
" <menu action='ExportMenu'>"
" <menuitem action='Postscript'/>"
" </menu>"
" <separator/>"
" <menuitem action='Quit'/>"
" </menu>"
" <menu name='Edit' action='EditMenu'>"
" <menuitem action='Cut'/>"
" <menuitem action='Copy'/>"
" <menuitem action='Paste'/>"
" <separator/>"
" <menuitem action='InsertCommand'/>"
" <menuitem action='DeleteCommand'/>"
" <separator/>"
" <menuitem action='ClearOutputs'/>"
" <menuitem action='DeleteOutput'/>"
" <separator/>"
" <menuitem action='EditComment'/>"
" </menu>"
" <menu name='Misc' action='MiscMenu'>"
" <menu name='Demo' action='DemoMenu'/>"
" <menuitem action='Editor'/>"
" <menuitem action='Preferences'/>"
" </menu>"
" <menu name='Help' action='HelpMenu'>"
" <menuitem action='Documentation'/>"
" <menuitem action='About'/>"
" </menu>"
" </menubar>"
" <toolbar name='ToolBar'>"
" <toolitem action='New'/>"
" <toolitem action='Open'/>"
" <toolitem action='Save'/>"
" <separator/>"
" <toolitem action='Cut'/>"
" <toolitem action='Copy'/>"
" <toolitem action='Paste'/>"
" <separator/>"
" <toolitem action='InsertCommand'/>"
" <toolitem action='DeleteCommand'/>"
" <separator/>"
" <toolitem action='ClearOutputs'/>"
" <toolitem action='DeleteOutput'/>"
" <separator/>"
" <toolitem action='EditComment'/>"
" <toolitem action='Editor'/>"
" </toolbar>"
" <popup name='Popup'>"
" <menuitem action='Cut'/>"
" <menuitem action='Copy'/>"
" <menuitem action='Paste'/>"
" <separator/>"
" <menuitem action='InsertCommand'/>"
" <menuitem action='DeleteCommand'/>"
" <separator/>"
" <menuitem action='ClearOutputs'/>"
" <menuitem action='DeleteOutput'/>"
" <separator/>"
" <menuitem action='EditComment'/>"
" </popup>"
"</ui>";
int main(int argc, char *argv[])
{
GtkWidget *vbox;
GtkUIManager *ui;
GtkActionGroup *actions,*demoactions;
GError *error = NULL;
GtkWidget *statusbar;
GtkWidget *hbox;
GtkWidget *scrollbar;
GdkBitmap *icon_mask;
GdkPixmap *icon_pixmap;
GdkColor alpha;
char **entries=NULL;
int n_entries=0,i;
char *s;
/* this should be equivalent to setlocale (LC_ALL, "") */
gtk_set_locale();
/* This must be the same for all locales */
setlocale(LC_NUMERIC, "POSIX");
/* Disable gtk's ability to set the locale. */
/* If gtk is allowed to set the locale, then it will override the */
/* setlocale for LC_NUMERIC (which is important for proper PS output. */
/* This may look funny here, given we make a call to gtk_set_locale() */
/* above. I don't know yet, if this is really the right thing to do. */
gtk_disable_setlocale();
gtk_init (&argc, &argv);
prefs = eulerrc_init();
/* allocate stack space */
if (!stack_init(prefs.estack)) {
g_print("Stack allocation failed!\nExiting.....\n");
exit(1);
}
/* allocate graphic stack space */
if (!openmeta(prefs.gstack,NULL)) {
g_print("Graphic stack allocation failed!\nExiting.....\n");
exit(1);
}
setmetalines(prefs.glines);
setmetacolors(prefs.colors);
/*
* setup atoms needed for drag & drop
*/
text_plain = gdk_atom_intern("text/plain", FALSE);
text_uri_list = gdk_atom_intern("text/uri-list", FALSE);
application_octet_stream = gdk_atom_intern("application/octet-stream", FALSE);
/*
* create the graphic window
*/
meta_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(meta_window), "Euler graphics window");
g_signal_connect(G_OBJECT(meta_window),"delete_event",
G_CALLBACK(on_file_quit),NULL);
g_signal_connect(G_OBJECT(meta_window),"destroy",
G_CALLBACK(on_file_quit),NULL);
meta = gtk_meta_new(prefs.gwidth,prefs.gheight);
gtk_container_add(GTK_CONTAINER(meta_window),meta);
/*
* add a hook to collect geometry changes of the graphic window
*/
g_signal_connect(G_OBJECT(meta_window),"configure_event",
G_CALLBACK(meta_cfg_cb),NULL);
gtk_widget_show_all(meta_window);
/*
* create the main window
*/
term_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (term_window), "Euler []");
gtk_widget_realize(term_window);
icon_pixmap = gdk_pixmap_create_from_xpm_d(term_window->window,&icon_mask,&alpha,icon_xpm);
gdk_window_set_icon(term_window->window,NULL,icon_pixmap,icon_mask);
gdk_window_set_group(meta_window->window,term_window->window);
actions = gtk_action_group_new ("Actions");
gtk_action_group_add_actions (actions, actionentries, n_actionentries, NULL);
ui = gtk_ui_manager_new ();
gtk_ui_manager_insert_action_group (ui, actions, 0);
gtk_window_add_accel_group (GTK_WINDOW (term_window),
gtk_ui_manager_get_accel_group (ui));
if(!gtk_ui_manager_add_ui_from_string(ui, ui_info, -1, &error))
{
g_message ("Building menus failed: %s", error->message);
g_error_free (error);
}
gtk_ui_manager_set_add_tearoffs(ui,TRUE);
gtk_toolbar_set_style(GTK_TOOLBAR(gtk_ui_manager_get_widget(ui, "ui/ToolBar")), GTK_TOOLBAR_ICONS);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (term_window), vbox);
gtk_box_pack_start (GTK_BOX (vbox), gtk_ui_manager_get_widget (ui, "/MenuBar"),
FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), gtk_ui_manager_get_widget (ui, "/ToolBar"),
FALSE, FALSE, 0);
/*
* parse the install directory for available demos
*/
s = g_strconcat(INSTALL_DIR,"/share/euler/progs",NULL);
scan_dir(s,"*.en",&entries,&n_entries);
if (entries) {
GtkActionEntry demoentries[n_entries];
for (i=0;i<n_entries;i++) {
demoentries[i].name = entries[i];
demoentries[i].stock_id = NULL;
demoentries[i].label = entries[i];
demoentries[i].accelerator = NULL;
demoentries[i].tooltip = NULL;
demoentries[i].callback = G_CALLBACK(demo_cb);
}
demoactions = gtk_action_group_new ("DemoActions");
gtk_action_group_add_actions (demoactions, demoentries, n_entries, NULL);
gtk_ui_manager_insert_action_group (ui, demoactions, 0);
for (i=0;i<n_entries;i++){
gtk_ui_manager_add_ui(ui,gtk_ui_manager_new_merge_id(ui), "/ui/MenuBar/Misc/Demo",
entries[i],entries[i], GTK_UI_MANAGER_MENUITEM, FALSE);
g_free(entries[i]);
}
g_free(entries);
entries = NULL;
}
g_free(s);
hbox = gtk_hbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(vbox),hbox,TRUE,TRUE,0);
term = gtk_term_new(prefs.twidth,prefs.theight,prefs.tfont);
gtk_box_pack_start_defaults(GTK_BOX(hbox),term);
g_signal_connect(G_OBJECT(term),"term_changed",
G_CALLBACK(term_changed_cb),NULL);
g_signal_connect(G_OBJECT(term),"term_saved",
G_CALLBACK(term_saved_cb),NULL);
g_signal_connect_after(G_OBJECT(term),"size_allocate",
G_CALLBACK(term_cfg_cb),NULL);
/* Set the window up to receive drops */
gtk_drag_dest_set(term,
GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT,
targets_to_accept,
sizeof(targets_to_accept) / sizeof(*targets_to_accept),
GDK_ACTION_COPY | GDK_ACTION_PRIVATE);
g_signal_connect(G_OBJECT(term), "drag_drop",
G_CALLBACK(drag_drop), NULL);
g_signal_connect(G_OBJECT(term), "drag_data_received",
G_CALLBACK(drag_data_received), NULL);
scrollbar = gtk_vscrollbar_new(GTK_TERM(term)->v_adj);
GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);
gtk_box_pack_start(GTK_BOX(hbox),scrollbar,FALSE,FALSE,0);
gtk_term_set_scrollbar(term, scrollbar);
/*
* set the popup menu
*/
gtk_term_set_popup(term,GTK_MENU(gtk_ui_manager_get_widget(ui,"/Popup")));
statusbar = gtk_statusbar_new ();
gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, FALSE, 0);
id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar),"euler status messages");
g_signal_connect_swapped(G_OBJECT(term),"term_editing",
G_CALLBACK(term_editing_cb),GTK_OBJECT(statusbar));
g_signal_connect_swapped(G_OBJECT(term),"term_interpreting",
G_CALLBACK(term_interpreting_cb),GTK_OBJECT(statusbar));
gtk_statusbar_push(GTK_STATUSBAR(statusbar),id," Initializing Euler ...");
g_signal_connect (G_OBJECT(term_window), "delete_event",
G_CALLBACK (on_file_quit),NULL);
g_signal_connect (G_OBJECT(term_window), "destroy",
G_CALLBACK (on_file_quit),NULL);
/*
* show everything and lets go
*/
gtk_widget_show_all(term_window);
setmetadevice(gtk_meta_get_device(meta));
while (gtk_events_pending()) gtk_main_iteration_do(FALSE);
s=g_strconcat(INSTALL_DIR,"/share/euler/help.txt",NULL);
loadhelp(s);
g_free(s);
main_loop(argc,argv);
closemeta();
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1