4 * PCB, interactive printed circuit board design
5 * Copyright (C) 1994,1995,1996 Thomas Nau
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
23 * Thomas.Nau@rz.uni-ulm.de
27 /* This file written by Bill Wilson for the PCB Gtk port.
38 #ifdef HAVE_LIBDMALLOC
42 /* ---------------------------------------------- */
44 ghid_dialog_input (const char * prompt
, const char * initial
)
47 GtkWidget
*content_area
;
48 GtkWidget
*vbox
, *label
, *entry
;
51 GHidPort
*out
= &ghid_port
;
53 dialog
= gtk_dialog_new_with_buttons (_("PCB User Input"),
54 GTK_WINDOW (out
->top_window
),
56 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
57 GTK_STOCK_OK
, GTK_RESPONSE_OK
, NULL
);
59 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
60 vbox
= gtk_vbox_new (FALSE
, 4);
61 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 4);
62 label
= gtk_label_new ("");
63 gtk_box_pack_start (GTK_BOX (vbox
), label
, TRUE
, TRUE
, 0);
65 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
66 gtk_label_set_markup (GTK_LABEL (label
),
67 prompt
? prompt
: _("Enter something"));
69 entry
= gtk_entry_new ();
71 gtk_entry_set_text (GTK_ENTRY (entry
), initial
);
73 gtk_entry_set_activates_default (GTK_ENTRY (entry
), TRUE
);
74 gtk_box_pack_start (GTK_BOX (vbox
), entry
, TRUE
, TRUE
, 0);
76 content_area
= gtk_dialog_get_content_area (GTK_DIALOG (dialog
));
77 gtk_container_add (GTK_CONTAINER (content_area
), vbox
);
78 gtk_widget_show_all (dialog
);
80 response
= gtk_dialog_run (GTK_DIALOG (dialog
));
81 if (response
!= GTK_RESPONSE_OK
)
82 string
= g_strdup (initial
? initial
: "");
84 string
= gtk_editable_get_chars (GTK_EDITABLE (entry
), 0, -1);
86 gtk_widget_destroy (dialog
);
90 /* ---------------------------------------------- */
92 ghid_dialog_about (void)
95 GHidPort
*out
= &ghid_port
;
96 dialog
= gtk_message_dialog_new (GTK_WINDOW (out
->top_window
),
97 (GtkDialogFlags
)(GTK_DIALOG_MODAL
98 | GTK_DIALOG_DESTROY_WITH_PARENT
),
101 "%s", GetInfoString ());
103 gtk_dialog_run (GTK_DIALOG (dialog
));
104 gtk_widget_destroy (dialog
);
107 /* ---------------------------------------------- */
109 ghid_dialog_confirm_all (gchar
* all_message
)
112 GtkWidget
*content_area
;
113 GtkWidget
*label
, *vbox
;
115 GHidPort
*out
= &ghid_port
;
117 dialog
= gtk_dialog_new_with_buttons (_("Confirm"),
118 GTK_WINDOW (out
->top_window
),
119 (GtkDialogFlags
)(GTK_DIALOG_MODAL
|
120 GTK_DIALOG_DESTROY_WITH_PARENT
),
121 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
122 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
124 GUI_DIALOG_RESPONSE_ALL
, NULL
);
126 content_area
= gtk_dialog_get_content_area (GTK_DIALOG (dialog
));
127 vbox
= ghid_framed_vbox (content_area
, NULL
, 6, FALSE
, 4, 6);
129 label
= gtk_label_new (all_message
);
130 gtk_box_pack_start (GTK_BOX (vbox
), label
, FALSE
, FALSE
, 3);
131 gtk_widget_show_all (dialog
);
133 response
= gtk_dialog_run (GTK_DIALOG (dialog
));
134 gtk_widget_destroy (dialog
);
139 /* ---------------------------------------------- */
141 ghid_dialog_message (gchar
* message
)
144 GHidPort
*out
= &ghid_port
;
146 dialog
= gtk_message_dialog_new (GTK_WINDOW (out
->top_window
),
147 (GtkDialogFlags
)(GTK_DIALOG_MODAL
|
148 GTK_DIALOG_DESTROY_WITH_PARENT
),
149 GTK_MESSAGE_WARNING
, GTK_BUTTONS_OK
,
152 gtk_dialog_run (GTK_DIALOG (dialog
));
153 gtk_widget_destroy (dialog
);
156 /* ---------------------------------------------- */
158 ghid_dialog_confirm (gchar
* message
, gchar
* cancelmsg
, gchar
* okmsg
)
160 static gint x
= -1, y
= -1;
162 gboolean confirm
= FALSE
;
163 GHidPort
*out
= &ghid_port
;
165 if (cancelmsg
== NULL
)
167 cancelmsg
= _("_Cancel");
174 dialog
= gtk_message_dialog_new (GTK_WINDOW (out
->top_window
),
175 (GtkDialogFlags
)(GTK_DIALOG_MODAL
|
176 GTK_DIALOG_DESTROY_WITH_PARENT
),
177 GTK_MESSAGE_QUESTION
,
180 gtk_dialog_add_buttons (GTK_DIALOG (dialog
),
181 cancelmsg
, GTK_RESPONSE_CANCEL
,
182 okmsg
, GTK_RESPONSE_OK
,
186 gtk_window_move(GTK_WINDOW (dialog
), x
, y
);
189 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_OK
)
192 gtk_window_get_position(GTK_WINDOW (dialog
), &x
, &y
);
194 gtk_widget_destroy (dialog
);
198 /* ---------------------------------------------- */
200 ghid_dialog_close_confirm ()
204 GHidPort
*out
= &ghid_port
;
208 if (PCB
->Filename
== NULL
)
210 tmp
= g_strdup_printf (
211 _("Save the changes to layout before closing?"));
213 tmp
= g_strdup_printf (
214 _("Save the changes to layout \"%s\" before closing?"),
217 str
= g_strconcat ("<big><b>", tmp
, "</b></big>", NULL
);
219 tmp
= _("If you don't save, all your changes will be permanently lost.");
220 str
= g_strconcat (str
, "\n\n", tmp
, NULL
);
222 dialog
= gtk_message_dialog_new (GTK_WINDOW (out
->top_window
),
223 (GtkDialogFlags
)(GTK_DIALOG_MODAL
|
224 GTK_DIALOG_DESTROY_WITH_PARENT
),
226 GTK_BUTTONS_NONE
, NULL
);
227 gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog
), str
);
228 gtk_dialog_add_buttons (GTK_DIALOG (dialog
),
229 _("Close _without saving"), GTK_RESPONSE_NO
,
230 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
231 GTK_STOCK_SAVE
, GTK_RESPONSE_YES
,
233 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_YES
);
235 /* Set the alternative button order (ok, cancel, help) for other systems */
236 gtk_dialog_set_alternative_button_order(GTK_DIALOG(dialog
),
242 switch (gtk_dialog_run (GTK_DIALOG (dialog
)))
244 case GTK_RESPONSE_NO
:
246 rv
= GUI_DIALOG_CLOSE_CONFIRM_NOSAVE
;
249 case GTK_RESPONSE_YES
:
251 rv
= GUI_DIALOG_CLOSE_CONFIRM_SAVE
;
254 case GTK_RESPONSE_CANCEL
:
257 rv
= GUI_DIALOG_CLOSE_CONFIRM_CANCEL
;
261 gtk_widget_destroy (dialog
);
265 /* ---------------------------------------------- */
266 /* Caller must g_free() the returned filename.*/
268 ghid_dialog_file_select_open (gchar
* title
, gchar
** path
, gchar
* shortcuts
)
271 gchar
*result
= NULL
, *folder
, *seed
;
272 GHidPort
*out
= &ghid_port
;
273 GtkFileFilter
*no_filter
;
275 dialog
= gtk_file_chooser_dialog_new (title
,
276 GTK_WINDOW (out
->top_window
),
277 GTK_FILE_CHOOSER_ACTION_OPEN
,
278 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
279 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
282 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
284 /* add a default filter for not filtering files */
285 no_filter
= gtk_file_filter_new ();
286 gtk_file_filter_set_name (no_filter
, "all");
287 gtk_file_filter_add_pattern (no_filter
, "*.*");
288 gtk_file_filter_add_pattern (no_filter
, "*");
289 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog
), no_filter
);
291 /* in case we have a dialog for loading a footprint file */
292 if (strcmp (title
, _("Load element to buffer")) == 0)
294 /* add a filter for footprint files */
295 GtkFileFilter
*fp_filter
;
296 fp_filter
= gtk_file_filter_new ();
297 gtk_file_filter_set_name (fp_filter
, "fp");
298 gtk_file_filter_add_mime_type (fp_filter
, "application/x-pcb-footprint");
299 gtk_file_filter_add_pattern (fp_filter
, "*.fp");
300 gtk_file_filter_add_pattern (fp_filter
, "*.FP");
301 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog
), fp_filter
);
304 /* in case we have a dialog for loading a layout file */
305 if ((strcmp (title
, _("Load layout file")) == 0)
306 || (strcmp (title
, _("Load layout file to buffer")) == 0))
308 /* add a filter for layout files */
309 GtkFileFilter
*pcb_filter
;
310 pcb_filter
= gtk_file_filter_new ();
311 gtk_file_filter_set_name (pcb_filter
, "pcb");
312 gtk_file_filter_add_mime_type (pcb_filter
, "application/x-pcb-layout");
313 gtk_file_filter_add_pattern (pcb_filter
, "*.pcb");
314 gtk_file_filter_add_pattern (pcb_filter
, "*.PCB");
315 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog
), pcb_filter
);
318 /* in case we have a dialog for loading a netlist file */
319 if (strcmp (title
, _("Load netlist file")) == 0)
321 /* add a filter for netlist files */
322 GtkFileFilter
*net_filter
;
323 net_filter
= gtk_file_filter_new ();
324 gtk_file_filter_set_name (net_filter
, "netlist");
325 gtk_file_filter_add_mime_type (net_filter
, "application/x-pcb-netlist");
326 gtk_file_filter_add_pattern (net_filter
, "*.net");
327 gtk_file_filter_add_pattern (net_filter
, "*.NET");
328 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog
), net_filter
);
332 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), *path
);
336 default_path
= g_get_current_dir();
337 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), default_path
);
338 g_free(default_path
);
341 if (shortcuts
&& *shortcuts
)
343 folder
= g_strdup (shortcuts
);
345 while ((folder
= strtok (seed
, ":")) != NULL
)
347 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog
),
354 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_OK
)
356 result
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
358 gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog
));
361 dup_string (path
, folder
);
365 gtk_widget_destroy (dialog
);
372 /* ---------------------------------------------- */
373 /* Caller must g_slist_free() the returned list .*/
375 ghid_dialog_file_select_multiple(gchar
* title
, gchar
** path
, gchar
* shortcuts
)
378 GSList
*result
= NULL
;
379 gchar
*folder
, *seed
;
380 GHidPort
*out
= &ghid_port
;
381 GtkFileFilter
*no_filter
;
383 dialog
= gtk_file_chooser_dialog_new (title
,
384 GTK_WINDOW (out
->top_window
),
385 GTK_FILE_CHOOSER_ACTION_OPEN
,
386 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
387 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
390 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
392 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER (dialog
), TRUE
);
394 /* add a default filter for not filtering files */
395 no_filter
= gtk_file_filter_new ();
396 gtk_file_filter_set_name (no_filter
, "all");
397 gtk_file_filter_add_pattern (no_filter
, "*.*");
398 gtk_file_filter_add_pattern (no_filter
, "*");
399 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog
), no_filter
);
401 /* in case we have a dialog for loading schematic files */
402 if (strcmp (title
, _("Load schematics")) == 0)
404 /* add a filter for schematic files */
405 GtkFileFilter
*sch_filter
;
406 sch_filter
= gtk_file_filter_new ();
407 gtk_file_filter_set_name (sch_filter
, "sch");
408 gtk_file_filter_add_mime_type (sch_filter
, "application/x-geda-schematic");
409 gtk_file_filter_add_pattern (sch_filter
, "*.sch");
410 gtk_file_filter_add_pattern (sch_filter
, "*.SCH");
411 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog
), sch_filter
);
415 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), *path
);
419 default_path
= g_get_current_dir();
420 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), default_path
);
421 g_free(default_path
);
424 if (shortcuts
&& *shortcuts
)
426 folder
= g_strdup (shortcuts
);
428 while ((folder
= strtok (seed
, ":")) != NULL
)
430 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog
),
437 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_OK
)
439 result
= gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dialog
));
441 gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog
));
444 dup_string (path
, folder
);
448 gtk_widget_destroy (dialog
);
455 /* ---------------------------------------------- */
456 /* Caller must g_free() the returned filename. */
458 ghid_dialog_file_select_save (gchar
* title
, gchar
** path
, gchar
* file
,
462 gchar
*result
= NULL
, *folder
, *seed
;
463 GHidPort
*out
= &ghid_port
;
465 dialog
= gtk_file_chooser_dialog_new (title
,
466 GTK_WINDOW (out
->top_window
),
467 GTK_FILE_CHOOSER_ACTION_SAVE
,
468 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
469 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
472 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog
),
474 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
476 if (path
&& *path
&& **path
)
477 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), *path
);
481 default_path
= g_get_current_dir();
482 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), default_path
);
483 g_free(default_path
);
488 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
),
489 g_path_get_basename(file
));
490 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
),
491 g_path_get_dirname (file
));
494 if (shortcuts
&& *shortcuts
)
496 folder
= g_strdup (shortcuts
);
498 while ((folder
= strtok (seed
, ":")) != NULL
)
500 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog
),
506 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_OK
)
508 result
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
510 gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog
));
513 dup_string (path
, folder
);
517 gtk_widget_destroy (dialog
);
524 /* ---------------------------------------------- */
525 /* how many files and directories to keep for the shortcuts */
527 typedef struct ghid_file_history_struct
530 * an identifier as to which recent files pool this is. For example
531 * "boards", "eco", "netlists", etc.
536 * the array of files or directories
538 char * history
[NHIST
];
541 static int n_recent_dirs
= 0;
542 static ghid_file_history
* recent_dirs
= NULL
;
544 /* ---------------------------------------------- */
545 /* Caller must g_free() the returned filename. */
547 ghid_fileselect (const char *title
, const char *descr
,
548 char *default_file
, char *default_ext
,
549 const char *history_tag
, int flags
)
552 gchar
*result
= NULL
;
553 GHidPort
*out
= &ghid_port
;
554 gchar
*path
= NULL
, *base
= NULL
;
555 int history_pool
= -1;
558 if (history_tag
&& *history_tag
)
561 * I used a simple linear search here because the number of
562 * entries in the array is likely to be quite small (5, maybe 10 at
563 * the absolute most) and this function is used when pulling up
564 * a file dialog box instead of something called over and over
565 * again as part of moving elements or autorouting. So, keep it
569 while (history_pool
< n_recent_dirs
&&
570 strcmp (recent_dirs
[history_pool
].id
, history_tag
) != 0)
576 * If we counted all the way to n_recent_dirs, that means we
577 * didn't find our entry
579 if (history_pool
>= n_recent_dirs
)
583 recent_dirs
= (ghid_file_history
*)realloc (recent_dirs
,
584 n_recent_dirs
* sizeof (ghid_file_history
));
586 if (recent_dirs
== NULL
)
588 fprintf (stderr
, "%s(): realloc failed\n", __FUNCTION__
);
592 recent_dirs
[history_pool
].id
= strdup (history_tag
);
594 /* Initialize the entries in our history list to all be NULL */
595 for (i
= 0; i
< NHIST
; i
++)
597 recent_dirs
[history_pool
].history
[i
] = NULL
;
602 if (default_file
&& *default_file
)
604 path
= g_path_get_dirname (default_file
);
605 base
= g_path_get_basename (default_file
);
608 dialog
= gtk_file_chooser_dialog_new (title
,
609 GTK_WINDOW (out
->top_window
),
610 (flags
& HID_FILESELECT_READ
) ?
611 GTK_FILE_CHOOSER_ACTION_OPEN
:
612 GTK_FILE_CHOOSER_ACTION_SAVE
,
613 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
614 GTK_STOCK_OK
, GTK_RESPONSE_OK
,
617 gtk_dialog_set_default_response (GTK_DIALOG (dialog
), GTK_RESPONSE_OK
);
621 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), path
);
627 default_path
= g_get_current_dir();
628 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog
), default_path
);
629 g_free(default_path
);
634 /* default file is only supposed to be for writing, not reading */
635 if (!(flags
& HID_FILESELECT_READ
))
637 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), base
);
642 for (i
= 0; i
< NHIST
&& recent_dirs
[history_pool
].history
[i
] != NULL
; i
++)
644 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog
),
645 recent_dirs
[history_pool
].history
[i
],
649 if (gtk_dialog_run (GTK_DIALOG (dialog
)) == GTK_RESPONSE_OK
)
651 result
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
653 path
= g_path_get_dirname (result
);
657 /* update the history list */
664 * Put this at the top of the list and bump everything else
665 * down but skip any old entry of this directory
669 recent_dirs
[history_pool
].history
[k
] != NULL
&&
670 strcmp ( recent_dirs
[history_pool
].history
[k
], path
) == 0)
674 tmps
= recent_dirs
[history_pool
].history
[k
];
675 recent_dirs
[history_pool
].history
[0] = path
;
676 for (i
= 1 ; i
< NHIST
; i
++)
678 /* store our current entry, but skip duplicates */
679 while (i
+ k
< NHIST
&&
680 recent_dirs
[history_pool
].history
[i
+ k
] != NULL
&&
681 strcmp ( recent_dirs
[history_pool
].history
[i
+ k
], path
) == 0)
687 tmps2
= recent_dirs
[history_pool
].history
[i
+ k
];
691 /* move down the one we stored last time */
692 recent_dirs
[history_pool
].history
[i
] = tmps
;
694 /* and remember the displace entry */
699 * the last one has fallen off the end of the history list
700 * so we need to free() it.
709 printf ("\n\n-----\n\n");
710 for (i
= 0 ; i
< NHIST
; i
++)
712 printf ("After update recent_dirs[%d].history[%d] = \"%s\"\n",
713 history_pool
, i
, recent_dirs
[history_pool
].history
[i
] != NULL
?
714 recent_dirs
[history_pool
].history
[i
] : "NULL");
719 gtk_widget_destroy (dialog
);